From 2d0ef3127f9e46af7a9688c523a813862958b70f Mon Sep 17 00:00:00 2001 From: Hirofumi Katayama Date: Tue, 12 Nov 2013 17:20:10 +0900 Subject: [PATCH] v0.48 --- STATUS.txt | 227 +++ clean.bat | 6 + colors.c | 2 +- del_git.sh | 1 + gle-3.1.0/ReadMe.txt | 6 + gle-3.1.0/include/GL/gle.h | 304 +++ gle-3.1.0/lib/gle.lib | Bin 0 -> 90908 bytes gle-3.1.0/lib/gled.lib | Bin 0 -> 458572 bytes hsv.c | 2 +- non-wgl/XScreenSaverWinNonWGL.sln | 582 ++++++ non-wgl/abstractile.c | 1612 +++++++++++++++ non-wgl/abstractile.vcproj | 253 +++ non-wgl/anemone.c | 479 +++++ non-wgl/anemone.vcproj | 269 +++ non-wgl/anemotaxis.c | 777 +++++++ non-wgl/anemotaxis.vcproj | 269 +++ non-wgl/ant.c | 2 +- non-wgl/ant.vcproj | 16 +- non-wgl/apollonian.c | 2 +- non-wgl/apollonian.vcproj | 14 +- non-wgl/attraction.c | 1175 +++++++++++ non-wgl/attraction.vcproj | 253 +++ non-wgl/barcode.c | 2005 ++++++++++++++++++ non-wgl/barcode.vcproj | 257 +++ non-wgl/blaster.c | 1289 ++++++++++++ non-wgl/blaster.vcproj | 253 +++ non-wgl/bouboule.c | 2 +- non-wgl/bouboule.vcproj | 14 +- non-wgl/braid.c | 3 +- non-wgl/braid.vcproj | 14 +- non-wgl/bumps.c | 761 +++++++ non-wgl/bumps.vcproj | 253 +++ non-wgl/ccurve.c | 881 ++++++++ non-wgl/ccurve.vcproj | 261 +++ non-wgl/celtic.c | 1164 +++++++++++ non-wgl/celtic.vcproj | 261 +++ non-wgl/clean.bat | 30 + non-wgl/cloudlife.c | 454 +++++ non-wgl/cloudlife.vcproj | 253 +++ non-wgl/compass.c | 1006 +++++++++ non-wgl/compass.vcproj | 269 +++ non-wgl/coral.c | 335 +++ non-wgl/coral.vcproj | 261 +++ non-wgl/critical.c | 483 +++++ non-wgl/critical.vcproj | 261 +++ non-wgl/crystal.c | 3 +- non-wgl/crystal.vcproj | 14 +- non-wgl/cynosure.c | 479 +++++ non-wgl/cynosure.vcproj | 253 +++ non-wgl/deco.c | 378 ++++ non-wgl/deco.vcproj | 253 +++ non-wgl/demon.c | 1002 +++++++++ non-wgl/demon.vcproj | 265 +++ non-wgl/discrete.c | 480 +++++ non-wgl/discrete.vcproj | 265 +++ non-wgl/drift.c | 717 +++++++ non-wgl/drift.vcproj | 265 +++ non-wgl/epicycle.c | 851 ++++++++ non-wgl/epicycle.vcproj | 261 +++ non-wgl/erase.c | 27 + non-wgl/eruption.c | 552 +++++ non-wgl/eruption.vcproj | 261 +++ non-wgl/euler2d.c | 898 ++++++++ non-wgl/euler2d.vcproj | 257 +++ non-wgl/fadeplot.c | 256 +++ non-wgl/fadeplot.vcproj | 257 +++ non-wgl/fiberlamp.c | 483 +++++ non-wgl/fiberlamp.vcproj | 261 +++ non-wgl/fireworkx.c | 879 ++++++++ non-wgl/fireworkx.vcproj | 257 +++ non-wgl/flame.c | 488 +++++ non-wgl/flame.vcproj | 257 +++ non-wgl/flow.c | 1239 +++++++++++ non-wgl/flow.vcproj | 265 +++ non-wgl/forest.c | 266 +++ non-wgl/forest.vcproj | 257 +++ non-wgl/fuzzyflakes.c | 686 +++++++ non-wgl/fuzzyflakes.vcproj | 261 +++ non-wgl/galaxy.c | 8 +- non-wgl/galaxy.vcproj | 14 +- non-wgl/grav.c | 370 ++++ non-wgl/grav.vcproj | 257 +++ non-wgl/greynetic.c | 314 +++ non-wgl/greynetic.vcproj | 261 +++ non-wgl/halftone.c | 436 ++++ non-wgl/halftone.vcproj | 261 +++ non-wgl/halo.c | 484 +++++ non-wgl/halo.vcproj | 261 +++ non-wgl/helix.c | 381 ++++ non-wgl/helix.vcproj | 261 +++ non-wgl/hexadrop.c | 444 ++++ non-wgl/hexadrop.vcproj | 253 +++ non-wgl/hopalong.c | 591 ++++++ non-wgl/hopalong.vcproj | 265 +++ non-wgl/hyperball.c | 2583 +++++++++++++++++++++++ non-wgl/hyperball.vcproj | 253 +++ non-wgl/hypercube.c | 676 ++++++ non-wgl/hypercube.vcproj | 253 +++ non-wgl/imsmap.c | 450 ++++ non-wgl/imsmap.vcproj | 257 +++ non-wgl/interaggregate.c | 1014 +++++++++ non-wgl/interaggregate.vcproj | 253 +++ non-wgl/interference.c | 994 +++++++++ non-wgl/interference.vcproj | 269 +++ non-wgl/intermomentary.c | 609 ++++++ non-wgl/intermomentary.vcproj | 261 +++ non-wgl/juggle.c | 2830 ++++++++++++++++++++++++++ non-wgl/julia.c | 466 +++++ non-wgl/julia.vcproj | 265 +++ non-wgl/kumppa.c | 561 +++++ non-wgl/kumppa.vcproj | 269 +++ non-wgl/laser.c | 373 ++++ non-wgl/laser.vcproj | 257 +++ non-wgl/lcdscrub.c | 284 +++ non-wgl/lcdscrub.vcproj | 253 +++ non-wgl/lightning.c | 619 ++++++ non-wgl/lightning.vcproj | 257 +++ non-wgl/lisa.c | 757 +++++++ non-wgl/lisa.vcproj | 257 +++ non-wgl/lissie.c | 338 +++ non-wgl/lissie.vcproj | 257 +++ non-wgl/lmorph.c | 599 ++++++ non-wgl/lmorph.vcproj | 253 +++ non-wgl/loop.c | 1714 ++++++++++++++++ non-wgl/loop.vcproj | 265 +++ non-wgl/maze.c | 1711 ++++++++++++++++ non-wgl/maze.vcproj | 269 +++ non-wgl/metaballs.c | 467 +++++ non-wgl/metaballs.vcproj | 257 +++ non-wgl/moire.c | 327 +++ non-wgl/moire.vcproj | 257 +++ non-wgl/moire2.c | 383 ++++ non-wgl/moire2.vcproj | 269 +++ non-wgl/mountain.c | 305 +++ non-wgl/mountain.vcproj | 257 +++ non-wgl/munch.c | 493 +++++ non-wgl/munch.vcproj | 253 +++ non-wgl/nerverot.c | 1407 +++++++++++++ non-wgl/nerverot.vcproj | 261 +++ non-wgl/non-wgl.c | 518 +---- non-wgl/pacman.c | 1810 ++++++++++++++++ non-wgl/pacman.h | 233 +++ non-wgl/pacman.vcproj | 269 +++ non-wgl/pacman_ai.c | 878 ++++++++ non-wgl/pacman_ai.h | 32 + non-wgl/pacman_level.c | 772 +++++++ non-wgl/pacman_level.h | 33 + non-wgl/pedal.c | 348 ++++ non-wgl/pedal.vcproj | 253 +++ non-wgl/penrose.c | 1363 +++++++++++++ non-wgl/penrose.vcproj | 265 +++ non-wgl/petri.c | 823 ++++++++ non-wgl/petri.vcproj | 253 +++ non-wgl/piecewise.c | 1046 ++++++++++ non-wgl/piecewise.vcproj | 269 +++ non-wgl/polyominoes.c | 2408 ++++++++++++++++++++++ non-wgl/polyominoes.vcproj | 273 +++ non-wgl/pyro.c | 397 ++++ non-wgl/pyro.vcproj | 253 +++ non-wgl/rd-bomb.c | 635 ++++++ non-wgl/rd-bomb.vcproj | 261 +++ non-wgl/ripples.c | 1192 +++++++++++ non-wgl/ripples.vcproj | 253 +++ non-wgl/rocks.c | 593 ++++++ non-wgl/rocks.vcproj | 253 +++ non-wgl/rorschach.c | 244 +++ non-wgl/rorschach.vcproj | 261 +++ non-wgl/rotor.c | 410 ++++ non-wgl/rotor.vcproj | 257 +++ non-wgl/rotzoomer.c | 512 +++++ non-wgl/rotzoomer.vcproj | 253 +++ non-wgl/shadebobs.c | 497 +++++ non-wgl/shadebobs.vcproj | 257 +++ non-wgl/sierpinski.c | 238 +++ non-wgl/sierpinski.vcproj | 257 +++ non-wgl/slip.c | 376 ++++ non-wgl/slip.vcproj | 265 +++ non-wgl/speedmine.c | 1726 ++++++++++++++++ non-wgl/speedmine.vcproj | 253 +++ non-wgl/sphere.c | 316 +++ non-wgl/sphere.vcproj | 257 +++ non-wgl/spiral.c | 343 ++++ non-wgl/spiral.vcproj | 257 +++ non-wgl/spline.c | 319 +++ non-wgl/spline.h | 51 + non-wgl/spotlight.c | 360 ++++ non-wgl/spotlight.vcproj | 253 +++ non-wgl/squiral.c | 324 +++ non-wgl/squiral.vcproj | 253 +++ non-wgl/src_only.bat | 3 + non-wgl/starfish.c | 591 ++++++ non-wgl/starfish.vcproj | 253 +++ non-wgl/strange.c | 707 +++++++ non-wgl/strange.vcproj | 253 +++ non-wgl/substrate.c | 782 +++++++ non-wgl/substrate.vcproj | 253 +++ non-wgl/swirl.c | 1497 ++++++++++++++ non-wgl/swirl.vcproj | 261 +++ non-wgl/t3d.c | 1016 +++++++++ non-wgl/t3d.vcproj | 253 +++ non-wgl/thornbird.c | 289 +++ non-wgl/thornbird.vcproj | 257 +++ non-wgl/triangle.c | 377 ++++ non-wgl/triangle.vcproj | 257 +++ non-wgl/truchet.c | 603 ++++++ non-wgl/truchet.vcproj | 261 +++ non-wgl/twang.c | 839 ++++++++ non-wgl/twang.vcproj | 253 +++ non-wgl/vermiculate.c | 1242 +++++++++++ non-wgl/vermiculate.vcproj | 253 +++ non-wgl/vines.c | 215 ++ non-wgl/vines.vcproj | 265 +++ non-wgl/wander.c | 300 +++ non-wgl/wander.vcproj | 269 +++ non-wgl/whirlwindwarp.c | 528 +++++ non-wgl/whirlwindwarp.vcproj | 253 +++ non-wgl/whirlygig.c | 816 ++++++++ non-wgl/whirlygig.vcproj | 269 +++ non-wgl/worm.c | 456 +++++ non-wgl/worm.vcproj | 257 +++ non-wgl/wormhole.c | 744 +++++++ non-wgl/wormhole.vcproj | 261 +++ non-wgl/xdbe.c | 20 + non-wgl/xdbe.h | 17 + non-wgl/xpm-pixmap.c | 368 ++++ non-wgl/xpm-pixmap.h | 26 + non-wgl/xrayswarm.c | 1241 +++++++++++ non-wgl/xrayswarm.vcproj | 253 +++ non-wgl/xspirograph.c | 365 ++++ non-wgl/xspirograph.vcproj | 261 +++ non-wgl/zoom.c | 319 +++ non-wgl/zoom.vcproj | 253 +++ pixmap.c | 76 + screenhack.c | 717 +++++++ screenhack.h | 133 ++ win32screensaver.rc => screenhack.rc | 0 src_only.bat | 6 + wgl/antinspect.c | 2 +- wgl/antinspect.vcproj | 8 +- wgl/antmaze.c | 2 +- wgl/antmaze.vcproj | 8 +- wgl/antspotlight.c | 2 +- wgl/antspotlight.vcproj | 8 +- wgl/atlantis.c | 8 +- wgl/atlantis.h | 2 +- wgl/atlantis.vcproj | 8 +- wgl/atunnel.c | 2 +- wgl/atunnel.vcproj | 8 +- wgl/blinkbox.c | 2 +- wgl/blinkbox.vcproj | 8 +- wgl/blocktube.c | 2 +- wgl/blocktube.vcproj | 8 +- wgl/boing.c | 2 +- wgl/boing.vcproj | 8 +- wgl/bouncingcow.c | 2 +- wgl/bouncingcow.vcproj | 8 +- wgl/boxed.c | 2 +- wgl/boxed.vcproj | 8 +- wgl/buildlwo.c | 2 +- wgl/cage.c | 2 +- wgl/cage.vcproj | 8 +- wgl/chessmodels.c | 2 +- wgl/clean.bat | 30 + wgl/companion.c | 2 +- wgl/companion.vcproj | 8 +- wgl/crackberg.c | 2 +- wgl/crackberg.vcproj | 8 +- wgl/cube21.c | 2 +- wgl/cube21.vcproj | 8 +- wgl/cubenetic.c | 2 +- wgl/cubenetic.vcproj | 8 +- wgl/cubestorm.c | 2 +- wgl/cubestorm.vcproj | 8 +- wgl/cubicgrid.c | 2 +- wgl/cubicgrid.vcproj | 8 +- wgl/dangerball.c | 2 +- wgl/dangerball.vcproj | 8 +- wgl/dnalogo.c | 2 +- wgl/dnalogo.vcproj | 8 +- wgl/dolphin.c | 2 +- wgl/endgame.c | 2 +- wgl/endgame.vcproj | 8 +- wgl/extrusion.c | 2 +- wgl/extrusion.h | 2 +- wgl/extrusion.vcproj | 14 +- wgl/flipflop.c | 2 +- wgl/flipflop.vcproj | 8 +- wgl/flipscreen3d.c | 2 +- wgl/flipscreen3d.vcproj | 8 +- wgl/flurry.h | 2 +- wgl/flurry.vcproj | 8 +- wgl/flyingtoasters.c | 2 +- wgl/flyingtoasters.vcproj | 8 +- wgl/gears.c | 2 +- wgl/gears.vcproj | 8 +- wgl/gflux.c | 2 +- wgl/gflux.vcproj | 8 +- wgl/glblur.c | 2 +- wgl/glblur.vcproj | 8 +- wgl/glcells.c | 2 +- wgl/glcells.vcproj | 8 +- wgl/gleidescope.c | 2 +- wgl/gleidescope.vcproj | 8 +- wgl/glforestfire.c | 2 +- wgl/glforestfire.vcproj | 8 +- wgl/glhanoi.c | 2 +- wgl/glhanoi.vcproj | 8 +- wgl/glknots.c | 2 +- wgl/glknots.vcproj | 8 +- wgl/gllist.h | 2 +- wgl/glmatrix.c | 2 +- wgl/glmatrix.vcproj | 8 +- wgl/glplanet.c | 2 +- wgl/glplanet.vcproj | 8 +- wgl/glschool.c | 2 +- wgl/glschool.vcproj | 8 +- wgl/glschool_alg.c | 2 +- wgl/glschool_gl.c | 2 +- wgl/glschool_gl.h | 2 +- wgl/glsnake.c | 2 +- wgl/glsnake.vcproj | 4 +- wgl/hilbert.c | 2 +- wgl/hilbert.vcproj | 8 +- wgl/hypertorus.c | 2 +- wgl/hypertorus.vcproj | 8 +- wgl/hypnowheel.c | 2 +- wgl/hypnowheel.vcproj | 8 +- wgl/involute.c | 2 +- wgl/jigglypuff.c | 2 +- wgl/jigglypuff.vcproj | 8 +- wgl/kaleidocycle.c | 2 +- wgl/kaleidocycle.vcproj | 8 +- wgl/klein.c | 2 +- wgl/klein.vcproj | 8 +- wgl/lament.c | 3 +- wgl/lament.vcproj | 8 +- wgl/lavalite.c | 2 +- wgl/lavalite.vcproj | 8 +- wgl/lockward.c | 2 +- wgl/lockward.vcproj | 8 +- wgl/marching.c | 2 +- wgl/menger.c | 2 +- wgl/menger.vcproj | 8 +- wgl/minixpm.c | 2 +- wgl/mirrorblob.c | 2 +- wgl/mirrorblob.vcproj | 8 +- wgl/moebius.c | 2 +- wgl/moebius.vcproj | 8 +- wgl/moebiusgears.c | 2 +- wgl/moebiusgears.vcproj | 8 +- wgl/morph3d.c | 2 +- wgl/morph3d.vcproj | 8 +- wgl/noof.c | 2 +- wgl/noof.vcproj | 8 +- wgl/normals.c | 2 +- wgl/pipeobjs.c | 2 +- wgl/pipes.c | 2 +- wgl/pipes.vcproj | 8 +- wgl/polytopes.c | 2 +- wgl/polytopes.vcproj | 8 +- wgl/providence.c | 2 +- wgl/providence.vcproj | 8 +- wgl/pulsar.c | 2 +- wgl/pulsar.vcproj | 8 +- wgl/quasicrystal.c | 2 +- wgl/quasicrystal.vcproj | 8 +- wgl/queens.c | 2 +- wgl/queens.vcproj | 8 +- wgl/rubik.c | 2 +- wgl/rubik.vcproj | 8 +- wgl/rubikblocks.c | 2 +- wgl/rubikblocks.vcproj | 8 +- wgl/sballs.c | 2 +- wgl/sballs.vcproj | 8 +- wgl/shark.c | 2 +- wgl/sierpinski3d.c | 2 +- wgl/sierpinski3d.vcproj | 8 +- wgl/skytentacles.c | 2 +- wgl/skytentacles.vcproj | 8 +- wgl/sproingies.c | 2 +- wgl/sproingies.vcproj | 8 +- wgl/sproingiewrap.c | 2 +- wgl/src_only.bat | 3 + wgl/stairs.c | 2 +- wgl/stairs.vcproj | 8 +- wgl/stonerview.c | 2 +- wgl/stonerview.vcproj | 8 +- wgl/superquadrics.c | 2 +- wgl/superquadrics.vcproj | 8 +- wgl/surfaces.c | 2 +- wgl/surfaces.vcproj | 8 +- wgl/swim.c | 2 +- wgl/teapot.c | 2 +- wgl/timetunnel.c | 4 +- wgl/timetunnel.vcproj | 8 +- wgl/topblock.c | 2 +- wgl/topblock.vcproj | 8 +- wgl/tronbit.c | 2 +- wgl/tronbit.vcproj | 8 +- wgl/tunnel_draw.c | 2 +- wgl/unknownpleasures.c | 2 +- wgl/unknownpleasures.vcproj | 8 +- wgl/voronoi.c | 2 +- wgl/voronoi.vcproj | 8 +- wgl/wgl.c | 12 +- wgl/whale.c | 2 +- wgl/xpm-ximage.c | 4 +- xcolor.c | 35 +- ximage.c | 15 +- win32screensaver.c => xlockmore.c | 99 +- xlockmore.h | 408 ++++ xlockmore.rc | 76 + xws2win.c | 982 +++++++++ xws2win.h | 560 ++--- yarandom.c | 9 +- 415 files changed, 106254 insertions(+), 1307 deletions(-) create mode 100644 STATUS.txt create mode 100644 clean.bat create mode 100644 del_git.sh create mode 100644 gle-3.1.0/ReadMe.txt create mode 100644 gle-3.1.0/include/GL/gle.h create mode 100644 gle-3.1.0/lib/gle.lib create mode 100644 gle-3.1.0/lib/gled.lib create mode 100644 non-wgl/abstractile.c create mode 100644 non-wgl/abstractile.vcproj create mode 100644 non-wgl/anemone.c create mode 100644 non-wgl/anemone.vcproj create mode 100644 non-wgl/anemotaxis.c create mode 100644 non-wgl/anemotaxis.vcproj create mode 100644 non-wgl/attraction.c create mode 100644 non-wgl/attraction.vcproj create mode 100644 non-wgl/barcode.c create mode 100644 non-wgl/barcode.vcproj create mode 100644 non-wgl/blaster.c create mode 100644 non-wgl/blaster.vcproj create mode 100644 non-wgl/bumps.c create mode 100644 non-wgl/bumps.vcproj create mode 100644 non-wgl/ccurve.c create mode 100644 non-wgl/ccurve.vcproj create mode 100644 non-wgl/celtic.c create mode 100644 non-wgl/celtic.vcproj create mode 100644 non-wgl/clean.bat create mode 100644 non-wgl/cloudlife.c create mode 100644 non-wgl/cloudlife.vcproj create mode 100644 non-wgl/compass.c create mode 100644 non-wgl/compass.vcproj create mode 100644 non-wgl/coral.c create mode 100644 non-wgl/coral.vcproj create mode 100644 non-wgl/critical.c create mode 100644 non-wgl/critical.vcproj create mode 100644 non-wgl/cynosure.c create mode 100644 non-wgl/cynosure.vcproj create mode 100644 non-wgl/deco.c create mode 100644 non-wgl/deco.vcproj create mode 100644 non-wgl/demon.c create mode 100644 non-wgl/demon.vcproj create mode 100644 non-wgl/discrete.c create mode 100644 non-wgl/discrete.vcproj create mode 100644 non-wgl/drift.c create mode 100644 non-wgl/drift.vcproj create mode 100644 non-wgl/epicycle.c create mode 100644 non-wgl/epicycle.vcproj create mode 100644 non-wgl/eruption.c create mode 100644 non-wgl/eruption.vcproj create mode 100644 non-wgl/euler2d.c create mode 100644 non-wgl/euler2d.vcproj create mode 100644 non-wgl/fadeplot.c create mode 100644 non-wgl/fadeplot.vcproj create mode 100644 non-wgl/fiberlamp.c create mode 100644 non-wgl/fiberlamp.vcproj create mode 100644 non-wgl/fireworkx.c create mode 100644 non-wgl/fireworkx.vcproj create mode 100644 non-wgl/flame.c create mode 100644 non-wgl/flame.vcproj create mode 100644 non-wgl/flow.c create mode 100644 non-wgl/flow.vcproj create mode 100644 non-wgl/forest.c create mode 100644 non-wgl/forest.vcproj create mode 100644 non-wgl/fuzzyflakes.c create mode 100644 non-wgl/fuzzyflakes.vcproj create mode 100644 non-wgl/grav.c create mode 100644 non-wgl/grav.vcproj create mode 100644 non-wgl/greynetic.c create mode 100644 non-wgl/greynetic.vcproj create mode 100644 non-wgl/halftone.c create mode 100644 non-wgl/halftone.vcproj create mode 100644 non-wgl/halo.c create mode 100644 non-wgl/halo.vcproj create mode 100644 non-wgl/helix.c create mode 100644 non-wgl/helix.vcproj create mode 100644 non-wgl/hexadrop.c create mode 100644 non-wgl/hexadrop.vcproj create mode 100644 non-wgl/hopalong.c create mode 100644 non-wgl/hopalong.vcproj create mode 100644 non-wgl/hyperball.c create mode 100644 non-wgl/hyperball.vcproj create mode 100644 non-wgl/hypercube.c create mode 100644 non-wgl/hypercube.vcproj create mode 100644 non-wgl/imsmap.c create mode 100644 non-wgl/imsmap.vcproj create mode 100644 non-wgl/interaggregate.c create mode 100644 non-wgl/interaggregate.vcproj create mode 100644 non-wgl/interference.c create mode 100644 non-wgl/interference.vcproj create mode 100644 non-wgl/intermomentary.c create mode 100644 non-wgl/intermomentary.vcproj create mode 100644 non-wgl/juggle.c create mode 100644 non-wgl/julia.c create mode 100644 non-wgl/julia.vcproj create mode 100644 non-wgl/kumppa.c create mode 100644 non-wgl/kumppa.vcproj create mode 100644 non-wgl/laser.c create mode 100644 non-wgl/laser.vcproj create mode 100644 non-wgl/lcdscrub.c create mode 100644 non-wgl/lcdscrub.vcproj create mode 100644 non-wgl/lightning.c create mode 100644 non-wgl/lightning.vcproj create mode 100644 non-wgl/lisa.c create mode 100644 non-wgl/lisa.vcproj create mode 100644 non-wgl/lissie.c create mode 100644 non-wgl/lissie.vcproj create mode 100644 non-wgl/lmorph.c create mode 100644 non-wgl/lmorph.vcproj create mode 100644 non-wgl/loop.c create mode 100644 non-wgl/loop.vcproj create mode 100644 non-wgl/maze.c create mode 100644 non-wgl/maze.vcproj create mode 100644 non-wgl/metaballs.c create mode 100644 non-wgl/metaballs.vcproj create mode 100644 non-wgl/moire.c create mode 100644 non-wgl/moire.vcproj create mode 100644 non-wgl/moire2.c create mode 100644 non-wgl/moire2.vcproj create mode 100644 non-wgl/mountain.c create mode 100644 non-wgl/mountain.vcproj create mode 100644 non-wgl/munch.c create mode 100644 non-wgl/munch.vcproj create mode 100644 non-wgl/nerverot.c create mode 100644 non-wgl/nerverot.vcproj create mode 100644 non-wgl/pacman.c create mode 100644 non-wgl/pacman.h create mode 100644 non-wgl/pacman.vcproj create mode 100644 non-wgl/pacman_ai.c create mode 100644 non-wgl/pacman_ai.h create mode 100644 non-wgl/pacman_level.c create mode 100644 non-wgl/pacman_level.h create mode 100644 non-wgl/pedal.c create mode 100644 non-wgl/pedal.vcproj create mode 100644 non-wgl/penrose.c create mode 100644 non-wgl/penrose.vcproj create mode 100644 non-wgl/petri.c create mode 100644 non-wgl/petri.vcproj create mode 100644 non-wgl/piecewise.c create mode 100644 non-wgl/piecewise.vcproj create mode 100644 non-wgl/polyominoes.c create mode 100644 non-wgl/polyominoes.vcproj create mode 100644 non-wgl/pyro.c create mode 100644 non-wgl/pyro.vcproj create mode 100644 non-wgl/rd-bomb.c create mode 100644 non-wgl/rd-bomb.vcproj create mode 100644 non-wgl/ripples.c create mode 100644 non-wgl/ripples.vcproj create mode 100644 non-wgl/rocks.c create mode 100644 non-wgl/rocks.vcproj create mode 100644 non-wgl/rorschach.c create mode 100644 non-wgl/rorschach.vcproj create mode 100644 non-wgl/rotor.c create mode 100644 non-wgl/rotor.vcproj create mode 100644 non-wgl/rotzoomer.c create mode 100644 non-wgl/rotzoomer.vcproj create mode 100644 non-wgl/shadebobs.c create mode 100644 non-wgl/shadebobs.vcproj create mode 100644 non-wgl/sierpinski.c create mode 100644 non-wgl/sierpinski.vcproj create mode 100644 non-wgl/slip.c create mode 100644 non-wgl/slip.vcproj create mode 100644 non-wgl/speedmine.c create mode 100644 non-wgl/speedmine.vcproj create mode 100644 non-wgl/sphere.c create mode 100644 non-wgl/sphere.vcproj create mode 100644 non-wgl/spiral.c create mode 100644 non-wgl/spiral.vcproj create mode 100644 non-wgl/spline.c create mode 100644 non-wgl/spline.h create mode 100644 non-wgl/spotlight.c create mode 100644 non-wgl/spotlight.vcproj create mode 100644 non-wgl/squiral.c create mode 100644 non-wgl/squiral.vcproj create mode 100644 non-wgl/src_only.bat create mode 100644 non-wgl/starfish.c create mode 100644 non-wgl/starfish.vcproj create mode 100644 non-wgl/strange.c create mode 100644 non-wgl/strange.vcproj create mode 100644 non-wgl/substrate.c create mode 100644 non-wgl/substrate.vcproj create mode 100644 non-wgl/swirl.c create mode 100644 non-wgl/swirl.vcproj create mode 100644 non-wgl/t3d.c create mode 100644 non-wgl/t3d.vcproj create mode 100644 non-wgl/thornbird.c create mode 100644 non-wgl/thornbird.vcproj create mode 100644 non-wgl/triangle.c create mode 100644 non-wgl/triangle.vcproj create mode 100644 non-wgl/truchet.c create mode 100644 non-wgl/truchet.vcproj create mode 100644 non-wgl/twang.c create mode 100644 non-wgl/twang.vcproj create mode 100644 non-wgl/vermiculate.c create mode 100644 non-wgl/vermiculate.vcproj create mode 100644 non-wgl/vines.c create mode 100644 non-wgl/vines.vcproj create mode 100644 non-wgl/wander.c create mode 100644 non-wgl/wander.vcproj create mode 100644 non-wgl/whirlwindwarp.c create mode 100644 non-wgl/whirlwindwarp.vcproj create mode 100644 non-wgl/whirlygig.c create mode 100644 non-wgl/whirlygig.vcproj create mode 100644 non-wgl/worm.c create mode 100644 non-wgl/worm.vcproj create mode 100644 non-wgl/wormhole.c create mode 100644 non-wgl/wormhole.vcproj create mode 100644 non-wgl/xdbe.c create mode 100644 non-wgl/xdbe.h create mode 100644 non-wgl/xpm-pixmap.c create mode 100644 non-wgl/xpm-pixmap.h create mode 100644 non-wgl/xrayswarm.c create mode 100644 non-wgl/xrayswarm.vcproj create mode 100644 non-wgl/xspirograph.c create mode 100644 non-wgl/xspirograph.vcproj create mode 100644 non-wgl/zoom.c create mode 100644 non-wgl/zoom.vcproj create mode 100644 pixmap.c create mode 100644 screenhack.c create mode 100644 screenhack.h rename win32screensaver.rc => screenhack.rc (100%) create mode 100644 src_only.bat create mode 100644 wgl/clean.bat create mode 100644 wgl/src_only.bat rename win32screensaver.c => xlockmore.c (92%) create mode 100644 xlockmore.h create mode 100644 xlockmore.rc create mode 100644 xws2win.c diff --git a/STATUS.txt b/STATUS.txt new file mode 100644 index 0000000..6d5e3e4 --- /dev/null +++ b/STATUS.txt @@ -0,0 +1,227 @@ +There are 112 Goods, 9 OKs and 102 NGs of total 223 screen savers +in XScreenSaver. + +(Name) (Status) (Comment) +Abstractile Good +Anemone Good +Anemotaxis Good +Ant OK Sometimes dirty +AntInspect Good +AntMaze Good +AntSpotlight Good +Apollonian Good +Apple2 NG +Atlantis Good +Attraction NG +Atunnel Good +BSOD NG +Barcode NG Bitmap broken +Blaster NG Stars not appears +BlinkBox Good +BlitSpin NG +BlockTube Good +Boing Good +Bouboule OK Colors bad +BouncingCow Good +BoxFit NG +Boxed Good +Braid NG Hung up +Bubble3D NG +Bubbles NG +Bumps NG +CCurve Good +CWaves NG +Cage Good +Carousel NG +Celtic Good +Circuit NG +CloudLife Good +CompanionCube Good +Compass Good +Coral Good +Crackberg Good +Critical Good +Crystal Good +Cube21 Good +CubeStorm Good +Cubenetic Good +CubicGrid Good +Cynosure NG Colors bad +DNALogo Good +DangerBall Good +DecayScreen NG +Deco NG Colors bad +Deluxe NG +Demon Good +Discrete NG Colors bad +Distort NG +Drift NG Colors bad +Endgame Good +Engine NG +Epicycle Good +Eruption Good +Euler2D OK Colors bad +Extrusion Good +FadePlot Good +Fiberlamp NG +Fireworkx NG +Flag NG +Flame NG Colors bad +FlipFlop Good +FlipScreen3D OK Blur +FlipText NG +Flow NG +FluidBalls NG +Flurry Good +FlyingToasters Good +FontGlide NG +Forest Good +FuzzyFlakes Good +GFlux Good +GLBlur OK Slow +GLCells Good +GLForestFire Good +GLHanoi Good +GLKnots Good +GLMatrix Good +GLPlanet Good +GLSchool Good +GLSlideshow NG +GLSnake NG +GLText NG +Galaxy OK Flickers +Gears Good +Gleidescope OK Slow +Goop NG +Grav Good +Greynetic NG Hung up +Halftone Good +Halo NG +Helix Good +Hexadrop Good +Hilbert Good +Hopalong NG Colors bad +HyperBall Good +HyperCube Good +Hypertorus Good +Hypnowheel Good +IFS NG +IMSMap OK Slow +Interaggregate NG Hung up +Interference Good +Intermomentary NG Black out +JigglyPuff Good +Jigsaw NG +Juggle NG +Juggler3D NG +Julia Good +Kaleidescope NG +Kaleidocycle Good +Klein Good +Kumppa NG +LCDscrub NG +LMorph Good +Lament Good +Laser Good +Lavalite NG Camera position bad +Lightning Good +Lisa Good +Lissie NG Colors bad +Lockward Good +Loop Good +Maze NG +MemScroller NG +Menger Good +MetaBalls Good +MirrorBlob OK Blur and slow +Moebius Good +MoebiusGears Good +Moire NG +Moire2 NG +Molecule NG +Morph3D Good +Mountain NG +Munch Good +NerveRot Good +Noof Good +NoseGuy NG +Pacman NG +Pedal NG +Penetrate NG +Penrose Good +Petri Good +Phosphor NG +Photopile NG +Piecewise NG Colors bad +Pinion NG +Pipes Good +Polyhedra NG +Polyominoes NG +Polytopes Good +Pong NG +PopSquares NG +Providence Good +Pulsar Good +Pyro NG +Qix NG +QuasiCrystal NG +Queens Good +RDbomb NG +Ripples NG +Rocks NG +Rorschach Good +RotZoomer NG +Rotor NG Colors bad +Rubik Good +RubikBlocks Good +SBalls Good +ShadeBobs Good +Sierpinski Good +Sierpinski3D Good +SkyTentacles Good +SlideScreen NG +Slip NG +Sonar NG +SpeedMine NG +Sphere Good +Spheremonics NG +Spiral NG Colors bad +Spotlight NG +Sproingies Good +Squiral Good +Stairs Good +StarWars NG +Starfish NG +StonerView Good +Strange NG +Substrate NG Hung up +Superquadrics Good +Surfaces Good +Swirl NG Colors bad +T3D NG +Tangram NG +Thornbird Good +TimeTunnel NG +TopBlock Good +Triangle NG Colors bad +TronBit Good +Truchet Good +Twang NG +UnknownPleasures Good +Vermiculate NG +Vines Good +Voronoi Good +Wander Good +WhirlWindWarp Good +Whirlygig Good +Worm NG +Wormhole NG +XAnalogTV NG +XFlame NG +XJack NG +XLyap NG +XMatrix NG +XRaySwarm NG +XSpirograph Good +Zoom NG +m6502 NG diff --git a/clean.bat b/clean.bat new file mode 100644 index 0000000..f3d9959 --- /dev/null +++ b/clean.bat @@ -0,0 +1,6 @@ +cd wgl +call clean.bat +cd .. +cd non-wgl +call clean.bat +cd .. diff --git a/colors.c b/colors.c index 91bc2ad..5434077 100644 --- a/colors.c +++ b/colors.c @@ -13,7 +13,7 @@ to hack the screen with. */ -#include "xws2win.h" +#include "xlockmore.h" //#include "utils.h" #include "hsv.h" diff --git a/del_git.sh b/del_git.sh new file mode 100644 index 0000000..d794236 --- /dev/null +++ b/del_git.sh @@ -0,0 +1 @@ +rm -R .git diff --git a/gle-3.1.0/ReadMe.txt b/gle-3.1.0/ReadMe.txt new file mode 100644 index 0000000..434e67d --- /dev/null +++ b/gle-3.1.0/ReadMe.txt @@ -0,0 +1,6 @@ +This folder contains the GLE library that the Extrusion screen saver needs. +Binary are compiled by VC++; using the run-time libraries "Debug Multithreaded" +and "Multithreaded" (non-DLL). + +Copy the include and lib folders to the compiling environment before compiling +Extrusion. diff --git a/gle-3.1.0/include/GL/gle.h b/gle-3.1.0/include/GL/gle.h new file mode 100644 index 0000000..1c9eebc --- /dev/null +++ b/gle-3.1.0/include/GL/gle.h @@ -0,0 +1,304 @@ + +/* + * FILE: + * gle.h + * + * FUNCTION: + * GLE Tubing and Extrusion top-level API header file. + * This file provides the protypes and defines for the extrusion + * and tubing public API. Applications that wish to use GLE must + * include this header file. + * + * HISTORY: + * Copyright (c) 1990, 1991, 2003 Linas Vepstas + */ + + +#ifndef GLE_H__ +#define GLE_H__ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* some types */ +#define __GLE_DOUBLE 1 +#if __GLE_DOUBLE +typedef double gleDouble; +#else +typedef float gleDouble; +#endif + +typedef gleDouble gleAffine[2][3]; +typedef float gleColor[3]; +typedef float gleColor4f[4]; + +/* ====================================================== */ + +/* Defines for tubing join styles */ +#define TUBE_JN_RAW 0x1 +#define TUBE_JN_ANGLE 0x2 +#define TUBE_JN_CUT 0x3 +#define TUBE_JN_ROUND 0x4 +#define TUBE_JN_MASK 0xf /* mask bits */ +#define TUBE_JN_CAP 0x10 + +/* Determine how normal vectors are to be handled */ +#define TUBE_NORM_FACET 0x100 +#define TUBE_NORM_EDGE 0x200 +#define TUBE_NORM_PATH_EDGE 0x400 /* for spiral, lathe, helix primitives */ +#define TUBE_NORM_MASK 0xf00 /* mask bits */ + +/* Closed or open countours */ +#define TUBE_CONTOUR_CLOSED 0x1000 + +#define GLE_TEXTURE_ENABLE 0x10000 +#define GLE_TEXTURE_STYLE_MASK 0xff +#define GLE_TEXTURE_VERTEX_FLAT 1 +#define GLE_TEXTURE_NORMAL_FLAT 2 +#define GLE_TEXTURE_VERTEX_CYL 3 +#define GLE_TEXTURE_NORMAL_CYL 4 +#define GLE_TEXTURE_VERTEX_SPH 5 +#define GLE_TEXTURE_NORMAL_SPH 6 +#define GLE_TEXTURE_VERTEX_MODEL_FLAT 7 +#define GLE_TEXTURE_NORMAL_MODEL_FLAT 8 +#define GLE_TEXTURE_VERTEX_MODEL_CYL 9 +#define GLE_TEXTURE_NORMAL_MODEL_CYL 10 +#define GLE_TEXTURE_VERTEX_MODEL_SPH 11 +#define GLE_TEXTURE_NORMAL_MODEL_SPH 12 + +#ifdef GL_32 +/* HACK for GL 3.2 -- needed because no way to tell if lighting is on. */ +#define TUBE_LIGHTING_ON 0x80000000 + +#define gleExtrusion extrusion +#define gleSetJoinStyle setjoinstyle +#define gleGetJoinStyle getjoinstyle +#define glePolyCone polycone +#define glePolyCylinder polycylinder +#define gleSuperExtrusion super_extrusion +#define gleTwistExtrusion twist_extrusion +#define gleSpiral spiral +#define gleLathe lathe +#define gleHelicoid helicoid +#define gleToroid toroid +#define gleScrew screw + +#endif /* GL_32 */ + +#ifdef _NO_PROTO /* NO ANSI C PROTOTYPING */ + +extern int gleGetJoinStyle (); +extern void gleSetJoinStyle (); +extern void glePolyCone (); +extern void glePolyCylinder (); +extern void gleExtrusion (); +extern void gleSuperExtrusion (); +extern void gleTwistExtrusion (); +extern void gleSpiral (); +extern void gleLathe (); +extern void gleHelicoid (); +extern void gleToroid (); +extern void gleScrew (); + +/* Rotation Utilities */ +extern void rot_axis (); +extern void rot_about_axis (); +extern void rot_omega (); +extern void urot_axis (); +extern void urot_about_axis (); +extern void urot_omega (); + +/* viewpoint functions */ +extern void uview_direction (); +extern void uviewpoint (); + +#else /* _NO_PROTO */ /* ANSI C PROTOTYPING */ + +/* clean up global memory usage */ +extern void gleDestroyGC (void); + +/* control join style of the tubes */ +extern int gleGetJoinStyle (void); +extern void gleSetJoinStyle (int style); /* bitwise OR of flags */ + +/* control number of sides used to draw cylinders, cones */ +extern int gleGetNumSides(void); +extern void gleSetNumSides(int slices); + +/* draw polyclinder, specified as a polyline */ +extern void +glePolyCylinder (int npoints, /* num points in polyline */ + gleDouble point_array[][3], /* polyline vertces */ + gleColor color_array[], /* colors at polyline verts */ + gleDouble radius); /* radius of polycylinder */ + +extern void +glePolyCylinder_c4f (int npoints, /* num points in polyline */ + gleDouble point_array[][3], /* polyline vertces */ + gleColor4f color_array[], /* colors at polyline verts */ + gleDouble radius); /* radius of polycylinder */ + +/* draw polycone, specified as a polyline with radii */ +extern void +glePolyCone (int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor color_array[], /* colors at polyline verts */ + gleDouble radius_array[]); /* cone radii at polyline verts */ + +extern void +glePolyCone_c4f (int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor4f color_array[], /* colors at polyline verts */ + gleDouble radius_array[]); /* cone radii at polyline verts */ + +/* extrude arbitrary 2D contour along arbitrary 3D path */ +extern void +gleExtrusion (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor color_array[]); /* colors at polyline verts */ + +extern void +gleExtrusion_c4f (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor4f color_array[]); /* colors at polyline verts */ + +/* extrude 2D contour, specifying local rotations (twists) */ +extern void +gleTwistExtrusion (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor color_array[], /* color at polyline verts */ + gleDouble twist_array[]); /* countour twists (in degrees) */ + +extern void +gleTwistExtrusion_c4f (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor4f color_array[], /* color at polyline verts */ + gleDouble twist_array[]); /* countour twists (in degrees) */ + +/* extrude 2D contour, specifying local affine tranformations */ +extern void +gleSuperExtrusion (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor color_array[], /* color at polyline verts */ + gleDouble xform_array[][2][3]); /* 2D contour xforms */ + +extern void +gleSuperExtrusion_c4f (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + int npoints, /* numpoints in poly-line */ + gleDouble point_array[][3], /* polyline vertices */ + gleColor4f color_array[], /* color at polyline verts */ + gleDouble xform_array[][2][3]); /* 2D contour xforms */ + +/* spiral moves contour along helical path by parallel transport */ +extern void gleSpiral (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + gleDouble startRadius, /* spiral starts in x-y plane */ + gleDouble drdTheta, /* change in radius per revolution */ + gleDouble startZ, /* starting z value */ + gleDouble dzdTheta, /* change in Z per revolution */ + gleDouble startXform[2][3], /* starting contour affine xform */ + gleDouble dXformdTheta[2][3], /* tangent change xform per revoln */ + gleDouble startTheta, /* start angle in x-y plane */ + gleDouble sweepTheta); /* degrees to spiral around */ + +/* lathe moves contour along helical path by helically shearing 3D space */ +extern void gleLathe (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + gleDouble startRadius, /* spiral starts in x-y plane */ + gleDouble drdTheta, /* change in radius per revolution */ + gleDouble startZ, /* starting z value */ + gleDouble dzdTheta, /* change in Z per revolution */ + gleDouble startXform[2][3], /* starting contour affine xform */ + gleDouble dXformdTheta[2][3], /* tangent change xform per revoln */ + gleDouble startTheta, /* start angle in x-y plane */ + gleDouble sweepTheta); /* degrees to spiral around */ + +/* similar to spiral, except contour is a circle */ +extern void gleHelicoid (gleDouble rToroid, /* circle contour (torus) radius */ + gleDouble startRadius, /* spiral starts in x-y plane */ + gleDouble drdTheta, /* change in radius per revolution */ + gleDouble startZ, /* starting z value */ + gleDouble dzdTheta, /* change in Z per revolution */ + gleDouble startXform[2][3], /* starting contour affine xform */ + gleDouble dXformdTheta[2][3], /* tangent change xform per revoln */ + gleDouble startTheta, /* start angle in x-y plane */ + gleDouble sweepTheta); /* degrees to spiral around */ + +/* similar to lathe, except contour is a circle */ +extern void gleToroid (gleDouble rToroid, /* circle contour (torus) radius */ + gleDouble startRadius, /* spiral starts in x-y plane */ + gleDouble drdTheta, /* change in radius per revolution */ + gleDouble startZ, /* starting z value */ + gleDouble dzdTheta, /* change in Z per revolution */ + gleDouble startXform[2][3], /* starting contour affine xform */ + gleDouble dXformdTheta[2][3], /* tangent change xform per revoln */ + gleDouble startTheta, /* start angle in x-y plane */ + gleDouble sweepTheta); /* degrees to spiral around */ + +/* draws a screw shape */ +extern void gleScrew (int ncp, /* number of contour points */ + gleDouble contour[][2], /* 2D contour */ + gleDouble cont_normal[][2], /* 2D contour normals */ + gleDouble up[3], /* up vector for contour */ + gleDouble startz, /* start of segment */ + gleDouble endz, /* end of segment */ + gleDouble twist); /* number of rotations */ + +extern void gleTextureMode (int mode); + +/* Rotation Utilities */ +extern void rot_axis (gleDouble omega, gleDouble axis[3]); +extern void rot_about_axis (gleDouble angle, gleDouble axis[3]); +extern void rot_omega (gleDouble axis[3]); +extern void rot_prince (gleDouble omega, char axis); +extern void urot_axis (gleDouble m[4][4], gleDouble omega, gleDouble axis[3]); +extern void urot_about_axis (gleDouble m[4][4], gleDouble angle, gleDouble axis[3]); +extern void urot_omega (gleDouble m[4][4], gleDouble axis[3]); +extern void urot_prince (gleDouble m[4][4], gleDouble omega, char axis); + +/* viewpoint functions */ +extern void uview_direction (gleDouble m[4][4], /* returned */ + gleDouble v21[3], /* input */ + gleDouble up[3]); /* input */ + +extern void uviewpoint (gleDouble m[4][4], /* returned */ + gleDouble v1[3], /* input */ + gleDouble v2[3], /* input */ + gleDouble up[3]); /* input */ + +#endif /* _NO_PROTO */ + +#if defined(__cplusplus) || defined(c_plusplus) +}; +#endif + +#endif /* GLE_H__ */ +/* ================== END OF FILE ======================= */ diff --git a/gle-3.1.0/lib/gle.lib b/gle-3.1.0/lib/gle.lib new file mode 100644 index 0000000000000000000000000000000000000000..0d51ccd122af21ab2b57edb6353336619ccdfbb3 GIT binary patch literal 90908 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 AtpET3 literal 0 HcmV?d00001 diff --git a/gle-3.1.0/lib/gled.lib b/gle-3.1.0/lib/gled.lib new file mode 100644 index 0000000000000000000000000000000000000000..efcbab5f385f63c3db063777010471cbd8612e54 GIT binary patch literal 458572 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

rpLzOd6em~v3UN)^w?ND<4+{{v9WlrVtQ;W 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 +#include +//#include +/*#include */ + +int sleep = 3; +int speed = 3; +char *tile_type = "random"; +char *background = "black"; +char *foreground = "white"; + +static argtype vars[] = +{ + {&sleep, "sleep", NULL, "3", t_Int}, + {&speed, "speed", NULL, "3", t_Int}, + {&tile_type, "tile", NULL, "random", t_String}, + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, +}; + +#define DEBUGFILE "/tmp/abstractile.dbg" + +#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 */ + unsigned int gridx, gridy, gridn; /* grid size */ + 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; + 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]; + + 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; + st->dline[st->li].color = (lt==LINE_NEW) ? + (_getcolor(st,x,y))%st->ncolors : 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"); + char *tile = tile_type; + 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"); + st->speed = speed; + if (st->speed < 0) st->speed = 0; + if (st->speed > 5) st->speed = 5; + //st->sleep = get_integer_resource(display, "sleep", "Integer"); + st->sleep = sleep; + 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"); + gcv.foreground = load_color(display, st->xgwa.colormap, background); + st->fgc = XCreateGC (display, window, GCForeground, &gcv); + //gcv.foreground = get_pixel_resource(display, st->xgwa.colormap, + // "background", "Background"); + gcv.foreground = load_color(display, st->xgwa.colormap, foreground); + 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; +} + +#if 0 + static Bool + abstractile_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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", + 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/non-wgl/abstractile.vcproj b/non-wgl/abstractile.vcproj new file mode 100644 index 0000000..922985f --- /dev/null +++ b/non-wgl/abstractile.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/anemone.c b/non-wgl/anemone.c new file mode 100644 index 0000000..b992902 --- /dev/null +++ b/non-wgl/anemone.c @@ -0,0 +1,479 @@ +/* anemon, 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 */ + + +char *background = "black"; +int arms = 128; +int width = 2; +int finpoints = 64; +int delay = 40000; +int withdraw = 1200; +float turnspeed = 50.0; +int colors = 20; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&arms, "arms", NULL, "128", t_Int}, + {&width, "width", NULL, "2", t_Int}, + {&finpoints, "finpoints", NULL, "64", t_Int}, + {&delay, "delay", NULL, "40000", t_Int}, + {&withdraw, "withdraw", NULL, "1200", t_Int}, + {&turnspeed, "turnspeed", NULL, "50.0", t_Float}, + {&colors, "colors", NULL, "20", t_Int}, +}; + +/*-----------------------------------------------------------------------+ + | 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.; + +#if 1 + st->width = width; + st->arms = arms; + st->finpoints = finpoints; + st->delay = delay; + st->withdraw = withdraw; + st->turndelta = turnspeed; +#else + 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; +#endif + + st->dbuf = TRUE; + +# ifdef HAVE_COCOA /* 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 = 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->gcv.foreground = load_color(st->dpy, st->cmap, 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 +} + +#if 0 + static Bool + anemone_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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 */ + 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/non-wgl/anemone.vcproj b/non-wgl/anemone.vcproj new file mode 100644 index 0000000..2663b7c --- /dev/null +++ b/non-wgl/anemone.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/anemotaxis.c b/non-wgl/anemotaxis.c new file mode 100644 index 0000000..23bee4e --- /dev/null +++ b/non-wgl/anemotaxis.c @@ -0,0 +1,777 @@ +/* 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 + +char *background = "black"; +int distance = 40; +int sources = 25; +int searchers = 25; +int delay = 20000; +int colors = 20; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&distance, "distance", NULL, "40", t_Int}, + {&sources, "sources", NULL, "25", t_Int}, + {&searchers, "searchers", NULL, "25", t_Int}, + {&delay, "delay", NULL, "20000", t_Int}, + {&colors, "colors", NULL, "20", t_Int}, +}; + +/*-----------------------------------------------------------------------+ + | 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 = 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"); + st->delay = delay; + st->max_dist = distance; + + 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"); + st->max_src = sources; + + if(st->max_src <= 0) + st->max_src = 1; + + //st->max_searcher = get_integer_resource(st->dpy, "searchers", "Integer"); + st->max_searcher = searchers; + + if(st->max_searcher < 0) + st->max_searcher = 0; + + st->dbuf = True; + +# ifdef HAVE_COCOA /* 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->gcv.foreground = load_color(st->dpy, st->cmap, 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++) { + + 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 - 2, y - 2, 4, 4, 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) +{ +} + +#if 0 + static Bool + anemotaxis_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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/non-wgl/anemotaxis.vcproj b/non-wgl/anemotaxis.vcproj new file mode 100644 index 0000000..23f0144 --- /dev/null +++ b/non-wgl/anemotaxis.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/ant.c b/non-wgl/ant.c index b8a0ba5..6b5afe1 100644 --- a/non-wgl/ant.c +++ b/non-wgl/ant.c @@ -82,7 +82,7 @@ static const char sccsid[] = "@(#)ant.c 5.00 2000/11/01 xlockmore"; #endif /* STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "erase.h" #include "automata.h" diff --git a/non-wgl/ant.vcproj b/non-wgl/ant.vcproj index 8644d0e..79e4f2e 100644 --- a/non-wgl/ant.vcproj +++ b/non-wgl/ant.vcproj @@ -199,7 +199,7 @@ > + + + + @@ -240,6 +248,10 @@ RelativePath="..\resource.h" > + + @@ -255,7 +267,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/non-wgl/apollonian.c b/non-wgl/apollonian.c index 2f371c3..916e69d 100644 --- a/non-wgl/apollonian.c +++ b/non-wgl/apollonian.c @@ -87,7 +87,7 @@ static const char sccsid[] = "@(#)apollonian.c 5.02 2001/07/01 xlockmore"; #endif /* STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" # include "erase.h" char *background = "black"; diff --git a/non-wgl/apollonian.vcproj b/non-wgl/apollonian.vcproj index af8b4f6..895bcbe 100644 --- a/non-wgl/apollonian.vcproj +++ b/non-wgl/apollonian.vcproj @@ -199,11 +199,15 @@ > + + + + @@ -247,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/non-wgl/attraction.c b/non-wgl/attraction.c new file mode 100644 index 0000000..7307ebb --- /dev/null +++ b/non-wgl/attraction.c @@ -0,0 +1,1175 @@ +/* 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 +#undef min +#define min(a,b) ((a)<(b)?(a):(b)) +#undef max +#define max(a,b) ((a)>(b)?(a):(b)) + +char *background = "black"; +char *foreground = "white"; +char *mode = "balls"; +char *graphmode = "none"; +int points = 0; +int size = 0; +int colors = 200; +int threshold = 200; +int delay = 10000; +Bool glow = False; +Bool walls = True; +Bool maxspeed = True; +Bool cbounce = True; +float viscosity = 1.0; +Bool orbit = False; +int colorShift = 3; +int segments = 500; +float vMult = 0.9; +int radius = 0; +int vx_ = 0; +int vy_ = 0; +char *mouseForeground = "white"; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&mode, "mode", NULL, "balls", t_String}, + {&graphmode, "graphmode", NULL, "none", t_String}, + {&points, "points", NULL, "0", t_Int}, + {&size, "size", NULL, "0", t_Int}, + {&colors, "colors", NULL, "200", t_Int}, + {&threshold, "threshold", NULL, "200", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&glow, "glow", NULL, "False", t_Bool}, + {&walls, "walls", NULL, "True", t_Bool}, + {&maxspeed, "maxspeed", NULL, "True", t_Bool}, + {&cbounce, "cbounce", NULL, "True", t_Bool}, + {&viscosity, "viscosity", NULL, "1.0", t_Float}, + {&orbit, "orbit", NULL, "False", t_Bool}, + {&colorShift, "colorShift", NULL, "3", t_Int}, + {&segments, "segments", NULL, "500", t_Int}, + {&vMult, "vMult", NULL, "0.9", t_Float}, + {&radius, "radius", NULL, "0", t_Int}, + {&vx_, "vx", NULL, "0", t_Int}, + {&vy_, "vy", NULL, "0", t_Int}, + {&mouseForeground, "mouseForeground", NULL, "white", t_String}, +}; + +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; + + 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"); + st->walls_p = walls; + + /* if there aren't walls, don't set a limit on the radius */ + //r = get_integer_resource (dpy, "radius", "Integer"); + r = radius; + 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"); + vx = vx_; + vy = vy_; + + //st->npoints = get_integer_resource (dpy, "points", "Integer"); + st->npoints = points; + 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"); + st->segments = segments; + if (st->segments < 0) st->segments = 1; + + //st->threshold = get_integer_resource (dpy, "threshold", "Integer"); + st->threshold = threshold; + if (st->threshold < 0) st->threshold = 0; + + //st->delay = get_integer_resource (dpy, "delay", "Integer"); + st->delay = delay; + if (st->delay < 0) st->delay = 0; + + //st->global_size = get_integer_resource (dpy, "size", "Integer"); + st->global_size = size; + if (st->global_size < 0) st->global_size = 0; + + //st->glow_p = get_boolean_resource (dpy, "glow", "Boolean"); + st->glow_p = glow; + + //st->orbit_p = get_boolean_resource (dpy, "orbit", "Boolean"); + st->orbit_p = orbit; + + //st->maxspeed_p = get_boolean_resource (dpy, "maxspeed", "Boolean"); + st->maxspeed_p = maxspeed; + + //st->cbounce_p = get_boolean_resource (dpy, "cbounce", "Boolean"); + st->cbounce_p = cbounce; + + //st->color_shift = get_integer_resource (dpy, "colorShift", "Integer"); + st->color_shift = colorShift; + if (st->color_shift <= 0) st->color_shift = 5; + + //st->viscosity = get_float_resource (dpy, "viscosity", "Float"); + st->viscosity = viscosity; + + //mode_str = get_string_resource (dpy, "mode", "Mode"); + mode_str = 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"); + graph_mode_str = graphmode; + 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"); + st->ncolors = 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_pixel = load_color(dpy, cmap, 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"); + gcv.foreground = load_color(dpy, cmap, 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"); + gcv.foreground = load_color(dpy, cmap, background); + st->erase_gc = XCreateGC (dpy, window, GCForeground|GCLineWidth|GCCapStyle,&gcv); + + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (dpy, st->draw_gc, False); + jwxyz_XSetAntiAliasing (dpy, st->erase_gc, False); +#endif + + /* let's make the balls bigger by default */ +#define rand_size() (3 * (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"); + double v_mult = vMult; + 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; +} + +#if 0 + 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; + } +#endif + +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 USE_IPHONE + "*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/non-wgl/attraction.vcproj b/non-wgl/attraction.vcproj new file mode 100644 index 0000000..339fc0d --- /dev/null +++ b/non-wgl/attraction.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/barcode.c b/non-wgl/barcode.c new file mode 100644 index 0000000..c341b54 --- /dev/null +++ b/non-wgl/barcode.c @@ -0,0 +1,2005 @@ +/* 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 "screenhack.h" +#include + +/* 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) + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +char *mode = "scroll"; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&mode, "mode", NULL, "scroll", t_String}, +}; + + +/* 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.background = load_color(st->dpy, xgwa.colormap, background); + //gcv.foreground = get_pixel_resource (st->dpy, xgwa.colormap, + // "foreground", "Foreground"); + gcv.foreground = load_color(st->dpy, xgwa.colormap, 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; + 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; +} + +#if 0 + 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; + } +#endif + +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", + "*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"); + st->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"); + s = _strdup(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/non-wgl/barcode.vcproj b/non-wgl/barcode.vcproj new file mode 100644 index 0000000..2c878a8 --- /dev/null +++ b/non-wgl/barcode.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/blaster.c b/non-wgl/blaster.c new file mode 100644 index 0000000..de75ce9 --- /dev/null +++ b/non-wgl/blaster.c @@ -0,0 +1,1289 @@ +/* -*- 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 "screenhack.h" +#include +#include +#include + +char *r_color0 = "#FF00FF"; +char *r_color1 = "#FFA500"; +char *r_color2 = "#FFFF00"; +char *r_color3 = "#FFFFFF"; +char *r_color4 = "#0000FF"; +char *r_color5 = "#00FFFF"; +char *l_color0 = "#00FF00"; +char *l_color1 = "#FF0000"; +char *mother_ship_color0 = "#00008B"; +char *mother_ship_color1 = "#FFFFFF"; +char *explode_color_1 = "#FFFF00"; +char *explode_color_2 = "#FFA500"; + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +int num_robots = 5; +int num_lasers = 3; +Bool mother_ship = False; +int mother_ship_width = 25; +int mother_ship_height = 7; +int mother_ship_laser = 15; +int mother_ship_period = 150; +int mother_ship_hits = 10; +int explode_size_1 = 27; +int explode_size_2 = 19; +int explode_size_3 = 7; +int num_stars = 50; +char *star_color = "white"; +Bool move_stars = True; +int move_stars_x = 2; +int move_stars_y = 1; +int move_stars_random = 0; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&num_robots, "num_robots", NULL, "5", t_Int}, + {&num_lasers, "num_lasers", NULL, "3", t_Int}, + {&mother_ship, "mother_ship", NULL, "False", t_Bool}, + {&mother_ship_width, "mother_ship_width", NULL, "25", t_Int}, + {&mother_ship_height, "mother_ship_height", NULL, "7", t_Int}, + {&mother_ship_laser, "mother_ship_laser", NULL, "15", t_Int}, + {&mother_ship_period, "mother_ship_period", NULL, "150", t_Int}, + {&mother_ship_hits, "mother_ship_hits", NULL, "10", t_Int}, + {&explode_size_1, "explode_size_1", NULL, "27", t_Int}, + {&explode_size_2, "explode_size_2", NULL, "19", t_Int}, + {&explode_size_3, "explode_size_3", NULL, "7", t_Int}, + {&num_stars, "num_stars", NULL, "50", t_Int}, + {&star_color, "star_color", NULL, "white", t_String}, + {&move_stars, "move_stars", NULL, "True", t_Bool}, + {&move_stars_x, "move_stars_x", NULL, "2", t_Int}, + {&move_stars_y, "move_stars_y", NULL, "1", t_Int}, + {&move_stars_random, "move_stars_random", NULL, "0", t_Int}, +}; + +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_COCOA /* 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"); + st->delay = delay; + if(st->delay==0) { + st->delay=10000; + } + //st->NUM_ROBOTS = get_integer_resource(st->dpy, "num_robots","Integer"); + st->NUM_ROBOTS = num_robots; + if(st->NUM_ROBOTS==0) { + st->NUM_ROBOTS=5; + } + //st->NUM_LASERS = get_integer_resource(st->dpy, "num_lasers","Integer"); + st->NUM_LASERS = num_lasers; + //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->EXPLODE_SIZE_1 = explode_size_1; + st->EXPLODE_SIZE_2 = explode_size_2; + st->EXPLODE_SIZE_3 = explode_size_3; + + //st->NUM_STARS = get_integer_resource(st->dpy, "num_stars","Integer"); + st->NUM_STARS = num_stars; + + //if(get_boolean_resource(st->dpy, "move_stars","Boolean")) + if(move_stars) + { + 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"); + st->MOVE_STARS_X = move_stars_x; + st->MOVE_STARS_Y = move_stars_y; + st->MOVE_STARS_RANDOM = move_stars_random; + } + else { + st->MOVE_STARS = 0; + } + + + //bg = get_pixel_resource(st->dpy, cmap, "background","Background"); + bg = load_color(st->dpy, cmap, 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); + +#define make_gc_(color,name) \ + gcv.foreground = load_color(st->dpy, cmap, name); \ + 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"); + gcv.foreground = load_color(st->dpy, cmap, 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")) + if(mother_ship) + { +#if 1 + st->MOTHER_SHIP_WIDTH=mother_ship_width; + st->MOTHER_SHIP_HEIGHT=mother_ship_height; + st->MOTHER_SHIP_LASER=mother_ship_laser; + st->MOTHER_SHIP_PERIOD=mother_ship_period; + st->MOTHER_SHIP_HITS=mother_ship_hits; +#else + 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"); +#endif + 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")) + if(mother_ship) + { +#if 1 + st->MOTHER_SHIP_WIDTH=mother_ship_width; + st->MOTHER_SHIP_HEIGHT=mother_ship_height; + st->MOTHER_SHIP_LASER=mother_ship_laser; + st->MOTHER_SHIP_PERIOD=mother_ship_period; + st->MOTHER_SHIP_HITS=mother_ship_hits; +#else + 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"); +#endif + 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_COCOA /* 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); +} + +#if 0 + static Bool + blaster_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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 [] = { + ".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 USE_IPHONE + "*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/non-wgl/blaster.vcproj b/non-wgl/blaster.vcproj new file mode 100644 index 0000000..e69df3f --- /dev/null +++ b/non-wgl/blaster.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/bouboule.c b/non-wgl/bouboule.c index b8a6777..1ea893c 100644 --- a/non-wgl/bouboule.c +++ b/non-wgl/bouboule.c @@ -103,7 +103,7 @@ static const char sccsid[] = "@(#)bouboule.c 4.00 97/01/01 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" ENTRYPOINT ModeSpecOpt bouboule_opts = { 0, NULL, 0, NULL, NULL }; diff --git a/non-wgl/bouboule.vcproj b/non-wgl/bouboule.vcproj index 4ac2303..f172888 100644 --- a/non-wgl/bouboule.vcproj +++ b/non-wgl/bouboule.vcproj @@ -195,11 +195,15 @@ > + + + + @@ -239,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/non-wgl/braid.c b/non-wgl/braid.c index 0c79d9e..de6d721 100644 --- a/non-wgl/braid.c +++ b/non-wgl/braid.c @@ -38,6 +38,7 @@ static const char sccsid[] = "@(#)braid.c 5.00 2000/11/01 xlockmore"; #define CYCLES 100 #define SIZE_ -7 #define NCOLORS 64 +#define COLORROUND # define DEFAULTS "*delay: 1000 \n" \ "*count: 15 \n" \ "*cycles: 100 \n" \ @@ -58,7 +59,7 @@ static const char sccsid[] = "@(#)braid.c 5.00 2000/11/01 xlockmore"; #endif /* STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" # include "erase.h" char *background = "black"; diff --git a/non-wgl/braid.vcproj b/non-wgl/braid.vcproj index 31d1019..ecf2813 100644 --- a/non-wgl/braid.vcproj +++ b/non-wgl/braid.vcproj @@ -199,11 +199,15 @@ > + + + + @@ -247,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/non-wgl/bumps.c b/non-wgl/bumps.c new file mode 100644 index 0000000..b4d4ff4 --- /dev/null +++ b/non-wgl/bumps.c @@ -0,0 +1,761 @@ +/* -*- 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/99] - Shane Smit: Creation + * [10/08/99] - Shane Smit: Port to C. (Ick) + * [03/08/02] - Shane Smit: New movement code. + * [09/12/02] - Shane Smit: MIT-SHM XImages. + * Thanks to Kennett Galbraith + * for code optimization. + */ + + +#include "screenhack.h" +#include +//#include + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; + +#ifdef HAVE_XSHM_EXTENSION +#include "xshm.h" +#endif /* HAVE_XSHM_EXTENSION */ + + +/* Defines: */ +/* #define VERBOSE */ +#define RANDOM() ((int) (random() & 0X7FFFFFFFL)) + +//typedef unsigned char BOOL; + + +/* Globals: */ + +char *background = "black"; +char *foreground = "white"; +char *color = "random"; +int colorcount = 64; +int delay = 30000; +int duration = 120; +int soften = 1; +Bool invert = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&color, "color", NULL, "random", t_String}, + {&colorcount, "colorcount", NULL, "64", t_Int}, + {&delay, "delay", NULL, "30000", t_Int}, + {&duration, "duration", NULL, "120", t_Int}, + {&soften, "soften", NULL, "1", t_Int}, + {&invert, "invert", NULL, "False", t_Bool}, +}; + +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 USE_IPHONE + "*ignoreRotation: 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; +#ifdef HAVE_XSHM_EXTENSION + XShmSegmentInfo XShmInfo; + Bool bUseShm; +#endif /* HAVE_XSHM_EXTENSION */ + + 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; + pBumps->pXImage = NULL; + + 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; + +#ifdef HAVE_XSHM_EXTENSION + pBumps->bUseShm = get_boolean_resource(dpy, "useSHM", "Boolean" ); + + if( pBumps->bUseShm ) + { + pBumps->pXImage = create_xshm_image( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth, + ZPixmap, NULL, &pBumps->XShmInfo, iDiameter, iDiameter ); + if( !pBumps->pXImage ) + { + fprintf( stderr, "%s: Unable to create XShmImage.\n", progname ); + pBumps->bUseShm = False; + } + } +#endif /* HAVE_XSHM_EXTENSION */ + if( !pBumps->pXImage ) + { + pBumps->pXImage = XCreateImage( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth, + ZPixmap, 0, NULL, iDiameter, iDiameter, BitmapPad( pBumps->dpy ), 0 ); + pBumps->pXImage->data = malloc( pBumps->pXImage->bytes_per_line * pBumps->pXImage->height * sizeof(int8_t) ); + } + + /* 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 ); +#ifdef HAVE_XSHM_EXTENSION + if( pBumps->bUseShm ) + destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo ); + else +#endif /* HAVE_XSHM_EXTENSION */ + XDestroyImage( pBumps->pXImage ); + 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" ); + sColor = 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" ); + pBumps->nColorCount = colorcount; + 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" ); + BOOL bInvert = invert; + 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" ); + nSoften = soften; + 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" ); + nSoften = soften; +#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; + } + +#ifdef HAVE_XSHM_EXTENSION + if( pBumps->bUseShm ) + XShmPutImage( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos, + nX, nY, False); + else +#endif /* HAVE_XSHM_EXTENSION */ + XPutImage( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos, + nX, nY ); +} + + +static void DestroySpotLight( SSpotLight *pSpotLight ) { free( pSpotLight->aLightMap ); } + +/* Clean up */ +static void DestroyBumps( SBumps *pBumps ) +{ + DestroySpotLight( &pBumps->SpotLight ); + free( pBumps->aColors ); + free( pBumps->aBumpMap ); +#ifdef HAVE_XSHM_EXTENSION + if( pBumps->bUseShm ) + destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo ); + else +#endif /* HAVE_XSHM_EXTENSION */ + XDestroyImage( pBumps->pXImage ); +} + + +/* 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"); + Bumps->delay = delay; + Bumps->duration = duration; + 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) +{ + 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/non-wgl/bumps.vcproj b/non-wgl/bumps.vcproj new file mode 100644 index 0000000..d69489c --- /dev/null +++ b/non-wgl/bumps.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/ccurve.c b/non-wgl/ccurve.c new file mode 100644 index 0000000..e3a0b40 --- /dev/null +++ b/non-wgl/ccurve.c @@ -0,0 +1,881 @@ +/* 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 "screenhack.h" +#include +#include +#include +#include +#include + +#include "colors.h" +#include "erase.h" + +#define SQRT3 (1.73205080756887729353) +#define MAXIMUM_COLOR_COUNT (256) +#define EPSILON (1e-5) + +char *background = "black"; +char *foreground = "white"; +int delay = 3; +float pause = 0.4; +int limit = 200000; + + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "3", t_Int}, + {&pause, "pause", NULL, "0.4", t_Float}, + {&limit, "limit", NULL, "200000", t_Int}, +}; + +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"); + st->delay = delay; + st->delay2 = pause; + st->maximum_lines = limit; + 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); +} + +#if 0 + static Bool + ccurve_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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 USE_IPHONE + "*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/non-wgl/ccurve.vcproj b/non-wgl/ccurve.vcproj new file mode 100644 index 0000000..4a507c5 --- /dev/null +++ b/non-wgl/ccurve.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/celtic.c b/non-wgl/celtic.c new file mode 100644 index 0000000..c935a29 --- /dev/null +++ b/non-wgl/celtic.c @@ -0,0 +1,1164 @@ +/* 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 + */ + +#define NOARGS +#include "screenhack.h" +#include +#include +#include "erase.h" + +#define SQRT_3 1.73205080756887729352 + +char *background = "black"; +char *foreground = "#333333"; +int ncolors = 20; +int delay = 10000; +int delay2 = 5; +Bool showGraph = False; + +char *eraseMode = NULL; +float eraseSeconds = 0; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&ncolors, "ncolors", NULL, "20", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&delay2, "delay2", NULL, "5", t_Int}, + {&showGraph, "showGraph", NULL, "False", t_Bool}, +}; + +/*-----------------------------------------*/ + +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; + double t; + + struct params params; +}; + + + + +static Array array_new(int increment) +{ + Array new; + new=(Array)calloc(1,sizeof(struct array)); + assert(new); + 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; + new = (Node)calloc(1,sizeof(struct node)); + assert(new); + 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; + new = (Edge)calloc(1,sizeof(struct edge)); + assert(new); + 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; + new = (Graph)calloc(1,sizeof(struct graph)); + assert(new); + 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; + new=(Pattern)calloc(1,sizeof(struct pattern)); + assert(new); + 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 USE_IPHONE + "*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->showGraph=showGraph; + + //st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + st->ncolors = ncolors; + + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->colors = (XColor *) calloc (st->ncolors,sizeof(XColor)); + assert(st->colors); + + //if (get_boolean_resource(st->dpy, "mono", "Boolean")) + if (False) + { + MONO: + st->ncolors = 1; + //st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap, + // "foreground", "Foreground"); + st->colors[0].pixel = load_color(st->dpy, st->xgwa.colormap, 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"); + st->colors[0].pixel = load_color(st->dpy, st->xgwa.colormap, foreground); + st->colors[1].pixel = load_color(st->dpy, st->xgwa.colormap, 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"); + st->delay2 = 1000000 * 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->reset = 0; + + pattern_del(st->pattern); + st->pattern = NULL; + graph_del(st->graph); + + /* recolor each time */ + //st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + st->ncolors = ncolors; + 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 st->delay2; + } + + 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.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); +} + +#if 0 + static Bool + celtic_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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/non-wgl/celtic.vcproj b/non-wgl/celtic.vcproj new file mode 100644 index 0000000..3d2a648 --- /dev/null +++ b/non-wgl/celtic.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/clean.bat b/non-wgl/clean.bat new file mode 100644 index 0000000..a0aa884 --- /dev/null +++ b/non-wgl/clean.bat @@ -0,0 +1,30 @@ +if exist *.user del *.user +if exist *.ncb del *.ncb +if exist *.suo del *.suo +if exist *.suo del /A:H *.suo + +if not exist Debug goto skip1 +cd Debug +if exist *.obj del *.obj +if exist *.pdb del *.pdb +if exist *.idb del *.idb +if exist *.ilk del *.ilk +if exist *.mani* del *.mani* +if exist *.res del *.res +if exist BuildLog.htm del BuildLog.htm +if exist mt.dep del mt.dep +cd .. +:skip1 + +if not exist Release goto skip2 +cd Release +if exist *.obj del *.obj +if exist *.pdb del *.pdb +if exist *.idb del *.idb +if exist *.ilk del *.ilk +if exist *.mani* del *.mani* +if exist *.res del *.res +if exist BuildLog.htm del BuildLog.htm +if exist mt.dep del mt.dep +cd .. +:skip2 diff --git a/non-wgl/cloudlife.c b/non-wgl/cloudlife.c new file mode 100644 index 0000000..796aeeb --- /dev/null +++ b/non-wgl/cloudlife.c @@ -0,0 +1,454 @@ +/* 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 + +char *background = "black"; +char *foreground = "blue"; +int cycleDelay = 25000; +int cycleColors = 2; +int ncolors = 64; +int maxAge = 64; +int initialDensity = 30; +int cellSize = 3; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&cycleDelay, "cycleDelay", NULL, "25000", t_Int}, + {&cycleColors, "cycleColors", NULL, "2", t_Int}, + {&ncolors, "ncolors", NULL, "64", t_Int}, + {&maxAge, "maxAge", NULL, "64", t_Int}, + {&initialDensity, "initialDensity", NULL, "30", t_Int}, + {&cellSize, "cellSize", NULL, "3", t_Int}, +}; + +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"); + f->cell_size = cellSize; + f->max_age = maxAge; + + 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 + +#if 0 + 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; +#else + st->cycle_delay = cycleDelay; + st->cycle_colors = cycleColors; + st->ncolors = ncolors; + st->density = (initialDensity % 100 * 256)/100; +#endif + + 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->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, 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->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, 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) +{ +} + +#if 0 + static Bool + cloudlife_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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 USE_IPHONE + "*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/non-wgl/cloudlife.vcproj b/non-wgl/cloudlife.vcproj new file mode 100644 index 0000000..c6ca1b4 --- /dev/null +++ b/non-wgl/cloudlife.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/compass.c b/non-wgl/compass.c new file mode 100644 index 0000000..1efd611 --- /dev/null +++ b/non-wgl/compass.c @@ -0,0 +1,1006 @@ +/* xscreensaver, Copyright (c) 1999 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 + +#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) + +char *background = "#000000"; +char *foreground = "#DDFFFF"; +char *arrow1Foreground = "#FFF66A"; +char *arrow2Foreground = "#F7D64A"; +char *pointerForeground = "#FF0000"; +int delay = 20000; +Bool doubleBuffer = True; + +static argtype vars[] = +{ + {&background, "background", NULL, "#000000", t_String}, + {&foreground, "foreground", NULL, "#DDFFFF", t_String}, + {&arrow1Foreground, "arrow1Foreground", NULL, "#FFF66A", t_String}, + {&arrow2Foreground, "arrow2Foreground", NULL, "#F7D64A", t_String}, + {&pointerForeground, "pointerForeground", NULL, "#FF0000", t_String}, + {&delay, "delay", NULL, "20000", t_Int}, + {&doubleBuffer, "doubleBuffer", NULL, "True", t_Bool}, +}; + +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"); + st->delay = delay; + st->dbuf = doubleBuffer; + +# ifdef HAVE_COCOA /* 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->size2 > 600) st->size2 = 600; + + 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.foreground = load_color(st->dpy, st->xgwa.colormap, 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.foreground = load_color(st->dpy, st->xgwa.colormap, arrow2Foreground); + 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.foreground = load_color(st->dpy, st->xgwa.colormap, arrow1Foreground); + 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"); + gcv.foreground = load_color(st->dpy, st->xgwa.colormap, pointerForeground); + st->ptr_gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth, &gcv); + + //gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap, + // "background", "Background"); + gcv.foreground = load_color(st->dpy, st->xgwa.colormap, 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; +} + +#if 0 + static Bool + compass_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +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/non-wgl/compass.vcproj b/non-wgl/compass.vcproj new file mode 100644 index 0000000..481a3d9 --- /dev/null +++ b/non-wgl/compass.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/coral.c b/non-wgl/coral.c new file mode 100644 index 0000000..ddbd218 --- /dev/null +++ b/non-wgl/coral.c @@ -0,0 +1,335 @@ +/* coral, by "Frederick G.M. Roeber" , 15-jul-97. + * + * 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 "erase.h" + +#define NCOLORSMAX 200 + +char *eraseMode = NULL; +float eraseSeconds = 0; + +char *background = "black"; +char *foreground = "white"; +int n_density = 25; +int n_seeds = 20; +int delay = 5; +int delay2 = 20000; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&n_density, "density", NULL, "25", t_Int}, + {&n_seeds, "seeds", NULL, "20", t_Int}, + {&delay, "delay", NULL, "5", t_Int}, + {&delay2, "delay2", NULL, "20000", t_Int}, +}; + +struct state { + Display *dpy; + Window window; + + GC draw_gc, erase_gc; + unsigned int default_fg_pixel; + XColor colors[NCOLORSMAX]; + int ncolors; + int colorindex; + int colorsloth; + + XPoint *walkers; + int nwalkers; + int width, widthb; + int height; + int delay, delay2; + int max_points; + XPoint *pointbuf; + + unsigned int *board; + + int done, reset; + int npoints; + eraser_state *eraser; +}; + + +#define getdot(x,y) (st->board[(y*st->widthb)+(x>>5)] & (1<<(x & 31))) +#define setdot(x,y) (st->board[(y*st->widthb)+(x>>5)] |= (1<<(x & 31))) + + +static void +init_coral(struct state *st) +{ + XGCValues gcv; + Colormap cmap; + XWindowAttributes xgwa; + Bool writeable = False; + int seeds; + int density; + int i; + + XClearWindow(st->dpy, st->window); + XGetWindowAttributes(st->dpy, st->window, &xgwa); + st->width = xgwa.width; + st->widthb = ((xgwa.width + 31) >> 5); + st->height = xgwa.height; + if (st->board) free(st->board); + st->board = (unsigned int *)calloc(st->widthb * xgwa.height, sizeof(unsigned int)); + if(!st->board) exit(1); + cmap = xgwa.colormap; + if( st->ncolors ) { + free_colors(xgwa.screen, cmap, st->colors, st->ncolors); + st->ncolors = 0; + } + //gcv.foreground = st->default_fg_pixel = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground"); + gcv.foreground = st->default_fg_pixel = load_color(st->dpy, cmap, foreground); + st->draw_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + //gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, cmap, background); + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + st->ncolors = NCOLORSMAX; + make_uniform_colormap(xgwa.screen, xgwa.visual, cmap, + st->colors, &st->ncolors, True, &writeable, False); + if (st->ncolors <= 0) { + st->ncolors = 2; + st->colors[0].red = st->colors[0].green = st->colors[0].blue = 0; + st->colors[1].red = st->colors[1].green = st->colors[1].blue = 0xFFFF; + XAllocColor(st->dpy, cmap, &st->colors[0]); + XAllocColor(st->dpy, cmap, &st->colors[1]); + } + st->colorindex = random()%st->ncolors; + + //density = get_integer_resource(st->dpy, "density", "Integer"); + density = n_density; + if( density < 1 ) density = 1; + if( density > 100 ) density = 90; /* more like mold than coral */ + st->nwalkers = (st->width*st->height*density)/100; + if (st->walkers) free(st->walkers); + st->walkers = (XPoint *)calloc(st->nwalkers, sizeof(XPoint)); + if( (XPoint *)0 == st->walkers ) exit(1); + + //seeds = get_integer_resource(st->dpy, "seeds", "Integer"); + seeds = n_seeds; + if( seeds < 1 ) seeds = 1; + if( seeds > 1000 ) seeds = 1000; + + st->colorsloth = st->nwalkers*2/st->ncolors; + XSetForeground(st->dpy, st->draw_gc, st->colors[st->colorindex].pixel); + + if ((st->width <= 2) || (st->height <= 2)) return; + + for( i = 0; i < seeds; i++ ) { + int x, y; + int max_repeat = 10; + do { + x = 1 + random() % (st->width - 2); + y = 1 + random() % (st->height - 2); + } while( getdot(x, y) && max_repeat--); + + setdot((x-1), (y-1)); setdot(x, (y-1)); setdot((x+1), (y-1)); + setdot((x-1), y ); setdot(x, y ); setdot((x+1), y ); + setdot((x-1), (y+1)); setdot(x, (y+1)); setdot((x+1), (y+1)); + XDrawPoint(st->dpy, st->window, st->draw_gc, x, y); + } + + for( i = 0; i < st->nwalkers; i++ ) { + st->walkers[i].x = (random() % (st->width-2)) + 1; + st->walkers[i].y = (random() % (st->height-2)) + 1; + } +} + + +/* returns 2 bits of randomness (conserving calls to random()). + This speeds things up a little, but not a lot (5-10% or so.) + */ +static int +rand_2(void) +{ + static int i = 0; + static int r = 0; + if (i != 0) { + i--; + } else { + i = 15; + r = random(); + } + + { + register int j = (r & 3); + r = r >> 2; + return j; + } +} + + +static int +coral(struct state *st) +{ + int i = 0; + + for( i = 0; i < st->nwalkers; i++ ) { + int x = st->walkers[i].x; + int y = st->walkers[i].y; + + if( getdot(x, y) ) { + + Bool flush = False; + Bool color = False; + + /* XDrawPoint(dpy, window, draw_gc, x, y); */ + st->pointbuf[st->npoints].x = x; + st->pointbuf[st->npoints].y = y; + st->npoints++; + + /* Mark the surrounding area as "sticky" */ + setdot((x-1), (y-1)); setdot(x, (y-1)); setdot((x+1), (y-1)); + setdot((x-1), y ); setdot((x+1), y ); + setdot((x-1), (y+1)); setdot(x, (y+1)); setdot((x+1), (y+1)); + st->nwalkers--; + st->walkers[i].x = st->walkers[st->nwalkers].x; + st->walkers[i].y = st->walkers[st->nwalkers].y; + if( 0 == + ((st->colorsloth ? st->nwalkers%st->colorsloth : 0)) ) { + color = True; + } + + if (flush || color || 0 == st->nwalkers || st->npoints >= st->max_points) { + XDrawPoints(st->dpy, st->window, st->draw_gc, st->pointbuf, st->npoints, + CoordModeOrigin); + st->npoints = 0; + } + + if (color) { + st->colorindex++; + if( st->colorindex == st->ncolors ) + st->colorindex = 0; + XSetForeground(st->dpy, st->draw_gc, st->colors[st->colorindex].pixel); + } + } else { + /* move it a notch */ + do { + switch(rand_2()) { + case 0: + if( 1 == x ) continue; + st->walkers[i].x--; + break; + case 1: + if( st->width-2 == x ) continue; + st->walkers[i].x++; + break; + case 2: + if( 1 == y ) continue; + st->walkers[i].y--; + break; + default: /* case 3: */ + if( st->height-2 == y ) continue; + st->walkers[i].y++; + break; + /* default: + abort(); */ + } + } while(0); + } + } + + return (0 == st->nwalkers); +} + +static void * +coral_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + st->max_points = 200; + st->pointbuf = (XPoint *) calloc(sizeof(XPoint), st->max_points+2); + if (!st->pointbuf) exit(-1); + + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + //st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer"); + st->delay = delay; + st->delay2 = delay2; + st->reset = 1; + return st; +} + + +static unsigned long +coral_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->eraser || st->done) + { + st->done = 0; + st->eraser = erase_window (st->dpy, st->window, st->eraser); + return st->delay2; + } + + if (st->reset) + init_coral(st); + st->reset = st->done = coral(st); + + return (st->reset + ? (st->delay * 1000000) + : st->delay2); +} + +static void +coral_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + init_coral(st); +} + +#if 0 + static Bool + coral_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +coral_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st->pointbuf); + if (st->walkers) free (st->walkers); + if (st->board) free (st->board); + free (st); +} + +static const char *coral_defaults[] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*density: 25", + "*seeds: 20", /* too many for 640x480, too few for 1280x1024 */ + "*delay: 5", + "*delay2: 20000", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec coral_options[] = { + { "-density", ".density", XrmoptionSepArg, 0 }, + { "-seeds", ".seeds", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-delay2", ".delay2", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Coral", coral) diff --git a/non-wgl/coral.vcproj b/non-wgl/coral.vcproj new file mode 100644 index 0000000..5a7dd80 --- /dev/null +++ b/non-wgl/coral.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/critical.c b/non-wgl/critical.c new file mode 100644 index 0000000..b9b169f --- /dev/null +++ b/non-wgl/critical.c @@ -0,0 +1,483 @@ +/* critical -- Self-organizing-criticality display hack for XScreenSaver + * Copyright (C) 1998, 1999, 2000 Martin Pool + * + * 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 `critical.man' for more information. + * + * Revision history: + * 13 Nov 1998: Initial version, Martin Pool + * 08 Feb 2000: Change to keeping and erasing a trail, + * + * It would be nice to draw curvy shapes rather than just straight + * lines, but X11 doesn't have spline primitives (?) so we'd have to + * do all the work ourselves */ + +#include "screenhack.h" +#include "erase.h" + +#include +#include +#include + +char *eraseMode = NULL; +float eraseSeconds = 0; + +char *background = "black"; +char *foreground = "white"; +char *colorscheme = "smooth"; +int delay = 10000; +int ncolors = 64; +int restart = 8; +int batchcount = 1500; +int trail = 50; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&colorscheme, "colorscheme", NULL, "smooth", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&ncolors, "ncolors", NULL, "64", t_Int}, + {&restart, "restart", NULL, "8", t_Int}, + {&batchcount, "batchcount", NULL, "1500", t_Int}, + {&trail, "trail", NULL, "50", t_Int}, +}; + +typedef struct { + int width, height; /* in cells */ + unsigned short *cells; +} CriticalModel; + +typedef struct { + int trail; /* length of trail */ + int cell_size; +} CriticalSettings; + + +/* Number of screens that should be drawn before reinitializing the + model, and count of the number of screens done so far. */ + +struct state { + Display *dpy; + Window window; + + int n_restart, i_restart; + XWindowAttributes wattr; + CriticalModel *model; + int batchcount; + XPoint *history; /* in cell coords */ + long delay_usecs; + GC fgc, bgc; + XGCValues gcv; + CriticalSettings settings; + + int d_n_colors; + XColor *d_colors; + int lines_per_color; + int d_i_color; + int d_pos; + int d_wrapped; + + int d_i_batch; + eraser_state *eraser; + +}; + + +static CriticalModel * model_allocate (int w, int h); +static void model_initialize (CriticalModel *); + + +static int +clip (int low, int val, int high) +{ + if (val < low) + return low; + else if (val > high) + return high; + else + return val; +} + + +/* Allocate an return a new simulation model datastructure. + */ + +static CriticalModel * +model_allocate (int model_w, int model_h) +{ + CriticalModel *mm; + + mm = malloc (sizeof (CriticalModel)); + if (!mm) + return 0; + + mm->width = model_w; + mm->height = model_h; + + mm->cells = malloc (sizeof (unsigned short) * model_w * model_h); + if (!mm->cells) + return 0; + + return mm; +} + + + +/* Initialize the data model underlying the hack. + + For the self-organizing criticality hack, this consists of a 2d + array full of random integers. + + I've considered storing the data as (say) a binary tree within a 2d + array, to make finding the highest value faster at the expense of + storage space: searching the whole array on each iteration seems a + little inefficient. However, the screensaver doesn't seem to take + up many cycles as it is: presumably the search is pretty quick + compared to the sleeps. The current version uses less than 1% of + the CPU time of an AMD K6-233. Many machines running X11 at this + point in time seem to be memory-limited, not CPU-limited. + + The root of all evil, and all that. +*/ + + +static void +model_initialize (CriticalModel *mm) +{ + int i; + + for (i = mm->width * mm->height - 1; i >= 0; i--) + { + mm->cells[i] = (unsigned short) random (); + } +} + + +/* Move one step forward in the criticality simulation. + + This function locates and returns in (TOP_X, TOP_Y) the location of + the highest-valued cell in the model. It also replaces that cell + and it's eight nearest neighbours with new random values. + Neighbours that fall off the edge of the model are simply + ignored. */ +static void +model_step (CriticalModel *mm, XPoint *ptop) +{ + int x, y, i; + int dx, dy; + unsigned short top_value = 0; + int top_x = 0, top_y = 0; + + /* Find the top cell */ + top_value = 0; + i = 0; + for (y = 0; y < mm->height; y++) + for (x = 0; x < mm->width; x++) + { + if (mm->cells[i] >= top_value) + { + top_value = mm->cells[i]; + top_x = x; + top_y = y; + } + i++; + } + + /* Replace it and its neighbours with new random values */ + for (dy = -1; dy <= 1; dy++) + { + int yy = top_y + dy; + if (yy < 0 || yy >= mm->height) + continue; + + for (dx = -1; dx <= 1; dx++) + { + int xx = top_x + dx; + if (xx < 0 || xx >= mm->width) + continue; + + mm->cells[yy * mm->width + xx] = (unsigned short) random(); + } + } + + ptop->x = top_x; + ptop->y = top_y; +} + + +/* Construct and return in COLORS and N_COLORS a new set of colors, + depending on the resource settings. */ +static void +setup_colormap (struct state *st, XColor **colors, int *n_colors) +{ + Bool writable; + char const * color_scheme; + + /* Make a colormap */ + //*n_colors = get_integer_resource (st->dpy, "ncolors", "Integer"); + *n_colors = ncolors; + if (*n_colors < 3) + *n_colors = 3; + + *colors = (XColor *) calloc (sizeof(XColor), *n_colors); + if (!*colors) + { + fprintf (stderr, "%s:%d: can't allocate memory for colors\n", + __FILE__, __LINE__); + return; + } + + writable = False; + //color_scheme = get_string_resource (st->dpy, "colorscheme", "ColorScheme"); + color_scheme = colorscheme; + + if (!strcmp (color_scheme, "random")) + { + make_random_colormap (st->wattr.screen, st->wattr.visual, + st->wattr.colormap, + *colors, n_colors, + True, True, &writable, True); + } + else if (!strcmp (color_scheme, "smooth")) + { + make_smooth_colormap (st->wattr.screen, st->wattr.visual, + st->wattr.colormap, + *colors, n_colors, + True, &writable, True); + } + else + { + make_uniform_colormap (st->wattr.screen, st->wattr.visual, + st->wattr.colormap, + *colors, n_colors, True, + &writable, True); + } +} + + +/* Free allocated colormap created by setup_colormap. */ +static void +free_colormap (struct state *st, XColor **colors, int n_colors) +{ + free_colors (st->wattr.screen, st->wattr.colormap, *colors, n_colors); + free (*colors); +} + + + +/* Draw one step of the hack. Positions are cell coordinates. */ +static void +draw_step (struct state *st, GC gc, int pos) +{ + int cell_size = st->settings.cell_size; + int half = cell_size/2; + int old_pos = (pos + st->settings.trail - 1) % st->settings.trail; + + pos = pos % st->settings.trail; + + XDrawLine (st->dpy, st->window, gc, + st->history[pos].x * cell_size + half, + st->history[pos].y * cell_size + half, + st->history[old_pos].x * cell_size + half, + st->history[old_pos].y * cell_size + half); +} + + + +static void * +critical_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int model_w, model_h; + st->dpy = dpy; + st->window = window; + + /* Find window attributes */ + XGetWindowAttributes (st->dpy, st->window, &st->wattr); + + //st->batchcount = get_integer_resource (st->dpy, "batchcount", "Integer"); + st->batchcount = batchcount; + if (st->batchcount < 5) + st->batchcount = 5; + + st->lines_per_color = 10; + + /* For the moment the model size is just fixed -- making it vary + with the screen size just makes the hack boring on large + screens. */ + model_w = 80; + st->settings.cell_size = st->wattr.width / model_w; + model_h = st->settings.cell_size ? + st->wattr.height / st->settings.cell_size : 0; + + /* Construct the initial model state. */ + + //st->settings.trail = clip(2, get_integer_resource (st->dpy, "trail", "Integer"), 1000); + st->settings.trail = clip(2, trail, 1000); + + st->history = calloc (st->settings.trail, sizeof (st->history[0])); + if (!st->history) + { + fprintf (stderr, "critical: " + "couldn't allocate trail history of %d cells\n", + st->settings.trail); + abort(); + } + + st->model = model_allocate (model_w, model_h); + if (!st->model) + { + fprintf (stderr, "critical: error preparing the model\n"); + abort(); + } + + /* make a black gc for the background */ + //st->gcv.foreground = get_pixel_resource (st->dpy, st->wattr.colormap, + // "background", "Background"); + st->gcv.foreground = load_color(st->dpy, st->wattr.colormap, background); + st->bgc = XCreateGC (st->dpy, st->window, GCForeground, &st->gcv); + + st->fgc = XCreateGC (st->dpy, st->window, 0, &st->gcv); + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (dpy, st->fgc, False); + jwxyz_XSetAntiAliasing (dpy, st->bgc, False); +#endif + + //st->delay_usecs = get_integer_resource (st->dpy, "delay", "Integer"); + //st->n_restart = get_integer_resource (st->dpy, "restart", "Integer"); + st->delay_usecs = delay; + st->n_restart = restart; + + setup_colormap (st, &st->d_colors, &st->d_n_colors); + model_initialize (st->model); + model_step (st->model, &st->history[0]); + st->d_pos = 1; + st->d_wrapped = 0; + st->i_restart = 0; + st->d_i_batch = st->batchcount; + + return st; +} + +static unsigned long +critical_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 st->delay_usecs; + } + + /* for (d_i_batch = batchcount; d_i_batch; d_i_batch--) */ + { + /* Set color */ + if ((st->d_i_batch % st->lines_per_color) == 0) + { + st->d_i_color = (st->d_i_color + 1) % st->d_n_colors; + st->gcv.foreground = st->d_colors[st->d_i_color].pixel; + XChangeGC (st->dpy, st->fgc, GCForeground, &st->gcv); + } + + assert(st->d_pos >= 0 && st->d_pos < st->settings.trail); + model_step (st->model, &st->history[st->d_pos]); + + draw_step (st, st->fgc, st->d_pos); + + /* we use the history as a ring buffer, but don't start erasing until + we've d_wrapped around once. */ + if (++st->d_pos >= st->settings.trail) + { + st->d_pos -= st->settings.trail; + st->d_wrapped = 1; + } + + if (st->d_wrapped) + { + draw_step (st, st->bgc, st->d_pos+1); + } + + } + + st->d_i_batch--; + if (st->d_i_batch < 0) + st->d_i_batch = st->batchcount; + else + return st->delay_usecs; + + st->i_restart = (st->i_restart + 1) % st->n_restart; + + if (st->i_restart == 0) + { + /* Time to start a new simulation, this one has probably got + to be a bit boring. */ + free_colormap (st, &st->d_colors, st->d_n_colors); + setup_colormap (st, &st->d_colors, &st->d_n_colors); + st->eraser = erase_window (st->dpy, st->window, st->eraser); + model_initialize (st->model); + model_step (st->model, &st->history[0]); + st->d_pos = 1; + st->d_wrapped = 0; + st->d_i_batch = st->batchcount; + } + + return st->delay_usecs; +} + +static void +critical_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + critical_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +critical_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +/* Options this module understands. */ +static XrmOptionDescRec critical_options[] = { + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-colorscheme", ".colorscheme", XrmoptionSepArg, 0 }, + { "-restart", ".restart", XrmoptionSepArg, 0 }, + { "-batchcount", ".batchcount", XrmoptionSepArg, 0 }, + { "-trail", ".trail", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } /* end */ +}; + + +/* Default xrm resources. */ +static const char *critical_defaults[] = { + ".background: black", + "*fpsSolid: true", + "*colorscheme: smooth", + "*delay: 10000", + "*ncolors: 64", + "*restart: 8", + "*batchcount: 1500", + "*trail: 50", + 0 /* end */ +}; + + +XSCREENSAVER_MODULE ("Critical", critical) diff --git a/non-wgl/critical.vcproj b/non-wgl/critical.vcproj new file mode 100644 index 0000000..ec8d2d0 --- /dev/null +++ b/non-wgl/critical.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/crystal.c b/non-wgl/crystal.c index 4c4e173..13358ec 100644 --- a/non-wgl/crystal.c +++ b/non-wgl/crystal.c @@ -73,6 +73,7 @@ static const char sccsid[] = "@(#)crystal.c 4.12 98/09/10 xlockmore"; #define COUNT -500 #define CYCLES 200 #define SIZE_ -15 +#define NCOLORS 100 # define DEFAULTS "*delay: 60000 \n" \ "*count: -500 \n" \ "*cycles: 200 \n" \ @@ -92,7 +93,7 @@ static const char sccsid[] = "@(#)crystal.c 4.12 98/09/10 xlockmore"; #endif /* STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #define DEF_CELL "True" /* Draw unit cell */ diff --git a/non-wgl/crystal.vcproj b/non-wgl/crystal.vcproj index 49f4309..507956f 100644 --- a/non-wgl/crystal.vcproj +++ b/non-wgl/crystal.vcproj @@ -195,11 +195,15 @@ > + + + + @@ -239,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/non-wgl/cynosure.c b/non-wgl/cynosure.c new file mode 100644 index 0000000..d63b161 --- /dev/null +++ b/non-wgl/cynosure.c @@ -0,0 +1,479 @@ +/* cynosure --- draw some rectangles + * + * 01-aug-96: written in Java by ozymandias G desiderata + * 25-dec-97: ported to C and XScreenSaver by Jamie Zawinski + * + * Original version: + * http://www.organic.com/staff/ogd/java/cynosure.html + * http://www.organic.com/staff/ogd/java/source/cynosure/Cynosure-java.txt + * + * Original comments and copyright: + * + * Cynosure.java + * A Java implementation of Stephen Linhart's Cynosure screen-saver as a + * drop-in class. + * + * Header: /home/ogd/lib/cvs/aoaioxxysz/graphics/Cynosure.java,v 1.2 1996/08/02 02:41:21 ogd Exp + * + * ozymandias G desiderata + * Thu Aug 1 1996 + * + * COPYRIGHT NOTICE + * + * Copyright 1996 ozymandias G desiderata. Title, ownership rights, and + * intellectual property rights in and to this software remain with + * ozymandias G desiderata. This software may be copied, modified, + * or used as long as this copyright is retained. Use this code at your + * own risk. + * + * Revision: 1.2 + * + * Log: Cynosure.java,v + * Revision 1.2 1996/08/02 02:41:21 ogd + * Added a few more comments, fixed messed-up header. + * + * Revision 1.1.1.1 1996/08/02 02:30:45 ogd + * First version + */ + +#include "screenhack.h" + +/* #define DO_STIPPLE */ + +char *background = "black"; +char *foreground = "white"; +int delay = 500000; +int colors = 128; +int iterations = 100; +int shadowWidth = 2; +int elevation = 5; +int sway = 30; +int tweak = 20; +int gridSize = 12; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "500000", t_Int}, + {&colors, "colors", NULL, "128", t_Int}, + {&iterations, "iterations", NULL, "100", t_Int}, + {&shadowWidth, "shadowWidth", NULL, "2", t_Int}, + {&elevation, "elevation", NULL, "5", t_Int}, + {&sway, "sway", NULL, "30", t_Int}, + {&tweak, "tweak", NULL, "20", t_Int}, + {&gridSize, "gridSize", NULL, "12", t_Int}, +}; + +struct state { + Display *dpy; + Window window; + + XColor *colors; + int ncolors; + +#ifndef DO_STIPPLE + XColor *colors2; + int ncolors2; +#endif + + int fg_pixel, bg_pixel; + GC fg_gc, bg_gc, shadow_gc; + + int curColor; + int curBase; /* color progression */ + int shadowWidth; + int elevation; /* offset of dropshadow */ + int sway; /* time until base color changed */ + int timeLeft; /* until base color used */ + int tweak; /* amount of color variance */ + int gridSize; + int iterations, i, delay; + XWindowAttributes xgwa; +}; + + +/** + * The smallest size for an individual cell. + **/ +#define MINCELLSIZE 16 + +/** + * The narrowest a rectangle can be. + **/ +#define MINRECTSIZE 6 + +/** + * Every so often genNewColor() generates a completely random + * color. This variable sets how frequently that happens. It's + * currently set to happen 1% of the time. + * + * @see #genNewColor + **/ +#define THRESHOLD 100 /*0.01*/ + +static void paint(struct state *st); +static int genNewColor(struct state *st); +static int genConstrainedColor(struct state *st, int base, int tweak); +static int c_tweak(struct state *st, int base, int tweak); + + +static void * +cynosure_init (Display *d, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + + st->dpy = d; + st->window = w; + + st->curColor = 0; + st->curBase = st->curColor; +#if 1 + st->shadowWidth = shadowWidth; + st->elevation = elevation; + st->sway = sway; + st->tweak = tweak; + st->gridSize = gridSize; +#else + st->shadowWidth = get_integer_resource (st->dpy, "shadowWidth", "Integer"); + st->elevation = get_integer_resource (st->dpy, "elevation", "Integer"); + st->sway = get_integer_resource (st->dpy, "sway", "Integer"); + st->tweak = get_integer_resource (st->dpy, "tweak", "Integer"); + st->gridSize = get_integer_resource (st->dpy, "gridSize", "Integer"); +#endif + st->timeLeft = 0; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + //st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors = colors; + if (st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + + if (mono_p) + st->colors = 0; + else + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + + if (mono_p) + ; + else { + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, + True, 0, True); + if (st->ncolors <= 2) { + mono_p = True; + st->ncolors = 2; + if (st->colors) free(st->colors); + st->colors = 0; + } + } + +#if 1 + st->bg_pixel = load_color(st->dpy, st->xgwa.colormap, background); + st->fg_pixel = load_color(st->dpy, st->xgwa.colormap, foreground); +#else + st->bg_pixel = get_pixel_resource(st->dpy, + st->xgwa.colormap, "background", "Background"); + st->fg_pixel = get_pixel_resource(st->dpy, + st->xgwa.colormap, "foreground", "Foreground"); +#endif + + gcv.foreground = st->fg_pixel; + st->fg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + gcv.foreground = st->bg_pixel; + st->bg_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + +#ifdef DO_STIPPLE + gcv.fill_style = FillStippled; + gcv.stipple = XCreateBitmapFromData(st->dpy, st->window, "\125\252", 8, 2); + st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground|GCFillStyle|GCStipple, &gcv); + XFreePixmap(st->dpy, gcv.stipple); + +#else /* !DO_STIPPLE */ + st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + +# ifdef HAVE_COCOA /* allow non-opaque alpha components in pixel values */ + jwxyz_XSetAlphaAllowed (st->dpy, st->shadow_gc, True); +# endif + + if (st->colors) + { + int i; + st->ncolors2 = st->ncolors; + st->colors2 = (XColor *) malloc(sizeof(*st->colors2) * (st->ncolors2+1)); + + for (i = 0; i < st->ncolors2; i++) + { +# ifdef HAVE_COCOA + /* give a non-opaque alpha to the shadow colors */ + unsigned long pixel = st->colors[i].pixel; + unsigned long amask = BlackPixelOfScreen (st->xgwa.screen); + unsigned long a = (0x77777777 & amask); + pixel = (pixel & (~amask)) | a; + st->colors2[i].pixel = pixel; +# else /* !HAVE_COCOA */ + int h; + double s, v; + rgb_to_hsv (st->colors[i].red, + st->colors[i].green, + st->colors[i].blue, + &h, &s, &v); + v *= 0.4; + hsv_to_rgb (h, s, v, + &st->colors2[i].red, + &st->colors2[i].green, + &st->colors2[i].blue); + st->colors2[i].pixel = st->colors[i].pixel; + XAllocColor (st->dpy, st->xgwa.colormap, &st->colors2[i]); +# endif /* !HAVE_COCOA */ + } + } +# endif /* !DO_STIPPLE */ + + //st->delay = get_integer_resource (st->dpy, "delay", "Delay"); + //st->iterations = get_integer_resource (st->dpy, "iterations", "Iterations"); + st->delay = delay; + st->iterations = iterations; + + return st; +} + +static unsigned long +cynosure_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->iterations > 0 && ++st->i >= st->iterations) + { + st->i = 0; + if (!mono_p) + XSetWindowBackground(st->dpy, st->window, + st->colors[random() % st->ncolors].pixel); + XClearWindow(st->dpy, st->window); + } + paint(st); + + return st->delay; +} + + +/** + * paint adds a new layer of multicolored rectangles within a grid of + * randomly generated size. Each row of rectangles is the same color, + * but colors vary slightly from row to row. Each rectangle is placed + * within a regularly-sized cell, but each rectangle is sized and + * placed randomly within that cell. + * + * @param g the Graphics coordinate in which to draw + * @see #genNewColor + **/ +static void paint(struct state *st) +{ + int i; + int cellsWide, cellsHigh, cellWidth, cellHeight; + int width = st->xgwa.width; + int height = st->xgwa.height; + + /* How many cells wide the grid is (equal to gridSize +/- (gridSize / 2)) + */ + cellsWide = c_tweak(st, st->gridSize, st->gridSize / 2); + /* How many cells high the grid is (equal to gridSize +/- (gridSize / 2)) + */ + cellsHigh = c_tweak(st, st->gridSize, st->gridSize / 2); + /* How wide each cell in the grid is */ + cellWidth = width / cellsWide; + /* How tall each cell in the grid is */ + cellHeight = height / cellsHigh; + + /* Ensure that each cell is above a certain minimum size */ + + if (cellWidth < MINCELLSIZE) { + cellWidth = MINCELLSIZE; + cellsWide = width / cellWidth; + } + + if (cellHeight < MINCELLSIZE) { + cellHeight = MINCELLSIZE; + cellsHigh = width / cellWidth; + } + + /* fill the grid with randomly-generated cells */ + for(i = 0; i < cellsHigh; i++) { + int j; + + /* Each row is a different color, randomly generated (but constrained) */ + if (!mono_p) + { + int c = genNewColor(st); + XSetForeground(st->dpy, st->fg_gc, st->colors[c].pixel); +# ifndef DO_STIPPLE + if (st->colors2) + XSetForeground(st->dpy, st->shadow_gc, st->colors2[c].pixel); +# endif + } + + for(j = 0; j < cellsWide; j++) { + int curWidth, curHeight, curX, curY; + + /* Generate a random height for a rectangle and make sure that */ + /* it's above a certain minimum size */ + curHeight = random() % (cellHeight - st->shadowWidth); + if (curHeight < MINRECTSIZE) + curHeight = MINRECTSIZE; + /* Generate a random width for a rectangle and make sure that + it's above a certain minimum size */ + curWidth = random() % (cellWidth - st->shadowWidth); + if (curWidth < MINRECTSIZE) + curWidth = MINRECTSIZE; + /* Figure out a random place to locate the rectangle within the + cell */ + curY = (i * cellHeight) + (random() % ((cellHeight - curHeight) - + st->shadowWidth)); + curX = (j * cellWidth) + (random() % ((cellWidth - curWidth) - + st->shadowWidth)); + + /* Draw the shadow */ + if (st->elevation > 0) + XFillRectangle(st->dpy, st->window, st->shadow_gc, + curX + st->elevation, curY + st->elevation, + curWidth, curHeight); + + /* Draw the edge */ + if (st->shadowWidth > 0) + XFillRectangle(st->dpy, st->window, st->bg_gc, + curX + st->shadowWidth, curY + st->shadowWidth, + curWidth, curHeight); + + XFillRectangle(st->dpy, st->window, st->fg_gc, curX, curY, curWidth, curHeight); + + /* Draw a 1-pixel black border around the rectangle */ + XDrawRectangle(st->dpy, st->window, st->bg_gc, curX, curY, curWidth, curHeight); + } + + } +} + + +/** + * genNewColor returns a new color, gradually mutating the colors and + * occasionally returning a totally random color, just for variety. + * + * @return the new color + **/ +static int genNewColor(struct state *st) +{ + /* These lines handle "sway", or the gradual random changing of */ + /* colors. After genNewColor() has been called a given number of */ + /* times (specified by a random permutation of the tweak variable), */ + /* take whatever color has been most recently randomly generated and */ + /* make it the new base color. */ + if (st->timeLeft == 0) { + st->timeLeft = c_tweak(st, st->sway, st->sway / 3); + st->curColor = st->curBase; + } else { + st->timeLeft--; + } + + /* If a randomly generated number is less than the threshold value, + produce a "sport" color value that is completely unrelated to the + current palette. */ + if (0 == (random() % THRESHOLD)) { + return (random() % st->ncolors); + } else { + st->curBase = genConstrainedColor(st, st->curColor, st->tweak); + return st->curBase; + } + +} + +/** + * genConstrainedColor creates a random new color within a certain + * range of an existing color. Right now this works with RGB color + * values, but a future version of the program will most likely use HSV + * colors, which should generate a more pleasing progression of values. + * + * @param base the color on which the new color will be based + * @param tweak the amount that the new color can be tweaked + * @return a new constrained color + * @see #genNewColor + **/ +static int genConstrainedColor(struct state *st, int base, int tweak) +{ + int i = 1 + (random() % st->tweak); + if (random() & 1) + i = -i; + i = (base + i) % st->ncolors; + while (i < 0) + i += st->ncolors; + return i; +} + +/** + * Utility function to generate a tweaked color value + * + * @param base the byte value on which the color is based + * @param tweak the amount the value will be skewed + * @see #tweak + * @return the tweaked byte + **/ +static int c_tweak(struct state *st, int base, int tweak) +{ + int ranTweak = (random() % (2 * tweak)); + int n = (base + (ranTweak - tweak)); + if (n < 0) n = -n; + return (n < 255 ? n : 255); +} + +static void +cynosure_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 0 + static Bool + cynosure_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +cynosure_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *cynosure_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 500000", + "*colors: 128", + "*iterations: 100", + "*shadowWidth: 2", + "*elevation: 5", + "*sway: 30", + "*tweak: 20", + "*gridSize: 12", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec cynosure_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-ncolors", ".colors", XrmoptionSepArg, 0 }, + { "-iterations", ".iterations", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Cynosure", cynosure) diff --git a/non-wgl/cynosure.vcproj b/non-wgl/cynosure.vcproj new file mode 100644 index 0000000..3b7fdb1 --- /dev/null +++ b/non-wgl/cynosure.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/deco.c b/non-wgl/deco.c new file mode 100644 index 0000000..e5bae75 --- /dev/null +++ b/non-wgl/deco.c @@ -0,0 +1,378 @@ +/* xscreensaver, Copyright (c) 1997-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. + * + * Concept snarfed from Michael D. Bayne in + * http://www.go2net.com/internet/deep/1997/04/16/body.html + * + * Changes by Lars Huttar, http://www.huttar.net: + * - allow use of golden ratio for dividing rectangles instead of 1/2. + * - allow smooth colors instead of random + * - added line thickness setting + * - added "Mondrian" mode + * Other ideas: + * - allow recomputing the colormap on each new frame (especially useful + * when ncolors is low) + */ + +#include "screenhack.h" +#include + +char *background = "black"; +char *foreground = "white"; +int maxDepth = 12; +int minWidth = 20; +int minHeight = 20; +int lineWidth = 1; +int delay = 5; +int ncolors = 64; +Bool goldenRatio = False; +Bool smoothColors = False; +Bool mondrian = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&maxDepth, "maxDepth", NULL, "12", t_Int}, + {&minWidth, "minWidth", NULL, "20", t_Int}, + {&minHeight, "minHeight", NULL, "20", t_Int}, + {&lineWidth, "lineWidth", NULL, "1", t_Int}, + {&delay, "delay", NULL, "5", t_Int}, + {&ncolors, "ncolors", NULL, "64", t_Int}, + {&goldenRatio, "goldenRatio", NULL, "False", t_Bool}, + {&smoothColors, "smoothColors", NULL, "False", t_Bool}, + {&mondrian, "mondrian", NULL, "False", t_Bool}, +}; + +struct state { + XColor colors[255]; + int ncolors; + int max_depth; + int min_height; + int min_width; + int line_width; + int old_line_width; + Bool goldenRatio; + Bool mondrian; + Bool smoothColors; + + int delay; + XWindowAttributes xgwa; + GC fgc, bgc; + int current_color; +}; + +/* Golden Ratio + * Suppose you're dividing a rectangle of length A+B + * into two parts, of length A and B respectively. You want the ratio of + * A to B to be the same as the ratio of the whole (A+B) to A. The golden + * ratio (phi) is that ratio. Supposed to be visually pleasing. */ +#define PHI 1.61803 +#define PHI1 (1.0/PHI) +#define PHI2 (1.0 - PHI1) + +/* copied from make_random_colormap in colors.c */ +static void +make_mondrian_colormap (Screen *screen, Visual *visual, Colormap cmap, + XColor *colors, int *ncolorsP, + Bool allocate_p, + Bool *writable_pP, + Bool verbose_p) +{ + Display *dpy = DisplayOfScreen (screen); + Bool wanted_writable = (allocate_p && writable_pP && *writable_pP); + int ncolors = 8; + int i; + + if (*ncolorsP <= 0) return; + + /* If this visual doesn't support writable cells, don't bother trying. */ + if (wanted_writable && !has_writable_cells(screen, visual)) + *writable_pP = False; + + for (i = 0; i < ncolors; i++) + { + colors[i].flags = DoRed|DoGreen|DoBlue; + colors[i].red = 0; + colors[i].green = 0; + colors[i].blue = 0; + + switch(i) { + case 0: case 1: case 2: case 3: case 7: /* white */ + colors[i].red = 0xE800; + colors[i].green = 0xE800; + colors[i].blue = 0xE800; + break; + case 4: + colors[i].red = 0xCFFF; break; /* red */ + case 5: + colors[i].red = 0x2000; + colors[i].blue = 0xCFFF; break; /* blue */ + case 6: + colors[i].red = 0xDFFF; /* yellow */ + colors[i].green = 0xCFFF; break; + } + } + + if (!allocate_p) + return; + + RETRY_NON_WRITABLE: + if (writable_pP && *writable_pP) + { + unsigned long *pixels = (unsigned long *) + malloc(sizeof(*pixels) * (ncolors + 1)); + + allocate_writable_colors (screen, cmap, pixels, &ncolors); + if (ncolors > 0) + for (i = 0; i < ncolors; i++) + colors[i].pixel = pixels[i]; + free (pixels); + if (ncolors > 0) + XStoreColors (dpy, cmap, colors, ncolors); + } + else + { + for (i = 0; i < ncolors; i++) + { + XColor color; + color = colors[i]; + if (!XAllocColor (dpy, cmap, &color)) + break; + colors[i].pixel = color.pixel; + } + ncolors = i; + } + + /* If we tried for writable cells and got none, try for non-writable. */ + if (allocate_p && ncolors == 0 && writable_pP && *writable_pP) + { + ncolors = *ncolorsP; + *writable_pP = False; + goto RETRY_NON_WRITABLE; + } + +#if 0 + /* I don't think we need to bother copying or linking to the complain + function. */ + if (verbose_p) + complain(*ncolorsP, ncolors, wanted_writable, + wanted_writable && *writable_pP); +#endif + + *ncolorsP = ncolors; +} + +static void +mondrian_set_sizes (struct state *st, int w, int h) +{ + if (w > h) { + st->line_width = w/50; + st->min_height = st->min_width = w/8; + } else { + st->line_width = h/50; + st->min_height = st->min_width = h/8; + } +} + +static void +deco (Display *dpy, Window window, struct state *st, + int x, int y, int w, int h, int depth) +{ + if (((random() % st->max_depth) < depth) || (w < st->min_width) || (h < st->min_height)) + { + if (!mono_p) + { + if (++st->current_color >= st->ncolors) + st->current_color = 0; + XSetForeground(dpy, st->bgc, st->colors[st->current_color].pixel); + } + XFillRectangle (dpy, window, st->bgc, x, y, w, h); + XDrawRectangle (dpy, window, st->fgc, x, y, w, h); + } + else + { + if ((st->goldenRatio || st->mondrian) ? (w > h) : (random() & 1)) + { /* Divide the rectangle side-by-side */ + int wnew = (st->goldenRatio ? (w * (random() & 1 ? PHI1 : PHI2)) : w/2); + deco (dpy, window, st, x, y, wnew, h, depth+1); + deco (dpy, window, st, x+wnew, y, w-wnew, h, depth+1); + } + else + { /* Divide the rectangle top-to-bottom */ + int hnew = (st->goldenRatio ? (h * (random() & 1 ? PHI1 : PHI2)) : h/2); + deco (dpy, window, st, x, y, w, hnew, depth+1); + deco (dpy, window, st, x, y+hnew, w, h-hnew, depth+1); + } + } +} + +static void * +deco_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + + //st->delay = get_integer_resource (dpy, "delay", "Integer"); + st->delay = delay; + + //st->smoothColors = get_boolean_resource(dpy, "smoothColors", "Boolean"); + st->smoothColors = smoothColors; + st->old_line_width = 1; + + //st->goldenRatio = get_boolean_resource (dpy, "goldenRatio", "Boolean"); + st->goldenRatio = goldenRatio; + + //st->max_depth = get_integer_resource (dpy, "maxDepth", "Integer"); + st->max_depth = maxDepth; + if (st->max_depth < 1) st->max_depth = 1; + else if (st->max_depth > 1000) st->max_depth = 1000; + + //st->min_width = get_integer_resource (dpy, "minWidth", "Integer"); + st->min_width = minWidth; + if (st->min_width < 2) st->min_width = 2; + //st->min_height = get_integer_resource (dpy, "minHeight", "Integer"); + st->min_height = minHeight; + if (st->min_height < 2) st->min_height = 2; + + //st->line_width = get_integer_resource (dpy, "lineWidth", "Integer"); + st->line_width = lineWidth; + + XGetWindowAttributes (dpy, window, &st->xgwa); + + //st->ncolors = get_integer_resource (dpy, "ncolors", "Integer"); + st->ncolors = ncolors; + + //gcv.foreground = get_pixel_resource(dpy, st->xgwa.colormap, + // "foreground", "Foreground"); + gcv.foreground = load_color(dpy, st->xgwa.colormap, foreground); + st->fgc = XCreateGC (dpy, window, GCForeground, &gcv); + + //gcv.foreground = get_pixel_resource(dpy, st->xgwa.colormap, + // "background", "Background"); + gcv.foreground = load_color(dpy, st->xgwa.colormap, background); + st->bgc = XCreateGC (dpy, window, GCForeground, &gcv); + + if (st->ncolors <= 2) + mono_p = True; + + if (!mono_p) + { + GC tmp = st->fgc; + st->fgc = st->bgc; + st->bgc = tmp; + } + + //st->mondrian = get_boolean_resource(dpy, "mondrian", "Boolean"); + st->mondrian = mondrian; + if (st->mondrian) { + /* Mondrian, if true, overrides several other options. */ + mondrian_set_sizes(st, st->xgwa.width, st->xgwa.height); + + /** set up red-yellow-blue-black-white colormap and fgc **/ + make_mondrian_colormap(st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, True); + + /** put white in several cells **/ + /** set min-height and min-width to about 10% of total w/h **/ + } + else if (st->smoothColors) + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, True); + else + make_random_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, + st->colors, &st->ncolors, False, True, 0, True); + + gcv.line_width = st->old_line_width = st->line_width; + XChangeGC(dpy, st->fgc, GCLineWidth, &gcv); + + return st; +} + +static unsigned long +deco_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XFillRectangle (dpy, window, st->bgc, 0, 0, st->xgwa.width, st->xgwa.height); + if (st->mondrian) { + mondrian_set_sizes(st, st->xgwa.width, st->xgwa.height); + if (st->line_width != st->old_line_width) { + XSetLineAttributes(dpy, st->fgc, st->line_width, + LineSolid, CapButt, JoinBevel); + st->old_line_width = st->line_width; + } + } + deco (dpy, window, st, 0, 0, st->xgwa.width, st->xgwa.height, 0); + return 1000000 * st->delay; +} + +static void +deco_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 0 + static Bool + deco_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +deco_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *deco_defaults [] = { + ".background: black", + ".foreground: white", + "*maxDepth: 12", + "*minWidth: 20", + "*minHeight: 20", + "*lineWidth: 1", + "*delay: 5", + "*ncolors: 64", + "*goldenRatio: False", + "*smoothColors: False", + "*mondrian: False", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec deco_options [] = { + { "-max-depth", ".maxDepth", XrmoptionSepArg, 0 }, + { "-min-width", ".minWidth", XrmoptionSepArg, 0 }, + { "-min-height", ".minHeight", XrmoptionSepArg, 0 }, + { "-line-width", ".lineWidth", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-golden-ratio", ".goldenRatio", XrmoptionNoArg, "True" }, + { "-no-golden-ratio", ".goldenRatio", XrmoptionNoArg, "False" }, + { "-smooth-colors", ".smoothColors",XrmoptionNoArg, "True" }, + { "-no-smooth-colors",".smoothColors",XrmoptionNoArg, "False" }, + { "-mondrian", ".mondrian", XrmoptionNoArg, "True" }, + { "-no-mondrian", ".mondrian", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Deco", deco) diff --git a/non-wgl/deco.vcproj b/non-wgl/deco.vcproj new file mode 100644 index 0000000..df07dc4 --- /dev/null +++ b/non-wgl/deco.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/demon.c b/non-wgl/demon.c new file mode 100644 index 0000000..fe8138f --- /dev/null +++ b/non-wgl/demon.c @@ -0,0 +1,1002 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* demon --- David Griffeath's cellular automata */ + +#if 0 +static const char sccsid[] = "@(#)demon.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, 9 (not sound mathematically), 12, and 8 added + * 30-May-1996: Ron Hitchens + * Fixed memory management that caused leaks + * 14-Apr-1996: -neighbors 6 runtime-time option added + * 21-Aug-1995: Coded from A.K. Dewdney's "Computer Recreations", Scientific + * American Magazine" Aug 1989 pp 102-105. Also very similar + * to hodgepodge machine described in A.K. Dewdney's "Computer + * Recreations", Scientific American Magazine" Aug 1988 + * pp 104-107. Also used life.c as a guide. + */ + +/*- + * A cellular universe of 4 phases debris, droplets, defects, and demons. + */ + +/*- + Grid Number of Neighbors + ---- ------------------ + Square 4 or 8 + Hexagon 6 + Triangle 3, 9, or 12 +*/ + +#if 0 + #ifndef HAVE_COCOA + # define DO_STIPPLE + #endif +#endif +#define STANDALONE + +# define MODE_demon +#define DELAY 50000 +#define COUNT 0 +#define CYCLES 1000 +#define SIZE_ -7 +#define NCOLORS 64 +# define DEFAULTS "*delay: 50000 \n" \ + "*count: 0 \n" \ + "*cycles: 1000 \n" \ + "*size: -7 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define demon_handle_event 0 +# define UNIFORM_COLORS + +#include "xlockmore.h" + +#if 0 + #ifdef STANDALONE + # include "xlockmore.h" /* in xscreensaver distribution */ + #else /* STANDALONE */ + # include "xlock.h" /* in xlockmore distribution */ + #endif /* STANDALONE */ +#endif + +#include "automata.h" + +#ifdef MODE_demon + +/*- + * neighbors of 0 randomizes it between 3, 4, 6, 8, 9, and 12. + */ +#define DEF_NEIGHBORS "0" /* choose random value */ + +static int neighbors = 0; + +static XrmOptionDescRec opts[] = +{ + {"-neighbors", ".demon.neighbors", XrmoptionSepArg, 0} +}; + +static argtype vars[] = +{ + {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int} +}; +static OptionStruct desc[] = +{ + {"-neighbors num", "squares 4 or 8, hexagons 6, triangles 3, 9 or 12"} +}; + +ENTRYPOINT ModeSpecOpt demon_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct demon_description = +{"demon", "init_demon", "draw_demon", "release_demon", + "refresh_demon", "init_demon", (char *) NULL, &demon_opts, + 50000, 0, 1000, -7, 64, 1.0, "", + "Shows Griffeath's cellular automata", 0, NULL}; +#endif + +#define DEMONBITS(n,w,h)\ + if ((dp->pixmaps[dp->init_bits]=\ + XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\ + free_demon(display,dp); return;} else {dp->init_bits++;} + +#define REDRAWSTEP 2000 /* How many cells to draw per cycle */ +#define MINSTATES 2 +#define MINGRIDSIZE 24 +#define MINSIZE 4 +#define NEIGHBORKINDS 6 + +/* Singly linked list */ +typedef struct _CellList { + XPoint pt; + struct _CellList *next; +} CellList; + +typedef struct { + int generation; + int xs, ys; + int xb, yb; + int nrows, ncols; + int width, height; + int states; + int state; + int redrawing, redrawpos; + int *ncells; + CellList **cellList; + unsigned char *oldcell, *newcell; + int neighbors; + int init_bits; + GC stippledGC; + Pixmap pixmaps[NUMSTIPPLES - 1]; + union { + XPoint hexagon[6]; + XPoint triangle[2][3]; + } shape; +} demonstruct; + +static char plots[2][NEIGHBORKINDS] = +{ + {3, 4, 6, 8, 9, 12}, /* Neighborhoods */ + {12, 16, 18, 20, 22, 24} /* Number of states */ +}; + +static demonstruct *demons = (demonstruct *) NULL; + +static void +drawcell(ModeInfo * mi, int col, int row, unsigned char state) +{ + demonstruct *dp = &demons[MI_SCREEN(mi)]; + GC gc; + + if (!state) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + gc = MI_GC(mi); + } else if (MI_NPIXELS(mi) >= NUMSTIPPLES) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_PIXEL(mi, (((int) state - 1) * MI_NPIXELS(mi) / + (dp->states - 1)) % MI_NPIXELS(mi))); + gc = MI_GC(mi); + } else { + XGCValues gcv; +#ifdef DO_STIPPLE + gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)]; +#endif /* DO_STIPPLE */ + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + XChangeGC(MI_DISPLAY(mi), dp->stippledGC, + GCStipple | GCForeground | GCBackground, &gcv); + gc = dp->stippledGC; + } + if (dp->neighbors == 6) { + int ccol = 2 * col + !(row & 1), crow = 2 * row; + + dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs; + dp->shape.hexagon[0].y = dp->yb + crow * dp->ys; + if (dp->xs == 1 && dp->ys == 1) + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), + gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y); + else + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + dp->shape.hexagon, 6, Convex, CoordModePrevious); + } else if (dp->neighbors == 4 || dp->neighbors == 8) { + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + dp->xb + dp->xs * col, dp->yb + dp->ys * row, + dp->xs - (dp->xs > 3), dp->ys - (dp->ys > 3)); + } else { /* TRI */ + int orient = (col + row) % 2; /* O left 1 right */ + + dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs; + dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys; + if (dp->xs <= 3 || dp->ys <= 3) + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x, + dp->shape.triangle[orient][0].y); + else { + if (orient) + dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1); + else + dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1); + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + dp->shape.triangle[orient], 3, Convex, CoordModePrevious); + + } + } +} + +static Bool +addtolist(ModeInfo * mi, int col, int row, unsigned char state) +{ + demonstruct *dp = &demons[MI_SCREEN(mi)]; + CellList *current; + + current = dp->cellList[state]; + if ((dp->cellList[state] = (CellList *) + malloc(sizeof (CellList))) == NULL) { + return False; + } + dp->cellList[state]->pt.x = col; + dp->cellList[state]->pt.y = row; + dp->cellList[state]->next = current; + dp->ncells[state]++; + return True; +} + +#ifdef DEBUG +static void +print_state(ModeInfo * mi, int state) +{ + demonstruct *dp = &demons[MI_SCREEN(mi)]; + CellList *locallist; + int i = 0; + + locallist = dp->cellList[state]; + (void) printf("state %d\n", state); + while (locallist) { + (void) printf("%d x %d, y %d\n", i, + locallist->pt.x, locallist->pt.y); + locallist = locallist->next; + i++; + } +} + +#endif + +static void +free_state(demonstruct * dp, int state) +{ + CellList *current; + + while (dp->cellList[state]) { + current = dp->cellList[state]; + dp->cellList[state] = dp->cellList[state]->next; + (void) free((void *) current); + } + dp->cellList[state] = (CellList *) NULL; + if (dp->ncells != NULL) + dp->ncells[state] = 0; +} + + +static void +free_list(demonstruct * dp) +{ + int state; + + for (state = 0; state < dp->states; state++) + free_state(dp, state); + (void) free((void *) dp->cellList); + dp->cellList = (CellList **) NULL; +} + +static void +free_struct(demonstruct * dp) +{ + if (dp->cellList != NULL) { + free_list(dp); + } + if (dp->ncells != NULL) { + (void) free((void *) dp->ncells); + dp->ncells = (int *) NULL; + } + if (dp->oldcell != NULL) { + (void) free((void *) dp->oldcell); + dp->oldcell = (unsigned char *) NULL; + } + if (dp->newcell != NULL) { + (void) free((void *) dp->newcell); + dp->newcell = (unsigned char *) NULL; + } +} + +static void +free_demon(Display *display, demonstruct *dp) +{ + int shade; + + if (dp->stippledGC != None) { + XFreeGC(display, dp->stippledGC); + dp->stippledGC = None; + } + for (shade = 0; shade < dp->init_bits; shade++) { + XFreePixmap(display, dp->pixmaps[shade]); + } + dp->init_bits = 0; + free_struct(dp); +} + +static Bool +draw_state(ModeInfo * mi, int state) +{ + demonstruct *dp = &demons[MI_SCREEN(mi)]; + GC gc; + XRectangle *rects; + CellList *current; + + if (!state) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + gc = MI_GC(mi); + } else if (MI_NPIXELS(mi) >= NUMSTIPPLES) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_PIXEL(mi, (((int) state - 1) * MI_NPIXELS(mi) / + (dp->states - 1)) % MI_NPIXELS(mi))); + gc = MI_GC(mi); + } else { + XGCValues gcv; + +#ifdef DO_STIPPLE + gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)]; +#endif /* DO_STIPPLE */ + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + XChangeGC(MI_DISPLAY(mi), dp->stippledGC, + GCStipple | GCForeground | GCBackground, &gcv); + gc = dp->stippledGC; + } + if (dp->neighbors == 6) { /* Draw right away, slow */ + current = dp->cellList[state]; + while (current) { + int col, row, ccol, crow; + + col = current->pt.x; + row = current->pt.y; + ccol = 2 * col + !(row & 1), crow = 2 * row; + dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs; + dp->shape.hexagon[0].y = dp->yb + crow * dp->ys; + if (dp->xs == 1 && dp->ys == 1) + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), + gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y); + else + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + dp->shape.hexagon, 6, Convex, CoordModePrevious); + current = current->next; + } + } else if (dp->neighbors == 4 || dp->neighbors == 8) { + /* Take advantage of XDrawRectangles */ + int ncells = 0; + + /* Create Rectangle list from part of the cellList */ + if ((rects = (XRectangle *) malloc(dp->ncells[state] * + sizeof (XRectangle))) == NULL) { + return False; + } + current = dp->cellList[state]; + while (current) { + rects[ncells].x = dp->xb + current->pt.x * dp->xs; + rects[ncells].y = dp->yb + current->pt.y * dp->ys; + rects[ncells].width = dp->xs - (dp->xs > 3); + rects[ncells].height = dp->ys - (dp->ys > 3); + current = current->next; + ncells++; + } + /* Finally get to draw */ + XFillRectangles(MI_DISPLAY(mi), MI_WINDOW(mi), gc, rects, ncells); + /* Free up rects list and the appropriate part of the cellList */ + (void) free((void *) rects); + } else { /* TRI */ + current = dp->cellList[state]; + while (current) { + int col, row, orient; + + col = current->pt.x; + row = current->pt.y; + orient = (col + row) % 2; /* O left 1 right */ + dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs; + dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys; + if (dp->xs <= 3 || dp->ys <= 3) + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x, + dp->shape.triangle[orient][0].y); + else { + if (orient) + dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1); + else + dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1); + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + dp->shape.triangle[orient], 3, Convex, CoordModePrevious); + } + current = current->next; + } + } + free_state(dp, state); + return True; +} + +static void +RandomSoup(ModeInfo * mi) +{ + demonstruct *dp = &demons[MI_SCREEN(mi)]; + int row, col, mrow = 0; + + for (row = 0; row < dp->nrows; ++row) { + for (col = 0; col < dp->ncols; ++col) { + dp->oldcell[col + mrow] = + (unsigned char) LRAND() % ((unsigned char) dp->states); + if (!addtolist(mi, col, row, dp->oldcell[col + mrow])) + return; /* sparse soup */ + } + mrow += dp->ncols; + } +} + +ENTRYPOINT void +init_demon (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + int size = MI_SIZE(mi), nk; + demonstruct *dp; + + if (demons == NULL) { + if ((demons = (demonstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (demonstruct))) == NULL) + return; + } + dp = &demons[MI_SCREEN(mi)]; + + dp->generation = 0; + dp->redrawing = 0; +#ifdef DO_STIPPLE + if (MI_NPIXELS(mi) < NUMSTIPPLES) { + Window window = MI_WINDOW(mi); + if (dp->stippledGC == None) { + XGCValues gcv; + + gcv.fill_style = FillOpaqueStippled; + if ((dp->stippledGC = XCreateGC(display, window, + GCFillStyle, &gcv)) == None) { + free_demon(display, dp); + return; + } + } + if (dp->init_bits == 0) { + int i; + + for (i = 1; i < NUMSTIPPLES; i++) { + DEMONBITS(stipples[i], STIPPLESIZE, STIPPLESIZE); + } + } + } +#endif /* DO_STIPPLE */ + free_struct(dp); + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False); +#endif + + for (nk = 0; nk < NEIGHBORKINDS; nk++) { + if (neighbors == plots[0][nk]) { + dp->neighbors = plots[0][nk]; + break; + } + if (nk == NEIGHBORKINDS - 1) { + nk = NRAND(NEIGHBORKINDS); + dp->neighbors = plots[0][nk]; + break; + } + } + + dp->states = MI_COUNT(mi); + if (dp->states < -MINSTATES) + dp->states = NRAND(-dp->states - MINSTATES + 1) + MINSTATES; + else if (dp->states < MINSTATES) + dp->states = plots[1][nk]; + if ((dp->cellList = (CellList **) calloc(dp->states, + sizeof (CellList *))) == NULL) { + free_demon(display, dp); + return; + } + if ((dp->ncells = (int *) calloc(dp->states, sizeof (int))) == NULL) { + free_demon(display, dp); + return; + } + + dp->state = 0; + + dp->width = MI_WIDTH(mi); + dp->height = MI_HEIGHT(mi); + + if (dp->neighbors == 6) { + int nccols, ncrows, i; + + if (dp->width < 8) + dp->width = 8; + if (dp->height < 8) + dp->height = 8; + if (size < -MINSIZE) + dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) { + if (!size) + dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE); + else + dp->ys = MINSIZE; + } else + dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) / + MINGRIDSIZE)); + dp->xs = dp->ys; + nccols = MAX(dp->width / dp->xs - 2, 2); + ncrows = MAX(dp->height / dp->ys - 1, 4); + dp->ncols = nccols / 2; + dp->nrows = 2 * (ncrows / 4); + dp->xb = (dp->width - dp->xs * nccols) / 2 + dp->xs / 2; + dp->yb = (dp->height - dp->ys * (ncrows / 2) * 2) / 2 + dp->ys - 2; + for (i = 0; i < 6; i++) { + dp->shape.hexagon[i].x = (dp->xs - 1) * hexagonUnit[i].x; + dp->shape.hexagon[i].y = ((dp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3; + } + } else if (dp->neighbors == 4 || dp->neighbors == 8) { + if (size < -MINSIZE) + dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) { + if (!size) + dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE); + else + dp->ys = MINSIZE; + } else + dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) / + MINGRIDSIZE)); + dp->xs = dp->ys; + dp->ncols = MAX(dp->width / dp->xs, 2); + dp->nrows = MAX(dp->height / dp->ys, 2); + dp->xb = (dp->width - dp->xs * dp->ncols) / 2; + dp->yb = (dp->height - dp->ys * dp->nrows) / 2; + } else { /* TRI */ + int orient, i; + + if (dp->width < 2) + dp->width = 2; + if (dp->height < 2) + dp->height = 2; + if (size < -MINSIZE) + dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) { + if (!size) + dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE); + else + dp->ys = MINSIZE; + } else + dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) / + MINGRIDSIZE)); + dp->xs = (int) (1.52 * dp->ys); + dp->ncols = (MAX(dp->width / dp->xs - 1, 2) / 2) * 2; + dp->nrows = (MAX(dp->height / dp->ys - 1, 2) / 2) * 2; + dp->xb = (dp->width - dp->xs * dp->ncols) / 2 + dp->xs / 2; + dp->yb = (dp->height - dp->ys * dp->nrows) / 2 + dp->ys / 2; + for (orient = 0; orient < 2; orient++) { + for (i = 0; i < 3; i++) { + dp->shape.triangle[orient][i].x = + (dp->xs - 2) * triangleUnit[orient][i].x; + dp->shape.triangle[orient][i].y = + (dp->ys - 2) * triangleUnit[orient][i].y; + } + } + } + + MI_CLEARWINDOW(mi); + + if ((dp->oldcell = (unsigned char *) + malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) { + free_demon(display, dp); + return; + } + + if ((dp->newcell = (unsigned char *) + malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) { + free_demon(display, dp); + return; + } + + RandomSoup(mi); +} + +ENTRYPOINT void +draw_demon (ModeInfo * mi) +{ + int i, j, k, l, mj = 0, ml; + demonstruct *dp; + + if (demons == NULL) + return; + dp = &demons[MI_SCREEN(mi)]; + if (dp->cellList == NULL) + return; + + MI_IS_DRAWN(mi) = True; + if (dp->state >= dp->states) { + (void) memcpy((char *) dp->newcell, (char *) dp->oldcell, + dp->ncols * dp->nrows * sizeof (unsigned char)); + + if (dp->neighbors == 6) { + for (j = 0; j < dp->nrows; j++) { + for (i = 0; i < dp->ncols; i++) { + /* NE */ + if (!(j & 1)) + k = (i + 1 == dp->ncols) ? 0 : i + 1; + else + k = i; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* E */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SE */ + if (!(j & 1)) + k = (i + 1 == dp->ncols) ? 0 : i + 1; + else + k = i; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SW */ + if (j & 1) + k = (!i) ? dp->ncols - 1 : i - 1; + else + k = i; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* W */ + k = (!i) ? dp->ncols - 1 : i - 1; + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* NW */ + if (j & 1) + k = (!i) ? dp->ncols - 1 : i - 1; + else + k = i; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } + mj += dp->ncols; + } + } else if (dp->neighbors == 4 || dp->neighbors == 8) { + for (j = 0; j < dp->nrows; j++) { + for (i = 0; i < dp->ncols; i++) { + /* N */ + k = i; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* E */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* S */ + k = i; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* W */ + k = (!i) ? dp->ncols - 1 : i - 1; + /*l = j;*/ + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } + mj += dp->ncols; + } + if (dp->neighbors == 8) { + mj = 0; + for (j = 0; j < dp->nrows; j++) { + for (i = 0; i < dp->ncols; i++) { + /* NE */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SE */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SW */ + k = (!i) ? dp->ncols - 1 : i - 1; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* NW */ + k = (!i) ? dp->ncols - 1 : i - 1; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } + mj += dp->ncols; + } + } + } else if (dp->neighbors == 3 || dp->neighbors == 9 || + dp->neighbors == 12) { + for (j = 0; j < dp->nrows; j++) { + for (i = 0; i < dp->ncols; i++) { + if ((i + j) % 2) { /* right */ + /* W */ + k = (!i) ? dp->ncols - 1 : i - 1; + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } else { /* left */ + /* E */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } + /* N */ + k = i; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* S */ + k = i; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } + mj += dp->ncols; + } + if (dp->neighbors == 9 || dp->neighbors == 12) { + mj = 0; + for (j = 0; j < dp->nrows; j++) { + for (i = 0; i < dp->ncols; i++) { + /* NN */ + k = i; + if (!j) + l = dp->nrows - 2; + else if (!(j - 1)) + l = dp->nrows - 1; + else + l = j - 2; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SS */ + k = i; + if (j + 1 == dp->nrows) + l = 1; + else if (j + 2 == dp->nrows) + l = 0; + else + l = j + 2; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* NW */ + k = (!i) ? dp->ncols - 1 : i - 1; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* NE */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + l = (!j) ? dp->nrows - 1 : j - 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SW */ + k = (!i) ? dp->ncols - 1 : i - 1; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SE */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + l = (j + 1 == dp->nrows) ? 0 : j + 1; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } + mj += dp->ncols; + } + if (dp->neighbors == 12) { + mj = 0; + for (j = 0; j < dp->nrows; j++) { + for (i = 0; i < dp->ncols; i++) { + if ((i + j) % 2) { /* right */ + /* NNW */ + k = (!i) ? dp->ncols - 1 : i - 1; + if (!j) + l = dp->nrows - 2; + else if (!(j - 1)) + l = dp->nrows - 1; + else + l = j - 2; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SSW */ + k = (!i) ? dp->ncols - 1 : i - 1; + if (j + 1 == dp->nrows) + l = 1; + else if (j + 2 == dp->nrows) + l = 0; + else + l = j + 2; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* EE */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + /*l = j;*/ + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } else { /* left */ + /* NNE */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + if (!j) + l = dp->nrows - 2; + else if (!(j - 1)) + l = dp->nrows - 1; + else + l = j - 2; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* SSE */ + k = (i + 1 == dp->ncols) ? 0 : i + 1; + if (j + 1 == dp->nrows) + l = 1; + else if (j + 2 == dp->nrows) + l = 0; + else + l = j + 2; + ml = l * dp->ncols; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + /* WW */ + k = (!i) ? dp->ncols - 1 : i - 1; + /*l = j;*/ + ml = mj; + if (dp->oldcell[k + ml] == + (int) (dp->oldcell[i + mj] + 1) % dp->states) + dp->newcell[i + mj] = dp->oldcell[k + ml]; + } + } + mj += dp->ncols; + } + } + } + } + mj = 0; + for (j = 0; j < dp->nrows; j++) { + for (i = 0; i < dp->ncols; i++) + if (dp->oldcell[i + mj] != dp->newcell[i + mj]) { + dp->oldcell[i + mj] = dp->newcell[i + mj]; + if (!addtolist(mi, i, j, dp->oldcell[i + mj])) { + free_demon(MI_DISPLAY(mi), dp); + return; + } + } + mj += dp->ncols; + } + if (++dp->generation > MI_CYCLES(mi)) + init_demon(mi); + dp->state = 0; + } else { + if (dp->ncells[dp->state]) + if (!draw_state(mi, dp->state)) { + free_demon(MI_DISPLAY(mi), dp); + return; + } + dp->state++; + } + if (dp->redrawing) { + for (i = 0; i < REDRAWSTEP; i++) { + if (dp->oldcell[dp->redrawpos]) { + drawcell(mi, dp->redrawpos % dp->ncols, dp->redrawpos / dp->ncols, + dp->oldcell[dp->redrawpos]); + } + if (++(dp->redrawpos) >= dp->ncols * dp->nrows) { + dp->redrawing = 0; + break; + } + } + } +} + + +ENTRYPOINT void +reshape_demon(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_demon (mi); +} + + +ENTRYPOINT void +release_demon (ModeInfo * mi) +{ + if (demons != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_demon(MI_DISPLAY(mi), &demons[screen]); + (void) free((void *) demons); + demons = (demonstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_demon (ModeInfo * mi) +{ + demonstruct *dp; + + if (demons == NULL) + return; + dp = &demons[MI_SCREEN(mi)]; + + dp->redrawing = 1; + dp->redrawpos = 0; +} + +XSCREENSAVER_MODULE ("Demon", demon) + +#endif /* MODE_demon */ diff --git a/non-wgl/demon.vcproj b/non-wgl/demon.vcproj new file mode 100644 index 0000000..75a1b15 --- /dev/null +++ b/non-wgl/demon.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/discrete.c b/non-wgl/discrete.c new file mode 100644 index 0000000..c53bb3d --- /dev/null +++ b/non-wgl/discrete.c @@ -0,0 +1,480 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* discrete --- chaotic mappings */ + +#if 0 +static const char sccsid[] = "@(#)discrete.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1996 by Tim Auckland + * + * 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. + * + * "discrete" shows a number of fractals based on the "discrete map" + * type of dynamical systems. They include a different way of looking + * at the HOPALONG system, an inverse julia-set iteration, the "Standard + * Map" and the "Bird in a Thornbush" fractal. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 31-Jul-1997: Ported to xlockmore-4 + * 08-Aug-1996: Adapted from hop.c Copyright (c) 1991 by Patrick J. Naughton. + */ + +#define STANDALONE + +# define MODE_discrete +#define NOARGS +#define DELAY 20000 +#define COUNT 4096 +#define CYCLES 2500 +#define NCOLORS 100 +#define DEFAULTS "*delay: 20000 \n" \ + "*count: 4096 \n" \ + "*cycles: 2500 \n" \ + "*ncolors: 100 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define SMOOTH_COLORS +# define discrete_handle_event 0 + +#include "xlockmore.h" +#include "erase.h" + +char *background = "black"; +char *foreground = "white"; +char *eraseMode = NULL; +float eraseSeconds = 0; + +#if 0 + #ifdef STANDALONE + # include "xlockmore.h" /* in xscreensaver distribution */ + # include "erase.h" + #else /* STANDALONE */ + # include "xlock.h" /* in xlockmore distribution */ + #endif /* STANDALONE */ +#endif + +#ifdef MODE_discrete + +ENTRYPOINT ModeSpecOpt discrete_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct discrete_description = +{"discrete", "init_discrete", "draw_discrete", "release_discrete", + "refresh_discrete", "init_discrete", (char *) NULL, &discrete_opts, + 1000, 4096, 2500, 1, 64, 1.0, "", + "Shows various discrete maps", 0, NULL}; + +#endif + +enum ftypes { + SQRT, BIRDIE, STANDARD, TRIG, CUBIC, HENON, AILUJ, HSHOE, DELOG +}; + +/*#define TEST STANDARD */ + +#define BIASES 18 +static enum ftypes bias[BIASES] = +{ + STANDARD, STANDARD, STANDARD, STANDARD, + SQRT, SQRT, SQRT, SQRT, + BIRDIE, BIRDIE, BIRDIE, + AILUJ, AILUJ, AILUJ, + TRIG, TRIG, + CUBIC, + HENON, +}; + +typedef struct { + int maxx; + int maxy; /* max of the screen */ + double a; + double b; + double c; + double d; + double e; + double i; + double j; /* discrete parameters */ + double ic; + double jc; + double is; + double js; + int inc; + int pix; + enum ftypes op; + int count; + XPoint *pointBuffer; /* pointer for XDrawPoints */ + + int sqrt_sign, std_sign; + +#ifdef STANDALONE + eraser_state *eraser; +#endif + +} discretestruct; + +static discretestruct *discretes = (discretestruct *) NULL; + +ENTRYPOINT void +init_discrete (ModeInfo * mi) +{ + double range; + discretestruct *hp; + + if (discretes == NULL) { + if ((discretes = + (discretestruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (discretestruct))) == NULL) + return; + } + hp = &discretes[MI_SCREEN(mi)]; + + hp->maxx = MI_WIDTH(mi); + hp->maxy = MI_HEIGHT(mi); +#ifdef TEST + hp->op = TEST; +#else + hp->op = bias[LRAND() % BIASES]; +#endif + switch (hp->op) { + case HSHOE: + hp->ic = 0; + hp->jc = 0; + hp->is = hp->maxx / (4); + hp->js = hp->maxy / (4); + hp->a = 0.5; + hp->b = 0.5; + hp->c = 0.2; + hp->d = -1.25; + hp->e = 1; + hp->i = hp->j = 0.0; + break; + case DELOG: + hp->ic = 0.5; + hp->jc = 0.3; + hp->is = hp->maxx / 1.5; + hp->js = hp->maxy / 1.5; + hp->a = 2.176399; + hp->i = hp->j = 0.01; + break; + case HENON: + hp->jc = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.4; + hp->ic = 1.3 * (1 - (hp->jc * hp->jc) / (0.4 * 0.4)); + hp->is = hp->maxx; + hp->js = hp->maxy * 1.5; + hp->a = 1; + hp->b = 1.4; + hp->c = 0.3; + hp->i = hp->j = 0; + break; + case SQRT: + hp->ic = 0; + hp->jc = 0; + hp->is = 1; + hp->js = 1; + range = sqrt((double) hp->maxx * 2 * hp->maxx * 2 + + (double) hp->maxy * 2 * hp->maxy * 2) / + (10.0 + LRAND() % 10); + + hp->a = (LRAND() / MAXRAND) * range - range / 2.0; + hp->b = (LRAND() / MAXRAND) * range - range / 2.0; + hp->c = (LRAND() / MAXRAND) * range - range / 2.0; + if (!(LRAND() % 2)) + hp->c = 0.0; + hp->i = hp->j = 0.0; + break; + case STANDARD: + hp->ic = M_PI; + hp->jc = M_PI; + hp->is = hp->maxx / (M_PI * 2); + hp->js = hp->maxy / (M_PI * 2); + hp->a = 0; /* decay */ + hp->b = (LRAND() / MAXRAND) * 2.0; + hp->c = 0; + hp->i = M_PI; + hp->j = M_PI; + break; + case BIRDIE: + hp->ic = 0; + hp->jc = 0; + hp->is = hp->maxx / 2; + hp->js = hp->maxy / 2; + hp->a = 1.99 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.2; + hp->b = 0; + hp->c = 0.8 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.1; + hp->i = hp->j = 0; + break; + case TRIG: + hp->a = 5; + hp->b = 0.5 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.3; + hp->ic = hp->a; + hp->jc = 0; + hp->is = hp->maxx / (hp->b * 20); + hp->js = hp->maxy / (hp->b * 20); + hp->i = hp->j = 0; + break; + case CUBIC: + hp->a = 2.77; + hp->b = 0.1 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.1; + hp->ic = 0; + hp->jc = 0; + hp->is = hp->maxx / 4; + hp->js = hp->maxy / 4; + hp->i = hp->j = 0.1; + break; + case AILUJ: + { + int i; + double x, y, xn, yn; + + hp->ic = 0; + hp->jc = 0; + hp->is = hp->maxx / 4; + hp->js = hp->maxx / 4; + do { + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 1.5 - 0.5; + hp->b = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 1.5; + x = y = 0; +#define MAXITER 10 + for (i = 0; i < MAXITER && x * x + y * y < 13; i++) { /* 'Brot calc */ + xn = x * x - y * y + hp->a; + yn = 2 * x * y + hp->b; + x = xn; + y = yn; + } + } while (i < MAXITER); /* wait for a connected set */ + hp->i = hp->j = 0.1; + break; + } + } + hp->pix = 0; + hp->inc = 0; + + if (hp->pointBuffer == NULL) { + hp->pointBuffer = (XPoint *) malloc(sizeof (XPoint) * MI_COUNT(mi)); + /* if fails will check later */ + } + +#ifndef STANDALONE + /* Clear the background. */ + MI_CLEARWINDOW(mi); +#endif + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + hp->count = 0; + hp->sqrt_sign = 1; + hp->std_sign = 1; +} + + +static void +draw_discrete_1 (ModeInfo * mi) +{ + Display *dsp = MI_DISPLAY(mi); + Window win = MI_WINDOW(mi); + double oldj, oldi; + int count = MI_COUNT(mi); + int cycles = MI_CYCLES(mi); + int k; + XPoint *xp; + GC gc = MI_GC(mi); + discretestruct *hp; + + if (discretes == NULL) + return; + hp = &discretes[MI_SCREEN(mi)]; + if (hp->pointBuffer == NULL) + return; + + k = count; + xp = hp->pointBuffer; + + hp->inc++; + + MI_IS_DRAWN(mi) = True; + + if (MI_NPIXELS(mi) > 2) { + XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix)); + if (++hp->pix >= MI_NPIXELS(mi)) + hp->pix = 0; + } + while (k--) { + oldj = hp->j; + oldi = hp->i; + switch (hp->op) { + case HSHOE: + { + int i; + +#if 0 + if (!k) { + XSetForeground(dsp, gc, MI_BLACK_PIXEL(mi)); + XFillRectangle(dsp, win, gc, 0, 0, hp->maxx, hp->maxy); + XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix)); + } else +#endif +#define HD +#ifdef HD + if (k < count / 4) { + hp->i = ((double) k / count) * 8 - 1; + hp->j = 1; + } else if (k < count / 2) { + hp->i = 1; + hp->j = 3 - ((double) k / count) * 8; + } else if (k < 3 * count / 4) { + hp->i = 5 - ((double) k / count) * 8; + hp->j = -1; + } else { + hp->i = -1; + hp->j = ((double) k / count) * 8 - 7; + } + for (i = 1; i < (hp->inc % 15); i++) { + oldj = hp->j; + oldi = hp->i; +#endif + hp->i = (hp->a * oldi + hp->b) * oldj; + hp->j = (hp->e - hp->d + hp->c * oldi) * oldj * oldj - hp->c * oldi + hp->d; +#ifdef HD + } +#endif + break; + } + case DELOG: + hp->j = oldi; + hp->i = hp->a * oldi * (1 - oldj); + break; + case HENON: + hp->i = oldj + hp->a - hp->b * oldi * oldi; + hp->j = hp->c * oldi; + break; + case SQRT: + if (k) { + hp->j = hp->a + hp->i; + hp->i = -oldj + (hp->i < 0 + ? sqrt(fabs(hp->b * (hp->i - hp->c))) + : -sqrt(fabs(hp->b * (hp->i - hp->c)))); + } else { + hp->i = (hp->sqrt_sign ? 1 : -1) * hp->inc * hp->maxx / cycles / 2; + hp->j = hp->a + hp->i; + hp->sqrt_sign = !hp->sqrt_sign; + } + break; + case STANDARD: + if (k) { + hp->j = (1 - hp->a) * oldj + hp->b * sin(oldi) + hp->a * hp->c; + hp->j = fmod(hp->j + 2 * M_PI, 2 * M_PI); + hp->i = oldi + hp->j; + hp->i = fmod(hp->i + 2 * M_PI, 2 * M_PI); + } else { + hp->j = M_PI + fmod((hp->std_sign ? 1 : -1) * hp->inc * 2 * M_PI / (cycles - 0.5), M_PI); + hp->i = M_PI; + hp->std_sign = !hp->std_sign; + } + break; + case BIRDIE: + hp->j = oldi; + hp->i = (1 - hp->c) * cos(M_PI * hp->a * oldj) + hp->c * hp->b; + hp->b = oldj; + break; + case TRIG: + { + double r2 = oldi * oldi + oldj * oldj; + + hp->i = hp->a + hp->b * (oldi * cos(r2) - oldj * sin(r2)); + hp->j = hp->b * (oldj * cos(r2) + oldi * sin(r2)); + } + break; + case CUBIC: + hp->i = oldj; + hp->j = hp->a * oldj - oldj * oldj * oldj - hp->b * oldi; + break; + case AILUJ: + hp->i = ((LRAND() < MAXRAND / 2) ? -1 : 1) * + sqrt(((oldi - hp->a) + + sqrt((oldi - hp->a) * (oldi - hp->a) + (oldj - hp->b) * (oldj - hp->b))) / 2); + if (hp->i < 0.00000001 && hp->i > -0.00000001) + hp->i = (hp->i > 0.0) ? 0.00000001 : -0.00000001; + hp->j = (oldj - hp->b) / (2 * hp->i); + break; + } + xp->x = hp->maxx / 2 + (int) ((hp->i - hp->ic) * hp->is); + xp->y = hp->maxy / 2 - (int) ((hp->j - hp->jc) * hp->js); + xp++; + } + XDrawPoints(dsp, win, gc, hp->pointBuffer, count, CoordModeOrigin); +} + +ENTRYPOINT void +draw_discrete (ModeInfo * mi) +{ + discretestruct *hp = &discretes[MI_SCREEN(mi)]; + int cycles = MI_CYCLES(mi); + int i; + + if (hp->eraser) { + hp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), hp->eraser); + return; + } + + for (i = 0; i < 10; i++) { + draw_discrete_1 (mi); + hp->count++; + } + + if (hp->count > cycles) { + hp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), hp->eraser); + init_discrete(mi); + } +} + + +ENTRYPOINT void +reshape_discrete(ModeInfo * mi, int width, int height) +{ + discretestruct *hp = &discretes[MI_SCREEN(mi)]; + hp->maxx = width; + hp->maxy = height; + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); +} + +ENTRYPOINT void +release_discrete(ModeInfo * mi) +{ + if (discretes != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + discretestruct *hp = &discretes[screen]; + + if (hp->pointBuffer != NULL) { + (void) free((void *) hp->pointBuffer); + /* hp->pointBuffer = NULL; */ + } + } + (void) free((void *) discretes); + discretes = (discretestruct *) NULL; + } +} + +ENTRYPOINT void +refresh_discrete(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Discrete", discrete) + +#endif /* MODE_discrete */ diff --git a/non-wgl/discrete.vcproj b/non-wgl/discrete.vcproj new file mode 100644 index 0000000..0a6181b --- /dev/null +++ b/non-wgl/discrete.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/drift.c b/non-wgl/drift.c new file mode 100644 index 0000000..a58a648 --- /dev/null +++ b/non-wgl/drift.c @@ -0,0 +1,717 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* drift --- drifting recursive fractal cosmic flames */ + +#if 0 +static const char sccsid[] = "@(#)drift.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1991 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. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 10-May-1997: Jamie Zawinski compatible with xscreensaver + * 01-Jan-1997: Moved new flame to drift. Compile time options now run time. + * 01-Jun-1995: Updated by Scott Draves. + * 27-Jun-1991: vary number of functions used. + * 24-Jun-1991: fixed portability problem with integer mod (%). + * 06-Jun-1991: Written, received from Scott Draves + */ + +#define STANDALONE +# define MODE_drift +#define DELAY 10000 +#define COUNT 30 +#define NCOLORS 200 +# define DEFAULTS "*delay: 10000 \n" \ + "*count: 30 \n" \ + "*ncolors: 200 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define SMOOTH_COLORS +# define drift_handle_event 0 + +#if 0 + #ifdef STANDALONE + # include "xlockmore.h" /* in xscreensaver distribution */ + # include "erase.h" + #else /* STANDALONE */ + # define ENTRYPOINT /**/ + # include "xlock.h" /* in xlockmore distribution */ + #endif /* STANDALONE */ +#endif + +#include "xlockmore.h" +#include "erase.h" + +char *background = "black"; +char *foreground = "white"; +char *eraseMode = NULL; +float eraseSeconds = 0; + +#ifdef MODE_drift + +#define DEF_GROW "False" /* Grow fractals instead of animating one at a time, + would then be like flame */ +#define DEF_LISS "False" /* if this is defined then instead of a point + bouncing around in a high dimensional sphere, we + use lissojous figures. Only makes sense if + grow is false. */ + +static Bool grow = False; +static Bool liss = False; + +static XrmOptionDescRec opts[] = +{ + {"-grow", ".drift.grow", XrmoptionNoArg, "on"}, + {"+grow", ".drift.grow", XrmoptionNoArg, "off"}, + {"-liss", ".drift.trail", XrmoptionNoArg, "on"}, + {"+liss", ".drift.trail", XrmoptionNoArg, "off"} +}; +static argtype vars[] = +{ + {&grow, "grow", "Grow", DEF_GROW, t_Bool}, + {&liss, "trail", "Trail", DEF_LISS, t_Bool} +}; +static OptionStruct desc[] = +{ + {"-/+grow", "turn on/off growing fractals, else they are animated"}, + {"-/+liss", "turn on/off using lissojous figures to get points"} +}; + +ENTRYPOINT ModeSpecOpt drift_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct drift_description = +{"drift", "init_drift", "draw_drift", "release_drift", + "refresh_drift", "init_drift", (char *) NULL, &drift_opts, + 10000, 30, 1, 1, 64, 1.0, "", + "Shows cosmic drifting flame fractals", 0, NULL}; + +#endif + +#define MAXBATCH1 200 /* mono */ +#define MAXBATCH2 20 /* color */ +#define FUSE 10 /* discard this many initial iterations */ +#define NMAJORVARS 7 +#define MAXLEV 10 + +typedef struct { + /* shape of current flame */ + int nxforms; + double f[2][3][MAXLEV]; /* a bunch of non-homogeneous xforms */ + int variation[10]; /* for each xform */ + + /* Animation */ + double df[2][3][MAXLEV]; + + /* high-level control */ + int mode; /* 0->slow/single 1->fast/many */ + int nfractals; /* draw this many fractals */ + int major_variation; + int fractal_len; /* pts/fractal */ + int color; + int rainbow; /* more than one color per fractal + 1-> computed by adding dimension to fractal */ + + int width, height; /* of window */ + int timer; + + /* draw info about current flame */ + int fuse; /* iterate this many before drawing */ + int total_points; /* draw this many pts before fractal ends */ + int npoints; /* how many we've computed but not drawn */ + XPoint pts[MAXBATCH1]; /* here they are */ + unsigned long pixcol; + /* when drawing in color, we have a buffer per color */ + int *ncpoints; + XPoint *cpts; + + double x, y, c; + int liss_time; + Bool grow, liss; + + short lasthalf; + long saved_random_bits; + int nbits; + +#ifdef STANDALONE + int erase_countdown; + eraser_state *eraser; +#endif +} driftstruct; + +static driftstruct *drifts = (driftstruct *) NULL; + +static short +halfrandom(driftstruct * dp, int mv) +{ + unsigned long r; + + if (dp->lasthalf) { + r = dp->lasthalf; + dp->lasthalf = 0; + } else { + r = LRAND(); + dp->lasthalf = (short) (r >> 16); + } + r = r % mv; + return r; +} + +static int +frandom(driftstruct * dp, int n) +{ + int result; + + if (3 > dp->nbits) { + dp->saved_random_bits = LRAND(); + dp->nbits = 31; + } + switch (n) { + case 2: + result = (int) (dp->saved_random_bits & 1); + dp->saved_random_bits >>= 1; + dp->nbits -= 1; + return result; + + case 3: + result = (int) (dp->saved_random_bits & 3); + dp->saved_random_bits >>= 2; + dp->nbits -= 2; + if (3 == result) + return frandom(dp, 3); + return result; + + case 4: + result = (int) (dp->saved_random_bits & 3); + dp->saved_random_bits >>= 2; + dp->nbits -= 2; + return result; + + case 5: + result = (int) (dp->saved_random_bits & 7); + dp->saved_random_bits >>= 3; + dp->nbits -= 3; + if (4 < result) + return frandom(dp, 5); + return result; + default: + (void) fprintf(stderr, "bad arg to frandom\n"); + } + return 0; +} + +#define DISTRIB_A (halfrandom(dp, 7000) + 9000) +#define DISTRIB_B ((frandom(dp, 3) + 1) * (frandom(dp, 3) + 1) * 120000) +#define LEN(x) (sizeof(x)/sizeof((x)[0])) + +static void +initmode(ModeInfo * mi, int mode) +{ + driftstruct *dp = &drifts[MI_SCREEN(mi)]; + +#define VARIATION_LEN 14 + + dp->mode = mode; + + dp->major_variation = halfrandom(dp, VARIATION_LEN); + /* 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 6 */ + dp->major_variation = ((dp->major_variation >= VARIATION_LEN >> 1) && + (dp->major_variation < VARIATION_LEN - 1)) ? + (dp->major_variation + 1) >> 1 : dp->major_variation >> 1; + + if (dp->grow) { + dp->rainbow = 0; + if (mode) { + if (!dp->color || halfrandom(dp, 8)) { + dp->nfractals = halfrandom(dp, 30) + 5; + dp->fractal_len = DISTRIB_A; + } else { + dp->nfractals = halfrandom(dp, 5) + 5; + dp->fractal_len = DISTRIB_B; + } + } else { + dp->rainbow = dp->color; + dp->nfractals = 1; + dp->fractal_len = DISTRIB_B; + } + } else { + dp->nfractals = 1; + dp->rainbow = dp->color; + dp->fractal_len = 2000000; + } + dp->fractal_len = (dp->fractal_len * MI_COUNT(mi)) / 20; + +#ifndef STANDALONE + MI_CLEARWINDOW(mi); +#endif +} + +static void +pick_df_coefs(ModeInfo * mi) +{ + driftstruct *dp = &drifts[MI_SCREEN(mi)]; + int i, j, k; + double r; + + for (i = 0; i < dp->nxforms; i++) { + + r = 1e-6; + for (j = 0; j < 2; j++) + for (k = 0; k < 3; k++) { + dp->df[j][k][i] = ((double) halfrandom(dp, 1000) / 500.0 - 1.0); + r += dp->df[j][k][i] * dp->df[j][k][i]; + } + r = (3 + halfrandom(dp, 5)) * 0.01 / sqrt(r); + for (j = 0; j < 2; j++) + for (k = 0; k < 3; k++) + dp->df[j][k][i] *= r; + } +} + +static void +free_drift(driftstruct *dp) +{ + if (dp->ncpoints != NULL) { + (void) free((void *) dp->ncpoints); + dp->ncpoints = (int *) NULL; + } + if (dp->cpts != NULL) { + (void) free((void *) dp->cpts); + dp->cpts = (XPoint *) NULL; + } +} + +static void +initfractal(ModeInfo * mi) +{ + driftstruct *dp = &drifts[MI_SCREEN(mi)]; + int i, j, k; + +#define XFORM_LEN 9 + + dp->fuse = FUSE; + dp->total_points = 0; + + if (!dp->ncpoints) { + if ((dp->ncpoints = (int *) malloc(sizeof (int) * MI_NCOLORS(mi))) == + NULL) { + free_drift(dp); + return; + } + } + if (!dp->cpts) { + if ((dp->cpts = (XPoint *) malloc(MAXBATCH2 * sizeof (XPoint) * + MI_NCOLORS(mi))) == NULL) { + free_drift(dp); + return; + } + } + + if (dp->rainbow) + for (i = 0; i < MI_NPIXELS(mi); i++) + dp->ncpoints[i] = 0; + else + dp->npoints = 0; + dp->nxforms = halfrandom(dp, XFORM_LEN); + /* 2, 2, 2, 3, 3, 3, 4, 4, 5 */ + dp->nxforms = (dp->nxforms >= XFORM_LEN - 1) + dp->nxforms / 3 + 2; + + dp->c = dp->x = dp->y = 0.0; + if (dp->liss && !halfrandom(dp, 10)) { + dp->liss_time = 0; + } + if (!dp->grow) + pick_df_coefs(mi); + for (i = 0; i < dp->nxforms; i++) { + if (NMAJORVARS == dp->major_variation) + dp->variation[i] = halfrandom(dp, NMAJORVARS); + else + dp->variation[i] = dp->major_variation; + for (j = 0; j < 2; j++) + for (k = 0; k < 3; k++) { + if (dp->liss) + dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]); + else + dp->f[j][k][i] = ((double) halfrandom(dp, 1000) / 500.0 - 1.0); + } + } + if (dp->color) + dp->pixcol = MI_PIXEL(mi, halfrandom(dp, MI_NPIXELS(mi))); + else + dp->pixcol = MI_WHITE_PIXEL(mi); + +} + + +ENTRYPOINT void +init_drift(ModeInfo * mi) +{ + driftstruct *dp; + + if (drifts == NULL) { + if ((drifts = (driftstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (driftstruct))) == NULL) + return; + } + dp = &drifts[MI_SCREEN(mi)]; + + dp->width = MI_WIDTH(mi); + dp->height = MI_HEIGHT(mi); + dp->color = MI_NPIXELS(mi) > 2; + + if (MI_IS_FULLRANDOM(mi)) { + if (NRAND(3) == 0) + dp->grow = True; + else { + dp->grow = False; + dp->liss = (Bool) (LRAND() & 1); + } + } else { + dp->grow = grow; + if (dp->grow) + dp->liss = False; + else + dp->liss = liss; + } + initmode(mi, 1); + initfractal(mi); +} + +static void +iter(driftstruct * dp) +{ + int i = frandom(dp, dp->nxforms); + double nx, ny, nc; + + + if (i) + nc = (dp->c + 1.0) / 2.0; + else + nc = dp->c / 2.0; + + nx = dp->f[0][0][i] * dp->x + dp->f[0][1][i] * dp->y + dp->f[0][2][i]; + ny = dp->f[1][0][i] * dp->x + dp->f[1][1][i] * dp->y + dp->f[1][2][i]; + + + switch (dp->variation[i]) { + case 1: + /* sinusoidal */ + nx = sin(nx); + ny = sin(ny); + break; + case 2: + { + /* complex */ + double r2 = nx * nx + ny * ny + 1e-6; + + nx = nx / r2; + ny = ny / r2; + break; + } + case 3: + /* bent */ + if (nx < 0.0) + nx = nx * 2.0; + if (ny < 0.0) + ny = ny / 2.0; + break; + case 4: + { + /* swirl */ + + double r = (nx * nx + ny * ny); /* times k here is fun */ + double c1 = sin(r); + double c2 = cos(r); + double t = nx; + + if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4) + ny = 1e4; + else + ny = c2 * t + c1 * ny; + nx = c1 * nx - c2 * ny; + break; + } + case 5: + { + /* horseshoe */ + double r, c1, c2, t; + + /* Avoid atan2: DOMAIN error message */ + if (nx == 0.0 && ny == 0.0) + r = 0.0; + else + r = atan2(nx, ny); /* times k here is fun */ + c1 = sin(r); + c2 = cos(r); + t = nx; + + nx = c1 * nx - c2 * ny; + ny = c2 * t + c1 * ny; + break; + } + case 6: + { + /* drape */ + double t; + + /* Avoid atan2: DOMAIN error message */ + if (nx == 0.0 && ny == 0.0) + t = 0.0; + else + t = atan2(nx, ny) / M_PI; + + if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4) + ny = 1e4; + else + ny = sqrt(nx * nx + ny * ny) - 1.0; + nx = t; + break; + } + } + +#if 0 + /* here are some others */ + { + /* broken */ + if (nx > 1.0) + nx = nx - 1.0; + if (nx < -1.0) + nx = nx + 1.0; + if (ny > 1.0) + ny = ny - 1.0; + if (ny < -1.0) + ny = ny + 1.0; + break; + } + { + /* complex sine */ + double u = nx, v = ny; + double ev = exp(v); + double emv = exp(-v); + + nx = (ev + emv) * sin(u) / 2.0; + ny = (ev - emv) * cos(u) / 2.0; + } + { + + /* polynomial */ + if (nx < 0) + nx = -nx * nx; + else + nx = nx * nx; + + if (ny < 0) + ny = -ny * ny; + else + ny = ny * ny; + } + { + /* spherical */ + double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6); + + nx = nx / r; + ny = ny / r; + } + { + nx = atan(nx) / M_PI_2 + ny = atan(ny) / M_PI_2 + } +#endif + + /* how to check nan too? some machines don't have finite(). + don't need to check ny, it'll propogate */ + if (nx > 1e4 || nx < -1e4) { + nx = halfrandom(dp, 1000) / 500.0 - 1.0; + ny = halfrandom(dp, 1000) / 500.0 - 1.0; + dp->fuse = FUSE; + } + dp->x = nx; + dp->y = ny; + dp->c = nc; + +} + +static void +draw(ModeInfo * mi, driftstruct * dp, Drawable d) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + double x = dp->x; + double y = dp->y; + int fixed_x, fixed_y, npix, c, n; + + if (dp->fuse) { + dp->fuse--; + return; + } + if (!(x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0)) + return; + + fixed_x = (int) ((dp->width / 2) * (x + 1.0)); + fixed_y = (int) ((dp->height / 2) * (y + 1.0)); + + if (!dp->rainbow) { + + dp->pts[dp->npoints].x = fixed_x; + dp->pts[dp->npoints].y = fixed_y; + dp->npoints++; + if (dp->npoints == MAXBATCH1) { + XSetForeground(display, gc, dp->pixcol); + XDrawPoints(display, d, gc, dp->pts, dp->npoints, CoordModeOrigin); + dp->npoints = 0; + } + } else { + + npix = MI_NPIXELS(mi); + c = (int) (dp->c * npix); + + if (c < 0) + c = 0; + if (c >= npix) + c = npix - 1; + n = dp->ncpoints[c]; + dp->cpts[c * MAXBATCH2 + n].x = fixed_x; + dp->cpts[c * MAXBATCH2 + n].y = fixed_y; + if (++dp->ncpoints[c] == MAXBATCH2) { + XSetForeground(display, gc, MI_PIXEL(mi, c)); + XDrawPoints(display, d, gc, &(dp->cpts[c * MAXBATCH2]), + dp->ncpoints[c], CoordModeOrigin); + dp->ncpoints[c] = 0; + } + } +} + +static void +draw_flush(ModeInfo * mi, driftstruct * dp, Drawable d) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + + if (dp->rainbow) { + int npix = MI_NPIXELS(mi); + int i; + + for (i = 0; i < npix; i++) { + if (dp->ncpoints[i]) { + XSetForeground(display, gc, MI_PIXEL(mi, i)); + XDrawPoints(display, d, gc, &(dp->cpts[i * MAXBATCH2]), + dp->ncpoints[i], CoordModeOrigin); + dp->ncpoints[i] = 0; + } + } + } else { + if (dp->npoints) + XSetForeground(display, gc, dp->pixcol); + XDrawPoints(display, d, gc, dp->pts, + dp->npoints, CoordModeOrigin); + dp->npoints = 0; + } +} + + +ENTRYPOINT void +draw_drift(ModeInfo * mi) +{ + Window window = MI_WINDOW(mi); + driftstruct *dp; + + if (drifts == NULL) + return; + dp = &drifts[MI_SCREEN(mi)]; + if (dp->ncpoints == NULL) + return; + + if (dp->erase_countdown) { + if (!--dp->erase_countdown) { + dp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), dp->eraser); + } + return; + } + if (dp->eraser) { + dp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), dp->eraser); + return; + } + + MI_IS_DRAWN(mi) = True; + dp->timer = 3000; + while (dp->timer) { + iter(dp); + draw(mi, dp, window); + if (dp->total_points++ > dp->fractal_len) { + draw_flush(mi, dp, window); + if (0 == --dp->nfractals) { +#ifdef STANDALONE + dp->erase_countdown = 4 * 1000000 / MI_PAUSE(mi); +#endif /* STANDALONE */ + initmode(mi, frandom(dp, 2)); + } + initfractal(mi); + } + dp->timer--; + } + if (!dp->grow) { + int i, j, k; + + draw_flush(mi, dp, window); + if (dp->liss) + dp->liss_time++; + for (i = 0; i < dp->nxforms; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 3; k++) { + if (dp->liss) + dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]); + else { + double t = dp->f[j][k][i] += dp->df[j][k][i]; + + if (t < -1.0 || 1.0 < t) + dp->df[j][k][i] *= -1.0; + } + } + } +} + +ENTRYPOINT void +release_drift(ModeInfo * mi) +{ + if (drifts != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_drift(&drifts[screen]); + (void) free((void *) drifts); + drifts = (driftstruct *) NULL; + } +} + +ENTRYPOINT void +reshape_drift(ModeInfo * mi, int width, int height) +{ + MI_CLEARWINDOW(mi); + init_drift (mi); +} + +ENTRYPOINT void +refresh_drift(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Drift", drift) + +#endif /* MODE_drift */ diff --git a/non-wgl/drift.vcproj b/non-wgl/drift.vcproj new file mode 100644 index 0000000..7ac2a25 --- /dev/null +++ b/non-wgl/drift.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/epicycle.c b/non-wgl/epicycle.c new file mode 100644 index 0000000..a53d242 --- /dev/null +++ b/non-wgl/epicycle.c @@ -0,0 +1,851 @@ +/* epicycle --- The motion of a body with epicycles, as in the pre-Copernican + * cosmologies. + * + * Copyright (c) 1998 James Youngman + * + * 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. + */ + +/* Standard C headers; screenhack.h assumes that these have already + * been included if required -- for example, it defines M_PI if not + * already defined. + */ +#include "screenhack.h" +#include +#include + + +#include "erase.h" + +/* MIT-SHM headers omitted; this screenhack doesn't use it */ + + + +/*********************************************************/ +/******************** MAGIC CONSTANTS ********************/ +/*********************************************************/ +#define MIN_RADIUS (5) /* smallest allowable circle radius */ +#define FILL_PROPORTION (0.9) /* proportion of screen to fill by scaling. */ +/*********************************************************/ +/***************** END OF MAGIC CONSTANTS ****************/ +/*********************************************************/ + + + +#define FULLCIRCLE (2.0 * M_PI) /* radians in a circle. */ + +float eraseSeconds = 0; +char *eraseMode = NULL; + +char *background = "black"; +char *foreground = "white"; +int colors = 100; +char *color0 = "red"; +int delay = 20000; +int holdtime = 2; +int lineWidth = 4; +int minCircles = 2; +int maxCircles = 10; +float minSpeed = 0.003; +float maxSpeed = 0.005; +int harmonics = 8; +float timestep = 1.0; +float timestepCoarseFactor = 1.0; +float divisorPoisson = 0.4; +float sizeFactorMin = 1.05; +float sizeFactorMax = 2.05; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&colors, "colors", NULL, "100", t_Int}, + {&color0, "color0", NULL, "red", t_String}, + {&delay, "delay", NULL, "20000", t_Int}, + {&holdtime, "holdtime", NULL, "2", t_Int}, + {&lineWidth, "lineWidth", NULL, "4", t_Int}, + {&minCircles, "minCircles", NULL, "2", t_Int}, + {&maxCircles, "maxCircles", NULL, "10", t_Int}, + {&minSpeed, "minSpeed", NULL, "0.003", t_Float}, + {&maxSpeed, "maxSpeed", NULL, "0.005", t_Float}, + {&harmonics, "harmonics", NULL, "8", t_Int}, + {×tep, "timestep", NULL, "1.0", t_Float}, + {×tepCoarseFactor, "timestepCoarseFactor", NULL, "1.0", t_Float}, + {&divisorPoisson, "divisorPoisson", NULL, "0.4", t_Float}, + {&sizeFactorMin, "sizeFactorMin", NULL, "1.05", t_Float}, + {&sizeFactorMax, "sizeFactorMax", NULL, "2.05", t_Float}, +}; + + +/* Some of these resource values here are hand-tuned to give a + * pleasing variety of interesting shapes. These are not the only + * good settings, but you may find you need to change some as a group + * to get pleasing figures. + */ +static const char *epicycle_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*colors: 100", + "*color0: red", + "*delay: 20000", + "*holdtime: 2", + "*lineWidth: 4", + "*minCircles: 2", + "*maxCircles: 10", + "*minSpeed: 0.003", + "*maxSpeed: 0.005", + "*harmonics: 8", + "*timestep: 1.0", + "*timestepCoarseFactor: 1.0", /* no option for this resource. */ + "*divisorPoisson: 0.4", + "*sizeFactorMin: 1.05", + "*sizeFactorMax: 2.05", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +/* options passed to this program */ +static XrmOptionDescRec epicycle_options [] = { + { "-color0", ".color0", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-colours", ".colors", XrmoptionSepArg, 0 }, + { "-foreground", ".foreground", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-holdtime", ".holdtime", XrmoptionSepArg, 0 }, + { "-linewidth", ".lineWidth", XrmoptionSepArg, 0 }, + { "-min_circles", ".minCircles", XrmoptionSepArg, 0 }, + { "-max_circles", ".maxCircles", XrmoptionSepArg, 0 }, + { "-min_speed", ".minSpeed", XrmoptionSepArg, 0 }, + { "-max_speed", ".maxSpeed", XrmoptionSepArg, 0 }, + { "-harmonics", ".harmonics", XrmoptionSepArg, 0 }, + { "-timestep", ".timestep", XrmoptionSepArg, 0 }, + { "-divisor_poisson",".divisorPoisson",XrmoptionSepArg, 0 }, + { "-size_factor_min", ".sizeFactorMin", XrmoptionSepArg, 0 }, + { "-size_factor_max", ".sizeFactorMax", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +/* Each circle is centred on a point on the rim of another circle. + */ +struct tagCircle +{ + long radius; /* in pixels */ + double w; /* position (radians ccw from x-axis) */ + double initial_w; /* starting position */ + double wdot; /* rotation rate (change in w per iteration) */ + int divisor; + + struct tagCircle *pchild; +}; +typedef struct tagCircle Circle; + + +struct tagBody /* a body that moves on a system of circles. */ +{ + int x_origin, y_origin; + int x, y; + int old_x, old_y; + int current_color; /* pixel index into colors[] */ + Circle *epicycles; /* system of circles on which it moves. */ + struct tagBody *next; /* next in list. */ +}; +typedef struct tagBody Body; + + +struct state { + Display *dpy; + Window window; + GC color0; + int width, height; + int x_offset, y_offset; + int unit_pixels; + unsigned long bg; + Colormap cmap; + int restart; + double wdot_max; + XColor *colors; + int ncolors; + int color_shift_pos; /* how far we are towards that. */ + double colour_cycle_rate; + int harmonics; + double divisorPoisson; + double sizeFactorMin; + double sizeFactorMax; + int minCircles; + int maxCircles; + + Bool done; + + long L; + double T, timestep, circle, timestep_coarse; + int delay; + int uncleared; + int holdtime; + int xmax, xmin, ymax, ymin; + Body *pb0; + double xtime; + eraser_state *eraser; +}; + + + +/* Determine the GCD of two numbers using Euclid's method. The other + * possible algorighm is Stein's method, but it's probably only going + * to be much faster on machines with no divide instruction, like the + * ARM and the Z80. The former is very fast anyway and the latter + * probably won't run X clients; in any case, this calculation is not + * the bulk of the computational expense of the program. I originally + * tried using Stein's method, but I wanted to remove the gotos. Not + * wanting to introduce possible bugs, I plumped for Euclid's method + * instead. Lastly, Euclid's algorithm is preferred to the + * generalisation for N inputs. + * + * See Knuth, section 4.5.2. + */ +static int +gcd(int u, int v) /* Euclid's Method */ +{ + /* If either operand of % is negative, the sign of the result is + * implementation-defined. See section 6.3.5 "Multiplicative + * Operators" of the ANSI C Standard (page 46 [LEFT HAND PAGE!] of + * "Annotated C Standard", Osborne, ISBN 0-07-881952-0). + */ + if (u < 0) u = -u; + if (v < 0) v = -v; + + while (0 != v) + { + int r; + r = u % v; + u = v; + v = r; + } + return u; +} + +/* Determine the Lowest Common Multiple of two integers, using + * Euclid's Proposition 34, as explained in Knuth's The Art of + * Computer Programming, Vol 2, section 4.5.2. + */ +static int +lcm(int u, int v) +{ + return u / gcd(u,v) * v; +} + +static long +random_radius(struct state *st, double scale) +{ + long r; + + r = frand(scale) * st->unit_pixels/2; /* for frand() see utils/yarandom.h */ + if (r < MIN_RADIUS) + r = MIN_RADIUS; + return r; +} + + +static long +random_divisor(struct state *st) +{ + int divisor = 1; + int sign; + + while (frand(1.0) < st->divisorPoisson && divisor <= st->harmonics) + { + ++divisor; + } + sign = (frand(1.0) < 0.5) ? +1 : -1; + return sign * divisor; +} + + +/* Construct a circle or die. + */ +static Circle * +new_circle(struct state *st, double scale) +{ + Circle *p = malloc(sizeof(Circle)); + + p->radius = random_radius(st, scale); + p->w = p->initial_w = 0.0; + p->divisor = random_divisor(st); + p->wdot = st->wdot_max / p->divisor; + p->pchild = NULL; + + return p; +} + +static void delete_circle(Circle *p) +{ + free(p); +} + +static void +delete_circle_chain(Circle *p) +{ + while (p) + { + Circle *q = p->pchild; + delete_circle(p); + p = q; + } +} + +static Circle * +new_circle_chain(struct state *st) +{ + Circle *head; + double scale = 1.0, factor; + int n; + + /* Parent circles are larger than their children by a factor of at + * least FACTOR_MIN and at most FACTOR_MAX. + */ + factor = st->sizeFactorMin + frand(st->sizeFactorMax - st->sizeFactorMin); + + /* There are between minCircles and maxCircles in each figure. + */ + if (st->maxCircles == st->minCircles) + n = st->minCircles; /* Avoid division by zero. */ + else + n = st->minCircles + random() % (st->maxCircles - st->minCircles); + + head = NULL; + while (n--) + { + Circle *p = new_circle(st, scale); + p->pchild = head; + head = p; + + scale /= factor; + } + return head; +} + +static void +assign_random_common_w(Circle *p) +{ + double w_common = frand(FULLCIRCLE); /* anywhere on the circle */ + while (p) + { + p->initial_w = w_common; + p = p->pchild; + } +} + +static Body * +new_body(struct state *st) +{ + Body *p = malloc(sizeof(Body)); + if (!p) abort(); + p->epicycles = new_circle_chain(st); + p->current_color = 0; /* ?? start them all on different colors? */ + p->next = NULL; + p->x = p->y = 0; + p->old_x = p->old_y = 0; + p->x_origin = p->y_origin = 0; + + /* Start all the epicycles at the same w value to make it easier to + * figure out at what T value the cycle is closed. We don't just fix + * the initial W value because that makes all the patterns tend to + * be symmetrical about the X axis. + */ + assign_random_common_w(p->epicycles); + return p; +} + +static void +delete_body(Body *p) +{ + delete_circle_chain(p->epicycles); + free(p); +} + + +static void +draw_body(struct state *st, Body *pb, GC gc) +{ + XDrawLine(st->dpy, st->window, gc, pb->old_x, pb->old_y, pb->x, pb->y); +} + +static long +compute_divisor_lcm(Circle *p) +{ + long l = 1; + + while (p) + { + l = lcm(l, p->divisor); + p = p->pchild; + } + return l; +} + + +/* move_body() + * + * Calculate the position for the body at time T. We work in double + * rather than int to avoid the cumulative errors that would be caused + * by the rounding implicit in an assignment to int. + */ +static void +move_body(Body *pb, double t) +{ + Circle *p; + double x, y; + + pb->old_x = pb->x; + pb->old_y = pb->y; + + x = pb->x_origin; + y = pb->y_origin; + + for (p=pb->epicycles; NULL != p; p=p->pchild) + { + /* angular pos = initial_pos + time * angular speed */ + /* but this is an angular position, so modulo FULLCIRCLE. */ + p->w = fmod(p->initial_w + (t * p->wdot), FULLCIRCLE); + + x += (p->radius * cos(p->w)); + y += (p->radius * sin(p->w)); + } + + pb->x = (int)x; + pb->y = (int)y; +} + +static int +colour_init(struct state *st, XWindowAttributes *pxgwa) +{ + XGCValues gcv; + +#if 0 + int H = random() % 360; /* colour choice from attraction.c. */ + double S1 = 0.25; + double S2 = 1.00; + double V = frand(0.25) + 0.75; + int line_width = 0; +#endif + + int retval = 1; + unsigned long valuemask = 0L; + unsigned long fg; + + /* Free any already allocated colors... + */ + if (st->colors) + { + free_colors(pxgwa->screen, st->cmap, st->colors, st->ncolors); + st->colors = 0; + st->ncolors = 0; + } + + //st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors = colors; + + if (st->ncolors < 2) + st->ncolors = 2; + if (st->ncolors <= 2) + mono_p = True; + st->colors = 0; + + if (!mono_p) + { + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + if (!st->colors) abort(); + + make_smooth_colormap (pxgwa->screen, pxgwa->visual, st->cmap, + st->colors, &st->ncolors, + True, /* allocate */ + False, /* not writable */ + True); /* verbose (complain about failure) */ + if (st->ncolors <= 2) + { + if (st->colors) + free (st->colors); + st->colors = 0; + mono_p = True; + } + } + + + //st->bg = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + st->bg = load_color(st->dpy, st->cmap, background); + + /* Set the line width + */ + //gcv.line_width = get_integer_resource (st->dpy, "lineWidth", "Integer"); + gcv.line_width = lineWidth; + if (gcv.line_width) + { + valuemask |= GCLineWidth; + + gcv.join_style = JoinRound; + gcv.cap_style = CapRound; + + valuemask |= (GCCapStyle | GCJoinStyle); + } + + + /* Set the drawing function. + */ + gcv.function = GXcopy; + valuemask |= GCFunction; + + /* Set the foreground. + */ +/* if (mono_p)*/ + //fg = get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + fg = load_color(st->dpy, st->cmap, foreground); +/* WTF? +else + //fg = st->bg ^ get_pixel_resource (st->dpy, st->cmap, ("color0"), "Foreground"); + fg = st->bg ^ load_color(st->dpy, st->cmap, color0); +*/ + gcv.foreground = fg; + valuemask |= GCForeground; + + /* Actually create the GC. + */ + st->color0 = XCreateGC (st->dpy, st->window, valuemask, &gcv); + + return retval; +} + + + + +static void +setup(struct state *st) +{ + XWindowAttributes xgwa; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->cmap = xgwa.colormap; + + st->width = xgwa.width; + st->height = xgwa.height; + st->x_offset = st->width / 2; + st->y_offset = st->height / 2; + st->unit_pixels = st->width < st->height ? st->width : st->height; + + { + if (!st->done) + { + colour_init(st, &xgwa); + st->done = True; + } + } +} + + +static void +color_step(struct state *st, Body *pb, double frac) +{ + if (!mono_p) + { + int newshift = st->ncolors * fmod(frac * st->colour_cycle_rate, 1.0); + if (newshift != st->color_shift_pos) + { + pb->current_color = newshift; + XSetForeground (st->dpy, st->color0, st->colors[pb->current_color].pixel); + st->color_shift_pos = newshift; + } + } +} + + +#if 0 +static long +distance(long x1, long y1, long x2, long y2) +{ + long dx, dy; + + dx = x2 - x1; + dy = y2 - y1; + return dx*dx + dy*dy; +} + +static int poisson_irand(double p) +{ + int r = 1; + while (fabs(frand(1.0)) < p) + ++r; + return r < 1 ? 1 : r; +} +#endif + +static void +precalculate_figure(Body *pb, + double this_xtime, double step, + int *x_max, int *y_max, + int *x_min, int *y_min) +{ + double t; + + move_body(pb, 0.0); /* move once to avoid initial line from origin */ + *x_min = *x_max = pb->x; + *y_min = *y_max = pb->y; + + for (t=0.0; tx > *x_max) + *x_max = pb->x; + if (pb->x < *x_min) + *x_min = pb->x; + if (pb->y > *y_max) + *y_max = pb->y; + if (pb->y < *y_min) + *y_min = pb->y; + } +} + +static int i_max(int a, int b) +{ + return (a>b) ? a : b; +} + +static void rescale_circles(struct state *st, Body *pb, + int x_max, int y_max, + int x_min, int y_min) +{ + double xscale, yscale, scale; + double xm, ym; + + x_max -= st->x_offset; + x_min -= st->x_offset; + y_max -= st->y_offset; + y_min -= st->y_offset; + + x_max = i_max(x_max, -x_min); + y_max = i_max(y_max, -y_min); + + + xm = st->width / 2.0; + ym = st->height / 2.0; + if (x_max > xm) + xscale = xm / x_max; + else + xscale = 1.0; + if (y_max > ym) + yscale = ym / y_max; + else + yscale = 1.0; + + if (xscale < yscale) /* wider than tall */ + scale = xscale; /* ensure width fits onscreen */ + else + scale = yscale; /* ensure height fits onscreen */ + + + scale *= FILL_PROPORTION; /* only fill FILL_PROPORTION of screen */ + if (scale < 1.0) /* only reduce, don't enlarge. */ + { + Circle *p; + for (p=pb->epicycles; p; p=p->pchild) + { + p->radius *= scale; + } + } + else + { + printf("enlarge by x%.2f skipped...\n", scale); + } +} + + +/* angular speeds of the circles are harmonics of a fundamental + * value. That should please the Pythagoreans among you... :-) + */ +static double +random_wdot_max(struct state *st) +{ + /* Maximum and minimum values for the choice of wdot_max. Possible + * epicycle speeds vary from wdot_max to (wdot_max * harmonics). + */ + double minspeed, maxspeed; + //minspeed = get_float_resource(st->dpy, "minSpeed", "Double"); + //maxspeed = get_float_resource(st->dpy, "maxSpeed", "Double"); + minspeed = minSpeed; + maxspeed = maxSpeed; + return st->harmonics * (minspeed + FULLCIRCLE * frand(maxspeed-minspeed)); +} + + +static void * +epicycle_init (Display *disp, Window win) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = disp; + st->window = win; + + //st->holdtime = get_integer_resource (st->dpy, "holdtime", "Integer"); + st->holdtime = holdtime; + + st->circle = FULLCIRCLE; + + XClearWindow(st->dpy, st->window); + st->uncleared = 0; + st->restart = 1; + +#if 1 + st->delay = delay; + st->harmonics = harmonics; + st->divisorPoisson = divisorPoisson; +#else + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->harmonics = get_integer_resource(st->dpy, "harmonics", "Integer"); + st->divisorPoisson = get_float_resource(st->dpy, "divisorPoisson", "Double"); +#endif + +#if 1 + st->timestep = timestep; + st->timestep_coarse = st->timestep * timestepCoarseFactor; +#else + st->timestep = get_float_resource(st->dpy, "timestep", "Double"); + st->timestep_coarse = st->timestep * + get_float_resource(st->dpy, "timestepCoarseFactor", "Double"); +#endif + +#if 1 + st->sizeFactorMin = sizeFactorMin; + st->sizeFactorMax = sizeFactorMax; + + st->minCircles = minCircles; + st->maxCircles = maxCircles; +#else + st->sizeFactorMin = get_float_resource(st->dpy, "sizeFactorMin", "Double"); + st->sizeFactorMax = get_float_resource(st->dpy, "sizeFactorMax", "Double"); + + st->minCircles = get_integer_resource (st->dpy, "minCircles", "Integer"); + st->maxCircles = get_integer_resource (st->dpy, "maxCircles", "Integer"); +#endif + st->xtime = 0; /* is this right? */ + + return st; +} + +static unsigned long +epicycle_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int this_delay = st->delay; + + if (st->eraser) { + st->eraser = erase_window (st->dpy, st->window, st->eraser); + return 10000; + } + + if (st->restart) + { + setup(st); + st->restart = 0; + + /* Flush any outstanding events; this has the side effect of + * reducing the number of "false restarts"; resdtarts caused by + * one event (e.g. ConfigureNotify) followed by another + * (e.g. Expose). + */ + + st->wdot_max = random_wdot_max(st); + + if (st->pb0) + { + delete_body(st->pb0); + st->pb0 = NULL; + } + st->pb0 = new_body(st); + st->pb0->x_origin = st->pb0->x = st->x_offset; + st->pb0->y_origin = st->pb0->y = st->y_offset; + + if (st->uncleared) + { + st->eraser = erase_window (st->dpy, st->window, st->eraser); + st->uncleared = 0; + } + + precalculate_figure(st->pb0, st->xtime, st->timestep_coarse, + &st->xmax, &st->ymax, &st->xmin, &st->ymin); + + rescale_circles(st, st->pb0, st->xmax, st->ymax, st->xmin, st->ymin); + + move_body(st->pb0, 0.0); /* move once to avoid initial line from origin */ + move_body(st->pb0, 0.0); /* move once to avoid initial line from origin */ + + + st->T = 0.0; /* start at time zero. */ + + st->L = compute_divisor_lcm(st->pb0->epicycles); + + st->colour_cycle_rate = fabs(st->L); + + st->xtime = fabs(st->L * st->circle / st->wdot_max); + + if (st->colors) /* (colors==NULL) if mono_p */ + XSetForeground (st->dpy, st->color0, st->colors[st->pb0->current_color].pixel); + } + + + color_step(st, st->pb0, st->T/st->xtime ); + draw_body(st, st->pb0, st->color0); + st->uncleared = 1; + + + /* Check if the figure is complete...*/ + if (st->T > st->xtime) + { + this_delay = st->holdtime * 1000000; + st->restart = 1; /* begin new figure. */ + } + + + + st->T += st->timestep; + move_body(st->pb0, st->T); + + return this_delay; +} + +static void +epicycle_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->restart = 1; +} + +#if 0 + static Bool + epicycle_event (Display *dpy, Window window, void *closure, XEvent *e) + { + struct state *st = (struct state *) closure; + if (e->type == ButtonPress) + { + st->restart = 1; + return True; + } + + return False; + } +#endif + +static void +epicycle_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +XSCREENSAVER_MODULE ("Epicycle", epicycle) diff --git a/non-wgl/epicycle.vcproj b/non-wgl/epicycle.vcproj new file mode 100644 index 0000000..97041c6 --- /dev/null +++ b/non-wgl/epicycle.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/erase.c b/non-wgl/erase.c index 79cc112..420b9ea 100644 --- a/non-wgl/erase.c +++ b/non-wgl/erase.c @@ -379,6 +379,32 @@ squaretate (eraser_state *st) static void fizzle (eraser_state *st) { +#if 1 // hacked by katahiromz + // NOTE: XDrawPoints is too slow in Win32 + XArc *arcs; + int chunk = 1000; + int narcs = st->width * st->height / 3; + narcs *= (st->ratio - st->prev_ratio); + + arcs = (XArc *) calloc (chunk, sizeof(*arcs)); + if (! arcs) return; + + while (narcs > 0) + { + int remain = (chunk > narcs ? narcs : chunk); + int i; + for (i = 0; i < remain; i++) + { + int r = random(); + arcs[i].x = r % st->width - 4; + arcs[i].y = (r >> 16) % st->height - 4; + arcs[i].width = arcs[i].height = 8; + } + XFillArcs(st->dpy, st->window, st->bg_gc, arcs, remain); + narcs -= remain; + } + free (arcs); +#else XPoint *points; int chunk = 20000; int npoints = st->width * st->height * 4; @@ -402,6 +428,7 @@ fizzle (eraser_state *st) npoints -= remain; } free (points); +#endif } diff --git a/non-wgl/eruption.c b/non-wgl/eruption.c new file mode 100644 index 0000000..2fd7b68 --- /dev/null +++ b/non-wgl/eruption.c @@ -0,0 +1,552 @@ +/* Eruption, Copyright (c) 2002-2003 W.P. van Paassen + * + * 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 - "eruption.c" + * + * [02-2003] - W.P. van Paassen: Improvements, added some code of jwz from the pyro hack for a spherical distribution of the particles + * [01-2003] - W.P. van Paassen: Port to X for use with XScreenSaver, the shadebob hack by Shane Smit was used as a template + * [04-2002] - W.P. van Paassen: Creation for the Demo Effects Collection (http://demo-effects.sourceforge.net) + */ + +#include "screenhack.h" +#include + +/*#define VERBOSE*/ + +char *background = "black"; +char *foreground = "white"; +int cycles = 80; +int ncolors = 256; +int delay = 10000; +int particles = 300; +int cooloff = 2; +int gravity = 1; +int heat = 256; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&cycles, "cycles", NULL, "80", t_Int}, + {&ncolors, "ncolors", NULL, "256", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&particles, "particles", NULL, "300", t_Int}, + {&cooloff, "cooloff", NULL, "2", t_Int}, + {&gravity, "gravity", NULL, "1", t_Int}, + {&heat, "heat", NULL, "256", t_Int}, +}; + +/* Slightly whacked, for better explosions + */ +#define PI_2000 6284 +#define SPREAD 15 + +/*particle structure*/ +typedef struct +{ + short xpos, ypos, xdir, ydir; + unsigned char colorindex; + unsigned char dead; +} PARTICLE; + +struct state { + Display *dpy; + Window window; + + int sin_cache[PI_2000]; + int cos_cache[PI_2000]; + + PARTICLE *particles; + unsigned short iWinWidth, iWinHeight; + unsigned char **fire; + unsigned short nParticleCount; + unsigned char xdelta, ydelta, decay; + signed char gravity; + signed short heat; + + int cycles, delay; + GC gc; + signed short iColorCount; + unsigned long *aiColorVals; + XImage *pImage; + + int draw_i; +}; + +static void +cache(struct state *st) /* jwz */ +{ /*needs to be run once. Could easily be */ + int i; /*reimplemented to run and cache at compile-time,*/ + double dA; + for (i=0; icos_cache[i]=-abs((int) (cos(((double)i)/1000.0)*dA*st->ydelta)); + st->sin_cache[i]=(int) (sin(((double)i)/1000.0)*dA*st->xdelta); + } +} + +static void init_particle(struct state *st, PARTICLE* particle, unsigned short xcenter, unsigned short ycenter) +{ + int v = random() % PI_2000; + particle->xpos = xcenter - SPREAD + (random() % (SPREAD * 2)); + particle->ypos = ycenter - SPREAD + (random() % (SPREAD * 2));; + particle->xdir = st->sin_cache[v]; + particle->ydir = st->cos_cache[v]; + particle->colorindex = st->iColorCount-1; + particle->dead = 0; +} + +static void Execute( struct state *st ) +{ + int i, j; + unsigned int temp; + + /* move and draw particles into st->fire array */ + + for (i = 0; i < st->nParticleCount; i++) + { + if (!st->particles[i].dead) + { + st->particles[i].xpos += st->particles[i].xdir; + st->particles[i].ypos += st->particles[i].ydir; + + /* is particle dead? */ + + if (st->particles[i].colorindex == 0) + { + st->particles[i].dead = 1; + continue; + } + + if (st->particles[i].xpos < 1) + { + st->particles[i].xpos = 1; + st->particles[i].xdir = -st->particles[i].xdir - 4; + st->particles[i].colorindex = st->iColorCount; + } + else if (st->particles[i].xpos >= st->iWinWidth - 2) + { + st->particles[i].xpos = st->iWinWidth - 2; + if (st->particles[i].xpos < 1) st->particles[i].xpos = 1; + st->particles[i].xdir = -st->particles[i].xdir + 4; + st->particles[i].colorindex = st->iColorCount; + } + + if (st->particles[i].ypos < 1) + { + st->particles[i].ypos = 1; + st->particles[i].ydir = -st->particles[i].ydir; + st->particles[i].colorindex = st->iColorCount; + } + else if (st->particles[i].ypos >= st->iWinHeight - 3) + { + st->particles[i].ypos = st->iWinHeight- 3; + if (st->particles[i].ypos < 1) st->particles[i].ypos = 1; + st->particles[i].ydir = (-st->particles[i].ydir >> 2) - (random() % 2); + st->particles[i].colorindex = st->iColorCount; + } + + + /* st->gravity kicks in */ + st->particles[i].ydir += st->gravity; + + /* particle cools off */ + st->particles[i].colorindex--; + + /* draw particle */ + if (st->iWinHeight <= 2 || st->iWinWidth <= 2) continue; + st->fire[st->particles[i].ypos][st->particles[i].xpos] = st->particles[i].colorindex; + st->fire[st->particles[i].ypos][st->particles[i].xpos - 1] = st->particles[i].colorindex; + st->fire[st->particles[i].ypos + 1][st->particles[i].xpos] = st->particles[i].colorindex; + st->fire[st->particles[i].ypos - 1][st->particles[i].xpos] = st->particles[i].colorindex; + st->fire[st->particles[i].ypos][st->particles[i].xpos + 1] = st->particles[i].colorindex; + } + } + + /* create st->fire effect */ + for (i = 0; i < st->iWinHeight; i++) + { + for (j = 0; j < st->iWinWidth; j++) + { + if (j + 1 >= st->iWinWidth) + temp = 0; + else + temp = st->fire[i][j + 1]; + + if (j - 1 >= 0) + temp += st->fire[i][j - 1]; + + if (i - 1 >= 0) + { + temp += st->fire[i - 1][j]; + if (j - 1 >= 0) + temp += st->fire[i - 1][j - 1]; + if (j + 1 < st->iWinWidth) + temp += st->fire[i - 1][j + 1]; + } + + if (i + 1 < st->iWinHeight) + { + temp += st->fire[i + 1][j]; + if (j + 1 < st->iWinWidth) + temp += st->fire[i + 1][j + 1]; + if (j - 1 >= 0) + temp += st->fire[i + 1][j - 1]; + } + + temp >>= 3; + + if (temp > st->decay) + { + temp -= st->decay; + } + else + temp = 0; + + st->fire[i][j] = temp; + } + } + + memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height ); + + /* draw st->fire array to screen */ + for (i = 0; i < st->iWinHeight; ++i) + { + for (j = 0; j < st->iWinWidth; ++j) + { + if (st->fire[i][j] > 0) + XPutPixel( st->pImage, j, i, st->aiColorVals[ st->fire[i][j] ] ); + } + } + XPutImage( st->dpy, st->window, st->gc, st->pImage, + 0,0,0,0, st->iWinWidth, st->iWinHeight ); +} + +static unsigned long * SetPalette(struct state *st) +{ + XWindowAttributes XWinAttribs; + XColor Color, *aColors; + signed short iColor; + + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + + //st->iColorCount = get_integer_resource(st->dpy, "ncolors", "Integer" ); + st->iColorCount = ncolors; + if( st->iColorCount < 16 ) st->iColorCount = 16; + if( st->iColorCount > 255 ) st->iColorCount = 256; + + aColors = calloc( st->iColorCount, sizeof(XColor) ); + st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) ); + + Color.red = Color.green = Color.blue = 65535 / st->iColorCount; + + /* create st->fire palette */ + for( iColor=0; iColor < st->iColorCount; iColor++ ) + { + if (iColor < st->iColorCount >> 3) + { + /* black to blue */ + aColors[iColor].red = 0; + aColors[iColor].green = 0; + aColors[iColor].blue = Color.blue * (iColor << 1); + } + else if (iColor < st->iColorCount >> 2) + { + /* blue to red */ + signed short temp = (iColor - (st->iColorCount >> 3)); + aColors[iColor].red = Color.red * (temp << 3); + aColors[iColor].green = 0; + aColors[iColor].blue = 16383 - Color.blue * (temp << 1); + } + else if (iColor < (st->iColorCount >> 2) + (st->iColorCount >> 3)) + { + /* red to yellow */ + signed short temp = (iColor - (st->iColorCount >> 2)) << 3; + aColors[iColor].red = 65535; + aColors[iColor].green = Color.green * temp; + aColors[iColor].blue = 0; + } + else if (iColor < st->iColorCount >> 1) + { + /* yellow to white */ + signed int temp = (iColor - ((st->iColorCount >> 2) + (st->iColorCount >> 3))) << 3; + aColors[iColor].red = 65535; + aColors[iColor].green = 65535; + aColors[iColor].blue = Color.blue * temp; + } + else + { + /* white */ + aColors[iColor].red = aColors[iColor].green = aColors[iColor].blue = 65535; + } + + if( !XAllocColor( st->dpy, XWinAttribs.colormap, &aColors[ iColor ] ) ) + { + /* start all over with less colors */ + XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, iColor, 0 ); + free( aColors ); + free( st->aiColorVals ); + (st->iColorCount)--; + aColors = calloc( st->iColorCount, sizeof(XColor) ); + st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) ); + iColor = -1; + } + else + st->aiColorVals[ iColor ] = aColors[ iColor ].pixel; + } + + if (st->heat < st->iColorCount) + st->iColorCount = st->heat; + + free( aColors ); + + XSetWindowBackground( st->dpy, st->window, st->aiColorVals[ 0 ] ); + + return st->aiColorVals; +} + + +static void Initialize( struct state *st ) +{ + XGCValues gcValues; + XWindowAttributes XWinAttribs; + int /*iBitsPerPixel,*/ i; + + /* Create the Image for drawing */ + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + + /* Find the preferred bits-per-pixel. (jwz) */ + { + int pfvc = 0; + XPixmapFormatValues *pfv = XListPixmapFormats( st->dpy, &pfvc ); + for( i=0; igc = XCreateGC( st->dpy, st->window, 0, &gcValues ); + + st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL, + XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 ); + (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height); + + st->iWinWidth = XWinAttribs.width; + st->iWinHeight = XWinAttribs.height; + + /* create st->fire array */ + st->fire = calloc( st->iWinHeight, sizeof(unsigned char*)); + for (i = 0; i < st->iWinHeight; ++i) + st->fire[i] = calloc( st->iWinWidth, sizeof(unsigned char)); + + /*create st->particles */ + st->particles = malloc (st->nParticleCount * sizeof(PARTICLE)); +} + +static void * +eruption_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XWindowAttributes XWinAttribs; + unsigned short sum = 0; +#ifdef VERBOSE + time_t nTime = time( NULL ); + unsigned short iFrame = 0; +#endif /* VERBOSE */ + + st->dpy = dpy; + st->window = window; + + //st->nParticleCount = get_integer_resource(st->dpy, "particles", "Integer" ); + st->nParticleCount = particles; + if (st->nParticleCount < 100) + st->nParticleCount = 100; + if (st->nParticleCount > 2000) + st->nParticleCount = 2000; + + //st->decay = get_integer_resource(st->dpy, "cooloff", "Integer" ); + st->decay = cooloff; + if (st->decay <= 0) + st->decay = 0; + if (st->decay > 10) + st->decay = 10; + + //st->gravity = get_integer_resource(st->dpy, "gravity", "Integer" ); + st->gravity = gravity; + if (st->gravity < -5) + st->gravity = -5; + if (st->gravity > 5) + st->gravity = 5; + + //st->heat = get_integer_resource(st->dpy, "heat", "Integer" ); + st->heat = heat; + if (st->heat < 64) + st->heat = 64; + if (st->heat > 256) + st->heat = 256; + +#ifdef VERBOSE + printf( "%s: Allocated %d st->particles\n", progclass, st->nParticleCount ); +#endif /* VERBOSE */ + + Initialize( st ); + + st->ydelta = 0; + while (sum < (st->iWinHeight >> 1) - SPREAD) + { + st->ydelta++; + sum += st->ydelta; + } + + sum = 0; + while (sum < (st->iWinWidth >> 3)) + { + st->xdelta++; + sum += st->xdelta; + } + + //st->delay = get_integer_resource(st->dpy, "delay", "Integer" ); + //st->cycles = get_integer_resource(st->dpy, "cycles", "Integer" ); + st->delay = delay; + st->cycles = cycles; + + cache(st); + + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, st->iColorCount, 0 ); + free( st->aiColorVals ); + st->aiColorVals = SetPalette( st ); + XClearWindow( st->dpy, st->window ); + memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height ); + + st->draw_i = -1; + + return st; +} + + +static unsigned long +eruption_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if( st->draw_i < 0 || st->draw_i++ >= st->cycles ) + { + /* compute random center */ + unsigned short xcenter, ycenter; + xcenter = random() % st->iWinWidth; + ycenter = random() % st->iWinHeight; + + for (st->draw_i = 0; st->draw_i < st->nParticleCount; st->draw_i++) + init_particle(st, st->particles + st->draw_i, xcenter, ycenter); + st->draw_i = 0; + } + + Execute( st ); + +#ifdef VERBOSE + iFrame++; + if( nTime - time( NULL ) ) + { + printf( "%s: %d FPS\n", progclass, iFrame ); + nTime = time( NULL ); + iFrame = 0; + } +#endif /* VERBOSE */ + + return st->delay; +} + + +static void +eruption_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +#if 0 + struct state *st = (struct state *) closure; + int i; + for (i = 0; i < st->iWinHeight; ++i) + free (st->fire[i]); + + st->iWinWidth = w; + st->iWinHeight = h; + + free (st->fire); + st->fire = calloc( st->iWinHeight, sizeof(unsigned char*)); + for (i = 0; i < st->iWinHeight; ++i) + st->fire[i] = calloc( st->iWinWidth, sizeof(unsigned char)); + st->draw_i = -1; +#endif +} + +#if 0 + static Bool + eruption_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +eruption_free (Display *dpy, Window window, void *closure) +{ +#if 0 + struct state *st = (struct state *) closure; + free( st->pImage->data ); + XDestroyImage( st->pImage ); + free( st->aiColorVals ); + for (i = 0; i < st->iWinHeight; ++i) + free( st->fire[i] ); + free( st->fire ); + free( st->particles ); +#endif +} + + +static const char *eruption_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsTop: true", + "*cycles: 80", + "*ncolors: 256", + "*delay: 10000", + "*particles: 300", + "*cooloff: 2", + "*gravity: 1", + "*heat: 256", + 0 +}; + +static XrmOptionDescRec eruption_options [] = { + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-cycles", ".cycles", XrmoptionSepArg, 0 }, + { "-particles", ".particles", XrmoptionSepArg, 0 }, + { "-cooloff", ".cooloff", XrmoptionSepArg, 0 }, + { "-gravity", ".gravity", XrmoptionSepArg, 0 }, + { "-heat", ".heat", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Eruption", eruption) + +/* End of Module - "eruption.c" */ + diff --git a/non-wgl/eruption.vcproj b/non-wgl/eruption.vcproj new file mode 100644 index 0000000..cee6d2f --- /dev/null +++ b/non-wgl/eruption.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/euler2d.c b/non-wgl/euler2d.c new file mode 100644 index 0000000..1557318 --- /dev/null +++ b/non-wgl/euler2d.c @@ -0,0 +1,898 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* euler2d --- 2 Dimensional Incompressible Inviscid Fluid Flow */ + +#if 0 +static const char sccsid[] = "@(#)euler2d.c 5.00 2000/11/01 xlockmore"; +#endif + +/* + * Copyright (c) 2000 by Stephen Montgomery-Smith + * + * 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: + * 04-Nov-2000: Added an option eulerpower. This allows for example the + * quasi-geostrophic equation by setting eulerpower to 2. + * 01-Nov-2000: Allocation checks. + * 10-Sep-2000: Added optimizations, and removed subtle_perturb, by stephen. + * 03-Sep-2000: Changed method of solving ode to Adams-Bashforth of order 2. + * Previously used a rather compilcated method of order 4. + * This doubles the speed of the program. Also it seems + * to have improved numerical stability. Done by stephen. + * 27-Aug-2000: Added rotation of region to maximize screen fill by stephen. + * 05-Jun-2000: Adapted from flow.c Copyright (c) 1996 by Tim Auckland + * 18-Jul-1996: Adapted from swarm.c Copyright (c) 1991 by Patrick J. Naughton. + * 31-Aug-1990: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org) + */ + +/* + * The mathematical aspects of this program are discussed in the file + * euler2d.tex. + */ + +#define STANDALONE + +# define MODE_euler2d +#define DELAY 10000 +#define COUNT 1024 +#define CYCLES 3000 +#define NCOLORS 64 +# define DEFAULTS "*delay: 10000 \n" \ + "*count: 1024 \n" \ + "*cycles: 3000 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define euler2d_handle_event 0 +# define SMOOTH_COLORS + +#include "xlockmore.h" +#if 0 + #ifdef STANDALONE + # include "xlockmore.h" /* in xscreensaver distribution */ + #else /* STANDALONE */ + # include "xlock.h" /* in xlockmore distribution */ + #endif /* STANDALONE */ +#endif + +#ifdef MODE_euler2d + +#define DEF_EULERTAIL "10" + +#define DEBUG_POINTED_REGION 0 + +static int tail_len = 10; +static int variable_boundary = 1; +static float power = 1; + +static XrmOptionDescRec opts[] = +{ + {"-eulertail", ".euler2d.eulertail", XrmoptionSepArg, NULL}, + {"-eulerpower", ".euler2d.eulerpower", XrmoptionSepArg, NULL}, +}; +static argtype vars[] = +{ + {&tail_len, "eulertail", + "EulerTail", (char *) DEF_EULERTAIL, t_Int}, + {&power, "eulerpower", + "EulerPower", "1", t_Float}, +}; +static OptionStruct desc[] = +{ + {"-eulertail len", "Length of Euler2d tails"}, + {"-eulerpower power", "power of interaction law for points for Euler2d"}, +}; + +ENTRYPOINT ModeSpecOpt euler2d_opts = +{sizeof opts / sizeof opts[0], opts, + sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct euler2d_description = { + "euler2d", "init_euler2d", "draw_euler2d", "release_euler2d", + "refresh_euler2d", "init_euler2d", (char *) NULL, &euler2d_opts, + 1000, 1024, 3000, 1, 64, 1.0, "", + "Simulates 2D incompressible invisid fluid.", 0, NULL +}; + +#endif + +#define balance_rand(v) ((LRAND()/MAXRAND*(v))-((v)/2)) /* random around 0 */ +#define positive_rand(v) (LRAND()/MAXRAND*(v)) /* positive random */ + +#define number_of_vortex_points 20 + +#define n_bound_p 500 +#define deg_p 6 + +static double delta_t; + +typedef struct { + int width; + int height; + int count; + double xshift,yshift,scale; + double radius; + + int N; + int Nvortex; + +/* x[2i+0] = x coord for nth point + x[2i+1] = y coord for nth point + w[i] = vorticity at nth point +*/ + double *x; + double *w; + + double *diffx; + double *olddiffx; + double *tempx; + double *tempdiffx; +/* (xs[2i+0],xs[2i+1]) is reflection of (x[2i+0],x[2i+1]) about unit circle + xs[2i+0] = x[2i+0]/nx + xs[2i+1] = x[2i+1]/nx + where + nx = x[2i+0]*x[2i+0] + x[2i+1]*x[2i+1] + + x_is_zero[i] = (nx < 1e-10) +*/ + double *xs; + short *x_is_zero; + +/* (p[2i+0],p[2i+1]) is image of (x[2i+0],x[2i+1]) under polynomial p. + mod_dp2 is |p'(z)|^2 when z = (x[2i+0],x[2i+1]). +*/ + double *p; + double *mod_dp2; + +/* Sometimes in our calculations we get overflow or numbers that are too big. + If that happens with the point x[2*i+0], x[2*i+1], we set dead[i]. +*/ + short *dead; + + XSegment *csegs; + int cnsegs; + XSegment *old_segs; + int *nold_segs; + int c_old_seg; + int boundary_color; + int hide_vortex; + short *lastx; + + double p_coef[2*(deg_p-1)]; + XSegment *boundary; + +} euler2dstruct; + +static euler2dstruct *euler2ds = (euler2dstruct *) NULL; + +/* + If variable_boundary == 1, then we make a variable boundary. + The way this is done is to map the unit disk under a + polynomial p, where + p(z) = z + c_2 z^2 + ... + c_n z^n + where n = deg_p. sp->p_coef contains the complex numbers + c_2, c_3, ... c_n. +*/ + +#define add(a1,a2,b1,b2) (a1)+=(b1);(a2)+=(b2) +#define mult(a1,a2,b1,b2) temp=(a1)*(b1)-(a2)*(b2); \ + (a2)=(a1)*(b2)+(a2)*(b1);(a1)=temp + +static void +calc_p(double *p1, double *p2, double z1, double z2, double p_coef[]) +{ + int i; + double temp; + + *p1=0; + *p2=0; + for(i=deg_p;i>=2;i--) + { + add(*p1,*p2,p_coef[(i-2)*2],p_coef[(i-2)*2+1]); + mult(*p1,*p2,z1,z2); + } + add(*p1,*p2,1,0); + mult(*p1,*p2,z1,z2); +} + +/* Calculate |p'(z)|^2 */ +static double +calc_mod_dp2(double z1, double z2, double p_coef[]) +{ + int i; + double temp,mp1,mp2; + + mp1=0; + mp2=0; + for(i=deg_p;i>=2;i--) + { + add(mp1,mp2,i*p_coef[(i-2)*2],i*p_coef[(i-2)*2+1]); + mult(mp1,mp2,z1,z2); + } + add(mp1,mp2,1,0); + return mp1*mp1+mp2*mp2; +} + +static void +calc_all_p(euler2dstruct *sp) +{ + int i,j; + double temp,p1,p2,z1,z2; + for(j=(sp->hide_vortex?sp->Nvortex:0);jN;j++) if(!sp->dead[j]) + { + p1=0; + p2=0; + z1=sp->x[2*j+0]; + z2=sp->x[2*j+1]; + for(i=deg_p;i>=2;i--) + { + add(p1,p2,sp->p_coef[(i-2)*2],sp->p_coef[(i-2)*2+1]); + mult(p1,p2,z1,z2); + } + add(p1,p2,1,0); + mult(p1,p2,z1,z2); + sp->p[2*j+0] = p1; + sp->p[2*j+1] = p2; + } +} + +static void +calc_all_mod_dp2(double *x, euler2dstruct *sp) +{ + int i,j; + double temp,mp1,mp2,z1,z2; + for(j=0;jN;j++) if(!sp->dead[j]) + { + mp1=0; + mp2=0; + z1=x[2*j+0]; + z2=x[2*j+1]; + for(i=deg_p;i>=2;i--) + { + add(mp1,mp2,i*sp->p_coef[(i-2)*2],i*sp->p_coef[(i-2)*2+1]); + mult(mp1,mp2,z1,z2); + } + add(mp1,mp2,1,0); + sp->mod_dp2[j] = mp1*mp1+mp2*mp2; + } +} + +static void +derivs(double *x, euler2dstruct *sp) +{ + int i,j; + double u1,u2,x1,x2,xij1,xij2,nxij; + double nx; + + if (variable_boundary) + calc_all_mod_dp2(sp->x,sp); + + for (j=0;jNvortex;j++) if (!sp->dead[j]) + { + nx = x[2*j+0]*x[2*j+0] + x[2*j+1]*x[2*j+1]; + if (nx < 1e-10) + sp->x_is_zero[j] = 1; + else { + sp->x_is_zero[j] = 0; + sp->xs[2*j+0] = x[2*j+0]/nx; + sp->xs[2*j+1] = x[2*j+1]/nx; + } + } + + (void) memset(sp->diffx,0,sizeof(double)*2*sp->N); + + for (i=0;iN;i++) if (!sp->dead[i]) + { + x1 = x[2*i+0]; + x2 = x[2*i+1]; + for (j=0;jNvortex;j++) if (!sp->dead[j]) + { +/* + Calculate the Biot-Savart kernel, that is, effect of a + vortex point at a = (x[2*j+0],x[2*j+1]) at the point + x = (x1,x2), returning the vector field in (u1,u2). + + In the plane, this is given by the formula + + u = (x-a)/|x-a|^2 or zero if x=a. + + However, in the unit disk we have to subtract from the + above: + + (x-as)/|x-as|^2 + + where as = a/|a|^2 is the reflection of a about the unit circle. + + If however power != 1, then + + u = (x-a)/|x-a|^(power+1) - |a|^(1-power) (x-as)/|x-as|^(power+1) + +*/ + + xij1 = x1 - x[2*j+0]; + xij2 = x2 - x[2*j+1]; + nxij = (power==1.0) ? xij1*xij1+xij2*xij2 : pow(xij1*xij1+xij2*xij2,(power+1)/2.0); + + if(nxij >= 1e-4) { + u1 = xij2/nxij; + u2 = -xij1/nxij; + } + else + u1 = u2 = 0.0; + + if (!sp->x_is_zero[j]) + { + xij1 = x1 - sp->xs[2*j+0]; + xij2 = x2 - sp->xs[2*j+1]; + nxij = (power==1.0) ? xij1*xij1+xij2*xij2 : pow(xij1*xij1+xij2*xij2,(power+1)/2.0); + + if (nxij < 1e-5) + { + sp->dead[i] = 1; + u1 = u2 = 0.0; + } + else + { + u1 -= xij2/nxij; + u2 += xij1/nxij; + } + } + + if (!sp->dead[i]) + { + sp->diffx[2*i+0] += u1*sp->w[j]; + sp->diffx[2*i+1] += u2*sp->w[j]; + } + } + + if (!sp->dead[i] && variable_boundary) + { + if (sp->mod_dp2[i] < 1e-5) + sp->dead[i] = 1; + else + { + sp->diffx[2*i+0] /= sp->mod_dp2[i]; + sp->diffx[2*i+1] /= sp->mod_dp2[i]; + } + } + } +} + +/* + What perturb does is effectively + ret = x + k, + where k should be of order delta_t. + + We have the option to do this more subtly by mapping points x + in the unit disk to points y in the plane, where y = f(|x|) x, + with f(t) = -log(1-t)/t. + + This might reduce (but does not remove) problems where particles near + the edge of the boundary bounce around. + + But it seems to be not that effective, so for now switch it off. +*/ + +#define SUBTLE_PERTURB 0 + +static void +perturb(double ret[], double x[], double k[], euler2dstruct *sp) +{ + int i; + double x1,x2,k1,k2; + +#if SUBTLE_PERTURB + double d1,d2,t1,t2,mag,mag2,mlog1mmag,memmagdmag,xdotk; + for (i=0;iN;i++) if (!sp->dead[i]) + { + x1 = x[2*i+0]; + x2 = x[2*i+1]; + k1 = k[2*i+0]; + k2 = k[2*i+1]; + mag2 = x1*x1 + x2*x2; + if (mag2 < 1e-10) + { + ret[2*i+0] = x1+k1; + ret[2*i+1] = x2+k2; + } + else if (mag2 > 1-1e-5) + sp->dead[i] = 1; + else + { + mag = sqrt(mag2); + mlog1mmag = -log(1-mag); + xdotk = x1*k1 + x2*k2; + t1 = (x1 + k1)*mlog1mmag/mag + x1*xdotk*(1.0/(1-mag)-mlog1mmag/mag)/mag/mag; + t2 = (x2 + k2)*mlog1mmag/mag + x2*xdotk*(1.0/(1-mag)-mlog1mmag/mag)/mag/mag; + mag = sqrt(t1*t1+t2*t2); + if (mag > 11.5 /* log(1e5) */) + sp->dead[i] = 1; + else + { + memmagdmag = (mag>1e-5) ? ((1.0-exp(-mag))/mag) : (1-mag/2.0); + ret[2*i+0] = t1*memmagdmag; + ret[2*i+1] = t2*memmagdmag; + } + } + if (!sp->dead[i]) + { + d1 = ret[2*i+0]-x1; + d2 = ret[2*i+1]-x2; + if (d1*d1+d2*d2 > 0.1) + sp->dead[i] = 1; + } + } + +#else + + for (i=0;iN;i++) if (!sp->dead[i]) + { + x1 = x[2*i+0]; + x2 = x[2*i+1]; + k1 = k[2*i+0]; + k2 = k[2*i+1]; + if (k1*k1+k2*k2 > 0.1 || x1*x1+x2*x2 > 1-1e-5) + sp->dead[i] = 1; + else + { + ret[2*i+0] = x1+k1; + ret[2*i+1] = x2+k2; + } + } +#endif +} + +static void +ode_solve(euler2dstruct *sp) +{ + int i; + double *temp; + + if (sp->count < 1) { + /* midpoint method */ + derivs(sp->x,sp); + (void) memcpy(sp->olddiffx,sp->diffx,sizeof(double)*2*sp->N); + for (i=0;iN;i++) if (!sp->dead[i]) { + sp->tempdiffx[2*i+0] = 0.5*delta_t*sp->diffx[2*i+0]; + sp->tempdiffx[2*i+1] = 0.5*delta_t*sp->diffx[2*i+1]; + } + perturb(sp->tempx,sp->x,sp->tempdiffx,sp); + derivs(sp->tempx,sp); + for (i=0;iN;i++) if (!sp->dead[i]) { + sp->tempdiffx[2*i+0] = delta_t*sp->diffx[2*i+0]; + sp->tempdiffx[2*i+1] = delta_t*sp->diffx[2*i+1]; + } + perturb(sp->x,sp->x,sp->tempdiffx,sp); + } else { + /* Adams Basforth */ + derivs(sp->x,sp); + for (i=0;iN;i++) if (!sp->dead[i]) { + sp->tempdiffx[2*i+0] = delta_t*(1.5*sp->diffx[2*i+0] - 0.5*sp->olddiffx[2*i+0]); + sp->tempdiffx[2*i+1] = delta_t*(1.5*sp->diffx[2*i+1] - 0.5*sp->olddiffx[2*i+1]); + } + perturb(sp->x,sp->x,sp->tempdiffx,sp); + temp = sp->olddiffx; + sp->olddiffx = sp->diffx; + sp->diffx = temp; + } +} + +#define deallocate(p,t) if (p!=NULL) {(void) free((void *) p); p=(t*)NULL; } +#define allocate(p,t,s) if ((p=(t*)malloc(sizeof(t)*s))==NULL)\ +{free_euler2d(sp);return;} + +static void +free_euler2d(euler2dstruct *sp) +{ + deallocate(sp->csegs, XSegment); + deallocate(sp->old_segs, XSegment); + deallocate(sp->nold_segs, int); + deallocate(sp->lastx, short); + deallocate(sp->x, double); + deallocate(sp->diffx, double); + deallocate(sp->w, double); + deallocate(sp->olddiffx, double); + deallocate(sp->tempdiffx, double); + deallocate(sp->tempx, double); + deallocate(sp->dead, short); + deallocate(sp->boundary, XSegment); + deallocate(sp->xs, double); + deallocate(sp->x_is_zero, short); + deallocate(sp->p, double); + deallocate(sp->mod_dp2, double); +} + +ENTRYPOINT void +init_euler2d (ModeInfo * mi) +{ +#define nr_rotates 18 /* how many rotations to try to fill as much of screen as possible - must be even number */ + euler2dstruct *sp; + int i,k,n,np; + double r,theta,x,y,w; + double mag,xscale,yscale,p1,p2; + double low[nr_rotates],high[nr_rotates],pp1,pp2,pn1,pn2,angle1,angle2,tempangle,dist,scale,bestscale,temp; + int besti = 0; + + if (power<0.5) power = 0.5; + if (power>3.0) power = 3.0; + variable_boundary &= power == 1.0; + delta_t = 0.001; + if (power>1.0) delta_t *= pow(0.1,power-1); + + if (euler2ds == NULL) { + if ((euler2ds = (euler2dstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (euler2dstruct))) == NULL) + return; + } + sp = &euler2ds[MI_SCREEN(mi)]; + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False); +#endif + + sp->boundary_color = NRAND(MI_NPIXELS(mi)); + sp->hide_vortex = NRAND(4) != 0; + + sp->count = 0; + + sp->width = MI_WIDTH(mi); + sp->height = MI_HEIGHT(mi); + + sp->N = MI_COUNT(mi)+number_of_vortex_points; + sp->Nvortex = number_of_vortex_points; + + if (tail_len < 1) { /* minimum tail */ + tail_len = 1; + } + if (tail_len > MI_CYCLES(mi)) { /* maximum tail */ + tail_len = MI_CYCLES(mi); + } + + /* Clear the background. */ + MI_CLEARWINDOW(mi); + + free_euler2d(sp); + + /* Allocate memory. */ + + if (sp->csegs == NULL) { + allocate(sp->csegs, XSegment, sp->N); + allocate(sp->old_segs, XSegment, sp->N * tail_len); + allocate(sp->nold_segs, int, tail_len); + allocate(sp->lastx, short, sp->N * 2); + allocate(sp->x, double, sp->N * 2); + allocate(sp->diffx, double, sp->N * 2); + allocate(sp->w, double, sp->Nvortex); + allocate(sp->olddiffx, double, sp->N * 2); + allocate(sp->tempdiffx, double, sp->N * 2); + allocate(sp->tempx, double, sp->N * 2); + allocate(sp->dead, short, sp->N); + allocate(sp->boundary, XSegment, n_bound_p); + allocate(sp->xs, double, sp->Nvortex * 2); + allocate(sp->x_is_zero, short, sp->Nvortex); + allocate(sp->p, double, sp->N * 2); + allocate(sp->mod_dp2, double, sp->N); + } + for (i=0;inold_segs[i] = 0; + } + sp->c_old_seg = 0; + (void) memset(sp->dead,0,sp->N*sizeof(short)); + + if (variable_boundary) + { + /* Initialize polynomial p */ +/* + The polynomial p(z) = z + c_2 z^2 + ... c_n z^n needs to be + a bijection of the unit disk onto its image. This is achieved + by insisting that sum_{k=2}^n k |c_k| <= 1. Actually we set + the inequality to be equality (to get more interesting shapes). +*/ + mag = 0; + for(k=2;k<=deg_p;k++) + { + r = positive_rand(1.0/k); + theta = balance_rand(2*M_PI); + sp->p_coef[2*(k-2)+0]=r*cos(theta); + sp->p_coef[2*(k-2)+1]=r*sin(theta); + mag += k*r; + } + if (mag > 0.0001) for(k=2;k<=deg_p;k++) + { + sp->p_coef[2*(k-2)+0] /= mag; + sp->p_coef[2*(k-2)+1] /= mag; + } + +#if DEBUG_POINTED_REGION + for(k=2;k<=deg_p;k++){ + sp->p_coef[2*(k-2)+0]=0; + sp->p_coef[2*(k-2)+1]=0; + } + sp->p_coef[2*(6-2)+0] = 1.0/6.0; +#endif + + +/* Here we figure out the best rotation of the domain so that it fills as + much of the screen as possible. The number of angles we look at is determined + by nr_rotates (we look every 180/nr_rotates degrees). + While we figure out the best angle to rotate, we also figure out the correct scaling factors. +*/ + + for(k=0;kp_coef); + calc_p(&pp1,&pp2,cos((double)(k-1)/(n_bound_p)*2*M_PI),sin((double)(k-1)/(n_bound_p)*2*M_PI),sp->p_coef); + calc_p(&pn1,&pn2,cos((double)(k+1)/(n_bound_p)*2*M_PI),sin((double)(k+1)/(n_bound_p)*2*M_PI),sp->p_coef); + angle1 = nr_rotates/M_PI*atan2(p2-pp2,p1-pp1)-nr_rotates/2; + angle2 = nr_rotates/M_PI*atan2(pn2-p2,pn1-p1)-nr_rotates/2; + while (angle1<0) angle1+=nr_rotates*2; + while (angle2<0) angle2+=nr_rotates*2; + if (angle1>nr_rotates*1.75 && angle2nr_rotates*1.75) angle1+=nr_rotates*2; + if (angle2high[i%nr_rotates]) high[i%nr_rotates] = dist; + if (disthigh[i%nr_rotates]) high[i%nr_rotates] = -dist; + if (-distwidth-5.0)/(high[i]-low[i]); + yscale = (sp->height-5.0)/(high[(i+nr_rotates/2)%nr_rotates]-low[(i+nr_rotates/2)%nr_rotates]); + scale = (xscale>yscale) ? yscale : xscale; + if (scale>bestscale) { + bestscale = scale; + besti = i; + } + } +/* Here we do the rotation. The way we do this is to replace the + polynomial p(z) by a^{-1} p(a z) where a = exp(i best_angle). +*/ + p1 = 1; + p2 = 0; + for(k=2;k<=deg_p;k++) + { + mult(p1,p2,cos((double)besti*M_PI/nr_rotates),sin((double)besti*M_PI/nr_rotates)); + mult(sp->p_coef[2*(k-2)+0],sp->p_coef[2*(k-2)+1],p1,p2); + } + + sp->scale = bestscale; + sp->xshift = -(low[besti]+high[besti])/2.0*sp->scale+sp->width/2; + if (bestiyshift = -(low[besti+nr_rotates/2]+high[besti+nr_rotates/2])/2.0*sp->scale+sp->height/2; + else + sp->yshift = (low[besti-nr_rotates/2]+high[besti-nr_rotates/2])/2.0*sp->scale+sp->height/2; + + +/* Initialize boundary */ + + for(k=0;kp_coef); + sp->boundary[k].x1 = (short)(p1*sp->scale+sp->xshift); + sp->boundary[k].y1 = (short)(p2*sp->scale+sp->yshift); + } + for(k=1;kboundary[k].x2 = sp->boundary[k-1].x1; + sp->boundary[k].y2 = sp->boundary[k-1].y1; + } + sp->boundary[0].x2 = sp->boundary[n_bound_p-1].x1; + sp->boundary[0].y2 = sp->boundary[n_bound_p-1].y1; + } + else + { + if (sp->width>sp->height) + sp->radius = sp->height/2.0-5.0; + else + sp->radius = sp->width/2.0-5.0; + } + + /* Initialize point positions */ + + for (i=sp->Nvortex;iN;i++) { + do { + r = sqrt(positive_rand(1.0)); + theta = balance_rand(2*M_PI); + sp->x[2*i+0]=r*cos(theta); + sp->x[2*i+1]=r*sin(theta); + /* This is to make sure the initial distribution of points is uniform */ + } while (variable_boundary && + calc_mod_dp2(sp->x[2*i+0],sp->x[2*i+1],sp->p_coef) + < positive_rand(4)); + } + + n = NRAND(4)+2; + /* number of vortex points with negative vorticity */ + if (n%2) { + np = NRAND(n+1); + } + else { + /* if n is even make sure that np==n/2 is twice as likely + as the other possibilities. */ + np = NRAND(n+2); + if (np==n+1) np=n/2; + } + for(k=0;kNvortex; + for (i=sp->Nvortex*k/n;iNvortex*(k+1)/n;i++) { + theta = balance_rand(2*M_PI); + sp->x[2*i+0]=x + r*cos(theta); + sp->x[2*i+1]=y + r*sin(theta); + sp->w[i]=w; + } + } +} + +ENTRYPOINT void +draw_euler2d (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + int b, col, n_non_vortex_segs; + euler2dstruct *sp; + + MI_IS_DRAWN(mi) = True; + + if (euler2ds == NULL) + return; + sp = &euler2ds[MI_SCREEN(mi)]; + if (sp->csegs == NULL) + return; + + ode_solve(sp); + if (variable_boundary) + calc_all_p(sp); + + sp->cnsegs = 0; + for(b=sp->Nvortex;bN;b++) if(!sp->dead[b]) + { + sp->csegs[sp->cnsegs].x1 = sp->lastx[2*b+0]; + sp->csegs[sp->cnsegs].y1 = sp->lastx[2*b+1]; + if (variable_boundary) + { + sp->csegs[sp->cnsegs].x2 = (short)(sp->p[2*b+0]*sp->scale+sp->xshift); + sp->csegs[sp->cnsegs].y2 = (short)(sp->p[2*b+1]*sp->scale+sp->yshift); + } + else + { + sp->csegs[sp->cnsegs].x2 = (short)(sp->x[2*b+0]*sp->radius+sp->width/2); + sp->csegs[sp->cnsegs].y2 = (short)(sp->x[2*b+1]*sp->radius+sp->height/2); + } + sp->lastx[2*b+0] = sp->csegs[sp->cnsegs].x2; + sp->lastx[2*b+1] = sp->csegs[sp->cnsegs].y2; + sp->cnsegs++; + } + n_non_vortex_segs = sp->cnsegs; + + if (!sp->hide_vortex) for(b=0;bNvortex;b++) if(!sp->dead[b]) + { + sp->csegs[sp->cnsegs].x1 = sp->lastx[2*b+0]; + sp->csegs[sp->cnsegs].y1 = sp->lastx[2*b+1]; + if (variable_boundary) + { + sp->csegs[sp->cnsegs].x2 = (short)(sp->p[2*b+0]*sp->scale+sp->xshift); + sp->csegs[sp->cnsegs].y2 = (short)(sp->p[2*b+1]*sp->scale+sp->yshift); + } + else + { + sp->csegs[sp->cnsegs].x2 = (short)(sp->x[2*b+0]*sp->radius+sp->width/2); + sp->csegs[sp->cnsegs].y2 = (short)(sp->x[2*b+1]*sp->radius+sp->height/2); + } + sp->lastx[2*b+0] = sp->csegs[sp->cnsegs].x2; + sp->lastx[2*b+1] = sp->csegs[sp->cnsegs].y2; + sp->cnsegs++; + } + + if (sp->count) { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + + XDrawSegments(display, window, gc, sp->old_segs+sp->c_old_seg*sp->N, sp->nold_segs[sp->c_old_seg]); + + if (MI_NPIXELS(mi) > 2){ /* render colour */ + for (col = 0; col < MI_NPIXELS(mi); col++) { + int start = col*n_non_vortex_segs/MI_NPIXELS(mi); + int finish = (col+1)*n_non_vortex_segs/MI_NPIXELS(mi); + XSetForeground(display, gc, MI_PIXEL(mi, col)); + XDrawSegments(display, window, gc,sp->csegs+start, finish-start); + } + if (!sp->hide_vortex) { + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + XDrawSegments(display, window, gc,sp->csegs+n_non_vortex_segs, sp->cnsegs-n_non_vortex_segs); + } + + } else { /* render mono */ + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + XDrawSegments(display, window, gc, + sp->csegs, sp->cnsegs); + } + + if (MI_NPIXELS(mi) > 2) /* render colour */ + XSetForeground(display, gc, MI_PIXEL(mi, sp->boundary_color)); + else + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + if (variable_boundary) + XDrawSegments(display, window, gc, + sp->boundary, n_bound_p); + else + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + sp->width/2 - (int) sp->radius - 1, sp->height/2 - (int) sp->radius -1, + (int) (2*sp->radius) + 2, (int) (2* sp->radius) + 2, 0, 64*360); + + /* Copy to erase-list */ + (void) memcpy(sp->old_segs+sp->c_old_seg*sp->N, sp->csegs, sp->cnsegs*sizeof(XSegment)); + sp->nold_segs[sp->c_old_seg] = sp->cnsegs; + sp->c_old_seg++; + if (sp->c_old_seg >= tail_len) + sp->c_old_seg = 0; + } + + if (++sp->count > MI_CYCLES(mi)) /* pick a new flow */ + init_euler2d(mi); + +} + +ENTRYPOINT void +reshape_euler2d(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_euler2d (mi); +} + +ENTRYPOINT void +release_euler2d (ModeInfo * mi) +{ + if (euler2ds != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_euler2d(&euler2ds[screen]); + (void) free((void *) euler2ds); + euler2ds = (euler2dstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_euler2d (ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Euler2D", euler2d) + +#endif /* MODE_euler2d */ diff --git a/non-wgl/euler2d.vcproj b/non-wgl/euler2d.vcproj new file mode 100644 index 0000000..0c8b448 --- /dev/null +++ b/non-wgl/euler2d.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/fadeplot.c b/non-wgl/fadeplot.c new file mode 100644 index 0000000..2a987e5 --- /dev/null +++ b/non-wgl/fadeplot.c @@ -0,0 +1,256 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* fadeplot --- a fading plot of sine squared */ + +#if 0 +static const char sccsid[] = "@(#)fadeplot.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Some easy plotting stuff, by Bas van Gaalen, Holland, PD + * + * Copyright (c) 1996 by Charles Vidal + * + * 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 screensaver + * 1996: Written by Charles Vidal based on work by Bas van Gaalen + */ + +#define NOARGS +#define STANDALONE + +# define MODE_fadeplot +#define DELAY 30000 +#define COUNT 10 +#define CYCLES 1500 +#define NCOLORS 64 +# define DEFAULTS "*delay: 30000 \n" \ + "*count: 10 \n" \ + "*cycles: 1500 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define BRIGHT_COLORS +# define UNIFORM_COLORS +# define fadeplot_handle_event 0 + +#include "xlockmore.h" +#if 0 + #ifdef STANDALONE + # include "xlockmore.h" /* in xscreensaver distribution */ + #else /* STANDALONE */ + # include "xlock.h" /* in xlockmore distribution */ + #endif /* STANDALONE */ +#endif + +#ifdef MODE_fadeplot + +ENTRYPOINT ModeSpecOpt fadeplot_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct fadeplot_description = +{"fadeplot", "init_fadeplot", "draw_fadeplot", "release_fadeplot", + "refresh_fadeplot", "init_fadeplot", (char *) NULL, &fadeplot_opts, + 30000, 10, 1500, 1, 64, 0.6, "", + "Shows a fading plot of sine squared", 0, NULL}; +#endif + +#define MINSTEPS 1 + +typedef struct { + XPoint speed, step, factor, st; + int temps, maxpts, nbstep; + int min; + int width, height; + int pix; + int angles; + int *stab; + XPoint *pts; +} fadeplotstruct; + +static fadeplotstruct *fadeplots = (fadeplotstruct *) NULL; + +static void +free_fadeplot(fadeplotstruct *fp) +{ + if (fp->pts != NULL) { + (void) free((void *) fp->pts); + fp->pts = (XPoint *) NULL; + } + if (fp->stab != NULL) { + (void) free((void *) fp->stab); + fp->stab = (int *) NULL; + } +} + +static Bool +initSintab(ModeInfo * mi) +{ + fadeplotstruct *fp = &fadeplots[MI_SCREEN(mi)]; + int i; + float x; + + fp->angles = NRAND(950) + 250; + if ((fp->stab = (int *) malloc(fp->angles * sizeof (int))) == NULL) { + free_fadeplot(fp); + return False; + } + for (i = 0; i < fp->angles; i++) { + x = SINF(2.0 * M_PI * i / fp->angles); + fp->stab[i] = (int) (x * ABS(x) * fp->min) + fp->min; + } + return True; +} + +ENTRYPOINT void +init_fadeplot (ModeInfo * mi) +{ + fadeplotstruct *fp; + + if (fadeplots == NULL) { + if ((fadeplots = (fadeplotstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (fadeplotstruct))) == NULL) + return; + } + fp = &fadeplots[MI_SCREEN(mi)]; + + fp->width = MI_WIDTH(mi); + fp->height = MI_HEIGHT(mi); + fp->min = MAX(MIN(fp->width, fp->height) / 2, 1); + + fp->speed.x = 8; + fp->speed.y = 10; + fp->step.x = 1; + fp->step.y = 1; + fp->temps = 0; + fp->factor.x = MAX(fp->width / (2 * fp->min), 1); + fp->factor.y = MAX(fp->height / (2 * fp->min), 1); + + fp->nbstep = MI_COUNT(mi); + if (fp->nbstep < -MINSTEPS) { + fp->nbstep = NRAND(-fp->nbstep - MINSTEPS + 1) + MINSTEPS; + } else if (fp->nbstep < MINSTEPS) + fp->nbstep = MINSTEPS; + + fp->maxpts = MI_CYCLES(mi); + if (fp->maxpts < 1) + fp->maxpts = 1; + + if (fp->pts == NULL) { + if ((fp->pts = (XPoint *) calloc(fp->maxpts, sizeof (XPoint))) == + NULL) { + free_fadeplot(fp); + return; + } + } + if (MI_NPIXELS(mi) > 2) + fp->pix = NRAND(MI_NPIXELS(mi)); + + if (fp->stab != NULL) + (void) free((void *) fp->stab); + if (!initSintab(mi)) + return; + MI_CLEARWINDOW(mi); +} + +ENTRYPOINT void +draw_fadeplot (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + int i, j, temp; + fadeplotstruct *fp; + + if (fadeplots == NULL) + return; + fp = &fadeplots[MI_SCREEN(mi)]; + if (fp->stab == NULL) + return; + + MI_IS_DRAWN(mi) = True; + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XDrawPoints(display, window, gc, fp->pts, fp->maxpts, CoordModeOrigin); + + if (MI_NPIXELS(mi) > 2) { + XSetForeground(display, gc, MI_PIXEL(mi, fp->pix)); + if (++fp->pix >= MI_NPIXELS(mi)) + fp->pix = 0; + } else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + + temp = 0; + for (j = 0; j < fp->nbstep; j++) { + for (i = 0; i < fp->maxpts / fp->nbstep; i++) { + fp->pts[temp].x = + fp->stab[(fp->st.x + fp->speed.x * j + i * fp->step.x) % fp->angles] * + fp->factor.x + fp->width / 2 - fp->min; + fp->pts[temp].y = + fp->stab[(fp->st.y + fp->speed.y * j + i * fp->step.y) % fp->angles] * + fp->factor.y + fp->height / 2 - fp->min; + temp++; + } + } + XDrawPoints(display, window, gc, fp->pts, temp, CoordModeOrigin); + fp->st.x = (fp->st.x + fp->speed.x) % fp->angles; + fp->st.y = (fp->st.y + fp->speed.y) % fp->angles; + fp->temps++; + if ((fp->temps % (fp->angles / 2)) == 0) { + fp->temps = fp->temps % fp->angles * 5; + if ((fp->temps % (fp->angles)) == 0) + fp->speed.y = (fp->speed.y + 1) % 30 + 1; + if ((fp->temps % (fp->angles * 2)) == 0) + fp->speed.x = (fp->speed.x) % 20; + if ((fp->temps % (fp->angles * 3)) == 0) + fp->step.y = (fp->step.y + 1) % 2 + 1; + + MI_CLEARWINDOW(mi); + } +} + +ENTRYPOINT void +reshape_fadeplot(ModeInfo * mi, int width, int height) +{ + fadeplotstruct *fp = &fadeplots[MI_SCREEN(mi)]; + fp->width = width; + fp->height = height; + fp->min = MAX(MIN(fp->width, fp->height) / 2, 1); + fp->factor.x = MAX(fp->width / (2 * fp->min), 1); + fp->factor.y = MAX(fp->height / (2 * fp->min), 1); +} + +ENTRYPOINT void +refresh_fadeplot (ModeInfo * mi) +{ +} + +ENTRYPOINT void +release_fadeplot (ModeInfo * mi) +{ + if (fadeplots != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_fadeplot(&fadeplots[screen]); + (void) free((void *) fadeplots); + fadeplots = (fadeplotstruct *) NULL; + } +} + +XSCREENSAVER_MODULE ("FadePlot", fadeplot) + +#endif /* MODE_fadeplot */ diff --git a/non-wgl/fadeplot.vcproj b/non-wgl/fadeplot.vcproj new file mode 100644 index 0000000..aaa32a8 --- /dev/null +++ b/non-wgl/fadeplot.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/fiberlamp.c b/non-wgl/fiberlamp.c new file mode 100644 index 0000000..a8eed85 --- /dev/null +++ b/non-wgl/fiberlamp.c @@ -0,0 +1,483 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* fiberlamp --- A Fiber Optic Lamp */ + +#if !defined( lint ) && !defined( SABER ) +static const char sccsid[] = "@(#)fiberlamp.c 5.00 2000/11/01 xlockmore"; + +#endif + +/*- + * Copyright (c) 2005 by Tim Auckland + * + * 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. + * + * "fiberlamp" shows Fiber Optic Lamp. Since there is no closed-form + * solution to the large-amplitude cantilever equation, the flexible + * fiber is modeled as a set of descrete nodes. + * + * Revision History: + * 13-Jan-2005: Initial development. + */ + +#define STANDALONE +#define NOARGS + +#define MODE_fiberlamp +#define DELAY 10000 +#define COUNT 500 +#define CYCLES 10000 +#define NCOLORS 64 +#define DEFAULTS "*delay: 10000 \n" \ + "*count: 500 \n" \ + "*cycles: 10000 \n" \ + "*ncolors: 64 \n" \ + "*fpsTop: true \n" \ + +# define UNIFORM_COLORS +# define fiberlamp_handle_event 0 + +#include "xlockmore.h" +#if 0 + #ifdef STANDALONE + # include "xlockmore.h" /* in xscreensaver distribution */ + #else /* STANDALONE */ + # include "xlock.h" /* in xlockmore distribution */ + #endif /* STANDALONE */ +#endif + +#ifdef MODE_fiberlamp + +ENTRYPOINT ModeSpecOpt fiberlamp_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct fiberlamp_description = +{"fiberlamp", "init_fiberlamp", "draw_fiberlamp", "release_fiberlamp", + "draw_fiberlamp", "change_fiberlamp", (char *) NULL, &fiberlamp_opts, + 1000, 500, 10000, 0, 64, 1.0, "", "Shows a Fiber Optic Lamp", 0, NULL}; +#endif + +#define SPREAD (30.0) /* Angular spread at the base */ +#define SCALE (MI_WIDTH(mi)/2) /* Screen size */ +#define NODES (20) /* Number of nodes in a fiber. Variable with range + 10 .. 30, if desired. High values have + stability problems unless you use small DT */ + +/* Physics parameters. Tune carefully to keep realism and avoid instability*/ +#define DT (0.5) /* Time increment: Low is slow, High is less stable. */ +#define PY (0.12) /* Rigidity: Low droops, High is stiff. */ +#define DAMPING (0.055) /* Damping: Low allows oscillations, High is boring. */ + +#undef PLAN /* Plan view (for debugging) */ +#undef CHECKCOLORWHEEL /* Plan view with no spread */ + +#define DRAND(v) (LRAND()/MAXRAND*(v)) /* double random 0 - v */ + +/* Length of nodes. Uniform except for shorter notes at the tips for + colour highlights. Sum from 0..NODES-1 should exactly 1.0 */ +#define LEN(A) ((Acx = (DRAND(SCALE/4)-SCALE/8)/SCALE; /* Knock the lamp */ + fl->count = 0; /* Reset counter */ + if (fl->dbufp) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), 0, 0, + MI_WIDTH(mi), MI_HEIGHT(mi)); + } +} + +static void +free_fiber(fiberlampstruct *fl) +{ + if (fl->fiber) { + int f; + + for (f = 0; f < fl->nfibers; f++) { + fiberstruct *fs = fl->fiber + f; + + if (fs->node) + free(fs->node); + if (fs->draw) + free(fs->draw); + } + free(fl->fiber); + fl->fiber = NULL; + } +} + +static void +free_fiberlamp(ModeInfo *mi, fiberlampstruct *fl) +{ + if (fl->buffer != None && fl->dbufp) { + XFreePixmap(MI_DISPLAY(mi), fl->buffer); + fl->buffer = None; + } + free_fiber(fl); +} + +ENTRYPOINT void +init_fiberlamp(ModeInfo * mi) +{ + fiberlampstruct *fl; + + if (fiberlamps == NULL) { + if ((fiberlamps = + (fiberlampstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (fiberlampstruct))) == NULL) + return; + } + fl = &fiberlamps[MI_SCREEN(mi)]; + + /* Create or Resize double buffer */ +#if 1 || defined(HAVE_COCOA) /* Don't second-guess Quartz's double-buffering */ + fl->dbufp = False; +#else + fl->dbufp = True; +#endif + + if(fl->buffer != None && fl->buffer != MI_WINDOW(mi) && fl->dbufp) + XFreePixmap(MI_DISPLAY(mi), fl->buffer); + + if(fl->dbufp) { + fl->buffer = XCreatePixmap(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_WIDTH(mi), MI_HEIGHT(mi), MI_DEPTH(mi)); + if (fl->buffer == None) { + free_fiberlamp(mi, fl); + return; + } + } else { + fl->buffer = MI_WINDOW(mi); + } + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), 0, 0, + MI_WIDTH(mi), MI_HEIGHT(mi)); + + if(fl->init) /* Nothing else to do (probably a resize) */ + return; + + fl->init = True; + fl->nfibers = MI_COUNT(mi); + /* Allocate fibers */ + if((fl->fiber = + (fiberstruct*) calloc(fl->nfibers, sizeof (fiberstruct))) == NULL) { + free_fiberlamp(mi, fl); + return; + } else { + int f; + for(f = 0; f < fl->nfibers; f++) { + fiberstruct *fs = fl->fiber + f; + if((fs->node = + (nodestruct*) calloc(NODES, sizeof (nodestruct))) == NULL + ||(fs->draw = + (XPoint*) calloc(NODES, sizeof (XPoint))) == NULL) { + free_fiberlamp(mi, fl); + return; + } + } + } + + { + int f, i; + for(f = 0; f < fl->nfibers; f++) { + double phi = M_PI/180 * DRAND(SPREAD); + double eta = DRAND(2*M_PI) - M_PI; + for(i = 0; i < NODES; i++) { + nodestruct *n = &fl->fiber[f].node[i]; + n->phi = phi; + n->phidash = 0; + n->eta = eta; + n->etadash = 0; + } + fl->fiber[f].node[0].etadash = 0.002/DT; + fl->fiber[f].node[0].y = 0; + fl->fiber[f].node[0].z = 0; + } + + } + + /* Set up rotation */ + fl->psi = DRAND(2*M_PI); + fl->dpsi = 0.01; + + /* no "NoExpose" events from XCopyArea wanted */ + XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False); + + /* Make sure we're using 'thin' lines */ + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 0, LineSolid, CapNotLast, + JoinMiter); +#ifdef CHECKCOLORWHEEL + /* Only interested in tips, leave the rest black */ + fl->bright = fl->medium = fl->dim = MI_BLACK_PIXEL(mi); +#else + if(MI_NPIXELS(mi) > 2) { + /* Set up colours for the fiber bodies. Tips handled seperately */ + XColor c, t; + if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#E0E0C0", &c, &t)){ + fl->bright = c.pixel; + } else { + fl->bright = MI_WHITE_PIXEL(mi); + } + if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#808070", &c, &t)){ + fl->medium = c.pixel; + } else { + fl->medium = MI_WHITE_PIXEL(mi); + } + if(XAllocNamedColor(MI_DISPLAY(mi), MI_COLORMAP(mi), "#404020", &c, &t)){ + fl->dim = c.pixel; + } else { + fl->dim = MI_BLACK_PIXEL(mi); + } + } else { + fl->bright = MI_WHITE_PIXEL(mi); + fl->medium = MI_WHITE_PIXEL(mi); + fl->dim = MI_BLACK_PIXEL(mi); + } +#endif + + /* Clear the background. */ + MI_CLEARWINDOW(mi); + change_fiberlamp(mi); +} + +/* Used by xscreensaver. xlock just uses init_fiberlamp */ +ENTRYPOINT void +reshape_fiberlamp(ModeInfo * mi, int width, int height) +{ + init_fiberlamp(mi); +} + +/* sort fibers so they get drawn back-to-front, one bubble pass is + enough as the order only changes slowly */ +static void +sort_fibers(fiberlampstruct *fl) +{ + int i; + + for(i = 1; i < fl->nfibers; i++) { + if (fl->fiber[i - 1].node[NODES - 1].z > fl->fiber[i].node[NODES - 1].z) { + fiberstruct tmp = fl->fiber[i - 1]; + fl->fiber[i - 1] = fl->fiber[i]; + fl->fiber[i] = tmp; + } + } +} + +ENTRYPOINT void +draw_fiberlamp (ModeInfo * mi) +{ + fiberlampstruct *fl; + int f, i; + int x, y; + Window unused; + + short cx = MI_WIDTH(mi)/2; +#if defined PLAN || defined CHECKCOLORWHEEL + short cy = MI_HEIGHT(mi)/2; +#else + short cy = MI_HEIGHT(mi); +#endif + + if (fiberlamps == NULL) + return; + fl = &fiberlamps[MI_SCREEN(mi)]; + + fl->psi += fl->dpsi; /* turn colorwheel */ + + XTranslateCoordinates(MI_DISPLAY(mi), MI_WINDOW(mi), + RootWindow(MI_DISPLAY(mi),0/*#### MI_SCREEN(mi)*/), + cx, cy, &x, &y, &unused); + sort_fibers(fl); + + for(f = 0; f < fl->nfibers; f++) { + fiberstruct *fs = fl->fiber + f; + + fs->node[0].eta += DT*fs->node[0].etadash; + fs->node[0].x = fl->cx; /* Handle center movement */ + /* Handle window move. NOTE, only x is deflected, since y doesn't + directly affect the physics */ + fs->node[NODES-2].x *= 0.1*(fl->ry - y); + fs->node[NODES-2].x += 0.05*(fl->rx - x); + + /* 2nd order diff equation */ + for(i = 1; i < NODES; i++) { + nodestruct *n = fs->node+i; + nodestruct *p = fs->node+i-1; + double pload = 0; + double eload = 0; + double pstress = (n->phi - p->phi)*PY; + double estress = (n->eta - p->eta)*PY; + double dxi = n->x - p->x; + double dzi = n->z - p->z; + double li = sqrt(dxi*dxi + dzi*dzi)/LEN(i); + double drag = DAMPING*LEN(i)*LEN(i)*NODES*NODES; + + if(li > 0) { + int j; + for(j = i+1; j < NODES; j++) { + nodestruct *nn = fs->node+j; + double dxj = nn->x - n->x; + double dzj = nn->z - n->z; + + pload += LEN(j)*(dxi*dxj + dzi*dzj)/li; /* Radial load */ + eload += LEN(j)*(dxi*dzj - dzi*dxj)/li; /* Transverse load */ + /* Not a perfect simulation: in reality the transverse load + is only indirectly coupled to the eta deflection, but of + all the approaches I've tried this produces the most + stable model and looks the most realistic. */ + } + } + +#ifndef CHECKCOLORWHEEL + n->phidash += DT*(pload - pstress - drag*n->phidash)/LEN(i); + n->phi += DT*n->phidash; +#endif + + n->etadash += DT*(eload - estress - drag*n->etadash)/LEN(i); + n->eta += DT*n->etadash; + + { + double sp = sin(p->phi); + double cp = cos(p->phi); + double se = sin(p->eta); + double ce = cos(p->eta); + + n->x = p->x + LEN(i-1) * ce * sp; + n->y = p->y - LEN(i-1) * cp; + n->z = p->z + LEN(i-1) * se * sp; + } + + fs->draw[i-1].x = cx + MI_WIDTH(mi)/2*n->x; +#if defined PLAN || defined CHECKCOLORWHEEL /* Plan */ + fs->draw[i-1].y = cy + MI_WIDTH(mi)/2*n->z; +#else /* Elevation */ + fs->draw[i-1].y = cy + MI_WIDTH(mi)/2*n->y; +#endif + } + MI_IS_DRAWN(mi) = True; + + /* Erase: this may only be erasing an off-screen buffer, but on a + slow system it may still be faster than XFillRectangle() */ + /* That's unpossible. -jwz */ + } + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XFillRectangle(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), + 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi)); + + for(f = 0; f < fl->nfibers; f++) { + fiberstruct *fs = fl->fiber + f; + + { + double x = fs->node[1].x - fl->cx + 0.025; + double y = fs->node[1].z + 0.02; + double angle = atan2(y, x) + fl->psi; + int tipcolor = (int)(MI_NPIXELS(mi)*angle/(2*M_PI)) % MI_NPIXELS(mi); + int fibercolor; + int tiplen; + + if (tipcolor < 0) tipcolor += MI_NPIXELS(mi); + tipcolor = MI_PIXEL(mi, tipcolor); + + if(fs->node[1].z < 0.0) { /* Back */ + tiplen = 2; + fibercolor = fl->dim; + }else if(fs->node[NODES-1].z < 0.7) { /* Middle */ + tiplen = 3; + fibercolor = fl->medium; + } else { /* Front */ + tiplen = 3; + fibercolor = fl->bright; + } + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), fibercolor); + XDrawLines(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), + fs->draw, NODES-tiplen, CoordModeOrigin); + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), tipcolor); + XDrawLines(MI_DISPLAY(mi), fl->buffer, MI_GC(mi), + fs->draw+NODES-1-tiplen, tiplen, CoordModeOrigin); + } + } + + /* Update the screen from the double-buffer */ + if (fl->dbufp) + XCopyArea(MI_DISPLAY(mi), fl->buffer, MI_WINDOW(mi), MI_GC(mi), 0, 0, + MI_WIDTH(mi), MI_HEIGHT(mi), 0, 0); + + fl->rx = x; + fl->ry = y; + + if(fl->count++ > MI_CYCLES(mi)) { + change_fiberlamp(mi); + } +} + +ENTRYPOINT void +release_fiberlamp(ModeInfo * mi) +{ + if (fiberlamps != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_fiberlamp(mi, &fiberlamps[screen]); + free(fiberlamps); + fiberlamps = (fiberlampstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_fiberlamp(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Fiberlamp", fiberlamp) + +#endif /* MODE_fiberlamp */ diff --git a/non-wgl/fiberlamp.vcproj b/non-wgl/fiberlamp.vcproj new file mode 100644 index 0000000..01742b7 --- /dev/null +++ b/non-wgl/fiberlamp.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/fireworkx.c b/non-wgl/fireworkx.c new file mode 100644 index 0000000..d6d678e --- /dev/null +++ b/non-wgl/fireworkx.c @@ -0,0 +1,879 @@ +/* + Fireworkx 2.2 - Pyrotechnic explosions simulation, + an eyecandy, live animating colorful fireworks super-blasts..! + Copyright (GPL) 1999-2013 Rony B Chandran + + From Kerala, INDIA + Website: http://www.ronybc.com + + 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. + + 2004-OCT: ronybc: Landed on Xscreensaver..! + 2012-DEC: ronybc: Almost rewrite of the last version (>4 years old) + with SSE2 optimization, colored light flashes, + HSV color and many visual and speed improvements. + + Additional coding: + --------------------------------------------------------------------------------- + Support for different display color modes: put_image() + Jean-Pierre Demailly + + Fixed array access problems by beating on it with a large hammer. + Nicholas Miell + + Help 'free'ing up of memory with needed 'XSync's. + Renuka S + Rugmini R Chandran +\ + */ + +#include "screenhack.h" + +#ifdef __SSE2__ +# include +#endif + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +int maxlife = 32; +Bool flash = True; +Bool shoot = False; +Bool verbose = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&maxlife, "maxlife", NULL, "32", t_Int}, + {&flash, "flash", NULL, "True", t_Bool}, + {&shoot, "shoot", NULL, "False", t_Bool}, + {&verbose, "verbose", NULL, "False", t_Bool}, +}; + +#define FWXVERSION "2.2" + +#define WIDTH 1024 /* 888 */ +#define HEIGHT 632 /* 548 */ +#define SHELLCOUNT 4 /* FIXED NUMBER; for SSE optimization */ +#define PIXCOUNT 500 /* 500 */ +#define SHELL_LIFE_DEFAULT 32 /* 32 */ +#define SHELL_LIFE_RATIO 6 /* 6 */ +#define POWDER 5.0 /* 5.0 */ +#define FTWEAK 12 /* 12 */ +#define FLASH_ZOOM 0.8 /* 1.0 */ +#define G_ACCELERATION 0.001 /* GRAVITY */ + +typedef struct +{ + unsigned int burn; + float x, y; + float xv, yv; +} firepix; + +typedef struct +{ + unsigned int cx, cy; + unsigned int seq_number, life; + unsigned int bicolor, flies, hshift, vshift; + unsigned int mortar_fired, explode_y; + float air_drag, vshift_phase; + float flash_r, flash_g, flash_b; + unsigned int h; + double s, v; + unsigned char r, g, b; + firepix *fpix; +} fireshell; + +struct state +{ + unsigned int fps_on; + unsigned int flash_on; + unsigned int shoot; + unsigned int verbose; + unsigned int width; + unsigned int height; + unsigned int fullscreen; + unsigned int max_shell_life; + unsigned int delay; + float flash_fade; + float *light_map; + unsigned char *palaka1; + unsigned char *palaka2; + void *mem1; + void *mem2; + fireshell *fireshell_array; + + Display *dpy; + Window window; + XImage *xim; + GC gc; + XColor *colors; + int depth; + int bigendian; + int ncolors; +}; + +/* + will return zero.. divide with care. +*/ +static unsigned int rnd(unsigned int x) +{ + return(random() % x); +} + +static void fs_roll_rgb(fireshell *fs) +{ + unsigned short r, g, b; + hsv_to_rgb (fs->h, fs->s, fs->v, &r, &g, &b); + fs->r = (unsigned char) (r >> 8); + fs->g = (unsigned char) (g >> 8); + fs->b = (unsigned char) (b >> 8); +} + +static void mix_colors(fireshell *fs) +{ + float flash; + fs->h = rnd(360); + fs->s = frand(0.4) + 0.6; + fs->v = 1.0; + fs_roll_rgb(fs); + + flash = rnd(444) + 111; /* Mega Jouls ! */ + fs->flash_r = fs->r * flash; + fs->flash_g = fs->g * flash; + fs->flash_b = fs->b * flash; +} + +static void render_light_map(struct state *st, fireshell *fs) +{ + signed int x, y, v = 0; + for (y = 0, v = fs->seq_number; y < st->height; y += 2) + { + for (x = 0; x < st->width; x += 2, v += SHELLCOUNT) + { + float f; + f = sqrtf((fs->cx - x) * (fs->cx - x) + (fs->cy - y) * (fs->cy - y)) + 4.0; + f = FLASH_ZOOM / f; + f += pow(f,0.1) * frand(0.0001); /* dither */ + st->light_map[v] = f; + } + } +} + +static void recycle(struct state *st, fireshell *fs, unsigned int x, unsigned int y) +{ + unsigned int n, pixlife; + firepix *fp = fs->fpix; + fs->mortar_fired = st->shoot; + fs->explode_y = y; + fs->cx = x; + fs->cy = st->shoot ? st->height : y ; + fs->life = rnd(st->max_shell_life) + (st->max_shell_life/SHELL_LIFE_RATIO); + fs->life += !rnd(25) ? st->max_shell_life * 5 : 0; + fs->air_drag = 1.0 - (float)(rnd(200)) / (10000.0 + fs->life); + fs->bicolor = !rnd(5) ? 120 : 0; + fs->flies = !rnd(10) ? 1 : 0; /* flies' motion */ + fs->hshift = !rnd(5) ? 1 : 0; /* hue shifting */ + fs->vshift = !rnd(10) ? 1 : 0; /* value shifting */ + fs->vshift_phase = M_PI/2.0; + pixlife = rnd(fs->life) + fs->life / 10 + 1; /* ! */ + for (n = 0; n < PIXCOUNT; n++) + { + fp->burn = rnd(pixlife) + 32; + fp->xv = frand(2.0) * POWDER - POWDER; + fp->yv = sqrt(POWDER * POWDER - fp->xv * fp->xv) * (frand(2.0) - 1.0); + fp->x = x; + fp->y = y; + fp++; + } + mix_colors(fs); + render_light_map(st, fs); +} + +static void recycle_oldest(struct state *st, unsigned int x, unsigned int y) +{ + unsigned int n; + fireshell *fs, *oldest; + fs = oldest = st->fireshell_array; + for (n = 0; n < SHELLCOUNT; n++) + { + if(fs[n].life < oldest->life) oldest = &fs[n]; + } + recycle(st, oldest, x, y); +} + +static void rotate_hue(fireshell *fs, int dh) +{ + fs->h = fs->h + dh; + fs->s = fs->s - 0.001; + fs_roll_rgb(fs); +} + +static void wave_value(fireshell *fs) +{ + fs->vshift_phase = fs->vshift_phase + 0.008; + fs->v = fabs(sin(fs->vshift_phase)); + fs_roll_rgb(fs); +} + +static int explode(struct state *st, fireshell *fs) +{ + float air_drag; + unsigned int n; + unsigned int h = st->height; + unsigned int w = st->width; + unsigned char r, g, b; + unsigned char *prgba; + unsigned char *palaka = st->palaka1; + firepix *fp = fs->fpix; + if (fs->mortar_fired) + { + if (--fs->cy == fs->explode_y) + { + fs->mortar_fired = 0; + mix_colors(fs); + render_light_map(st, fs); + } + else + { + fs->flash_r = + fs->flash_g = + fs->flash_b = 50 + (fs->cy - fs->explode_y) * 10; + prgba = palaka + (fs->cy * w + fs->cx + rnd(5) - 2) * 4; + prgba[0] = (rnd(32) + 128); + prgba[1] = (rnd(32) + 128); + prgba[2] = (rnd(32) + 128); + return(1); + } + } + if ((fs->bicolor + 1) % 50 == 0) rotate_hue(fs, 180); + if (fs->bicolor) --fs->bicolor; + if (fs->hshift) rotate_hue(fs, rnd(8)); + if (fs->vshift) wave_value(fs); + if (fs->flash_r > 1.0) fs->flash_r *= st->flash_fade; + if (fs->flash_g > 1.0) fs->flash_g *= st->flash_fade; + if (fs->flash_b > 1.0) fs->flash_b *= st->flash_fade; + air_drag = fs->air_drag; + r = fs->r; + g = fs->g; + b = fs->b; + for (n = 0; n < PIXCOUNT; n++, fp++) + { + if (!fp->burn) continue; + --fp->burn; + if (fs->flies) + { + fp->x += fp->xv = fp->xv * air_drag + frand(0.1) - 0.05; + fp->y += fp->yv = fp->yv * air_drag + frand(0.1) - 0.05 + G_ACCELERATION; + } + else + { + fp->x += fp->xv = fp->xv * air_drag + frand(0.01) - 0.005; + fp->y += fp->yv = fp->yv * air_drag + frand(0.005) - 0.0025 + G_ACCELERATION; + } + if (fp->y > h) + { + if (rnd(5) == 3) + { + fp->yv *= -0.24; + fp->y = h; + } + /* touch muddy ground :) */ + else fp->burn = 0; + } + if (fp->x < w && fp->x > 0 && fp->y < h && fp->y > 0) + { + prgba = palaka + ((int)fp->y * w + (int)fp->x) * 4; + prgba[0] = b; + prgba[1] = g; + prgba[2] = r; + } + } + return(--fs->life); +} + +#ifdef __SSE2__ + +/* SSE2 optimized versions of glow_blur() and chromo_2x2_light() */ + +static void glow_blur(struct state *st) +{ + unsigned int n, nn; + unsigned char *ps = st->palaka1; + unsigned char *pd = st->palaka2; + unsigned char *pa = st->palaka1 - (st->width * 4); + unsigned char *pb = st->palaka1 + (st->width * 4); + __m128i xmm0, xmm1, xmm2, xmm3, xmm4; + + xmm0 = _mm_setzero_si128(); + nn = st->width * st->height * 4; + for (n = 0; n < nn; n+=16) + { + _mm_prefetch((const void *)&ps[n+16],_MM_HINT_T0); + _mm_prefetch((const void *)&pa[n+16],_MM_HINT_T0); + _mm_prefetch((const void *)&pb[n+16],_MM_HINT_T0); + + xmm1 = _mm_load_si128((const __m128i*)&ps[n]); + xmm2 = xmm1; + xmm1 = _mm_unpacklo_epi8(xmm1,xmm0); + xmm2 = _mm_unpackhi_epi8(xmm2,xmm0); + xmm3 = _mm_loadu_si128((const __m128i*)&ps[n+4]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm3 = _mm_slli_epi16(xmm3,3); + xmm4 = _mm_slli_epi16(xmm4,3); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + xmm3 = _mm_loadu_si128((const __m128i*)&ps[n+8]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + + xmm3 = _mm_load_si128((const __m128i*)&pa[n]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + xmm3 = _mm_loadu_si128((const __m128i*)&pa[n+4]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + xmm3 = _mm_loadu_si128((const __m128i*)&pa[n+8]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + + xmm3 = _mm_load_si128((const __m128i*)&pb[n]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + xmm3 = _mm_loadu_si128((const __m128i*)&pb[n+4]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + xmm3 = _mm_loadu_si128((const __m128i*)&pb[n+8]); + xmm4 = xmm3; + xmm3 = _mm_unpacklo_epi8(xmm3,xmm0); + xmm4 = _mm_unpackhi_epi8(xmm4,xmm0); + xmm1 = _mm_add_epi16(xmm1,xmm3); + xmm2 = _mm_add_epi16(xmm2,xmm4); + + xmm3 = xmm1; + xmm4 = xmm2; + xmm1 = _mm_srli_epi16(xmm1,4); + xmm2 = _mm_srli_epi16(xmm2,4); + xmm3 = _mm_srli_epi16(xmm3,3); + xmm4 = _mm_srli_epi16(xmm4,3); + xmm1 = _mm_packus_epi16(xmm1,xmm2); + xmm3 = _mm_packus_epi16(xmm3,xmm4); + + _mm_storeu_si128((__m128i*)&ps[n+4], xmm1); + _mm_storeu_si128((__m128i*)&pd[n+4], xmm3); + } +} + +static void chromo_2x2_light(struct state *st) +{ + __m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; + __m128i xmi4, xmi5, xmi6, xmi7; + + unsigned int x, y, v = 0; + unsigned int nl = st->width * 4; + unsigned char *mem = st->palaka2; + fireshell *fs = st->fireshell_array; + + xmm0 = _mm_setr_ps(fs[0].flash_b, fs[0].flash_g, fs[0].flash_r, 0.0); + xmm1 = _mm_setr_ps(fs[1].flash_b, fs[1].flash_g, fs[1].flash_r, 0.0); + xmm2 = _mm_setr_ps(fs[2].flash_b, fs[2].flash_g, fs[2].flash_r, 0.0); + xmm3 = _mm_setr_ps(fs[3].flash_b, fs[3].flash_g, fs[3].flash_r, 0.0); + + for (y = st->height/2; y; y--, mem += nl) + { + for (x = st->width/4; x; x--, v += 8, mem += 16) + { + xmm4 = _mm_set1_ps(st->light_map[v+0]); + xmm5 = xmm0; + xmm5 = _mm_mul_ps(xmm5,xmm4); + xmm4 = _mm_set1_ps(st->light_map[v+1]); + xmm4 = _mm_mul_ps(xmm4,xmm1); + xmm5 = _mm_add_ps(xmm5,xmm4); + xmm4 = _mm_set1_ps(st->light_map[v+2]); + xmm4 = _mm_mul_ps(xmm4,xmm2); + xmm5 = _mm_add_ps(xmm5,xmm4); + xmm4 = _mm_set1_ps(st->light_map[v+3]); + xmm4 = _mm_mul_ps(xmm4,xmm3); + xmm5 = _mm_add_ps(xmm5,xmm4); + + xmm4 = _mm_set1_ps(st->light_map[v+4]); + xmm6 = xmm0; + xmm6 = _mm_mul_ps(xmm6,xmm4); + xmm4 = _mm_set1_ps(st->light_map[v+5]); + xmm4 = _mm_mul_ps(xmm4,xmm1); + xmm6 = _mm_add_ps(xmm6,xmm4); + xmm4 = _mm_set1_ps(st->light_map[v+6]); + xmm4 = _mm_mul_ps(xmm4,xmm2); + xmm6 = _mm_add_ps(xmm6,xmm4); + xmm4 = _mm_set1_ps(st->light_map[v+7]); + xmm4 = _mm_mul_ps(xmm4,xmm3); + xmm6 = _mm_add_ps(xmm6,xmm4); + + xmi6 = _mm_cvtps_epi32(xmm5); + xmi7 = _mm_cvtps_epi32(xmm6); + xmi6 = _mm_packs_epi32(xmi6,xmi6); + xmi7 = _mm_packs_epi32(xmi7,xmi7); + + xmi4 = _mm_load_si128((const __m128i*) mem); + xmi5 = _mm_unpacklo_epi8(xmi5,xmi4); + xmi5 = _mm_srli_epi16(xmi5,8); + xmi4 = _mm_unpackhi_epi8(xmi4,xmi4); + xmi4 = _mm_srli_epi16(xmi4,8); + xmi5 = _mm_add_epi16(xmi5,xmi6); + xmi4 = _mm_add_epi16(xmi4,xmi7); + xmi5 = _mm_packus_epi16(xmi5,xmi4); + _mm_store_si128((__m128i*) mem, xmi5); + + xmi4 = _mm_load_si128((const __m128i*) &mem[nl]); + xmi5 = _mm_unpacklo_epi8(xmi5,xmi4); + xmi5 = _mm_srli_epi16(xmi5,8); + xmi4 = _mm_unpackhi_epi8(xmi4,xmi4); + xmi4 = _mm_srli_epi16(xmi4,8); + xmi5 = _mm_add_epi16(xmi5,xmi6); + xmi4 = _mm_add_epi16(xmi4,xmi7); + xmi5 = _mm_packus_epi16(xmi5,xmi4); + _mm_store_si128((__m128i*) &mem[nl], xmi5); + } + } +} + +#else + +static void glow_blur(struct state *st) +{ + unsigned int n, q; + unsigned char *pm = st->palaka1; + unsigned char *po = st->palaka2; + unsigned char *pa = pm - (st->width * 4); + unsigned char *pb = pm + (st->width * 4); + /* + unsigned int rgba = 0; + for (n = st->width*st->height*4; n; n--, pm++, pa++, pb++, po++) + { + if(++rgba > 3) + { + rgba = 0; + continue; + } + q = pm[0] + pm[4] * 8 + pm[8] + + pa[0] + pa[4] + pa[8] + + pb[0] + pb[4] + pb[8]; + pm[4] = q >> 4; + po[4] = q > 2047 ? 255 : q >> 3; + } + --- using unrolled version ------------ + */ + for (n = st->width*st->height*4; n; n-=4) + { + q = pm[0] + pm[4] * 8 + pm[8] + + pa[0] + pa[4] + pa[8] + + pb[0] + pb[4] + pb[8]; + pm[4] = q >> 4; + po[4] = q > 2047 ? 255 : q >> 3; + q = pm[1] + pm[5] * 8 + pm[9] + + pa[1] + pa[5] + pa[9] + + pb[1] + pb[5] + pb[9]; + pm[5] = q >> 4; + po[5] = q > 2047 ? 255 : q >> 3; + q = pm[2] + pm[6] * 8 + pm[10] + + pa[2] + pa[6] + pa[10] + + pb[2] + pb[6] + pb[10]; + pm[6] = q >> 4; + po[6] = q > 2047 ? 255 : q >> 3; + + pm+=4, pa+=4, pb+=4, po+=4; + } +} + +static inline unsigned char addbs(unsigned char c, unsigned int i) +{ + i += c; + return(i > 255 ? 255 : i); +} + +static void chromo_2x2_light(struct state *st) +{ + unsigned int n, x, y, v = 0; + unsigned int nl = st->width * 4; + unsigned char *mem = st->palaka2; + float r, g, b; + float rgb[SHELLCOUNT*4]; + fireshell *fs = st->fireshell_array; + + for (n = 0, x = 0; n < SHELLCOUNT; n++, x += 4, fs++) + { + rgb[x ] = fs->flash_r; + rgb[x+1] = fs->flash_g; + rgb[x+2] = fs->flash_b; + } + + for (y = st->height/2; y; y--) + { + for (x = st->width/2; x; x--, v += 4) + { + r = rgb[0] * st->light_map[v] + rgb[4] * st->light_map[v+1] + + rgb[ 8] * st->light_map[v+2] + rgb[12] * st->light_map[v+3]; + g = rgb[1] * st->light_map[v] + rgb[5] * st->light_map[v+1] + + rgb[ 9] * st->light_map[v+2] + rgb[13] * st->light_map[v+3]; + b = rgb[2] * st->light_map[v] + rgb[6] * st->light_map[v+1] + + rgb[10] * st->light_map[v+2] + rgb[14] * st->light_map[v+3]; + + mem[0] = addbs(mem[0], b); + mem[1] = addbs(mem[1], g); + mem[2] = addbs(mem[2], r); + mem[4] = addbs(mem[4], b); + mem[5] = addbs(mem[5], g); + mem[6] = addbs(mem[6], r); + + mem += nl; + + mem[0] = addbs(mem[0], b); + mem[1] = addbs(mem[1], g); + mem[2] = addbs(mem[2], r); + mem[4] = addbs(mem[4], b); + mem[5] = addbs(mem[5], g); + mem[6] = addbs(mem[6], r); + + mem -= nl - 8; + } + mem += nl; + } +} + +#endif + +static void resize(struct state *st) +{ + unsigned int n; + fireshell *fs = st->fireshell_array; + XWindowAttributes xwa; + XGetWindowAttributes (st->dpy, st->window, &xwa); + xwa.width -= xwa.width % 4; + xwa.height -= xwa.height % 2; + st->width = xwa.width; + st->height = xwa.height; + if (st->verbose) + { + printf("resolution: %d x %d \n",st->width,st->height); + } + XSync(st->dpy, 0); + if (st->xim) + { + if (st->xim->data == (char *)st->palaka2) st->xim->data = NULL; + XDestroyImage(st->xim); + XSync(st->dpy, 0); + free(st->mem2); + free(st->mem1); + } + st->xim = XCreateImage(st->dpy, xwa.visual, xwa.depth, ZPixmap, 0, 0, + st->width, st->height, 8, 0); + if (!st->xim) return; + +#ifdef __SSE2___ABANDONED /* causes __ERROR_use_memset_not_bzero_in_xscreensaver__ */ + st->mem1 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16); + bzero(st->mem1, ((st->height + 2) * st->width + 8)*4); + st->mem2 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16); + bzero(st->mem2, ((st->height + 2) * st->width + 8)*4); +#else + st->mem1 = calloc((st->height + 2) * st->width + 8, 4); + st->mem2 = calloc((st->height + 2) * st->width + 8, 4); +#endif + st->palaka1 = (unsigned char *) st->mem1 + (st->width * 4 + 16); + st->palaka2 = (unsigned char *) st->mem2 + (st->width * 4 + 16); + + if (xwa.depth >= 24) + { + st->xim->data = (char *)st->palaka2; + } + else + { + st->xim->data = calloc(st->height, st->xim->bytes_per_line); + } + + if (st->light_map) free(st->light_map); + st->light_map = calloc((st->width * st->height * SHELLCOUNT)/4, sizeof(float)); + for (n = 0; n < SHELLCOUNT; n++, fs++) + { + render_light_map(st, fs); + } +} + +static void put_image(struct state *st) +{ + int x,y,i,j; + unsigned char r, g, b; + if (!st->xim) return; + i = 0; + j = 0; + if (st->depth==16) + { + if(st->bigendian) + for (y=0; yxim->height; y++) + for (x=0; xxim->width; x++) + { + r = st->palaka2[j++]; + g = st->palaka2[j++]; + b = st->palaka2[j++]; + j++; + st->xim->data[i++] = (g&224)>>5 | (r&248); + st->xim->data[i++] = (b&248)>>3 | (g&28)<<3; + } + else + for (y=0; yxim->height; y++) + for (x=0; xxim->width; x++) + { + r = st->palaka2[j++]; + g = st->palaka2[j++]; + b = st->palaka2[j++]; + j++; + st->xim->data[i++] = (b&248)>>3 | (g&28)<<3; + st->xim->data[i++] = (g&224)>>5 | (r&248); + } + } + if (st->depth==15) + { + if(st->bigendian) + for (y=0; yxim->height; y++) + for (x=0; xxim->width; x++) + { + r = st->palaka2[j++]; + g = st->palaka2[j++]; + b = st->palaka2[j++]; + j++; + st->xim->data[i++] = (g&192)>>6 | (r&248)>>1; + st->xim->data[i++] = (b&248)>>3 | (g&56)<<2; + } + else + for (y=0; yxim->height; y++) + for (x=0; xxim->width; x++) + { + r = st->palaka2[j++]; + g = st->palaka2[j++]; + b = st->palaka2[j++]; + j++; + st->xim->data[i++] = (b&248)>>3 | (g&56)<<2; + st->xim->data[i++] = (g&192)>>6 | (r&248)>>1; + } + } + if (st->depth==8) + { + for (y=0; yxim->height; y++) + for (x=0; xxim->width; x++) + { + r = st->palaka2[j++]; + g = st->palaka2[j++]; + b = st->palaka2[j++]; + j++; + st->xim->data[i++] = (((7*g)/256)*36)+(((6*r)/256)*6)+((6*b)/256); + } + } + XPutImage(st->dpy,st->window,st->gc,st->xim,0,0,0,0,st->xim->width,st->xim->height); +} + +static void * +fireworkx_init (Display *dpy, Window win) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + unsigned int n; + Visual *vi; + Colormap cmap; + Bool writable; + XWindowAttributes xwa; + XGCValues gcv; + firepix *fp; + fireshell *fs; + + st->dpy = dpy; + st->window = win; + st->xim = NULL; + st->flash_on = 1; + st->shoot = 0; + st->width = 0; + st->height = 0; + st->max_shell_life = SHELL_LIFE_DEFAULT; + st->flash_fade = 0.995; + st->light_map = NULL; + st->palaka1 = NULL; + st->palaka2 = NULL; + +#if 1 + st->flash_on = flash; + st->shoot = shoot; + st->verbose = verbose; + st->max_shell_life = maxlife; +#else + st->flash_on = get_boolean_resource(st->dpy, "flash" , "Boolean"); + st->shoot = get_boolean_resource(st->dpy, "shoot" , "Boolean"); + st->verbose = get_boolean_resource(st->dpy, "verbose" , "Boolean"); + st->max_shell_life = get_integer_resource(st->dpy, "maxlife" , "Integer"); +#endif + /* transition from xscreensaver <= 5.20 */ + if (st->max_shell_life > 100) st->max_shell_life = 100; + + //st->delay = get_integer_resource(st->dpy, "delay" , "Integer"); + st->delay = delay; + + st->max_shell_life = pow(10.0,(st->max_shell_life/50.0)+2.7); + if(st->max_shell_life < 1000) st->flash_fade = 0.998; + + if(st->verbose) + { + printf("Fireworkx %s - Pyrotechnics explosions simulation \n", FWXVERSION); + printf("Copyright (GPL) 1999-2013 Rony B Chandran \n\n"); + printf("url: http://www.ronybc.com \n\n"); + printf("Life = %u\n", st->max_shell_life); +#ifdef __SSE2__ + printf("Using SSE2 optimization.\n"); +#endif + } + + XGetWindowAttributes(st->dpy,win,&xwa); + st->depth = xwa.depth; + vi = xwa.visual; + cmap = xwa.colormap; + st->bigendian = (ImageByteOrder(st->dpy) == MSBFirst); + + if(st->depth==8) + { + st->colors = (XColor *) calloc(sizeof(XColor),st->ncolors+1); + writable = False; + make_smooth_colormap(xwa.screen, vi, cmap, + st->colors, &st->ncolors, + False, &writable, True); + } + st->gc = XCreateGC(st->dpy, win, 0, &gcv); + + fs = calloc(SHELLCOUNT, sizeof(fireshell)); + fp = calloc(PIXCOUNT * SHELLCOUNT, sizeof(firepix)); + st->fireshell_array = fs; + + XGetWindowAttributes (st->dpy, st->window, &xwa); + st->depth = xwa.depth; + + resize(st); /* initialize palakas */ + + for (n = 0; n < SHELLCOUNT; n++, fs++) + { + fs->seq_number = n; + fs->fpix = fp; + recycle (st, fs, rnd(st->width), rnd(st->height)); + fp += PIXCOUNT; + } + + return st; +} + +static unsigned long +fireworkx_draw (Display *dpy, Window win, void *closure) +{ + struct state *st = (struct state *) closure; + fireshell *fs; + unsigned int n, q; + for (q = FTWEAK; q; q--) + { + fs = st->fireshell_array; + for (n = 0; n < SHELLCOUNT; n++, fs++) + { + if (!explode(st, fs)) + { + recycle(st, fs, rnd(st->width), rnd(st->height)); + } + } + } + + glow_blur(st); + + if (st->flash_on) + { + chromo_2x2_light(st); + } + + put_image(st); + return st->delay; +} + +static void +fireworkx_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; + resize(st); +} + +#if 0 + static Bool + fireworkx_event (Display *dpy, Window window, void *closure, XEvent *event) + { + struct state *st = (struct state *) closure; + if (event->type == ButtonPress) + { + recycle_oldest(st, event->xbutton.x, event->xbutton.y); + return True; + } + return False; + } +#endif + +static void +fireworkx_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free(st->mem2); + free(st->mem1); + free(st->fireshell_array->fpix); + free(st->fireshell_array); +} + +static const char *fireworkx_defaults [] = +{ + ".background: black", + ".foreground: white", + "*delay: 10000", /* never default to zero! */ + "*maxlife: 32", + "*flash: True", + "*shoot: False", + "*verbose: False", + 0 +}; + +static XrmOptionDescRec fireworkx_options [] = +{ + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-maxlife", ".maxlife", XrmoptionSepArg, 0 }, + { "-no-flash", ".flash", XrmoptionNoArg, "False" }, + { "-shoot", ".shoot", XrmoptionNoArg, "True" }, + { "-verbose", ".verbose", XrmoptionNoArg, "True" }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Fireworkx", fireworkx) diff --git a/non-wgl/fireworkx.vcproj b/non-wgl/fireworkx.vcproj new file mode 100644 index 0000000..527665d --- /dev/null +++ b/non-wgl/fireworkx.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/flame.c b/non-wgl/flame.c new file mode 100644 index 0000000..017c906 --- /dev/null +++ b/non-wgl/flame.c @@ -0,0 +1,488 @@ +/* xscreensaver, Copyright (c) 1993-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. + */ + +/* This file was ported from xlock for use in xscreensaver (and standalone) + * by jwz on 18-Oct-93. (And again, 11-May-97.) Original copyright reads: + * + * static char sccsid[] = "@(#)flame.c 1.4 91/09/27 XLOCK"; + * + * flame.c - recursive fractal cosmic flames. + * + * Copyright (c) 1991 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. + * + * Comments and additions should be sent to the author: + * + * naughton@eng.sun.com + * + * Patrick J. Naughton + * MS 21-14 + * Sun Laboritories, Inc. + * 2550 Garcia Ave + * Mountain View, CA 94043 + * + * Revision History: + * 01-Jun-95: This should look more like the original with some updates by + * Scott Draves. + * 27-Jun-91: vary number of functions used. + * 24-Jun-91: fixed portability problem with integer mod (%). + * 06-Jun-91: Written. (received from Scott Draves, spot@cs.cmu.edu). + */ + +#include "screenhack.h" +#include + +//#include /* so we can ignore SIGFPE */ + +char *background = "black"; +char *foreground = "white"; +int colors = 64; +int iterations = 25; +int delay = 50000; +int delay2 = 2000000; +int points = 10000; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&colors, "colors", NULL, "64", t_Int}, + {&iterations, "iterations", NULL, "25", t_Int}, + {&delay, "delay", NULL, "50000", t_Int}, + {&delay2, "delay2", NULL, "2000000", t_Int}, + {&points, "points", NULL, "10000", t_Int}, +}; + +#define POINT_BUFFER_SIZE 10 +#define MAXLEV 4 +#define MAXKINDS 10 + +struct state { + Display *dpy; + Window window; + + double f[2][3][MAXLEV]; /* three non-homogeneous transforms */ + int max_total; + int max_levels; + int max_points; + int cur_level; + int variation; + int snum; + int anum; + int num_points; + int total_points; + int pixcol; + int ncolors; + XColor *colors; + XPoint points [POINT_BUFFER_SIZE]; + GC gc; + + int delay, delay2; + int width, height; + + short lasthalf; + + int flame_alt; + int do_reset; +}; + + +static short +halfrandom (struct state *st, int mv) +{ + unsigned long r; + + if (st->lasthalf) + { + r = st->lasthalf; + st->lasthalf = 0; + } + else + { + r = random (); + st->lasthalf = r >> 16; + } + return (r % mv); +} + +static void * +flame_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + Colormap cmap; + + st->dpy = dpy; + st->window = window; + +#if defined(SIGFPE) && defined(SIG_IGN) + /* No doubt a better fix would be to track down where the NaN is coming + from, and code around that; but this should do. Apparently most systems + (Linux, Solaris, Irix, ...) ignore FPE by default -- but FreeBSD dumps + core by default. */ + signal (SIGFPE, SIG_IGN); +#endif + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->width = xgwa.width; + st->height = xgwa.height; + cmap = xgwa.colormap; + + //st->max_points = get_integer_resource (st->dpy, "iterations", "Integer"); + st->max_points = iterations; + if (st->max_points <= 0) st->max_points = 100; + + st->max_levels = st->max_points; + + //st->max_total = get_integer_resource (st->dpy, "points", "Integer"); + st->max_total = points; + if (st->max_total <= 0) st->max_total = 10000; + + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay = delay; + if (st->delay < 0) st->delay = 0; + //st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer"); + st->delay2 = delay2; + if (st->delay2 < 0) st->delay2 = 0; + + st->variation = random() % MAXKINDS; + + if (mono_p) + st->ncolors = 0; + else + { + //st->ncolors = get_integer_resource (st->dpy, "colors", "Integer"); + st->ncolors = colors; + if (st->ncolors <= 0) st->ncolors = 128; + st->colors = (XColor *) malloc ((st->ncolors+1) * sizeof (*st->colors)); + make_smooth_colormap (xgwa.screen, xgwa.visual, xgwa.colormap, + st->colors, &st->ncolors, + True, 0, True); + if (st->ncolors <= 2) + mono_p = True, st->ncolors = 0; + } + + //gcv.foreground = get_pixel_resource (st->dpy, cmap, "foreground", "Foreground"); + //gcv.background = get_pixel_resource (st->dpy, cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, cmap, foreground); + gcv.background = load_color(st->dpy, cmap, background); + + if (! mono_p) + { + st->pixcol = halfrandom (st, st->ncolors); + gcv.foreground = (st->colors [st->pixcol].pixel); + } + + st->gc = XCreateGC (st->dpy, st->window, GCForeground | GCBackground, &gcv); + return st; +} + +static int +recurse (struct state *st, double x, double y, int l, Display *dpy, Window win) +{ + int i; + double nx, ny; + + if (l == st->max_levels) + { + st->total_points++; + if (st->total_points > st->max_total) /* how long each fractal runs */ + return 0; + + if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0) + { + st->points[st->num_points].x = (int) ((st->width / 2) * (x + 1.0)); + st->points[st->num_points].y = (int) ((st->height / 2) * (y + 1.0)); + st->num_points++; + if (st->num_points >= POINT_BUFFER_SIZE) + { + XDrawPoints (st->dpy, win, st->gc, st->points, st->num_points, CoordModeOrigin); + st->num_points = 0; + } + } + } + else + { + for (i = 0; i < st->snum; i++) + { + + /* Scale back when values get very large. Spot sez: + "I think this happens on HPUX. I think it's non-IEEE + to generate an exception instead of a silent NaN." + */ + if ((abs(x) > 1.0E5) || (abs(y) > 1.0E5)) + x = x / y; + + nx = st->f[0][0][i] * x + st->f[0][1][i] * y + st->f[0][2][i]; + ny = st->f[1][0][i] * x + st->f[1][1][i] * y + st->f[1][2][i]; + if (i < st->anum) + { + switch (st->variation) + { + case 0: /* sinusoidal */ + nx = sin(nx); + ny = sin(ny); + break; + case 1: /* complex */ + { + double r2 = nx * nx + ny * ny + 1e-6; + nx = nx / r2; + ny = ny / r2; + } + break; + case 2: /* bent */ + if (nx < 0.0) + nx = nx * 2.0; + if (ny < 0.0) + ny = ny / 2.0; + break; + case 3: /* swirl */ + { + double r = (nx * nx + ny * ny); /* times k here is fun */ + double c1 = sin(r); + double c2 = cos(r); + double t = nx; + + if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4) + ny = 1e4; + else + ny = c2 * t + c1 * ny; + nx = c1 * nx - c2 * ny; + } + break; + case 4: /* horseshoe */ + { + double r, c1, c2, t; + + /* Avoid atan2: DOMAIN error message */ + if (nx == 0.0 && ny == 0.0) + r = 0.0; + else + r = atan2(nx, ny); /* times k here is fun */ + c1 = sin(r); + c2 = cos(r); + t = nx; + + nx = c1 * nx - c2 * ny; + ny = c2 * t + c1 * ny; + } + break; + case 5: /* drape */ + { + double t; + + /* Avoid atan2: DOMAIN error message */ + if (nx == 0.0 && ny == 0.0) + t = 0.0; + else + t = atan2(nx, ny) / M_PI; + + if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4) + ny = 1e4; + else + ny = sqrt(nx * nx + ny * ny) - 1.0; + nx = t; + } + break; + case 6: /* broken */ + if (nx > 1.0) + nx = nx - 1.0; + if (nx < -1.0) + nx = nx + 1.0; + if (ny > 1.0) + ny = ny - 1.0; + if (ny < -1.0) + ny = ny + 1.0; + break; + case 7: /* spherical */ + { + double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6); + + nx = nx / r; + ny = ny / r; + } + break; + case 8: /* */ + nx = atan(nx) / M_PI_2; + ny = atan(ny) / M_PI_2; + break; +/* #if 0 */ /* core dumps on some machines, why not all? */ + case 9: /* complex sine */ + { + double u = nx; + double v = ny; + double ev = exp(v); + double emv = exp(-v); + + nx = (ev + emv) * sin(u) / 2.0; + ny = (ev - emv) * cos(u) / 2.0; + } + break; + case 10: /* polynomial */ + if (nx < 0) + nx = -nx * nx; + else + nx = nx * nx; + if (ny < 0) + ny = -ny * ny; + else + ny = ny * ny; + break; +/* #endif */ + default: + nx = sin(nx); + ny = sin(ny); + } + } + if (!recurse (st, nx, ny, l + 1, st->dpy, win)) + return 0; + } + } + return 1; +} + +static unsigned long +flame_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i, j, k; + unsigned long this_delay = st->delay; + + if (st->do_reset) + { + st->do_reset = 0; + XClearWindow (st->dpy, st->window); + } + + if (!(st->cur_level++ % st->max_levels)) + { + st->do_reset = 1; + this_delay = st->delay2; + st->flame_alt = !st->flame_alt; + st->variation = random() % MAXKINDS; + } + else + { + if (st->ncolors > 2) + { + XSetForeground (st->dpy, st->gc, st->colors [st->pixcol].pixel); + if (--st->pixcol < 0) + st->pixcol = st->ncolors - 1; + } + } + + /* number of functions */ + st->snum = 2 + (st->cur_level % (MAXLEV - 1)); + + /* how many of them are of alternate form */ + if (st->flame_alt) + st->anum = 0; + else + st->anum = halfrandom (st, st->snum) + 2; + + /* 6 coefs per function */ + for (k = 0; k < st->snum; k++) + { + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + st->f[i][j][k] = ((double) (random() & 1023) / 512.0 - 1.0); + } + st->num_points = 0; + st->total_points = 0; + recurse (st, 0.0, 0.0, 0, st->dpy, st->window); + XDrawPoints (st->dpy, st->window, st->gc, st->points, st->num_points, CoordModeOrigin); + + return this_delay; +} + + +#if defined(__hpux) && defined(PLOSS) +/* I don't understand why this is necessary, but I'm told that this program + does nothing at all on HP-sUX without it. + + I'm further told that HPUX 11.0 doesn't define PLOSS, and works ok without + this section. Go figure. + */ +#undef random +#undef srandom +#include +int matherr(x) + register struct exception *x; +{ + if (x->type == PLOSS) return 1; + else return 0; +} +#endif /* __hpux */ + + + +static const char *flame_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*colors: 64", + "*iterations: 25", + "*delay: 50000", + "*delay2: 2000000", + "*points: 10000", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec flame_options [] = { + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-iterations", ".iterations", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-delay2", ".delay2", XrmoptionSepArg, 0 }, + { "-points", ".points", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +static void +flame_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; +} + +#if 0 + static Bool + flame_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +flame_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +XSCREENSAVER_MODULE ("Flame", flame) + diff --git a/non-wgl/flame.vcproj b/non-wgl/flame.vcproj new file mode 100644 index 0000000..08ee49b --- /dev/null +++ b/non-wgl/flame.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/flow.c b/non-wgl/flow.c new file mode 100644 index 0000000..f62bf27 --- /dev/null +++ b/non-wgl/flow.c @@ -0,0 +1,1239 @@ +/* -*- Mode: C; tab-width: 4; c-basic-offset: 4 -*- */ +/* flow --- flow of strange bees */ + +#if 0 +#if !defined( lint ) && !defined( SABER ) +static const char sccsid[] = "@(#)flow.c 5.00 2000/11/01 xlockmore"; +#endif +#endif + +/*- + * Copyright (c) 1996 by Tim Auckland + * Incorporating some code from Stephen Davies Copyright (c) 2000 + * + * Search code based on techniques described in "Strange Attractors: + * Creating Patterns in Chaos" by Julien C. Sprott + * + * 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. + * + * "flow" shows a variety of continuous phase-space flows around strange + * attractors. It includes the well-known Lorentz mask (the "Butterfly" + * of chaos fame), two forms of Rossler's "Folded Band" and Poincare' + * sections of the "Birkhoff Bagel" and Duffing's forced occilator. "flow" + * can now discover new attractors. + * + * Revision History: + * + * 29-Oct-2004: [TDA] Discover Attractors unknown to science. + * Replace 2D rendering of Periodic Attractors with a 3D + * 'interrupted' rendering. Replace "-/+allow2d" with "-/+periodic" + * Replace all ODE formulae with completely generic forms. + * Add '-search' option to perform background high-speed discovery + * for completely new attractors without impacting rendering + * performance. + * Use gaussian distribution for initial point positions and for + * parameter search. + * Add "+dbuf" option to allow Double-Buffering to be turned off on + * slow X servers. + * Remove redundant '-zoom' option. Now automatically zooms if both + * rotation and riding are permitted. + * Replace dynamic bounding box with static one pre-calculated + * during discovery phase. + * Simplify and fix bounding box clipping code. Should now be safe + * to run without double buffer on all XFree86 servers if desired. + * 12-Oct-2004: [TDA] Merge Xscreensaver and Xlockmore branches + * Added Chalky's orbital camera, but made the zooming work by + * flying the camera rather than interpolating the view transforms. + * Added Chalky's Bounding Box, but time-averaged the boundaries to + * let the lost bees escape. + * Added Chalky's 'view-frustrum' clipping, but only applying it to + * the Bounding Box. Trails make clipping less useful. + * Added Chalky's "-slow" and "-freeze" options for compatibility, + * but haven't implemented the features, since the results are ugly + * and make no mathematical contribution. + * Added Double-Buffering as a work-around for a persistent XFree86 + * bug that left debris on the screen. + * 21-Mar-2003: [TDA] Trails added (XLockmore branch) + * 01-Nov-2000: [TDA] Allocation checks (XLockmore branch) + * 21-Feb-2000: [Chalky] Major hackage (Stephen Davies, chalky@null.net) + * (Xscreensaver branch) + * Forced perspective mode, added 3d box around attractor which + * involved coding 3d-planar-clipping against the view-frustrum + * thingy. Also made view alternate between piggybacking on a 'bee' + * to zooming around outside the attractor. Most bees slow down and + * stop, to make the structure of the attractor more obvious. +* 28-Jan-1999: [TDA] Catch 'lost' bees in flow.c and disable them. + * (XLockmore branch) + * I chose to disable them rather than reinitialise them because + * reinitialising can produce fake attractors. + * This has allowed me to relax some of the parameters and initial + * conditions slightly to catch some of the more extreme cases. As a + * result you may see some bees fly away at the start - these are the ones + * that 'missed' the attractor. If the bee with the camera should fly + * away the mode will restart :-) + * 31-Nov-1998: [TDA] Added Duffing (what a strange day that was :) DAB) + * Duffing's forced oscillator has been added to the formula list and + * the parameters section has been updated to display it in Poincare' + * section. + * 30-Nov-1998: [TDA] Added travelling perspective option + * A more exciting point-of-view has been added to all autonomous flows. + * This views the flow as seen by a particle moving with the flow. In the + * metaphor of the original code, I've attached a camera to one of the + * trained bees! + * 30-Nov-1998: [TDA] Much code cleanup. + * 09-Apr-1997: [TDA] Ported to xlockmore-4 + * 18-Jul-1996: Adapted from swarm.c Copyright (c) 1991 by Patrick J. Naughton. + * 31-Aug-1990: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org). + */ + +#define STANDALONE + +# define MODE_flow +#define DELAY 10000 +#define COUNT 3000 +#define SIZE_ -10 +#define CYCLES 10000 +#define NCOLORS 200 +# define DEFAULTS "*delay: 10000 \n" \ + "*count: 3000 \n" \ + "*size: -10 \n" \ + "*cycles: 10000 \n" \ + "*ncolors: 200 \n" + +# define flow_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_flow + +#define DEF_ROTATE "TRUE" +#define DEF_RIDE "TRUE" +#define DEF_BOX "TRUE" +#define DEF_PERIODIC "TRUE" +#define DEF_SEARCH "TRUE" +#define DEF_DBUF "TRUE" + +static Bool rotatep = True; +static Bool ridep = True; +static Bool boxp = True; +static Bool periodicp = True; +static Bool searchp = True; +static Bool dbufp = True; + +static XrmOptionDescRec opts[] = { + {"-rotate", ".flow.rotate", XrmoptionNoArg, "on"}, + {"+rotate", ".flow.rotate", XrmoptionNoArg, "off"}, + {"-ride", ".flow.ride", XrmoptionNoArg, "on"}, + {"+ride", ".flow.ride", XrmoptionNoArg, "off"}, + {"-box", ".flow.box", XrmoptionNoArg, "on"}, + {"+box", ".flow.box", XrmoptionNoArg, "off"}, + {"-periodic", ".flow.periodic", XrmoptionNoArg, "on"}, + {"+periodic", ".flow.periodic", XrmoptionNoArg, "off"}, + {"-search", ".flow.search", XrmoptionNoArg, "on"}, + {"+search", ".flow.search", XrmoptionNoArg, "off"}, + {"-dbuf", ".flow.dbuf", XrmoptionNoArg, "on"}, + {"+dbuf", ".flow.dbuf", XrmoptionNoArg, "off"}, +}; + +static argtype vars[] = { + {&rotatep, "rotate", "Rotate", DEF_ROTATE, t_Bool}, + {&ridep, "ride", "Ride", DEF_RIDE, t_Bool}, + {&boxp, "box", "Box", DEF_BOX, t_Bool}, + {&periodicp, "periodic", "Periodic", DEF_PERIODIC, t_Bool}, + {&searchp, "search", "Search", DEF_SEARCH, t_Bool}, + {&dbufp, "dbuf", "Dbuf", DEF_DBUF, t_Bool}, +}; + +static OptionStruct desc[] = { + {"-/+rotate", "turn on/off rotating around attractor."}, + {"-/+ride", "turn on/off ride in the flow."}, + {"-/+box", "turn on/off bounding box."}, + {"-/+periodic", "turn on/off periodic attractors."}, + {"-/+search", "turn on/off search for new attractors."}, + {"-/+dbuf", "turn on/off double buffering."}, +}; + +ENTRYPOINT ModeSpecOpt flow_opts = +{sizeof opts / sizeof opts[0], opts, + sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct flow_description = { + "flow", "init_flow", "draw_flow", "release_flow", + "refresh_flow", "init_flow", NULL, &flow_opts, + 1000, 1024, 10000, -10, 200, 1.0, "", + "Shows dynamic strange attractors", 0, NULL +}; + +#endif + +typedef struct { double x, y, z; } dvector; + +#define N_PARS 20 /* Enough for Full Cubic or Periodic Cubic */ +typedef dvector Par[N_PARS]; +enum { /* Name the parameter indices to make it easier to write + standard examples */ + C, + X,XX,XXX,XXY,XXZ,XY,XYY,XYZ,XZ,XZZ, + Y,YY,YYY,YYZ,YZ,YZZ, + Z,ZZ,ZZZ, + SINY = XY /* OK to overlap in this case */ +}; + +/* Camera target [TDA] */ +typedef enum { + ORBIT = 0, + BEE = 1 +} Chaseto; + +/* Macros */ +#define IX(C) ((C) * segindex + sp->cnsegs[(C)]) +#define B(t,b) (sp->p + (t) + (b) * sp->taillen) +#define X(t,b) (B((t),(b))->x) +#define Y(t,b) (B((t),(b))->y) +#define Z(t,b) (B((t),(b))->z) +#define balance_rand(v) ((LRAND()/MAXRAND*(v))-((v)/2)) /* random around 0 */ +#define LOST_IN_SPACE 2000.0 +#define INITIALSTEP 0.04 +#define EYEHEIGHT 0.005 +#define MINTRAIL 2 +#define BOX_L 36 + +/* Points that make up the box (normalized coordinates) */ +static const double box[][3] = { + {1,1,1}, /* 0 */ + {1,1,-1}, /* 1 */ + {1,-1,-1}, /* 2 */ + {1,-1,1}, /* 3 */ + {-1,1,1}, /* 4 */ + {-1,1,-1}, /* 5 */ + {-1,-1,-1},/* 6 */ + {-1,-1,1}, /* 7 */ + {1, .8, .8}, + {1, .8,-.8}, + {1,-.8,-.8}, + {1,-.8, .8}, + { .8,1, .8}, + { .8,1,-.8}, + {-.8,1,-.8}, + {-.8,1, .8}, + { .8, .8,1}, + { .8,-.8,1}, + {-.8,-.8,1}, + {-.8, .8,1}, + {-1, .8, .8}, + {-1, .8,-.8}, + {-1,-.8,-.8}, + {-1,-.8, .8}, + { .8,-1, .8}, + { .8,-1,-.8}, + {-.8,-1,-.8}, + {-.8,-1, .8}, + { .8, .8,-1}, + { .8,-.8,-1}, + {-.8,-.8,-1}, + {-.8, .8,-1} +}; + +/* Lines connecting the box dots */ +static const double lines[][2] = { + {0,1}, {1,2}, {2,3}, {3,0}, /* box */ + {4,5}, {5,6}, {6,7}, {7,4}, + {0,4}, {1,5}, {2,6}, {3,7}, + {4+4,5+4}, {5+4,6+4}, {6+4,7+4}, {7+4,4+4}, + {4+8,5+8}, {5+8,6+8}, {6+8,7+8}, {7+8,4+8}, + {4+12,5+12}, {5+12,6+12}, {6+12,7+12}, {7+12,4+12}, + {4+16,5+16}, {5+16,6+16}, {6+16,7+16}, {7+16,4+16}, + {4+20,5+20}, {5+20,6+20}, {6+20,7+20}, {7+20,4+20}, + {4+24,5+24}, {5+24,6+24}, {6+24,7+24}, {7+24,4+24}, +}; + +typedef struct { + /* Variables used in rendering */ + dvector cam[3]; /* camera flight path */ + int chasetime; + Chaseto chaseto; + Pixmap buffer; /* Double Buffer */ + dvector circle[2]; /* POV that circles around the scene */ + dvector centre; /* centre */ + int beecount; /* number of bees */ + XSegment *csegs; /* bee lines */ + int *cnsegs; + XSegment *old_segs; /* old bee lines */ + int nold_segs; + int taillen; + + /* Variables common to iterators */ + dvector (*ODE) (Par par, double x, double y, double z); + dvector range; /* Initial conditions */ + double yperiod; /* ODE's where Y is periodic. */ + + /* Variables used in iterating main flow */ + Par par; + dvector *p; /* bee positions x[time][bee#] */ + int count; + double lyap; + double size; + dvector mid; /* Effective bounding box */ + double step; + + /* second set of variables, used for parallel search */ + Par par2; + dvector p2[2]; + int count2; + double lyap2; + double size2; + dvector mid2; + double step2; + +} flowstruct; + +static flowstruct *flows = (flowstruct *) NULL; + +/* + * Private functions + */ + + +/* ODE functions */ + +/* Generic 3D Cubic Polynomial. Includes all the Quadratics (Lorentz, + Rossler) and much more! */ + +/* I considered offering a seperate 'Quadratic' option, since Cubic is + clearly overkill for the standard examples, but the performance + difference is too small to measure. The compute time is entirely + dominated by the XDrawSegments calls anyway. [TDA] */ +static dvector +Cubic(Par a, double x, double y, double z) +{ + dvector d; + d.x = a[C].x + a[X].x*x + a[XX].x*x*x + a[XXX].x*x*x*x + a[XXY].x*x*x*y + + a[XXZ].x*x*x*z + a[XY].x*x*y + a[XYY].x*x*y*y + a[XYZ].x*x*y*z + + a[XZ].x*x*z + a[XZZ].x*x*z*z + a[Y].x*y + a[YY].x*y*y + + a[YYY].x*y*y*y + a[YYZ].x*y*y*z + a[YZ].x*y*z + a[YZZ].x*y*z*z + + a[Z].x*z + a[ZZ].x*z*z + a[ZZZ].x*z*z*z; + + d.y = a[C].y + a[X].y*x + a[XX].y*x*x + a[XXX].y*x*x*x + a[XXY].y*x*x*y + + a[XXZ].y*x*x*z + a[XY].y*x*y + a[XYY].y*x*y*y + a[XYZ].y*x*y*z + + a[XZ].y*x*z + a[XZZ].y*x*z*z + a[Y].y*y + a[YY].y*y*y + + a[YYY].y*y*y*y + a[YYZ].y*y*y*z + a[YZ].y*y*z + a[YZZ].y*y*z*z + + a[Z].y*z + a[ZZ].y*z*z + a[ZZZ].y*z*z*z; + + d.z = a[C].z + a[X].z*x + a[XX].z*x*x + a[XXX].z*x*x*x + a[XXY].z*x*x*y + + a[XXZ].z*x*x*z + a[XY].z*x*y + a[XYY].z*x*y*y + a[XYZ].z*x*y*z + + a[XZ].z*x*z + a[XZZ].z*x*z*z + a[Y].z*y + a[YY].z*y*y + + a[YYY].z*y*y*y + a[YYZ].z*y*y*z + a[YZ].z*y*z + a[YZZ].z*y*z*z + + a[Z].z*z + a[ZZ].z*z*z + a[ZZZ].z*z*z*z; + + return d; +} + +/* 3D Cubic in (x,z) with periodic sinusoidal forcing term in x. y is + the independent periodic (time) axis. This includes Birkhoff's + Bagel and Duffing's Attractor */ +static dvector +Periodic(Par a, double x, double y, double z) +{ + dvector d; + + d.x = a[C].x + a[X].x*x + a[XX].x*x*x + a[XXX].x*x*x*x + + a[XXZ].x*x*x*z + a[XZ].x*x*z + a[XZZ].x*x*z*z + a[Z].x*z + + a[ZZ].x*z*z + a[ZZZ].x*z*z*z + a[SINY].x*sin(y); + + d.y = a[C].y; + + d.z = a[C].z + a[X].z*x + a[XX].z*x*x + a[XXX].z*x*x*x + + a[XXZ].z*x*x*z + a[XZ].z*x*z + a[XZZ].z*x*z*z + a[Z].z*z + + a[ZZ].z*z*z + a[ZZZ].z*z*z*z; + + return d; +} + +/* Numerical integration of the ODE using 2nd order Runge Kutta. + Returns length^2 of the update, so that we can detect if the step + size needs reducing. */ +static double +Iterate(dvector *p, dvector(*ODE)(Par par, double x, double y, double z), + Par par, double step) +{ + dvector k1, k2, k3; + + k1 = ODE(par, p->x, p->y, p->z); + k1.x *= step; + k1.y *= step; + k1.z *= step; + k2 = ODE(par, p->x + k1.x, p->y + k1.y, p->z + k1.z); + k2.x *= step; + k2.y *= step; + k2.z *= step; + k3.x = (k1.x + k2.x) / 2.0; + k3.y = (k1.y + k2.y) / 2.0; + k3.z = (k1.z + k2.z) / 2.0; + + p->x += k3.x; + p->y += k3.y; + p->z += k3.z; + + return k3.x*k3.x + k3.y*k3.y + k3.z*k3.z; +} + +/* Memory functions */ + +#define deallocate(p,t) if (p!=NULL) {free(p); p=(t*)NULL; } +#define allocate(p,t,s) if ((p=(t*)malloc(sizeof(t)*s))==NULL)\ +{free_flow(sp);return;} + +static void +free_flow(flowstruct *sp) +{ + deallocate(sp->csegs, XSegment); + deallocate(sp->cnsegs, int); + deallocate(sp->old_segs, XSegment); + deallocate(sp->p, dvector); +} + +/* Generate Gaussian random number: mean 0, "amplitude" A (actually + A is 3*standard deviation). */ + +/* Note this generates a pair of gaussian variables, so it saves one + to give out next time it's called */ +static double +Gauss_Rand(double A) +{ + static double d; + static Bool ready = 0; + if(ready) { + ready = 0; + return A/3 * d; + } else { + double x, y, w; + do { + x = 2.0 * (double)LRAND() / MAXRAND - 1.0; + y = 2.0 * (double)LRAND() / MAXRAND - 1.0; + w = x*x + y*y; + } while(w >= 1.0); + + w = sqrt((-2 * log(w))/w); + ready = 1; + d = x * w; + return A/3 * y * w; + } +} + +/* Attempt to discover new atractors by sending a pair of bees on a + fast trip through the new flow and computing their Lyapunov + exponent. Returns False if the bees fly away. + + If the bees stay bounded, the new bounds and the Lyapunov exponent + are stored in sp and the function returns True. + + Repeat invocations continue the flow and improve the accuracy of + the bounds and the Lyapunov exponent. Set sp->count2 to zero to + start a new test. + + Acts on alternate variable set, so that it can be run in parallel + with the main flow */ + +static Bool +discover(ModeInfo * mi) +{ + flowstruct *sp; + double l = 0; + dvector dl; + dvector max, min; + double dl2, df, rs, lsum = 0, s, maxv2 = 0, v2; + + int N, i, nl = 0; + + if (flows == NULL) + return 0; + sp = &flows[MI_SCREEN(mi)]; + + if(sp->count2 == 0) { + /* initial conditions */ + sp->p2[0].x = Gauss_Rand(sp->range.x); + sp->p2[0].y = (sp->yperiod > 0)? + balance_rand(sp->range.y) : Gauss_Rand(sp->range.y); + sp->p2[0].z = Gauss_Rand(sp->range.z); + + /* 1000 steps to find an attractor */ + /* Most cases explode out here */ + for(N=0; N < 1000; N++){ + Iterate(sp->p2, sp->ODE, sp->par2, sp->step2); + if(sp->yperiod > 0 && sp->p2[0].y > sp->yperiod) + sp->p2[0].y -= sp->yperiod; + if(fabs(sp->p2[0].x) > LOST_IN_SPACE || + fabs(sp->p2[0].y) > LOST_IN_SPACE || + fabs(sp->p2[0].z) > LOST_IN_SPACE) { + return 0; + } + sp->count2++; + } + /* Small perturbation */ + sp->p2[1].x = sp->p2[0].x + 0.000001; + sp->p2[1].y = sp->p2[0].y; + sp->p2[1].z = sp->p2[0].z; + } + + /* Reset bounding box */ + max.x = min.x = sp->p2[0].x; + max.y = min.y = sp->p2[0].y; + max.z = min.z = sp->p2[0].z; + + /* Compute Lyapunov Exponent */ + + /* (Technically, we're only estimating the largest Lyapunov + Exponent, but that's all we need to know to determine if we + have a strange attractor.) [TDA] */ + + /* Fly two bees close together */ + for(N=0; N < 5000; N++){ + for(i=0; i< 2; i++) { + v2 = Iterate(sp->p2+i, sp->ODE, sp->par2, sp->step2); + if(sp->yperiod > 0 && sp->p2[i].y > sp->yperiod) + sp->p2[i].y -= sp->yperiod; + + if(fabs(sp->p2[i].x) > LOST_IN_SPACE || + fabs(sp->p2[i].y) > LOST_IN_SPACE || + fabs(sp->p2[i].z) > LOST_IN_SPACE) { + return 0; + } + if(v2 > maxv2) maxv2 = v2; /* Track max v^2 */ + } + + /* find bounding box */ + if ( sp->p2[0].x < min.x ) min.x = sp->p2[0].x; + else if ( sp->p2[0].x > max.x ) max.x = sp->p2[0].x; + if ( sp->p2[0].y < min.y ) min.y = sp->p2[0].y; + else if ( sp->p2[0].y > max.y ) max.y = sp->p2[0].y; + if ( sp->p2[0].z < min.z ) min.z = sp->p2[0].z; + else if ( sp->p2[0].z > max.z ) max.z = sp->p2[0].z; + + /* Measure how much we have to pull the two bees to prevent + them diverging. */ + dl.x = sp->p2[1].x - sp->p2[0].x; + dl.y = sp->p2[1].y - sp->p2[0].y; + dl.z = sp->p2[1].z - sp->p2[0].z; + + dl2 = dl.x*dl.x + dl.y*dl.y + dl.z*dl.z; + if(dl2 > 0) { + df = 1e12 * dl2; + rs = 1/sqrt(df); + sp->p2[1].x = sp->p2[0].x + rs * dl.x; + sp->p2[1].y = sp->p2[0].y + rs * dl.y; + sp->p2[1].z = sp->p2[0].z + rs * dl.z; + lsum = lsum + log(df); + nl = nl + 1; + l = M_LOG2E / 2 * lsum / nl / sp->step2; + } + sp->count2++; + } + /* Anything that didn't explode has a finite attractor */ + /* If Lyapunov is negative then it probably hit a fixed point or a + * limit cycle. Positive Lyapunov indicates a strange attractor. */ + + sp->lyap2 = l; + + sp->size2 = max.x - min.x; + s = max.y - min.y; + if(s > sp->size2) sp->size2 = s; + s = max.z - min.z; + if(s > sp->size2) sp->size2 = s; + + sp->mid2.x = (max.x + min.x) / 2; + sp->mid2.y = (max.y + min.y) / 2; + sp->mid2.z = (max.z + min.z) / 2; + + if(sqrt(maxv2) > sp->size2 * 0.2) { + /* Flowing too fast, reduce step size. This + helps to eliminate high-speed limit cycles, + which can show +ve Lyapunov due to integration + inaccuracy. */ + sp->step2 /= 2; + } + return 1; +} + +/* Sets up initial conditions for a flow without all the extra baggage + that goes with init_flow */ +static void +restart_flow(ModeInfo * mi) +{ + flowstruct *sp; + int b; + + if (flows == NULL) + return; + sp = &flows[MI_SCREEN(mi)]; + sp->count = 0; + + /* Re-Initialize point positions, velocities, etc. */ + for (b = 0; b < sp->beecount; b++) { + X(0, b) = Gauss_Rand(sp->range.x); + Y(0, b) = (sp->yperiod > 0)? + balance_rand(sp->range.y) : Gauss_Rand(sp->range.y); + Z(0, b) = Gauss_Rand(sp->range.z); + } +} + +/* Returns true if line was behind a clip plane, or it clips the line */ +/* nx,ny,nz is the normal to the plane. d is the distance from the origin */ +/* s and e are the end points of the line to be clipped */ +static int +clip(double nx, double ny, double nz, double d, dvector *s, dvector *e) +{ + int front1, front2; + dvector w, p; + double t; + + front1 = (nx*s->x + ny*s->y + nz*s->z >= -d); + front2 = (nx*e->x + ny*e->y + nz*e->z >= -d); + if (!front1 && !front2) return 1; + if (front1 && front2) return 0; + w.x = e->x - s->x; + w.y = e->y - s->y; + w.z = e->z - s->z; + + /* Find t in line equation */ + t = ( -d - nx*s->x - ny*s->y - nz*s->z) / ( nx*w.x + ny*w.y + nz*w.z); + + p.x = s->x + w.x * t; + p.y = s->y + w.y * t; + p.z = s->z + w.z * t; + + /* Move clipped point to the intersection */ + if (front2) { + *s = p; + } else { + *e = p; + } + return 0; +} + +/* + * Public functions + */ + +ENTRYPOINT void +init_flow (ModeInfo * mi) +{ + flowstruct *sp; + char *name; + + if (flows == NULL) { + if ((flows = (flowstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (flowstruct))) == NULL) + return; + } + sp = &flows[MI_SCREEN(mi)]; + + sp->count2 = 0; + + sp->taillen = MI_SIZE(mi); + if (sp->taillen < -MINTRAIL) { + /* Change by sqrt so it seems more variable */ + sp->taillen = NRAND((int)sqrt((double) (-sp->taillen - MINTRAIL + 1))); + sp->taillen = sp->taillen * sp->taillen + MINTRAIL; + } else if (sp->taillen < MINTRAIL) { + sp->taillen = MINTRAIL; + } + + if(!rotatep && !ridep) rotatep = True; /* We need at least one viewpoint */ + + /* Start camera at Orbit or Bee */ + if(rotatep) { + sp->chaseto = ORBIT; + } else { + sp->chaseto = BEE; + } + sp->chasetime = 1; /* Go directly to target */ + + sp->lyap = 0; + sp->yperiod = 0; + sp->step2 = INITIALSTEP; + + /* Zero parameter set */ + memset(sp->par2, 0, N_PARS * sizeof(dvector)); + + /* Set up standard examples */ + switch (NRAND((periodicp) ? 5 : 3)) { + case 0: + /* + x' = a(y - x) + y' = x(b - z) - y + z' = xy - cz + */ + name = "Lorentz"; + sp->par2[Y].x = 10 + balance_rand(5*0); /* a */ + sp->par2[X].x = - sp->par2[Y].x; /* -a */ + sp->par2[X].y = 28 + balance_rand(5*0); /* b */ + sp->par2[XZ].y = -1; + sp->par2[Y].y = -1; + sp->par2[XY].z = 1; + sp->par2[Z].z = - 2 + balance_rand(1*0); /* -c */ + break; + case 1: + /* + x' = -(y + az) + y' = x + by + z' = c + z(x - 5.7) + */ + name = "Rossler"; + sp->par2[Y].x = -1; + sp->par2[Z].x = -2 + balance_rand(1); /* a */ + sp->par2[X].y = 1; + sp->par2[Y].y = 0.2 + balance_rand(0.1); /* b */ + sp->par2[C].z = 0.2 + balance_rand(0.1); /* c */ + sp->par2[XZ].z = 1; + sp->par2[Z].z = -5.7; + break; + case 2: + /* + x' = -(y + az) + y' = x + by - cz^2 + z' = 0.2 + z(x - 5.7) + */ + name = "RosslerCone"; + sp->par2[Y].x = -1; + sp->par2[Z].x = -2; /* a */ + sp->par2[X].y = 1; + sp->par2[Y].y = 0.2; /* b */ + sp->par2[ZZ].y = -0.331 + balance_rand(0.01); /* c */ + sp->par2[C].z = 0.2; + sp->par2[XZ].z = 1; + sp->par2[Z].z = -5.7; + break; + case 3: + /* + x' = -z + b sin(y) + y' = c + z' = 0.7x + az(0.1 - x^2) + */ + name = "Birkhoff"; + sp->par2[Z].x = -1; + sp->par2[SINY].x = 0.35 + balance_rand(0.25); /* b */ + sp->par2[C].y = 1.57; /* c */ + sp->par2[X].z = 0.7; + sp->par2[Z].z = 1 + balance_rand(0.5); /* a/10 */ + sp->par2[XXZ].z = -10 * sp->par2[Z].z; /* -a */ + sp->yperiod = 2 * M_PI; + break; + default: + /* + x' = -ax - z/2 - z^3/8 + b sin(y) + y' = c + z' = 2x + */ + name = "Duffing"; + sp->par2[X].x = -0.2 + balance_rand(0.1); /* a */ + sp->par2[Z].x = -0.5; + sp->par2[ZZZ].x = -0.125; + sp->par2[SINY].x = 27.0 + balance_rand(3.0); /* b */ + sp->par2[C].y = 1.33; /* c */ + sp->par2[X].z = 2; + sp->yperiod = 2 * M_PI; + break; + + } + + sp->range.x = 5; + sp->range.z = 5; + + if(sp->yperiod > 0) { + sp->ODE = Periodic; + /* periodic flows show either uniform distribution or a + snapshot on the 'time' axis */ + sp->range.y = NRAND(2)? sp->yperiod : 0; + } else { + sp->range.y = 5; + sp->ODE = Cubic; + } + + /* Run discoverer to set up bounding box, etc. Lyapunov will + probably be innaccurate, since we're only running it once, but + we're using known strange attractors so it should be ok. */ + discover(mi); + if(MI_IS_VERBOSE(mi)) + fprintf(stdout, + "flow: Lyapunov exponent: %g, step: %g, size: %g (%s)\n", + sp->lyap2, sp->step2, sp->size2, name); + /* Install new params */ + sp->lyap = sp->lyap2; + sp->size = sp->size2; + sp->mid = sp->mid2; + sp->step = sp->step2; + memcpy(sp->par, sp->par2, sizeof(sp->par2)); + + sp->count2 = 0; /* Reset search */ + + free_flow(sp); + sp->beecount = MI_COUNT(mi); + if (sp->beecount < 0) { /* random variations */ + sp->beecount = NRAND(-sp->beecount) + 1; /* Minimum 1 */ + } + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + dbufp = False; +# endif + + if(dbufp) { /* Set up double buffer */ + if (sp->buffer != None) + XFreePixmap(MI_DISPLAY(mi), sp->buffer); + sp->buffer = XCreatePixmap(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_WIDTH(mi), MI_HEIGHT(mi), MI_DEPTH(mi)); + } else { + sp->buffer = MI_WINDOW(mi); + } + /* no "NoExpose" events from XCopyArea wanted */ + XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False); + + /* Make sure we're using 'thin' lines */ + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 0, LineSolid, CapNotLast, + JoinMiter); + + /* Clear the background (may be slow depending on user prefs). */ + MI_CLEARWINDOW(mi); + + /* Allocate memory. */ + if (sp->csegs == NULL) { + allocate(sp->csegs, XSegment, + (sp->beecount + BOX_L) * MI_NPIXELS(mi) * sp->taillen); + allocate(sp->cnsegs, int, MI_NPIXELS(mi)); + allocate(sp->old_segs, XSegment, sp->beecount * sp->taillen); + allocate(sp->p, dvector, sp->beecount * sp->taillen); + } + + /* Initialize point positions, velocities, etc. */ + restart_flow(mi); + + /* Set up camera tail */ + X(1, 0) = sp->cam[1].x = 0; + Y(1, 0) = sp->cam[1].y = 0; + Z(1, 0) = sp->cam[1].z = 0; +} + +ENTRYPOINT void +draw_flow (ModeInfo * mi) +{ + int b, i; + int col, begin, end; + double M[3][3]; /* transformation matrix */ + flowstruct *sp = NULL; + int swarm = 0; + int segindex; + + if (flows == NULL) + return; + sp = &flows[MI_SCREEN(mi)]; + if (sp->csegs == NULL) + return; + +#ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi)); +#endif + + /* multiplier for indexing segment arrays. Used in IX macro, etc. */ + segindex = (sp->beecount + BOX_L) * sp->taillen; + + if(searchp){ + if(sp->count2 == 0) { /* start new search */ + sp->step2 = INITIALSTEP; + /* Pick random parameters. Actual range is irrelevant + since parameter scale determines flow speed but not + structure. */ + for(i=0; i< N_PARS; i++) { + sp->par2[i].x = Gauss_Rand(1.0); + sp->par2[i].y = Gauss_Rand(1.0); + sp->par2[i].z = Gauss_Rand(1.0); + } + } + if(!discover(mi)) { /* Flow exploded, reset. */ + sp->count2 = 0; + } else { + if(sp->lyap2 < 0) { + sp->count2 = 0; /* Attractor found, but it's not strange */ + }else if(sp->count2 > 1000000) { /* This one will do */ + sp->count2 = 0; /* Reset search */ + if(MI_IS_VERBOSE(mi)) + fprintf(stdout, + "flow: Lyapunov exponent: %g, step: %g, size: %g (unnamed)\n", + sp->lyap2, sp->step2, sp->size2); + /* Install new params */ + sp->lyap = sp->lyap2; + sp->size = sp->size2; + sp->mid = sp->mid2; + sp->step = sp->step2; + memcpy(sp->par, sp->par2, sizeof(sp->par2)); + + /* If we're allowed to zoom out, do so now, so that we + get a look at the new attractor. */ + if(sp->chaseto == BEE && rotatep) { + sp->chaseto = ORBIT; + sp->chasetime = 100; + } + /* Reset initial conditions, so we don't get + misleading artifacts in the particle density. */ + restart_flow(mi); + } + } + } + + /* Reset segment buffers */ + for (col = 0; col < MI_NPIXELS(mi); col++) + sp->cnsegs[col] = 0; + + MI_IS_DRAWN(mi) = True; + + /* Calculate circling POV [Chalky]*/ + sp->circle[1] = sp->circle[0]; + sp->circle[0].x = sp->size * 2 * sin(sp->count / 100.0) * + (-0.6 + 0.4 *cos(sp->count / 500.0)) + sp->mid.x; + sp->circle[0].y = sp->size * 2 * cos(sp->count / 100.0) * + (0.6 + 0.4 *cos(sp->count / 500.0)) + sp->mid.y; + sp->circle[0].z = sp->size * 2 * sin(sp->count / 421.0) + sp->mid.z; + + /* Timed chase instead of Chalkie's Bistable oscillator [TDA] */ + if(rotatep && ridep) { + if(sp->chaseto == BEE && NRAND(1000) == 0){ + sp->chaseto = ORBIT; + sp->chasetime = 100; + }else if(NRAND(4000) == 0){ + sp->chaseto = BEE; + sp->chasetime = 100; + } + } + + /* Set up orientation matrix */ + { + double x[3], p[3], x2=0, xp=0; + int j; + + /* Chasetime is here to guarantee the camera makes it all the + way to the target in a finite number of steps. */ + if(sp->chasetime > 1) + sp->chasetime--; + + if(sp->chaseto == BEE){ + /* Camera Head targets bee 0 */ + sp->cam[0].x += (X(0, 0) - sp->cam[0].x)/sp->chasetime; + sp->cam[0].y += (Y(0, 0) - sp->cam[0].y)/sp->chasetime; + sp->cam[0].z += (Z(0, 0) - sp->cam[0].z)/sp->chasetime; + + /* Camera Tail targets previous position of bee 0 */ + sp->cam[1].x += (X(1, 0) - sp->cam[1].x)/sp->chasetime; + sp->cam[1].y += (Y(1, 0) - sp->cam[1].y)/sp->chasetime; + sp->cam[1].z += (Z(1, 0) - sp->cam[1].z)/sp->chasetime; + + /* Camera Wing targets bee 1 */ + sp->cam[2].x += (X(0, 1) - sp->cam[2].x)/sp->chasetime; + sp->cam[2].y += (Y(0, 1) - sp->cam[2].y)/sp->chasetime; + sp->cam[2].z += (Z(0, 1) - sp->cam[2].z)/sp->chasetime; + } else { + /* Camera Head targets Orbiter */ + sp->cam[0].x += (sp->circle[0].x - sp->cam[0].x)/sp->chasetime; + sp->cam[0].y += (sp->circle[0].y - sp->cam[0].y)/sp->chasetime; + sp->cam[0].z += (sp->circle[0].z - sp->cam[0].z)/sp->chasetime; + + /* Camera Tail targets diametrically opposite the middle + of the bounding box from the Orbiter */ + sp->cam[1].x += + (2*sp->circle[0].x - sp->mid.x - sp->cam[1].x)/sp->chasetime; + sp->cam[1].y += + (2*sp->circle[0].y - sp->mid.y - sp->cam[1].y)/sp->chasetime; + sp->cam[1].z += + (2*sp->circle[0].z - sp->mid.z - sp->cam[1].z)/sp->chasetime; + /* Camera Wing targets previous position of Orbiter */ + sp->cam[2].x += (sp->circle[1].x - sp->cam[2].x)/sp->chasetime; + sp->cam[2].y += (sp->circle[1].y - sp->cam[2].y)/sp->chasetime; + sp->cam[2].z += (sp->circle[1].z - sp->cam[2].z)/sp->chasetime; + } + + /* Viewpoint from Tail of camera */ + sp->centre.x=sp->cam[1].x; + sp->centre.y=sp->cam[1].y; + sp->centre.z=sp->cam[1].z; + + /* forward vector */ + x[0] = sp->cam[0].x - sp->cam[1].x; + x[1] = sp->cam[0].y - sp->cam[1].y; + x[2] = sp->cam[0].z - sp->cam[1].z; + + /* side */ + p[0] = sp->cam[2].x - sp->cam[1].x; + p[1] = sp->cam[2].y - sp->cam[1].y; + p[2] = sp->cam[2].z - sp->cam[1].z; + + + /* So long as X and P don't collide, these can be used to form + three mutually othogonal axes: X, (X x P) x X and X x P. + After being normalised to unit length, these form the + Orientation Matrix. */ + + for(i=0; i<3; i++){ + x2+= x[i]*x[i]; /* X . X */ + xp+= x[i]*p[i]; /* X . P */ + M[0][i] = x[i]; /* X */ + } + + for(i=0; i<3; i++) /* (X x P) x X */ + M[1][i] = x2*p[i] - xp*x[i]; /* == (X . X) P - (X . P) X */ + + M[2][0] = x[1]*p[2] - x[2]*p[1]; /* X x P */ + M[2][1] = -x[0]*p[2] + x[2]*p[0]; + M[2][2] = x[0]*p[1] - x[1]*p[0]; + + /* normalise axes */ + for(j=0; j<3; j++){ + double A=0; + for(i=0; i<3; i++) A+=M[j][i]*M[j][i]; /* sum squares */ + A=sqrt(A); + if(A>0) + for(i=0; i<3; i++) M[j][i]/=A; + } + + if(sp->chaseto == BEE) { + X(0, 1)=X(0, 0)+M[1][0]*sp->step; /* adjust neighbour */ + Y(0, 1)=Y(0, 0)+M[1][1]*sp->step; + Z(0, 1)=Z(0, 0)+M[1][2]*sp->step; + } + } + + /* <=- Bounding Box -=> */ + if(boxp) { + for (b = 0; b < BOX_L; b++) { + + /* Chalky's clipping code, Only used for the box */ + /* clipping trails is slow and of little benefit. [TDA] */ + int p1 = lines[b][0]; + int p2 = lines[b][1]; + dvector A1, A2; + double x1=box[p1][0]* sp->size/2 + sp->mid.x - sp->centre.x; + double y1=box[p1][1]* sp->size/2 + sp->mid.y - sp->centre.y; + double z1=box[p1][2]* sp->size/2 + sp->mid.z - sp->centre.z; + double x2=box[p2][0]* sp->size/2 + sp->mid.x - sp->centre.x; + double y2=box[p2][1]* sp->size/2 + sp->mid.y - sp->centre.y; + double z2=box[p2][2]* sp->size/2 + sp->mid.z - sp->centre.z; + + A1.x=M[0][0]*x1 + M[0][1]*y1 + M[0][2]*z1; + A1.y=M[1][0]*x1 + M[1][1]*y1 + M[1][2]*z1; + A1.z=M[2][0]*x1 + M[2][1]*y1 + M[2][2]*z1 + EYEHEIGHT * sp->size; + A2.x=M[0][0]*x2 + M[0][1]*y2 + M[0][2]*z2; + A2.y=M[1][0]*x2 + M[1][1]*y2 + M[1][2]*z2; + A2.z=M[2][0]*x2 + M[2][1]*y2 + M[2][2]*z2 + EYEHEIGHT * sp->size; + + /* Clip in 3D before projecting down to 2D. A 2D clip + after projection wouldn't be able to handle lines that + cross x=0 */ + if (clip(1, 0, 0,-1, &A1, &A2) || /* Screen */ + clip(1, 2, 0, 0, &A1, &A2) || /* Left */ + clip(1,-2, 0, 0, &A1, &A2) || /* Right */ + clip(1,0, 2.0*MI_WIDTH(mi)/MI_HEIGHT(mi), 0, &A1, &A2)||/*UP*/ + clip(1,0,-2.0*MI_WIDTH(mi)/MI_HEIGHT(mi), 0, &A1, &A2))/*Down*/ + continue; + + /* Colour according to bee */ + col = b % (MI_NPIXELS(mi) - 1); + + sp->csegs[IX(col)].x1 = MI_WIDTH(mi)/2 + MI_WIDTH(mi) * A1.y/A1.x; + sp->csegs[IX(col)].y1 = MI_HEIGHT(mi)/2 + MI_WIDTH(mi) * A1.z/A1.x; + sp->csegs[IX(col)].x2 = MI_WIDTH(mi)/2 + MI_WIDTH(mi) * A2.y/A2.x; + sp->csegs[IX(col)].y2 = MI_HEIGHT(mi)/2 + MI_WIDTH(mi) * A2.z/A2.x; + sp->cnsegs[col]++; + } + } + + /* <=- Bees -=> */ + for (b = 0; b < sp->beecount; b++) { + if(fabs(X(0, b)) > LOST_IN_SPACE || + fabs(Y(0, b)) > LOST_IN_SPACE || + fabs(Z(0, b)) > LOST_IN_SPACE){ + if(sp->chaseto == BEE && b == 0){ + /* Lost camera bee. Need to replace it since + rerunning init_flow could lose us a hard-won new + attractor. Try moving it very close to a random + other bee. This way we have a good chance of being + close to the attractor and not forming a false + artifact. If we've lost many bees this may need to + be repeated. */ + /* Don't worry about camera wingbee. It stays close + to the main camera bee no matter what happens. */ + int newb = 1 + NRAND(sp->beecount - 1); + X(0, 0) = X(0, newb) + 0.001; + Y(0, 0) = Y(0, newb); + Z(0, 0) = Z(0, newb); + if(MI_IS_VERBOSE(mi)) + fprintf(stdout, + "flow: resetting lost camera near bee %d\n", + newb); + } + continue; + } + + /* Age the tail. It's critical this be fast since + beecount*taillen can be large. */ + memmove(B(1, b), B(0, b), (sp->taillen - 1) * sizeof(dvector)); + + Iterate(B(0,b), sp->ODE, sp->par, sp->step); + + /* Don't show wingbee since he's not quite in the flow. */ + if(sp->chaseto == BEE && b == 1) continue; + + /* Colour according to bee */ + col = b % (MI_NPIXELS(mi) - 1); + + /* Fill the segment lists. */ + + begin = 0; /* begin new trail */ + end = MIN(sp->taillen, sp->count); /* short trails at first */ + for(i=0; i < end; i++){ + double x = X(i,b)-sp->centre.x; + double y = Y(i,b)*(sp->yperiod < 0? (sp->size/sp->yperiod) :1) + -sp->centre.y; + double z = Z(i,b)-sp->centre.z; + double XM=M[0][0]*x + M[0][1]*y + M[0][2]*z; + double YM=M[1][0]*x + M[1][1]*y + M[1][2]*z; + double ZM=M[2][0]*x + M[2][1]*y + M[2][2]*z + EYEHEIGHT * sp->size; + short absx, absy; + + swarm++; /* count the remaining bees */ + if(sp->yperiod > 0 && Y(i,b) > sp->yperiod){ + int j; + Y(i,b) -= sp->yperiod; + /* hide tail to prevent streaks in Y. Streaks in X,Z + are ok, they help to outline the Poincare' + slice. */ + for(j = i; j < end; j++) Y(j,b) = Y(i,b); + /*begin = i + 1;*/ + break; + } + + if(XM <= 0){ /* off screen - new trail */ + begin = i + 1; + continue; + } + absx = MI_WIDTH(mi)/2 + MI_WIDTH(mi) * YM/XM; + absy = MI_HEIGHT(mi)/2 + MI_WIDTH(mi) * ZM/XM; + /* Performance bottleneck */ + if(absx <= 0 || absx >= MI_WIDTH(mi) || + absy <= 0 || absy >= MI_HEIGHT(mi)) { + /* off screen - new trail */ + begin = i + 1; + continue; + } + if(i > begin) { /* complete previous segment */ + sp->csegs[IX(col)].x2 = absx; + sp->csegs[IX(col)].y2 = absy; + sp->cnsegs[col]++; + } + + if(i < end -1){ /* start new segment */ + sp->csegs[IX(col)].x1 = absx; + sp->csegs[IX(col)].y1 = absy; + } + } + } + + /* Erase */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + if (dbufp) { /* In Double Buffer case, prepare off-screen copy */ + /* For slow systems, this can be the single biggest bottleneck + in the program. These systems may be better of not using + the double buffer. */ + XFillRectangle(MI_DISPLAY(mi), sp->buffer, MI_GC(mi), 0, 0, + MI_WIDTH(mi), MI_HEIGHT(mi)); + } else { /* Otherwise, erase previous segment list directly */ + XDrawSegments(MI_DISPLAY(mi), sp->buffer, MI_GC(mi), + sp->old_segs, sp->nold_segs); + } + + /* Render */ + if (MI_NPIXELS(mi) > 2){ /* colour */ + int mn = 0; + for (col = 0; col < MI_NPIXELS(mi) - 1; col++) + if (sp->cnsegs[col] > 0) { + if(sp->cnsegs[col] > mn) mn = sp->cnsegs[col]; + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, col+1)); + /* This is usually the biggest bottleneck on most + systems. The maths load is insignificant compared + to this. */ + XDrawSegments(MI_DISPLAY(mi), sp->buffer, MI_GC(mi), + sp->csegs + col * segindex, sp->cnsegs[col]); + } + } else { /* mono handled seperately since xlockmore uses '1' for + mono white! */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + XDrawSegments(MI_DISPLAY(mi), sp->buffer, MI_GC(mi), + sp->csegs, sp->cnsegs[0]); + } + if (dbufp) { /* In Double Buffer case, this updates the screen */ + XCopyArea(MI_DISPLAY(mi), sp->buffer, MI_WINDOW(mi), MI_GC(mi), 0, 0, + MI_WIDTH(mi), MI_HEIGHT(mi), 0, 0); + } else { /* Otherwise, screen is already updated. Copy segments + to erase-list to be erased directly next time. */ + int c = 0; + for (col = 0; col < MI_NPIXELS(mi) - 1; col++) { + memcpy(sp->old_segs + c, sp->csegs + col * segindex, + sp->cnsegs[col] * sizeof(XSegment)); + c += sp->cnsegs[col]; + } + sp->nold_segs = c; + } + + if(sp->count > 1 && swarm == 0) { /* all gone */ + if(MI_IS_VERBOSE(mi)) + fprintf(stdout, "flow: all gone at %d\n", sp->count); + init_flow(mi); + } + + if(sp->count++ > MI_CYCLES(mi)){ /* Time's up. If we haven't + found anything new by now we + should pick a new standard + flow */ + init_flow(mi); + } +} + +ENTRYPOINT void +reshape_flow(ModeInfo * mi, int width, int height) +{ + init_flow (mi); +} + + +ENTRYPOINT void +release_flow (ModeInfo * mi) +{ + if (flows != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_flow(&flows[screen]); + free(flows); + flows = (flowstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_flow (ModeInfo * mi) +{ + if(!dbufp) MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Flow", flow) + +#endif /* MODE_flow */ diff --git a/non-wgl/flow.vcproj b/non-wgl/flow.vcproj new file mode 100644 index 0000000..91e83c0 --- /dev/null +++ b/non-wgl/flow.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/forest.c b/non-wgl/forest.c new file mode 100644 index 0000000..fff6b2e --- /dev/null +++ b/non-wgl/forest.c @@ -0,0 +1,266 @@ +/* forest.c (aka xtree.c), Copyright (c) 1999 + * Peter Baumung + * + * Most code taken from + * xscreensaver, Copyright (c) 1992, 1995, 1997 + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* ****************************** NOTE ****************************** + + This is not the xlockmore version of forest, but a much better + looking rewrite. Be careful not to delete it in a merging frenzy... + + ********************************************************************** + */ + +#define STANDALONE +#define NOARGS +#define DELAY 500000 +#define NCOLORS 20 +# define DEFAULTS "*delay: 500000 \n" \ + "*ncolors: 20 \n" \ + "*fpsSolid: true \n" \ + +# define refresh_trees 0 +# define reshape_trees 0 +# define trees_handle_event 0 + + +#ifdef STANDALONE +# include "xlockmore.h" /* from the xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +#endif /* !STANDALONE */ + +ENTRYPOINT ModeSpecOpt trees_opts = {0, NULL, 0, NULL, NULL}; + +typedef struct { + int x; + int y; + int thick; + double size; + long color; + int toDo; + int pause; + int season; +} treestruct; + +static treestruct *trees = NULL; + +static XColor colors[20]; +static int color; + +static long colorM[12] = {0xff0000, 0xff8000, 0xffff00, 0x80ff00, + 0x00ff00, 0x00ff80, 0x00ffff, 0x0080ff, + 0x0000ff, 0x8000ff, 0xff00ff, 0xff0080}; + +static long colorV[12] = {0x0a0000, 0x0a0500, 0x0a0a00, 0x050a00, + 0x000a00, 0x000a05, 0x000a0a, 0x00050a, + 0x00000a, 0x05000a, 0x0a000a, 0x0a0005}; + +ENTRYPOINT void +init_trees(ModeInfo * mi) +{ + unsigned long pixels[20]; + treestruct *tree; + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + int i; + + if (trees == NULL) { + trees = (treestruct *) calloc(MI_NUM_SCREENS(mi), sizeof (treestruct)); + if (trees == NULL) { + return; + } + + if (mi->npixels > 20) { + printf("%d colors selected. Setting limit to 20...\n", mi->npixels); + mi->npixels = 20; + } + + if (mi->npixels < 4) { + for (i = 0; i < mi->npixels; i++) { + colors[i].red = 65535 * (i & 1); + colors[i].green = 65535 * (i & 1); + colors[i].blue = 65535 * (i & 1); + colors[i].flags = DoRed | DoGreen | DoBlue; + } + } else { + if (mi->npixels < 8) { + for (i = 0; i < mi->npixels; i++) { + colors[i].red = 32768 + 4096 * (i % 4); + colors[i].green = 32768 + 4096 * (i % 4); + colors[i].blue = 32768 + 4096 * (i % 4); + colors[i].flags = DoRed | DoGreen | DoBlue; + } + } else { + for (i = 0; i < mi->npixels; i++) { + colors[i].red = 24576 + 4096 * (i % 4); + colors[i].green = 10240 + 2048 * (i % 4); + colors[i].blue = 0; + colors[i].flags = DoRed | DoGreen | DoBlue; + } + } + } + + for (i = 0; i < mi->npixels; i++) + if (!XAllocColor(display, mi->xgwa.colormap, &colors[i])) break; + color = i; + + XSetForeground(display, gc, colors[1].pixel); + } + + XClearWindow(display, MI_WINDOW(mi)); + XSetLineAttributes(display, gc, 2, LineSolid, CapButt, JoinMiter); + tree = &trees[MI_SCREEN(mi)]; + tree->toDo = 25; + tree->season = NRAND(12); + + for (i = 4; i < mi->npixels; i++) { + int sIndex = (tree->season + (i-4) / 4) % 12; + long color = colorM[sIndex] - 2 * colorV[sIndex] * (i % 4); + colors[i].red = (color & 0xff0000) / 256; + colors[i].green = (color & 0x00ff00); + colors[i].blue = (color & 0x0000ff) * 256; + colors[i].flags = DoRed | DoGreen | DoBlue; + } + + for (i = 0; i < color; i++) + pixels[i] = colors[i].pixel; + + XFreeColors(display, mi->xgwa.colormap, pixels, mi->npixels, 0L); + + for (i = 0; i < mi->npixels; i++) + if (!XAllocColor(display, mi->xgwa.colormap, &colors[i])) break; + + color = i; +} + +static double rRand(double a, double b) +{ + return (a+(b-a)*NRAND(10001)/10000.0); +} + +static void draw_line(ModeInfo * mi, + int x1, int y1, int x2, int y2, + double angle, int widths, int widthe) +{ + + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + double sns = 0.5*widths*sin(angle + M_PI_2); + double css = 0.5*widths*cos(angle + M_PI_2); + double sne = 0.5*widthe*sin(angle + M_PI_2); + double cse = 0.5*widthe*cos(angle + M_PI_2); + + int xs1 = (int) (x1-sns); + int xs2 = (int) (x1+sns); + int ys1 = (int) (y1-css); + int ys2 = (int) (y1+css); + int xe1 = (int) (x2-sne); + int xe2 = (int) (x2+sne); + int ye1 = (int) (y2-cse); + int ye2 = (int) (y2+cse); + int i; + + for (i = 0; i < widths; i++) { + if (color >= 4) + XSetForeground(display, gc, colors[i*4/widths].pixel); + XDrawLine(display, MI_WINDOW(mi), gc, + xs1+(xs2-xs1)*i/widths, ys1+(ys2-ys1)*i/widths, + xe1+(xe2-xe1)*i/widths, ye1+(ye2-ye1)*i/widths); + } +} + +static void draw_tree_rec(ModeInfo * mi, double thick, int x, int y, double angle) +{ + treestruct *tree = &trees[MI_SCREEN(mi)]; + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + int length = (24+NRAND(12))*tree->size; + int a = (int) (x - length*sin(angle)); + int b = (int) (y - length*cos(angle)); + int i; + + draw_line(mi, x, y, a, b, angle, thick*tree->size, 0.68*thick*tree->size); + + if (thick > 2) { + draw_tree_rec(mi, 0.68*thick, a, b, 0.8*angle+rRand(-0.2, 0.2)); + if (thick < tree->thick-1) { + draw_tree_rec(mi, 0.68*thick, a, b, angle+rRand(0.2, 0.9)); + draw_tree_rec(mi, 0.68*thick, (a+x)/2, (b+y)/2, angle-rRand(0.2, 0.9)); + } + } + + if (thick < 0.5*tree->thick) { + int nleaf = 12 + NRAND(4); + XArc leaf[16]; + for (i = 0; i < nleaf; i++) { + leaf[i].x = a + (int) (tree->size * rRand(-12, 12)); + leaf[i].y = b + (int) (tree->size * rRand(-12, 12)); + leaf[i].width = (int) (tree->size * rRand(2, 6)); + leaf[i].height = leaf[i].width; + leaf[i].angle1 = 0; + leaf[i].angle2 = 360 * 64; + } + if (mi->npixels >= 4) + XSetForeground(display, gc, colors[tree->color+NRAND(4)].pixel); + XFillArcs(display, MI_WINDOW(mi), gc, leaf, nleaf); + } +} + +ENTRYPOINT void +draw_trees(ModeInfo * mi) +{ + treestruct *tree = &trees[MI_SCREEN(mi)]; + int width = MI_WIN_WIDTH(mi); + int height = MI_WIN_HEIGHT(mi); + + if (tree->pause == 1) { + tree->pause--; + init_trees(mi); + } else if (tree->pause > 1) { + tree->pause--; + return; + } else if (--(tree->toDo) == 0) { + tree->pause = 6; + return; + } + + tree->x = NRAND(width); + tree->y = (int) (1.25 * height * (1 - tree->toDo / 23.0)); + tree->thick = rRand(7, 12); + tree->size = height / 480.0; + if (color < 8) { + tree->color = 0; + } else { + tree->color = 4 * (1 + NRAND(color / 4 - 1)); + } + + draw_tree_rec(mi, tree->thick, tree->x, tree->y, rRand(-0.1, 0.1)); +} + + +ENTRYPOINT void +release_trees(ModeInfo * mi) +{ + if (trees != NULL) { + (void) free((void *) trees); + trees = NULL; + } +} + +XSCREENSAVER_MODULE_2 ("Forest", forest, trees) diff --git a/non-wgl/forest.vcproj b/non-wgl/forest.vcproj new file mode 100644 index 0000000..a973fd5 --- /dev/null +++ b/non-wgl/forest.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/fuzzyflakes.c b/non-wgl/fuzzyflakes.c new file mode 100644 index 0000000..27b2a8a --- /dev/null +++ b/non-wgl/fuzzyflakes.c @@ -0,0 +1,686 @@ +/* fuzzyflakes, Copyright (c) 2004 + * Barry Dmytro + * + * ! 2004.06.10 21:05 + * ! - Added support for resizing + * ! - Added a color scheme generation algorithm + * ! Thanks to from #vegans@irc.blitzed.org + * ! - Added random color generation + * ! - Fixed errors in the xml config file + * ! - Cleaned up a few inconsistencies in the code + * ! - Changed the default color to #EFBEA5 + * + * ! 2004.05.?? ??:?? + * ! -original creation + * + * 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 + +char *color = "#efbea5"; +int arms = 5; +int thickness = 10; +int bthickness = 3; +int radius = 20; +int layers = 3; +int density = 5; +int fallingspeed = 10; +int delay = 10000; +Bool doubleBuffer = True; +Bool randomColors = False; + +static argtype vars[] = +{ + {&color, "color", NULL, "3", t_String}, + {&arms, "arms", NULL, "5", t_Int}, + {&thickness, "thickness", NULL, "10", t_Int}, + {&bthickness, "bthickness", NULL, "3", t_Int}, + {&radius, "radius", NULL, "20", t_Int}, + {&layers, "layers", NULL, "3", t_Int}, + {&density, "density", NULL, "5", t_Int}, + {&fallingspeed, "fallingspeed", NULL, "10", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&doubleBuffer, "doubleBuffer", NULL, "True", t_Bool}, + {&randomColors, "randomColors", NULL, "False", t_Bool}, +}; + +/* I have need of 1/3 and 2/3 constants later on */ +#define N1_3 0.3333333333 +#define N2_3 0.6666666666 + +typedef struct _flake_var +{ + double Ticks; + double XPos, YPos; + double TrueX; + double XOffset; + double Angle; +} FlakeVariable; + +/* Struct containing the atrributes to our flakes */ +typedef struct _flake +{ + Display *dpy; + Window window; + + int Arms; + int Thickness; + int BorderThickness; + int Radius; + unsigned long BordColor; + unsigned long ForeColor; + unsigned long BackColor; + Bool RandomColors; + int Layers; + int Density; + int Delay; + int FallingSpeed; + struct _colors + { + char *Fore; + char *Bord; + char *Back; + } Colors; +/* a dynamic array containing positions of all the flakes */ + FlakeVariable ***Flakes; + XGCValues GCValues; + unsigned long GCFlags; + GC GCVar; + XWindowAttributes XGWA; + struct _dbevar + { + Bool dbuf; + Pixmap b, ba, bb; + } DB; +} Flake; + +/* + *This gets the pixel resource for a color: #ffffff + */ +static unsigned int +FuzzyFlakesColorResource(Flake *flake, char *Color) +{ + XColor color; + + if (!XParseColor(flake->dpy, flake->XGWA.colormap, Color, &color)) + { + fprintf(stderr, "%s: can't parse color %s", progname, Color); + return 0; + } + if (!XAllocColor(flake->dpy, flake->XGWA.colormap, &color)) + { + fprintf(stderr, "%s: can't allocate color %s", progname, Color); + return 0; + } + return color.pixel; +} + +/* + * This is a great color matching algorithm that I got from + * a friend of mine on #vegans@irc.blitzed.org + * She wrote it in PHP and I ported it over to C + * her site is http://beautifulfreak.net/ + */ +static int +FuzzyFlakesColorHelper(Flake *flake) +{ + unsigned int iR, iG, iB; + unsigned int iR0, iG0, iB0; + unsigned int iR1, iG1, iB1; + float fR, fG, fB; + float Max = 0, Min = 0, Lig, Sat; + float Hue, Hue0, Hue1; + float f1, f2; + float fR0, fG0, fB0; + float fR1, fG1, fB1; + float nR0, nG0, nB0; + float nR1, nG1, nB1; + XColor color; + + /* First convert from hex to dec */ + /* while splitting up the RGB values */ + if (!XParseColor(flake->dpy, flake->XGWA.colormap, + flake->Colors.Back, &color)) + { + fprintf(stderr, "%s: can't parse color %s", progname, + flake->Colors.Back); + return 1; + } + iR = color.red >> 8; + iG = color.green >> 8; + iB = color.blue >> 8; + + /* Convert from int to float */ + fR = iR; + fG = iG; + fB = iB; + + /* convert from 0-255 to 0-1 */ + fR = fR / 255; + fG = fG / 255; + fB = fB / 255; + + /* work out the lightness */ + if (fR >= fG && fR >= fB) + Max = fR; + if (fG >= fR && fG >= fB) + Max = fG; + if (fB >= fR && fB >= fG) + Max = fB; + + if (fR <= fG && fR <= fB) + Min = fR; + if (fG <= fR && fG <= fB) + Min = fG; + if (fB <= fR && fB <= fG) + Min = fB; + + Lig = (Max + Min) / 2; + + /* work out the saturation */ + if (Max == Min) + Sat = 0; + else + { + if (Lig < 0.5) + Sat = (Max - Min) / (Max + Min); + else + Sat = (Max - Min) / (2 - Max - Min); + } + + /* + * if our satration is too low we won't be + * able to see any objects + */ + if (Sat < 0.03) + { + return 1; + } + + /* work out the hue */ + if (fR == Max) + Hue = (fG - fB) / (Max - Min); + else if (fG == Max) + Hue = 2 + (fB - fR) / (Max - Min); + else + Hue = 4 + (fR - fG) / (Max - Min); + + Hue = Hue / 6; + + /* fine two equidistant hues */ + Hue0 = Hue + N1_3; + if (Hue0 > 1) + Hue0 = Hue0 - 1; + Hue1 = Hue0 + N1_3; + if (Hue1 > 1) + Hue1 = Hue1 - 1; + + /* convert the colors into hex codes */ + if (Lig < 0.5) + f2 = Lig * (1 + Sat); + else + f2 = (Lig + Sat) - (Lig * Sat); + + f1 = (2 * Lig) - f2; + + fR0 = (Hue0 + 1) / 3; + fR1 = (Hue1 + 1) / 3; + fG0 = Hue0; + fG1 = Hue1; + fB0 = (Hue0 - 1) / 3; + fB1 = (Hue1 - 1) / 3; + + if (fR0 < 0) + fR0 = fR0 + 1; + if (fR0 > 1) + fR0 = fR0 - 1; + if (fG0 < 0) + fG0 = fG0 + 1; + if (fG0 > 1) + fG0 = fG0 - 1; + if (fB0 < 0) + fB0 = fB0 + 1; + if (fB0 > 1) + fB0 = fB0 - 1; + + if (fR1 < 0) + fR1 = fR1 + 1; + if (fR1 > 1) + fR1 = fR1 - 1; + if (fG1 < 0) + fG1 = fG1 + 1; + if (fG1 > 1) + fG1 = fG1 - 1; + if (fB1 < 0) + fB1 = fB1 + 1; + if (fB1 > 1) + fB1 = fB1 - 1; + + if (6 * fR0 < 1) + nR0 = f1 + (f2 - f1) * 6 * fR0; + else if (2 * fR0 < 1) + nR0 = f2; + else if (3 * fR0 < 2) + nR0 = f1 + (f2 - f1) * (N2_3 - fR0) * 6; + else + nR0 = f1; + + if (6 * fG0 < 1) + nG0 = f1 + (f2 - f1) * 6 * fG0; + else if (2 * fG0 < 1) + nG0 = f2; + else if (3 * fG0 < 2) + nG0 = f1 + (f2 - f1) * (N2_3 - fG0) * 6; + else + nG0 = f1; + + if (6 * fB0 < 1) + nB0 = f1 + (f2 - f1) * 6 * fB0; + else if (2 * fB0 < 1) + nB0 = f2; + else if (3 * fB0 < 2) + nB0 = f1 + (f2 - f1) * (N2_3 - fB0) * 6; + else + nB0 = f1; + + if (6 * fR1 < 1) + nR1 = f1 + (f2 - f1) * 6 * fR1; + else if (2 * fR1 < 1) + nR1 = f2; + else if (3 * fR1 < 2) + nR1 = f1 + (f2 - f1) * (N2_3 - fR1) * 6; + else + nR1 = f1; + + if (6 * fG1 < 1) + nG1 = f1 + (f2 - f1) * 6 * fG1; + else if (2 * fG1 < 1) + nG1 = f2; + else if (3 * fG1 < 2) + nG1 = f1 + (f2 - f1) * (N2_3 - fG1) * 6; + else + nG1 = f1; + + if (6 * fB1 < 1) + nB1 = f1 + (f2 - f1) * 6 * fB1; + else if (2 * fB1 < 1) + nB1 = f2; + else if (3 * fB1 < 2) + nB1 = f1 + (f2 - f1) * (N2_3 - fB1) * 6; + else + nB1 = f1; + + /* at last convert them to a hex string */ + iR0 = nR0 * 255; + iG0 = nG0 * 255; + iB0 = nB0 * 255; + + iR1 = nR1 * 255; + iG1 = nG1 * 255; + iB1 = nB1 * 255; + + flake->Colors.Fore = malloc(sizeof(unsigned char) * 8); + flake->Colors.Bord = malloc(sizeof(unsigned char) * 8); + + sprintf(flake->Colors.Fore, "#%02X%02X%02X", iR0, iG0, iB0); + sprintf(flake->Colors.Bord, "#%02X%02X%02X", iR1, iG1, iB1); + + return 0; +} + +static void +FuzzyFlakesInit(Flake *flake) +{ + int i, j; + XWindowAttributes xgwa; + + XGetWindowAttributes(flake->dpy, flake->window, &xgwa); + flake->XGWA = xgwa; + flake->DB.b = flake->DB.ba = flake->DB.bb = 0; + //flake->DB.dbuf = get_boolean_resource(flake->dpy, "doubleBuffer", "Boolean"); + flake->DB.dbuf = doubleBuffer; + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + flake->DB.dbuf = False; +# endif + + if (flake->DB.dbuf) + { + flake->DB.ba = + XCreatePixmap(flake->dpy, flake->window, xgwa.width, xgwa.height, xgwa.depth); + flake->DB.bb = + XCreatePixmap(flake->dpy, flake->window, xgwa.width, xgwa.height, xgwa.depth); + flake->DB.b = flake->DB.ba; + } + else + { + flake->DB.b = flake->window; + } + +#if 1 + flake->Arms = arms; + flake->Thickness = thickness; + flake->BorderThickness = bthickness; + flake->Radius = radius; +#else + flake->Arms = get_integer_resource(flake->dpy, "arms", "Integer"); + flake->Thickness = get_integer_resource(flake->dpy, "thickness", "Integer"); + flake->BorderThickness = get_integer_resource(flake->dpy, "bthickness", "Integer"); + flake->Radius = get_integer_resource(flake->dpy, "radius", "Integer"); +#endif + +#if 1 + flake->Density = density; + flake->Layers = layers; + flake->FallingSpeed = fallingspeed; + flake->Delay = delay; + if (flake->RandomColors == True) + flake->RandomColors = randomColors; +#else + flake->Density = get_integer_resource(flake->dpy, "density", "Integer"); + flake->Layers = get_integer_resource(flake->dpy, "layers", "Integer"); + flake->FallingSpeed = get_integer_resource(flake->dpy, "fallingspeed", "Integer"); + flake->Delay = get_integer_resource(flake->dpy, "delay", "Integer"); + if (flake->RandomColors == True) + flake->RandomColors = get_boolean_resource(flake->dpy, "randomColors", "Boolean"); +#endif + + if (flake->Delay < 0) + flake->Delay = 0; + + if (!flake->Colors.Back) + { + //flake->Colors.Back = get_string_resource(flake->dpy, "color", "Color"); + flake->Colors.Back = color; + if (!FuzzyFlakesColorResource(flake, flake->Colors.Back)) + { + fprintf(stderr, " reverting to random\n"); + flake->RandomColors = True; + } + + if (flake->RandomColors) + { + if (flake->Colors.Back) + free(flake->Colors.Back); + flake->Colors.Back = malloc(sizeof(unsigned char) * 8); + sprintf(flake->Colors.Back, "#%X%X%X%X%X%X", random() % 16, + random() % 16, random() % 16, random() % 16, random() % 16, + random() % 16); + } + + /* + * Here we establish our colormap based on what is in + * flake->Colors.Back + */ + if (FuzzyFlakesColorHelper(flake)) + { + fprintf(stderr, " reverting to random\n"); + if (flake->Colors.Back) + free(flake->Colors.Back); + flake->Colors.Back = malloc(sizeof(unsigned char) * 8); + sprintf(flake->Colors.Back, "#%X%X%X%X%X%X", random() % 16, + random() % 16, random() % 16, random() % 16, random() % 16, + random() % 16); + FuzzyFlakesColorHelper(flake); + } + + flake->ForeColor = FuzzyFlakesColorResource(flake, flake->Colors.Fore); + flake->BackColor = FuzzyFlakesColorResource(flake, flake->Colors.Back); + flake->BordColor = FuzzyFlakesColorResource(flake, flake->Colors.Bord); + + flake->GCValues.foreground = flake->ForeColor; + flake->GCValues.background = flake->BackColor; + flake->RandomColors = False; + } + + flake->GCValues.line_width = flake->Thickness; + flake->GCValues.cap_style = CapProjecting; + flake->GCValues.join_style = JoinMiter; + flake->GCFlags |= (GCLineWidth | GCCapStyle | GCJoinStyle); + + flake->GCVar = + XCreateGC(flake->dpy, flake->window, flake->GCFlags, + &flake->GCValues); + + flake->Density = flake->XGWA.width / 200 * flake->Density; + flake->Flakes = malloc(sizeof(FlakeVariable **) * flake->Layers); + for (i = 1; i <= flake->Layers; i++) + { + flake->Flakes[i - 1] = malloc(sizeof(FlakeVariable *) * flake->Density); + for (j = 0; j < flake->Density; j++) + { + flake->Flakes[i - 1][j] = malloc(sizeof(FlakeVariable)); + flake->Flakes[i - 1][j]->XPos = random() % flake->XGWA.width; + flake->Flakes[i - 1][j]->YPos = random() % flake->XGWA.height; + flake->Flakes[i - 1][j]->Angle = random() % 360 * (M_PI / 180); + flake->Flakes[i - 1][j]->Ticks = random() % 360; + flake->Flakes[i - 1][j]->XOffset = random() % flake->XGWA.height; + } + } +} + +static void +FuzzyFlakesFreeFlake(Flake *flake) +{ + int i, j; + + for (i = 1; i <= flake->Layers; i++) + { + for (j = 0; j < flake->Density; j++) + { + free(flake->Flakes[i - 1][j]); + } + free(flake->Flakes[i - 1]); + } + + if (flake->DB.bb) XFreePixmap(flake->dpy, flake->DB.bb); + if (flake->DB.ba) XFreePixmap(flake->dpy, flake->DB.ba); +} + +static void +FuzzyFlakesMove(Flake *flake) +{ + int i, j; + + for (i = 1; i <= flake->Layers; i++) + { + for (j = 0; j < flake->Density; j++) + { + FlakeVariable *FlakeVar; + + FlakeVar = flake->Flakes[i - 1][j]; + FlakeVar->Ticks++; + FlakeVar->YPos = + FlakeVar->YPos + ((double)flake->FallingSpeed) / 10 / i; + FlakeVar->TrueX = + (sin + (FlakeVar->XOffset + + FlakeVar->Ticks * (M_PI / 180) * ((double)flake->FallingSpeed / + 10))) * 10 + FlakeVar->XPos; + FlakeVar->Angle = + FlakeVar->Angle + 0.005 * ((double)flake->FallingSpeed / 10); + if (FlakeVar->YPos - flake->Radius > flake->XGWA.height) + { + FlakeVar->Ticks = 0; + FlakeVar->YPos = 0 - flake->Radius; + } + } + } +} + +static void +FuzzyFlakesDrawFlake(Flake *flake, int XPos, int YPos, double AngleOffset, int Layer) +{ + int i; + double x, y, Angle, Radius; + + /* calculate the shrink factor debending on which layer we are drawing atm */ + Radius = (double)(flake->Radius - Layer * 5); + /* draw the flake one arm at a time */ + for (i = 1; i <= flake->Arms; i++) + { + int Diameter; + + Diameter = (flake->BorderThickness * 2 + flake->Thickness) / Layer; + /* compute the angle of this arm of the flake */ + Angle = ((2 * M_PI) / flake->Arms) * i + AngleOffset; + /* calculate the x and y dispositions for this arm */ + y = (int)(sin(Angle) * Radius); + x = (int)(cos(Angle) * Radius); + /* draw the base for the arm */ + flake->GCValues.line_width = Diameter; + XFreeGC(flake->dpy, flake->GCVar); + flake->GCVar = + XCreateGC(flake->dpy, flake->DB.b, flake->GCFlags, + &flake->GCValues); + XSetForeground(flake->dpy, flake->GCVar, flake->BordColor); + XDrawLine(flake->dpy, flake->DB.b, flake->GCVar, XPos, YPos, + XPos + x, YPos + y); + } + /* draw the flake one arm at a time */ + for (i = 1; i <= flake->Arms; i++) + { + /* compute the angle of this arm of the flake */ + Angle = ((2 * M_PI) / flake->Arms) * i + AngleOffset; + /* calculate the x and y dispositions for this arm */ + y = (int)(sin(Angle) * Radius); + x = (int)(cos(Angle) * Radius); + /* draw the inside of the arm */ + flake->GCValues.line_width = flake->Thickness / Layer; + XFreeGC(flake->dpy, flake->GCVar); + flake->GCVar = + XCreateGC(flake->dpy, flake->DB.b, flake->GCFlags, + &flake->GCValues); + XSetForeground(flake->dpy, flake->GCVar, flake->ForeColor); + XDrawLine(flake->dpy, flake->DB.b, flake->GCVar, XPos, YPos, + XPos + x, YPos + y); + } +} + +static void +FuzzyFlakes(Flake *flake) +{ + int i, j; + + FuzzyFlakesMove(flake); + XSetForeground(flake->dpy, flake->GCVar, flake->BackColor); + XFillRectangle(flake->dpy, flake->DB.b, flake->GCVar, 0, 0, + flake->XGWA.width, flake->XGWA.height); + for (i = flake->Layers; i >= 1; i--) + { + for (j = 0; j < flake->Density; j++) + { + FuzzyFlakesDrawFlake(flake, + flake->Flakes[i - 1][j]->TrueX, + flake->Flakes[i - 1][j]->YPos, + flake->Flakes[i - 1][j]->Angle, i); + } + } + +} + +static void * +fuzzyflakes_init (Display *dpy, Window window) +{ + Flake *flake = (Flake *) calloc (1, sizeof(*flake)); + flake->dpy = dpy; + flake->window = window; + + /* This is needed even if it is going to be set to false */ + flake->RandomColors = True; + + /* set up our colors amoung many other things */ + FuzzyFlakesInit(flake); + + return flake; +} + +static unsigned long +fuzzyflakes_draw (Display *dpy, Window window, void *closure) +{ + Flake *flake = (Flake *) closure; + + FuzzyFlakes(flake); + if (flake->DB.dbuf) + { + XCopyArea(flake->dpy, flake->DB.b, flake->window, + flake->GCVar, 0, 0, flake->XGWA.width, flake->XGWA.height, + 0, 0); + flake->DB.b = + (flake->DB.b == flake->DB.ba ? flake->DB.bb : flake->DB.ba); + } + + return flake->Delay; +} + +static void +fuzzyflakes_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + Flake *flake = (Flake *) closure; + + if (flake->XGWA.width != w || flake->XGWA.height != h) + { + FuzzyFlakesFreeFlake(flake); + FuzzyFlakesInit(flake); + } +} + +#if 0 + static Bool + fuzzyflakes_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +fuzzyflakes_free (Display *dpy, Window window, void *closure) +{ + Flake *flake = (Flake *) closure; + FuzzyFlakesFreeFlake(flake); + free(flake); +} + + +static const char *fuzzyflakes_defaults[] = { + "*color: #efbea5", + "*arms: 5", + "*thickness: 10", + "*bthickness: 3", + "*radius: 20", + "*layers: 3", + "*density: 5", + "*fallingspeed: 10", + "*delay: 10000", + "*doubleBuffer: True", + "*randomColors: False", + 0 +}; + +static XrmOptionDescRec fuzzyflakes_options[] = { + { "-color", ".color", XrmoptionSepArg, 0}, + { "-arms", ".arms", XrmoptionSepArg, 0}, + { "-thickness", ".thickness", XrmoptionSepArg, 0}, + { "-bthickness", ".bthickness", XrmoptionSepArg, 0}, + { "-radius", ".radius", XrmoptionSepArg, 0}, + { "-layers", ".layers", XrmoptionSepArg, 0}, + { "-density", ".density", XrmoptionSepArg, 0}, + { "-speed", ".fallingspeed", XrmoptionSepArg, 0}, + { "-delay", ".delay", XrmoptionSepArg, 0}, + { "-db", ".doubleBuffer", XrmoptionNoArg, "True"}, + { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False"}, + { "-random-colors", ".randomColors", XrmoptionNoArg, "True"}, + { 0, 0, 0, 0} +}; + + +XSCREENSAVER_MODULE ("FuzzyFlakes", fuzzyflakes) diff --git a/non-wgl/fuzzyflakes.vcproj b/non-wgl/fuzzyflakes.vcproj new file mode 100644 index 0000000..758585f --- /dev/null +++ b/non-wgl/fuzzyflakes.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/galaxy.c b/non-wgl/galaxy.c index ac21da6..d82d5dd 100644 --- a/non-wgl/galaxy.c +++ b/non-wgl/galaxy.c @@ -60,15 +60,17 @@ static const char sccsid[] = "@(#)galaxy.c 4.04 97/07/28 xlockmore"; # include "xlock.h" /* from the xlockmore distribution */ #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" static Bool tracks = True; static Bool spin = True; -static Bool dbufp = False; +//static Bool dbufp = False; +static Bool dbufp = True; #define DEF_TRACKS "True" #define DEF_SPIN "True" -#define DEF_DBUF "False" +//#define DEF_DBUF "False" +#define DEF_DBUF "True" static XrmOptionDescRec opts[] = { diff --git a/non-wgl/galaxy.vcproj b/non-wgl/galaxy.vcproj index ecca029..4a4e6d1 100644 --- a/non-wgl/galaxy.vcproj +++ b/non-wgl/galaxy.vcproj @@ -195,11 +195,15 @@ > + + + + @@ -239,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/non-wgl/grav.c b/non-wgl/grav.c new file mode 100644 index 0000000..4644cd7 --- /dev/null +++ b/non-wgl/grav.c @@ -0,0 +1,370 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* grav --- planets spinning around a pulsar */ + +#if 0 +static const char sccsid[] = "@(#)grav.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1993 by Greg Boewring + * + * 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 + * 11-Jul-1994: color version + * 06-Oct-1993: Written by Greg Bowering + */ + +#define STANDALONE + +#define MODE_grav +#define DELAY 10000 +#define COUNT 12 +#define NCOLORS 64 +#define DEFAULTS "*delay: 10000 \n" \ + "*count: 12 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +#define BRIGHT_COLORS +# define grav_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_grav + +#define DEF_DECAY "True" /* Damping for decaying orbits */ +#define DEF_TRAIL "True" /* For trails (works good in mono only) */ + +static Bool decay = True; +static Bool trail = True; + +static XrmOptionDescRec opts[] = +{ + {"-decay", ".grav.decay", XrmoptionNoArg, "on"}, + {"+decay", ".grav.decay", XrmoptionNoArg, "off"}, + {"-trail", ".grav.trail", XrmoptionNoArg, "on"}, + {"+trail", ".grav.trail", XrmoptionNoArg, "off"} +}; +static argtype vars[] = +{ + {&decay, "decay", "Decay", DEF_DECAY, t_Bool}, + {&trail, "trail", "Trail", DEF_TRAIL, t_Bool} +}; +static OptionStruct desc[] = +{ + {"-/+decay", "turn on/off decaying orbits"}, + {"-/+trail", "turn on/off trail dots"} +}; + +ENTRYPOINT ModeSpecOpt grav_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct grav_description = +{"grav", "init_grav", "draw_grav", "release_grav", + "refresh_grav", "init_grav", (char *) NULL, &grav_opts, + 10000, -12, 1, 1, 64, 1.0, "", + "Shows orbiting planets", 0, NULL}; + +#endif + +#define GRAV -0.02 /* Gravitational constant */ +#define DIST 16.0 +#define COLLIDE 0.0001 +#define ALMOST 15.99 +#define HALF 0.5 +/* #define INTRINSIC_RADIUS 200.0 */ +#define INTRINSIC_RADIUS ((float) (gp->height/5)) +#define STARRADIUS (unsigned int)(gp->height/(2*DIST)) +#define AVG_RADIUS (INTRINSIC_RADIUS/DIST) +#define RADIUS (unsigned int)(INTRINSIC_RADIUS/(POS(Z)+DIST)) + +#define XR HALF*ALMOST +#define YR HALF*ALMOST +#define ZR HALF*ALMOST + +#define VR 0.04 + +#define DIMENSIONS 3 +#define X 0 +#define Y 1 +#define Z 2 + +#define DAMP 0.999999 +#define MaxA 0.1 /* Maximum acceleration (w/ damping) */ + +#define POS(c) planet->P[c] +#define VEL(c) planet->V[c] +#define ACC(c) planet->A[c] + +#define Planet(x,y)\ + if ((x) >= 0 && (y) >= 0 && (x) <= gp->width && (y) <= gp->height) {\ + if (planet->ri < 2)\ + XDrawPoint(display, window, gc, (x), (y));\ + else\ + XFillArc(display, window, gc,\ + (x) - planet->ri / 2, (y) - planet->ri / 2, planet->ri, planet->ri,\ + 0, 23040);\ + } + +#define FLOATRAND(min,max) ((min)+(LRAND()/MAXRAND)*((max)-(min))) + +typedef struct { + double P[DIMENSIONS], V[DIMENSIONS], A[DIMENSIONS]; + int xi, yi, ri; + unsigned long colors; +} planetstruct; + +typedef struct { + int width, height; + int x, y, sr, nplanets; + unsigned long starcolor; + planetstruct *planets; +} gravstruct; + +static gravstruct *gravs = (gravstruct *) NULL; + +static void +init_planet(ModeInfo * mi, planetstruct * planet) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + gravstruct *gp = &gravs[MI_SCREEN(mi)]; + +# ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False); +# endif + + if (MI_NPIXELS(mi) > 2) + planet->colors = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + else + planet->colors = MI_WHITE_PIXEL(mi); + /* Initialize positions */ + POS(X) = FLOATRAND(-XR, XR); + POS(Y) = FLOATRAND(-YR, YR); + POS(Z) = FLOATRAND(-ZR, ZR); + + if (POS(Z) > -ALMOST) { + planet->xi = (int) + ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST))); + planet->yi = (int) + ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST))); + } else + planet->xi = planet->yi = -1; + planet->ri = RADIUS; + + /* Initialize velocities */ + VEL(X) = FLOATRAND(-VR, VR); + VEL(Y) = FLOATRAND(-VR, VR); + VEL(Z) = FLOATRAND(-VR, VR); + + /* Draw planets */ + Planet(planet->xi, planet->yi); +} + +static void +draw_planet(ModeInfo * mi, planetstruct * planet) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + gravstruct *gp = &gravs[MI_SCREEN(mi)]; + double D; /* A distance variable to work with */ + register unsigned char cmpt; + + D = POS(X) * POS(X) + POS(Y) * POS(Y) + POS(Z) * POS(Z); + if (D < COLLIDE) + D = COLLIDE; + D = sqrt(D); + D = D * D * D; + for (cmpt = X; cmpt < DIMENSIONS; cmpt++) { + ACC(cmpt) = POS(cmpt) * GRAV / D; + if (decay) { + if (ACC(cmpt) > MaxA) + ACC(cmpt) = MaxA; + else if (ACC(cmpt) < -MaxA) + ACC(cmpt) = -MaxA; + VEL(cmpt) = VEL(cmpt) + ACC(cmpt); + VEL(cmpt) *= DAMP; + } else { + /* update velocity */ + VEL(cmpt) = VEL(cmpt) + ACC(cmpt); + } + /* update position */ + POS(cmpt) = POS(cmpt) + VEL(cmpt); + } + + gp->x = planet->xi; + gp->y = planet->yi; + + if (POS(Z) > -ALMOST) { + planet->xi = (int) + ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST))); + planet->yi = (int) + ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST))); + } else + planet->xi = planet->yi = -1; + + /* Mask */ + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + Planet(gp->x, gp->y); + if (trail) { + XSetForeground(display, gc, planet->colors); + XDrawPoint(display, MI_WINDOW(mi), gc, gp->x, gp->y); + } + /* Move */ + gp->x = planet->xi; + gp->y = planet->yi; + planet->ri = RADIUS; + + /* Redraw */ + XSetForeground(display, gc, planet->colors); + Planet(gp->x, gp->y); +} + +ENTRYPOINT void +init_grav(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + unsigned char ball; + gravstruct *gp; + + if (gravs == NULL) { + if ((gravs = (gravstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (gravstruct))) == NULL) + return; + } + gp = &gravs[MI_SCREEN(mi)]; + + gp->width = MI_WIDTH(mi); + gp->height = MI_HEIGHT(mi); + + gp->sr = STARRADIUS; + + gp->nplanets = MI_COUNT(mi); + if (gp->nplanets < 0) { + if (gp->planets) { + (void) free((void *) gp->planets); + gp->planets = (planetstruct *) NULL; + } + gp->nplanets = NRAND(-gp->nplanets) + 1; /* Add 1 so its not too boring */ + } + if (gp->planets == NULL) { + if ((gp->planets = (planetstruct *) calloc(gp->nplanets, + sizeof (planetstruct))) == NULL) + return; + } + + MI_CLEARWINDOW(mi); + + if (MI_NPIXELS(mi) > 2) + gp->starcolor = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + else + gp->starcolor = MI_WHITE_PIXEL(mi); + for (ball = 0; ball < (unsigned char) gp->nplanets; ball++) + init_planet(mi, &gp->planets[ball]); + + /* Draw centrepoint */ + XDrawArc(display, MI_WINDOW(mi), gc, + gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr, + 0, 23040); +} + +ENTRYPOINT void +draw_grav(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + register unsigned char ball; + gravstruct *gp; + + if (gravs == NULL) + return; + gp = &gravs[MI_SCREEN(mi)]; + if (gp->planets == NULL) + return; + + MI_IS_DRAWN(mi) = True; + /* Mask centrepoint */ + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XDrawArc(display, window, gc, + gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr, + 0, 23040); + + /* Resize centrepoint */ + switch (NRAND(4)) { + case 0: + if (gp->sr < (int) STARRADIUS) + gp->sr++; + break; + case 1: + if (gp->sr > 2) + gp->sr--; + } + + /* Draw centrepoint */ + XSetForeground(display, gc, gp->starcolor); + XDrawArc(display, window, gc, + gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr, + 0, 23040); + + for (ball = 0; ball < (unsigned char) gp->nplanets; ball++) + draw_planet(mi, &gp->planets[ball]); +} + +ENTRYPOINT void +reshape_grav(ModeInfo * mi, int width, int height) +{ + gravstruct *gp = &gravs[MI_SCREEN(mi)]; + gp->width = width; + gp->height = height; + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); +} + +ENTRYPOINT void +release_grav(ModeInfo * mi) +{ + if (gravs != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + gravstruct *gp = &gravs[screen]; + + if (gp->planets) + (void) free((void *) gp->planets); + } + (void) free((void *) gravs); + gravs = (gravstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_grav(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Grav", grav) + +#endif /* MODE_grav */ diff --git a/non-wgl/grav.vcproj b/non-wgl/grav.vcproj new file mode 100644 index 0000000..af5d4ba --- /dev/null +++ b/non-wgl/grav.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/greynetic.c b/non-wgl/greynetic.c new file mode 100644 index 0000000..3360c8a --- /dev/null +++ b/non-wgl/greynetic.c @@ -0,0 +1,314 @@ +/* xscreensaver, Copyright (c) 1992-2008 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 HAVE_COCOA +# define DO_STIPPLE +#endif + +#define NBITS 12 + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +Bool grey = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&grey, "grey", NULL, "False", t_Bool}, +}; + +/* On some systems (notably MacOS X) these files are messed up. + * They're tiny, so we might as well just inline them here. + * + * # include + * # include + * # include + * # include + * # include + * # include + * # include + * # include + * # include + * # include + * # include + * # include +*/ + +#ifdef DO_STIPPLE +#define stipple_width 16 +#define stipple_height 4 +static unsigned char stipple_bits[] = { + 0x55, 0x55, 0xee, 0xee, 0x55, 0x55, 0xba, 0xbb}; + +#define cross_weave_width 16 +#define cross_weave_height 16 +static unsigned char cross_weave_bits[] = { + 0x55, 0x55, 0x88, 0x88, 0x55, 0x55, 0x22, 0x22, 0x55, 0x55, 0x88, 0x88, + 0x55, 0x55, 0x22, 0x22, 0x55, 0x55, 0x88, 0x88, 0x55, 0x55, 0x22, 0x22, + 0x55, 0x55, 0x88, 0x88, 0x55, 0x55, 0x22, 0x22}; + +#define dimple1_width 16 +#define dimple1_height 16 +static unsigned char dimple1_bits[] = { + 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, + 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, + 0x55, 0x55, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00}; + +#define dimple3_width 16 +#define dimple3_height 16 +static unsigned char dimple3_bits[] = { + 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +#define flipped_gray_width 4 +#define flipped_gray_height 2 +static char flipped_gray_bits[] = { 0x07, 0x0d}; +#define gray1_width 2 +#define gray1_height 2 +static char gray1_bits[] = { 0x01, 0x02}; +#define gray3_width 4 +#define gray3_height 4 +static char gray3_bits[] = { 0x01, 0x00, 0x04, 0x00}; +#define hlines2_width 1 +#define hlines2_height 2 +static char hlines2_bits[] = { 0x01, 0x00}; +#define light_gray_width 4 +#define light_gray_height 2 +static char light_gray_bits[] = { 0x08, 0x02}; +#define root_weave_width 4 +#define root_weave_height 4 +static char root_weave_bits[] = { 0x07, 0x0d, 0x0b, 0x0e}; +#define vlines2_width 2 +#define vlines2_height 1 +static char vlines2_bits[] = { 0x01}; +#define vlines3_width 3 +#define vlines3_height 1 +static char vlines3_bits[] = { 0x02}; + +#endif /* DO_STIPPLE */ + +struct state { + Display *dpy; + Window window; + + Pixmap pixmaps [NBITS]; + + GC gc; + int delay; + unsigned long fg, bg, pixels [512]; + int npixels; + int xlim, ylim; + Bool grey_p; + Colormap cmap; +}; + + +static void * +greynetic_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); +# ifdef DO_STIPPLE + int i; +# endif /* DO_STIPPLE */ + XGCValues gcv; + XWindowAttributes xgwa; + st->dpy = dpy; + st->window = window; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->xlim = xgwa.width; + st->ylim = xgwa.height; + st->cmap = xgwa.colormap; + st->npixels = 0; +#if 1 + st->grey_p = grey; + gcv.foreground= st->fg= load_color(st->dpy, st->cmap, foreground); + gcv.background= st->bg= load_color(st->dpy, st->cmap, background); + st->delay = delay; +#else + st->grey_p = get_boolean_resource(st->dpy, "grey", "Boolean"); + gcv.foreground= st->fg= get_pixel_resource(st->dpy, st->cmap, "foreground","Foreground"); + gcv.background= st->bg= get_pixel_resource(st->dpy, st->cmap, "background","Background"); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); +#endif + if (st->delay < 0) st->delay = 0; + +# ifndef DO_STIPPLE + st->gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); +# ifdef HAVE_COCOA /* allow non-opaque alpha components in pixel values */ + jwxyz_XSetAlphaAllowed (st->dpy, st->gc, True); +# endif /* HAVE_COCOA */ +# else /* DO_STIPPLE */ + gcv.fill_style= FillOpaqueStippled; + st->gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground|GCFillStyle, &gcv); + + i = 0; +# define BITS(n,w,h) \ + st->pixmaps [i++] = \ + XCreatePixmapFromBitmapData (st->dpy, st->window, (char *) n, w, h, 1, 0, 1) + + BITS (stipple_bits, stipple_width, stipple_height); + BITS (cross_weave_bits, cross_weave_width, cross_weave_height); + BITS (dimple1_bits, dimple1_width, dimple1_height); + BITS (dimple3_bits, dimple3_width, dimple3_height); + BITS (flipped_gray_bits, flipped_gray_width, flipped_gray_height); + BITS (gray1_bits, gray1_width, gray1_height); + BITS (gray3_bits, gray3_width, gray3_height); + BITS (hlines2_bits, hlines2_width, hlines2_height); + BITS (light_gray_bits, light_gray_width, light_gray_height); + BITS (root_weave_bits, root_weave_width, root_weave_height); + BITS (vlines2_bits, vlines2_width, vlines2_height); + BITS (vlines3_bits, vlines3_width, vlines3_height); +# endif /* DO_STIPPLE */ + return st; +} + +static unsigned long +greynetic_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int x, y, w=0, h=0, i; + XGCValues gcv; + + for (i = 0; i < 10; i++) /* minimize area, but don't try too hard */ + { + w = 50 + random () % (st->xlim - 50); + h = 50 + random () % (st->ylim - 50); + if (w + h < st->xlim && w + h < st->ylim) + break; + } + x = random () % (st->xlim - w); + y = random () % (st->ylim - h); +# ifdef DO_STIPPLE + gcv.stipple = st->pixmaps [random () % NBITS]; +# endif /* !DO_STIPPLE */ + if (mono_p) + { + MONO: + if (random () & 1) + gcv.foreground = st->fg, gcv.background = st->bg; + else + gcv.foreground = st->bg, gcv.background = st->fg; + } + else + { + XColor fgc, bgc; + if (st->npixels == sizeof (st->pixels) / sizeof (unsigned long)) + goto REUSE; + fgc.flags = bgc.flags = DoRed|DoGreen|DoBlue; + fgc.red = random (); + fgc.green = random (); + fgc.blue = random (); +# ifdef DO_STIPPLE + bgc.red = random (); + bgc.green = random (); + bgc.blue = random (); +# endif /* DO_STIPPLE */ + + if (st->grey_p) + { + fgc.green = fgc.blue = fgc.red; + bgc.green = bgc.blue = bgc.red; + } + + if (! XAllocColor (st->dpy, st->cmap, &fgc)) + goto REUSE; + st->pixels [st->npixels++] = fgc.pixel; + gcv.foreground = fgc.pixel; +# ifdef DO_STIPPLE + if (! XAllocColor (st->dpy, st->cmap, &bgc)) + goto REUSE; + st->pixels [st->npixels++] = bgc.pixel; + gcv.background = bgc.pixel; +# endif /* DO_STIPPLE */ + goto DONE; + REUSE: + if (st->npixels <= 0) + { + mono_p = 1; + goto MONO; + } + gcv.foreground = st->pixels [random () % st->npixels]; +# ifdef DO_STIPPLE + gcv.background = st->pixels [random () % st->npixels]; +# endif /* DO_STIPPLE */ + DONE: + ; + +# ifdef HAVE_COCOA + { + /* give a non-opaque alpha to the color */ + unsigned long pixel = gcv.foreground; + unsigned long amask = BlackPixelOfScreen (0); + unsigned long a = (random() & amask); + pixel = (pixel & (~amask)) | a; + gcv.foreground = pixel; + } +# endif /* !HAVE_COCOA */ + } +# ifndef DO_STIPPLE + XChangeGC (st->dpy, st->gc, GCForeground, &gcv); +# else /* DO_STIPPLE */ + XChangeGC (st->dpy, st->gc, GCStipple|GCForeground|GCBackground, &gcv); +# endif /* DO_STIPPLE */ + XFillRectangle (st->dpy, st->window, st->gc, x, y, w, h); + return st->delay; +} + + +static const char *greynetic_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 10000", + "*grey: false", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec greynetic_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-grey", ".grey", XrmoptionNoArg, "True" }, + { 0, 0, 0, 0 } +}; + +static void +greynetic_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; +} + +#if 0 + static Bool + greynetic_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +greynetic_free (Display *dpy, Window window, void *closure) +{ +} + +XSCREENSAVER_MODULE ("Greynetic", greynetic) + diff --git a/non-wgl/greynetic.vcproj b/non-wgl/greynetic.vcproj new file mode 100644 index 0000000..3a56455 --- /dev/null +++ b/non-wgl/greynetic.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/halftone.c b/non-wgl/halftone.c new file mode 100644 index 0000000..33aafb4 --- /dev/null +++ b/non-wgl/halftone.c @@ -0,0 +1,436 @@ +/* halftone, Copyright (c) 2002 by Peter Jaric + * + * 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. + * + * Description: + * Draws the gravitational force in each point on the screen seen + * through a halftone dot pattern. The force is calculated from a set + * of moving mass points. View it from a distance for best effect. + */ + +#include "screenhack.h" +#include +#include +#include + +#define DEFAULT_DELAY 10000 +#define DEFAULT_SPACING 14 +#define DEFAULT_SIZE_FACTOR 1.5 +#define DEFAULT_COUNT 10 +#define DEFAULT_MIN_MASS 0.001 +#define DEFAULT_MAX_MASS 0.02 +#define DEFAULT_MIN_SPEED 0.001 +#define DEFAULT_MAX_SPEED 0.02 + +char *background = "Black"; +int delay = 10000; +int count_ = 10; +float minMass = 0.001; +float maxMass = 0.02; +float minSpeed = 0.001; +float maxSpeed = 0.02; +int spacing_ = 14; +float sizeFactor = 1.5; +int colors = 200; +int cycleSpeed = 10; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&count_, "count", NULL, "10", t_Int}, + {&minMass, "minMass", NULL, "0.001", t_Float}, + {&maxMass, "maxMass", NULL, "0.02", t_Float}, + {&minSpeed, "minSpeed", NULL, "0.001", t_Float}, + {&maxSpeed, "maxSpeed", NULL, "0.02", t_Float}, + {&spacing_, "spacing", NULL, "14", t_Int}, + {&sizeFactor, "sizeFactor", NULL, "1.5", t_Float}, + {&colors, "colors", NULL, "200", t_Int}, + {&cycleSpeed, "cycleSpeed", NULL, "10", t_Int}, +}; + +typedef struct +{ + /* halftone dots */ + double * dots; + int dots_width; + int dots_height; + int spacing; + int max_dot_size; + + /* Moving gravity points */ + int gravity_point_count; + + double* gravity_point_x; + double* gravity_point_y; + double* gravity_point_mass; + double* gravity_point_x_inc; + double* gravity_point_y_inc; + + /* X stuff */ + Display *dpy; + Window window; + GC gc; + + int ncolors; + XColor *colors; + int color0, color1; + int color_tick, cycle_speed; + + /* Off screen buffer */ + Pixmap buffer; + GC buffer_gc; + int buffer_width; + int buffer_height; + + int delay; + +} halftone_screen; + + +static void update_buffer(halftone_screen *halftone, XWindowAttributes * attrs) +{ + if (halftone->buffer_width != attrs->width || + halftone->buffer_height != attrs->height) + { + XGCValues gc_values; + + if (halftone->buffer_width != -1 && + halftone->buffer_height != -1) + { + if (halftone->buffer != halftone->window) + XFreePixmap(halftone->dpy, halftone->buffer); + XFreeGC(halftone->dpy, halftone->buffer_gc); + } + + halftone->buffer_width = attrs->width; + halftone->buffer_height = attrs->height; +#ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + halftone->buffer = halftone->window; +#else + halftone->buffer = XCreatePixmap(halftone->dpy, halftone->window, halftone->buffer_width, halftone->buffer_height, attrs->depth); +#endif + + halftone->buffer_gc = XCreateGC(halftone->dpy, halftone->buffer, 0, &gc_values); + } +} + +static void update_dot_attributes(halftone_screen *halftone, XWindowAttributes * attrs) +{ + double dots_width = attrs->width / halftone->spacing + 1; + double dots_height = attrs->height / halftone->spacing + 1; + + if (halftone->dots == NULL || + (dots_width != halftone->dots_width || + dots_height != halftone->dots_height)) + { + if (halftone->dots != NULL) + free(halftone->dots); + + halftone->dots_width = dots_width; + halftone->dots_height = dots_height; + halftone->dots = (double *) malloc(halftone->dots_width * halftone->dots_height * sizeof(double)); + } +} + +static void * +halftone_init (Display *dpy, Window window) +{ + int x, y, i; + int count; + int spacing; + double factor; + double min_mass; + double max_mass; + double min_speed; + double max_speed; + XGCValues gc_values; + XWindowAttributes attrs; + halftone_screen *halftone; + + halftone = (halftone_screen *) calloc (1, sizeof(halftone_screen)); + + halftone->dpy = dpy; + halftone->window = window; + + //halftone->delay = get_integer_resource (dpy, "delay", "Integer"); + //halftone->delay = (halftone->delay < 0 ? DEFAULT_DELAY : halftone->delay); + halftone->delay = delay; + halftone->delay = (halftone->delay < 0 ? DEFAULT_DELAY : halftone->delay); + + halftone->gc = XCreateGC (halftone->dpy, halftone->window, 0, &gc_values); + + halftone->buffer_width = -1; + halftone->buffer_height = -1; + halftone->dots = NULL; + + /* Read command line arguments and set all settings. */ + //count = get_integer_resource (dpy, "count", "Count"); + count = count_; + halftone->gravity_point_count = count < 1 ? DEFAULT_COUNT : count; + + //spacing = get_integer_resource (dpy, "spacing", "Integer"); + spacing = spacing_; + halftone->spacing = spacing < 1 ? DEFAULT_SPACING : spacing; + + //factor = get_float_resource (dpy, "sizeFactor", "Double"); + factor = sizeFactor; + halftone->max_dot_size = + (factor < 0 ? DEFAULT_SIZE_FACTOR : factor) * halftone->spacing; + + //min_mass = get_float_resource (dpy, "minMass", "Double"); + min_mass = minMass; + min_mass = min_mass < 0 ? DEFAULT_MIN_MASS : min_mass; + + //max_mass = get_float_resource (dpy, "maxMass", "Double"); + max_mass = maxMass; + max_mass = max_mass < 0 ? DEFAULT_MAX_MASS : max_mass; + max_mass = max_mass < min_mass ? min_mass : max_mass; + + //min_speed = get_float_resource (dpy, "minSpeed", "Double"); + min_speed = minSpeed; + min_speed = min_speed < 0 ? DEFAULT_MIN_SPEED : min_speed; + + //max_speed = get_float_resource (dpy, "maxSpeed", "Double"); + max_speed = maxSpeed; + max_speed = max_speed < 0 ? DEFAULT_MAX_SPEED : max_speed; + max_speed = max_speed < min_speed ? min_speed : max_speed; + + + /* Set up the moving gravity points. */ + halftone->gravity_point_x = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_y = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_mass = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_x_inc = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_y_inc = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + + for (i = 0; i < halftone->gravity_point_count; i++) + { + halftone->gravity_point_x[i] = frand(1); + halftone->gravity_point_y[i] = frand(1); + halftone->gravity_point_mass[i] = min_mass + (max_mass - min_mass) * frand(1); + halftone->gravity_point_x_inc[i] = min_speed + (max_speed - min_speed) * frand(1); + halftone->gravity_point_y_inc[i] = min_speed + (max_speed - min_speed) * frand(1); + } + + + /* Set up the dots. */ + XGetWindowAttributes(halftone->dpy, halftone->window, &attrs); + + //halftone->ncolors = get_integer_resource (dpy, "colors", "Colors"); + halftone->ncolors = colors; + if (halftone->ncolors < 4) halftone->ncolors = 4; + halftone->colors = (XColor *) calloc(halftone->ncolors, sizeof(XColor)); + make_smooth_colormap (attrs.screen, attrs.visual, attrs.colormap, + halftone->colors, &halftone->ncolors, + True, 0, False); + halftone->color0 = 0; + halftone->color1 = halftone->ncolors / 2; + //halftone->cycle_speed = get_integer_resource (dpy, "cycleSpeed", "CycleSpeed"); + halftone->cycle_speed = cycleSpeed; + halftone->color_tick = 0; + + update_buffer(halftone, &attrs); + update_dot_attributes(halftone, &attrs); + + for (x = 0; x < halftone->dots_width; x++) + for (y = 0; y < halftone->dots_height; y++) + { + halftone->dots[x + y * halftone->dots_width] = 0; + } + + return halftone; +} + + + +static void fill_circle(Display *dpy, Window window, GC gc, int x, int y, int size) +{ + int start_x = x - (size / 2); + int start_y = y - (size / 2); + unsigned int width = size; + unsigned int height = size; + int angle1 = 0; + int angle2 = 360 * 64; /* A full circle */ + + XFillArc (dpy, window, gc, + start_x, start_y, width, height, + angle1, angle2); +} + +static void repaint_halftone(halftone_screen *halftone) +{ + int x, y; + /* + int x_offset = halftone->spacing / 2; + int y_offset = halftone->spacing / 2; + */ + int x_offset = 0; + int y_offset = 0; + + + /* Fill buffer with background color */ + XSetForeground (halftone->dpy, halftone->buffer_gc, + halftone->colors[halftone->color0].pixel); + XFillRectangle(halftone->dpy, halftone->buffer, halftone->buffer_gc, 0, 0, halftone->buffer_width, halftone->buffer_height); + + /* Draw dots on buffer */ + XSetForeground (halftone->dpy, halftone->buffer_gc, + halftone->colors[halftone->color1].pixel); + + if (halftone->color_tick++ >= halftone->cycle_speed) + { + halftone->color_tick = 0; + halftone->color0 = (halftone->color0 + 1) % halftone->ncolors; + halftone->color1 = (halftone->color1 + 1) % halftone->ncolors; + } + + for (x = 0; x < halftone->dots_width; x++) + for (y = 0; y < halftone->dots_height; y++) + fill_circle(halftone->dpy, halftone->buffer, halftone->buffer_gc, + x_offset + x * halftone->spacing, y_offset + y * halftone->spacing, + halftone->max_dot_size * halftone->dots[x + y * halftone->dots_width]); + + /* Copy buffer to window */ + if (halftone->buffer != halftone->window) + XCopyArea(halftone->dpy, halftone->buffer, halftone->window, halftone->gc, 0, 0, halftone->buffer_width, halftone->buffer_height, 0, 0); +} + +static double calculate_gravity(halftone_screen *halftone, int x, int y) +{ + int i; + double gx = 0; + double gy = 0; + + for (i = 0; i < halftone->gravity_point_count; i++) + { + double dx = ((double) x) - halftone->gravity_point_x[i] * halftone->dots_width; + double dy = ((double) y) - halftone->gravity_point_y[i] * halftone->dots_height; + double distance = sqrt(dx * dx + dy * dy); + + if (distance != 0) + { + double gravity = halftone->gravity_point_mass[i] / (distance * distance / (halftone->dots_width * halftone->dots_height)); + + gx += (dx / distance) * gravity; + gy += (dy / distance) * gravity; + } + } + + return sqrt(gx * gx + gy * gy); +} + +static void update_halftone(halftone_screen *halftone) +{ + int x, y, i; + XWindowAttributes attrs; + + XGetWindowAttributes(halftone->dpy, halftone->window, &attrs); + + /* Make sure we have a valid buffer */ + update_buffer(halftone, &attrs); + + /* Make sure all dot attributes (spacing, width, height, etc) are correct */ + update_dot_attributes(halftone, &attrs); + + /* Move gravity points */ + for (i = 0; i < halftone->gravity_point_count; i++) + { + halftone->gravity_point_x_inc[i] = + (halftone->gravity_point_x[i] >= 1 || halftone->gravity_point_x[i] <= 0 ? + -halftone->gravity_point_x_inc[i] : + halftone->gravity_point_x_inc[i]); + halftone->gravity_point_y_inc[i] = + (halftone->gravity_point_y[i] >= 1 || halftone->gravity_point_y[i] <= 0 ? + -halftone->gravity_point_y_inc[i] : + halftone->gravity_point_y_inc[i]); + + halftone->gravity_point_x[i] += halftone->gravity_point_x_inc[i]; + halftone->gravity_point_y[i] += halftone->gravity_point_y_inc[i]; + } + + /* Update gravity in each dot .*/ + for (x = 0; x < halftone->dots_width; x++) + for (y = 0; y < halftone->dots_height; y++) + { + double gravity = calculate_gravity(halftone, x, y); + + halftone->dots[x + y * halftone->dots_width] = (gravity > 1 ? 1 : (gravity < 0 ? 0 : gravity)); + } +} + + +static unsigned long +halftone_draw (Display *dpy, Window window, void *closure) +{ + halftone_screen *halftone = (halftone_screen *) closure; + + repaint_halftone(halftone); + update_halftone(halftone); + + return halftone->delay; +} + + +static void +halftone_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + halftone_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +halftone_free (Display *dpy, Window window, void *closure) +{ + halftone_screen *halftone = (halftone_screen *) closure; + free (halftone); +} + + +static const char *halftone_defaults [] = { + ".background: Black", + "*delay: 10000", + "*count: 10", + "*minMass: 0.001", + "*maxMass: 0.02", + "*minSpeed: 0.001", + "*maxSpeed: 0.02", + "*spacing: 14", + "*sizeFactor: 1.5", + "*colors: 200", + "*cycleSpeed: 10", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec halftone_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-minmass", ".minMass", XrmoptionSepArg, 0 }, + { "-maxmass", ".maxMass", XrmoptionSepArg, 0 }, + { "-minspeed", ".minSpeed", XrmoptionSepArg, 0 }, + { "-maxspeed", ".maxSpeed", XrmoptionSepArg, 0 }, + { "-spacing", ".spacing", XrmoptionSepArg, 0 }, + { "-sizefactor", ".sizeFactor", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-cycle-speed", ".cycleSpeed", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Halftone", halftone) diff --git a/non-wgl/halftone.vcproj b/non-wgl/halftone.vcproj new file mode 100644 index 0000000..9592418 --- /dev/null +++ b/non-wgl/halftone.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/halo.c b/non-wgl/halo.c new file mode 100644 index 0000000..3dd3b90 --- /dev/null +++ b/non-wgl/halo.c @@ -0,0 +1,484 @@ +/* xscreensaver, Copyright (c) 1993-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. + */ + +/* I wanted to lay down new circles with TV:ALU-ADD instead of TV:ALU-XOR, + but X doesn't support arithmetic combinations of pixmaps!! What losers. + I suppose I could crank out the 2's compliment math by hand, but that's + a real drag... + + This would probably look good with shapes other than circles as well. + + */ + +#include "screenhack.h" +#include + +char *background = "black"; +char *foreground = "white"; +char *colorMode = "random"; +int colors = 100; +int count = 0; +int delay = 100000; +int delay2 = 20; +int increment = 0; +Bool animate = False; + + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&colorMode, "colorMode", NULL, "random", t_String}, + {&colors, "colors", NULL, "100", t_Int}, + {&count, "count", NULL, "0", t_Int}, + {&delay, "delay", NULL, "100000", t_Int}, + {&delay2, "delay2", NULL, "20", t_Int}, + {&increment, "increment", NULL, "0", t_Int}, + {&animate, "animate", NULL, "False", t_Bool}, +}; + + +struct circle { + int x, y, radius; + int increment; + int dx, dy; +}; + +static enum color_mode { + seuss_mode, ramp_mode, random_mode +} cmode; + + +struct state { + Display *dpy; + Window window; + + struct circle *circles; + int count, global_count; + Pixmap pixmap, buffer; + int width, height, global_inc; + int delay, delay2; + unsigned long fg_pixel, bg_pixel; + GC draw_gc, erase_gc, copy_gc, merge_gc; + Bool anim_p; + Colormap cmap; + + int ncolors; + XColor *colors; + int fg_index; + int bg_index; + + int iterations; + Bool done_once; + Bool done_once_no_really; + int clear_tick; + struct timeval then; +}; + +#undef min +#define min(x,y) ((x)<(y)?(x):(y)) +#undef max +#define max(x,y) ((x)>(y)?(x):(y)) + +static void +init_circles_1 (struct state *st) +{ + int i; + st->count = (st->global_count ? st->global_count + : (3 + (random () % max (1, (min (st->width, st->height) / 50))) + + (random () % max (1, (min (st->width, st->height) / 50))))); + st->circles = (struct circle *) malloc (st->count * sizeof (struct circle)); + for (i = 0; i < st->count; i++) + { + st->circles [i].x = 10 + random () % (st->width - 20); + st->circles [i].y = 10 + random () % (st->height - 20); + if (st->global_inc) + st->circles [i].increment = st->global_inc; + else + { /* prefer smaller increments to larger ones */ + int j = 8; + int inc = ((random()%j) + (random()%j) + (random()%j)) - ((j*3)/2); + if (inc < 0) inc = -inc + 3; + st->circles [i].increment = inc + 3; + } + st->circles [i].radius = random () % st->circles [i].increment; + st->circles [i].dx = ((random () % 3) - 1) * (1 + random () % 5); + st->circles [i].dy = ((random () % 3) - 1) * (1 + random () % 5); + } +} + +static void * +halo_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + char *mode_str = 0; + st->dpy = dpy; + st->window = window; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->cmap = xgwa.colormap; + //st->global_count = get_integer_resource (st->dpy, "count", "Integer"); + st->global_count = count; + if (st->global_count < 0) st->global_count = 0; + //st->global_inc = get_integer_resource (st->dpy, "increment", "Integer"); + st->global_inc = increment; + if (st->global_inc < 0) st->global_inc = 0; +#if 1 + st->anim_p = animate; + st->delay = delay; + st->delay2 = delay2; + mode_str = colorMode; +#else + st->anim_p = get_boolean_resource (st->dpy, "animate", "Boolean"); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer") * 1000000; + mode_str = get_string_resource (st->dpy, "colorMode", "ColorMode"); +#endif + if (! mode_str) cmode = random_mode; + else if (!strcmp (mode_str, "seuss")) cmode = seuss_mode; + else if (!strcmp (mode_str, "ramp")) cmode = ramp_mode; + else if (!strcmp (mode_str, "random")) cmode = random_mode; + else { + fprintf (stderr, + "%s: colorMode must be seuss, ramp, or random, not \"%s\"\n", + progname, mode_str); + exit (1); + } + + if (mono_p) cmode = seuss_mode; + if (cmode == random_mode) + cmode = ((random()&3) == 1) ? ramp_mode : seuss_mode; + + if (cmode == ramp_mode) + st->anim_p = False; /* This combo doesn't work right... */ + + //st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors = colors; + if (st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + + if (mono_p) + st->colors = 0; + else + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + + + if (mono_p) + ; + else if (random() % (cmode == seuss_mode ? 2 : 10)) + make_uniform_colormap (xgwa.screen, xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + else + make_smooth_colormap (xgwa.screen, xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + + if (st->ncolors <= 2) mono_p = True; + if (mono_p) cmode = seuss_mode; + + if (mono_p) + { +#if 1 + st->fg_pixel = load_color(st->dpy, st->cmap, foreground); + st->bg_pixel = load_color(st->dpy, st->cmap, background); +#else + st->fg_pixel = get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + st->bg_pixel = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); +#endif + } + else + { + st->fg_index = 0; + st->bg_index = st->ncolors / 4; + if (st->fg_index == st->bg_index) st->bg_index++; + st->fg_pixel = st->colors[st->fg_index].pixel; + st->bg_pixel = st->colors[st->bg_index].pixel; + } + + st->width = max (50, xgwa.width); + st->height = max (50, xgwa.height); + +#ifdef DEBUG + st->width/=2; st->height/=2; +#endif + + st->pixmap = XCreatePixmap (st->dpy, st->window, st->width, st->height, 1); + if (cmode == seuss_mode) + st->buffer = XCreatePixmap (st->dpy, st->window, st->width, st->height, 1); + else + st->buffer = 0; + + gcv.foreground = 1; + gcv.background = 0; + st->draw_gc = XCreateGC (st->dpy, st->pixmap, GCForeground | GCBackground, &gcv); + gcv.foreground = 0; + st->erase_gc = XCreateGC (st->dpy, st->pixmap, GCForeground, &gcv); + gcv.foreground = st->fg_pixel; + gcv.background = st->bg_pixel; + st->copy_gc = XCreateGC (st->dpy, st->window, GCForeground | GCBackground, &gcv); + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (dpy, st->draw_gc, False); + jwxyz_XSetAntiAliasing (dpy, st->erase_gc, False); + jwxyz_XSetAntiAliasing (dpy, st->copy_gc, False); +#endif + + if (cmode == seuss_mode) + { + gcv.foreground = 1; + gcv.background = 0; + gcv.function = GXxor; + st->merge_gc = XCreateGC (st->dpy, st->pixmap, + GCForeground | GCBackground | GCFunction, &gcv); + } + else + { + gcv.foreground = st->fg_pixel; + gcv.background = st->bg_pixel; + gcv.function = GXcopy; + st->merge_gc = XCreateGC (st->dpy, st->window, + GCForeground | GCBackground | GCFunction, &gcv); + } + + init_circles_1 (st); + XClearWindow (st->dpy, st->window); + if (st->buffer) XFillRectangle (st->dpy, st->buffer, st->erase_gc, 0, 0, st->width, st->height); + return st; +} + +static unsigned long +halo_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + Bool done = False; + Bool inhibit_sleep = False; + int this_delay = st->delay; + + XFillRectangle (st->dpy, st->pixmap, st->erase_gc, 0, 0, st->width, st->height); + for (i = 0; i < st->count; i++) + { + int radius = st->circles [i].radius; + int inc = st->circles [i].increment; + + if (! (st->iterations & 1)) /* never stop on an odd number of iterations */ + ; + else if (radius == 0) /* eschew inf */ + ; + else if (radius < 0) /* stop when the circles are points */ + done = True; + else /* stop when the circles fill the st->window */ + { + /* Probably there's a simpler way to ask the musical question, + "is this square completely enclosed by this circle," but I've + forgotten too much trig to know it... (That's not really the + right question anyway, but the right question is too hard.) */ + double x1 = ((double) (-st->circles [i].x)) / ((double) radius); + double y1 = ((double) (-st->circles [i].y)) / ((double) radius); + double x2 = ((double) (st->width - st->circles [i].x)) / ((double) radius); + double y2 = ((double) (st->height - st->circles [i].y)) / ((double) radius); + x1 *= x1; x2 *= x2; y1 *= y1; y2 *= y2; + if ((x1 + y1) < 1 && (x2 + y2) < 1 && (x1 + y2) < 1 && (x2 + y1) < 1) + done = True; + } + + if (radius > 0 && + (cmode == seuss_mode || /* drawing all circles, or */ + st->circles [0].increment < 0)) /* on the way back in */ + { + XFillArc (st->dpy, + (cmode == seuss_mode ? st->pixmap : st->window), + (cmode == seuss_mode ? st->draw_gc : st->merge_gc), + st->circles [i].x - radius, st->circles [i].y - radius, + radius * 2, radius * 2, 0, 360*64); + } + st->circles [i].radius += inc; + } + + if (st->anim_p && !st->done_once) + inhibit_sleep = !done; + + if (done) + { + if (st->anim_p) + { + st->done_once = True; + for (i = 0; i < st->count; i++) + { + st->circles [i].x += st->circles [i].dx; + st->circles [i].y += st->circles [i].dy; + st->circles [i].radius %= st->circles [i].increment; + if (st->circles [i].x < 0 || st->circles [i].x >= st->width) + { + st->circles [i].dx = -st->circles [i].dx; + st->circles [i].x += (2 * st->circles [i].dx); + } + if (st->circles [i].y < 0 || st->circles [i].y >= st->height) + { + st->circles [i].dy = -st->circles [i].dy; + st->circles [i].y += (2 * st->circles [i].dy); + } + } + } + else if (st->circles [0].increment < 0) + { + /* We've zoomed out and the screen is blank -- re-pick the + center points, and shift the st->colors. + */ + free (st->circles); + init_circles_1 (st); + if (! mono_p) + { + st->fg_index = (st->fg_index + 1) % st->ncolors; + st->bg_index = (st->fg_index + (st->ncolors/2)) % st->ncolors; + XSetForeground (st->dpy, st->copy_gc, st->colors [st->fg_index].pixel); + XSetBackground (st->dpy, st->copy_gc, st->colors [st->bg_index].pixel); + } + } + /* Sometimes go out from the inside instead of the outside */ + else if (st->clear_tick == 0 && ((random () % 3) == 0)) + { + st->iterations = 0; /* ick */ + for (i = 0; i < st->count; i++) + st->circles [i].radius %= st->circles [i].increment; + + st->clear_tick = ((random() % 8) + 4) | 1; /* must be odd */ + } + else + { + for (i = 0; i < st->count; i++) + { + st->circles [i].increment = -st->circles [i].increment; + st->circles [i].radius += (2 * st->circles [i].increment); + } + } + } + + if (st->buffer) + XCopyPlane (st->dpy, st->pixmap, st->buffer, st->merge_gc, 0, 0, st->width, st->height, 0, 0, 1); + else if (cmode != seuss_mode) + { + + if (!mono_p) + { + st->fg_index++; + st->bg_index++; + if (st->fg_index >= st->ncolors) st->fg_index = 0; + if (st->bg_index >= st->ncolors) st->bg_index = 0; + XSetForeground (st->dpy, st->merge_gc, st->colors [st->fg_index].pixel); + } + + if (st->circles [0].increment >= 0) + inhibit_sleep = True; + else if (done && cmode == seuss_mode) + XFillRectangle (st->dpy, st->window, st->merge_gc, 0, 0, st->width, st->height); + } + else + XCopyPlane (st->dpy, st->pixmap, st->window, st->merge_gc, 0, 0, st->width, st->height, 0, 0, 1); + + /* st->buffer is only used in seuss-mode or anim-mode */ + if (st->buffer && (st->anim_p + ? (done || (!st->done_once && (st->iterations & 1))) + : (st->iterations & 1))) + { + XCopyPlane (st->dpy, st->buffer, st->window, st->copy_gc, 0, 0, st->width, st->height, 0, 0, 1); + if (st->anim_p && done) + XFillRectangle (st->dpy, st->buffer, st->erase_gc, 0, 0, st->width, st->height); + } + +#ifdef DEBUG + XCopyPlane (st->dpy, st->pixmap, st->window, st->copy_gc, 0,0,st->width,st->height,st->width,st->height, 1); + if (st->buffer) + XCopyPlane (st->dpy, st->buffer, st->window, st->copy_gc, 0,0,st->width,st->height,0,st->height, 1); +#endif + + if (done) + st->iterations = 0; + else + st->iterations++; + + if (st->delay && !inhibit_sleep) + { + int d = st->delay; + + if (cmode == seuss_mode && st->anim_p) + this_delay = d/100; + else + this_delay = d; + + if (done) + st->done_once_no_really = True; + } + + if (done && st->clear_tick > 0) + { + st->clear_tick--; + if (!st->clear_tick) + { + XClearWindow (st->dpy, st->window); + if (st->buffer) XFillRectangle (st->dpy, st->buffer, st->erase_gc, 0,0,st->width,st->height); + } + } + + if (inhibit_sleep) this_delay = 0; + + return this_delay; +} + + + +static const char *halo_defaults [] = { + ".background: black", + ".foreground: white", + "*colorMode: random", + "*colors: 100", + "*count: 0", + "*delay: 100000", + "*delay2: 20", + "*increment: 0", + "*animate: False", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec halo_options [] = { + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-animate", ".animate", XrmoptionNoArg, "True" }, + { "-mode", ".colorMode", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +static void +halo_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + halo_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +halo_free (Display *dpy, Window window, void *closure) +{ +} + +XSCREENSAVER_MODULE ("Halo", halo) diff --git a/non-wgl/halo.vcproj b/non-wgl/halo.vcproj new file mode 100644 index 0000000..bd30df2 --- /dev/null +++ b/non-wgl/halo.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/helix.c b/non-wgl/helix.c new file mode 100644 index 0000000..114758a --- /dev/null +++ b/non-wgl/helix.c @@ -0,0 +1,381 @@ +/* xscreensaver, Copyright (c) 1992-2008 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. + */ + +/* Algorithm from a Mac program by Chris Tate, written in 1988 or so. */ + +/* 18-Sep-97: Johannes Keukelaar (johannes@nada.kth.se): Improved screen + * eraser. + * 10-May-97: merged ellipse code by Dan Stromberg + * as found in xlockmore 4.03a10. + * 1992: jwz created. + */ + +/* 25 April 2002: Matthew Strait added +-subdelay option so the drawing process can be watched */ + +#include "screenhack.h" +#include +#include "erase.h" + +char *background = "black"; +char *foreground = "white"; +int delay = 5; +int subdelay = 20000; + +float eraseSeconds = 0; +char *eraseMode = NULL; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "5", t_Int}, + {&subdelay, "subdelay", NULL, "20000", t_Int}, +}; + +#undef LINGER +#define LINGER LINGER_ + +enum draw_state { HELIX, DRAW_HELIX, TRIG, DRAW_TRIG, LINGER, ERASE }; + +struct state { + enum draw_state dstate; + double sins [360]; + double coss [360]; + + GC draw_gc; + unsigned int default_fg_pixel; + int sleep_time; + int subdelay; + eraser_state *eraser; + + int width, height; + Colormap cmap; + + int x1, y1, x2, y2, angle, i; + + int radius1, radius2, d_angle, factor1, factor2, factor3, factor4; + int d_angle_offset; + int offset, dir, density; +}; + +static void * +helix_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int i; + XGCValues gcv; + XWindowAttributes xgwa; + + //st->sleep_time = get_integer_resource(dpy, "delay", "Integer"); + //st->subdelay = get_integer_resource(dpy, "subdelay", "Integer"); + st->sleep_time = delay; + st->subdelay = subdelay; + + XGetWindowAttributes (dpy, window, &xgwa); + st->width = xgwa.width; + st->height = xgwa.height; + st->cmap = xgwa.colormap; + //gcv.foreground = st->default_fg_pixel = + // get_pixel_resource (dpy, st->cmap, "foreground", "Foreground"); + gcv.foreground = st->default_fg_pixel = load_color(dpy, st->cmap, foreground); + st->draw_gc = XCreateGC (dpy, window, GCForeground, &gcv); + //gcv.foreground = get_pixel_resource (dpy, st->cmap, "background", "Background"); + gcv.foreground = load_color(dpy, st->cmap, background); + + for (i = 0; i < 360; i++) + { + st->sins [i] = sin ((((double) i) / 180.0) * M_PI); + st->coss [i] = cos ((((double) i) / 180.0) * M_PI); + } + + st->dstate = (random() & 1) ? HELIX : TRIG; + + return st; +} + +static int +gcd (int a, int b) +{ + while (b > 0) + { + int tmp; + tmp = a % b; + a = b; + b = tmp; + } + return (a < 0 ? -a : a); +} + +static void +helix (Display *dpy, Window window, struct state *st) +{ + int xmid = st->width / 2; + int ymid = st->height / 2; + int limit = 1 + (360 / gcd (360, st->d_angle)); + + if (st->i == 0) + { + st->x1 = xmid; + st->y1 = ymid + st->radius2; + st->x2 = xmid; + st->y2 = ymid + st->radius1; + st->angle = 0; + } + +/* for (st->i = 0; st->i < limit; st->i++)*/ + { + int tmp; +#define pmod(x,y) (tmp=((x) % (y)), (tmp >= 0 ? tmp : (tmp + (y)))) + + st->x1 = xmid + (((double) st->radius1) * st->sins [pmod ((st->angle * st->factor1), 360)]); + st->y1 = ymid + (((double) st->radius2) * st->coss [pmod ((st->angle * st->factor2), 360)]); + XDrawLine (dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2); + st->x2 = xmid + (((double) st->radius2) * st->sins [pmod ((st->angle * st->factor3), 360)]); + st->y2 = ymid + (((double) st->radius1) * st->coss [pmod ((st->angle * st->factor4), 360)]); + XDrawLine (dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2); + st->angle += st->d_angle; + } + st->i++; + + if (st->i >= limit) + st->dstate = LINGER; +} + +static void +trig (Display *dpy, Window window, struct state *st) +{ + int xmid = st->width / 2; + int ymid = st->height / 2; + +/* while (st->d_angle >= -360 && st->d_angle <= 360)*/ + { + int tmp; + int angle = st->d_angle + st->d_angle_offset; + st->x1 = (st->sins [pmod(angle * st->factor1, 360)] * xmid) + xmid; + st->y1 = (st->coss [pmod(angle * st->factor1, 360)] * ymid) + ymid; + st->x2 = (st->sins [pmod(angle * st->factor2 + st->offset, 360)] * xmid) + xmid; + st->y2 = (st->coss [pmod(angle * st->factor2 + st->offset, 360)] * ymid) + ymid; + XDrawLine(dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2); + tmp = (int) 360 / (2 * st->density * st->factor1 * st->factor2); + if (tmp == 0) /* Do not want it getting stuck... */ + tmp = 1; /* Would not need if floating point */ + st->d_angle += st->dir * tmp; + } + + if (st->d_angle < -360 || st->d_angle > 360) + st->dstate = LINGER; +} + +#undef min +#define min(a,b) ((a)<(b)?(a):(b)) + +static void +random_helix (Display *dpy, Window window, struct state *st, + XColor *color, Bool *got_color) +{ + int radius; + double divisor; + + radius = min (st->width, st->height) / 2; + + st->i = 0; + st->d_angle = 0; + st->factor1 = 2; + st->factor2 = 2; + st->factor3 = 2; + st->factor4 = 2; + + divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1)); + + if ((random () & 1) == 0) + { + st->radius1 = radius; + st->radius2 = radius / divisor; + } + else + { + st->radius2 = radius; + st->radius1 = radius / divisor; + } + + while (gcd (360, st->d_angle) >= 2) + st->d_angle = random () % 360; + +#define random_factor() \ + (((random() % 7) ? ((random() & 1) + 1) : 3) \ + * (((random() & 1) * 2) - 1)) + + while (gcd (gcd (gcd (st->factor1, st->factor2), st->factor3), st->factor4) != 1) + { + st->factor1 = random_factor (); + st->factor2 = random_factor (); + st->factor3 = random_factor (); + st->factor4 = random_factor (); + } + + if (mono_p) + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); + else + { + hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5, + &color->red, &color->green, &color->blue); + if ((*got_color = XAllocColor (dpy, st->cmap, color))) + XSetForeground (dpy, st->draw_gc, color->pixel); + else + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); + } + + XClearWindow (dpy, window); +} + +static void +random_trig (Display *dpy, Window window, struct state *st, + XColor *color, Bool *got_color) +{ + st->d_angle = 0; + st->factor1 = (random() % 8) + 1; + do { + st->factor2 = (random() % 8) + 1; + } while (st->factor1 == st->factor2); + + st->dir = (random() & 1) ? 1 : -1; + st->d_angle_offset = random() % 360; + st->offset = ((random() % ((360 / 4) - 1)) + 1) / 4; + st->density = 1 << ((random() % 4) + 4); /* Higher density, higher angles */ + + if (mono_p) + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); + else + { + hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5, + &color->red, &color->green, &color->blue); + if ((*got_color = XAllocColor (dpy, st->cmap, color))) + XSetForeground (dpy, st->draw_gc, color->pixel); + else + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); + } + + XClearWindow (dpy, window); +} + + +/* random_helix_or_trig */ +static unsigned long +helix_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + Bool free_color = False; + XColor color; + int delay = st->subdelay; + int erase_delay = 10000; + int ii; + + if (st->eraser) { + st->eraser = erase_window (dpy, window, st->eraser); + if (st->eraser) + delay = erase_delay; + goto END; + } + + switch (st->dstate) + { + case LINGER: + delay = st->sleep_time * 1000000; + st->dstate = ERASE; + break; + + case ERASE: + st->eraser = erase_window (dpy, window, st->eraser); + delay = erase_delay; + if (free_color) XFreeColors (dpy, st->cmap, &color.pixel, 1, 0); + st->dstate = (random() & 1) ? HELIX : TRIG; + break; + + case DRAW_HELIX: + for (ii = 0; ii < 10; ii++) { + helix (dpy, window, st); + if (st->dstate != DRAW_HELIX) + break; + } + break; + + case DRAW_TRIG: + for (ii = 0; ii < 5; ii++) { + trig (dpy, window, st); + if (st->dstate != DRAW_TRIG) + break; + } + break; + + case HELIX: + random_helix (dpy, window, st, &color, &free_color); + st->dstate = DRAW_HELIX; + break; + + case TRIG: + random_trig(dpy, window, st, &color, &free_color); + st->dstate = DRAW_TRIG; + break; + + default: + abort(); + } + + END: + return delay; +} + +static void +helix_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; +} + +#if 0 + static Bool + helix_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +helix_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + +static const char *helix_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 5", + "*subdelay: 20000", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec helix_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-subdelay", ".subdelay", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 }, +}; + +XSCREENSAVER_MODULE ("Helix", helix) diff --git a/non-wgl/helix.vcproj b/non-wgl/helix.vcproj new file mode 100644 index 0000000..cfeff6b --- /dev/null +++ b/non-wgl/helix.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/hexadrop.c b/non-wgl/hexadrop.c new file mode 100644 index 0000000..74ecfd6 --- /dev/null +++ b/non-wgl/hexadrop.c @@ -0,0 +1,444 @@ +/* xscreensaver, Copyright (c) 1999-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. + * + * Draws a grid of hexagons or other shapes and drops them out. + * Created 8-Jul-2013. + */ + +#include "screenhack.h" +#include + +char *background = "black"; +char *foreground = "white"; +int delay = 30000; +int sides = 0; +int size_ = 15; +float speed = 1.0; +int ncolors = 128; +char *uniform = "Maybe"; +char *lockstep = "Maybe"; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "30000", t_Int}, + {&sides, "sides", NULL, "0", t_Int}, + {&size_, "size", NULL, "15", t_Int}, + {&speed, "speed", NULL, "1.0", t_Float}, + {&ncolors, "ncolors", NULL, "128", t_Int}, + {&uniform, "uniform", NULL, "Maybe", t_String}, + {&lockstep, "lockstep", NULL, "Maybe", t_String}, +}; + +#define countof(x) (sizeof(x)/sizeof(*(x))) +#define ABS(x) ((x)<0?-(x):(x)) + +typedef struct { + int sides; + int cx, cy; + double th0, th, radius, i, speed; + int colors[2]; + Bool initted_p; +} cell; + +typedef struct { + Display *dpy; + Window window; + XWindowAttributes xgwa; + + int ncells, cells_size, gw, gh; + cell *cells; + + int delay; + double speed; + int sides; + Bool lockstep_p; + Bool uniform_p; + Bool initted_p; + + int ncolors; + XColor *colors; + GC gc; + +} state; + + +static void +make_cells (state *st) +{ + //int grid_size = get_integer_resource (st->dpy, "size", "Size"); + int grid_size; + cell *cells2; + int size, r, gw, gh, x, y, i; + double th = 0; + + //grid_size = get_integer_resource (st->dpy, "size", "Size"); + grid_size = size_; + if (grid_size < 5) grid_size = 5; + + size = ((st->xgwa.width > st->xgwa.height + ? st->xgwa.width : st->xgwa.height) + / grid_size); + gw = st->xgwa.width / size; + gh = st->xgwa.height / size; + + switch (st->sides) { + case 8: + r = size * 0.75; + th = M_PI / st->sides; + gw *= 1.25; + gh *= 1.25; + break; + case 6: + r = size / sqrt(3); + th = M_PI / st->sides; + gh *= 1.2; + break; + case 3: + size *= 2; + r = size / sqrt(3); + th = M_PI / st->sides / 2; + break; + case 4: + size /= 2; + r = size * sqrt (2); + th = M_PI / st->sides; + break; + default: + abort(); + break; + } + + gw += 3; /* leave a few extra columns off screen just in case */ + gh += 3; + + st->ncells = gw * gh; + + if (st->initted_p && !st->cells) abort(); + if (!st->initted_p && st->cells) abort(); + + cells2 = (cell *) calloc (st->ncells, sizeof(*cells2)); + if (! cells2) abort(); + + if (st->cells) + { + for (y = 0; y < (st->gh < gh ? st->gh : gh); y++) + for (x = 0; x < (st->gw < gw ? st->gw : gw); x++) + cells2[y * gw + x] = st->cells [y * st->gw + x]; + free (st->cells); + st->cells = 0; + } + + st->cells = cells2; + st->gw = gw; + st->gh = gh; + + i = 0; + for (y = 0; y < gh; y++) + for (x = 0; x < gw; x++) + { + cell *c = &st->cells[i]; + c->sides = st->sides; + c->radius = r; + c->th = th; + + switch (st->sides) { + case 8: + if (x & 1) + { + c->cx = x * size; + c->radius /= 2; + c->th = M_PI / 4; + c->sides = 4; + c->radius *= 1.1; + } + else + { + c->cx = x * size; + c->radius *= 1.02; + c->radius--; + } + + if (y & 1) + c->cx -= size; + + c->cy = y * size; + + break; + case 6: + c->cx = x * size; + c->cy = y * size * sqrt(3)/2; + if (y & 1) + c->cx -= size * 0.5; + break; + case 4: + c->cx = x * size * 2; + c->cy = y * size * 2; + break; + case 3: + c->cx = x * size * 0.5; + c->cy = y * size * sqrt(3)/2; + if ((x & 1) ^ (y & 1)) + { + c->th = th + M_PI; + c->cy -= (r * 0.5); + } + break; + default: + abort(); + } + + if (! c->initted_p) + { + c->speed = st->speed * (st->uniform_p ? 1 : (0.1 + frand(0.9))); + c->i = st->lockstep_p ? 0 : random() % r; + c->colors[0] = (st->lockstep_p ? 0 : random() % st->ncolors); + c->colors[1] = 0; + c->initted_p = True; + } + + c->radius += 2; /* Avoid rounding errors */ + + if (c->i > c->radius) c->i = c->radius; + if (c->colors[0] >= st->ncolors) c->colors[0] = st->ncolors-1; + if (c->colors[1] >= st->ncolors) c->colors[1] = st->ncolors-1; + + i++; + } + + st->initted_p = True; +} + + +static void +draw_cell (state *st, cell *c) +{ + XPoint points[20]; + int i, j; + for (j = 0; j <= 1; j++) + { + int r = (j == 0 ? c->radius : c->i); + for (i = 0; i < c->sides; i++) + { + double th = i * M_PI * 2 / c->sides; + points[i].x = c->cx + r * cos (th + c->th) + 0.5; + points[i].y = c->cy + r * sin (th + c->th) + 0.5; + } + XSetForeground (st->dpy, st->gc, st->colors[c->colors[j]].pixel); + XFillPolygon (st->dpy, st->window, st->gc, points, c->sides, + Convex, CoordModeOrigin); + } + + c->i -= c->speed; + if (c->i < 0) + { + c->i = c->radius; + c->colors[1] = c->colors[0]; + if (c != &st->cells[0]) + c->colors[0] = st->cells[0].colors[0]; + else + c->colors[0] = random() % st->ncolors; + } +} + + +static void +hexadrop_init_1 (Display *dpy, Window window, state *st) +{ + XGCValues gcv; + char *s1, *s2; + + st->dpy = dpy; + st->window = window; +#if 1 + st->delay = delay; + st->ncolors = ncolors; + st->speed = speed; +#else + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + st->speed = get_float_resource (st->dpy, "speed", "Speed"); +#endif + if (st->speed < 0) st->speed = 0; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + if (st->ncolors < 2) st->ncolors = 2; + + st->colors = (XColor *) calloc (sizeof(*st->colors), st->ncolors); + + if (st->ncolors < 10) + make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, False, True, 0, True); + else + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, True); + XSetWindowBackground (dpy, window, st->colors[0].pixel); + + //s1 = get_string_resource (st->dpy, "uniform", "Uniform"); + //s2 = get_string_resource (st->dpy, "lockstep", "Lockstep"); + s1 = uniform; + s2 = lockstep; + + if ((!s1 || !*s1 || !strcasecmp(s1, "maybe")) && + (!s2 || !*s2 || !strcasecmp(s2, "maybe"))) + { + /* When being random, don't do both. */ + st->uniform_p = random() & 1; + st->lockstep_p = st->uniform_p ? 0 : random() & 1; + } + else + { + if (!s1 || !*s1 || !strcasecmp(s1, "maybe")) + st->uniform_p = random() & 1; + else + //st->uniform_p = get_boolean_resource (st->dpy, "uniform", "Uniform"); + st->uniform_p = (_stricmp(uniform, "True") == 0 ? True : False); + + if (!s2 || !*s2 || !strcasecmp(s2, "maybe")) + st->lockstep_p = random() & 1; + else + //st->lockstep_p = get_boolean_resource (st->dpy, "lockstep","Lockstep"); + st->lockstep_p = (_stricmp(lockstep, "True") == 0 ? True : False); + } + + + //st->sides = get_integer_resource (st->dpy, "sides", "Sides"); + st->sides = sides; + if (! (st->sides == 0 || st->sides == 3 || st->sides == 4 || + st->sides == 6 || st->sides == 8)) + { + printf ("%s: invalid number of sides: %d\n", progname, st->sides); + st->sides = 0; + } + + if (! st->sides) + { + static int defs[] = { 3, 3, 3, + 4, + 6, 6, 6, 6, + 8, 8, 8 }; + st->sides = defs[random() % countof(defs)]; + } + + make_cells (st); + gcv.foreground = st->colors[0].pixel; + st->gc = XCreateGC (dpy, window, GCForeground, &gcv); +} + + +static void * +hexadrop_init (Display *dpy, Window window) +{ + state *st = (state *) calloc (1, sizeof(*st)); + hexadrop_init_1 (dpy, window, st); + return st; +} + + + +static unsigned long +hexadrop_draw (Display *dpy, Window window, void *closure) +{ + state *st = (state *) closure; + int i; + + for (i = 0; i < st->ncells; i++) + draw_cell (st, &st->cells[i]); + + return st->delay; +} + + +static void +hexadrop_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + state *st = (state *) closure; + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + make_cells (st); +} + + +static void +hexadrop_free (Display *dpy, Window window, void *closure) +{ + state *st = (state *) closure; + if (st->colors) + { + free_colors (st->xgwa.screen, st->xgwa.colormap, st->colors, st->ncolors); + free (st->colors); + st->colors = 0; + } + if (st->cells) + { + free (st->cells); + st->cells = 0; + } + if (st->gc) + { + XFreeGC (st->dpy, st->gc); + st->gc = 0; + } +} + +#if 0 + static Bool + hexadrop_event (Display *dpy, Window window, void *closure, XEvent *event) + { + state *st = (state *) closure; + + if (event->type == ButtonPress || event->type == KeyPress) + { + cell *c = st->cells; + st->cells = 0; + hexadrop_free (st->dpy, st->window, st); + free (st->cells); + st->cells = c; + hexadrop_init_1 (st->dpy, st->window, st); + return True; + } + + return False; + } +#endif + +static const char *hexadrop_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 30000", + "*sides: 0", + "*size: 15", + "*speed: 1.0", + "*ncolors: 128", + "*uniform: Maybe", + "*lockstep: Maybe", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec hexadrop_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-sides", ".sides", XrmoptionSepArg, 0 }, + { "-size", ".size", XrmoptionSepArg, 0 }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-uniform-speed", ".uniform", XrmoptionNoArg, "True" }, + { "-no-uniform-speed",".uniform", XrmoptionNoArg, "False" }, + { "-lockstep", ".lockstep", XrmoptionNoArg, "True" }, + { "-no-lockstep", ".lockstep", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Hexadrop", hexadrop) diff --git a/non-wgl/hexadrop.vcproj b/non-wgl/hexadrop.vcproj new file mode 100644 index 0000000..31b7366 --- /dev/null +++ b/non-wgl/hexadrop.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/hopalong.c b/non-wgl/hopalong.c new file mode 100644 index 0000000..af11938 --- /dev/null +++ b/non-wgl/hopalong.c @@ -0,0 +1,591 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* hop --- real plane fractals */ + +#if 0 +static const char sccsid[] = "@(#)hop.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1991 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. + * + * Revision History: + * Changes in xlockmore distribution + * 01-Nov-2000: Allocation checks + * 24-Jun-1997: EJK and RR functions stolen from xmartin2.2 + * Ed Kubaitis ejk functions and xmartin + * Renaldo Recuerdo rr function, generalized exponent version + * of the Barry Martin's square root function + * 10-May-1997: Compatible with xscreensaver + * 27-Jul-1995: added Peter de Jong's hop from Scientific American + * July 87 p. 111. Sometimes they are amazing but there are a + * few duds (I did not see a pattern in the parameters). + * 29-Mar-1995: changed name from hopalong to hop + * 09-Dec-1994: added Barry Martin's sine hop + * Changes in original xlock + * 29-Oct-1990: fix bad (int) cast. + * 29-Jul-1990: support for multiple screens. + * 08-Jul-1990: new timing and colors and new algorithm for fractals. + * 15-Dec-1989: Fix for proper skipping of {White,Black}Pixel() in colors. + * 08-Oct-1989: Fixed long standing typo bug in RandomInitHop(); + * Fixed bug in memory allocation in init_hop(); + * Moved seconds() to an extern. + * Got rid of the % mod since .mod is slow on a sparc. + * 20-Sep-1989: Lint. + * 31-Aug-1988: Forked from xlock.c for modularity. + * 23-Mar-1988: Coded HOPALONG routines from Scientific American Sept. 86 p. 14. + * Hopalong was attributed to Barry Martin of Aston University + * (Birmingham, England) + */ + +#define STANDALONE + +#define MODE_hop +#define DELAY 10000 +#define COUNT 1000 +#define CYCLES 2500 +#define NCOLORS 200 +#define DEFAULTS "*delay: 10000 \n" \ + "*count: 1000 \n" \ + "*cycles: 2500 \n" \ + "*ncolors: 200 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define SMOOTH_COLORS +# define reshape_hop 0 +# define hop_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +# include "erase.h" +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +char *background = "black"; +char *foreground = "white"; +char *eraseMode = NULL; +float eraseSeconds = 0; + +#ifdef MODE_hop + +#define DEF_MARTIN "False" +#define DEF_POPCORN "False" +#define DEF_EJK1 "False" +#define DEF_EJK2 "False" +#define DEF_EJK3 "False" +#define DEF_EJK4 "False" +#define DEF_EJK5 "False" +#define DEF_EJK6 "False" +#define DEF_RR "False" +#define DEF_JONG "False" +#define DEF_SINE "False" + +static Bool martin = False; +static Bool popcorn = False; +static Bool ejk1 = False; +static Bool ejk2 = False; +static Bool ejk3 = False; +static Bool ejk4 = False; +static Bool ejk5 = False; +static Bool ejk6 = False; +static Bool rr = False; +static Bool jong = False; +static Bool sine = False; + +static XrmOptionDescRec opts[] = +{ + {"-martin", ".hop.martin", XrmoptionNoArg, "on"}, + {"+martin", ".hop.martin", XrmoptionNoArg, "off"}, + {"-popcorn", ".hop.popcorn", XrmoptionNoArg, "on"}, + {"+popcorn", ".hop.popcorn", XrmoptionNoArg, "off"}, + {"-ejk1", ".hop.ejk1", XrmoptionNoArg, "on"}, + {"+ejk1", ".hop.ejk1", XrmoptionNoArg, "off"}, + {"-ejk2", ".hop.ejk2", XrmoptionNoArg, "on"}, + {"+ejk2", ".hop.ejk2", XrmoptionNoArg, "off"}, + {"-ejk3", ".hop.ejk3", XrmoptionNoArg, "on"}, + {"+ejk3", ".hop.ejk3", XrmoptionNoArg, "off"}, + {"-ejk4", ".hop.ejk4", XrmoptionNoArg, "on"}, + {"+ejk4", ".hop.ejk4", XrmoptionNoArg, "off"}, + {"-ejk5", ".hop.ejk5", XrmoptionNoArg, "on"}, + {"+ejk5", ".hop.ejk5", XrmoptionNoArg, "off"}, + {"-ejk6", ".hop.ejk6", XrmoptionNoArg, "on"}, + {"+ejk6", ".hop.ejk6", XrmoptionNoArg, "off"}, + {"-rr", ".hop.rr", XrmoptionNoArg, "on"}, + {"+rr", ".hop.rr", XrmoptionNoArg, "off"}, + {"-jong", ".hop.jong", XrmoptionNoArg, "on"}, + {"+jong", ".hop.jong", XrmoptionNoArg, "off"}, + {"-sine", ".hop.sine", XrmoptionNoArg, "on"}, + {"+sine", ".hop.sine", XrmoptionNoArg, "off"} +}; +static argtype vars[] = +{ + {&martin, "martin", "Martin", DEF_MARTIN, t_Bool}, + {&popcorn, "popcorn", "Popcorn", DEF_POPCORN, t_Bool}, + {&ejk1, "ejk1", "EJK1", DEF_EJK1, t_Bool}, + {&ejk2, "ejk2", "EJK2", DEF_EJK2, t_Bool}, + {&ejk3, "ejk3", "EJK3", DEF_EJK3, t_Bool}, + {&ejk4, "ejk4", "EJK4", DEF_EJK4, t_Bool}, + {&ejk5, "ejk5", "EJK5", DEF_EJK5, t_Bool}, + {&ejk6, "ejk6", "EJK6", DEF_EJK6, t_Bool}, + {&rr, "rr", "RR", DEF_RR, t_Bool}, + {&jong, "jong", "Jong", DEF_JONG, t_Bool}, + {&sine, "sine", "Sine", DEF_SINE, t_Bool} +}; +static OptionStruct desc[] = +{ + {"-/+martin", "turn on/off sqrt format"}, + {"-/+popcorn", "turn on/off Clifford A. Pickover's popcorn format"}, + {"-/+ejk1", "turn on/off ejk1 format"}, + {"-/+ejk2", "turn on/off ejk2 format"}, + {"-/+ejk3", "turn on/off ejk3 format"}, + {"-/+ejk4", "turn on/off ejk4 format"}, + {"-/+ejk5", "turn on/off ejk5 format"}, + {"-/+ejk6", "turn on/off ejk6 format"}, + {"-/+rr", "turn on/off rr format"}, + {"-/+jong", "turn on/off jong format"}, + {"-/+sine", "turn on/off sine format"} +}; + +ENTRYPOINT ModeSpecOpt hop_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct hop_description = +{"hop", "init_hop", "draw_hop", "release_hop", + "refresh_hop", "init_hop", (char *) NULL, &hop_opts, + 10000, 1000, 2500, 1, 64, 1.0, "", + "Shows real plane iterated fractals", 0, NULL}; + +#endif + +#define MARTIN 0 +#define POPCORN 7 +#define SINE 8 +#define EJK1 1 +#define EJK2 2 +#define EJK3 9 +#define EJK4 3 +#define EJK5 4 +#define EJK6 10 +#define RR 5 +#define JONG 6 +#ifdef OFFENDING +#define OPS 8 /* 8, 9, 10 might be too close to a swastika for some... */ +#else +#define OPS 11 +#endif + +typedef struct { + int centerx, centery; /* center of the screen */ + double a, b, c, d; + double i, j; /* hopalong parameters */ + int inc; + int pix; + int op; + int count; + int bufsize; + XPoint *pointBuffer; /* pointer for XDrawPoints */ +#ifdef STANDALONE + eraser_state *eraser; +#endif +} hopstruct; + +static hopstruct *hops = (hopstruct *) NULL; + +ENTRYPOINT void +init_hop(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + double range; + hopstruct *hp; + + if (hops == NULL) { + if ((hops = (hopstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (hopstruct))) == NULL) + return; + } + hp = &hops[MI_SCREEN(mi)]; + + hp->centerx = MI_WIDTH(mi) / 2; + hp->centery = MI_HEIGHT(mi) / 2; + /* Make the other operations less common since they are less interesting */ + if (MI_IS_FULLRANDOM(mi)) { + hp->op = NRAND(OPS); + } else { + if (martin) + hp->op = MARTIN; + else if (popcorn) + hp->op = POPCORN; + else if (ejk1) + hp->op = EJK1; + else if (ejk2) + hp->op = EJK2; + else if (ejk3) + hp->op = EJK3; + else if (ejk4) + hp->op = EJK4; + else if (ejk5) + hp->op = EJK5; + else if (ejk6) + hp->op = EJK6; + else if (rr) + hp->op = RR; + else if (jong) + hp->op = JONG; + else if (sine) + hp->op = SINE; + else + hp->op = NRAND(OPS); + } + + range = sqrt((double) hp->centerx * hp->centerx + + (double) hp->centery * hp->centery) / (1.0 + LRAND() / MAXRAND); + hp->i = hp->j = 0.0; + hp->inc = (int) ((LRAND() / MAXRAND) * 200) - 100; +#undef XMARTIN + switch (hp->op) { + case MARTIN: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 1500.0 + 40.0; + hp->b = (LRAND() / MAXRAND) * 17.0 + 3.0; + hp->c = (LRAND() / MAXRAND) * 3000.0 + 100.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 20.0; + hp->b = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 20.0; + if (LRAND() & 1) + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 20.0; + else + hp->c = 0.0; +#endif + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "sqrt a=%g, b=%g, c=%g\n", hp->a, hp->b, hp->c); + break; + case EJK1: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 500.0; + hp->c = (LRAND() / MAXRAND) * 100.0 + 10.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 30.0; + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 40.0; +#endif + hp->b = (LRAND() / MAXRAND) * 0.4; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "ejk1 a=%g, b=%g, c=%g\n", hp->a, hp->b, hp->c); + break; + case EJK2: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 500.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 30.0; +#endif + hp->b = pow(10.0, 6.0 + (LRAND() / MAXRAND) * 24.0); + if (LRAND() & 1) + hp->b = -hp->b; + hp->c = pow(10.0, (LRAND() / MAXRAND) * 9.0); + if (LRAND() & 1) + hp->c = -hp->c; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "ejk2 a=%g, b=%g, c=%g\n", hp->a, hp->b, hp->c); + break; + case EJK3: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 500.0; + hp->c = (LRAND() / MAXRAND) * 80.0 + 30.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 30.0; + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 70.0; +#endif + hp->b = (LRAND() / MAXRAND) * 0.35 + 0.5; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "ejk3 a=%g, b=%g, c=%g\n", hp->a, hp->b, hp->c); + break; + case EJK4: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 1000.0; + hp->c = (LRAND() / MAXRAND) * 40.0 + 30.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 2.0; + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 200.0; +#endif + hp->b = (LRAND() / MAXRAND) * 9.0 + 1.0; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "ejk4 a=%g, b=%g, c=%g\n", hp->a, hp->b, hp->c); + break; + case EJK5: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 600.0; + hp->c = (LRAND() / MAXRAND) * 90.0 + 20.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 2.0; + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 200.0; +#endif + hp->b = (LRAND() / MAXRAND) * 0.3 + 0.1; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "ejk5 a=%g, b=%g, c=%g\n", hp->a, hp->b, hp->c); + break; + case EJK6: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 100.0 + 550.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 30.0; +#endif + hp->b = (LRAND() / MAXRAND) + 0.5; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "ejk6 a=%g, b=%g\n", hp->a, hp->b); + break; + case RR: +#ifdef XMARTIN + hp->a = (LRAND() / MAXRAND) * 100.0; + hp->b = (LRAND() / MAXRAND) * 20.0; + hp->c = (LRAND() / MAXRAND) * 200.0; +#else + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 40.0; + hp->b = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 200.0; + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * range / 20.0; +#endif + hp->d = (LRAND() / MAXRAND) * 0.9; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "rr a=%g, b=%g, c=%g, d=%g\n", + hp->a, hp->b, hp->c, hp->d); + break; + case POPCORN: + hp->a = 0.0; + hp->b = 0.0; + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.24 + 0.25; + hp->inc = 100; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "popcorn a=%g, b=%g, c=%g, d=%g\n", + hp->a, hp->b, hp->c, hp->d); + break; + case JONG: + hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * M_PI; + hp->b = ((LRAND() / MAXRAND) * 2.0 - 1.0) * M_PI; + hp->c = ((LRAND() / MAXRAND) * 2.0 - 1.0) * M_PI; + hp->d = ((LRAND() / MAXRAND) * 2.0 - 1.0) * M_PI; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "jong a=%g, b=%g, c=%g, d=%g\n", + hp->a, hp->b, hp->c, hp->d); + break; + case SINE: /* MARTIN2 */ +#ifdef XMARTIN + hp->a = M_PI + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.07; +#else + hp->a = M_PI + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.7; +#endif + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, "sine a=%g\n", hp->a); + break; + } + if (MI_NPIXELS(mi) > 2) + hp->pix = NRAND(MI_NPIXELS(mi)); + hp->bufsize = MI_COUNT(mi); + + if (hp->pointBuffer == NULL) { + if ((hp->pointBuffer = (XPoint *) malloc(hp->bufsize * + sizeof (XPoint))) == NULL) + return; + } + +#ifndef STANDALONE + MI_CLEARWINDOW(mi); +#endif + + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + hp->count = 0; +} + + +ENTRYPOINT void +draw_hop(ModeInfo * mi) +{ + double oldj, oldi; + XPoint *xp; + int k; + hopstruct *hp; + + if (hops == NULL) + return; + hp = &hops[MI_SCREEN(mi)]; + +#ifdef STANDALONE + if (hp->eraser) { + hp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), hp->eraser); + return; + } +#endif + + + if (hp->pointBuffer == NULL) + return; + xp = hp->pointBuffer; + k = hp->bufsize; + + MI_IS_DRAWN(mi) = True; + hp->inc++; + if (MI_NPIXELS(mi) > 2) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, hp->pix)); + if (++hp->pix >= MI_NPIXELS(mi)) + hp->pix = 0; + } + while (k--) { + oldj = hp->j; + switch (hp->op) { + case MARTIN: /* SQRT, MARTIN1 */ + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj + ((hp->i < 0) + ? sqrt(fabs(hp->b * oldi - hp->c)) + : -sqrt(fabs(hp->b * oldi - hp->c))); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case EJK1: + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - ((hp->i > 0) ? (hp->b * oldi - hp->c) : + -(hp->b * oldi - hp->c)); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case EJK2: + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - ((hp->i < 0) ? log(fabs(hp->b * oldi - hp->c)) : + -log(fabs(hp->b * oldi - hp->c))); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case EJK3: + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - ((hp->i > 0) ? sin(hp->b * oldi) - hp->c : + -sin(hp->b * oldi) - hp->c); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case EJK4: + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - ((hp->i > 0) ? sin(hp->b * oldi) - hp->c : + -sqrt(fabs(hp->b * oldi - hp->c))); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case EJK5: + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - ((hp->i > 0) ? sin(hp->b * oldi) - hp->c : + -(hp->b * oldi - hp->c)); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case EJK6: + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - asin((hp->b * oldi) - (long) (hp->b * oldi)); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case RR: /* RR1 */ + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - ((hp->i < 0) ? -pow(fabs(hp->b * oldi - hp->c), hp->d) : + pow(fabs(hp->b * oldi - hp->c), hp->d)); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + case POPCORN: +#define HVAL 0.05 +#define INCVAL 50 + { + double tempi, tempj; + + if (hp->inc >= 100) + hp->inc = 0; + if (hp->inc == 0) { + if (hp->a++ >= INCVAL) { + hp->a = 0; + if (hp->b++ >= INCVAL) + hp->b = 0; + } + hp->i = (-hp->c * INCVAL / 2 + hp->c * hp->a) * M_PI / 180.0; + hp->j = (-hp->c * INCVAL / 2 + hp->c * hp->b) * M_PI / 180.0; + } + tempi = hp->i - HVAL * sin(hp->j + tan(3.0 * hp->j)); + tempj = hp->j - HVAL * sin(hp->i + tan(3.0 * hp->i)); + xp->x = hp->centerx + (int) (MI_WIDTH(mi) / 40 * tempi); + xp->y = hp->centery + (int) (MI_HEIGHT(mi) / 40 * tempj); + hp->i = tempi; + hp->j = tempj; + } + break; + case JONG: + if (hp->centerx > 0) + oldi = hp->i + 4 * hp->inc / hp->centerx; + else + oldi = hp->i; + hp->j = sin(hp->c * hp->i) - cos(hp->d * hp->j); + hp->i = sin(hp->a * oldj) - cos(hp->b * oldi); + xp->x = hp->centerx + (int) (hp->centerx * (hp->i + hp->j) / 4.0); + xp->y = hp->centery - (int) (hp->centery * (hp->i - hp->j) / 4.0); + break; + case SINE: /* MARTIN2 */ + oldi = hp->i + hp->inc; + hp->j = hp->a - hp->i; + hp->i = oldj - sin(oldi); + xp->x = hp->centerx + (int) (hp->i + hp->j); + xp->y = hp->centery - (int) (hp->i - hp->j); + break; + } + xp++; + } + XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + hp->pointBuffer, hp->bufsize, CoordModeOrigin); + if (++hp->count > MI_CYCLES(mi)) { +#ifdef STANDALONE + hp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), hp->eraser); +#endif /* STANDALONE */ + init_hop(mi); + } +} + +ENTRYPOINT void +release_hop(ModeInfo * mi) +{ + if (hops != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + hopstruct *hp = &hops[screen]; + + if (hp->pointBuffer != NULL) + (void) free((void *) hp->pointBuffer); + } + (void) free((void *) hops); + hops = (hopstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_hop(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE_2 ("Hopalong", hopalong, hop) + +#endif /* MODE_hop */ diff --git a/non-wgl/hopalong.vcproj b/non-wgl/hopalong.vcproj new file mode 100644 index 0000000..8123e64 --- /dev/null +++ b/non-wgl/hopalong.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/hyperball.c b/non-wgl/hyperball.c new file mode 100644 index 0000000..b545719 --- /dev/null +++ b/non-wgl/hyperball.c @@ -0,0 +1,2583 @@ +/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1998, 2000 + * 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 code derived from TI Explorer Lisp code by Joe Keane, Fritz Mueller, + * and Jamie Zawinski. + */ + +#include "screenhack.h" +#include + +#define __STDC__ + +int observer_z_ = 3; +int delay_ = 20000; +float xy_ = 3; +float xz_ = 5; +float yw_ = 10; +float yz_ = 0; +float xw_ = 0; +float zw_ = 0; +char *background = "black"; +char *foreground = "white"; + +static argtype vars[] = +{ + {&observer_z_, "observer_z", NULL, "3", t_Int}, + {&delay_, "delay", NULL, "20000", t_Int}, + {&xy_, "xy", NULL, "3", t_Float}, + {&xz_, "xz", NULL, "5", t_Float}, + {&yw_, "yw", NULL, "10", t_Float}, + {&yz_, "yz", NULL, "0", t_Float}, + {&xw_, "xw", NULL, "0", t_Float}, + {&zw_, "zw", NULL, "0", t_Float}, + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, +}; + +char *colors[][8] = { + { + "#FF66BE", /* color00 */ + "#FFA300", /* color10 */ + "#BEDC00", /* color20 */ + "#12FB00", /* color30 */ + "#00F9BE", /* color40 */ + "#12D5FF", /* color50 */ + "#BE9AFF", /* color60 */ + "#FF5FFF", /* color70 */ + }, { + "#FF5BAA", /* color01 */ + "#F09200", /* color11 */ + "#AAC500", /* color21 */ + "#10E100", /* color31 */ + "#00DFAA", /* color41 */ + "#10BFFF", /* color51 */ + "#AA8AFF", /* color61 */ + "#F055FF", /* color71 */ + }, { + "#EE529A", /* color02 */ + "#D98400", /* color12 */ + "#9AB200", /* color22 */ + "#0ECB00", /* color32 */ + "#00C99A", /* color42 */ + "#0EADE7", /* color52 */ + "#9A7DFF", /* color62 */ + "#D94DE7", /* color72 */ + }, { + "#DA4B8C", /* color03 */ + "#C67900", /* color13 */ + "#8CA300", /* color23 */ + "#0DBA00", /* color33 */ + "#00B88C", /* color43 */ + "#0D9ED3", /* color53 */ + "#8C72EA", /* color63 */ + "#C646D3", /* color73 */ + }, { + "#C84581", /* color04 */ + "#B66F00", /* color14 */ + "#819600", /* color24 */ + "#0CAB00", /* color34 */ + "#00A981", /* color44 */ + "#0C91C2", /* color54 */ + "#8169D7", /* color64 */ + "#B641C2", /* color74 */ + }, { + "#B94078", /* color05 */ + "#A96700", /* color15 */ + "#788B00", /* color25 */ + "#0B9E00", /* color35 */ + "#009D78", /* color45 */ + "#0B86B3", /* color55 */ + "#7861C7", /* color65 */ + "#A93CB3", /* color75 */ + }, { + "#AC3C6F", /* color06 */ + "#9D6000", /* color16 */ + "#6F8100", /* color26 */ + "#0A9300", /* color36 */ + "#00926F", /* color46 */ + "#0A7DA7", /* color56 */ + "#6F5AB9", /* color66 */ + "#9D38A7", /* color76 */ + }, { + "#A13868", /* color07 */ + "#935900", /* color17 */ + "#687900", /* color27 */ + "#0A8A00", /* color37 */ + "#008868", /* color47 */ + "#0A759C", /* color57 */ + "#6854AD", /* color67 */ + "#93349C", /* color77 */ + } +}; + +#define POINT_COUNT 600 +#define LINE_COUNT 1200 + +#define ANGLE_SCALE 0.001 + +struct point_info +{ + float pg_a; + float pg_b; + float pg_c; + float pg_d; +}; + +struct line_info +{ + short li_ip; + short li_iq; + char li_color; + char li_pad[3]; +}; + +struct point_state +{ + short old_x, old_y; + short new_x, new_y; + unsigned char old_dep, new_dep; +}; + +struct hyper_state +{ + char hs_stop; + char hs_resize; + char hs_redraw; + char hs_icon; + Display *hs_display; + Window hs_window; + float hs_observer_z; + float hs_unit_scale; + float hs_offset_x; + float hs_offset_y; + int hs_delay; + double hs_angle_xy; + double hs_angle_xz; + double hs_angle_yz; + double hs_angle_xw; + double hs_angle_yw; + double hs_angle_zw; + double hs_cos_xy, hs_sin_xy; + double hs_cos_xz, hs_sin_xz; + double hs_cos_yz, hs_sin_yz; + double hs_cos_xw, hs_sin_xw; + double hs_cos_yw, hs_sin_yw; + double hs_cos_zw, hs_sin_zw; + double hs_ref_ax, hs_ref_ay, hs_ref_az, hs_ref_aw; + double hs_ref_bx, hs_ref_by, hs_ref_bz, hs_ref_bw; + double hs_ref_cx, hs_ref_cy, hs_ref_cz, hs_ref_cw; + double hs_ref_dx, hs_ref_dy, hs_ref_dz, hs_ref_dw; + GC hs_color_gcs[8][8]; + GC black_gc; + char hs_moved[POINT_COUNT]; + struct point_state hs_points[POINT_COUNT]; + int roted; +}; + +static const struct point_info point_table[POINT_COUNT]; +static const struct line_info line_table[LINE_COUNT]; + +static void set_sizes (struct hyper_state *hs, int width, int height); + +static void * +hyperball_init (Display *dpy, Window win) +{ + struct hyper_state *hs = (struct hyper_state *) calloc (1, sizeof(*hs)); + + XGCValues gcv; + Colormap cmap; + /* double xy, xz, yz, xw, yw, zw; */ + unsigned long bg_pixel; + float observer_z; + int delay; + + hs->hs_display = dpy; + hs->hs_window = win; + + //observer_z = get_float_resource (dpy, "observer-z", "Float"); + observer_z = observer_z_; + if (observer_z < 1.125) + observer_z = 1.125; + hs->hs_observer_z = observer_z; + + { + XWindowAttributes wa; + XGetWindowAttributes (dpy, win, &wa); + cmap = wa.colormap; + set_sizes (hs, wa.width, wa.height); + } + +#if 1 + hs->hs_angle_xy = xy_ * ANGLE_SCALE; + hs->hs_angle_xz = xz_ * ANGLE_SCALE; + hs->hs_angle_yz = yz_ * ANGLE_SCALE; + hs->hs_angle_xw = xw_ * ANGLE_SCALE; + hs->hs_angle_yw = yw_ * ANGLE_SCALE; + hs->hs_angle_zw = zw_ * ANGLE_SCALE; +#else + hs->hs_angle_xy = get_float_resource (dpy, "xy", "Float") * ANGLE_SCALE; + hs->hs_angle_xz = get_float_resource (dpy, "xz", "Float") * ANGLE_SCALE; + hs->hs_angle_yz = get_float_resource (dpy, "yz", "Float") * ANGLE_SCALE; + hs->hs_angle_xw = get_float_resource (dpy, "xw", "Float") * ANGLE_SCALE; + hs->hs_angle_yw = get_float_resource (dpy, "yw", "Float") * ANGLE_SCALE; + hs->hs_angle_zw = get_float_resource (dpy, "zw", "Float") * ANGLE_SCALE; +#endif + + //delay = get_integer_resource (dpy, "delay", "Integer"); + delay = delay_; + hs->hs_delay = delay; + + //bg_pixel = get_pixel_resource (dpy, cmap, "background", "Background"); + bg_pixel = load_color(dpy, cmap, background); + + if (mono_p) + { + GC black_gc; + unsigned long fg_pixel; + GC white_gc; + + gcv.function = GXcopy; + gcv.foreground = bg_pixel; + black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + //fg_pixel = get_pixel_resource (dpy, cmap, "foreground", "Foreground"); + fg_pixel = load_color(dpy, cmap, foreground); + gcv.foreground = fg_pixel; + white_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[0][0] = black_gc; + hs->hs_color_gcs[0][1] = white_gc; + } + else + { + int col; + int dep; + + gcv.function = GXcopy; + + //gcv.foreground = get_pixel_resource (dpy, cmap, + // "background", "Background"); + gcv.foreground = load_color(dpy, cmap, background); + hs->black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + + for (col = 0; col < 8; col++) + for (dep = 0; dep < 8; dep++) + { + char buffer[16]; + unsigned long fg_pixel; + GC color_gc; + + sprintf (buffer, "color%d%d", col, dep); + //fg_pixel = get_pixel_resource (dpy, cmap, buffer, "Foreground"); + fg_pixel = load_color(dpy, cmap, colors[dep][col]); + gcv.foreground = fg_pixel /*^ bg_pixel*/; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[col][dep] = color_gc; + } + } + + { + double xy; + double xz; + double yz; + double xw; + double yw; + double zw; +#if 1 + double cos_xy, sin_xy; + double cos_xz, sin_xz; + double cos_yz, sin_yz; + double cos_xw, sin_xw; + double cos_yw, sin_yw; + double cos_zw, sin_zw; +#endif + + hs->hs_ref_ax = 1.0, hs->hs_ref_ay = 0.0, hs->hs_ref_az = 0.0, hs->hs_ref_aw = 0.0; + hs->hs_ref_bx = 0.0, hs->hs_ref_by = 1.0, hs->hs_ref_bz = 0.0, hs->hs_ref_bw = 0.0; + hs->hs_ref_cx = 0.0, hs->hs_ref_cy = 0.0, hs->hs_ref_cz = 1.0, hs->hs_ref_cw = 0.0; + hs->hs_ref_dx = 0.0, hs->hs_ref_dy = 0.0, hs->hs_ref_dz = 0.0, hs->hs_ref_dw = 1.0; + + xy = hs->hs_angle_xy; + xz = hs->hs_angle_xz; + yz = hs->hs_angle_yz; + xw = hs->hs_angle_xw; + yw = hs->hs_angle_yw; + zw = hs->hs_angle_zw; + + cos_xy = cos (xy), sin_xy = sin (xy); + hs->hs_cos_xy = cos_xy, hs->hs_sin_xy = sin_xy; + cos_xz = cos (xz), sin_xz = sin (xz); + hs->hs_cos_xz = cos_xz, hs->hs_sin_xz = sin_xz; + cos_yz = cos (yz), sin_yz = sin (yz); + hs->hs_cos_yz = cos_yz, hs->hs_sin_yz = sin_yz; + cos_xw = cos (xw), sin_xw = sin (xw); + hs->hs_cos_xw = cos_xw, hs->hs_sin_xw = sin_xw; + cos_yw = cos (yw), sin_yw = sin (yw); + hs->hs_cos_yw = cos_yw, hs->hs_sin_yw = sin_yw; + cos_zw = cos (zw), sin_zw = sin (zw); + hs->hs_cos_zw = cos_zw, hs->hs_sin_zw = sin_zw; + } + + return hs; +} + + +static unsigned long +hyperball_draw (Display *dpy, Window window, void *closure) +{ + struct hyper_state *hs = (struct hyper_state *) closure; + + int icon; + int resize; + int redraw; + int stop; + int delay; + + icon = hs->hs_icon; + resize = hs->hs_resize; + if (icon || !(hs->roted | resize)) + goto skip1; + +#ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + XClearWindow (dpy, window); +#endif + + { + int pc; + const struct point_info *point_ptr; + struct point_state *point_state; + float observer_z; + float unit_scale; + float offset_x; + float offset_y; + char *mark_ptr; + + pc = POINT_COUNT; + point_ptr = &point_table[0]; + point_state = &hs->hs_points[0]; + mark_ptr = &hs->hs_moved[0]; + + while (--pc >= 0) + { + double pos_a; + double pos_b; + double pos_c; + double pos_d; + double az, bz, cz, dz; + double sum_z; + double ax, bx, cx, dx; + double sum_x; + double ay, by, cy, dy; + double sum_y; + double mul; + int old_x; + int old_y; + int old_dep; + double xf; + double yf; + int new_x; + int new_y; + int new_dep; + int mov; + + pos_a = point_ptr->pg_a; + pos_b = point_ptr->pg_b; + pos_c = point_ptr->pg_c; + pos_d = point_ptr->pg_d; + point_ptr++; + az = hs->hs_ref_az; bz = hs->hs_ref_bz; cz = hs->hs_ref_cz; dz = hs->hs_ref_dz; + ax = hs->hs_ref_ax; bx = hs->hs_ref_bx; cx = hs->hs_ref_cx; dx = hs->hs_ref_dx; + ay = hs->hs_ref_ay; by = hs->hs_ref_by; cy = hs->hs_ref_cy; dy = hs->hs_ref_dy; + sum_z = pos_a * az + pos_b * bz + pos_c * cz + pos_d * dz; + observer_z = hs->hs_observer_z; + unit_scale = hs->hs_unit_scale; + sum_x = pos_a * ax + pos_b * bx + pos_c * cx + pos_d * dx; + sum_y = pos_a * ay + pos_b * by + pos_c * cy + pos_d * dy; + mul = unit_scale / (observer_z - sum_z); + offset_x = hs->hs_offset_x; + offset_y = hs->hs_offset_y; + old_x = point_state->new_x; + old_y = point_state->new_y; + old_dep = point_state->new_dep; + xf = sum_x * mul + offset_x; + yf = sum_y * mul + offset_y; + new_x = (int)rint(xf); + new_y = (int)rint(yf); + new_dep = (int)floor(sum_z * -128.0) + 128; + point_state->old_x = old_x; + point_state->old_y = old_y; + point_state->old_dep = old_dep; + point_state->new_x = new_x; + point_state->new_y = new_y; + point_state->new_dep = new_dep; + point_state++; + mov = new_x != old_x || new_y != old_y || new_dep != old_dep; + *mark_ptr = mov; + mark_ptr++; + } + } + + skip1: + icon = hs->hs_icon; + redraw = hs->hs_redraw; + if (icon || !(hs->roted | redraw)) + goto skip2; + + { + int lc; + const struct line_info *li_ptr; + int mono; + Window win = hs->hs_window; + + lc = LINE_COUNT; + li_ptr = &line_table[0]; + mono = mono_p; + + while (--lc >= 0) + { + int ip; + int iq; + int col; + int mov_p; + int mov_q; + struct point_state *sp; + struct point_state *sq; + int p_x; + int p_y; + int q_x; + int q_y; + GC erase_gc; + GC draw_gc; + int old_sum; + int new_sum; + int old_dep; + int new_dep; + + ip = li_ptr->li_ip; + iq = li_ptr->li_iq; + col = li_ptr->li_color; + li_ptr++; + mov_p = hs->hs_moved[ip]; + mov_q = hs->hs_moved[iq]; + if (!(redraw | mov_p | mov_q)) + continue; + + sp = &hs->hs_points[ip]; + sq = &hs->hs_points[iq]; + + if (mono) + { + erase_gc = hs->hs_color_gcs[0][0]; + draw_gc = hs->hs_color_gcs[0][1]; + } + else + { + GC *row; + + old_sum = sp->old_dep + sq->old_dep; + new_sum = sp->new_dep + sq->new_dep; + row = &hs->hs_color_gcs[col][0]; + old_dep = old_sum >> 6; + new_dep = new_sum >> 6; + erase_gc = hs->black_gc; + draw_gc = row[new_dep]; + } + + if (!redraw && erase_gc) + { + p_x = sp->old_x; + p_y = sp->old_y; + q_x = sq->old_x; + q_y = sq->old_y; + XDrawLine (dpy, win, erase_gc, p_x, p_y, q_x, q_y); + } + + p_x = sp->new_x; + p_y = sp->new_y; + q_x = sq->new_x; + q_y = sq->new_y; + XDrawLine (dpy, win, draw_gc, p_x, p_y, q_x, q_y); + } + } + + skip2: + stop = hs->hs_stop; + hs->roted = 0; + if (stop) + goto skip3; + + hs->roted = 1; + + { + double cos_a; + double sin_a; + double old_u; + double old_v; + double new_u; + double new_v; + + /* If you get error messages about the following forms, and you think you're + using an ANSI C conforming compiler, then you're mistaken. Possibly you're + mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa. + Regardless, your system is broken; it's not a bug in this program. + */ +#if defined(__STDC__) || defined(__ANSI_CPP__) + +#define rotate(name,dim0,dim1) \ + old_u = hs->hs_ref_##name##dim0; \ + old_v = hs->hs_ref_##name##dim1; \ + new_u = old_u * cos_a + old_v * sin_a; \ + new_v = old_v * cos_a - old_u * sin_a; \ + hs->hs_ref_##name##dim0 = new_u; \ + hs->hs_ref_##name##dim1 = new_v; + +#define rotates(dim0,dim1) \ + if (hs->hs_sin_##dim0##dim1 != 0) { \ + cos_a = hs->hs_cos_##dim0##dim1; \ + sin_a = hs->hs_sin_##dim0##dim1; \ + rotate(a, dim0, dim1); \ + rotate(b, dim0, dim1); \ + rotate(c, dim0, dim1); \ + rotate(d, dim0, dim1); \ + } + +#else /* !__STDC__, courtesy of Andreas Luik */ + +#define rotate(name,dim0,dim1,cos,sin) \ + old_u = hs->hs_ref_/**/name/**/dim0; \ + old_v = hs->hs_ref_/**/name/**/dim1; \ + new_u = old_u * cos_a + old_v * sin_a; \ + new_v = old_v * cos_a - old_u * sin_a; \ + hs->hs_ref_/**/name/**/dim0 = new_u; \ + hs->hs_ref_/**/name/**/dim1 = new_v; + +#define rotates(dim0,dim1) \ + if (hs->hs_sin_/**/dim0/**/dim1 != 0) { \ + cos_a = hs->hs_cos_/**/dim0/**/dim1; \ + sin_a = hs->hs_sin_/**/dim0/**/dim1; \ + rotate(a, dim0, dim1); \ + rotate(b, dim0, dim1); \ + rotate(c, dim0, dim1); \ + rotate(d, dim0, dim1); \ + } + +#endif + + rotates (x, y); + rotates (x, z); + rotates (y, z); + rotates (x, w); + rotates (y, w); + rotates (z, w); + } + + skip3: + /* stop = hs->hs_stop; */ + delay = hs->hs_delay; + if (stop && delay < 10000) + delay = 10000; + + hs->hs_redraw = 0; + hs->hs_resize = 0; + + return delay; +} + + +#if 0 + static Bool + hyperball_event (Display *dpy, Window win, void *closure, XEvent *event) + { + struct hyper_state *hs = (struct hyper_state *) closure; + + hs->hs_redraw = 0; + + switch (event->type) + { + case Expose: + hs->hs_icon = 0; + hs->hs_redraw = 1; + break; + + case ButtonPress: + switch (event->xbutton.button) + { + case 2: + hs->hs_stop = !hs->hs_stop; + break; + default: + break; + } + break; + + #ifndef HAVE_COCOA + case UnmapNotify: + hs->hs_icon = 1; + hs->hs_redraw = 0; + break; + #endif + + default: + break; + } + + if (hs->hs_redraw) + XClearWindow (dpy, win); + + return False; + } +#endif + +static void +hyperball_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct hyper_state *hs = (struct hyper_state *) closure; + hs->hs_icon = 0; + hs->hs_resize = 1; + hs->hs_redraw = 1; + set_sizes (hs, w, h); + XClearWindow (dpy, window); +} + + +static void +set_sizes (struct hyper_state *hs, int width, int height) +{ + double observer_z; + int min_dim; + double var; + double offset_x; + double offset_y; + double unit_scale; + + observer_z = hs->hs_observer_z; + min_dim = width < height ? width : height; + var = sqrt(observer_z * observer_z - 1.0); + offset_x = 0.5 * (width - 1); + offset_y = 0.5 * (height - 1); + unit_scale = 0.4 * min_dim * var; + hs->hs_offset_x = (float)offset_x; + hs->hs_offset_y = (float)offset_y; + hs->hs_unit_scale = (float)unit_scale; +} + +static void +hyperball_free (Display *dpy, Window window, void *closure) +{ + struct hyper_state *hs = (struct hyper_state *) closure; + free (hs); +} + +/* data */ + +static const struct point_info point_table[POINT_COUNT] = +{ + { 0.93, 0.30, 0.09, 0.03, }, + { 0.84, 0.49, -0.08, 0.05, }, + { 0.72, 0.65, 0.02, -0.09, }, + { 0.57, 0.79, 0.05, 0.07, }, + { 0.40, 0.89, -0.09, -0.01, }, + { 0.20, 0.95, 0.07, -0.06, }, + { 0.00, 0.97, 0.00, 0.09, }, + { -0.20, 0.95, -0.07, -0.06, }, + { -0.40, 0.89, 0.09, -0.01, }, + { -0.57, 0.79, -0.05, 0.07, }, + { -0.72, 0.65, -0.02, -0.09, }, + { -0.84, 0.49, 0.08, 0.05, }, + { -0.93, 0.30, -0.09, 0.03, }, + { -0.97, 0.10, 0.04, -0.08, }, + { -0.97, -0.10, 0.04, 0.08, }, + { -0.93, -0.30, -0.09, -0.03, }, + { -0.84, -0.49, 0.08, -0.05, }, + { -0.72, -0.65, -0.02, 0.09, }, + { -0.57, -0.79, -0.05, -0.07, }, + { -0.40, -0.89, 0.09, 0.01, }, + { -0.20, -0.95, -0.07, 0.06, }, + { 0.00, -0.97, 0.00, -0.09, }, + { 0.20, -0.95, 0.07, 0.06, }, + { 0.40, -0.89, -0.09, 0.01, }, + { 0.57, -0.79, 0.05, -0.07, }, + { 0.72, -0.65, 0.02, 0.09, }, + { 0.84, -0.49, -0.08, -0.05, }, + { 0.93, -0.30, 0.09, -0.03, }, + { 0.97, -0.10, -0.04, 0.08, }, + { 0.97, 0.10, -0.04, -0.08, }, + { 0.27, 0.83, -0.13, -0.41, }, + { 0.09, 0.87, 0.40, 0.18, }, + { -0.09, 0.87, -0.40, 0.18, }, + { -0.27, 0.83, 0.13, -0.41, }, + { -0.44, 0.76, 0.22, 0.38, }, + { -0.59, 0.65, -0.42, -0.09, }, + { -0.71, 0.51, 0.35, -0.25, }, + { -0.80, 0.36, -0.05, 0.43, }, + { -0.86, 0.18, -0.29, -0.32, }, + { -0.88, 0.00, 0.43, 0.00, }, + { -0.86, -0.18, -0.29, 0.32, }, + { -0.80, -0.36, -0.05, -0.43, }, + { -0.71, -0.51, 0.35, 0.25, }, + { -0.59, -0.65, -0.42, 0.09, }, + { -0.44, -0.76, 0.22, -0.38, }, + { -0.27, -0.83, 0.13, 0.41, }, + { -0.09, -0.87, -0.40, -0.18, }, + { 0.09, -0.87, 0.40, -0.18, }, + { 0.27, -0.83, -0.13, 0.41, }, + { 0.44, -0.76, -0.22, -0.38, }, + { 0.59, -0.65, 0.42, 0.09, }, + { 0.71, -0.51, -0.35, 0.25, }, + { 0.80, -0.36, 0.05, -0.43, }, + { 0.86, -0.18, 0.29, 0.32, }, + { 0.88, 0.00, -0.43, 0.00, }, + { 0.86, 0.18, 0.29, -0.32, }, + { 0.80, 0.36, 0.05, 0.43, }, + { 0.71, 0.51, -0.35, -0.25, }, + { 0.59, 0.65, 0.42, -0.09, }, + { 0.44, 0.76, -0.22, 0.38, }, + { -0.13, 0.41, -0.27, 0.83, }, + { -0.22, 0.38, -0.44, -0.76, }, + { -0.29, 0.32, 0.86, 0.18, }, + { -0.35, 0.25, -0.71, 0.51, }, + { -0.40, 0.18, 0.09, -0.87, }, + { -0.42, 0.09, 0.59, 0.65, }, + { -0.43, 0.00, -0.88, 0.00, }, + { -0.42, -0.09, 0.59, -0.65, }, + { -0.40, -0.18, 0.09, 0.87, }, + { -0.35, -0.25, -0.71, -0.51, }, + { -0.29, -0.32, 0.86, -0.18, }, + { -0.22, -0.38, -0.44, 0.76, }, + { -0.13, -0.41, -0.27, -0.83, }, + { -0.05, -0.43, 0.80, 0.36, }, + { 0.05, -0.43, -0.80, 0.36, }, + { 0.13, -0.41, 0.27, -0.83, }, + { 0.22, -0.38, 0.44, 0.76, }, + { 0.29, -0.32, -0.86, -0.18, }, + { 0.35, -0.25, 0.71, -0.51, }, + { 0.40, -0.18, -0.09, 0.87, }, + { 0.42, -0.09, -0.59, -0.65, }, + { 0.43, 0.00, 0.88, 0.00, }, + { 0.42, 0.09, -0.59, 0.65, }, + { 0.40, 0.18, -0.09, -0.87, }, + { 0.35, 0.25, 0.71, 0.51, }, + { 0.29, 0.32, -0.86, 0.18, }, + { 0.22, 0.38, 0.44, -0.76, }, + { 0.13, 0.41, 0.27, 0.83, }, + { 0.05, 0.43, -0.80, -0.36, }, + { -0.05, 0.43, 0.80, -0.36, }, + { 0.09, -0.03, -0.93, 0.30, }, + { 0.09, -0.01, 0.40, -0.89, }, + { 0.09, 0.01, 0.40, 0.89, }, + { 0.09, 0.03, -0.93, -0.30, }, + { 0.08, 0.05, 0.84, -0.49, }, + { 0.07, 0.06, -0.20, 0.95, }, + { 0.05, 0.07, -0.57, -0.79, }, + { 0.04, 0.08, 0.97, 0.10, }, + { 0.02, 0.09, -0.72, 0.65, }, + { 0.00, 0.09, 0.00, -0.97, }, + { -0.02, 0.09, 0.72, 0.65, }, + { -0.04, 0.08, -0.97, 0.10, }, + { -0.05, 0.07, 0.57, -0.79, }, + { -0.07, 0.06, 0.20, 0.95, }, + { -0.08, 0.05, -0.84, -0.49, }, + { -0.09, 0.03, 0.93, -0.30, }, + { -0.09, 0.01, -0.40, 0.89, }, + { -0.09, -0.01, -0.40, -0.89, }, + { -0.09, -0.03, 0.93, 0.30, }, + { -0.08, -0.05, -0.84, 0.49, }, + { -0.07, -0.06, 0.20, -0.95, }, + { -0.05, -0.07, 0.57, 0.79, }, + { -0.04, -0.08, -0.97, -0.10, }, + { -0.02, -0.09, 0.72, -0.65, }, + { 0.00, -0.09, 0.00, 0.97, }, + { 0.02, -0.09, -0.72, -0.65, }, + { 0.04, -0.08, 0.97, -0.10, }, + { 0.05, -0.07, -0.57, 0.79, }, + { 0.07, -0.06, -0.20, -0.95, }, + { 0.08, -0.05, 0.84, 0.49, }, + { 0.64, 0.67, -0.15, -0.28, }, + { 0.49, 0.79, 0.30, 0.07, }, + { 0.31, 0.87, -0.26, 0.18, }, + { 0.13, 0.92, 0.04, -0.31, }, + { -0.07, 0.92, 0.20, 0.24, }, + { -0.26, 0.89, -0.31, -0.01, }, + { -0.44, 0.82, 0.22, -0.23, }, + { -0.60, 0.71, 0.02, 0.31, }, + { -0.73, 0.57, -0.25, -0.19, }, + { -0.83, 0.40, 0.31, -0.06, }, + { -0.90, 0.22, -0.16, 0.27, }, + { -0.93, 0.03, -0.09, -0.30, }, + { -0.91, -0.16, 0.28, 0.14, }, + { -0.86, -0.35, -0.29, 0.12, }, + { -0.77, -0.52, 0.11, -0.29, }, + { -0.64, -0.67, 0.15, 0.28, }, + { -0.49, -0.79, -0.30, -0.07, }, + { -0.31, -0.87, 0.26, -0.18, }, + { -0.13, -0.92, -0.04, 0.31, }, + { 0.07, -0.92, -0.20, -0.24, }, + { 0.26, -0.89, 0.31, 0.01, }, + { 0.44, -0.82, -0.22, 0.23, }, + { 0.60, -0.71, -0.02, -0.31, }, + { 0.73, -0.57, 0.25, 0.19, }, + { 0.83, -0.40, -0.31, 0.06, }, + { 0.90, -0.22, 0.16, -0.27, }, + { 0.93, -0.03, 0.09, 0.30, }, + { 0.91, 0.16, -0.28, -0.14, }, + { 0.86, 0.35, 0.29, -0.12, }, + { 0.77, 0.52, -0.11, 0.29, }, + { 0.44, 0.82, -0.22, -0.23, }, + { 0.26, 0.89, 0.31, -0.01, }, + { 0.07, 0.92, -0.20, 0.24, }, + { -0.12, 0.92, -0.04, -0.31, }, + { -0.31, 0.87, 0.26, 0.18, }, + { -0.49, 0.79, -0.30, 0.07, }, + { -0.64, 0.67, 0.15, -0.28, }, + { -0.77, 0.52, 0.11, 0.29, }, + { -0.86, 0.35, -0.29, -0.12, }, + { -0.91, 0.16, 0.28, -0.14, }, + { -0.93, -0.03, -0.09, 0.30, }, + { -0.90, -0.22, -0.16, -0.27, }, + { -0.83, -0.40, 0.31, 0.06, }, + { -0.73, -0.57, -0.25, 0.19, }, + { -0.60, -0.71, 0.02, -0.31, }, + { -0.44, -0.82, 0.22, 0.23, }, + { -0.26, -0.89, -0.31, 0.01, }, + { -0.07, -0.92, 0.20, -0.24, }, + { 0.12, -0.92, 0.04, 0.31, }, + { 0.31, -0.87, -0.26, -0.18, }, + { 0.49, -0.79, 0.30, -0.07, }, + { 0.64, -0.67, -0.15, 0.28, }, + { 0.77, -0.52, -0.11, -0.29, }, + { 0.86, -0.35, 0.29, 0.12, }, + { 0.91, -0.16, -0.28, 0.14, }, + { 0.93, 0.03, 0.09, -0.30, }, + { 0.90, 0.22, 0.16, 0.27, }, + { 0.83, 0.40, -0.31, -0.06, }, + { 0.73, 0.57, 0.25, -0.19, }, + { 0.60, 0.71, -0.02, 0.31, }, + { -0.13, 0.83, -0.27, -0.41, }, + { -0.30, 0.79, 0.49, 0.07, }, + { -0.46, 0.71, -0.38, 0.31, }, + { -0.60, 0.60, 0.02, -0.49, }, + { -0.71, 0.46, 0.35, 0.35, }, + { -0.79, 0.30, -0.49, 0.03, }, + { -0.83, 0.13, 0.31, -0.38, }, + { -0.84, -0.05, 0.08, 0.49, }, + { -0.81, -0.22, -0.41, -0.27, }, + { -0.75, -0.38, 0.48, -0.13, }, + { -0.65, -0.53, -0.22, 0.44, }, + { -0.53, -0.66, -0.18, -0.46, }, + { -0.38, -0.75, 0.46, 0.17, }, + { -0.22, -0.82, -0.44, 0.23, }, + { -0.04, -0.84, 0.12, -0.48, }, + { 0.13, -0.83, 0.27, 0.41, }, + { 0.30, -0.79, -0.49, -0.07, }, + { 0.46, -0.71, 0.38, -0.31, }, + { 0.60, -0.60, -0.02, 0.49, }, + { 0.71, -0.46, -0.35, -0.35, }, + { 0.79, -0.30, 0.49, -0.03, }, + { 0.83, -0.13, -0.31, 0.38, }, + { 0.84, 0.05, -0.08, -0.49, }, + { 0.81, 0.22, 0.41, 0.27, }, + { 0.75, 0.38, -0.48, 0.13, }, + { 0.65, 0.53, 0.22, -0.44, }, + { 0.53, 0.66, 0.18, 0.46, }, + { 0.38, 0.75, -0.46, -0.17, }, + { 0.22, 0.82, 0.44, -0.23, }, + { 0.04, 0.84, -0.12, 0.48, }, + { -0.65, 0.53, -0.22, -0.44, }, + { -0.75, 0.38, 0.48, 0.13, }, + { -0.81, 0.22, -0.41, 0.27, }, + { -0.84, 0.05, 0.08, -0.49, }, + { -0.83, -0.13, 0.31, 0.38, }, + { -0.79, -0.30, -0.49, -0.03, }, + { -0.71, -0.46, 0.35, -0.35, }, + { -0.60, -0.60, 0.02, 0.49, }, + { -0.46, -0.71, -0.38, -0.31, }, + { -0.30, -0.79, 0.49, -0.07, }, + { -0.13, -0.83, -0.27, 0.41, }, + { 0.04, -0.84, -0.13, -0.48, }, + { 0.22, -0.82, 0.44, 0.23, }, + { 0.38, -0.75, -0.46, 0.17, }, + { 0.53, -0.66, 0.18, -0.46, }, + { 0.65, -0.53, 0.22, 0.44, }, + { 0.75, -0.38, -0.48, -0.13, }, + { 0.81, -0.22, 0.41, -0.27, }, + { 0.84, -0.05, -0.08, 0.49, }, + { 0.83, 0.13, -0.31, -0.38, }, + { 0.79, 0.30, 0.49, 0.03, }, + { 0.71, 0.46, -0.35, 0.35, }, + { 0.60, 0.60, -0.02, -0.49, }, + { 0.46, 0.71, 0.38, 0.31, }, + { 0.30, 0.79, -0.49, 0.07, }, + { 0.13, 0.83, 0.27, -0.41, }, + { -0.04, 0.84, 0.13, 0.48, }, + { -0.22, 0.82, -0.44, -0.23, }, + { -0.38, 0.75, 0.46, -0.17, }, + { -0.53, 0.66, -0.18, 0.46, }, + { 0.11, 0.78, -0.33, -0.47, }, + { -0.05, 0.79, 0.57, 0.07, }, + { -0.22, 0.76, -0.44, 0.38, }, + { -0.37, 0.70, 0.01, -0.58, }, + { -0.51, 0.60, 0.42, 0.40, }, + { -0.62, 0.49, -0.57, 0.05, }, + { -0.71, 0.35, 0.35, -0.46, }, + { -0.77, 0.19, 0.11, 0.57, }, + { -0.79, 0.03, -0.49, -0.30, }, + { -0.78, -0.14, 0.55, -0.16, }, + { -0.73, -0.29, -0.25, 0.52, }, + { -0.65, -0.44, -0.22, -0.53, }, + { -0.55, -0.57, 0.54, 0.19, }, + { -0.42, -0.67, -0.51, 0.28, }, + { -0.27, -0.74, 0.13, -0.56, }, + { -0.11, -0.78, 0.33, 0.47, }, + { 0.05, -0.79, -0.57, -0.07, }, + { 0.22, -0.76, 0.44, -0.38, }, + { 0.37, -0.70, -0.01, 0.58, }, + { 0.51, -0.60, -0.42, -0.40, }, + { 0.62, -0.49, 0.57, -0.05, }, + { 0.71, -0.35, -0.35, 0.46, }, + { 0.77, -0.19, -0.11, -0.57, }, + { 0.79, -0.03, 0.49, 0.30, }, + { 0.78, 0.14, -0.55, 0.16, }, + { 0.73, 0.29, 0.25, -0.52, }, + { 0.65, 0.44, 0.22, 0.53, }, + { 0.55, 0.57, -0.54, -0.19, }, + { 0.42, 0.67, 0.51, -0.28, }, + { 0.27, 0.74, -0.13, 0.56, }, + { -0.73, 0.29, -0.25, -0.52, }, + { -0.78, 0.14, 0.55, 0.16, }, + { -0.79, -0.03, -0.49, 0.30, }, + { -0.77, -0.19, 0.11, -0.57, }, + { -0.71, -0.35, 0.35, 0.46, }, + { -0.62, -0.49, -0.57, -0.05, }, + { -0.51, -0.60, 0.42, -0.40, }, + { -0.37, -0.70, 0.01, 0.58, }, + { -0.22, -0.76, -0.44, -0.38, }, + { -0.05, -0.79, 0.57, -0.07, }, + { 0.11, -0.78, -0.33, 0.47, }, + { 0.27, -0.74, -0.13, -0.56, }, + { 0.42, -0.67, 0.51, 0.28, }, + { 0.55, -0.57, -0.54, 0.19, }, + { 0.65, -0.44, 0.22, -0.53, }, + { 0.73, -0.29, 0.25, 0.52, }, + { 0.78, -0.14, -0.55, -0.16, }, + { 0.79, 0.03, 0.49, -0.30, }, + { 0.77, 0.19, -0.11, 0.57, }, + { 0.71, 0.35, -0.35, -0.46, }, + { 0.62, 0.49, 0.57, 0.05, }, + { 0.51, 0.60, -0.42, 0.40, }, + { 0.37, 0.70, -0.01, -0.58, }, + { 0.22, 0.76, 0.44, 0.38, }, + { 0.05, 0.79, -0.57, 0.07, }, + { -0.11, 0.78, 0.33, -0.47, }, + { -0.27, 0.74, 0.13, 0.56, }, + { -0.42, 0.67, -0.51, -0.28, }, + { -0.55, 0.57, 0.54, -0.19, }, + { -0.65, 0.44, -0.22, 0.53, }, + { -0.28, 0.70, -0.24, -0.58, }, + { -0.42, 0.62, 0.59, 0.21, }, + { -0.54, 0.52, -0.55, 0.29, }, + { -0.64, 0.40, 0.15, -0.60, }, + { -0.71, 0.25, 0.35, 0.51, }, + { -0.75, 0.10, -0.62, -0.08, }, + { -0.75, -0.06, 0.48, -0.40, }, + { -0.72, -0.21, -0.02, 0.62, }, + { -0.66, -0.36, -0.45, -0.43, }, + { -0.57, -0.49, 0.62, -0.05, }, + { -0.46, -0.60, -0.38, 0.49, }, + { -0.33, -0.68, -0.11, -0.61, }, + { -0.18, -0.73, 0.53, 0.33, }, + { -0.02, -0.75, -0.60, 0.17, }, + { 0.13, -0.74, 0.27, -0.56, }, + { 0.28, -0.70, 0.24, 0.58, }, + { 0.42, -0.62, -0.59, -0.21, }, + { 0.54, -0.52, 0.55, -0.29, }, + { 0.64, -0.40, -0.15, 0.60, }, + { 0.71, -0.25, -0.35, -0.51, }, + { 0.75, -0.10, 0.62, 0.08, }, + { 0.75, 0.06, -0.48, 0.40, }, + { 0.72, 0.21, 0.02, -0.62, }, + { 0.66, 0.36, 0.45, 0.43, }, + { 0.57, 0.49, -0.62, 0.05, }, + { 0.46, 0.60, 0.38, -0.49, }, + { 0.33, 0.68, 0.11, 0.61, }, + { 0.18, 0.73, -0.53, -0.33, }, + { 0.02, 0.75, 0.60, -0.17, }, + { -0.13, 0.74, -0.27, 0.56, }, + { -0.46, 0.60, -0.38, -0.49, }, + { -0.57, 0.49, 0.62, 0.05, }, + { -0.66, 0.36, -0.45, 0.43, }, + { -0.72, 0.21, -0.02, -0.62, }, + { -0.75, 0.06, 0.48, 0.40, }, + { -0.75, -0.10, -0.62, 0.08, }, + { -0.71, -0.25, 0.35, -0.51, }, + { -0.64, -0.40, 0.15, 0.60, }, + { -0.54, -0.52, -0.55, -0.29, }, + { -0.42, -0.62, 0.59, -0.21, }, + { -0.28, -0.70, -0.24, 0.58, }, + { -0.13, -0.74, -0.27, -0.56, }, + { 0.02, -0.75, 0.60, 0.17, }, + { 0.18, -0.73, -0.53, 0.33, }, + { 0.33, -0.68, 0.11, -0.61, }, + { 0.46, -0.60, 0.38, 0.49, }, + { 0.57, -0.49, -0.62, -0.05, }, + { 0.66, -0.36, 0.45, -0.43, }, + { 0.72, -0.21, 0.02, 0.62, }, + { 0.75, -0.06, -0.48, -0.40, }, + { 0.75, 0.10, 0.62, -0.08, }, + { 0.71, 0.25, -0.35, 0.51, }, + { 0.64, 0.40, -0.15, -0.60, }, + { 0.54, 0.52, 0.55, 0.29, }, + { 0.42, 0.62, -0.59, 0.21, }, + { 0.28, 0.70, 0.24, -0.58, }, + { 0.13, 0.74, 0.27, 0.56, }, + { -0.02, 0.75, -0.60, -0.17, }, + { -0.18, 0.73, 0.53, -0.33, }, + { -0.33, 0.68, -0.11, 0.61, }, + { -0.24, 0.58, 0.28, 0.70, }, + { -0.35, 0.51, -0.71, -0.25, }, + { -0.45, 0.43, 0.66, -0.36, }, + { -0.53, 0.33, -0.18, 0.73, }, + { -0.59, 0.21, -0.42, -0.62, }, + { -0.62, 0.08, 0.75, 0.10, }, + { -0.62, -0.05, -0.57, 0.49, }, + { -0.60, -0.17, 0.02, -0.75, }, + { -0.55, -0.29, 0.54, 0.52, }, + { -0.48, -0.40, -0.75, 0.06, }, + { -0.38, -0.49, 0.46, -0.60, }, + { -0.27, -0.56, 0.13, 0.74, }, + { -0.15, -0.60, -0.64, -0.40, }, + { -0.02, -0.62, 0.72, -0.21, }, + { 0.11, -0.61, -0.33, 0.68, }, + { 0.24, -0.58, -0.29, -0.70, }, + { 0.35, -0.51, 0.71, 0.25, }, + { 0.45, -0.43, -0.66, 0.36, }, + { 0.53, -0.33, 0.18, -0.73, }, + { 0.59, -0.21, 0.42, 0.62, }, + { 0.62, -0.08, -0.75, -0.10, }, + { 0.62, 0.05, 0.57, -0.49, }, + { 0.60, 0.17, -0.02, 0.75, }, + { 0.55, 0.29, -0.54, -0.52, }, + { 0.48, 0.40, 0.75, -0.06, }, + { 0.38, 0.49, -0.46, 0.60, }, + { 0.27, 0.56, -0.13, -0.74, }, + { 0.15, 0.60, 0.64, 0.40, }, + { 0.02, 0.62, -0.72, 0.21, }, + { -0.11, 0.61, 0.33, -0.68, }, + { -0.38, 0.49, 0.46, 0.60, }, + { -0.48, 0.40, -0.75, -0.06, }, + { -0.55, 0.29, 0.54, -0.52, }, + { -0.60, 0.17, 0.02, 0.75, }, + { -0.62, 0.05, -0.57, -0.49, }, + { -0.62, -0.08, 0.75, -0.10, }, + { -0.59, -0.21, -0.42, 0.62, }, + { -0.53, -0.33, -0.18, -0.73, }, + { -0.45, -0.43, 0.66, 0.36, }, + { -0.35, -0.51, -0.71, 0.25, }, + { -0.24, -0.58, 0.28, -0.70, }, + { -0.11, -0.61, 0.33, 0.68, }, + { 0.02, -0.62, -0.72, -0.21, }, + { 0.15, -0.60, 0.64, -0.40, }, + { 0.27, -0.56, -0.13, 0.74, }, + { 0.38, -0.49, -0.46, -0.60, }, + { 0.48, -0.40, 0.75, 0.06, }, + { 0.55, -0.29, -0.54, 0.52, }, + { 0.60, -0.17, -0.02, -0.75, }, + { 0.62, -0.05, 0.57, 0.49, }, + { 0.62, 0.08, -0.75, 0.10, }, + { 0.59, 0.21, 0.42, -0.62, }, + { 0.53, 0.33, 0.18, 0.73, }, + { 0.45, 0.43, -0.66, -0.36, }, + { 0.35, 0.51, 0.71, -0.25, }, + { 0.24, 0.58, -0.28, 0.70, }, + { 0.11, 0.61, -0.33, -0.68, }, + { -0.02, 0.62, 0.72, 0.21, }, + { -0.15, 0.60, -0.64, 0.40, }, + { -0.27, 0.56, 0.13, -0.74, }, + { -0.33, 0.47, -0.11, 0.78, }, + { -0.42, 0.40, -0.51, -0.60, }, + { -0.49, 0.30, 0.79, 0.03, }, + { -0.54, 0.19, -0.55, 0.57, }, + { -0.57, 0.07, -0.05, -0.79, }, + { -0.57, -0.05, 0.62, 0.49, }, + { -0.55, -0.16, -0.78, 0.14, }, + { -0.51, -0.28, 0.42, -0.67, }, + { -0.44, -0.38, 0.22, 0.76, }, + { -0.35, -0.46, -0.71, -0.35, }, + { -0.25, -0.52, 0.73, -0.29, }, + { -0.13, -0.56, -0.27, 0.74, }, + { -0.01, -0.58, -0.37, -0.70, }, + { 0.11, -0.57, 0.77, 0.19, }, + { 0.22, -0.53, -0.65, 0.44, }, + { 0.33, -0.47, 0.11, -0.78, }, + { 0.42, -0.40, 0.51, 0.60, }, + { 0.49, -0.30, -0.79, -0.03, }, + { 0.54, -0.19, 0.55, -0.57, }, + { 0.57, -0.07, 0.05, 0.79, }, + { 0.57, 0.05, -0.62, -0.49, }, + { 0.55, 0.16, 0.78, -0.14, }, + { 0.51, 0.28, -0.42, 0.67, }, + { 0.44, 0.38, -0.22, -0.76, }, + { 0.35, 0.46, 0.71, 0.35, }, + { 0.25, 0.52, -0.73, 0.29, }, + { 0.13, 0.56, 0.27, -0.74, }, + { 0.01, 0.58, 0.37, 0.70, }, + { -0.11, 0.57, -0.77, -0.19, }, + { -0.22, 0.53, 0.65, -0.44, }, + { -0.25, 0.52, 0.73, 0.29, }, + { -0.35, 0.46, -0.71, 0.35, }, + { -0.44, 0.38, 0.22, -0.76, }, + { -0.51, 0.28, 0.42, 0.67, }, + { -0.55, 0.16, -0.78, -0.14, }, + { -0.57, 0.05, 0.62, -0.49, }, + { -0.57, -0.07, -0.05, 0.79, }, + { -0.54, -0.19, -0.55, -0.57, }, + { -0.49, -0.30, 0.79, -0.03, }, + { -0.42, -0.40, -0.51, 0.60, }, + { -0.33, -0.47, -0.11, -0.78, }, + { -0.22, -0.53, 0.65, 0.44, }, + { -0.11, -0.57, -0.77, 0.19, }, + { 0.01, -0.58, 0.37, -0.70, }, + { 0.13, -0.56, 0.27, 0.74, }, + { 0.25, -0.52, -0.73, -0.29, }, + { 0.35, -0.46, 0.71, -0.35, }, + { 0.44, -0.38, -0.22, 0.76, }, + { 0.51, -0.28, -0.42, -0.67, }, + { 0.55, -0.16, 0.78, 0.14, }, + { 0.57, -0.05, -0.62, 0.49, }, + { 0.57, 0.07, 0.05, -0.79, }, + { 0.54, 0.19, 0.55, 0.57, }, + { 0.49, 0.30, -0.79, 0.03, }, + { 0.42, 0.40, 0.51, -0.60, }, + { 0.33, 0.47, 0.11, 0.78, }, + { 0.22, 0.53, -0.65, -0.44, }, + { 0.11, 0.57, 0.77, -0.19, }, + { -0.01, 0.58, -0.37, 0.70, }, + { -0.13, 0.56, -0.27, -0.74, }, + { -0.27, 0.41, 0.13, 0.83, }, + { -0.35, 0.35, -0.71, -0.46, }, + { -0.41, 0.27, 0.81, -0.22, }, + { -0.46, 0.17, -0.38, 0.75, }, + { -0.49, 0.07, -0.30, -0.79, }, + { -0.49, -0.03, 0.79, 0.30, }, + { -0.48, -0.13, -0.75, 0.38, }, + { -0.44, -0.23, 0.22, -0.82, }, + { -0.38, -0.31, 0.46, 0.71, }, + { -0.31, -0.38, -0.83, -0.13, }, + { -0.22, -0.44, 0.65, -0.53, }, + { -0.13, -0.48, -0.04, 0.84, }, + { -0.02, -0.49, -0.60, -0.60, }, + { 0.08, -0.49, 0.84, -0.05, }, + { 0.18, -0.46, -0.53, 0.66, }, + { 0.27, -0.41, -0.13, -0.83, }, + { 0.35, -0.35, 0.71, 0.46, }, + { 0.41, -0.27, -0.81, 0.22, }, + { 0.46, -0.17, 0.38, -0.75, }, + { 0.49, -0.07, 0.30, 0.79, }, + { 0.49, 0.03, -0.79, -0.30, }, + { 0.48, 0.13, 0.75, -0.38, }, + { 0.44, 0.23, -0.22, 0.82, }, + { 0.38, 0.31, -0.46, -0.71, }, + { 0.31, 0.38, 0.83, 0.13, }, + { 0.22, 0.44, -0.65, 0.53, }, + { 0.12, 0.48, 0.04, -0.84, }, + { 0.02, 0.49, 0.60, 0.60, }, + { -0.08, 0.49, -0.84, 0.05, }, + { -0.18, 0.46, 0.53, -0.66, }, + { -0.22, 0.44, 0.65, 0.53, }, + { -0.31, 0.38, -0.83, 0.13, }, + { -0.38, 0.31, 0.46, -0.71, }, + { -0.44, 0.23, 0.22, 0.82, }, + { -0.48, 0.13, -0.75, -0.38, }, + { -0.49, 0.03, 0.79, -0.30, }, + { -0.49, -0.07, -0.30, 0.79, }, + { -0.46, -0.17, -0.38, -0.75, }, + { -0.41, -0.27, 0.81, 0.22, }, + { -0.35, -0.35, -0.71, 0.46, }, + { -0.27, -0.41, 0.13, -0.83, }, + { -0.18, -0.46, 0.53, 0.66, }, + { -0.08, -0.49, -0.84, -0.05, }, + { 0.02, -0.49, 0.60, -0.60, }, + { 0.12, -0.48, 0.04, 0.84, }, + { 0.22, -0.44, -0.65, -0.53, }, + { 0.31, -0.38, 0.83, -0.13, }, + { 0.38, -0.31, -0.46, 0.71, }, + { 0.44, -0.23, -0.22, -0.82, }, + { 0.48, -0.13, 0.75, 0.38, }, + { 0.49, -0.03, -0.79, 0.30, }, + { 0.49, 0.07, 0.30, -0.79, }, + { 0.46, 0.17, 0.38, 0.75, }, + { 0.41, 0.27, -0.81, -0.22, }, + { 0.35, 0.35, 0.71, -0.46, }, + { 0.27, 0.41, -0.13, 0.83, }, + { 0.18, 0.46, -0.53, -0.66, }, + { 0.08, 0.49, 0.84, 0.05, }, + { -0.02, 0.49, -0.60, 0.60, }, + { -0.12, 0.48, -0.04, -0.84, }, + { -0.15, 0.28, -0.64, 0.67, }, + { -0.20, 0.24, -0.07, -0.92, }, + { -0.25, 0.19, 0.73, 0.57, }, + { -0.28, 0.14, -0.91, 0.16, }, + { -0.30, 0.07, 0.49, -0.79, }, + { -0.31, 0.01, 0.26, 0.89, }, + { -0.31, -0.06, -0.83, -0.40, }, + { -0.29, -0.12, 0.86, -0.35, }, + { -0.26, -0.18, -0.31, 0.87, }, + { -0.22, -0.23, -0.44, -0.82, }, + { -0.16, -0.27, 0.90, 0.22, }, + { -0.11, -0.29, -0.77, 0.52, }, + { -0.04, -0.31, 0.12, -0.92, }, + { 0.02, -0.31, 0.60, 0.71, }, + { 0.09, -0.30, -0.93, -0.03, }, + { 0.15, -0.28, 0.64, -0.67, }, + { 0.20, -0.24, 0.07, 0.92, }, + { 0.25, -0.19, -0.73, -0.57, }, + { 0.28, -0.14, 0.91, -0.16, }, + { 0.30, -0.07, -0.49, 0.79, }, + { 0.31, -0.01, -0.26, -0.89, }, + { 0.31, 0.06, 0.83, 0.40, }, + { 0.29, 0.12, -0.86, 0.35, }, + { 0.26, 0.18, 0.31, -0.87, }, + { 0.22, 0.23, 0.44, 0.82, }, + { 0.16, 0.27, -0.90, -0.22, }, + { 0.11, 0.29, 0.77, -0.52, }, + { 0.04, 0.31, -0.12, 0.92, }, + { -0.02, 0.31, -0.60, -0.71, }, + { -0.09, 0.30, 0.93, 0.03, }, + { -0.22, 0.23, -0.44, 0.82, }, + { -0.26, 0.18, -0.31, -0.87, }, + { -0.29, 0.12, 0.86, 0.35, }, + { -0.31, 0.06, -0.83, 0.40, }, + { -0.31, -0.01, 0.26, -0.89, }, + { -0.30, -0.07, 0.49, 0.79, }, + { -0.28, -0.14, -0.91, -0.16, }, + { -0.25, -0.19, 0.73, -0.57, }, + { -0.20, -0.24, -0.07, 0.92, }, + { -0.15, -0.28, -0.64, -0.67, }, + { -0.09, -0.30, 0.93, -0.03, }, + { -0.02, -0.31, -0.60, 0.71, }, + { 0.04, -0.31, -0.13, -0.92, }, + { 0.11, -0.29, 0.77, 0.52, }, + { 0.16, -0.27, -0.90, 0.22, }, + { 0.22, -0.23, 0.44, -0.82, }, + { 0.26, -0.18, 0.31, 0.87, }, + { 0.29, -0.12, -0.86, -0.35, }, + { 0.31, -0.06, 0.83, -0.40, }, + { 0.31, 0.01, -0.26, 0.89, }, + { 0.30, 0.07, -0.49, -0.79, }, + { 0.28, 0.14, 0.91, 0.16, }, + { 0.25, 0.19, -0.73, 0.57, }, + { 0.20, 0.24, 0.07, -0.92, }, + { 0.15, 0.28, 0.64, 0.67, }, + { 0.09, 0.30, -0.93, 0.03, }, + { 0.02, 0.31, 0.60, -0.71, }, + { -0.04, 0.31, 0.13, 0.92, }, + { -0.11, 0.29, -0.77, -0.52, }, + { -0.16, 0.27, 0.90, -0.22, }, +}; + +static const struct line_info line_table[LINE_COUNT] = +{ + { 0, 1, 0, }, + { 0, 29, 0, }, + { 0, 148, 0, }, + { 0, 176, 0, }, + { 1, 2, 0, }, + { 1, 149, 0, }, + { 1, 177, 0, }, + { 2, 3, 0, }, + { 2, 120, 0, }, + { 2, 178, 0, }, + { 3, 4, 0, }, + { 3, 121, 0, }, + { 3, 179, 0, }, + { 4, 5, 0, }, + { 4, 122, 0, }, + { 4, 150, 0, }, + { 5, 6, 0, }, + { 5, 123, 0, }, + { 5, 151, 0, }, + { 6, 7, 0, }, + { 6, 124, 0, }, + { 6, 152, 0, }, + { 7, 8, 0, }, + { 7, 125, 0, }, + { 7, 153, 0, }, + { 8, 9, 0, }, + { 8, 126, 0, }, + { 8, 154, 0, }, + { 9, 10, 0, }, + { 9, 127, 0, }, + { 9, 155, 0, }, + { 10, 11, 0, }, + { 10, 128, 0, }, + { 10, 156, 0, }, + { 11, 12, 0, }, + { 11, 129, 0, }, + { 11, 157, 0, }, + { 12, 13, 0, }, + { 12, 130, 0, }, + { 12, 158, 0, }, + { 13, 14, 0, }, + { 13, 131, 0, }, + { 13, 159, 0, }, + { 14, 15, 0, }, + { 14, 132, 0, }, + { 14, 160, 0, }, + { 15, 16, 0, }, + { 15, 133, 0, }, + { 15, 161, 0, }, + { 16, 17, 0, }, + { 16, 134, 0, }, + { 16, 162, 0, }, + { 17, 18, 0, }, + { 17, 135, 0, }, + { 17, 163, 0, }, + { 18, 19, 0, }, + { 18, 136, 0, }, + { 18, 164, 0, }, + { 19, 20, 0, }, + { 19, 137, 0, }, + { 19, 165, 0, }, + { 20, 21, 0, }, + { 20, 138, 0, }, + { 20, 166, 0, }, + { 21, 22, 0, }, + { 21, 139, 0, }, + { 21, 167, 0, }, + { 22, 23, 0, }, + { 22, 140, 0, }, + { 22, 168, 0, }, + { 23, 24, 0, }, + { 23, 141, 0, }, + { 23, 169, 0, }, + { 24, 25, 0, }, + { 24, 142, 0, }, + { 24, 170, 0, }, + { 25, 26, 0, }, + { 25, 143, 0, }, + { 25, 171, 0, }, + { 26, 27, 0, }, + { 26, 144, 0, }, + { 26, 172, 0, }, + { 27, 28, 0, }, + { 27, 145, 0, }, + { 27, 173, 0, }, + { 28, 29, 0, }, + { 28, 146, 0, }, + { 28, 174, 0, }, + { 29, 147, 0, }, + { 29, 175, 0, }, + { 30, 123, 0, }, + { 30, 150, 0, }, + { 30, 240, 0, }, + { 30, 292, 0, }, + { 31, 124, 0, }, + { 31, 151, 0, }, + { 31, 241, 0, }, + { 31, 293, 0, }, + { 32, 125, 0, }, + { 32, 152, 0, }, + { 32, 242, 0, }, + { 32, 294, 0, }, + { 33, 126, 0, }, + { 33, 153, 0, }, + { 33, 243, 0, }, + { 33, 295, 0, }, + { 34, 127, 0, }, + { 34, 154, 0, }, + { 34, 244, 0, }, + { 34, 296, 0, }, + { 35, 128, 0, }, + { 35, 155, 0, }, + { 35, 245, 0, }, + { 35, 297, 0, }, + { 36, 129, 0, }, + { 36, 156, 0, }, + { 36, 246, 0, }, + { 36, 298, 0, }, + { 37, 130, 0, }, + { 37, 157, 0, }, + { 37, 247, 0, }, + { 37, 299, 0, }, + { 38, 131, 0, }, + { 38, 158, 0, }, + { 38, 248, 0, }, + { 38, 270, 0, }, + { 39, 132, 0, }, + { 39, 159, 0, }, + { 39, 249, 0, }, + { 39, 271, 0, }, + { 40, 133, 0, }, + { 40, 160, 0, }, + { 40, 250, 0, }, + { 40, 272, 0, }, + { 41, 134, 0, }, + { 41, 161, 0, }, + { 41, 251, 0, }, + { 41, 273, 0, }, + { 42, 135, 0, }, + { 42, 162, 0, }, + { 42, 252, 0, }, + { 42, 274, 0, }, + { 43, 136, 0, }, + { 43, 163, 0, }, + { 43, 253, 0, }, + { 43, 275, 0, }, + { 44, 137, 0, }, + { 44, 164, 0, }, + { 44, 254, 0, }, + { 44, 276, 0, }, + { 45, 138, 1, }, + { 45, 165, 1, }, + { 45, 255, 1, }, + { 45, 277, 1, }, + { 46, 139, 1, }, + { 46, 166, 1, }, + { 46, 256, 1, }, + { 46, 278, 1, }, + { 47, 140, 1, }, + { 47, 167, 1, }, + { 47, 257, 1, }, + { 47, 279, 1, }, + { 48, 141, 1, }, + { 48, 168, 1, }, + { 48, 258, 1, }, + { 48, 280, 1, }, + { 49, 142, 1, }, + { 49, 169, 1, }, + { 49, 259, 1, }, + { 49, 281, 1, }, + { 50, 143, 1, }, + { 50, 170, 1, }, + { 50, 260, 1, }, + { 50, 282, 1, }, + { 51, 144, 1, }, + { 51, 171, 1, }, + { 51, 261, 1, }, + { 51, 283, 1, }, + { 52, 145, 1, }, + { 52, 172, 1, }, + { 52, 262, 1, }, + { 52, 284, 1, }, + { 53, 146, 1, }, + { 53, 173, 1, }, + { 53, 263, 1, }, + { 53, 285, 1, }, + { 54, 147, 1, }, + { 54, 174, 1, }, + { 54, 264, 1, }, + { 54, 286, 1, }, + { 55, 148, 1, }, + { 55, 175, 1, }, + { 55, 265, 1, }, + { 55, 287, 1, }, + { 56, 149, 1, }, + { 56, 176, 1, }, + { 56, 266, 1, }, + { 56, 288, 1, }, + { 57, 120, 1, }, + { 57, 177, 1, }, + { 57, 267, 1, }, + { 57, 289, 1, }, + { 58, 121, 1, }, + { 58, 178, 1, }, + { 58, 268, 1, }, + { 58, 290, 1, }, + { 59, 122, 1, }, + { 59, 179, 1, }, + { 59, 269, 1, }, + { 59, 291, 1, }, + { 60, 420, 1, }, + { 60, 478, 1, }, + { 60, 567, 1, }, + { 60, 570, 1, }, + { 61, 421, 1, }, + { 61, 479, 1, }, + { 61, 568, 1, }, + { 61, 571, 1, }, + { 62, 422, 1, }, + { 62, 450, 1, }, + { 62, 569, 1, }, + { 62, 572, 1, }, + { 63, 423, 1, }, + { 63, 451, 1, }, + { 63, 540, 1, }, + { 63, 573, 1, }, + { 64, 424, 1, }, + { 64, 452, 1, }, + { 64, 541, 1, }, + { 64, 574, 1, }, + { 65, 425, 1, }, + { 65, 453, 1, }, + { 65, 542, 1, }, + { 65, 575, 1, }, + { 66, 426, 1, }, + { 66, 454, 1, }, + { 66, 543, 1, }, + { 66, 576, 1, }, + { 67, 427, 1, }, + { 67, 455, 1, }, + { 67, 544, 1, }, + { 67, 577, 1, }, + { 68, 428, 1, }, + { 68, 456, 1, }, + { 68, 545, 1, }, + { 68, 578, 1, }, + { 69, 429, 1, }, + { 69, 457, 1, }, + { 69, 546, 1, }, + { 69, 579, 1, }, + { 70, 430, 1, }, + { 70, 458, 1, }, + { 70, 547, 1, }, + { 70, 580, 1, }, + { 71, 431, 1, }, + { 71, 459, 1, }, + { 71, 548, 1, }, + { 71, 581, 1, }, + { 72, 432, 1, }, + { 72, 460, 1, }, + { 72, 549, 1, }, + { 72, 582, 1, }, + { 73, 433, 1, }, + { 73, 461, 1, }, + { 73, 550, 1, }, + { 73, 583, 1, }, + { 74, 434, 1, }, + { 74, 462, 1, }, + { 74, 551, 1, }, + { 74, 584, 1, }, + { 75, 435, 1, }, + { 75, 463, 1, }, + { 75, 552, 1, }, + { 75, 585, 1, }, + { 76, 436, 1, }, + { 76, 464, 1, }, + { 76, 553, 1, }, + { 76, 586, 1, }, + { 77, 437, 1, }, + { 77, 465, 1, }, + { 77, 554, 1, }, + { 77, 587, 1, }, + { 78, 438, 1, }, + { 78, 466, 1, }, + { 78, 555, 1, }, + { 78, 588, 1, }, + { 79, 439, 1, }, + { 79, 467, 1, }, + { 79, 556, 1, }, + { 79, 589, 1, }, + { 80, 440, 1, }, + { 80, 468, 1, }, + { 80, 557, 1, }, + { 80, 590, 1, }, + { 81, 441, 1, }, + { 81, 469, 1, }, + { 81, 558, 1, }, + { 81, 591, 1, }, + { 82, 442, 1, }, + { 82, 470, 1, }, + { 82, 559, 2, }, + { 82, 592, 2, }, + { 83, 443, 2, }, + { 83, 471, 2, }, + { 83, 560, 2, }, + { 83, 593, 2, }, + { 84, 444, 2, }, + { 84, 472, 2, }, + { 84, 561, 2, }, + { 84, 594, 2, }, + { 85, 445, 2, }, + { 85, 473, 2, }, + { 85, 562, 2, }, + { 85, 595, 2, }, + { 86, 446, 2, }, + { 86, 474, 2, }, + { 86, 563, 2, }, + { 86, 596, 2, }, + { 87, 447, 2, }, + { 87, 475, 2, }, + { 87, 564, 2, }, + { 87, 597, 2, }, + { 88, 448, 2, }, + { 88, 476, 2, }, + { 88, 565, 2, }, + { 88, 598, 2, }, + { 89, 449, 2, }, + { 89, 477, 2, }, + { 89, 566, 2, }, + { 89, 599, 2, }, + { 90, 101, 2, }, + { 90, 109, 2, }, + { 90, 562, 2, }, + { 90, 584, 2, }, + { 91, 102, 2, }, + { 91, 110, 2, }, + { 91, 563, 2, }, + { 91, 585, 2, }, + { 92, 103, 2, }, + { 92, 111, 2, }, + { 92, 564, 2, }, + { 92, 586, 2, }, + { 93, 104, 2, }, + { 93, 112, 2, }, + { 93, 565, 2, }, + { 93, 587, 2, }, + { 94, 105, 2, }, + { 94, 113, 2, }, + { 94, 566, 2, }, + { 94, 588, 2, }, + { 95, 106, 2, }, + { 95, 114, 2, }, + { 95, 567, 2, }, + { 95, 589, 2, }, + { 96, 107, 2, }, + { 96, 115, 2, }, + { 96, 568, 2, }, + { 96, 590, 2, }, + { 97, 108, 2, }, + { 97, 116, 2, }, + { 97, 569, 2, }, + { 97, 591, 2, }, + { 98, 109, 2, }, + { 98, 117, 2, }, + { 98, 540, 2, }, + { 98, 592, 2, }, + { 99, 110, 2, }, + { 99, 118, 2, }, + { 99, 541, 2, }, + { 99, 593, 2, }, + { 100, 111, 2, }, + { 100, 119, 2, }, + { 100, 542, 2, }, + { 100, 594, 2, }, + { 101, 112, 2, }, + { 101, 543, 2, }, + { 101, 595, 2, }, + { 102, 113, 2, }, + { 102, 544, 2, }, + { 102, 596, 2, }, + { 103, 114, 2, }, + { 103, 545, 2, }, + { 103, 597, 2, }, + { 104, 115, 2, }, + { 104, 546, 2, }, + { 104, 598, 2, }, + { 105, 116, 2, }, + { 105, 547, 2, }, + { 105, 599, 2, }, + { 106, 117, 2, }, + { 106, 548, 2, }, + { 106, 570, 2, }, + { 107, 118, 2, }, + { 107, 549, 2, }, + { 107, 571, 2, }, + { 108, 119, 2, }, + { 108, 550, 2, }, + { 108, 572, 2, }, + { 109, 551, 2, }, + { 109, 573, 2, }, + { 110, 552, 2, }, + { 110, 574, 2, }, + { 111, 553, 2, }, + { 111, 575, 2, }, + { 112, 554, 2, }, + { 112, 576, 2, }, + { 113, 555, 2, }, + { 113, 577, 2, }, + { 114, 556, 2, }, + { 114, 578, 2, }, + { 115, 557, 2, }, + { 115, 579, 2, }, + { 116, 558, 2, }, + { 116, 580, 2, }, + { 117, 559, 2, }, + { 117, 581, 2, }, + { 118, 560, 2, }, + { 118, 582, 2, }, + { 119, 561, 2, }, + { 119, 583, 2, }, + { 120, 150, 2, }, + { 120, 232, 2, }, + { 121, 151, 2, }, + { 121, 233, 2, }, + { 122, 152, 2, }, + { 122, 234, 2, }, + { 123, 153, 2, }, + { 123, 235, 2, }, + { 124, 154, 2, }, + { 124, 236, 2, }, + { 125, 155, 2, }, + { 125, 237, 2, }, + { 126, 156, 2, }, + { 126, 238, 2, }, + { 127, 157, 2, }, + { 127, 239, 2, }, + { 128, 158, 2, }, + { 128, 210, 2, }, + { 129, 159, 2, }, + { 129, 211, 2, }, + { 130, 160, 2, }, + { 130, 212, 2, }, + { 131, 161, 2, }, + { 131, 213, 2, }, + { 132, 162, 2, }, + { 132, 214, 2, }, + { 133, 163, 2, }, + { 133, 215, 2, }, + { 134, 164, 2, }, + { 134, 216, 2, }, + { 135, 165, 3, }, + { 135, 217, 3, }, + { 136, 166, 3, }, + { 136, 218, 3, }, + { 137, 167, 3, }, + { 137, 219, 3, }, + { 138, 168, 3, }, + { 138, 220, 3, }, + { 139, 169, 3, }, + { 139, 221, 3, }, + { 140, 170, 3, }, + { 140, 222, 3, }, + { 141, 171, 3, }, + { 141, 223, 3, }, + { 142, 172, 3, }, + { 142, 224, 3, }, + { 143, 173, 3, }, + { 143, 225, 3, }, + { 144, 174, 3, }, + { 144, 226, 3, }, + { 145, 175, 3, }, + { 145, 227, 3, }, + { 146, 176, 3, }, + { 146, 228, 3, }, + { 147, 177, 3, }, + { 147, 229, 3, }, + { 148, 178, 3, }, + { 148, 230, 3, }, + { 149, 179, 3, }, + { 149, 231, 3, }, + { 150, 207, 3, }, + { 151, 208, 3, }, + { 152, 209, 3, }, + { 153, 180, 3, }, + { 154, 181, 3, }, + { 155, 182, 3, }, + { 156, 183, 3, }, + { 157, 184, 3, }, + { 158, 185, 3, }, + { 159, 186, 3, }, + { 160, 187, 3, }, + { 161, 188, 3, }, + { 162, 189, 3, }, + { 163, 190, 3, }, + { 164, 191, 3, }, + { 165, 192, 3, }, + { 166, 193, 3, }, + { 167, 194, 3, }, + { 168, 195, 3, }, + { 169, 196, 3, }, + { 170, 197, 3, }, + { 171, 198, 3, }, + { 172, 199, 3, }, + { 173, 200, 3, }, + { 174, 201, 3, }, + { 175, 202, 3, }, + { 176, 203, 3, }, + { 177, 204, 3, }, + { 178, 205, 3, }, + { 179, 206, 3, }, + { 180, 237, 3, }, + { 180, 240, 3, }, + { 180, 300, 3, }, + { 181, 238, 3, }, + { 181, 241, 3, }, + { 181, 301, 3, }, + { 182, 239, 3, }, + { 182, 242, 3, }, + { 182, 302, 3, }, + { 183, 210, 3, }, + { 183, 243, 3, }, + { 183, 303, 3, }, + { 184, 211, 3, }, + { 184, 244, 3, }, + { 184, 304, 3, }, + { 185, 212, 3, }, + { 185, 245, 3, }, + { 185, 305, 3, }, + { 186, 213, 3, }, + { 186, 246, 3, }, + { 186, 306, 3, }, + { 187, 214, 3, }, + { 187, 247, 3, }, + { 187, 307, 3, }, + { 188, 215, 3, }, + { 188, 248, 3, }, + { 188, 308, 3, }, + { 189, 216, 3, }, + { 189, 249, 3, }, + { 189, 309, 3, }, + { 190, 217, 3, }, + { 190, 250, 3, }, + { 190, 310, 3, }, + { 191, 218, 3, }, + { 191, 251, 3, }, + { 191, 311, 3, }, + { 192, 219, 3, }, + { 192, 252, 3, }, + { 192, 312, 3, }, + { 193, 220, 3, }, + { 193, 253, 3, }, + { 193, 313, 3, }, + { 194, 221, 3, }, + { 194, 254, 3, }, + { 194, 314, 3, }, + { 195, 222, 3, }, + { 195, 255, 3, }, + { 195, 315, 3, }, + { 196, 223, 3, }, + { 196, 256, 3, }, + { 196, 316, 3, }, + { 197, 224, 3, }, + { 197, 257, 3, }, + { 197, 317, 3, }, + { 198, 225, 3, }, + { 198, 258, 3, }, + { 198, 318, 3, }, + { 199, 226, 3, }, + { 199, 259, 3, }, + { 199, 319, 3, }, + { 200, 227, 3, }, + { 200, 260, 3, }, + { 200, 320, 3, }, + { 201, 228, 3, }, + { 201, 261, 3, }, + { 201, 321, 3, }, + { 202, 229, 3, }, + { 202, 262, 3, }, + { 202, 322, 3, }, + { 203, 230, 3, }, + { 203, 263, 3, }, + { 203, 323, 3, }, + { 204, 231, 3, }, + { 204, 264, 3, }, + { 204, 324, 3, }, + { 205, 232, 3, }, + { 205, 265, 3, }, + { 205, 325, 3, }, + { 206, 233, 3, }, + { 206, 266, 3, }, + { 206, 326, 3, }, + { 207, 234, 3, }, + { 207, 267, 3, }, + { 207, 327, 3, }, + { 208, 235, 3, }, + { 208, 268, 3, }, + { 208, 328, 3, }, + { 209, 236, 3, }, + { 209, 269, 3, }, + { 209, 329, 3, }, + { 210, 270, 4, }, + { 210, 330, 4, }, + { 211, 271, 4, }, + { 211, 331, 4, }, + { 212, 272, 4, }, + { 212, 332, 4, }, + { 213, 273, 4, }, + { 213, 333, 4, }, + { 214, 274, 4, }, + { 214, 334, 4, }, + { 215, 275, 4, }, + { 215, 335, 4, }, + { 216, 276, 4, }, + { 216, 336, 4, }, + { 217, 277, 4, }, + { 217, 337, 4, }, + { 218, 278, 4, }, + { 218, 338, 4, }, + { 219, 279, 4, }, + { 219, 339, 4, }, + { 220, 280, 4, }, + { 220, 340, 4, }, + { 221, 281, 4, }, + { 221, 341, 4, }, + { 222, 282, 4, }, + { 222, 342, 4, }, + { 223, 283, 4, }, + { 223, 343, 4, }, + { 224, 284, 4, }, + { 224, 344, 4, }, + { 225, 285, 4, }, + { 225, 345, 4, }, + { 226, 286, 4, }, + { 226, 346, 4, }, + { 227, 287, 4, }, + { 227, 347, 4, }, + { 228, 288, 4, }, + { 228, 348, 4, }, + { 229, 289, 4, }, + { 229, 349, 4, }, + { 230, 290, 4, }, + { 230, 350, 4, }, + { 231, 291, 4, }, + { 231, 351, 4, }, + { 232, 292, 4, }, + { 232, 352, 4, }, + { 233, 293, 4, }, + { 233, 353, 4, }, + { 234, 294, 4, }, + { 234, 354, 4, }, + { 235, 295, 4, }, + { 235, 355, 4, }, + { 236, 296, 4, }, + { 236, 356, 4, }, + { 237, 297, 4, }, + { 237, 357, 4, }, + { 238, 298, 4, }, + { 238, 358, 4, }, + { 239, 299, 4, }, + { 239, 359, 4, }, + { 240, 327, 4, }, + { 240, 416, 4, }, + { 241, 328, 4, }, + { 241, 417, 4, }, + { 242, 329, 4, }, + { 242, 418, 4, }, + { 243, 300, 4, }, + { 243, 419, 4, }, + { 244, 301, 4, }, + { 244, 390, 4, }, + { 245, 302, 4, }, + { 245, 391, 4, }, + { 246, 303, 4, }, + { 246, 392, 4, }, + { 247, 304, 4, }, + { 247, 393, 4, }, + { 248, 305, 4, }, + { 248, 394, 4, }, + { 249, 306, 4, }, + { 249, 395, 4, }, + { 250, 307, 4, }, + { 250, 396, 4, }, + { 251, 308, 4, }, + { 251, 397, 4, }, + { 252, 309, 4, }, + { 252, 398, 4, }, + { 253, 310, 4, }, + { 253, 399, 4, }, + { 254, 311, 4, }, + { 254, 400, 4, }, + { 255, 312, 4, }, + { 255, 401, 4, }, + { 256, 313, 4, }, + { 256, 402, 4, }, + { 257, 314, 4, }, + { 257, 403, 4, }, + { 258, 315, 4, }, + { 258, 404, 4, }, + { 259, 316, 4, }, + { 259, 405, 4, }, + { 260, 317, 4, }, + { 260, 406, 4, }, + { 261, 318, 4, }, + { 261, 407, 4, }, + { 262, 319, 4, }, + { 262, 408, 4, }, + { 263, 320, 4, }, + { 263, 409, 4, }, + { 264, 321, 4, }, + { 264, 410, 4, }, + { 265, 322, 4, }, + { 265, 411, 4, }, + { 266, 323, 4, }, + { 266, 412, 4, }, + { 267, 324, 4, }, + { 267, 413, 4, }, + { 268, 325, 4, }, + { 268, 414, 4, }, + { 269, 326, 4, }, + { 269, 415, 4, }, + { 270, 333, 4, }, + { 270, 364, 4, }, + { 271, 334, 4, }, + { 271, 365, 4, }, + { 272, 335, 4, }, + { 272, 366, 4, }, + { 273, 336, 4, }, + { 273, 367, 4, }, + { 274, 337, 4, }, + { 274, 368, 4, }, + { 275, 338, 4, }, + { 275, 369, 4, }, + { 276, 339, 4, }, + { 276, 370, 4, }, + { 277, 340, 4, }, + { 277, 371, 4, }, + { 278, 341, 4, }, + { 278, 372, 4, }, + { 279, 342, 4, }, + { 279, 373, 4, }, + { 280, 343, 4, }, + { 280, 374, 4, }, + { 281, 344, 4, }, + { 281, 375, 4, }, + { 282, 345, 4, }, + { 282, 376, 4, }, + { 283, 346, 4, }, + { 283, 377, 4, }, + { 284, 347, 4, }, + { 284, 378, 4, }, + { 285, 348, 5, }, + { 285, 379, 5, }, + { 286, 349, 5, }, + { 286, 380, 5, }, + { 287, 350, 5, }, + { 287, 381, 5, }, + { 288, 351, 5, }, + { 288, 382, 5, }, + { 289, 352, 5, }, + { 289, 383, 5, }, + { 290, 353, 5, }, + { 290, 384, 5, }, + { 291, 354, 5, }, + { 291, 385, 5, }, + { 292, 355, 5, }, + { 292, 386, 5, }, + { 293, 356, 5, }, + { 293, 387, 5, }, + { 294, 357, 5, }, + { 294, 388, 5, }, + { 295, 358, 5, }, + { 295, 389, 5, }, + { 296, 359, 5, }, + { 296, 360, 5, }, + { 297, 330, 5, }, + { 297, 361, 5, }, + { 298, 331, 5, }, + { 298, 362, 5, }, + { 299, 332, 5, }, + { 299, 363, 5, }, + { 300, 330, 5, }, + { 300, 479, 5, }, + { 301, 331, 5, }, + { 301, 450, 5, }, + { 302, 332, 5, }, + { 302, 451, 5, }, + { 303, 333, 5, }, + { 303, 452, 5, }, + { 304, 334, 5, }, + { 304, 453, 5, }, + { 305, 335, 5, }, + { 305, 454, 5, }, + { 306, 336, 5, }, + { 306, 455, 5, }, + { 307, 337, 5, }, + { 307, 456, 5, }, + { 308, 338, 5, }, + { 308, 457, 5, }, + { 309, 339, 5, }, + { 309, 458, 5, }, + { 310, 340, 5, }, + { 310, 459, 5, }, + { 311, 341, 5, }, + { 311, 460, 5, }, + { 312, 342, 5, }, + { 312, 461, 5, }, + { 313, 343, 5, }, + { 313, 462, 5, }, + { 314, 344, 5, }, + { 314, 463, 5, }, + { 315, 345, 5, }, + { 315, 464, 5, }, + { 316, 346, 5, }, + { 316, 465, 5, }, + { 317, 347, 5, }, + { 317, 466, 5, }, + { 318, 348, 5, }, + { 318, 467, 5, }, + { 319, 349, 5, }, + { 319, 468, 5, }, + { 320, 350, 5, }, + { 320, 469, 5, }, + { 321, 351, 5, }, + { 321, 470, 5, }, + { 322, 352, 5, }, + { 322, 471, 5, }, + { 323, 353, 5, }, + { 323, 472, 5, }, + { 324, 354, 5, }, + { 324, 473, 5, }, + { 325, 355, 5, }, + { 325, 474, 5, }, + { 326, 356, 5, }, + { 326, 475, 5, }, + { 327, 357, 5, }, + { 327, 476, 5, }, + { 328, 358, 5, }, + { 328, 477, 5, }, + { 329, 359, 5, }, + { 329, 478, 5, }, + { 330, 421, 5, }, + { 331, 422, 5, }, + { 332, 423, 5, }, + { 333, 424, 5, }, + { 334, 425, 5, }, + { 335, 426, 5, }, + { 336, 427, 5, }, + { 337, 428, 5, }, + { 338, 429, 5, }, + { 339, 430, 5, }, + { 340, 431, 5, }, + { 341, 432, 5, }, + { 342, 433, 5, }, + { 343, 434, 5, }, + { 344, 435, 5, }, + { 345, 436, 5, }, + { 346, 437, 5, }, + { 347, 438, 5, }, + { 348, 439, 5, }, + { 349, 440, 5, }, + { 350, 441, 5, }, + { 351, 442, 5, }, + { 352, 443, 5, }, + { 353, 444, 5, }, + { 354, 445, 5, }, + { 355, 446, 5, }, + { 356, 447, 5, }, + { 357, 448, 5, }, + { 358, 449, 5, }, + { 359, 420, 5, }, + { 360, 390, 5, }, + { 360, 447, 5, }, + { 360, 480, 5, }, + { 361, 391, 5, }, + { 361, 448, 5, }, + { 361, 481, 5, }, + { 362, 392, 5, }, + { 362, 449, 5, }, + { 362, 482, 5, }, + { 363, 393, 5, }, + { 363, 420, 5, }, + { 363, 483, 5, }, + { 364, 394, 5, }, + { 364, 421, 5, }, + { 364, 484, 5, }, + { 365, 395, 5, }, + { 365, 422, 5, }, + { 365, 485, 5, }, + { 366, 396, 5, }, + { 366, 423, 5, }, + { 366, 486, 5, }, + { 367, 397, 5, }, + { 367, 424, 5, }, + { 367, 487, 5, }, + { 368, 398, 5, }, + { 368, 425, 5, }, + { 368, 488, 5, }, + { 369, 399, 5, }, + { 369, 426, 5, }, + { 369, 489, 5, }, + { 370, 400, 6, }, + { 370, 427, 6, }, + { 370, 490, 6, }, + { 371, 401, 6, }, + { 371, 428, 6, }, + { 371, 491, 6, }, + { 372, 402, 6, }, + { 372, 429, 6, }, + { 372, 492, 6, }, + { 373, 403, 6, }, + { 373, 430, 6, }, + { 373, 493, 6, }, + { 374, 404, 6, }, + { 374, 431, 6, }, + { 374, 494, 6, }, + { 375, 405, 6, }, + { 375, 432, 6, }, + { 375, 495, 6, }, + { 376, 406, 6, }, + { 376, 433, 6, }, + { 376, 496, 6, }, + { 377, 407, 6, }, + { 377, 434, 6, }, + { 377, 497, 6, }, + { 378, 408, 6, }, + { 378, 435, 6, }, + { 378, 498, 6, }, + { 379, 409, 6, }, + { 379, 436, 6, }, + { 379, 499, 6, }, + { 380, 410, 6, }, + { 380, 437, 6, }, + { 380, 500, 6, }, + { 381, 411, 6, }, + { 381, 438, 6, }, + { 381, 501, 6, }, + { 382, 412, 6, }, + { 382, 439, 6, }, + { 382, 502, 6, }, + { 383, 413, 6, }, + { 383, 440, 6, }, + { 383, 503, 6, }, + { 384, 414, 6, }, + { 384, 441, 6, }, + { 384, 504, 6, }, + { 385, 415, 6, }, + { 385, 442, 6, }, + { 385, 505, 6, }, + { 386, 416, 6, }, + { 386, 443, 6, }, + { 386, 506, 6, }, + { 387, 417, 6, }, + { 387, 444, 6, }, + { 387, 507, 6, }, + { 388, 418, 6, }, + { 388, 445, 6, }, + { 388, 508, 6, }, + { 389, 419, 6, }, + { 389, 446, 6, }, + { 389, 509, 6, }, + { 390, 453, 6, }, + { 390, 510, 6, }, + { 391, 454, 6, }, + { 391, 511, 6, }, + { 392, 455, 6, }, + { 392, 512, 6, }, + { 393, 456, 6, }, + { 393, 513, 6, }, + { 394, 457, 6, }, + { 394, 514, 6, }, + { 395, 458, 6, }, + { 395, 515, 6, }, + { 396, 459, 6, }, + { 396, 516, 6, }, + { 397, 460, 6, }, + { 397, 517, 6, }, + { 398, 461, 6, }, + { 398, 518, 6, }, + { 399, 462, 6, }, + { 399, 519, 6, }, + { 400, 463, 6, }, + { 400, 520, 6, }, + { 401, 464, 6, }, + { 401, 521, 6, }, + { 402, 465, 6, }, + { 402, 522, 6, }, + { 403, 466, 6, }, + { 403, 523, 6, }, + { 404, 467, 6, }, + { 404, 524, 6, }, + { 405, 468, 6, }, + { 405, 525, 6, }, + { 406, 469, 6, }, + { 406, 526, 6, }, + { 407, 470, 6, }, + { 407, 527, 6, }, + { 408, 471, 6, }, + { 408, 528, 6, }, + { 409, 472, 6, }, + { 409, 529, 6, }, + { 410, 473, 6, }, + { 410, 530, 6, }, + { 411, 474, 6, }, + { 411, 531, 6, }, + { 412, 475, 6, }, + { 412, 532, 6, }, + { 413, 476, 6, }, + { 413, 533, 6, }, + { 414, 477, 6, }, + { 414, 534, 6, }, + { 415, 478, 6, }, + { 415, 535, 6, }, + { 416, 479, 6, }, + { 416, 536, 6, }, + { 417, 450, 6, }, + { 417, 537, 6, }, + { 418, 451, 6, }, + { 418, 538, 6, }, + { 419, 452, 6, }, + { 419, 539, 6, }, + { 420, 480, 6, }, + { 421, 481, 6, }, + { 422, 482, 6, }, + { 423, 483, 6, }, + { 424, 484, 6, }, + { 425, 485, 6, }, + { 426, 486, 6, }, + { 427, 487, 6, }, + { 428, 488, 6, }, + { 429, 489, 6, }, + { 430, 490, 6, }, + { 431, 491, 6, }, + { 432, 492, 6, }, + { 433, 493, 6, }, + { 434, 494, 6, }, + { 435, 495, 6, }, + { 436, 496, 6, }, + { 437, 497, 6, }, + { 438, 498, 6, }, + { 439, 499, 6, }, + { 440, 500, 6, }, + { 441, 501, 6, }, + { 442, 502, 6, }, + { 443, 503, 6, }, + { 444, 504, 6, }, + { 445, 505, 6, }, + { 446, 506, 6, }, + { 447, 507, 6, }, + { 448, 508, 6, }, + { 449, 509, 6, }, + { 450, 510, 7, }, + { 451, 511, 7, }, + { 452, 512, 7, }, + { 453, 513, 7, }, + { 454, 514, 7, }, + { 455, 515, 7, }, + { 456, 516, 7, }, + { 457, 517, 7, }, + { 458, 518, 7, }, + { 459, 519, 7, }, + { 460, 520, 7, }, + { 461, 521, 7, }, + { 462, 522, 7, }, + { 463, 523, 7, }, + { 464, 524, 7, }, + { 465, 525, 7, }, + { 466, 526, 7, }, + { 467, 527, 7, }, + { 468, 528, 7, }, + { 469, 529, 7, }, + { 470, 530, 7, }, + { 471, 531, 7, }, + { 472, 532, 7, }, + { 473, 533, 7, }, + { 474, 534, 7, }, + { 475, 535, 7, }, + { 476, 536, 7, }, + { 477, 537, 7, }, + { 478, 538, 7, }, + { 479, 539, 7, }, + { 480, 513, 7, }, + { 480, 597, 7, }, + { 481, 514, 7, }, + { 481, 598, 7, }, + { 482, 515, 7, }, + { 482, 599, 7, }, + { 483, 516, 7, }, + { 483, 570, 7, }, + { 484, 517, 7, }, + { 484, 571, 7, }, + { 485, 518, 7, }, + { 485, 572, 7, }, + { 486, 519, 7, }, + { 486, 573, 7, }, + { 487, 520, 7, }, + { 487, 574, 7, }, + { 488, 521, 7, }, + { 488, 575, 7, }, + { 489, 522, 7, }, + { 489, 576, 7, }, + { 490, 523, 7, }, + { 490, 577, 7, }, + { 491, 524, 7, }, + { 491, 578, 7, }, + { 492, 525, 7, }, + { 492, 579, 7, }, + { 493, 526, 7, }, + { 493, 580, 7, }, + { 494, 527, 7, }, + { 494, 581, 7, }, + { 495, 528, 7, }, + { 495, 582, 7, }, + { 496, 529, 7, }, + { 496, 583, 7, }, + { 497, 530, 7, }, + { 497, 584, 7, }, + { 498, 531, 7, }, + { 498, 585, 7, }, + { 499, 532, 7, }, + { 499, 586, 7, }, + { 500, 533, 7, }, + { 500, 587, 7, }, + { 501, 534, 7, }, + { 501, 588, 7, }, + { 502, 535, 7, }, + { 502, 589, 7, }, + { 503, 536, 7, }, + { 503, 590, 7, }, + { 504, 537, 7, }, + { 504, 591, 7, }, + { 505, 538, 7, }, + { 505, 592, 7, }, + { 506, 539, 7, }, + { 506, 593, 7, }, + { 507, 510, 7, }, + { 507, 594, 7, }, + { 508, 511, 7, }, + { 508, 595, 7, }, + { 509, 512, 7, }, + { 509, 596, 7, }, + { 510, 542, 7, }, + { 511, 543, 7, }, + { 512, 544, 7, }, + { 513, 545, 7, }, + { 514, 546, 7, }, + { 515, 547, 7, }, + { 516, 548, 7, }, + { 517, 549, 7, }, + { 518, 550, 7, }, + { 519, 551, 7, }, + { 520, 552, 7, }, + { 521, 553, 7, }, + { 522, 554, 7, }, + { 523, 555, 7, }, + { 524, 556, 7, }, + { 525, 557, 7, }, + { 526, 558, 7, }, + { 527, 559, 7, }, + { 528, 560, 7, }, + { 529, 561, 7, }, + { 530, 562, 7, }, + { 531, 563, 7, }, + { 532, 564, 7, }, + { 533, 565, 7, }, + { 534, 566, 7, }, + { 535, 567, 7, }, + { 536, 568, 7, }, + { 537, 569, 7, }, + { 538, 540, 7, }, + { 539, 541, 7, }, + { 540, 570, 7, }, + { 541, 571, 7, }, + { 542, 572, 7, }, + { 543, 573, 7, }, + { 544, 574, 7, }, + { 545, 575, 7, }, + { 546, 576, 7, }, + { 547, 577, 7, }, + { 548, 578, 7, }, + { 549, 579, 7, }, + { 550, 580, 7, }, + { 551, 581, 7, }, + { 552, 582, 7, }, + { 553, 583, 7, }, + { 554, 584, 7, }, + { 555, 585, 7, }, + { 556, 586, 7, }, + { 557, 587, 7, }, + { 558, 588, 7, }, + { 559, 589, 7, }, + { 560, 590, 7, }, + { 561, 591, 7, }, + { 562, 592, 7, }, + { 563, 593, 7, }, + { 564, 594, 7, }, + { 565, 595, 7, }, + { 566, 596, 7, }, + { 567, 597, 7, }, + { 568, 598, 7, }, + { 569, 599, 7, }, +}; + + +static const char *hyperball_defaults[] = +{ + "*observer-z: 3", + "*delay: 20000", + "*xy: 3", + "*xz: 5", + "*yw: 10", + "*yz: 0", + "*xw: 0", + "*zw: 0", + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*color00:#FF66BE", + "*color10:#FFA300", + "*color20:#BEDC00", + "*color30:#12FB00", + "*color40:#00F9BE", + "*color50:#12D5FF", + "*color60:#BE9AFF", + "*color70:#FF5FFF", + "*color01:#FF5BAA", + "*color11:#F09200", + "*color21:#AAC500", + "*color31:#10E100", + "*color41:#00DFAA", + "*color51:#10BFFF", + "*color61:#AA8AFF", + "*color71:#F055FF", + "*color02:#EE529A", + "*color12:#D98400", + "*color22:#9AB200", + "*color32:#0ECB00", + "*color42:#00C99A", + "*color52:#0EADE7", + "*color62:#9A7DFF", + "*color72:#D94DE7", + "*color03:#DA4B8C", + "*color13:#C67900", + "*color23:#8CA300", + "*color33:#0DBA00", + "*color43:#00B88C", + "*color53:#0D9ED3", + "*color63:#8C72EA", + "*color73:#C646D3", + "*color04:#C84581", + "*color14:#B66F00", + "*color24:#819600", + "*color34:#0CAB00", + "*color44:#00A981", + "*color54:#0C91C2", + "*color64:#8169D7", + "*color74:#B641C2", + "*color05:#B94078", + "*color15:#A96700", + "*color25:#788B00", + "*color35:#0B9E00", + "*color45:#009D78", + "*color55:#0B86B3", + "*color65:#7861C7", + "*color75:#A93CB3", + "*color06:#AC3C6F", + "*color16:#9D6000", + "*color26:#6F8100", + "*color36:#0A9300", + "*color46:#00926F", + "*color56:#0A7DA7", + "*color66:#6F5AB9", + "*color76:#9D38A7", + "*color07:#A13868", + "*color17:#935900", + "*color27:#687900", + "*color37:#0A8A00", + "*color47:#008868", + "*color57:#0A759C", + "*color67:#6854AD", + "*color77:#93349C", + 0, +}; + +static XrmOptionDescRec hyperball_options [] = +{ + { "-observer-z", ".observer-z", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-xw", ".xw", XrmoptionSepArg, 0 }, + { "-xy", ".xy", XrmoptionSepArg, 0 }, + { "-xz", ".xz", XrmoptionSepArg, 0 }, + { "-yw", ".yw", XrmoptionSepArg, 0 }, + { "-yz", ".yz", XrmoptionSepArg, 0 }, + { "-zw", ".zw", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 }, +}; + +XSCREENSAVER_MODULE ("HyperBall", hyperball) diff --git a/non-wgl/hyperball.vcproj b/non-wgl/hyperball.vcproj new file mode 100644 index 0000000..be7f348 --- /dev/null +++ b/non-wgl/hyperball.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/hypercube.c b/non-wgl/hypercube.c new file mode 100644 index 0000000..89c720f --- /dev/null +++ b/non-wgl/hypercube.c @@ -0,0 +1,676 @@ +/* xscreensaver, Copyright (c) 1992-2008 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 code derived from TI Explorer Lisp code by Joe Keane, Fritz Mueller, + * and Jamie Zawinski. + */ + +#include "screenhack.h" +#include + +#define __STDC__ + +float observer_z_ = 3.0; +int delay_ = 10000; +float xy_ = 3; +float xz_ = 5; +float yw_ = 10; +float yz_ = 0; +float xw_ = 0; +float zw_ = 0; +char *background = "black"; +char *foreground = "white"; +char *color0 = "magenta"; +char *color1 = "yellow"; +char *color2 = "#FF9300"; +char *color3 = "#FF0093"; +char *color4 = "green"; +char *color5 = "#8080FF"; +char *color6 = "#00D0FF"; +char *color7 = "#00FFD0"; + +static argtype vars[] = +{ + {&observer_z_, "observer_z", NULL, "3.0", t_Float}, + {&delay_, "delay", NULL, "10000", t_Int}, + {&xy_, "xy", NULL, "3", t_Float}, + {&xz_, "xz", NULL, "5", t_Float}, + {&yw_, "yw", NULL, "10", t_Float}, + {&yz_, "yz", NULL, "0", t_Float}, + {&xw_, "xw", NULL, "0", t_Float}, + {&zw_, "zw", NULL, "0", t_Float}, + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&color0, "color0", NULL, "magenta", t_String}, + {&color1, "color1", NULL, "yellow", t_String}, + {&color2, "color2", NULL, "#FF9300", t_String}, + {&color3, "color3", NULL, "#FF0093", t_String}, + {&color4, "color4", NULL, "green", t_String}, + {&color5, "color5", NULL, "#8080FF", t_String}, + {&color6, "color6", NULL, "#00D0FF", t_String}, + {&color7, "color7", NULL, "#00FFD0", t_String}, +}; + +#define POINT_COUNT 16 +#define LINE_COUNT 32 + +#define ANGLE_SCALE 0.001 + +struct line_info +{ + char li_ip; + char li_iq; + char li_color; + char li_pad; +}; + +struct point_state +{ + short old_x, old_y; + short new_x, new_y; +}; + +struct hyper_state +{ + char hs_stop; + char hs_icon; + char hs_resize; + char hs_redraw; + Display *hs_display; + Window hs_window; + float hs_two_observer_z; + float hs_offset_x; + float hs_offset_y; + float hs_unit_scale; + int hs_delay; + GC hs_color_gcs[8]; + GC black_gc; +#if 0 + double hs_angle_xy; + double hs_angle_xz; + double hs_angle_yz; + double hs_angle_xw; + double hs_angle_yw; + double hs_angle_zw; +#endif + double hs_cos_xy, hs_sin_xy; + double hs_cos_xz, hs_sin_xz; + double hs_cos_yz, hs_sin_yz; + double hs_cos_xw, hs_sin_xw; + double hs_cos_yw, hs_sin_yw; + double hs_cos_zw, hs_sin_zw; + double hs_ref_ax, hs_ref_ay, hs_ref_az, hs_ref_aw; + double hs_ref_bx, hs_ref_by, hs_ref_bz, hs_ref_bw; + double hs_ref_cx, hs_ref_cy, hs_ref_cz, hs_ref_cw; + double hs_ref_dx, hs_ref_dy, hs_ref_dz, hs_ref_dw; + struct point_state hs_points[POINT_COUNT]; + int roted; +}; + +static const struct line_info line_table[LINE_COUNT]; + +static const char *hypercube_defaults[] = +{ + "*observer-z: 3.0", + "*delay: 10000", + "*xy: 3", + "*xz: 5", + "*yw: 10", + "*yz: 0", + "*xw: 0", + "*zw: 0", + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*color0: magenta", + "*color3: #FF0093", + "*color1: yellow", + "*color2: #FF9300", + "*color4: green", + "*color7: #00FFD0", + "*color5: #8080FF", + "*color6: #00D0FF", + + 0 +}; + +static XrmOptionDescRec hypercube_options [] = +{ + { "-color0", ".color0", XrmoptionSepArg, 0 }, + { "-color1", ".color1", XrmoptionSepArg, 0 }, + { "-color2", ".color2", XrmoptionSepArg, 0 }, + { "-color3", ".color3", XrmoptionSepArg, 0 }, + { "-color4", ".color4", XrmoptionSepArg, 0 }, + { "-color5", ".color5", XrmoptionSepArg, 0 }, + { "-color6", ".color6", XrmoptionSepArg, 0 }, + { "-color7", ".color7", XrmoptionSepArg, 0 }, + + { "-xw", ".xw", XrmoptionSepArg, 0 }, + { "-xy", ".xy", XrmoptionSepArg, 0 }, + { "-xz", ".xz", XrmoptionSepArg, 0 }, + { "-yw", ".yw", XrmoptionSepArg, 0 }, + { "-yz", ".yz", XrmoptionSepArg, 0 }, + { "-zw", ".zw", XrmoptionSepArg, 0 }, + + { "-observer-z", ".observer-z", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +static void set_sizes (struct hyper_state *hs, int width, int height); + +static void * +hypercube_init (Display *dpy, Window win) +{ + XGCValues gcv; + Colormap cmap; + unsigned long bg_pixel; + int delay; + float observer_z; + + struct hyper_state *hs = (struct hyper_state *) calloc (1, sizeof(*hs)); + hs->hs_display = dpy; + hs->hs_window = win; + + //observer_z = get_float_resource (dpy, "observer-z", "Float"); + observer_z = observer_z_; + if (observer_z < 1.125) + observer_z = 1.125; + /* hs->hs_observer_z = observer_z; */ + hs->hs_two_observer_z = 2.0 * observer_z; + + { + XWindowAttributes wa; + XGetWindowAttributes (dpy, win, &wa); + cmap = wa.colormap; + set_sizes (hs, wa.width, wa.height); + } + + //delay = get_integer_resource (dpy, "delay", "Integer"); + delay = delay_; + hs->hs_delay = delay; + + //bg_pixel = get_pixel_resource (dpy, cmap, "background", "Background"); + bg_pixel = load_color(dpy, cmap, background); + + if (mono_p) + { + GC black_gc; + unsigned long fg_pixel; + GC white_gc; + + gcv.function = GXcopy; + gcv.foreground = bg_pixel; + black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + //fg_pixel = get_pixel_resource (dpy, cmap, "foreground", "Foreground"); + fg_pixel = load_color(dpy, cmap, foreground); + gcv.foreground = fg_pixel ^ bg_pixel; + white_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[0] = black_gc; + hs->hs_color_gcs[1] = white_gc; + } + else + { + //int col; + + gcv.function = GXcopy; + + //gcv.foreground = get_pixel_resource (dpy, cmap, + // "background", "Background"); + gcv.foreground = load_color(dpy, cmap, background); + hs->black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + +#if 1 + { + unsigned long fg_pixel; + GC color_gc; + + fg_pixel = load_color(dpy, cmap, color0); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[0] = color_gc; + + fg_pixel = load_color(dpy, cmap, color1); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[1] = color_gc; + + fg_pixel = load_color(dpy, cmap, color2); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[2] = color_gc; + + fg_pixel = load_color(dpy, cmap, color3); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[3] = color_gc; + + fg_pixel = load_color(dpy, cmap, color4); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[4] = color_gc; + + fg_pixel = load_color(dpy, cmap, color5); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[5] = color_gc; + + fg_pixel = load_color(dpy, cmap, color6); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[6] = color_gc; + + fg_pixel = load_color(dpy, cmap, color7); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[7] = color_gc; + } +#else + for (col = 0; col < 8; col++) + { + char buffer[16]; + unsigned long fg_pixel; + GC color_gc; + + sprintf (buffer, "color%d", col); + fg_pixel = get_pixel_resource (dpy, cmap, buffer, "Foreground"); + gcv.foreground = fg_pixel; + color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); + hs->hs_color_gcs[col] = color_gc; + } +#endif + } + + hs->hs_ref_ax = 1.0, hs->hs_ref_ay = 0.0, hs->hs_ref_az = 0.0, hs->hs_ref_aw = 0.0; + hs->hs_ref_bx = 0.0, hs->hs_ref_by = 1.0, hs->hs_ref_bz = 0.0, hs->hs_ref_bw = 0.0; + hs->hs_ref_cx = 0.0, hs->hs_ref_cy = 0.0, hs->hs_ref_cz = 1.0, hs->hs_ref_cw = 0.0; + hs->hs_ref_dx = 0.0, hs->hs_ref_dy = 0.0, hs->hs_ref_dz = 0.0, hs->hs_ref_dw = 1.0; + + { + double xy; + double xz; + double yz; + double xw; + double yw; + double zw; + double cos_xy, sin_xy; + double cos_xz, sin_xz; + double cos_yz, sin_yz; + double cos_xw, sin_xw; + double cos_yw, sin_yw; + double cos_zw, sin_zw; + +#if 1 + xy = xy_ * ANGLE_SCALE; + xz = xz_ * ANGLE_SCALE; + yz = yz_ * ANGLE_SCALE; + xw = xw_ * ANGLE_SCALE; + yw = yw_ * ANGLE_SCALE; + zw = zw_ * ANGLE_SCALE; +#else + xy = get_float_resource (dpy, "xy", "Float") * ANGLE_SCALE; + xz = get_float_resource (dpy, "xz", "Float") * ANGLE_SCALE; + yz = get_float_resource (dpy, "yz", "Float") * ANGLE_SCALE; + xw = get_float_resource (dpy, "xw", "Float") * ANGLE_SCALE; + yw = get_float_resource (dpy, "yw", "Float") * ANGLE_SCALE; + zw = get_float_resource (dpy, "zw", "Float") * ANGLE_SCALE; +#endif + + cos_xy = cos (xy), sin_xy = sin (xy); + hs->hs_cos_xy = cos_xy, hs->hs_sin_xy = sin_xy; + cos_xz = cos (xz), sin_xz = sin (xz); + hs->hs_cos_xz = cos_xz, hs->hs_sin_xz = sin_xz; + cos_yz = cos (yz), sin_yz = sin (yz); + hs->hs_cos_yz = cos_yz, hs->hs_sin_yz = sin_yz; + cos_xw = cos (xw), sin_xw = sin (xw); + hs->hs_cos_xw = cos_xw, hs->hs_sin_xw = sin_xw; + cos_yw = cos (yw), sin_yw = sin (yw); + hs->hs_cos_yw = cos_yw, hs->hs_sin_yw = sin_yw; + cos_zw = cos (zw), sin_zw = sin (zw); + hs->hs_cos_zw = cos_zw, hs->hs_sin_zw = sin_zw; + } + + return hs; +} + + +static unsigned long +hypercube_draw (Display *dpy, Window window, void *closure) +{ + struct hyper_state *hs = (struct hyper_state *) closure; + int this_delay = hs->hs_delay; + +#ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + XClearWindow (dpy, window); +#endif + + { + int icon; + int resize; + char moved[POINT_COUNT]; + int redraw; + int stop; + int delay; + + icon = hs->hs_icon; + resize = hs->hs_resize; + if (icon || !(hs->roted | resize)) + goto skip1; + + { + float observer_z; + float unit_scale; + float offset_x; + float offset_y; + double az, bz, cz, dz; + double sum_z; + double ax, bx, cx, dx; + double sum_x; + double ay, by, cy, dy; + double sum_y; + struct point_state *ps; + int old_x; + int old_y; + double mul; + double xf; + double yf; + int new_x; + int new_y; + int mov; + + +#define compute(as,bs,cs,ds,i) \ + az = hs->hs_ref_az; bz = hs->hs_ref_bz; cz = hs->hs_ref_cz; dz = hs->hs_ref_dz; \ + ax = hs->hs_ref_ax; bx = hs->hs_ref_bx; cx = hs->hs_ref_cx; dx = hs->hs_ref_dx; \ + ay = hs->hs_ref_ay; by = hs->hs_ref_by; cy = hs->hs_ref_cy; dy = hs->hs_ref_dy; \ + sum_z = as az bs bz cs cz ds dz; \ + observer_z = hs->hs_two_observer_z; \ + unit_scale = hs->hs_unit_scale; \ + sum_x = as ax bs bx cs cx ds dx; \ + sum_y = as ay bs by cs cy ds dy; \ + ps = &hs->hs_points[i]; \ + mul = unit_scale / (observer_z - sum_z); \ + offset_x = hs->hs_offset_x; \ + offset_y = hs->hs_offset_y; \ + old_x = ps->new_x; \ + old_y = ps->new_y; \ + xf = sum_x * mul + offset_x; \ + yf = sum_y * mul + offset_y; \ + new_x = (int)rint(xf); \ + new_y = (int)rint(yf); \ + ps->old_x = old_x; \ + ps->old_y = old_y; \ + ps->new_x = new_x; \ + ps->new_y = new_y; \ + mov = old_x != new_x || old_y != new_y; \ + moved[i] = mov; + + compute (-, -, -, -, 0); + compute (-, -, -, +, 1); + compute (-, -, +, -, 2); + compute (-, -, +, +, 3); + compute (-, +, -, -, 4); + compute (-, +, -, +, 5); + compute (-, +, +, -, 6); + compute (-, +, +, +, 7); + compute (+, -, -, -, 8); + compute (+, -, -, +, 9); + compute (+, -, +, -, 10); + compute (+, -, +, +, 11); + compute (+, +, -, -, 12); + compute (+, +, -, +, 13); + compute (+, +, +, -, 14); + compute (+, +, +, +, 15); + } + + skip1: + icon = hs->hs_icon; + redraw = hs->hs_redraw; + if (icon || !(hs->roted | redraw)) + goto skip2; + + { + int lc; + const struct line_info *lip; + int mono; + Window win; + + lc = LINE_COUNT; + lip = &line_table[0]; + mono = mono_p; + win = hs->hs_window; + + while (--lc >= 0) + { + int ip; + int iq; + int col; + struct point_state *sp; + struct point_state *sq; + int mov_p; + int mov_q; + GC erase_gc; + GC draw_gc; + int p_x; + int p_y; + int q_x; + int q_y; + + ip = lip->li_ip; + iq = lip->li_iq; + col = lip->li_color; + lip++; + mov_p = moved[ip]; + mov_q = moved[iq]; + if (!(redraw | mov_p | mov_q)) + continue; + + sp = &hs->hs_points[ip]; + sq = &hs->hs_points[iq]; + + if (mono) + { + erase_gc = hs->hs_color_gcs[0]; + draw_gc = hs->hs_color_gcs[1]; + } + else + { + erase_gc = hs->black_gc; + draw_gc = hs->hs_color_gcs[col]; + } + + if (!redraw) + { + p_x = sp->old_x; + p_y = sp->old_y; + q_x = sq->old_x; + q_y = sq->old_y; + XDrawLine (dpy, win, erase_gc, p_x, p_y, q_x, q_y); + } + + p_x = sp->new_x; + p_y = sp->new_y; + q_x = sq->new_x; + q_y = sq->new_y; + XDrawLine (dpy, win, draw_gc, p_x, p_y, q_x, q_y); + } + } + + skip2: + stop = hs->hs_stop; + hs->roted = 0; + if (stop) + goto skip3; + + hs->roted = 1; + + { + double cos_a; + double sin_a; + double old_u; + double old_v; + double new_u; + double new_v; + + /* If you get error messages about the following forms, and you think you're + using an ANSI C conforming compiler, then you're mistaken. Possibly you're + mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa. + Regardless, your system is broken; it's not a bug in this program. + */ +#if defined(__STDC__) || defined(__ANSI_CPP__) + +#define rotate(name,dim0,dim1) \ + old_u = hs->hs_ref_##name##dim0; \ + old_v = hs->hs_ref_##name##dim1; \ + new_u = old_u * cos_a + old_v * sin_a; \ + new_v = old_v * cos_a - old_u * sin_a; \ + hs->hs_ref_##name##dim0 = new_u; \ + hs->hs_ref_##name##dim1 = new_v; + +#define rotates(dim0,dim1) \ + if (hs->hs_sin_##dim0##dim1 != 0) { \ + cos_a = hs->hs_cos_##dim0##dim1; \ + sin_a = hs->hs_sin_##dim0##dim1; \ + rotate(a,dim0,dim1); \ + rotate(b,dim0,dim1); \ + rotate(c,dim0,dim1); \ + rotate(d,dim0,dim1); \ + } + +#else /* !__STDC__, courtesy of Andreas Luik */ + +#define rotate(name,dim0,dim1) \ + old_u = hs->hs_ref_/**/name/**/dim0; \ + old_v = hs->hs_ref_/**/name/**/dim1; \ + new_u = old_u * cos_a + old_v * sin_a; \ + new_v = old_v * cos_a - old_u * sin_a; \ + hs->hs_ref_/**/name/**/dim0 = new_u; \ + hs->hs_ref_/**/name/**/dim1 = new_v; + +#define rotates(dim0,dim1) \ + if (hs->hs_sin_/**/dim0/**/dim1 != 0) { \ + cos_a = hs->hs_cos_/**/dim0/**/dim1; \ + sin_a = hs->hs_sin_/**/dim0/**/dim1; \ + rotate(a,dim0,dim1); \ + rotate(b,dim0,dim1); \ + rotate(c,dim0,dim1); \ + rotate(d,dim0,dim1); \ + } + +#endif /* !__STDC__ */ + + rotates (x,y); + rotates (x,z); + rotates (y,z); + rotates (x,w); + rotates (y,w); + rotates (z,w); + } + + skip3: + /* stop = hs->hs_stop; */ + delay = hs->hs_delay; + if (stop && this_delay < 10000) + this_delay = 10000; + } + return this_delay; +} + +#if 0 + static Bool + hypercube_event (Display *dpy, Window window, void *closure, XEvent *e) + { + struct hyper_state *hs = (struct hyper_state *) closure; + if (e->type == ButtonPress && e->xbutton.button == 2) + { + hs->hs_stop = !hs->hs_stop; + return True; + } + return False; + } +#endif + +static void +hypercube_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct hyper_state *hs = (struct hyper_state *) closure; + set_sizes (hs, w, h); + XClearWindow (dpy, window); +} + + +static void +set_sizes (struct hyper_state *hs, int width, int height) +{ + double observer_z; + int min_dim; + double var; + double offset_x; + double offset_y; + double unit_scale; + + observer_z = 0.5 * hs->hs_two_observer_z; + min_dim = width < height ? width : height; + var = sqrt(observer_z * observer_z - 1.0); + offset_x = 0.5 * (double)(width - 1); + offset_y = 0.5 * (double)(height - 1); + unit_scale = 0.4 * min_dim * var; + hs->hs_offset_x = (float)offset_x; + hs->hs_offset_y = (float)offset_y; + hs->hs_unit_scale = (float)unit_scale; +} + + +/* data */ + +static const struct line_info line_table[LINE_COUNT] = +{ + { 0, 1, 0, }, + { 0, 2, 0, }, + { 1, 3, 0, }, + { 2, 3, 0, }, + { 4, 5, 1, }, + { 4, 6, 1, }, + { 5, 7, 1, }, + { 6, 7, 1, }, + { 0, 4, 4, }, + { 0, 8, 4, }, + { 4, 12, 4, }, + { 8, 12, 4, }, + { 1, 5, 5, }, + { 1, 9, 5, }, + { 5, 13, 5, }, + { 9, 13, 5, }, + { 2, 6, 6, }, + { 2, 10, 6, }, + { 6, 14, 6, }, + { 10, 14, 6, }, + { 3, 7, 7, }, + { 3, 11, 7, }, + { 7, 15, 7, }, + { 11, 15, 7, }, + { 8, 9, 2, }, + { 8, 10, 2, }, + { 9, 11, 2, }, + { 10, 11, 2, }, + { 12, 13, 3, }, + { 12, 14, 3, }, + { 13, 15, 3, }, + { 14, 15, 3, }, +}; + +static void +hypercube_free (Display *dpy, Window window, void *closure) +{ +} + +XSCREENSAVER_MODULE ("HyperCube", hypercube) diff --git a/non-wgl/hypercube.vcproj b/non-wgl/hypercube.vcproj new file mode 100644 index 0000000..bf2befc --- /dev/null +++ b/non-wgl/hypercube.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/imsmap.c b/non-wgl/imsmap.c new file mode 100644 index 0000000..ffd1219 --- /dev/null +++ b/non-wgl/imsmap.c @@ -0,0 +1,450 @@ +/* imsmap, Copyright (c) 1992-2013 Juergen Nickelsen and Jamie Zawinski. + * Derived from code by Markus Schirmer, TU Berlin. + * + * 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. + * + * Revision History: + * 24-aug-92: jwz: hacked. + * 17-May-97: jwz: hacked more. + */ + +#include "screenhack.h" +#include +#include + +char *background = "#000066"; +char *foreground = "#FF00FF"; +char *mode = "random"; +int ncolors = 50; +int iterations = 7; +int delay = 5; +int delay2 = 20000; + +static argtype vars[] = +{ + {&background, "background", NULL, "#000066", t_String}, + {&foreground, "foreground", NULL, "#FF00FF", t_String}, + {&mode, "mode", NULL, "random", t_String}, + {&ncolors, "ncolors", NULL, "50", t_Int}, + {&iterations, "iterations", NULL, "7", t_Int}, + {&delay, "delay", NULL, "5", t_Int}, + {&delay2, "delay2", NULL, "20000", t_Int}, +}; + +#define NSTEPS 7 +#define COUNT (1 << NSTEPS) +#define CELL(c, r) st->cell[((unsigned int)(c)) + ((unsigned int) (r)) * st->xmax] + +#if defined(sun) && !__STDC__ /* sun cc doesn't know "signed char" */ +#define signed /**/ +#endif + +struct state { + Display *dpy; + Window window; + Colormap cmap; + int ncolors; + XColor *colors; + Bool extra_krinkly_p; + + int delay, delay2; + signed char *cell; + int xmax, ymax; + int iteration, iterations; + + int cx, xstep, ystep, xnextStep, ynextStep; + + unsigned int last_pixel, last_valid; + int flip_x; + int flip_xy; + + GC gc, gc2; + XWindowAttributes xgwa; + + struct timeval then; +}; + + +#define HEIGHT_TO_PIXEL(height) \ + ((height) < 0 \ + ? (st->extra_krinkly_p \ + ? st->ncolors - 1 - ((-(height)) % st->ncolors) \ + : 0) \ + : ((height) >= st->ncolors \ + ? (st->extra_krinkly_p \ + ? (height) % st->ncolors \ + : st->ncolors-1) \ + : (height))) + + +static unsigned int +set (struct state *st, + unsigned int l, + unsigned int c, + unsigned int size, + int height) +{ + int rang = 1 << (NSTEPS - size); + height = height + (random () % rang) - rang / 2; + height = HEIGHT_TO_PIXEL(height); + CELL (l, c) = height; + return st->colors[height].pixel; +} + + +static void +floyd_steinberg (struct state *st) +{ + int x, y, err; + + /* Instead of repeatedly calling XPutPixel(), we make an Image and then + send its bits over all at once. This consumes much less network + bandwidth. The image we create is Wx1 intead of WxH, so that we + don't use enormous amounts of memory. + */ + XImage *image = + XCreateImage (st->dpy, st->xgwa.visual, + 1, XYBitmap, 0, /* depth, format, offset */ + (char *) calloc ((st->xmax + 8) / 8, 1), /* data */ + st->xmax, 1, 8, 0); /* w, h, pad, bpl */ + + XSetForeground (st->dpy, st->gc, st->colors[0].pixel); + XSetBackground (st->dpy, st->gc, st->colors[1].pixel); + + for (y = 0; y < st->ymax - 1; y++) + { + for (x = 0; x < st->xmax - 1; x++) + { + if (CELL(x, y) < 0) + { + err = CELL (x, y); + XPutPixel (image, x, 0, 1); + } + else + { + err = CELL (x, y) - 1; + XPutPixel (image, x, 0, 0); + } + /* distribute error */ + CELL (x, y+1) += (int) (((float) err) * 3.0/8.0); + CELL (x+1, y) += (int) (((float) err) * 3.0/8.0); + CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0); + } + XPutImage (st->dpy, st->window, st->gc, image, 0, 0, 0, y, st->xmax, 1); + } + XDestroyImage (image); +} + + +static void +draw (struct state *st, + int x, int y, unsigned long pixel, int grid_size) +{ + if (st->flip_x) + x = st->xmax - x; + + if (st->flip_xy) + { + int swap = x; + x = y; + y = swap; + } + + if (! (st->last_valid && pixel == st->last_pixel)) + XSetForeground (st->dpy, st->gc, pixel); + st->last_valid = 1, st->last_pixel = pixel; + if (grid_size == 1) + XDrawPoint (st->dpy, st->window, st->gc, x, y); + else + XFillRectangle (st->dpy, st->window, st->gc, x, y, grid_size, grid_size); +} + + +static void +init_map (struct state *st) +{ + XGCValues gcv; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->cmap = st->xgwa.colormap; + + st->flip_x = (random() % 2); + st->flip_xy = (random() % 2); + + if (mono_p) + st->flip_xy = 0; + else if (st->colors) + free_colors (st->xgwa.screen, st->cmap, st->colors, st->ncolors); + st->colors = 0; + +#if 1 + st->ncolors = ncolors; + st->delay = delay; + st->delay2 = delay2; + st->iterations = iterations; +#else + st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer"); + st->iterations = get_integer_resource (st->dpy, "iterations", "Integer"); +#endif + if (st->iterations < 0) st->iterations = 0; + else if (st->iterations > 7) st->iterations = 7; + + if (st->ncolors <= 2) st->ncolors = 0; + if (st->ncolors == 0) mono_p = True; + if (st->ncolors > 255) st->ncolors = 255; /* too many look bad */ + + if (!st->gc) st->gc = XCreateGC (st->dpy, st->window, 0, &gcv); + if (!st->gc2) st->gc2 = XCreateGC (st->dpy, st->window, 0, &gcv); + + if (mono_p) + st->extra_krinkly_p = !(random() % 15); + else + st->extra_krinkly_p = !(random() % 5); + + if (!mono_p) + { + st->colors = (XColor *) malloc (st->ncolors * sizeof(*st->colors)); + + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, False); + if (st->ncolors <= 2) + mono_p = 1; + } + + if (mono_p) + { + int i; +#if 1 + unsigned long fg_pixel = load_color(st->dpy, st->xgwa.colormap, foreground); + unsigned long bg_pixel = load_color(st->dpy, st->xgwa.colormap, background); +#else + unsigned long fg_pixel = + get_pixel_resource (st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + unsigned long bg_pixel = + get_pixel_resource (st->dpy, st->xgwa.colormap, + "background", "Background"); +#endif + if (!st->colors) + { + st->ncolors = 50; + st->colors = (XColor *) calloc (st->ncolors, sizeof(*st->colors)); + } + st->colors[0].pixel = fg_pixel; + for (i = 1; i < st->ncolors; i++) + st->colors[i].pixel = bg_pixel; + } + + XSetForeground (st->dpy, st->gc, st->colors[1].pixel); + XFillRectangle (st->dpy, st->window, st->gc, 0, 0, + st->xgwa.width, st->xgwa.height); + + if (st->flip_xy) + { + st->xmax = st->xgwa.height; + st->ymax = st->xgwa.width; + } + else + { + st->xmax = st->xgwa.width; + st->ymax = st->xgwa.height; + } + + if (st->cell) free (st->cell); + st->cell = (signed char *) calloc (st->xmax * st->ymax, 1); + + CELL (0, 0) = 0; + st->xstep = COUNT; + st->ystep = COUNT; + + st->iteration = 0; + st->cx = 0; +} + + +static void * +imsmap_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + init_map (st); + return st; +} + + +static unsigned long +imsmap_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int this_delay = st->delay2; + int i; + + /* do this many lines at a time without pausing */ + int col_chunk = st->iteration * 2 + 1; + + if (st->iteration > st->iterations) + init_map (st); + + if (st->cx == 0) + { + st->xnextStep = st->xstep / 2; + st->ynextStep = st->ystep / 2; + } + + for (i = 0; i < col_chunk; i++) + { + int x1, x2, y1, y2; + int y; + int x = st->cx; + + x1 = x + st->xnextStep; + if (x1 < 0) + x1 = st->xmax-1; + else if (x1 >= st->xmax) + x1 = 0; + + x2 = x + st->xstep; + if (x2 < 0) + x2 = st->xmax-1; + else if (x2 >= st->xmax) + x2 = 0; + + for (y = 0; y < st->ymax; y += st->ystep) + { + unsigned int pixel, qpixels [4]; + + y1 = y + st->ynextStep; + if (y1 < 0) + y1 = st->ymax-1; + else if (y1 >= st->ymax) + y1 = 0; + + y2 = y + st->ystep; + if (y2 < 0) + y2 = st->ymax-1; + else if (y2 >= st->ymax) + y2 = 0; + + qpixels [0] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel; + qpixels [1] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel; + qpixels [2] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel; + qpixels [3] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel; + + pixel = set (st, x, y1, st->iteration, + ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2); + + if (! mono_p && + (pixel != qpixels[0] || pixel != qpixels[1] || + pixel != qpixels[2] || pixel != qpixels[3])) + draw (st, x, y1, pixel, st->ynextStep); + + pixel = set (st, x1, y, st->iteration, + ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2); + if (! mono_p && + (pixel != qpixels[0] || pixel != qpixels[1] || + pixel != qpixels[2] || pixel != qpixels[3])) + draw (st, x1, y, pixel, st->ynextStep); + + pixel = set (st, x1, y1, st->iteration, + ((int) CELL (x, y) + (int) CELL (x, y2) + + (int) CELL (x2, y) + (int) CELL (x2, y2) + 2) + / 4); + if (! mono_p && + (pixel != qpixels[0] || pixel != qpixels[1] || + pixel != qpixels[2] || pixel != qpixels[3])) + draw (st, x1, y1, pixel, st->ynextStep); + } + + st->cx += st->xstep; + if (st->cx >= st->xmax) + break; + } + + if (st->cx >= st->xmax) + { + st->cx = 0; + st->xstep = st->xnextStep; + st->ystep = st->ynextStep; + + st->iteration++; + + if (st->iteration > st->iterations) + this_delay = st->delay * 1000000; + + if (mono_p) + floyd_steinberg (st); /* in mono, do all drawing at the end */ + } + + return this_delay; +} + + +static void +imsmap_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + init_map (st); +} + + +#if 0 + static Bool + imsmap_event (Display *dpy, Window window, void *closure, XEvent *event) + { + struct state *st = (struct state *) closure; + if (event->xany.type == ButtonPress) + { + init_map (st); + return True; + } + + return False; + } +#endif + +static void +imsmap_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->colors) free (st->colors); + if (st->cell) free (st->cell); + free (st); +} + + +static const char *imsmap_defaults [] = { + ".background: #000066", + ".foreground: #FF00FF", + "*fpsSolid: true", + "*mode: random", + "*ncolors: 50", + "*iterations: 7", + "*delay: 5", + "*delay2: 20000", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec imsmap_options [] = { + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-delay2", ".delay2", XrmoptionSepArg, 0 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-iterations", ".iterations", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("IMSMap", imsmap) diff --git a/non-wgl/imsmap.vcproj b/non-wgl/imsmap.vcproj new file mode 100644 index 0000000..ac58ae9 --- /dev/null +++ b/non-wgl/imsmap.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/interaggregate.c b/non-wgl/interaggregate.c new file mode 100644 index 0000000..ce7d488 --- /dev/null +++ b/non-wgl/interaggregate.c @@ -0,0 +1,1014 @@ +/* + * InterAggregate (dagraz@gmail.com) + * Based on code from complexification.net Intersection Aggregate + * http://www.complexification.net/gallery/machines/interAggregate/index.php + * + * Intersection Aggregate code: + * j.tarbell May, 2004 + * Albuquerque, New Mexico + * complexification.net + * + * Also based on substrate, a port of j.tarbell's Substrate Art done + * by dragorn@kismetwireless.net + * + * + * Interesting command line options, all of which serve to + * concentrate the painting in some way: + * + * -percent-orbits 100 -base-orbits 50 -base-on-center -growth-delay 0 + * + * Paint should be concentrated in the center of the canvas, orbiting + * about it. -percent-orbits 100 implies -base-on-center, so that's + * not really needed. + * + * + * -percent-orbits 99 -base-orbits 50 -growth-delay 0 + * + * Like the above example, but the 'center' will rove about the screen. + * + * -percent-orbits 98 -base-orbits 50 -growth-delay 0 + * + * Like the above example, but there will be two roving centers. + * + * + * TODO: + * -fix alpha blending / byte ordering + * + * CHANGES + * + * + * 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 + + +/* 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 + +#ifndef MIN +#define MIN(x,y) ((x < y) ? x : y) +#endif + +#ifndef MAX +#define MAX(x,y) ((x < y) ? y : x) +#endif + +char *background = "white"; +char *foreground = "black"; +int maxCycles = 100000; +int growthDelay = 18000; +int numCircles = 100; +int percentOrbits = 0; +int baseOrbits = 75; +Bool baseOnCenter = False; +Bool drawCenters = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&maxCycles, "maxCycles", NULL, "100000", t_Int}, + {&growthDelay, "growthDelay", NULL, "18000", t_Int}, + {&numCircles, "numCircles", NULL, "100", t_Int}, + {&percentOrbits, "percentOrbits", NULL, "0", t_Int}, + {&baseOrbits, "baseOrbits", NULL, "75", t_Int}, + {&baseOnCenter, "baseOnCenter", NULL, "False", t_Bool}, + {&drawCenters, "drawCenters", NULL, "False", t_Bool}, +}; + +static const char *interaggregate_defaults[] = +{ + ".background: white", + ".foreground: black", + "*fpsSolid: true", + "*maxCycles: 100000", +#ifdef TIME_ME + "*growthDelay: 0", +#else + "*growthDelay: 18000", +#endif + "*numCircles: 100", + "*percentOrbits: 0", + "*baseOrbits: 75", + "*baseOnCenter: False", + "*drawCenters: False", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec interaggregate_options[] = +{ + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-max-cycles", ".maxCycles", XrmoptionSepArg, 0}, + {"-growth-delay", ".growthDelay", XrmoptionSepArg, 0}, + {"-num-circles", ".numCircles", XrmoptionSepArg, 0}, + {"-percent-orbits", ".percentOrbits", XrmoptionSepArg, 0}, + {"-base-orbits", ".baseOrbits", XrmoptionSepArg, 0}, + {"-base-on-center", ".baseOnCenter", XrmoptionNoArg, "true"}, + {"-draw-centers", ".drawCenters", XrmoptionNoArg, "true"}, + {0, 0, 0, 0} +}; + +/* Raw colormap extracted from pollockEFF.gif */ +#if 0 +char *rgb_colormap[] = +{ + "#FFFFFF", /* white */ + "#000000", /* black */ + "#000000", /* more black */ + /* "#736451", */ + "#4e3e2e", /* olive */ + /* "#666666", */ + "#694d35", /* camel */ + "#b9a88c", /* tan */ + 0 +}; +#endif + +static const char *rgb_colormap[] = +{ + "#FFFFFF", /* white */ + "#000000", /* more black */ + "#000000", /* more black */ + "#4e3e2e", /* olive */ + "#694d35", /* camel */ + "#b0a085", /* tan */ + "#e6d3ae", + 0 +}; + +/* black white brown olive grey camel */ + +typedef enum { LINEAR, ORBIT } PathType; + +typedef struct +{ + + unsigned long color; + double gain; + double p; + +} SandPainter; + +typedef struct _circle +{ + double radius; + + double x; + double y; + + PathType path_type; + + /* for a linear path */ + double dx; + double dy; + + /* for orbital path */ + double theta; + double r; + double dtheta; + + struct _circle* center; + + int num_painters; + SandPainter* painters; + +} Circle; + + +struct field +{ + int height; + int width; + + int num_circles; + Circle* circles; + + int percent_orbits; + int base_orbits; + Bool base_on_center; + + /* used for orbits circling the center of the screen */ + Circle center_of_universe; + + /* Raw map of pixels we need to keep for alpha blending */ + unsigned long int *off_img; + + /* color parms */ + int numcolors; + unsigned long *parsedcolors; + unsigned long fgcolor; + unsigned long bgcolor; + int visdepth; + + unsigned int cycles; + + double max_gain; + + /* for debugging */ + Bool draw_centers; + + /* for profiling whatnot */ + int possible_intersections; + int intersection_count; +}; + + +static struct field * +init_field(void) +{ + struct field *f = (struct field*) malloc(sizeof(struct field)); + if ( f == NULL ) + { + fprintf(stderr, "%s: Failed to allocate field!\n", progname); + exit(1); + } + + f->height = 0; + f->width = 0; + f->num_circles = 0; + f->circles = NULL; + f->percent_orbits = 0; + f->base_orbits = 0; + f->base_on_center = False; + f->off_img = NULL; + f->numcolors = 0; + f->parsedcolors = NULL; + f->fgcolor = 0; + f->bgcolor = 0; + f->visdepth = 0; + + f->cycles = 0; + + f->max_gain = 0.22; + + f->draw_centers = False; + + f->possible_intersections = 0; + f->intersection_count = 0; + + return f; +} + +/* Quick references to pixels in the offscreen map and in the crack grid */ +#define ref_pixel(f, x, y) ((f)->off_img[(y) * (f)->width + (x)]) + +#define in_bounds(f, x, y) ((x >= 0) && (x < f->width) && (y >= 0) && (y < f->height)) + +/* Consider rewriting with XQueryColor, or ImageByteOrder */ + +static inline void point2rgb(int depth, unsigned long c, int *r, int *g, int *b) +{ + switch(depth) + { + case 32: + case 24: +#ifdef HAVE_COCOA + /* 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 + *b = c & 0xff; + *g = (c & 0xff00) >> 8; + *r = (c & 0xff0000) >> 16; +#endif + break; + case 16: + *b = (c & 0x1f) << 3; + *g = ((c >> 5) & 0x3f) << 2; + *r = ((c >> 11) & 0x1f) << 3; + break; + case 15: + *b = (c & 0x1f) << 3; + *g = ((c >> 5) & 0x1f) << 3; + *r = ((c >> 10) & 0x1f) << 3; + break; + } +} + +static inline unsigned long rgb2point(int depth, int r, int g, int b) +{ + unsigned long ret = 0; + + switch(depth) + { + case 32: + case 24: +#ifdef HAVE_COCOA + /* 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; +} + +/* alpha blended point drawing -- this is Not Right and will likely fail on + * non-intel platforms as it is now, needs fixing */ +static inline unsigned long trans_point(int x1, int y1, unsigned long myc, double a, + struct field *f) +{ + if (a >= 1.0) + { + ref_pixel(f, x1, y1) = myc; + return myc; + } + else + { + int or=0, og=0, ob=0; + int r=0, g=0, b=0; + int nr, ng, nb; + unsigned long c; + + c = ref_pixel(f, x1, y1); + + point2rgb(f->visdepth, c, &or, &og, &ob); + point2rgb(f->visdepth, myc, &r, &g, &b); + + nr = or + (r - or) * a; + ng = og + (g - og) * a; + nb = ob + (b - ob) * a; + + c = rgb2point(f->visdepth, nr, ng, nb); + + ref_pixel(f, x1, y1) = c; + + return c; + } +} + +static inline void drawPoint(int x, int y, unsigned long color, double intensity, + Display *dpy, Window window, GC fgc, struct field *f) + +{ + unsigned long c; + + while ( x >= f->width ) x -= f->width; + while ( x < 0 ) x += f->width; + + while ( y >= f->height ) y -= f->height; + while ( y < 0 ) y += f->height; + + /* if ( in_bounds(f, x, y) ) ... */ + + c = trans_point(x, y, color, intensity, f); + + XSetForeground(dpy, fgc, c); + XDrawPoint(dpy, window, fgc, x, y); +} + +static inline void paint(SandPainter* painter, double ax, double ay, double bx, double by, + Display *dpy, Window window, GC fgc, + struct field *f) +{ + /* the sand painter */ + + double inc, sandp; + int i; + + /* XXX try adding tpoint here, like orig */ + + /* jitter the painter's values */ + painter->gain += frand(0.05) - 0.025; + + if ( painter->gain > f->max_gain ) + painter->gain = -f->max_gain; + else if ( painter->gain < -f->max_gain ) + painter->gain = f->max_gain; + + painter->p += frand(0.1) - 0.05; + + if ( 0 < painter->p ) + painter->p = 0; + else if ( painter->p > 1.0 ) + painter->p = 1.0; + + /* replace 0.1 with 1 / f->grains */ + inc = painter->gain * 0.1; + sandp = 0; + + for(i = 0; i <= 10; ++i) + { + int drawx, drawy; + double sp, sm; + double intensity = 0.1 - 0.009 * i; + + sp = sin(painter->p + sandp); + drawx = ax + (bx - ax) * sp; + drawy = ay + (by - ay) * sp; + + drawPoint(drawx, drawy, painter->color, + intensity, + dpy, window, fgc, f); + + sm = sin(painter->p - sandp); + drawx = ax + (bx - ax) * sm; + drawy = ay + (by - ay) * sm; + + drawPoint(drawx, drawy, painter->color, + intensity, + dpy, window, fgc, f); + + sandp += inc; + } +} + +static void build_colors(struct field *f, Display *dpy, XWindowAttributes *xgwa) +{ + + XColor tmpcolor; + int i; + /* Count the colors in our map and assign them in a horrifically inefficient + * manner but it only happens once */ + + for( f->numcolors = 0; + rgb_colormap[f->numcolors] != NULL; + ++f->numcolors ) + { + ; + } + + f->parsedcolors = (unsigned long *) calloc(f->numcolors, + sizeof(unsigned long)); + if ( f->parsedcolors == NULL ) + { + fprintf(stderr, "%s: Failed to allocate parsedcolors\n", + progname); + exit(1); + } + + for(i = 0; i < f->numcolors; ++i) + { + if (!XParseColor(dpy, xgwa->colormap, + rgb_colormap[i], &tmpcolor)) + { + fprintf(stderr, "%s: couldn't parse color %s\n", progname, + rgb_colormap[i]); + exit(1); + } + + if (!XAllocColor(dpy, xgwa->colormap, &tmpcolor)) + { + fprintf(stderr, "%s: couldn't allocate color %s\n", progname, + rgb_colormap[i]); + exit(1); + } + + f->parsedcolors[i] = tmpcolor.pixel; + + } +} + +/* used when the window is resized */ +static void build_img(struct field *f) +{ + if (f->off_img) { + free(f->off_img); + f->off_img = NULL; + } + + f->off_img = (unsigned long *) calloc(f->width * f->height, + sizeof(unsigned long)); + + + if ( f->off_img == NULL ) + { + fprintf(stderr, "%s: Failed to allocate off_img\n", + progname); + exit(1); + } + + memset(f->off_img, f->bgcolor, + sizeof(unsigned long) * f->width * f->height); +} + +static void free_circles(struct field *f) +{ + int i; + + if ( f->circles != NULL ) + { + for(i = 0; i < f->num_circles; ++i) + { + free (f->circles[i].painters); + } + + free (f->circles); + f->circles = NULL; + } +} + +static void build_field(Display *dpy, Window window, XWindowAttributes xgwa, GC fgc, + struct field *f) +{ + int i; + int num_orbits; + int base_orbits; + int orbit_start; + build_img(f); + + f->center_of_universe.x = f->width / 2.0; + f->center_of_universe.y = f->height / 2.0; + f->center_of_universe.r = MAX(f->width, f->height) / 2.0; + + num_orbits = (f->percent_orbits * f->num_circles) / 100; + orbit_start = f->num_circles - num_orbits; + base_orbits = orbit_start + (num_orbits * f->base_orbits) / 100; + + free_circles(f); + + f->circles = (Circle*) calloc(f->num_circles, sizeof(Circle)); + if ( f->circles == NULL ) + { + fprintf(stderr, "%s: Failed to allocate off_img\n", + progname); + exit(1); + } + + for(i = 0; i < f->num_circles; ++i) + { + int j; + Circle *circle = f->circles + i; + + /* make this a pref */ + + if ( i >= orbit_start ) + circle->path_type = ORBIT; + else + circle->path_type = LINEAR; + + + if ( circle->path_type == LINEAR ) + { + circle->x = frand(f->width); + circle->y = frand(f->height); + + circle->dx = frand(0.5) - 0.25; + circle->dy = frand(0.5) - 0.25; + /* circle->dy = 0; */ + /* circle->r = f->height * (0.05 + frand(0.1)); */ + circle->radius = 5 + frand(55); + + /* in case we want orbits based on lines */ + circle->r = MIN(f->width, f->height) / 2.0; + circle->center = NULL; + } + else /* == ORBIT */ + { + if (i < base_orbits ) + { + if ( f->base_on_center ) + circle->center = &f->center_of_universe; + else + { + circle->center = f->circles + + ((int)frand(orbit_start - 0.1)); + } + + circle->r = 1 + frand(MIN(f->width, f->height) / 2.0); + + /* circle->radius = 5 + frand(55); */ + } + else + { + /* give a preference for the earlier circles */ + + double p = frand(0.9); + + circle->center = f->circles + (int) (p*i); + + circle->r = 1 + 0.5 * circle->center->r + 0.5 * frand(circle->center->r); + /* circle->r = 1 + frand(circle->center->r / 2); */ + + + /* circle->radius = MAX(5, frand(circle->r)); */ + /* circle->radius = 5 + frand(55); */ + } + + circle->radius = 5 + frand(MIN(55, circle->r)); + circle->dtheta = (frand(0.5) - 0.25) / circle->r; + circle->theta = frand(2 * M_PI); + + circle->x = circle->r * cos(circle->theta) + circle->center->x; + circle->y = circle->r * sin(circle->theta) + circle->center->y; + + } + + /* make this a command line option */ + circle->num_painters = 3; + circle->painters = (SandPainter*) calloc(circle->num_painters, + sizeof(SandPainter)); + if ( circle->painters == NULL ) + { + fprintf(stderr, "%s: failed to allocate painters", progname); + exit(1); + } + + for(j = 0; j < circle->num_painters; ++j) + { + SandPainter *painter = circle->painters + j; + + painter->gain = frand(0.09) + 0.01; + painter->p = frand(1.0); + painter->color = + f->parsedcolors[(int)(frand(0.999) * f->numcolors)]; + } + } +} + +static void moveCircles(struct field *f) +{ + int i; + + for(i = 0; i < f->num_circles; ++i) + { + Circle *circle = f->circles + i; + + if ( circle->path_type == LINEAR ) + { + circle->x += circle->dx; + circle->y += circle->dy; + +#if 0 + if ( circle->x < -circle->radius ) + circle->x = f->width + circle->radius; + else if ( circle->x >= f->width + circle->radius ) + circle->x = -circle->radius; + + if ( circle->y < -circle->radius ) + circle->y = f->height + circle->radius; + else if ( circle->y >= f->height + circle->radius ) + circle->y = -circle->radius; +#else + if ( circle->x < 0 ) circle->x += f->width; + else if ( circle->x >= f->width ) circle->x -= f->width; + + if ( circle->y < 0 ) circle->y += f->height; + else if ( circle->y >= f->height ) circle->y -= f->height; +#endif + } + else /* (circle->path_type == ORBIT) */ + { + circle->theta += circle->dtheta; + + if ( circle->theta < 0 ) circle->theta += 2 * M_PI; + else if ( circle->theta > 2 * M_PI ) circle->theta -= 2 * M_PI; + + circle->x = circle->r * cos(circle->theta) + circle->center->x; + circle->y = circle->r * sin(circle->theta) + circle->center->y; + +#if 0 + if ( circle->x < -circle->radius ) + circle->x += f->width + 2 * circle->radius; + else if ( circle->x >= f->width + circle->radius ) + circle->x -= f->width + 2 * circle->radius; + + if ( circle->y < -circle->radius ) + circle->y += f->height + 2 * circle->radius; + else if ( circle->y >= f->height + circle->radius ) + circle->y -= f->height + 2 * circle->radius; +#else + if ( circle->x < 0 ) circle->x += f->width; + else if ( circle->x >= f->width ) circle->x -= f->width; + + if ( circle->y < 0 ) circle->y += f->height; + else if ( circle->y >= f->height ) circle->y -= f->height; +#endif + } + } +} + +static void drawIntersections(Display *dpy, Window window, GC fgc, struct field *f) +{ + int i,j; + + /* One might be tempted to think 'hey, this is a crude algorithm + * that is going to check each of the n (n-1) / 2 possible + * intersections! Why not try bsp trees, quad trees, etc, etc, + * etc' + * + * In practice the time spent drawing the intersection of two + * circles dwarfs the time takes to check for intersection. + * Profiling on a 640x480 screen with 100 circles shows possible + * speed gains to be only a couple of percent. + * + * But hey, if you're bored, go have fun. Let me know how it + * turns out. + */ + + + for(i = 0; i < f->num_circles; ++i) + { + Circle *c1 = f->circles + i; + + if ( !f->draw_centers ) + { + /* the default branch */ + + for(j = i + 1; j < f->num_circles; ++j) + { + double d, dsqr, dx, dy; + Circle *c2 = f->circles + j; + +#ifdef TIME_ME + ++f->possible_intersections; +#endif + dx = c2->x - c1->x; + dy = c2->y - c1->y; + + dsqr = dx * dx + dy * dy; + d = sqrt(dsqr); + + if ( (fabs(dx) < (c1->radius + c2->radius)) && + (fabs(dy) < (c1->radius + c2->radius)) && + ( d < (c1->radius + c2->radius) ) && + ( d > fabs(c1->radius - c2->radius) ) ) + { + double d1, d2, r1sqr; + double bx, by; + double midpx, midpy; + double int1x, int1y; + double int2x, int2y; + int s; + + /* woo-hoo. the circles are neither outside nor + * inside each other. they intersect. + * + * Now, compute the coordinates of the points of + * intersection + */ + +#ifdef TIME_ME + ++f->intersection_count; +#endif + + /* unit vector in direction of c1 to c2 */ + bx = dx / d; + by = dy / d; + + r1sqr = c1->radius * c1->radius; + + /* distance from c1's center midpoint of intersection + * points */ + + d1 = 0.5 * (r1sqr - c2->radius * c2->radius + dsqr) / d; + + midpx = c1->x + d1 * bx; + midpy = c1->y + d1 * by; + + /* distance from midpoint to points of intersection */ + + d2 = sqrt(r1sqr - d1 * d1); + + int1x = midpx + d2 * by; + int1y = midpy - d2 * bx; + + int2x = midpx - d2 * by; + int2y = midpy + d2 * bx; + + for(s = 0; s < c1->num_painters; ++s) + { + paint(c1->painters + s, int1x, int1y, int2x, int2y, + dpy, window, fgc, f); + } + } + } + } + else /* f->draw_centers */ + { + XDrawPoint(dpy, window, fgc, c1->x, c1->y); + } + } +} + +struct state { + Display *dpy; + Window window; + + unsigned int max_cycles; + int growth_delay; + GC fgc; + XGCValues gcv; + XWindowAttributes xgwa; + + struct field *f; +}; + + +static void * +interaggregate_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + +#ifdef TIME_ME + int frames; + struct timeval tm1, tm2; + double tdiff; +#endif + + st->dpy = dpy; + st->window = window; + st->f = init_field(); +#if 1 + st->growth_delay = growthDelay; + st->max_cycles = maxCycles; + st->f->num_circles = numCircles; + st->f->percent_orbits = percentOrbits; + st->f->base_orbits = baseOrbits; + st->f->base_on_center = baseOnCenter; + st->f->draw_centers = drawCenters; +#else + st->growth_delay = (get_integer_resource(st->dpy, "growthDelay", "Integer")); + st->max_cycles = (get_integer_resource(st->dpy, "maxCycles", "Integer")); + st->f->num_circles = (get_integer_resource(st->dpy, "numCircles", "Integer")); + st->f->percent_orbits = (get_integer_resource(st->dpy, "percentOrbits", "Integer")); + st->f->base_orbits = (get_integer_resource(st->dpy, "baseOrbits", "Integer")); + st->f->base_on_center = (get_boolean_resource(st->dpy, "baseOnCenter", "Boolean")); + st->f->draw_centers = (get_boolean_resource(st->dpy, "drawCenters", "Boolean")); +#endif + + if (st->f->num_circles <= 1) + { + fprintf(stderr, "%s: Minimum number of circles is 2\n", + progname); + exit (1); + } + + if ( (st->f->percent_orbits < 0) || (st->f->percent_orbits > 100) ) + { + fprintf(stderr, "%s: percent-oribts must be between 0 and 100\n", + progname); + exit (1); + } + + if ( (st->f->base_orbits < 0) || (st->f->base_orbits > 100) ) + { + fprintf(stderr, "%s: base-oribts must be between 0 and 100\n", + progname); + exit (1); + } + + if ( st->f->percent_orbits == 100 ) + st->f->base_on_center = True; + + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + + build_colors(st->f, st->dpy, &st->xgwa); + +#if 1 + st->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, foreground); + st->gcv.background = load_color(st->dpy, st->xgwa.colormap, background); +#else + st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->gcv.background = get_pixel_resource(st->dpy, st->xgwa.colormap, + "background", "Background"); +#endif + + st->fgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); + + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + st->f->fgcolor = st->gcv.foreground; + st->f->bgcolor = st->gcv.background; + + /* Initialize stuff */ + build_field(st->dpy, st->window, st->xgwa, st->fgc, st->f); + +#ifdef TIME_ME + gettimeofday(&tm1, NULL); + frames = 0; +#endif + + return st; +} + + +static unsigned long +interaggregate_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if ((st->f->cycles % 10) == 0) + { + /* Restart if the window size changes */ + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + + if (st->f->height != st->xgwa.height || st->f->width != st->xgwa.width) + { + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + + build_field(st->dpy, st->window, st->xgwa, st->fgc, st->f); + XSetForeground(st->dpy, st->fgc, st->gcv.background); + XFillRectangle(st->dpy, st->window, st->fgc, 0, 0, st->xgwa.width, st->xgwa.height); + XSetForeground(st->dpy, st->fgc, st->gcv.foreground); + } + } + + moveCircles(st->f); + drawIntersections(st->dpy, st->window, st->fgc, st->f); + + st->f->cycles++; + + + if (st->f->cycles >= st->max_cycles && st->max_cycles != 0) + { + build_field(st->dpy, st->window, st->xgwa, st->fgc, st->f); + XSetForeground(st->dpy, st->fgc, st->gcv.background); + XFillRectangle(st->dpy, st->window, st->fgc, 0, 0, st->xgwa.width, st->xgwa.height); + XSetForeground(st->dpy, st->fgc, st->gcv.foreground); + } + +#ifdef TIME_ME + frames++; + gettimeofday(&tm2, NULL); + + tdiff = (tm2.tv_sec - tm1.tv_sec) + + (tm2.tv_usec - tm1.tv_usec) * 0.00001; + + if ( tdiff > 1 ) + { + fprintf(stderr, "fps: %d %f %f\n", + frames, tdiff, frames / tdiff ); + + fprintf(stderr, "intersections: %d %d %f\n", + f->intersection_count, f->possible_intersections, + ((double)f->intersection_count) / + f->possible_intersections); + + fprintf(stderr, "fpi: %f\n", + ((double)frames) / f->intersection_count ); + + frames = 0; + tm1.tv_sec = tm2.tv_sec; + tm1.tv_usec = tm2.tv_usec; + + f->intersection_count = f->possible_intersections = 0; + } +#endif + + return st->growth_delay; +} + + +static void +interaggregate_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + interaggregate_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +interaggregate_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +XSCREENSAVER_MODULE ("Interaggregate", interaggregate) diff --git a/non-wgl/interaggregate.vcproj b/non-wgl/interaggregate.vcproj new file mode 100644 index 0000000..990b4cb --- /dev/null +++ b/non-wgl/interaggregate.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/interference.c b/non-wgl/interference.c new file mode 100644 index 0000000..ed29630 --- /dev/null +++ b/non-wgl/interference.c @@ -0,0 +1,994 @@ +/* interference.c --- colored fields via decaying sinusoidal waves. + * An entry for the RHAD Labs Screensaver Contest. + * + * Author: Hannu Mallat + * + * Copyright (C) 1998 Hannu Mallat. + * + * 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. + * + * decaying sinusoidal waves, which extend spherically from their + * respective origins, move around the plane. a sort of interference + * between them is calculated and the resulting twodimensional wave + * height map is plotted in a grid, using softly changing colours. + * + * not physically (or in any sense) accurate, but fun to look at for + * a while. you may tune the speed/resolution/interestingness tradeoff + * with X resources, see below. + * + * Created : Wed Apr 22 09:30:30 1998, hmallat + * Last modified: Wed Apr 22 09:30:30 1998, hmallat + * Last modified: Sun Aug 31 23:40:14 2003, + * david slimp + * added -hue option to specify base color hue + * Last modified: Wed May 15 00:04:43 2013, + * Dave Odell + * Tuned performance; double-buffering is now off by default. + * Made animation speed independant of FPS. + * Added cleanup code, fixed a few glitches. + * Added gratuitous #ifdefs. + */ + +#include "screenhack.h" +#include +#include + +#ifdef HAVE_STDINT_H +# include +#else + +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +#endif + +/* +Tested on an Intel(R) Pentium(R) 4 CPU 3.00GHz (family 15, model 6, 2 cores), +1 GB PC2-4200, nouveau - Gallium 0.4 on NV44, X.Org version: 1.13.3. A very +modest system by current standards. + +Does double-buffering make sense? (gridsize = 2) +USE_XIMAGE is off: Yes (-db: 4.1 FPS, -no-db: 2.9 FPS) +XPutImage in strips: No (-db: 35.9 FPS, -no-db: 38.7 FPS) +XPutImage, whole image: No (-db: 32.3 FPS, -no-db: 33.7 FPS) +MIT-SHM, whole image: Doesn't work anyway: (37.3 FPS) + +If gridsize = 1, XPutImage is slow when the XImage is one line at a time. +XPutImage in strips: -db: 21.2 FPS, -no-db: 19.7 FPS +XPutimage, whole image: -db: 23.2 FPS, -no-db: 23.4 FPS +MIT-SHM: 26.0 FPS + +So XPutImage in strips is very slightly faster when gridsize >= 2, but +quite a bit worse when gridsize = 1. +*/ + +/* I thought it would be faster this way, but it turns out not to be... -jwz */ +/* It's a lot faster for me, though - D.O. */ +#define USE_XIMAGE + +/* i.e. make the XImage the size of the screen. This is much faster when + * gridsize = 1. (And SHM is turned off.) */ +#define USE_BIG_XIMAGE + +/* Numbers are wave_table size, measured in unsigned integers. + * FPS/radius = 50/radius = 800/radius = 1500/Big-O memory usage + * + * Use at most one of the following: + * Both off = regular sqrt() - 13.5 FPS, 50/800/1500. */ + +/* #define USE_FAST_SQRT_HACKISH */ /* 17.8 FPS/2873/4921/5395/O(lg(radius)) */ +#define USE_FAST_SQRT_BIGTABLE2 /* 26.1 FPS/156/2242/5386/O(radius^2) */ + +#ifndef USE_XIMAGE +# undef HAVE_XSHM_EXTENSION /* only applicable when using XImages */ +#endif /* USE_XIMAGE */ + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# include "xdbe.h" +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +#ifdef HAVE_XSHM_EXTENSION +# include "xshm.h" +#endif /* HAVE_XSHM_EXTENSION */ + +char *background = "black"; +char *foreground = "white"; +int count = 3; +int gridsize = 4; +int ncolors = 128; +int hue = 0; +int speed = 30; +int delay = 30000; +float color_shift = 60.0; +int radius_ = 800; +Bool gray_ = False; +Bool mono_ = False; +Bool doubleBuffer = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&count, "count", NULL, "3", t_Int}, + {&gridsize, "gridsize", NULL, "4", t_Int}, + {&ncolors, "ncolors", NULL, "128", t_Int}, + {&hue, "hue", NULL, "0", t_Int}, + {&speed, "speed", NULL, "30", t_Int}, + {&delay, "delay", NULL, "30000", t_Int}, + {&color_shift, "color_shift", NULL, "60.0", t_Float}, + {&radius_, "radius", NULL, "800", t_Int}, + {&gray_, "gray", NULL, "False", t_Bool}, + {&mono_, "mono", NULL, "False", t_Bool}, + {&doubleBuffer, "doubleBuffer", NULL, "False", t_Bool}, +}; + +static const char *interference_defaults [] = { + ".background: black", + ".foreground: white", + "*count: 3", /* number of waves */ + "*gridsize: 4", /* pixel size, smaller values for better resolution */ + "*ncolors: 128", /* number of colours used */ + "*hue: 0", /* hue to use for base color (0-360) */ + "*speed: 30", /* speed of wave origins moving around */ + "*delay: 30000", /* or something */ + "*color-shift: 60", /* h in hsv space, smaller values for smaller + * color gradients */ + "*radius: 800", /* wave extent */ + "*gray: false", /* color or grayscale */ + "*mono: false", /* monochrome, not very much fun */ + + "*doubleBuffer: False", /* doubleBuffer slows things down for me - D.O. */ +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + "*useDBE: True", /* use double buffering extension */ +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", /* use shared memory extension */ +#endif /* HAVE_XSHM_EXTENSION */ +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec interference_options [] = { + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-gridsize", ".gridsize", XrmoptionSepArg, 0 }, + { "-hue", ".hue", XrmoptionSepArg, 0 }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-color-shift", ".color-shift", XrmoptionSepArg, 0 }, + { "-radius", ".radius", XrmoptionSepArg, 0 }, + { "-gray", ".gray", XrmoptionNoArg, "True" }, + { "-mono", ".mono", XrmoptionNoArg, "True" }, + { "-db", ".doubleBuffer", XrmoptionNoArg, "True" }, + { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" }, +#ifdef HAVE_XSHM_EXTENSION + { "-shm", ".useSHM", XrmoptionNoArg, "True" }, + { "-no-shm", ".useSHM", XrmoptionNoArg, "False" }, +#endif /* HAVE_XSHM_EXTENSION */ + { 0, 0, 0, 0 } +}; + +struct inter_source { + int x; + int y; + double x_theta; + double y_theta; +}; + +struct inter_context { + /* + * Display-related entries + */ + Display* dpy; + Window win; + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + XdbeBackBuffer back_buf; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + Pixmap pix_buf; + + GC copy_gc; +#ifdef USE_XIMAGE + XImage *ximage; +#endif /* USE_XIMAGE */ + +#ifdef HAVE_XSHM_EXTENSION + Bool use_shm, shm_can_draw; + XShmSegmentInfo shm_info; +#endif /* HAVE_XSHM_EXTENSION */ + + /* + * Resources + */ + int count; + int grid_size; + int colors; + float hue; + int speed; + int delay; + int shift; + + /* + * Drawing-related entries + */ + int w; + int h; + Colormap cmap; + Screen *screen; + XColor* pal; +#ifndef USE_XIMAGE + GC* gcs; +#endif + int radius; /* Not always the same as the X resource. */ + double last_frame; +#ifdef USE_XIMAGE + uint32_t* row; +#endif + + /* + * lookup tables + */ + unsigned* wave_height; + + /* + * Interference sources + */ + struct inter_source* source; +}; + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# define TARGET(c) ((c)->back_buf ? (c)->back_buf : \ + (c)->pix_buf ? (c)->pix_buf : (c)->win) +#else /* HAVE_DOUBLE_BUFFER_EXTENSION */ +# define TARGET(c) ((c)->pix_buf ? (c)->pix_buf : (c)->win) +#endif /* !HAVE_DOUBLE_BUFFER_EXTENSION */ + +#ifdef USE_FAST_SQRT_HACKISH +/* Based loosely on code from Wikipedia: + * https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Approximations_that_depend_on_IEEE_representation + */ + +/* FAST_SQRT_EXTRA_BITS = 3: Smallest useful value + * = 5/6: A little bit of banding, wave_height table is on par with regular + * sqrt() code. + * = 7: No apparent difference with original @ radius = 800. + * = 8: One more just to be comfortable. + */ + +# define FAST_SQRT_EXTRA_BITS 8 + +union int_float +{ + uint32_t i; + float f; +}; + +static unsigned fast_log2(unsigned x) +{ + union int_float u; + if(!x) + return x; + u.f = x; + return ((u.i - 0x3f800000) >> (23 - FAST_SQRT_EXTRA_BITS)) + 1; +} + +static float fast_inv_log2(unsigned x) +{ + union int_float u; + if(!x) + return 0.0f; + u.i = ((x - 1) << (23 - FAST_SQRT_EXTRA_BITS)) + 0x3f800000; + return u.f; +} + +#endif + +#ifdef USE_FAST_SQRT_BIGTABLE2 + +/* I eyeballed these figures. They could be improved. - D.O. */ + +# define FAST_SQRT_DISCARD_BITS1 4 +/* = 5: Dot in center is almost invisible at radius = 800. */ +/* = 4: Dot in center looks OK at radius = 50. */ + +/* 156/2740/9029 */ +/* # define FAST_SQRT_DISCARD_BITS2 8 */ +/* # define FAST_SQRT_CUTOFF 64 * 64 */ + +/* 156/2242/5386 */ +# define FAST_SQRT_DISCARD_BITS2 9 +# define FAST_SQRT_CUTOFF 128 * 128 + +/* + * This is a little faster: + * 44.5 FPS, 19/5000/17578 + * + * # define FAST_SQRT_DISCARD_BITS1 7 + * # define FAST_SQRT_DISCARD_BITS2 7 + * # define FAST_SQRT_CUTOFF 0 + * + * For radius = 800, FAST_SQRT_DISCARD_BITS2 = + * = 9/10: Approximately the original table size, some banding near origins. + * = 7: wave_height is 20 KB, and just fits inside a 32K L1 cache. + * = 6: Nearly indistinguishable from original + */ + +/* + FAST_TABLE(x) is equivalent to, but slightly faster than: + x < FAST_SQRT_CUTOFF ? + (x >> FAST_SQRT_DISCARD_BITS1) : + ((x - FAST_SQRT_CUTOFF) >> FAST_SQRT_DISCARD_BITS2) + + (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1); +*/ + +#define FAST_TABLE(x) \ + ((x) < FAST_SQRT_CUTOFF ? \ + ((x) >> FAST_SQRT_DISCARD_BITS1) : \ + (((x) + \ + ((FAST_SQRT_CUTOFF << (FAST_SQRT_DISCARD_BITS2 - \ + FAST_SQRT_DISCARD_BITS1)) - FAST_SQRT_CUTOFF)) >> \ + FAST_SQRT_DISCARD_BITS2)) + +static double fast_inv_table(unsigned x) +{ + return x < (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1) ? + (x << FAST_SQRT_DISCARD_BITS1) : + ((x - (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1)) << + FAST_SQRT_DISCARD_BITS2) + FAST_SQRT_CUTOFF; +} + +#endif + +/* Also destroys c->row. */ +static void destroy_image(Display* dpy, struct inter_context* c) +{ +#ifdef USE_XIMAGE + if(c->ximage) { +# ifdef HAVE_XSHM_EXTENSION + if(c->use_shm) { + destroy_xshm_image(dpy, c->ximage, &c->shm_info); + } else +# endif + { + /* Also frees c->ximage->data, which isn't allocated by XCreateImage. */ + XDestroyImage(c->ximage); + } + } + + free(c->row); +#endif +} + +static void inter_free(Display* dpy, struct inter_context* c) +{ +#ifndef USE_XIMAGE + unsigned i; +#endif + + if(c->pix_buf) + XFreePixmap(dpy, c->pix_buf); + + if(c->copy_gc) + XFreeGC(dpy, c->copy_gc); + + destroy_image(dpy, c); + + if(c->colors <= 2) + free(c->pal); + else + free_colors(c->screen, c->cmap, c->pal, c->colors); + +#ifndef USE_XIMAGE + for(i = 0; i != c->colors; ++i) + XFreeGC(dpy, c->gcs[i]); + free(c->gcs); +#endif + + free(c->wave_height); + free(c->source); +} + +static void abort_no_mem(void) +{ + fprintf(stderr, "interference: %s\n", strerror(ENOMEM)); + exit(1); +} + +static void check_no_mem(Display* dpy, struct inter_context* c, void* ptr) +{ + if(!ptr) { + inter_free(dpy, c); + abort_no_mem(); + } +} + +/* On allocation error, c->row == NULL. */ +static void create_image( + Display* dpy, + struct inter_context* c, + const XWindowAttributes* xgwa) +{ +#ifdef USE_XIMAGE + c->row = malloc((c->w / c->grid_size) * sizeof(uint32_t)); + check_no_mem(dpy, c, c->row); + +# ifdef HAVE_XSHM_EXTENSION + /* + * interference used to put one row at a time to the X server. This changes + * today. + * + * XShmPutImage is asynchronous; the contents of the XImage must not be + * modified until the server has placed the data on the screen. Waiting for + * an XShmCompletionEvent after every line of pixels is a little nutty, so + * shared-memory XImages will cover the entire screen, and it only has to be + * sent once per frame. + * + * The non-SHM code, on the other hand is noticeably slower when + * gridsize = 1 with one row at a time. If, on the other hand, gridsize >= 2, + * there's a slight speed increase with one row at a time. + * + * This uses a lot more RAM than the single line approach. Users with only + * 4 MB of RAM may wish to disable USE_BIG_XIMAGE and specify -no-shm on the + * command line. Since this is 2013 and desktop computers are shipping with + * 8 GB of RAM, I doubt that this will be a major issue. - D.O. + */ + + if (c->use_shm) + { + c->ximage = create_xshm_image(dpy, xgwa->visual, xgwa->depth, + ZPixmap, 0, &c->shm_info, + xgwa->width, xgwa->height); + if (!c->ximage) + c->use_shm = False; + /* If create_xshm_image fails, it will not be attempted again. */ + + c->shm_can_draw = True; + } +# endif /* HAVE_XSHM_EXTENSION */ + + if (!c->ximage) + { + c->ximage = + XCreateImage(dpy, xgwa->visual, + xgwa->depth, ZPixmap, 0, 0, /* depth, fmt, offset, data */ + xgwa->width, /* width */ +# ifdef USE_BIG_XIMAGE + xgwa->height, /* height */ +# else + c->grid_size, /* height */ +# endif + 8, 0); /* pad, bpl */ + + if(c->ximage) + { + c->ximage->data = (char *) + calloc(c->ximage->height, c->ximage->bytes_per_line); + + if(!c->ximage->data) + { + free(c->ximage); + c->ximage = NULL; + } + } + } + + if(!c->ximage) + { + free(c->row); + c->row = 0; + } + + check_no_mem(dpy, c, c->row); +#endif /* USE_XIMAGE */ +} + +static void create_pix_buf(Display* dpy, Window win, struct inter_context *c, + const XWindowAttributes* xgwa) +{ +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if(c->back_buf) + return; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + c->pix_buf = XCreatePixmap(dpy, win, xgwa->width, xgwa->height, xgwa->depth); +} + +static double float_time(void) +{ + struct timeval result; + gettimeofday( + &result +#ifdef GETTIMEOFDAY_TWO_ARGS + , NULL +#endif + ); + + return result.tv_usec * 1.0e-6 + result.tv_sec; +} + +static void inter_init(Display* dpy, Window win, struct inter_context* c) +{ + XWindowAttributes xgwa; + double H[3], S[3], V[3]; + int i; + int mono; + int gray; + int radius; + XGCValues val; + //Bool dbuf = get_boolean_resource (dpy, "doubleBuffer", "Boolean"); + Bool dbuf = doubleBuffer; + +#ifndef USE_XIMAGE + unsigned long valmask = 0; +#endif + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + dbuf = False; +# endif + + memset (c, 0, sizeof(*c)); + + c->dpy = dpy; + c->win = win; + + //c->delay = get_integer_resource(dpy, "delay", "Integer"); + c->delay = delay; + + XGetWindowAttributes(c->dpy, c->win, &xgwa); + c->w = xgwa.width; + c->h = xgwa.height; + c->cmap = xgwa.colormap; + c->screen = xgwa.screen; + +#ifdef HAVE_XSHM_EXTENSION + c->use_shm = get_boolean_resource(dpy, "useSHM", "Boolean"); +#endif /* HAVE_XSHM_EXTENSION */ + + val.function = GXcopy; + c->copy_gc = XCreateGC(c->dpy, TARGET(c), GCFunction, &val); + + //c->count = get_integer_resource(dpy, "count", "Integer"); + c->count = count; + if(c->count < 1) + c->count = 1; + //c->grid_size = get_integer_resource(dpy, "gridsize", "Integer"); + c->grid_size = gridsize; + if(c->grid_size < 1) + c->grid_size = 1; + //mono = get_boolean_resource(dpy, "mono", "Boolean"); + mono = mono_; + if(!mono) { + //c->colors = get_integer_resource(dpy, "ncolors", "Integer"); + c->colors = ncolors; + if(c->colors < 2) + c->colors = 2; + } + //c->hue = get_integer_resource(dpy, "hue", "Float"); + c->hue = hue; + while (c->hue < 0 || c->hue >= 360) + c->hue = frand(360.0); + //c->speed = get_integer_resource(dpy, "speed", "Integer"); + //c->shift = get_float_resource(dpy, "color-shift", "Float"); + c->speed = speed; + c->shift = color_shift; + while(c->shift >= 360.0) + c->shift -= 360.0; + while(c->shift <= -360.0) + c->shift += 360.0; + //radius = get_integer_resource(dpy, "radius", "Integer");; + radius = radius_; + if(radius < 1) + radius = 1; + + create_image(dpy, c, &xgwa); + + if(!mono) { + c->pal = calloc(c->colors, sizeof(XColor)); + check_no_mem(dpy, c, c->pal); + + //gray = get_boolean_resource(dpy, "gray", "Boolean"); + gray = gray_; + if(!gray) { + H[0] = c->hue; + H[1] = H[0] + c->shift < 360.0 ? H[0]+c->shift : H[0] + c->shift-360.0; + H[2] = H[1] + c->shift < 360.0 ? H[1]+c->shift : H[1] + c->shift-360.0; + S[0] = S[1] = S[2] = 1.0; + V[0] = V[1] = V[2] = 1.0; + } else { + H[0] = H[1] = H[2] = 0.0; + S[0] = S[1] = S[2] = 0.0; + V[0] = 1.0; V[1] = 0.5; V[2] = 0.0; + } + + make_color_loop(c->screen, xgwa.visual, c->cmap, + H[0], S[0], V[0], + H[1], S[1], V[1], + H[2], S[2], V[2], + c->pal, &(c->colors), + True, False); + if(c->colors < 2) { /* color allocation failure */ + mono = 1; + free(c->pal); + } + } + + if(mono) { /* DON'T else this with the previous if! */ + c->colors = 2; + c->pal = calloc(2, sizeof(XColor)); + check_no_mem(dpy, c, c->pal); + c->pal[0].pixel = BlackPixel(c->dpy, DefaultScreen(c->dpy)); + c->pal[1].pixel = WhitePixel(c->dpy, DefaultScreen(c->dpy)); + } + +#ifdef HAVE_XSHM_EXTENSION + if(c->use_shm) + dbuf = False; + /* Double-buffering doesn't work with MIT-SHM: XShmPutImage must draw to the + * window. Otherwise, XShmCompletion events will have the XAnyEvent::window + * field set to the back buffer, and XScreenSaver will ignore the event. */ +#endif + + if (dbuf) + { +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + c->back_buf = xdbe_get_backbuffer (c->dpy, c->win, XdbeUndefined); +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + create_pix_buf(dpy, win, c, &xgwa); + } + +#ifndef USE_XIMAGE + valmask = GCForeground; + c->gcs = calloc(c->colors, sizeof(GC)); + check_no_mem(dpy, c, c->gcs); + for(i = 0; i < c->colors; i++) { + val.foreground = c->pal[i].pixel; + c->gcs[i] = XCreateGC(c->dpy, TARGET(c), valmask, &val); + } +#endif + +#if defined USE_FAST_SQRT_HACKISH + c->radius = fast_log2(radius * radius); +#elif defined USE_FAST_SQRT_BIGTABLE2 + c->radius = radius * radius; + c->radius = FAST_TABLE(c->radius); +#else + c->radius = radius; +#endif + + c->wave_height = calloc(c->radius, sizeof(unsigned)); + check_no_mem(dpy, c, c->wave_height); + + for(i = 0; i < c->radius; i++) { + float max, fi; +#if defined USE_FAST_SQRT_HACKISH + fi = sqrt(fast_inv_log2(i)); +#elif defined USE_FAST_SQRT_BIGTABLE2 + fi = sqrt(fast_inv_table(i)); +#else + fi = i; +#endif + max = + ((float)c->colors) * + ((float)radius - fi) / + ((float)radius); + c->wave_height[i] = + (unsigned) + ((max + max*cos(fi/50.0)) / 2.0); + } + + c->source = calloc(c->count, sizeof(struct inter_source)); + check_no_mem(dpy, c, c->source); + + for(i = 0; i < c->count; i++) { + c->source[i].x_theta = frand(2.0)*3.14159; + c->source[i].y_theta = frand(2.0)*3.14159; + } + + c->last_frame = float_time(); +} + +#define source_x(c, i) \ + (c->w/2 + ((int)(cos(c->source[i].x_theta)*((float)c->w/2.0)))) +#define source_y(c, i) \ + (c->h/2 + ((int)(cos(c->source[i].y_theta)*((float)c->h/2.0)))) + +/* + * This is rather suboptimal. Calculating the distance per-pixel is going to + * be a lot slower than using now-ubiquitous SIMD CPU instructions to do four + * or eight pixels at a time. Plus, this could be almost trivially + * parallelized, what with all the multi-core hardware nowadays. + */ + +static unsigned long do_inter(struct inter_context* c) +{ + int i, j, k; + unsigned result; + int dist; + int g = c->grid_size; + unsigned w_div_g = c->w/g; + + int dx, dy; + int px, py; + +#ifdef USE_XIMAGE + unsigned img_y = 0; + void *scanline = c->ximage->data; +#endif + + double now; + float elapsed; + +#if defined USE_XIMAGE && defined HAVE_XSHM_EXTENSION + /* Wait a little while for the XServer to become ready if necessary. */ + if(c->use_shm && !c->shm_can_draw) + return 2000; +#endif + + now = float_time(); + elapsed = (now - c->last_frame) * 10.0; + + c->last_frame = now; + + for(i = 0; i < c->count; i++) { + c->source[i].x_theta += (elapsed*c->speed/1000.0); + if(c->source[i].x_theta > 2.0*3.14159) + c->source[i].x_theta -= 2.0*3.14159; + c->source[i].y_theta += (elapsed*c->speed/1000.0); + if(c->source[i].y_theta > 2.0*3.14159) + c->source[i].y_theta -= 2.0*3.14159; + c->source[i].x = source_x(c, i); + c->source[i].y = source_y(c, i); + } + + for(j = 0; j < c->h/g; j++) { + for(i = 0; i < w_div_g; i++) { + result = 0; + px = i*g + g/2; + py = j*g + g/2; + for(k = 0; k < c->count; k++) { + + dx = px - c->source[k].x; + dy = py - c->source[k].y; + + /* + * Other possibilities for improving performance here: + * 1. Using octagon-based distance estimation + * (Which causes giant octagons to appear.) + * 2. Square root approximation by reinterpret-casting IEEE floats to + * integers. + * (Which causes angles to appear when two waves interfere.) + */ + +/* int_float u; + u.f = dx*dx + dy*dy; + u.i = (1 << 29) + (u.i >> 1) - (1 << 22); + dist = u.f; */ + +#if defined USE_FAST_SQRT_BIGTABLE2 + dist = dx*dx + dy*dy; + dist = FAST_TABLE(dist); +#elif defined USE_FAST_SQRT_HACKISH + dist = fast_log2(dx*dx + dy*dy); +#else + dist = sqrt(dx*dx + dy*dy); +#endif + + result += (dist >= c->radius ? 0 : c->wave_height[dist]); + } + + /* It's slightly faster to do a subtraction or two before calculating the + * modulus. - D.O. */ + if(result >= c->colors) + { + result -= c->colors; + if(result >= c->colors) + result %= (unsigned)c->colors; + } + +#ifdef USE_XIMAGE + c->row[i] = c->pal[result].pixel; +#else + XFillRectangle(c->dpy, TARGET(c), c->gcs[result], g*i, g*j, g, g); +#endif /* USE_XIMAGE */ + } + +#ifdef USE_XIMAGE + /* Fill in these `gridsize' horizontal bits in the scanline */ + if(c->ximage->bits_per_pixel == 32) + { + uint32_t *ptr = (uint32_t *)scanline; + for(i = 0; i < w_div_g; i++) { + for(k = 0; k < g; k++) + ptr[g*i+k] = c->row[i]; + } + } + else if(c->ximage->bits_per_pixel == 24) + { + uint8_t *ptr = (uint8_t *)scanline; + for(i = 0; i < w_div_g; i++) { + for(k = 0; k < g; k++) { + uint32_t pixel = c->row[i]; + /* Might not work on big-endian. */ + ptr[0] = pixel; + ptr[1] = (pixel & 0x0000ff00) >> 8; + ptr[2] = (pixel & 0x00ff0000) >> 16; + ptr += 3; + } + } + } + else if(c->ximage->bits_per_pixel == 16) + { + uint16_t *ptr = (uint16_t *)scanline; + for(i = 0; i < w_div_g; i++) { + for(k = 0; k < g; k++) + ptr[g*i+k] = c->row[i]; + } + } + else if(c->ximage->bits_per_pixel == 8) + { + uint8_t *ptr = (uint8_t *)scanline; + for(i = 0; i < w_div_g; i++) { + for(k = 0; k < g; k++) + ptr[g*i+k] = c->row[i]; + } + } + else + { + for(i = 0; i < w_div_g; i++) { + for(k = 0; k < g; k++) + XPutPixel(c->ximage, (g*i)+k, img_y, c->row[i]); + } + } + + /* Only the first scanline of the image has been filled in; clone that + scanline to the rest of the `gridsize' lines in the ximage */ + for(k = 0; k < (g-1); k++) + memcpy(c->ximage->data + (c->ximage->bytes_per_line * (img_y + k + 1)), + c->ximage->data + (c->ximage->bytes_per_line * img_y), + c->ximage->bytes_per_line); + +# ifndef USE_BIG_XIMAGE + /* Move the bits for this horizontal stripe to the server. */ +# ifdef HAVE_XSHM_EXTENSION + if (!c->use_shm) +# endif /* HAVE_XSHM_EXTENSION */ + XPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage, + 0, 0, 0, g*j, c->ximage->width, c->ximage->height); +# endif + +# if defined HAVE_XSHM_EXTENSION && !defined USE_BIG_XIMAGE + if (c->use_shm) +# endif + { +# if defined HAVE_XSHM_EXTENSION || defined USE_BIG_XIMAGE + scanline = (char *)scanline + c->ximage->bytes_per_line * g; + img_y += g; +# endif + } + +#endif /* USE_XIMAGE */ + } + +#ifdef HAVE_XSHM_EXTENSION + if (c->use_shm) + { + XShmPutImage(c->dpy, c->win, c->copy_gc, c->ximage, + 0, 0, 0, 0, c->ximage->width, c->ximage->height, + True); + c->shm_can_draw = False; + } +#endif +#if defined HAVE_XSHM_EXTENSION && defined USE_BIG_XIMAGE + else +#endif +#ifdef USE_BIG_XIMAGE + { + XPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage, + 0, 0, 0, 0, c->ximage->width, c->ximage->height); + } +#endif + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (c->back_buf) + { + XdbeSwapInfo info[1]; + info[0].swap_window = c->win; + info[0].swap_action = XdbeUndefined; + XdbeSwapBuffers(c->dpy, info, 1); + } + else +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + if (c->pix_buf) + { + XCopyArea (c->dpy, c->pix_buf, c->win, c->copy_gc, + 0, 0, c->w, c->h, 0, 0); + } + + return c->delay; +} + +static void * +interference_init (Display *dpy, Window win) +{ + struct inter_context *c = (struct inter_context *) calloc (1, sizeof(*c)); + if(!c) + abort_no_mem(); + inter_init(dpy, win, c); + return c; +} + +static unsigned long +interference_draw (Display *dpy, Window win, void *closure) +{ + struct inter_context *c = (struct inter_context *) closure; + return do_inter(c); +} + +static void +interference_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct inter_context *c = (struct inter_context *) closure; + XWindowAttributes xgwa; + Bool dbuf = (c->pix_buf +# ifdef HAVE_DOUBLE_BUFFER_EXTENSION + || c->back_buf +# endif + ); + + c->w = w; + c->h = h; + +#ifdef USE_XIMAGE + destroy_image(dpy, c); + c->ximage = 0; +#endif + + if(c->pix_buf) + XFreePixmap(dpy, c->pix_buf); + c->pix_buf = None; + + XGetWindowAttributes(dpy, window, &xgwa); + xgwa.width = w; + xgwa.height = h; + create_image(dpy, c, &xgwa); + if(dbuf) + create_pix_buf(dpy, window, c, &xgwa); +} + +#if 0 + static Bool + interference_event (Display *dpy, Window window, void *closure, XEvent *event) + { + #if HAVE_XSHM_EXTENSION + struct inter_context *c = (struct inter_context *) closure; + + if(c->use_shm && event->type == XShmGetEventBase(dpy) + ShmCompletion) + { + c->shm_can_draw = True; + return True; + } + #endif + return False; + } +#endif + +static void +interference_free (Display *dpy, Window window, void *closure) +{ + struct inter_context *c = (struct inter_context *) closure; + inter_free(dpy, c); +} + +XSCREENSAVER_MODULE ("Interference", interference) + diff --git a/non-wgl/interference.vcproj b/non-wgl/interference.vcproj new file mode 100644 index 0000000..01a7a7c --- /dev/null +++ b/non-wgl/interference.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/intermomentary.c b/non-wgl/intermomentary.c new file mode 100644 index 0000000..dac77fd --- /dev/null +++ b/non-wgl/intermomentary.c @@ -0,0 +1,609 @@ +/* + * InterMomentary (dragorn@kismetwireless.net) + * Directly ported code from complexification.net InterMomentary art + * http://www.complexification.net/gallery/machines/interMomentary/applet_l/interMomentary_l.pde + * + * Intersecting Circles, Instantaneous + * J. Tarbell + complexification.net + * Albuquerque, New Mexico + * May, 2004 + * + * a REAS collaboration for the + groupc.net + * Whitney Museum of American Art ARTPORT + artport.whitney.org + * Robert Hodgin + flight404.com + * William Ngan + metaphorical.net + * + * + * 1.0 Oct 10 2004 dragorn Completed first port + * + * + * Based, of course, on other hacks in: + * + * 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 +#include "hsv.h" + +/* 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 + +char *background = "black"; +char *foreground = "yellow"; +int drawDelay = 30000; +int numDiscs = 85; +int maxRiders = 40; +int maxRadius = 100; +int colors = 256; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&drawDelay, "drawDelay", NULL, "30000", t_Int}, + {&numDiscs, "numDiscs", NULL, "85", t_Int}, + {&maxRiders, "maxRiders", NULL, "40", t_Int}, + {&maxRadius, "maxRadius", NULL, "100", t_Int}, + {&colors, "colors", NULL, "256", t_Int}, +}; + +/* Pixel rider */ +typedef struct { + float t; + float vt; + float mycharge; +} PxRider; + +/* disc of light */ +typedef struct { + /* index identifier */ + int id; + /* position */ + float x, y; + /* radius */ + float r, dr; + /* velocity */ + float vx, vy; + + /* pixel riders */ + int numr; + PxRider *pxRiders; +} Disc; + +struct field { + unsigned int height; + unsigned int width; + + int initial_discs; + Disc *discs; + + unsigned int num; + + unsigned int maxrider; + unsigned int maxradius; + + /* color parms */ + unsigned long fgcolor; + unsigned long bgcolor; + int visdepth; + + unsigned int cycles; + + /* Offscreen image we draw to */ + Pixmap off_map; + unsigned char *off_alpha; +}; + + +struct state { + Display *dpy; + Window window; + + struct field *f; + GC fgc, copygc; + XWindowAttributes xgwa; + int draw_delay; + + XColor *colors; + int ncolors; +}; + + +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(void) +{ + struct field *f = xrealloc(NULL, sizeof(struct field)); + f->height = 0; + f->width = 0; + f->initial_discs = 0; + f->discs = NULL; + f->num = 0; + f->maxrider = 0; + f->maxradius = 0; + f->cycles = 0; + f->fgcolor = 0; + f->bgcolor = 0; + f->off_alpha = NULL; + f->visdepth = 0; + return f; +} + +/* Quick-ref to pixels in the alpha map */ +#define ref_pixel(f, x, y) ((f)->off_alpha[(y) * (f)->width + (x)]) + +static inline void make_disc(struct field *f, float x, float y, float vx, float vy, float r) +{ + /* Synthesis of Disc::Disc and PxRider::PxRider */ + Disc *nd; + int ix; + + /* allocate a new disc */ + f->discs = (Disc *) xrealloc(f->discs, sizeof(Disc) * (f->num + 1)); + + nd = &(f->discs[f->num]); + + nd->id = f->num++; + nd->x = x; + nd->y = y; + nd->vx = vx; + nd->vy = vy; + nd->dr = r; + nd->r = frand(r) / 3; + + nd->numr = (frand(r) / 2.62); + if (nd->numr > f->maxrider) + nd->numr = f->maxrider; + + nd->pxRiders = NULL; + nd->pxRiders = (PxRider *) xrealloc(nd->pxRiders, sizeof(PxRider) * (f->maxrider)); + for (ix = 0; ix < f->maxrider; ix++) { + nd->pxRiders[ix].vt = 0.0; + nd->pxRiders[ix].t = frand(M_PI * 2); + nd->pxRiders[ix].mycharge = 0; + } +} + + +/* alpha blended point drawing */ +static inline unsigned long +trans_point(struct state *st, + int x1, int y1, unsigned char myc, float a, struct field *f) +{ + if ((x1 >= 0) && (x1 < f->width) && (y1 >= 0) && (y1 < f->height)) { + if (a >= 1.0) { + ref_pixel(f, x1, y1) = myc; + } else { + unsigned long c = ref_pixel(f, x1, y1); + c = c + (myc - c) * a; + ref_pixel(f, x1, y1) = c; + return c; + } + } + + return 0; +} + +static inline unsigned long +get_pixel (struct state *st, unsigned char v) +{ + return st->colors [v * (st->ncolors-1) / 255].pixel; +} + + +static inline void move_disc(struct field *f, int dnum) +{ + Disc *d = &(f->discs[dnum]); + + /* add velocity to position */ + d->x += d->vx; + d->y += d->vy; + + /* bound check */ + if (d->x + d->r < 0) + d->x += f->width + d->r + d->r; + if (d->x - d->r > f->width) + d->x -= f->width + d->r + d->r; + if (d->y + d->r < 0) + d->y += f->height + d->r + d->r; + if (d->y - d->r > f->height) + d->y -= f->height + d->r + d->r; + + /* increase to destination radius */ + if (d->r < d->dr) + d->r += 0.1; +} + +static inline void +draw_glowpoint(struct state *st, Drawable drawable, + GC fgc, struct field *f, float px, float py) +{ + int i, j; + float a; + unsigned long c; + + for (i = -2; i < 3; i++) { + for (j = -2; j < 3; j++) { + a = 0.8 - i * i * 0.1 - j * j * 0.1; + + c = trans_point(st, px+i, py+j, 255, a, f); + XSetForeground(st->dpy, fgc, get_pixel (st, c)); + XDrawPoint(st->dpy, drawable, fgc, px + i, py + j); + XSetForeground(st->dpy, fgc, f->fgcolor); + } + } +} + +static inline void +moverender_rider(struct state *st, Drawable drawable, + GC fgc, struct field *f, PxRider *rid, + float x, float y, float r) +{ + float px, py; + unsigned long int c; + double cv; + + /* add velocity to theta */ + rid->t = fmod((rid->t + rid->vt + M_PI), (2 * M_PI)) - M_PI; + + rid->vt += frand(0.002) - 0.001; + + /* apply friction brakes */ + if (abs(rid->vt) > 0.02) + rid->vt *= 0.9; + + /* draw */ + px = x + r * cos(rid->t); + py = y + r * sin(rid->t); + + if ((px < 0) || (px >= f->width) || (py < 0) || (py >= f->height)) + return; + + /* max brightness seems to be 0.003845 */ + + c = ref_pixel(f, (int) px, (int) py); + cv = c / 255.0; + + /* guestimated - 40 is 18% of 255, so scale this to 0.0 to 0.003845 */ + if (cv > 0.0006921) { + draw_glowpoint(st, drawable, fgc, f, px, py); + + rid->mycharge = 0.003845; + } else { + rid->mycharge *= 0.98; + + c = 255 * rid->mycharge; + + trans_point(st, px, py, c, 0.5, f); + + XSetForeground(st->dpy, fgc, get_pixel(st, c)); + XDrawPoint(st->dpy, drawable, fgc, px, py); + XSetForeground(st->dpy, fgc, f->fgcolor); + } +} + +static inline void +render_disc(struct state *st, Drawable drawable, GC fgc, struct field *f, int dnum) +{ + Disc *di = &(f->discs[dnum]); + int n, m; + float dx, dy, d; + float a, p2x, p2y, h, p3ax, p3ay, p3bx, p3by; + unsigned long c; + + /* Find intersecting points with all ascending discs */ + for (n = di->id + 1; n < f->num; n++) { + dx = f->discs[n].x - di->x; + dy = f->discs[n].y - di->y; + d = sqrt(dx * dx + dy * dy); + + /* intersection test */ + if (d < (f->discs[n].r + di->r)) { + /* complete containment test */ + if (d > abs(f->discs[n].r - di->r)) { + /* find solutions */ + a = (di->r * di->r - f->discs[n].r * f->discs[n].r + d * d) / (2 * d); + p2x = di->x + a * (f->discs[n].x - di->x) / d; + p2y = di->y + a * (f->discs[n].y - di->y) / d; + + h = sqrt(di->r * di->r - a * a); + + p3ax = p2x + h * (f->discs[n].y - di->y) / d; + p3ay = p2y - h * (f->discs[n].x - di->x) / d; + + p3bx = p2x - h * (f->discs[n].y - di->y) / d; + p3by = p2y + h * (f->discs[n].x - di->x) / d; + + /* bounds check */ + if ((p3ax < 0) || (p3ax >= f->width) || (p3ay < 0) || (p3ay >= f->height) || + (p3bx < 0) || (p3bx >= f->width) || (p3by < 0) || (p3by >= f->height)) + continue; + + /* p3a and p3b might be identical, ignore this case for now */ + /* XPutPixel(f->off_map, p3ax, p3ay, f->fgcolor); */ + c = trans_point(st, p3ax, p3ay, 255, 0.75, f); + XSetForeground(st->dpy, fgc, get_pixel (st, c)); + XDrawPoint(st->dpy, drawable, fgc, p3ax, p3ay); + + /* XPutPixel(f->off_map, p3bx, p3by, f->fgcolor); */ + c = trans_point(st, p3bx, p3by, 255, 0.75, f); + XSetForeground(st->dpy, fgc, get_pixel (st, c)); + XDrawPoint(st->dpy, drawable, fgc, p3bx, p3by); + XSetForeground(st->dpy, fgc, f->fgcolor); + } + } + + } + + /* Render all the pixel riders */ + for (m = 0; m < di->numr; m++) { + moverender_rider(st, drawable, fgc, f, &(di->pxRiders[m]), + di->x, di->y, di->r); + } +} + +static void build_img(Display *dpy, Window window, struct field *f) +{ + if (f->off_alpha) { + free(f->off_alpha); + f->off_alpha = NULL; + + /* Assume theres also an off pixmap */ + if (f->off_map != window) + XFreePixmap(dpy, f->off_map); + } + + f->off_alpha = (unsigned char *) + xrealloc(f->off_alpha, sizeof(unsigned char) * f->width * f->height); + + memset(f->off_alpha, 0, sizeof(unsigned char) * f->width * f->height); + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + f->off_map = window; +# else + f->off_map = XCreatePixmap(dpy, window, f->width, f->height, f->visdepth); +# endif + +} + +static inline void blank_img(Display *dpy, Window window, XWindowAttributes xgwa, GC fgc, struct field *f) +{ + memset(f->off_alpha, 0, sizeof(unsigned char) * f->width * f->height); + + XSetForeground(dpy, fgc, f->bgcolor); + XFillRectangle(dpy, window, fgc, 0, 0, xgwa.width, xgwa.height); + XSetForeground(dpy, fgc, f->fgcolor); +} + + +static void * +intermomentary_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + +#ifdef TIME_ME + time_t start_time = time(NULL); +#endif + + int tempx; + XGCValues gcv; + + st->dpy = dpy; + st->window = window; + + XGetWindowAttributes(dpy, window, &st->xgwa); + + //st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors = colors; + st->ncolors++; + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + +#if 1 + gcv.foreground = load_color(dpy, st->xgwa.colormap, foreground); + gcv.background = load_color(dpy, st->xgwa.colormap, background); +#else + gcv.foreground = get_pixel_resource(dpy, st->xgwa.colormap, + "foreground", "Foreground"); + gcv.background = get_pixel_resource(dpy, st->xgwa.colormap, + "background", "Background"); +#endif + + { + XColor fgc, bgc; + int fgh, bgh; + double fgs, fgv, bgs, bgv; + fgc.pixel = gcv.foreground; + bgc.pixel = gcv.background; + XQueryColor (st->dpy, st->xgwa.colormap, &fgc); + XQueryColor (st->dpy, st->xgwa.colormap, &bgc); + rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv); + rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv); +#if 0 + bgh = fgh; + bgs = fgs; + bgv = fgv / 10.0; +#endif + make_color_ramp (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + bgh, bgs, bgv, + fgh, fgs, fgv, + st->colors, &st->ncolors, + False, /* closed */ + True, False); + } + + st->f = init_field(); + + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + +#if 1 + st->draw_delay = drawDelay; + st->f->maxrider = maxRiders; + st->f->maxradius = maxRadius; + st->f->initial_discs = numDiscs; +#else + st->draw_delay = (get_integer_resource(dpy, "drawDelay", "Integer")); + st->f->maxrider = (get_integer_resource(dpy, "maxRiders", "Integer")); + st->f->maxradius = (get_integer_resource(dpy, "maxRadius", "Integer")); + st->f->initial_discs = (get_integer_resource(dpy, "numDiscs", "Integer")); +#endif + + if (st->f->initial_discs <= 10) { + fprintf(stderr, "%s: Initial discs must be greater than 10\n", progname); + exit (1); + } + + if (st->f->maxradius <= 30) { + fprintf(stderr, "%s: Max radius must be greater than 30\n", progname); + exit (1); + } + + if (st->f->maxrider <= 10) { + fprintf(stderr, "%s: Max riders must be greater than 10\n", progname); + exit (1); + } + + st->fgc = XCreateGC(dpy, window, GCForeground, &gcv); + st->copygc = XCreateGC(dpy, window, GCForeground, &gcv); + + st->f->fgcolor = gcv.foreground; + st->f->bgcolor = gcv.background; + + /* Initialize stuff */ + build_img(dpy, window, st->f); + + for (tempx = 0; tempx < st->f->initial_discs; tempx++) { + float fx, fy, x, y, r; + int bt; + + /* Arrange in anti-collapsing circle */ + fx = 0.4 * st->f->width * cos((2 * M_PI) * tempx / st->f->initial_discs); + fy = 0.4 * st->f->height * sin((2 * M_PI) * tempx / st->f->initial_discs); + x = frand(st->f->width / 2) + fx; + y = frand(st->f->height / 2) + fy; + r = 5 + frand(st->f->maxradius); + bt = 1; + + if ((random() % 100) < 50) + bt = -1; + + make_disc(st->f, x, y, bt * fx / 1000.0, bt * fy / 1000.0, r); + + } + + return st; +} + +static unsigned long +intermomentary_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int tempx; + + if ((st->f->cycles % 10) == 0) { + /* Restart if the window size changes */ + XGetWindowAttributes(dpy, window, &st->xgwa); + + if (st->f->height != st->xgwa.height || st->f->width != st->xgwa.width) { + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + + build_img(dpy, window, st->f); + } + } + + blank_img(dpy, st->f->off_map, st->xgwa, st->fgc, st->f); + for (tempx = 0; tempx < st->f->num; tempx++) { + move_disc(st->f, tempx); + render_disc(st, st->f->off_map, st->fgc, st->f, tempx); + } + +#if 0 + XSetFillStyle(dpy, st->copygc, FillTiled); + XSetTile(dpy, st->copygc, st->f->off_map); + XFillRectangle(dpy, window, st->copygc, 0, 0, st->f->width, st->f->height); +#else + if (st->f->off_map != window) + XCopyArea (dpy, st->f->off_map, window, st->copygc, 0, 0, + st->f->width, st->f->height, 0, 0); + +#endif + + st->f->cycles++; + + return st->draw_delay; +} + + +static void +intermomentary_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + intermomentary_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +intermomentary_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *intermomentary_defaults[] = { + ".background: black", + ".foreground: yellow", + "*drawDelay: 30000", + "*numDiscs: 85", + "*maxRiders: 40", + "*maxRadius: 100", + "*colors: 256", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec intermomentary_options[] = { + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-draw-delay", ".drawDelay", XrmoptionSepArg, 0}, + {"-num-discs", ".numDiscs", XrmoptionSepArg, 0}, + {"-max-riders", ".maxRiders", XrmoptionSepArg, 0}, + {"-max-radius", ".maxRadius", XrmoptionSepArg, 0}, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + {0, 0, 0, 0} +}; + + +XSCREENSAVER_MODULE ("Intermomentary", intermomentary) diff --git a/non-wgl/intermomentary.vcproj b/non-wgl/intermomentary.vcproj new file mode 100644 index 0000000..5556674 --- /dev/null +++ b/non-wgl/intermomentary.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/juggle.c b/non-wgl/juggle.c new file mode 100644 index 0000000..eef0732 --- /dev/null +++ b/non-wgl/juggle.c @@ -0,0 +1,2830 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* juggle */ + +#if !defined( lint ) && !defined( SABER ) +static const char sccsid[] = "@(#)juggle.c 5.10 2003/09/02 xlockmore"; + +#endif + +/*- + * Copyright (c) 1996 by Tim Auckland + * + * 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 + * 13-Dec-2004: [TDA] Use -cycles and -count in a rational manner. + * Add -rings, -bballs. Add -describe. Finally made + * live pattern updates possible. Add refill_juggle(), + * change_juggle() and reshape_juggle(). Make + * init_juggle() non-destructive. Reorder erase/draw + * operations. Update xscreensaver xml and manpage. + * 15-Nov-2004: [TDA] Fix all memory leaks. + * 12-Nov-2004: [TDA] Add -torches and another new trail + * implementation, so that different objects can have + * different length trails. + * 11-Nov-2004: [TDA] Clap when all the balls are in the air. + * 10-Nov-2004: [TDA] Display pattern name converted to hight + * notation. + * 31-Oct-2004: [TDA] Add -clubs and new trail implementation. + * 02-Sep-2003: Non-real time to see what is happening without a + * strobe effect for slow machines. + * 01-Nov-2000: Allocation checks + * 1996: Written + */ + +/*- + * TODO + * Implement the anonymously promised -uni option. + */ + + +/* + * Notes on Adam Chalcraft Juggling Notation (used by permission) + * a-> Adam's notation s-> Site swap (Cambridge) notation + * + * To define a map from a-notation to s-notation ("site-swap"), both + * of which look like doubly infinite sequences of natural numbers. In + * s-notation, there is a restriction on what is allowed, namely for + * the sequence s_n, the associated function f(n)=n+s_n must be a + * bijection. In a-notation, there is no restriction. + * + * To go from a-notation to s-notation, you start by mapping each a_n + * to a permutation of N, the natural numbers. + * + * 0 -> the identity + * 1 -> (10) [i.e. f(1)=0, f(0)=1] + * 2 -> (210) [i.e. f(2)=1, f(1)=0, f(0)=2] + * 3 -> (3210) [i.e. f(3)=2, f(2)=1, f(1)=0, f(0)=3] + * etc. + * + * Then for each n, you look at how long 0 takes to get back to 0 + * again and you call this t_n. If a_n=0, for example, then since the + * identity leaves 0 alone, it gets back to 0 in 1 step, so t_n=1. If + * a_n=1, then f(0)=1. Now any further a_n=0 leave 1 alone, but the + * next a_n>0 sends 1 back to 0. Hence t_n is 2 + the number of 0's + * following the 1. Finally, set s_n = t_n - 1. + * + * To give some examples, it helps to have a notation for cyclic + * sequences. By (123), for example, I mean ...123123123123... . Now + * under the a-notation -> s-notation mapping we have some familiar + * examples: + * + * (0)->(0), (1)->(1), (2)->(2) etc. + * (21)->(31), (31)->(51), (41)->(71) etc. + * (10)->(20), (20)->(40), (30)->(60) etc. + * (331)->(441), (312)->(612), (303)->(504), (321)->(531) + * (43)->(53), (434)->(534), (433)->(633) + * (552)->(672) + * + * In general, the number of balls is the *average* of the s-notation, + * and the *maximum* of the a-notation. Another theorem is that the + * minimum values in the a-notation and the s-notation and equal, and + * preserved in the same positions. + * + * The usefulness of a-notation is the fact that there are no + * restrictions on what is allowed. This makes random juggle + * generation much easier. It also makes enumeration very + * easy. Another handy feature is computing changes. Suppose you can + * do (5) and want a neat change up to (771) in s-notation [Mike Day + * actually needed this example!]. Write them both in a-notation, + * which gives (5) and (551). Now concatenate them (in general, there + * may be more than one way to do this, but not in this example), to + * get + * + * ...55555555551551551551551... + * + * Now convert back to s-notation, to get + * + * ...55555566771771771771771... + * + * So the answer is to do two 6 throws and then go straight into + * (771). Coming back down of course, + * + * ...5515515515515515555555555... + * + * converts to + * + * ...7717717717716615555555555... + * + * so the answer is to do a single 661 and then drop straight down to + * (5). + * + * [The number of balls in the generated pattern occasionally changes. + * In order to decrease the number of balls I had to introduce a new + * symbol into the Adam notation, [*] which means 'lose the current + * ball'.] + */ + +/* This code uses so many linked lists it's worth having a built-in + * leak-checker */ +#undef MEMTEST + +#define STANDALONE + +# define MODE_juggle +#define DELAY 10000 +#define COUNT 200 +#define CYCLES 1000 +#define NCOLORS 32 +# define DEFAULTS "*delay: 10000 \n" \ + "*count: 200 \n" \ + "*cycles: 1000 \n" \ + "*ncolors: 32 \n" \ + "*font: -*-helvetica-bold-r-normal-*-180-*\n" \ + "*fpsSolid: true\n" \ + +# define refresh_juggle 0 +# define juggle_handle_event 0 +# undef SMOOTH_COLORS + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_juggle + +#if 0 +#define XClearWindow(d, w) \ +{ \ + XSetForeground(d, MI_GC(mi), MI_PIXEL(mi, 3)); \ + XFillRectangle(d, w, MI_GC(mi), \ + 0, 0, (unsigned int) MI_WIDTH(mi), (unsigned int) MI_HEIGHT(mi)); \ +} +#endif + +#define DEF_PATTERN "random" /* All patterns */ +#define DEF_TAIL "1" /* No trace */ +#ifdef UNI +/* Maybe a ROLA BOLA would be at a better angle for viewing */ +#define DEF_UNI "False" /* No unicycle */ /* Not implemented yet */ +#endif +#define DEF_REAL "True" +#define DEF_DESCRIBE "True" + +#define DEF_BALLS "True" /* Use Balls */ +#define DEF_CLUBS "True" /* Use Clubs */ +#define DEF_TORCHES "True" /* Use Torches */ +#define DEF_KNIVES "True" /* Use Knives */ +#define DEF_RINGS "True" /* Use Rings */ +#define DEF_BBALLS "True" /* Use Bowling Balls */ + +#ifndef XtNumber +#define XtNumber(arr) ((unsigned int) (sizeof(arr) / sizeof(arr[0]))) +#endif + +static char *pattern; +static int tail; +#ifdef UNI +static Bool uni; +#endif +static Bool real; +static Bool describe; +static Bool balls; +static Bool clubs; +static Bool torches; +static Bool knives; +static Bool rings; +static Bool bballs; +static char *only; + +static XrmOptionDescRec opts[] = +{ + {"-pattern", ".juggle.pattern", XrmoptionSepArg, NULL }, + {"-tail", ".juggle.tail", XrmoptionSepArg, NULL }, +#ifdef UNI + {"-uni", ".juggle.uni", XrmoptionNoArg, "on" }, + {"+uni", ".juggle.uni", XrmoptionNoArg, "off" }, +#endif + {"-real", ".juggle.real", XrmoptionNoArg, "on" }, + {"+real", ".juggle.real", XrmoptionNoArg, "off" }, + {"-describe", ".juggle.describe", XrmoptionNoArg, "on" }, + {"+describe", ".juggle.describe", XrmoptionNoArg, "off" }, + {"-balls", ".juggle.balls", XrmoptionNoArg, "on" }, + {"+balls", ".juggle.balls", XrmoptionNoArg, "off" }, + {"-clubs", ".juggle.clubs", XrmoptionNoArg, "on" }, + {"+clubs", ".juggle.clubs", XrmoptionNoArg, "off" }, + {"-torches", ".juggle.torches", XrmoptionNoArg, "on" }, + {"+torches", ".juggle.torches", XrmoptionNoArg, "off" }, + {"-knives", ".juggle.knives", XrmoptionNoArg, "on" }, + {"+knives", ".juggle.knives", XrmoptionNoArg, "off" }, + {"-rings", ".juggle.rings", XrmoptionNoArg, "on" }, + {"+rings", ".juggle.rings", XrmoptionNoArg, "off" }, + {"-bballs", ".juggle.bballs", XrmoptionNoArg, "on" }, + {"+bballs", ".juggle.bballs", XrmoptionNoArg, "off" }, + {"-only", ".juggle.only", XrmoptionSepArg, NULL }, +}; +static argtype vars[] = +{ + { &pattern, "pattern", "Pattern", DEF_PATTERN, t_String }, + { &tail, "tail", "Tail", DEF_TAIL, t_Int }, +#ifdef UNI + { &uni, "uni", "Uni", DEF_UNI, t_Bool }, +#endif + { &real, "real", "Real", DEF_REAL, t_Bool }, + { &describe, "describe", "Describe", DEF_DESCRIBE, t_Bool }, + { &balls, "balls", "Clubs", DEF_BALLS, t_Bool }, + { &clubs, "clubs", "Clubs", DEF_CLUBS, t_Bool }, + { &torches, "torches", "Torches", DEF_TORCHES, t_Bool }, + { &knives, "knives", "Knives", DEF_KNIVES, t_Bool }, + { &rings, "rings", "Rings", DEF_RINGS, t_Bool }, + { &bballs, "bballs", "BBalls", DEF_BBALLS, t_Bool }, + { &only, "only", "BBalls", " ", t_String }, +}; +static OptionStruct desc[] = +{ + { "-pattern string", "Cambridge Juggling Pattern" }, + { "-tail num", "Trace Juggling Patterns" }, +#ifdef UNI + { "-/+uni", "Unicycle" }, +#endif + { "-/+real", "Real-time" }, + { "-/+describe", "turn on/off pattern descriptions." }, + { "-/+balls", "turn on/off Balls." }, + { "-/+clubs", "turn on/off Clubs." }, + { "-/+torches", "turn on/off Flaming Torches." }, + { "-/+knives", "turn on/off Knives." }, + { "-/+rings", "turn on/off Rings." }, + { "-/+bballs", "turn on/off Bowling Balls." }, + { "-only", "Turn off all objects but the named one." }, +}; + +ENTRYPOINT ModeSpecOpt juggle_opts = + { XtNumber(opts), opts, XtNumber(vars), vars, desc }; + +#ifdef USE_MODULES +ModStruct juggle_description = { + "juggle", "init_juggle", "draw_juggle", "release_juggle", + "draw_juggle", "change_juggle", (char *) NULL, &juggle_opts, + 10000, 200, 1000, 1, 64, 1.0, "", + "Shows a Juggler, juggling", 0, NULL +}; + +#endif + +#ifdef USE_XVMSUTILS +# include +#endif + +/* Note: All "lengths" are scaled by sp->scale = MI_HEIGHT/480. All + "thicknesses" are scaled by sqrt(sp->scale) so that they are + proportionally thicker for smaller windows. Objects spinning out + of the plane (such as clubs) fake perspective by compressing their + horizontal coordinates by PERSPEC */ + +/* Figure */ +#define ARMLENGTH 50 +#define ARMWIDTH ((int) (8.0 * sqrt(sp->scale))) +#define POSE 10 +#define BALLRADIUS ARMWIDTH + +#define PERSPEC 0.4 + +/* macros */ +#define GRAVITY(h, t) 4*(double)(h)/((t)*(t)) + +/* Timing based on count. Units are milliseconds. Juggles per second + is: 2000 / THROW_CATCH_INTERVAL + CATCH_THROW_INTERVAL */ + +#define THROW_CATCH_INTERVAL (sp->count) +#define THROW_NULL_INTERVAL (sp->count * 0.5) +#define CATCH_THROW_INTERVAL (sp->count * 0.2) + +/******************************************************************** + * Trace Definitions * + * * + * These record rendering data so that a drawn object can be erased * + * later. Each object has its own Trace list. * + * * + ********************************************************************/ + +typedef struct {double x, y; } DXPoint; +typedef struct trace *TracePtr; +typedef struct trace { + TracePtr next, prev; + double x, y; + double angle; + int divisions; + DXPoint dlast; +#ifdef MEMTEST + char pad[1024]; +#endif +} Trace; + +/******************************************************************* + * Object Definitions * + * * + * These describe the various types of Object that can be juggled * + * * + *******************************************************************/ +typedef void (DrawProc)(ModeInfo*, unsigned long, Trace *); + +static DrawProc show_ball, show_europeanclub, show_torch, show_knife; +static DrawProc show_ring, show_bball; + +typedef enum {BALL, CLUB, TORCH, KNIFE, RING, BBALLS, + NUM_OBJECT_TYPES} ObjType; +#define OBJMIXPROB 20 /* inverse of the chances of using an odd + object in the pattern */ + +static const struct { + DrawProc *draw; /* Object Rendering function */ + int handle; /* Length of object's handle */ + int mintrail; /* Minimum trail length */ + double cor; /* Coefficient of Restitution. perfect bounce = 1 */ + double weight; /* Heavier objects don't get thrown as high */ +} ObjectDefs[] = { + { /* Ball */ + show_ball, + 0, + 1, + 0.9, + 1.0, + }, + { /* Club */ + show_europeanclub, + 15, + 1, + 0.55, /* Clubs don't bounce too well */ + 1.0, + }, + { /* Torch */ + show_torch, + 15, + 20, /* Torches need flames */ + 0, /* Torches don't bounce -- fire risk! */ + 1.0, + }, + { /* Knife */ + show_knife, + 15, + 1, + 0, /* Knives don't bounce */ + 1.0, + }, + { /* Ring */ + show_ring, + 15, + 1, + 0.8, + 1.0, + }, + { /* Bowling Ball */ + show_bball, + 0, + 1, + 0.2, + 5.0, + }, +}; + +/************************** + * Trajectory definitions * + **************************/ + +typedef enum {HEIGHT, ADAM} Notation; +typedef enum {Empty, Full, Ball} Throwable; +typedef enum {LEFT, RIGHT} Hand; +typedef enum {THROW, CATCH} Action; +typedef enum {HAND, ELBOW, SHOULDER} Joint; +typedef enum {ATCH, THRATCH, ACTION, LINKEDACTION, + PTHRATCH, BPREDICTOR, PREDICTOR} TrajectoryStatus; +typedef struct {double a, b, c, d; } Spline; +typedef DXPoint Arm[3]; + +/* A Wander contains a Spline and a time interval. A list of Wanders + * describes the performer's position as he moves around the screen. */ +typedef struct wander *WanderPtr; +typedef struct wander { + WanderPtr next, prev; + double x; + unsigned long finish; + Spline s; +#ifdef MEMTEST + char pad[1024]; +#endif +} Wander; + +/* Object is an arbitrary object being juggled. Each Trajectory + * references an Object ("count" tracks this), and each Object is also + * linked into a global Objects list. Objects may include a Trace + * list for tracking erasures. */ +typedef struct object *ObjectPtr; +typedef struct object { + ObjectPtr next, prev; + + ObjType type; + int color; + int count; /* reference count */ + Bool active; /* Object is in use */ + + Trace *trace; + int tracelen; + int tail; +#ifdef MEMTEST + char pad[1024]; +#endif +} Object; + +/* Trajectory is a segment of juggling action. A list of Trajectories + * defines the juggling performance. The Trajectory list goes through + * multiple processing steps to convert it from basic juggling + * notation into rendering data. */ + +typedef struct trajectory *TrajectoryPtr; +typedef struct trajectory { + TrajectoryPtr prev, next; /* for building list */ + TrajectoryStatus status; + + /* Throw */ + char posn; + int height; + int adam; + char *pattern; + char *name; + + /* Action */ + Hand hand; + Action action; + + /* LinkedAction */ + int color; + Object *object; + int divisions; + double angle, spin; + TrajectoryPtr balllink; + TrajectoryPtr handlink; + + /* PThratch */ + double cx; /* Moving juggler */ + double x, y; /* current position */ + double dx, dy; /* initial velocity */ + + /* Predictor */ + Throwable type; + unsigned long start, finish; + Spline xp, yp; + +#ifdef MEMTEST + char pad[1024]; +#endif +} Trajectory; + + +/******************* + * Pattern Library * + *******************/ + +typedef struct { + const char * pattern; + const char * name; +} patternstruct; + +/* List of popular patterns, in any order */ +/* Patterns should be given in Adam notation so the generator can + concatenate them safely. Null descriptions are ok. Height + notation will be displayed automatically. */ +/* Can't const this because it is qsorted. This *should* be reentrant, + I think... */ +static /*const*/ patternstruct portfolio[] = { + {"[+2 1]", /* +3 1 */ "Typical 2 ball juggler"}, + {"[2 0]", /* 4 0 */ "2 in 1 hand"}, + {"[2 0 1]", /* 5 0 1 */}, + {"[+2 0 +2 0 0]" /* +5 0 +5 0 0 */}, + {"[+2 0 1 2 2]", /* +4 0 1 2 3 */}, + {"[2 0 1 1]", /* 6 0 1 1 */}, + + {"[3]", /* 3 */ "3 cascade"}, + {"[+3]", /* +3 */ "reverse 3 cascade"}, + {"[=3]", /* =3 */ "cascade 3 under arm"}, + {"[&3]", /* &3 */ "cascade 3 catching under arm"}, + {"[_3]", /* _3 */ "bouncing 3 cascade"}, + {"[+3 x3 =3]", /* +3 x3 =3 */ "Mill's mess"}, + {"[3 2 1]", /* 5 3 1" */}, + {"[3 3 1]", /* 4 4 1" */}, + {"[3 1 2]", /* 6 1 2 */ "See-saw"}, + {"[=3 3 1 2]", /* =4 5 1 2 */}, + {"[=3 2 2 3 1 2]", /* =6 2 2 5 1 2 */ "=4 5 1 2 stretched"}, + {"[+3 3 1 3]", /* +4 4 1 3 */ "anemic shower box"}, + {"[3 3 1]", /* 4 4 1 */}, + {"[+3 2 3]", /* +4 2 3 */}, + {"[+3 1]", /* +5 1 */ "3 shower"}, + {"[_3 1]", /* _5 1 */ "bouncing 3 shower"}, + {"[3 0 3 0 3]", /* 5 0 5 0 5 */ "shake 3 out of 5"}, + {"[3 3 3 0 0]", /* 5 5 5 0 0 */ "flash 3 out of 5"}, + {"[3 3 0]", /* 4 5 0 */ "complete waste of a 5 ball juggler"}, + {"[3 3 3 0 0 0 0]", /* 7 7 7 0 0 0 0 */ "3 flash"}, + {"[+3 0 +3 0 +3 0 0]", /* +7 0 +7 0 +7 0 0 */}, + {"[3 2 2 0 3 2 0 2 3 0 2 2 0]", /* 7 3 3 0 7 3 0 3 7 0 3 3 0 */}, + {"[3 0 2 0]", /* 8 0 4 0 */}, + {"[_3 2 1]", /* _5 3 1 */}, + {"[_3 0 1]", /* _8 0 1 */}, + {"[1 _3 1 _3 0 1 _3 0]", /* 1 _7 1 _7 0 1 _7 0 */}, + {"[_3 2 1 _3 1 2 1]", /* _6 3 1 _6 1 3 1 */}, + + {"[4]", /* 4 */ "4 cascade"}, + {"[+4 3]", /* +5 3 */ "4 ball half shower"}, + {"[4 4 2]", /* 5 5 2 */}, + {"[+4 4 4 +4]", /* +4 4 4 +4 */ "4 columns"}, + {"[+4 3 +4]", /* +5 3 +4 */}, + {"[4 3 4 4]", /* 5 3 4 4 */}, + {"[4 3 3 4]", /* 6 3 3 4 */}, + {"[4 3 2 4", /* 6 4 2 4 */}, + {"[+4 1]", /* +7 1 */ "4 shower"}, + {"[4 4 4 4 0]", /* 5 5 5 5 0 */ "learning 5"}, + {"[+4 x4 =4]", /* +4 x4 =4 */ "Mill's mess for 4"}, + {"[+4 2 1 3]", /* +9 3 1 3 */}, + {"[4 4 1 4 1 4]", /* 6 6 1 5 1 5, by Allen Knutson */}, + {"[_4 _4 _4 1 _4 1]", /* _5 _6 _6 1 _5 1 */}, + {"[_4 3 3]", /* _6 3 3 */}, + {"[_4 3 1]", /* _7 4 1 */}, + {"[_4 2 1]", /* _8 3 1 */}, + {"[_4 3 3 3 0]", /* _8 4 4 4 0 */}, + {"[_4 1 3 1]", /* _9 1 5 1 */}, + {"[_4 1 3 1 2]", /* _10 1 6 1 2 */}, + + {"[5]", /* 5 */ "5 cascade"}, + {"[_5 _5 _5 _5 _5 5 5 5 5 5]", /* _5 _5 _5 _5 _5 5 5 5 5 5 */}, + {"[+5 x5 =5]", /* +5 x5 =5 */ "Mill's mess for 5"}, + {"[5 4 4]", /* 7 4 4 */}, + {"[_5 4 4]", /* _7 4 4 */}, + {"[1 2 3 4 5 5 5 5 5]", /* 1 2 3 4 5 6 7 8 9 */ "5 ramp"}, + {"[5 4 5 3 1]", /* 8 5 7 4 1, by Allen Knutson */}, + {"[_5 4 1 +4]", /* _9 5 1 5 */}, + {"[_5 4 +4 +4]", /* _8 4 +4 +4 */}, + {"[_5 4 4 4 1]", /* _9 5 5 5 1 */}, + {"[_5 4 4 5 1]",}, + {"[_5 4 4 +4 4 0]", /*_10 5 5 +5 5 0 */}, + + {"[6]", /* 6 */ "6 cascade"}, + {"[+6 5]", /* +7 5 */}, + {"[6 4]", /* 8 4 */}, + {"[+6 3]", /* +9 3 */}, + {"[6 5 4 4]", /* 9 7 4 4 */}, + {"[+6 5 5 5]", /* +9 5 5 5 */}, + {"[6 0 6]", /* 9 0 9 */}, + {"[_6 0 _6]", /* _9 0 _9 */}, + + {"[_7]", /* _7 */ "bouncing 7 cascade"}, + {"[7]", /* 7 */ "7 cascade"}, + {"[7 6 6 6 6]", /* 11 6 6 6 6 */ "Gatto's High Throw"}, + +}; + + + +typedef struct { int start; int number; } PatternIndex; + +struct patternindex { + int minballs; + int maxballs; + PatternIndex index[XtNumber(portfolio)]; +}; + + +/* Jugglestruct: per-screen global data. The master Wander, Object + * and Trajectory lists are anchored here. */ +typedef struct { + double scale; + Wander *wander; + double cx; + double Gr; + Trajectory *head; + Arm arm[2][2]; + char *pattern; + int count; + int num_balls; + time_t begintime; /* should make 'time' usable for at least 48 days + on a 32-bit machine */ + unsigned long time; /* millisecond timer*/ + ObjType objtypes; + Object *objects; + struct patternindex patternindex; + XFontStruct *mode_font; +} jugglestruct; + +static jugglestruct *juggles = (jugglestruct *) NULL; + +/******************* + * list management * + *******************/ + +#define DUP_OBJECT(n, t) { \ + (n)->object = (t)->object; \ + if((n)->object != NULL) (n)->object->count++; \ +} + +/* t must point to an existing element. t must not be an + expression ending ->next or ->prev */ +#define REMOVE(t) { \ + (t)->next->prev = (t)->prev; \ + (t)->prev->next = (t)->next; \ + free(t); \ +} + +/* t receives element to be created and added to the list. ot must + point to an existing element or be identical to t to start a new + list. Applicable to Trajectories, Objects and Traces. */ +#define ADD_ELEMENT(type, t, ot) \ + if (((t) = (type*)calloc(1,sizeof(type))) != NULL) { \ + (t)->next = (ot)->next; \ + (t)->prev = (ot); \ + (ot)->next = (t); \ + (t)->next->prev = (t); \ + } + +static void +object_destroy(Object* o) +{ + if(o->trace != NULL) { + while(o->trace->next != o->trace) { + Trace *s = o->trace->next; + REMOVE(s); /* Don't eliminate 's' */ + } + free(o->trace); + } + REMOVE(o); +} + +static void +trajectory_destroy(Trajectory *t) { + if(t->name != NULL) free(t->name); + if(t->pattern != NULL) free(t->pattern); + /* Reduce object link count and call destructor if necessary */ + if(t->object != NULL && --t->object->count < 1 && t->object->tracelen == 0) { + object_destroy(t->object); + } + REMOVE(t); /* Unlink and free */ +} + +static void +free_juggle(jugglestruct *sp) { + if (sp->head != NULL) { + while (sp->head->next != sp->head) { + trajectory_destroy(sp->head->next); + } + free(sp->head); + sp->head = (Trajectory *) NULL; + } + if(sp->objects != NULL) { + while (sp->objects->next != sp->objects) { + object_destroy(sp->objects->next); + } + free(sp->objects); + sp->objects = (Object*)NULL; + } + if(sp->wander != NULL) { + while (sp->wander->next != sp->wander) { + Wander *w = sp->wander->next; + REMOVE(w); + } + free(sp->wander); + sp->wander = (Wander*)NULL; + } + if(sp->pattern != NULL) { + free(sp->pattern); + sp->pattern = NULL; + } + if (sp->mode_font!=None) { + XFreeFontInfo(NULL,sp->mode_font,1); + sp->mode_font = None; + } +} + +static Bool +add_throw(jugglestruct *sp, char type, int h, Notation n, const char* name) +{ + Trajectory *t; + + ADD_ELEMENT(Trajectory, t, sp->head->prev); + if(t == NULL){ /* Out of Memory */ + free_juggle(sp); + return False; + } + t->object = NULL; + if(name != NULL) + t->name = strdup(name); + t->posn = type; + if (n == ADAM) { + t->adam = h; + t->height = 0; + t->status = ATCH; + } else { + t->height = h; + t->status = THRATCH; + } + return True; +} + +/* add a Thratch to the performance */ +static Bool +program(ModeInfo *mi, const char *patn, const char *name, int cycles) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + const char *p; + int w, h, i, seen; + Notation notation; + char type; + + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "juggle[%d]: Programmed: %s x %d\n", + MI_SCREEN(mi), (name == NULL) ? patn : name, cycles); + } + + for(w=i=0; i < cycles; i++, w++) { /* repeat until at least "cycles" throws + have been programmed */ + /* title is the pattern name to be supplied to the first throw of + a sequence. If no name if given, use an empty title so that + the sequences are still delimited. */ + const char *title = (name != NULL)? name : ""; + type=' '; + h = 0; + seen = 0; + notation = HEIGHT; + for(p=patn; *p; p++) { + if (*p >= '0' && *p <='9') { + seen = 1; + h = 10*h + (*p - '0'); + } else { + Notation nn = notation; + switch (*p) { + case '[': /* begin Adam notation */ + notation = ADAM; + break; + case '-': /* Inside throw */ + type = ' '; + break; + case '+': /* Outside throw */ + case '=': /* Cross throw */ + case '&': /* Cross catch */ + case 'x': /* Cross throw and catch */ + case '_': /* Bounce */ + case 'k': /* Kickup */ + type = *p; + break; + case '*': /* Lose ball */ + seen = 1; + h = -1; + /* fall through */ + case ']': /* end Adam notation */ + nn = HEIGHT; + /* fall through */ + case ' ': + if (seen) { + i++; + if (!add_throw(sp, type, h, notation, title)) + return False; + title = NULL; + type=' '; + h = 0; + seen = 0; + } + notation = nn; + break; + default: + if(w == 0) { /* Only warn on first pass */ + (void) fprintf(stderr, + "juggle[%d]: Unexpected pattern instruction: '%c'\n", + MI_SCREEN(mi), *p); + } + break; + } + } + } + if (seen) { /* end of sequence */ + if (!add_throw(sp, type, h, notation, title)) + return False; + title = NULL; + } + } + return True; +} + +/* + ~~~~\~~~~~\~~~ + \\~\\~\~\\\~~~ + \\~\\\\~\\\~\~ + \\\\\\\\\\\~\\ + +[ 3 3 1 3 4 2 3 1 3 3 4 0 2 1 ] + +4 4 1 3 12 2 4 1 4 4 13 0 3 1 + +*/ +#define BOUNCEOVER 10 +#define KICKMIN 7 +#define THROWMAX 20 + +/* Convert Adam notation into heights */ +static void +adam(jugglestruct *sp) +{ + Trajectory *t, *p; + for(t = sp->head->next; t != sp->head; t = t->next) { + if (t->status == ATCH) { + int a = t->adam; + t->height = 0; + for(p = t->next; a > 0; p = p->next) { + if(p == sp->head) { + t->height = -9; /* Indicate end of processing for name() */ + return; + } + if (p->status != ATCH || p->adam < 0 || p->adam>= a) { + a--; + } + t->height++; + } + if(t->height > BOUNCEOVER && t->posn == ' '){ + t->posn = '_'; /* high defaults can be bounced */ + } else if(t->height < 3 && t->posn == '_') { + t->posn = ' '; /* Can't bounce short throws. */ + } + if(t->height < KICKMIN && t->posn == 'k'){ + t->posn = ' '; /* Can't kick short throws */ + } + if(t->height > THROWMAX){ + t->posn = 'k'; /* Use kicks for ridiculously high throws */ + } + t->status = THRATCH; + } + } +} + +/* Discover converted heights and update the sequence title */ +static void +name(jugglestruct *sp) +{ + Trajectory *t, *p; + char buffer[BUFSIZ]; + char *b; + for(t = sp->head->next; t != sp->head; t = t->next) { + if (t->status == THRATCH && t->name != NULL) { + b = buffer; + for(p = t; p == t || p->name == NULL; p = p->next) { + if(p == sp->head || p->height < 0) { /* end of reliable data */ + return; + } + if(p->posn == ' ') { + b += sprintf(b, " %d", p->height); + } else { + b += sprintf(b, " %c%d", p->posn, p->height); + } + if(b - buffer > 500) break; /* otherwise this could eventually + overflow. It'll be too big to + display anyway. */ + } + if(*t->name != 0) { + (void) sprintf(b, ", %s", t->name); + } + free(t->name); /* Don't need name any more, it's been converted + to pattern */ + t->name = NULL; + if(t->pattern != NULL) free(t->pattern); + t->pattern = strdup(buffer); + } + } +} + +/* Split Thratch notation into explicit throws and catches. + Usually Catch follows Throw in same hand, but take care of special + cases. */ + +/* ..n1.. -> .. LTn RT1 LC RC .. */ +/* ..nm.. -> .. LTn LC RTm RC .. */ + +static Bool +part(jugglestruct *sp) +{ + Trajectory *t, *nt, *p; + Hand hand = (LRAND() & 1) ? RIGHT : LEFT; + + for (t = sp->head->next; t != sp->head; t = t->next) { + if (t->status > THRATCH) { + hand = t->hand; + } else if (t->status == THRATCH) { + char posn = '='; + + /* plausibility check */ + if (t->height <= 2 && t->posn == '_') { + t->posn = ' '; /* no short bounces */ + } + if (t->height <= 1 && (t->posn == '=' || t->posn == '&')) { + t->posn = ' '; /* 1's need close catches */ + } + + switch (t->posn) { + /* throw catch */ + case ' ': posn = '-'; t->posn = '+'; break; + case '+': posn = '+'; t->posn = '-'; break; + case '=': posn = '='; t->posn = '+'; break; + case '&': posn = '+'; t->posn = '='; break; + case 'x': posn = '='; t->posn = '='; break; + case '_': posn = '_'; t->posn = '-'; break; + case 'k': posn = 'k'; t->posn = 'k'; break; + default: + (void) fprintf(stderr, "juggle: unexpected posn %c\n", t->posn); + break; + } + hand = (Hand) ((hand + 1) % 2); + t->status = ACTION; + t->hand = hand; + p = t->prev; + + if (t->height == 1 && p != sp->head) { + p = p->prev; /* '1's are thrown earlier than usual */ + } + + + + t->action = CATCH; + ADD_ELEMENT(Trajectory, nt, p); + if(nt == NULL){ + free_juggle(sp); + return False; + } + nt->object = NULL; + nt->status = ACTION; + nt->action = THROW; + nt->height = t->height; + nt->hand = hand; + nt->posn = posn; + + } + } + return True; +} + +static ObjType +choose_object(void) { + ObjType o; + for (;;) { + o = (ObjType)NRAND((ObjType)NUM_OBJECT_TYPES); + if(balls && o == BALL) break; + if(clubs && o == CLUB) break; + if(torches && o == TORCH) break; + if(knives && o == KNIFE) break; + if(rings && o == RING) break; + if(bballs && o == BBALLS) break; + } + return o; +} + +/* Connnect up throws and catches to figure out which ball goes where. + Do the same with the juggler's hands. */ + +static void +lob(ModeInfo *mi) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + Trajectory *t, *p; + int h; + for (t = sp->head->next; t != sp->head; t = t->next) { + if (t->status == ACTION) { + if (t->action == THROW) { + if (t->type == Empty) { + /* Create new Object */ + ADD_ELEMENT(Object, t->object, sp->objects); + t->object->count = 1; + t->object->tracelen = 0; + t->object->active = False; + /* Initialise object's circular trace list */ + ADD_ELEMENT(Trace, t->object->trace, t->object->trace); + + if (MI_NPIXELS(mi) > 2) { + t->object->color = 1 + NRAND(MI_NPIXELS(mi) - 2); + } else { +#ifdef STANDALONE + t->object->color = 1; +#else + t->object->color = 0; +#endif + } + + /* Small chance of picking a random object instead of the + current theme. */ + if(NRAND(OBJMIXPROB) == 0) { + t->object->type = choose_object(); + } else { + t->object->type = sp->objtypes; + } + + /* Check to see if we need trails for this object */ + if(tail < ObjectDefs[t->object->type].mintrail) { + t->object->tail = ObjectDefs[t->object->type].mintrail; + } else { + t->object->tail = tail; + } + } + + /* Balls can change divisions at each throw */ + t->divisions = 2 * (NRAND(2) + 1); + + /* search forward for next catch in this hand */ + for (p = t->next; t->handlink == NULL; p = p->next) { + if(p->status < ACTION || p == sp->head) return; + if (p->action == CATCH) { + if (t->handlink == NULL && p->hand == t->hand) { + t->handlink = p; + } + } + } + + if (t->height > 0) { + h = t->height - 1; + + /* search forward for next ball catch */ + for (p = t->next; t->balllink == NULL; p = p->next) { + if(p->status < ACTION || p == sp->head) { + t->handlink = NULL; + return; + } + if (p->action == CATCH) { + if (t->balllink == NULL && --h < 1) { /* caught */ + t->balllink = p; /* complete trajectory */ +# if 0 + if (p->type == Full) { + (void) fprintf(stderr, "juggle[%d]: Dropped %d\n", + MI_SCREEN(mi), t->object->color); + } +#endif + p->type = Full; + DUP_OBJECT(p, t); /* accept catch */ + p->angle = t->angle; + p->divisions = t->divisions; + } + } + } + } + t->type = Empty; /* thrown */ + } else if (t->action == CATCH) { + /* search forward for next throw from this hand */ + for (p = t->next; t->handlink == NULL; p = p->next) { + if(p->status < ACTION || p == sp->head) return; + if (p->action == THROW && p->hand == t->hand) { + p->type = t->type; /* pass ball */ + DUP_OBJECT(p, t); /* pass object */ + p->divisions = t->divisions; + t->handlink = p; + } + } + } + t->status = LINKEDACTION; + } + } +} + +/* Clap when both hands are empty */ +static void +clap(jugglestruct *sp) +{ + Trajectory *t, *p; + for (t = sp->head->next; t != sp->head; t = t->next) { + if (t->status == LINKEDACTION && + t->action == CATCH && + t->type == Empty && + t->handlink != NULL && + t->handlink->height == 0) { /* Completely idle hand */ + + for (p = t->next; p != sp->head; p = p->next) { + if (p->status == LINKEDACTION && + p->action == CATCH && + p->hand != t->hand) { /* Next catch other hand */ + if(p->type == Empty && + p->handlink != NULL && + p->handlink->height == 0) { /* Also completely idle */ + + t->handlink->posn = '^'; /* Move first hand's empty throw */ + p->posn = '^'; /* to meet second hand's empty + catch */ + + } + break; /* Only need first catch */ + } + } + } + } +} + +#define CUBIC(s, t) ((((s).a * (t) + (s).b) * (t) + (s).c) * (t) + (s).d) + +/* Compute single spline from x0 with velocity dx0 at time t0 to x1 + with velocity dx1 at time t1 */ +static Spline +makeSpline(double x0, double dx0, int t0, double x1, double dx1, int t1) +{ + Spline s; + double a, b, c, d; + double x10; + double t10; + + x10 = x1 - x0; + t10 = t1 - t0; + a = ((dx0 + dx1)*t10 - 2*x10) / (t10*t10*t10); + b = (3*x10 - (2*dx0 + dx1)*t10) / (t10*t10); + c = dx0; + d = x0; + s.a = a; + s.b = -3*a*t0 + b; + s.c = (3*a*t0 - 2*b)*t0 + c; + s.d = ((-a*t0 + b)*t0 - c)*t0 +d; + return s; +} + +/* Compute a pair of splines. s1 goes from x0 vith velocity dx0 at + time t0 to x1 at time t1. s2 goes from x1 at time t1 to x2 with + velocity dx2 at time t2. The arrival and departure velocities at + x1, t1 must be the same. */ +static double +makeSplinePair(Spline *s1, Spline *s2, + double x0, double dx0, int t0, + double x1, int t1, + double x2, double dx2, int t2) +{ + double x10, x21, t21, t10, t20, dx1; + x10 = x1 - x0; + x21 = x2 - x1; + t21 = t2 - t1; + t10 = t1 - t0; + t20 = t2 - t0; + dx1 = (3*x10*t21*t21 + 3*x21*t10*t10 + 3*dx0*t10*t21*t21 + - dx2*t10*t10*t21 - 4*dx0*t10*t21*t21) / + (2*t10*t21*t20); + *s1 = makeSpline(x0, dx0, t0, x1, dx1, t1); + *s2 = makeSpline(x1, dx1, t1, x2, dx2, t2); + return dx1; +} + +/* Compute a Ballistic path in a pair of degenerate splines. sx goes + from x at time t at constant velocity dx. sy goes from y at time t + with velocity dy and constant acceleration g. */ +static void +makeParabola(Trajectory *n, + double x, double dx, double y, double dy, double g) +{ + double t = (double)n->start; + n->xp.a = 0; + n->xp.b = 0; + n->xp.c = dx; + n->xp.d = -dx*t + x; + n->yp.a = 0; + n->yp.b = g/2; + n->yp.c = -g*t + dy; + n->yp.d = g/2*t*t - dy*t + y; +} + + + +/* Make juggler wander around the screen */ +static double wander(jugglestruct *sp, unsigned long time) +{ + Wander *w = NULL; + for (w = sp->wander->next; w != sp->wander; w = w->next) { + if (w->finish < sp->time) { /* expired */ + Wander *ww = w; + w = w->prev; + REMOVE(ww); + } else if(w->finish > time) { + break; + } + } + if(w == sp->wander) { /* Need a new one */ + ADD_ELEMENT(Wander, w, sp->wander->prev); + if(w == NULL) { /* Memory problem */ + return 0.0; + } + w->finish = time + 3*THROW_CATCH_INTERVAL + NRAND(10*THROW_CATCH_INTERVAL); + if(time == 0) { + w->x = 0; + } else { + w->x = w->prev->x * 0.9 + NRAND(40) - 20; + } + w->s = makeSpline(w->prev->x, 0.0, w->prev->finish, w->x, 0.0, w->finish); + } + return CUBIC(w->s, time); +} + +#define SX 25 /* Shoulder Width */ + +/* Convert hand position symbols into actual time/space coordinates */ +static void +positions(jugglestruct *sp) +{ + Trajectory *t; + unsigned long now = sp->time; /* Make sure we're not lost in the past */ + for (t = sp->head->next; t != sp->head; t = t->next) { + if (t->status >= PTHRATCH) { + now = t->start; + } else if (t->status == ACTION || t->status == LINKEDACTION) { + /* Allow ACTIONs to be annotated, but we won't mark them ready + for the next stage */ + + double xo = 0, yo; + double sx = SX; + double pose = SX/2; + + /* time */ + if (t->action == CATCH) { /* Throw-to-catch */ + if (t->type == Empty) { + now += (int) THROW_NULL_INTERVAL; /* failed catch is short */ + } else { /* successful catch */ + now += (int)(THROW_CATCH_INTERVAL); + } + } else { /* Catch-to-throw */ + if(t->object != NULL) { + now += (int) (CATCH_THROW_INTERVAL * + ObjectDefs[t->object->type].weight); + } else { + now += (int) (CATCH_THROW_INTERVAL); + } + } + + if(t->start == 0) + t->start = now; + else /* Concatenated performances may need clock resync */ + now = t->start; + + t->cx = wander(sp, t->start); + + /* space */ + yo = 90; + + /* Add room for the handle */ + if(t->action == CATCH && t->object != NULL) + yo -= ObjectDefs[t->object->type].handle; + + switch (t->posn) { + case '-': xo = sx - pose; break; + case '_': + case 'k': + case '+': xo = sx + pose; break; + case '~': + case '=': xo = - sx - pose; yo += pose; break; + case '^': xo = 0; yo += pose*2; break; /* clap */ + default: + (void) fprintf(stderr, "juggle: unexpected posn %c\n", t->posn); + break; + } + + t->angle = (((t->hand == LEFT) ^ + (t->posn == '+' || t->posn == '_' || t->posn == 'k' ))? + -1 : 1) * M_PI/2; + + t->x = t->cx + ((t->hand == LEFT) ? xo : -xo); + t->y = yo; + + /* Only mark complete if it was already linked */ + if(t->status == LINKEDACTION) { + t->status = PTHRATCH; + } + } + } +} + + +/* Private physics functions */ + +/* Compute the spin-rate for a trajectory. Different types of throw + (eg, regular thows, bounces, kicks, etc) have different spin + requirements. + + type = type of object + h = trajectory of throwing hand (throws), or next throwing hand (catches) + old = earlier spin to consider + dt = time span of this trajectory + height = height of ball throw or 0 if based on old spin + turns = full club turns required during this operation + togo = partial club turns required to match hands +*/ +static double +spinrate(ObjType type, Trajectory *h, double old, double dt, + int height, int turns, double togo) +{ + const int dir = (h->hand == LEFT) ^ (h->posn == '+')? -1 : 1; + + if(ObjectDefs[type].handle != 0) { /* Clubs */ + return (dir * turns * 2 * M_PI + togo) / dt; + } else if(height == 0) { /* Balls already spinning */ + return old/2; + } else { /* Balls */ + return dir * NRAND(height*10)/20/ObjectDefs[type].weight * 2 * M_PI / dt; + } +} + + +/* compute the angle at the end of a spinning trajectory */ +static double +end_spin(Trajectory *t) +{ + return t->angle + t->spin * (t->finish - t->start); +} + +/* Sets the initial angle of the catch following hand movement t to + the final angle of the throw n. Also sets the angle of the + subsequent throw to the same angle plus half a turn. */ +static void +match_spins_on_catch(Trajectory *t, Trajectory *n) +{ + if(ObjectDefs[t->balllink->object->type].handle == 0) { + t->balllink->angle = end_spin(n); + if(t->balllink->handlink != NULL) { + t->balllink->handlink->angle = t->balllink->angle + M_PI; + } + } +} + +static double +find_bounce(jugglestruct *sp, + double yo, double yf, double yc, double tc, double cor) +{ + double tb, i, dy = 0; + const double e = 1; /* permissible error in yc */ + + /* + tb = time to bounce + yt = height at catch time after one bounce + one or three roots according to timing + find one by interval bisection + */ + tb = tc; + for(i = tc / 2; i > 0.0001; i/=2){ + double dt, yt; + if(tb == 0){ + (void) fprintf(stderr, "juggle: bounce div by zero!\n"); + break; + } + dy = (yf - yo)/tb + sp->Gr/2*tb; + dt = tc - tb; + yt = -cor*dy*dt + sp->Gr/2*dt*dt + yf; + if(yt < yc + e){ + tb-=i; + }else if(yt > yc - e){ + tb+=i; + }else{ + break; + } + } + if(dy*THROW_CATCH_INTERVAL < -200) { /* bounce too hard */ + tb = -1; + } + return tb; +} + +static Trajectory* +new_predictor(const Trajectory *t, int start, int finish, double angle) +{ + Trajectory *n; + ADD_ELEMENT(Trajectory, n, t->prev); + if(n == NULL){ + return NULL; + } + DUP_OBJECT(n, t); + n->divisions = t->divisions; + n->type = Ball; + n->status = PREDICTOR; + + n->start = start; + n->finish = finish; + n->angle = angle; + return n; +} + +/* Turn abstract timings into physically appropriate object trajectories. */ +static Bool +projectile(jugglestruct *sp) +{ + Trajectory *t; + const int yf = 0; /* Floor height */ + + for (t = sp->head->next; t != sp->head; t = t->next) { + if (t->status != PTHRATCH || t->action != THROW) { + continue; + } else if (t->balllink == NULL) { /* Zero Throw */ + t->status = BPREDICTOR; + } else if (t->balllink->handlink == NULL) { /* Incomplete */ + return True; + } else if(t->balllink == t->handlink) { + /* '2' height - hold on to ball. Don't need to consider + flourishes, 'hands' will do that automatically anyway */ + + t->type = Full; + /* Zero spin to avoid wrist injuries */ + t->spin = 0; + match_spins_on_catch(t, t); + t->dx = t->dy = 0; + t->status = BPREDICTOR; + continue; + } else { + if (t->posn == '_') { /* Bounce once */ + + const int tb = t->start + + find_bounce(sp, t->y, (double) yf, t->balllink->y, + (double) (t->balllink->start - t->start), + ObjectDefs[t->object->type].cor); + + if(tb < t->start) { /* bounce too hard */ + t->posn = '+'; /* Use regular throw */ + } else { + Trajectory *n; /* First (throw) trajectory. */ + double dt; /* Time span of a trajectory */ + double dy; /* Distance span of a follow-on trajectory. + First trajectory uses t->dy */ + /* dx is constant across both trajectories */ + t->dx = (t->balllink->x - t->x) / (t->balllink->start - t->start); + + { /* ball follows parabola down */ + n = new_predictor(t, t->start, tb, t->angle); + if(n == NULL) return False; + dt = n->finish - n->start; + /* Ball rate 4, no flight or matching club turns */ + n->spin = spinrate(t->object->type, t, 0.0, dt, 4, 0, 0.0); + t->dy = (yf - t->y)/dt - sp->Gr/2*dt; + makeParabola(n, t->x, t->dx, t->y, t->dy, sp->Gr); + } + + { /* ball follows parabola up */ + Trajectory *m = new_predictor(t, n->finish, t->balllink->start, + end_spin(n)); + if(m == NULL) return False; + dt = m->finish - m->start; + /* Use previous ball rate, no flight club turns */ + m->spin = spinrate(t->object->type, t, n->spin, dt, 0, 0, + t->balllink->angle - m->angle); + match_spins_on_catch(t, m); + dy = (t->balllink->y - yf)/dt - sp->Gr/2 * dt; + makeParabola(m, t->balllink->x - t->dx * dt, + t->dx, (double) yf, dy, sp->Gr); + } + + t->status = BPREDICTOR; + continue; + } + } else if (t->posn == 'k') { /* Drop & Kick */ + Trajectory *n; /* First (drop) trajectory. */ + Trajectory *o; /* Second (rest) trajectory */ + Trajectory *m; /* Third (kick) trajectory */ + const int td = t->start + 2*THROW_CATCH_INTERVAL; /* Drop time */ + const int tk = t->balllink->start - 5*THROW_CATCH_INTERVAL; /* Kick */ + double dt, dy; + + { /* Fall to ground */ + n = new_predictor(t, t->start, td, t->angle); + if(n == NULL) return False; + dt = n->finish - n->start; + /* Ball spin rate 4, no flight club turns */ + n->spin = spinrate(t->object->type, t, 0.0, dt, 4, 0, + t->balllink->angle - n->angle); + t->dx = (t->balllink->x - t->x) / dt; + t->dy = (yf - t->y)/dt - sp->Gr/2*dt; + makeParabola(n, t->x, t->dx, t->y, t->dy, sp->Gr); + } + + { /* Rest on ground */ + o = new_predictor(t, n->finish, tk, end_spin(n)); + if(o == NULL) return False; + o->spin = 0; + makeParabola(o, t->balllink->x, 0.0, (double) yf, 0.0, 0.0); + } + + /* Kick up */ + { + m = new_predictor(t, o->finish, t->balllink->start, end_spin(o)); + if(m == NULL) return False; + dt = m->finish - m->start; + /* Match receiving hand, ball rate 4, one flight club turn */ + m->spin = spinrate(t->object->type, t->balllink->handlink, 0.0, dt, + 4, 1, t->balllink->angle - m->angle); + match_spins_on_catch(t, m); + dy = (t->balllink->y - yf)/dt - sp->Gr/2 * dt; + makeParabola(m, t->balllink->x, 0.0, (double) yf, dy, sp->Gr); + } + + t->status = BPREDICTOR; + continue; + } + + /* Regular flight, no bounce */ + { /* ball follows parabola */ + double dt; + Trajectory *n = new_predictor(t, t->start, + t->balllink->start, t->angle); + if(n == NULL) return False; + dt = t->balllink->start - t->start; + /* Regular spin */ + n->spin = spinrate(t->object->type, t, 0.0, dt, t->height, t->height/2, + t->balllink->angle - n->angle); + match_spins_on_catch(t, n); + t->dx = (t->balllink->x - t->x) / dt; + t->dy = (t->balllink->y - t->y) / dt - sp->Gr/2 * dt; + makeParabola(n, t->x, t->dx, t->y, t->dy, sp->Gr); + } + + t->status = BPREDICTOR; + } + } + return True; +} + +/* Turn abstract hand motions into cubic splines. */ +static void +hands(jugglestruct *sp) +{ + Trajectory *t, *u, *v; + + for (t = sp->head->next; t != sp->head; t = t->next) { + /* no throw => no velocity */ + if (t->status != BPREDICTOR) { + continue; + } + + u = t->handlink; + if (u == NULL) { /* no next catch */ + continue; + } + v = u->handlink; + if (v == NULL) { /* no next throw */ + continue; + } + + /* double spline takes hand from throw, thru catch, to + next throw */ + + t->finish = u->start; + t->status = PREDICTOR; + + u->finish = v->start; + u->status = PREDICTOR; + + + /* FIXME: These adjustments leave a small glitch when alternating + balls and clubs. Just hope no-one notices. :-) */ + + /* make sure empty hand spin matches the thrown object in case it + had a handle */ + + t->spin = ((t->hand == LEFT)? -1 : 1 ) * + fabs((u->angle - t->angle)/(u->start - t->start)); + + u->spin = ((v->hand == LEFT) ^ (v->posn == '+')? -1 : 1 ) * + fabs((v->angle - u->angle)/(v->start - u->start)); + + (void) makeSplinePair(&t->xp, &u->xp, + t->x, t->dx, t->start, + u->x, u->start, + v->x, v->dx, v->start); + (void) makeSplinePair(&t->yp, &u->yp, + t->y, t->dy, t->start, + u->y, u->start, + v->y, v->dy, v->start); + + t->status = PREDICTOR; + } +} + +/* Given target x, y find_elbow puts hand at target if possible, + * otherwise makes hand point to the target */ +static void +find_elbow(int armlength, DXPoint *h, DXPoint *e, DXPoint *p, DXPoint *s, + int z) +{ + double r, h2, t; + double x = p->x - s->x; + double y = p->y - s->y; + h2 = x*x + y*y + z*z; + if (h2 > 4 * armlength * armlength) { + t = armlength/sqrt(h2); + e->x = t*x + s->x; + e->y = t*y + s->y; + h->x = 2 * t * x + s->x; + h->y = 2 * t * y + s->y; + } else { + r = sqrt((double)(x*x + z*z)); + t = sqrt(4 * armlength * armlength / h2 - 1); + e->x = x*(1 + y*t/r)/2 + s->x; + e->y = (y - r*t)/2 + s->y; + h->x = x + s->x; + h->y = y + s->y; + } +} + + +/* NOTE: returned x, y adjusted for arm reach */ +static void +reach_arm(ModeInfo * mi, Hand side, DXPoint *p) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + DXPoint h, e; + find_elbow(40, &h, &e, p, &sp->arm[1][side][SHOULDER], 25); + *p = sp->arm[1][side][HAND] = h; + sp->arm[1][side][ELBOW] = e; +} + +#if DEBUG +/* dumps a human-readable rendition of the current state of the juggle + pipeline to stderr for debugging */ +static void +dump(jugglestruct *sp) +{ + Trajectory *t; + for (t = sp->head->next; t != sp->head; t = t->next) { + switch (t->status) { + case ATCH: + (void) fprintf(stderr, "%p a %c%d\n", (void*)t, t->posn, t->adam); + break; + case THRATCH: + (void) fprintf(stderr, "%p T %c%d %s\n", (void*)t, t->posn, t->height, + t->pattern == NULL?"":t->pattern); + break; + case ACTION: + if (t->action == CATCH) + (void) fprintf(stderr, "%p A %c%cC\n", + (void*)t, t->posn, + t->hand ? 'R' : 'L'); + else + (void) fprintf(stderr, "%p A %c%c%c%d\n", + (void*)t, t->posn, + t->hand ? 'R' : 'L', + (t->action == THROW)?'T':'N', + t->height); + break; + case LINKEDACTION: + (void) fprintf(stderr, "%p L %c%c%c%d %d %p %p\n", + (void*)t, t->posn, + t->hand?'R':'L', + (t->action == THROW)?'T':(t->action == CATCH?'C':'N'), + t->height, t->object == NULL?0:t->object->color, + (void*)t->handlink, (void*)t->balllink); + break; + case PTHRATCH: + (void) fprintf(stderr, "%p O %c%c%c%d %d %2d %6lu %6lu\n", + (void*)t, t->posn, + t->hand?'R':'L', + (t->action == THROW)?'T':(t->action == CATCH?'C':'N'), + t->height, t->type, t->object == NULL?0:t->object->color, + t->start, t->finish); + break; + case BPREDICTOR: + (void) fprintf(stderr, "%p B %c %2d %6lu %6lu %g\n", + (void*)t, t->type == Ball?'b':t->type == Empty?'e':'f', + t->object == NULL?0:t->object->color, + t->start, t->finish, t->yp.c); + break; + case PREDICTOR: + (void) fprintf(stderr, "%p P %c %2d %6lu %6lu %g\n", + (void*)t, t->type == Ball?'b':t->type == Empty?'e':'f', + t->object == NULL?0:t->object->color, + t->start, t->finish, t->yp.c); + break; + default: + (void) fprintf(stderr, "%p: status %d not implemented\n", + (void*)t, t->status); + break; + } + } + (void) fprintf(stderr, "---\n"); +} +#endif + +static int get_num_balls(const char *j) +{ + int balls = 0; + const char *p; + int h = 0; + if (!j) abort(); + for (p = j; *p; p++) { + if (*p >= '0' && *p <='9') { /* digit */ + h = 10*h + (*p - '0'); + } else { + if (h > balls) { + balls = h; + } + h = 0; + } + } + return balls; +} + +#ifdef __cplusplus +extern "C" { +#endif + +static int +compare_num_balls(const void *p1, const void *p2) +{ + int i, j; + i = get_num_balls(((patternstruct*)p1)->pattern); + j = get_num_balls(((patternstruct*)p2)->pattern); + if (i > j) { + return (1); + } else if (i < j) { + return (-1); + } else { + return (0); + } +} + +#ifdef __cplusplus +} +#endif + + +/************************************************************************** + * Rendering Functions * + * * + **************************************************************************/ + +static void +show_arms(ModeInfo * mi, unsigned long color) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + unsigned int i, j; + Hand side; + XPoint a[XtNumber(sp->arm[0][0])]; + if(color == MI_BLACK_PIXEL(mi)) { + j = 0; + } else { + j = 1; + } + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), + ARMWIDTH, LineSolid, CapRound, JoinRound); + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + for(side = LEFT; side <= RIGHT; side = (Hand)((int)side + 1)) { + /* Translate into device coords */ + for(i = 0; i < XtNumber(a); i++) { + a[i].x = (short)(MI_WIDTH(mi)/2 + sp->arm[j][side][i].x*sp->scale); + a[i].y = (short)(MI_HEIGHT(mi) - sp->arm[j][side][i].y*sp->scale); + if(j == 1) + sp->arm[0][side][i] = sp->arm[1][side][i]; + } + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + a, XtNumber(a), CoordModeOrigin); + } +} + +static void +show_figure(ModeInfo * mi, unsigned long color, Bool init) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + XPoint p[7]; + unsigned int i; + + /* +-----+ 9 + | 6 | + 10 +--+--+ + 2 +---+---+ 3 + \ 5 / + \ / + \ / + 1 + + / \ + / \ + 0 +-----+ 4 + | | + | | + | | + 7 + + 8 + */ + + static const XPoint figure[] = { + { 15, 70}, /* 0 Left Hip */ + { 0, 90}, /* 1 Waist */ + { SX, 130}, /* 2 Left Shoulder */ + {-SX, 130}, /* 3 Right Shoulder */ + {-15, 70}, /* 4 Right Hip */ + { 0, 130}, /* 5 Neck */ + { 0, 140}, /* 6 Chin */ + { SX, 0}, /* 7 Left Foot */ + {-SX, 0}, /* 8 Right Foot */ + {-17, 174}, /* 9 Head1 */ + { 17, 140}, /* 10 Head2 */ + }; + XPoint a[XtNumber(figure)]; + + /* Translate into device coords */ + for(i = 0; i < XtNumber(figure); i++) { + a[i].x = (short)(MI_WIDTH(mi)/2 + (sp->cx + figure[i].x)*sp->scale); + a[i].y = (short)(MI_HEIGHT(mi) - figure[i].y*sp->scale); + } + + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), + ARMWIDTH, LineSolid, CapRound, JoinRound); + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + + i = 0; /* Body */ + p[i++] = a[0]; p[i++] = a[1]; p[i++] = a[2]; + p[i++] = a[3]; p[i++] = a[1]; p[i++] = a[4]; + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, CoordModeOrigin); + + i = 0; /* Legs */ + p[i++] = a[7]; p[i++] = a[0]; p[i++] = a[4]; p[i++] = a[8]; + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, CoordModeOrigin); + + i = 0; /* Neck */ + p[i++] = a[5]; p[i++] = a[6]; + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, CoordModeOrigin); + + /* Head */ + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + a[9].x, a[9].y, + a[10].x - a[9].x, a[10].y - a[9].y, 0, 64*360); + sp->arm[1][LEFT][SHOULDER].x = sp->cx + figure[2].x; + sp->arm[1][RIGHT][SHOULDER].x = sp->cx + figure[3].x; + if(init) { + /* Initialise arms */ + unsigned int i; + for(i = 0; i < 2; i++){ + sp->arm[i][LEFT][SHOULDER].y = figure[2].y; + sp->arm[i][LEFT][ELBOW].x = figure[2].x; + sp->arm[i][LEFT][ELBOW].y = figure[1].y; + sp->arm[i][LEFT][HAND].x = figure[0].x; + sp->arm[i][LEFT][HAND].y = figure[1].y; + sp->arm[i][RIGHT][SHOULDER].y = figure[3].y; + sp->arm[i][RIGHT][ELBOW].x = figure[3].x; + sp->arm[i][RIGHT][ELBOW].y = figure[1].y; + sp->arm[i][RIGHT][HAND].x = figure[4].x; + sp->arm[i][RIGHT][HAND].y = figure[1].y; + } + } +} + +static void +show_ball(ModeInfo *mi, unsigned long color, Trace *s) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + int offset = (int)(s->angle*64*180/M_PI); + short x = (short)(MI_WIDTH(mi)/2 + s->x * sp->scale); + short y = (short)(MI_HEIGHT(mi) - s->y * sp->scale); + + /* Avoid wrapping */ + if(s->y*sp->scale > MI_HEIGHT(mi) * 2) return; + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + if (s->divisions == 0 || color == MI_BLACK_PIXEL(mi)) { + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x - BALLRADIUS, y - BALLRADIUS, + 2*BALLRADIUS, 2*BALLRADIUS, + 0, 23040); + } else if (s->divisions == 4) { /* 90 degree divisions */ + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x - BALLRADIUS, y - BALLRADIUS, + 2*BALLRADIUS, 2*BALLRADIUS, + offset % 23040, 5760); + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x - BALLRADIUS, y - BALLRADIUS, + 2*BALLRADIUS, 2*BALLRADIUS, + (offset + 11520) % 23040, 5760); + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x - BALLRADIUS, y - BALLRADIUS, + 2*BALLRADIUS, 2*BALLRADIUS, + (offset + 5760) % 23040, 5760); + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x - BALLRADIUS, y - BALLRADIUS, + 2*BALLRADIUS, 2*BALLRADIUS, + (offset + 17280) % 23040, 5760); + } else if (s->divisions == 2) { /* 180 degree divisions */ + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x - BALLRADIUS, y - BALLRADIUS, + 2*BALLRADIUS, 2*BALLRADIUS, + offset % 23040, 11520); + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x - BALLRADIUS, y - BALLRADIUS, + 2*BALLRADIUS, 2*BALLRADIUS, + (offset + 11520) % 23040, 11520); + } else { + (void) fprintf(stderr, "juggle[%d]: unexpected divisions: %d\n", + MI_SCREEN(mi), s->divisions); + } +} + +static void +show_europeanclub(ModeInfo *mi, unsigned long color, Trace *s) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + XPoint p[4]; + const double sa = sin(s->angle); + const double ca = cos(s->angle); + unsigned int i; + + /* 6 6 + +-+ + / \ + 4 +-----+ 7 + ////////\ + 3 +---------+ 8 + 2 +---------+ 9 + |///////| + 1 +-------+ 10 + | | + | | + | | + | | + | | + | | + +-+ + 0 11 */ + + static const XPoint club[] = { + {-24, 2}, /* 0 */ + {-10, 3}, /* 1 */ + { 1, 6}, /* 2 */ + { 8, 6}, /* 3 */ + { 14, 4}, /* 4 */ + { 16, 3}, /* 5 */ + { 16,-3}, /* 6 */ + { 14,-4}, /* 7 */ + { 8,-6}, /* 8 */ + { 1,-6}, /* 9 */ + {-10,-3}, /* 10 */ + {-24,-2}, /* 11 */ + {-24, 2}, /* 0 close boundary */ + }; + XPoint a[XtNumber(club)]; + + /* Avoid wrapping */ + if(s->y*sp->scale > MI_HEIGHT(mi) * 2) return; + + /* Translate and fake perspective */ + for(i = 0; i < XtNumber(club); i++) { + a[i].x = (short)(MI_WIDTH(mi)/2 + + (s->x + club[i].x*PERSPEC*sa)*sp->scale - + club[i].y*sqrt(sp->scale)*ca); + a[i].y = (short)(MI_HEIGHT(mi) - (s->y - club[i].x*ca)*sp->scale + + club[i].y*sa*sqrt(sp->scale)); + } + + if(color != MI_BLACK_PIXEL(mi)) { + /* Outline in black */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 2, + LineSolid, CapRound, JoinRound); + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + a, XtNumber(a), CoordModeOrigin); + } + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + + /* Don't be tempted to optimize erase by drawing all the black in + one X operation. It must use the same ops as the colours to + guarantee a clean erase. */ + + i = 0; /* Colored stripes */ + p[i++] = a[1]; p[i++] = a[2]; + p[i++] = a[9]; p[i++] = a[10]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); + i = 0; + p[i++] = a[3]; p[i++] = a[4]; + p[i++] = a[7]; p[i++] = a[8]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); + + if(color != MI_BLACK_PIXEL(mi)) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + } + + i = 0; /* White center band */ + p[i++] = a[2]; p[i++] = a[3]; p[i++] = a[8]; p[i++] = a[9]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); + + i = 0; /* White handle */ + p[i++] = a[0]; p[i++] = a[1]; p[i++] = a[10]; p[i++] = a[11]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); + + i = 0; /* White tip */ + p[i++] = a[4]; p[i++] = a[5]; p[i++] = a[6]; p[i++] = a[7]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); +} + +#if 0 +static void +show_jugglebugclub(ModeInfo *mi, unsigned long color, Trace *s) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + XPoint p[6]; + const double sa = sin(s->angle); + const double ca = cos(s->angle); + unsigned int i; + + /* 4 5 + +-+ + / \ + 3 +-----+ 6 + ////////\ + 2 +/////////+ 7 + |///////| + 1 +-------+ 8 + | | + | | + | | + | | + | | + | | + +-+ + 0 9 */ + + static const XPoint club[] = { + {-24, 2}, /* 0 */ + { -9, 3}, /* 1 */ + { 5, 6}, /* 2 */ + { 11, 4}, /* 3 */ + { 16, 3}, /* 4 */ + { 16,-3}, /* 5 */ + { 11,-4}, /* 6 */ + { 5,-6}, /* 7 */ + { -9,-3}, /* 8 */ + {-24,-2}, /* 9 */ + {-24, 2}, /* 0 close boundary */ + }; + XPoint a[XtNumber(club)]; + + /* Avoid wrapping */ + if(s->y*sp->scale > MI_HEIGHT(mi) * 2) return; + + /* Translate and fake perspective */ + for(i = 0; i < XtNumber(club); i++) { + a[i].x = (short)(MI_WIDTH(mi)/2 + + (s->x + club[i].x*PERSPEC*sa)*sp->scale - + club[i].y*sqrt(sp->scale)*ca); + a[i].y = (short)(MI_HEIGHT(mi) - (s->y - club[i].x*ca)*sp->scale + + club[i].y*sa*sqrt(sp->scale)); + } + + if(color != MI_BLACK_PIXEL(mi)) { + /* Outline in black */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 2, + LineSolid, CapRound, JoinRound); + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + a, XtNumber(a), CoordModeOrigin); + } + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + + /* Don't be tempted to optimize erase by drawing all the black in + one X operation. It must use the same ops as the colours to + guarantee a clean erase. */ + + i = 0; /* Coloured center band */ + p[i++] = a[1]; p[i++] = a[2]; p[i++] = a[3]; + p[i++] = a[6]; p[i++] = a[7]; p[i++] = a[8]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); + + if(color != MI_BLACK_PIXEL(mi)) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + } + + i = 0; /* White handle */ + p[i++] = a[0]; p[i++] = a[1]; p[i++] = a[8]; p[i++] = a[9]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); + + i = 0; /* White tip */ + p[i++] = a[3]; p[i++] = a[4]; p[i++] = a[5]; p[i++] = a[6]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); +} +#endif + +static void +show_torch(ModeInfo *mi, unsigned long color, Trace *s) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + XPoint head, tail, last; + DXPoint dhead, dlast; + const double sa = sin(s->angle); + const double ca = cos(s->angle); + + const double TailLen = -24; + const double HeadLen = 16; + const short Width = (short)(5 * sqrt(sp->scale)); + + /* + +///+ head + last | + | + | + | + | + + tail + */ + + dhead.x = s->x + HeadLen * PERSPEC * sa; + dhead.y = s->y - HeadLen * ca; + + if(color == MI_BLACK_PIXEL(mi)) { /* Use 'last' when erasing */ + dlast = s->dlast; + } else { /* Store 'last' so we can use it later when s->prev has + gone */ + if(s->prev != s->next) { + dlast.x = s->prev->x + HeadLen * PERSPEC * sin(s->prev->angle); + dlast.y = s->prev->y - HeadLen * cos(s->prev->angle); + } else { + dlast = dhead; + } + s->dlast = dlast; + } + + /* Avoid wrapping (after last is stored) */ + if(s->y*sp->scale > MI_HEIGHT(mi) * 2) return; + + head.x = (short)(MI_WIDTH(mi)/2 + dhead.x*sp->scale); + head.y = (short)(MI_HEIGHT(mi) - dhead.y*sp->scale); + + last.x = (short)(MI_WIDTH(mi)/2 + dlast.x*sp->scale); + last.y = (short)(MI_HEIGHT(mi) - dlast.y*sp->scale); + + tail.x = (short)(MI_WIDTH(mi)/2 + + (s->x + TailLen * PERSPEC * sa)*sp->scale ); + tail.y = (short)(MI_HEIGHT(mi) - (s->y - TailLen * ca)*sp->scale ); + + if(color != MI_BLACK_PIXEL(mi)) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), + Width, LineSolid, CapRound, JoinRound); + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + head.x, head.y, tail.x, tail.y); + } + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), + Width * 2, LineSolid, CapRound, JoinRound); + + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + head.x, head.y, last.x, last.y); + +} + +static void +show_knife(ModeInfo *mi, unsigned long color, Trace *s) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + unsigned int i; + const double sa = sin(s->angle); + const double ca = cos(s->angle); + + /* + 2 + + |+ 3 + || + 1 +++ 5 + |4| + | | + + 0 + */ + static const XPoint knife[] = { + {-24, 0}, /* 0 */ + { -5,-3}, /* 1 */ + { 16,-3}, /* 2 */ + { 12, 0}, /* 3 */ + { -5, 0}, /* 4 */ + { -5, 3}, /* 5 */ + }; + XPoint a[XtNumber(knife)], p[5]; + + /* Avoid wrapping */ + if(s->y*sp->scale > MI_HEIGHT(mi) * 2) return; + + /* Translate and fake perspective */ + for(i = 0; i < XtNumber(knife); i++) { + a[i].x = (short)(MI_WIDTH(mi)/2 + + (s->x + knife[i].x*PERSPEC*sa)*sp->scale - + knife[i].y*sqrt(sp->scale)*ca*PERSPEC); + a[i].y = (short)(MI_HEIGHT(mi) - (s->y - knife[i].x*ca)*sp->scale + + knife[i].y*sa*sqrt(sp->scale)); + } + + /* Handle */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), (short)(4*sqrt(sp->scale)), + LineSolid, CapRound, JoinRound); + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + a[0].x, a[0].y, a[4].x, a[4].y); + + /* Blade */ + if(color != MI_BLACK_PIXEL(mi)) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + } + i = 0; + p[i++] = a[1]; p[i++] = a[2]; p[i++] = a[3]; p[i++] = a[5]; + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + p, i, Convex, CoordModeOrigin); +} + +static void +show_ring(ModeInfo *mi, unsigned long color, Trace *s) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + short x = (short)(MI_WIDTH(mi)/2 + s->x * sp->scale); + short y = (short)(MI_HEIGHT(mi) - s->y * sp->scale); + double radius = 15 * sp->scale; + short thickness = (short)(8 * sqrt(sp->scale)); + + /* Avoid wrapping */ + if(s->y*sp->scale > MI_HEIGHT(mi) * 2) return; + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), + thickness, LineSolid, CapRound, JoinRound); + + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (short)(x - radius*PERSPEC), (short)(y - radius), + (short)(2*radius*PERSPEC), (short)(2*radius), + 0, 23040); +} + + +static void +show_bball(ModeInfo *mi, unsigned long color, Trace *s) +{ + jugglestruct *sp = &juggles[MI_SCREEN(mi)]; + short x = (short)(MI_WIDTH(mi)/2 + s->x * sp->scale); + short y = (short)(MI_HEIGHT(mi) - s->y * sp->scale); + double radius = 12 * sp->scale; + int offset = (int)(s->angle*64*180/M_PI); + int holesize = (int)(3.0*sqrt(sp->scale)); + + /* Avoid wrapping */ + if(s->y*sp->scale > MI_HEIGHT(mi) * 2) return; + + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (short)(x - radius), (short)(y - radius), + (short)(2*radius), (short)(2*radius), + 0, 23040); + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), color); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 2, + LineSolid, CapRound, JoinRound); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (short)(x - radius), (short)(y - radius), + (short)(2*radius), (short)(2*radius), + 0, 23040); + + /* Draw finger holes */ + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), holesize, + LineSolid, CapRound, JoinRound); + + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (short)(x - radius*0.5), (short)(y - radius*0.5), + (short)(2*radius*0.5), (short)(2*radius*0.5), + (offset + 960) % 23040, 0); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (short)(x - radius*0.7), (short)(y - radius*0.7), + (short)(2*radius*0.7), (short)(2*radius*0.7), + (offset + 1920) % 23040, 0); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (short)(x - radius*0.7), (short)(y - radius*0.7), + (short)(2*radius*0.7), (short)(2*radius*0.7), + offset % 23040, 0); +} + +/************************************************************************** + * Public Functions * + * * + **************************************************************************/ + + +ENTRYPOINT void +release_juggle (ModeInfo * mi) +{ + if (juggles != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_juggle(&juggles[screen]); + free(juggles); + juggles = (jugglestruct *) NULL; + } +} + +/* FIXME: refill_juggle currently just appends new throws to the + * programme. This is fine if the programme is empty, but if there + * are still some trajectories left then it really should take these + * into account */ + +static void +refill_juggle(ModeInfo * mi) +{ + jugglestruct *sp = NULL; + int i; + + if (juggles == NULL) + return; + sp = &juggles[MI_SCREEN(mi)]; + + /* generate pattern */ + if (pattern == NULL) { + +#define MAXPAT 10 +#define MAXREPEAT 300 +#define CHANGE_BIAS 8 /* larger makes num_ball changes less likely */ +#define POSITION_BIAS 20 /* larger makes hand movements less likely */ + + int count = 0; + while (count < MI_CYCLES(mi)) { + char buf[MAXPAT * 3 + 3], *b = buf; + int maxseen = 0; + int l = NRAND(MAXPAT) + 1; + int t = NRAND(MIN(MAXREPEAT, (MI_CYCLES(mi) - count))) + 1; + + { /* vary number of balls */ + int new_balls = sp->num_balls; + int change; + + if (new_balls == 2) /* Do not juggle 2 that often */ + change = NRAND(2 + CHANGE_BIAS / 4); + else + change = NRAND(2 + CHANGE_BIAS); + switch (change) { + case 0: + new_balls++; + break; + case 1: + new_balls--; + break; + default: + break; /* NO-OP */ + } + if (new_balls < sp->patternindex.minballs) { + new_balls += 2; + } + if (new_balls > sp->patternindex.maxballs) { + new_balls -= 2; + } + if (new_balls < sp->num_balls) { + if (!program(mi, "[*]", NULL, 1)) /* lose ball */ + return; + } + sp->num_balls = new_balls; + } + + count += t; + if (NRAND(2) && sp->patternindex.index[sp->num_balls].number) { + /* Pick from PortFolio */ + int p = sp->patternindex.index[sp->num_balls].start + + NRAND(sp->patternindex.index[sp->num_balls].number); + if (!program(mi, portfolio[p].pattern, portfolio[p].name, t)) + return; + } else { + /* Invent a new pattern */ + *b++='['; + for(i = 0; i < l; i++){ + int n, m; + do { /* Triangular Distribution => high values more likely */ + m = NRAND(sp->num_balls + 1); + n = NRAND(sp->num_balls + 1); + } while(m >= n); + if (n == sp->num_balls) { + maxseen = 1; + } + switch(NRAND(5 + POSITION_BIAS)){ + case 0: /* Outside throw */ + *b++ = '+'; break; + case 1: /* Cross throw */ + *b++ = '='; break; + case 2: /* Cross catch */ + *b++ = '&'; break; + case 3: /* Cross throw and catch */ + *b++ = 'x'; break; + case 4: /* Bounce */ + *b++ = '_'; break; + default: + break; /* Inside throw (default) */ + } + + *b++ = n + '0'; + *b++ = ' '; + } + *b++ = ']'; + *b = '\0'; + if (maxseen) { + if (!program(mi, buf, NULL, t)) + return; + } + } + } + } else { /* pattern supplied in height or 'a' notation */ + if (!program(mi, pattern, NULL, MI_CYCLES(mi))) + return; + } + + adam(sp); + + name(sp); + + if (!part(sp)) + return; + + lob(mi); + + clap(sp); + + positions(sp); + + if (!projectile(sp)) { + free_juggle(sp); + return; + } + + hands(sp); +#ifdef DEBUG + if(MI_IS_DEBUG(mi)) dump(sp); +#endif +} + +static void +change_juggle(ModeInfo * mi) +{ + jugglestruct *sp = NULL; + Trajectory *t; + + if (juggles == NULL) + return; + sp = &juggles[MI_SCREEN(mi)]; + + /* Strip pending trajectories */ + for (t = sp->head->next; t != sp->head; t = t->next) { + if(t->start > sp->time || t->finish < sp->time) { + Trajectory *n = t; + t=t->prev; + trajectory_destroy(n); + } + } + + /* Pick the current object theme */ + sp->objtypes = choose_object(); + + refill_juggle(mi); + + /* Clean up the Screen. Don't use MI_CLEARWINDOW(mi), since we + don't all those special effects. */ + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); + + show_figure(mi, MI_WHITE_PIXEL(mi), True); + +} + +ENTRYPOINT void +init_juggle (ModeInfo * mi) +{ + jugglestruct *sp = 0; + int i; + + if (juggles == NULL) { /* First-time initialisation */ + + /* allocate jugglestruct */ + if ((juggles = + (jugglestruct *)calloc(MI_NUM_SCREENS(mi), + sizeof (jugglestruct))) == NULL) { + release_juggle(mi); + return; + } + } + + sp = &juggles[MI_SCREEN(mi)]; + + if (only && *only && strcmp(only, " ")) { + balls = clubs = torches = knives = rings = bballs = False; + if (!strcasecmp (only, "balls")) balls = True; + else if (!strcasecmp (only, "clubs")) clubs = True; + else if (!strcasecmp (only, "torches")) torches = True; + else if (!strcasecmp (only, "knives")) knives = True; + else if (!strcasecmp (only, "rings")) rings = True; + else if (!strcasecmp (only, "bballs")) bballs = True; + else { + (void) fprintf (stderr, + "Juggle: -only must be one of: balls, clubs, torches, knives,\n" + "\t rings, or bballs (not \"%s\")\n", only); +#ifdef STANDALONE /* xlock mustn't exit merely because of a bad argument */ + exit (1); +#endif + } + } + + if (sp->head == 0) { /* first time initializing this juggler */ + + sp->count = ABS(MI_COUNT(mi)); + if (sp->count == 0) + sp->count = 200; + + /* record start time */ + sp->begintime = time(NULL); + if(sp->patternindex.maxballs > 0) { + sp->num_balls = sp->patternindex.minballs + + NRAND(sp->patternindex.maxballs - sp->patternindex.minballs); + } + + show_figure(mi, MI_WHITE_PIXEL(mi), True); /* Draw figure. Also discovers + information about the juggler's + proportions */ + + /* "7" should be about three times the height of the juggler's + shoulders */ + sp->Gr = -GRAVITY(3 * sp->arm[0][RIGHT][SHOULDER].y, + 7 * THROW_CATCH_INTERVAL); + + if(!balls && !clubs && !torches && !knives && !rings && !bballs) + balls = True; /* Have to juggle something! */ + + /* create circular trajectory list */ + ADD_ELEMENT(Trajectory, sp->head, sp->head); + if(sp->head == NULL){ + free_juggle(sp); + return; + } + + /* create circular object list */ + ADD_ELEMENT(Object, sp->objects, sp->objects); + if(sp->objects == NULL){ + free_juggle(sp); + return; + } + + /* create circular wander list */ + ADD_ELEMENT(Wander, sp->wander, sp->wander); + if(sp->wander == NULL){ + free_juggle(sp); + return; + } + (void)wander(sp, 0); /* Initialize wander */ + + sp->pattern = strdup(""); /* Initialise saved pattern with + free-able memory */ + } + + sp = &juggles[MI_SCREEN(mi)]; + + if (pattern && + (!*pattern || + !strcasecmp (pattern, ".") || + !strcasecmp (pattern, "random"))) + pattern = NULL; + + if (pattern == NULL && sp->patternindex.maxballs == 0) { + /* pattern list needs indexing */ + int nelements = XtNumber(portfolio); + int numpat = 0; + + /* sort according to number of balls */ + qsort((void*)portfolio, nelements, + sizeof(portfolio[1]), compare_num_balls); + + /* last pattern has most balls */ + sp->patternindex.maxballs = get_num_balls(portfolio[nelements - 1].pattern); + /* run through sorted list, indexing start of each group + and number in group */ + sp->patternindex.maxballs = 1; + for (i = 0; i < nelements; i++) { + int b = get_num_balls(portfolio[i].pattern); + if (b > sp->patternindex.maxballs) { + sp->patternindex.index[sp->patternindex.maxballs].number = numpat; + if(numpat == 0) sp->patternindex.minballs = b; + sp->patternindex.maxballs = b; + numpat = 1; + sp->patternindex.index[sp->patternindex.maxballs].start = i; + } else { + numpat++; + } + } + sp->patternindex.index[sp->patternindex.maxballs].number = numpat; + } + + /* Set up programme */ + change_juggle(mi); + + /* Clean up the Screen. Don't use MI_CLEARWINDOW(mi), since we may + only be resizing and then we won't all those special effects. */ + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); + + /* Only put things here that won't interrupt the programme during + a window resize */ + + /* Use MIN so that users can resize in interesting ways, eg + narrow windows for tall patterns, etc */ + sp->scale = MIN(MI_HEIGHT(mi)/480.0, MI_WIDTH(mi)/160.0); + + if(describe && !sp->mode_font) { /* Check to see if there's room to describe patterns. */ + char *font = get_string_resource (MI_DISPLAY(mi), "font", "Font"); + sp->mode_font = XLoadQueryFont(MI_DISPLAY(mi), font); + } +} + +ENTRYPOINT void +reshape_juggle (ModeInfo * mi, int width, int height) +{ + init_juggle(mi); +} + +ENTRYPOINT void +draw_juggle (ModeInfo * mi) +{ + Trajectory *traj = NULL; + Object *o = NULL; + unsigned long future = 0; + jugglestruct *sp = NULL; + char *pattern = NULL; + double cx; + + if (juggles == NULL) + return; + sp = &juggles[MI_SCREEN(mi)]; + + MI_IS_DRAWN(mi) = True; + +#ifdef HAVE_COCOA + /* Don't worry about flicker, trust Quartz's double-buffering. + This is a fast fix for the pixel-turds I can't track down... + */ + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); +#endif + + /* Update timer */ + if (real) { + struct timeval tv; + (void)gettimeofday(&tv, NULL); + sp->time = (int) ((tv.tv_sec - sp->begintime)*1000 + tv.tv_usec/1000); + } else { + sp->time += MI_DELAY(mi) / 1000; + } + + /* First pass: Move arms and strip out expired elements */ + for (traj = sp->head->next; traj != sp->head; traj = traj->next) { + if (traj->status != PREDICTOR) { + /* Skip any elements that need further processing */ + /* We could remove them, but there shoudn't be many and they + would be needed if we ever got the pattern refiller + working */ + continue; + } + if (traj->start > future) { /* Lookahead to the end of the show */ + future = traj->start; + } + if (sp->time < traj->start) { /* early */ + continue; + } else if (sp->time < traj->finish) { /* working */ + + /* Look for pattern name */ + if(traj->pattern != NULL) { + pattern=traj->pattern; + } + + if (traj->type == Empty || traj->type == Full) { + /* Only interested in hands on this pass */ + double angle = traj->angle + traj->spin * (sp->time - traj->start); + double xd = 0, yd = 0; + DXPoint p; + + /* Find the catching offset */ + if(traj->object != NULL) { + if(ObjectDefs[traj->object->type].handle > 0) { + /* Handles Need to be oriented */ + xd = ObjectDefs[traj->object->type].handle * + PERSPEC * sin(angle); + yd = ObjectDefs[traj->object->type].handle * + cos(angle); + } else { + /* Balls are always caught at the bottom */ + xd = 0; + yd = -4; + } + } + p.x = (CUBIC(traj->xp, sp->time) - xd); + p.y = (CUBIC(traj->yp, sp->time) + yd); + reach_arm(mi, traj->hand, &p); + + /* Store updated hand position */ + traj->x = p.x + xd; + traj->y = p.y - yd; + } + if (traj->type == Ball || traj->type == Full) { + /* Only interested in objects on this pass */ + double x, y; + Trace *s; + + if(traj->type == Full) { + /* Adjusted these in the first pass */ + x = traj->x; + y = traj->y; + } else { + x = CUBIC(traj->xp, sp->time); + y = CUBIC(traj->yp, sp->time); + } + + ADD_ELEMENT(Trace, s, traj->object->trace->prev); + s->x = x; + s->y = y; + s->angle = traj->angle + traj->spin * (sp->time - traj->start); + s->divisions = traj->divisions; + traj->object->tracelen++; + traj->object->active = True; + } + } else { /* expired */ + Trajectory *n = traj; + traj=traj->prev; + trajectory_destroy(n); + } + } + + /* Erase end of trails */ + for (o = sp->objects->next; o != sp->objects; o = o->next) { + Trace *s; + for (s = o->trace->next; + o->trace->next != o->trace && + (o->count == 0 || o->tracelen > o->tail); + s = o->trace->next) { + ObjectDefs[o->type].draw(mi, MI_BLACK_PIXEL(mi), s); + REMOVE(s); + o->tracelen--; + if(o->count <= 0 && o->tracelen <= 0) { + /* Object no longer in use and trail gone */ + Object *n = o; + o = o->prev; + object_destroy(n); + } + if(o->count <= 0) break; /* Allow loop for catch-up, but not clean-up */ + } + } + + show_arms(mi, MI_BLACK_PIXEL(mi)); + cx = wander(sp, sp->time); + /* Reduce flicker by only permitting movements of more than a pixel */ + if(fabs((sp->cx - cx))*sp->scale >= 2.0 ) { + show_figure(mi, MI_BLACK_PIXEL(mi), False); + sp->cx = cx; + } + + show_figure(mi, MI_WHITE_PIXEL(mi), False); + + show_arms(mi, MI_WHITE_PIXEL(mi)); + + /* Draw Objects */ + for (o = sp->objects->next; o != sp->objects; o = o->next) { + if(o->active) { + ObjectDefs[o->type].draw(mi,MI_PIXEL(mi, o->color), o->trace->prev); + o->active = False; + } + } + + + /* Save pattern name so we can erase it when it changes */ + if(pattern != NULL && strcmp(sp->pattern, pattern) != 0 ) { + /* Erase old name */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); +# if 0 + XDrawString(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + 0, 20, sp->pattern, strlen(sp->pattern)); +# else + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + 0, 0, MI_WIDTH(mi), 25); +# endif + free(sp->pattern); + sp->pattern = strdup(pattern); + + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Juggle[%d]: Running: %s\n", + MI_SCREEN(mi), sp->pattern); + } + } + if(sp->mode_font != None && + XTextWidth(sp->mode_font, sp->pattern, strlen(sp->pattern)) < MI_WIDTH(mi)) { + /* Redraw once a cycle, in case it's obscured or it changed */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + XDrawImageString(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + 0, 20, sp->pattern, strlen(sp->pattern)); + } + +#ifdef MEMTEST + if((int)(sp->time/10) % 1000 == 0) + (void) fprintf(stderr, "sbrk: %d\n", (int)sbrk(0)); +#endif + + if (future < sp->time + 100 * THROW_CATCH_INTERVAL) { + refill_juggle(mi); + } else if (sp->time > 1<<30) { /* Hard Reset before the clock wraps */ + release_juggle(mi); + init_juggle(mi); + } +} + +XSCREENSAVER_MODULE ("Juggle", juggle) + +#endif /* MODE_juggle */ diff --git a/non-wgl/julia.c b/non-wgl/julia.c new file mode 100644 index 0000000..1180dfe --- /dev/null +++ b/non-wgl/julia.c @@ -0,0 +1,466 @@ +/* -*- Mode: C; tab-width: 4 -*- + * julia --- continuously varying Julia set. + */ +#if 0 +static const char sccsid[] = "@(#)julia.c 4.03 97/04/10 xlockmore"; +#endif + +/* Copyright (c) 1995 Sean McCullough . + * + * 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: + * 10-Jun-06: j.grahl@ucl.ac.uk: tweaked functions for parameter of Julia set + * 28-May-97: jwz@jwz.org: added interactive frobbing with the mouse. + * 10-May-97: jwz@jwz.org: turned into a standalone program. + * 02-Dec-95: snagged boilerplate from hop.c + * used ifs {w0 = sqrt(x-c), w1 = -sqrt(x-c)} with random iteration + * to plot the julia set, and sinusoidially varied parameter for set + * and plotted parameter with a circle. + */ + +/*- + * One thing to note is that batchcount is the *depth* of the search tree, + * so the number of points computed is 2^batchcount - 1. I use 8 or 9 + * on a dx266 and it looks okay. The sinusoidal variation of the parameter + * might not be as interesting as it could, but it still gives an idea of + * the effect of the parameter. + */ + +#define STANDALONE +#define HAVE_COCOA +#define NOARGS + +#define COUNT 1000 +#define CYCLES 20 +#define DELAY 10000 +#define NCOLORS 200 +# define DEFAULTS "*count: 1000 \n" \ + "*cycles: 20 \n" \ + "*delay: 10000 \n" \ + "*ncolors: 200 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define UNIFORM_COLORS + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* !STANDALONE */ + + +#define DEF_MOUSE "False" + +ENTRYPOINT ModeSpecOpt julia_opts = { 0, }; + + +#define numpoints ((0x2<depth)-1) + +typedef struct { + int centerx; + int centery; /* center of the screen */ + double cr; + double ci; /* julia params */ + int depth; + int inc; + int circsize; + int erase; + int pix; + long itree; + int buffer; + int nbuffers; + int redrawing, redrawpos; + Pixmap pixmap; +#ifndef HAVE_COCOA + Cursor cursor; +#endif + GC stippledGC; + XPoint **pointBuffer; /* pointer for XDrawPoints */ + Bool button_down_p; + int mouse_x, mouse_y; + +} juliastruct; + +static juliastruct *julias = NULL; + +/* How many segments to draw per cycle when redrawing */ +#define REDRAWSTEP 3 + +static void +apply(juliastruct * jp, register double xr, register double xi, int d) +{ + double theta, r; + + jp->pointBuffer[jp->buffer][jp->itree].x = + (int) (0.5 * xr * jp->centerx + jp->centerx); + jp->pointBuffer[jp->buffer][jp->itree].y = + (int) (0.5 * xi * jp->centery + jp->centery); + jp->itree++; + + if (d > 0) { + xi -= jp->ci; + xr -= jp->cr; + +/* Avoid atan2: DOMAIN error message */ + if (xi == 0.0 && xr == 0.0) + theta = 0.0; + else + theta = atan2(xi, xr) / 2.0; + + /*r = pow(xi * xi + xr * xr, 0.25); */ + r = sqrt(sqrt(xi * xi + xr * xr)); /* 3 times faster */ + + xr = r * cos(theta); + xi = r * sin(theta); + + d--; + apply(jp, xr, xi, d); + apply(jp, -xr, -xi, d); + } +} + +static void +incr(ModeInfo * mi, juliastruct * jp) +{ + if (jp->button_down_p) + { + jp->cr = ((double) (jp->mouse_x + 2 - jp->centerx)) * 2 / jp->centerx; + jp->ci = ((double) (jp->mouse_y + 2 - jp->centery)) * 2 / jp->centery; + } + else + { +#if 0 + jp->cr = 1.5 * (sin(M_PI * (jp->inc / 300.0)) * + sin(jp->inc * M_PI / 200.0)); + jp->ci = 1.5 * (cos(M_PI * (jp->inc / 300.0)) * + cos(jp->inc * M_PI / 200.0)); + + jp->cr += 0.5 * cos(M_PI * jp->inc / 400.0); + jp->ci += 0.5 * sin(M_PI * jp->inc / 400.0); +#else + jp->cr = 1.5 * (sin(M_PI * (jp->inc / 290.0)) * + sin(jp->inc * M_PI / 210.0)); + jp->ci = 1.5 * (cos(M_PI * (jp->inc / 310.0)) * + cos(jp->inc * M_PI / 190.0)); + + jp->cr += 0.5 * cos(M_PI * jp->inc / 395.0); + jp->ci += 0.5 * sin(M_PI * jp->inc / 410.0); +#endif + } +} + +ENTRYPOINT void +init_julia(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + juliastruct *jp; + XGCValues gcv; + int i; + + if (julias == NULL) { + if ((julias = (juliastruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (juliastruct))) == NULL) + return; + } + jp = &julias[MI_SCREEN(mi)]; + + jp->centerx = MI_WIN_WIDTH(mi) / 2; + jp->centery = MI_WIN_HEIGHT(mi) / 2; + + jp->depth = MI_BATCHCOUNT(mi); + if (jp->depth > 10) + jp->depth = 10; + + +#ifndef HAVE_COCOA + if (jp->button_down_p && !jp->cursor && !jp->cursor) + { + Pixmap bit; + XColor black; + black.red = black.green = black.blue = 0; + black.flags = DoRed|DoGreen|DoBlue; + bit = XCreatePixmapFromBitmapData (display, window, "\000", 1, 1, + MI_WIN_BLACK_PIXEL(mi), + MI_WIN_BLACK_PIXEL(mi), 1); + jp->cursor = XCreatePixmapCursor (display, bit, bit, &black, &black, + 0, 0); + XFreePixmap (display, bit); + } +#endif /* HAVE_COCOA */ + + if (jp->pixmap != None && + jp->circsize != (MIN(jp->centerx, jp->centery) / 60) * 2 + 1) { + XFreePixmap(display, jp->pixmap); + jp->pixmap = None; + } + if (jp->pixmap == None) { + GC fg_gc = None, bg_gc = None; + + jp->circsize = MAX(8, (MIN(jp->centerx, jp->centery) / 96) * 2 + 1); + jp->pixmap = XCreatePixmap(display, window, jp->circsize, jp->circsize, 1); + gcv.foreground = 1; + fg_gc = XCreateGC(display, jp->pixmap, GCForeground, &gcv); + gcv.foreground = 0; + bg_gc = XCreateGC(display, jp->pixmap, GCForeground, &gcv); + XFillRectangle(display, jp->pixmap, bg_gc, + 0, 0, jp->circsize, jp->circsize); + if (jp->circsize < 2) + XDrawPoint(display, jp->pixmap, fg_gc, 0, 0); + else + XFillArc(display, jp->pixmap, fg_gc, + 0, 0, jp->circsize, jp->circsize, 0, 23040); + if (fg_gc != None) + XFreeGC(display, fg_gc); + if (bg_gc != None) + XFreeGC(display, bg_gc); + } + +#ifndef HAVE_COCOA + if (MI_WIN_IS_INROOT(mi)) + ; + else if (jp->circsize > 0) + XDefineCursor (display, window, jp->cursor); + else + XUndefineCursor (display, window); +#endif /* HAVE_COCOA */ + + if (!jp->stippledGC) { + gcv.foreground = MI_WIN_BLACK_PIXEL(mi); + gcv.background = MI_WIN_BLACK_PIXEL(mi); + if ((jp->stippledGC = XCreateGC(display, window, + GCForeground | GCBackground, &gcv)) == None) + return; + } + if (MI_NPIXELS(mi) > 2) + jp->pix = NRAND(MI_NPIXELS(mi)); + jp->inc = ((LRAND() & 1) * 2 - 1) * NRAND(200); + jp->nbuffers = (MI_CYCLES(mi) + 1); + if (!jp->pointBuffer) + jp->pointBuffer = (XPoint **) calloc(jp->nbuffers, sizeof (XPoint *)); + for (i = 0; i < jp->nbuffers; ++i) + if (jp->pointBuffer[i]) + (void) memset((char *) jp->pointBuffer[i], 0, + numpoints * sizeof (XPoint)); + else + jp->pointBuffer[i] = (XPoint *) calloc(numpoints, sizeof (XPoint)); + jp->buffer = 0; + jp->redrawing = 0; + jp->erase = 0; + XClearWindow(display, window); +} + + +static void +reshape_julia (ModeInfo *mi, int w, int h) +{ + init_julia (mi); +} + +#if 0 + ENTRYPOINT Bool + julia_handle_event (ModeInfo *mi, XEvent *event) + { + juliastruct *jp = &julias[MI_SCREEN(mi)]; + + if (event->xany.type == ButtonPress && + event->xbutton.button == Button1) + { + jp->button_down_p = True; + jp->mouse_x = event->xbutton.x; + jp->mouse_y = event->xbutton.y; + return True; + } + else if (event->xany.type == ButtonRelease && + event->xbutton.button == Button1) + { + jp->button_down_p = False; + return True; + } + else if (event->xany.type == MotionNotify && jp->button_down_p) + { + jp->mouse_x = event->xmotion.x; + jp->mouse_y = event->xmotion.y; + return True; + } + + return False; + } +#endif + + +/* hack: moved here by jwz. */ +#define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \ +if (yly) \ +(y>yl-ys)?XFillRectangle(d,w,g,xl,y+ys,xs,yl-y): \ +XFillRectangle(d,w,g,xl,yl,xs,ys); \ +if (xlx) \ +(x>xl-xs)?XFillRectangle(d,w,g,x+xs,yl,xl-x,ys): \ +XFillRectangle(d,w,g,xl,yl,xs,ys) + + +ENTRYPOINT void +draw_julia (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + juliastruct *jp = &julias[MI_SCREEN(mi)]; + double r, theta; + register double xr = 0.0, xi = 0.0; + int k = 64, rnd = 0, i, j; + XPoint *xp = jp->pointBuffer[jp->buffer], old_circle, new_circle; + + old_circle.x = (int) (jp->centerx * jp->cr / 2) + jp->centerx - 2; + old_circle.y = (int) (jp->centery * jp->ci / 2) + jp->centery - 2; + incr(mi, jp); + new_circle.x = (int) (jp->centerx * jp->cr / 2) + jp->centerx - 2; + new_circle.y = (int) (jp->centery * jp->ci / 2) + jp->centery - 2; + XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi)); + XFillArc(display, window, gc, + old_circle.x-jp->circsize/2-2, + old_circle.y-jp->circsize/2-2, + jp->circsize+4, jp->circsize+4, + 0, 360*64); + /* draw a circle at the c-parameter so you can see it's effect on the + structure of the julia set */ + XSetForeground(display, jp->stippledGC, MI_WIN_WHITE_PIXEL(mi)); +#ifndef HAVE_COCOA + XSetTSOrigin(display, jp->stippledGC, new_circle.x, new_circle.y); + XSetStipple(display, jp->stippledGC, jp->pixmap); + XSetFillStyle(display, jp->stippledGC, FillOpaqueStippled); +#endif /* HAVE_COCOA */ + XDrawArc(display, window, jp->stippledGC, + new_circle.x-jp->circsize/2, + new_circle.y-jp->circsize/2, + jp->circsize, jp->circsize, + 0, 360*64); + + if (jp->erase == 1) { + XDrawPoints(display, window, gc, + jp->pointBuffer[jp->buffer], numpoints, CoordModeOrigin); + } + jp->inc++; + if (MI_NPIXELS(mi) > 2) { + XSetForeground(display, gc, MI_PIXEL(mi, jp->pix)); + if (++jp->pix >= MI_NPIXELS(mi)) + jp->pix = 0; + } else + XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi)); + while (k--) { + + /* save calls to LRAND by using bit shifts over and over on the same + int for 32 iterations, then get a new random int */ + if (!(k % 32)) + rnd = LRAND(); + + /* complex sqrt: x^0.5 = radius^0.5*(cos(theta/2) + i*sin(theta/2)) */ + + xi -= jp->ci; + xr -= jp->cr; + + /* Avoid atan2: DOMAIN error message */ + if (xi == 0.0 && xr == 0.0) + theta = 0.0; + else + theta = atan2(xi, xr) / 2.0; + + /*r = pow(xi * xi + xr * xr, 0.25); */ + r = sqrt(sqrt(xi * xi + xr * xr)); /* 3 times faster */ + + xr = r * cos(theta); + xi = r * sin(theta); + + if ((rnd >> (k % 32)) & 0x1) { + xi = -xi; + xr = -xr; + } + xp->x = jp->centerx + (int) ((jp->centerx >> 1) * xr); + xp->y = jp->centery + (int) ((jp->centery >> 1) * xi); + xp++; + } + + jp->itree = 0; + apply(jp, xr, xi, jp->depth); + + XDrawPoints(display, window, gc, + jp->pointBuffer[jp->buffer], numpoints, CoordModeOrigin); + + jp->buffer++; + if (jp->buffer > jp->nbuffers - 1) { + jp->buffer -= jp->nbuffers; + jp->erase = 1; + } + if (jp->redrawing) { + for (i = 0; i < REDRAWSTEP; i++) { + j = (jp->buffer - jp->redrawpos + jp->nbuffers) % jp->nbuffers; + XDrawPoints(display, window, gc, + jp->pointBuffer[j], numpoints, CoordModeOrigin); + + if (++(jp->redrawpos) >= jp->nbuffers) { + jp->redrawing = 0; + break; + } + } + } +} + +ENTRYPOINT void +release_julia (ModeInfo * mi) +{ + if (julias != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + Display *display = MI_DISPLAY(mi); + juliastruct *jp = &julias[screen]; + int buffer; + + if (jp->pointBuffer) { + for (buffer = 0; buffer < jp->nbuffers; buffer++) + if (jp->pointBuffer[buffer]) + (void) free((void *) jp->pointBuffer[buffer]); + (void) free((void *) jp->pointBuffer); + } + if (jp->stippledGC != None) + XFreeGC(display, jp->stippledGC); + if (jp->pixmap != None) + XFreePixmap(display, jp->pixmap); +#ifndef HAVE_COCOA + if (jp->cursor) + XFreeCursor (display, jp->cursor); +#endif + } + (void) free((void *) julias); + julias = NULL; + } +} + +ENTRYPOINT void +refresh_julia (ModeInfo * mi) +{ + juliastruct *jp = &julias[MI_SCREEN(mi)]; + + jp->redrawing = 1; + jp->redrawpos = 0; +} + +XSCREENSAVER_MODULE ("Julia", julia) diff --git a/non-wgl/julia.vcproj b/non-wgl/julia.vcproj new file mode 100644 index 0000000..a93056f --- /dev/null +++ b/non-wgl/julia.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/kumppa.c b/non-wgl/kumppa.c new file mode 100644 index 0000000..7137326 --- /dev/null +++ b/non-wgl/kumppa.c @@ -0,0 +1,561 @@ +/* + +Copyright (C) Teemu Suutari (temisu@utu.fi) Feb 1998 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ + + + + +/* + +*** This is contest-version. Don't look any further, code is *very* ugly. + +*/ + +#include "screenhack.h" +#include + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# include "xdbe.h" +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +char *background = "black"; +char *foreground = "white"; +float speed = 0.1; +int delay = 10000; +Bool random_ = True; +Bool useDBE = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&speed, "speed", NULL, "0.1", t_Float}, + {&delay, "delay", NULL, "10000", t_Int}, + {&random_, "random", NULL, "True", t_Bool}, + {&useDBE, "useDBE", NULL, "False", t_Bool}, +}; + +static const char *kumppa_defaults [] ={ + ".background: black", + "*fpsSolid: true", + "*speed: 0.1", + "*delay: 10000", + "*random: True", + /* leave this off by default, since it slows things down. -- jwz. */ + "*useDBE: False", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec kumppa_options [] = { + {"-delay", ".delay", XrmoptionSepArg, 0 }, + {"-speed", ".speed", XrmoptionSepArg, 0 }, + {"-random", ".random", XrmoptionNoArg, "True" }, + {"-no-random", ".random", XrmoptionNoArg, "False" }, + {"-db", ".useDBE", XrmoptionNoArg, "True" }, + {"-no-db", ".useDBE", XrmoptionNoArg, "False" }, + {0,0,0,0} +}; + +static const unsigned char colors[96]= + {0,0,255, 0,51,255, 0,102,255, 0,153,255, 0,204,255, + 0,255,255,0,255,204, 0,255,153, 0,255,102, 0,255,51, + 0,255,0, 51,255,0, 102,255,0, 153,255,0, 204,255,0, + 255,255,0, 255,204,0, 255,153,0, 255,102,0, 255,51,0, + 255,0,0, 255,0,51, 255,0,102, 255,0,153, 255,0,204, + 255,0,255, 219,0,255, 182,0,255, 146,0,255, 109,0,255, + 73,0,255, 37,0,255}; +static const float cosinus[8][6]= + {{-0.07,0.12,-0.06,32,25,37},{0.08,-0.03,0.05,51,46,32},{0.12,0.07,-0.13,27,45,36}, + {0.05,-0.04,-0.07,36,27,39},{-0.02,-0.07,0.1,21,43,42},{-0.11,0.06,0.02,51,25,34},{0.04,-0.15,0.02,42,32,25}, + {-0.02,-0.04,-0.13,34,20,15}}; + + +struct state { + Display *dpy; + Window win[2]; + + float acosinus[8][3]; + int coords[8]; + int ocoords[8]; + + GC fgc[33]; + GC cgc; + int sizx,sizy; + int midx,midy; + unsigned long delay; + Bool cosilines; + + int *Xrotations; + int *Yrotations; + int *Xrottable; + int *Yrottable; + + int *rotateX; + int *rotateY; + + int rotsizeX,rotsizeY; + int stateX,stateY; + + int rx,ry; + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + XdbeSwapInfo xdswp; + Bool usedouble; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + int draw_count; +}; + + +static int Satnum(int maxi) +{ + return (int)(maxi*frand(1)); +} + + +static void palaRotate(struct state *st, int x,int y) +{ + int ax,ay,bx,by,cx,cy; + + ax=st->rotateX[x]; + ay=st->rotateY[y]; + bx=st->rotateX[x+1]+2; + by=st->rotateY[y+1]+2; + cx=st->rotateX[x]-(y-st->ry)+x-st->rx; + cy=st->rotateY[y]+(x-st->rx)+y-st->ry; + if (cx<0) + { + ax-=cx; + cx=0; + } + if (cy<0) + { + ay-=cy; + cy=0; + } + if (cx+bx-ax>st->sizx) bx=ax-cx+st->sizx; + if (cy+by-ay>st->sizy) by=ay-cy+st->sizy; + if (axdpy,st->win[0],st->win[1],st->cgc,ax,ay,bx-ax,by-ay,cx,cy); +} + + +static void rotate(struct state *st) +{ + int x,y; + int dx,dy; + + st->rx=st->Xrottable[st->stateX+1]-st->Xrottable[st->stateX]; + st->ry=st->Yrottable[st->stateY+1]-st->Yrottable[st->stateY]; + + + for (x=0;x<=st->rx;x++) + st->rotateX[x]=(x)?st->midx-1-st->Xrotations[st->Xrottable[st->stateX+1]-x]:0; + for (x=0;x<=st->rx;x++) + st->rotateX[x+st->rx+1]=(x==st->rx)?st->sizx-1:st->midx+st->Xrotations[st->Xrottable[st->stateX]+x]; + for (y=0;y<=st->ry;y++) + st->rotateY[y]=(y)?st->midy-1-st->Yrotations[st->Yrottable[st->stateY+1]-y]:0; + for (y=0;y<=st->ry;y++) + st->rotateY[y+st->ry+1]=(y==st->ry)?st->sizy-1:st->midy+st->Yrotations[st->Yrottable[st->stateY]+y]; + + x=(st->rx>st->ry)?st->rx:st->ry; + for (dy=0;dy<(x+1)<<1;dy++) + for (dx=0;dx<(x+1)<<1;dx++) + { + y=(st->rx>st->ry)?st->ry-st->rx:0; + if (dy+y>=0 && dy<(st->ry+1)<<1 && dx<(st->rx+1)<<1) + if (dy+y+dx<=st->ry+st->rx && dy+y-dx<=st->ry-st->rx) + { + palaRotate(st, (st->rx<<1)+1-dx,dy+y); + palaRotate(st, dx,(st->ry<<1)+1-dy-y); + } + y=(st->ry>st->rx)?st->rx-st->ry:0; + if (dy+y>=0 && dx<(st->ry+1)<<1 && dy<(st->rx+1)<<1) + if (dy+y+dx<=st->ry+st->rx && dx-dy-y>=st->ry-st->rx) + { + palaRotate(st, dy+y,dx); + palaRotate(st, (st->rx<<1)+1-dy-y,(st->ry<<1)+1-dx); + } + } + st->stateX++; + if (st->stateX==st->rotsizeX) st->stateX=0; + st->stateY++; + if (st->stateY==st->rotsizeY) st->stateY=0; +} + + + +static Bool make_rots(struct state *st, double xspeed,double yspeed) +{ + int a,b,c,f,g,j,k=0,l; + double m,om,ok; + double d,ix,iy; + int maxi; + + Bool *chks; + + st->rotsizeX=(int)(2/xspeed+1); + ix=(double)(st->midx+1)/(double)(st->rotsizeX); + st->rotsizeY=(int)(2/yspeed+1); + iy=(double)(st->midy+1)/(double)(st->rotsizeY); + + st->Xrotations=malloc((st->midx+2)*sizeof(unsigned int)); + st->Xrottable=malloc((st->rotsizeX+1)*sizeof(unsigned int)); + st->Yrotations=malloc((st->midy+2)*sizeof(unsigned int)); + st->Yrottable=malloc((st->rotsizeY+1)*sizeof(unsigned int)); + chks=malloc(((st->midx>st->midy)?st->midx:st->midy)*sizeof(Bool)); + if (!st->Xrottable || !st->Yrottable || !st->Xrotations || !st->Yrotations || !chks) return False; + + + maxi=0; + c=0; + d=0; + g=0; + for (a=0;amidx;a++) chks[a]=True; + for (a=0;arotsizeX;a++) + { + st->Xrottable[a]=c; + f=(int)(d+ix)-g; /*viivojen lkm.*/ + g+=f; + if (g>st->midx) + { + f-=g-st->midx; + g=st->midx; + } + for (b=0;bmidx;j++) /*testi*/ + { + if (chks[j]) + { + om=0; + ok=1; + l=0; + while (j+lmidx && om+12*ok>m) + { + if (j-l>=0) if (chks[j-l]) om+=ok; + else; else if (chks[l-j]) om+=ok; + if (chks[j+l]) om+=ok; + ok/=1.5; + l++; + } + if (om>=m) + { + k=j; + m=om; + } + } + } + chks[k]=False; + l=c; + while (l>=st->Xrottable[a]) + { + if (l!=st->Xrottable[a]) st->Xrotations[l]=st->Xrotations[l-1]; + if (k>st->Xrotations[l] || l==st->Xrottable[a]) + { + st->Xrotations[l]=k; + c++; + l=st->Xrottable[a]; + } + l--; + } + } + d+=ix; + if (maxiXrottable[a]) maxi=c-st->Xrottable[a]; + } + st->Xrottable[a]=c; + st->rotateX=malloc((maxi+2)*sizeof(int)<<1); + if (!st->rotateX) return False; + + maxi=0; + c=0; + d=0; + g=0; + for (a=0;amidy;a++) chks[a]=True; + for (a=0;arotsizeY;a++) + { + st->Yrottable[a]=c; + f=(int)(d+iy)-g; /*viivojen lkm.*/ + g+=f; + if (g>st->midy) + { + f-=g-st->midy; + g=st->midy; + } + for (b=0;bmidy;j++) /*testi*/ + { + if (chks[j]) + { + om=0; + ok=1; + l=0; + while (j+lmidy && om+12*ok>m) + { + if (j-l>=0) if (chks[j-l]) om+=ok; + else; else if (chks[l-j]) om+=ok; + if (chks[j+l]) om+=ok; + ok/=1.5; + l++; + } + if (om>=m) + { + k=j; + m=om; + } + } + } + chks[k]=False; + l=c; + while (l>=st->Yrottable[a]) + { + if (l!=st->Yrottable[a]) st->Yrotations[l]=st->Yrotations[l-1]; + if (k>st->Yrotations[l] || l==st->Yrottable[a]) + { + st->Yrotations[l]=k; + c++; + l=st->Yrottable[a]; + } + l--; + } + + } + d+=iy; + if (maxiYrottable[a]) maxi=c-st->Yrottable[a]; + } + st->Yrottable[a]=c; + st->rotateY=malloc((maxi+2)*sizeof(int)<<1); + if (!st->rotateY) return False; + + free(chks); + return (True); +} + + +static Bool InitializeAll(struct state *st) +{ + XGCValues xgcv; + XWindowAttributes xgwa; +/* XSetWindowAttributes xswa;*/ + Colormap cmap; + XColor color; + int n,i; + double rspeed; + + st->cosilines = True; + + XGetWindowAttributes(st->dpy,st->win[0],&xgwa); + cmap=xgwa.colormap; +/* xswa.backing_store=Always; + XChangeWindowAttributes(st->dpy,st->win[0],CWBackingStore,&xswa);*/ + xgcv.function=GXcopy; + + //xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background"); + xgcv.foreground=load_color(st->dpy, cmap, background); + st->fgc[32]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv); + + n=0; + if (mono_p) + { + st->fgc[0]=st->fgc[32]; + //xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground"); + xgcv.foreground=load_color(st->dpy, cmap, foreground); + st->fgc[1]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv); + for (i=0;i<32;i+=2) st->fgc[i]=st->fgc[0]; + for (i=1;i<32;i+=2) st->fgc[i]=st->fgc[1]; + } else + for (i=0;i<32;i++) + { + color.red=colors[n++]<<8; + color.green=colors[n++]<<8; + color.blue=colors[n++]<<8; + color.flags=DoRed|DoGreen|DoBlue; + XAllocColor(st->dpy,cmap,&color); + xgcv.foreground=color.pixel; + st->fgc[i]=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv); + } + st->cgc=XCreateGC(st->dpy,st->win[0],GCForeground|GCFunction,&xgcv); + XSetGraphicsExposures(st->dpy,st->cgc,False); + + //st->cosilines = get_boolean_resource(st->dpy, "random","Boolean"); + st->cosilines = random_; + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + //if (get_boolean_resource (st->dpy, "useDBE", "Boolean")) + if (useDBE) + st->usedouble = True; + st->win[1] = xdbe_get_backbuffer (st->dpy, st->win[0], XdbeUndefined); + if (!st->win[1]) + { + st->usedouble = False; + st->win[1] = st->win[0]; + } +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + //st->delay=get_integer_resource(st->dpy, "delay","Integer"); + //rspeed=get_float_resource(st->dpy, "speed","Float"); + st->delay=delay; + rspeed=speed; + if (rspeed<0.0001 || rspeed>0.2) + { + fprintf(stderr,"Speed not in valid range! (0.0001 - 0.2), using 0.1 \n"); + rspeed=0.1; + } + + st->sizx=xgwa.width; + st->sizy=xgwa.height; + st->midx=st->sizx>>1; + st->midy=st->sizy>>1; + st->stateX=0; + st->stateY=0; + + if (!make_rots(st,rspeed,rspeed)) + { + fprintf(stderr,"Not enough memory for tables!\n"); + return False; + } + return True; +} + +static void * +kumppa_init (Display *d, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy=d; + st->win[0]=w; + if (!InitializeAll(st)) abort(); + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (st->usedouble) + { + st->xdswp.swap_action=XdbeUndefined; + st->xdswp.swap_window=st->win[0]; + } + else +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + st->win[1]=st->win[0]; + + return st; +} + +static unsigned long +kumppa_draw (Display *d, Window w, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->cosilines) + { + int a; + st->draw_count++; + for (a=0;a<8;a++) + { + float f=0; + int b; + for (b=0;b<3;b++) + { + st->acosinus[a][b]+=cosinus[a][b]; + f+=cosinus[a][b+3]*sin((double)st->acosinus[a][b]); + } + st->coords[a]=(int)f; + } + for (a=0;a<4;a++) + { + XDrawLine(st->dpy,st->win[0],(mono_p)?st->fgc[1]:st->fgc[((a<<2)+st->draw_count)&31],st->midx+st->ocoords[a<<1],st->midy+st->ocoords[(a<<1)+1] + ,st->midx+st->coords[a<<1],st->midy+st->coords[(a<<1)+1]); + st->ocoords[a<<1]=st->coords[a<<1]; + st->ocoords[(a<<1)+1]=st->coords[(a<<1)+1]; + } + + } else { + int e; + for (e=0;e<8;e++) + { + int a=Satnum(50); + int b; + if (a>=32) a=32; + b=Satnum(32)-16+st->midx; + st->draw_count=Satnum(32)-16+st->midy; + XFillRectangle(st->dpy,st->win[0],st->fgc[a],b,st->draw_count,2,2); + } + } + XFillRectangle(st->dpy,st->win[0],st->fgc[32],st->midx-2,st->midy-2,4,4); + rotate(st); +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (st->usedouble) XdbeSwapBuffers(st->dpy,&st->xdswp,1); +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + return st->delay; +} + + +static void +kumppa_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->sizx=w; + st->sizy=w; + st->midx=st->sizx>>1; + st->midy=st->sizy>>1; + st->stateX=0; + st->stateY=0; +} + +#if 0 + static Bool + kumppa_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +kumppa_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + for (i = 0; i < countof(st->fgc); i++) + if (st->fgc[i]) XFreeGC (dpy, st->fgc[i]); + XFreeGC (dpy, st->cgc); + free (st->Xrotations); + free (st->Yrotations); + free (st->Xrottable); + free (st->Yrottable); + free (st); +} + +XSCREENSAVER_MODULE ("Kumppa", kumppa) diff --git a/non-wgl/kumppa.vcproj b/non-wgl/kumppa.vcproj new file mode 100644 index 0000000..7246103 --- /dev/null +++ b/non-wgl/kumppa.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/laser.c b/non-wgl/laser.c new file mode 100644 index 0000000..99c0304 --- /dev/null +++ b/non-wgl/laser.c @@ -0,0 +1,373 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* laser --- spinning lasers */ + +#if 0 +static const char sccsid[] = "@(#)laser.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1995 Pascal Pensa + * + * 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 + * 1995: Written. + */ + +#define STANDALONE +#define NOARGS + +# define MODE_laser +#define DELAY 40000 +#define COUNT 10 +#define CYCLES 200 +#define NCOLORS 64 +# define DEFAULTS "*delay: 40000 \n" \ + "*count: 10 \n" \ + "*cycles: 200 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + +# define BRIGHT_COLORS +# define reshape_laser 0 +# define laser_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_laser + +ENTRYPOINT ModeSpecOpt laser_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct laser_description = +{"laser", "init_laser", "draw_laser", "release_laser", + "refresh_laser", "init_laser", (char *) NULL, &laser_opts, + 20000, -10, 200, 1, 64, 1.0, "", + "Shows spinning lasers", 0, NULL}; +#endif + +#define MINREDRAW 3 /* Number of redrawn on each frame */ +#define MAXREDRAW 8 + +#define MINLASER 1 /* Laser number */ + +#define MINWIDTH 2 /* Laser ray width range */ +#define MAXWIDTH 40 + +#define MINSPEED 2 /* Speed range */ +#define MAXSPEED 17 + +#define MINDIST 10 /* Minimal distance from edges */ + +#define COLORSTEP 2 /* Laser color step */ + +#define RANGE_RAND(min,max) (int) ((min) + LRAND() % ((max) - (min))) + +typedef enum { + TOP, RIGHT, BOTTOM, LEFT +} border; + +typedef struct { + int bx; /* border x */ + int by; /* border y */ + border bn; /* active border */ + int dir; /* direction */ + int speed; /* laser velocity from MINSPEED to MAXSPEED */ + int sx[MAXWIDTH]; /* x stack */ + int sy[MAXWIDTH]; /* x stack */ + XGCValues gcv; /* for color */ +} laserstruct; + +typedef struct { + int width; + int height; + int cx; /* center x */ + int cy; /* center y */ + int lw; /* laser width */ + int ln; /* laser number */ + int lr; /* laser redraw */ + int sw; /* stack width */ + int so; /* stack offset */ + int time; /* up time */ + GC stippledGC; + XGCValues gcv_black; /* for black color */ + laserstruct *laser; +} lasersstruct; + +static lasersstruct *lasers = (lasersstruct *) NULL; + +static void +free_laser(Display *display, lasersstruct *lp) +{ + if (lp->laser != NULL) { + (void) free((void *) lp->laser); + lp->laser = (laserstruct *) NULL; + } + if (lp->stippledGC != None) { + XFreeGC(display, lp->stippledGC); + lp->stippledGC = None; + } +} + +ENTRYPOINT void +init_laser(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + int i, c = 0; + lasersstruct *lp; + + if (lasers == NULL) { + if ((lasers = (lasersstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (lasersstruct))) == NULL) + return; + } + lp = &lasers[MI_SCREEN(mi)]; + + lp->width = MI_WIDTH(mi); + lp->height = MI_HEIGHT(mi); + lp->time = 0; + + lp->ln = MI_COUNT(mi); + if (lp->ln < -MINLASER) { + /* if lp->ln is random ... the size can change */ + if (lp->laser != NULL) { + (void) free((void *) lp->laser); + lp->laser = (laserstruct *) NULL; + } + lp->ln = NRAND(-lp->ln - MINLASER + 1) + MINLASER; + } else if (lp->ln < MINLASER) + lp->ln = MINLASER; + + if (lp->laser == NULL) { + if ((lp->laser = (laserstruct *) malloc(lp->ln * + sizeof (laserstruct))) == NULL) { + free_laser(display, lp); + return; + } + } + if (lp->stippledGC == None) { + XGCValues gcv; + + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + lp->gcv_black.foreground = MI_BLACK_PIXEL(mi); + if ((lp->stippledGC = XCreateGC(display, MI_WINDOW(mi), + GCForeground | GCBackground, &gcv)) == None) { + free_laser(display, lp); + return; + } +# ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), lp->stippledGC, False); +# endif + } + MI_CLEARWINDOW(mi); + + if (MINDIST < lp->width - MINDIST) + lp->cx = RANGE_RAND(MINDIST, lp->width - MINDIST); + else + lp->cx = RANGE_RAND(0, lp->width); + if (MINDIST < lp->height - MINDIST) + lp->cy = RANGE_RAND(MINDIST, lp->height - MINDIST); + else + lp->cy = RANGE_RAND(0, lp->height); + lp->lw = RANGE_RAND(MINWIDTH, MAXWIDTH); + lp->lr = RANGE_RAND(MINREDRAW, MAXREDRAW); + lp->sw = 0; + lp->so = 0; + + if (MI_NPIXELS(mi) > 2) + c = NRAND(MI_NPIXELS(mi)); + + for (i = 0; i < lp->ln; i++) { + laserstruct *l = &lp->laser[i]; + + l->bn = (border) NRAND(4); + + switch (l->bn) { + case TOP: + l->bx = NRAND(lp->width); + l->by = 0; + break; + case RIGHT: + l->bx = lp->width; + l->by = NRAND(lp->height); + break; + case BOTTOM: + l->bx = NRAND(lp->width); + l->by = lp->height; + break; + case LEFT: + l->bx = 0; + l->by = NRAND(lp->height); + } + + l->dir = (int) (LRAND() & 1); + l->speed = ((RANGE_RAND(MINSPEED, MAXSPEED) * lp->width) / 1000) + 1; + if (MI_NPIXELS(mi) > 2) { + l->gcv.foreground = MI_PIXEL(mi, c); + c = (c + COLORSTEP) % MI_NPIXELS(mi); + } else + l->gcv.foreground = MI_WHITE_PIXEL(mi); + } +} + +static void +draw_laser_once(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + lasersstruct *lp = &lasers[MI_SCREEN(mi)]; + int i; + + for (i = 0; i < lp->ln; i++) { + laserstruct *l = &lp->laser[i]; + + if (lp->sw >= lp->lw) { + XChangeGC(display, lp->stippledGC, GCForeground, &(lp->gcv_black)); + XDrawLine(display, MI_WINDOW(mi), lp->stippledGC, + lp->cx, lp->cy, + l->sx[lp->so], l->sy[lp->so]); + } + if (l->dir) { + switch (l->bn) { + case TOP: + l->bx -= l->speed; + if (l->bx < 0) { + l->by = -l->bx; + l->bx = 0; + l->bn = LEFT; + } + break; + case RIGHT: + l->by -= l->speed; + if (l->by < 0) { + l->bx = lp->width + l->by; + l->by = 0; + l->bn = TOP; + } + break; + case BOTTOM: + l->bx += l->speed; + if (l->bx >= lp->width) { + l->by = lp->height - l->bx % lp->width; + l->bx = lp->width; + l->bn = RIGHT; + } + break; + case LEFT: + l->by += l->speed; + if (l->by >= lp->height) { + l->bx = l->by % lp->height; + l->by = lp->height; + l->bn = BOTTOM; + } + } + } else { + switch (l->bn) { + case TOP: + l->bx += l->speed; + if (l->bx >= lp->width) { + l->by = l->bx % lp->width; + l->bx = lp->width; + l->bn = RIGHT; + } + break; + case RIGHT: + l->by += l->speed; + if (l->by >= lp->height) { + l->bx = lp->width - l->by % lp->height; + l->by = lp->height; + l->bn = BOTTOM; + } + break; + case BOTTOM: + l->bx -= l->speed; + if (l->bx < 0) { + l->by = lp->height + l->bx; + l->bx = 0; + l->bn = LEFT; + } + break; + case LEFT: + l->by -= l->speed; + if (l->by < 0) { + l->bx = -l->bx; + l->by = 0; + l->bn = TOP; + } + } + } + + XChangeGC(display, lp->stippledGC, GCForeground, &l->gcv); + XDrawLine(display, MI_WINDOW(mi), lp->stippledGC, + lp->cx, lp->cy, l->bx, l->by); + + l->sx[lp->so] = l->bx; + l->sy[lp->so] = l->by; + + } + + if (lp->sw < lp->lw) + ++lp->sw; + + lp->so = (lp->so + 1) % lp->lw; +} + +ENTRYPOINT void +draw_laser(ModeInfo * mi) +{ + int i; + lasersstruct *lp; + + if (lasers == NULL) + return; + lp = &lasers[MI_SCREEN(mi)]; + if (lp->laser == NULL) + return; + + MI_IS_DRAWN(mi) = True; + for (i = 0; i < lp->lr; i++) + draw_laser_once(mi); + + if (++lp->time > MI_CYCLES(mi)) + init_laser(mi); +} + +ENTRYPOINT void +release_laser(ModeInfo * mi) +{ + if (lasers != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_laser(MI_DISPLAY(mi), &lasers[screen]); + (void) free((void *) lasers); + lasers = (lasersstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_laser(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Laser", laser) + +#endif /* MODE_laser */ diff --git a/non-wgl/laser.vcproj b/non-wgl/laser.vcproj new file mode 100644 index 0000000..af3ccf5 --- /dev/null +++ b/non-wgl/laser.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/lcdscrub.c b/non-wgl/lcdscrub.c new file mode 100644 index 0000000..4679b17 --- /dev/null +++ b/non-wgl/lcdscrub.c @@ -0,0 +1,284 @@ +/* xscreensaver, Copyright (c) 2008-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. + * + * Draws repetitive patterns that should undo burned in LCD screens. + * Concept shamelessly cloned from + * http://toastycode.com/blog/2008/02/05/lcd-scrub/ + */ + +#include "screenhack.h" + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +char *background = "black"; +char *foreground = "white"; +int delay = 100000; +int spread = 8; +int cycles = 60; +Bool modeHW = True; +Bool modeHB = True; +Bool modeVW = True; +Bool modeVB = True; +Bool modeDW = True; +Bool modeDB = True; +Bool modeW = True; +Bool modeB = True; +Bool modeRGB = True; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "100000", t_Int}, + {&spread, "spread", NULL, "8", t_Int}, + {&cycles, "cycles", NULL, "60", t_Int}, + {&modeHW, "modeHW", NULL, "True", t_Bool}, + {&modeHB, "modeHB", NULL, "True", t_Bool}, + {&modeVW, "modeVW", NULL, "True", t_Bool}, + {&modeVB, "modeVB", NULL, "True", t_Bool}, + {&modeDW, "modeDW", NULL, "True", t_Bool}, + {&modeDB, "modeDB", NULL, "True", t_Bool}, + {&modeW, "modeW", NULL, "True", t_Bool}, + {&modeB, "modeB", NULL, "True", t_Bool}, + {&modeRGB, "modeRGB", NULL, "True", t_Bool}, +}; + +struct state { + Display *dpy; + Window window; + XWindowAttributes xgwa; + enum { HORIZ_W, HORIZ_B, + VERT_W, VERT_B, + DIAG_W, DIAG_B, + WHITE, BLACK, + RGB, + END } mode; + unsigned int enabled_mask; + int count; + GC fg, bg, bg2; + int color_tick; + int delay; + int spread; + int cycles; +}; + + +static void +pick_mode (struct state *st) +{ + st->count = 0; + while (1) + { + if (++st->mode == END) + st->mode = 0; + if (st->enabled_mask & (1 << st->mode)) + break; + } +} + +static void * +lcdscrub_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->spread = get_integer_resource (st->dpy, "spread", "Integer"); + //st->cycles = get_integer_resource (st->dpy, "cycles", "Integer"); + st->delay = delay; + st->spread = spread; + st->cycles = cycles; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + gcv.foreground = BlackPixelOfScreen (st->xgwa.screen); + gcv.background = WhitePixelOfScreen (st->xgwa.screen); + st->bg = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + st->bg2 = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + gcv.foreground = WhitePixelOfScreen (st->xgwa.screen); + gcv.background = BlackPixelOfScreen (st->xgwa.screen); + st->fg = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (st->dpy, st->fg, False); + jwxyz_XSetAntiAliasing (st->dpy, st->bg, False); + jwxyz_XSetAntiAliasing (st->dpy, st->bg2, False); +#endif + + st->enabled_mask = 0; +#if 1 + # define PREF(R,F) \ + if (R) st->enabled_mask |= (1 << F) +#else + # define PREF(R,F) \ + if (get_boolean_resource (st->dpy, R, "Mode")) st->enabled_mask |= (1 << F) +#endif + PREF("modeHW", HORIZ_W); + PREF("modeHB", HORIZ_B); + PREF("modeVW", VERT_W); + PREF("modeVB", VERT_B); + PREF("modeDW", DIAG_W); + PREF("modeDB", DIAG_B); + PREF("modeW", WHITE); + PREF("modeB", BLACK); + PREF("modeRGB", RGB); +# undef PREF + if (! st->enabled_mask) + { + fprintf (stderr, "%s: no modes enabled\n", progname); + exit (1); + } + + pick_mode (st); + + return st; +} + +static unsigned long +lcdscrub_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int count = st->count % st->spread; + int i; + GC fg = (st->mode & 1 ? st->fg : st->bg); + GC bg = (st->mode & 1 ? st->bg : st->fg); + + switch (st->mode) { + case HORIZ_W: + case HORIZ_B: + XFillRectangle (st->dpy, st->window, bg, 0, 0, + st->xgwa.width, st->xgwa.height); + for (i = count; i < st->xgwa.height; i += st->spread) + XDrawLine (st->dpy, st->window, fg, 0, i, st->xgwa.width, i); + break; + case VERT_W: + case VERT_B: + XFillRectangle (st->dpy, st->window, bg, 0, 0, + st->xgwa.width, st->xgwa.height); + for (i = count; i < st->xgwa.width; i += st->spread) + XDrawLine (st->dpy, st->window, fg, i, 0, i, st->xgwa.height); + break; + case DIAG_W: + case DIAG_B: + XFillRectangle (st->dpy, st->window, bg, 0, 0, + st->xgwa.width, st->xgwa.height); + for (i = count; i < st->xgwa.width; i += st->spread) + XDrawLine (st->dpy, st->window, fg, i, 0, + i + st->xgwa.width, st->xgwa.width); + for (i = -count; i < st->xgwa.height; i += st->spread) + XDrawLine (st->dpy, st->window, fg, 0, i, + st->xgwa.height, i + st->xgwa.height); + break; + case RGB: + { + int scale = 10 * 8; /* 8 sec */ + static const unsigned short colors[][3] = { + { 0xFFFF, 0x0000, 0x0000 }, + { 0x0000, 0xFFFF, 0x0000 }, + { 0x0000, 0x0000, 0xFFFF }, + { 0xFFFF, 0xFFFF, 0x0000 }, + { 0xFFFF, 0x0000, 0xFFFF }, + { 0x0000, 0xFFFF, 0xFFFF }, + { 0xFFFF, 0xFFFF, 0xFFFF }, + { 0x0000, 0x0000, 0x0000 }, + }; + static unsigned long last = 0; + XColor xc; + bg = st->bg2; + xc.red = colors[st->color_tick / scale][0]; + xc.green = colors[st->color_tick / scale][1]; + xc.blue = colors[st->color_tick / scale][2]; + if (last) XFreeColors (st->dpy, st->xgwa.colormap, &last, 1, 0); + XAllocColor (st->dpy, st->xgwa.colormap, &xc); + last = xc.pixel; + XSetForeground (st->dpy, bg, xc.pixel); + st->color_tick = (st->color_tick + 1) % (countof(colors) * scale); + /* fall through */ + } + case WHITE: + case BLACK: + XFillRectangle (st->dpy, st->window, bg, 0, 0, + st->xgwa.width, st->xgwa.height); + break; + default: + abort(); + break; + } + + st->count++; + + if (st->count > st->spread * st->cycles) + pick_mode (st); + + return st->delay; +} + +static void +lcdscrub_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + lcdscrub_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +lcdscrub_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XFreeGC (dpy, st->fg); + XFreeGC (dpy, st->bg); + XFreeGC (dpy, st->bg2); + free (st); +} + + +static const char *lcdscrub_defaults [] = { + ".background: black", + ".foreground: white", + "*delay: 100000", + "*spread: 8", + "*cycles: 60", + "*modeHW: True", + "*modeHB: True", + "*modeVW: True", + "*modeVB: True", + "*modeDW: True", + "*modeDB: True", + "*modeW: True", + "*modeB: True", + "*modeRGB: True", + 0 +}; + +static XrmOptionDescRec lcdscrub_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-spread", ".spread", XrmoptionSepArg, 0 }, + { "-cycles", ".cycles", XrmoptionSepArg, 0 }, + { "-no-hw", ".modeHW", XrmoptionNoArg, "False" }, + { "-no-hb", ".modeHB", XrmoptionNoArg, "False" }, + { "-no-vw", ".modeVW", XrmoptionNoArg, "False" }, + { "-no-vb", ".modeVB", XrmoptionNoArg, "False" }, + { "-no-dw", ".modeDW", XrmoptionNoArg, "False" }, + { "-no-db", ".modeDB", XrmoptionNoArg, "False" }, + { "-no-w", ".modeW", XrmoptionNoArg, "False" }, + { "-no-b", ".modeB", XrmoptionNoArg, "False" }, + { "-no-rgb", ".modeRGB", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("LCDscrub", lcdscrub) diff --git a/non-wgl/lcdscrub.vcproj b/non-wgl/lcdscrub.vcproj new file mode 100644 index 0000000..042978f --- /dev/null +++ b/non-wgl/lcdscrub.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/lightning.c b/non-wgl/lightning.c new file mode 100644 index 0000000..db24be4 --- /dev/null +++ b/non-wgl/lightning.c @@ -0,0 +1,619 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* lightning --- fractal lightning bolds */ + +#if 0 +static const char sccsid[] = "@(#)lightning.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1996 by Keith Romberg + * + * 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 + * 14-Jul-1996: Cleaned up code. + * 27-Jun-1996: Written and submitted by Keith Romberg . + */ + +#define STANDALONE +#define NOARGS + +# define MODE_lightning +#define DELAY 10000 +#define NCOLORS 64 +# define DEFAULTS "*delay: 10000 \n" \ + "*ncolors: 64 \n" + +# define BRIGHT_COLORS +# define reshape_lightning 0 +# define lightning_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_lightning + +ENTRYPOINT ModeSpecOpt lightning_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct lightning_description = +{"lightning", "init_lightning", "draw_lightning", "release_lightning", + "refresh_lightning", "init_lightning", (char *) NULL, &lightning_opts, + 10000, 1, 1, 1, 64, 0.6, "", + "Shows Keith's fractal lightning bolts", 0, NULL}; +#endif + +#define BOLT_NUMBER 4 +#define BOLT_ITERATION 4 +#define LONG_FORK_ITERATION 3 +#define MEDIUM_FORK_ITERATION 2 +#define SMALL_FORK_ITERATION 1 + +#define WIDTH_VARIATION 30 +#define HEIGHT_VARIATION 15 + +#define DELAY_TIME_AMOUNT 15 +#define MULTI_DELAY_TIME_BASE 5 + +#define MAX_WIGGLES 16 +#define WIGGLE_BASE 8 +#define WIGGLE_AMOUNT 14 + +#define RANDOM_FORK_PROBILITY 4 + +#define FIRST_LEVEL_STRIKE 0 +#define LEVEL_ONE_STRIKE 1 +#define LEVEL_TWO_STRIKE 2 + +#define BOLT_VERTICIES ((1<= 51) && (multi_prob < 75)) + result = 2; + else if ((multi_prob >= 76) && (multi_prob < 92)) + result = 3; + else + result = BOLT_NUMBER; /* 4 */ + + return (result); +} + +/*-------------------------------------------------------------------------*/ + +static int +flashing_strike(void) +{ + int tmp = NRAND(FLASH_PROBILITY); + + if (tmp <= FLASH_PROBILITY) + return (1); + return (0); +} + +/*-------------------------------------------------------------------------*/ + +static void +flash_duration(int *start, int *end, int total_duration) +{ + int mid, d; + + mid = total_duration / MAX_FLASH_AMOUNT; + d = NRAND(total_duration / MAX_FLASH_AMOUNT) / 2; + *start = mid - d; + *end = mid + d; +} + +/*-------------------------------------------------------------------------*/ + +static void +random_storm(Storm * st) +{ + int i, j, tmp; + XPoint p; + + for (i = 0; i < st->multi_strike; i++) { + st->bolts[i].end1.x = NRAND(st->scr_width); + st->bolts[i].end1.y = 0; + st->bolts[i].end2.x = NRAND(st->scr_width); + st->bolts[i].end2.y = st->scr_height; + st->bolts[i].wiggle_number = WIGGLE_BASE + NRAND(MAX_WIGGLES); + if ((st->bolts[i].flash = flashing_strike())) + flash_duration(&(st->bolts[i].flash_begin), &(st->bolts[i].flash_stop), + st->bolts[i].wiggle_number); + else + st->bolts[i].flash_begin = st->bolts[i].flash_stop = 0; + st->bolts[i].wiggle_amount = WIGGLE_AMOUNT; + if (i == 0) + st->bolts[i].delay_time = NRAND(DELAY_TIME_AMOUNT); + else + st->bolts[i].delay_time = NRAND(DELAY_TIME_AMOUNT) + + (MULTI_DELAY_TIME_BASE * i); + st->bolts[i].strike_level = FIRST_LEVEL_STRIKE; + tmp = 0; + generate(st->bolts[i].end1, st->bolts[i].end2, BOLT_ITERATION, + st->bolts[i].middle, &tmp); + st->bolts[i].fork_number = 0; + st->bolts[i].visible = 0; + for (j = 0; j < BOLT_VERTICIES; j++) { + if (st->bolts[i].fork_number >= 2) + break; + if (NRAND(100) < RANDOM_FORK_PROBILITY) { + p.x = NRAND(st->scr_width); + p.y = st->scr_height; + st->bolts[i].forks_start[st->bolts[i].fork_number] = j; + create_fork(&(st->bolts[i].branch[st->bolts[i].fork_number]), + st->bolts[i].middle[j], p, j); + st->bolts[i].fork_number++; + } + } + } +} + +static void +generate(XPoint A, XPoint B, int iter, XPoint * verts, int *vert_index) +{ + XPoint mid; + + mid.x = (A.x + B.x) / 2 + NRAND(WIDTH_VARIATION) - WIDTH_VARIATION / 2; + mid.y = (A.y + B.y) / 2 + NRAND(HEIGHT_VARIATION) - HEIGHT_VARIATION / 2; + + if (!iter) { + verts[*vert_index].x = mid.x; + verts[*vert_index].y = mid.y; + (*vert_index)++; + return; + } + generate(A, mid, iter - 1, verts, vert_index); + generate(mid, B, iter - 1, verts, vert_index); +} + +/*------------------------------------------------------------------------*/ + +static void +create_fork(Fork * f, XPoint start, XPoint end, int level) +{ + int tmp = 1; + + f->ForkVerticies[0].x = start.x; + f->ForkVerticies[0].y = start.y; + + if (level <= 6) { + generate(start, end, LONG_FORK_ITERATION, f->ForkVerticies, &tmp); + f->num_used = 9; + } else if ((level > 6) && (level <= 11)) { + generate(start, end, MEDIUM_FORK_ITERATION, f->ForkVerticies, &tmp); + f->num_used = 5; + } else { + if (distance(start, end) > 100) { + generate(start, end, MEDIUM_FORK_ITERATION, f->ForkVerticies, &tmp); + f->num_used = 5; + } else { + generate(start, end, SMALL_FORK_ITERATION, f->ForkVerticies, &tmp); + f->num_used = 3; + } + } + + f->ForkVerticies[f->num_used - 1].x = end.x; + f->ForkVerticies[f->num_used - 1].y = end.y; +} + +/*------------------------------------------------------------------------*/ + +static void +update_bolt(Lightning * bolt, int time_now) +{ + wiggle_bolt(bolt); + if ((bolt->wiggle_amount == 0) && (bolt->wiggle_number > 2)) + bolt->wiggle_number = 0; + if (((time_now % 3) == 0)) + bolt->wiggle_amount++; + + if (((time_now >= bolt->delay_time) && (time_now < bolt->flash_begin)) || + (time_now > bolt->flash_stop)) + bolt->visible = 1; + else + bolt->visible = 0; + + if (time_now == bolt->delay_time) + bolt->strike_level = FIRST_LEVEL_STRIKE; + else if (time_now == (bolt->delay_time + 1)) + bolt->strike_level = LEVEL_ONE_STRIKE; + else if ((time_now > (bolt->delay_time + 1)) && + (time_now <= (bolt->delay_time + bolt->flash_begin - 2))) + bolt->strike_level = LEVEL_TWO_STRIKE; + else if (time_now == (bolt->delay_time + bolt->flash_begin - 1)) + bolt->strike_level = LEVEL_ONE_STRIKE; + else if (time_now == (bolt->delay_time + bolt->flash_stop + 1)) + bolt->strike_level = LEVEL_ONE_STRIKE; + else + bolt->strike_level = LEVEL_TWO_STRIKE; +} + +/*------------------------------------------------------------------------*/ + +static void +draw_bolt(Lightning * bolt, ModeInfo * mi) +{ + if (bolt->visible) { + if (bolt->strike_level == FIRST_LEVEL_STRIKE) + first_strike(*bolt, mi); + else if (bolt->strike_level == LEVEL_ONE_STRIKE) + level1_strike(*bolt, mi); + else + level2_strike(*bolt, mi); + } +} + +/*------------------------------------------------------------------------*/ + +static void +first_strike(Lightning bolt, ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + int i; + + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + XDrawLine(display, window, gc, + bolt.end1.x, bolt.end1.y, bolt.middle[0].x, bolt.middle[0].y); + draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, 0); + XDrawLine(display, window, gc, + bolt.middle[BOLT_VERTICIES - 1].x, bolt.middle[BOLT_VERTICIES - 1].y, + bolt.end2.x, bolt.end2.y); + + for (i = 0; i < bolt.fork_number; i++) + draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used, + gc, 0); +} + +/*------------------------------------------------------------------------*/ + +static void +draw_line(ModeInfo * mi, XPoint * points, int number, GC to_use, int offset) +{ + int i; + + for (i = 0; i < number - 1; i++) { + if (points[i].y <= points[i + 1].y) + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), to_use, points[i].x + offset, + points[i].y, points[i + 1].x + offset, points[i + 1].y); + else { + if (points[i].x < points[i + 1].x) + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), to_use, points[i].x + + offset, points[i].y + offset, points[i + 1].x + offset, + points[i + 1].y + offset); + else + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), to_use, points[i].x - + offset, points[i].y + offset, points[i + 1].x - offset, + points[i + 1].y + offset); + } + } +} + +/*------------------------------------------------------------------------*/ + +static void +level1_strike(Lightning bolt, ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + Storm *st = &Helga[MI_SCREEN(mi)]; + GC gc = MI_GC(mi); + int i; + + if (MI_NPIXELS(mi) > 2) /* color */ + XSetForeground(display, gc, MI_PIXEL(mi, st->color)); + else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + XDrawLine(display, window, gc, + bolt.end1.x - 1, bolt.end1.y, bolt.middle[0].x - 1, bolt.middle[0].y); + draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, -1); + XDrawLine(display, window, gc, + bolt.middle[BOLT_VERTICIES - 1].x - 1, + bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x - 1, bolt.end2.y); + XDrawLine(display, window, gc, + bolt.end1.x + 1, bolt.end1.y, bolt.middle[0].x + 1, bolt.middle[0].y); + draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, 1); + XDrawLine(display, window, gc, + bolt.middle[BOLT_VERTICIES - 1].x + 1, + bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x + 1, bolt.end2.y); + + for (i = 0; i < bolt.fork_number; i++) { + draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used, + gc, -1); + draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used, + gc, 1); + } + first_strike(bolt, mi); +} + +/*------------------------------------------------------------------------*/ + +static int +distance(XPoint a, XPoint b) +{ + return ((int) sqrt((double) (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y))); +} + +/*------------------------------------------------------------------------*/ + +static void +level2_strike(Lightning bolt, ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + Storm *st = &Helga[MI_SCREEN(mi)]; + GC gc = MI_GC(mi); + int i; + + /* This was originally designed to be a little darker then the + level1 strike. This was changed to get it to work on + multiscreens and to add more color variety. I tried + stippling but it did not look good. */ + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, st->color)); + else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + XDrawLine(display, window, gc, + bolt.end1.x - 2, bolt.end1.y, bolt.middle[0].x - 2, bolt.middle[0].y); + draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, -2); + XDrawLine(display, window, gc, + bolt.middle[BOLT_VERTICIES - 1].x - 2, + bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x - 2, bolt.end2.y); + + XDrawLine(display, window, gc, + bolt.end1.x + 2, bolt.end1.y, bolt.middle[0].x + 2, bolt.middle[0].y); + draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, 2); + XDrawLine(display, window, gc, + bolt.middle[BOLT_VERTICIES - 1].x + 2, + bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x + 2, bolt.end2.y); + + for (i = 0; i < bolt.fork_number; i++) { + draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used, + gc, -2); + draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used, + gc, 2); + } + level1_strike(bolt, mi); +} + +/*------------------------------------------------------------------------*/ + +static int +storm_active(Storm * st) +{ + int i, atleast_1 = 0; + + for (i = 0; i < st->multi_strike; i++) + if (st->bolts[i].wiggle_number > 0) + atleast_1++; + + return (atleast_1); +} + +/*------------------------------------------------------------------------*/ + +static void +wiggle_bolt(Lightning * bolt) +{ + int i; + + wiggle_line(bolt->middle, BOLT_VERTICIES, bolt->wiggle_amount); + bolt->end2.x += NRAND(bolt->wiggle_amount) - bolt->wiggle_amount / 2; + bolt->end2.y += NRAND(bolt->wiggle_amount) - bolt->wiggle_amount / 2; + + for (i = 0; i < bolt->fork_number; i++) { + wiggle_line(bolt->branch[i].ForkVerticies, bolt->branch[i].num_used, + bolt->wiggle_amount); + bolt->branch[i].ForkVerticies[0].x = bolt->middle[bolt->forks_start[i]].x; + bolt->branch[i].ForkVerticies[0].y = bolt->middle[bolt->forks_start[i]].y; + } + + if (bolt->wiggle_amount > 1) + bolt->wiggle_amount -= 1; + else + bolt->wiggle_amount = 0; +} + +/*------------------------------------------------------------------------*/ + +static void +wiggle_line(XPoint * p, int number, int amount) +{ + int i; + + for (i = 0; i < number; i++) { + p[i].x += NRAND(amount) - amount / 2; + p[i].y += NRAND(amount) - amount / 2; + } +} + +/*------------------------------------------------------------------------*/ + +ENTRYPOINT void +init_lightning (ModeInfo * mi) +{ + Storm *st; + + if (Helga == NULL) { + if ((Helga = (Storm *) calloc(MI_NUM_SCREENS(mi), + sizeof (Storm))) == NULL) + return; + } + st = &Helga[MI_SCREEN(mi)]; + + st->scr_width = MI_WIDTH(mi); + st->scr_height = MI_HEIGHT(mi); + + st->multi_strike = setup_multi_strike(); + random_storm(st); + st->stage = 0; +} + +/*------------------------------------------------------------------------*/ + +ENTRYPOINT void +draw_lightning (ModeInfo * mi) +{ + int i; + Storm *st; + + if (Helga == NULL) + return; + st = &Helga[MI_SCREEN(mi)]; + MI_IS_DRAWN(mi) = True; + switch (st->stage) { + case 0: + MI_IS_DRAWN(mi) = False; + MI_CLEARWINDOW(mi); + MI_IS_DRAWN(mi) = True; + + st->color = NRAND(MI_NPIXELS(mi)); + st->draw_time = 0; + if (storm_active(st)) + st->stage++; + else + st->stage = 4; + break; + case 1: + for (i = 0; i < st->multi_strike; i++) { + if (st->bolts[i].visible) + draw_bolt(&(st->bolts[i]), mi); + update_bolt(&(st->bolts[i]), st->draw_time); + } + st->draw_time++; + st->stage++; + st->busyLoop = 0; + break; + case 2: + if (++st->busyLoop > 6) { + st->stage++; + st->busyLoop = 0; + } + break; + case 3: + MI_IS_DRAWN(mi) = False; + MI_CLEARWINDOW(mi); + MI_IS_DRAWN(mi) = True; + + if (storm_active(st)) + st->stage = 1; + else + st->stage++; + break; + case 4: + if (++st->busyLoop > 100) { + st->busyLoop = 0; + } + init_lightning(mi); + break; + } +} + +ENTRYPOINT void +release_lightning(ModeInfo * mi) +{ + if (Helga != NULL) { + (void) free((void *) Helga); + Helga = (Storm *) NULL; + } +} + +ENTRYPOINT void +refresh_lightning(ModeInfo * mi) +{ + /* Do nothing, it will refresh by itself */ +} + +XSCREENSAVER_MODULE ("Lightning", lightning) + + +#endif /* MODE_lightning */ diff --git a/non-wgl/lightning.vcproj b/non-wgl/lightning.vcproj new file mode 100644 index 0000000..182afcd --- /dev/null +++ b/non-wgl/lightning.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/lisa.c b/non-wgl/lisa.c new file mode 100644 index 0000000..38a3703 --- /dev/null +++ b/non-wgl/lisa.c @@ -0,0 +1,757 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* lisa --- animated full-loop lissajous figures */ + +#if 0 +static const char sccsid[] = "@(#)lisa.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1997, 2006 by Caleb Cullen. + * + * 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: + * 23-Feb-2006: fixed color-cycling issues + * 01-Nov-2000: Allocation checks + * 10-May-1997: Compatible with xscreensaver + * + * The inspiration for this program, Lasp, was written by Adam B. Roach + * in 1990, assisted by me, Caleb Cullen. It was written first in C, then + * in assembly, and used pre-calculated data tables to graph lissajous + * figures on 386 machines and lower. This version bears only superficial + * resemblances to the original Lasp. + * + * The `lissie' module's source code was studied as an example of how + * to incorporate a new module into xlock. Resemblances to it are + * expected, but not intended to be plaigiaristic. + * + * February, 2006: 21st Century Update for Lisa + * + fixed color-mapping: the 'beginning' of the loop always uses the + * same (starting) pixel value, causing the loop's coloration to + * appear solid rather than flickering as in the previous version + * + all lines/points in a single color are drawn at once using XDrawLines() + * or XDrawPoints(); the artifacting evident in the previous version + * has been masked by the use of CapNotLast to separate individual drawn + * areas with intentional "whitespace" (typically black) + * + added many new elements to the Function[] array + * + randomized selection of next function + * + introduced concept of "rarely-chosen" functions + * + cleaned up code somewhat, standardized capitalization, commented all + * #directives with block labels + */ + +#define STANDALONE +# define MODE_lisa +#define DELAY 17000 +#define COUNT 1 +#define CYCLES 768 +#define SIZE_ 500 +#define NCOLORS 64 +# define DEFAULTS "*delay: 17000 \n" \ + "*count: 1 \n" \ + "*cycles: 768 \n" \ + "*size: 500 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + +# define UNIFORM_COLORS +# define reshape_lisa 0 +# define lisa_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_lisa + +#define DEF_ADDITIVE "True" + +static Bool additive = True; + +static XrmOptionDescRec opts[] = +{ + {"-additive", ".lisa.additive", XrmoptionNoArg, "True"}, + {"+additive", ".lisa.additive", XrmoptionNoArg, "False"} +}; + +static argtype vars[] = +{ + {&additive, "additive", "Additive", DEF_ADDITIVE, t_Bool} +}; + +static OptionStruct desc[] = +{ + {"-/+additive", "turn on/off additive functions mode"} +}; + +ENTRYPOINT ModeSpecOpt lisa_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct lisa_description = +{"lisa", "init_lisa", "draw_lisa", "release_lisa", + "refresh_lisa", "change_lisa", (char *) NULL, &lisa_opts, + 17000, 1, 768, -1, 64, 1.0, "", + "Shows animated lissajous figures", 0, NULL}; + +#endif + +#define DRAWLINES 1 +/* #define FOLLOW_FUNC_ORDER 1 */ +#define TWOLOOPS 1 +#define XVMAX 10 /* Maximum velocities */ +#define YVMAX 10 +#define LISAMAXFUNCS 2 +#define NUMSTDFUNCS 28 +#define RAREFUNCMIN 25 +#define RAREFUNCODDS 4 /* 1:n chance a rare function will be re-randomized */ +#define MAXCYCLES 3 +#define MINLISAS 1 +#define STARTCOLOR 0 +#define STARTFUNC 24 /* if negative, is upper-bound on randomization */ +#define LINEWIDTH -8 /* if negative, is upper-bound on randomization */ +#define LINESTYLE LineSolid /* an insane man might have fun with this :) */ +#define LINECAP CapNotLast /* anything else looks pretty crappy */ +#define LINEJOIN JoinBevel /* this ought to be fastest */ +#define SET_COLOR() \ + if (MI_NPIXELS(mi) > 2) { \ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, loop->color)); \ + if (loop->cstep \ + && pctr % loop->cstep == 0 \ + && ++(loop->color) >= (unsigned) MI_NPIXELS(mi)) \ + { loop->color=STARTCOLOR; } \ + } else { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); } +#define GET_RADIUS(context) \ + ((context->width > context->height)?context->height:context->width) * 3 / 8 +#define CHECK_RADIUS(loop, context) \ + if ((context->height / 2 > MI_SIZE(mi)) && (context->width / 2 > MI_SIZE(mi))) \ + loop->radius = MI_SIZE(mi); \ + if ((loop->radius < 0) || \ + (loop->radius > loop->center.x) || \ + (loop->radius > loop->center.y)) loop->radius = GET_RADIUS(context) +#define PRINT_FUNC(funcptr) \ + printf("new function -- #%d:\n\tx = sin(%gs) * sin(%gs)\n\ty = sin(%gt) * sin(%gt)\n", \ + funcptr->index, \ + funcptr->xcoeff[0], funcptr->xcoeff[1], \ + funcptr->ycoeff[0], funcptr->ycoeff[1]) + + +typedef struct lisafunc_struct { + double xcoeff[2], ycoeff[2]; + int nx, ny; + int index; +} lisafuncs; + +typedef struct lisa_struct { + unsigned long color; + int radius, dx, dy, nsteps, nfuncs, melting, cstep; + double pistep, phi, theta; + XPoint center, *lastpoint; + lisafuncs *function[LISAMAXFUNCS]; + int linewidth; +} lisas; + +typedef struct lisacontext_struct { + lisas *lissajous; + int width, height, nlissajous, loopcount; + int maxcycles; + Bool painted; +} lisacons; + +static lisacons *Lisa = (lisacons *) NULL; + +static lisafuncs Function[NUMSTDFUNCS] = + { + { + {1.0, 2.0}, + {1.0, 2.0}, 2, 2, 0}, + { + {1.0, 2.0}, + {1.0, 1.0}, 2, 2, 1}, + { + {1.0, 3.0}, + {1.0, 2.0}, 2, 2, 2}, + { + {1.0, 3.0}, + {1.0, 3.0}, 2, 2, 3}, + { + {2.0, 4.0}, + {1.0, 2.0}, 2, 2, 4}, + { + {1.0, 4.0}, + {1.0, 3.0}, 2, 2, 5}, + { + {1.0, 4.0}, + {1.0, 4.0}, 2, 2, 6}, + { + {1.0, 5.0}, + {1.0, 5.0}, 2, 2, 7}, + { + {2.0, 5.0}, + {2.0, 5.0}, 2, 2, 8}, + { + {1.0, 2.0}, + {2.0, 5.0}, 2, 2, 9}, + { + {1.0, 2.0}, + {3.0, 5.0}, 2, 2, 10}, + { + {1.0, 2.0}, + {2.0, 3.0}, 2, 2, 11}, + { + {1.0, 3.0}, + {2.0, 3.0}, 2, 2, 12}, + { + {2.0, 3.0}, + {1.0, 3.0}, 2, 2, 13}, + { + {2.0, 4.0}, + {1.0, 3.0}, 2, 2, 14}, + { + {1.0, 4.0}, + {2.0, 3.0}, 2, 2, 15}, + { + {2.0, 4.0}, + {2.0, 3.0}, 2, 2, 16}, + { + {1.0, 5.0}, + {2.0, 3.0}, 2, 2, 17}, + { + {2.0, 5.0}, + {2.0, 3.0}, 2, 2, 18}, + { + {1.0, 5.0}, + {2.0, 5.0}, 2, 2, 19}, + { + {1.0, 3.0}, + {2.0, 7.0}, 2, 2, 20}, + { + {2.0, 3.0}, + {5.0, 7.0}, 2, 2, 21}, + { + {1.0, 2.0}, + {3.0, 7.0}, 2, 2, 22}, + { + {2.0, 5.0}, + {5.0, 7.0}, 2, 2, 23}, + { + {5.0, 7.0}, + {5.0, 7.0}, 2, 2, 24}, + { /* functions past here are 'rare' and won't */ + {2.0, 7.0}, /* show up as often. tweak the #defines above */ + {1.0, 7.0}, 2, 2, 25}, /* to see them more frequently */ + { + {2.0, 9.0}, + {1.0, 7.0}, 2, 2, 26}, + { + {5.0, 11.0}, + {2.0, 9.0}, 2, 2, 27} +}; + +int xMaxLines; + +static void +free_lisa(lisacons *lc) +{ + while (lc->lissajous) { + int lctr; + + for (lctr = 0; lctr < lc->nlissajous; lctr++) { + (void) free((void *) lc->lissajous[lctr].lastpoint); + } + (void) free((void *) lc->lissajous); + lc->lissajous = (lisas *) NULL; + } +} + +static Bool +drawlisa(ModeInfo * mi, lisas * loop) +{ + XPoint *np; + XPoint *lp = loop->lastpoint; + lisacons *lc = &Lisa[MI_SCREEN(mi)]; + lisafuncs **lf = loop->function; + int phase = lc->loopcount % loop->nsteps; + int pctr, fctr, xctr, yctr, extra_points; + double xprod, yprod, xsum, ysum; + + /* why carry this around in the struct when we can calculate it on demand? */ + extra_points = loop->cstep - (loop->nsteps % loop->cstep); + + /* Allocate the np (new point) array (with padding) */ + if ((np = (XPoint *) calloc(loop->nsteps+extra_points, sizeof (XPoint))) == NULL) { + free_lisa(lc); + return False; + } + + /* Update the center */ + loop->center.x += loop->dx; + loop->center.y += loop->dy; + CHECK_RADIUS(loop, lc); + + /* check for overlaps -- where the figure might go off the screen */ + + if ((loop->center.x - loop->radius) <= 0) { + loop->center.x = loop->radius; + loop->dx = NRAND(XVMAX); + } else if ((loop->center.x + loop->radius) >= lc->width) { + loop->center.x = lc->width - loop->radius; + loop->dx = -NRAND(XVMAX); + }; + if ((loop->center.y - loop->radius) <= 0) { + loop->center.y = loop->radius; + loop->dy = NRAND(YVMAX); + } else if ((loop->center.y + loop->radius) >= lc->height) { + loop->center.y = lc->height - loop->radius; + loop->dy = -NRAND(YVMAX); + }; + + /* Now draw the points, and erase the ones from the last cycle */ + + for (pctr = 0; pctr < loop->nsteps; pctr++) { + fctr = loop->nfuncs; + loop->phi = (double) (pctr - phase) * loop->pistep; + loop->theta = (double) (pctr + phase) * loop->pistep; + xsum = ysum = 0; + while (fctr--) { + xctr = lf[fctr]->nx; + yctr = lf[fctr]->ny; + if (additive) { + xprod = yprod = 0.0; + while (xctr--) + xprod += sin(lf[fctr]->xcoeff[xctr] * loop->theta); + while (yctr--) + yprod += sin(lf[fctr]->ycoeff[yctr] * loop->phi); + if (loop->melting) { + if (fctr) { + xsum += xprod * (double) (loop->nsteps - loop->melting) / + (double) loop->nsteps; + ysum += yprod * (double) (loop->nsteps - loop->melting) / + (double) loop->nsteps; + } else { + xsum += xprod * (double) loop->melting / (double) loop->nsteps; + ysum += yprod * (double) loop->melting / (double) loop->nsteps; + } + } else { + xsum = xprod; + ysum = yprod; + } + if (!fctr) { + xsum = xsum * (double) loop->radius / (double) lf[fctr]->nx; + ysum = ysum * (double) loop->radius / (double) lf[fctr]->ny; + } + } else { + if (loop->melting) { + if (fctr) { + yprod = xprod = (double) loop->radius * + (double) (loop->nsteps - loop->melting) / + (double) (loop->nsteps); + } else { + yprod = xprod = (double) loop->radius * + (double) (loop->melting) / (double) (loop->nsteps); + } + } else { + xprod = yprod = (double) loop->radius; + } + while (xctr--) + xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta); + while (yctr--) + yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi); + xsum += xprod; + ysum += yprod; + } + } + if ((loop->nfuncs > 1) && (!loop->melting)) { + xsum /= (double) loop->nfuncs; + ysum /= (double) loop->nfuncs; + } + xsum += (double) loop->center.x; + ysum += (double) loop->center.y; + + np[pctr].x = (int) ceil(xsum); + np[pctr].y = (int) ceil(ysum); + } + /* fill in extra points */ + for (pctr=loop->nsteps; pctr < loop->nsteps+extra_points; pctr++) { + np[pctr].x = np[pctr - loop->nsteps].x; + np[pctr].y = np[pctr - loop->nsteps].y; + } + if (loop->melting) { + if (!--loop->melting) { + loop->nfuncs = 1; + loop->function[0] = loop->function[1]; + } + } + + /* reset starting color each time to prevent ass-like appearance */ + loop->color = STARTCOLOR; + + if (loop->cstep < xMaxLines) { + /* printf("Drawing dashes\n"); */ + for (pctr = 0; pctr < loop->nsteps; pctr+=loop->cstep) { +#if defined DRAWLINES + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth, + LINESTYLE, LINECAP, LINEJOIN); + /* erase the last cycle's point */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &lp[pctr], + loop->cstep, CoordModeOrigin); + + /* Set the new color */ + SET_COLOR(); + + /* plot this cycle's point */ + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + &np[pctr], loop->cstep, CoordModeOrigin); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, + LINESTYLE, LINECAP, LINEJOIN); +#else + /* erase the last cycle's point */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + &lp[pctr], loop->cstep, CoordModeOrigin); + + /* Set the new color */ + SET_COLOR(); + + /* plot this cycle's point */ + XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_GC(mi), &np[pctr], loop->cstep, CoordModeOrigin); +#endif + } + } else { /* on my system, cstep is larger than 65532/2 if we get here */ + for (pctr = 0; pctr < loop->nsteps; pctr++) { +#if defined DRAWLINES + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth, + LINESTYLE, LINECAP, LINEJOIN); + /* erase the last cycle's point */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_GC(mi), lp[pctr].x, lp[pctr].y, + lp[(pctr + 1) % loop->nsteps].x, + lp[(pctr + 1) % loop->nsteps].y); + + /* Set the new color */ + SET_COLOR(); + + /* plot this cycle's point */ + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_GC(mi), np[pctr].x, np[pctr].y, + np[(pctr + 1) % loop->nsteps].x, + np[(pctr + 1) % loop->nsteps].y); + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, + LINESTYLE, LINECAP, LINEJOIN); +#else /* DRAWLINES */ + /* erase the last cycle's point */ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_GC(mi), lp[pctr].x, lp[pctr].y); + + /* Set the new color */ + SET_COLOR(); + + /* plot this cycle's point */ + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_GC(mi), np[pctr].x, np[pctr].y); +#endif /* DRAWLINES */ + } + } + (void) free((void *) lp); + loop->lastpoint = np; + return True; +} + +static Bool +initlisa(ModeInfo * mi, lisas * loop) +{ + lisacons *lc = &Lisa[MI_SCREEN(mi)]; + lisafuncs **lf = loop->function; + XPoint *lp; + int phase, pctr, fctr, xctr, yctr, extra_points; + double xprod, yprod, xsum, ysum; + + xMaxLines = (XMaxRequestSize(MI_DISPLAY(mi))-3)/2; + /* printf("Got xMaxLines = %d\n", xMaxLines); */ + loop->nsteps = MI_CYCLES(mi); + if (loop->nsteps == 0) + loop->nsteps = 1; + if (MI_NPIXELS(mi) > 2) { + loop->color = STARTCOLOR; + loop->cstep = (loop->nsteps > MI_NPIXELS(mi)) ? loop->nsteps / MI_NPIXELS(mi) : 1; + } else { + loop->color = MI_WHITE_PIXEL(mi); + loop->cstep = 0; + } + extra_points = loop->cstep - (loop->nsteps % loop->cstep); + lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1; + loop->cstep = ( loop->nsteps > MI_NPIXELS(mi) ) ? loop->nsteps / MI_NPIXELS(mi) : 1; + /* printf("Got cstep = %d\n", loop->cstep); */ + loop->melting = 0; + loop->nfuncs = 1; + loop->pistep = 2.0 * M_PI / (double) loop->nsteps; + loop->center.x = lc->width / 2; + loop->center.y = lc->height / 2; + loop->radius = (int) MI_SIZE(mi); + CHECK_RADIUS(loop, lc); + loop->dx = NRAND(XVMAX); + loop->dy = NRAND(YVMAX); + loop->dx++; + loop->dy++; +#if defined STARTFUNC + lf[0] = &Function[STARTFUNC]; +#else /* STARTFUNC */ + lf[0] = &Function[NRAND(NUMSTDFUNCS)]; +#endif /* STARTFUNC */ + + if ((lp = loop->lastpoint = (XPoint *) + calloc(loop->nsteps+extra_points, sizeof (XPoint))) == NULL) { + free_lisa(lc); + return False; + } + phase = lc->loopcount % loop->nsteps; + +#if defined DEBUG + printf( "nsteps = %d\tcstep = %d\tmrs = %d\textra_points = %d\n", + loop->nsteps, loop->cstep, xMaxLines, extra_points ); + PRINT_FUNC(lf[0]); +#endif /* DEBUG */ + + for (pctr = 0; pctr < loop->nsteps; pctr++) { + loop->phi = (double) (pctr - phase) * loop->pistep; + loop->theta = (double) (pctr + phase) * loop->pistep; + fctr = loop->nfuncs; + xsum = ysum = 0.0; + while (fctr--) { + xprod = yprod = (double) loop->radius; + xctr = lf[fctr]->nx; + yctr = lf[fctr]->ny; + while (xctr--) + xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta); + while (yctr--) + yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi); + xsum += xprod; + ysum += yprod; + } + if (loop->nfuncs > 1) { + xsum /= 2.0; + ysum /= 2.0; + } + xsum += (double) loop->center.x; + ysum += (double) loop->center.y; + + lp[pctr].x = (int) ceil(xsum); + lp[pctr].y = (int) ceil(ysum); + } + /* this fills in the extra points, so we can use segment-drawing calls */ + for (pctr = loop->nsteps; pctr < loop->nsteps + extra_points; pctr++) { + lp[pctr].x=lp[pctr - loop->nsteps].x; + lp[pctr].y=lp[pctr - loop->nsteps].y; + } +#if defined DRAWLINES + loop->linewidth = LINEWIDTH; /* #### make this a resource */ + + if (loop->linewidth == 0) + loop->linewidth = 1; + if (loop->linewidth < 0) + loop->linewidth = NRAND(-loop->linewidth) + 1; + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth, + LINESTYLE, LINECAP, LINEJOIN); +#endif /* DRAWLINES */ + + if ( loop->cstep < xMaxLines ) { + /* we can send each color segment in a single request + * because the max request length is long enough + * and because we have padded out the array to have extra elements + * to support calls which would otherwise fall off the end*/ + for (pctr = 0; pctr < loop->nsteps; pctr+=loop->cstep) { + /* Set the color */ + SET_COLOR(); + +#if defined DRAWLINES + XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), + MI_GC(mi), &lp[pctr], loop->cstep, CoordModeOrigin ); +#else /* DRAWLINES */ + XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + &lp[pctr], loop->cstep, CoordModeOrigin ); +#endif /* DRAWLINES */ + } + } else { /* do it one by one as before */ + for (pctr = 0; pctr < loop->nsteps; pctr++ ) { + SET_COLOR(); + +#if defined DRAWLINES + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + lp[pctr].x, lp[pctr].y, + lp[pctr+1 % loop->nsteps].x, lp[pctr+1 % loop->nsteps].y); +#else /* DRAWLINES */ + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + lp[pctr].x, lp[pctr].y); +#endif /* DRAWLINES */ + } + } + +#if defined DRAWLINES + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, + LINESTYLE, LINECAP, LINEJOIN); +#endif /* DRAWLINES */ + return True; +} + +static void +refreshlisa(ModeInfo * mi) +{ + lisacons *lc = &Lisa[MI_SCREEN(mi)]; + int lctr; + + for (lctr = 0; lctr < lc->nlissajous; lctr++) { + if (!drawlisa(mi, &lc->lissajous[lctr])) + return; + } +} + +ENTRYPOINT void +refresh_lisa(ModeInfo * mi) +{ + lisacons *lc; + + if (Lisa == NULL) + return; + lc = &Lisa[MI_SCREEN(mi)]; + if (lc->lissajous == NULL) + return; + + if (lc->painted) { + lc->painted = False; + MI_CLEARWINDOW(mi); + refreshlisa(mi); + } +} + +static void +change_lisa(ModeInfo * mi) +{ + lisas *loop; + int lctr, newfunc; + lisacons *lc; + + if (Lisa == NULL) + return; + lc = &Lisa[MI_SCREEN(mi)]; + if (lc->lissajous == NULL) + return; + + lc->loopcount = 0; + for (lctr = 0; lctr < lc->nlissajous; lctr++) { + loop = &lc->lissajous[lctr]; /* count through the loops we're drawing */ + newfunc = NRAND(NUMSTDFUNCS); /* choose a new function at random */ +#if defined FOLLOW_FUNC_ORDER + loop->function[1] = + &Function[(loop->function[0]->index + 1) % NUMSTDFUNCS]; +#else /* FOLLOW_FUNC_ORDER */ + if (newfunc == loop->function[0]->index) { + ++newfunc; + newfunc %= NUMSTDFUNCS; /* take the next if we got the one we have */ + } + if (newfunc >= RAREFUNCMIN \ + && !(random() % RAREFUNCODDS) \ + && (newfunc = NRAND(NUMSTDFUNCS)) == loop->function[0]->index) { + ++newfunc; + newfunc %= NUMSTDFUNCS; + } + loop->function[1] = /* set 2nd function pointer on the loop */ + &Function[newfunc]; /* to the new function we just chose */ +#endif /* FOLLOW_FUNC_ORDER */ +#if defined DEBUG + PRINT_FUNC(loop->function[1]); +#endif /* DEBUG */ + loop->melting = loop->nsteps - 1; /* melt the two functions together */ + loop->nfuncs = 2; /* simultaneously for a full cycle */ + } +} + +ENTRYPOINT void +init_lisa (ModeInfo * mi) +{ + int lctr; + lisacons *lc; + + if (Lisa == NULL) { + if ((Lisa = (lisacons *) calloc(MI_NUM_SCREENS(mi), + sizeof (lisacons))) == NULL) + return; + } + lc = &Lisa[MI_SCREEN(mi)]; + lc->width = MI_WIDTH(mi); + lc->height = MI_HEIGHT(mi); + lc->loopcount = 0; + lc->nlissajous = MI_COUNT(mi); + if (lc->nlissajous <= 0) + lc->nlissajous = 1; + MI_CLEARWINDOW(mi); + lc->painted = False; + + if (lc->lissajous == NULL) { + if ((lc->lissajous = (lisas *) calloc(lc->nlissajous, + sizeof (lisas))) == NULL) + return; + for (lctr = 0; lctr < lc->nlissajous; lctr++) { + if (!initlisa(mi, &lc->lissajous[lctr])) + return; + lc->loopcount++; + } + } else { + refreshlisa(mi); + } +} + +ENTRYPOINT void +draw_lisa (ModeInfo * mi) +{ + lisacons *lc; + + if (Lisa == NULL) + return; + lc = &Lisa[MI_SCREEN(mi)]; + if (lc->lissajous == NULL) + return; + +#ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi)); +#endif + + MI_IS_DRAWN(mi) = True; + lc->painted = True; + if (++lc->loopcount > lc->maxcycles) { + change_lisa(mi); + } + refreshlisa(mi); +} + +ENTRYPOINT void +release_lisa (ModeInfo * mi) +{ + if (Lisa) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_lisa(&Lisa[screen]); + (void) free(Lisa); + Lisa = (lisacons *) NULL; + } +} + +XSCREENSAVER_MODULE ("Lisa", lisa) + +#endif /* MODE_lisa */ diff --git a/non-wgl/lisa.vcproj b/non-wgl/lisa.vcproj new file mode 100644 index 0000000..c2375f4 --- /dev/null +++ b/non-wgl/lisa.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/lissie.c b/non-wgl/lissie.c new file mode 100644 index 0000000..9cf4403 --- /dev/null +++ b/non-wgl/lissie.c @@ -0,0 +1,338 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* lissie --- the Lissajous worm */ + +#if 0 +static const char sccsid[] = "@(#)lissie.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * lissie.c - The Lissajous worm for xlock, the X Window System + * lockscreen. + * + * Copyright (c) 1996 by Alexander Jolk + * + * 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 + * 18-Aug-1996: added refresh-hook. + * 01-May-1996: written. + */ + +#define STANDALONE +#define NOARGS + +# define MODE_lissie +#define DELAY 10000 +#define COUNT 1 +#define CYCLES 20000 +#define SIZE_ -200 +#define NCOLORS 200 +# define DEFAULTS "*delay: 10000 \n" \ + "*count: 1 \n" \ + "*cycles: 20000 \n" \ + "*size: -200 \n" \ + "*ncolors: 200 \n" \ + "*fpsSolid: true \n" \ + +# define SMOOTH_COLORS +# define reshape_lissie 0 +# define lissie_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_lissie + +ENTRYPOINT ModeSpecOpt lissie_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct lissie_description = +{"lissie", "init_lissie", "draw_lissie", "release_lissie", + "refresh_lissie", "init_lissie", (char *) NULL, &lissie_opts, + 10000, 1, 2000, -200, 64, 0.6, "", + "Shows lissajous worms", 0, NULL}; + +#endif + +#define MINSIZE 1 + +#define Lissie(n)\ + if (lissie->loc[(n)].x > 0 && lissie->loc[(n)].y > 0 &&\ + lissie->loc[(n)].x <= lp->width && lissie->loc[(n)].y <= lp->height) {\ + if (lissie->ri < 2)\ + XDrawPoint(display, MI_WINDOW(mi),\ + gc, lissie->loc[(n)].x, lissie->loc[(n)].y);\ + else\ + XDrawArc(display, MI_WINDOW(mi), gc,\ + lissie->loc[(n)].x - lissie->ri / 2,\ + lissie->loc[(n)].y - lissie->ri / 2,\ + lissie->ri, lissie->ri, 0, 23040);\ + } + +#define FLOATRAND(min,max) ((min)+(LRAND()/MAXRAND)*((max)-(min))) +#define INTRAND(min,max) ((min)+NRAND((max)-(min)+1)) + +#define MINDT 0.01 +#define MAXDT 0.15 + +#define MAXLISSIELEN 100 +#define MINLISSIELEN 10 +#define MINLISSIES 1 + +/* How many segments to draw per cycle when redrawing */ +#define REDRAWSTEP 3 + +typedef struct { + double tx, ty, dtx, dty; + int xi, yi, ri, rx, ry, len, pos; + int redrawing, redrawpos; + XPoint loc[MAXLISSIELEN]; + unsigned long color; +} lissiestruct; + +typedef struct { + Bool painted; + int width, height; + int nlissies; + lissiestruct *lissie; + int loopcount; +} lissstruct; + +static lissstruct *lisses = (lissstruct *) NULL; + + +static void +drawlissie(ModeInfo * mi, lissiestruct * lissie) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + lissstruct *lp = &lisses[MI_SCREEN(mi)]; + int p = (++lissie->pos) % MAXLISSIELEN; + int oldp = (lissie->pos - lissie->len + MAXLISSIELEN) % MAXLISSIELEN; + + /* Let time go by ... */ + lissie->tx += lissie->dtx; + lissie->ty += lissie->dty; + if (lissie->tx > 2 * M_PI) + lissie->tx -= 2 * M_PI; + if (lissie->ty > 2 * M_PI) + lissie->ty -= 2 * M_PI; + + /* vary both (x/y) speeds by max. 1% */ + lissie->dtx *= FLOATRAND(0.99, 1.01); + lissie->dty *= FLOATRAND(0.99, 1.01); + if (lissie->dtx < MINDT) + lissie->dtx = MINDT; + else if (lissie->dtx > MAXDT) + lissie->dtx = MAXDT; + if (lissie->dty < MINDT) + lissie->dty = MINDT; + else if (lissie->dty > MAXDT) + lissie->dty = MAXDT; + + lissie->loc[p].x = lissie->xi + (int) (sin(lissie->tx) * lissie->rx); + lissie->loc[p].y = lissie->yi + (int) (sin(lissie->ty) * lissie->ry); + + /* Mask */ + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + Lissie(oldp); + + /* Redraw */ + if (MI_NPIXELS(mi) > 2) { + XSetForeground(display, gc, MI_PIXEL(mi, lissie->color)); + if (++lissie->color >= (unsigned) MI_NPIXELS(mi)) + lissie->color = 0; + } else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + Lissie(p); + if (lissie->redrawing) { + int i; + + lissie->redrawpos++; + /* This compensates for the changed p + since the last callback. */ + + for (i = 0; i < REDRAWSTEP; i++) { + Lissie((p - lissie->redrawpos + MAXLISSIELEN) % MAXLISSIELEN); + if (++(lissie->redrawpos) >= lissie->len) { + lissie->redrawing = 0; + break; + } + } + } +} + +static void +initlissie(ModeInfo * mi, lissiestruct * lissie) +{ + lissstruct *lp = &lisses[MI_SCREEN(mi)]; + int size = MI_SIZE(mi); + int i; + + if (MI_NPIXELS(mi) > 2) + lissie->color = NRAND(MI_NPIXELS(mi)); + else + lissie->color = MI_WHITE_PIXEL(mi); + /* Initialize parameters */ + if (size < -MINSIZE) + lissie->ri = NRAND(MIN(-size, MAX(MINSIZE, + MIN(lp->width, lp->height) / 4)) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) { + if (!size) + lissie->ri = MAX(MINSIZE, MIN(lp->width, lp->height) / 4); + else + lissie->ri = MINSIZE; + } else + lissie->ri = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) / 4)); + lissie->xi = INTRAND(lp->width / 4 + lissie->ri, + lp->width * 3 / 4 - lissie->ri); + lissie->yi = INTRAND(lp->height / 4 + lissie->ri, + lp->height * 3 / 4 - lissie->ri); + lissie->rx = INTRAND(lp->width / 4, + MIN(lp->width - lissie->xi, lissie->xi)) - 2 * lissie->ri; + lissie->ry = INTRAND(lp->height / 4, + MIN(lp->height - lissie->yi, lissie->yi)) - 2 * lissie->ri; + lissie->len = INTRAND(MINLISSIELEN, MAXLISSIELEN - 1); + lissie->pos = 0; + + lissie->redrawing = 0; + + lissie->tx = FLOATRAND(0, 2 * M_PI); + lissie->ty = FLOATRAND(0, 2 * M_PI); + lissie->dtx = FLOATRAND(MINDT, MAXDT); + lissie->dty = FLOATRAND(MINDT, MAXDT); + + for (i = 0; i < MAXLISSIELEN; i++) + lissie->loc[i].x = lissie->loc[i].y = 0; + /* Draw lissie */ + drawlissie(mi, lissie); +} + +ENTRYPOINT void +init_lissie (ModeInfo * mi) +{ + lissstruct *lp; + unsigned char ball; + + if (lisses == NULL) { + if ((lisses = (lissstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (lissstruct))) == NULL) + return; + } + lp = &lisses[MI_SCREEN(mi)]; + + lp->width = MI_WIDTH(mi); + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False); +#endif + + lp->height = MI_HEIGHT(mi); + + lp->nlissies = MI_COUNT(mi); + if (lp->nlissies < -MINLISSIES) { + if (lp->lissie) { + (void) free((void *) lp->lissie); + lp->lissie = (lissiestruct *) NULL; + } + lp->nlissies = NRAND(-lp->nlissies - MINLISSIES + 1) + MINLISSIES; + } else if (lp->nlissies < MINLISSIES) + lp->nlissies = MINLISSIES; + + lp->loopcount = 0; + + if (lp->lissie == NULL) + if ((lp->lissie = (lissiestruct *) calloc(lp->nlissies, + sizeof (lissiestruct))) == NULL) + return; + + MI_CLEARWINDOW(mi); + lp->painted = False; + + for (ball = 0; ball < (unsigned char) lp->nlissies; ball++) + initlissie(mi, &lp->lissie[ball]); + +} + +ENTRYPOINT void +draw_lissie (ModeInfo * mi) +{ + register unsigned char ball; + lissstruct *lp; + + if (lisses == NULL) + return; + lp = &lisses[MI_SCREEN(mi)]; + if (lp->lissie == NULL) + return; + + MI_IS_DRAWN(mi) = True; + + if (++lp->loopcount > MI_CYCLES(mi)) { + init_lissie(mi); + } else { + lp->painted = True; + for (ball = 0; ball < (unsigned char) lp->nlissies; ball++) + drawlissie(mi, &lp->lissie[ball]); + } +} + +ENTRYPOINT void +release_lissie (ModeInfo * mi) +{ + if (lisses != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + lissstruct *lp = &lisses[screen]; + + if (lp->lissie != NULL) { + (void) free((void *) lp->lissie); + /* lp->lissie = NULL; */ + } + } + (void) free((void *) lisses); + lisses = (lissstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_lissie(ModeInfo * mi) +{ + int i; + lissstruct *lp; + + if (lisses == NULL) + return; + lp = &lisses[MI_SCREEN(mi)]; + if (lp->lissie == NULL) + return; + + if (lp->painted) { + MI_CLEARWINDOW(mi); + for (i = 0; i < lp->nlissies; i++) { + lp->lissie[i].redrawing = 1; + lp->lissie[i].redrawpos = 0; + } + } +} + +XSCREENSAVER_MODULE ("Lissie", lissie) + +#endif /* MODE_lissie */ diff --git a/non-wgl/lissie.vcproj b/non-wgl/lissie.vcproj new file mode 100644 index 0000000..80e9240 --- /dev/null +++ b/non-wgl/lissie.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/lmorph.c b/non-wgl/lmorph.c new file mode 100644 index 0000000..cf9c99c --- /dev/null +++ b/non-wgl/lmorph.c @@ -0,0 +1,599 @@ +/* lmorph, Copyright (c) 1993-1999 Sverre H. Huseby and Glenn T. Lines + * + * 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 lmorph.c + | MODULE OF xscreensaver + | + | DESCRIPTION Smooth and non-linear morphing between 1D curves. + | + | WRITTEN BY Sverre H. Huseby Glenn T. Lines + | Kurvn. 30 Østgaardsgt. 5 + | N-0495 Oslo N-0474 Oslo + | Norway Norway + | + | Phone: +47 901 63 579 Phone: +47 22 04 67 28 + | E-mail: sverrehu@online.no E-mail: glennli@ifi.uio.no + | URL: http://home.sol.no/~sverrehu/ + | + | The original idea, and the bilinear interpolation + | mathematics used, emerged in the head of the wise + | Glenn T. Lines. + | + | MODIFICATIONS october 1999 (shh) + | * Removed option to use integer arithmetic. + | * Increased default number of points, and brightened + | the foreground color a little bit. + | * Minor code cleanup (very minor, that is). + | * Default number of steps is no longer random. + | * Added -linewidth option (and resource). + | + | october 1999 (gtl) + | * Added cubic interpolation between shapes + | * Added non-linear transformation speed + | + | june 1998 (shh) + | * Minor code cleanup. + | + | january 1997 (shh) + | * Some code reformatting. + | * Added possibility to use float arithmetic. + | * Added -figtype option. + | * Made color blue default. + | + | december 1995 (jwz) + | * Function headers converted from ANSI to K&R. + | * Added posibility for random number of steps, and + | made this the default. + | + | march 1995 (shh) + | * Converted from an MS-Windows program to X Window. + | + | november 1993 (gtl, shh, lots of beer) + | * Original Windows version (we didn't know better). + +----------------------------------------------------------------------*/ + +#include "screenhack.h" +#include + +/*-----------------------------------------------------------------------+ +| PRIVATE DATA | ++-----------------------------------------------------------------------*/ + +/* define MARGINS to make some space around the figure. */ +#define MARGINS + +#define MAXFIGS 20 +#define TWO_PI (2.0 * M_PI) +#define RND(x) (random() % (x)) + +#define FT_OPEN 1 +#define FT_CLOSED 2 +#define FT_ALL (FT_OPEN | FT_CLOSED) + +struct state { + Display *dpy; + Window window; + + int numFigs; /* number of figure arrays. */ + int numPoints; /* number of points in each array. */ + int nWork; /* current work array number. */ + int nFrom; /* current from array number. */ + int nTo; /* current to array number. */ + int nNext; /* current next array number (after to).*/ + int shift; /* shifts the starting point of a figure */ + int figType; + + long delay; /* usecs to wait between updates. */ + + XPoint *aWork[2]; /* working arrays. */ + XPoint *a[MAXFIGS]; /* the figure arrays. */ + XPoint *aTmp; /* used as source when interrupting morph */ + XPoint *aPrev; /* previous points displayed. */ + XPoint *aCurr; /* the current points displayed. */ + XPoint *aFrom; /* figure converting from. */ + XPoint *aTo; /* figure converting to. */ + XPoint *aNext; /* figure converting to next time. */ + XPoint *aSlopeFrom; /* slope at start of morph */ + XPoint *aSlopeTo; /* slope at end of morph */ + + int scrWidth, scrHeight; + double currGamma, maxGamma, deltaGamma; + GC gcDraw, gcClear; +}; + + +/*-----------------------------------------------------------------------+ +| PUBLIC DATA | ++-----------------------------------------------------------------------*/ + +char *background = "black"; +char *foreground = "#4444FF"; +int points = 200; +int steps_ = 150; +int delay = 70000; +char *figtype = "all"; +int linewidth = 5; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&points, "points", NULL, "200", t_Int}, + {&steps_, "steps", NULL, "150", t_Int}, + {&delay, "delay", NULL, "70000", t_Int}, + {&figtype, "figtype", NULL, "all", t_String}, + {&linewidth, "linewidth", NULL, "5", t_Int}, +}; + +static const char *lmorph_defaults [] = { + ".background: black", + ".foreground: #4444FF", + "*points: 200", + "*steps: 150", + "*delay: 70000", + "*figtype: all", + "*linewidth: 5", + 0 +}; + +static XrmOptionDescRec lmorph_options [] = { + { "-points", ".points", XrmoptionSepArg, 0 }, + { "-steps", ".steps", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-figtype", ".figtype", XrmoptionSepArg, 0 }, + { "-linewidth", ".linewidth", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +/*-----------------------------------------------------------------------+ +| PRIVATE FUNCTIONS | ++-----------------------------------------------------------------------*/ + +static void * +xmalloc(size_t size) +{ + void *ret; + + if ((ret = malloc(size)) == NULL) { + fprintf(stderr, "lmorph: out of memory\n"); + exit(1); + } + return ret; +} + +static void +initPointArrays(struct state *st) +{ + int q, w; + int mx, my; /* max screen coordinates. */ + int mp; /* max point number. */ + int s, rx, ry; + int marginx, marginy; + double scalex, scaley; + + mx = st->scrWidth - 1; + my = st->scrHeight - 1; + mp = st->numPoints - 1; + + st->aWork[0] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + st->aWork[1] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + st->aTmp = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + + if (st->figType & FT_CLOSED) { + /* rectangle */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + s = st->numPoints / 4; + for (q = 0; q < s; q++) { + st->a[st->numFigs][q].x = ((double) q / s) * mx; + st->a[st->numFigs][q].y = 0; + st->a[st->numFigs][s + q].x = mx; + st->a[st->numFigs][s + q].y = ((double) q / s) * my; + st->a[st->numFigs][2 * s + q].x = mx - ((double) q / s) * mx; + st->a[st->numFigs][2 * s + q].y = my; + st->a[st->numFigs][3 * s + q].x = 0; + st->a[st->numFigs][3 * s + q].y = my - ((double) q / s) * my; + } + for (q = 4 * s; q < st->numPoints; q++) + st->a[st->numFigs][q].x = st->a[st->numFigs][q].y = 0; + st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x; + st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y; + ++st->numFigs; + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + rx * sin(1 * TWO_PI * (double) q / mp); + st->a[st->numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp); + } + st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x; + st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y; + ++st->numFigs; + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + ry * sin(3 * TWO_PI * (double) q / mp); + st->a[st->numFigs][q].y = my / 2 + ry * cos(1 * TWO_PI * (double) q / mp); + } + st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x; + st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y; + ++st->numFigs; + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + ry + * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp)) + * sin(TWO_PI * (double) q / mp); + st->a[st->numFigs][q].y = my / 2 + ry + * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp)) + * cos(TWO_PI * (double) q / mp); + } + st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x; + st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y; + ++st->numFigs; + + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + ry * sin(TWO_PI * (double) q / mp); + st->a[st->numFigs][q].y = my / 2 + ry * cos(TWO_PI * (double) q / mp); + } + st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x; + st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y; + ++st->numFigs; + + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + rx * cos(TWO_PI * (double) q / mp); + st->a[st->numFigs][q].y = my / 2 + ry * sin(TWO_PI * (double) q / mp); + } + st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x; + st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y; + ++st->numFigs; + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + rx * sin(2 * TWO_PI * (double) q / mp); + st->a[st->numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp); + } + st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x; + st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y; + ++st->numFigs; + } + + if (st->figType & FT_OPEN) { + /* sine wave, one period */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = ((double) q / st->numPoints) * mx; + st->a[st->numFigs][q].y = (1.0 - sin(((double) q / mp) * TWO_PI)) + * my / 2.0; + } + ++st->numFigs; + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = ((double) q / mp) * mx; + st->a[st->numFigs][q].y = (1.0 - cos(((double) q / mp) * 3 * TWO_PI)) + * my / 2.0; + } + ++st->numFigs; + + /* spiral, one endpoint at bottom */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + ry * sin(5 * TWO_PI * (double) q / mp) + * ((double) q / mp); + st->a[st->numFigs][q].y = my / 2 + ry * cos(5 * TWO_PI * (double) q / mp) + * ((double) q / mp); + } + ++st->numFigs; + + /* spiral, one endpoint at top */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + rx = mx / 2; + ry = my / 2; + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = mx / 2 + ry * sin(6 * TWO_PI * (double) q / mp) + * ((double) q / mp); + st->a[st->numFigs][q].y = my / 2 - ry * cos(6 * TWO_PI * (double) q / mp) + * ((double) q / mp); + } + ++st->numFigs; + + /* */ + st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + for (q = 0; q < st->numPoints; q++) { + st->a[st->numFigs][q].x = ((double) q / mp) * mx; + st->a[st->numFigs][q].y = (1.0 - sin(((double) q / mp) * 5 * TWO_PI)) + * my / 2.0; + } + ++st->numFigs; + } + +#ifdef MARGINS + /* make some space around the figures. */ + marginx = (mx + 1) / 10; + marginy = (my + 1) / 10; + scalex = (double) ((mx + 1) - 2.0 * marginx) / (mx + 1.0); + scaley = (double) ((my + 1) - 2.0 * marginy) / (my + 1.0); + for (q = 0; q < st->numFigs; q++) + for (w = 0; w < st->numPoints; w++) { + st->a[q][w].x = marginx + st->a[q][w].x * scalex; + st->a[q][w].y = marginy + st->a[q][w].y * scaley; + } +#endif +} + +static void +initLMorph(struct state *st) +{ + int steps; + XGCValues gcv; + XWindowAttributes wa; + Colormap cmap; + char *ft; + int i; + + st->maxGamma = 1.0; +#if 1 + st->numPoints = points; + steps = steps_; + st->delay = delay; + ft = figtype; +#else + st->numPoints = get_integer_resource(st->dpy, "points", "Integer"); + steps = get_integer_resource(st->dpy, "steps", "Integer"); + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + ft = get_string_resource(st->dpy, "figtype", "String"); +#endif + + if (strcmp(ft, "all") == 0) + st->figType = FT_ALL; + else if (strcmp(ft, "open") == 0) + st->figType = FT_OPEN; + else if (strcmp(ft, "closed") == 0) + st->figType = FT_CLOSED; + else { + fprintf(stderr, "figtype should be `all', `open' or `closed'.\n"); + st->figType = FT_ALL; + } + + if (steps <= 0) + steps = (random() % 400) + 100; + + st->deltaGamma = 1.0 / steps; + XGetWindowAttributes(st->dpy, st->window, &wa); + st->scrWidth = wa.width; + st->scrHeight = wa.height; + cmap = wa.colormap; + //gcv.foreground = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground"); + gcv.foreground = load_color(st->dpy, cmap, foreground); + st->gcDraw = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + XSetForeground(st->dpy, st->gcDraw, gcv.foreground); + //gcv.foreground = get_pixel_resource(st->dpy, cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, cmap, background); + st->gcClear = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + XClearWindow(st->dpy, st->window); + + initPointArrays(st); + st->aCurr = st->aWork[st->nWork = 0]; + st->aPrev = NULL; + st->currGamma = st->maxGamma + 1.0; /* force creation of new figure at startup */ + st->nTo = RND(st->numFigs); + do { + st->nNext = RND(st->numFigs); + } while (st->nNext == st->nTo); + + st->aSlopeTo = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + st->aSlopeFrom = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + st->aNext = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint)); + + for (i = 0; i < st->numPoints ; i++) { + st->aSlopeTo[i].x = 0.0; + st->aSlopeTo[i].y = 0.0; + } + + { /* jwz for version 2.11 */ + /* int width = random() % 10;*/ + //int width = get_integer_resource(st->dpy, "linewidth", "Integer"); + int width = linewidth; + int style = LineSolid; + int cap = (width > 1 ? CapRound : CapButt); + int join = (width > 1 ? JoinRound : JoinBevel); + if (width == 1) + width = 0; + XSetLineAttributes(st->dpy, st->gcDraw, width, style, cap, join); + XSetLineAttributes(st->dpy, st->gcClear, width, style, cap, join); + } +} + +/* 55% of execution time */ +static void +createPoints(struct state *st) +{ + int q; + XPoint *pa = st->aCurr, *pa1 = st->aFrom, *pa2 = st->aTo; + XPoint *qa1 = st->aSlopeFrom, *qa2 = st->aSlopeTo; + float fg, f1g; + float speed; + + fg = st->currGamma; + f1g = 1.0 - st->currGamma; + for (q = st->numPoints; q; q--) { + speed = 0.45 * sin(TWO_PI * (double) (q + st->shift) / (st->numPoints - 1)); + fg = st->currGamma + 1.67 * speed + * exp(-200.0 * (st->currGamma - 0.5 + 0.7 * speed) + * (st->currGamma - 0.5 + 0.7 * speed)); + + f1g = 1.0 - fg; + pa->x = (short) (f1g * f1g * f1g * pa1->x + f1g * f1g * fg + * (3 * pa1->x + qa1->x) + f1g * fg * fg + * (3 * pa2->x - qa2->x) + fg * fg * fg * pa2->x); + pa->y = (short) (f1g * f1g * f1g * pa1->y + f1g * f1g * fg + * (3 * pa1->y + qa1->y) + f1g * fg * fg + * (3 * pa2->y - qa2->y) + fg * fg * fg * pa2->y); + + ++pa; + ++pa1; + ++pa2; + ++qa1; + ++qa2; + } +} + +/* 36% of execution time */ +static void +drawImage(struct state *st) +{ +#if 0 + int q; + XPoint *old0, *old1, *new0, *new1; + + /* Problem: update the window without too much flickering. I do + * this by handling each linesegment separately. First remove a + * line, then draw the new line. The problem is that this leaves + * small black pixels on the figure. To fix this, we draw the + * entire figure using XDrawLines() afterwards. */ + if (st->aPrev) { + old0 = st->aPrev; + old1 = st->aPrev + 1; + new0 = st->aCurr; + new1 = st->aCurr + 1; + for (q = st->numPoints - 1; q; q--) { + XDrawLine(st->dpy, st->window, st->gcClear, + old0->x, old0->y, old1->x, old1->y); + XDrawLine(st->dpy, st->window, st->gcDraw, + new0->x, new0->y, new1->x, new1->y); + ++old0; + ++old1; + ++new0; + ++new1; + } + } +#else + XClearWindow(st->dpy,st->window); +#endif + XDrawLines(st->dpy, st->window, st->gcDraw, st->aCurr, st->numPoints, CoordModeOrigin); +} + +/* neglectible % of execution time */ +static void +animateLMorph(struct state *st) +{ + int i; + if (st->currGamma > st->maxGamma) { + st->currGamma = 0.0; + st->nFrom = st->nTo; + st->nTo = st->nNext; + st->aFrom = st->a[st->nFrom]; + st->aTo = st->a[st->nTo]; + do { + st->nNext = RND(st->numFigs); + } while (st->nNext == st->nTo); + st->aNext = st->a[st->nNext]; + + st->shift = RND(st->numPoints); + if (RND(2)) { + /* reverse the array to get more variation. */ + int i1, i2; + XPoint p; + + for (i1 = 0, i2 = st->numPoints - 1; i1 < st->numPoints / 2; i1++, i2--) { + p = st->aNext[i1]; + st->aNext[i1] = st->aNext[i2]; + st->aNext[i2] = p; + } + } + + /* calculate the slopes */ + for (i = 0; i < st->numPoints ; i++) { + st->aSlopeFrom[i].x = st->aSlopeTo[i].x; + st->aSlopeFrom[i].y = st->aSlopeTo[i].y; + st->aSlopeTo[i].x = st->aNext[i].x - st->aTo[i].x; + st->aSlopeTo[i].y = (st->aNext[i].y - st->aTo[i].y); + } + } + + createPoints(st); + drawImage(st); + st->aPrev = st->aCurr; + st->aCurr = st->aWork[st->nWork ^= 1]; + + st->currGamma += st->deltaGamma; +} + +/*-----------------------------------------------------------------------+ +| PUBLIC FUNCTIONS | ++-----------------------------------------------------------------------*/ + +static void * +lmorph_init (Display *d, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = d; + st->window = w; + initLMorph(st); + return st; +} + +static unsigned long +lmorph_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + animateLMorph(st); + return st->delay; +} + +static void +lmorph_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + lmorph_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +lmorph_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +XSCREENSAVER_MODULE ("LMorph", lmorph) diff --git a/non-wgl/lmorph.vcproj b/non-wgl/lmorph.vcproj new file mode 100644 index 0000000..9c42acd --- /dev/null +++ b/non-wgl/lmorph.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/loop.c b/non-wgl/loop.c new file mode 100644 index 0000000..3a7bf6d --- /dev/null +++ b/non-wgl/loop.c @@ -0,0 +1,1714 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* loop --- Chris Langton's self-producing loops */ + +#if 0 +static const char sccsid[] = "@(#)loop.c 5.01 2000/03/15 xlockmore"; +#endif + +/*- + * Copyright (c) 1996 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: + * 15-Mar-2001: Added some flaws, random blue wall spots, to liven it up. + * This mod seems to expose a bug where hexagons are erased + * for no apparent reason. + * 01-Nov-2000: Allocation checks + * 16-Jun-2000: Fully coded the hexagonal rules. (Rules that end up in + * state zero were not bothered with since a calloc was used + * to set non-explicit rules to zero. This allows the + * compile-time option RAND_RULES to work here (at least to + * generation 540).) + * Also added compile-time option DELAYDEBUGLOOP for debugging + * life form. This also turns off the random initial direction + * of the loop. Set DELAYDEBUGLOOP to be 10 and use with + * something like this: + * xlock -mode loop -neighbors 6 -size 5 -delay 1 -count 540 -nolock + * 18-Oct-1998: Started creating a hexagon version. + * It proved not that difficult because I used Langton's Loop + * as a guide, hexagons have more neighbors so there is more + * freedom to program, and the loop will has six sides to + * store its genes (data). + * (Soon after this a triangular version with neighbors = 6 + * was attempted but was unsuccessful). + * 10-May-1997: Compatible with xscreensaver + * 15-Nov-1995: Coded from Chris Langton's Self-Reproduction in Cellular + * Automata Physica 10D 135-144 1984, also used wire.c as a + * guide. + */ + +/*- + Grid Number of Neighbors + ---- ------------------ + Square 4 + Hexagon 6 (currently in development) +*/ + +/*- + * From Steven Levy's Artificial Life + * Chris Langton's cellular automata "loops" reproduce in the spirit of life. + * Beginning from a single organism, the loops from a colony. As the loops + * on the outer fringes reproduce, the inner loops -- blocked by their + * daughters -- can no longer produce offspring. These dead progenitors + * provide a base for future generations' expansion, much like the formation + * of a coral reef. This self-organizing behavior emerges spontaneously, + * from the bottom up -- a key characteristic of artificial life. + */ + +/*- + Don't Panic -- When the artificial life tries to leave its petri + dish (ie. the screen) it will (usually) die... + The loops are short of "real" life because a general purpose Turing + machine is not contained in the loop. This is a simplification of + von Neumann and Codd's self-producing Turing machine. + The data spinning around could be viewed as both its DNA and its internal + clock. The program can be initalized to have the loop spin both ways... + but only one way around will work for a given rule. An open question (at + least to me): Is handedness a requirement for (artificial) life? Here + there is handedness at both the initial condition and the transition rule. + */ + +#define STANDALONE +#define HAVE_COCOA + +#ifndef HAVE_COCOA +# define DO_STIPPLE +#endif + +# define MODE_loop +#define DELAY 100000 +#define COUNT -5 +#define CYCLES 1600 +#define SIZE_ -12 +#define NCOLORS 15 +# define DEFAULTS "*delay: 100000 \n" \ + "*count: -5 \n" \ + "*cycles: 1600 \n" \ + "*size: -12 \n" \ + "*ncolors: 15 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define UNIFORM_COLORS +# define loop_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#include "automata.h" + +#ifdef MODE_loop + +/*- + * neighbors of 0 randomizes between 4 and 6. + */ +#define DEF_NEIGHBORS "0" /* choose random value */ + +static int neighbors = 0; + +static XrmOptionDescRec opts[] = +{ + {"-neighbors", ".loop.neighbors", XrmoptionSepArg, 0} +}; + +static argtype vars[] = +{ + {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int} +}; + +static OptionStruct desc[] = +{ + {"-neighbors num", "squares 4 or hexagons 6"} +}; + +ENTRYPOINT ModeSpecOpt loop_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + + +#ifdef USE_MODULES +ModStruct loop_description = +{"loop", "init_loop", "draw_loop", "release_loop", + "refresh_loop", "init_loop", (char *) NULL, &loop_opts, + 100000, 5, 1600, -12, 64, 1.0, "", + "Shows Langton's self-producing loops", 0, NULL}; + +#endif + +#define LOOPBITS(n,w,h)\ + if ((lp->pixmaps[lp->init_bits]=\ + XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\ + free_loop(display,lp); return;} else {lp->init_bits++;} + +static int local_neighbors = 0; + +#if 0 +/* Used to fast forward to troubled generations, mainly used for debugging. + -delay 1 -count 170 -neighbors 6 # divisions starts + 540 first cell collision + 1111 mutant being born from 2 parents + 1156 mutant born + */ +#define DELAYDEBUGLOOP 10 +#endif + +#define COLORS 8 +#define REALCOLORS (COLORS-2) +#define MINLOOPS 1 +#define REDRAWSTEP 2000 /* How many cells to draw per cycle */ +#define ADAM_SIZE 8 /* MIN 5 */ +#if 1 +#define ADAM_LOOPX (ADAM_SIZE+2) +#define ADAM_LOOPY (ADAM_SIZE+2) +#else +#define ADAM_LOOPX 16 +#define ADAM_LOOPY 10 +#endif +#define MINGRIDSIZE (3*ADAM_LOOPX) +#if 0 +/* TRIA stuff was an attempt to make a triangular lifeform on a + hexagonal grid but I got bored. You may need an additional 7th + state for a coherent step by step process of cell separation and + initial stem development. + */ +#define TRIA 1 +#endif +#ifdef TRIA +#define HEX_ADAM_SIZE 3 /* MIN 3 */ +#else +#define HEX_ADAM_SIZE 5 /* MIN 3 */ +#endif +#if 1 +#define HEX_ADAM_LOOPX (2*HEX_ADAM_SIZE+1) +#define HEX_ADAM_LOOPY (2*HEX_ADAM_SIZE+1) +#else +#define HEX_ADAM_LOOPX 3 +#define HEX_ADAM_LOOPY 7 +#endif +#define HEX_MINGRIDSIZE (6*HEX_ADAM_LOOPX) +#define MINSIZE ((MI_NPIXELS(mi)>=COLORS)?1:(2+(local_neighbors==6))) +#define NEIGHBORKINDS 2 +#define ANGLES 360 +#define MAXNEIGHBORS 6 + +/* Singly linked list */ +typedef struct _CellList { + XPoint pt; + struct _CellList *next; +} CellList; + +typedef struct { + int init_bits; + int generation; + int xs, ys; + int xb, yb; + int nrows, ncols; + int bx, by, bnrows, bncols; + int mincol, minrow, maxcol, maxrow; + int width, height; + int redrawing, redrawpos; + Bool dead, clockwise; + unsigned char *newcells, *oldcells; + int ncells[COLORS]; + CellList *cellList[COLORS]; + unsigned long colors[COLORS]; + GC stippledGC; + Pixmap pixmaps[COLORS]; + union { + XPoint hexagon[6]; + } shape; +} loopstruct; + +static loopstruct *loops = (loopstruct *) NULL; + +#define TRANSITION(TT,V) V=TT&7;TT>>=3 +#define FINALTRANSITION(TT,V) V=TT&7 +#define TABLE(R,T,L,B) (table[((B)<<9)|((L)<<6)|((T)<<3)|(R)]) +#define HEX_TABLE(R,T,t,l,b,B) (table[((B)<<15)|((b)<<12)|((l)<<9)|((t)<<6)|((T)<<3)|(R)]) + +#if 0 +/* Instead of setting "unused" state rules to zero it randomizes them. + These rules take over when something unexpected happens... like when a + cell hits a wall (the end of the screen). + */ +#define RAND_RULES +#endif + +#ifdef RAND_RULES +#define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)&=~(7<<((C)*3)));\ +(TABLE(R,T,L,B)|=((I)<<((C)*3))) +#define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)&=~(7<<((C)*3)));\ +(HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3))) +#else +#define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)|=((I)<<((C)*3))) +#define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3))) +#endif +#define TABLE_OUT(C,R,T,L,B) ((TABLE(R,T,L,B)>>((C)*3))&7) +#define HEX_TABLE_OUT(C,R,T,t,l,b,B) ((HEX_TABLE(R,T,t,l,b,B)>>((C)*3))&7) + +static unsigned int *table = (unsigned int *) NULL; + /* square: 8*8*8*8 = 2^12 = 2^3^4 = 4096 */ + /* hexagon: 8*8*8*8*8*8 = 2^18 = 2^3^6 = 262144 = too big? */ + +static char plots[NEIGHBORKINDS] = +{ + 4, 6 /* Neighborhoods */ +}; + +static unsigned int transition_table[] = +{ /* Octal CBLTR->I */ + /* CBLTRI CBLTRI CBLTRI CBLTRI CBLTRI */ + 0000000, 0025271, 0113221, 0202422, 0301021, + 0000012, 0100011, 0122244, 0202452, 0301220, + 0000020, 0100061, 0122277, 0202520, 0302511, + 0000030, 0100077, 0122434, 0202552, 0401120, + 0000050, 0100111, 0122547, 0202622, 0401220, + 0000063, 0100121, 0123244, 0202722, 0401250, + 0000071, 0100211, 0123277, 0203122, 0402120, + 0000112, 0100244, 0124255, 0203216, 0402221, + 0000122, 0100277, 0124267, 0203226, 0402326, + 0000132, 0100511, 0125275, 0203422, 0402520, + 0000212, 0101011, 0200012, 0204222, 0403221, + 0000220, 0101111, 0200022, 0205122, 0500022, + 0000230, 0101244, 0200042, 0205212, 0500215, + 0000262, 0101277, 0200071, 0205222, 0500225, + 0000272, 0102026, 0200122, 0205521, 0500232, + 0000320, 0102121, 0200152, 0205725, 0500272, + 0000525, 0102211, 0200212, 0206222, 0500520, + 0000622, 0102244, 0200222, 0206722, 0502022, + 0000722, 0102263, 0200232, 0207122, 0502122, + 0001022, 0102277, 0200242, 0207222, 0502152, + 0001120, 0102327, 0200250, 0207422, 0502220, + 0002020, 0102424, 0200262, 0207722, 0502244, + 0002030, 0102626, 0200272, 0211222, 0502722, + 0002050, 0102644, 0200326, 0211261, 0512122, + 0002125, 0102677, 0200423, 0212222, 0512220, + 0002220, 0102710, 0200517, 0212242, 0512422, + 0002322, 0102727, 0200522, 0212262, 0512722, + 0005222, 0105427, 0200575, 0212272, 0600011, + 0012321, 0111121, 0200722, 0214222, 0600021, + 0012421, 0111221, 0201022, 0215222, 0602120, + 0012525, 0111244, 0201122, 0216222, 0612125, + 0012621, 0111251, 0201222, 0217222, 0612131, + 0012721, 0111261, 0201422, 0222272, 0612225, + 0012751, 0111277, 0201722, 0222442, 0700077, + 0014221, 0111522, 0202022, 0222462, 0701120, + 0014321, 0112121, 0202032, 0222762, 0701220, + 0014421, 0112221, 0202052, 0222772, 0701250, + 0014721, 0112244, 0202073, 0300013, 0702120, + 0016251, 0112251, 0202122, 0300022, 0702221, + 0017221, 0112277, 0202152, 0300041, 0702251, + 0017255, 0112321, 0202212, 0300076, 0702321, + 0017521, 0112424, 0202222, 0300123, 0702525, + 0017621, 0112621, 0202272, 0300421, 0702720, + 0017721, 0112727, 0202321, 0300622 +}; + +static unsigned int hex_transition_table[] = +{ /* Octal CBbltTR->I */ + /* CBbltTRI CBbltTRI CBbltTRI CBbltTRI CBbltTRI */ + +#ifdef TRIA + 000000000, 000000020, 000000220, 000002220, 000022220, + 011122121, 011121221, 011122221, 011221221, + 011222221, 011112121, 011112221, + 020021122, 020002122, 020211222, 021111222, + 020221122, 020027122, 020020722, 020021022, + 001127221, + 011122727, 011227227, 010122121, 010222211, + 021117222, 020112272, + 070221220, + 001227221, + 010221121, 011721221, 011222277, + 020111222, 020221172, + 070211220, + 001217221, + 010212277, 010221221, + 020122112, + 070122220, + 001722221, + 010221271, + 020002022, 021122172, + 070121220, + 011122277, 011172121, + 010212177, 011212277, + 070112220, + 001772221, + 021221772, + 070121270, 070721220, + 000112721, 000272211, + 010022211, 012222277, + 020072272, 020227122, 020217222, + 010211121, + 020002727, + 070222220, + 001727721, + 020021072, 020070722, + 070002072, 070007022, + 001772721, + 070002022, + 000000070, 000000770, 000072220, 000000270, + 020110222, 020220272, 020220722, + 070007071, 070002072, 070007022, + 000000012, 000000122, 000000212, 001277721, + 020122072, 020202212, + 010002121, + 020001122, 020002112, + 020021722, + 020122022, 020027022, 020070122, 020020122, + 010227027, + 020101222, + 010227227, 010227277, + 021722172, + 001727221, + 010222277, + 020702272, + 070122020, + 000172721, + 010022277, 010202177, 010227127, + + 001214221, + 010202244, + 020024122, 020020422, + 040122220, + 001422221, + 010221241, 010224224, + 021122142, + 040121220, + 001124221, + 010224274, + 020112242, 021422172, + 040221220, + 001224221, 001427221, + 010222244, + 020227042, + 040122020, + 000142721, + 010022244, 010202144, 010224124, + 040112220, + 001442221, + 021221442, + 040121240, 040421220, + 000242211, 000112421, + 020042242, 020214222, 020021422, 020220242, 020024022, + 011224224, + 020224122, + 020220422, + 012222244, + 020002424, + 040222220, + 001244421, 000000420, 000000440, 000000240, 000000040, + 020040121, 020021042, + 040004022, 040004042, 040002042, + 010021121, + 020011122, 020002112, + 001424421, + 020040422, + 001442421, + 040002022, + 001724221, + 010227247, + 020224072, 021417222, + 000172421, + 010021721, + 020017022, + 020120212, + 020271727, + 070207072, 070701220, + 000001222, + 020110122, + 001277221, + 001777721, + 020021222, 020202272, 020120222, 020221722, + 020027227, + 070070222, + 000007220, + 020101272, 020272172, 020721422, 020721722, + 020011222, 020202242, +#if 0 + {2,2,0,0,2,7,0}, + {2,0,2,0,2,0,2}, + {2,4,1,2,2,1,2}, + {2,1,2,1,2,1,2}, + {2,0,2,2,1,1,2}, + {2,7,1,1,1,1,2}, + {0,2,2,2,2,2,2}, + {2,2,0,0,7,7,0}, + {2,1,2,0,2,0,7}, + {2,0,1,2,2,1,2}, + {2,4,2,1,2,1,2}, + {2,1,2,2,1,1,2}, + {2,0,7,1,1,1,2}, + {0,2,2,2,2,2,2}, +#endif +#else + 000000000, 000000020, 000000220, 000002220, + 011212121, 011212221, 011221221, 011222221, + 020002122, 020021122, 020211122, + + 010221221, 010222121, + 020002022, 020021022, 020020122, 020112022, + + 010202121, + 020102022, 020202112, + + 000000012, 000000122, 000000212, + 010002121, + 020001122, 020002112, 020011122, + + + 001227221, 001272221, 001272721, + 012212277, 011222727, 011212727, + 020021722, 020027122, 020020722, 020027022, + 020211722, 020202172, 020120272, + 020271122, 020202172, 020207122, 020217122, + 020120272, 020210722, 020270722, + 070212220, 070221220, 070212120, + + + 012222277, + 020002727, + 070222220, + + 001277721, 000000070, 000000270, 000000720, 000000770, + 020070122, 020021072, + 070002072, 070007022, 070007071, + + 020070722, + 070002022, + + 010227227, 010222727, 010202727, + 020172022, 020202712, + + 001224221, 001242221, 001242421, + 012212244, 011222424, 011212424, + 020021422, 020024122, 020020422, 020024022, + 020211422, 020202142, 020120242, + 020241122, 020202142, 020204122, 020214122, + 020120242, 020210422, 020240422, + 040212220, 040221220, 040212120, + + + 012222244, + 020002424, + 040222220, + + 001244421, 000000040, 000000240, 000000420, 000000440, + 020040122, 020021042, + 040002042, + 040004021, 040004042, + + 020040422, + 040002022, + + 010224224, 010222424, 010202424, + 020142022, 020202412, + 020011722, 020112072, 020172072, 020142072, + + + + 000210225, 000022015, 000022522, + 011225521, + 020120525, 020020152, 020005122, 020214255, 020021152, + 020255242, + 050215222, 050225121, + + 000225220, 001254222, + 010221250, 011221251, 011225221, + 020025122, 020152152, 020211252, 020214522, 020511125, + 050212241, 05221120, + 040521225, + + 000000250, 000000520, 000150220, 000220520, 000222210, + 001224251, + 010022152, 010251221, 010522121, 011212151, 011221251, + 011215221, + 020000220, 020002152, 020020220, 020022152, + 020021422, 020022152, 020022522, 020025425, 020050422, + 020051022, 020051122, 020211122, 020211222, 020215222, + 020245122, + 050021125, 050021025, 050011125, 051242221, + 041225220, + + 000220250, 000220520, 001227521, 001275221, + 011257227, 011522727, + 020002052, 020002752, 020021052, 020057125, + 050020722, 050027125, + 070215220, + + 070212255, + 071225220, + 020275122, + 051272521, + 020055725, + 020021552, + 012252277, + 050002521, + 020005725, + + 050011022, + 000000155, + 020050722, + 001227250, + 010512727, + 010002151, + 020027112, + 001227251, + 012227257, + 050002125, + 020517122, + 050002025, + 020050102, + 050002725, + 020570722, + 001252721, + 020007051, + 020102052, + 020271072, + 050001122, + 010002151, + 011227257, + 020051722, + 020057022, + 020050122, + + + 020051422, + 011224254, + 012224254, + + 020054022, + 050002425, + 040252220, + 020002454, + + + 000000540, + 001254425, + 050004024, + 040004051, + + 000000142, + 040001522, + 010002547, + 020045122, + 051221240, + 020002512, + 020021522, + + + 020020022, + 021125522, + 020521122, + 020025022, + 020025522, + 020020522, + + 020202222, + 020212222, + 021212222, + 021222722, + 021222422, + 020002222, + 020021222, + 020022122, + 020212122, + 020027222, + 020024222, + 020212722, + 020212422, + 020202122, + 001222221, + 020002522, + + 020017125, + 010022722, + 020212052, + + 020205052, + 070221250, + + 000000050, 000005220, 000002270, 070252220, + 000000450, 000007220, + 000220220, 000202220, 000022020, 000020220, + + 000222040, + 000220440, + 000022040, + 000040220, + + 000252220, + 050221120, 010221520, + 002222220, + + 000070220, 000220720, + 000020520, 000070250, 000222070, 000027020, + 000022070, 000202270, 000024020, 000220420, + 000220270, 000220240, 000072020, 000042020, + 000002020, 000002070, 000020270, 000020250, + 000270270, 000007020, 000040270, + + /* Collision starts (gen 540), not sure to have rules to save it + or depend on calloc to intialize remaining rules to 0 so that + the mutant will be born + */ + 000050220, +#endif +}; + + +/*- +Neighborhoods are read as follows (rotations are not listed): + T + L C R ==> I + B + + t T + l C R ==> I + b B + */ + +static unsigned char self_reproducing_loop[ADAM_LOOPY][ADAM_LOOPX] = +{ +/* 10x10 */ + {0, 2, 2, 2, 2, 2, 2, 2, 2, 0}, + {2, 4, 0, 1, 4, 0, 1, 1, 1, 2}, + {2, 1, 2, 2, 2, 2, 2, 2, 1, 2}, + {2, 0, 2, 0, 0, 0, 0, 2, 1, 2}, + {2, 7, 2, 0, 0, 0, 0, 2, 7, 2}, + {2, 1, 2, 0, 0, 0, 0, 2, 0, 2}, + {2, 0, 2, 0, 0, 0, 0, 2, 1, 2}, + {2, 7, 2, 2, 2, 2, 2, 2, 7, 2}, + {2, 1, 0, 6, 1, 0, 7, 1, 0, 2}, + {0, 2, 2, 2, 2, 2, 2, 2, 2, 0} +}; + +static unsigned char hex_self_reproducing_loop[HEX_ADAM_LOOPY][HEX_ADAM_LOOPX] = +{ +#if 0 +/* Experimental TRIA5:7x7 */ + {2,2,0,0,0,0,0}, + {2,1,2,0,2,2,0}, + {2,0,4,2,2,0,2}, + {2,7,2,0,2,0,2}, + {2,1,2,2,1,1,2}, + {2,0,7,1,0,7,2}, + {0,2,2,2,2,2,2}, + /* Stem cells, only "5" will fully reproduce itself */ +/* 3:12x7 */ + {2,2,2,2,0,0,0,0,0,0,0,0}, + {2,1,1,1,2,0,0,0,0,0,0,0}, + {2,1,2,2,1,2,2,2,2,2,2,0}, + {2,1,2,0,2,7,1,1,1,1,1,2}, + {0,2,1,2,2,0,2,2,2,2,2,2}, + {0,0,2,0,4,1,2,0,0,0,0,0}, + {0,0,0,2,2,2,2,0,0,0,0,0} +/* 4:14x9 */ + {2,2,2,2,2,0,0,0,0,0,0,0,0,0}, + {2,1,1,1,1,2,0,0,0,0,0,0,0,0}, + {2,1,2,2,2,1,2,0,0,0,0,0,0,0}, + {2,1,2,0,0,2,1,2,2,2,2,2,2,0}, + {2,1,2,0,0,0,2,7,1,1,1,1,1,2}, + {0,2,1,2,0,0,2,0,2,2,2,2,2,2}, + {0,0,2,0,2,2,2,1,2,0,0,0,0,0}, + {0,0,0,2,4,1,0,7,2,0,0,0,0,0}, + {0,0,0,0,2,2,2,2,2,0,0,0,0,0} +/* 5:16x11 */ + {2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0}, + {2,1,1,1,1,1,2,0,0,0,0,0,0,0,0,0}, + {2,1,2,2,2,2,1,2,0,0,0,0,0,0,0,0}, + {2,1,2,0,0,0,2,1,2,0,0,0,0,0,0,0}, + {2,1,2,0,0,0,0,2,1,2,2,2,2,2,2,0}, + {2,1,2,0,0,0,0,0,2,7,1,1,1,1,1,2}, + {0,2,1,2,0,0,0,0,2,0,2,2,2,2,2,2}, + {0,0,2,0,2,0,0,0,2,1,2,0,0,0,0,0}, + {0,0,0,2,4,2,2,2,2,7,2,0,0,0,0,0}, + {0,0,0,0,2,1,0,7,1,0,2,0,0,0,0,0}, + {0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0} +/* test:3x7 (0,4) is blank ... very strange. + init_adam seems ok something after that I guess */ + {2,2,0}, + {2,0,2}, + {0,2,2}, + {0,0,0}, + {2,2,0}, + {2,1,2}, + {0,2,2}, +#else /* this might be better for hexagons, spacewise efficient... */ +#ifdef TRIA +/* Experimental TRIA5:7x7 */ + {2,2,0,0,2,2,0}, + {2,4,2,0,2,7,2}, + {2,1,0,2,2,0,2}, + {2,0,2,1,2,1,2}, + {2,7,2,2,7,7,2}, + {2,1,0,7,1,0,2}, + {0,2,2,2,2,2,2}, +#else +/* 5:11x11 */ + {2,2,2,2,2,2,0,0,0,0,0}, + {2,1,1,7,0,1,2,0,0,0,0}, + {2,1,2,2,2,2,7,2,0,0,0}, + {2,1,2,0,0,0,2,0,2,0,0}, + {2,1,2,0,0,0,0,2,1,2,0}, + {2,1,2,0,0,0,0,0,2,7,2}, + {0,2,1,2,0,0,0,0,2,0,2}, + {0,0,2,1,2,0,0,0,2,1,2}, + {0,0,0,2,1,2,2,2,2,4,2}, + {0,0,0,0,2,1,1,1,1,5,2}, + {0,0,0,0,0,2,2,2,2,2,2} +#endif +#endif +}; + +static void +position_of_neighbor(int dir, int *pcol, int *prow) +{ + int col = *pcol, row = *prow; + + /* NO WRAPING */ + + if (local_neighbors == 6) { + switch (dir) { + case 0: + col++; + break; + case 60: + col += (row & 1); + row--; + break; + case 120: + col -= !(row & 1); + row--; + break; + case 180: + col--; + break; + case 240: + col -= !(row & 1); + row++; + break; + case 300: + col += (row & 1); + row++; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } else { + switch (dir) { + case 0: + col++; + break; + case 90: + row--; + break; + case 180: + col--; + break; + case 270: + row++; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } + *pcol = col; + *prow = row; +} + +static Bool +withinBounds(loopstruct * lp, int col, int row) +{ + return (row >= 1 && row < lp->bnrows - 1 && + col >= 1 && col < lp->bncols - 1 - (local_neighbors == 6 && (row % 2))); +} + +static void +fillcell(ModeInfo * mi, GC gc, int col, int row) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + + if (local_neighbors == 6) { + int ccol = 2 * col + !(row & 1), crow = 2 * row; + + lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs; + lp->shape.hexagon[0].y = lp->yb + crow * lp->ys; + if (lp->xs == 1 && lp->ys == 1) + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + lp->shape.hexagon[0].x, lp->shape.hexagon[0].y); + else + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + lp->shape.hexagon, 6, Convex, CoordModePrevious); + } else { + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + lp->xb + lp->xs * col, lp->yb + lp->ys * row, + lp->xs - (lp->xs > 3), lp->ys - (lp->ys > 3)); + } +} + +static void +drawcell(ModeInfo * mi, int col, int row, int state) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + XGCValues gcv; + GC gc; + + if (MI_NPIXELS(mi) >= COLORS) { + gc = MI_GC(mi); + XSetForeground(MI_DISPLAY(mi), gc, lp->colors[state]); + } else { +#ifdef DO_STIPPLE + gcv.stipple = lp->pixmaps[state]; +#endif /* DO_STIPPLE */ + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + XChangeGC(MI_DISPLAY(mi), lp->stippledGC, +#ifdef DO_STIPPLE + GCStipple | +#endif /* DO_STIPPLE */ + GCForeground | GCBackground, &gcv); + gc = lp->stippledGC; + } + fillcell(mi, gc, col, row); +} + +#ifdef DEBUG +static void +print_state(ModeInfo * mi, int state) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + CellList *locallist = lp->cellList[state]; + int i = 0; + + (void) printf("state %d\n", state); + while (locallist) { + (void) printf("%d x %d, y %d\n", i, + locallist->pt.x, locallist->pt.y); + locallist = locallist->next; + i++; + } +} + +#endif + +static void +free_state(loopstruct * lp, int state) +{ + CellList *current; + + while (lp->cellList[state]) { + current = lp->cellList[state]; + lp->cellList[state] = lp->cellList[state]->next; + (void) free((void *) current); + } + lp->ncells[state] = 0; +} + +static void +free_list(loopstruct * lp) +{ + int state; + + for (state = 0; state < COLORS; state++) + free_state(lp, state); +} + +static void +free_loop(Display *display, loopstruct * lp) +{ + int shade; + + for (shade = 0; shade < lp->init_bits; shade++) + if (lp->pixmaps[shade] != None) { + XFreePixmap(display, lp->pixmaps[shade]); + lp->pixmaps[shade] = None; + } + if (lp->stippledGC != None) { + XFreeGC(display, lp->stippledGC); + lp->stippledGC = None; + } + if (lp->oldcells != NULL) { + (void) free((void *) lp->oldcells); + lp->oldcells = (unsigned char *) NULL; + } + if (lp->newcells != NULL) { + (void) free((void *) lp->newcells); + lp->newcells = (unsigned char *) NULL; + } + free_list(lp); +} + +static Bool +addtolist(ModeInfo * mi, int col, int row, unsigned char state) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + CellList *current = lp->cellList[state]; + + if ((lp->cellList[state] = (CellList *) malloc(sizeof (CellList))) == + NULL) { + lp->cellList[state] = current; + free_loop(MI_DISPLAY(mi), lp); + return False; + } + lp->cellList[state]->pt.x = col; + lp->cellList[state]->pt.y = row; + lp->cellList[state]->next = current; + lp->ncells[state]++; + return True; +} + +static Bool +draw_state(ModeInfo * mi, int state) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + Display *display = MI_DISPLAY(mi); + GC gc; + XGCValues gcv; + CellList *current = lp->cellList[state]; + + if (MI_NPIXELS(mi) >= COLORS) { + gc = MI_GC(mi); + XSetForeground(display, gc, lp->colors[state]); + } else { +#ifdef DO_STIPPLE + gcv.stipple = lp->pixmaps[state]; +#endif /* DO_STIPPLE */ + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + XChangeGC(display, lp->stippledGC, +#ifdef DO_STIPPLE + GCStipple | +#endif /* DO_STIPPLE */ + GCForeground | GCBackground, &gcv); + gc = lp->stippledGC; + } + + if (local_neighbors == 6) { /* Draw right away, slow */ + while (current) { + int col, row, ccol, crow; + + col = current->pt.x; + row = current->pt.y; + ccol = 2 * col + !(row & 1), crow = 2 * row; + lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs; + lp->shape.hexagon[0].y = lp->yb + crow * lp->ys; + if (lp->xs == 1 && lp->ys == 1) + XDrawPoint(display, MI_WINDOW(mi), gc, + lp->shape.hexagon[0].x, lp->shape.hexagon[0].y); + else + XFillPolygon(display, MI_WINDOW(mi), gc, + lp->shape.hexagon, 6, Convex, CoordModePrevious); + current = current->next; + } + } else { + /* Take advantage of XFillRectangles */ + XRectangle *rects; + int nrects = 0; + + /* Create Rectangle list from part of the cellList */ + if ((rects = (XRectangle *) malloc(lp->ncells[state] * + sizeof (XRectangle))) == NULL) { + return False; + } + + while (current) { + rects[nrects].x = lp->xb + current->pt.x * lp->xs; + rects[nrects].y = lp->yb + current->pt.y * lp->ys; + rects[nrects].width = lp->xs - (lp->xs > 3); + rects[nrects].height = lp->ys - (lp->ys > 3); + current = current->next; + nrects++; + } + /* Finally get to draw */ + XFillRectangles(display, MI_WINDOW(mi), gc, rects, nrects); + /* Free up rects list and the appropriate part of the cellList */ + (void) free((void *) rects); + } + free_state(lp, state); + return True; +} + +static Bool +init_table(void) +{ + if (table == NULL) { + int mult = 1; + unsigned int tt, c, n[MAXNEIGHBORS], i; + int j, k; + int size_transition_table = sizeof (transition_table) / + sizeof (unsigned int); + int size_hex_transition_table = sizeof (hex_transition_table) / + sizeof (unsigned int); + + for (j = 0; j < local_neighbors; j++) + mult *= 8; + + if ((table = (unsigned int *) calloc(mult, sizeof (unsigned int))) == NULL) { + return False; + } + + +#ifdef RAND_RULES + /* Here I was interested to see what happens when it hits a wall.... + Rules not normally used take over... takes too much time though */ + /* Each state = 3 bits */ + if (MAXRAND < 16777216.0) { + for (j = 0; j < mult; j++) { + table[j] = (unsigned int) ((NRAND(4096) << 12) & NRAND(4096)); + } + } else { + for (j = 0; j < mult; j++) { + table[j] = (unsigned int) (NRAND(16777216)); + } + } +#endif + if (local_neighbors == 6) { + for (j = 0; j < size_hex_transition_table; j++) { + tt = hex_transition_table[j]; + TRANSITION(tt, i); + for (k = 0; k < local_neighbors; k++) { + TRANSITION(tt, n[k]); + } + FINALTRANSITION(tt, c); + HEX_TABLE_IN(c, n[0], n[1], n[2], n[3], n[4], n[5], i); + HEX_TABLE_IN(c, n[1], n[2], n[3], n[4], n[5], n[0], i); + HEX_TABLE_IN(c, n[2], n[3], n[4], n[5], n[0], n[1], i); + HEX_TABLE_IN(c, n[3], n[4], n[5], n[0], n[1], n[2], i); + HEX_TABLE_IN(c, n[4], n[5], n[0], n[1], n[2], n[3], i); + HEX_TABLE_IN(c, n[5], n[0], n[1], n[2], n[3], n[4], i); + } + } else { + for (j = 0; j < size_transition_table; j++) { + tt = transition_table[j]; + TRANSITION(tt, i); + for (k = 0; k < local_neighbors; k++) { + TRANSITION(tt, n[k]); + } + FINALTRANSITION(tt, c); + TABLE_IN(c, n[0], n[1], n[2], n[3], i); + TABLE_IN(c, n[1], n[2], n[3], n[0], i); + TABLE_IN(c, n[2], n[3], n[0], n[1], i); + TABLE_IN(c, n[3], n[0], n[1], n[2], i); + } + } + } + return True; +} + +static void +init_flaw(ModeInfo * mi) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + int a, b; + +#define BLUE 2 + if (lp->bncols <= 3 || lp->bnrows <= 3) + return; + a = MIN(lp->bncols - 3, 2 * ((local_neighbors == 6) ? + HEX_MINGRIDSIZE : MINGRIDSIZE)); + a = NRAND(a) + (lp->bncols - a) / 2; + b = MIN(lp->bnrows - 3, 2 * ((local_neighbors == 6) ? + HEX_MINGRIDSIZE : MINGRIDSIZE)); + b = NRAND(b) + (lp->bnrows - b) / 2; + if (lp->mincol > a) + lp->mincol = a; + if (lp->minrow > b) + lp->minrow = b; + if (lp->maxcol < a + 2) + lp->maxcol = a + 2; + if (lp->maxrow < b + 2) + lp->maxrow = b + 2; + + if (local_neighbors == 6) { + lp->newcells[b * lp->bncols + a + !(b % 2) ] = BLUE; + lp->newcells[b * lp->bncols + a + 1 + !(b % 2)] = BLUE; + lp->newcells[(b + 1) * lp->bncols + a] = BLUE; + lp->newcells[(b + 1) * lp->bncols + a + 2] = BLUE; + lp->newcells[(b + 2) * lp->bncols + a + !(b % 2)] = BLUE; + lp->newcells[(b + 2) * lp->bncols + a + 1 + !(b % 2)] = BLUE; + } else { + int orient = NRAND(4); + lp->newcells[lp->bncols * (b + 1) + a + 1] = BLUE; + if (orient == 0 || orient == 1) { + lp->newcells[lp->bncols * b + a + 1] = BLUE; + } + if (orient == 1 || orient == 2) { + lp->newcells[lp->bncols * (b + 1) + a + 2] = BLUE; + } + if (orient == 2 || orient == 3) { + lp->newcells[lp->bncols * (b + 2) + a + 1] = BLUE; + } + if (orient == 3 || orient == 0) { + lp->newcells[lp->bncols * (b + 1) + a] = BLUE; + } + } +} + +static void +init_adam(ModeInfo * mi) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + XPoint start = { 0, 0 }, dirx = { 0, 0 }, diry = { 0, 0 }; + int i, j, dir; + +#ifdef DELAYDEBUGLOOP + lp->clockwise = 0; + if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */ +#endif + lp->clockwise = (Bool) (LRAND() & 1); +#ifdef DELAYDEBUGLOOP + dir = 0; + if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */ +#endif + dir = NRAND(local_neighbors); + if (local_neighbors == 6) { + int k; + + switch (dir) { + case 0: + start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2; + start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2; + if (lp->mincol > start.x - 2) + lp->mincol = start.x - 2; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + for (j = 0; j < HEX_ADAM_LOOPY; j++) { + for (i = 0; i < HEX_ADAM_LOOPX; i++) { + k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2); + lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = + (lp->clockwise) ? + hex_self_reproducing_loop[i][j] : + hex_self_reproducing_loop[j][i]; + } + } + break; + case 1: + start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2; + start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2; + if (lp->mincol > start.x - 1) + lp->mincol = start.x - 1; + if (lp->minrow > start.y - HEX_ADAM_LOOPX) + lp->minrow = start.y - HEX_ADAM_LOOPX; + if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1) + lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + for (j = 0; j < HEX_ADAM_LOOPY; j++) { + for (i = 0; i < HEX_ADAM_LOOPX; i++) { + k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2) + ? -(i + j + 1) / 2 : -(i + j) / 2); + lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] = + (lp->clockwise) ? + hex_self_reproducing_loop[i][j] : + hex_self_reproducing_loop[j][i]; + } + } + break; + case 2: + start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2; + start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2; + if (lp->mincol > start.x - 2) + lp->mincol = start.x - 2; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + for (j = 0; j < HEX_ADAM_LOOPX; j++) { + for (i = 0; i < HEX_ADAM_LOOPY; i++) { + k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2); + lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = + (lp->clockwise) ? + hex_self_reproducing_loop[j][HEX_ADAM_LOOPX - i - 1] : + hex_self_reproducing_loop[i][HEX_ADAM_LOOPY - j - 1]; + } + } + break; + case 3: + start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2; + start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2; + if (lp->mincol > start.x - 1) + lp->mincol = start.x - 1; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + for (j = 0; j < HEX_ADAM_LOOPY; j++) { + for (i = 0; i < HEX_ADAM_LOOPX; i++) { + k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2); + lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = + (lp->clockwise) ? + hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] : + hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; + } + } + break; + case 4: + start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2; + start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2; + if (lp->mincol > start.x - 1) + lp->mincol = start.x - 1; + if (lp->minrow > start.y - HEX_ADAM_LOOPX) + lp->minrow = start.y - HEX_ADAM_LOOPX; + if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1) + lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + for (j = 0; j < HEX_ADAM_LOOPY; j++) { + for (i = 0; i < HEX_ADAM_LOOPX; i++) { + k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2) + ? -(i + j + 1) / 2 : -(i + j) / 2); + lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] = + (lp->clockwise) ? + hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] : + hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; + } + } + break; + case 5: + start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2; + start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2; + if (lp->mincol > start.x - 2) + lp->mincol = start.x - 2; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPY + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPY + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPX + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPX + 1; + for (j = 0; j < HEX_ADAM_LOOPX; j++) { + for (i = 0; i < HEX_ADAM_LOOPY; i++) { + k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2); + lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = + (lp->clockwise) ? + hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][i] : + hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][j]; + } + } + break; + } +#if DEBUGTEST + /* (void) printf ("s %d s %d \n", start.x, start.y); */ + (void) printf ("%d %d %d %d %d\n", + start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx, + start.y + j - lp->by, i, j, hex_self_reproducing_loop[j][i]); + /* Draw right away */ + drawcell(mi, start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx, + start.y + j - lp->by, + hex_self_reproducing_loop[j][i]); +#endif + } else { + switch (dir) { + case 0: + start.x = (lp->bncols - ADAM_LOOPX) / 2; + start.y = (lp->bnrows - ADAM_LOOPY) / 2; + dirx.x = 1, dirx.y = 0; + diry.x = 0, diry.y = 1; + if (lp->mincol > start.x) + lp->mincol = start.x; + if (lp->minrow > start.y) + lp->minrow = start.y; + if (lp->maxcol < start.x + ADAM_LOOPX) + lp->maxcol = start.x + ADAM_LOOPX; + if (lp->maxrow < start.y + ADAM_LOOPY) + lp->maxrow = start.y + ADAM_LOOPY; + break; + case 1: + start.x = (lp->bncols + ADAM_LOOPY) / 2; + start.y = (lp->bnrows - ADAM_LOOPX) / 2; + dirx.x = 0, dirx.y = 1; + diry.x = -1, diry.y = 0; + if (lp->mincol > start.x - ADAM_LOOPY) + lp->mincol = start.x - ADAM_LOOPY; + if (lp->minrow > start.y) + lp->minrow = start.y; + if (lp->maxcol < start.x) + lp->maxcol = start.x; + if (lp->maxrow < start.y + ADAM_LOOPX) + lp->maxrow = start.y + ADAM_LOOPX; + break; + case 2: + start.x = (lp->bncols + ADAM_LOOPX) / 2; + start.y = (lp->bnrows + ADAM_LOOPY) / 2; + dirx.x = -1, dirx.y = 0; + diry.x = 0, diry.y = -1; + if (lp->mincol > start.x - ADAM_LOOPX) + lp->mincol = start.x - ADAM_LOOPX; + if (lp->minrow > start.y - ADAM_LOOPY) + lp->minrow = start.y - ADAM_LOOPY; + if (lp->maxcol < start.x) + lp->maxcol = start.x; + if (lp->maxrow < start.y) + lp->maxrow = start.y; + break; + case 3: + start.x = (lp->bncols - ADAM_LOOPY) / 2; + start.y = (lp->bnrows + ADAM_LOOPX) / 2; + dirx.x = 0, dirx.y = -1; + diry.x = 1, diry.y = 0; + if (lp->mincol > start.x) + lp->mincol = start.x; + if (lp->minrow > start.y - ADAM_LOOPX) + lp->minrow = start.y - ADAM_LOOPX; + if (lp->maxcol < start.x + ADAM_LOOPX) + lp->maxcol = start.x + ADAM_LOOPX; + if (lp->maxrow < start.y) + lp->maxrow = start.y; + break; + } + for (j = 0; j < ADAM_LOOPY; j++) + for (i = 0; i < ADAM_LOOPX; i++) + lp->newcells[lp->bncols * (start.y + dirx.y * i + diry.y * j) + + start.x + dirx.x * i + diry.x * j] = + (lp->clockwise) ? + self_reproducing_loop[j][ADAM_LOOPX - i - 1] : + self_reproducing_loop[j][i]; +#if DEBUG + /* Draw right away */ + drawcell(mi, start.x + dirx.x * i + diry.x * j - lp->bx, + start.y + dirx.y * i + diry.y * j - lp->by, + (lp->clockwise) ? self_reproducing_loop[j][ADAM_LOOPX - i - i] : self_reproducing_loop[j][i]); +#endif + } +} + + +static void +do_gen(loopstruct * lp) +{ + int i, j, k; + unsigned char *z; + unsigned int n[MAXNEIGHBORS]; + unsigned int c; + +#define LOC(X, Y) (*(lp->oldcells + (X) + ((Y) * lp->bncols))) + + for (j = lp->minrow; j <= lp->maxrow; j++) { + for (i = lp->mincol; i <= lp->maxcol; i++) { + z = lp->newcells + i + j * lp->bncols; + c = LOC(i, j); + for (k = 0; k < local_neighbors; k++) { + int newi = i, newj = j; + + position_of_neighbor(k * ANGLES / local_neighbors, &newi, &newj); + n[k] = 0; + if (withinBounds(lp, newi, newj)) { + n[k] = LOC(newi, newj); + } + } + if (local_neighbors == 6) { + *z = (lp->clockwise) ? + HEX_TABLE_OUT(c, n[5], n[4], n[3], n[2], n[1], n[0]) : + HEX_TABLE_OUT(c, n[0], n[1], n[2], n[3], n[4], n[5]); + } else { + *z = (lp->clockwise) ? + TABLE_OUT(c, n[3], n[2], n[1], n[0]) : + TABLE_OUT(c, n[0], n[1], n[2], n[3]); + } + } + } +} + +ENTRYPOINT void +release_loop (ModeInfo * mi) +{ + if (loops != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_loop(MI_DISPLAY(mi), &loops[screen]); + (void) free((void *) loops); + loops = (loopstruct *) NULL; + } + if (table != NULL) { + (void) free((void *) table); + table = (unsigned int *) NULL; + } +} + +static void *stop_warning_about_triangleUnit_already; + + +ENTRYPOINT void +init_loop (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + int i, size = MI_SIZE(mi); + loopstruct *lp; + + stop_warning_about_triangleUnit_already = (void *) &triangleUnit; + + if (loops == NULL) { + if ((loops = (loopstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (loopstruct))) == NULL) + return; + } + lp = &loops[MI_SCREEN(mi)]; + + lp->redrawing = 0; + +#ifdef DO_STIPPLE + if ((MI_NPIXELS(mi) < COLORS) && (lp->init_bits == 0)) { + Window window = MI_WINDOW(mi); + XGCValues gcv; + if (lp->stippledGC == None) { + gcv.fill_style = FillOpaqueStippled; + if ((lp->stippledGC = XCreateGC(display, window, + GCFillStyle, &gcv)) == None) { + free_loop(display, lp); + return; + } + } + LOOPBITS(stipples[0], STIPPLESIZE, STIPPLESIZE); + LOOPBITS(stipples[2], STIPPLESIZE, STIPPLESIZE); + LOOPBITS(stipples[3], STIPPLESIZE, STIPPLESIZE); + LOOPBITS(stipples[4], STIPPLESIZE, STIPPLESIZE); + LOOPBITS(stipples[6], STIPPLESIZE, STIPPLESIZE); + LOOPBITS(stipples[7], STIPPLESIZE, STIPPLESIZE); + LOOPBITS(stipples[8], STIPPLESIZE, STIPPLESIZE); + LOOPBITS(stipples[10], STIPPLESIZE, STIPPLESIZE); + } +#endif /* DO_STIPPLE */ + if (MI_NPIXELS(mi) >= COLORS) { + /* Maybe these colors should be randomized */ + lp->colors[0] = MI_BLACK_PIXEL(mi); + lp->colors[1] = MI_PIXEL(mi, 0); /* RED */ + lp->colors[5] = MI_PIXEL(mi, MI_NPIXELS(mi) / REALCOLORS); /* YELLOW */ + lp->colors[4] = MI_PIXEL(mi, 2 * MI_NPIXELS(mi) / REALCOLORS); /* GREEN */ + lp->colors[6] = MI_PIXEL(mi, 3 * MI_NPIXELS(mi) / REALCOLORS); /* CYAN */ + lp->colors[2] = MI_PIXEL(mi, 4 * MI_NPIXELS(mi) / REALCOLORS); /* BLUE */ + lp->colors[3] = MI_PIXEL(mi, 5 * MI_NPIXELS(mi) / REALCOLORS); /* MAGENTA */ + lp->colors[7] = MI_WHITE_PIXEL(mi); + } + free_list(lp); + lp->generation = 0; + lp->width = MI_WIDTH(mi); + lp->height = MI_HEIGHT(mi); + + if (!local_neighbors) { + for (i = 0; i < NEIGHBORKINDS; i++) { + if (neighbors == plots[i]) { + local_neighbors = neighbors; + break; + } + if (i == NEIGHBORKINDS - 1) { +#if 1 + local_neighbors = plots[NRAND(NEIGHBORKINDS)]; +#else + local_neighbors = 4; +#endif + break; + } + } + } + + + if (local_neighbors == 6) { + int nccols, ncrows; + + if (lp->width < 8) + lp->width = 8; + if (lp->height < 8) + lp->height = 8; + if (size < -MINSIZE) { + lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) / + HEX_MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + } else if (size < MINSIZE) { + if (!size) + lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE); + else + lp->ys = MINSIZE; + } else + lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) / + HEX_MINGRIDSIZE)); + lp->xs = lp->ys; + nccols = MAX(lp->width / lp->xs - 2, HEX_MINGRIDSIZE); + ncrows = MAX(lp->height / lp->ys - 1, HEX_MINGRIDSIZE); + lp->ncols = nccols / 2; + lp->nrows = ncrows / 2; + lp->nrows -= !(lp->nrows & 1); /* Must be odd */ + lp->xb = (lp->width - lp->xs * nccols) / 2 + lp->xs; + lp->yb = (lp->height - lp->ys * ncrows) / 2 + lp->ys; + for (i = 0; i < 6; i++) { + lp->shape.hexagon[i].x = (lp->xs - 1) * hexagonUnit[i].x; + lp->shape.hexagon[i].y = ((lp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3; + } + } else { + if (size < -MINSIZE) + lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) { + if (!size) + lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / MINGRIDSIZE); + else + lp->ys = MINSIZE; + } else + lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) / + MINGRIDSIZE)); + lp->xs = lp->ys; + lp->ncols = MAX(lp->width / lp->xs, ADAM_LOOPX + 1); + lp->nrows = MAX(lp->height / lp->ys, ADAM_LOOPX + 1); + lp->xb = (lp->width - lp->xs * lp->ncols) / 2; + lp->yb = (lp->height - lp->ys * lp->nrows) / 2; + } + lp->bx = 1; + lp->by = 1; + lp->bncols = lp->ncols + 2 * lp->bx; + lp->bnrows = lp->nrows + 2 * lp->by; + + MI_CLEARWINDOW(mi); + + if (lp->oldcells != NULL) { + (void) free((void *) lp->oldcells); + lp->oldcells = (unsigned char *) NULL; + } + if ((lp->oldcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, + sizeof (unsigned char))) == NULL) { + free_loop(display, lp); + return; + } + if (lp->newcells != NULL) { + (void) free((void *) lp->newcells); + lp->newcells = (unsigned char *) NULL; + } + if ((lp->newcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, + sizeof (unsigned char))) == NULL) { + free_loop(display, lp); + return; + } + if (!init_table()) { + release_loop(mi); + return; + } + lp->mincol = lp->bncols - 1; + lp->minrow = lp->bnrows - 1; + lp->maxcol = 0; + lp->maxrow = 0; +#ifndef DELAYDEBUGLOOP + { + int flaws = MI_COUNT(mi); + + if (flaws < 0) + flaws = NRAND(-MI_COUNT(mi) + 1); + for (i = 0; i < flaws; i++) { + init_flaw(mi); + } + /* actual flaws might be less since the adam loop done next */ + } +#endif + init_adam(mi); +} + +ENTRYPOINT void +draw_loop (ModeInfo * mi) +{ + int offset, i, j; + unsigned char *z, *znew; + loopstruct *lp; + + if (loops == NULL) + return; + lp = &loops[MI_SCREEN(mi)]; + if (lp->newcells == NULL) + return; + + MI_IS_DRAWN(mi) = True; + lp->dead = True; +#ifdef DELAYDEBUGLOOP + if (MI_COUNT(mi) && lp->generation > MI_COUNT(mi)) { + (void) sleep(DELAYDEBUGLOOP); + } +#endif + + for (j = lp->minrow; j <= lp->maxrow; j++) { + for (i = lp->mincol; i <= lp->maxcol; i++) { + offset = j * lp->bncols + i; + z = lp->oldcells + offset; + znew = lp->newcells + offset; + if (*z != *znew) { + lp->dead = False; + *z = *znew; + if (!addtolist(mi, i - lp->bx, j - lp->by, *znew)) + return; + if (i == lp->mincol && i > lp->bx) + lp->mincol--; + if (j == lp->minrow && j > lp->by) + lp->minrow--; + if (i == lp->maxcol && i < lp->bncols - 2 * lp->bx) + lp->maxcol++; + if (j == lp->maxrow && j < lp->bnrows - 2 * lp->by) + lp->maxrow++; + } + } + } + for (i = 0; i < COLORS; i++) + if (!draw_state(mi, i)) { + free_loop(MI_DISPLAY(mi), lp); + return; + } + if (++lp->generation > MI_CYCLES(mi) || lp->dead) { + init_loop(mi); + return; + } else + do_gen(lp); + + if (lp->redrawing) { + for (i = 0; i < REDRAWSTEP; i++) { + if ((*(lp->oldcells + lp->redrawpos))) { + drawcell(mi, lp->redrawpos % lp->bncols - lp->bx, + lp->redrawpos / lp->bncols - lp->by, + *(lp->oldcells + lp->redrawpos)); + } + if (++(lp->redrawpos) >= lp->bncols * (lp->bnrows - lp->bx)) { + lp->redrawing = 0; + break; + } + } + } +} + +ENTRYPOINT void +reshape_loop(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_loop (mi); +} + +ENTRYPOINT void +refresh_loop (ModeInfo * mi) +{ + loopstruct *lp; + + if (loops == NULL) + return; + lp = &loops[MI_SCREEN(mi)]; + + MI_CLEARWINDOW(mi); + lp->redrawing = 1; + lp->redrawpos = lp->by * lp->ncols + lp->bx; +} + +XSCREENSAVER_MODULE ("Loop", loop) + +#endif /* MODE_loop */ diff --git a/non-wgl/loop.vcproj b/non-wgl/loop.vcproj new file mode 100644 index 0000000..80c5f5d --- /dev/null +++ b/non-wgl/loop.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/maze.c b/non-wgl/maze.c new file mode 100644 index 0000000..bf6f7fd --- /dev/null +++ b/non-wgl/maze.c @@ -0,0 +1,1711 @@ +/****************************************************************************** + * [ maze ] ... + * + * modified: [ 13-08-08 ] Jamie Zawinski + * Removed the bridge option: it didn't look good, and it made + * the code a lot harder to understand. + * Made the maze stay out of the area used for the -fps display. + * Cleaned up and commented. + * + * modified: [ 1-04-00 ] Johannes Keukelaar + * Added -ignorant option (not the default) to remove knowlege + * of the direction in which the exit lies. + * + * modified: [ 6-28-98 ] Zack Weinberg + * + * Made the maze-solver somewhat more intelligent. There are + * three optimizations: + * + * - Straight-line lookahead: the solver does not enter dead-end + * corridors. This is a win with all maze generators. + * + * - First order direction choice: the solver knows where the + * exit is in relation to itself, and will try paths leading in + * that direction first. This is a major win on maze generator 1 + * which tends to offer direct routes to the exit. + * + * - Dead region elimination: the solver already has a map of + * all squares visited. Whenever it starts to backtrack, it + * consults this map and marks off all squares that cannot be + * reached from the exit without crossing a square already + * visited. Those squares can never contribute to the path to + * the exit, so it doesn't bother checking them. This helps a + * lot with maze generator 2 and somewhat less with generator 1. + * + * Further improvements would require knowledge of the wall map + * as well as the position of the exit and the squares visited. + * I would consider that to be cheating. Generator 0 makes + * mazes which are remarkably difficult to solve mechanically -- + * even with these optimizations the solver generally must visit + * at least two-thirds of the squares. This is partially + * because generator 0's mazes have longer paths to the exit. + * + * modified: [ 4-10-97 ] Johannes Keukelaar + * Added multiple maze creators. Robustified solver. + * Added bridge option. + * modified: [ 8-11-95 ] Ed James + * added fill of dead-end box to solve_maze while loop. + * modified: [ 3-7-93 ] Jamie Zawinski + * added the XRoger logo, cleaned up resources, made + * grid size a parameter. + * modified: [ 3-3-93 ] Jim Randell + * Added the colour stuff and integrated it with jwz's + * screenhack stuff. There's still some work that could + * be done on this, particularly allowing a resource to + * specify how big the squares are. + * modified: [ 10-4-88 ] Richard Hess ...!uunet!cimshop!rhess + * [ Revised primary execution loop within main()... + * [ Extended X event handler, check_events()... + * modified: [ 1-29-88 ] Dave Lemke lemke@sun.com + * [ Hacked for X11... + * [ Note the word "hacked" -- this is extremely ugly, but at + * [ least it does the job. NOT a good programming example + * [ for X. + * original: [ 6/21/85 ] Martin Weiss Sun Microsystems [ SunView ] + * + ****************************************************************************** + Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + + 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, and that the names of Sun or MIT not be + used in advertising or publicity pertaining to distribution of the + software without specific prior written permission. Sun and M.I.T. + make no representations about the suitability of this software for + any purpose. It is provided "as is" without any express or implied warranty. + + SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT + OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + OR PERFORMANCE OF THIS SOFTWARE. + *****************************************************************************/ + +#include "screenhack.h" +#include "erase.h" + +#include + +float eraseSeconds = 0; +char *eraseMode = NULL; + +char *background = "black"; +char *foreground = "white"; +int gridSize = 0; +int generator_ = -1; +int maxLength = 5; +Bool ignorant = False; + +int solveDelay = 10000; +int preDelay = 2000000; +int postDelay = 4000000; + +char *liveColor = "#00FF00"; +char *deadColor = "#880000"; +char *skipColor = "#8B5A00"; +char *surroundColor = "#220055"; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&gridSize, "gridSize", NULL, "0", t_Int}, + {&generator_, "generator", NULL, "-1", t_Int}, + {&maxLength, "maxLength", NULL, "5", t_Int}, + {&ignorant, "ignorant", NULL, "False", t_Bool}, + {&solveDelay, "solveDelay", NULL, "10000", t_Int}, + {&preDelay, "preDelay", NULL, "2000000", t_Int}, + {&postDelay, "postDelay", NULL, "4000000", t_Int}, + {&liveColor, "liveColor", NULL, "#00FF00", t_String}, + {&deadColor, "deadColor", NULL, "#880000", t_String}, + {&skipColor, "skipColor", NULL, "#8B5A00", t_String}, + {&surroundColor, "surroundColor", NULL, "#220055", t_String}, +}; + +/* #include */ +#define gray1_width 2 +#define gray1_height 2 +static const char gray1_bits[] = { 0x01, 0x02 }; + + +#define MAX_MAZE_SIZE_X 1000 +#define MAX_MAZE_SIZE_Y 1000 + +#define MOVE_LIST_SIZE (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y) + +#define NOT_DEAD 0x8000 +#define SOLVER_VISIT 0x4000 +#define START_SQUARE 0x2000 +#define END_SQUARE 0x1000 + +#define WALL_TOP 0x8 +#define WALL_RIGHT 0x4 +#define WALL_BOTTOM 0x2 +#define WALL_LEFT 0x1 +#define WALL_ANY 0xF + +#define DOOR_IN_TOP 0x800 +#define DOOR_IN_RIGHT 0x400 +#define DOOR_IN_BOTTOM 0x200 +#define DOOR_IN_LEFT 0x100 +#define DOOR_IN_ANY 0xF00 + +#define DOOR_OUT_TOP 0x80 +#define DOOR_OUT_RIGHT 0x40 +#define DOOR_OUT_BOTTOM 0x20 +#define DOOR_OUT_LEFT 0x10 + + +#define border_x (0) +#define border_y (0) + +#define get_random(x) (random() % (x)) + + +struct move_list_struct { + unsigned short x; + unsigned short y; + unsigned char dir, ways; +}; + +struct solve_state { + int running; + int i, x, y, bt; +}; + + +struct state { + Display *dpy; + Window window; + + GC gc, cgc, tgc, sgc, ugc, logo_gc, erase_gc; + Pixmap logo_map; + + int logo_x, logo_y; /* in grid cells (or -1) */ + int logo_width, logo_height; /* in pixels */ + int fps_width, fps_height; /* in pixels */ + + int solve_delay, pre_solve_delay, post_solve_delay; + + unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y]; + + struct move_list_struct move_list[MOVE_LIST_SIZE]; + struct move_list_struct save_path[MOVE_LIST_SIZE]; + struct move_list_struct path[MOVE_LIST_SIZE]; + + int maze_size_x, maze_size_y; + int sqnum, cur_sq_x, cur_sq_y, path_length; + int start_x, start_y, start_dir, end_x, end_y, end_dir; + int grid_width, grid_height; + int bw; + + int x, y, restart, stop, state, max_length; + int sync_p, sync_tick; + int ignorant_p; + + struct solve_state *solve_state; + + int *sets; /* The sets that our squares are in. */ + int *hedges; /* The `list' of hedges. */ + + int this_gen; + int erase_window; + eraser_state *eraser; + + int ifrandom; + int ifinit; + +}; + + +static void draw_wall (struct state *, int, int, int, GC); +static void draw_solid_square (struct state *, int, int, int, GC); +static void build_wall (struct state *, int, int, int); + + +static void +set_maze_sizes (struct state *st, int width, int height) +{ + st->maze_size_x = width / st->grid_width; + st->maze_size_y = height / st->grid_height; + + if (st->maze_size_x < 4) st->maze_size_x = 4; + if (st->maze_size_y < 4) st->maze_size_y = 4; +} + + +/* Resets the maze grid, picks the starting and ending points, + and the position of the logo, if any. + */ +static void +initialize_maze (struct state *st) +{ + int retry_count = 0; + int i, j, wall; + int logow = 1 + st->logo_width / st->grid_width; + int logoh = 1 + st->logo_height / st->grid_height; + + AGAIN: + + /* This can happen if the window is really small. Let's not sweat it. */ + if (++retry_count > 100) return; + + + /* initialize all squares */ + for ( i=0; imaze_size_x; i++) { + for ( j=0; jmaze_size_y; j++) { + st->maze[i][j] = 0; + } + } + + /* top wall */ + for ( i=0; imaze_size_x; i++ ) { + st->maze[i][0] |= WALL_TOP; + } + + /* right wall */ + for ( j=0; jmaze_size_y; j++ ) { + st->maze[st->maze_size_x-1][j] |= WALL_RIGHT; + } + + /* bottom wall */ + for ( i=0; imaze_size_x; i++ ) { + st->maze[i][st->maze_size_y-1] |= WALL_BOTTOM; + } + + /* left wall */ + for ( j=0; jmaze_size_y; j++ ) { + st->maze[0][j] |= WALL_LEFT; + } + + /* set start square */ + wall = get_random(4); + switch (wall) { + case 0: + i = get_random(st->maze_size_x); + j = 0; + break; + case 1: + i = st->maze_size_x - 1; + j = get_random(st->maze_size_y); + break; + case 2: + i = get_random(st->maze_size_x); + j = st->maze_size_y - 1; + break; + case 3: + i = 0; + j = get_random(st->maze_size_y); + break; + } + st->maze[i][j] |= START_SQUARE; + st->maze[i][j] |= ( DOOR_IN_TOP >> wall ); + st->maze[i][j] &= ~( WALL_TOP >> wall ); + st->cur_sq_x = i; + st->cur_sq_y = j; + st->start_x = i; + st->start_y = j; + st->start_dir = wall; + st->sqnum = 0; + + /* set end square */ + wall = (wall + 2)%4; + switch (wall) { + case 0: + i = get_random(st->maze_size_x); + j = 0; + break; + case 1: + i = st->maze_size_x - 1; + j = get_random(st->maze_size_y); + break; + case 2: + i = get_random(st->maze_size_x); + j = st->maze_size_y - 1; + break; + case 3: + i = 0; + j = get_random(st->maze_size_y); + break; + } + st->maze[i][j] |= END_SQUARE; + st->maze[i][j] |= ( DOOR_OUT_TOP >> wall ); + st->maze[i][j] &= ~( WALL_TOP >> wall ); + st->end_x = i; + st->end_y = j; + st->end_dir = wall; + + /* set logo */ + if ((st->maze_size_x-logow >= 6) && (st->maze_size_y-logoh >= 6)) + { + /* not closer than 3 grid units from a wall, to ensure that it + won't overlap the entrance or exit. */ + st->logo_x = get_random (st->maze_size_x - logow - 5) + 3; + st->logo_y = get_random (st->maze_size_y - logoh - 5) + 3; + for (i=0; imaze[st->logo_x + i][st->logo_y + j] |= DOOR_IN_ANY; + } + else + st->logo_y = st->logo_x = -1; + + /* mask out the fps area */ + if (st->fps_width > 0) + { + int fpsw = 1 + st->fps_width / st->grid_width; + int fpsh = 1 + st->fps_height / st->grid_width; + + /* if the chosen logo position overlapped the fps area, try again! */ + if (st->logo_x < fpsw+3 && st->logo_y+logoh > st->maze_size_y-fpsh-4) + goto AGAIN; + + /* if the start or end point is inside the fps area, try again! */ + if ((st->start_x <= fpsw && st->start_y >= st->maze_size_y-fpsh-1) || + (st->end_x <= fpsw && st->end_y >= st->maze_size_y-fpsh-1)) + goto AGAIN; + + for (i=0; imaze[i][st->maze_size_y - j - 1] |= DOOR_IN_ANY|SOLVER_VISIT; + /* take off left/bottom wall or the FPS text overlaps it */ + st->maze[i][st->maze_size_y - j - 1] &= ~(WALL_BOTTOM|WALL_LEFT); + } + } +} + + +/**************************************************************************** + Generator 2: Set-based maze generator. + + Put each square in the maze in a separate set. Also, make a list of all the + hedges. Randomize that list. Walk through the list. If, for a certain + hedge, the two squares on both sides of it are in different sets, union the + sets and remove the hedge. Continue until all hedges have been processed or + only one set remains. + + This is essentially the "Kruskal" algorithm. + + ****************************************************************************/ + +static void mask_out_set_rect(struct state *st, int x, int y, int w, int h); + +/* Initialise the sets. */ +static void +init_sets(struct state *st) +{ + int i, t, r; + + if(st->sets) + free(st->sets); + st->sets = (int *)malloc(st->maze_size_x*st->maze_size_y*sizeof(int)); + if(!st->sets) + abort(); + for(i = 0; i < st->maze_size_x*st->maze_size_y; i++) + { + st->sets[i] = i; + } + + if(st->hedges) + free(st->hedges); + st->hedges = (int *)malloc(st->maze_size_x*st->maze_size_y*2*sizeof(int)); + if(!st->hedges) + abort(); + for(i = 0; i < st->maze_size_x*st->maze_size_y*2; i++) + { + st->hedges[i] = i; + } + /* Mask out outside walls. */ + for(i = 0; i < st->maze_size_y; i++) + { + st->hedges[2*((st->maze_size_x)*i+st->maze_size_x-1)+1] = -1; + } + for(i = 0; i < st->maze_size_x; i++) + { + st->hedges[2*((st->maze_size_y-1)*st->maze_size_x+i)] = -1; + } + + /* Mask out the logo area. */ + if(st->logo_x!=-1) + { + int logow = 1 + st->logo_width / st->grid_width; + int logoh = 1 + st->logo_height / st->grid_height; + mask_out_set_rect(st, st->logo_x, st->logo_y, logow, logoh); + } + + /* Mask out the FPS area. */ + if(st->fps_width > 0) + { + int fpsw = 1 + st->fps_width / st->grid_width; + int fpsh = 1 + st->fps_height / st->grid_height; + mask_out_set_rect(st, 0, st->maze_size_y-fpsh, fpsw, fpsh); + } + + for(i = 0; i < st->maze_size_x*st->maze_size_y*2; i++) + { + t = st->hedges[i]; + r = random()%(st->maze_size_x*st->maze_size_y*2); + st->hedges[i] = st->hedges[r]; + st->hedges[r] = t; + } +} + +/* Get the representative of a set. */ +static int +get_set(struct state *st, int num) +{ + int s; + + if(st->sets[num]==num) + return num; + else + { + s = get_set(st, st->sets[num]); + st->sets[num] = s; + return s; + } +} + +/* Join two sets together. */ +static void +join_sets(struct state *st, int num1, int num2) +{ + int s1, s2; + + s1 = get_set(st, num1); + s2 = get_set(st, num2); + + if(s1sets[s2] = s1; + else + st->sets[s1] = s2; +} + +/* Exitialise the sets. */ +static void +exit_sets(struct state *st) +{ + if(st->hedges) + free(st->hedges); + st->hedges = 0; + if(st->sets) + free(st->sets); + st->sets = 0; +} + + +static void +set_create_maze(struct state *st) +{ + int i, h, xx, yy, dir, v, w; + + /* Do almost all the setup. */ + init_sets(st); + + /* Start running through the hedges. */ + for(i = 0; i < 2*st->maze_size_x*st->maze_size_y; i++) + { + h = st->hedges[i]; + + /* This one is in the logo or outside border. */ + if(h==-1) + continue; + + dir = h%2?1:2; + xx = (h>>1)%st->maze_size_x; + yy = (h>>1)/st->maze_size_x; + + v = xx; + w = yy; + switch(dir) + { + case 1: + v++; + break; + case 2: + w++; + break; + } + + if(get_set(st, xx+yy*st->maze_size_x)!=get_set(st, v+w*st->maze_size_x)) + { + join_sets(st, xx+yy*st->maze_size_x, v+w*st->maze_size_x); + /* Don't draw the wall. */ + } + else + { + /* Don't join the sets. */ + build_wall(st, xx, yy, dir); + } + } + + /* Free some memory. */ + exit_sets(st); +} + +/* mark a rectangle as being unavailable for usage in the maze */ +static void +mask_out_set_rect(struct state *st, int x, int y, int w, int h) +{ + int xx, yy; + for(xx = x; xx < x+w; xx++) + for(yy = y; yy < y+h; yy++) + { + st->hedges[2*(xx+st->maze_size_x*yy)+1] = -1; + st->hedges[2*(xx+st->maze_size_x*yy)] = -1; + } + for(xx = x; xx < x+w; xx++) + { + build_wall(st, xx, y, 0); + build_wall(st, xx, y+h, 0); + st->hedges[2*(xx+st->maze_size_x*(y-1))] = -1; + } + for(yy = y; yy < y+h; yy++) + { + build_wall(st, x, yy, 3); + build_wall(st, x+w, yy, 3); + st->hedges[2*(x-1+st->maze_size_x*yy)+1] = -1; + } +} + + +/**************************************************************************** + Generator 1: Wall-building maze generator. + + Pick a random, empty corner in the maze. Pick a random direction. Draw a + wall in that direction, from that corner until we hit a wall. Option: Only + draw the wall if it's going to be shorter than a certain length. Otherwise + we get lots of long walls. + + This is essentially the "Prim" algorithm. + ****************************************************************************/ + +static void alt_mask_out_rect(struct state *st, char *corners, + int x, int y, int w, int h); + +static void +alt_create_maze(struct state *st) +{ + char *corners; + int *c_idx; + int i, j, height, width, open_corners, k, dir, xx, yy; + + height = st->maze_size_y+1; + width = st->maze_size_x+1; + + /* Allocate and clear some mem. */ + corners = (char *)calloc(height*width, 1); + if(!corners) + return; + + /* Set up the indexing array. */ + c_idx = (int *)malloc(sizeof(int)*height*width); + if(!c_idx) + { + free(corners); + return; + } + for(i = 0; i < height*width; i++) + c_idx[i] = i; + for(i = 0; i < height*width; i++) + { + j = c_idx[i]; + k = random()%(height*width); + c_idx[i] = c_idx[k]; + c_idx[k] = j; + } + + /* Set up some initial walls. */ + /* Outside walls. */ + for(i = 0; i < width; i++) + { + corners[i] = 1; + corners[i+width*(height-1)] = 1; + } + for(i = 0; i < height; i++) + { + corners[i*width] = 1; + corners[i*width+width-1] = 1; + } + + /* mask out the logo area */ + if(st->logo_x!=-1) + { + int logow = 1 + st->logo_width / st->grid_width; + int logoh = 1 + st->logo_height / st->grid_height; + alt_mask_out_rect (st, corners, st->logo_x, st->logo_y, logow, logoh); + } + + /* mask out the FPS area */ + if(st->fps_width>0) + { + int fpsw = 1 + st->fps_width / st->grid_width; + int fpsh = 1 + st->fps_height / st->grid_height; + alt_mask_out_rect (st, corners, 0, st->maze_size_y-fpsh, fpsw, fpsh); + } + + /* Count open gridpoints. */ + open_corners = 0; + for(i = 0; i < width; i++) + for(j = 0; j < height; j++) + if(!corners[i+width*j]) + open_corners++; + + /* Now do actual maze generation. */ + while(open_corners>0) + { + for(i = 0; i < width*height; i++) + { + if(!corners[c_idx[i]]) + { + xx = c_idx[i]%width; + yy = c_idx[i]/width; + /* Choose a random direction. */ + dir = random()%4; + + k = 0; + /* Measure the length of the wall we'd draw. */ + while(!corners[xx+width*yy]) + { + k++; + switch(dir) + { + case 0: + yy--; + break; + case 1: + xx++; + break; + case 2: + yy++; + break; + case 3: + xx--; + break; + } + } + + if(k<=st->max_length) + { + xx = c_idx[i]%width; + yy = c_idx[i]/width; + + /* Draw a wall until we hit something. */ + while(!corners[xx+width*yy]) + { + open_corners--; + corners[xx+width*yy] = 1; + switch(dir) + { + case 0: + build_wall(st, xx-1, yy-1, 1); + yy--; + break; + case 1: + build_wall(st, xx, yy, 0); + xx++; + break; + case 2: + build_wall(st, xx, yy, 3); + yy++; + break; + case 3: + build_wall(st, xx-1, yy-1, 2); + xx--; + break; + } + } + } + } + } + } + + /* Free some memory we used. */ + free(corners); + free(c_idx); +} + + +/* mark a rectangle as being unavailable for usage in the maze */ +static void +alt_mask_out_rect(struct state *st, char *corners, int x, int y, int w, int h) +{ + int i, j, xx, yy; + int mazew = st->maze_size_x+1; + + for(i = x; i <= x+w; i++) + for(j = y; j <= y+h; j++) + corners[i+mazew*j] = 1; + + for(xx = x; xx < x+w; xx++) + { + build_wall(st, xx, y, 0); + if (y+h < st->maze_size_y) + build_wall(st, xx, y+h, 0); + } + for(yy = y; yy < y+h; yy++) + { + if (x > 0) + build_wall(st, x, yy, 3); + build_wall(st, x+w, yy, 3); + } +} + + +/**************************************************************************** + Generator 0: The original maze generator. + + Start somewhere. Take a step in a random direction. Keep doing this until + we hit a wall. Then, backtrack until we find a point where we can go in + another direction. + + This is essentially the "depth-first recursive backtracker" algorithm. + ****************************************************************************/ + +static int choose_door (struct state *st); +static int backup (struct state *st); + +static void +create_maze (struct state *st) /* create a maze layout given the initialized maze */ +{ + int i, newdoor = 0; + + do { + st->move_list[st->sqnum].x = st->cur_sq_x; + st->move_list[st->sqnum].y = st->cur_sq_y; + st->move_list[st->sqnum].dir = newdoor; + while ( ( newdoor = choose_door(st) ) == -1 ) { /* pick a door */ + if ( backup(st) == -1 ) { /* no more doors ... backup */ + return; /* done ... return */ + } + } + + /* mark the out door */ + st->maze[st->cur_sq_x][st->cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor ); + + switch (newdoor) { + case 0: st->cur_sq_y--; + break; + case 1: st->cur_sq_x++; + break; + case 2: st->cur_sq_y++; + break; + case 3: st->cur_sq_x--; + break; + } + st->sqnum++; + + /* mark the in door */ + st->maze[st->cur_sq_x][st->cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) ); + + /* if end square set path length and save path */ + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & END_SQUARE ) { + st->path_length = st->sqnum; + for ( i=0; ipath_length; i++) { + st->save_path[i].x = st->move_list[i].x; + st->save_path[i].y = st->move_list[i].y; + st->save_path[i].dir = st->move_list[i].dir; + } + } + + } while (1); + +} + + +static int +choose_door (struct state *st) /* pick a new path */ +{ + int candidates[3]; + int num_candidates; + + num_candidates = 0; + + /* top wall */ + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_TOP ) + goto rightwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_TOP ) + goto rightwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_TOP ) + goto rightwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y - 1] & DOOR_IN_ANY ) { + st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_TOP; + st->maze[st->cur_sq_x][st->cur_sq_y - 1] |= WALL_BOTTOM; + draw_wall(st, st->cur_sq_x, st->cur_sq_y, 0, st->gc); + goto rightwall; + } + candidates[num_candidates++] = 0; + + rightwall: + /* right wall */ + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_RIGHT ) + goto bottomwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_RIGHT ) + goto bottomwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_RIGHT ) + goto bottomwall; + if ( st->maze[st->cur_sq_x + 1][st->cur_sq_y] & DOOR_IN_ANY ) { + st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_RIGHT; + st->maze[st->cur_sq_x + 1][st->cur_sq_y] |= WALL_LEFT; + draw_wall(st, st->cur_sq_x, st->cur_sq_y, 1, st->gc); + goto bottomwall; + } + candidates[num_candidates++] = 1; + + bottomwall: + /* bottom wall */ + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_BOTTOM ) + goto leftwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_BOTTOM ) + goto leftwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_BOTTOM ) + goto leftwall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y + 1] & DOOR_IN_ANY ) { + st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_BOTTOM; + st->maze[st->cur_sq_x][st->cur_sq_y + 1] |= WALL_TOP; + draw_wall(st, st->cur_sq_x, st->cur_sq_y, 2, st->gc); + goto leftwall; + } + candidates[num_candidates++] = 2; + + leftwall: + /* left wall */ + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_LEFT ) + goto donewall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_LEFT ) + goto donewall; + if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_LEFT ) + goto donewall; + if ( st->maze[st->cur_sq_x - 1][st->cur_sq_y] & DOOR_IN_ANY ) { + st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_LEFT; + st->maze[st->cur_sq_x - 1][st->cur_sq_y] |= WALL_RIGHT; + draw_wall(st, st->cur_sq_x, st->cur_sq_y, 3, st->gc); + goto donewall; + } + candidates[num_candidates++] = 3; + + donewall: + if (num_candidates == 0) + return ( -1 ); + if (num_candidates == 1) + return ( candidates[0] ); + return ( candidates[ get_random(num_candidates) ] ); + +} + + +static int +backup (struct state *st) /* back up a move */ +{ + st->sqnum--; + st->cur_sq_x = st->move_list[st->sqnum].x; + st->cur_sq_y = st->move_list[st->sqnum].y; + return ( st->sqnum ); +} + + +/**************************************************************************** + Drawing the maze + ****************************************************************************/ + +/* draws the maze outline, and the logo */ +static void +draw_maze_border (struct state *st) +{ + int i, j; + + for ( i=0; imaze_size_x; i++) { + if ( st->maze[i][0] & WALL_TOP ) { + XDrawLine(st->dpy, st->window, st->gc, + border_x + st->grid_width * i, + border_y, + border_x + st->grid_width * (i+1) - 1, + border_y); + } + if ((st->maze[i][st->maze_size_y - 1] & WALL_BOTTOM)) { + XDrawLine(st->dpy, st->window, st->gc, + border_x + st->grid_width * i, + border_y + st->grid_height * (st->maze_size_y) - 1, + border_x + st->grid_width * (i+1) - 1, + border_y + st->grid_height * (st->maze_size_y) - 1); + } + } + for ( j=0; jmaze_size_y; j++) { + if ( st->maze[st->maze_size_x - 1][j] & WALL_RIGHT ) { + XDrawLine(st->dpy, st->window, st->gc, + border_x + st->grid_width * st->maze_size_x - 1, + border_y + st->grid_height * j, + border_x + st->grid_width * st->maze_size_x - 1, + border_y + st->grid_height * (j+1) - 1); + } + if ( st->maze[0][j] & WALL_LEFT ) { + XDrawLine(st->dpy, st->window, st->gc, + border_x, + border_y + st->grid_height * j, + border_x, + border_y + st->grid_height * (j+1) - 1); + } + } + + if (st->logo_x != -1) + { + Window r; + int xx, yy; + unsigned int w, h, bbw, d; + + /* round up to grid size */ + int ww = ((st->logo_width / st->grid_width) + 1) * st->grid_width; + int hh = ((st->logo_height / st->grid_height) + 1) * st->grid_height; + int lx, ly; + + XGetGeometry (st->dpy, st->logo_map, &r, &xx, &yy, &w, &h, &bbw, &d); + + /* kludge: if the logo "hole" is around the same size as the logo, + don't center it (since the xscreensaver logo image is a little + off center... But do center it if the hole/gridsize is large. */ + if (ww < st->logo_width + 5) ww = w; + if (hh < st->logo_height + 5) hh = h; + + + lx = border_x + 3 + st->grid_width * st->logo_x + ((ww - w) / 2); + ly = border_y + 3 + st->grid_height * st->logo_y + ((hh - h) / 2); + + /* Fill the background of the logo box with the "unreachable" color */ + XFillRectangle (st->dpy, st->window, st->ugc, + border_x + 3 + st->grid_width * st->logo_x, + border_y + 3 + st->grid_height * st->logo_y, + ww, hh); + + XSetClipOrigin (st->dpy, st->logo_gc, lx, ly); + if (d == 1) + XCopyPlane (st->dpy, st->logo_map, st->window, st->logo_gc, + 0, 0, w, h, lx, ly, 1); + else + XCopyArea (st->dpy, st->logo_map, st->window, st->logo_gc, + 0, 0, w, h, lx, ly); + } + draw_solid_square (st, st->start_x, st->start_y, WALL_TOP >> st->start_dir, st->tgc); + draw_solid_square (st, st->end_x, st->end_y, WALL_TOP >> st->end_dir, st->tgc); +} + + +/* Mark the maze grid as having a wall at the given coordinate, + and draw that wall on the screen. */ +static void +build_wall(struct state *st, int i, int j, int dir) +{ + /* Draw it on the screen. */ + draw_wall(st, i, j, dir, st->gc); + /* Put it in the maze. */ + switch(dir) + { + case 0: + st->maze[i][j] |= WALL_TOP; + if(j>0) + st->maze[i][j-1] |= WALL_BOTTOM; + break; + case 1: + st->maze[i][j] |= WALL_RIGHT; + if(imaze_size_x-1) + st->maze[i+1][j] |= WALL_LEFT; + break; + case 2: + st->maze[i][j] |= WALL_BOTTOM; + if(jmaze_size_y-1) + st->maze[i][j+1] |= WALL_TOP; + break; + case 3: + st->maze[i][j] |= WALL_LEFT; + if(i>0) + st->maze[i-1][j] |= WALL_RIGHT; + break; + } +} + + +static void +draw_wall(struct state *st, int i, int j, int dir, GC with_gc) /* draw a single wall */ +{ + switch (dir) { + case 0: + XDrawLine(st->dpy, st->window, with_gc, + border_x + st->grid_width * i, + border_y + st->grid_height * j, + border_x + st->grid_width * (i+1), + border_y + st->grid_height * j); + break; + case 1: + XDrawLine(st->dpy, st->window, with_gc, + border_x + st->grid_width * (i+1), + border_y + st->grid_height * j, + border_x + st->grid_width * (i+1), + border_y + st->grid_height * (j+1)); + break; + case 2: + XDrawLine(st->dpy, st->window, with_gc, + border_x + st->grid_width * i, + border_y + st->grid_height * (j+1), + border_x + st->grid_width * (i+1), + border_y + st->grid_height * (j+1)); + break; + case 3: + XDrawLine(st->dpy, st->window, with_gc, + border_x + st->grid_width * i, + border_y + st->grid_height * j, + border_x + st->grid_width * i, + border_y + st->grid_height * (j+1)); + break; + } + + if(st->sync_p) { + /* too slow if we sync on every wall, so only sync about ten times + during the maze-creation process. + */ + st->sync_tick--; + if (st->sync_tick <= 0) { + XSync(st->dpy, False); + st->sync_tick = st->maze_size_x * st->maze_size_x / 10; + } + } +} + + +static void +draw_solid_square(struct state *st, + int i, int j, + int dir, GC with_gc) +{ + switch (dir) { + case WALL_TOP: + XFillRectangle(st->dpy, st->window, with_gc, + border_x + st->bw+(st->bw==0?1:0) + st->grid_width * i, + border_y - st->bw-(st->bw==0?1:0) + st->grid_height * j, + st->grid_width - (st->bw+st->bw+(st->bw==0?1:0)), st->grid_height); + break; + case WALL_RIGHT: + XFillRectangle(st->dpy, st->window, with_gc, + border_x + st->bw+(st->bw==0?1:0) + st->grid_width * i, + border_y + st->bw+(st->bw==0?1:0) + st->grid_height * j, + st->grid_width, st->grid_height - (st->bw+st->bw+(st->bw==0?1:0))); + break; + case WALL_BOTTOM: + XFillRectangle(st->dpy, st->window, with_gc, + border_x + st->bw+(st->bw==0?1:0) + st->grid_width * i, + border_y + st->bw+(st->bw==0?1:0) + st->grid_height * j, + st->grid_width - (st->bw+st->bw+(st->bw==0?1:0)), st->grid_height); + break; + case WALL_LEFT: + XFillRectangle(st->dpy, st->window, with_gc, + border_x - st->bw-(st->bw==0?1:0) + st->grid_width * i, + border_y + st->bw+(st->bw==0?1:0) + st->grid_height * j, + st->grid_width, st->grid_height - (st->bw+st->bw+(st->bw==0?1:0))); + break; + } +} + +/**************************************************************************** + Solving the maze + ****************************************************************************/ + +static int +longdeadend_p(struct state *st, int x1, int y1, int x2, int y2, int endwall) +{ + int dx = x2 - x1, dy = y2 - y1; + int sidewalls; + + sidewalls = endwall | (endwall >> 2 | endwall << 2); + sidewalls = ~sidewalls & WALL_ANY; + + while((st->maze[x2][y2] & WALL_ANY) == sidewalls) + { + if (x2 + dx < 0 || x2 + dx >= st->maze_size_x || + y2 + dy < 0 || y2 + dy >= st->maze_size_y) + break; + x2 += dx; + y2 += dy; + } + + if((st->maze[x2][y2] & WALL_ANY) == (sidewalls | endwall)) + { + endwall = (endwall >> 2 | endwall << 2) & WALL_ANY; + while(x1 != x2 || y1 != y2) + { + x1 += dx; + y1 += dy; + draw_solid_square(st, x1, y1, endwall, st->sgc); + st->maze[x1][y1] |= SOLVER_VISIT; + } + return 1; + } + else + return 0; +} + +/* Find all dead regions -- areas from which the goal cannot be reached -- + and mark them visited. */ +static void +find_dead_regions(struct state *st) +{ + int xx, yy, flipped; + + /* Find all not SOLVER_VISIT squares bordering NOT_DEAD squares + and mark them NOT_DEAD also. Repeat until no more such squares. */ + st->maze[st->start_x][st->start_y] |= NOT_DEAD; + + do + { + flipped = 0; + for(xx = 0; xx < st->maze_size_x; xx++) + for(yy = 0; yy < st->maze_size_y; yy++) + if(!(st->maze[xx][yy] & (SOLVER_VISIT | NOT_DEAD)) + && ( (xx && (st->maze[xx-1][yy] & NOT_DEAD)) + || (yy && (st->maze[xx][yy-1] & NOT_DEAD)))) + { + flipped = 1; + st->maze[xx][yy] |= NOT_DEAD; + } + for(xx = st->maze_size_x-1; xx >= 0; xx--) + for(yy = st->maze_size_y-1; yy >= 0; yy--) + if(!(st->maze[xx][yy] & (SOLVER_VISIT | NOT_DEAD)) + && ( (xx != st->maze_size_x-1 && (st->maze[xx+1][yy] & NOT_DEAD)) + || (yy != st->maze_size_y-1 && (st->maze[xx][yy+1] & NOT_DEAD)))) + { + flipped = 1; + st->maze[xx][yy] |= NOT_DEAD; + } + } + while(flipped); + + for (yy = 0; yy < st->maze_size_y; yy++) + for (xx = 0; xx < st->maze_size_x; xx++) + { + if (st->maze[xx][yy] & NOT_DEAD) + st->maze[xx][yy] &= ~NOT_DEAD; + else if (!(st->maze[xx][yy] & SOLVER_VISIT)) + { + st->maze[xx][yy] |= SOLVER_VISIT; + if((xx < st->logo_x || xx > st->logo_x + st->logo_width / st->grid_width) || + (yy < st->logo_y || yy > st->logo_y + st->logo_height / st->grid_height)) + { + /* if we are completely surrounded by walls, just draw the + inside part */ + if ((st->maze[xx][yy] & WALL_ANY) == WALL_ANY) + XFillRectangle(st->dpy, st->window, st->ugc, + border_x + st->bw + st->grid_width * xx, + border_y + st->bw + st->grid_height * yy, + st->grid_width - (st->bw+st->bw), st->grid_height - (st->bw+st->bw)); + else + { + if (! (st->maze[xx][yy] & WALL_LEFT)) + draw_solid_square(st, xx, yy, WALL_LEFT, st->ugc); + if (! (st->maze[xx][yy] & WALL_RIGHT)) + draw_solid_square(st, xx, yy, WALL_RIGHT, st->ugc); + if (! (st->maze[xx][yy] & WALL_TOP)) + draw_solid_square(st, xx, yy, WALL_TOP, st->ugc); + if (! (st->maze[xx][yy] & WALL_BOTTOM)) + draw_solid_square(st, xx, yy, WALL_BOTTOM, st->ugc); + } + } + } + } +} + +/* solve the maze by one more tick */ +static int +solve_maze (struct state *st) +{ + struct solve_state *ss = st->solve_state; + if (!ss) + ss = st->solve_state = (struct solve_state *) calloc (1, sizeof(*ss)); + + if (!ss->running) { + /* plug up the surrounding wall */ + st->maze[st->end_x][st->end_y] |= (WALL_TOP >> st->end_dir); + + /* initialize search path */ + ss->i = 0; + st->path[ss->i].x = st->end_x; + st->path[ss->i].y = st->end_y; + st->path[ss->i].dir = 0; + st->maze[st->end_x][st->end_y] |= SOLVER_VISIT; + + ss->running = 1; + } + + /* do it */ + /* while (1) */ + { + int dir, from, ways; + + if ( st->maze[st->path[ss->i].x][st->path[ss->i].y] & START_SQUARE ) + { + ss->running = 0; + return 1; + } + + if(!st->path[ss->i].dir) + { + ways = 0; + /* First visit this square. Which adjacent squares are open? */ + for(dir = WALL_TOP; dir & WALL_ANY; dir >>= 1) + { + if(st->maze[st->path[ss->i].x][st->path[ss->i].y] & dir) + continue; + + ss->y = st->path[ss->i].y - !!(dir & WALL_TOP) + !!(dir & WALL_BOTTOM); + ss->x = st->path[ss->i].x + !!(dir & WALL_RIGHT) - !!(dir & WALL_LEFT); + + if(st->maze[ss->x][ss->y] & SOLVER_VISIT) + continue; + + from = (dir << 2 & WALL_ANY) | (dir >> 2 & WALL_ANY); + /* don't enter obvious dead ends */ + if(((st->maze[ss->x][ss->y] & WALL_ANY) | from) != WALL_ANY) + { + if(!longdeadend_p(st, st->path[ss->i].x, st->path[ss->i].y, ss->x, ss->y, dir)) + ways |= dir; + } + else + { + draw_solid_square(st, ss->x, ss->y, from, st->sgc); + st->maze[ss->x][ss->y] |= SOLVER_VISIT; + } + } + } + else + ways = st->path[ss->i].ways; + /* ways now has a bitmask of open paths. */ + + if(!ways) + goto backtrack; + + if (!st->ignorant_p) + { + ss->x = st->path[ss->i].x - st->start_x; + ss->y = st->path[ss->i].y - st->start_y; + /* choice one */ + if(abs(ss->y) <= abs(ss->x)) + dir = (ss->x > 0) ? WALL_LEFT : WALL_RIGHT; + else + dir = (ss->y > 0) ? WALL_TOP : WALL_BOTTOM; + + if(dir & ways) + goto found; + + /* choice two */ + switch(dir) + { + case WALL_LEFT: + case WALL_RIGHT: + dir = (ss->y > 0) ? WALL_TOP : WALL_BOTTOM; break; + case WALL_TOP: + case WALL_BOTTOM: + dir = (ss->x > 0) ? WALL_LEFT : WALL_RIGHT; + } + + if(dir & ways) + goto found; + + /* choice three */ + + dir = (dir << 2 & WALL_ANY) | (dir >> 2 & WALL_ANY); + if(dir & ways) + goto found; + + /* choice four */ + dir = ways; + if(!dir) + goto backtrack; + + found: ; + } + else + { + if(ways&WALL_TOP) + dir = WALL_TOP; + else if(ways&WALL_LEFT) + dir = WALL_LEFT; + else if(ways&WALL_BOTTOM) + dir = WALL_BOTTOM; + else if(ways&WALL_RIGHT) + dir = WALL_RIGHT; + else + goto backtrack; + } + ss->bt = 0; + ways &= ~dir; /* tried this one */ + + ss->y = st->path[ss->i].y - !!(dir & WALL_TOP) + !!(dir & WALL_BOTTOM); + ss->x = st->path[ss->i].x + !!(dir & WALL_RIGHT) - !!(dir & WALL_LEFT); + + /* advance in direction dir */ + st->path[ss->i].dir = dir; + st->path[ss->i].ways = ways; + draw_solid_square(st, st->path[ss->i].x, st->path[ss->i].y, dir, st->tgc); + + ss->i++; + st->path[ss->i].dir = 0; + st->path[ss->i].ways = 0; + st->path[ss->i].x = ss->x; + st->path[ss->i].y = ss->y; + st->maze[ss->x][ss->y] |= SOLVER_VISIT; + return 0; + /* continue; */ + + backtrack: + if(ss->i == 0) + { + printf("Unsolvable maze.\n"); + ss->running = 0; + return 1; + } + + if(!ss->bt && !st->ignorant_p) + find_dead_regions(st); + ss->bt = 1; + from = st->path[ss->i-1].dir; + from = (from << 2 & WALL_ANY) | (from >> 2 & WALL_ANY); + + draw_solid_square(st, st->path[ss->i].x, st->path[ss->i].y, from, st->cgc); + ss->i--; + } + + return 0; +} + + +/**************************************************************************** + XScreenSaver boilerplate: resources, command line options, and main loop. + ****************************************************************************/ + +static const char *maze_defaults[] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*gridSize: 0", + "*generator: -1", + "*maxLength: 5", + "*ignorant: False", + + "*solveDelay: 10000", + "*preDelay: 2000000", + "*postDelay: 4000000", + + "*liveColor: #00FF00", + "*deadColor: #880000", + "*skipColor: #8B5A00", + "*surroundColor: #220055", + + 0 +}; + +static XrmOptionDescRec maze_options[] = { + { "-ignorant", ".ignorant", XrmoptionNoArg, "True" }, + { "-no-ignorant", ".ignorant", XrmoptionNoArg, "False" }, + { "-grid-size", ".gridSize", XrmoptionSepArg, 0 }, + { "-solve-delay", ".solveDelay", XrmoptionSepArg, 0 }, + { "-pre-delay", ".preDelay", XrmoptionSepArg, 0 }, + { "-post-delay", ".postDelay", XrmoptionSepArg, 0 }, + { "-bg-color", ".background", XrmoptionSepArg, 0 }, + { "-fg-color", ".foreground", XrmoptionSepArg, 0 }, + { "-live-color", ".liveColor", XrmoptionSepArg, 0 }, + { "-dead-color", ".deadColor", XrmoptionSepArg, 0 }, + { "-skip-color", ".skipColor", XrmoptionSepArg, 0 }, + { "-surround-color", ".surroundColor",XrmoptionSepArg, 0 }, + { "-generator", ".generator", XrmoptionSepArg, 0 }, + { "-max-length", ".maxLength", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +static int generator = 0; + +static void * +maze_init (Display *dpy_arg, Window window_arg) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int size; + XWindowAttributes xgwa; + unsigned long bg, fg, pfg, pbg, sfg, ufg; + + st->dpy = dpy_arg; + st->window = window_arg; + + st->stop = 0; + st->state = 1; + st->restart = 1; + + st->ifrandom = 0; + st->ifinit = 1; + +#if 1 + size = gridSize; + st->solve_delay = solveDelay; + st->pre_solve_delay = preDelay; + st->post_solve_delay = postDelay; + generator = generator_; + st->max_length = maxLength; + st->ignorant_p = ignorant; +#else + size = get_integer_resource (st->dpy, "gridSize", "Dimension"); + st->solve_delay = get_integer_resource (st->dpy, "solveDelay", "Integer"); + st->pre_solve_delay = get_integer_resource (st->dpy, "preDelay", "Integer"); + st->post_solve_delay = get_integer_resource (st->dpy, "postDelay", "Integer"); + generator = get_integer_resource(st->dpy, "generator", "Integer"); + st->max_length = get_integer_resource(st->dpy, "maxLength", "Integer"); + st->ignorant_p = get_boolean_resource(st->dpy, "ignorant", "Boolean"); +#endif + + //if (get_boolean_resource (st->dpy, "doFPS", "DoFPS")) + if (False) + { + /* Just guess, rather than loading and measuring the "fpsFont"... */ + st->fps_width = 210; + st->fps_height = 62; + } + + if (!size) st->ifrandom = 1; + + if (size < 2) size = 7 + (random () % 30); + st->grid_width = st->grid_height = size; + st->bw = (size > 6 ? 3 : (size-1)/2); + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->x = 0; + st->y = 0; + + set_maze_sizes (st, xgwa.width, xgwa.height); + + st->gc = XCreateGC(st->dpy, st->window, 0, 0); + st->cgc = XCreateGC(st->dpy, st->window, 0, 0); + st->tgc = XCreateGC(st->dpy, st->window, 0, 0); + st->sgc = XCreateGC(st->dpy, st->window, 0, 0); + st->ugc = XCreateGC(st->dpy, st->window, 0, 0); + st->logo_gc = XCreateGC(st->dpy, st->window, 0, 0); + st->erase_gc = XCreateGC(st->dpy, st->window, 0, 0); + +#if 1 + bg = load_color(st->dpy, xgwa.colormap, background); + fg = load_color(st->dpy, xgwa.colormap, foreground); + pfg = load_color(st->dpy, xgwa.colormap, liveColor); + pbg = load_color(st->dpy, xgwa.colormap, deadColor); + sfg = load_color(st->dpy, xgwa.colormap, skipColor); + ufg = load_color(st->dpy, xgwa.colormap, surroundColor); +#else + bg = get_pixel_resource (st->dpy, xgwa.colormap, "background","Background"); + fg = get_pixel_resource (st->dpy, xgwa.colormap, "foreground","Foreground"); + pfg = get_pixel_resource (st->dpy, xgwa.colormap, "liveColor", "Foreground"); + pbg = get_pixel_resource (st->dpy, xgwa.colormap, "deadColor", "Foreground"); + sfg = get_pixel_resource (st->dpy, xgwa.colormap, "skipColor", "Foreground"); + ufg = get_pixel_resource (st->dpy, xgwa.colormap, "surroundColor", "Foreground"); +#endif + + XSetForeground (st->dpy, st->gc, fg); + XSetBackground (st->dpy, st->gc, bg); + XSetForeground (st->dpy, st->cgc, pbg); + XSetBackground (st->dpy, st->cgc, bg); + XSetForeground (st->dpy, st->tgc, pfg); + XSetBackground (st->dpy, st->tgc, bg); + XSetForeground (st->dpy, st->sgc, sfg); + XSetBackground (st->dpy, st->sgc, bg); + XSetForeground (st->dpy, st->ugc, ufg); + XSetBackground (st->dpy, st->ugc, bg); + XSetForeground (st->dpy, st->logo_gc, fg); + XSetBackground (st->dpy, st->logo_gc, bg); + XSetForeground (st->dpy, st->erase_gc, bg); + XSetBackground (st->dpy, st->erase_gc, bg); + + { + Window r; + int x, y; + unsigned int w, h, bbw, d; + unsigned long *pixels; + int npixels; + Pixmap logo_mask = 0; + st->logo_map = xscreensaver_logo (xgwa.screen, xgwa.visual, st->window, + xgwa.colormap, bg, + &pixels, &npixels, &logo_mask, + xgwa.width > 800 || xgwa.height > 800); + if (logo_mask) { + XSetClipMask (st->dpy, st->logo_gc, logo_mask); + XFreePixmap (st->dpy, logo_mask); + } + if (pixels) free (pixels); + XGetGeometry (st->dpy, st->logo_map, &r, &x, &y, &w, &h, &bbw, &d); + st->logo_width = w; + st->logo_height = h; + } + + + st->restart = 0; + st->sync_p = 1; + + return st; +} + + +static void +maze_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->restart = 1; +} + + +static unsigned long +maze_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int this_delay = st->solve_delay; + + if (st->eraser || st->erase_window) + { + st->erase_window = 0; + st->eraser = erase_window (st->dpy, st->window, st->eraser); + if (st->eraser) + this_delay = 10000; + else { + this_delay = 1000000; + if (this_delay > st->pre_solve_delay) + this_delay = st->pre_solve_delay; + } + goto END; + } + + if (st->restart || st->stop) goto pop; + switch (st->state) { + case 1: + initialize_maze(st); + if (st->ifrandom && st->ifinit) + { + int size; + size = 7 + (random () % 30); + st->grid_width = st->grid_height = size; + st->bw = (size > 6 ? 3 : (size-1)/2); + st->ifinit = 0; + st->restart = 1; + } + break; + case 2: + XClearWindow(st->dpy, st->window); + draw_maze_border(st); + break; + case 3: + st->this_gen = generator; + if(st->this_gen<0 || st->this_gen>2) + st->this_gen = random()%3; + + switch(st->this_gen) + { + case 0: + create_maze(st); + break; + case 1: + alt_create_maze(st); + break; + case 2: + set_create_maze(st); + break; + } + break; + case 4: + this_delay = st->pre_solve_delay; + break; + case 5: + if (! solve_maze(st)) + --st->state; /* stay in state 5 */ + break; + case 6: + st->erase_window = 1; + this_delay = st->post_solve_delay; + st->state = 0 ; + st->ifinit = 1; + break; + default: + abort (); + } + ++st->state; + pop: + if (st->restart) + { + XWindowAttributes xgwa; + int size; + + st->restart = 0; + st->stop = 0; + st->state = 1; + + if (st->solve_state && st->solve_state->running) + st->solve_state->running = 0; + + st->sync_p = ((random() % 4) != 0); + + //size = get_integer_resource (st->dpy, "gridSize", "Dimension"); + size = gridSize; + if (size < 2) size = 7 + (random () % 30); + st->grid_width = st->grid_height = size; + st->bw = (size > 6 ? 3 : (size-1)/2); + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + set_maze_sizes (st, xgwa.width, xgwa.height); + } + + END: + return this_delay; +} + + +#if 0 + static Bool + maze_event (Display *dpy, Window window, void *closure, XEvent *event) + { + struct state *st = (struct state *) closure; + switch (event->type) + { + case ButtonPress: + switch (event->xbutton.button) + { + case 2: + st->stop = !st->stop ; + if (st->state == 5) st->state = 4 ; + else { + st->restart = 1; + st->stop = 0; + } + return True; + + default: + st->restart = 1 ; + st->stop = 0 ; + return True; + } + break; + + case Expose: + st->restart = 1; + break; + + default: + break; + } + return False; + } +#endif + +static void +maze_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +XSCREENSAVER_MODULE ("Maze", maze) diff --git a/non-wgl/maze.vcproj b/non-wgl/maze.vcproj new file mode 100644 index 0000000..e4d0eaf --- /dev/null +++ b/non-wgl/maze.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/metaballs.c b/non-wgl/metaballs.c new file mode 100644 index 0000000..ad82266 --- /dev/null +++ b/non-wgl/metaballs.c @@ -0,0 +1,467 @@ +/* MetaBalls, Copyright (c) 2002-2003 W.P. van Paassen + * + * 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 - "metaballs.c" + * + * [01/24/03] - W.P. van Paassen: Additional features + * [12/29/02] - W.P. van Paassen: Port to X for use with XScreenSaver, the shadebob hack by Shane Smit was used as a template + * [12/26/02] - W.P. van Paassen: Creation for the Demo Effects Collection (http://demo-effects.sourceforge.net) + */ + +#include "screenhack.h" +#include + +char *background = "black"; +char *foreground = "white"; +char *color = "random"; +int count = 10; +int cycles = 1000; +int ncolors = 256; +int delay = 10000; +int radius = 100; +int delta = 3; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&color, "color", NULL, "random", t_String}, + {&count, "count", NULL, "10", t_Int}, + {&cycles, "cycles", NULL, "1000", t_Int}, + {&ncolors, "ncolors", NULL, "256", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&radius, "radius", NULL, "100", t_Int}, + {&delta, "delta", NULL, "3", t_Int}, +}; + +/*#define VERBOSE*/ + +#undef BLOB +#define BLOB _BLOB_ + +/*blob structure*/ +typedef struct +{ + short xpos,ypos; +} BLOB; + +struct state { + Display *dpy; + Window window; + + unsigned short iWinWidth, iWinHeight; + char *sColor; + + unsigned int nBlobCount; + unsigned char radius; + unsigned char delta; + unsigned char dradius; + unsigned short sradius; + unsigned char **blob; + BLOB *blobs; + unsigned char **blub; + + int delay, cycles; + signed short iColorCount; + unsigned long *aiColorVals; + XImage *pImage; + GC gc; + int draw_i; +}; + + +#undef BELLRAND +#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) + +static void init_blob(struct state *st, BLOB *blob) +{ + blob->xpos = st->iWinWidth/4 + BELLRAND(st->iWinWidth/2) - st->radius; + blob->ypos = st->iWinHeight/4 + BELLRAND(st->iWinHeight/2) - st->radius; +} + +static void Execute( struct state *st ) +{ + int i, j, k; + + /* clear st->blub array */ + for (i = 0; i < st->iWinHeight; ++i) + memset(st->blub[i], 0, st->iWinWidth * sizeof(unsigned char)); + + /* move st->blobs */ + for (i = 0; i < st->nBlobCount; i++) + { + st->blobs[i].xpos += -st->delta + (int)((st->delta + .5f) * frand(2.0)); + st->blobs[i].ypos += -st->delta + (int)((st->delta + .5f) * frand(2.0)); + } + + /* draw st->blobs to st->blub array */ + for (k = 0; k < st->nBlobCount; ++k) + { + if (st->blobs[k].ypos > -st->dradius && st->blobs[k].xpos > -st->dradius && st->blobs[k].ypos < st->iWinHeight && st->blobs[k].xpos < st->iWinWidth) + { + for (i = 0; i < st->dradius; ++i) + { + if (st->blobs[k].ypos + i >= 0 && st->blobs[k].ypos + i < st->iWinHeight) + { + for (j = 0; j < st->dradius; ++j) + { + if (st->blobs[k].xpos + j >= 0 && st->blobs[k].xpos + j < st->iWinWidth) + { + if (st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] < st->iColorCount-1) + { + if (st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] + st->blob[i][j] > st->iColorCount-1) + st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] = st->iColorCount-1; + else + st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] += st->blob[i][j]; + } + } + } + } + } + } + else + init_blob(st, st->blobs + k); + } + + memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height); + + /* draw st->blub array to screen */ + for (i = 0; i < st->iWinHeight; ++i) + { + for (j = 0; j < st->iWinWidth; ++j) + { + if (st->aiColorVals[st->blub[i][j]] > 0) + XPutPixel( st->pImage, j, i, st->aiColorVals[st->blub[i][j]] ); + } + } + + XPutImage( st->dpy, st->window, st->gc, st->pImage, + 0, 0, 0, 0, st->iWinWidth, st->iWinHeight ); +} + +static unsigned long * SetPalette(struct state *st ) +{ + XWindowAttributes XWinAttribs; + XColor Color, *aColors; + signed short iColor; + float nHalfColors; + + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + + Color.red = random() % 0xFFFF; + Color.green = random() % 0xFFFF; + Color.blue = random() % 0xFFFF; + + if( strcasecmp( st->sColor, "random" ) && !XParseColor( st->dpy, XWinAttribs.colormap, st->sColor, &Color ) ) + fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, st->sColor ); + +#ifdef VERBOSE + printf( "%s: Base color (RGB): <%d, %d, %d>\n", progname, Color.red, Color.green, Color.blue ); +#endif /* VERBOSE */ + + //st->iColorCount = get_integer_resource(st->dpy, "ncolors", "Integer" ); + st->iColorCount = ncolors; + if( st->iColorCount < 2 ) st->iColorCount = 2; + if( st->iColorCount > 255 ) st->iColorCount = 255; + + aColors = calloc( st->iColorCount, sizeof(XColor) ); + st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) ); + + for( iColor=0; iColor < st->iColorCount; iColor++ ) + { + nHalfColors = st->iColorCount / 2.0F; + /* Black -> Base Color */ + if( iColor < (st->iColorCount/2) ) + { + aColors[ iColor ].red = ( Color.red / nHalfColors ) * iColor; + aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor; + aColors[ iColor ].blue = ( Color.blue / nHalfColors ) * iColor; + } + /* Base Color -> White */ + else + { + aColors[ iColor ].red = ( ( ( 0xFFFF - Color.red ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.red; + aColors[ iColor ].green = ( ( ( 0xFFFF - Color.green ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.green; + aColors[ iColor ].blue = ( ( ( 0xFFFF - Color.blue ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.blue; + } + + if( !XAllocColor( st->dpy, XWinAttribs.colormap, &aColors[ iColor ] ) ) + { + /* start all over with less colors */ + XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, iColor, 0 ); + free( aColors ); + free( st->aiColorVals ); + (st->iColorCount)--; + + if (st->iColorCount < 6) + { + fprintf (stderr, "%s: insufficient colors!\n", + progname); + exit (1); + } + + aColors = calloc( st->iColorCount, sizeof(XColor) ); + st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) ); + iColor = -1; + } + else + st->aiColorVals[ iColor ] = aColors[ iColor ].pixel; + } + + free( aColors ); + + XSetWindowBackground( st->dpy, st->window, st->aiColorVals[ 0 ] ); + + return st->aiColorVals; +} + + +static void Initialize( struct state *st ) +{ + XGCValues gcValues; + XWindowAttributes XWinAttribs; + int /*iBitsPerPixel,*/ i, j; + unsigned int distance_squared; + float fraction; + + /* Create the Image for drawing */ + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + + /* Find the preferred bits-per-pixel. (jwz) */ +#if 0 + { + int pfvc = 0; + XPixmapFormatValues *pfv = XListPixmapFormats( st->dpy, &pfvc ); + for( i=0; igc = XCreateGC( st->dpy, st->window, 0, &gcValues ); + + st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL, + XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 ); + (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height); + + st->iWinWidth = XWinAttribs.width; + st->iWinHeight = XWinAttribs.height; + + /* Get the base color. */ + //st->sColor = get_string_resource(st->dpy, "color", "Color" ); + st->sColor = color; + + /* Get the st->delta. */ + //st->delta = get_integer_resource(st->dpy, "delta", "Integer" ); + st->delta = delta; + if (st->delta < 1) + st->delta = 1; + else if (st->delta > 20) + st->delta = 20; + + /* Get the st->radius. */ + //st->radius = get_integer_resource(st->dpy, "radius", "Integer" ); + st->radius = radius; + if (st->radius < 2) + st->radius = 2; + if (st->radius > 100) + st->radius = 100; + + st->radius = (st->radius / 100.0) * (st->iWinHeight >> 3); + if (st->radius >= 128) /* should use UCHAR_MAX? */ + st->radius = 127; /* st->dradius should fit in u_char */ + + st->dradius = st->radius * 2; + st->sradius = st->radius * st->radius; + + /* create st->blob */ + st->blob = malloc ( st->dradius * sizeof(unsigned char*)); + for (i = 0; i < st->dradius; ++i) + st->blob[i] = malloc( st->dradius * sizeof(unsigned char)); + + /* create st->blub array */ + st->blub = malloc( st->iWinHeight * sizeof(unsigned char*)); + for (i = 0; i < st->iWinHeight; ++i) + st->blub[i] = malloc( st->iWinWidth * sizeof(unsigned char)); + + /* create st->blob */ + for (i = -st->radius; i < st->radius; ++i) + { + for (j = -st->radius; j < st->radius; ++j) + { + distance_squared = i * i + j * j; + if (distance_squared <= st->sradius) + { + /* compute density */ + fraction = (float)distance_squared / (float)st->sradius; + st->blob[i + st->radius][j + st->radius] = pow((1.0 - (fraction * fraction)),4.0) * 255.0; + } + else + { + st->blob[i + st->radius][j + st->radius] = 0; + } + } + } + + for (i = 0; i < st->nBlobCount; i++) + { + init_blob(st, st->blobs + i); + } +} + +static void * +metaballs_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); +#ifdef VERBOSE + time_t nTime = time( NULL ); + unsigned short iFrame = 0; +#endif /* VERBOSE */ + + st->dpy = dpy; + st->window = window; + + //st->nBlobCount = get_integer_resource(st->dpy, "count", "Integer" ); + st->nBlobCount = count; + if( st->nBlobCount > 255 ) st->nBlobCount = 255; + if( st->nBlobCount < 2 ) st->nBlobCount = 2; + + if( ( st->blobs = calloc( st->nBlobCount, sizeof(BLOB) ) ) == NULL ) + { + fprintf( stderr, "%s: Could not allocate %d Blobs\n", progname, st->nBlobCount ); + abort(); + } +#ifdef VERBOSE + printf( "%s: Allocated %d Blobs\n", progname, st->nBlobCount ); +#endif /* VERBOSE */ + + Initialize( st ); + + //st->delay = get_integer_resource(st->dpy, "delay", "Integer" ); + //st->cycles = get_integer_resource(st->dpy, "cycles", "Integer" ); + st->delay = delay; + st->cycles = cycles; + + st->draw_i = -1; + return st; +} + + + +static unsigned long +metaballs_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if( st->draw_i < 0 || st->draw_i++ >= st->cycles ) + { + int i; + XWindowAttributes XWinAttribs; + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + + memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height ); + XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, st->iColorCount, 0 ); + free( st->aiColorVals ); + st->aiColorVals = SetPalette( st ); + XClearWindow( st->dpy, st->window ); + for (i = 0; i < st->nBlobCount; i++) + { + init_blob(st, st->blobs + i); + } + st->draw_i = 0; + } + + Execute( st ); + +#ifdef VERBOSE + iFrame++; + if( nTime - time( NULL ) ) + { + printf( "%s: %d FPS\n", progname, iFrame ); + nTime = time( NULL ); + iFrame = 0; + } +#endif /* VERBOSE */ + + return st->delay; +} + + +static void +metaballs_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + metaballs_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +metaballs_free (Display *dpy, Window window, void *closure) +{ +#if 0 + struct state *st = (struct state *) closure; + free( st->pImage->data ); + XDestroyImage( st->pImage ); + free( st->aiColorVals ); + free( st->blobs ); + for (i = 0; i < st->iWinHeight; ++i) + free( st->blub[i] ); + free( st->blub ); + for (i = 0; i < st->dradius; ++i) + free( st->blob[i] ); + free( st->blob ); +#endif +} + + +static const char *metaballs_defaults [] = { + ".background: black", + ".foreground: white", + "*color: random", + "*count: 10", + "*cycles: 1000", + "*ncolors: 256", + "*delay: 10000", + "*radius: 100", + "*delta: 3", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec metaballs_options [] = { + { "-color", ".color", XrmoptionSepArg, 0 }, + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-cycles", ".cycles", XrmoptionSepArg, 0 }, + { "-radius", ".radius", XrmoptionSepArg, 0 }, + { "-delta", ".delta", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("MetaBalls", metaballs) + +/* End of Module - "metaballs.c" */ + diff --git a/non-wgl/metaballs.vcproj b/non-wgl/metaballs.vcproj new file mode 100644 index 0000000..32229fa --- /dev/null +++ b/non-wgl/metaballs.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/moire.c b/non-wgl/moire.c new file mode 100644 index 0000000..6d3cb5c --- /dev/null +++ b/non-wgl/moire.c @@ -0,0 +1,327 @@ +/* xscreensaver, Copyright (c) 1997-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. + * + * Concept snarfed from Michael D. Bayne in + * http://www.go2net.com/internet/deep/1997/04/16/body.html + */ + +#include "screenhack.h" + +#undef HAVE_XSHM_EXTENSION /* this is broken here at the moment */ + + +#ifdef HAVE_XSHM_EXTENSION +# include "xshm.h" +#endif /* HAVE_XSHM_EXTENSION */ + + +char *background = "blue"; +char *foreground = "red"; +Bool random_ = True; +int delay = 5; +int ncolors = 64; +int offset = 50; + +static argtype vars[] = +{ + {&background, "background", NULL, "blue", t_String}, + {&foreground, "foreground", NULL, "red", t_String}, + {&random_, "random", NULL, "True", t_Bool}, + {&delay, "delay", NULL, "5", t_Int}, + {&ncolors, "ncolors", NULL, "64", t_Int}, + {&offset, "offset", NULL, "50", t_Int}, +}; + + +struct state { + Display *dpy; + Window window; +#ifdef HAVE_XSHM_EXTENSION + Bool use_shm; + XShmSegmentInfo shm_info; +#endif /* HAVE_XSHM_EXTENSION */ + + int delay; + int offset; + XColor *colors; + int ncolors; + GC gc; + unsigned long fg_pixel; + unsigned long bg_pixel; + int depth; + + int draw_y, draw_xo, draw_yo; + int draw_factor; + XImage *draw_image; + XWindowAttributes xgwa; +}; + +static void +moire_init_1 (struct state *st) +{ + int oncolors; + int i; + int fgh, bgh; + double fgs, fgv, bgs, bgv; + XWindowAttributes xgwa; + XColor fgc, bgc; + XGCValues gcv; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + //st->offset = get_integer_resource (st->dpy, "offset", "Integer"); + st->delay = delay; + st->offset = offset; + if (st->offset < 2) st->offset = 2; + +#ifdef HAVE_XSHM_EXTENSION + st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean"); +#endif /* HAVE_XSHM_EXTENSION */ + + MONO: + if (st->colors) + { + for (i = 0; i < st->ncolors; i++) + XFreeColors (st->dpy, xgwa.colormap, &st->colors[i].pixel, 1, 0); + free(st->colors); + st->colors = 0; + } + + if (mono_p) + { + st->fg_pixel = WhitePixelOfScreen (DefaultScreenOfDisplay(st->dpy)); + st->bg_pixel = BlackPixelOfScreen (DefaultScreenOfDisplay(st->dpy)); + } + else + { +#if 1 + st->fg_pixel = load_color(st->dpy, xgwa.colormap, foreground); + st->bg_pixel = load_color(st->dpy, xgwa.colormap, background); +#else + st->fg_pixel = get_pixel_resource (st->dpy, + xgwa.colormap, "foreground", "Foreground"); + st->bg_pixel = get_pixel_resource (st->dpy, + xgwa.colormap, "background", "Background"); +#endif + } + + if (mono_p) + { + st->offset *= 20; /* compensate for lack of shading */ + gcv.foreground = st->fg_pixel; + } + else + { + //st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + st->ncolors = ncolors; + if (st->ncolors < 2) st->ncolors = 2; + oncolors = st->ncolors; + + fgc.flags = bgc.flags = DoRed|DoGreen|DoBlue; + //if (get_boolean_resource(st->dpy, "random","Boolean")) + if (random_) + { + fgc.red = random() & 0xFFFF; + fgc.green = random() & 0xFFFF; + fgc.blue = random() & 0xFFFF; + bgc.red = random() & 0xFFFF; + bgc.green = random() & 0xFFFF; + bgc.blue = random() & 0xFFFF; + } + else + { + fgc.pixel = st->fg_pixel; + bgc.pixel = st->bg_pixel; + XQueryColor (st->dpy, xgwa.colormap, &fgc); + XQueryColor (st->dpy, xgwa.colormap, &bgc); + } + rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv); + rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv); + + st->colors = (XColor *) malloc (sizeof (XColor) * (st->ncolors+2)); + memset(st->colors, 0, (sizeof (XColor) * (st->ncolors+2))); + make_color_ramp (xgwa.screen, xgwa.visual, xgwa.colormap, + fgh, fgs, fgv, bgh, bgs, bgv, + st->colors, &st->ncolors, + True, True, False); + if (st->ncolors != oncolors) + fprintf(stderr, "%s: got %d of %d requested colors.\n", + progname, st->ncolors, oncolors); + + if (st->ncolors <= 2) + { + mono_p = True; + goto MONO; + } + + gcv.foreground = st->colors[0].pixel; + } + st->gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); +} + + +static void * +moire_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + moire_init_1 (st); + return st; +} + + +static unsigned long +moire_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XGCValues gcv; + int chunk_size = 20, ii; + + if (st->draw_y == 0) + { + moire_init_1 (st); + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + st->draw_xo = (random() % st->xgwa.width) - st->xgwa.width/2; + st->draw_yo = (random() % st->xgwa.height) - st->xgwa.height/2; + st->draw_factor = (random() % st->offset) + 1; + + st->depth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual); + +# ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) + { + st->draw_image = create_xshm_image(st->dpy, st->xgwa.visual, + st->depth, ZPixmap, 0, + &st->shm_info, st->xgwa.width, 1); + if (!st->draw_image) + st->use_shm = False; + } +# endif /* HAVE_XSHM_EXTENSION */ + + if (!st->draw_image) + { + st->draw_image = XCreateImage (st->dpy, st->xgwa.visual, + st->depth, ZPixmap, 0, /* depth, format, offset */ + 0, st->xgwa.width, 1, 8, 0); /* data, w, h, pad, bpl */ + st->draw_image->data = (char *) calloc(st->draw_image->height, st->draw_image->bytes_per_line); + } + } + + /* for (y = 0; y < st->xgwa.height; y++) */ + for (ii = 0; ii < chunk_size; ii++) + { + int x; + for (x = 0; x < st->xgwa.width; x++) + { + double xx = x + st->draw_xo; + double yy = st->draw_y + st->draw_yo; + double i = ((xx * xx) + (yy * yy)) / (double) st->draw_factor; + if (mono_p) + gcv.foreground = ((((long) i) & 1) ? st->fg_pixel : st->bg_pixel); + else + gcv.foreground = st->colors[((long) i) % st->ncolors].pixel; + XPutPixel (st->draw_image, x, 0, gcv.foreground); + } + +# ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) + XShmPutImage(st->dpy, st->window, st->gc, st->draw_image, 0, 0, 0, st->draw_y, st->xgwa.width, 1, False); + else +# endif /* HAVE_XSHM_EXTENSION */ + XPutImage (st->dpy, st->window, st->gc, st->draw_image, 0, 0, 0, st->draw_y, st->xgwa.width, 1); + + st->draw_y++; + if (st->draw_y >= st->xgwa.height) + break; + } + + + if (st->draw_y >= st->xgwa.height) + { + st->draw_y = 0; + +# ifdef HAVE_XSHM_EXTENSION + if (!st->use_shm) +# endif /* HAVE_XSHM_EXTENSION */ + if (st->draw_image->data) + { + free(st->draw_image->data); + st->draw_image->data = 0; + } + +# ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) + destroy_xshm_image (st->dpy, st->draw_image, &st->shm_info); + else +# endif /* HAVE_XSHM_EXTENSION */ + XDestroyImage (st->draw_image); + st->draw_image = 0; + + return st->delay * 1000000; + } + + return st->delay * 10000; +} + + +static const char *moire_defaults [] = { + ".background: blue", + ".foreground: red", + "*fpsSolid: true", + "*random: true", + "*delay: 5", + "*ncolors: 64", + "*offset: 50", +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#else + "*useSHM: False", +#endif +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec moire_options [] = { + { "-random", ".random", XrmoptionNoArg, "True" }, + { "-no-random", ".random", XrmoptionNoArg, "False" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-offset", ".offset", XrmoptionSepArg, 0 }, + { "-shm", ".useSHM", XrmoptionNoArg, "True" }, + { "-no-shm", ".useSHM", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + +static void +moire_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + moire_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +moire_free (Display *dpy, Window window, void *closure) +{ +} + +XSCREENSAVER_MODULE ("Moire", moire) diff --git a/non-wgl/moire.vcproj b/non-wgl/moire.vcproj new file mode 100644 index 0000000..8a1c47a --- /dev/null +++ b/non-wgl/moire.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/moire2.c b/non-wgl/moire2.c new file mode 100644 index 0000000..df1893c --- /dev/null +++ b/non-wgl/moire2.c @@ -0,0 +1,383 @@ +/* xscreensaver, Copyright (c) 1997-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. + */ + +#include "screenhack.h" + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# include "xdbe.h" +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +char *background = "black"; +char *foreground = "white"; +int delay = 50000; +int thickness = 0; +int colors = 150; +int colorShift = 5; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "50000", t_Int}, + {&thickness, "thickness", NULL, "0", t_Int}, + {&colors, "colors", NULL, "150", t_Int}, + {&colorShift, "colorShift", NULL, "5", t_Int}, +}; + +struct state { + Display *dpy; + Window window; + + int ncolors; + XColor *colors; + int fg_pixel, bg_pixel; + Pixmap p0, p1, p2, p3; + GC copy_gc, erase_gc, window_gc; + int width, height, size; + int x1, x2, y1, y2, x3, y3; + int dx1, dx2, dx3, dy1, dy2, dy3; + int othickness, thickness; + Bool do_three; +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + XdbeBackBuffer back_buf; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + Bool flip_a, flip_b; + int pix; + int delay, color_shift; + + int reset; + int iterations, iteration; +}; + +static void +moire2_init_1 (struct state *st) +{ + XWindowAttributes xgwa; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + //st->othickness = get_integer_resource(st->dpy, "thickness", "Thickness"); + st->othickness = thickness; + + if (mono_p) + st->ncolors = 2; + else + //st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors = colors; + if (st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + + if (mono_p) + st->colors = 0; + else + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + + if (mono_p) + ; + else + make_smooth_colormap (xgwa.screen, xgwa.visual, xgwa.colormap, + st->colors, &st->ncolors, + True, 0, True); + +#if 1 + st->bg_pixel = load_color(st->dpy, xgwa.colormap, background); + st->fg_pixel = load_color(st->dpy, xgwa.colormap, foreground); +#else + st->bg_pixel = get_pixel_resource(st->dpy, + xgwa.colormap, "background", "Background"); + st->fg_pixel = get_pixel_resource(st->dpy, + xgwa.colormap, "foreground", "Foreground"); +#endif + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + st->back_buf = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined); +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ +} + + +static void +reset_moire2 (struct state *st) +{ + GC gc; + XWindowAttributes xgwa; + XGCValues gcv; + Bool xor; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->do_three = (0 == (random() % 3)); + + st->width = xgwa.width; + st->height = xgwa.height; + st->size = st->width > st->height ? st->width : st->height; + + if (st->p0) XFreePixmap(st->dpy, st->p0); + if (st->p1) XFreePixmap(st->dpy, st->p1); + if (st->p2) XFreePixmap(st->dpy, st->p2); + if (st->p3) XFreePixmap(st->dpy, st->p3); + + st->p0 = XCreatePixmap(st->dpy, st->window, st->width, st->height, 1); + st->p1 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1); + st->p2 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1); + if (st->do_three) + st->p3 = XCreatePixmap(st->dpy, st->window, st->width*2, st->height*2, 1); + else + st->p3 = 0; + + st->thickness = (st->othickness > 0 ? st->othickness : (1 + (random() % 4))); + + gcv.foreground = 0; + gcv.line_width = (st->thickness == 1 ? 0 : st->thickness); + gc = XCreateGC (st->dpy, st->p1, GCForeground|GCLineWidth, &gcv); + + XFillRectangle(st->dpy, st->p1, gc, 0, 0, st->width*2, st->height*2); + XFillRectangle(st->dpy, st->p2, gc, 0, 0, st->width*2, st->height*2); + if (st->do_three) + XFillRectangle(st->dpy, st->p3, gc, 0, 0, st->width*2, st->height*2); + + XSetForeground(st->dpy, gc, 1); + + xor = (st->do_three || (st->thickness == 1) || (random() & 1)); + + { + int i, ii, maxx, maxy; + +#define FROB(P) do { \ + maxx = (st->size*4); \ + maxy = (st->size*4); \ + if (0 == (random() % 5)) { \ + float f = 1.0 + frand(0.05); \ + if (random() & 1) maxx *= f; \ + else maxy *= f; \ + } \ + ii = (st->thickness + 1 + (xor ? 0 : 1) + (random() % (4 * st->thickness))); \ + for (i = 0; i < (st->size*2); i += ii) \ + XDrawArc(st->dpy, (P), gc, i-st->size, i-st->size, maxx-i-i, maxy-i-i, 0, 360*64); \ + if (0 == (random() % 5)) \ + { \ + XSetFunction(st->dpy, gc, GXxor); \ + XFillRectangle(st->dpy, (P), gc, 0, 0, st->width*2, st->height*2); \ + XSetFunction(st->dpy, gc, GXcopy); \ + } \ + } while(0) + + FROB(st->p1); + FROB(st->p2); + if (st->do_three) + FROB(st->p3); +#undef FROB + } + + XFreeGC(st->dpy, gc); + + if (st->copy_gc) XFreeGC(st->dpy, st->copy_gc); + gcv.function = (xor ? GXxor : GXor); + gcv.foreground = 1; + gcv.background = 0; + + st->copy_gc = XCreateGC (st->dpy, st->p0, GCFunction|GCForeground|GCBackground, &gcv); + + gcv.foreground = 0; + if (st->erase_gc) XFreeGC(st->dpy, st->erase_gc); + st->erase_gc = XCreateGC (st->dpy, st->p0, GCForeground, &gcv); + + gcv.foreground = st->fg_pixel; + gcv.background = st->bg_pixel; + if (st->window_gc) XFreeGC(st->dpy, st->window_gc); + st->window_gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); + +#define FROB(N,DN,MAX) \ + N = (MAX/2) + (random() % MAX); \ + DN = ((1 + (random() % (7*st->thickness))) * ((random() & 1) ? 1 : -1)) + + FROB(st->x1,st->dx1,st->width); + FROB(st->x2,st->dx2,st->width); + FROB(st->x3,st->dx3,st->width); + FROB(st->y1,st->dy1,st->height); + FROB(st->y2,st->dy2,st->height); + FROB(st->y3,st->dy3,st->height); +#undef FROB +} + + + +static void +moire2 (struct state *st) +{ +#define FROB(N,DN,MAX) \ + N += DN; \ + if (N <= 0) N = 0, DN = -DN; \ + else if (N >= MAX) N = MAX, DN = -DN; \ + else if (0 == (random() % 100)) DN = -DN; \ + else if (0 == (random() % 50)) \ + DN += (DN <= -20 ? 1 : (DN >= 20 ? -1 : ((random() & 1) ? 1 : -1))) + + FROB(st->x1,st->dx1,st->width); + FROB(st->x2,st->dx2,st->width); + FROB(st->x3,st->dx3,st->width); + FROB(st->y1,st->dy1,st->height); + FROB(st->y2,st->dy2,st->height); + FROB(st->y3,st->dy3,st->height); +#undef FROB + + XFillRectangle(st->dpy, st->p0, st->erase_gc, 0, 0, st->width, st->height); + XCopyArea(st->dpy, st->p1, st->p0, st->copy_gc, st->x1, st->y1, st->width, st->height, 0, 0); + XCopyArea(st->dpy, st->p2, st->p0, st->copy_gc, st->x2, st->y2, st->width, st->height, 0, 0); + if (st->do_three) + XCopyArea(st->dpy, st->p3, st->p0, st->copy_gc, st->x3, st->y3, st->width, st->height, 0, 0); + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (st->back_buf) + { + XdbeSwapInfo info[1]; + info[0].swap_window = st->window; + info[0].swap_action = XdbeUndefined; + XCopyPlane (st->dpy, st->p0, st->back_buf, st->window_gc, 0, 0, st->width, st->height, 0, 0, 1L); + XdbeSwapBuffers (st->dpy, info, 1); + } + else +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + XCopyPlane (st->dpy, st->p0, st->window, st->window_gc, 0, 0, st->width, st->height, 0, 0, 1L); + +#if 0 + XCopyPlane(st->dpy, st->p1, st->window, st->window_gc, (st->width*2)/3, (st->height*2)/3, + st->width/2, st->height/2, + 0, st->height/2, 1L); + XCopyPlane(st->dpy, st->p2, st->window, st->window_gc, (st->width*2)/3, (st->height*2)/3, + st->width/2, st->height/2, + st->width/2, st->height/2, 1L); +#endif +} + + + +static void * +moire2_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + st->reset = 1; + + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + //st->color_shift = get_integer_resource (st->dpy, "colorShift", "Integer"); + st->delay = delay; + st->color_shift = colorShift; + + if (st->color_shift <= 0) st->color_shift = 1; + moire2_init_1 (st); + return st; +} + +static unsigned long +moire2_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->reset) + { + st->reset = 0; + + st->iteration = 0; + st->iterations = 30 + (random() % 70) + (random() % 70); + reset_moire2 (st); + + st->flip_a = mono_p ? False : (random() & 1); + st->flip_b = mono_p ? False : (random() & 1); + + if (st->flip_b) + { + XSetForeground(st->dpy, st->window_gc, st->bg_pixel); + XSetBackground(st->dpy, st->window_gc, st->fg_pixel); + } + else + { + XSetForeground(st->dpy, st->window_gc, st->fg_pixel); + XSetBackground(st->dpy, st->window_gc, st->bg_pixel); + } + } + + if (!mono_p) + { + st->pix++; + st->pix = st->pix % st->ncolors; + + if (st->flip_a) + XSetBackground(st->dpy, st->window_gc, st->colors[st->pix].pixel); + else + XSetForeground(st->dpy, st->window_gc, st->colors[st->pix].pixel); + } + + + moire2 (st); + st->iteration++; + if (st->iteration >= st->color_shift) + { + st->iteration = 0; + st->iterations--; + if (st->iterations <= 0) + st->reset = 1; + } + + return st->delay; +} + +static void +moire2_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->reset = 1; +} + +#if 0 + static Bool + moire2_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +moire2_free (Display *dpy, Window window, void *closure) +{ +} + +static const char *moire2_defaults [] = { + ".background: black", + ".foreground: white", + "*delay: 50000", + "*thickness: 0", + "*colors: 150", + "*colorShift: 5", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + /* Off by default, since it slows it down a lot, and the flicker isn't really + all that bad without it... Or rather, it flickers just as badly with it. + The XFree86 implementation of the XDBE extension totally blows! There is + just *no* excuse for the "swap buffers" operation to flicker like it does. + */ + "*useDBE: False", +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + 0 +}; + +static XrmOptionDescRec moire2_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-ncolors", ".colors", XrmoptionSepArg, 0 }, + { "-thickness", ".thickness", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Moire2", moire2) diff --git a/non-wgl/moire2.vcproj b/non-wgl/moire2.vcproj new file mode 100644 index 0000000..2e4f2ee --- /dev/null +++ b/non-wgl/moire2.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/mountain.c b/non-wgl/mountain.c new file mode 100644 index 0000000..eb82cd1 --- /dev/null +++ b/non-wgl/mountain.c @@ -0,0 +1,305 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* mountain -- square grid mountains */ + +#if 0 +static const char sccsid[] = "@(#)mountain.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1995 Pascal Pensa + * + * 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 + * 1995: Written + */ + +#define STANDALONE +#define NOARGS + +# define MODE_mountain +#define DELAY 20000 +#define COUNT 30 +#define CYCLES 4000 +#define NCOLORS 64 +#define DEFAULTS "*delay: 20000 \n" \ + "*count: 30 \n" \ + "*cycles: 4000 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + +# define SMOOTH_COLORS +# define mountain_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_mountain + +ENTRYPOINT ModeSpecOpt mountain_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct mountain_description = +{"mountain", "init_mountain", "draw_mountain", "release_mountain", + "refresh_mountain", "init_mountain", (char *) NULL, &mountain_opts, + 1000, 30, 4000, 1, 64, 1.0, "", + "Shows Papo's mountain range", 0, NULL}; +#endif + +/* ~ 5000 Max mountain height (1000 - 10000) */ +#define MAXHEIGHT (3 * (mp->width + mp->height)) + +#define WORLDWIDTH 50 /* World size x * y */ + +#define RANGE_RAND(min,max) ((min) + NRAND((max) - (min))) + +typedef struct { + int pixelmode; + int width; + int height; + int x, y; + int offset; + int stage; + int h[WORLDWIDTH][WORLDWIDTH]; + long time; /* up time */ + Bool wireframe; + Bool joke; + GC stippledGC; +} mountainstruct; + +static mountainstruct *mountains = (mountainstruct *) NULL; + +static void +spread(int (*m)[50], int x, int y) +{ + int x2, y2; + int h = m[x][y]; + + for (y2 = y - 1; y2 <= y + 1; y2++) + for (x2 = x - 1; x2 <= x + 1; x2++) + if (x2 >= 0 && y2 >= 0 && x2 < WORLDWIDTH && y2 < WORLDWIDTH) + m[x2][y2] = (m[x2][y2] + h) / 2; +} + +static void +drawamountain(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + mountainstruct *mp = &mountains[MI_SCREEN(mi)]; + int x2, y2, x3, y3, y4, y5, c = 0; + XPoint p[5]; + + if (MI_NPIXELS(mi) > 2) { + c = (mp->h[mp->x][mp->y] + mp->h[mp->x + 1][mp->y] + + mp->h[mp->x][mp->y + 1] + mp->h[mp->x + 1][mp->y + 1]) / 4; + c = (c / 10 + mp->offset) % MI_NPIXELS(mi); + } + x2 = mp->x * (2 * mp->width) / (3 * WORLDWIDTH); + y2 = mp->y * (2 * mp->height) / (3 * WORLDWIDTH); + p[0].x = (x2 - y2 / 2) + (mp->width / 4); + p[0].y = (y2 - mp->h[mp->x][mp->y]) + mp->height / 4; + + x3 = (mp->x + 1) * (2 * mp->width) / (3 * WORLDWIDTH); + y3 = mp->y * (2 * mp->height) / (3 * WORLDWIDTH); + p[1].x = (x3 - y3 / 2) + (mp->width / 4); + p[1].y = (y3 - mp->h[mp->x + 1][mp->y]) + mp->height / 4; + + y4 = (mp->y + 1) * (2 * mp->height) / (3 * WORLDWIDTH); + p[2].x = (x3 - y4 / 2) + (mp->width / 4); + p[2].y = (y4 - mp->h[mp->x + 1][mp->y + 1]) + mp->height / 4; + + y5 = (mp->y + 1) * (2 * mp->height) / (3 * WORLDWIDTH); + p[3].x = (x2 - y5 / 2) + (mp->width / 4); + p[3].y = (y5 - mp->h[mp->x][mp->y + 1]) + mp->height / 4; + + p[4].x = p[0].x; + p[4].y = p[0].y; + + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, c)); + else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + + if (mp->joke) { + if ((Bool) (LRAND() & 1)) + XDrawLines(display, window, gc, p, 5, CoordModeOrigin); + else { + XFillPolygon(display, window, gc, p, 4, Complex, CoordModeOrigin); + if (!mp->pixelmode) { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XDrawLines(display, window, gc, p, 5, CoordModeOrigin); + } + } + } else { + if (mp->wireframe) { + XDrawLines(display, window, gc, p, 5, CoordModeOrigin); + } else { + XFillPolygon(display, window, gc, p, 4, Complex, CoordModeOrigin); + + if (!mp->pixelmode) { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XDrawLines(display, window, gc, p, 5, CoordModeOrigin); + } + } + } + mp->x++; + if (mp->x == WORLDWIDTH - 1) { + mp->y++; + mp->x = 0; + } + if (mp->y == WORLDWIDTH - 1) + mp->stage++; +} + +ENTRYPOINT void +init_mountain (ModeInfo * mi) +{ + int i, j, x, y; + XGCValues gcv; + mountainstruct *mp; + + if (mountains == NULL) { + if ((mountains = (mountainstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (mountainstruct))) == NULL) + return; + } + mp = &mountains[MI_SCREEN(mi)]; + + mp->width = MI_WIDTH(mi); + mp->height = MI_HEIGHT(mi); + mp->pixelmode = (mp->width + mp->height < 200); + mp->stage = 0; + mp->time = 0; + mp->x = mp->y = 0; + if (MI_IS_FULLRANDOM(mi)) { + mp->joke = (Bool) (NRAND(10) == 0); + mp->wireframe = (Bool) (LRAND() & 1); + } else { + mp->joke = False; + mp->wireframe = MI_IS_WIREFRAME(mi); + } + + if (mp->stippledGC == None) { + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + if ((mp->stippledGC = XCreateGC(MI_DISPLAY(mi), MI_WINDOW(mi), + GCForeground | GCBackground, &gcv)) == None) + return; + } + MI_CLEARWINDOW(mi); + + for (y = 0; y < (int) WORLDWIDTH; y++) + for (x = 0; x < (int) WORLDWIDTH; x++) + mp->h[x][y] = 0; + + j = MI_COUNT(mi); + if (j < 0) + j = NRAND(-j) + 1; + for (i = 0; i < j; i++) + mp->h[RANGE_RAND(1, WORLDWIDTH - 1)][RANGE_RAND(1, WORLDWIDTH - 1)] = + NRAND(MAXHEIGHT); + + for (y = 0; y < WORLDWIDTH; y++) + for (x = 0; x < WORLDWIDTH; x++) + spread(mp->h, x, y); + + for (y = 0; y < WORLDWIDTH; y++) + for (x = 0; x < WORLDWIDTH; x++) { + mp->h[x][y] = mp->h[x][y] + NRAND(10) - 5; + if (mp->h[x][y] < 10) + mp->h[x][y] = 0; + } + + if (MI_NPIXELS(mi) > 2) + mp->offset = NRAND(MI_NPIXELS(mi)); + else + mp->offset = 0; +} + +ENTRYPOINT void +draw_mountain (ModeInfo * mi) +{ + mountainstruct *mp; + + if (mountains == NULL) + return; + mp = &mountains[MI_SCREEN(mi)]; + if (mp->stippledGC == NULL) + return; + + MI_IS_DRAWN(mi) = True; + + switch (mp->stage) { + case 0: + drawamountain(mi); + break; + case 1: + if (++mp->time > MI_CYCLES(mi)) + mp->stage++; + break; + case 2: + init_mountain(mi); + break; + } +} + +ENTRYPOINT void +reshape_mountain(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_mountain (mi); +} + + +ENTRYPOINT void +release_mountain (ModeInfo * mi) +{ + if (mountains != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + mountainstruct *mp = &mountains[screen]; + + if (mp->stippledGC) + XFreeGC(MI_DISPLAY(mi), mp->stippledGC); + } + (void) free((void *) mountains); + mountains = (mountainstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_mountain(ModeInfo * mi) +{ + mountainstruct *mp; + + if (mountains == NULL) + return; + mp = &mountains[MI_SCREEN(mi)]; + + MI_CLEARWINDOW(mi); + mp->x = 0; + mp->y = 0; +} + +XSCREENSAVER_MODULE ("Mountain", mountain) + +#endif /* MODE_mountain */ diff --git a/non-wgl/mountain.vcproj b/non-wgl/mountain.vcproj new file mode 100644 index 0000000..6b2df76 --- /dev/null +++ b/non-wgl/mountain.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/munch.c b/non-wgl/munch.c new file mode 100644 index 0000000..153effd --- /dev/null +++ b/non-wgl/munch.c @@ -0,0 +1,493 @@ +/* Munching Squares and Mismunch + * + * Portions copyright 1992-2008 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. + * + * Portions Copyright 1997, Tim Showalter + * + * Permission is granted to copy, modify, and use this as long + * as this notice remains intact. No warranties are expressed or + * implied. CMU Sucks. + * + * Portions Copyright 2004 Steven Hazel + * + * (The "mismunch" part). + * + * "munch.c" and "mismunch.c" merged by jwz, 29-Aug-2008. + * + * + * + *********************************************************************** + * + * HAKMEM + * + * MIT AI Memo 239, Feb. 29, 1972. + * Beeler, M., Gosper, R.W., and Schroeppel, R. + * + * http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item146 + * + *********************************************************************** + * + * ITEM 146: MUNCHING SQUARES + * + * Another simple display program. It is thought that this was + * discovered by Jackson Wright on the RLE PDP-1 circa 1962. + * + * DATAI 2 + * ADDB 1,2 + * ROTC 2,-22 + * XOR 1,2 + * JRST .-4 + * + * 2=X, 3=Y. Try things like 1001002 in data switches. This also + * does * interesting things with operations other than XOR, and + * rotations * other than -22. (Try IOR; AND; TSC; FADR; FDV(!); + * ROT * -14, -9, -20, * ...) + * + * ITEM 147 (Schroeppel): + * + * Munching squares is just views of the graph Y = X XOR T for + * consecutive values of T = time. + * + * ITEM 147 (Cohen, Beeler): + * + * A modification to munching squares which reveals them in frozen + * states through opening and closing curtains: insert FADR 2,1 + * before the XOR. Try data switches = + * + * 4000,,4 1000,,2002 2000,,4 0,,1002 + * + * (Notation: ,,) + * Also try the FADR after the XOR, switches = 1001,,1. + * + *********************************************************************** + */ + +#include "screenhack.h" +#include + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +char *mismunch = "random"; +int simul = 5; +int clear = 65; +Bool xor_ = True; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&mismunch, "mismunch", NULL, "random", t_String}, + {&simul, "simul", NULL, "5", t_Int}, + {&clear, "clear", NULL, "65", t_Int}, + {&xor_, "speed", NULL, "True", t_Bool}, +}; + + +typedef struct _muncher { + int mismunch; + int width; + int atX, atY; + int kX, kT, kY; + int grav; + XColor fgc; + int yshadow, xshadow; + int x, y, t; + int doom; + int done; +} muncher; + + +struct state { + Display *dpy; + Window window; + + GC gc; + int delay, simul, clear, xor; + int logminwidth, logmaxwidth; + int restart, window_width, window_height; + + int draw_n; /* number of squares before we have to clear */ + int draw_i; + int mismunch; + + muncher **munchers; +}; + + +/* + * dumb way to get # of digits in number. Probably faster than actually + * doing a log and a division, maybe. + */ +static int dumb_log_2(int k) +{ + int r = -1; + while (k > 0) { + k >>= 1; r++; + } + return r; +} + + +static void calc_logwidths (struct state *st) +{ + /* Choose a range of square sizes based on the window size. We want + a power of 2 for the square width or the munch doesn't fill up. + Also, if a square doesn't fit inside an area 20% smaller than the + window, it's too big. Mismunched squares that big make things + look too noisy. */ + + if (st->window_height < st->window_width) { + st->logmaxwidth = (int)dumb_log_2(st->window_height * 0.8); + } else { + st->logmaxwidth = (int)dumb_log_2(st->window_width * 0.8); + } + + if (st->logmaxwidth < 2) { + st->logmaxwidth = 2; + } + + /* we always want three sizes of squares */ + st->logminwidth = st->logmaxwidth - 2; + + if (st->logminwidth < 2) { + st->logminwidth = 2; + } +} + + + +static muncher *make_muncher (struct state *st) +{ + int logwidth; + XWindowAttributes xgwa; + muncher *m = (muncher *) malloc(sizeof(muncher)); + + XGetWindowAttributes(st->dpy, st->window, &xgwa); + + m->mismunch = st->mismunch; + + /* choose size -- power of two */ + logwidth = (st->logminwidth + + (random() % (1 + st->logmaxwidth - st->logminwidth))); + + m->width = 1 << logwidth; + + /* draw at this location */ + m->atX = (random() % (xgwa.width <= m->width ? 1 + : xgwa.width - m->width)); + m->atY = (random() % (xgwa.height <= m->width ? 1 + : xgwa.width - m->width)); + + /* wrap-around by these values; no need to % as we end up doing that + later anyway */ + m->kX = ((random() % 2) + ? (random() % m->width) : 0); + m->kT = ((random() % 2) + ? (random() % m->width) : 0); + m->kY = ((random() % 2) + ? (random() % m->width) : 0); + + /* set the gravity of the munch, or rather, which direction we draw + stuff in. */ + m->grav = random() % 2; + + /* I like this color scheme better than random colors. */ + switch (random() % 4) { + case 0: + m->fgc.red = random() % 65536; + m->fgc.blue = random() % 32768; + m->fgc.green = random() % 16384; + break; + + case 1: + m->fgc.red = 0; + m->fgc.blue = random() % 65536; + m->fgc.green = random() % 16384; + break; + + case 2: + m->fgc.red = random() % 8192; + m->fgc.blue = random() % 8192; + m->fgc.green = random() % 49152; + break; + + case 3: + m->fgc.red = random() % 65536; + m->fgc.green = m->fgc.red; + m->fgc.blue = m->fgc.red; + break; + } + + /* Sometimes draw a mostly-overlapping copy of the square. This + generates all kinds of neat blocky graphics when drawing in xor + mode. */ + if (!m->mismunch || (random() % 4)) { + m->xshadow = 0; + m->yshadow = 0; + } else { + m->xshadow = (random() % (m->width/3)) - (m->width/6); + m->yshadow = (random() % (m->width/3)) - (m->width/6); + } + + /* Start with a random y value -- this sort of controls the type of + deformities seen in the squares. */ + m->y = random() % 256; + + m->t = 0; + + /* + Doom each square to be aborted at some random point. + (When doom == (width - 1), the entire square will be drawn.) + */ + m->doom = (m->mismunch ? (random() % m->width) : (m->width - 1)); + m->done = 0; + + return m; +} + + +static void munch (struct state *st, muncher *m) +{ + int drawX, drawY; + XWindowAttributes xgwa; + + if (m->done) { + return; + } + + XGetWindowAttributes(st->dpy, st->window, &xgwa); + + if (!mono_p) { + /* XXX there are probably bugs with this. */ + if (XAllocColor(st->dpy, xgwa.colormap, &m->fgc)) { + XSetForeground(st->dpy, st->gc, m->fgc.pixel); + } + } + + /* Finally draw this pass of the munching error. */ + + for(m->x = 0; m->x < m->width; m->x++) { + /* figure out the next point */ + + /* + The ordinary Munching Squares calculation is: + m->y = ((m->x ^ ((m->t + m->kT) % m->width)) + m->kY) % m->width; + + We create some feedback by plugging in y in place of x, and + make a couple of values negative so that some parts of some + squares get drawn in the wrong place. + */ + if (m->mismunch) + m->y = ((-m->y ^ ((-m->t + m->kT) % m->width)) + m->kY) % m->width; + else + m->y = ((m->x ^ ((m->t + m->kT) % m->width)) + m->kY) % m->width; + + drawX = ((m->x + m->kX) % m->width) + m->atX; + drawY = (m->grav ? m->y + m->atY : m->atY + m->width - 1 - m->y); + + XDrawPoint(st->dpy, st->window, st->gc, drawX, drawY); + if ((m->xshadow != 0) || (m->yshadow != 0)) { + /* draw the corresponding shadow point */ + XDrawPoint(st->dpy, st->window, st->gc, drawX + m->xshadow, drawY + m->yshadow); + } + /* XXX may want to change this to XDrawPoints, + but it's fast enough without it for the moment. */ + + } + + m->t++; + if (m->t > m->doom) { + m->done = 1; + } +} + + +static void * +munch_init (Display *dpy, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XWindowAttributes xgwa; + XGCValues gcv; + int i; + char *mm; + + st->dpy = dpy; + st->window = w; + st->restart = 0; + + /* get the dimensions of the window */ + XGetWindowAttributes(st->dpy, w, &xgwa); + + /* create the gc */ +#if 1 + gcv.foreground= load_color(st->dpy, xgwa.colormap, foreground); + gcv.background= load_color(st->dpy, xgwa.colormap, background); +#else + gcv.foreground= get_pixel_resource(st->dpy, xgwa.colormap, + "foreground","Foreground"); + gcv.background= get_pixel_resource(st->dpy, xgwa.colormap, + "background","Background"); +#endif + + st->gc = XCreateGC(st->dpy, w, GCForeground|GCBackground, &gcv); + + //st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->delay = delay; + if (st->delay < 0) st->delay = 0; + + //st->simul = get_integer_resource(st->dpy, "simul", "Integer"); + st->simul = simul; + if (st->simul < 1) st->simul = 1; + + //st->clear = get_integer_resource(st->dpy, "clear", "Integer"); + st->clear = clear; + if (st->clear < 0) st->clear = 0; + + //st->xor = get_boolean_resource(st->dpy, "xor", "Boolean"); + st->xor = xor_; + + //mm = get_string_resource (st->dpy, "mismunch", "Mismunch"); + mm = mismunch; + if (!mm || !*mm || !strcmp(mm, "random")) + st->mismunch = random() & 1; + else + //st->mismunch = get_boolean_resource (st->dpy, "mismunch", "Mismunch"); + st->mismunch = atoi(mismunch); + + st->window_width = xgwa.width; + st->window_height = xgwa.height; + + calc_logwidths(st); + + /* always draw xor on mono. */ + if (mono_p || st->xor) { + XSetFunction(st->dpy, st->gc, GXxor); + } + + st->munchers = (muncher **) calloc(st->simul, sizeof(muncher *)); + for (i = 0; i < st->simul; i++) { + st->munchers[i] = make_muncher(st); + } + + return st; +} + +static unsigned long +munch_draw (Display *dpy, Window w, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + + for (i = 0; i < 5; i++) { + + /* for (draw_i = 0; draw_i < simul; draw_i++) */ + { + munch(st, st->munchers[st->draw_i]); + + if (st->munchers[st->draw_i]->done) { + st->draw_n++; + + free(st->munchers[st->draw_i]); + st->munchers[st->draw_i] = make_muncher(st); + } + } + + st->draw_i++; + if (st->draw_i >= st->simul) { + int i = 0; + st->draw_i = 0; + if (st->restart || (st->clear && st->draw_n >= st->clear)) { + + //char *mm = get_string_resource (st->dpy, "mismunch", "Mismunch"); + char *mm = mismunch; + if (!mm || !*mm || !strcmp(mm, "random")) + st->mismunch = random() & 1; + + for (i = 0; i < st->simul; i++) { + free(st->munchers[i]); + st->munchers[i] = make_muncher(st); + } + + XClearWindow(st->dpy, w); + st->draw_n = 0; + st->restart = 0; + } + } + + } + + return st->delay; +} + + +static void +munch_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + if (w != st->window_width || + h != st->window_height) { + st->window_width = w; + st->window_height = h; + calc_logwidths(st); + st->restart = 1; + st->draw_i = 0; + } +} + +#if 0 + static Bool + munch_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +munch_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *munch_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 10000", + "*mismunch: random", + "*simul: 5", + "*clear: 65", + "*xor: True", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec munch_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-simul", ".simul", XrmoptionSepArg, 0 }, + { "-clear", ".clear", XrmoptionSepArg, "true" }, + { "-xor", ".xor", XrmoptionNoArg, "true" }, + { "-no-xor", ".xor", XrmoptionNoArg, "false" }, + { "-classic", ".mismunch", XrmoptionNoArg, "false" }, + { "-mismunch", ".mismunch", XrmoptionNoArg, "true" }, + { "-random", ".mismunch", XrmoptionNoArg, "random" }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Munch", munch) diff --git a/non-wgl/munch.vcproj b/non-wgl/munch.vcproj new file mode 100644 index 0000000..c9c4ca1 --- /dev/null +++ b/non-wgl/munch.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/nerverot.c b/non-wgl/nerverot.c new file mode 100644 index 0000000..e2ad458 --- /dev/null +++ b/non-wgl/nerverot.c @@ -0,0 +1,1407 @@ +/* nerverot, nervous rotation of random thingies, v1.4 + * by Dan Bornstein, danfuzz@milk.com + * Copyright (c) 2000-2001 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. + * + * The goal of this screensaver is to be interesting and compelling to + * watch, yet induce a state of nervous edginess in the viewer. + * + * See the included man page for more details. + */ + +#include "screenhack.h" +#include + +#define FLOAT double + +/* random float in the range (-1..1) */ +#define RAND_FLOAT_PM1 \ + (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000) * 2 - 1) + +/* random float in the range (0..1) */ +#define RAND_FLOAT_01 \ + (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000)) + +char *background = "black"; +char *foreground = "white"; +int count = 250; +int colors = 4; +int delay = 10000; +int maxIters = 1200; +Bool doubleBuffer = False; +float eventChance = 0.2; +float iterAmt = 0.01; +int lineWidth = 0; +float minScale = 0.6; +float maxScale = 1.75; +float minRadius = 3; +int maxRadius = 25; +float maxNerveRadius = 0.7; +float nervousness = 0.3; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&count, "count", NULL, "250", t_Int}, + {&colors, "colors", NULL, "4", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&maxIters, "maxIters", NULL, "1200", t_Int}, + {&doubleBuffer, "doubleBuffer", NULL, "False", t_Bool}, + {&eventChance, "eventChance", NULL, "0.2", t_Float}, + {&iterAmt, "iterAmt", NULL, "0.01", t_Float}, + {&lineWidth, "lineWidth", NULL, "0", t_Int}, + {&minScale, "minScale", NULL, "0.6", t_Float}, + {&maxScale, "maxScale", NULL, "1.75", t_Float}, + {&minRadius, "minRadius", NULL, "3.0", t_Float}, + {&maxRadius, "maxRadius", NULL, "25", t_Int}, + {&maxNerveRadius, "maxNerveRadius", NULL, "0.7", t_Float}, + {&nervousness, "nervousness", NULL, "0.3", t_Float}, +}; + +/* structure of the model */ + +/* each point-like thingy to draw is represented as a blot */ +typedef struct blot_s +{ + FLOAT x; /* 3d x position (-1..1) */ + FLOAT y; /* 3d y position (-1..1) */ + FLOAT z; /* 3d z position (-1..1) */ + FLOAT xoff[3][3]; /* display x offset per drawn point (-1..1) */ + FLOAT yoff[3][3]; /* display x offset per drawn point (-1..1) */ +} Blot; + +/* each drawn line is represented as a LineSegment */ +typedef struct linesegment_s +{ + GC gc; + int x1; + int y1; + int x2; + int y2; +} LineSegment; + +/* each blot draws as a simple 2d shape with each coordinate as an int + * in the range (-1..1); this is the base shape */ +static const XPoint blotShape[] = { { 0, 0}, { 1, 0}, { 1, 1}, + { 0, 1}, {-1, 1}, {-1, 0}, + {-1,-1}, { 0,-1}, { 1,-1} }; +static int blotShapeCount = sizeof (blotShape) / sizeof (XPoint); + + + + + +struct state { + Display *dpy; + Window window; + + int requestedBlotCount; /* number of blots */ + int delay; /* delay (usec) between iterations */ + int maxIters; /* max iterations per model */ + FLOAT nervousness; /* variability of xoff/yoff per iteration (0..1) */ + FLOAT maxNerveRadius; /* max nervousness radius (0..1) */ + FLOAT eventChance; /* chance per iteration that an event will happen */ + FLOAT iterAmt; /* fraction (0..1) towards rotation target or scale target to move each * iteration */ + FLOAT minScale; /* min and max scale for drawing, as fraction of baseScale */ + FLOAT maxScale; + int minRadius; /* min and max radius of blot drawing */ + int maxRadius; + int colorCount; /* the number of colors to use */ + + int lineWidth; /* width of lines */ + + Bool doubleBuffer; /* whether or not to do double-buffering */ + + + int baseScale; /* base scale factor for drawing, calculated as max(screenWidth,screenHeight) */ + + + int windowWidth; /* width and height of the window */ + int windowHeight; + + int centerX; /* center position of the window */ + int centerY; + + Drawable drawable; /* the thing to directly draw on */ + GC *gcs; /* array of gcs, one per color used */ + + Blot *blots; /* array of the blots in the model */ + int blotCount; + + int segCount; /* two arrays of line segments; one for the ones to erase, and one for the ones to draw */ + + LineSegment *segsToDraw; + LineSegment *segsToErase; + + + FLOAT xRot; /* current rotation values per axis, scale factor, and light position */ + + FLOAT yRot; + FLOAT zRot; + FLOAT curScale; + FLOAT lightX; + FLOAT lightY; + FLOAT lightZ; + + FLOAT xRotTarget; /* target rotation values per axis, scale factor, and light position */ + + FLOAT yRotTarget; + FLOAT zRotTarget; + FLOAT scaleTarget; + FLOAT lightXTarget; + FLOAT lightYTarget; + FLOAT lightZTarget; + + int centerXOff; /* current absolute offsets from the center */ + int centerYOff; + + int itersTillNext; /* iterations until the model changes */ +}; + + +/* + * generic blot setup and manipulation + */ + +/* initialize a blot with the given coordinates and random display offsets */ +static void initBlot (Blot *b, FLOAT x, FLOAT y, FLOAT z) +{ + int i, j; + + b->x = x; + b->y = y; + b->z = z; + + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + b->xoff[i][j] = RAND_FLOAT_PM1; + b->yoff[i][j] = RAND_FLOAT_PM1; + } + } +} + +/* scale the blots to have a max distance of 1 from the center */ +static void scaleBlotsToRadius1 (struct state *st) +{ + FLOAT max = 0.0; + int n; + + for (n = 0; n < st->blotCount; n++) + { + FLOAT distSquare = + st->blots[n].x * st->blots[n].x + + st->blots[n].y * st->blots[n].y + + st->blots[n].z * st->blots[n].z; + if (distSquare > max) + { + max = distSquare; + } + } + + if (max == 0.0) + { + return; + } + + max = sqrt (max); + + for (n = 0; n < st->blotCount; n++) + { + st->blots[n].x /= max; + st->blots[n].y /= max; + st->blots[n].z /= max; + } +} + +/* randomly reorder the blots */ +static void randomlyReorderBlots (struct state *st) +{ + int n; + + for (n = 0; n < st->blotCount; n++) + { + int m = RAND_FLOAT_01 * (st->blotCount - n) + n; + Blot tmpBlot = st->blots[n]; + st->blots[n] = st->blots[m]; + st->blots[m] = tmpBlot; + } +} + +/* randomly rotate the blots around the origin */ +static void randomlyRotateBlots (struct state *st) +{ + int n; + + /* random amounts to rotate about each axis */ + FLOAT xRot = RAND_FLOAT_PM1 * M_PI; + FLOAT yRot = RAND_FLOAT_PM1 * M_PI; + FLOAT zRot = RAND_FLOAT_PM1 * M_PI; + + /* rotation factors */ + FLOAT sinX = sin (xRot); + FLOAT cosX = cos (xRot); + FLOAT sinY = sin (yRot); + FLOAT cosY = cos (yRot); + FLOAT sinZ = sin (zRot); + FLOAT cosZ = cos (zRot); + + for (n = 0; n < st->blotCount; n++) + { + FLOAT x1 = st->blots[n].x; + FLOAT y1 = st->blots[n].y; + FLOAT z1 = st->blots[n].z; + FLOAT x2, y2, z2; + + /* rotate on z axis */ + x2 = x1 * cosZ - y1 * sinZ; + y2 = x1 * sinZ + y1 * cosZ; + z2 = z1; + + /* rotate on x axis */ + y1 = y2 * cosX - z2 * sinX; + z1 = y2 * sinX + z2 * cosX; + x1 = x2; + + /* rotate on y axis */ + z2 = z1 * cosY - x1 * sinY; + x2 = z1 * sinY + x1 * cosY; + y2 = y1; + + st->blots[n].x = x2; + st->blots[n].y = y2; + st->blots[n].z = z2; + } +} + + + +/* + * blot configurations + */ + +/* set up the initial array of blots to be a at the edge of a sphere */ +static void setupBlotsSphere (struct state *st) +{ + int n; + + st->blotCount = st->requestedBlotCount; + st->blots = calloc (sizeof (Blot), st->blotCount); + + for (n = 0; n < st->blotCount; n++) + { + /* pick a spot, but reject if its radius is < 0.2 or > 1 to + * avoid scaling problems */ + FLOAT x, y, z, radius; + + for (;;) + { + x = RAND_FLOAT_PM1; + y = RAND_FLOAT_PM1; + z = RAND_FLOAT_PM1; + + radius = sqrt (x * x + y * y + z * z); + if ((radius >= 0.2) && (radius <= 1.0)) + { + break; + } + } + + x /= radius; + y /= radius; + z /= radius; + + initBlot (&st->blots[n], x, y, z); + } +} + +/* set up the initial array of blots to be a simple cube */ +static void setupBlotsCube (struct state *st) +{ + int i, j, k, n; + + /* derive blotsPerEdge from blotCount, but then do the reverse + * since roundoff may have changed blotCount */ + int blotsPerEdge = ((st->requestedBlotCount - 8) / 12) + 2; + FLOAT distBetween; + + if (blotsPerEdge < 2) + { + blotsPerEdge = 2; + } + + distBetween = 2.0 / (blotsPerEdge - 1.0); + + st->blotCount = 8 + (blotsPerEdge - 2) * 12; + st->blots = calloc (sizeof (Blot), st->blotCount); + n = 0; + + /* define the corners */ + for (i = -1; i < 2; i += 2) + { + for (j = -1; j < 2; j += 2) + { + for (k = -1; k < 2; k += 2) + { + initBlot (&st->blots[n], i, j, k); + n++; + } + } + } + + /* define the edges */ + for (i = 1; i < (blotsPerEdge - 1); i++) + { + FLOAT varEdge = distBetween * i - 1; + initBlot (&st->blots[n++], varEdge, -1, -1); + initBlot (&st->blots[n++], varEdge, 1, -1); + initBlot (&st->blots[n++], varEdge, -1, 1); + initBlot (&st->blots[n++], varEdge, 1, 1); + initBlot (&st->blots[n++], -1, varEdge, -1); + initBlot (&st->blots[n++], 1, varEdge, -1); + initBlot (&st->blots[n++], -1, varEdge, 1); + initBlot (&st->blots[n++], 1, varEdge, 1); + initBlot (&st->blots[n++], -1, -1, varEdge); + initBlot (&st->blots[n++], 1, -1, varEdge); + initBlot (&st->blots[n++], -1, 1, varEdge); + initBlot (&st->blots[n++], 1, 1, varEdge); + } + + scaleBlotsToRadius1 (st); + randomlyReorderBlots (st); + randomlyRotateBlots (st); +} + +/* set up the initial array of blots to be a cylinder */ +static void setupBlotsCylinder (struct state *st) +{ + int i, j, n; + FLOAT distBetween; + + /* derive blotsPerEdge and blotsPerRing from blotCount, but then do the + * reverse since roundoff may have changed blotCount */ + FLOAT reqRoot = sqrt ((FLOAT) st->requestedBlotCount); + int blotsPerRing = ceil (RAND_FLOAT_PM1 * reqRoot) / 2 + reqRoot; + int blotsPerEdge = st->requestedBlotCount / blotsPerRing; + + if (blotsPerRing < 2) + { + blotsPerRing = 2; + } + + if (blotsPerEdge < 2) + { + blotsPerEdge = 2; + } + + distBetween = 2.0 / (blotsPerEdge - 1); + + st->blotCount = blotsPerEdge * blotsPerRing; + st->blots = calloc (sizeof (Blot), st->blotCount); + n = 0; + + /* define the edges */ + for (i = 0; i < blotsPerRing; i++) + { + FLOAT x = sin (2 * M_PI / blotsPerRing * i); + FLOAT y = cos (2 * M_PI / blotsPerRing * i); + for (j = 0; j < blotsPerEdge; j++) + { + initBlot (&st->blots[n], x, y, j * distBetween - 1); + n++; + } + } + + scaleBlotsToRadius1 (st); + randomlyReorderBlots (st); + randomlyRotateBlots (st); +} + +/* set up the initial array of blots to be a squiggle */ +static void setupBlotsSquiggle (struct state *st) +{ + FLOAT x, y, z, xv, yv, zv, len; + int minCoor, maxCoor; + int n; + + st->blotCount = st->requestedBlotCount; + st->blots = calloc (sizeof (Blot), st->blotCount); + + maxCoor = (int) (RAND_FLOAT_01 * 5) + 1; + minCoor = -maxCoor; + + x = RAND_FLOAT_PM1; + y = RAND_FLOAT_PM1; + z = RAND_FLOAT_PM1; + + xv = RAND_FLOAT_PM1; + yv = RAND_FLOAT_PM1; + zv = RAND_FLOAT_PM1; + len = sqrt (xv * xv + yv * yv + zv * zv); + xv /= len; + yv /= len; + zv /= len; + + for (n = 0; n < st->blotCount; n++) + { + FLOAT newx, newy, newz; + initBlot (&st->blots[n], x, y, z); + + for (;;) + { + xv += RAND_FLOAT_PM1 * 0.1; + yv += RAND_FLOAT_PM1 * 0.1; + zv += RAND_FLOAT_PM1 * 0.1; + len = sqrt (xv * xv + yv * yv + zv * zv); + xv /= len; + yv /= len; + zv /= len; + + newx = x + xv * 0.1; + newy = y + yv * 0.1; + newz = z + zv * 0.1; + + if ( (newx >= minCoor) && (newx <= maxCoor) + && (newy >= minCoor) && (newy <= maxCoor) + && (newz >= minCoor) && (newz <= maxCoor)) + { + break; + } + } + + x = newx; + y = newy; + z = newz; + } + + scaleBlotsToRadius1 (st); + randomlyReorderBlots (st); +} + +/* set up the initial array of blots to be near the corners of a + * cube, distributed slightly */ +static void setupBlotsCubeCorners (struct state *st) +{ + int n; + + st->blotCount = st->requestedBlotCount; + st->blots = calloc (sizeof (Blot), st->blotCount); + + for (n = 0; n < st->blotCount; n++) + { + FLOAT x = rint (RAND_FLOAT_01) * 2 - 1; + FLOAT y = rint (RAND_FLOAT_01) * 2 - 1; + FLOAT z = rint (RAND_FLOAT_01) * 2 - 1; + + x += RAND_FLOAT_PM1 * 0.3; + y += RAND_FLOAT_PM1 * 0.3; + z += RAND_FLOAT_PM1 * 0.3; + + initBlot (&st->blots[n], x, y, z); + } + + scaleBlotsToRadius1 (st); + randomlyRotateBlots (st); +} + +/* set up the initial array of blots to be randomly distributed + * on the surface of a tetrahedron */ +static void setupBlotsTetrahedron (struct state *st) +{ + /* table of corners of the tetrahedron */ + static const FLOAT cor[4][3] = { { 0.0, 1.0, 0.0 }, + { -0.75, -0.5, -0.433013 }, + { 0.0, -0.5, 0.866025 }, + { 0.75, -0.5, -0.433013 } }; + + int n, c; + + /* derive blotsPerSurface from blotCount, but then do the reverse + * since roundoff may have changed blotCount */ + int blotsPerSurface = st->requestedBlotCount / 4; + + st->blotCount = blotsPerSurface * 4; + st->blots = calloc (sizeof (Blot), st->blotCount); + + for (n = 0; n < st->blotCount; n += 4) + { + /* pick a random point on a unit right triangle */ + FLOAT rawx = RAND_FLOAT_01; + FLOAT rawy = RAND_FLOAT_01; + + if ((rawx + rawy) > 1) + { + /* swap coords into place */ + FLOAT t = 1.0 - rawx; + rawx = 1.0 - rawy; + rawy = t; + } + + /* translate the point to be on each of the surfaces */ + for (c = 0; c < 4; c++) + { + FLOAT x, y, z; + + int c1 = (c + 1) % 4; + int c2 = (c + 2) % 4; + + x = (cor[c1][0] - cor[c][0]) * rawx + + (cor[c2][0] - cor[c][0]) * rawy + + cor[c][0]; + + y = (cor[c1][1] - cor[c][1]) * rawx + + (cor[c2][1] - cor[c][1]) * rawy + + cor[c][1]; + + z = (cor[c1][2] - cor[c][2]) * rawx + + (cor[c2][2] - cor[c][2]) * rawy + + cor[c][2]; + + initBlot (&st->blots[n + c], x, y, z); + } + } + + randomlyRotateBlots (st); +} + +/* set up the initial array of blots to be an almost-evenly-distributed + * square sheet */ +static void setupBlotsSheet (struct state *st) +{ + int x, y; + + int blotsPerDimension = floor (sqrt (st->requestedBlotCount)); + FLOAT spaceBetween; + + if (blotsPerDimension < 2) + { + blotsPerDimension = 2; + } + + spaceBetween = 2.0 / (blotsPerDimension - 1); + + st->blotCount = blotsPerDimension * blotsPerDimension; + st->blots = calloc (sizeof (Blot), st->blotCount); + + for (x = 0; x < blotsPerDimension; x++) + { + for (y = 0; y < blotsPerDimension; y++) + { + FLOAT x1 = x * spaceBetween - 1.0; + FLOAT y1 = y * spaceBetween - 1.0; + FLOAT z1 = 0.0; + + x1 += RAND_FLOAT_PM1 * spaceBetween / 3; + y1 += RAND_FLOAT_PM1 * spaceBetween / 3; + z1 += RAND_FLOAT_PM1 * spaceBetween / 2; + + initBlot (&st->blots[x + y * blotsPerDimension], x1, y1, z1); + } + } + + scaleBlotsToRadius1 (st); + randomlyReorderBlots (st); + randomlyRotateBlots (st); +} + +/* set up the initial array of blots to be a swirlycone */ +static void setupBlotsSwirlyCone (struct state *st) +{ + FLOAT radSpace = 1.0 / (st->requestedBlotCount - 1); + FLOAT zSpace = radSpace * 2; + FLOAT rotAmt = RAND_FLOAT_PM1 * M_PI / 10; + + int n; + FLOAT rot = 0.0; + + st->blotCount = st->requestedBlotCount; + st->blots = calloc (sizeof (Blot), st->blotCount); + + for (n = 0; n < st->blotCount; n++) + { + FLOAT radius = n * radSpace; + FLOAT x = cos (rot) * radius; + FLOAT y = sin (rot) * radius; + FLOAT z = n * zSpace - 1.0; + + rot += rotAmt; + initBlot (&st->blots[n], x, y, z); + } + + scaleBlotsToRadius1 (st); + randomlyReorderBlots (st); + randomlyRotateBlots (st); +} + +/* forward declaration for recursive use immediately below */ +static void setupBlots (struct state *st); + +/* set up the blots to be two of the other choices, placed next to + * each other */ +static void setupBlotsDuo (struct state *st) +{ + int origRequest = st->requestedBlotCount; + FLOAT tx, ty, tz, radius; + Blot *blots1, *blots2; + int count1, count2; + int n; + + if (st->requestedBlotCount < 15) + { + /* special case bottom-out */ + setupBlotsSphere (st); + return; + } + + tx = RAND_FLOAT_PM1; + ty = RAND_FLOAT_PM1; + tz = RAND_FLOAT_PM1; + radius = sqrt (tx * tx + ty * ty + tz * tz); + tx /= radius; + ty /= radius; + tz /= radius; + + /* recursive call to setup set 1 */ + st->requestedBlotCount = origRequest / 2; + setupBlots (st); + + if (st->blotCount >= origRequest) + { + /* return immediately if this satisfies the original count request */ + st->requestedBlotCount = origRequest; + return; + } + + blots1 = st->blots; + count1 = st->blotCount; + st->blots = NULL; + st->blotCount = 0; + + /* translate to new position */ + for (n = 0; n < count1; n++) + { + blots1[n].x += tx; + blots1[n].y += ty; + blots1[n].z += tz; + } + + /* recursive call to setup set 2 */ + st->requestedBlotCount = origRequest - count1; + setupBlots (st); + blots2 = st->blots; + count2 = st->blotCount; + + /* translate to new position */ + for (n = 0; n < count2; n++) + { + blots2[n].x -= tx; + blots2[n].y -= ty; + blots2[n].z -= tz; + } + + /* combine the two arrays */ + st->blotCount = count1 + count2; + st->blots = calloc (sizeof (Blot), st->blotCount); + memcpy (&st->blots[0], blots1, sizeof (Blot) * count1); + memcpy (&st->blots[count1], blots2, sizeof (Blot) * count2); + free (blots1); + free (blots2); + + scaleBlotsToRadius1 (st); + randomlyReorderBlots (st); + + /* restore the original requested count, for future iterations */ + st->requestedBlotCount = origRequest; +} + + + +/* + * main blot setup + */ + +/* free the blots, in preparation for a new shape */ +static void freeBlots (struct state *st) +{ + if (st->blots != NULL) + { + free (st->blots); + st->blots = NULL; + } + + if (st->segsToErase != NULL) + { + free (st->segsToErase); + st->segsToErase = NULL; + } + + if (st->segsToDraw != NULL) + { + free (st->segsToDraw); + st->segsToDraw = NULL; + } +} + +/* set up the initial arrays of blots */ +static void setupBlots (struct state *st) +{ + int which = RAND_FLOAT_01 * 11; + + freeBlots (st); + + switch (which) + { + case 0: + setupBlotsCube (st); + break; + case 1: + setupBlotsSphere (st); + break; + case 2: + setupBlotsCylinder (st); + break; + case 3: + setupBlotsSquiggle (st); + break; + case 4: + setupBlotsCubeCorners (st); + break; + case 5: + setupBlotsTetrahedron (st); + break; + case 6: + setupBlotsSheet (st); + break; + case 7: + setupBlotsSwirlyCone (st); + break; + case 8: + case 9: + case 10: + setupBlotsDuo (st); + break; + } +} + +/* set up the segments arrays */ +static void setupSegs (struct state *st) +{ + /* there are blotShapeCount - 1 line segments per blot */ + st->segCount = st->blotCount * (blotShapeCount - 1); + st->segsToErase = calloc (sizeof (LineSegment), st->segCount); + st->segsToDraw = calloc (sizeof (LineSegment), st->segCount); +} + + + +/* + * color setup stuff + */ + +/* set up the colormap */ +static void setupColormap (struct state *st, XWindowAttributes *xgwa) +{ + int n; + XGCValues gcv; + XColor *colors = (XColor *) calloc (sizeof (XColor), st->colorCount + 1); + + unsigned short r, g, b; + int h1, h2; + double s1, s2, v1, v2; + + r = RAND_FLOAT_01 * 0x10000; + g = RAND_FLOAT_01 * 0x10000; + b = RAND_FLOAT_01 * 0x10000; + rgb_to_hsv (r, g, b, &h1, &s1, &v1); + v1 = 1.0; + s1 = 1.0; + + r = RAND_FLOAT_01 * 0x10000; + g = RAND_FLOAT_01 * 0x10000; + b = RAND_FLOAT_01 * 0x10000; + rgb_to_hsv (r, g, b, &h2, &s2, &v2); + s2 = 0.7; + v2 = 0.7; + + //colors[0].pixel = get_pixel_resource (st->dpy, xgwa->colormap, + // "background", "Background"); + colors[0].pixel = load_color(st->dpy, xgwa->colormap, background); + + make_color_ramp (xgwa->screen, xgwa->visual, xgwa->colormap, + h1, s1, v1, h2, s2, v2, + colors + 1, &st->colorCount, False, True, False); + + if (st->colorCount < 1) + { + fprintf (stderr, "%s: couldn't allocate any colors\n", progname); + exit (-1); + } + + st->gcs = (GC *) calloc (sizeof (GC), st->colorCount + 1); + + for (n = 0; n <= st->colorCount; n++) + { + gcv.foreground = colors[n].pixel; + gcv.line_width = st->lineWidth; + st->gcs[n] = XCreateGC (st->dpy, st->window, GCForeground | GCLineWidth, &gcv); + } + + free (colors); +} + + + +/* + * overall setup stuff + */ + +/* set up the system */ +static void setup (struct state *st) +{ + XWindowAttributes xgwa; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->windowWidth = xgwa.width; + st->windowHeight = xgwa.height; + st->centerX = st->windowWidth / 2; + st->centerY = st->windowHeight / 2; + st->baseScale = (xgwa.height < xgwa.width) ? xgwa.height : xgwa.width; + + if (st->doubleBuffer) + { + st->drawable = XCreatePixmap (st->dpy, st->window, xgwa.width, xgwa.height, + xgwa.depth); + } + else + { + st->drawable = st->window; + } + + setupColormap (st, &xgwa); + setupBlots (st); + setupSegs (st); + + /* set up the initial rotation, scale, and light values as random, but + * with the targets equal to where it is */ + st->xRot = st->xRotTarget = RAND_FLOAT_01 * M_PI; + st->yRot = st->yRotTarget = RAND_FLOAT_01 * M_PI; + st->zRot = st->zRotTarget = RAND_FLOAT_01 * M_PI; + st->curScale = st->scaleTarget = RAND_FLOAT_01 * (st->maxScale - st->minScale) + st->minScale; + st->lightX = st->lightXTarget = RAND_FLOAT_PM1; + st->lightY = st->lightYTarget = RAND_FLOAT_PM1; + st->lightZ = st->lightZTarget = RAND_FLOAT_PM1; + + st->itersTillNext = RAND_FLOAT_01 * st->maxIters; +} + + + +/* + * the simulation + */ + +/* "render" the blots into segsToDraw, with the current rotation factors */ +static void renderSegs (struct state *st) +{ + int n; + int m = 0; + + /* rotation factors */ + FLOAT sinX = sin (st->xRot); + FLOAT cosX = cos (st->xRot); + FLOAT sinY = sin (st->yRot); + FLOAT cosY = cos (st->yRot); + FLOAT sinZ = sin (st->zRot); + FLOAT cosZ = cos (st->zRot); + + for (n = 0; n < st->blotCount; n++) + { + Blot *b = &st->blots[n]; + int i, j; + int baseX, baseY; + FLOAT radius; + int x[3][3]; + int y[3][3]; + int color; + + FLOAT x1 = st->blots[n].x; + FLOAT y1 = st->blots[n].y; + FLOAT z1 = st->blots[n].z; + FLOAT x2, y2, z2; + + /* rotate on z axis */ + x2 = x1 * cosZ - y1 * sinZ; + y2 = x1 * sinZ + y1 * cosZ; + z2 = z1; + + /* rotate on x axis */ + y1 = y2 * cosX - z2 * sinX; + z1 = y2 * sinX + z2 * cosX; + x1 = x2; + + /* rotate on y axis */ + z2 = z1 * cosY - x1 * sinY; + x2 = z1 * sinY + x1 * cosY; + y2 = y1; + + /* the color to draw is based on the distance from the light of + * the post-rotation blot */ + x1 = x2 - st->lightX; + y1 = y2 - st->lightY; + z1 = z2 - st->lightZ; + color = 1 + (x1 * x1 + y1 * y1 + z1 * z1) / 4 * st->colorCount; + if (color > st->colorCount) + { + color = st->colorCount; + } + + /* set up the base screen coordinates for drawing */ + baseX = x2 / 2 * st->baseScale * st->curScale + st->centerX + st->centerXOff; + baseY = y2 / 2 * st->baseScale * st->curScale + st->centerY + st->centerYOff; + + radius = (z2 + 1) / 2 * (st->maxRadius - st->minRadius) + st->minRadius; + + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + x[i][j] = baseX + + ((i - 1) + (b->xoff[i][j] * st->maxNerveRadius)) * radius; + y[i][j] = baseY + + ((j - 1) + (b->yoff[i][j] * st->maxNerveRadius)) * radius; + } + } + + for (i = 1; i < blotShapeCount; i++) + { + st->segsToDraw[m].gc = st->gcs[color]; + st->segsToDraw[m].x1 = x[blotShape[i-1].x + 1][blotShape[i-1].y + 1]; + st->segsToDraw[m].y1 = y[blotShape[i-1].x + 1][blotShape[i-1].y + 1]; + st->segsToDraw[m].x2 = x[blotShape[i].x + 1][blotShape[i].y + 1]; + st->segsToDraw[m].y2 = y[blotShape[i].x + 1][blotShape[i].y + 1]; + m++; + } + } +} + +/* update blots, adjusting the offsets and rotation factors. */ +static void updateWithFeeling (struct state *st) +{ + int n, i, j; + + /* pick a new model if the time is right */ + st->itersTillNext--; + if (st->itersTillNext < 0) + { + st->itersTillNext = RAND_FLOAT_01 * st->maxIters; + setupBlots (st); + setupSegs (st); + renderSegs (st); + } + + /* update the rotation factors by moving them a bit toward the targets */ + st->xRot = st->xRot + (st->xRotTarget - st->xRot) * st->iterAmt; + st->yRot = st->yRot + (st->yRotTarget - st->yRot) * st->iterAmt; + st->zRot = st->zRot + (st->zRotTarget - st->zRot) * st->iterAmt; + + /* similarly the scale factor */ + st->curScale = st->curScale + (st->scaleTarget - st->curScale) * st->iterAmt; + + /* and similarly the light position */ + st->lightX = st->lightX + (st->lightXTarget - st->lightX) * st->iterAmt; + st->lightY = st->lightY + (st->lightYTarget - st->lightY) * st->iterAmt; + st->lightZ = st->lightZ + (st->lightZTarget - st->lightZ) * st->iterAmt; + + /* for each blot... */ + for (n = 0; n < st->blotCount; n++) + { + /* add a bit of random jitter to xoff/yoff */ + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + FLOAT newOff; + + newOff = st->blots[n].xoff[i][j] + RAND_FLOAT_PM1 * st->nervousness; + if (newOff < -1) newOff = -(newOff + 1) - 1; + else if (newOff > 1) newOff = -(newOff - 1) + 1; + st->blots[n].xoff[i][j] = newOff; + + newOff = st->blots[n].yoff[i][j] + RAND_FLOAT_PM1 * st->nervousness; + if (newOff < -1) newOff = -(newOff + 1) - 1; + else if (newOff > 1) newOff = -(newOff - 1) + 1; + st->blots[n].yoff[i][j] = newOff; + } + } + } + + /* depending on random chance, update one or more factors */ + if (RAND_FLOAT_01 <= st->eventChance) + { + int which = RAND_FLOAT_01 * 14; + switch (which) + { + case 0: + { + st->xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + break; + } + case 1: + { + st->yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + break; + } + case 2: + { + st->zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + break; + } + case 3: + { + st->xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + st->yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + break; + } + case 4: + { + st->xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + st->zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + break; + } + case 5: + { + st->yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + st->zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + break; + } + case 6: + { + st->xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + st->yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + st->zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; + break; + } + case 7: + { + st->centerXOff = RAND_FLOAT_PM1 * st->maxRadius; + break; + } + case 8: + { + st->centerYOff = RAND_FLOAT_PM1 * st->maxRadius; + break; + } + case 9: + { + st->centerXOff = RAND_FLOAT_PM1 * st->maxRadius; + st->centerYOff = RAND_FLOAT_PM1 * st->maxRadius; + break; + } + case 10: + { + st->scaleTarget = + RAND_FLOAT_01 * (st->maxScale - st->minScale) + st->minScale; + break; + } + case 11: + { + st->curScale = + RAND_FLOAT_01 * (st->maxScale - st->minScale) + st->minScale; + break; + } + case 12: + { + st->lightX = RAND_FLOAT_PM1; + st->lightY = RAND_FLOAT_PM1; + st->lightZ = RAND_FLOAT_PM1; + break; + } + case 13: + { + st->lightXTarget = RAND_FLOAT_PM1; + st->lightYTarget = RAND_FLOAT_PM1; + st->lightZTarget = RAND_FLOAT_PM1; + break; + } + } + } +} + +/* erase segsToErase and draw segsToDraw */ +static void eraseAndDraw (struct state *st) +{ + int n; + + if (st->doubleBuffer) + XFillRectangle (st->dpy, st->drawable, st->gcs[0], 0, 0, + st->windowWidth, st->windowHeight); + else + XClearWindow (st->dpy, st->drawable); + + for (n = 0; n < st->segCount; n++) + { + LineSegment *seg = &st->segsToErase[n]; +#ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + XDrawLine (st->dpy, st->drawable, st->gcs[0], + seg->x1, seg->y1, seg->x2, seg->y2); +#endif + seg = &st->segsToDraw[n]; + XDrawLine (st->dpy, st->drawable, seg->gc, + seg->x1, seg->y1, seg->x2, seg->y2); + } + + if (st->doubleBuffer) + { + XCopyArea (st->dpy, st->drawable, st->window, st->gcs[0], 0, 0, + st->windowWidth, st->windowHeight, 0, 0); + } +} + +/* do one iteration */ +static unsigned long +nerverot_draw (Display *dpy, Window win, void *closure) +{ + struct state *st = (struct state *) closure; + /* switch segsToErase and segsToDraw */ + LineSegment *temp = st->segsToDraw; + st->segsToDraw = st->segsToErase; + st->segsToErase = temp; + + /* update the model */ + updateWithFeeling (st); + + /* render new segments */ + renderSegs (st); + + /* erase old segments and draw new ones */ + eraseAndDraw (st); + + return st->delay; +} + +/* initialize the user-specifiable params */ +static void initParams (struct state *st) +{ + int problems = 0; + + //st->delay = get_integer_resource (st->dpy, "delay", "Delay"); + st->delay = delay; + if (st->delay < 0) + { + fprintf (stderr, "error: delay must be at least 0\n"); + problems = 1; + } + + //st->maxIters = get_integer_resource (st->dpy, "maxIters", "Integer"); + st->maxIters = maxIters; + if (st->maxIters < 0) + { + fprintf (stderr, "error: maxIters must be at least 0\n"); + problems = 1; + } + + //st->doubleBuffer = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean"); + st->doubleBuffer = doubleBuffer; + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + st->doubleBuffer = False; +# endif + + //st->requestedBlotCount = get_integer_resource (st->dpy, "count", "Count"); + st->requestedBlotCount = count; + if (st->requestedBlotCount <= 0) + { + fprintf (stderr, "error: count must be at least 0\n"); + problems = 1; + } + + //st->colorCount = get_integer_resource (st->dpy, "colors", "Colors"); + st->colorCount = colors; + if (st->colorCount <= 0) + { + fprintf (stderr, "error: colors must be at least 1\n"); + problems = 1; + } + + //st->lineWidth = get_integer_resource (st->dpy, "lineWidth", "LineWidth"); + st->lineWidth = lineWidth; + if (st->lineWidth < 0) + { + fprintf (stderr, "error: line width must be at least 0\n"); + problems = 1; + } + + //st->nervousness = get_float_resource (st->dpy, "nervousness", "Float"); + st->nervousness = nervousness; + if ((st->nervousness < 0) || (st->nervousness > 1)) + { + fprintf (stderr, "error: nervousness must be in the range 0..1\n"); + problems = 1; + } + + //st->maxNerveRadius = get_float_resource (st->dpy, "maxNerveRadius", "Float"); + st->maxNerveRadius = maxNerveRadius; + if ((st->maxNerveRadius < 0) || (st->maxNerveRadius > 1)) + { + fprintf (stderr, "error: maxNerveRadius must be in the range 0..1\n"); + problems = 1; + } + + //st->eventChance = get_float_resource (st->dpy, "eventChance", "Float"); + st->eventChance = eventChance; + if ((st->eventChance < 0) || (st->eventChance > 1)) + { + fprintf (stderr, "error: eventChance must be in the range 0..1\n"); + problems = 1; + } + + //st->iterAmt = get_float_resource (st->dpy, "iterAmt", "Float"); + st->iterAmt = iterAmt; + if ((st->iterAmt < 0) || (st->iterAmt > 1)) + { + fprintf (stderr, "error: iterAmt must be in the range 0..1\n"); + problems = 1; + } + + //st->minScale = get_float_resource (st->dpy, "minScale", "Float"); + st->minScale = minScale; + if ((st->minScale < 0) || (st->minScale > 10)) + { + fprintf (stderr, "error: minScale must be in the range 0..10\n"); + problems = 1; + } + + //st->maxScale = get_float_resource (st->dpy, "maxScale", "Float"); + st->maxScale = maxScale; + if ((st->maxScale < 0) || (st->maxScale > 10)) + { + fprintf (stderr, "error: maxScale must be in the range 0..10\n"); + problems = 1; + } + + if (st->maxScale < st->minScale) + { + fprintf (stderr, "error: maxScale must be >= minScale\n"); + problems = 1; + } + + //st->minRadius = get_integer_resource (st->dpy, "minRadius", "Integer"); + st->minRadius = minRadius; + if ((st->minRadius < 1) || (st->minRadius > 100)) + { + fprintf (stderr, "error: minRadius must be in the range 1..100\n"); + problems = 1; + } + + //st->maxRadius = get_integer_resource (st->dpy, "maxRadius", "Integer"); + st->maxRadius = maxRadius; + if ((st->maxRadius < 1) || (st->maxRadius > 100)) + { + fprintf (stderr, "error: maxRadius must be in the range 1..100\n"); + problems = 1; + } + + if (st->maxRadius < st->minRadius) + { + fprintf (stderr, "error: maxRadius must be >= minRadius\n"); + problems = 1; + } + + if (problems) + { + exit (1); + } +} + +static void * +nerverot_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + + initParams (st); + setup (st); + + /* make a valid set to erase at first */ + renderSegs (st); + return st; +} + +static void +nerverot_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + nerverot_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +nerverot_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + freeBlots (st); + free (st); +} + + +static const char *nerverot_defaults [] = { + ".background: black", + ".foreground: white", + "*count: 250", + "*colors: 4", + "*delay: 10000", + "*maxIters: 1200", + "*doubleBuffer: false", + "*eventChance: 0.2", + "*iterAmt: 0.01", + "*lineWidth: 0", + "*minScale: 0.6", + "*maxScale: 1.75", + "*minRadius: 3", + "*maxRadius: 25", + "*maxNerveRadius: 0.7", + "*nervousness: 0.3", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec nerverot_options [] = { + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-max-iters", ".maxIters", XrmoptionSepArg, 0 }, + { "-db", ".doubleBuffer", XrmoptionNoArg, "true" }, + { "-no-db", ".doubleBuffer", XrmoptionNoArg, "false" }, + { "-event-chance", ".eventChance", XrmoptionSepArg, 0 }, + { "-iter-amt", ".iterAmt", XrmoptionSepArg, 0 }, + { "-line-width", ".lineWidth", XrmoptionSepArg, 0 }, + { "-min-scale", ".minScale", XrmoptionSepArg, 0 }, + { "-max-scale", ".maxScale", XrmoptionSepArg, 0 }, + { "-min-radius", ".minRadius", XrmoptionSepArg, 0 }, + { "-max-radius", ".maxRadius", XrmoptionSepArg, 0 }, + { "-max-nerve-radius", ".maxNerveRadius", XrmoptionSepArg, 0 }, + { "-nervousness", ".nervousness", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("NerveRot", nerverot) diff --git a/non-wgl/nerverot.vcproj b/non-wgl/nerverot.vcproj new file mode 100644 index 0000000..781da60 --- /dev/null +++ b/non-wgl/nerverot.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/non-wgl.c b/non-wgl/non-wgl.c index 7877129..6883c98 100644 --- a/non-wgl/non-wgl.c +++ b/non-wgl/non-wgl.c @@ -1,10 +1,12 @@ -#include "xws2win.h" -#include "colors.h" +#include "xlockmore.h" BOOL InitPixelFormat(SCREENSAVER *ss) { ModeInfo *mi; - int i; + int i; + + ss->modeinfo.gc = XCreateGC(ss->hdc, 0, 0, NULL); + assert(ss->modeinfo.gc != NULL); if (hack_ncolors <= 0) hack_ncolors = 64; @@ -12,12 +14,24 @@ BOOL InitPixelFormat(SCREENSAVER *ss) hack_ncolors = MAX_COLORS; mi = &ss->modeinfo; + + mi->install_p = fChildPreview; + mi->writable_p = True; + mi->black_pixel = 0; + mi->white_pixel = 255; mi->npixels = hack_ncolors; mi->colors = NULL; mi->pixels = NULL; + mi->threed = False; + mi->threed_delta = 1.5; + mi->threed_right_color = load_color(NULL, 0, "red"); + mi->threed_left_color = load_color(NULL, 0, "blue"); + mi->threed_both_color = load_color(NULL, 0, "magenta"); + mi->threed_none_color = load_color(NULL, 0, "black"); + if (hack_ncolors_enabled) { mi->colors = (XColor *) calloc(mi->npixels, sizeof(*mi->colors)); @@ -80,7 +94,6 @@ void ss_term(void) hack_free(&ss.modeinfo); ReleaseDC(ss.hwnd, ss.hdc); DeleteObject(ss.hbmScreenShot); - ss.hbmScreenShot = NULL; } void ss_clear(Display *d) @@ -88,503 +101,8 @@ void ss_clear(Display *d) XClearWindow(d, 0); } -static void get_2_skewed_angles(double *skewed1, double *skewed2, - int width, int height, int angle1, int angle2) -{ -#define M_PI_PER_180_PER_64 (M_PI / 180.0 / 64.0) -#define M_PI_3_PER_2 (3.0 * M_PI / 2.0) - double radian1, radian2; - - angle1 = angle1 % (360 * 64); - angle2 = angle2 % (360 * 64); - angle2 += angle1; - radian1 = angle1 * M_PI_PER_180_PER_64; - radian2 = angle2 * M_PI_PER_180_PER_64; - *skewed1 = atan(tan(radian1) * width / height); - if (M_PI_2 <= radian1 && radian1 < M_PI_3_PER_2) - *skewed1 += M_PI; - else if (M_PI_3_PER_2 <= radian1 && radian1 <= M_2_PI) - *skewed1 += 2.0 * M_PI; - *skewed2 = atan(tan(radian2) * width / height); - if (M_PI_2 <= radian2 && radian2 < M_PI_3_PER_2) - *skewed2 += M_PI; - else if (M_PI_3_PER_2 <= radian2 && radian2 <= M_2_PI) - *skewed2 += M_2_PI; -} - -int XSetLineAttributes(Display *dpy, GC gc, - unsigned int line_width, int line_style, - int cap_style, int join_style) -{ - XGCValues *values; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - values->line_width = line_width; - values->line_style = line_style; - values->cap_style = cap_style; - values->join_style = join_style; - return 0; -} - -int XDrawPoint(Display *dpy, Drawable d, GC gc, - int x, int y) -{ - XGCValues *values; - COLORREF rgb; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - rgb = values->foreground_rgb; - SetPixel(dpy, x, y, rgb); - return 0; -} - -int XDrawPoints(Display *dpy, Drawable w, GC gc, - XPoint *points, int npoints, int CoordMode) -{ - XGCValues *values; - COLORREF rgb; - int i; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - rgb = values->foreground_rgb; - if (CoordMode == CoordModeOrigin) - { - for (i = 0; i < npoints; i++) - { - SetPixel(dpy, points[i].x, points[i].y, rgb); - } - } - else - { - int x = points[0].x, y = points[0].y; - SetPixel(dpy, x, y, rgb); - for (i = 1; i < npoints; i++) - { - x += points[i].x; - y += points[i].y; - SetPixel(dpy, x, y, rgb); - } - } - return 0; -} - -HPEN XCreateWinPen(XGCValues *values) -{ - LOGBRUSH lb; - lb.lbColor = values->foreground_rgb; - lb.lbStyle = BS_SOLID; - return ExtCreatePen( - values->line_style | values->cap_style | values->join_style, - values->line_width, &lb, 0, NULL); -} - -HBRUSH XCreateWinBrush(XGCValues *values) -{ - LOGBRUSH lb; - lb.lbColor = values->foreground_rgb; - lb.lbStyle = BS_SOLID; - return CreateBrushIndirect(&lb); -} - -HFONT XCreateWinFont(XGCValues *values) -{ - return (HFONT)GetStockObject(DEFAULT_GUI_FONT); -} - -int XDrawLine(Display *dpy, Drawable d, GC gc, - int x1, int y1, int x2, int y2) -{ - XGCValues *values; - HPEN hPen; - HGDIOBJ hPenOld; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hPen = XCreateWinPen(values); - if (hPen == NULL) - return BadAlloc; - - hPenOld = SelectObject(dpy, hPen); - MoveToEx(dpy, x1, y1, NULL); - LineTo(dpy, x2, y2); - SelectObject(dpy, hPenOld); - - DeleteObject(hPen); - return 0; -} - -int XDrawLines(Display *dpy, Drawable d, GC gc, - XPoint *points, int npoints, int mode) -{ - XGCValues *values; - LPPOINT lpPoints; - HPEN hPen; - HGDIOBJ hPenOld; - int i; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - lpPoints = (LPPOINT)calloc(npoints, sizeof(POINT)); - if (lpPoints == NULL) - return BadAlloc; - - if (mode == CoordModeOrigin) - { - for (i = 0; i < npoints; i++) - { - lpPoints[i].x = points[i].x; - lpPoints[i].y = points[i].y; - } - } - else - { - int x = points[0].x, y = points[0].y; - lpPoints[0].x = x; - lpPoints[0].y = y; - for (i = 1; i < npoints; i++) - { - x += points[i].x; - y += points[i].y; - lpPoints[i].x = x; - lpPoints[i].y = y; - } - } - - hPen = XCreateWinPen(values); - if (hPen == NULL) - return BadAlloc; - - hPenOld = SelectObject(dpy, hPen); - Polyline(dpy, lpPoints, npoints); - SelectObject(dpy, hPenOld); - - free(lpPoints); - DeleteObject(hPen); - return 0; -} - -int XDrawSegments(Display *dpy, Drawable d, GC gc, - XSegment *segments, int nsegments) -{ - XGCValues *values; - HPEN hPen; - HGDIOBJ hPenOld; - int i; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hPen = XCreateWinPen(values); - if (hPen == NULL) - return BadAlloc; - - hPenOld = SelectObject(dpy, hPen); - for (i = 0; i < nsegments; i++) - { - MoveToEx(dpy, segments[i].x1, segments[i].y1, NULL); - LineTo(dpy, segments[i].x2, segments[i].y2); - } - SelectObject(dpy, hPenOld); - - DeleteObject(hPen); - return 0; -} - -int XDrawArc(Display *dpy, Drawable d, GC gc, - int x, int y, unsigned int width, unsigned int height, - int angle1, int angle2) -{ - XGCValues *values; - HPEN hPen; - HGDIOBJ hPenOld; - double skewed1, skewed2; - int xStartArc, yStartArc, xEndArc, yEndArc; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hPen = XCreateWinPen(values); - if (hPen == NULL) - return BadAlloc; - - get_2_skewed_angles(&skewed1, &skewed2, width, height, angle1, angle2); - xStartArc = x + width / 2.0 + (width / 2.0) * cos(skewed1); - yStartArc = y + height / 2.0 + (height / 2.0) * sin(skewed1); - xEndArc = x + width / 2.0 + (width / 2.0) * cos(skewed2); - yEndArc = y + height / 2.0 + (height / 2.0) * sin(skewed2); - - hPenOld = SelectObject(dpy, hPen); - Arc(dpy, x, y, x + width, y + height, - xStartArc, yStartArc, xEndArc, yEndArc); - SelectObject(dpy, hPenOld); - - DeleteObject(hPen); - return 0; -} - -int XDrawString(Display *dpy, Drawable d, GC gc, - int x, int y, const char *string, int length) -{ - XGCValues *values; - HFONT hFont; - HGDIOBJ hFontOld; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hFont = XCreateWinFont(values); - if (hFont == NULL) - return BadAlloc; - - hFontOld = SelectObject(dpy, hFont); - TextOut(dpy, x, y, string, length); - SelectObject(dpy, hFontOld); - - DeleteObject(hFont); - return 0; -} - -int XDrawImageString(Display *dpy, Drawable d, GC gc, - int x, int y, const char *string, int length) -{ - assert(0); - return 0; -} - -int XFillRectangle( - Display *dpy, Drawable d, GC gc, - int x, int y, unsigned int width, unsigned int height) -{ - XGCValues *values; - HBRUSH hbr; - RECT rc; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hbr = XCreateWinBrush(values); - if (hbr == NULL) - return BadAlloc; - - SetRect(&rc, x, y, x + width, y + height); - FillRect(dpy, &rc, hbr); - DeleteObject(hbr); - return 0; -} - -int XFillRectangles( - Display *dpy, Drawable d, GC gc, - XRectangle *rectangles, int n_rects) -{ - XGCValues *values; - HBRUSH hbr; - RECT rc; - int i; - short x, y; - unsigned short width, height; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hbr = XCreateWinBrush(values); - if (hbr == NULL) - return BadAlloc; - - for (i = 0; i < n_rects; i++) - { - x = rectangles[i].x; - y = rectangles[i].x; - width = rectangles[i].width; - height = rectangles[i].height; - SetRect(&rc, x, y, x + width, y + height); - FillRect(dpy, &rc, hbr); - } - - DeleteObject(hbr); - return 0; -} - -int XFillPolygon(Display *dpy, Drawable d, GC gc, - XPoint *points, int n_points, int shape, int mode) -{ - XGCValues *values; - HBRUSH hbr; - HGDIOBJ hbrOld; - LPPOINT lpPoints; - INT i; - - assert(shape == Convex); - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - lpPoints = calloc(n_points, sizeof(POINT)); - if (lpPoints == NULL) - return BadAlloc; - - if (mode == CoordModeOrigin) - { - for (i = 0; i < n_points; i++) - { - lpPoints[i].x = points[i].x; - lpPoints[i].y = points[i].y; - } - } - else - { - int x = points[0].x, y = points[0].y; - lpPoints[0].x = x; - lpPoints[0].y = y; - for (i = 1; i < n_points; i++) - { - x += points[i].x; - y += points[i].y; - lpPoints[i].x = x; - lpPoints[i].y = y; - } - } - - hbr = XCreateWinBrush(values); - if (hbr == NULL) - { - free(lpPoints); - return BadAlloc; - } - - BeginPath(dpy); - Polygon(dpy, lpPoints, n_points); - EndPath(dpy); - hbrOld = SelectObject(dpy, hbr); - FillPath(dpy); - SelectObject(dpy, hbrOld); - - free(lpPoints); - DeleteObject(hbr); - return 0; -} - -int XFillArc(Display *dpy, Drawable d, GC gc, - int x, int y, unsigned int width, unsigned int height, - int angle1, int angle2) -{ - XGCValues *values; - HBRUSH hbr; - HGDIOBJ hbrOld; - double skewed1, skewed2; - int xStartArc, yStartArc, xEndArc, yEndArc; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hbr = XCreateWinBrush(values); - if (hbr == NULL) - return BadAlloc; - - get_2_skewed_angles(&skewed1, &skewed2, width, height, angle1, angle2); - xStartArc = x + width / 2.0 + (width / 2.0) * cos(skewed1); - yStartArc = y + height / 2.0 + (height / 2.0) * sin(skewed1); - xEndArc = x + width / 2.0 + (width / 2.0) * cos(skewed2); - yEndArc = y + height / 2.0 + (height / 2.0) * sin(skewed2); - - BeginPath(dpy); - Arc(dpy, x, y, x + width, y + height, - xStartArc, yStartArc, xEndArc, yEndArc); - EndPath(dpy); - hbrOld = SelectObject(dpy, hbr); - FillPath(dpy); - SelectObject(dpy, hbrOld); - - DeleteObject(hbr); - return 0; -} - -int XFillArcs(Display *dpy, Drawable d, GC gc, - XArc *arcs, int n_arcs) -{ - XGCValues *values; - HBRUSH hbr; - HGDIOBJ hbrOld; - int i, x, y; - unsigned int width, height; - short angle1, angle2; - double skewed1, skewed2; - int xStartArc, yStartArc, xEndArc, yEndArc; - - values = XGetGCValues0(gc); - if (values == NULL) - return BadGC; - - hbr = XCreateWinBrush(values); - if (hbr == NULL) - return BadAlloc; - - hbrOld = SelectObject(dpy, hbr); - for (i = 0; i < n_arcs; i++) - { - x = arcs[i].x; y = arcs[i].y; - width = arcs[i].width; height = arcs[i].height; - angle1 = arcs[i].angle1; angle2 = arcs[i].angle2; - - get_2_skewed_angles(&skewed1, &skewed2, width, height, angle1, angle2); - xStartArc = x + width / 2.0 + (width / 2.0) * cos(skewed1); - yStartArc = y + height / 2.0 + (height / 2.0) * sin(skewed1); - xEndArc = x + width / 2.0 + (width / 2.0) * cos(skewed2); - yEndArc = y + height / 2.0 + (height / 2.0) * sin(skewed2); - - BeginPath(dpy); - Arc(dpy, x, y, x + width, y + height, - xStartArc, yStartArc, xEndArc, yEndArc); - EndPath(dpy); - FillPath(dpy); - } - SelectObject(dpy, hbrOld); - - DeleteObject(hbr); - return 0; -} - -Status XGetWindowAttributes( - Display *dpy, - Window w, - XWindowAttributes *attr) +Status XGetWindowAttributes(Display *dpy, Window w, XWindowAttributes *attr) { *attr = ss.modeinfo.xgwa; return 0; } - -int XCopyArea(Display *dpy, - Drawable src_drawable, Drawable dst_drawable, GC gc, - int src_x, int src_y, - unsigned int width, unsigned int height, - int dst_x, int dst_y) -{ - assert(src_drawable == dst_drawable); - BitBlt(dpy, dst_x, dst_y, width, height, dpy, src_x, src_y, SRCCOPY); - return 0; -} - -int XSync(Display *dpy, Bool b) -{ - GdiFlush(); - return 0; -} diff --git a/non-wgl/pacman.c b/non-wgl/pacman.c new file mode 100644 index 0000000..235daeb --- /dev/null +++ b/non-wgl/pacman.c @@ -0,0 +1,1810 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* pacman --- Mr. Pacman and his ghost friends */ + +#if !defined( lint ) && !defined( SABER ) +static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore"; + +#endif + +/*- + * Copyright (c) 2002 by Edwin de Jong . + * + * 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: + * 25-Feb-2005: Added bonus dots. I am using a recursive back track algorithm + * to help the ghost find there way home. This also means that + * they do not know the shorts path. + * Jeremy English jhe@jeremyenglish.org + * 15-Aug-2004: Added support for pixmap pacman. + * Jeremy English jhe@jeremyenglish.org + * 11-Aug-2004: Added support for pixmap ghost. + * Jeremy English jhe@jeremyenglish.org + * 13-May-2002: Added -trackmouse feature thanks to code from 'maze.c'. + * splitted up code into several files. Retouched AI code, cleaned + * up code. + * 3-May-2002: Added AI to pacman and ghosts, slowed down ghosts. + * 26-Nov-2001: Random level generator added + * 01-Nov-2000: Allocation checks + * 04-Jun-1997: Compatible with xscreensaver + * + */ + +/* TODO: + 1. think of a better level generation algorithm +*/ + +#define STANDALONE +#define DEF_TRACKMOUSE "False" + +# define MODE_pacman +#define DELAY 10000 +#define SIZE_ 0 +#define NCOLORS 6 +# define DEFAULTS "*delay: 10000 \n" \ + "*size: 0 \n" \ + "*ncolors: 6 \n" \ + "*fpsTop: true \n" \ + "*fpsSolid: true \n" \ + +# define UNIFORM_COLORS +# define BRIGHT_COLORS +# define pacman_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +# include +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_pacman + +#include "pacman.h" +#include "pacman_ai.h" +#include "pacman_level.h" + +#if defined(USE_PIXMAP) /* computed in pacman.h */ +# include "images/pacman/ghost-u1.xpm" +# include "images/pacman/ghost-u2.xpm" +# include "images/pacman/ghost-r1.xpm" +# include "images/pacman/ghost-r2.xpm" +# include "images/pacman/ghost-l1.xpm" +# include "images/pacman/ghost-l2.xpm" +# include "images/pacman/ghost-d1.xpm" +# include "images/pacman/ghost-d2.xpm" +/* Used to clean up the dust left by wag. */ +# include "images/pacman/ghost-mask.xpm" +# include "images/pacman/pacman-u1.xpm" +# include "images/pacman/pacman-u2.xpm" +# include "images/pacman/pacman-r1.xpm" +# include "images/pacman/pacman-r2.xpm" +# include "images/pacman/pacman-l1.xpm" +# include "images/pacman/pacman-l2.xpm" +# include "images/pacman/pacman-d1.xpm" +# include "images/pacman/pacman-d2.xpm" +# include "images/pacman/pacman-0.xpm" +# include "images/pacman/ghost-s1.xpm" +# include "images/pacman/ghost-s2.xpm" +# include "images/pacman/ghost-sf1.xpm" +# include "images/pacman/ghost-sf2.xpm" +# include "images/pacman/eyes-l.xpm" +# include "images/pacman/eyes-r.xpm" +# include "images/pacman/eyes-u.xpm" +# include "images/pacman/eyes-d.xpm" +# include "images/pacman/pacman-ds1.xpm" +# include "images/pacman/pacman-ds2.xpm" +# include "images/pacman/pacman-ds3.xpm" +# include "images/pacman/pacman-ds4.xpm" +# include "images/pacman/pacman-ds5.xpm" +# include "images/pacman/pacman-ds6.xpm" +# include "images/pacman/pacman-ds7.xpm" +# include "images/pacman/pacman-ds8.xpm" +#endif + +static const struct +{ + int dx, dy; +} dirvecs[DIRVECS] = { { -1, 0}, + { 0, 1}, + { 1, 0}, + { 0, -1}}; + +Bool pacman_trackmouse = False; + +#ifdef DISABLE_INTERACTIVE +ENTRYPOINT ModeSpecOpt pacman_opts = { + 0, + (XrmOptionDescRec *) NULL, + 0, + (argtype *) NULL, + (OptionStruct *) NULL +}; +#else +static XrmOptionDescRec opts[] = { + {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"}, + {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"} +}; + +static argtype vars[] = { + {&pacman_trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool} +}; + +static OptionStruct desc[] = { + {"-/+trackmouse", "turn on/off the tracking of the mouse"} +}; + +ENTRYPOINT ModeSpecOpt pacman_opts = + { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, +desc }; +#endif + +#ifdef USE_MODULES +ModStruct pacman_description = { + "pacman", /* *cmdline_arg; */ + "init_pacman", /* *init_name; */ + "draw_pacman", /* *callback_name; */ + "release_pacman", /* *release_name; */ + "refresh_pacman", /* *refresh_name; */ + "change_pacman", /* *change_name; */ + (char *) NULL, /* *unused_name; */ + &pacman_opts, /* *msopts */ + 10000, 4, 1, 0, 64, 1.0, "", "Shows Pacman(tm)", 0, NULL +}; + +#endif + +pacmangamestruct *pacman_games = (pacmangamestruct *) NULL; + +static void repopulate (ModeInfo * mi); +static void drawlevel (ModeInfo * mi); + + +static void +free_pacman (Display * display, pacmangamestruct * pp) +{ + int dir, mouth, i, j, k; + + if (pp->ghosts != NULL) { + free (pp->ghosts); + pp->ghosts = (ghoststruct *) NULL; + } + if (pp->stippledGC != None) { + XFreeGC (display, pp->stippledGC); + pp->stippledGC = None; + } + for (i = 0; i < 4; i++) { + for (j = 0; j < MAXGDIR; j++) { + for (k = 0; k < MAXGWAG; k++) { + if (pp->ghostPixmap[i][j][k] != None) { + XFreePixmap (display, pp->ghostPixmap[i][j][k]); + pp->ghostPixmap[i][j][k] = None; + } + } + } + } + for (dir = 0; dir < 4; dir++) + for (mouth = 0; mouth < MAXMOUTH; mouth++) + if (pp->pacmanPixmap[dir][mouth] != None) { + XFreePixmap (display, pp->pacmanPixmap[dir][mouth]); + pp->pacmanPixmap[dir][mouth] = None; + } +} + +/* set pacman and the ghost in there starting positions, but don't draw a new + level */ +static void +reset_level (ModeInfo * mi, int n, int pac_init) +{ + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + unsigned int ghost; + + MI_CLEARWINDOW (mi); + drawlevel (mi); + + pp->gamestate = GHOST_DANGER; + + if ( pac_init ){ + pp->pacman.row = (LEVHEIGHT + JAILHEIGHT) / 2 - n; + pp->pacman.init_row = pp->pacman.row; + } + else{ + pp->pacman.row = pp->pacman.init_row; + } + pp->pacman.col = (LEVWIDTH / 2); + pp->pacman.nextrow = NOWHERE; + pp->pacman.nextcol = NOWHERE; + pp->pacman.cf = NOWHERE; + pp->pacman.rf = NOWHERE; + pp->pacman.oldcf = NOWHERE; + pp->pacman.oldrf = NOWHERE; + pp->pacman.oldlx = NOWHERE; + pp->pacman.oldly = NOWHERE; + pp->pacman.aistate = ps_eating; + pp->pacman.cur_trace = 0; + pp->pacman.roundscore = 0; + pp->pacman.speed = 4; + pp->pacman.lastturn = 0; + pp->pacman.delta.x = 0; + pp->pacman.delta.y = 0; + + for (ghost = 0; ghost < pp->nghosts; ghost++) { + pp->ghosts[ghost].col = (LEVWIDTH / 2); + pp->ghosts[ghost].row = (LEVHEIGHT / 2); + pp->ghosts[ghost].nextcol = NOWHERE; + pp->ghosts[ghost].nextrow = NOWHERE; + pp->ghosts[ghost].dead = 0; + pp->ghosts[ghost].lastbox = START; + pp->ghosts[ghost].cf = NOWHERE; + pp->ghosts[ghost].rf = NOWHERE; + pp->ghosts[ghost].oldcf = NOWHERE; + pp->ghosts[ghost].oldrf = NOWHERE; + pp->ghosts[ghost].aistate = inbox; + pp->ghosts[ghost].timeleft = ghost * 20; + pp->ghosts[ghost].speed = 3; + pp->ghosts[ghost].delta.x = 0; + pp->ghosts[ghost].delta.y = 0; + pp->ghosts[ghost].flash_scared = False; + pp->ghosts[ghost].wait_pos = False; + pacman_ghost_update (pp, &(pp->ghosts[ghost])); + } + pacman_update (mi, pp, &(pp->pacman)); +} + +static int +pacman_ghost_collision(unsigned int ghost, pacmangamestruct * pp) +{ + return (((pp->ghosts[ghost].nextrow == pp->pacman.nextrow) && + (pp->ghosts[ghost].nextcol == pp->pacman.nextcol)) || + ((pp->ghosts[ghost].nextrow == pp->pacman.row) && + (pp->ghosts[ghost].nextcol == pp->pacman.col) && + (pp->ghosts[ghost].row == pp->pacman.nextrow) && + (pp->ghosts[ghost].col == pp->pacman.nextcol))); +} + + +/* Checks for death of any ghosts/pacman and updates. It also makes a new + level if all ghosts are dead or all dots are eaten. */ +static void +check_death (ModeInfo * mi, pacmangamestruct * pp) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + unsigned int ghost; + + if (pp->pacman.aistate == ps_dieing) return; + + for (ghost = 0; ghost < pp->nghosts; ghost++) { + + /* The ghost have to be scared before you can kill them */ + if ( pacman_ghost_collision ( ghost, pp ) ) { + if (pp->ghosts[ghost].aistate == goingin) continue; + + if (pp->ghosts[ghost].aistate == hiding) { + pp->ghosts[ghost].dead = 1; + pp->ghosts[ghost].aistate = goingin; + pp->ghosts[ghost].wait_pos = True; + XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi)); + XFillRectangle (display, window, + pp->stippledGC, + pp->ghosts[ghost].cf, + pp->ghosts[ghost].rf, + pp->spritexs, pp->spriteys); + } + /* DIE PACMAN... */ + else { + pp->pacman.deaths++; + pp->pacman.aistate = ps_dieing; + + } + continue; + } + } +} + +/* Resets state of ghosts + pacman. Creates a new level, draws that level. */ +static void +repopulate (ModeInfo * mi) +{ + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + pp->pacman.deaths = 0; + reset_level (mi, pacman_createnewlevel (pp), True); + check_death (mi, pp); +} + +/* Sets the color to the color of a wall. */ +static void +setwallcolor (ModeInfo * mi) +{ + Display *display = MI_DISPLAY (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + + if (MI_NPIXELS (mi) > 2) + XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, BLUE)); + else + XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi)); +} + +/* Sets the color to the color of a dot. */ +static void +setdotcolor (ModeInfo * mi) +{ + Display *display = MI_DISPLAY (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + + XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi)); +} + +static void +cleardotcolor (ModeInfo * mi) +{ + Display *display = MI_DISPLAY (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + + XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi)); +} + +#if 0 +static void +draw_position (ModeInfo * mi, int x, int y, int color) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + XFontStruct *font = NULL; + char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*"; + char *s = NULL; + + font = XLoadQueryFont (display, f_name); + assert (font != NULL); + + s = (char *) malloc (256); + assert (s != NULL); + sprintf (s, "(%d,%d)", x, y); + XSetForeground (display, pp->stippledGC, color); + XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s)); + free (s); + free (font); +} +#endif +#if 0 +static void +draw_number (ModeInfo * mi, int x, int y, int num, int color) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + XFontStruct *font = NULL; + char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*"; + char *s = NULL; + + font = XLoadQueryFont (display, f_name); + assert (font != NULL); + + s = (char *) malloc (256); + assert (s != NULL); + sprintf (s, "%d", num); + XSetForeground (display, pp->stippledGC, color); + XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s)); + free (s); + free (font); +} +#endif + +#if 0 +/* draw_grid - draws a grid on top of the playing field. + * Used so that I can determine if I'm converting from rows and columns to x and y + * coordinates correctly. + */ +static void +draw_grid (ModeInfo * mi) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + int h = MI_HEIGHT (mi); + int w = MI_WIDTH (mi); + int y = 0; + int x = 0; + XSetForeground (display, pp->stippledGC, 0xff0000); + while (y < h) { + while (x < w) { + XDrawLine (display, window, pp->stippledGC, x, 0, x, h); + x += 10; + } + x = 0; + XDrawLine (display, window, pp->stippledGC, 0, y, w, y); + y += 10; + } +} +#endif + +#if 0 +static void +draw_string (ModeInfo * mi, int x, int y, char *s, int color) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + XFontStruct *font = NULL; + char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*"; + + font = XLoadQueryFont (display, f_name); + assert (font != NULL); + + assert (s != NULL); + XSetForeground (display, pp->stippledGC, color); + XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s)); + free (font); +} + +/* I think this function has a memory leak. Be careful if you enable it. */ +/* I only used it briefly to help me debug the ghost's aistate. It prints */ +/* the state of each ghost on the left hand side of the screen */ +static void +print_ghost_stats (ModeInfo *mi, ghoststruct *g , int ghost_num) +{ + char s[1024]; + + sprintf (s, "GHOST: %d", ghost_num ); + switch (g->aistate){ + case inbox: + sprintf (s, "%s inbox", s); + break; + case goingout: + sprintf (s, "%s goingout", s); + break; + case randdir: + sprintf (s, "%s randdir", s); + break; + case chasing: + sprintf (s, "%s chasing", s); + break; + case hiding: + sprintf (s, "%s hiding", s); + break; + case goingin: + sprintf (s, "%s goingin",s); + break; + } + draw_string (mi, 0, (ghost_num *3) *10+50, g->last_stat, 0x000000); + draw_string (mi, 0, (ghost_num *3) *10+50, s, 0xff0000); + strcpy(g->last_stat,s); +} + +/* prints the number of times pacman has died and his aistate on the left hand */ +/* side of the screen */ +static void +print_pac_stats ( ModeInfo *mi, pacmanstruct *pac ) +{ + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + char s[1024]; + sprintf (s, "Pacman, Deaths: %d", pac->deaths ); + switch ( pac->aistate ){ + case ps_eating: + sprintf(s, "%s ps_eating",s ); + break; + case ps_chasing: + sprintf(s, "%s ps_chasing",s ); + break; + case ps_hiding: + sprintf(s, "%s ps_hiding",s ); + break; + case ps_random: + sprintf(s, "%s ps_random",s ); + break; + case ps_dieing: + sprintf(s, "%s ps_dieing",s ); + break; + } + draw_string ( mi, 0, 200, pp->last_pac_stat, 0x000000); + draw_string ( mi, 0, 200, s, 0xff0000); + strcpy(pp->last_pac_stat, s ); +} + +#endif + +/*Ok, yeah whatever?*/ +/*dot_rc_to_pixel - magic that converts row and columns into + *the x and y coordinates of the screen. + */ +static void +dot_rc_to_pixel (ModeInfo * mi, int *x, int *y) +{ + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + *x = (pp->xs * *x) + + (pp->xs / 2) - (pp->xs > 32 ? (pp->xs / 16) : 1) + pp->xb; + *y = (pp->ys * *y) + + (pp->ys / 2) - (pp->ys > 32 ? (pp->ys / 16) : 1) + pp->yb; +} + +/* dot_width_height - magic used to get the width and height of + * a dot. This dot can also be scaled by a value. + */ +static void +dot_width_height (ModeInfo *mi, int *w, int *h) +{ + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + if (pp->xs > 32){ + *w = *h = (pp->xs / 32 ); + }else { + *w = *h = 1; + } +} + +static void +bonus_dot_width_height (ModeInfo *mi, int *w, int *h ) +{ + *w = *h = MI_HEIGHT (mi) / 65; +} + + + +static void +draw_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y, + void (*width_height)(ModeInfo * mi, int *w, int *h), + int (*arc_func) (Display * display, Drawable d, GC gc, + int x, int y, unsigned int width, + unsigned int height, int angle1, + int angle2)) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + int w, h; + dot_rc_to_pixel (mi, &x, &y); + width_height(mi, &w, &h); + (void) arc_func (display, window, pp->stippledGC, + x, y, w, h, 0, 23040); +} + +static void +draw_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y) +{ + int x2 = x; + int y2 = y; + setdotcolor (mi); + draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc); + dot_rc_to_pixel (mi, &x2, &y2); +#if 0 + draw_position (mi, x2, y2, 0xff0000); +#endif +} + +static void +clear_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y) +{ + cleardotcolor (mi); + draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc); +} + +static void +draw_regular_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y) +{ + setdotcolor (mi); + draw_dot (mi, pp, x, y, dot_width_height, XDrawArc); +} + +/* Draws a block in the level at the specified x and y locations. */ +static void +drawlevelblock (ModeInfo * mi, pacmangamestruct * pp, + const unsigned x, const unsigned y) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + int dx = 0, dy = 0; + + if (pp->xs % 2 == 1) + dx = -1; + if (pp->ys % 2 == 1) + dy = -1; + +#ifndef HAVE_COCOA + XSetFillStyle (display, pp->stippledGC, FillSolid); +#endif /* !HAVE_COCOA */ + XSetLineAttributes (display, pp->stippledGC, pp->wallwidth, + LineSolid, CapRound, JoinMiter); + + if (pp->xs < 2 || pp->ys < 2) { + switch (pp->level[y * LEVWIDTH + x]) { + case ' ': + case '=': + break; + case '.': + setdotcolor (mi); + (void) XDrawPoint (display, window, + pp->stippledGC, + x * pp->xs + pp->xb, y * pp->ys + pp->yb); + break; + default: + setwallcolor (mi); + (void) XDrawPoint (display, window, + pp->stippledGC, + x * pp->xs + pp->xb, y * pp->ys + pp->yb); + } + + return; + } + + switch (pp->level[y * LEVWIDTH + x]) { + case ' ': + case '=': + break; + + case '.': + setdotcolor (mi); + if (pp->xs < 8 || pp->ys < 8) { + (void) XDrawPoint (display, window, + pp->stippledGC, + x * pp->xs + pp->xb + + pp->xs / 2, y * pp->ys + pp->yb + pp->ys / 2); + break; + } + + draw_regular_dot (mi, pp, x, y); + break; + /* What we will probably want to do here is have the pp->level store a 'o' for + * the bonus dots. The we can use the drawing routine above just with a bigger + * radius. + */ + case 'o': + draw_bonus_dot (mi, pp, x, y); + break; + + + case '-': + setwallcolor (mi); + (void) XDrawLine (display, window, pp->stippledGC, + (pp->xs * x) + pp->xb, + (pp->ys * y) + (pp->ys / 2) + pp->yb, + (pp->xs * (x + 1)) + pp->xb, + (pp->ys * y) + (pp->ys / 2) + pp->yb); + break; + + case '|': + setwallcolor (mi); + (void) XDrawLine (display, window, pp->stippledGC, + (pp->xs * x) + (pp->xs / 2) + pp->xb, + (pp->ys * y) + pp->yb, + (pp->xs * x) + (pp->xs / 2) + pp->xb, + (pp->ys * (y + 1)) + pp->yb); + break; + + case '_': + setwallcolor (mi); + (void) XDrawArc (display, window, pp->stippledGC, + (pp->xs * x) - (pp->ys / 2) + pp->xb + dx, + (pp->ys * y) + (pp->ys / 2) + pp->yb, + pp->xs, pp->ys, 0 * 64, 90 * 64); + break; + + case ',': + setwallcolor (mi); + (void) XDrawArc (display, window, pp->stippledGC, + (pp->xs * x) + (pp->ys / 2) + pp->xb, + (pp->ys * y) + (pp->ys / 2) + pp->yb, + pp->xs, pp->ys, 90 * 64, 90 * 64); + break; + + case '`': + setwallcolor (mi); + (void) XDrawArc (display, window, pp->stippledGC, + (pp->xs * x) + (pp->ys / 2) + pp->xb, + (pp->ys * y) - (pp->ys / 2) + pp->yb + dy, + pp->xs, pp->ys, 180 * 64, 90 * 64); + break; + + case '\'': + setwallcolor (mi); + (void) XDrawArc (display, window, pp->stippledGC, + (pp->xs * x) - (pp->ys / 2) + pp->xb + dx, + (pp->ys * y) - (pp->ys / 2) + pp->yb + dy, + pp->xs, pp->ys, 270 * 64, 90 * 64); + break; + + } +} + +/* Draws a complete level. */ +static void +drawlevel (ModeInfo * mi) +{ + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + unsigned int x, y; + + for (y = 0; y < LEVHEIGHT; y++) + for (x = 0; x < LEVWIDTH; x++) + drawlevelblock (mi, pp, x, y); +} + +/* There is some overlap so it can be made more efficient */ +#define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \ + if (yly) \ + (y>(yl-(ys)))?XFillRectangle(d,w,g,xl,y+ys,xs,yl-(y)): \ + XFillRectangle(d,w,g,xl,yl,xs,ys); \ + if (xlx) \ + (x>(xl-(xs)))?XFillRectangle(d,w,g,x+xs,yl,xl-(x),ys): \ + XFillRectangle(d,w,g,xl,yl,xs,ys) + + +/* Draws the pacman sprite, removing the previous location. */ +#if defined(USE_PIXMAP) + +static void +draw_pacman_sprite (ModeInfo * mi) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + unsigned int dir = 0; + int old_mask_dir = 0; + int old_mask_mouth = 0; + Pixmap old_mask, new_mask; + Pixmap pacman; + +#define MAX_MOUTH_DELAY 2 +#define MAX_DEATH_DELAY 20 + + if (pp->pacman.aistate == ps_dieing){ + pp->pacman.cf = pp->pacman.oldcf; + pp->pacman.rf = pp->pacman.oldrf; + } + else { + pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x * + pp->pacman.cfactor + pp->xb + pp->spritedx; + pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y * + pp->pacman.rfactor + pp->yb + pp->spritedy; + } + + dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) + + ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4; + + if (pp->pm_mouth_delay == MAX_MOUTH_DELAY) { + if (pp->pm_mouth == (MAXMOUTH - 1) || pp->pm_mouth == 0) { + pp->pm_open_mouth = !pp->pm_open_mouth; + } + pp->pm_open_mouth ? pp->pm_mouth++ : pp->pm_mouth--; + pp->pm_mouth_delay = 0; + } + else { + pp->pm_mouth_delay++; + } + + if (pp->pacman.aistate == ps_dieing){ + if (pp->pm_death_frame >= PAC_DEATH_FRAMES) { + pp->pacman.aistate = ps_eating; + pp->pm_death_frame = 0; + pp->pm_death_delay = 0; + reset_level (mi, 0, False); + return; + } + else { + old_mask = pp->pacmanMask[0][0]; + new_mask = pp->pacmanMask[0][0]; + pacman = pp->pacman_ds[pp->pm_death_frame]; + if (pp->pm_death_delay == MAX_DEATH_DELAY){ + pp->pm_death_frame++; + pp->pm_death_delay = 0; + } + else{ + pp->pm_death_delay++; + } + } + } + else{ + old_mask = pp->pacmanMask[old_mask_dir][old_mask_mouth]; + new_mask = pp->pacmanMask[dir][pp->pm_mouth]; + pacman = pp->pacmanPixmap[dir][pp->pm_mouth]; + } + + XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi)); + + XSetClipMask (display, pp->stippledGC, old_mask); + + XSetClipOrigin (display, pp->stippledGC, pp->pacman.oldcf, + pp->pacman.oldrf); + XFillRectangle (display, window, pp->stippledGC, pp->pacman.oldcf, + pp->pacman.oldrf, pp->spritexs, pp->spriteys); + XSetClipMask (display, pp->stippledGC, new_mask); + XSetClipOrigin (display, pp->stippledGC, pp->pacman.cf, pp->pacman.rf); + XCopyArea (display, pacman, window, + pp->stippledGC, 0, 0, pp->spritexs, pp->spriteys, + pp->pacman.cf, pp->pacman.rf); + XSetClipMask (display, pp->stippledGC, None); + if (pp->pacman.aistate != ps_dieing){ + pp->pacman.oldcf = pp->pacman.cf; + pp->pacman.oldrf = pp->pacman.rf; + } +} + +#if 0 +static void +draw_ghost_position (ModeInfo * mi, ghoststruct * ghost) +{ + draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi)); + draw_position (mi, ghost->cf, ghost->rf, 0x00ff00); +} +#endif +#if 0 +static void +draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost) +{ + draw_number (mi, ghost->oldcf, ghost->oldrf, ghost->oldndirs, MI_BLACK_PIXEL (mi)); + ghost->oldndirs = ghost->ndirs; + draw_number (mi, ghost->cf, ghost->rf, ghost->ndirs, 0x00ff00); +} + +#endif + +static void +draw_ghost_sprite (ModeInfo * mi, const unsigned ghost) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; +#define MAX_WAG_COUNT 50 + unsigned int dir = 0; + unsigned int fs = 0; /*flash scared*/ + Pixmap g_pix; /*ghost pixmap*/ + + + dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) + + ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4; + + + fs = pp->ghosts[ghost].flash_scared; + assert (fs == 0 || fs == 1); + + /* Choose the pixmap */ + switch (pp->ghosts[ghost].aistate){ + case hiding: + g_pix = pp->s_ghostPixmap[fs][pp->gh_wag]; + break; + case goingin: + g_pix = pp->ghostEyes[dir]; +#if 1 + { + int i = 0; + while ( i < pp->ghosts[ghost].trace_idx ){ + XFillRectangle (display, + window, + pp->stippledGC, + pp->ghosts[ghost].trace[i].vx, + pp->ghosts[ghost].trace[i].vy, + pp->spritexs, pp->spriteys); + + i++; + } + } +#endif + + break; + default: + g_pix = pp->ghostPixmap[ghost][dir][pp->gh_wag]; + } + + pp->ghosts[ghost].cf = + pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x * + pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx; + pp->ghosts[ghost].rf = + pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y * + pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy; + + XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi)); + + XSetClipMask (display, pp->stippledGC, pp->ghostMask); + XSetClipOrigin (display, pp->stippledGC, + pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf); + XFillRectangle (display, + window, + pp->stippledGC, + pp->ghosts[ghost].oldcf, + pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys); + + + if (pp->pacman.aistate != ps_dieing) { + drawlevelblock (mi, pp, + (unsigned int) pp->ghosts[ghost].col, + (unsigned int) pp->ghosts[ghost].row); + + + + XSetClipOrigin (display, pp->stippledGC, + pp->ghosts[ghost].cf, pp->ghosts[ghost].rf); + + XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0, + pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf, + pp->ghosts[ghost].rf); + } + XSetClipMask (display, pp->stippledGC, None); + +#if 0 + draw_ghost_position (mi, &(pp->ghosts[ghost])); +#endif + +#if 0 + draw_ghost_ndirs ( mi, &(pp->ghosts[ghost])); +#endif + + if (pp->pacman.aistate != ps_dieing) { + pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf; + pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf; + if (pp->gh_wag_count++ == MAX_WAG_COUNT) { + pp->gh_wag = !pp->gh_wag; + pp->gh_wag_count = 0; + } + } +} + +#else /* USE_PIXMAP */ + +/* Draws the pacman sprite, removing the previous location. */ +static void +draw_pacman_sprite (ModeInfo * mi) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + unsigned int dir; + + pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x * + pp->pacman.cfactor + pp->xb + pp->spritedx; + pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y * + pp->pacman.rfactor + pp->yb + pp->spritedy; + + dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) + + ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4; + + XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi)); + if (pp->pacman.oldcf != NOWHERE && pp->pacman.oldrf != NOWHERE) { + + ERASE_IMAGE (display, window, pp->stippledGC, + pp->pacman.cf, pp->pacman.rf, + pp->pacman.oldcf, pp->pacman.oldrf, + pp->spritexs, pp->spriteys); + } + + if (MI_NPIXELS (mi) > 2) + XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, YELLOW)); + else + XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi)); + + XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled); + + if (pp->xs < 2 || pp->ys < 2) + XDrawPoint (display, window, pp->stippledGC, + pp->pacman.cf, pp->pacman.rf); + else + XFillRectangle (display, window, pp->stippledGC, + pp->pacman.cf, pp->pacman.rf, + pp->spritexs, pp->spriteys); + pp->pacman.mouthstage += pp->pacman.mouthdirection; + if ((pp->pacman.mouthstage >= MAXMOUTH) || (pp->pacman.mouthstage < 0)) { + pp->pacman.mouthdirection *= -1; + pp->pacman.mouthstage += pp->pacman.mouthdirection * 2; + } + pp->pacman.oldcf = pp->pacman.cf; + pp->pacman.oldrf = pp->pacman.rf; +} + +/* Draws a ghost sprite, removing the previous sprite and restores the level. */ +static void +draw_ghost_sprite (ModeInfo * mi, const unsigned ghost) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + + pp->ghosts[ghost].cf = + pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x * + pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx; + pp->ghosts[ghost].rf = + pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y * + pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy; + + XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi)); + XFillRectangle (display, + window, + pp->stippledGC, + pp->ghosts[ghost].cf, + pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys); + + if (pp->ghosts[ghost].oldcf != NOWHERE || + pp->ghosts[ghost].oldrf != NOWHERE) { + + ERASE_IMAGE (display, window, pp->stippledGC, + pp->ghosts[ghost].cf, pp->ghosts[ghost].rf, + pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf, + pp->spritexs, pp->spriteys); + } + + drawlevelblock (mi, pp, + (unsigned int) pp->ghosts[ghost].col, + (unsigned int) pp->ghosts[ghost].row); + + if (MI_NPIXELS (mi) > 2) + XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, GREEN)); + else + XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi)); + + XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled); + + if (pp->xs < 2 || pp->ys < 2) + XDrawPoint (display, window, pp->stippledGC, + pp->ghosts[ghost].cf, pp->ghosts[ghost].rf); + else + XFillRectangle (display, + window, + pp->stippledGC, + pp->ghosts[ghost].cf, + pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys); + + pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf; + pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf; +} +#endif /* USE_PIXMAP */ + +static int +ghost_over (ModeInfo * mi, int x, int y) +{ + int ghost = 0; + int ret = False; + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + dot_rc_to_pixel (mi, &x, &y); + for (ghost = 0; ghost < pp->nghosts; ghost++) { + if ((pp->ghosts[ghost].cf <= x + && x <= pp->ghosts[ghost].cf + pp->spritexs) + && (pp->ghosts[ghost].rf <= y + && y <= pp->ghosts[ghost].rf + pp->spriteys)) { + ret = True; + break; + } + } + return ret; +} + + +static void +flash_bonus_dots (ModeInfo * mi) +{ +#define MAX_FLASH_COUNT 25 + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + int i, x, y; + for (i = 0; i < NUM_BONUS_DOTS; i++) { + if (!pacman_bonus_dot_eaten (pp, i)) { + pacman_bonus_dot_pos (pp, i, &x, &y); + if (ghost_over (mi, x, y)) + continue; + if (pp->bd_on) + draw_bonus_dot (mi, pp, x, y); + else + clear_bonus_dot (mi, pp, x, y); + } + } + if (pp->bd_flash_count-- == 0) { + pp->bd_flash_count = MAX_FLASH_COUNT; + pp->bd_on = !pp->bd_on; + } +} + +static unsigned int +ate_bonus_dot (ModeInfo * mi) +{ + /*Check pacman's position. If it is over a bonus dot and that dot + *has not been eaten, then return true + */ + unsigned int ret = 0; + int idx = 0; + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + if (pacman_is_bonus_dot (pp, pp->pacman.col, pp->pacman.row, &idx)) { + ret = !pacman_bonus_dot_eaten (pp, idx); + pacman_eat_bonus_dot (pp, idx); + } + return ret; +} + +static void +ghost_scared (ModeInfo * mi) +{ + unsigned int ghost; + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + for (ghost = 0; ghost < pp->nghosts; ghost++) { + if (pp->ghosts[ghost].aistate == goingin || + pp->ghosts[ghost].aistate == goingout || + pp->ghosts[ghost].aistate == inbox ) continue; + pp->ghosts[ghost].aistate = hiding; + pp->ghosts[ghost].flash_scared = 0; + if (pp->pacman.aistate != ps_dieing) + pp->pacman.aistate = ps_chasing; + } +} + +static void +ghost_not_scared (ModeInfo * mi) +{ + unsigned int ghost; + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + for (ghost = 0; ghost < pp->nghosts; ghost++){ + if (pp->ghosts[ghost].aistate == goingin || + pp->ghosts[ghost].aistate == goingout || + pp->ghosts[ghost].aistate == inbox ) continue; + pp->ghosts[ghost].aistate = chasing; + } + if (pp->pacman.aistate != ps_dieing) + pp->pacman.aistate = ps_eating; + +} + +static void +ghost_flash_scared (ModeInfo * mi) +{ + unsigned int ghost; + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + for (ghost = 0; ghost < pp->nghosts; ghost++) + pp->ghosts[ghost].flash_scared = !pp->ghosts[ghost].flash_scared; +} + +/* Does all drawing of moving sprites in the level. */ +static void +pacman_tick (ModeInfo * mi) +{ +#define DEFAULT_SCARED_TIME 500 +#define START_FLASH 200 +#define FLASH_COUNT 25 + + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + unsigned int ghost; +#if 0 + draw_grid (mi); +#endif + for (ghost = 0; ghost < pp->nghosts; ghost++) { + draw_ghost_sprite (mi, ghost); +#if 0 + print_ghost_stats (mi, &(pp->ghosts[ghost]), ghost); +#endif + } +#if 0 + print_pac_stats (mi, &(pp->pacman)); +#endif + draw_pacman_sprite (mi); + flash_bonus_dots (mi); + if (ate_bonus_dot (mi)) { + pp->ghost_scared_timer = (random () % 100) + DEFAULT_SCARED_TIME; + ghost_scared (mi); + } + + if (pp->ghost_scared_timer > 0) { + if (--pp->ghost_scared_timer == 0) + ghost_not_scared (mi); + else if (pp->ghost_scared_timer <= START_FLASH) { + if (pp->flash_timer <= 0) { + pp->flash_timer = FLASH_COUNT; + ghost_flash_scared (mi); + } + pp->flash_timer--; + } + } + + /* + We don't want to miss the last death sequence. So if pacman has died three times + we wait for his state to change from dieing to something else before we repopulate + the level. If pacman ate all of the dots then we just repopulate. + */ + + if (pp->dotsleft == 0 ) + repopulate (mi); + else if (pp->pacman.deaths >= 3){ + if (pp->old_pac_state == ps_dieing && pp->pacman.aistate != ps_dieing) + repopulate (mi); + } + + pp->old_pac_state = pp->pacman.aistate; +} + + +/* CODE TO LOAD AND SCALE THE PIXMAPS + */ + +#if defined(USE_PIXMAP) +/* Grabbed the scaling routine off of usenet. + * Changed it so that the information specific + * to the source pixmap does not have to be a parameter. + * + * There is probably a better way to scale pixmaps. + * From: Chris Fiddyment (cxf@itd.dsto.gov.au) + * Subject: Scaling Pixmap Algorithm. + * Newsgroups: comp.graphics.algorithms + * Date: 1994-07-06 18:51:38 PST + * -jeremy + */ + +static Pixmap +scale_pixmap (Display ** dpy, GC gc, Pixmap source, int dwidth, int dheight) +{ + Pixmap temp, dest; + int j, end; + float i; + float xscale, yscale; + unsigned int swidth, sheight; + Window window; + int x, y; + unsigned border_width_return, depth; + XGetGeometry (*dpy, source, &window, &x, &y, &swidth, &sheight, + &border_width_return, &depth); + + xscale = (float) swidth / (float) dwidth; /* Scaling factors */ + yscale = (float) sheight / (float) dheight; + + dest = XCreatePixmap (*dpy, window, dwidth, dheight, depth); + if (!dest) { + fprintf (stderr, "%s Could not scale image", progname); + } + temp = XCreatePixmap (*dpy, window, dwidth, sheight, depth); + if (!temp) { + fprintf (stderr, "%s Could not scale image", progname); + } + + j = 0; + end = dwidth * xscale; + /* Scale width of source into temp pixmap */ + for (i = 0; i <= end; i += xscale) + XCopyArea (*dpy, source, temp, gc, i, 0, 1, sheight, j++, 0); + + j = 0; + end = dheight * yscale; + /* Scale height of temp into dest pixmap */ + for (i = 0; i <= end; i += yscale) + XCopyArea (*dpy, temp, dest, gc, 0, i, swidth, 1, 0, j++); + + XFreePixmap (*dpy, temp); + return (Pixmap) dest; +} + +static void +pacman_fail (char *s) +{ + fprintf (stderr, "%s: %s\n", progname, s); + exit (1); +} + +/* Load the ghost pixmaps and their mask. */ +static void +load_ghost_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps) +{ + pacmangamestruct *pp = *ps; + Display *display = *dpy; + char *colors[] = { + ". c #FF0000", /*Red */ + ". c #00FFDE", /*Blue */ + ". c #FFB847", /*Orange */ + ". c #FFB8DE", /*Pink */ + }; + + char **bits[] = { + ghost_u1_xpm, ghost_u2_xpm, ghost_r1_xpm, ghost_r2_xpm, + ghost_d1_xpm, ghost_d2_xpm, ghost_l1_xpm, ghost_l2_xpm + }; + char * const *s_bits[] = { + ghost_s1_xpm, ghost_s2_xpm, + ghost_sf1_xpm, ghost_sf2_xpm + }; + char * const *e_bits[] = { + eyes_u_xpm, eyes_r_xpm, eyes_d_xpm, eyes_l_xpm + }; + + int i, j, k, m; + int w = pp->spritexs; + int h = pp->spriteys; + GC gc = 0; + Pixmap temp; + + for (i = 0; i < 4; i++) { + m = 0; + for (j = 0; j < MAXGDIR; j++) { + for (k = 0; k < MAXGWAG; k++) { + bits[m][2] = colors[i]; + pp->ghostPixmap[i][j][k] = + xpm_data_to_pixmap (display, window, bits[m], &w, &h, + &pp->ghostMask); + + if (!pp->ghostPixmap[i][j][k]) + pacman_fail ("Cannot load ghost images"); + + pp->ghostPixmap[i][j][k] = + scale_pixmap (&display, pp->stippledGC, + pp->ghostPixmap[i][j][k], pp->spritexs, + pp->spriteys); + + if (!pp->ghostPixmap[i][j][k]) + pacman_fail ("Cannot scale ghost images"); + m++; + } + } + } + /* load the scared ghost */ + m = 0; + for (i = 0; i < MAXGFLASH; i++) { + for (j = 0; j < MAXGWAG; j++) { + pp->s_ghostPixmap[i][j] = + xpm_data_to_pixmap (display, window, s_bits[m++], &w, &h, + &pp->ghostMask); + + if (!pp->s_ghostPixmap[i][j]) + pacman_fail ("Cannot Scare Ghost images"); + pp->s_ghostPixmap[i][j] = scale_pixmap (&display, pp->stippledGC, + pp->s_ghostPixmap[i][j], + pp->spritexs, + pp->spriteys); + + if (!pp->s_ghostPixmap[i][j]) + pacman_fail ("Cannot scale Scared Ghost images"); + } + } + /* load the ghost eyes */ + for (i = 0; i < MAXGDIR; i++) { + pp->ghostEyes[i] = + xpm_data_to_pixmap (display, window, e_bits[i], &w, &h, + &pp->ghostMask); + + if (!pp->ghostEyes[i]) + pacman_fail ("Cannot open ghost eye images"); + + pp->ghostEyes[i] = scale_pixmap (&display, pp->stippledGC, + pp->ghostEyes[i], + pp->spritexs, + pp->spriteys); + + if (!pp->ghostEyes[i]) + pacman_fail ("Cannot open ghost eye images"); + } + + + + /* We really only need a single mask. This saves the headache of getting the + * bottom of the ghost to clip just right. What we'll do is mask + * the top portion of the ghost, but the bottom of the ghost will be solid. + * I did this by setting the pixels between the fringe of their sheets + * to black instead of none. -jeremy + */ + temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm, + &w, &h, &pp->ghostMask); + + if (!temp) + pacman_fail ("Cannot load temporary ghost image"); + + temp = scale_pixmap (&display, pp->stippledGC, + temp, pp->spritexs, pp->spriteys); + + if (!temp) + pacman_fail ("Cannot scale temporary ghost image"); + + gc = XCreateGC (display, pp->ghostMask, 0, 0); + + pp->ghostMask = scale_pixmap (&display, gc, pp->ghostMask, + pp->spritexs, pp->spriteys); + XFreePixmap (display, temp); +} + +/* Load the pacman pixmaps and their mask. */ +static void +load_pacman_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps) +{ + pacmangamestruct *pp = *ps; + Display *display = *dpy; + + char **bits[] = { + pacman_0_xpm, pacman_u1_xpm, pacman_u2_xpm, + pacman_0_xpm, pacman_r1_xpm, pacman_r2_xpm, + pacman_0_xpm, pacman_d1_xpm, pacman_d2_xpm, + pacman_0_xpm, pacman_l1_xpm, pacman_l2_xpm + }; + + char * const *ds_bits[] = { + pacman_ds1_xpm, pacman_ds2_xpm, pacman_ds3_xpm, pacman_ds4_xpm, + pacman_ds5_xpm, pacman_ds6_xpm, pacman_ds7_xpm, pacman_ds8_xpm + }; + + int i, j, m; + int w = pp->spritexs; + int h = pp->spriteys; + GC gc = 0; + + m = 0; + for (i = 0; i < 4; i++) { + for (j = 0; j < MAXMOUTH; j++) { + pp->pacmanPixmap[i][j] = + xpm_data_to_pixmap (display, window, bits[m++], &w, &h, + &pp->pacmanMask[i][j]); + + if (!pp->pacmanPixmap[i][j]) + pacman_fail ("Cannot load pacman pixmap."); + + pp->pacmanPixmap[i][j] = scale_pixmap (&display, pp->stippledGC, + pp->pacmanPixmap[i][j], + pp->spritexs, + pp->spriteys); + + if (!pp->pacmanPixmap[i][j]) + pacman_fail ("Cannot scale pacman pixmap."); + + if (!gc) + gc = XCreateGC (display, pp->pacmanMask[i][j], 0, 0); + + pp->pacmanMask[i][j] = + scale_pixmap (&display, gc, pp->pacmanMask[i][j], + pp->spritexs, pp->spriteys); + } + } + + /* Load pacman death sequence */ + for ( i = 0; i < PAC_DEATH_FRAMES; i++ ){ + pp->pacman_ds[i] = + xpm_data_to_pixmap (display, window, ds_bits[i], &w, &h, + &pp->pacman_ds_mask[i]); + + if (!pp->pacman_ds[i]) + pacman_fail ("Cannot load pacman death frame."); + + pp->pacman_ds[i] = scale_pixmap ( &display, pp->stippledGC, + pp->pacman_ds[i], + pp->spritexs, + pp->spriteys); + + if (!pp->pacman_ds[i]) + pacman_fail ("Cannot scale pixmap."); + + if (!gc) + gc = XCreateGC (display, pp->pacman_ds_mask[i], 0, 0); + + pp->pacman_ds_mask[i] = + scale_pixmap (&display, gc, pp->pacman_ds_mask[i], + pp->spritexs, pp->spriteys); + } + +} +#endif /* USE_PIXMAP */ + +/* Hook function, sets state to initial position. */ +ENTRYPOINT void +init_pacman (ModeInfo * mi) +{ + Display *display = MI_DISPLAY (mi); + Window window = MI_WINDOW (mi); + int size = MI_SIZE (mi); + pacmangamestruct *pp; + XGCValues gcv; + int i, j, k; + +#if (! defined( USE_PIXMAP )) + GC fg_gc, bg_gc; + XPoint points[9]; + int dir, mouth; +#endif + + if (pacman_games == NULL) { + if ((pacman_games = (pacmangamestruct *) + calloc ((size_t) MI_NUM_SCREENS (mi), + sizeof (pacmangamestruct))) == NULL) + return; + } + pp = &pacman_games[MI_SCREEN (mi)]; + + pp->width = (unsigned short) MI_WIDTH (mi); + pp->height = (unsigned short) MI_HEIGHT (mi); + for (i = 0; i < 4; i++) { + for (j = 0; j < MAXGDIR; j++) { + for (k = 0; k < MAXGWAG; k++) { + if (pp->ghostPixmap[i][j][k] != None) { + XFreePixmap (display, pp->ghostPixmap[i][j][k]); + pp->ghostPixmap[i][j][k] = None; + pp->graphics_format = 0 /*IS_NONE */ ; + } + } + } + } + + for (i = 0; i < MAXGFLASH; i++) { + for (j = 0; j < MAXGWAG; j++) { + if (pp->s_ghostPixmap[i][j] != None) { + XFreePixmap (display, pp->s_ghostPixmap[i][j]); + pp->s_ghostPixmap[i][j] = None; + } + } + } + + if (size == 0 || + MINGRIDSIZE * size > (int) pp->width || + MINGRIDSIZE * size > (int) pp->height) { + + pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH, + pp->height / LEVHEIGHT), 1); + } + else { + if (size < -MINSIZE) + pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE, + MIN (pp->width, + pp->height) / + MINGRIDSIZE)) + - MINSIZE + 1) + MINSIZE); + else if (size < MINSIZE) + pp->ys = MINSIZE; + else + pp->ys = (short) (MIN (size, + MAX (MINSIZE, MIN (pp->width, pp->height) / + MINGRIDSIZE))); + pp->xs = pp->ys; + } + + pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4; + if (pp->wallwidth < 1) + pp->wallwidth = 1; + pp->incx = (pp->xs >> 3) + 1; + pp->incy = (pp->ys >> 3) + 1; + pp->ncols = (unsigned short) MAX (LEVWIDTH, 2); + pp->nrows = (unsigned short) MAX (LEVHEIGHT, 2); + pp->xb = (pp->width - pp->ncols * pp->xs) >> 1; + pp->yb = (pp->height - pp->nrows * pp->ys) >> 1; + pp->spritexs = MAX (pp->xs + (pp->xs >> 1) - 1, 1); + pp->spriteys = MAX (pp->ys + (pp->ys >> 1) - 1, 1); + pp->spritedx = (pp->xs - pp->spritexs) >> 1; + pp->spritedy = (pp->ys - pp->spriteys) >> 1; + pp->old_pac_state = ps_chasing; + + if (!pp->stippledGC) { + gcv.foreground = MI_BLACK_PIXEL (mi); + gcv.background = MI_BLACK_PIXEL (mi); + if ((pp->stippledGC = XCreateGC (display, window, + GCForeground | GCBackground, + &gcv)) == None) { + free_pacman (display, pp); + return; + } + } + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (display, pp->stippledGC, False); +#endif + +#if defined(USE_PIXMAP) + load_ghost_pixmaps (&display, window, &pp); + load_pacman_pixmaps (&display, window, &pp); +#else + if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window, + pp->spritexs, pp->spriteys, + 1)) == None) { + free_pacman (display, pp); + return; + } + + gcv.foreground = 0; + gcv.background = 1; + if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0], + GCForeground | GCBackground, &gcv)) == None) { + free_pacman (display, pp); + return; + } + + gcv.foreground = 1; + gcv.background = 0; + if ((fg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0], + GCForeground | GCBackground, &gcv)) == None) { + XFreeGC (display, bg_gc); + free_pacman (display, pp); + return; + } + +#define SETPOINT(p, xp, yp) p.x = xp; p.y = yp + + /* draw the triangles on the bottom (scalable) */ + SETPOINT (points[0], 1, pp->spriteys * 5 / 6); + SETPOINT (points[1], pp->spritexs / 6, pp->spriteys); + SETPOINT (points[2], pp->spritexs / 3, pp->spriteys * 5 / 6); + SETPOINT (points[3], pp->spritexs / 2, pp->spriteys); + SETPOINT (points[4], pp->spritexs * 2 / 3, pp->spriteys * 5 / 6); + SETPOINT (points[5], pp->spritexs * 5 / 6, pp->spriteys); + SETPOINT (points[6], pp->spritexs, pp->spriteys * 5 / 6); + SETPOINT (points[7], pp->spritexs, pp->spriteys / 2); + SETPOINT (points[8], 1, pp->spriteys / 2); + + XFillRectangle (display, pp->ghostPixmap[0][0][0], bg_gc, + 0, 0, pp->spritexs, pp->spriteys); + XFillArc (display, pp->ghostPixmap[0][0][0], fg_gc, + 0, 0, pp->spritexs, pp->spriteys, 0, 11520); + XFillPolygon (display, pp->ghostPixmap[0][0][0], fg_gc, + points, 9, Nonconvex, CoordModeOrigin); + XFreeGC (display, bg_gc); + XFreeGC (display, fg_gc); + + + if (pp->pacmanPixmap[0][0] != None) + for (dir = 0; dir < 4; dir++) + for (mouth = 0; mouth < MAXMOUTH; mouth++) + XFreePixmap (display, pp->pacmanPixmap[dir] + [mouth]); + + for (dir = 0; dir < 4; dir++) + for (mouth = 0; mouth < MAXMOUTH; mouth++) { + if ((pp->pacmanPixmap[dir][mouth] = + XCreatePixmap (display, MI_WINDOW (mi), pp->spritexs, + pp->spriteys, 1)) == None) { + free_pacman (display, pp); + return; + } + gcv.foreground = 1; + gcv.background = 0; + if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth], + GCForeground | GCBackground, + &gcv)) == None) { + free_pacman (display, pp); + return; + } + gcv.foreground = 0; + gcv.background = 0; + if ((bg_gc = XCreateGC (display, + pp->pacmanPixmap[dir][mouth], + GCForeground | + GCBackground, &gcv)) == None) { + XFreeGC (display, fg_gc); + free_pacman (display, pp); + return; + } + XFillRectangle (display, + pp->pacmanPixmap[dir][mouth], bg_gc, + 0, 0, pp->spritexs, pp->spriteys); + if (pp->spritexs == 1 && pp->spriteys == 1) + XFillRectangle (display, + pp->pacmanPixmap[dir][mouth], + fg_gc, 0, 0, pp->spritexs, pp->spriteys); + else + XFillArc (display, + pp->pacmanPixmap[dir][mouth], + fg_gc, + 0, 0, pp->spritexs, pp->spriteys, + ((90 - dir * 90) + mouth * 5) * 64, + (360 + (-2 * mouth * 5)) * 64); + XFreeGC (display, fg_gc); + XFreeGC (display, bg_gc); + } +#endif /* USE_PIXMAP */ + + pp->pacman.lastbox = START; + pp->pacman.mouthdirection = 1; + pp->pacman.nextcol = NOWHERE; + pp->pacman.nextrow = NOWHERE; + + if (pp->ghosts != NULL) { + free (pp->ghosts); + pp->ghosts = (ghoststruct *) NULL; + } + pp->nghosts = GHOSTS; + + if (!pp->ghosts) + if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts, + sizeof (ghoststruct))) == + NULL) { + free_pacman (display, pp); + return; + } + + pp->pacman.mouthstage = MAXMOUTH - 1; + + MI_CLEARWINDOW (mi); + repopulate (mi); +} + +/* Callback function called for each tick. This is the complete machinery of + everything that moves. */ +ENTRYPOINT void +draw_pacman (ModeInfo * mi) +{ + unsigned int g; + pacmangamestruct *pp; + + if (pacman_games == NULL) + return; + pp = &pacman_games[MI_SCREEN (mi)]; + if (pp->ghosts == NULL) + return; + + pp->pacman.err.x = (pp->pacman.err.x + 1) % pp->pacman.speed; + pp->pacman.err.y = (pp->pacman.err.y + 1) % pp->pacman.speed; + pp->pacman.delta.x += pp->pacman.err.x != 0 ? pp->incx : 0; + pp->pacman.delta.y += pp->pacman.err.y != 0 ? pp->incy : 0; + + if (pp->pacman.delta.x >= pp->xs && pp->pacman.delta.y >= pp->ys) { + pacman_update (mi, pp, &(pp->pacman)); + check_death (mi, pp); + pp->pacman.delta.x = pp->incx; + pp->pacman.delta.y = pp->incy; + } + + if (pp->pacman.delta.x > pp->xs + pp->incx) + pp->pacman.delta.x = pp->xs + pp->incx; + if (pp->pacman.delta.y > pp->ys + pp->incy) + pp->pacman.delta.y = pp->ys + pp->incy; + + for (g = 0; g < pp->nghosts; g++) { + pp->ghosts[g].err.x = (pp->ghosts[g].err.x + 1) % pp->ghosts[g].speed; + pp->ghosts[g].err.y = (pp->ghosts[g].err.y + 1) % pp->ghosts[g].speed; + pp->ghosts[g].delta.x += pp->ghosts[g].err.x != 0 ? pp->incx : 0; + pp->ghosts[g].delta.y += pp->ghosts[g].err.y != 0 ? pp->incy : 0; + + if (pp->ghosts[g].delta.x >= pp->xs && + pp->ghosts[g].delta.y >= pp->ys) { + pacman_ghost_update (pp, &(pp->ghosts[g])); + pp->ghosts[g].delta.x = pp->incx; + pp->ghosts[g].delta.y = pp->incy; + } + + if (pp->ghosts[g].delta.x > pp->xs + pp->incx) + pp->ghosts[g].delta.x = pp->xs + pp->incx; + if (pp->ghosts[g].delta.y > pp->ys + pp->incy) + pp->ghosts[g].delta.y = pp->ys + pp->incy; + } + pacman_tick (mi); +} + +/* Releases resources. */ +ENTRYPOINT void +release_pacman (ModeInfo * mi) +{ + if (pacman_games != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS (mi); screen++) + free_pacman (MI_DISPLAY (mi), &pacman_games[screen]); + free (pacman_games); + pacman_games = (pacmangamestruct *) NULL; + } +} + +/* Refresh current level. */ +ENTRYPOINT void +refresh_pacman (ModeInfo * mi) +{ + drawlevel (mi); + pacman_tick (mi); +} + +ENTRYPOINT void +reshape_pacman(ModeInfo * mi, int width, int height) +{ + pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)]; + pp->width = width; + pp->height = height; + pp->xb = (pp->width - pp->ncols * pp->xs) >> 1; + pp->yb = (pp->height - pp->nrows * pp->ys) >> 1; + MI_CLEARWINDOW (mi); + /* repopulate (mi); */ + drawlevel (mi); +} + +#ifndef STANDALONE +/* Callback to change level. */ +ENTRYPOINT void +change_pacman (ModeInfo * mi) +{ + MI_CLEARWINDOW (mi); + repopulate (mi); +} +#endif /* !STANDALONE */ + + +XSCREENSAVER_MODULE ("Pacman", pacman) + +#endif /* MODE_pacman */ diff --git a/non-wgl/pacman.h b/non-wgl/pacman.h new file mode 100644 index 0000000..a9fbd2e --- /dev/null +++ b/non-wgl/pacman.h @@ -0,0 +1,233 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/*- + * Copyright (c) 2002 by Edwin de Jong . + * + * 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: + * 3-May-2002: Added AI to pacman and ghosts, slowed down ghosts. + * 26-Nov-2001: Random level generator added + * 01-Nov-2000: Allocation checks + * 04-Jun-1997: Compatible with xscreensaver + * + */ + +#ifndef __PACMAN_H__ +#define __PACMAN_H__ + +#if 0 + #ifdef HAVE_CONFIG_H + # include "config.h" + #endif +#endif + +#include "xlockmore.h" + +#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM) || defined(HAVE_COCOA) +# define USE_PIXMAP +#include "xpm-pixmap.h" +# else +# if defined(USE_PIXMAP) +# undef USE_PIXMAP +# endif +#endif + +#define LEVHEIGHT 32U +#define LEVWIDTH 40U + +#define TILEWIDTH 5U +#define TILEHEIGHT 5U + +#define GETNB(n) ((1 << (n)) - 1) +#define TESTNB(v, n) (((1 << (n)) & v) != 0x00) +#define SNB(v, n) ((v) |= (1 << (n))) +#define UNSNB(v, n) ((v) &= ~(1 << (n))) +#define GHOSTS 4U +#if defined(USE_PIXMAP) +#define MAXMOUTH 3 +#else +#define MAXMOUTH 11 +#endif +#define MAXGPOS 2 +#define MAXGDIR 4 +#define MAXGWAG 2 +#define MAXGFLASH 2 +#define MINGRIDSIZE 4 +#define MINSIZE 3 +#define NOWHERE 16383 +#define START ((LRAND() & 1) ? 1 : 3) +#define MINDOTPERC 10 + +#define YELLOW (MI_NPIXELS(mi) / 6) +#define GREEN (23 * MI_NPIXELS(mi) / 64) +#define BLUE (45 * MI_NPIXELS(mi) / 64) +#define WHITE (MI_NPIXELS(mi)) + +#define LINEWIDTH 4 +#define HLINEWIDTH 1 +#define JAILHEIGHT 7 +#define JAILWIDTH 8 + +#define GETFACTOR(x, y) ((x) > (y) ? 1 : ((x) < (y) ? -1 : 0)) +#define SIGN(x) GETFACTOR((x), 0) +#define TRACEVECS 40 +#define PAC_DEATH_FRAMES 8 + +#define GHOST_TRACE ( LEVWIDTH * LEVHEIGHT ) + +#define DIRVECS 4 +#define NUM_BONUS_DOTS 4 + +typedef struct +{ + int vx, vy; +} tracevec_struct; + +typedef enum + { inbox = 0, goingout, randdir, chasing, hiding, goingin } GhostState; +typedef enum + { ps_eating = 0, ps_chasing, ps_hiding, ps_random, ps_dieing } PacmanState; +typedef enum +{ GHOST_DANGER, GHOST_EATEN } GameState; + +typedef struct +{ + volatile unsigned int col, row; + unsigned int lastbox, nextcol, nextrow; + int dead; + int cfactor, rfactor; + int cf, rf; + int oldcf, oldrf; + volatile int timeleft; + GhostState aistate; + int speed; + XPoint delta; + XPoint err; + int flash_scared; + int trace_idx; + tracevec_struct trace[GHOST_TRACE]; + int home_idx; + volatile int home_count; + tracevec_struct way_home[GHOST_TRACE]; + volatile int wait_pos; /* a cycle before calculating the position */ +#if 0 /* Used for debugging */ + int ndirs; + int oldndirs; +#endif + +#if 0 /* Used for debugging */ + char last_stat[1024]; +#endif + +} ghoststruct; + +typedef struct +{ + unsigned int col, row; + unsigned int lastbox, nextcol, nextrow; + int mouthstage, mouthdirection; + int cfactor, rfactor; + int cf, rf; + int oldcf, oldrf; + int oldlx, oldly; + int justate; + PacmanState aistate; + tracevec_struct trace[TRACEVECS]; + int cur_trace; + int state_change; + int roundscore; + int speed; + int lastturn; + XPoint delta; + XPoint err; + int deaths; + int init_row; +} pacmanstruct; + + +typedef struct +{ + unsigned int x, y; + int eaten; +} bonus_dot; + + +/* This are tiles which can be placed to create a level. */ +struct tiles { + char block[TILEWIDTH * TILEHEIGHT + 1]; + unsigned dirvec[4]; + unsigned ndirs; + unsigned simular_to; +}; + +typedef struct +{ + unsigned short width, height; + unsigned short nrows, ncols; + short xs, ys, xb, yb; + short incx, incy; + GC stippledGC; + int graphics_format; + pacmanstruct pacman; + ghoststruct *ghosts; + unsigned int nghosts; + Pixmap pacmanPixmap[4][MAXMOUTH]; + Pixmap pacmanMask[4][MAXMOUTH]; + Pixmap pacman_ds[PAC_DEATH_FRAMES]; /* pacman death sequence */ + Pixmap pacman_ds_mask[PAC_DEATH_FRAMES]; + Pixmap ghostPixmap[4][MAXGDIR][MAXGWAG]; + Pixmap ghostMask; + Pixmap s_ghostPixmap[MAXGFLASH][MAXGWAG]; /* Scared ghost Pixmaps */ + Pixmap ghostEyes[MAXGDIR]; + char level[LEVHEIGHT * LEVWIDTH]; + unsigned int wallwidth; + unsigned int dotsleft; + int spritexs, spriteys, spritedx, spritedy; + + GameState gamestate; + unsigned int timeleft; + + char last_pac_stat[1024]; + + /* draw_pacman_sprite */ + int pm_mouth; + int pm_mouth_delay; + int pm_open_mouth; + int pm_death_frame; + int pm_death_delay; + + /* draw_ghost_sprite */ + int gh_wag; + int gh_wag_count; + + /* flash_bonus_dots */ + int bd_flash_count; + int bd_on; + + /* pacman_tick */ + int ghost_scared_timer; + int flash_timer; + PacmanState old_pac_state; + + /* pacman_level.c */ + bonus_dot bonus_dots[NUM_BONUS_DOTS]; + struct tiles *tiles; + +} pacmangamestruct; + +extern pacmangamestruct *pacman_games; +extern Bool pacman_trackmouse; + +typedef char lev_t[LEVHEIGHT][LEVWIDTH + 1]; + +#endif /* __PACMAN_H__ */ diff --git a/non-wgl/pacman.vcproj b/non-wgl/pacman.vcproj new file mode 100644 index 0000000..9330b9e --- /dev/null +++ b/non-wgl/pacman.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/pacman_ai.c b/non-wgl/pacman_ai.c new file mode 100644 index 0000000..851e4c7 --- /dev/null +++ b/non-wgl/pacman_ai.c @@ -0,0 +1,878 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/*- + * Copyright (c) 2002 by Edwin de Jong . + * + * 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. + */ + +/* this file handles the AI of the ghosts and the pacman. */ + +#include +#include +#include "pacman.h" +#include "pacman_ai.h" +#include "pacman_level.h" + +#if 0 + #define MI_DISPLAY(MI) ((MI)->dpy) + #define MI_WINDOW(MI) ((MI)->window) + #define MI_WIDTH(MI) ((MI)->xgwa.width) + #define MI_HEIGHT(MI) ((MI)->xgwa.height) +#endif + +#define DIRVECS 4 +static const struct +{ + int dx, dy; +} dirvecs[DIRVECS] = { { +-1, 0}, { +0, 1}, { +1, 0}, { +0, -1}}; + +/* positions that match the dirvecs */ +typedef enum {pos_none = -1, pos_left = 0, pos_up = 1, pos_right = 2, pos_down = 3} pos; + + +/* fills array of DIRVECS size with possible directions, returns number of + directions. 'posdirs' points to a possibly undefined array of four + integers. The vector will contain booleans wether the direction is + a possible direction or not. Reverse directions are deleted. */ +static int +ghost_get_posdirs (pacmangamestruct * pp, int *posdirs, ghoststruct * g) +{ + unsigned int i, nrdirs = 0; + unsigned int can_go_in = 0; + + /* bit of black magic here */ + for (i = 0; i < DIRVECS; i++) { + /* remove opposite */ + if (g->lastbox != NOWHERE && i == (g->lastbox + 2) % DIRVECS + && (g->aistate != goingout )) { + posdirs[i] = 0; + continue; + } + if (g->aistate == goingout && i == 1) { + posdirs[i] = 0; + continue; + } + /* check if possible direction */ + can_go_in = (g->aistate == goingout || g->aistate == goingin); + if ((posdirs[i] = + pacman_check_pos (pp, g->row + dirvecs[i].dy, + g->col + dirvecs[i].dx, + can_go_in)) == True) { + nrdirs++; + } + } + + return nrdirs; +} + +/* Directs ghost to a random direction, exluding opposite (except in the + impossible situation that there is only one valid direction). */ +static void +ghost_random (pacmangamestruct * pp, ghoststruct * g) +{ + int posdirs[DIRVECS], nrdirs = 0, i, dir = 0; + + nrdirs = ghost_get_posdirs (pp, posdirs, g); +#if 0 + g->ndirs = nrdirs; +#endif + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] == True) + dir = i; + + if (nrdirs == 0) + dir = (g->lastbox + 2) % DIRVECS; + else if (nrdirs > 1) + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == True && NRAND (nrdirs) == 0) { + dir = i; + break; + } + } + + g->nextrow = g->row + dirvecs[dir].dy; + g->nextcol = g->col + dirvecs[dir].dx; + g->lastbox = dir; +} + +/* Determines best direction to chase the pacman and goes that direction. */ +static void +ghost_chasing (pacmangamestruct * pp, ghoststruct * g) +{ + int posdirs[DIRVECS], nrdirs = 0, i, dir = 0, highest = -100000, + thisvecx, thisvecy, thisvec; + + nrdirs = ghost_get_posdirs (pp, posdirs, g); +#if 0 + g->ndirs = nrdirs; +#endif + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] == True) + dir = i; + + if (nrdirs == 0) + dir = (g->lastbox + 2) % DIRVECS; + else if (nrdirs > 1) + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == False) + continue; + thisvecx = (pp->pacman.col - g->col) * dirvecs[i].dx; + thisvecy = (pp->pacman.row - g->row) * dirvecs[i].dy; + thisvec = thisvecx + thisvecy; + if (thisvec >= highest) { + dir = i; + highest = thisvec; + } + } + + g->nextrow = g->row + dirvecs[dir].dy; + g->nextcol = g->col + dirvecs[dir].dx; + g->lastbox = dir; +} + +/* Determines the best direction to go away from the pacman, and goes that + direction. */ +static void +ghost_hiding (pacmangamestruct * pp, ghoststruct * g) +{ + int posdirs[DIRVECS], nrdirs = 0, i, dir = 0, highest = -100000, + thisvecx, thisvecy, thisvec; + + nrdirs = ghost_get_posdirs (pp, posdirs, g); +#if 0 + g->ndirs = nrdirs; +#endif + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] == True) + dir = i; + + if (nrdirs == 0) + dir = (g->lastbox + 2) % DIRVECS; + else if (nrdirs > 1) + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == False) + continue; + thisvecx = (g->col - pp->pacman.col) * dirvecs[i].dx; + thisvecy = (g->row - pp->pacman.row) * dirvecs[i].dy; + thisvec = thisvecx + thisvecy; + if (thisvec >= highest) + dir = i; + } + + g->nextrow = g->row + dirvecs[dir].dy; + g->nextcol = g->col + dirvecs[dir].dx; + g->lastbox = dir; +} + +#if 1 +static void +clear_trace(ghoststruct *g) +{ + int i = 0; + g->trace_idx = 0; + while (i < GHOST_TRACE){ + g->trace[i].vx = -1; + g->trace[i++].vy = -1; + } +} + + +static void +save_position (ghoststruct *g, int x, int y) +{ + int i = g->trace_idx; + assert ( 0 <= i && i < GHOST_TRACE ); + g->trace[i].vx = x; + g->trace[i].vy = y; + g->trace_idx++; +} + +static int +already_tried (ghoststruct *g, int x, int y) +{ + int i = 0; + if (! ( 0 <= g->trace_idx && g->trace_idx < GHOST_TRACE ) ){ + fprintf(stderr, "FOUND TRACE ERROR. DUMPING TRACE.\n"); + fprintf(stderr, "%d\n", g->trace_idx ); + for ( i = 0; i < GHOST_TRACE; i++ ){ + fprintf(stderr, "( %d, %d )\n", g->trace[i].vx, g->trace[i].vy ); + } + assert ( False ); + } + while (i < g->trace_idx){ + if ( x == g->trace[i].vx && y == g->trace[i].vy ){ + /* fprintf ( stderr, "Match FOUND (%d, %d)\n", x, y); */ + return 1; + } + i++; + } + return 0; +} +#endif + +static void +store_dir ( ghoststruct *g, pos ps ){ + int i = g->home_count; + assert ( 0 <= i && i < GHOST_TRACE ); + g->way_home[i].vx = dirvecs[ps].dx; + g->way_home[i].vy = dirvecs[ps].dy; + g->home_count++; +} + +static void +clear_dir ( ghoststruct *g ){ + int i = 0; + g->home_count = 0; + g->home_idx = 0; + while (i < GHOST_TRACE){ + g->way_home[i].vx = -1; + g->way_home[i++].vy = -1; + } +} + +static int +found_jail ( int col, int row ){ + int cx, cy; + pacman_get_jail_opening ( &cx, &cy ); + cy += 1; + if (row == cy && col == cx ) + return 1; + else + return 0; +} + +static int +move_ghost ( pacmangamestruct * pp, + int row, int col, + pos ps, + int *new_row, int *new_col){ + int idx = (int)ps; + int tr = row + dirvecs[idx].dx; + int tc = col + dirvecs[idx].dy; + if ( pacman_check_pos ( pp, tr, tc, True )){ + *new_row = tr; + *new_col = tc; + return True; + } + else { + return False; + } +} + +static int +recur_back_track ( pacmangamestruct * pp, ghoststruct *g, int row, int col ){ + int new_row, new_col; + + if ( already_tried ( g, col, row ) ) + return False; + + if ( found_jail ( col, row ) ) + return True; + + save_position ( g, col, row ); + + if ( move_ghost ( pp, row, col, pos_left, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_left ); + return True; + } + + if ( move_ghost ( pp, row, col, pos_up, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_up ); + return True; + } + + if ( move_ghost ( pp, row, col, pos_down, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_down ); + return True; + } + + if ( move_ghost ( pp, row, col, pos_right, &new_row, &new_col )) + if ( recur_back_track ( pp, g, new_row, new_col )){ + store_dir ( g, pos_right ); + return True; + } + + return False; +} + +static void +find_home ( pacmangamestruct *pp, ghoststruct *g ){ + int i; + int r,c; + int cx, cy; + ghoststruct *tmp_ghost; + tmp_ghost = (ghoststruct*)malloc(sizeof ( ghoststruct )); + if ( tmp_ghost == NULL ){ + fprintf(stderr, "find_home : Could not allocate memory."); + exit ( 1 ); + } + tmp_ghost = memmove(tmp_ghost, g, sizeof ( ghoststruct )); + if ( tmp_ghost == NULL ){ + fprintf(stderr, "find_home : Could not copy memory."); + exit ( 1 ); + } + clear_trace ( tmp_ghost ); + clear_dir ( tmp_ghost ); + r = tmp_ghost->row; + c = tmp_ghost->col; + if ( ! recur_back_track ( pp, tmp_ghost, r, c ) ){ + fprintf(stderr, "Could not find way home.#@$?\n"); + pacman_get_jail_opening ( &cx, &cy); + fprintf(stderr, "Jail was at (%d%d)\n", cx,cy); + } + for ( i = 0; i < GHOST_TRACE; i++ ){ + g->way_home[i].vx = tmp_ghost->way_home[i].vx; + g->way_home[i].vy = tmp_ghost->way_home[i].vy; + } + g->home_count = tmp_ghost->home_count; + g->home_idx = tmp_ghost->home_count; + free(tmp_ghost); +} + +/* Make the ghost go back to the inbox */ +static void +ghost_goingin (pacmangamestruct * pp, ghoststruct * g) +{ + g->home_idx--; + if (g->home_idx < 0){ g->aistate = goingout; return;} + /* row == vx ? wtf... Don't Ask */ + g->nextrow = g->row + g->way_home[g->home_idx].vx; + g->nextcol = g->col + g->way_home[g->home_idx].vy; +} + + +/* Determines a vector from the pacman position, towards all dots. The vector + is inversely proportional to the square of the distance of each dot. + (so, close dots attract more than far away dots). */ +static void +pac_dot_vec (pacmangamestruct * pp, pacmanstruct * p, long *vx, long *vy) +{ + int x, y, bx = 0, by = 0, ex = LEVWIDTH, ey = LEVHEIGHT; + long dx, dy, dist, top = 0; + +#if 0 + int rnr = NRAND (50); + /* determine begin and end vectors */ + + switch (rnr) { + case 0: + ex = LEVHEIGHT / 2; + break; + case 1: + bx = LEVHEIGHT / 2; + break; + case 2: + ey = LEVHEIGHT / 2; + break; + case 3: + by = LEVHEIGHT / 2; + break; + } +#endif + *vx = *vy = 0; + + for (y = by; y < ey; y++) + for (x = bx; x < ex; x++) + if (pacman_check_dot (pp, x, y) == 1) { + dx = (long) x - (long) (p->col); + dy = (long) y - (long) (p->row); + dist = dx * dx + dy * dy; + if (dist > top) + top = dist; + *vx += (dx * ((long) LEVWIDTH * (long) LEVHEIGHT)) + / dist; + *vy += (dy * ((long) LEVWIDTH * (long) LEVHEIGHT)) + / dist; + } +} + +/* Determine a vector towards the closest ghost (in one loop, so we spare a + couple of cycles which we can spoil somewhere else just as fast). */ +static int +pac_ghost_prox_and_vector (pacmangamestruct * pp, pacmanstruct * p, + int *vx, int *vy) +{ + int dx, dy, dist, closest = 100000; + unsigned int g; + + if (vx != NULL) + *vx = *vy = 0; + + for (g = 0; g < pp->nghosts; g++) { + if (pp->ghosts[g].dead == True || + pp->ghosts[g].aistate == inbox || + pp->ghosts[g].aistate == goingout) + continue; + dx = pp->ghosts[g].col + /*dirvecs[pp->ghosts[g].lastbox].dx */ - + p->col; + dy = pp->ghosts[g].row + /*dirvecs[pp->ghosts[g].lastbox].dy */ - + p->row; + dist = dx * dx + dy * dy; + if (dist < closest) { + closest = dist; + if (vx != NULL) { + *vx = dx; + *vy = dy; + } + } + } + return closest; +} + +/* fills array of DIRVECS size with possible directions, returns number of + directions. posdirs should point to an array of 4 integers. */ +static int +pac_get_posdirs (pacmangamestruct * pp, pacmanstruct * p, int *posdirs) +{ + int nrdirs = 0; + unsigned int i; + + for (i = 0; i < DIRVECS; i++) { + /* if we just ate, or we are in a statechange, it is allowed + * to go the opposite direction */ + if (p->justate == 0 && + p->state_change == 0 && + p->lastbox != NOWHERE && i == (p->lastbox + 2) % DIRVECS) { + posdirs[i] = 0; + } + else if ((posdirs[i] = + pacman_check_pos (pp, p->row + dirvecs[i].dy, + p->col + dirvecs[i].dx, 0)) == 1) + nrdirs++; + } + p->state_change = 0; + + return nrdirs; +} + +/* Clears the trace of vectors. */ +void +pacman_clear_trace (pacmanstruct * p) +{ + int i; + + for (i = 0; i < TRACEVECS; i++) { + p->trace[i].vx = NOWHERE; + p->trace[i].vy = NOWHERE; + } + p->cur_trace = 0; +} + +/* Adds a new vector to the trace. */ +static void +pac_save_trace (pacmanstruct * p, const int vx, const int vy) +{ + if (!(vx == NOWHERE && vy == NOWHERE)) { + p->trace[p->cur_trace].vx = vx; + p->trace[p->cur_trace].vy = vy; + p->cur_trace = (p->cur_trace + 1) % TRACEVECS; + } +} + +/* Check if a vector can be found in the trace. */ +static int +pac_check_trace (const pacmanstruct * p, const int vx, const int vy) +{ + int i, curel; + + for (i = 1; i < TRACEVECS; i++) { + curel = (p->cur_trace - i + TRACEVECS) % TRACEVECS; + if (p->trace[curel].vx == NOWHERE && p->trace[curel].vy == NOWHERE) + continue; + if (p->trace[curel].vx == vx && p->trace[curel].vy == vy) + return 1; + } + + + return 0; +} + +/* AI mode "Eating" for pacman. Tries to eat as many dots as possible, goes + to "hiding" if too close to a ghost. If in state "hiding" the vectors + of the ghosts are also taken into account (thus not running towards them + is the general idea). */ +static void +pac_eating (pacmangamestruct * pp, pacmanstruct * p) +{ + int posdirs[DIRVECS], nrdirs, i, highest = -(1 << 16), + score, dir = 0, dotfound = 0, prox, worst = 0; + int vx, vy; + + if ((prox = pac_ghost_prox_and_vector (pp, p, &vx, &vy)) < + 4 * 4 && p->aistate == ps_eating) { + p->aistate = ps_hiding; + p->state_change = 1; + pacman_clear_trace (p); + } + + if (prox > 6 * 6 && p->aistate == ps_hiding) { + p->aistate = ps_eating; + if (p->justate == 0) + p->state_change = 1; + pacman_clear_trace (p); + } + + if (prox < 3 * 3) + p->state_change = 1; + + nrdirs = pac_get_posdirs (pp, p, posdirs); + + /* remove directions which lead to ghosts */ + if (p->aistate == ps_hiding) { + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = vx * dirvecs[i].dx + vy * dirvecs[i].dy; + if (score > highest) { + worst = i; + highest = score; + } + dir = i; + } + nrdirs--; + posdirs[worst] = 0; + highest = -(1 << 16); + } + + /* get last possible direction if all else fails */ + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] != 0) + dir = i; + + { + long lvx = vx; + long lvy = vy; + pac_dot_vec (pp, p, &lvx, &lvy); + vx = lvx; + vy = lvy; + } + + if (vx != NOWHERE && vy != NOWHERE && pac_check_trace (p, vx, vy) > 0) { + p->roundscore++; + if (p->roundscore >= 12) { + p->roundscore = 0; + p->aistate = ps_random; + pacman_clear_trace (p); + } + } + else + p->roundscore = 0; + + if (p->justate == 0) + pac_save_trace (p, vx, vy); + + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = dirvecs[i].dx * vx + dirvecs[i].dy * vy; + if (pacman_check_dot (pp, p->col + dirvecs[i].dx, + p->row + dirvecs[i].dy) == 1) { + if (dotfound == 0) { + highest = score; + dir = i; + dotfound = 1; + } + else if (score > highest) { + highest = score; + dir = i; + } + } + else if (score > highest && dotfound == 0) { + dir = i; + highest = score; + } + } + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; +} + +#if 1 +/* Tries to catch the ghosts. */ +static void +pac_chasing (pacmangamestruct * pp, pacmanstruct * p) +{ + int posdirs[DIRVECS], nrdirs, i, highest = -(1 << 16), + score, dir = 0, worst = 0; + int vx = 0, vy = 0; + + nrdirs = pac_get_posdirs (pp, p, posdirs); + + /* keep directions which lead to ghosts */ + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = vx * dirvecs[i].dx + vy * dirvecs[i].dy; + if (score < highest) { + worst = i; + highest = score; + } + dir = i; + } + nrdirs--; + posdirs[worst] = 0; + + + /* get last possible direction if all else fails */ + for (i = 0; i < DIRVECS; i++) + if (posdirs[i] != 0) + dir = i; + + { + long lvx = vx; + long lvy = vy; + pac_dot_vec (pp, p, &lvx, &lvy); + vx = lvx; + vy = lvy; + } + + if (vx != NOWHERE && vy != NOWHERE && pac_check_trace (p, vx, vy) > 0) { + p->roundscore++; + if (p->roundscore >= 12) { + p->roundscore = 0; + p->aistate = ps_random; + pacman_clear_trace (p); + } + } + else + p->roundscore = 0; + + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; +} +#endif + +/* Goes completely random, but not in the opposite direction. Used when a + loop is detected. */ +static void +pac_random (pacmangamestruct * pp, pacmanstruct * p) +{ + int posdirs[DIRVECS], nrdirs, i, dir = -1, lastdir = 0; + + if (pac_ghost_prox_and_vector (pp, p, NULL, NULL) < 5 * 5) { + p->aistate = ps_hiding; + p->state_change = 1; + } + if (NRAND (20) == 0) { + p->aistate = ps_eating; + p->state_change = 1; + pacman_clear_trace (p); + } + + nrdirs = pac_get_posdirs (pp, p, posdirs); + + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + lastdir = i; + if (pacman_check_dot (pp, p->col + dirvecs[i].dx, + p->row + dirvecs[i].dy) == 1) { + dir = i; + p->aistate = ps_eating; + p->state_change = 1; + pacman_clear_trace (p); + break; + } + else if (NRAND (nrdirs) == 0) + dir = i; + } + + if (dir == -1) + dir = lastdir; + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; +} + +static int +pac_get_vector_screen (pacmangamestruct * pp, pacmanstruct * p, + const int x, const int y, int *vx, int *vy) +{ + int lx, ly; + + lx = (x - pp->xb) / pp->xs; + ly = (y - pp->yb) / pp->ys; + + if (lx < 0) + lx = 0; + else if ((unsigned int) lx > LEVWIDTH) + lx = LEVWIDTH - 1; + + if (ly < 0) + ly = 0; + else if ((unsigned int) ly > LEVHEIGHT) + ly = LEVHEIGHT - 1; + + *vx = lx - p->col; + *vy = ly - p->row; + + if (lx == p->oldlx && ly == p->oldly) + return 0; + p->oldlx = lx; + p->oldly = ly; + return 1; +} + +static int +pac_trackmouse (ModeInfo * mi, pacmangamestruct * pp, pacmanstruct * p) +{ + int dx, dy, cx, cy, vx, vy; + unsigned int m; + int posdirs[DIRVECS], i, dir = -1, highest = -(2 << 16), score; + Window r, c; + + (void) XQueryPointer (MI_DISPLAY (mi), MI_WINDOW (mi), + &r, &c, &dx, &dy, &cx, &cy, &m); + + if (cx <= 0 || cy <= 0 || + cx >= MI_WIDTH (mi) - 1 || cy >= MI_HEIGHT (mi) - 1) + return 0; + /* get vector */ + p->state_change = pac_get_vector_screen (pp, p, cx, cy, &vx, &vy); + + (void) pac_get_posdirs (pp, p, posdirs); + + for (i = 0; i < DIRVECS; i++) { + if (posdirs[i] == 0) + continue; + score = dirvecs[i].dx * vx + dirvecs[i].dy * vy; + if (score > highest) { + highest = score; + dir = i; + } + } + + p->nextrow = p->row + dirvecs[dir].dy; + p->nextcol = p->col + dirvecs[dir].dx; + p->lastbox = dir; + return 1; +} + +/* Calls correct state function, and changes between states. */ +void +pacman_ghost_update (pacmangamestruct * pp, ghoststruct * g) +{ + + if (!(g->nextrow == NOWHERE && g->nextcol == NOWHERE)) { + g->row = g->nextrow; + g->col = g->nextcol; + } + + if ((g->aistate == randdir || g->aistate == chasing) && NRAND (10) == 0) { + switch (NRAND (3)) { + case 0: + g->aistate = randdir; + break; + case 1: + g->aistate = chasing; + break; + case 2: + g->aistate = chasing; + break; + } + + } + else if (g->aistate == inbox) { + if (g->timeleft < 0) + g->aistate = goingout; + else + g->timeleft--; + + } + else if (g->aistate == goingout) { + if (g->col < LEVWIDTH / 2 - JAILWIDTH / 2 || + g->col > LEVWIDTH / 2 + JAILWIDTH / 2 || + g->row < LEVHEIGHT / 2 - JAILHEIGHT / 2 || + g->row > LEVHEIGHT / 2 + JAILHEIGHT / 2) + g->aistate = randdir; + } + + switch (g->aistate) { + case inbox: + case goingout: + case randdir: + ghost_random (pp, g); + break; + case chasing: + ghost_chasing (pp, g); + break; + case hiding: + ghost_hiding (pp, g); + break; + case goingin: + if ( g->wait_pos ){ + find_home(pp, g); + g->wait_pos = False; + } + ghost_goingin (pp, g); + break; + } + + g->cfactor = GETFACTOR (g->nextcol, g->col); + g->rfactor = GETFACTOR (g->nextrow, g->row); +} + +/* Calls correct pacman state function. */ +void +pacman_update (ModeInfo * mi, pacmangamestruct * pp, pacmanstruct * p) +{ + if (!(p->nextrow == NOWHERE && p->nextcol == NOWHERE)) { + p->row = p->nextrow; + p->col = p->nextcol; + } + + if (pp->level[p->row * LEVWIDTH + p->col] == '.' || + pp->level[p->row * LEVWIDTH + p->col] == 'o') { + pp->level[p->row * LEVWIDTH + p->col] = ' '; + if (!pacman_trackmouse) + p->justate = 1; + pp->dotsleft--; + } + else if (!pacman_trackmouse) { + p->justate = 0; + } + + if (!(pacman_trackmouse && pac_trackmouse (mi, pp, p))) { + /* update pacman */ + switch (p->aistate) { + case ps_eating: + pac_eating (pp, p); + break; + case ps_hiding: + pac_eating (pp, p); + break; + case ps_random: + pac_random (pp, p); + break; + case ps_chasing: + pac_chasing (pp, p); + break; + case ps_dieing: + break; /* Don't move */ + } + } + + p->cfactor = GETFACTOR (p->nextcol, p->col); + p->rfactor = GETFACTOR (p->nextrow, p->row); +} diff --git a/non-wgl/pacman_ai.h b/non-wgl/pacman_ai.h new file mode 100644 index 0000000..2488600 --- /dev/null +++ b/non-wgl/pacman_ai.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2002 by Edwin de Jong . + * + * 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: + * 3-May-2002: Added AI to pacman and ghosts, slowed down ghosts. + * 26-Nov-2001: Random level generator added + * 01-Nov-2000: Allocation checks + * 04-Jun-1997: Compatible with xscreensaver + * + */ + +#ifndef __PACMAN_AI_H__ +#define __PACMAN_AI_H__ + +extern void pacman_ghost_update (pacmangamestruct * pp, ghoststruct * g); +extern void pacman_clear_trace (pacmanstruct * p); +extern void pacman_update (ModeInfo * mi, pacmangamestruct * pp, + pacmanstruct * p); + +#endif /* __PACMAN_AI_H__ */ diff --git a/non-wgl/pacman_level.c b/non-wgl/pacman_level.c new file mode 100644 index 0000000..f26b3bf --- /dev/null +++ b/non-wgl/pacman_level.c @@ -0,0 +1,772 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/*- + * Copyright (c) 2002 by Edwin de Jong . + * + * 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. + */ + +#include +#include "pacman.h" +#include "pacman_level.h" + + +#define NONE 0x0000 +#define LT 0x1000 +#define RT 0x0001 +#define RB 0x0010 +#define LB 0x0100 +#define ALL 0x1111 + +#define BLOCK_EMPTY ' ' +#define BLOCK_DOT_1 '`' +#define BLOCK_DOT_2 '.' +#define BLOCK_WALL '#' +#define BLOCK_GHOST_ONLY '=' +#define BLOCK_WALL_TL '\'' +#define BLOCK_WALL_TR '`' +#define BLOCK_WALL_BR ',' +#define BLOCK_WALL_BL '_' +#define BLOCK_WALL_HO '-' +#define BLOCK_WALL_VE '|' +#define BLOCK_DOT_BONUS 'o' + +/* This is more or less the standard pacman level (without the left-right + tunnel. */ +static const lev_t stdlevel = { + "########################################", + "########################################", + "#######````````````##````````````#######", + "#######`####`#####`##`#####`####`#######", + "#######`####`#####`##`#####`####`#######", + "#######`####`#####`##`#####`####`#######", + "#######``````````````````````````#######", + "#######`####`##`########`##`####`#######", + "#######`####`##`########`##`####`#######", + "#######``````##````##````##``````#######", + "############`#####`##`#####`############", + "############`#####`##`#####`############", + "############`##``````````##`############", + "############`##`###==###`##`############", + "############`##`########`##`############", + "############````########````############", + "############`##`########`##`############", + "############`##`########`##`############", + "############`##``````````##`############", + "############`##`########`##`############", + "############`##`########`##`############", + "#######````````````##````````````#######", + "#######`####`#####`##`#####`####`#######", + "#######`####`#####`##`#####`####`#######", + "#######```##````````````````##```#######", + "#########`##`##`########`##`##`#########", + "#########`##`##`########`##`##`#########", + "#######``````##````##````##``````#######", + "#######`##########`##`##########`#######", + "#######`##########`##`##########`#######", + "#######``````````````````````````#######", + "########################################" +}; + +#define TILES_COUNT 11U + +#define GO_UP 0x0001U +#define GO_LEFT 0x0002U +#define GO_RIGHT 0x0004U +#define GO_DOWN 0x0008U + +static const struct tiles def_tiles[TILES_COUNT] = { +/* + * ' ' == dont care == BLOCK_EMPTY + * '#' == set wall, and not clear == BLOCK_WALL + * '`' == clear == BLOCK_DOT_1 + * middle position is always set as cleardef + */ + { + " # " " # " " ``` " " # " " # ", { + GO_LEFT, GO_RIGHT, 0, 0}, 2, + (unsigned) (1 << 0 | 1 << 6 | 1 << 8 | 1 << 10)}, { + " " " ` " "##`##" " ` " " ", { + GO_UP, GO_DOWN, 0, 0}, 2, + (unsigned) (1 << 1 | 1 << 7 | 1 << 9 | 1 << 10)}, { + " ##" "##`##" "##`` " "#### " "#### ", { + GO_UP, GO_RIGHT, 0, 0}, 2, + (unsigned) (1 << 2 | 1 << 6 | 1 << 7 | 1 << 10)}, { + "#### " "#### " "##`` " "##`##" " ##", { + GO_RIGHT, GO_DOWN, 0, 0}, 2, + (unsigned) (1 << 3 | 1 << 7 | 1 << 8 | 1 << 10)}, { + " ###" " ###" " ``##" "##` " "## ", { + GO_LEFT, GO_DOWN, 0, 0}, 2, + (unsigned) (1 << 4 | 1 << 8 | 1 << 9 | 1 << 10)}, { + "## " "##`##" " ``##" " ####" " ####", { + GO_LEFT, GO_UP, 0, 0}, 2, + (unsigned) (1 << 5 | 1 << 6 | 1 << 9 | 1 << 10)}, { + "##`##" "##`##" "`````" " ### " " ### ", { + GO_LEFT, GO_UP, GO_RIGHT, 0}, 3, (unsigned) 1 << 6}, { + " `##" "##`##" "##```" "##`##" " `##", { + GO_UP, GO_RIGHT, GO_DOWN, 0}, 3, (unsigned) (1 << 7)}, { + " ### " " ### " "`````" "##`##" "##`##", { + GO_LEFT, GO_RIGHT, GO_DOWN, 0}, 3, (unsigned) (1 << 8)}, { + "##` " "##`##" "```##" "##`##" "##` ", { + GO_UP, GO_DOWN, GO_LEFT, 0}, 3, (unsigned) (1 << 9)}, { + "##`##" "##`##" "`````" "##`##" "##`##", { + GO_UP, GO_DOWN, GO_LEFT, GO_RIGHT}, 4, (unsigned) (1 << 10)} +}; + +/* probability array for each of the tiles */ +#define MAXTILEPROB 22 +static const unsigned tileprob[MAXTILEPROB] = + { 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10 }; + + +static int creatlevelblock (pacmangamestruct *pp, + lev_t * level, const unsigned x, + const unsigned y); + + +enum +{ TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; + +/* Sets a block in the level to a certain state. */ +static void +setblockto (lev_t * level, const unsigned x, const unsigned y, const char c) +{ + if (!(x < LEVWIDTH && y < LEVHEIGHT)) + return; + (*level)[y][x] = c; +} + +/* check if a block is set */ +static int +checkset (lev_t * level, const unsigned x, const unsigned y) +{ + if (!(x < LEVWIDTH && y < LEVHEIGHT) || + (*level)[y][x] == BLOCK_WALL || (*level)[y][x] == BLOCK_GHOST_ONLY) + return True; + return False; +} + +/* Check if a block is not set */ +static int +checksetout (lev_t * level, const unsigned x, const unsigned y) +{ + if (!(x < LEVWIDTH && y < LEVHEIGHT) || checkset (level, x, y) != 0) + return True; + + return False; +} + +/* Check if a block cannot be set */ +static int +checkunsetdef (lev_t * level, const unsigned x, const unsigned y) +{ + if (!(x < LEVWIDTH && y < LEVHEIGHT)) + return False; + if ((*level)[y][x] == BLOCK_DOT_1) + return True; + return False; +} + +/* Initializes a level to empty state. */ +static void +clearlevel (lev_t * level) +{ + unsigned x, y; + + for (y = 0; y < LEVHEIGHT; y++) + for (x = 0; x < LEVWIDTH; x++) + (*level)[y][x] = BLOCK_EMPTY; +} + +/* Changes a level from the level creation structure ((array to array) to + array. */ +static void +copylevel (char *dest, lev_t * level) +{ + unsigned x, y; + + for (y = 0; y < LEVHEIGHT; y++) + for (x = 0; x < LEVWIDTH; x++) + dest[y * LEVWIDTH + x] = (*level)[y][x]; +} + +/* Creates a jail to work around, so we can finish it later. */ +static void +createjail (lev_t * level, const unsigned width, const unsigned height) +{ + unsigned x, y, xstart, xend, ystart, yend; + + if (LEVWIDTH < width || LEVHEIGHT < height) + return; + + xstart = LEVWIDTH / 2 - width / 2; + xend = LEVWIDTH / 2 + width / 2; + ystart = LEVHEIGHT / 2 - height / 2; + yend = LEVHEIGHT / 2 + height / 2; + + for (y = ystart - 1; y < yend + 1; y++) + for (x = xstart - 1; x < xend + 1; x++) + setblockto (level, x, y, BLOCK_DOT_1); + + for (y = ystart; y < yend; y++) + for (x = xstart; x < xend; x++) + setblockto (level, x, y, BLOCK_WALL); +} + +void +pacman_get_jail_opening ( int *x, int *y) +{ + int xstart = LEVWIDTH / 2 - JAILWIDTH / 2; + int ystart = LEVHEIGHT / 2 - JAILHEIGHT / 2; + *x = xstart + JAILWIDTH / 2; + *y = ystart; +} + +/* Finishes a jail so it is empty and the ghostpass is on top. */ +static void +finishjail (lev_t * level, const unsigned width, const unsigned height) +{ + unsigned x, y, xstart, xend, ystart, yend; + + xstart = LEVWIDTH / 2 - width / 2; + xend = LEVWIDTH / 2 + width / 2; + ystart = LEVHEIGHT / 2 - height / 2; + yend = LEVHEIGHT / 2 + height / 2; + + for (y = ystart + 1; y < yend - 1; y++) + for (x = xstart + 1; x < xend - 1; x++) + setblockto (level, x, y, BLOCK_EMPTY); + + for (x = xstart - 1; x < xend + 1; x++) { + setblockto (level, x, ystart - 1, BLOCK_EMPTY); + setblockto (level, x, yend, BLOCK_EMPTY); + } + + for (y = ystart - 1; y < yend + 1; y++) { + setblockto (level, xstart - 1, y, BLOCK_EMPTY); + setblockto (level, xend, y, BLOCK_EMPTY); + } + + setblockto (level, xstart + width / 2 - 1, ystart, BLOCK_GHOST_ONLY); + setblockto (level, xstart + width / 2, ystart, BLOCK_GHOST_ONLY); +} + +/* Tries to set a block at a certain position. Returns true if possible, + and leaves level in new state (plus block), or False if not possible, + and leaves level in unpredictable state. */ +static int +tryset (lev_t * level, const unsigned xpos, const unsigned ypos, + const char *block) +{ + register unsigned x, y; + register char locchar; + int xstart, ystart; + unsigned xend, yend; + + if ((*level)[ypos][xpos] == BLOCK_DOT_1) + return False; + + xstart = xpos - 2; + ystart = ypos - 2; + + for (y = 0; y < TILEHEIGHT; y++) + for (x = 0; x < TILEWIDTH; x++) { + locchar = block[y * TILEWIDTH + x]; + if (locchar == BLOCK_EMPTY) + continue; + if (locchar == BLOCK_DOT_1 && + (xstart + x < 1 || + xstart + x >= LEVWIDTH - 1 || + ystart + y < 1 || + ystart + y >= LEVHEIGHT - 1 || + checkset (level, xstart + x, ystart + y) != 0)) + return False; + else if (locchar == BLOCK_WALL && + (xstart + x > 1 && + xstart + x < LEVWIDTH && + ystart + y > 1 && + ystart + y < LEVHEIGHT - 1) && + checkunsetdef (level, + (unsigned) (xstart + x), + (unsigned) (ystart + y)) != 0) + return False; + } + + /* and set the block in place */ + + xend = (xstart + TILEWIDTH < LEVWIDTH - 1) ? + TILEWIDTH : LEVWIDTH - xstart - 2; + yend = (ystart + TILEHEIGHT < LEVHEIGHT - 1) ? + TILEHEIGHT : LEVHEIGHT - ystart - 2; + + for (y = (ystart < 1) ? (unsigned) (1 - ystart) : 0U; y < yend; y++) + for (x = (xstart < 1) ? (unsigned) (1 - xstart) : 0U; x < xend; x++) { + locchar = block[y * TILEWIDTH + x]; + if ((locchar == BLOCK_WALL) && + ((*level)[ystart + y][xstart + x] == BLOCK_EMPTY)) { + (*level)[ystart + y][xstart + x] = BLOCK_WALL; + (*level)[ystart + y] + [LEVWIDTH - (xstart + x + 1)] = BLOCK_WALL; + } + } + + (*level)[ypos][xpos] = BLOCK_DOT_1; + (*level)[ypos][LEVWIDTH - xpos - 1] = BLOCK_DOT_1; + + return True; +} + +/* Tries certain combinations of blocks in the level recursively. */ +static unsigned +nextstep (pacmangamestruct *pp, + lev_t * level, const unsigned x, const unsigned y, + unsigned dirvec[], unsigned ndirs) +{ + unsigned dirpos, curdir, inc = 0; + int ret = 0; + + while (ndirs > 0) { + ndirs--; + if (ndirs == 0) { + curdir = dirvec[0]; + } + else { + dirpos = NRAND (ndirs); + curdir = dirvec[dirpos]; + /* nope, no bufoverflow, but ndirs - 1 + 1 */ + dirvec[dirpos] = dirvec[ndirs]; + dirvec[ndirs] = curdir; + } + + switch (curdir) { + case GO_UP: + if (y < 1 || (ret = creatlevelblock (pp, level, x, y - 1)) + == 0) + return 0; + break; + case GO_RIGHT: + if (x > LEVWIDTH - 2 || (ret = creatlevelblock (pp, level, x + 1, y)) + == 0) + return 0; + break; + case GO_DOWN: + if (y > LEVHEIGHT - 2 || (ret = creatlevelblock (pp, level, x, y + 1)) + == 0) + return 0; + break; + case GO_LEFT: + if (x < 1 || (ret = creatlevelblock (pp, level, x - 1, y)) + == 0) + return 0; + } + if (ret != -1) + inc += (unsigned) ret; + } + if (inc == 0) + inc = 1; + return inc; +} + +static int +creatlevelblock (pacmangamestruct *pp, + lev_t * level, const unsigned x, const unsigned y) +{ + unsigned tried = GETNB (TILES_COUNT); + unsigned tilenr; + unsigned ret; + lev_t savedlev; + + if (!pp->tiles) { + pp->tiles = (struct tiles *) malloc (sizeof (def_tiles)); + memcpy (pp->tiles, def_tiles, sizeof (def_tiles)); + } + + if (!((x < LEVWIDTH) && (y < LEVHEIGHT))) + return 0; + + if (checkunsetdef (level, x, y) != 0) + return -1; + + if (x == 0) + tried &= ~(1 << 0); + else if (x == 1) + tried &= ~(1 << 4 | 1 << 5 | 1 << 6 | 1 << 8 | 1 << 9 | 1 << 10); + else if (x == LEVWIDTH - 1) + tried &= ~(1 << 0); + else if (x == LEVWIDTH - 2) + tried &= ~(1 << 2 | 1 << 3 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 10); + + if (y == 1) + tried &= ~(1 << 2 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 9 | 1 << 10); + else if (y == 0) + tried &= ~(1 << 1); + else if (y == LEVHEIGHT - 1) + tried &= ~(1 << 1); + else if (y == LEVHEIGHT - 2) + tried &= ~(1 << 3 | 1 << 4 | 1 << 7 | 1 << 8 | 1 << 9 | 1 << 10); + + /* make a copy of the current level, so we can go back on the stack */ + (void) memcpy (&savedlev, level, sizeof (lev_t)); + + /* while there are still some blocks left to try */ + while (tried != 0x00) { + tilenr = tileprob[NRAND (MAXTILEPROB)]; + + if (!TESTNB (tried, tilenr)) + continue; + + if (tryset (level, x, y, pp->tiles[tilenr].block) != 0) { + if ((ret = nextstep (pp, level, x, y, pp->tiles[tilenr].dirvec, + pp->tiles[tilenr].ndirs)) != 0) { + return ret + 1; + } + (void) memcpy (level, &savedlev, sizeof (lev_t)); + } + tried &= ~(pp->tiles[tilenr].simular_to); + } + return 0; +} + +/* Fills up all empty space so there is wall everywhere. */ +static void +filllevel (lev_t * level) +{ + unsigned x, y; + + for (y = 0; y < LEVHEIGHT; y++) + for (x = 0; x < LEVWIDTH; x++) + if ((*level)[y][x] == BLOCK_EMPTY) + (*level)[y][x] = BLOCK_WALL; +} + + +/* Check to see if the x and y value are in the corners. + * we could probable compute these values once and avoid + * go through the loops every time. + */ +static void +top_left (lev_t * level, unsigned int *passed_x, unsigned int *passed_y) +{ + int x, y; + for (y = 0; y < LEVHEIGHT; y++) + for (x = 0; x < LEVWIDTH; x++) { + if (checkset (level, x, y) == 0) { + *passed_x = x; + *passed_y = y; + return; + } + } +} + + +static void +bottom_left (lev_t * level, unsigned int *passed_x, unsigned int *passed_y) +{ + int x, y; + for (y = LEVHEIGHT; y > -1; y--) + for (x = 0; x < LEVWIDTH; x++) { + if (checkset (level, x, y) == 0) { + *passed_x = x; + *passed_y = y; + return; + } + } +} + +static void +top_right (lev_t * level, unsigned int *passed_x, unsigned int *passed_y) +{ + int x, y; + + for (y = 0; y < LEVHEIGHT; y++) + for (x = LEVWIDTH; x >= 0; x--) { + if (checkset (level, x, y) == 0) { + *passed_x = x; + *passed_y = y; + return; + } + } +} + +static void +bottom_right (lev_t * level, unsigned int *passed_x, unsigned int *passed_y) +{ + int x, y; + + for (y = LEVHEIGHT; y >= 0; y--) + for (x = LEVWIDTH; x >= 0; x--) { + if (checkset (level, x, y) == 0) { + *passed_x = x; + *passed_y = y; + return; + } + } +} + +static void +init_bonus_dots (pacmangamestruct *pp, lev_t * level) +{ + unsigned int x = 0, y = 0; + top_left (level, &x, &y); + pp->bonus_dots[TOP_LEFT].x = x; + pp->bonus_dots[TOP_LEFT].y = y; + pp->bonus_dots[TOP_LEFT].eaten = False; + top_right (level, &x, &y); + pp->bonus_dots[TOP_RIGHT].x = x; + pp->bonus_dots[TOP_RIGHT].y = y; + pp->bonus_dots[TOP_RIGHT].eaten = False; + bottom_left (level, &x, &y); + pp->bonus_dots[BOTTOM_LEFT].x = x; + pp->bonus_dots[BOTTOM_LEFT].y = y; + pp->bonus_dots[BOTTOM_LEFT].eaten = False; + bottom_right (level, &x, &y); + pp->bonus_dots[BOTTOM_RIGHT].x = x; + pp->bonus_dots[BOTTOM_RIGHT].y = y; + pp->bonus_dots[BOTTOM_RIGHT].eaten = False; +} + +int +pacman_is_bonus_dot (pacmangamestruct *pp, int x, int y, int *idx) +{ + int ret = False; + int i; + for (i = 0; i < NUM_BONUS_DOTS; i++) { +/* fprintf(stderr,"is bonus: passed x (%d, %d) bonus (%d, %d)\n",x,y,bonus_dots[i].x, bonus_dots[i].y); */ + if (x == pp->bonus_dots[i].x && y == pp->bonus_dots[i].y) { + ret = True; + *idx = i; + break; + } + } + return ret; +} + +static void +check_bonus_idx (int idx) +{ + assert (0 <= idx && idx < NUM_BONUS_DOTS); +} + +int +pacman_bonus_dot_eaten (pacmangamestruct *pp, int idx) +{ + check_bonus_idx (idx); + return pp->bonus_dots[idx].eaten; +} + +void +pacman_eat_bonus_dot (pacmangamestruct *pp, int idx) +{ + check_bonus_idx (idx); + pp->bonus_dots[idx].eaten = True; +} + +void +pacman_bonus_dot_pos (pacmangamestruct *pp, int idx, int *x, int *y) +{ + check_bonus_idx (idx); + *x = pp->bonus_dots[idx].x; + *y = pp->bonus_dots[idx].y; +} + +/* Changes a level from a simple wall/nowall to a wall with rounded corners + and such. Stupid algorithm, could be done better! */ +static void +frmtlevel (pacmangamestruct *pp, lev_t * level) +{ + lev_t frmtlev; + int x, y; + int idx; + register unsigned poscond; + register unsigned poscond2; + + clearlevel (&frmtlev); + init_bonus_dots (pp, level); + for (y = 0; y < LEVHEIGHT; y++) + for (x = 0; x < LEVWIDTH; x++) { + + if (checkset (level, x, y) == 0) { + if (pacman_is_bonus_dot (pp, x, y, &idx)) { + frmtlev[y][x] = BLOCK_DOT_BONUS; + } + else { + frmtlev[y][x] = BLOCK_DOT_2; + } + continue; + } + + if ((*level)[y][x] == BLOCK_GHOST_ONLY) { + frmtlev[y][x] = BLOCK_GHOST_ONLY; + continue; + } + + poscond = + (checksetout (level, x - 1, y - 1) != 0 ? + 0x01U : 0U) | + (checksetout (level, x + 1, y - 1) != 0 ? + 0x02U : 0U) | + (checksetout (level, x + 1, y + 1) != 0 ? + 0x04U : 0U) | + (checksetout (level, x - 1, y + 1) != 0 ? 0x08U : 0U); + + poscond2 = + (checksetout (level, x - 1, y) != 0 ? + 0x01U : 0) | + (checksetout (level, x, y - 1) != 0 ? + 0x02U : 0) | + (checksetout (level, x + 1, y) != 0 ? + 0x04U : 0) | + (checksetout (level, x, y + 1) != 0 ? 0x08U : 0); + + switch (poscond) { + /* completely filled */ + case 0x01U | 0x02U | 0x04U | 0x08U: + frmtlev[y][x] = BLOCK_EMPTY; + continue; + + /* left to top corner */ + case 0x01U: + frmtlev[y][x] = BLOCK_WALL_TL; + continue; + /* top to right corner */ + case 0x02U: + frmtlev[y][x] = BLOCK_WALL_TR; + continue; + /* right to bottom corner */ + case 0x04U: + frmtlev[y][x] = BLOCK_WALL_BR; + continue; + /* bottom to left corner */ + case 0x08U: + frmtlev[y][x] = BLOCK_WALL_BL; + continue; + } + + switch (poscond2) { + case 0x01U | 0x04U: + case 0x01U | 0x04U | 0x08U: + case 0x01U | 0x04U | 0x02U: + frmtlev[y][x] = BLOCK_WALL_HO; + continue; + case 0x02U | 0x08U: + case 0x02U | 0x08U | 0x01U: + case 0x02U | 0x08U | 0x04U: + frmtlev[y][x] = BLOCK_WALL_VE; + continue; + case 0x01U | 0x02U: + frmtlev[y][x] = BLOCK_WALL_TL; + continue; + case 0x02U | 0x04U: + frmtlev[y][x] = BLOCK_WALL_TR; + continue; + case 0x04U | 0x08U: + frmtlev[y][x] = BLOCK_WALL_BR; + continue; + case 0x08U | 0x01U: + frmtlev[y][x] = BLOCK_WALL_BL; + continue; + } + switch (poscond) { + case 0x02U | 0x04U | 0x08U: + frmtlev[y][x] = BLOCK_WALL_TL; + continue; + case 0x01U | 0x04U | 0x08U: + frmtlev[y][x] = BLOCK_WALL_TR; + continue; + case 0x01U | 0x02U | 0x08U: + frmtlev[y][x] = BLOCK_WALL_BR; + continue; + case 0x01U | 0x02U | 0x04U: + frmtlev[y][x] = BLOCK_WALL_BL; + continue; + } + frmtlev[y][x] = BLOCK_EMPTY; + } + (void) memcpy ((lev_t *) level, (lev_t *) & frmtlev, sizeof (lev_t)); +} + +/* Counts the number of dots in the level, and returns that number. */ +static unsigned +countdots (pacmangamestruct *pp) +{ + unsigned i, count = 0; + + for (i = 0; i < LEVWIDTH * LEVHEIGHT; i++) + if (pp->level[i] == BLOCK_DOT_2 || pp->level[i] == BLOCK_DOT_BONUS) + count++; + + return count; +} + +/* Creates a new level, and places that in the pacmangamestruct. */ +int +pacman_createnewlevel (pacmangamestruct *pp) +{ + lev_t *level; + unsigned dirvec[1] = { GO_UP }; + unsigned ret = 0, i = 0; + + if ((level = (lev_t *) calloc (1, sizeof (lev_t))) == NULL) + return i; + + if (NRAND (2) == 0) { + + do { + clearlevel (level); + createjail (level, JAILWIDTH, JAILHEIGHT); + if ((ret = nextstep (pp, level, LEVWIDTH / 2 - 1, + LEVHEIGHT / 2 - JAILHEIGHT / 2 - 3, + dirvec, 1)) == 0) { + (void) free ((void *) level); + return i; + } + } while (ret * 100 < (LEVWIDTH * LEVHEIGHT * MINDOTPERC)); + + filllevel (level); + frmtlevel (pp, level); + finishjail (level, JAILWIDTH, JAILHEIGHT); + } + else { + (void) memcpy (level, stdlevel, sizeof (lev_t)); + frmtlevel (pp, level); + i = 1; + } + copylevel (pp->level, level); + pp->dotsleft = countdots (pp); + + (void) free ((void *) level); + return i; +} + +/* Checks if a position is allowable for ghosts/pacs to enter. */ +int +pacman_check_pos (pacmangamestruct * pp, int y, int x, int ghostpass) +{ + if ((pp->level[y * LEVWIDTH + x] == BLOCK_DOT_2) || + (pp->level[y * LEVWIDTH + x] == BLOCK_EMPTY) || + (pp->level[y * LEVWIDTH + x] == BLOCK_DOT_BONUS) || + ((pp->level[y * LEVWIDTH + x] == BLOCK_GHOST_ONLY) && ghostpass)) { + return 1; + } + return 0; +} + +/* Checks if there is a dot on the specified position in the level. */ +int +pacman_check_dot (pacmangamestruct * pp, unsigned int x, unsigned int y) +{ + if (x >= LEVWIDTH || y >= LEVHEIGHT) + return 0; + if (pp->level[y * LEVWIDTH + x] == BLOCK_DOT_2) + return 1; + return 0; +} diff --git a/non-wgl/pacman_level.h b/non-wgl/pacman_level.h new file mode 100644 index 0000000..0eccc33 --- /dev/null +++ b/non-wgl/pacman_level.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2002 by Edwin de Jong . + * + * 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. + */ + +#ifndef __PACMAN_LEVEL_H__ +#define __PACMAN_LEVEL_H__ + +/* typedef struct { */ +/* int x, y; */ +/* } XY; */ + +extern int pacman_createnewlevel (pacmangamestruct *); +extern int pacman_check_pos (pacmangamestruct *, int y, int x, int ghostpass); +extern int pacman_check_dot (pacmangamestruct *, + unsigned int x, unsigned int y); +extern int pacman_is_bonus_dot (pacmangamestruct *, int x, int y, int *idx); +extern int pacman_bonus_dot_eaten (pacmangamestruct *, int idx); +extern void pacman_eat_bonus_dot (pacmangamestruct *, int idx); +extern void pacman_bonus_dot_pos (pacmangamestruct *, int idx, int *x, int *y); +extern void pacman_get_jail_opening (int *x, int *y); +#endif /* __PACMAN_LEVEL_H__ */ diff --git a/non-wgl/pedal.c b/non-wgl/pedal.c new file mode 100644 index 0000000..751da61 --- /dev/null +++ b/non-wgl/pedal.c @@ -0,0 +1,348 @@ +/* + * pedal + * + * Based on a program for some old PDP-11 Graphics Display Processors + * at CMU. + * + * X version by + * + * Dale Moore + * 24-Jun-1994 + * + * Copyright (c) 1994, by Carnegie Mellon University. Permission to use, + * copy, modify, distribute, and sell this software and its documentation + * for any purpose is hereby granted without fee, provided fnord 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 fnord this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + */ + +#include "screenhack.h" +#include +#include +#include "erase.h" + +char *background = "black"; +char *foreground = "white"; +int delay = 5; +int maxlines = 1000; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "5", t_Int}, + {&maxlines, "maxlines", NULL, "1000", t_Int}, +}; + +/* If MAXLINES is too big, we might not be able to get it + * to the X server in the 2byte length field. Must be less + * than 16k + */ +#define MAXLINES (16 * 1024) +#define MAXPOINTS MAXLINES + +/* + * If the pedal has only this many lines, it must be ugly and we dont + * want to see it. + */ +#define MINLINES 7 + + +struct state { + Display *dpy; + Window window; + + XPoint *points; + + int sizex, sizey; + int delay; + int maxlines; + GC gc; + XColor foreground, background; + Colormap cmap; + + eraser_state *eraser; + int erase_p; +}; + + +/* + * Routine (Macro actually) + * mysin + * Description: + * Assume that degrees is .. oh 360... meaning that + * there are 360 degress in a circle. Then this function + * would return the sin of the angle in degrees. But lets + * say that they are really big degrees, with 4 big degrees + * the same as one regular degree. Then this routine + * would be called mysin(t, 90) and would return sin(t degrees * 4) + */ +#define mysin(t, degrees) sin(t * 2 * M_PI / (degrees)) +#define mycos(t, degrees) cos(t * 2 * M_PI / (degrees)) + +/* + * Macro: + * rand_range + * Description: + * Return a random number between a inclusive and b exclusive. + * rand (3, 6) returns 3 or 4 or 5, but not 6. + */ +#define rand_range(a, b) (a + random() % (b - a)) + + +static int +gcd(int m, int n) /* Greatest Common Divisor (also Greates common factor). */ +{ + int r; + + for (;;) { + r = m % n; + if (r == 0) return (n); + m = n; + n = r; + } +} + +static int numlines (int a, int b, int d) +/* + * Description: + * + * Given parameters a and b, how many lines will we have to draw? + * + * Algorithm: + * + * This algorithm assumes that r = sin (theta * a), where we + * evaluate theta on multiples of b. + * + * LCM (i, j) = i * j / GCD (i, j); + * + * So, at LCM (b, 360) we start over again. But since we + * got to LCM (b, 360) by steps of b, the number of lines is + * LCM (b, 360) / b. + * + * If a is odd, then at 180 we cross over and start the + * negative. Someone should write up an elegant way of proving + * this. Why? Because I'm not convinced of it myself. + * + */ +{ +#define odd(x) (x & 1) +#define even(x) (!odd(x)) + if ( odd(a) && odd(b) && even(d)) d /= 2; + return (d / gcd (d, b)); +#undef odd +} + +static int +compute_pedal(struct state *st, XPoint *points, int maxpoints) +/* + * Description: + * + * Basically, it's combination spirograph and string art. + * Instead of doing lines, we just use a complex polygon, + * and use an even/odd rule for filling in between. + * + * The spirograph, in mathematical terms is a polar + * plot of the form r = sin (theta * c); + * The string art of this is that we evaluate that + * function only on certain multiples of theta. That is + * we let theta advance in some random increment. And then + * we draw a straight line between those two adjacent points. + * + * Eventually, the lines will start repeating themselves + * if we've evaluated theta on some rational portion of the + * whole. + * + * The number of lines generated is limited to the + * ratio of the increment we put on theta to the whole. + * If we say that there are 360 degrees in a circle, then we + * will never have more than 360 lines. + * + * Return: + * + * The number of points. + * + */ +{ + int a, b, d; /* These describe a unique pedal */ + + double r; + int theta = 0; + XPoint *pp = st->points; + int count; + int numpoints; + + /* Just to make sure that this division is not done inside the loop */ + int h_width = st->sizex / 2, h_height = st->sizey / 2 ; + + for (;;) { + d = rand_range (MINLINES, st->maxlines); + + a = rand_range (1, d); + b = rand_range (1, d); + numpoints = numlines(a, b, d); + if (numpoints > MINLINES) break; + } + + /* it might be nice to try to move as much sin and cos computing + * (or at least the argument computing) out of the loop. + */ + for (count = numpoints; count-- ; ) + { + r = mysin (theta * a, d); + + /* Convert from polar to cartesian coordinates */ + /* We could round the results, but coercing seems just fine */ + pp->x = mysin (theta, d) * r * h_width + h_width; + pp->y = mycos (theta, d) * r * h_height + h_height; + + /* Advance index into array */ + pp++; + + /* Advance theta */ + theta += b; + theta %= d; + } + + return(numpoints); +} + +static void * +pedal_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + + st->dpy = dpy; + st->window = window; + + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay = delay; + if (st->delay < 0) st->delay = 0; + + //st->maxlines = get_integer_resource (st->dpy, "maxlines", "Integer"); + st->maxlines = maxlines; + if (st->maxlines < MINLINES) st->maxlines = MINLINES; + else if (st->maxlines > MAXLINES) st->maxlines = MAXLINES; + + st->points = (XPoint *)malloc(sizeof(XPoint) * st->maxlines); + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->sizex = xgwa.width; + st->sizey = xgwa.height; + + st->cmap = xgwa.colormap; + + gcv.function = GXcopy; + //gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + //gcv.background = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, st->cmap, foreground); + gcv.background = load_color(st->dpy, st->cmap, background); + st->gc = XCreateGC (st->dpy, st->window, GCForeground | GCBackground |GCFunction, &gcv); + + return st; +} + +/* + * Since the XFillPolygon doesn't require that the last + * point == first point, the number of points is the same + * as the number of lines. We just let XFillPolygon supply + * the line from the last point to the first point. + * + */ +static unsigned long +pedal_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int numpoints; + int erase_delay = 10000; + int long_delay = 1000000 * st->delay; + + if (st->erase_p || st->eraser) { + st->eraser = erase_window (dpy, window, st->eraser); + st->erase_p = 0; + return (st->eraser ? erase_delay : 1000000); + } + + numpoints = compute_pedal(st, st->points, st->maxlines); + + /* Pick a new foreground color (added by jwz) */ + if (! mono_p) + { + XColor color; + hsv_to_rgb (random()%360, 1.0, 1.0, + &color.red, &color.green, &color.blue); + if (XAllocColor (st->dpy, st->cmap, &color)) + { + XSetForeground (st->dpy, st->gc, color.pixel); + XFreeColors (st->dpy, st->cmap, &st->foreground.pixel, 1, 0); + st->foreground.red = color.red; + st->foreground.green = color.green; + st->foreground.blue = color.blue; + st->foreground.pixel = color.pixel; + } + } + + XFillPolygon (st->dpy, st->window, st->gc, st->points, numpoints, + Complex, CoordModeOrigin); + + st->erase_p = 1; + return long_delay; +} + +static void +pedal_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->sizex = w; + st->sizey = h; +} + +#if 0 + static Bool + pedal_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +pedal_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + + +/* + * If we are trying to save the screen, the background + * should be dark. + */ +static const char *pedal_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 5", + "*maxlines: 1000", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec pedal_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-maxlines", ".maxlines", XrmoptionSepArg, 0 }, + { "-foreground", ".foreground", XrmoptionSepArg, 0 }, + { "-background", ".background", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Pedal", pedal) diff --git a/non-wgl/pedal.vcproj b/non-wgl/pedal.vcproj new file mode 100644 index 0000000..d458891 --- /dev/null +++ b/non-wgl/pedal.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/penrose.c b/non-wgl/penrose.c new file mode 100644 index 0000000..7d913f8 --- /dev/null +++ b/non-wgl/penrose.c @@ -0,0 +1,1363 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* penrose --- quasiperiodic tilings */ + +/* As reported in News of the Weird: + + In April, Sir Roger Penrose, a British math professor who has worked + with Stephen Hawking on such topics as relativity, black holes, and + whether time has a beginning, filed a copyright-infringement lawsuit + against the Kimberly-Clark Corporation, which Penrose said copied a + pattern he created (a pattern demonstrating that "a nonrepeating + pattern could exist in nature") for its Kleenex quilted toilet paper. + Penrose said he doesn't like litigation but, "When it comes to the + population of Great Britain being invited by a multinational to wipe + their bottoms on what appears to be the work of a Knight of the + Realm, then a last stand must be taken." + + NOTW #491, 4-jul-1997, by Chuck Shepherd. + http://www.nine.org/notw/notw.html + */ + +#if 0 +static const char sccsid[] = "@(#)penrose.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1996 by Timo Korvola + * + * 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 + * 09-Sep-1996: Written. + */ + +/*- +Be careful, this probably still has a few bugs (many of which may only +appear with a very low probability). These are seen with -verbose . +If one of these are hit penrose will reinitialize. +*/ + +/*- + * See Onoda, Steinhardt, DiVincenzo and Socolar in + * Phys. Rev. Lett. 60, #25, 1988 or + * Strandburg in Computers in Physics, Sep/Oct 1991. + * + * This implementation uses the simpler version of the growth + * algorithm, i.e., if there are no forced vertices, a randomly chosen + * tile is added to a randomly chosen vertex (no preference for those + * 108 degree angles). + * + * There are two essential differences to the algorithm presented in + * the literature: First, we do not allow the tiling to enclose an + * untiled area. Whenever this is in danger of happening, we just + * do not add the tile, hoping for a better random choice the next + * time. Second, when choosing a vertex randomly, we will take + * one that lies within the viewport if available. If this seems to + * cause enclosures in the forced rule case, we will allow invisible + * vertices to be chosen. + * + * Tiling is restarted whenever one of the following happens: there + * are no incomplete vertices within the viewport or the tiling has + * extended a window's length beyond the edge of the window + * horizontally or vertically or forced rule choice has failed 100 + * times due to areas about to become enclosed. + * + * Introductory info: + * Science News March 23 1985 Vol 127, No. 12 + * Science News July 16 1988 Vol 134, No. 3 + * The Economist Sept 17 1988 pg. 100 + * + */ + +#define STANDALONE + +#define MODE_penrose +#define DELAY 10000 +#define SIZE_ 40 +#define NCOLORS 64 +#define DEFAULTS "*delay: 10000 \n" \ + "*size: 40 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define refresh_penrose 0 +# define penrose_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* from the xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +#endif /* !STANDALONE */ + +#ifdef MODE_penrose + +#define DEF_AMMANN "False" + +static Bool ammann = False; + +static XrmOptionDescRec opts[] = +{ + {"-ammann", ".penrose.ammann", XrmoptionNoArg, "on"}, + {"+ammann", ".penrose.ammann", XrmoptionNoArg, "off"} +}; +static argtype vars[] = +{ + {&ammann, "ammann", "Ammann", DEF_AMMANN, t_Bool} +}; +static OptionStruct desc[] = +{ + {"-/+ammann", "turn on/off Ammann lines"} +}; + +ENTRYPOINT ModeSpecOpt penrose_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct penrose_description = +{"penrose", "init_penrose", "draw_penrose", "release_penrose", + "init_penrose", "init_penrose", (char *) NULL, &penrose_opts, + 10000, 1, 1, -40, 64, 1.0, "", + "Shows Penrose's quasiperiodic tilings", 0, NULL}; + +#endif + +/*- + * Annoyingly the ANSI C library people have reserved all identifiers + * ending with _t for future use. Hence we use _c as a suffix for + * typedefs (c for class, although this is not C++). + */ + +#define MINSIZE 5 + +/*- + * In theory one could fit 10 tiles to a single vertex. However, the + * vertex rules only allow at most seven tiles to meet at a vertex. + */ + +#define CELEBRATE 31415 /* This causes a pause, an error occurred. */ +#define COMPLETION 3141 /* This causes a pause, tiles filled up screen. */ + +#define MAX_TILES_PER_VERTEX 7 +#define N_VERTEX_RULES 8 +#define ALLOC_NODE(type) (type *)malloc(sizeof (type)) + +/*- + * These are used to specify directions. They can also be used in bit + * masks to specify a combination of directions. + */ +#define S_LEFT 1 +#define S_RIGHT 2 + + +/*- + * We do not actually maintain objects corresponding to the tiles since + * we do not really need them and they would only consume memory and + * cause additional bookkeeping. Instead we only have vertices, and + * each vertex lists the type of each adjacent tile as well as the + * position of the vertex on the tile (hereafter refered to as + * "corner"). These positions are numbered in counterclockwise order + * so that 0 is where two double arrows meet (see one of the + * articles). The tile type and vertex number are stored in a single + * integer (we use char, and even most of it remains unused). + * + * The primary use of tile objects would be draw traversal, but we do + * not currently do redraws at all (we just start over). + */ +#define VT_CORNER_MASK 0x3 +#define VT_TYPE_MASK 0x4 +#define VT_THIN 0 +#define VT_THICK 0x4 +#define VT_BITS 3 +#define VT_TOTAL_MASK 0x7 + +typedef unsigned char vertex_type_c; + +/*- + * These allow one to compute the types of the other corners of the tile. If + * you are standing at a vertex of type vt looking towards the middle of the + * tile, VT_LEFT( vt) is the vertex on your left etc. + */ +#define VT_LEFT( vt) ((((vt) - 1) & VT_CORNER_MASK) | (((vt) & VT_TYPE_MASK))) +#define VT_RIGHT( vt) ((((vt) + 1) & VT_CORNER_MASK) | (((vt) & VT_TYPE_MASK))) +#define VT_FAR( vt) ((vt) ^ 2) + + +/*- + * Since we do not do redraws, we only store the vertices we need. These are + * the ones with still some empty space around them for the growth algorithm + * to fill. + * + * Here we use a doubly chained ring-like structure as vertices often need + * to be removed or inserted (they are kept in geometrical order + * circling the tiled area counterclockwise). The ring is refered to by + * a pointer to one more or less random node. When deleting nodes one + * must make sure that this pointer continues to refer to a valid + * node. A vertex count is maintained to make it easier to pick + * vertices randomly. + */ +typedef struct forced_node forced_node_c; + +typedef struct fringe_node { + struct fringe_node *prev; + struct fringe_node *next; + /* These are numbered counterclockwise. The gap, if any, lies + between the last and first tiles. */ + vertex_type_c tiles[MAX_TILES_PER_VERTEX]; + int n_tiles; + /* A bit mask used to indicate vertex rules that are still applicable for + completing this vertex. Initialize this to (1 << N_VERTEX_RULES) - 1, + i.e., all ones, and the rule matching functions will automatically mask + out rules that no longer match. */ + unsigned char rule_mask; + /* If the vertex is on the forced vertex list, this points to the + pointer to the appropriate node in the list. To remove the + vertex from the list just set *list_ptr to the next node, + deallocate and decrement node count. */ + struct forced_node **list_ptr; + /* Screen coordinates. */ + XPoint loc; + /* We also keep track of 5D coordinates to avoid rounding errors. + These are in units of edge length. */ + int fived[5]; + /* This is used to quickly check if a vertex is visible. */ + unsigned char off_screen; +} fringe_node_c; + +typedef struct { + fringe_node_c *nodes; + /* This does not count off-screen nodes. */ + int n_nodes; +} fringe_c; + + +/*- + * The forced vertex pool contains vertices where at least one + * side of the tiled region can only be extended in one way. Note + * that this does not necessarily mean that there would only be one + * applicable rule. forced_sides are specified using S_LEFT and + * S_RIGHT as if looking at the untiled region from the vertex. + */ +struct forced_node { + fringe_node_c *vertex; + unsigned forced_sides; + struct forced_node *next; +}; + +typedef struct { + forced_node_c *first; + int n_nodes, n_visible; +} forced_pool_c; + + +/* The tiles are listed in counterclockwise order. */ +typedef struct { + vertex_type_c tiles[MAX_TILES_PER_VERTEX]; + int n_tiles; +} vertex_rule_c; + +static vertex_rule_c vertex_rules[N_VERTEX_RULES] = +{ + { + {VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2}, 5}, + { + {VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THICK | 0}, 5}, + { + {VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THIN | 0}, 4}, + { + {VT_THICK | 2, VT_THICK | 2, VT_THIN | 1, VT_THIN | 3, VT_THICK | 2, + VT_THIN | 1, VT_THIN | 3}, 7}, + { + {VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, + VT_THIN | 1, VT_THIN | 3}, 6}, + { + {VT_THICK | 1, VT_THICK | 3, VT_THIN | 2}, 3}, + { + {VT_THICK | 0, VT_THIN | 0, VT_THIN | 0}, 3}, + { + {VT_THICK | 2, VT_THIN | 1, VT_THICK | 3, VT_THICK | 1, VT_THIN | 3}, 5} +}; + + +/* Match information returned by match_rules. */ +typedef struct { + int rule; + int pos; +} rule_match_c; + + +/* Occasionally floating point coordinates are needed. */ +typedef struct { + float x, y; +} fcoord_c; + + +/* All angles are measured in multiples of 36 degrees. */ +typedef int angle_c; + +static angle_c vtype_angles[] = +{4, 1, 4, 1, 2, 3, 2, 3}; + +#define vtype_angle( v) (vtype_angles[ v]) + + +/* This is the data related to the tiling of one screen. */ +typedef struct { + int width, height; + XPoint origin; + int edge_length; + fringe_c fringe; + forced_pool_c forced; + int done, failures; + unsigned long thick_color, thin_color; + int busyLoop; + Bool ammann; + float ammann_r; + fcoord_c fived_table[5]; +} tiling_c; + +static tiling_c *tilings = (tiling_c *) NULL; + + + +/* Direction angle of an edge. */ +static angle_c +vertex_dir(ModeInfo * mi, fringe_node_c * vertex, unsigned side) +{ + tiling_c *tp = &tilings[MI_SCREEN(mi)]; + fringe_node_c *v2 = + (side == S_LEFT ? vertex->next : vertex->prev); + register int i; + + for (i = 0; i < 5; i++) + switch (v2->fived[i] - vertex->fived[i]) { + case 1: + return 2 * i; + case -1: + return (2 * i + 5) % 10; + } + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, + "Weirdness in vertex_dir (this has been reported)\n"); + for (i = 0; i < 5; i++) + (void) fprintf(stderr, "v2->fived[%d]=%d, vertex->fived[%d]=%d\n", + i, v2->fived[i], i, vertex->fived[i]); + } + tp->busyLoop = CELEBRATE; + return 0; +} + + +/* Move one step to a given direction. */ +static void +add_unit_vec(angle_c dir, int *fived) +{ + static const int dir2i[] = {0, 3, 1, 4, 2}; + + while (dir < 0) + dir += 10; + fived[dir2i[dir % 5]] += (dir % 2 ? -1 : 1); +} + + +/* For comparing coordinates. */ +#define fived_equal( f1, f2) (!memcmp( (f1), (f2), 5 * sizeof( int))) + + +/*- + * This computes screen coordinates from 5D representation. Note that X + * uses left-handed coordinates (y increases downwards). + */ +static void +fived_to_loc(int fived[], tiling_c * tp, XPoint *pt) +{ + float fifth = 8 * atan(1.) / 5; + register int i; + register float r; + register fcoord_c offset; + + *pt = tp->origin; + offset.x = 0.0; + offset.y = 0.0; + if (tp->fived_table[0].x == .0) + for (i = 0; i < 5; i++) { + tp->fived_table[i].x = cos(fifth * i); + tp->fived_table[i].y = sin(fifth * i); + } + for (i = 0; i < 5; i++) { + r = fived[i] * tp->edge_length; + offset.x += r * tp->fived_table[i].x; + offset.y -= r * tp->fived_table[i].y; + } + (*pt).x += (int) (offset.x + .5); + (*pt).y += (int) (offset.y + .5); +} + + +/* Mop up dynamic data for one screen. */ +static void +free_penrose(tiling_c * tp) +{ + register fringe_node_c *fp1, *fp2; + register forced_node_c *lp1, *lp2; + + if (tp->fringe.nodes == NULL) + return; + fp1 = tp->fringe.nodes; + do { + fp2 = fp1; + fp1 = fp1->next; + (void) free((void *) fp2); + } while (fp1 != tp->fringe.nodes); + tp->fringe.nodes = (fringe_node_c *) NULL; + for (lp1 = tp->forced.first; lp1 != 0;) { + lp2 = lp1; + lp1 = lp1->next; + (void) free((void *) lp2); + } + tp->forced.first = 0; +} + + +/* Called to init the mode. */ +ENTRYPOINT void +init_penrose(ModeInfo * mi) +{ + tiling_c *tp; + fringe_node_c *fp; + int i, size; + + if (tilings == NULL) { + if ((tilings = (tiling_c *) calloc(MI_NUM_SCREENS(mi), + sizeof (tiling_c))) == NULL) + return; + } + tp = &tilings[MI_SCREEN(mi)]; + +#if 0 /* if you do this, then the -ammann and -no-ammann options don't work. + -- jwz */ + if (MI_IS_FULLRANDOM(mi)) + tp->ammann = (Bool) (LRAND() & 1); + else +#endif /* 0 */ + tp->ammann = ammann; + + tp->done = False; + tp->busyLoop = 0; + tp->failures = 0; + tp->width = MI_WIDTH(mi); + tp->height = MI_HEIGHT(mi); + if (MI_NPIXELS(mi) > 2) { + tp->thick_color = NRAND(MI_NPIXELS(mi)); + /* Insure good contrast */ + tp->thin_color = (NRAND(2 * MI_NPIXELS(mi) / 3) + tp->thick_color + + MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi); + } + size = MI_SIZE(mi); + if (size < -MINSIZE) + tp->edge_length = NRAND(MIN(-size, MAX(MINSIZE, + MIN(tp->width, tp->height) / 2)) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) { + if (!size) + tp->edge_length = MAX(MINSIZE, MIN(tp->width, tp->height) / 2); + else + tp->edge_length = MINSIZE; + } else + tp->edge_length = MIN(size, MAX(MINSIZE, + MIN(tp->width, tp->height) / 2)); + tp->origin.x = (tp->width / 2 + NRAND(tp->width)) / 2; + tp->origin.y = (tp->height / 2 + NRAND(tp->height)) / 2; + tp->fringe.n_nodes = 2; + if (tp->fringe.nodes != NULL) + free_penrose(tp); + if (tp->fringe.nodes != NULL || tp->forced.first != 0) { + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in init_penrose()\n"); + (void) fprintf(stderr, "tp->fringe.nodes = NULL && tp->forced.first = 0\n"); + } + free_penrose(tp); /* Try again */ + tp->done = True; + } + tp->forced.n_nodes = tp->forced.n_visible = 0; + if ((fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c)) == NULL) { + free_penrose(tp); + return; + } + if (fp == 0) { + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in init_penrose()\n"); + (void) fprintf(stderr, "fp = 0\n"); + } + if ((fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c)) == NULL) { + free_penrose(tp); + return; + } + tp->done = True; + } + /* First vertex. */ + fp->rule_mask = (1 << N_VERTEX_RULES) - 1; + fp->list_ptr = 0; + if ((fp->prev = fp->next = ALLOC_NODE(fringe_node_c)) == NULL) { + free_penrose(tp); + return; + } + if (fp->next == 0) { + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in init_penrose()\n"); + (void) fprintf(stderr, "fp->next = 0\n"); + } + if ((fp->prev = fp->next = ALLOC_NODE(fringe_node_c)) == NULL) { + free_penrose(tp); + return; + } + tp->done = True; + } + fp->n_tiles = 0; + fp->loc = tp->origin; + fp->off_screen = False; + for (i = 0; i < 5; i++) + fp->fived[i] = 0; + + /* Second vertex. */ + *(fp->next) = *fp; + fp->next->prev = fp->next->next = fp; + fp = fp->next; + i = NRAND(5); + fp->fived[i] = 2 * NRAND(2) - 1; + fived_to_loc(fp->fived, tp, &(fp->loc)); + /* That's it! We have created our first edge. */ +} + +/*- + * This attempts to match the configuration of vertex with the vertex + * rules. The return value is a total match count. If matches is + * non-null, it will be used to store information about the matches + * and must be large enough to contain it. To play it absolutely + * safe, allocate room for MAX_TILES_PER_VERTEX * N_VERTEX_RULES + * entries when searching all matches. The rule mask of vertex will + * be applied and rules masked out will not be searched. Only strict + * subsequences match. If first_only is true, the search stops when + * the first match is found. Otherwise all matches will be found and + * the rule_mask of vertex will be updated, which also happens in + * single-match mode if no match is found. + */ +static int +match_rules(fringe_node_c * vertex, rule_match_c * matches, int first_only) +{ + /* I will assume that I can fit all the relevant bits in vertex->tiles + into one unsigned long. With 3 bits per element and at most 7 + elements this means 21 bits, which should leave plenty of room. + After packing the bits the rest is just integer comparisons and + some bit shuffling. This is essentially Rabin-Karp without + congruence arithmetic. */ + register int i, j; + int hits = 0, good_rules[N_VERTEX_RULES], n_good = 0; + unsigned long + vertex_hash = 0, lower_bits_mask = ~(VT_TOTAL_MASK << VT_BITS * (vertex->n_tiles - 1)); + unsigned new_rule_mask = 0; + + for (i = 0; i < N_VERTEX_RULES; i++) + if (vertex->n_tiles >= vertex_rules[i].n_tiles) + vertex->rule_mask &= ~(1 << i); + else if (vertex->rule_mask & 1 << i) + good_rules[n_good++] = i; + for (i = 0; i < vertex->n_tiles; i++) + vertex_hash |= (unsigned long) vertex->tiles[i] << (VT_BITS * i); + + for (j = 0; j < n_good; j++) { + unsigned long rule_hash = 0; + vertex_rule_c *vr = vertex_rules + good_rules[j]; + + for (i = 0; i < vertex->n_tiles; i++) + rule_hash |= (unsigned long) vr->tiles[i] << (VT_BITS * i); + if (rule_hash == vertex_hash) { + if (matches != 0) { + matches[hits].rule = good_rules[j]; + matches[hits].pos = 0; + } + hits++; + if (first_only) + return hits; + else + new_rule_mask |= 1 << good_rules[j]; + } + for (i = vr->n_tiles - 1; i > 0; i--) { + rule_hash = vr->tiles[i] | (rule_hash & lower_bits_mask) << VT_BITS; + if (vertex_hash == rule_hash) { + if (matches != 0) { + matches[hits].rule = good_rules[j]; + matches[hits].pos = i; + } + hits++; + if (first_only) + return hits; + else + new_rule_mask |= 1 << good_rules[j]; + } + } + } + vertex->rule_mask = new_rule_mask; + return hits; +} + + +/*- + * find_completions finds the possible ways to add a tile to a vertex. + * The return values is the number of such possibilities. You must + * first call match_rules to produce matches and n_matches. sides + * specifies which side of the vertex to extend and can be S_LEFT or + * S_RIGHT. If results is non-null, it should point to an array large + * enough to contain the results, which will be stored there. + * MAX_COMPL elements will always suffice. If first_only is true we + * stop as soon as we find one possibility (NOT USED). + */ +#define MAX_COMPL 2 + +static int +find_completions(fringe_node_c * vertex, rule_match_c * matches, int n_matches, + unsigned side, vertex_type_c * results /*, int first_only */ ) +{ + int n_res = 0, cont; + register int i, j; + vertex_type_c buf[MAX_COMPL]; + + if (results == 0) + results = buf; + if (n_matches <= 0) + return 0; + for (i = 0; i < n_matches; i++) { + vertex_rule_c *rule = vertex_rules + matches[i].rule; + int pos = (matches[i].pos + + (side == S_RIGHT ? vertex->n_tiles : rule->n_tiles - 1)) + % rule->n_tiles; + vertex_type_c vtype = rule->tiles[pos]; + + cont = 1; + for (j = 0; j < n_res; j++) + if (vtype == results[j]) { + cont = 0; + break; + } + if (cont) + results[n_res++] = vtype; + } + return n_res; +} + + +/*- + * Draw a tile on the display. Vertices must be given in a + * counterclockwise order. vtype is the vertex type of v1 (and thus + * also gives the tile type). + */ +static void +draw_tile(fringe_node_c * v1, fringe_node_c * v2, + fringe_node_c * v3, fringe_node_c * v4, + vertex_type_c vtype, ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + tiling_c *tp = &tilings[MI_SCREEN(mi)]; + XPoint pts[5]; + vertex_type_c corner = vtype & VT_CORNER_MASK; + + if (v1->off_screen && v2->off_screen && v3->off_screen && v4->off_screen) + return; + pts[corner] = v1->loc; + pts[VT_RIGHT(corner)] = v2->loc; + pts[VT_FAR(corner)] = v3->loc; + pts[VT_LEFT(corner)] = v4->loc; + pts[4] = pts[0]; + if (MI_NPIXELS(mi) > 2) { + if ((vtype & VT_TYPE_MASK) == VT_THICK) + XSetForeground(display, gc, MI_PIXEL(mi, tp->thick_color)); + else + XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color)); + } else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + XFillPolygon(display, window, gc, pts, 4, Convex, CoordModeOrigin); + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XDrawLines(display, window, gc, pts, 5, CoordModeOrigin); + + if (tp->ammann) { + /* Draw some Ammann lines for debugging purposes. This will probably + fail miserably on a b&w display. */ + + if ((vtype & VT_TYPE_MASK) == VT_THICK) { + + if (tp->ammann_r == .0) { + float pi10 = 2 * atan(1.) / 5; + + tp->ammann_r = 1 - sin(pi10) / (2 * sin(3 * pi10)); + } + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color)); + else { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter); + } + XDrawLine(display, window, gc, + (int) (tp->ammann_r * pts[3].x + (1 - tp->ammann_r) * pts[0].x + .5), + (int) (tp->ammann_r * pts[3].y + (1 - tp->ammann_r) * pts[0].y + .5), + (int) (tp->ammann_r * pts[1].x + (1 - tp->ammann_r) * pts[0].x + .5), + (int) (tp->ammann_r * pts[1].y + (1 - tp->ammann_r) * pts[0].y + .5)); + if (MI_NPIXELS(mi) <= 2) + XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter); + } else { + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, tp->thick_color)); + else { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter); + } + XDrawLine(display, window, gc, + (int) ((pts[3].x + pts[2].x) / 2 + .5), + (int) ((pts[3].y + pts[2].y) / 2 + .5), + (int) ((pts[1].x + pts[2].x) / 2 + .5), + (int) ((pts[1].y + pts[2].y) / 2 + .5)); + if (MI_NPIXELS(mi) <= 2) + XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter); + } + } +} + +/*- + * Update the status of this vertex on the forced vertex queue. If + * the vertex has become untileable set tp->done. This is supposed + * to detect dislocations -- never call this routine with a completely + * tiled vertex. + * + * Check for untileable vertices in check_vertex and stop tiling as + * soon as one finds one. I don't know if it is possible to run out + * of forced vertices while untileable vertices exist (or will + * cavities inevitably appear). If this can happen, add_random_tile + * might get called with an untileable vertex, causing ( n <= 1). + * (This is what the tp->done checks for). + * + * A delayLoop celebrates the dislocation. + */ +static void +check_vertex(ModeInfo * mi, fringe_node_c * vertex, tiling_c * tp) +{ + rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES]; + int n_hits = match_rules(vertex, hits, False); + unsigned forced_sides = 0; + + if (vertex->rule_mask == 0) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Dislocation occurred!\n"); + } + tp->busyLoop = CELEBRATE; /* Should be able to recover */ + } + if (1 == find_completions(vertex, hits, n_hits, S_LEFT, 0 /*, False */ )) + forced_sides |= S_LEFT; + if (1 == find_completions(vertex, hits, n_hits, S_RIGHT, 0 /*, False */ )) + forced_sides |= S_RIGHT; + if (forced_sides == 0) { + if (vertex->list_ptr != 0) { + forced_node_c *node = *vertex->list_ptr; + + *vertex->list_ptr = node->next; + if (node->next != 0) + node->next->vertex->list_ptr = vertex->list_ptr; + (void) free((void *) node); + tp->forced.n_nodes--; + if (!vertex->off_screen) + tp->forced.n_visible--; + vertex->list_ptr = 0; + } + } else { + forced_node_c *node; + + if (vertex->list_ptr == 0) { + if ((node = ALLOC_NODE(forced_node_c)) == NULL) + return; + node->vertex = vertex; + node->next = tp->forced.first; + if (tp->forced.first != 0) + tp->forced.first->vertex->list_ptr = &(node->next); + tp->forced.first = node; + vertex->list_ptr = &(tp->forced.first); + tp->forced.n_nodes++; + if (!vertex->off_screen) + tp->forced.n_visible++; + } else + node = *vertex->list_ptr; + node->forced_sides = forced_sides; + } +} + + +/*- + * Delete this vertex. If the vertex is a member of the forced vertex queue, + * also remove that entry. We assume that the vertex is no longer + * connected to the fringe. Note that tp->fringe.nodes must not point to + * the vertex being deleted. + */ +static void +delete_vertex(ModeInfo * mi, fringe_node_c * vertex, tiling_c * tp) +{ + if (tp->fringe.nodes == vertex) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in delete_penrose()\n"); + (void) fprintf(stderr, "tp->fringe.nodes == vertex\n"); + } + tp->busyLoop = CELEBRATE; + } + if (vertex->list_ptr != 0) { + forced_node_c *node = *vertex->list_ptr; + + *vertex->list_ptr = node->next; + if (node->next != 0) + node->next->vertex->list_ptr = vertex->list_ptr; + (void) free((void *) node); + tp->forced.n_nodes--; + if (!vertex->off_screen) + tp->forced.n_visible--; + } + if (!vertex->off_screen) + tp->fringe.n_nodes--; + (void) free((void *) vertex); +} + + +/*- + * Check whether the addition of a tile of type vtype would completely fill + * the space available at vertex. + */ +static int +fills_vertex(ModeInfo * mi, vertex_type_c vtype, fringe_node_c * vertex) +{ + return + (vertex_dir(mi, vertex, S_LEFT) - vertex_dir(mi, vertex, S_RIGHT) + - vtype_angle(vtype)) % 10 == 0; +} + + +/*- + * If you were to add a tile of type vtype to a specified side of + * vertex, fringe_changes tells you which other vertices it would + * attach to. The addresses of these vertices will be stored in the + * last three arguments. Null is stored if the corresponding vertex + * would need to be allocated. + * + * The function also analyzes which vertices would be swallowed by the tiling + * and thus cut off from the fringe. The result is returned as a bit pattern. + */ +#define FC_BAG 1 /* Total enclosure. Should never occur. */ +#define FC_NEW_RIGHT 2 +#define FC_NEW_FAR 4 +#define FC_NEW_LEFT 8 +#define FC_NEW_MASK 0xe +#define FC_CUT_THIS 0x10 +#define FC_CUT_RIGHT 0x20 +#define FC_CUT_FAR 0x40 +#define FC_CUT_LEFT 0x80 +#define FC_CUT_MASK 0xf0 +#define FC_TOTAL_MASK 0xff + +#undef far +static unsigned +fringe_changes(ModeInfo * mi, fringe_node_c * vertex, + unsigned side, vertex_type_c vtype, + fringe_node_c ** right, fringe_node_c ** far, + fringe_node_c ** left) +{ + fringe_node_c *v, *f = (fringe_node_c *) NULL; + unsigned result = FC_NEW_FAR; /* We clear this later if necessary. */ + + if (far) + *far = 0; + if (fills_vertex(mi, vtype, vertex)) { + result |= FC_CUT_THIS; + } else if (side == S_LEFT) { + result |= FC_NEW_RIGHT; + if (right) + *right = 0; + } else { + result |= FC_NEW_LEFT; + if (left) + *left = 0; + } + + if (!(result & FC_NEW_LEFT)) { + v = vertex->next; + if (left) + *left = v; + if (fills_vertex(mi, VT_LEFT(vtype), v)) { + result = (result & ~FC_NEW_FAR) | FC_CUT_LEFT; + f = v->next; + if (far) + *far = f; + } + } + if (!(result & FC_NEW_RIGHT)) { + v = vertex->prev; + if (right) + *right = v; + if (fills_vertex(mi, VT_RIGHT(vtype), v)) { + result = (result & ~FC_NEW_FAR) | FC_CUT_RIGHT; + f = v->prev; + if (far) + *far = f; + } + } + if (!(result & FC_NEW_FAR) + && fills_vertex(mi, VT_FAR(vtype), f)) { + result |= FC_CUT_FAR; + result &= (~FC_NEW_LEFT & ~FC_NEW_RIGHT); + if (right && (result & FC_CUT_LEFT)) + *right = f->next; + if (left && (result & FC_CUT_RIGHT)) + *left = f->prev; + } + if (((result & FC_CUT_LEFT) && (result & FC_CUT_RIGHT)) + || ((result & FC_CUT_THIS) && (result & FC_CUT_FAR))) + result |= FC_BAG; + return result; +} + + +/* A couple of lesser helper functions for add_tile. */ +static void +add_vtype(fringe_node_c * vertex, unsigned side, vertex_type_c vtype) +{ + if (side == S_RIGHT) + vertex->tiles[vertex->n_tiles++] = vtype; + else { + register int i; + + for (i = vertex->n_tiles; i > 0; i--) + vertex->tiles[i] = vertex->tiles[i - 1]; + vertex->tiles[0] = vtype; + vertex->n_tiles++; + } +} + +static fringe_node_c * +alloc_vertex(ModeInfo * mi, angle_c dir, fringe_node_c * from, tiling_c * tp) +{ + fringe_node_c *v; + + if ((v = ALLOC_NODE(fringe_node_c)) == NULL) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "No memory in alloc_vertex()\n"); + } + tp->busyLoop = CELEBRATE; + return v; + } + *v = *from; + add_unit_vec(dir, v->fived); + fived_to_loc(v->fived, tp, &(v->loc)); + if (v->loc.x < 0 || v->loc.y < 0 + || v->loc.x >= tp->width || v->loc.y >= tp->height) { + v->off_screen = True; + if (v->loc.x < -tp->width || v->loc.y < -tp->height + || v->loc.x >= 2 * tp->width || v->loc.y >= 2 * tp->height) + tp->done = True; + } else { + v->off_screen = False; + tp->fringe.n_nodes++; + } + v->n_tiles = 0; + v->rule_mask = (1 << N_VERTEX_RULES) - 1; + v->list_ptr = 0; + return v; +} + +/*- + * Add a tile described by vtype to the side of vertex. This must be + * allowed by the rules -- we do not check it here. New vertices are + * allocated as necessary. The fringe and the forced vertex pool are updated. + * The new tile is drawn on the display. + * + * One thing we do check here is whether the new tile causes an untiled + * area to become enclosed by the tiling. If this would happen, the tile + * is not added. The return value is true iff a tile was added. + */ +static int +add_tile(ModeInfo * mi, + fringe_node_c * vertex, unsigned side, vertex_type_c vtype) +{ + tiling_c *tp = &tilings[MI_SCREEN(mi)]; + + fringe_node_c + *left = (fringe_node_c *) NULL, + *right = (fringe_node_c *) NULL, + *far = (fringe_node_c *) NULL, + *node; + unsigned fc = fringe_changes(mi, vertex, side, vtype, &right, &far, &left); + + vertex_type_c + ltype = VT_LEFT(vtype), + rtype = VT_RIGHT(vtype), + ftype = VT_FAR(vtype); + + /* By our conventions vertex->next lies to the left of vertex and + vertex->prev to the right. */ + + /* This should never occur. */ + if (fc & FC_BAG) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in add_tile()\n"); + (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG); + } + } + if (side == S_LEFT) { + if (right == NULL) + if ((right = alloc_vertex(mi, vertex_dir(mi, vertex, S_LEFT) - + vtype_angle(vtype), vertex, tp)) == NULL) + return False; + if (far == NULL) + if ((far = alloc_vertex(mi, vertex_dir(mi, left, S_RIGHT) + + vtype_angle(ltype), left, tp)) == NULL) + return False; + } else { + if (left == NULL) + if ((left = alloc_vertex(mi, vertex_dir(mi, vertex, S_RIGHT) + + vtype_angle(vtype), vertex, tp)) == NULL) + return False; + if (far == NULL) + if ((far = alloc_vertex(mi, vertex_dir(mi, right, S_LEFT) - + vtype_angle(rtype), right, tp)) == NULL) + return False; + } + + /* Having allocated the new vertices, but before joining them with + the rest of the fringe, check if vertices with same coordinates + already exist. If any such are found, give up. */ + node = tp->fringe.nodes; + do { + if (((fc & FC_NEW_LEFT) && fived_equal(node->fived, left->fived)) + || ((fc & FC_NEW_RIGHT) && fived_equal(node->fived, right->fived)) + || ((fc & FC_NEW_FAR) && fived_equal(node->fived, far->fived))) { + /* Better luck next time. */ + if (fc & FC_NEW_LEFT) + delete_vertex(mi, left, tp); + if (fc & FC_NEW_RIGHT) + delete_vertex(mi, right, tp); + if (fc & FC_NEW_FAR) + delete_vertex(mi, far, tp); + return False; + } + node = node->next; + } while (node != tp->fringe.nodes); + + /* Rechain. */ + if (!(fc & FC_CUT_THIS)) { + if (side == S_LEFT) { + vertex->next = right; + right->prev = vertex; + } else { + vertex->prev = left; + left->next = vertex; + } + } + if (!(fc & FC_CUT_FAR)) { + if (!(fc & FC_CUT_LEFT)) { + far->next = left; + left->prev = far; + } + if (!(fc & FC_CUT_RIGHT)) { + far->prev = right; + right->next = far; + } + } + draw_tile(vertex, right, far, left, vtype, mi); + + /* Delete vertices that are no longer on the fringe. Check the others. */ + if (fc & FC_CUT_THIS) { + tp->fringe.nodes = far; + delete_vertex(mi, vertex, tp); + } else { + add_vtype(vertex, side, vtype); + check_vertex(mi, vertex, tp); + tp->fringe.nodes = vertex; + } + if (fc & FC_CUT_FAR) + delete_vertex(mi, far, tp); + else { + add_vtype(far, fc & FC_CUT_RIGHT ? S_LEFT : S_RIGHT, ftype); + check_vertex(mi, far, tp); + } + if (fc & FC_CUT_LEFT) + delete_vertex(mi, left, tp); + else { + add_vtype(left, fc & FC_CUT_FAR ? S_LEFT : S_RIGHT, ltype); + check_vertex(mi, left, tp); + } + if (fc & FC_CUT_RIGHT) + delete_vertex(mi, right, tp); + else { + add_vtype(right, fc & FC_CUT_FAR ? S_RIGHT : S_LEFT, rtype); + check_vertex(mi, right, tp); + } + return True; +} + + +/*- + * Add a forced tile to a given forced vertex. Basically an easy job, + * since we know what to add. But it might fail if adding the tile + * would cause some untiled area to become enclosed. There is also another + * more exotic culprit: we might have a dislocation. Fortunately, they + * are very rare (the PRL article reported that perfect tilings of over + * 2^50 tiles had been generated). There is a version of the algorithm + * that doesn't produce dislocations, but it's a lot hairier than the + * simpler version I used. + */ +static int +add_forced_tile(ModeInfo * mi, forced_node_c * node) +{ + tiling_c *tp = &tilings[MI_SCREEN(mi)]; + unsigned side; + vertex_type_c vtype; + rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES]; + int n; + + if (node->forced_sides == (S_LEFT | S_RIGHT)) + side = NRAND(2) ? S_LEFT : S_RIGHT; + else + side = node->forced_sides; + n = match_rules(node->vertex, hits, True); + n = find_completions(node->vertex, hits, n, side, &vtype /*, True */ ); + if (n <= 0) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in add_forced_tile()\n"); + (void) fprintf(stderr, "n = %d\n", n); + } + } + return add_tile(mi, node->vertex, side, vtype); +} + + +/*- + * Whether the addition of a tile of vtype on the given side of vertex + * would conform to the rules. The efficient way to do this would be + * to add the new tile and then use the same type of search as in + * match_rules. However, this function is not a performance + * bottleneck (only needed for random tile additions, which are + * relatively infrequent), so I will settle for a simpler implementation. + */ +static int +legal_move(fringe_node_c * vertex, unsigned side, vertex_type_c vtype) +{ + rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES]; + vertex_type_c legal_vt[MAX_COMPL]; + int n_hits, n_legal, i; + + n_hits = match_rules(vertex, hits, False); + n_legal = find_completions(vertex, hits, n_hits, side, legal_vt /*, False */ ); + for (i = 0; i < n_legal; i++) + if (legal_vt[i] == vtype) + return True; + return False; +} + + +/*- + * Add a randomly chosen tile to a given vertex. This requires more checking + * as we must make sure the new tile conforms to the vertex rules at every + * vertex it touches. */ +static void +add_random_tile(fringe_node_c * vertex, ModeInfo * mi) +{ + fringe_node_c *right, *left, *far; + int i, j, n, n_hits, n_good; + unsigned side, fc, no_good, s; + vertex_type_c vtypes[MAX_COMPL]; + rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES]; + tiling_c *tp = &tilings[MI_SCREEN(mi)]; + + if (MI_NPIXELS(mi) > 2) { + tp->thick_color = NRAND(MI_NPIXELS(mi)); + /* Insure good contrast */ + tp->thin_color = (NRAND(2 * MI_NPIXELS(mi) / 3) + tp->thick_color + + MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi); + } else + tp->thick_color = tp->thin_color = MI_WHITE_PIXEL(mi); + n_hits = match_rules(vertex, hits, False); + side = NRAND(2) ? S_LEFT : S_RIGHT; + n = find_completions(vertex, hits, n_hits, side, vtypes /*, False */ ); + /* One answer would mean a forced tile. */ + if (n <= 0) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in add_random_tile()\n"); + (void) fprintf(stderr, "n = %d\n", n); + } + } + no_good = 0; + n_good = n; + for (i = 0; i < n; i++) { + fc = fringe_changes(mi, vertex, side, vtypes[i], &right, &far, &left); + if (fc & FC_BAG) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in add_random_tile()\n"); + (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG); + } + } + if (right) { + s = (((fc & FC_CUT_FAR) && (fc & FC_CUT_LEFT)) ? S_RIGHT : S_LEFT); + if (!legal_move(right, s, VT_RIGHT(vtypes[i]))) { + no_good |= (1 << i); + n_good--; + continue; + } + } + if (left) { + s = (((fc & FC_CUT_FAR) && (fc & FC_CUT_RIGHT)) ? S_LEFT : S_RIGHT); + if (!legal_move(left, s, VT_LEFT(vtypes[i]))) { + no_good |= (1 << i); + n_good--; + continue; + } + } + if (far) { + s = ((fc & FC_CUT_LEFT) ? S_RIGHT : S_LEFT); + if (!legal_move(far, s, VT_FAR(vtypes[i]))) { + no_good |= (1 << i); + n_good--; + } + } + } + if (n_good <= 0) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in add_random_tile()\n"); + (void) fprintf(stderr, "n_good = %d\n", n_good); + } + } + n = NRAND(n_good); + for (i = j = 0; i <= n; i++, j++) + while (no_good & (1 << j)) + j++; + + if (!add_tile(mi, vertex, side, vtypes[j - 1])) { + tp->done = True; + if (MI_IS_VERBOSE(mi)) { + (void) fprintf(stderr, "Weirdness in add_random_tile()\n"); + } + free_penrose(tp); + } +} + +/* One step of the growth algorithm. */ +ENTRYPOINT void +draw_penrose(ModeInfo * mi) +{ + int i = 0, n; + forced_node_c *p; + tiling_c *tp; + + if (tilings == NULL) + return; + tp = &tilings[MI_SCREEN(mi)]; + if (tp->fringe.nodes == NULL) + return; + + MI_IS_DRAWN(mi) = True; + p = tp->forced.first; + if (tp->busyLoop > 0) { + tp->busyLoop--; + return; + } + if (tp->done || tp->failures >= 100) { + init_penrose(mi); + return; + } + /* Check for the initial "2-gon". */ + if (tp->fringe.nodes->prev == tp->fringe.nodes->next) { + vertex_type_c vtype = (unsigned char) (VT_TOTAL_MASK & LRAND()); + + MI_CLEARWINDOW(mi); + + if (!add_tile(mi, tp->fringe.nodes, S_LEFT, vtype)) + free_penrose(tp); + return; + } + /* No visible nodes left. */ + if (tp->fringe.n_nodes == 0) { + tp->done = True; + tp->busyLoop = COMPLETION; /* Just finished drawing */ + return; + } + if (tp->forced.n_visible > 0 && tp->failures < 10) { + n = NRAND(tp->forced.n_visible); + for (;;) { + while (p->vertex->off_screen) + p = p->next; + if (i++ < n) + p = p->next; + else + break; + } + } else if (tp->forced.n_nodes > 0) { + n = NRAND(tp->forced.n_nodes); + while (i++ < n) + p = p->next; + } else { + fringe_node_c *fringe_p = tp->fringe.nodes; + + n = NRAND(tp->fringe.n_nodes); + i = 0; + for (; i <= n; i++) + do { + fringe_p = fringe_p->next; + } while (fringe_p->off_screen); + add_random_tile(fringe_p, mi); + tp->failures = 0; + return; + } + if (add_forced_tile(mi, p)) + tp->failures = 0; + else + tp->failures++; +} + + +ENTRYPOINT void +reshape_penrose(ModeInfo * mi, int width, int height) +{ + tiling_c *tp = &tilings[MI_SCREEN(mi)]; + tp->width = width; + tp->height = height; +} + +/* Total clean-up. */ +ENTRYPOINT void +release_penrose(ModeInfo * mi) +{ + if (tilings != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_penrose(&tilings[screen]); + (void) free((void *) tilings); + tilings = (tiling_c *) NULL; + } +} + +XSCREENSAVER_MODULE ("Penrose", penrose) + +#endif /* MODE_penrose */ diff --git a/non-wgl/penrose.vcproj b/non-wgl/penrose.vcproj new file mode 100644 index 0000000..5efced1 --- /dev/null +++ b/non-wgl/penrose.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/petri.c b/non-wgl/petri.c new file mode 100644 index 0000000..9016231 --- /dev/null +++ b/non-wgl/petri.c @@ -0,0 +1,823 @@ +/* petri, simulate mold in a petri dish. v2.7 + * by Dan Bornstein, danfuzz@milk.com + * with help from Jamie Zawinski, jwz@jwz.org + * Copyright (c) 1992-1999 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. + * + * + * Brief description of options/resources: + * + * delay: the delay in microseconds between iterations + * size: the size of a cell in pixels + * count: the number of different kinds of mold (minimum: 2) + * diaglim: the age limit for diagonal growth as a multiplier of orthogonal + * growth (minimum: 1, maximum 2). 1 means square growth, 1.414 + * (i.e., sqrt(2)) means approximately circular growth, 2 means diamond + * growth. + * anychan: the chance (fraction, between 0 and 1) that at each iteration, + * any new cell will be born + * minorchan: the chance (fraction, between 0 and 1) that, given that new + * cells will be added, that only two will be added (a minor cell birth + * event) + * instantdeathchan: the chance (fraction, between 0 and 1) that, given + * that death and destruction will happen, that instead of using plague + * cells, death will be instantaneous + * minlifespan: the minimum lifespan of a colony (before black death ensues) + * maxlifespan: the maximum lifespan of a colony (before black death ensues) + * minlifespeed: the minimum speed for living cells as a fraction of the + * maximum possible speed (fraction, between 0 and 1) + * maxlifespeed: the maximum speed for living cells as a fraction of the + * maximum possible speed (fraction, between 0 and 1) + * mindeathspeed: the minimum speed for black death cells as a fraction of the + * maximum possible speed (fraction, between 0 and 1) + * maxdeathspeed: the maximum speed for black death cells as a fraction of the + * maximum possible speed (fraction, between 0 and 1) + * originalcolors: if true, count must be 8 or less and the colors are a + * fixed set of primary and secondary colors (the artist's original choices) + * + * Interesting settings: + * + * petri -originalcolors -size 8 + * petri -size 2 + * petri -size 8 -diaglim 1.8 + * petri -diaglim 1.1 + * + * petri -count 4 -anychan 0.01 -minorchan 1 \ + * -minlifespan 2000 -maxlifespan 5000 + * + * petri -count 3 -anychan 1 -minlifespan 100000 \ + * -instantdeathchan 0 + * + * petri -minlifespeed 0.02 -maxlifespeed 0.03 -minlifespan 1 \ + * -maxlifespan 1 -instantdeathchan 0 -minorchan 0 \ + * -anychan 0.3 -delay 4000 + */ + +#include "screenhack.h" +#include +#include "spline.h" + +#define FLOAT float +#define RAND_FLOAT (((FLOAT) (random() & 0xffff)) / ((FLOAT) 0x10000)) + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +int count = 20; +int size = 2; +float diaglim = 1.414; +float anychan = 0.0015; +float minorchan = 0.5; +float instantdeathchan = 0.2; +int minlifespan = 500; +int maxlifespan = 1500; +float minlifespeed = 0.04; +float maxlifespeed = 0.13; +float mindeathspeed = 0.42; +float maxdeathspeed = 0.46; +Bool originalcolors = False; +char *memThrottle = "22M"; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&count, "count", NULL, "20", t_Int}, + {&size, "size", NULL, "2", t_Int}, + {&diaglim, "diaglim", NULL, "1.414", t_Float}, + {&anychan, "anychan", NULL, "0.0015", t_Float}, + {&minorchan, "minorchan", NULL, "0.5", t_Float}, + {&instantdeathchan, "instantdeathchan", NULL, "0.2", t_Float}, + {&minlifespan, "minlifespan", NULL, "500", t_Int}, + {&maxlifespan, "maxlifespan", NULL, "1500", t_Int}, + {&minlifespeed, "minlifespeed", NULL, "0.04", t_Float}, + {&maxlifespeed, "maxlifespeed", NULL, "0.13", t_Float}, + {&mindeathspeed, "mindeathspeed", NULL, "0.42", t_Float}, + {&maxdeathspeed, "maxdeathspeed", NULL, "0.46", t_Float}, + {&originalcolors, "originalcolors", NULL, "False", t_Bool}, + {&memThrottle, "memThrottle", NULL, "22M", t_String}, +}; + + +typedef struct cell_s +{ + unsigned char col; /* 0 */ + unsigned char isnext; /* 1 */ + unsigned char nextcol; /* 2 */ + /* 3 */ + struct cell_s *next; /* 4 */ + struct cell_s *prev; /* 8 - */ + FLOAT speed; /* 12 */ + FLOAT growth; /* 16 20 - */ + FLOAT nextspeed; /* 20 28 */ + /* 24 36 - */ +} cell; + +struct state { + Display *dpy; + Window window; + + int arr_width; + int arr_height; + int count; + + cell *arr; + cell *head; + cell *tail; + int blastcount; + + GC *coloredGCs; + + int windowWidth; + int windowHeight; + int xOffset; + int yOffset; + int xSize; + int ySize; + + FLOAT orthlim; + FLOAT diaglim; + FLOAT anychan; + FLOAT minorchan; + FLOAT instantdeathchan; + int minlifespan; + int maxlifespan; + FLOAT minlifespeed; + FLOAT maxlifespeed; + FLOAT mindeathspeed; + FLOAT maxdeathspeed; + Bool originalcolors; + + int warned; + int delay; +}; + + +#define cell_x(c) (st->arr_width ? ((c) - st->arr) % st->arr_width : 0) +#define cell_y(c) (st->arr_width ? ((c) - st->arr) / st->arr_width : 0) + + +static int random_life_value (struct state *st) +{ + return (int) ((RAND_FLOAT * (st->maxlifespan - st->minlifespan)) + st->minlifespan); +} + +static void setup_random_colormap (struct state *st, XWindowAttributes *xgwa) +{ + XGCValues gcv; + int lose = 0; + int ncolors = st->count - 1; + int n; + XColor *colors = (XColor *) calloc (sizeof(*colors), st->count*2); + + + //colors[0].pixel = get_pixel_resource (st->dpy, xgwa->colormap, + // "background", "Background"); + colors[0].pixel = load_color(st->dpy, xgwa->colormap, background); + + make_random_colormap (xgwa->screen, xgwa->visual, xgwa->colormap, + colors+1, &ncolors, True, True, 0, True); + if (ncolors < 1) + { + fprintf (stderr, "%s: couldn't allocate any colors\n", progname); + exit (-1); + } + + ncolors++; + st->count = ncolors; + + memcpy (colors + st->count, colors, st->count * sizeof(*colors)); + //colors[st->count].pixel = get_pixel_resource (st->dpy, xgwa->colormap, + // "foreground", "Foreground"); + colors[st->count].pixel = load_color(st->dpy, xgwa->colormap, foreground); + + for (n = 1; n < st->count; n++) + { + int m = n + st->count; + colors[n].red = colors[m].red / 2; + colors[n].green = colors[m].green / 2; + colors[n].blue = colors[m].blue / 2; + + if (!XAllocColor (st->dpy, xgwa->colormap, &colors[n])) + { + lose++; + colors[n] = colors[m]; + } + } + + if (lose) + { + fprintf (stderr, + "%s: unable to allocate %d half-intensity colors.\n", + progname, lose); + } + + for (n = 0; n < st->count*2; n++) + { + gcv.foreground = colors[n].pixel; + st->coloredGCs[n] = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + } + + free (colors); +} + +static void setup_original_colormap (struct state *st, XWindowAttributes *xgwa) +{ + XGCValues gcv; + int lose = 0; + int n; + XColor *colors = (XColor *) calloc (sizeof(*colors), st->count*2); + + //colors[0].pixel = get_pixel_resource (st->dpy, xgwa->colormap, + // "background", "Background"); + colors[0].pixel = load_color(st->dpy, xgwa->colormap, background); + + //colors[st->count].pixel = get_pixel_resource (st->dpy, xgwa->colormap, + // "foreground", "Foreground"); + colors[st->count].pixel = load_color(st->dpy, xgwa->colormap, foreground); + + for (n = 1; n < st->count; n++) + { + int m = n + st->count; + colors[n].red = ((n & 0x01) != 0) * 0x8000; + colors[n].green = ((n & 0x02) != 0) * 0x8000; + colors[n].blue = ((n & 0x04) != 0) * 0x8000; + + if (!XAllocColor (st->dpy, xgwa->colormap, &colors[n])) + { + lose++; + colors[n] = colors[0]; + } + + colors[m].red = colors[n].red + 0x4000; + colors[m].green = colors[n].green + 0x4000; + colors[m].blue = colors[n].blue + 0x4000; + + if (!XAllocColor (st->dpy, xgwa->colormap, &colors[m])) + { + lose++; + colors[m] = colors[st->count]; + } + } + + if (lose) + { + fprintf (stderr, + "%s: unable to allocate %d colors.\n", + progname, lose); + } + + for (n = 0; n < st->count*2; n++) + { + gcv.foreground = colors[n].pixel; + st->coloredGCs[n] = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + } + + free (colors); +} + +static void +setup_display (struct state *st) +{ + XWindowAttributes xgwa; + + //int cell_size = get_integer_resource (st->dpy, "size", "Integer"); + int cell_size = size; + int osize, alloc_size, oalloc; + int mem_throttle = 0; + char *s; + + if (cell_size < 1) cell_size = 1; + + osize = cell_size; + + //s = get_string_resource (st->dpy, "memThrottle", "MemThrottle"); + s = _strdup(memThrottle); + if (s) + { + int n; + char c; + if (1 == sscanf (s, " %d M %c", &n, &c) || + 1 == sscanf (s, " %d m %c", &n, &c)) + mem_throttle = n * (1 << 20); + else if (1 == sscanf (s, " %d K %c", &n, &c) || + 1 == sscanf (s, " %d k %c", &n, &c)) + mem_throttle = n * (1 << 10); + else if (1 == sscanf (s, " %d %c", &n, &c)) + mem_throttle = n; + else + { + fprintf (stderr, "%s: invalid memThrottle \"%s\" (try \"10M\")\n", + progname, s); + exit (1); + } + + free (s); + } + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + //st->originalcolors = get_boolean_resource (st->dpy, "originalcolors", "Boolean"); + st->originalcolors = originalcolors; + + //st->count = get_integer_resource (st->dpy, "count", "Integer"); + st->count = count; + if (st->count < 2) st->count = 2; + + /* number of colors can't be greater than the half depth of the screen. */ + if (st->count > (unsigned int) (1L << (xgwa.depth-1))) + st->count = (unsigned int) (1L << (xgwa.depth-1)); + + /* Actually, since cell->col is of type char, this has to be small. */ + if (st->count >= (unsigned int) (1L << ((sizeof(st->arr[0].col) * 8) - 1))) + st->count = (unsigned int) (1L << ((sizeof(st->arr[0].col) * 8) - 1)); + + + if (st->originalcolors && (st->count > 8)) + { + st->count = 8; + } + + st->coloredGCs = (GC *) calloc (sizeof(GC), st->count * 2); + + //st->diaglim = get_float_resource (st->dpy, "diaglim", "Float"); + st->diaglim = diaglim; + if (st->diaglim < 1.0) + { + st->diaglim = 1.0; + } + else if (st->diaglim > 2.0) + { + st->diaglim = 2.0; + } + st->diaglim *= st->orthlim; + + //st->anychan = get_float_resource (st->dpy, "anychan", "Float"); + st->anychan = anychan; + if (st->anychan < 0.0) + { + st->anychan = 0.0; + } + else if (st->anychan > 1.0) + { + st->anychan = 1.0; + } + + //st->minorchan = get_float_resource (st->dpy, "minorchan","Float"); + st->minorchan = minorchan; + if (st->minorchan < 0.0) + { + st->minorchan = 0.0; + } + else if (st->minorchan > 1.0) + { + st->minorchan = 1.0; + } + + //st->instantdeathchan = get_float_resource (st->dpy, "instantdeathchan","Float"); + st->instantdeathchan = instantdeathchan; + if (st->instantdeathchan < 0.0) + { + st->instantdeathchan = 0.0; + } + else if (st->instantdeathchan > 1.0) + { + st->instantdeathchan = 1.0; + } + + //st->minlifespan = get_integer_resource (st->dpy, "minlifespan", "Integer"); + st->minlifespan = minlifespan; + if (st->minlifespan < 1) + { + st->minlifespan = 1; + } + + //st->maxlifespan = get_integer_resource (st->dpy, "maxlifespan", "Integer"); + st->maxlifespan = maxlifespan; + if (st->maxlifespan < st->minlifespan) + { + st->maxlifespan = st->minlifespan; + } + + //st->minlifespeed = get_float_resource (st->dpy, "minlifespeed", "Float"); + st->minlifespeed = minlifespeed; + if (st->minlifespeed < 0.0) + { + st->minlifespeed = 0.0; + } + else if (st->minlifespeed > 1.0) + { + st->minlifespeed = 1.0; + } + + //st->maxlifespeed = get_float_resource (st->dpy, "maxlifespeed", "Float"); + st->maxlifespeed = maxlifespeed; + if (st->maxlifespeed < st->minlifespeed) + { + st->maxlifespeed = st->minlifespeed; + } + else if (st->maxlifespeed > 1.0) + { + st->maxlifespeed = 1.0; + } + + //st->mindeathspeed = get_float_resource (st->dpy, "mindeathspeed", "Float"); + st->mindeathspeed = mindeathspeed; + if (st->mindeathspeed < 0.0) + { + st->mindeathspeed = 0.0; + } + else if (st->mindeathspeed > 1.0) + { + st->mindeathspeed = 1.0; + } + + //st->maxdeathspeed = get_float_resource (st->dpy, "maxdeathspeed", "Float"); + st->maxdeathspeed = maxdeathspeed; + if (st->maxdeathspeed < st->mindeathspeed) + { + st->maxdeathspeed = st->mindeathspeed; + } + else if (st->maxdeathspeed > 1.0) + { + st->maxdeathspeed = 1.0; + } + + st->minlifespeed *= st->diaglim; + st->maxlifespeed *= st->diaglim; + st->mindeathspeed *= st->diaglim; + st->maxdeathspeed *= st->diaglim; + + st->windowWidth = xgwa.width; + st->windowHeight = xgwa.height; + + st->arr_width = st->windowWidth / cell_size; + st->arr_height = st->windowHeight / cell_size; + + alloc_size = sizeof(cell) * st->arr_width * st->arr_height; + oalloc = alloc_size; + + if (mem_throttle > 0) + while (cell_size < st->windowWidth/10 && + cell_size < st->windowHeight/10 && + alloc_size > mem_throttle) + { + cell_size++; + st->arr_width = st->windowWidth / cell_size; + st->arr_height = st->windowHeight / cell_size; + alloc_size = sizeof(cell) * st->arr_width * st->arr_height; + } + + if (osize != cell_size) + { + if (!st->warned) + { + fprintf (stderr, + "%s: throttling cell size from %d to %d because of %dM limit.\n", + progname, osize, cell_size, mem_throttle / (1 << 20)); + fprintf (stderr, "%s: %dx%dx%d = %.1fM, %dx%dx%d = %.1fM.\n", + progname, + st->windowWidth, st->windowHeight, osize, + ((float) oalloc) / (1 << 20), + st->windowWidth, st->windowHeight, cell_size, + ((float) alloc_size) / (1 << 20)); + st->warned = 1; + } + } + + st->xSize = st->arr_width ? st->windowWidth / st->arr_width : 0; + st->ySize = st->arr_height ? st->windowHeight / st->arr_height : 0; + if (st->xSize > st->ySize) + { + st->xSize = st->ySize; + } + else + { + st->ySize = st->xSize; + } + + st->xOffset = (st->windowWidth - (st->arr_width * st->xSize)) / 2; + st->yOffset = (st->windowHeight - (st->arr_height * st->ySize)) / 2; + + if (st->originalcolors) + { + setup_original_colormap (st, &xgwa); + } + else + { + setup_random_colormap (st, &xgwa); + } +} + +static void drawblock (struct state *st, int x, int y, unsigned char c) +{ + if (st->xSize == 1 && st->ySize == 1) + XDrawPoint (st->dpy, st->window, st->coloredGCs[c], x + st->xOffset, y + st->yOffset); + else + XFillRectangle (st->dpy, st->window, st->coloredGCs[c], + x * st->xSize + st->xOffset, y * st->ySize + st->yOffset, + st->xSize, st->ySize); +} + +static void setup_arr (struct state *st) +{ + int x, y; + + if (st->arr != NULL) + { + free (st->arr); + } + + XFillRectangle (st->dpy, st->window, st->coloredGCs[0], 0, 0, + st->windowWidth, st->windowHeight); + + if (!st->arr_width) st->arr_width = 1; + if (!st->arr_height) st->arr_height = 1; + + st->arr = (cell *) calloc (sizeof(cell), st->arr_width * st->arr_height); + if (!st->arr) + { + fprintf (stderr, "%s: out of memory allocating %dx%d grid\n", + progname, st->arr_width, st->arr_height); + exit (1); + } + + for (y = 0; y < st->arr_height; y++) + { + int row = y * st->arr_width; + for (x = 0; x < st->arr_width; x++) + { + st->arr[row+x].speed = 0.0; + st->arr[row+x].growth = 0.0; + st->arr[row+x].col = 0; + st->arr[row+x].isnext = 0; + st->arr[row+x].next = 0; + st->arr[row+x].prev = 0; + } + } + + if (st->head == NULL) + { + st->head = (cell *) malloc (sizeof (cell)); + } + + if (st->tail == NULL) + { + st->tail = (cell *) malloc (sizeof (cell)); + } + + st->head->next = st->tail; + st->head->prev = st->head; + st->tail->next = st->tail; + st->tail->prev = st->head; + + st->blastcount = random_life_value (st); +} + +static void newcell (struct state *st, cell *c, unsigned char col, FLOAT sp) +{ + if (! c) return; + + if (c->col == col) return; + + c->nextcol = col; + c->nextspeed = sp; + c->isnext = 1; + + if (c->prev == 0) { + c->next = st->head->next; + c->prev = st->head; + st->head->next = c; + c->next->prev = c; + } +} + +static void killcell (struct state *st, cell *c) +{ + c->prev->next = c->next; + c->next->prev = c->prev; + c->prev = 0; + c->speed = 0.0; + drawblock (st, cell_x(c), cell_y(c), c->col); +} + + +static void randblip (struct state *st, int doit) +{ + int n; + int b = 0; + if (!doit + && (st->blastcount-- >= 0) + && (RAND_FLOAT > st->anychan)) + { + return; + } + + if (st->blastcount < 0) + { + b = 1; + n = 2; + st->blastcount = random_life_value (st); + if (RAND_FLOAT < st->instantdeathchan) + { + /* clear everything every so often to keep from getting into a + * rut */ + setup_arr (st); + b = 0; + } + } + else if (RAND_FLOAT <= st->minorchan) + { + n = 2; + } + else + { + n = random () % 3 + 3; + } + + while (n--) + { + int x = st->arr_width ? random () % st->arr_width : 0; + int y = st->arr_height ? random () % st->arr_height : 0; + int c; + FLOAT s; + if (b) + { + c = 0; + s = RAND_FLOAT * (st->maxdeathspeed - st->mindeathspeed) + st->mindeathspeed; + } + else + { + c = ((st->count - 1) ? random () % (st->count-1) : 0) + 1; + s = RAND_FLOAT * (st->maxlifespeed - st->minlifespeed) + st->minlifespeed; + } + newcell (st, &st->arr[y * st->arr_width + x], c, s); + } +} + +static void update (struct state *st) +{ + cell *a; + + for (a = st->head->next; a != st->tail; a = a->next) + { + static const XPoint all_coords[] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}, + {-1, 0}, { 1, 0}, {0, -1}, {0, 1}, + {99, 99}}; + + const XPoint *coords = 0; + + if (a->speed == 0) continue; + a->growth += a->speed; + + if (a->growth >= st->diaglim) + { + coords = all_coords; + } + else if (a->growth >= st->orthlim) + { + coords = &all_coords[4]; + } + else + { + continue; + } + + while (coords->x != 99) + { + int x = cell_x(a) + coords->x; + int y = cell_y(a) + coords->y; + coords++; + + if (x < 0) x = st->arr_width - 1; + else if (x >= st->arr_width) x = 0; + + if (y < 0) y = st->arr_height - 1; + else if (y >= st->arr_height) y = 0; + + newcell (st, &st->arr[y * st->arr_width + x], a->col, a->speed); + } + + if (a->growth >= st->diaglim) + killcell (st, a); + } + + randblip (st, (st->head->next) == st->tail); + + for (a = st->head->next; a != st->tail; a = a->next) + { + if (a->isnext) + { + a->isnext = 0; + a->speed = a->nextspeed; + a->growth = 0.0; + a->col = a->nextcol; + drawblock (st, cell_x(a), cell_y(a), a->col + st->count); + } + } +} + +static void * +petri_init (Display *dpy, Window win) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = win; + + //st->delay = get_integer_resource (st->dpy, "delay", "Delay"); + st->delay = delay; + st->orthlim = 1; + + setup_display (st); + setup_arr (st); + randblip (st, 1); + + return st; +} + +static unsigned long +petri_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + update (st); + return st->delay; +} + +static void +petri_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + petri_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +petri_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + +static const char *petri_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 10000", + "*count: 20", + "*size: 2", + "*diaglim: 1.414", + "*anychan: 0.0015", + "*minorchan: 0.5", + "*instantdeathchan: 0.2", + "*minlifespan: 500", + "*maxlifespan: 1500", + "*minlifespeed: 0.04", + "*maxlifespeed: 0.13", + "*mindeathspeed: 0.42", + "*maxdeathspeed: 0.46", + "*originalcolors: false", + "*memThrottle: 22M", /* don't malloc more than this much. + Scale the pixels up if necessary. */ +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec petri_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-size", ".size", XrmoptionSepArg, 0 }, + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-diaglim", ".diaglim", XrmoptionSepArg, 0 }, + { "-anychan", ".anychan", XrmoptionSepArg, 0 }, + { "-minorchan", ".minorchan", XrmoptionSepArg, 0 }, + { "-instantdeathchan", ".instantdeathchan", XrmoptionSepArg, 0 }, + { "-minlifespan", ".minlifespan", XrmoptionSepArg, 0 }, + { "-maxlifespan", ".maxlifespan", XrmoptionSepArg, 0 }, + { "-minlifespeed", ".minlifespeed", XrmoptionSepArg, 0 }, + { "-maxlifespeed", ".maxlifespeed", XrmoptionSepArg, 0 }, + { "-mindeathspeed", ".mindeathspeed", XrmoptionSepArg, 0 }, + { "-maxdeathspeed", ".maxdeathspeed", XrmoptionSepArg, 0 }, + { "-originalcolors", ".originalcolors", XrmoptionNoArg, "true" }, + { "-mem-throttle", ".memThrottle", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Petri", petri) diff --git a/non-wgl/petri.vcproj b/non-wgl/petri.vcproj new file mode 100644 index 0000000..f72ede3 --- /dev/null +++ b/non-wgl/petri.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/piecewise.c b/non-wgl/piecewise.c new file mode 100644 index 0000000..7030078 --- /dev/null +++ b/non-wgl/piecewise.c @@ -0,0 +1,1046 @@ +/* piecewise, 21jan2003 + * Geoffrey Irving + * + * 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 +#include + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# include "xdbe.h" +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +#if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus) +#undef inline +#define inline /* */ +#endif + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +int speed_ = 15; +int ncolors = 256; +int colorspeed = 10; +int count = 32; +float minradius_ = 0.05; +float maxradius_ = 0.2; +Bool doubleBuffer = True; +Bool useDBE = True; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&speed_, "speed", NULL, "15", t_Int}, + {&ncolors, "ncolors", NULL, "256", t_Int}, + {&colorspeed, "colorspeed", NULL, "10", t_Int}, + {&count, "count", NULL, "32", t_Int}, + {&minradius_, "minradius", NULL, "0.05", t_Float}, + {&maxradius_, "maxradius", NULL, "0.2", t_Float}, + {&doubleBuffer, "doubleBuffer", NULL, "True", t_Bool}, + {&useDBE, "useDBE", NULL, "True", t_Bool}, +}; + +#define X_PI (180 * 64) + +#define START 0 +#define CROSS 1 +#define FINISH 2 + +#define ARC_BUFFER_SIZE 256 + + +typedef struct _tree { + struct _tree *l, *r; /* left and right children */ + /* extra stuff would go here */ + } tree; + + +struct _fringe; + +typedef struct _circle { + int r; /* radius */ + double x, y; /* position */ + double dx, dy; /* velocity */ + + int visible; /* default visibility */ + struct _fringe *lo, *hi; /* lo and hi fringes */ + + int ni; /* number of intersections */ + int *i; /* sorted intersection list */ + } circle; + +typedef struct _fringe { + struct _fringe *l, *r; /* left and right children for splay trees */ + + circle *c; /* associated circle */ + int side; /* 0 for lo, 1 for hi */ + + int mni; /* size of intersection array */ + int ni; /* number of intersections */ + int *i; /* sorted intersection list */ + } fringe; + + +typedef struct _event { + struct _event *l, *r; /* left and right children for splay tree */ + + int kind; /* type of event */ + double x, y; /* position */ + fringe *lo, *hi; /* fringes */ + } event; + + +struct state { + Display *dpy; + Window window; + + double event_cut_y; + + double fringe_start_cut_x; + double fringe_start_cut_y; + + double fringe_double_cut_x; + double fringe_double_cut_y; + fringe *fringe_double_cut_lo; + fringe *fringe_double_cut_hi; + + int arc_buffer_count; + XArc arc_buffer[ARC_BUFFER_SIZE]; + + Bool dbuf; + XColor *colors; + XGCValues gcv; + GC erase_gc, draw_gc; + XWindowAttributes xgwa; + Pixmap b, ba, bb; /* double-buffering pixmap */ + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + XdbeBackBuffer backb; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + int count, delay, ncolors, colorspeed, color_index, flags, iterations; + int color_iterations; + circle *circles; +}; + +typedef int (*cut)(struct state *, tree*); /* cut x is <, =, or > 0 given a <, =, or > x for some a */ + + + +/******** splaying code */ + +/* Top-down splay routine. Reference: + * "Self-adjusting Binary Search Trees", Sleator and Tarjan, + * JACM Volume 32, No 3, July 1985, pp 652-686. + * See page 668 for specific splay transformations */ + +static tree *splay(struct state *st, cut c, tree *t) +{ + int v, vv; + tree *l, *r; + tree **lr, **rl; + tree *x, *y, *z; + + if (!t) + return 0; + + /* initialization */ + x = t; + l = r = 0; + lr = &l; + rl = &r; + + /* top-down splaying loop */ + for (;;) { + v = c(st, x); + if (v == 0) + break; /*** success ***/ + else if (v < 0) { + y = x->l; + if (!y) + break; /*** trivial ***/ + else { + vv = c(st, y); + if (vv == 0) { + *rl = x; /*** zig ***/ + rl = &x->l; + x = y; + break; + } + else if (vv < 0) { + z = y->l; + if (!z) { + *rl = x; /*** zig ***/ + rl = &x->l; + x = y; + break; + } + else { + x->l = y->r; /*** zig-zig ***/ + y->r = x; + *rl = y; + rl = &y->l; + x = z; + } + } + else { /* vv > 0 */ + z = y->r; + if (!z) { + *rl = x; /*** zig ***/ + rl = &x->l; + x = y; + break; + } + else { /*** zig-zag ***/ + *lr = y; + lr = &y->r; + *rl = x; + rl = &x->l; + x = z; + } + } + } + } + else { /* v > 0 */ + y = x->r; + if (!y) + break; /*** trivial ***/ + else { + vv = c(st, y); + if (vv == 0) { + *lr = x; /*** zig ***/ + lr = &x->r; + x = y; + break; + } + else if (vv > 0) { + z = y->r; + if (!z) { + *lr = x; /*** zig ***/ + lr = &x->r; + x = y; + break; + } + else { + x->r = y->l; /*** zig-zig ***/ + y->l = x; + *lr = y; + lr = &y->r; + x = z; + } + } + else { /* vv < 0 */ + z = y->l; + if (!z) { + *lr = x; /*** zig ***/ + lr = &x->r; + x = y; + break; + } + else { /*** zig-zag ***/ + *rl = y; + rl = &y->l; + *lr = x; + lr = &x->r; + x = z; + } + } + } + } + } + + /* completion */ + *lr = x->l; + x->l = l; + *rl = x->r; + x->r = r; + return x; + } + +static tree *splay_min(tree *t) +{ + tree *r, **rl; + tree *x, *y, *z; + + if (!t) + return 0; + + x = t; + r = 0; + rl = &r; + + for (;;) { + y = x->l; + if (!y) + break; /*** trivial ***/ + else { + z = y->l; + if (!z) { + *rl = x; /*** zig ***/ + rl = &x->l; + x = y; + break; + } + else { + x->l = y->r; /*** zig-zig ***/ + y->r = x; + *rl = y; + rl = &y->l; + x = z; + } + } + } + + x->l = 0; + *rl = x->r; + x->r = r; + return x; + } + +static tree *splay_max(tree *t) +{ + tree *l, **lr; + tree *x, *y, *z; + + if (!t) + return 0; + + x = t; + l = 0; + lr = &l; + + for (;;) { + y = x->r; + if (!y) + break; /*** trivial ***/ + else { + z = y->r; + if (!z) { + *lr = x; /*** zig ***/ + lr = &x->r; + x = y; + break; + } + else { + x->r = y->l; /*** zig-zig ***/ + y->l = x; + *lr = y; + lr = &y->r; + x = z; + } + } + } + + *lr = x->l; + x->l = l; + x->r = 0; + return x; + } + +/******** circles and fringe */ + +static inline double fringe_x(fringe *f, double y) +{ + double dy, d; + dy = f->c->y - y; + d = sqrt(f->c->r * f->c->r - dy * dy); + return f->side ? f->c->x + d : f->c->x - d; + } + +static inline void fringe_add_intersection(fringe *f, double x, double y) +{ + f->ni++; + if (f->mni < f->ni) { + f->mni += 2; + f->i = realloc(f->i, sizeof(int) * f->mni); + } + f->i[f->ni-1] = rint(atan2(y - f->c->y, x - f->c->x) * X_PI / M_PI); + } + +static circle *init_circles(struct state *st, int n, int w, int h) +{ + int i, r0, dr, speed; + double v, a; + double minradius, maxradius; + fringe *s = malloc(sizeof(fringe) * n * 2); /* never freed */ + circle *c = malloc(sizeof(circle) * n); + + //speed = get_integer_resource(st->dpy, "speed", "Speed"); + //minradius = get_float_resource(st->dpy, "minradius", "Float"); + //maxradius = get_float_resource(st->dpy, "maxradius", "Float"); + speed = speed_; + minradius = minradius_; + maxradius = maxradius_; + if (maxradius < minradius) + maxradius = minradius; + + r0 = ceil(minradius * h); + dr = floor(maxradius * h) - r0 + 1; + + for (i=0;i 0) ? random() % dr : 0); + c[i].x = c[i].r + frand(w - 1 - 2 * c[i].r); + c[i].y = c[i].r + frand(h - 1 - 2 * c[i].r); + c[i].visible = random() & 1; + + c[i].ni = 0; + c[i].i = 0; + + a = frand(2 * M_PI); + v = (1 + frand(0.5)) * speed / 10.0; + c[i].dx = v * cos(a); + c[i].dy = v * sin(a); + + c[i].lo = s+i+i; + c[i].hi = s+i+i+1; + c[i].lo->c = c[i].hi->c = c+i; + c[i].lo->side = 0; + c[i].hi->side = 1; + c[i].lo->mni = c[i].lo->ni = c[i].hi->mni = c[i].hi->ni = 0; + c[i].lo->i = c[i].hi->i = 0; + } + + return c; + } + +/* this is a hack, but I guess that's what I writing anyways */ +static void tweak_circle(circle *c) +{ + c->x += frand(2) - 1; + c->y += frand(1) + 0.1; + } + +static void move_circle(circle *c, int w, int h) +{ + c->x += c->dx; + if (c->x < c->r) { + c->x = c->r; + c->dx = -c->dx; + } + else if (c->x >= w - c->r) { + c->x = w - 1 - c->r; + c->dx = -c->dx; + } + c->y += c->dy; + if (c->y < c->r) { + c->y = c->r; + c->dy = -c->dy; + } + else if (c->y >= h - c->r) { + c->y = h - 1 - c->r; + c->dy = -c->dy; + } + } + +/******** event queue */ + +static int event_cut(struct state *st, event *e) +{ + return st->event_cut_y == e->y ? 0 : st->event_cut_y < e->y ? -1 : 1; + } + +static void event_insert(struct state *st, event **eq, event *e) +{ + if (!*eq) { + e->l = e->r = 0; + *eq = e; + return; /* avoid leak */ + } + + st->event_cut_y = e->y; + *eq = (event*)splay(st, (cut)event_cut, (tree*)*eq); + + if (e->y == (*eq)->y) { + if (!((e->lo == (*eq)->lo && e->hi == (*eq)->hi) || (e->lo == (*eq)->hi && e->hi == (*eq)->lo))) { + e->l = (*eq)->l; + e->r = 0; /* doing this instead of dying might be dangerous */ + (*eq)->l = e; + } + else + free(e); /* don't leak! */ + } + else if (e->y < (*eq)->y) { + e->l = (*eq)->l; + e->r = *eq; + (*eq)->l = 0; + *eq = e; + } + else { + e->l = *eq; + e->r = (*eq)->r; + (*eq)->r = 0; + *eq = e; + } + } + +static void circle_start_event(struct state *st, event **eq, circle *c) +{ + event *s; + s = malloc(sizeof(event)); + s->kind = START; + s->x = c->x; + s->y = c->y - c->r; + s->lo = c->lo; + s->hi = c->hi; + event_insert(st, eq, s); + } + +static void circle_finish_event(struct state *st, event **eq, circle *c) +{ + event *f; + f = malloc(sizeof(event)); + f->kind = FINISH; + f->x = c->x; + f->y = c->y + c->r; + f->lo = c->lo; + f->hi = c->hi; + event_insert(st, eq, f); + } + +static event *event_next(event **eq) +{ + event *e; + if (!*eq) + return 0; + else { + e = (event*)splay_min((tree*)*eq); + *eq = e->r; + return e; + } + } + +static void event_shred(event *e) +{ + if (e) { + event_shred(e->l); + event_shred(e->r); + free(e); + } + } + +/******** fringe intersection */ + +static inline int check_fringe_intersection(double ye, fringe *lo, fringe *hi, double x, double y) +{ + return ye <= y && ((x < lo->c->x) ^ lo->side) && ((x < hi->c->x) ^ hi->side); + } + +static void fringe_intersect(struct state *st, event **eq, double y, fringe *lo, fringe *hi) +{ + event *e; + double dx, dy, sd, rs, rd, d, sx, sy, rp, sqd; + double x1, y1, x2, y2; + + if (lo->c == hi->c) + return; + + dx = hi->c->x - lo->c->x; + dy = hi->c->y - lo->c->y; + sd = dx * dx + dy * dy; + + if (sd == 0) + return; + + rs = hi->c->r + lo->c->r; + rd = hi->c->r - lo->c->r; + d = (rd * rd - sd) * (sd - rs * rs); + + if (d <= 0) + return; + + sd = 0.5 / sd; + rp = rs * rd; + sqd = sqrt(d); + sx = (lo->c->x + hi->c->x) / 2; + sy = (lo->c->y + hi->c->y) / 2; + x1 = sx + sd * (dy * sqd - dx * rp); + y1 = sy - sd * (dx * sqd + dy * rp); + x2 = sx - sd * (dy * sqd + dx * rp); + y2 = sy + sd * (dx * sqd - dy * rp); + + #define CHECK(xi, yi) (y <= yi && ((xi < lo->c->x) ^ lo->side) && ((xi < hi->c->x) ^ hi->side)) + + #define ADD_CROSS(xi, yi, ilo, ihi) { \ + e = malloc(sizeof(event)); /* #### LEAK */ \ + e->kind = CROSS; \ + e->x = xi; e->y = yi; \ + e->lo = ilo; e->hi = ihi; \ + event_insert(st, eq, e); \ + } + + if (CHECK(x1, y1)) { + if (CHECK(x2, y2)) { + if (y1 < y2) { + ADD_CROSS(x1, y1, lo, hi); + ADD_CROSS(x2, y2, hi, lo); + } + else { + ADD_CROSS(x1, y1, hi, lo); + ADD_CROSS(x2, y2, lo, hi); + } + } + else + ADD_CROSS(x1, y1, lo, hi); + } + else if (CHECK(x2, y2)) + ADD_CROSS(x2, y2, lo, hi); + + return; + } + +/******** fringe trees and event handling */ + +#define PANIC ((fringe*)1) /* by alignment, no fringe should every be 1 */ + +static fringe *check_lo(struct state *st, event **eq, double y, fringe *f, fringe *hi) +{ + if (f) { + f = (fringe*)splay_max((tree*)f); + fringe_intersect(st, eq, y, f, hi); + } + return f; + } + +static fringe *check_hi(struct state *st, event **eq, double y, fringe *lo, fringe *f) +{ + if (f) { + f = (fringe*)splay_min((tree*)f); + fringe_intersect(st, eq, y, lo, f); + } + return f; + } + +static int fringe_start_cut(struct state *st, fringe *f) +{ + double x = fringe_x(f, st->fringe_start_cut_y); + return st->fringe_start_cut_x == x ? 0 : st->fringe_start_cut_x < x ? -1 : 1; + } + +static fringe *fringe_start(struct state *st, event **eq, fringe *f, double x, double y, fringe *lo, fringe *hi) +{ + double sx; + + if (!f) { + circle_finish_event(st, eq, lo->c); + lo->l = 0; + lo->r = hi; + hi->l = hi->r = 0; + return lo; + } + + st->fringe_start_cut_x = x; + st->fringe_start_cut_y = y; + f = (fringe*)splay(st, (cut)fringe_start_cut, (tree*)f); + + sx = fringe_x(f, y); + if (x == sx) { /* time to cheat my way out of handling degeneracies */ + tweak_circle(lo->c); + circle_start_event(st, eq, lo->c); + return f; + } + else if (x < sx) { + circle_finish_event(st, eq, lo->c); + f->l = check_lo(st, eq, y, f->l, lo); + fringe_intersect(st, eq, y, hi, f); + lo->l = f->l; + lo->r = f; + f->l = hi; + hi->l = hi->r = 0; + return lo; + } + else { + circle_finish_event(st, eq, lo->c); + fringe_intersect(st, eq, y, f, lo); + f->r = check_hi(st, eq, y, hi, f->r); + hi->r = f->r; + hi->l = f; + f->r = lo; + lo->l = lo->r = 0; + return hi; + } + } + +static int fringe_double_cut(struct state *st, fringe *f) +{ + double x; + if (f == st->fringe_double_cut_lo || f == st->fringe_double_cut_hi) + return 0; + x = fringe_x(f, st->fringe_double_cut_y); + return st->fringe_double_cut_x == x ? 0 : st->fringe_double_cut_x < x ? -1 : 1; + } + +static int fringe_double_splay(struct state *st, fringe *f, double x, double y, fringe *lo, fringe *hi) +{ + st->fringe_double_cut_x = x; + st->fringe_double_cut_y = y; + st->fringe_double_cut_lo = lo; + st->fringe_double_cut_hi = hi; + f = (fringe*)splay(st, (cut)fringe_double_cut, (tree*)f); + + if (f == lo) + return (f->r = (fringe*)splay_min((tree*)f->r)) == hi; + else if (f == hi) + return (f->l = (fringe*)splay_max((tree*)f->l)) == lo; + else + return 0; + } + +static fringe *fringe_cross(struct state *st, event **eq, fringe *f, double x, double y, fringe *lo, fringe *hi) +{ + fringe *l, *r; + if (!fringe_double_splay(st, f, x, y, lo, hi)) + return PANIC; + l = check_lo(st, eq, y, lo->l, hi); + r = check_hi(st, eq, y, lo, hi->r); + lo->l = hi; + lo->r = r; + hi->l = l; + hi->r = 0; + return lo; + } + +static fringe *fringe_finish(struct state *st, event **eq, fringe *f, double x, double y, fringe *lo, fringe *hi) +{ + if (!fringe_double_splay(st, f, x, y, lo, hi)) + return PANIC; + else if (!lo->l) + return hi->r; + else if (!hi->r) + return lo->l; + else { + lo->l = (fringe*)splay_max((tree*)lo->l); + hi->r = (fringe*)splay_min((tree*)hi->r); + fringe_intersect(st, eq, y, lo->l, hi->r); + lo->l->r = hi->r; + hi->r->l = 0; + return lo->l; + } + } + +/******** plane sweep */ + +static void sweep(struct state *st, int n, circle *c) +{ + int i; + event *eq, *e; + fringe *f; + + RESTART: + #define CHECK_PANIC() \ + if (f == PANIC) { \ + free(e); \ + event_shred(eq); \ + for (i=0;ini = c[i].hi->ni = 0; \ + } \ + goto RESTART; \ + } + + eq = 0; + for (i=0;ikind) { + case START: + f = fringe_start(st, &eq, f, e->x, e->y, e->lo, e->hi); + break; + case CROSS: + f = fringe_cross(st, &eq, f, e->x, e->y, e->lo, e->hi); + CHECK_PANIC(); + fringe_add_intersection(e->lo, e->x, e->y); + fringe_add_intersection(e->hi, e->x, e->y); + break; + case FINISH: + f = fringe_finish(st, &eq, f, e->x, e->y, e->lo, e->hi); + CHECK_PANIC(); + break; + } + free(e); + } + } + +/******** circle drawing */ + +static void adjust_circle_visibility(circle *c) +{ + int i, j, n, a; + int *in; + n = c->lo->ni + c->hi->ni; + in = malloc(sizeof(int) * n); + for (i=0;ihi->ni;i++) + in[i] = c->hi->i[i]; + for (i=c->lo->ni-1;i>=0;i--) + in[n-i-1] = c->lo->i[i] > 0 ? c->lo->i[i] : c->lo->i[i] + 2 * X_PI; + c->lo->ni = c->hi->ni = 0; + + i = j = 0; + a = 0; + while (i < n && j < c->ni) /* whee */ + a = (in[i] < c->i[j] ? in[i++] : c->i[j++]) - a; + while (i < n) + a = in[i++] - a; + while (j < c->ni) + a = c->i[j++] - a; + + if (a > X_PI) + c->visible = !c->visible; + free(c->i); + c->ni = n; + c->i = in; + } + +static void flush_arc_buffer(struct state *st, Drawable w, GC gc) +{ + if (st->arc_buffer_count) { + XDrawArcs(st->dpy, w, gc, st->arc_buffer, st->arc_buffer_count); + st->arc_buffer_count = 0; + } + } + +static void draw_circle(struct state *st, Drawable w, GC gc, circle *c) +{ + int i, xi, yi, di; + adjust_circle_visibility(c); + + xi = rint(c->x - c->r); + yi = rint(c->y - c->r); + di = c->r << 1; + + #define ARC(p, a1, a2) { \ + if (((p) & 1) ^ c->visible) { \ + st->arc_buffer[st->arc_buffer_count].x = xi; \ + st->arc_buffer[st->arc_buffer_count].y = yi; \ + st->arc_buffer[st->arc_buffer_count].width = di; \ + st->arc_buffer[st->arc_buffer_count].height = di; \ + st->arc_buffer[st->arc_buffer_count].angle1 = -(a1); \ + st->arc_buffer[st->arc_buffer_count].angle2 = (a1) - (a2); \ + st->arc_buffer_count++; \ + if (st->arc_buffer_count == ARC_BUFFER_SIZE) \ + flush_arc_buffer(st, w, gc); \ + } \ + } + + if (!c->ni) + ARC(0, 0, 2 * X_PI) + else + ARC(0, c->i[c->ni-1], c->i[0] + 2 * X_PI) + for (i=1;ini;i++) + ARC(i, c->i[i-1], c->i[i]) + } + +/******** toplevel */ + +static void +check_for_leaks (void) +{ +#ifdef HAVE_SBRK + static unsigned long early_brk = 0; + unsigned long max = 30 * 1024 * 1024; /* 30 MB */ + int b = (unsigned long) sbrk(0); + if (early_brk == 0) + early_brk = b; + else if (b > early_brk + max) + { + fprintf (stderr, "%s: leaked %lu MB -- aborting!\n", + progname, ((b - early_brk) >> 20)); + exit (1); + } +#endif /* HAVE_SBRK */ +} + +static void * +piecewise_init (Display *dd, Window ww) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dd; + st->window = ww; + +#if 1 + st->count = count; + st->delay = delay; + st->ncolors = ncolors; + st->colorspeed = colorspeed; + st->dbuf = doubleBuffer; +#else + st->count = get_integer_resource(st->dpy, "count", "Integer"); + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer"); + st->colorspeed = get_integer_resource(st->dpy, "colorspeed", "Integer"); + st->dbuf = get_boolean_resource(st->dpy, "doubleBuffer", "Boolean"); +#endif + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + st->dbuf = False; +# endif + + st->color_iterations = st->colorspeed ? 100 / st->colorspeed : 100000; + if (!st->color_iterations) + st->color_iterations = 1; + + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + st->colors = calloc(sizeof(XColor), st->ncolors); + + //if (get_boolean_resource(st->dpy, "mono", "Boolean")) + if (False) + { + MONO: + st->ncolors = 1; + //st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap, "foreground", "Foreground"); + st->colors[0].pixel = load_color(st->dpy, st->xgwa.colormap, foreground); + } + else { + make_color_loop(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + 0, 1, 1, 120, 1, 1, 240, 1, 1, + st->colors, &st->ncolors, True, False); + if (st->ncolors < 2) + goto MONO; + } + + 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->ba = XCreatePixmap(st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth); + st->bb = XCreatePixmap(st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth); + st->b = st->ba; + } + } + else + st->b = st->window; + + /* erasure gc */ + //st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, "background", "Background"); + st->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, background); + st->erase_gc = XCreateGC (st->dpy, st->b, GCForeground, &st->gcv); + + /* drawing gc */ + st->flags = GCForeground; + st->color_index = random() % st->ncolors; + st->gcv.foreground = st->colors[st->color_index].pixel; + st->draw_gc = XCreateGC(st->dpy, st->b, st->flags, &st->gcv); + + /* initialize circles */ + st->circles = init_circles(st, st->count, st->xgwa.width, st->xgwa.height); + + st->iterations = 0; + + return st; +} + +static unsigned long +piecewise_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + + XFillRectangle (st->dpy, st->b, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height); + + sweep(st, st->count, st->circles); + for (i=0;icount;i++) { + draw_circle(st, st->b, st->draw_gc, st->circles+i); + move_circle(st->circles+i, st->xgwa.width, st->xgwa.height); + } + flush_arc_buffer(st, st->b, st->draw_gc); + + if (++st->iterations % st->color_iterations == 0) { + st->color_index = (st->color_index + 1) % st->ncolors; + XSetForeground(st->dpy, st->draw_gc, st->colors[st->color_index].pixel); + } + +#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->xgwa.width, st->xgwa.height, 0, 0); + st->b = (st->b == st->ba ? st->bb : st->ba); + } + + check_for_leaks(); + return st->delay; +} + +static void +piecewise_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); +} + +#if 0 + static Bool + piecewise_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +piecewise_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + +static const char *piecewise_defaults [] = { + ".background: black", + ".foreground: white", + "*delay: 10000", + "*speed: 15", + "*ncolors: 256", + ".colorspeed: 10", + + ".count: 32", + ".minradius: 0.05", + ".maxradius: 0.2", + + "*doubleBuffer: True", +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + "*useDBE: True", +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 + }; + +static XrmOptionDescRec piecewise_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-colorspeed", ".colorspeed", XrmoptionSepArg, 0 }, + + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-minradius", ".minradius", XrmoptionSepArg, 0 }, + { "-maxradius", ".maxradius", XrmoptionSepArg, 0 }, + + { "-db", ".doubleBuffer", XrmoptionNoArg, "True" }, + { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } + }; + + +XSCREENSAVER_MODULE ("Piecewise", piecewise) diff --git a/non-wgl/piecewise.vcproj b/non-wgl/piecewise.vcproj new file mode 100644 index 0000000..479b69d --- /dev/null +++ b/non-wgl/piecewise.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/polyominoes.c b/non-wgl/polyominoes.c new file mode 100644 index 0000000..d16922c --- /dev/null +++ b/non-wgl/polyominoes.c @@ -0,0 +1,2408 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* polyominoes --- Shows attempts to place polyominoes into a rectangle */ + +#if 0 +static const char sccsid[] = "@(#)polyominoes.c 5.01 2000/12/18 xlockmore"; +#endif + +/* + * Copyright (c) 2000 by Stephen Montgomery-Smith + * + * 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: + * 07-Jan-2001: Made improvement to the search algorithm for the puzzles + * involving identical polyominoes (via the variable + * reason_to_not_attach). By Stephen Montgomery-Smith. + * 20-Dec-2000: Added more puzzles at David Bagley's request. + * 27-Nov-2000: Adapted from euler2d.c Copyright (c) 2000 by Stephen + * Montgomery-Smith + * 05-Jun-2000: Adapted from flow.c Copyright (c) 1996 by Tim Auckland + * 18-Jul-1996: Adapted from swarm.c Copyright (c) 1991 by Patrick J. Naughton. + * 31-Aug-1990: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org) + */ + +#define STANDALONE +# define MODE_polyominoes + +#define DELAY 10000 +#define CYCLES 2000 +#define NCOLORS 64 +#define DEFAULTS "*delay: 10000 \n" \ + "*cycles: 2000 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + +# define polyominoes_handle_event 0 +# define SMOOTH_COLORS + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +# include "erase.h" +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +char *background = "black"; +char *foreground = "white"; +char *eraseMode = NULL; +float eraseSeconds = 0; + +#ifdef MODE_polyominoes +#define DEF_IDENTICAL "False" +#define DEF_PLAIN "False" + +static Bool identical = False; +static Bool plain = False; + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +static XrmOptionDescRec opts[] = +{ + {"-identical", ".polyominoes.identical", XrmoptionNoArg, "on"}, + {"+identical", ".polyominoes.identical", XrmoptionNoArg, "off"}, + {"-plain", ".polyominoes.plain", XrmoptionNoArg, "on"}, + {"+plain", ".polyominoes.plain", XrmoptionNoArg, "off"} +}; +static argtype vars[] = +{ + {&identical, "identical", "Identical", DEF_IDENTICAL, t_Bool}, + {&plain, "plain", "Plain", DEF_PLAIN, t_Bool} +}; +static OptionStruct desc[] = +{ + {"-/+identical", "turn on/off puzzles where the polyomino pieces are identical"}, + {"-/+plain", "turn on/off plain pieces"} +}; + +ENTRYPOINT ModeSpecOpt polyominoes_opts = +{sizeof opts / sizeof opts[0], opts, + sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct polyominoes_description = { + "polyominoes", "init_polyominoes", "draw_polyominoes", "release_polyominoes", + "refresh_polyominoes", "init_polyominoes", (char *) NULL, &polyominoes_opts, + 6000, 1, 8192, 1, 64, 1.0, "", + "Shows attempts to place polyominoes into a rectangle", 0, NULL +}; + +#endif + +/* Each polyomino is described by several quantities: + len: the number of squares in the polyomino; + point: the list of points; + tranform_len: the number of items in transform_list; + transform_list: a list of transformations that need to be done in order + to get all rotations and reflections (see the function + transform below); + max_white: the maximum number of white squares covered if polyomino + is placed on a chess board; + color: it's display color; + attached: whether it is currently attached to the rectangle; + attach_point: point on rectangle where attached; + point_no: the number of the point where it is attached; + transform_index: which element of transform_list is currently being used. +*/ + +typedef struct {int x,y;} point_type; + +typedef struct {int len; point_type *point; + int transform_len, transform_list[8], max_white; + unsigned long color; + int attached; + point_type attach_point; + int point_no, transform_index;} polyomino_type; + + +typedef struct _polyominoesstruct{ + int wait; + + int width, height; + unsigned border_color; + int mono; + + polyomino_type *polyomino; + int nr_polyominoes; + Bool identical, use3D; + int *attach_list; + int nr_attached; + +/* The array that tells where the polyominoes are attached. */ + int *array, *changed_array; + +/* These specify the dimensions of how things appear on the screen. */ + int box, x_margin, y_margin; + +/* These booleans decide in which way to try to attach the polyominoes. */ + int left_right, top_bottom; + +/* Bitmaps for display purposes. */ + int use_bitmaps; + XImage *bitmaps[256]; + +/* Structures used for display purposes if there is not enough memory + to allocate bitmaps (or if the screen is small). */ + XSegment *lines; + XRectangle *rectangles; + +/* A procedure that may be used to see if certain configurations + are permissible. */ + int (*check_ok)(struct _polyominoesstruct *sp); + +/* Tells program that solutions are invariant under 180 degree + rotation. */ + int rot180; + +/* This is a variable used in the case that all the polyominoes are identical + that will further prune the search tree. Essentially it will be + int reason_to_not_attach[nr_polynominoes][nr_polynominoes]; + Let me first explain the effect it is trying to overcome. Often + in the search process, the computer will first try to fit shapes into + a region (call it A), and then into another region (call it B) that is + essentially disjoint from A. But it may be that it just is not possible + to fit shapes into region B. So it fits something into A, and then + tries to fit something into B. Failing it fits something else into A, + and then tried again to fit something into B. Thus the program is trying + again and again to fit something into B, when it should have figured out + the first time that it was impossible. + + To overcome this, everytime we try to attach a piece, we collect the reasons + why it cannot be attached (a boolean for each piece that got in the way). + If we see that a piece cannot be attached, we detach the other pieces until + we have detached at least one piece for which the boolean reason_to_not_attach + is set. +*/ + int *reason_to_not_attach; + + int counter; + +#ifdef STANDALONE + eraser_state *eraser; +#endif +} polyominoesstruct; + +#define ARRAY(x,y) (sp->array[(x)*sp->height+(y)]) +#define CHANGED_ARRAY(x,y) (sp->changed_array[(x)*sp->height+(y)]) +#define ARRAY_P(p) (sp->array[(p).x*sp->height+(p).y]) +#define CHANGED_ARRAY_P(p) (sp->changed_array[(p).x*sp->height+(p).y]) +#define ARR(x,y) (((x)<0||(x)>=sp->width||(y)<0||(y)>=sp->height)?-2:ARRAY(x,y)) + +#define REASON_TO_NOT_ATTACH(x,y) (sp->reason_to_not_attach[(x)*sp->nr_polyominoes+(y)]) + +#define ROUND8(n) ((((n)+7)/8)*8) + +/* Defines to index the bitmaps. A set bit indicates that an edge or + corner is required. */ +#define LEFT (1<<0) +#define RIGHT (1<<1) +#define UP (1<<2) +#define DOWN (1<<3) +#define LEFT_UP (1<<4) +#define LEFT_DOWN (1<<5) +#define RIGHT_UP (1<<6) +#define RIGHT_DOWN (1<<7) +#define IS_LEFT(n) ((n) & LEFT) +#define IS_RIGHT(n) ((n) & RIGHT) +#define IS_UP(n) ((n) & UP) +#define IS_DOWN(n) ((n) & DOWN) +#define IS_LEFT_UP(n) ((n) & LEFT_UP) +#define IS_LEFT_DOWN(n) ((n) & LEFT_DOWN) +#define IS_RIGHT_UP(n) ((n) & RIGHT_UP) +#define IS_RIGHT_DOWN(n) ((n) & RIGHT_DOWN) + +/* Defines to access the bitmaps. */ +#define BITNO(x,y) ((x)+(y)*ROUND8(sp->box)) +#define SETBIT(n,x,y) {data[BITNO(x,y)/8] |= 1<<(BITNO(x,y)%8);} +#define RESBIT(n,x,y) {data[BITNO(x,y)/8] &= ~(1<<(BITNO(x,y)%8));} +#define TWOTHIRDSBIT(n,x,y) {if ((x+y-1)%3) SETBIT(n,x,y) else RESBIT(n,x,y)} +#define HALFBIT(n,x,y) {if ((x-y)%2) SETBIT(n,x,y) else RESBIT(n,x,y)} +#define THIRDBIT(n,x,y) {if (!((x-y-1)%3)) SETBIT(n,x,y) else RESBIT(n,x,y)} +#define THREEQUARTERSBIT(n,x,y) \ + {if ((y%2)||((x+2+y/2+1)%2)) SETBIT(n,x,y) else RESBIT(n,x,y)} +#define NOTHALFBIT(n,x,y) {if ((x-y)%2) RESBIT(n,x,y) else SETBIT(n,x,y)} + +/* Parameters for bitmaps. */ +#define G ((sp->box/45)+1) /* 1/2 of gap between polyominoes. */ +#define T ((sp->box<=12)?1:(G*2)) /* Thickness of walls of polyominoes. */ +#define R ((sp->box<=12)?1:(G*6)) /* Amount of rounding. */ +#define RT ((sp->box<=12)?1:(G*3)) /* Thickness of wall of rounded parts. + Here 3 is an approximation to 2 sqrt(2). */ +#define RR 0 /* Roof ridge thickness */ + +#if 0 +/* A list of those bitmaps we need to create to display any pentomino. */ +/* (not used right now because it does not seem to work for hexonimoes.) */ + +static int bitmaps_needed[] = +{ + LEFT_UP|LEFT_DOWN|RIGHT_UP|RIGHT_DOWN, + + LEFT|RIGHT_UP|RIGHT_DOWN, + RIGHT|LEFT_UP|LEFT_DOWN, + UP|LEFT_DOWN|RIGHT_DOWN, + DOWN|LEFT_UP|RIGHT_UP, + LEFT|RIGHT_UP, + RIGHT|LEFT_UP, + UP|LEFT_DOWN, + DOWN|LEFT_UP, + LEFT|RIGHT_DOWN, + RIGHT|LEFT_DOWN, + UP|RIGHT_DOWN, + DOWN|RIGHT_UP, + +/* These needed for hexonimoes*/ + LEFT, + RIGHT, + UP, + DOWN, + LEFT_DOWN|RIGHT_UP|RIGHT_DOWN, + LEFT_UP|RIGHT_UP|RIGHT_DOWN, + LEFT_UP|LEFT_DOWN|RIGHT_DOWN, + LEFT_UP|LEFT_DOWN|RIGHT_UP, + + LEFT|UP|RIGHT_DOWN, + LEFT|DOWN|RIGHT_UP, + RIGHT|UP|LEFT_DOWN, + RIGHT|DOWN|LEFT_UP, + LEFT|UP, + LEFT|DOWN, + RIGHT|UP, + RIGHT|DOWN, + + LEFT|RIGHT, + UP|DOWN, + + RIGHT|UP|DOWN, + LEFT|UP|DOWN, + LEFT|RIGHT|DOWN, + LEFT|RIGHT|UP, + + -1 +}; + +static int bitmap_needed(int n) +{ + int i; + + for (i=0;bitmaps_needed[i]!=-1;i++) + if (n == bitmaps_needed[i]) + return 1; + return 0; +} + +#endif + +/* Some debugging routines. + +static void print_board(polyominoesstruct *sp) +{ + int x,y; + for (y=0;yheight;y++) { + for (x=0;xwidth;x++) + if (ARRAY(x,y) == -1) + fprintf(stderr," "); + else + fprintf(stderr,"%c",'a'+ARRAY(x,y)); + fprintf(stderr,"\n"); + } + fprintf(stderr,"\n"); +} + +static void print_points(point_type *point, int len) +{ + int i; + + for (i=0;ix=in.x-offset.x+attach_point.x; + out->y=in.y-offset.y+attach_point.y; + break; + case 1: out->x=-(in.y-offset.y)+attach_point.x; + out->y=in.x-offset.x+attach_point.y; + break; + case 2: out->x=-(in.x-offset.x)+attach_point.x; + out->y=-(in.y-offset.y)+attach_point.y; + break; + case 3: out->x=in.y-offset.y+attach_point.x; + out->y=-(in.x-offset.x)+attach_point.y; + break; + case 4: out->x=-(in.x-offset.x)+attach_point.x; + out->y=in.y-offset.y+attach_point.y; + break; + case 5: out->x=in.y-offset.y+attach_point.x; + out->y=in.x-offset.x+attach_point.y; + break; + case 6: out->x=in.x-offset.x+attach_point.x; + out->y=-(in.y-offset.y)+attach_point.y; + break; + case 7: out->x=-(in.y-offset.y)+attach_point.x; + out->y=-(in.x-offset.x)+attach_point.y; + break; + } +} + +static int first_poly_no(polyominoesstruct *sp) +{ + int poly_no; + + poly_no = 0; + while(poly_nonr_polyominoes && sp->polyomino[poly_no].attached) + poly_no++; + return poly_no; +} + +static void next_poly_no(polyominoesstruct *sp, int *poly_no) +{ + + if (sp->identical) { + *poly_no = sp->nr_polyominoes; + } else { + do { + (*poly_no)++; + } while (*poly_nonr_polyominoes && sp->polyomino[*poly_no].attached); + } +} + +/* check_all_regions_multiple_of looks for connected regions of + blank spaces, and returns 0 if it finds a connected region containing + a number of blanks that is not a multiple of n. +*/ + +static void count_adjacent_blanks(polyominoesstruct *sp, int *count, int x, int y, int blank_mark) +{ + + if (ARRAY(x,y) == -1) { + (*count)++; + ARRAY(x,y) = blank_mark; + if (x>=1) count_adjacent_blanks(sp, count,x-1,y,blank_mark); + if (xwidth-1) count_adjacent_blanks(sp, count,x+1,y,blank_mark); + if (y>=1) count_adjacent_blanks(sp, count,x,y-1,blank_mark); + if (yheight-1) count_adjacent_blanks(sp, count,x,y+1,blank_mark); + } +} + +static int check_all_regions_multiple_of(polyominoesstruct *sp, int n) +{ + int x,y,count,good = 1; + + for (x=0;xwidth && good;x++) for (y=0;yheight && good;y++) { + count = 0; + count_adjacent_blanks(sp, &count,x,y,-2); + good = count%n == 0; + } + + for (x=0;xwidth;x++) for (y=0;yheight;y++) + if (ARRAY(x,y) == -2) + ARRAY(x,y) = -1; + + return good; +} + +static int check_all_regions_positive_combination_of(polyominoesstruct *sp, int m, int n) +{ + int x,y,count,good = 1; + + for (x=0;xwidth && good;x++) for (y=0;yheight && good;y++) { + count = 0; + count_adjacent_blanks(sp, &count,x,y,-2); + good = 0; + for (;count>=0 && !good;count-=m) + good = count%n == 0; + } + + for (x=0;xwidth;x++) for (y=0;yheight;y++) + if (ARRAY(x,y) == -2) + ARRAY(x,y) = -1; + + return good; +} + +static int find_smallest_blank_component(polyominoesstruct *sp) +{ + int x,y,size,smallest_size,blank_mark,smallest_mark; + + smallest_mark = blank_mark = -10; + smallest_size = 1000000000; + for (x=0;xwidth;x++) for (y=0;yheight;y++) if (ARRAY(x,y) == -1) { + size = 0; + count_adjacent_blanks(sp, &size,x,y,blank_mark); + if (sizewidth;x++) for (y=0;yheight;y++) { + if (ARRAY(x,y) == -1 && (x+y)%2) whites++; + if (ARRAY(x,y) == -1 && (x+y+1)%2) blacks++; + } + for (poly_no=0;poly_nonr_polyominoes;poly_no++) if (!sp->polyomino[poly_no].attached) { + max_white += sp->polyomino[poly_no].max_white; + min_white += sp->polyomino[poly_no].len - sp->polyomino[poly_no].max_white; + } + return (min_white <= blacks && min_white <= whites + && blacks <= max_white && whites <= max_white); +} + +/* This routine looks at the point (x,y) and sees how many polyominoes + and all their various transforms may be attached there. +*/ + +static int +score_point(polyominoesstruct *sp, int x, int y, int min_score_so_far) +{ + int poly_no, point_no, transform_index, i, attachable; + point_type attach_point, target_point; + int score = 0; + + if (x>=1 && xwidth-1 && y>=1 && yheight-1 && + ARRAY(x-1,y-1)<0 && ARRAY(x-1,y)<0 && ARRAY(x-1,y+1)<0 && + ARRAY(x+1,y-1)<0 && ARRAY(x+1,y)<0 && ARRAY(x+1,y+1)<0 && + ARRAY(x,y-1)<0 && ARRAY(x,y+1)<0) + return 10000; + + attach_point.x = x; + attach_point.y = y; + for (poly_no=first_poly_no(sp);poly_nonr_polyominoes;next_poly_no(sp,&poly_no)) + if (!sp->polyomino[poly_no].attached) { + for (point_no=0;point_nopolyomino[poly_no].len;point_no++) + for (transform_index=0;transform_indexpolyomino[poly_no].transform_len;transform_index++) { + attachable = 1; + for (i=0;ipolyomino[poly_no].len;i++) { + transform(sp->polyomino[poly_no].point[i], + sp->polyomino[poly_no].point[point_no], + sp->polyomino[poly_no].transform_list[transform_index], + attach_point, &target_point); + if ( ! ((target_point.x>=0) && (target_point.xwidth) + && (target_point.y>=0) && (target_point.yheight) + && (ARRAY_P(target_point)<0))) { + attachable = 0; + break; + } + } + if (attachable) { + score++; + if (score>=min_score_so_far) + return score; + } + } + } + + return score; +} + +static void find_blank(polyominoesstruct *sp, point_type *point) +{ + int score, worst_score; + int x, y; + int blank_mark; + + blank_mark = find_smallest_blank_component(sp); + + worst_score = 1000000; + for (x=0;xwidth;x++) for (y=0;yheight;y++) if (ARRAY(x,y)==blank_mark) { + score = 100*score_point(sp,x,y,worst_score); + if (score>0) { + if (sp->left_right) score += 10*x; + else score += 10*(sp->width-1-x); + if (sp->top_bottom) score += y; + else score += (sp->height-1-y); + } + if (scorex = x; + point->y = y; + worst_score = score; + } + } + + for (x=0;xwidth;x++) for (y=0;yheight;y++) + if (ARRAY(x,y)<0) ARRAY(x,y) = -1; +} + +/* Detaches the most recently attached polyomino. */ + +static +void detach(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index, point_type *attach_point, int rot180) +{ + int i; + point_type target_point; + + if (sp->nr_attached == 0) return; + sp->nr_attached--; + *poly_no = sp->attach_list[sp->nr_attached]; + *point_no = sp->polyomino[*poly_no].point_no; + *transform_index = sp->polyomino[*poly_no].transform_index; + *attach_point = sp->polyomino[*poly_no].attach_point; + for (i=0;ipolyomino[*poly_no].len;i++) { + transform(sp->polyomino[*poly_no].point[i], + sp->polyomino[*poly_no].point[*point_no], + sp->polyomino[*poly_no].transform_list[*transform_index]^(rot180<<1), + *attach_point, &target_point); + ARRAY_P(target_point) = -1; + CHANGED_ARRAY_P(target_point) = 1; + } + + sp->polyomino[*poly_no].attached = 0; +} + +/* Attempts to attach a polyomino at point (x,y) at the + point_no-th point of that polyomino, using the transform + transform_no. Returns 1 if successful. +*/ + +static +int attach(polyominoesstruct *sp, int poly_no, int point_no, int transform_index, point_type attach_point, int rot180, + int *reason_to_not_attach) { + point_type target_point; + int i; + int attachable = 1, worst_reason_not_to_attach = 1000000000; + + if (rot180) { + attach_point.x = sp->width-1-attach_point.x; + attach_point.y = sp->height-1-attach_point.y; + } + + if (sp->polyomino[poly_no].attached) + return 0; + + for (i=0;ipolyomino[poly_no].len;i++) { + transform(sp->polyomino[poly_no].point[i], + sp->polyomino[poly_no].point[point_no], + sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1), + attach_point, &target_point); + if ( ! ((target_point.x>=0) && (target_point.xwidth) + && (target_point.y>=0) && (target_point.yheight) + && (ARRAY_P(target_point) == -1))) { + if (sp->identical) { + attachable = 0; + if ((target_point.x>=0) && (target_point.xwidth) + && (target_point.y>=0) && (target_point.yheight) + && (ARRAY_P(target_point) >= 0) + && (ARRAY_P(target_point)identical && !attachable) { + if (worst_reason_not_to_attach < 1000000000) + reason_to_not_attach[worst_reason_not_to_attach] = 1; + return 0; + } + + for (i=0;ipolyomino[poly_no].len;i++) { + transform(sp->polyomino[poly_no].point[i], + sp->polyomino[poly_no].point[point_no], + sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1), + attach_point, &target_point); + ARRAY_P(target_point) = poly_no; + CHANGED_ARRAY_P(target_point) = 1; + } + + sp->attach_list[sp->nr_attached] = poly_no; + sp->nr_attached++; + + sp->polyomino[poly_no].attached = 1; + sp->polyomino[poly_no].point_no = point_no; + sp->polyomino[poly_no].attach_point = attach_point; + sp->polyomino[poly_no].transform_index = transform_index; + + if (!sp->check_ok(sp)) { + detach(sp,&poly_no,&point_no,&transform_index,&attach_point,rot180); + return 0; + } + + return 1; +} + +static +int next_attach_try(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index) +{ + + (*transform_index)++; + if (*transform_index>=sp->polyomino[*poly_no].transform_len) { + *transform_index = 0; + (*point_no)++; + if (*point_no>=sp->polyomino[*poly_no].len) { + *point_no = 0; + next_poly_no(sp,poly_no); + if (*poly_no>=sp->nr_polyominoes) { + *poly_no = first_poly_no(sp); + return 0; + } + } + } + return 1; +} + + +/******************************************************* +Display routines. +*******************************************************/ + +static void +draw_without_bitmaps(ModeInfo * mi, polyominoesstruct *sp) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + int x,y,poly_no,nr_lines,nr_rectangles; + + XSetLineAttributes(display,gc,sp->box/10+1,LineSolid,CapRound,JoinRound); + + for (poly_no=-1;poly_nonr_polyominoes;poly_no++) { + nr_rectangles = 0; + for (x=0;xwidth;x++) for (y=0;yheight;y++) + if (CHANGED_ARRAY(x,y) && ARRAY(x,y) == poly_no) { + sp->rectangles[nr_rectangles].x = sp->x_margin + sp->box*x; + sp->rectangles[nr_rectangles].y = sp->y_margin + sp->box*y; + sp->rectangles[nr_rectangles].width = sp->box; + sp->rectangles[nr_rectangles].height = sp->box; + nr_rectangles++; + } + if (poly_no == -1) + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + else + XSetForeground(display, gc, sp->polyomino[poly_no].color); + XFillRectangles(display, window, gc, sp->rectangles, nr_rectangles); + } + + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + + nr_lines = 0; + for (x=0;xwidth-1;x++) for (y=0;yheight;y++) { + if (ARRAY(x,y) == -1 && ARRAY(x+1,y) == -1 + && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x+1,y))) { + sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1); + sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y; + sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1); + sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1); + nr_lines++; + } + } + XDrawSegments(display, window, gc, sp->lines, nr_lines); + + nr_lines = 0; + for (x=0;xwidth;x++) for (y=0;yheight-1;y++) { + if (ARRAY(x,y) == -1 && ARRAY(x,y+1) == -1 + && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x,y+1))) { + sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x; + sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1); + sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1); + sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1); + nr_lines++; + } + } + XDrawSegments(display, window, gc, sp->lines, nr_lines); + + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + XDrawRectangle(display, window, gc, sp->x_margin, sp->y_margin, sp->box*sp->width, sp->box*sp->height); + + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + + nr_lines = 0; + for (x=0;xwidth-1;x++) for (y=0;yheight;y++) { + if (ARRAY(x+1,y) != ARRAY(x,y)) { + sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1); + sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y; + sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1); + sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1); + nr_lines++; + } + } + XDrawSegments(display, window, gc, sp->lines, nr_lines); + + nr_lines = 0; + for (x=0;xwidth;x++) for (y=0;yheight-1;y++) { + if (ARRAY(x,y+1) != ARRAY(x,y)) { + sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x; + sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1); + sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1); + sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1); + nr_lines++; + } + } + XDrawSegments(display, window, gc, sp->lines, nr_lines); + XSetLineAttributes(display,gc,1,LineSolid,CapRound,JoinRound); +} + +static void create_bitmaps(ModeInfo * mi, polyominoesstruct *sp) +{ + int x,y,n; + char *data; + + for (n=0;nbitmaps);n++) { + +/* Avoid duplication of identical bitmaps. */ + if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n))) + sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_UP]; + else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n))) + sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_DOWN]; + else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n))) + sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_UP]; + else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n))) + sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_DOWN]; + + else /* if (bitmap_needed(n)) */ { + data = (char *) malloc(sizeof(char)*(sp->box*ROUND8(sp->box)/8)); + if (data == NULL) { + sp->use_bitmaps = 0; + return; + } + + for (y=0;ybox;y++) for (x=0;xbox;x++) { + if (!sp->use3D) { +#ifdef SMALL_BELLYBUTTON + if (x >= sp->box / 2 && x <= sp->box / 2 + 1 && + y >= sp->box / 2 && y <= sp->box / 2 + 1) + NOTHALFBIT(n,x,y) + else +#endif + HALFBIT(n,x,y) + } else if ((x>=y && x<=sp->box-y-1 && IS_UP(n)) + || (x<=y && x<=sp->box-y-1 && ybox/2 && !IS_LEFT(n)) + || (x>=y && x>=sp->box-y-1 && ybox/2 && !IS_RIGHT(n))) + SETBIT(n,x,y) + else if ((x<=y && x<=sp->box-y-1 && IS_LEFT(n)) + || (x>=y && x<=sp->box-y-1 && xbox/2 && !IS_UP(n)) + || (x<=y && x>=sp->box-y-1 && xbox/2 && !IS_DOWN(n))) + TWOTHIRDSBIT(n,x,y) + else if ((x>=y && x>=sp->box-y-1 && IS_RIGHT(n)) + || (x>=y && x<=sp->box-y-1 && x>=sp->box/2 && !IS_UP(n)) + || (x<=y && x>=sp->box-y-1 && x>=sp->box/2 && !IS_DOWN(n))) + HALFBIT(n,x,y) + else if ((x<=y && x>=sp->box-y-1 && IS_DOWN(n)) + || (x<=y && x<=sp->box-y-1 && y>=sp->box/2 && !IS_LEFT(n)) + || (x>=y && x>=sp->box-y-1 && y>=sp->box/2 && !IS_RIGHT(n))) + THIRDBIT(n,x,y) + } + + if (IS_LEFT(n)) + for (y=0;ybox;y++) for (x=G;xbox;y++) for (x=G;xbox-1-x,y) + if (IS_UP(n)) + for (x=0;xbox;x++) for (y=G;ybox;x++) for (y=G;ybox-1-y) + if (IS_LEFT(n)) + for (y=0;ybox;y++) for (x=0;xbox;y++) for (x=0;xbox-1-x,y) + if (IS_UP(n)) + for (x=0;xbox;x++) for (y=0;ybox;x++) for (y=0;ybox-1-y) + + if (IS_LEFT(n) && IS_UP(n)) + for (x=G;x<=G+R;x++) + for (y=G;y<=R+2*G-x;y++) { + if (x+y>R+2*G-RT) + SETBIT(n,x,y) + else + RESBIT(n,x,y) + } + if (IS_LEFT(n) && IS_DOWN(n)) + for (x=G;x<=G+R;x++) + for (y=G;y<=R+2*G-x;y++) { + if (x+y>R+2*G-RT) + SETBIT(n,x,sp->box-1-y) + else + RESBIT(n,x,sp->box-1-y) + } + if (IS_RIGHT(n) && IS_UP(n)) + for (x=G;x<=G+R;x++) + for (y=G;y<=R+2*G-x;y++) { + if (x+y>R+2*G-RT) + SETBIT(n,sp->box-1-x,y) + else + RESBIT(n,sp->box-1-x,y) + } + if (IS_RIGHT(n) && IS_DOWN(n)) + for (x=G;x<=G+R;x++) + for (y=G;y<=R+2*G-x;y++) { + if (x+y>R+2*G-RT) + SETBIT(n,sp->box-1-x,sp->box-1-y) + else + RESBIT(n,sp->box-1-x,sp->box-1-y) + } + + if (!IS_LEFT(n) && !IS_UP(n) && IS_LEFT_UP(n)) { + for (x=0;xbox-1-y) + for (x=G;xbox-1-y) + for (x=0;xbox-1-y) + } + if (!IS_RIGHT(n) && !IS_UP(n) && IS_RIGHT_UP(n)) { + for (x=0;xbox-1-x,y) + for (x=G;xbox-1-x,y) + for (x=0;xbox-1-x,y) + } + if (!IS_RIGHT(n) && !IS_DOWN(n) && IS_RIGHT_DOWN(n)) { + for (x=0;xbox-1-x,sp->box-1-y) + for (x=G;xbox-1-x,sp->box-1-y) + for (x=0;xbox-1-x,sp->box-1-y) + } + +#ifdef LARGE_BELLYBUTTON + if (!sp->use3D) { + if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n)) + for (x=0;xbox-G-T;ybox;y++) + SETBIT(n,x,y) + if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n)) + for (x=sp->box-G-T;xbox;x++) for(y=0;ybox-G-T;xbox;x++) for(y=sp->box-G-T;ybox;y++) + SETBIT(n,x,y) + } else +#else + if (sp->use3D) +#endif + { + if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n)) + for (x=0;xbox/2-RR;x++) for(y=0;ybox/2-RR;y++) + THREEQUARTERSBIT(n,x,y) + if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n)) + for (x=0;xbox/2-RR;x++) for(y=sp->box/2+RR;ybox;y++) + THREEQUARTERSBIT(n,x,y) + if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n)) + for (x=sp->box/2+RR;xbox;x++) for(y=0;ybox/2-RR;y++) + THREEQUARTERSBIT(n,x,y) + if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n)) + for (x=sp->box/2+RR;xbox;x++) for(y=sp->box/2+RR;ybox;y++) + THREEQUARTERSBIT(n,x,y) + } + + sp->bitmaps[n] = XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi), 1, XYBitmap, + 0, data, sp->box, sp->box, 8, 0); + if (sp->bitmaps[n] == None) { + free(data); + sp->use_bitmaps = 0; + return; + } + sp->bitmaps[n]->byte_order = MSBFirst; + //sp->bitmaps[n]->bitmap_unit = 8; + sp->bitmaps[n]->bitmap_bit_order = LSBFirst; + } + } + + sp->use_bitmaps = 1; +} + +static void draw_with_bitmaps(ModeInfo * mi, polyominoesstruct *sp) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + int x,y,t,bitmap_index; + + for (x=0;xwidth;x++) for (y=0;yheight;y++) { + if (ARRAY(x,y) == -1) { + if (CHANGED_ARRAY(x,y)) { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XFillRectangle(display,window,gc, + sp->x_margin + sp->box*x, + sp->y_margin + sp->box*y, + sp->box,sp->box); + } + } + else { + XSetForeground(display, gc, sp->polyomino[ARRAY(x,y)].color); + bitmap_index = 0; + if (ARR(x,y) != ARR(x-1,y)) bitmap_index |= LEFT; + if (ARR(x,y) != ARR(x+1,y)) bitmap_index |= RIGHT; + if (ARR(x,y) != ARR(x,y-1)) bitmap_index |= UP; + if (ARR(x,y) != ARR(x,y+1)) bitmap_index |= DOWN; + if (ARR(x,y) != ARR(x-1,y-1)) bitmap_index |= LEFT_UP; + if (ARR(x,y) != ARR(x-1,y+1)) bitmap_index |= LEFT_DOWN; + if (ARR(x,y) != ARR(x+1,y-1)) bitmap_index |= RIGHT_UP; + if (ARR(x,y) != ARR(x+1,y+1)) bitmap_index |= RIGHT_DOWN; + (void) XPutImage(display,window,gc, + sp->bitmaps[bitmap_index], + 0,0, + sp->x_margin + sp->box*x, + sp->y_margin + sp->box*y, + sp->box,sp->box); + } + } + + XSetForeground(display, gc, sp->border_color); + for (t=G;tx_margin-t-1,sp->y_margin-t-1, + sp->box*sp->width+1+2*t, sp->box*sp->height+1+2*t); +} + + +/*************************************************** +Routines to initialise and close down polyominoes. +***************************************************/ + +static void free_bitmaps(polyominoesstruct *sp) +{ + int n; + + for (n=0;nbitmaps);n++) +/* Don't bother to free duplicates */ + if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n))) + sp->bitmaps[n] = None; + else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n))) + sp->bitmaps[n] = None; + else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n))) + sp->bitmaps[n] = None; + else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n))) + sp->bitmaps[n] = None; + + else if (sp->bitmaps[n] != None) { + XDestroyImage(sp->bitmaps[n]); + sp->bitmaps[n] = None; + } +} + +#define deallocate(p,t) if ((p)!=NULL) {free(p); p=(t*)NULL;} + +static void free_polyominoes(polyominoesstruct *sp) +{ + int n; + + for (n=0;nnr_polyominoes;n++) { + deallocate(sp->polyomino[n].point, point_type); + } + + deallocate(sp->polyomino, polyomino_type); + deallocate(sp->attach_list, int); + deallocate(sp->rectangles, XRectangle); + deallocate(sp->lines, XSegment); + deallocate(sp->reason_to_not_attach, int); + deallocate(sp->array, int); + deallocate(sp->changed_array, int); + + free_bitmaps(sp); +} + +#define set_allocate(p,type,size) p = (type *) malloc(size); \ + if ((p)==NULL) {free_polyominoes(sp);return 0;} + +#define copy_polyomino(dst,src,new_rand) \ + (dst).len=(src).len; \ + (dst).max_white = (src).max_white; \ + set_allocate((dst).point,point_type,sizeof(point_type)*(src).len); \ + (dst).len = (src).len; \ + if (new_rand) \ + random_permutation((src).len,perm_point); \ + for (i=0;i<(src).len;i++) \ + (dst).point[i] = (src).point[perm_point[i]]; \ + (dst).transform_len = (src).transform_len; \ + if (new_rand) \ + random_permutation((src).transform_len,perm_transform); \ + for (i=0;i<(src).transform_len;i++) \ + (dst).transform_list[i] = (src).transform_list[perm_transform[i]]; \ + (dst).attached = 0 + + +/*************************************************** +Puzzle specific initialization routines. +***************************************************/ + +static +int check_pentomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_multiple_of(sp, 5) && whites_ok(sp); +} + +static +int check_hexomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_multiple_of(sp, 6) && whites_ok(sp); +} + +static +int check_tetr_pentomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_positive_combination_of(sp, 5, 4) && whites_ok(sp); +} + +static +int check_pent_hexomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_positive_combination_of(sp, 6, 5) && whites_ok(sp); +} + +static +int check_heptomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_multiple_of(sp, 7) && whites_ok(sp); +} + +static +int check_octomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_multiple_of(sp, 8) && whites_ok(sp); +} + +static +int check_dekomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_multiple_of(sp, 10) && whites_ok(sp); +} + +static +int check_elevenomino_puzzle(polyominoesstruct *sp) +{ + return check_all_regions_multiple_of(sp, 11) && whites_ok(sp); +} + +static struct {int len; point_type point[4]; + int transform_len, transform_list[8], max_white;} tetromino[5] = +{ +/* +xxxx +*/ + {4, {{0,0}, {1,0}, {2,0}, {3,0}}, + 2, {0, 1, -1, -1, -1, -1, -1, -1}, 2}, +/* +xxx + x +*/ + {4, {{0,0}, {1,0}, {2,0}, {2,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 2}, +/* +xxx + x +*/ + {4, {{0,0}, {1,0}, {1,1}, {2,0}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* +xx + xx +*/ + {4, {{0,0}, {1,0}, {1,1}, {2,1}}, + 4, {0, 1, 4, 5, -1, -1, -1, -1}, 2}, +/* +xx +xx +*/ + {4, {{0,0}, {0,1}, {1,0}, {1,1}}, + 1, {0, -1, -1, -1, -1, -1, -1, -1}, 2}}; + + +static struct pentomino_struct {int len; point_type point[5]; + int transform_len, transform_list[8], max_white;} + pentomino[12] = +{ +/* +xxxxx +*/ + {5, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}}, + 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3}, +/* +xxxx + x +*/ + {5, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxxx + x +*/ + {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* + x +xxx + x +*/ + {5, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* +xxx + xx +*/ + {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxx + xx +*/ + {5, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxx + x + x +*/ + {5, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* + x +xxx + x +*/ + {5, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxx +x x +*/ + {5, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* + x +xxx +x +*/ + {5, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}}, + 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}, +/* + x +xxx + x +*/ + {5, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}}, + 1, {0, -1, -1, -1, -1, -1, -1, -1}, 4}, +/* +xx + xx + x +*/ + {5, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}}; + + +static struct hexomino_struct {int len; point_type point[6]; + int transform_len, transform_list[8], max_white;} + hexomino[35] = +{ +/* +xxxxxx +*/ + {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {5,0}}, + 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3}, +/* +xxxxx + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {4,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxxxx + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,0}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}, +/* +xxxxx + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {4,0}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* + x +xxxx + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {3,-1}, {3,0}, {3,1}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4}, +/* +xxxx + xx +*/ + {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxxx + xx +*/ + {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxxx + x + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {3,2}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* + x +xxxx + x +*/ + {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {3,0}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxxx + x x +*/ + {6, {{0,0}, {1,0}, {1,1}, {2,0}, {3,0}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}, +/* + x +xxxx + x +*/ + {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {3,0}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}, +/* +xxxx +x x +*/ + {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,0}, {3,1}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* + x +xxxx +x +*/ + {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,-1}, {3,0}}, + 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}, +/* + x +xxxx + x +*/ + {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,0}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4}, +/* +xxxx + xx +*/ + {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,0}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* +xxxx + x + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,0}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* + x +xxxx + x +*/ + {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,0}}, + 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}, +/* + xx +xxx + x +*/ + {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,-1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* + xx +xxx + x +*/ + {6, {{0,0}, {1,-1}, {1,0}, {2,-1}, {2,0}, {2,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* + x +xxx +x x +*/ + {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {2,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}, +/* +xxx + xxx +*/ + {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {4,1}}, + 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}, +/* +xxx + xx + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {3,2}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxx + xxx +*/ + {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,1}}, + 4, {0, 1, 4, 5, -1, -1, -1, -1}, 4}, +/* +xxx + xx + x +*/ + {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}, +/* + x +xxx + xx +*/ + {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}, +/* +xxx +x xx +*/ + {6, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}, {3,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxx + xx + x +*/ + {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {2,2}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4}, +/* + x +xxx + xx +*/ + {6, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}, {2,1}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4}, +/* +xxx +xxx +*/ + {6, {{0,0}, {0,1}, {1,0}, {1,1}, {2,0}, {2,1}}, + 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3}, +/* +xxx + x + xx +*/ + {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,2}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xxx + x + xx +*/ + {6, {{0,0}, {1,0}, {1,2}, {2,0}, {2,1}, {2,2}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* + x +xxx +x x +*/ + {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,0}, {2,1}}, + 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}, +/* + xx +xxx +x +*/ + {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {3,-1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* + xx +xxx +x +*/ + {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,-1}, {2,0}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}, +/* +xx + xx + xx +*/ + {6, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}, {3,2}}, + 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}}; + +static struct pentomino_struct one_sided_pentomino[60]; + +static void make_one_sided_pentomino(void) +{ + int i,j,t,u; + + j=0; + for (i=0;i=4) { + one_sided_pentomino[j].transform_len = t; + j++; + one_sided_pentomino[j] = pentomino[i]; + for (u=t;u<8;u++) one_sided_pentomino[j].transform_list[u-t] = one_sided_pentomino[j].transform_list[u]; + one_sided_pentomino[j].transform_len -= t; + break; + } + j++; + } +} + +static struct hexomino_struct one_sided_hexomino[60]; + +static void make_one_sided_hexomino(void) +{ + int i,j,t,u; + + j=0; + for (i=0;i=4) { + one_sided_hexomino[j].transform_len = t; + j++; + one_sided_hexomino[j] = hexomino[i]; + for (u=t;u<8;u++) one_sided_hexomino[j].transform_list[u-t] = one_sided_hexomino[j].transform_list[u]; + one_sided_hexomino[j].transform_len -= t; + break; + } + j++; + } +} + +/* +Find all the ways of placing all twelve pentominoes +into a rectangle whose size is 20x3, 15x4, 12x5 or 10x6. +*/ + +static +int set_pentomino_puzzle(polyominoesstruct *sp) +{ + int perm_poly[12], perm_point[5], perm_transform[8], i, p; + + switch (NRAND(4)) { + case 0: + sp->width = 20; + sp->height = 3; + break; + case 1: + sp->width = 15; + sp->height = 4; + break; + case 2: + sp->width = 12; + sp->height = 5; + break; + case 3: + sp->width = 10; + sp->height = 6; + break; + } + + sp->nr_polyominoes = 12; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + random_permutation(sp->nr_polyominoes,perm_poly); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],pentomino[perm_poly[p]],1); + } + + sp->check_ok = check_pentomino_puzzle; + + return 1; +} + +/* +Many of the following puzzles are inspired by +http://www.xs4all.nl/~gp/PolyominoSolver/Polyomino.html +*/ + +/* +Find all the ways of placing all eighteen one-sided pentominoes +into a rectangle. +*/ + +static +int set_one_sided_pentomino_puzzle(polyominoesstruct *sp) +{ + int perm_poly[18], perm_point[5], perm_transform[8], i, p; + + make_one_sided_pentomino(); + + switch (NRAND(4)) { + case 0: + sp->width = 30; + sp->height = 3; + break; + case 1: + sp->width = 18; + sp->height = 5; + break; + case 2: + sp->width = 15; + sp->height = 6; + break; + case 3: + sp->width = 10; + sp->height = 9; + break; + } + + sp->nr_polyominoes = 18; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + random_permutation(sp->nr_polyominoes,perm_poly); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],one_sided_pentomino[perm_poly[p]],1); + } + + sp->check_ok = check_pentomino_puzzle; + + return 1; +} + +/* +Find all the ways of placing all sixty one-sided hexominoes +into a rectangle. +*/ + +static +int set_one_sided_hexomino_puzzle(polyominoesstruct *sp) +{ + int perm_poly[60], perm_point[6], perm_transform[8], i, p; + + make_one_sided_hexomino(); + + switch (NRAND(8)) { + case 0: + sp->width = 20; + sp->height = 18; + break; + case 1: + sp->width = 24; + sp->height = 15; + break; + case 2: + sp->width = 30; + sp->height = 12; + break; + case 3: + sp->width = 36; + sp->height = 10; + break; + case 4: + sp->width = 40; + sp->height = 9; + break; + case 5: + sp->width = 45; + sp->height = 8; + break; + case 6: + sp->width = 60; + sp->height = 6; + break; + case 7: + sp->width = 72; + sp->height = 5; + break; + } + + sp->nr_polyominoes = 60; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + random_permutation(sp->nr_polyominoes,perm_poly); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],one_sided_hexomino[perm_poly[p]],1); + } + + sp->check_ok = check_hexomino_puzzle; + + return 1; +} + +/* +Find all the ways of placing all five tetrominoes and all twelve +pentominoes into a rectangle. +*/ + +static +int set_tetr_pentomino_puzzle(polyominoesstruct *sp) +{ + int perm_poly[17], perm_point[5], perm_transform[8], i, p; + + switch (NRAND(3)) { + case 0: + sp->width = 20; + sp->height = 4; + break; + case 1: + sp->width = 16; + sp->height = 5; + break; + case 2: + sp->width = 10; + sp->height = 8; + break; + } + + sp->nr_polyominoes = 17; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + random_permutation(sp->nr_polyominoes,perm_poly); + for (p=0;ppolyomino[perm_poly[p]],tetromino[p],1); + } + for (p=0;ppolyomino[perm_poly[p+5]],pentomino[p],1); + } + + sp->check_ok = check_tetr_pentomino_puzzle; + + return 1; +} +/* +Find all the ways of placing all twelve pentominoes and all thirty five +hexominoes into a rectangle whose size is 18x15. +*/ + +static +int set_pent_hexomino_puzzle(polyominoesstruct *sp) +{ + int perm_poly[47], perm_point[6], perm_transform[8], i, p; + + switch (NRAND(5)) { + case 0: + sp->width = 54; + sp->height = 5; + break; + case 1: + sp->width = 45; + sp->height = 6; + break; + case 2: + sp->width = 30; + sp->height = 9; + break; + case 3: + sp->width = 27; + sp->height = 10; + break; + case 4: + sp->width = 18; + sp->height = 15; + break; + } + + sp->nr_polyominoes = 47; + set_allocate(sp->polyomino,polyomino_type,47*sizeof(polyomino_type)); + random_permutation(47,perm_poly); + for (p=0;ppolyomino[perm_poly[p]],pentomino[p],1); + } + for (p=0;ppolyomino[perm_poly[p+12]],hexomino[p],1); + } + + sp->check_ok = check_pent_hexomino_puzzle; + + return 1; +} + +/* +Other puzzles: + +Science News September 20, 1986 Vol 130, No 12 +Science News November 14, 1987 Vol 132, Pg 310 +*/ + +/* + + * +**** fills a 10x5 rectangle + +*/ + +static struct {int len; point_type point[5]; + int transform_len, transform_list[8], max_white;} pentomino1 = + {5, {{0,0}, {1,0}, {2,0}, {3,0}, {1,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3}; + +static +int set_pentomino_puzzle1(polyominoesstruct *sp) +{ + int perm_point[5], perm_transform[8], i, p; + + sp->width = 10; + sp->height =5; + + sp->nr_polyominoes = 10; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],pentomino1,1); + } + + sp->check_ok = check_pentomino_puzzle; + + return 1; +} + +/* + + * +***** fills a 24x23 rectangle + +*/ + +static struct {int len; point_type point[6]; + int transform_len, transform_list[8], max_white;} hexomino1 = + {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}; + +static +int set_hexomino_puzzle1(polyominoesstruct *sp) +{ + int perm_point[6], perm_transform[8], i, p; + + sp->width = 24; + sp->height =23; + + sp->nr_polyominoes = 92; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],hexomino1,1); + } + + sp->check_ok = check_hexomino_puzzle; + + return 1; +} + +/* + + ** +***** fills a 21x26 rectangle + +(All solutions have 180 degree rotational symmetry) + +*/ + +static struct {int len; point_type point[7]; + int transform_len, transform_list[8], max_white;} heptomino1 = + {7, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}, {2,1}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4}; + +static +int set_heptomino_puzzle1(polyominoesstruct *sp) +{ + int perm_point[7], perm_transform[8], i, p; + + sp->rot180 = 1; + + sp->width = 26; + sp->height =21; + + sp->nr_polyominoes = 78; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p+=2) { + copy_polyomino(sp->polyomino[p],heptomino1,1); + copy_polyomino(sp->polyomino[p+1],heptomino1,0); + } + + sp->check_ok = check_heptomino_puzzle; + + return 1; +} + +/* The following puzzles from +Polyominoes Puzzles, Patterns, Problems, and Packings Revised (2nd) Edition +by Solomon W. Golomb Princeton University Press 1994 +*/ + +/* + + ** +***** fills a 28x19 rectangle + +*/ +static +int set_heptomino_puzzle2(polyominoesstruct *sp) +{ + int perm_point[7], perm_transform[8], i, p; + + sp->width = 28; + sp->height =19; + + sp->nr_polyominoes = 76; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],heptomino1,1); + } + + sp->check_ok = check_heptomino_puzzle; + + return 1; +} + +/* + +*** +**** fills a 25x22 rectangle +**** + +*/ + +static struct {int len; point_type point[11]; + int transform_len, transform_list[8], max_white;} elevenomino1 = + {11, {{0,0}, {1,0}, {2,0}, + {0,1}, {1,1}, {2,1}, {3,1}, + {0,2}, {1,2}, {2,2}, {3,2}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 6}; + +static +int set_elevenomino_puzzle1(polyominoesstruct *sp) +{ + int perm_point[11], perm_transform[8], i, p; + + sp->rot180 = 1; + + sp->width = 25; + sp->height =22; + + sp->nr_polyominoes = 50; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p+=2) { + copy_polyomino(sp->polyomino[p],elevenomino1,1); + copy_polyomino(sp->polyomino[p+1],elevenomino1,0); + } + + sp->check_ok = check_elevenomino_puzzle; + + return 1; +} + +/* + + * + * +**** fills 32 x 30 rectangle +**** + +*/ + +static struct {int len; point_type point[10]; + int transform_len, transform_list[8], max_white;} dekomino1 = + {10, { {1,-1}, + {1,0}, + {0,1}, {1,1}, {2,1}, {3,1}, + {0,2}, {1,2}, {2,2}, {3,2}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 5}; + +static +int set_dekomino_puzzle1(polyominoesstruct *sp) +{ + int perm_point[10], perm_transform[8], i, p; + + sp->width = 32; + sp->height =30; + + sp->nr_polyominoes = 96; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],dekomino1,1); + } + + sp->check_ok = check_dekomino_puzzle; + + return 1; +} + +/* + + * +*** fills 96 x 26 rectangle +**** + +*/ + +static struct {int len; point_type point[10]; + int transform_len, transform_list[8], max_white;} octomino1 = + {8, { {1,0}, + {0,1}, {1,1}, {2,1}, + {0,2}, {1,2}, {2,2}, {3,2}}, + 8, {0, 1, 2, 3, 4, 5, 6, 7}, 5}; + +static +int set_octomino_puzzle1(polyominoesstruct *sp) +{ + int perm_point[8], perm_transform[8], i, p; + + sp->width = 96; + sp->height =26; + + sp->nr_polyominoes = 312; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],octomino1,1); + } + + sp->check_ok = check_octomino_puzzle; + + return 1; +} + +/* + + * fills 15 x 15 rectangle +**** + +*/ + +static +int set_pentomino_puzzle2(polyominoesstruct *sp) +{ + int perm_point[5], perm_transform[8], i, p; + + sp->width = 15; + sp->height =15; + + sp->nr_polyominoes = 45; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],pentomino1,1); + } + + sp->check_ok = check_pentomino_puzzle; + + return 1; +} + +/* + +*** +**** fills a 47x33 rectangle +**** + +*/ + +static +int set_elevenomino_puzzle2(polyominoesstruct *sp) +{ + int perm_point[11], perm_transform[8], i, p; + + sp->width = 47; + sp->height =33; + + sp->nr_polyominoes = 141; + set_allocate(sp->polyomino,polyomino_type, + sp->nr_polyominoes*sizeof(polyomino_type)); + for (p=0;pnr_polyominoes;p++) { + copy_polyomino(sp->polyomino[p],elevenomino1,1); + } + + sp->check_ok = check_elevenomino_puzzle; + + return 1; +} + +/************************************************** +The main functions. +**************************************************/ + +#define allocate(p,type,size) p = (type *) malloc(size); if ((p)==NULL) {free_polyominoes(sp); return;} + +ENTRYPOINT void +init_polyominoes (ModeInfo * mi) +{ + polyominoesstruct *sp; + int i,x,y, start; + int box1, box2; + int *perm; + + if (polyominoeses == NULL) { + if ((polyominoeses + = (polyominoesstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (polyominoesstruct))) + == NULL) + return; + } + sp = &polyominoeses[MI_SCREEN(mi)]; + + free_polyominoes(sp); + + sp->rot180 = 0; + sp->counter = 0; + + if (MI_IS_FULLRANDOM(mi)) { + sp->identical = (Bool) (LRAND() & 1); + sp->use3D = (Bool) (NRAND(4)); + } else { + sp->identical = identical; + sp->use3D = !plain; + } + if (sp->identical) { + switch (NRAND(9)) { + case 0: + if (!set_pentomino_puzzle1(sp)) + return; + break; + case 1: + if (!set_hexomino_puzzle1(sp)) + return; + break; + case 2: + if (!set_heptomino_puzzle1(sp)) + return; + break; + case 3: + if (!set_heptomino_puzzle2(sp)) + return; + break; + case 4: + if (!set_elevenomino_puzzle1(sp)) + return; + break; + case 5: + if (!set_dekomino_puzzle1(sp)) + return; + break; + case 6: + if (!set_octomino_puzzle1(sp)) + return; + break; + case 7: + if (!set_pentomino_puzzle2(sp)) + return; + break; + case 8: + if (!set_elevenomino_puzzle2(sp)) + return; + break; + } + } else { + switch (NRAND(5)) { + case 0: + if (!set_pentomino_puzzle(sp)) + return; + break; + case 1: + if (!set_one_sided_pentomino_puzzle(sp)) + return; + break; + case 2: + if (!set_one_sided_hexomino_puzzle(sp)) + return; + break; + case 3: + if (!set_pent_hexomino_puzzle(sp)) + return; + break; + case 4: + if (!set_tetr_pentomino_puzzle(sp)) + return; + break; + } + } + + allocate(sp->attach_list,int,sp->nr_polyominoes*sizeof(int)); + sp->nr_attached = 0; + + if (sp->identical) { + allocate(sp->reason_to_not_attach,int,sp->nr_polyominoes*sp->nr_polyominoes*sizeof(int)); + } + + allocate(sp->array,int,sp->width*sp->height*sizeof(int)); + allocate(sp->changed_array,int,sp->width*sp->height*sizeof(int)); + for (x=0;xwidth;x++) for (y=0;yheight;y++) ARRAY(x,y) = -1; + + sp->left_right = NRAND(2); + sp->top_bottom = NRAND(2); + + box1 = MI_WIDTH(mi)/(sp->width+2); + box2 = MI_HEIGHT(mi)/(sp->height+2); + if (box1box = box1; + else + sp->box = box2; + + if (sp->box >= 12) { + sp->box = (sp->box/12)*12; + create_bitmaps(mi,sp); + if (!sp->use_bitmaps) + free_bitmaps(sp); + } + else + sp->use_bitmaps = 0; + + if (!sp->use_bitmaps) { + allocate(sp->rectangles,XRectangle,sp->width*sp->height*sizeof(XRectangle)); + allocate(sp->lines,XSegment,sp->width*sp->height*sizeof(XSegment)); + } + + allocate(perm,int,sp->nr_polyominoes*sizeof(int)); + random_permutation(sp->nr_polyominoes, perm); + sp->mono = MI_NPIXELS(mi) < 12; + start = NRAND(MI_NPIXELS(mi)); + for (i=0;inr_polyominoes;i++) + if (!sp->mono) { + sp->polyomino[i].color = MI_PIXEL(mi,(perm[i]*MI_NPIXELS(mi) / sp->nr_polyominoes + start) % MI_NPIXELS(mi)); + if (sp->rot180) { + sp->polyomino[i+1].color = sp->polyomino[i].color; + i++; + } + } + else + if(sp->use_bitmaps) + sp->polyomino[i].color = MI_WHITE_PIXEL(mi); + else + sp->polyomino[i].color = MI_BLACK_PIXEL(mi); + free(perm); + + if (sp->use_bitmaps) { + if (sp->mono) + sp->border_color = MI_WHITE_PIXEL(mi); + else + sp->border_color = MI_PIXEL(mi,NRAND(MI_NPIXELS(mi))); + } + + sp->x_margin = (MI_WIDTH(mi)-sp->box*sp->width)/2; + sp->y_margin = (MI_HEIGHT(mi)-sp->box*sp->height)/2; + + sp->wait = 0; + +#ifndef STANDALONE + /* Clear the background. */ + MI_CLEARWINDOW(mi); +#endif + +} + +ENTRYPOINT void +draw_polyominoes (ModeInfo * mi) +{ + polyominoesstruct *sp; + int poly_no,point_no,transform_index,done,another_attachment_try; + point_type attach_point; + int i,detach_until; + + if (polyominoeses == NULL) + return; + sp = &polyominoeses[MI_SCREEN(mi)]; + +#ifdef STANDALONE + if (sp->eraser) { + sp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), sp->eraser); + return; + } +#endif + + if (MI_CYCLES(mi) != 0) { + if (++sp->counter > MI_CYCLES(mi)) { +#ifdef STANDALONE + sp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), sp->eraser); +#endif /* STANDALONE */ + init_polyominoes(mi); + return; + } + } + + if (sp->box == 0) { +#ifdef STANDALONE + sp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), sp->eraser); +#endif /* STANDALONE */ + init_polyominoes(mi); + return; + } + + MI_IS_DRAWN(mi) = True; + sp->wait--; + if (sp->wait>0) return; + + memset(sp->changed_array,0,sp->width*sp->height*sizeof(int)); + + poly_no = first_poly_no(sp); + point_no = 0; + transform_index = 0; + done = 0; + another_attachment_try = 1; + find_blank(sp,&attach_point); + if (sp->identical && sp->nr_attached < sp->nr_polyominoes) + memset(&REASON_TO_NOT_ATTACH(sp->nr_attached,0),0,sp->nr_polyominoes*sizeof(int)); + while(!done) { + if (sp->nr_attached < sp->nr_polyominoes) { + while (!done && another_attachment_try) { + done = attach(sp,poly_no,point_no,transform_index,attach_point,0,&REASON_TO_NOT_ATTACH(sp->nr_attached,0)); + if (done && sp->rot180) { + poly_no = first_poly_no(sp); + done = attach(sp,poly_no,point_no,transform_index,attach_point,1,&REASON_TO_NOT_ATTACH(sp->nr_attached-1,0)); + if (!done) + detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0); + } + if (!done) + another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index); + } + } + + if (sp->identical) { + if (!done) { + if (sp->nr_attached == 0) + done = 1; + else { + detach_until=sp->nr_attached-1; + if (sp->nr_attached < sp->nr_polyominoes) + while (detach_until>0 && REASON_TO_NOT_ATTACH(sp->nr_attached,detach_until)==0) + detach_until--; + while (sp->nr_attached>detach_until) { + if (sp->rot180) + detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1); + detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0); + if (sp->nr_attached+1+sp->rot180 < sp->nr_polyominoes) + for (i=0;inr_polyominoes;i++) + REASON_TO_NOT_ATTACH(sp->nr_attached,i) |= REASON_TO_NOT_ATTACH(sp->nr_attached+1+sp->rot180,i); + } + another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index); + } + } + } + else { + if (!done) { + if (sp->nr_attached == 0) + done = 1; + else { + if (sp->rot180) + detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1); + detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0); + } + another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index); + } + } + } + + if (sp->use_bitmaps) + draw_with_bitmaps(mi,sp); + else + draw_without_bitmaps(mi,sp); + + if (sp->nr_attached == sp->nr_polyominoes) + sp->wait = 100; + else + sp->wait = 0; +} + +ENTRYPOINT void +reshape_polyominoes(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_polyominoes (mi); +} + +ENTRYPOINT void +release_polyominoes(ModeInfo * mi) +{ + int screen; + + if (polyominoeses != NULL) { + for (screen=0;screen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/pyro.c b/non-wgl/pyro.c new file mode 100644 index 0000000..fb8b012 --- /dev/null +++ b/non-wgl/pyro.c @@ -0,0 +1,397 @@ +/* xscreensaver, Copyright (c) 1992-2008 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. + */ + +/* Draw some fireworks. Inspired from TI Explorer Lisp code by + John S. Pezaris + */ + +#include "screenhack.h" +#include + +char *background = "black"; +char *foreground = "white"; +int count = 600; +int delay = 10000; +int frequency = 30; +int scatter = 100; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&count, "count", NULL, "600", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&frequency, "frequency", NULL, "30", t_Int}, + {&scatter, "scatter", NULL, "100", t_Int}, +}; + +struct projectile { + int x, y; /* position */ + int dx, dy; /* velocity */ + int decay; + int size; + int fuse; + Bool primary; + Bool dead; + XColor color; + struct projectile *next_free; +}; + +#define PI_2000 6284 + + +struct state { + Display *dpy; + Window window; + + struct projectile *projectiles, *free_projectiles; + struct projectile **sorted_projectiles; + + GC draw_gc, erase_gc; + unsigned int default_fg_pixel; + Colormap cmap; + + int how_many, frequency, scatter, delay; + + int sin_cache[PI_2000]; + int cos_cache[PI_2000]; + + int draw_xlim, draw_ylim, real_draw_xlim, real_draw_ylim; + + unsigned long last_pixel; +}; + + + +/* Slightly whacked, for better explosions + */ + +static void +cache(struct state *st) +{ /*needs to be run once. Could easily be */ + int i; /*reimplemented to run and cache at compile-time,*/ + double dA; /*saving on init_pyro time */ + for (i=0; icos_cache[i]=(int) (cos(((double)i)/1000.0)*dA*2500.0); + st->sin_cache[i]=(int) (sin(((double)i)/1000.0)*dA*2500.0); + } +} + + +static struct projectile * +get_projectile (struct state *st) +{ + struct projectile *p; + if (st->free_projectiles) + { + p = st->free_projectiles; + st->free_projectiles = p->next_free; + p->next_free = 0; + p->dead = False; + return p; + } + else + return 0; +} + +static void +free_projectile (struct state *st, struct projectile *p) +{ + p->next_free = st->free_projectiles; + st->free_projectiles = p; + p->dead = True; +} + +static void +launch (struct state *st, + int xlim, int ylim, int g) +{ + struct projectile *p = get_projectile (st); + int x, dx, xxx; + if (! p) return; + + do { + x = (random () % xlim); + dx = 30000 - (random () % 60000); + xxx = x + (dx * 200); + } while (xxx <= 0 || xxx >= xlim); + + p->x = x; + p->y = ylim; + p->dx = dx; + p->size = 8000; + p->decay = 0; + p->dy = (random () % 4000) - 13000; + p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000); + p->primary = True; + + /* cope with small windows -- those constants assume big windows. */ + { + int dd = 1000000 / ylim; + if (dd > 1) + p->fuse /= dd; + } + + if (! mono_p) + { + hsv_to_rgb (random () % 360, 1.0, 1.0, + &p->color.red, &p->color.green, &p->color.blue); + p->color.flags = DoRed | DoGreen | DoBlue; + if (!XAllocColor (st->dpy, st->cmap, &p->color)) + { + p->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); + p->color.red = p->color.green = p->color.blue = 0xFFFF; + } + } +} + +static struct projectile * +shrapnel (struct state *st, struct projectile *parent) +{ + struct projectile *p = get_projectile (st); + int v; + if (! p) return 0; + p->x = parent->x; + p->y = parent->y; + v=random () % PI_2000; + p->dx =(st->sin_cache[v]) + parent->dx; + p->dy =(st->cos_cache[v]) + parent->dy; + p->decay = (random () % 50) - 60; + p->size = (parent->size * 2) / 3; + p->fuse = 0; + p->primary = False; + + p->color = parent->color; + if (! mono_p) + XAllocColor (st->dpy, st->cmap, &p->color); /* dup the lock */ + + return p; +} + +static void * +pyro_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int i; + XGCValues gcv; + XWindowAttributes xgwa; + st->dpy = dpy; + st->window = window; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->last_pixel = ~0; + st->cmap = xgwa.colormap; +#if 1 + st->delay = delay; + st->how_many = count; + st->frequency = frequency; + st->scatter = scatter; +#else + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->how_many = get_integer_resource (st->dpy, "count", "Integer"); + st->frequency = get_integer_resource (st->dpy, "frequency", "Integer"); + st->scatter = get_integer_resource (st->dpy, "scatter", "Integer"); +#endif + if (st->how_many <= 0) st->how_many = 100; + if (st->frequency <= 0) st->frequency = 30; + if (st->scatter <= 0) st->scatter = 20; + st->projectiles = 0; + st->free_projectiles = 0; + st->projectiles = (struct projectile *) + calloc (st->how_many, sizeof (*st->projectiles)); + st->sorted_projectiles = (struct projectile **) + calloc (st->how_many, sizeof (*st->sorted_projectiles)); + for (i = 0; i < st->how_many; i++) + free_projectile (st, &st->projectiles [i]); + for (i = 0; i < st->how_many; i++) + st->sorted_projectiles[i] = &st->projectiles[i]; + //gcv.foreground = st->default_fg_pixel = + // get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + gcv.foreground = st->default_fg_pixel = + load_color(st->dpy, st->cmap, foreground); + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + //gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, st->cmap, background); + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + XClearWindow (st->dpy, st->window); + cache(st); + + return st; +} + + +static int +projectile_pixel_sorter (const void *a, const void *b) +{ + struct projectile *pa = *(struct projectile **) a; + struct projectile *pb = *(struct projectile **) b; + if (pa->color.pixel == pb->color.pixel) return 0; + else if (pa->color.pixel < pb->color.pixel) return -1; + else return 1; +} + +static void +sort_by_pixel (struct state *st, int length) +{ + qsort ((void *) st->sorted_projectiles, + length, + sizeof(*st->sorted_projectiles), + projectile_pixel_sorter); +} + + +static unsigned long +pyro_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XWindowAttributes xgwa; + int g = 100; + int resort = 0; + int i; + + for (i = 0; i < st->how_many; i++) + { + struct projectile *p = st->sorted_projectiles [i]; + int old_x, old_y, old_size; + int size, x, y; + if (p->dead) continue; + old_x = p->x >> 10; + old_y = p->y >> 10; + old_size = p->size >> 10; + size = (p->size += p->decay) >> 10; + x = (p->x += p->dx) >> 10; + y = (p->y += p->dy) >> 10; + p->dy += (p->size >> 6); + if (p->primary) p->fuse--; + + /* erase old one */ + if (old_size > 0) + { + if (old_size == 1) + XDrawPoint (st->dpy, st->window, st->erase_gc, old_x, old_y); + else + XFillRectangle (st->dpy, st->window, st->erase_gc, old_x, old_y, + old_size, old_size); + } + + if ((p->primary ? (p->fuse > 0) : (p->size > 0)) && + x < st->real_draw_xlim && + y < st->real_draw_ylim && + x > 0 && + y > 0) + { + if (size > 0) + { + unsigned long pixel; + + if (mono_p || p->primary) + pixel = st->default_fg_pixel; + else + pixel = p->color.pixel; + + if (pixel != st->last_pixel) + { + st->last_pixel = pixel; + XSetForeground (st->dpy, st->draw_gc, pixel); + } + + if (size == 1) + XDrawPoint (st->dpy, st->window, st->draw_gc, x, y); + else if (size < 4) + XFillRectangle (st->dpy, st->window, st->draw_gc, x, y, size, size); + else + XFillArc (st->dpy, st->window, st->draw_gc, x, y, size, size, 0, 360*64); + } + } + else + { + free_projectile (st, p); + if (! mono_p) + if (p->color.pixel != WhitePixel (st->dpy, DefaultScreen (st->dpy))) + XFreeColors (st->dpy, st->cmap, &p->color.pixel, 1, 0); + } + + if (p->primary && p->fuse <= 0) + { + int j = (random () % st->scatter) + (st->scatter/2); + while (j--) + shrapnel (st, p); + resort = 1; + } + } + + if ((random () % st->frequency) == 0) + { + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->real_draw_xlim = xgwa.width; + st->real_draw_ylim = xgwa.height; + st->draw_xlim = st->real_draw_xlim * 1000; + st->draw_ylim = st->real_draw_ylim * 1000; + launch (st, st->draw_xlim, st->draw_ylim, g); + resort = 1; + } + + /* being sorted lets us avoid changing the GC's foreground color as often. */ + if (resort) + sort_by_pixel (st, st->how_many); + + return st->delay; +} + +static void +pyro_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + pyro_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +pyro_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + +static const char *pyro_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*count: 600", + "*delay: 10000", + "*frequency: 30", + "*scatter: 100", + "*geometry: 800x500", + 0 +}; + +static XrmOptionDescRec pyro_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-frequency", ".frequency", XrmoptionSepArg, 0 }, + { "-scatter", ".scatter", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Pyro", pyro) diff --git a/non-wgl/pyro.vcproj b/non-wgl/pyro.vcproj new file mode 100644 index 0000000..1470bb2 --- /dev/null +++ b/non-wgl/pyro.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/rd-bomb.c b/non-wgl/rd-bomb.c new file mode 100644 index 0000000..0f68605 --- /dev/null +++ b/non-wgl/rd-bomb.c @@ -0,0 +1,635 @@ +/* xscreensaver, Copyright (c) 1992-2013 Jamie Zawinski + * + * reaction/diffusion textures + * Copyright (c) 1997 Scott Draves spot@transmeta.com + * this code is derived from Bomb + * see http://www.cs.cmu.edu/~spot/bomb.html + * + * 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. + * + * And remember: X Windows is to graphics hacking as roman numerals are to + * the square root of pi. + */ + +#include "screenhack.h" +#include + +#ifdef HAVE_XSHM_EXTENSION +# include "xshm.h" +#endif /* HAVE_XSHM_EXTENSION */ + +char *background = "black"; +char *foreground = "white"; +int width = 0; +int height = 0; +int epoch = 40000; +int reaction = -1; +int diffusion = -1; +int radius = -1; +float speed = 0.0; +float size = 1.0; +int delay = 30000; +int colors = 255; + + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&width, "width", NULL, "0", t_Int}, + {&height, "height", NULL, "0", t_Int}, + {&epoch, "epoch", NULL, "40000", t_Int}, + {&reaction, "reaction", NULL, "-1", t_Int}, + {&diffusion, "diffusion", NULL, "-1", t_Int}, + {&radius, "radius", NULL, "-1", t_Int}, + {&speed, "speed", NULL, "0.0", t_Float}, + {&size, "size", NULL, "1.0", t_Float}, + {&delay, "delay", NULL, "30000", t_Int}, + {&colors, "colors", NULL, "255", t_Int}, +}; + +/* costs ~6% speed */ +#define dither_when_mapped 1 + +struct state { + Display *dpy; + Window window; + + int ncolors; + XColor *colors; + Visual *visual; +#if dither_when_mapped + unsigned char *mc; +#endif + Colormap cmap; + int mapped; + int pdepth; + + int frame, epoch_time; + unsigned short *r1, *r2, *r1b, *r2b; + int width, height, npix; + int radius; + int reaction; + int diffusion; + + char *pd; + int array_width, array_height; + +#ifdef HAVE_XSHM_EXTENSION + Bool use_shm; + XShmSegmentInfo shm_info; +#endif + + GC gc; + XImage *image; + double array_x, array_y; + double array_dx, array_dy; + XWindowAttributes xgwa; + int delay; +}; + +static void random_colors(struct state *st); + +/* ----------------------------------------------------------- + pixel hack, 8-bit pixel grid, first/next frame interface + + pixack_init(int *size_h, int *size_v) + pixack_frame(char *pix_buf) + */ + + +#define bps 16 +#define mx ((1<<16)-1) + +/* you can replace integer mults wish shift/adds with these, + but it doesn't help on my 586 */ +#define x5(n) ((n<<2)+n) +#define x7(n) ((n<<3)-n) + +/* why strip bit? */ +#define R (random()&((1<<30)-1)) +#define BELLRAND(x) (((random()%(x)) + (random()%(x)) + (random()%(x)))/3) + +/* returns number of pixels that the pixack produces. called once. */ +static void +pixack_init(struct state *st, int *size_h, int *size_v) +{ + //st->width = get_integer_resource (st->dpy, "width", "Integer"); + //st->height = get_integer_resource (st->dpy, "height", "Integer"); + st->width = width; + st->height = height; + + if (st->width <= 0 && st->height <= 0 && (R & 1)) + st->width = st->height = 48 + BELLRAND(256); + + if (st->width <= 0) st->width = 48 + BELLRAND(256); + if (st->height <= 0) st->height = 48 + BELLRAND(256); + + /* jwz: when (and only when) XSHM is in use on an SGI 8-bit visual, + we get shear unless st->width is a multiple of 4. I don't understand + why. This is undoubtedly the wrong fix... */ + if (visual_depth (st->xgwa.screen, st->xgwa.visual) == 8) + st->width &= ~0x7; + + /* don't go there */ + if (st->width < 10) st->width = 10; + if (st->height < 10) st->height = 10; + //st->epoch_time = get_integer_resource (st->dpy, "epoch", "Integer"); + st->epoch_time = epoch; + st->npix = (st->width + 2) * (st->height + 2); + st->r1 = (unsigned short *) malloc(sizeof(unsigned short) * st->npix); + st->r2 = (unsigned short *) malloc(sizeof(unsigned short) * st->npix); + st->r1b = (unsigned short *) malloc(sizeof(unsigned short) * st->npix); + st->r2b = (unsigned short *) malloc(sizeof(unsigned short) * st->npix); + + if (!st->r1 || !st->r2 || !st->r1b || !st->r2b) { + fprintf(stderr, "not enough memory for %d pixels.\n", st->npix); + exit(1); + } + + *size_h = st->width; + *size_v = st->height; +} + +#define test_pattern_hyper 0 + + +/* returns the pixels. called many times. */ +static void +pixack_frame(struct state *st, char *pix_buf) +{ + int i, j; + int w2 = st->width + 2; + unsigned short *t; +#if test_pattern_hyper + if (st->frame&0x100) + sleep(1); +#endif + + if (!(st->frame%st->epoch_time)) { + int s; + if (0 != st->frame) { + int tt = st->epoch_time / 500; + if (tt > 15) + tt = 15; + /*sleep(tt);*/ + } + + for (i = 0; i < st->npix; i++) { + /* equilibrium */ + st->r1[i] = 65500; + st->r2[i] = 11; + } + + random_colors(st); + + XSetWindowBackground(st->dpy, st->window, st->colors[255 % st->ncolors].pixel); + XClearWindow(st->dpy, st->window); + + s = w2 * (st->height/2) + st->width/2; + //st->radius = get_integer_resource (st->dpy, "radius", "Integer"); + st->radius = radius; + { + int maxr = st->width/2-2; + int maxr2 = st->height/2-2; + if (maxr2 < maxr) maxr = maxr2; + + if (st->radius < 0) + st->radius = 1 + ((R%10) ? (R%5) : (R % maxr)); + if (st->radius > maxr) st->radius = maxr; + } + for (i = -st->radius; i < (st->radius+1); i++) + for (j = -st->radius; j < (st->radius+1); j++) + st->r2[s + i + j*w2] = mx - (R&63); + //st->reaction = get_integer_resource (st->dpy, "reaction", "Integer"); + st->reaction = reaction; + if (st->reaction < 0 || st->reaction > 2) st->reaction = R&1; + //st->diffusion = get_integer_resource (st->dpy, "diffusion", "Integer"); + st->diffusion = diffusion; + if (st->diffusion < 0 || st->diffusion > 2) + st->diffusion = (R%5) ? ((R%3)?0:1) : 2; + if (2 == st->reaction && 2 == st->diffusion) + st->reaction = st->diffusion = 0; + } + for (i = 0; i <= st->width+1; i++) { + st->r1[i] = st->r1[i + w2 * st->height]; + st->r2[i] = st->r2[i + w2 * st->height]; + st->r1[i + w2 * (st->height + 1)] = st->r1[i + w2]; + st->r2[i + w2 * (st->height + 1)] = st->r2[i + w2]; + } + for (i = 0; i <= st->height+1; i++) { + st->r1[w2 * i] = st->r1[st->width + w2 * i]; + st->r2[w2 * i] = st->r2[st->width + w2 * i]; + st->r1[w2 * i + st->width + 1] = st->r1[w2 * i + 1]; + st->r2[w2 * i + st->width + 1] = st->r2[w2 * i + 1]; + } + for (i = 0; i < st->height; i++) { + int ii = i + 1; + char *q = pix_buf + st->width * i; + short *qq = ((short *) pix_buf) + st->width * i; +/* long *qqq = ((long *) pix_buf) + st->width * i; -- crashes on Alpha */ + int *qqq = ((int *) pix_buf) + st->width * i; + unsigned short *i1 = st->r1 + 1 + w2 * ii; + unsigned short *i2 = st->r2 + 1 + w2 * ii; + unsigned short *o1 = st->r1b + 1 + w2 * ii; + unsigned short *o2 = st->r2b + 1 + w2 * ii; + for (j = 0; j < st->width; j++) { +#if test_pattern_hyper + int r1 = (i * j + (st->frame&127)*frame)&65535; +#else + int uvv, r1 = 0, r2 = 0; + switch (st->diffusion) { + case 0: + r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2]; + r1 = r1 / 5; + r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2]; + r2 = r2 / 12; + break; + case 1: + r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2]; + r1 = r1 >> 2; + r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2]; + r2 = r2 >> 3; + break; + case 2: + r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2]; + r1 = r1 >> 3; + r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2]; + r2 = r2 >> 3; + break; + } + + /* John E. Pearson "Complex Patterns in a Simple System" + Science, July 1993 */ + + uvv = (((r1 * r2) >> bps) * r2) >> bps; + switch (st->reaction) { /* costs 4% */ + case 0: + r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv); + r2 += 4 * (uvv - ((80 * r2) >> 10)); + break; + case 1: + r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv); + r2 += 3 * (uvv - ((80 * r2) >> 10)); + break; + case 2: + r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv); + r2 += 3 * (uvv - ((80 * r2) >> 10)); + break; + } + if (r1 > mx) r1 = mx; + if (r2 > mx) r2 = mx; + if (r1 < 0) r1 = 0; + if (r2 < 0) r2 = 0; + o1[j] = r1; + o2[j] = r2; +#endif + + /* this is terrible. here i want to assume ncolors = 256. + should lose double indirection */ + + if (st->mapped) +#if dither_when_mapped + q[j] = st->colors[st->mc[r1] % st->ncolors].pixel; +#else + q[j] = st->colors[(r1>>8) % st->ncolors].pixel; +#endif + else if (st->pdepth == 8) + q[j] = st->colors[(r1>>8) % st->ncolors].pixel; + else if (st->pdepth == 16) +#if dither_when_mapped + qq[j] = st->colors[st->mc[r1] % st->ncolors].pixel; +#else + qq[j] = st->colors[(r1>>8) % st->ncolors].pixel; +#endif + else if (st->pdepth == 32) +#if dither_when_mapped + qqq[j] = st->colors[st->mc[r1] % st->ncolors].pixel; +#else + qqq[j] = st->colors[(r1>>8) % st->ncolors].pixel; +#endif + else + abort(); + } + } + t = st->r1; st->r1 = st->r1b; st->r1b = t; + t = st->r2; st->r2 = st->r2b; st->r2b = t; +} + + +/* ------------- xscreensaver rendering -------------- */ + +static const char *rd_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*width: 0", /* tried to use -1 but it complained */ + "*height: 0", + "*epoch: 40000", + "*reaction: -1", + "*diffusion: -1", + "*radius: -1", + "*speed: 0.0", + "*size: 1.0", + "*delay: 30000", + "*colors: 255", +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#else + "*useSHM: False", +#endif +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec rd_options [] = { + { "-width", ".width", XrmoptionSepArg, 0 }, + { "-height", ".height", XrmoptionSepArg, 0 }, + { "-epoch", ".epoch", XrmoptionSepArg, 0 }, + { "-reaction", ".reaction", XrmoptionSepArg, 0 }, + { "-diffusion", ".diffusion", XrmoptionSepArg, 0 }, + { "-radius", ".radius", XrmoptionSepArg, 0 }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-size", ".size", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-ncolors", ".colors", XrmoptionSepArg, 0 }, + { "-shm", ".useSHM", XrmoptionNoArg, "True" }, + { "-no-shm", ".useSHM", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + + +static void +random_colors(struct state *st) +{ + memset(st->colors, 0, st->ncolors*sizeof(*st->colors)); + make_smooth_colormap (st->xgwa.screen, st->visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + if (st->ncolors <= 2) { + mono_p = True; + st->ncolors = 2; + st->colors[0].flags = DoRed|DoGreen|DoBlue; + st->colors[0].red = st->colors[0].green = st->colors[0].blue = 0; + XAllocColor(st->dpy, st->cmap, &st->colors[0]); + st->colors[1].flags = DoRed|DoGreen|DoBlue; + st->colors[1].red = st->colors[1].green = st->colors[1].blue = 0xFFFF; + XAllocColor(st->dpy, st->cmap, &st->colors[1]); + } + + /* Scale it up so that there are exactly 255 colors -- that keeps the + animation speed consistent, even when there aren't many allocatable + colors, and prevents the -mono mode from looking like static. */ + if (st->ncolors != 255) { + int i, n = 255; + double scale = (double) st->ncolors / (double) (n+1); + XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1)); + for (i = 0; i < n; i++) + c2[i] = st->colors[(int) (i * scale)]; + free(st->colors); + st->colors = c2; + st->ncolors = n; + } + +} + + +/* should factor into RD-specfic and compute-every-pixel general */ +static void * +rd_init (Display *dpy, Window win) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + int w2; + int vdepth; + + st->dpy = dpy; + st->window = win; + + //st->delay = get_integer_resource (st->dpy, "delay", "Float"); + st->delay = delay; + +#ifdef HAVE_XSHM_EXTENSION + st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean"); +#endif + + XGetWindowAttributes (st->dpy, win, &st->xgwa); + st->visual = st->xgwa.visual; + pixack_init(st, &st->width, &st->height); + { + //double s = get_float_resource (st->dpy, "size", "Float"); + //double p = get_float_resource (st->dpy, "speed", "Float"); + double s = size; + double p = speed; + if (s < 0.0 || s > 1.0) + s = 1.0; + s = sqrt(s); + st->array_width = st->xgwa.width * s; + st->array_height = st->xgwa.height * s; + if (s < 0.99) { + st->array_width = (st->array_width / st->width) * st->width; + st->array_height = (st->array_height / st->height) * st->height; + } + if (st->array_width < st->width) st->array_width = st->width; + if (st->array_height < st->height) st->array_height = st->height; + st->array_x = (st->xgwa.width - st->array_width)/2; + st->array_y = (st->xgwa.height - st->array_height)/2; + st->array_dx = p; + st->array_dy = .31415926 * p; + + /* start in a random direction */ + if (random() & 1) st->array_dx = -st->array_dx; + if (random() & 1) st->array_dy = -st->array_dy; + + } + st->npix = (st->width + 2) * (st->height + 2); + w2 = st->width + 2; +/* gcv.function = GXcopy;*/ + st->gc = XCreateGC(st->dpy, win, 0 /*GCFunction*/, &gcv); + vdepth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual); + + /* This code only deals with pixmap depths of 1, 8, 16, and 32. + Therefore, we assume that those depths will be supported by the + coresponding visual depths (that depth-24 dpys accept depth-32 + pixmaps, and that depth-12 dpys accept depth-16 pixmaps.) */ + st->pdepth = (vdepth == 1 ? 1 : + vdepth <= 8 ? 8 : + vdepth <= 16 ? 16 : + 32); + + /* Ok, this like, sucks and stuff. There are some XFree86 systems + that have depth-24 visuals, that do not accept depth-32 XImages! + Which if you ask me is just absurd, since all it would take is + for the server to truncate the bits in that case. So, this crap + here detects the specific case of: we have chosen depth 32; + and the server does not support depth 32. In that case, we + try and use depth 16 instead. + + The real fix would be to rewrite this program to deal with + depth 24 directly (or even better, arbitrary depths, but that + would mean going through the XImage routines instead of messing + with the XImage->data directly.) + + jwz, 18-Mar-99: well, the X servers I have access to these days do + support 32-deep images on deep visuals, so I no longer have the + ability to test this code -- but it was causing problems on the + visuals that I do have, and I think that's because I mistakenly + wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'. + The symptom I was seeing was that the grid was 64x64, but the + images were being drawn 32x32 -- so there was a black stripe on + every other row. Wow, this code sucks so much. + */ + if (st->pdepth == 32) + { + int i, pfvc = 0; + Bool ok = False; + XPixmapFormatValues *pfv = XListPixmapFormats (st->dpy, &pfvc); + for (i = 0; i < pfvc; i++) + if (pfv[i].bits_per_pixel == st->pdepth) + ok = True; + if (!ok) + st->pdepth = 16; + } + + st->cmap = st->xgwa.colormap; + //st->ncolors = get_integer_resource (st->dpy, "colors", "Integer"); + st->ncolors = colors; + + if (st->ncolors <= 0 || st->ncolors >= 255) { + if (vdepth > 8) + st->ncolors = 2047; + else + st->ncolors = 255; + } + + if (mono_p || st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + + st->mapped = (vdepth <= 8 && + has_writable_cells(st->xgwa.screen, st->xgwa.visual)); + + { + int i, di; + st->mc = (unsigned char *) malloc(1<<16); + for (i = 0; i < (1<<16); i++) { + di = (i + (random()&255))>>8; + if (di > 255) di = 255; + st->mc[i] = di; + } + } + + st->pd = malloc(st->npix * (st->pdepth == 1 ? 1 : (st->pdepth / 8))); + if (!st->pd) { + fprintf(stderr, "not enough memory for %d pixels.\n", st->npix); + exit(1); + } + + st->image = 0; + +#ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) + { + st->image = create_xshm_image(st->dpy, st->xgwa.visual, vdepth, + ZPixmap, 0, &st->shm_info, st->width, st->height); + if (!st->image) + st->use_shm = False; + else + { + free(st->pd); + st->pd = st->image->data; + } + } +#endif /* HAVE_XSHM_EXTENSION */ + + if (!st->image) + { + st->image = XCreateImage(st->dpy, st->xgwa.visual, vdepth, + ZPixmap, 0, st->pd, + st->width, st->height, 8, 0); + } + + return st; +} + +static unsigned long +rd_draw (Display *dpy, Window win, void *closure) +{ + struct state *st = (struct state *) closure; + Bool bump = False; + + int i, j; + pixack_frame(st, st->pd); + for (i = 0; i < st->array_width; i += st->width) + for (j = 0; j < st->array_height; j += st->height) +#ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) + XShmPutImage(st->dpy, st->window, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y, + st->width, st->height, False); + else +#endif + XPutImage(st->dpy, win, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y, + st->width, st->height); + + st->array_x += st->array_dx; + st->array_y += st->array_dy; + if (st->array_x < 0) { + st->array_x = 0; + st->array_dx = -st->array_dx; + bump = True; + } else if (st->array_x > (st->xgwa.width - st->array_width)) { + st->array_x = (st->xgwa.width - st->array_width); + st->array_dx = -st->array_dx; + bump = True; + } + if (st->array_y < 0) { + st->array_y = 0; + st->array_dy = -st->array_dy; + bump = True; + } else if (st->array_y > (st->xgwa.height - st->array_height)) { + st->array_y = (st->xgwa.height - st->array_height); + st->array_dy = -st->array_dy; + bump = True; + } + + if (bump) { + if (random() & 1) { + double swap = st->array_dx; + st->array_dx = st->array_dy; + st->array_dy = swap; + } + } + + st->frame++; + + return st->delay; +} + +static void +rd_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + rd_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +rd_free (Display *dpy, Window window, void *closure) +{ +} + +XSCREENSAVER_MODULE_2 ("RDbomb", rdbomb, rd) diff --git a/non-wgl/rd-bomb.vcproj b/non-wgl/rd-bomb.vcproj new file mode 100644 index 0000000..ea2e377 --- /dev/null +++ b/non-wgl/rd-bomb.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/ripples.c b/non-wgl/ripples.c new file mode 100644 index 0000000..087c604 --- /dev/null +++ b/non-wgl/ripples.c @@ -0,0 +1,1192 @@ +/* ripples, Copyright (c) 1999 Ian McConnell + * + * 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. + */ + +/* + * "Water" ripples that can cross and interfere with each other. + * + * I can't remember where I got this idea from, but it's been around for a + * while in various demos. Some inspiration from + * water.txt by Tom Hammersley,tomh@globalnet.co.uk + * + * Options + * -delay usleep every iteration + * -rate Add one drop every "rate" iterations + * -box Add big square splash every "box" iters (not very good) + * -water Ripples on a grabbed background image + * -foreground Interpolate ripples between these two colors + * -background + * -oily Psychedelic colours like man + * -stir Add a regular pattern of drops + * -fluidity Between 0 and 16. 16 = big drops + * -light Hack to add lighting effect + * + * Code mainly hacked from xflame and decayscreen. + */ + +/* Version history: + * 13 Oct 1999: Initial hack + * 30 Oct 1999: Speeded up graphics with dirty buffer. Returned to using + * putpixel for greater portability + * Added a variety of methods for splashing screen. + * 31 Oct 1999: Added in lighting hack + * 13 Nov 1999: Speed up tweaks + * Adjust "light" for different bits per colour (-water only) + * + */ + +#include "screenhack.h" +#include + +typedef enum {ripple_drop, ripple_blob, ripple_box, ripple_stir} ripple_mode; + +#ifdef HAVE_XSHM_EXTENSION +#include "xshm.h" +#endif /* HAVE_XSHM_EXTENSION */ + +char *background = "black"; +char *foreground = "#FFAF5F"; +int colors = 200; +Bool dontClearRoot = True; +int delay = 50000; +int duration = 120; +int rate = 5; +int box = 0; +Bool water = True; +Bool oily = False; +Bool stir = False; +int fluidity = 6; +int light = 4; +Bool grayscale_ = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "#FFAF5F", t_String}, + {&colors, "colors", NULL, "200", t_Int}, + {&dontClearRoot, "dontClearRoot", NULL, "True", t_Bool}, + {&delay, "delay", NULL, "50000", t_Int}, + {&duration, "duration", NULL, "120", t_Int}, + {&rate, "rate", NULL, "5", t_Int}, + {&box, "box", NULL, "0", t_Int}, + {&water, "water", NULL, "True", t_Bool}, + {&oily, "oily", NULL, "False", t_Bool}, + {&stir, "stir", NULL, "False", t_Bool}, + {&fluidity, "fluidity", NULL, "6", t_Int}, + {&light, "light", NULL, "4", t_Int}, + {&grayscale_, "grayscale", NULL, "False", t_Bool}, +}; + + +#define TABLE 256 + +struct state { + Display *dpy; + Window window; + GC gc; + Visual *visual; + + XImage *orig_map, *buffer_map; + int ctab[256]; + Colormap colormap; + Screen *screen; + int ncolors; + int light; + + int width, height; /* ripple size */ + int bigwidth, bigheight; /* screen size */ + + Bool transparent; + short *bufferA, *bufferB, *temp; + char *dirty_buffer; + + double cos_tab[TABLE]; + + Bool grayscale_p; + + unsigned long rmask; /* This builds on the warp effect by adding */ + unsigned long gmask; /* in a lighting effect: brighten pixels by an */ + unsigned long bmask; /* amount corresponding to the vertical gradient */ + + int rshift; + int gshift; + int bshift; + + double stir_ang; + + int draw_toggle; + int draw_count; + + int iterations, delay, rate, box, oily, stir, fluidity; + int duration; + time_t start_time; + + void (*draw_transparent) (struct state *st, short *src); + + async_load_state *img_loader; + +#ifdef HAVE_XSHM_EXTENSION + Bool use_shm; + XShmSegmentInfo shm_info; +#endif /* HAVE_XSHM_EXTENSION */ +}; + + +/* Distribution of drops: many little ones and a few big ones. */ +static const double drop_dist[] = + {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.2, 0.6}; + + +/* How hard to hit the water */ +#define SPLASH 512 +#undef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#undef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#undef DIRTY +#define DIRTY 3 /* dirty >= 2, 1 = restore original pixel, 0 = leave alone */ + +/* From fortune(6) */ +/* -- really weird C code to count the number of bits in a word */ +#define BITCOUNT(x) (((BX_(x)+(BX_(x)>>4)) & 0x0F0F0F0F) % 255) +#define BX_(x) ((x) - (((x)>>1)&0x77777777) \ + - (((x)>>2)&0x33333333) \ + - (((x)>>3)&0x11111111)) + + +static unsigned long grayscale(struct state *st, unsigned long color); + +/* ------------------------------------------- */ + + +static int +map_color(struct state *st, int grey) +{ + /* Clip it */ + grey = st->ncolors * abs(grey) / (SPLASH/4); + if (grey > st->ncolors) + grey = st->ncolors; + + /* Display it */ + return st->ctab[grey]; +} + + +static void +draw_ripple(struct state *st, short *src) +{ + int across, down; + char *dirty = st->dirty_buffer; + + for (down = 0; down < st->height - 1; down++, src += 1, dirty += 1) + for (across = 0; across < st->width - 1; across++, src++, dirty++) { + int v1, v2, v3, v4; + v1 = (int)*src; + v2 = (int)*(src + 1); + v3 = (int)*(src + st->width); + v4 = (int)*(src + st->width + 1); + if ((v1 == 0 && v2 == 0 && v3 == 0 && v4 == 0)) { + if (*dirty > 0) + (*dirty)--; + } else + *dirty = DIRTY; + + if (*dirty > 0) { + int dx; + if (st->light > 0) { + dx = ((v3 - v1) + (v4 - v2)) << st->light; /* light from top */ + } else + dx = 0; + XPutPixel(st->buffer_map,(across<<1), (down<<1), map_color(st, dx + v1)); + XPutPixel(st->buffer_map,(across<<1)+1,(down<<1), map_color(st, dx + ((v1 + v2) >> 1))); + XPutPixel(st->buffer_map,(across<<1), (down<<1)+1,map_color(st, dx + ((v1 + v3) >> 1))); + XPutPixel(st->buffer_map,(across<<1)+1,(down<<1)+1,map_color(st, dx + ((v1 + v4) >> 1))); + } + } +} + + +/* ------------------------------------------- */ + + +/* Uses the horizontal gradient as an offset to create a warp effect */ +static void +draw_transparent_vanilla(struct state *st, short *src) +{ + int across, down, pixel; + char *dirty = st->dirty_buffer; + + pixel = 0; + for (down = 0; down < st->height - 2; down++, pixel += 2) + for (across = 0; across < st->width-2; across++, pixel++) { + int gradx, grady, gradx1, grady1; + int x0, x1, x2, y1, y2; + + x0 = src[pixel]; + x1 = src[pixel + 1]; + x2 = src[pixel + 2]; + y1 = src[pixel + st->width]; + y2 = src[pixel + 2*st->width]; + + gradx = (x1 - x0); + grady = (y1 - x0); + gradx1= (x2 - x1); + grady1= (y2 - y1); + gradx1 = 1 + (gradx + gradx1) / 2; + grady1 = 1 + (grady + grady1) / 2; + + if ((2*across+MIN(gradx,gradx1) < 0) || + (2*across+MAX(gradx,gradx1) >= st->bigwidth)) { + gradx = 0; + gradx1= 1; + } + if ((2*down+MIN(grady,grady1) < 0) || + (2*down+MAX(grady,grady1) >= st->bigheight)) { + grady = 0; + grady1 = 1; + } + + if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) { + if (dirty[pixel] > 0) + dirty[pixel]--; + } else + dirty[pixel] = DIRTY; + + if (dirty[pixel] > 0) { + XPutPixel(st->buffer_map, (across<<1), (down<<1), + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx, (down<<1) + grady))); + XPutPixel(st->buffer_map, (across<<1)+1,(down<<1), + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx1,(down<<1) + grady))); + XPutPixel(st->buffer_map, (across<<1), (down<<1)+1, + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx, (down<<1) + grady1))); + XPutPixel(st->buffer_map, (across<<1)+1,(down<<1)+1, + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx1,(down<<1) + grady1))); + } + } +} + + +/* ------------------------------------------- */ + + +static void +set_mask(unsigned long color, unsigned long *mask, int *shift) +{ + *shift = 0; + while (color != 0 && (color & 1) == 0) { + (*shift)++; + color >>= 1; + } + *mask = color; +} + + +static unsigned long +cadd(unsigned long color, int dx, unsigned long mask, int shift) +{ + int x; + color >>= shift; + x = (color & mask); + x += dx; + if (x < 0) x = 0; + else if (x > (int)mask) x = mask; + color = x; + return color << shift; +} + + +static unsigned long +bright(struct state *st, int dx, unsigned long color) +{ + return (cadd(color, dx, st->rmask, st->rshift) | + cadd(color, dx, st->gmask, st->gshift) | + cadd(color, dx, st->bmask, st->bshift)); +} + + +static unsigned long +grayscale(struct state *st, unsigned long color) +{ + int red; + int green; + int blue; + int total; + int gray_r; + int gray_g; + int gray_b; + + if (!st->grayscale_p) + return color; + if (!st->transparent) + return color; + if ((st->rmask == 0) || (st->gmask == 0) || (st->bmask == 0)) + return color; + + red = ((color >> st->rshift) & st->rmask); + green = ((color >> st->gshift) & st->gmask); + blue = ((color >> st->bshift) & st->bmask); + total = red * st->gmask * st->bmask + green * st->rmask * st->bmask + blue * st->rmask * st->gmask; + + gray_r = total / (3 * st->gmask * st->bmask); + if (gray_r < 0) + gray_r = 0; + if (gray_r > st->rmask) + gray_r = st->rmask; + + gray_g = total / (3 * st->rmask * st->bmask); + if (gray_g < 0) + gray_g = 0; + if (gray_g > st->gmask) + gray_g = st->gmask; + + gray_b = total / (3 * st->rmask * st->gmask); + if (gray_b < 0) + gray_b = 0; + if (gray_b > st->bmask) + gray_b = st->bmask; + + return ((unsigned long) + ((gray_r << st->rshift) | (gray_g << st->gshift) | (gray_b << st->bshift))); +} + + +static void +draw_transparent_light(struct state *st, short *src) +{ + int across, down, pixel; + char *dirty = st->dirty_buffer; + + pixel = 0; + for (down = 0; down < st->height - 2; down++, pixel += 2) + for (across = 0; across < st->width-2; across++, pixel++) { + int gradx, grady, gradx1, grady1; + int x0, x1, x2, y1, y2; + + x0 = src[pixel]; + x1 = src[pixel + 1]; + x2 = src[pixel + 2]; + y1 = src[pixel + st->width]; + y2 = src[pixel + 2*st->width]; + + gradx = (x1 - x0); + grady = (y1 - x0); + gradx1= (x2 - x1); + grady1= (y2 - y1); + gradx1 = 1 + (gradx + gradx1) / 2; + grady1 = 1 + (grady + grady1) / 2; + + if ((2*across+MIN(gradx,gradx1) < 0) || + (2*across+MAX(gradx,gradx1) >= st->bigwidth)) { + gradx = 0; + gradx1= 1; + } + if ((2*down+MIN(grady,grady1) < 0) || + (2*down+MAX(grady,grady1) >= st->bigheight)) { + grady = 0; + grady1 = 1; + } + + if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) { + if (dirty[pixel] > 0) + dirty[pixel]--; + } else + dirty[pixel] = DIRTY; + + if (dirty[pixel] > 0) { + int dx; + + /* light from top */ + if (4-st->light >= 0) + dx = (grady + (src[pixel+st->width+1]-x1)) >> (4-st->light); + else + dx = (grady + (src[pixel+st->width+1]-x1)) << (st->light-4); + + if (dx != 0) { + XPutPixel(st->buffer_map, (across<<1), (down<<1), + bright(st, dx, grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx, (down<<1) + grady)))); + XPutPixel(st->buffer_map, (across<<1)+1,(down<<1), + bright(st, dx, grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx1,(down<<1) + grady)))); + XPutPixel(st->buffer_map, (across<<1), (down<<1)+1, + bright(st, dx, grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx, (down<<1) + grady1)))); + XPutPixel(st->buffer_map, (across<<1)+1,(down<<1)+1, + bright(st, dx, grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx1,(down<<1) + grady1)))); + } else { + /* Could use XCopyArea, but XPutPixel is faster */ + XPutPixel(st->buffer_map, (across<<1), (down<<1), + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx, (down<<1) + grady))); + XPutPixel(st->buffer_map, (across<<1)+1,(down<<1), + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx1,(down<<1) + grady))); + XPutPixel(st->buffer_map, (across<<1), (down<<1)+1, + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx, (down<<1) + grady1))); + XPutPixel(st->buffer_map, (across<<1)+1,(down<<1)+1, + grayscale(st, XGetPixel(st->orig_map, (across<<1) + gradx1,(down<<1) + grady1))); + } + } + } +} + + +/* ------------------------------------------- */ + + +#if 0 +/* Doesn't go any faster and doesn't work at all colour depths */ +static void +draw_transparent16l(short *src) +{ + int across, down, bigpix, pixel; + char *dirty = st->dirty_buffer; + unsigned short *buffer, *orig; + + buffer = (unsigned short *) st->buffer_map->data; + orig = (unsigned short *) st->orig_map->data; + + for (pixel = bigpix = down = 0; + down < st->height - 2; + down++, pixel += 2, bigpix += st->bigwidth+4) + for (across = 0; across < st->width-2; across++, pixel++, bigpix+=2) { + int gradx, grady, gradx1, grady1; + int x0, x1, x2, y1, y2; + + x0 = src[pixel]; + x1 = src[pixel + 1]; + x2 = src[pixel + 2]; + y1 = src[pixel + st->width]; + y2 = src[pixel + 2*st->width]; + + gradx = (x1 - x0); + grady = (y1 - x0); + gradx1= (x2 - x1); + grady1= (y2 - y1); + gradx1 = 1 + (gradx + gradx1) / 2; + grady1 = 1 + (grady + grady1) / 2; + + if ((2*across+MIN(gradx,gradx1) < 0) || + (2*across+MAX(gradx,gradx1) >= st->bigwidth)) { + gradx = 0; + gradx1= 1; + } + if ((2*down+MIN(grady,grady1) < 0) || + (2*down+MAX(grady,grady1) >= st->bigheight)) { + grady = 0; + grady1 = 1; + } + + if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) { + if (dirty[pixel] > 0) + dirty[pixel]--; + } else + dirty[pixel] = DIRTY; + + if (dirty[pixel] > 0) { + unsigned short *dest = buffer + bigpix; + unsigned short *image = orig + bigpix; + int dx; + + /* light from top */ + if (4-st->light >= 0) + dx = (grady + (src[pixel+st->width+1]-x1)) >> (4-st->light); + else + dx = (grady + (src[pixel+st->width+1]-x1)) << (st->light-4); + + grady *= st->bigwidth; + grady1*= st->bigwidth; + + if (dx != 0) { + *dest++ = dobright(dx, *(image + gradx + grady)); + *dest = dobright(dx, *(image + gradx1 + grady)); + dest += st->bigwidth - 1; + *dest++ = dobright(dx, *(image + gradx + grady1)); + *dest = dobright(dx, *(image + gradx1 + grady1)); + } else { + *dest++ = *(image + gradx + grady); + *dest = *(image + gradx1 + grady); + dest += st->bigwidth - 1; + *dest++ = *(image + gradx + grady1); + *dest = *(image + gradx1 + grady1); + } + } + } +} +#endif + + +/* ------------------------------------------- */ + + +static void +setup_X(struct state *st) +{ + XWindowAttributes xgwa; + int depth; + + XGetWindowAttributes(st->dpy, st->window, &xgwa); + depth = xgwa.depth; + st->colormap = xgwa.colormap; + st->screen = xgwa.screen; + st->bigwidth = xgwa.width; + st->bigheight = xgwa.height; + st->visual = xgwa.visual; + + + /* This causes buffer_map to be 1 pixel taller and wider than orig_map, + which can cause the two XImages to have different bytes-per-line, + which causes stair-stepping. So this better not be necessary... + -jwz, 23-Nov-01 + */ +#if 0 /* I'm not entirely sure if I need this */ + if (st->bigwidth % 2) + st->bigwidth++; + if (st->bigheight % 2) + st->bigheight++; +#endif + + + st->width = st->bigwidth / 2; + st->height = st->bigheight / 2; + + if (st->transparent) { + XGCValues gcv; + long gcflags; + + gcv.function = GXcopy; + gcv.subwindow_mode = IncludeInferiors; + + gcflags = GCFunction; + if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */ + gcflags |= GCSubwindowMode; + + st->gc = XCreateGC(st->dpy, st->window, gcflags, &gcv); + + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, + st->window, 0, 0); + st->start_time = time ((time_t) 0); + } else { + XGCValues gcv; + + st->gc = XCreateGC(st->dpy, st->window, 0, &gcv); + st->orig_map = 0; + } + + if (!st->gc) { + fprintf(stderr, "XCreateGC failed\n"); + exit(1); + } + + st->buffer_map = 0; + +#ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) { + st->buffer_map = create_xshm_image(st->dpy, xgwa.visual, depth, + ZPixmap, 0, &st->shm_info, st->bigwidth, st->bigheight); + if (!st->buffer_map) { + st->use_shm = False; + fprintf(stderr, "create_xshm_image failed\n"); + } + } +#endif /* HAVE_XSHM_EXTENSION */ + + if (!st->buffer_map) { + st->buffer_map = XCreateImage(st->dpy, xgwa.visual, + depth, ZPixmap, 0, 0, + st->bigwidth, st->bigheight, 8, 0); + st->buffer_map->data = (char *) + calloc(st->buffer_map->height, st->buffer_map->bytes_per_line); + } +} + + +static void +DisplayImage(struct state *st) +{ +#ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) + XShmPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, 0, 0, + st->bigwidth, st->bigheight, False); + else +#endif /* HAVE_XSHM_EXTENSION */ + XPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, 0, 0, + st->bigwidth, st->bigheight); +} + + +/* ------------------------------------------- */ + + +static int +cinterp(double a, int bg, int fg) +{ + int result; + result = (int)((1-a) * bg + a * fg + 0.5); + if (result < 0) result = 0; + if (result > 255) result = 255; + return result; +} + + +/* Interpolate the ripple colours between the background colour and + foreground colour */ +static void +init_linear_colors(struct state *st) +{ + int i, j, red, green, blue, bred, bgreen, bblue; + XColor fg, bg; + + if (st->ncolors < 2 || mono_p) + st->ncolors = 2; + if (st->ncolors <= 2) + mono_p = True; + + /* Make it possible to set the color of the ripples, + Based on work by Raymond Medeiros and jwz. + */ + //fg.pixel = get_pixel_resource(st->dpy, st->colormap, "foreground", "Foreground"); + fg.pixel = load_color(st->dpy, st->colormap, foreground); + XQueryColor(st->dpy, st->colormap, &fg); + red = (fg.red >> 8); + green = (fg.green >> 8); + blue = (fg.blue >> 8); + + //bg.pixel = get_pixel_resource(st->dpy, st->colormap, "background", "Background"); + bg.pixel = load_color(st->dpy, st->colormap, background); + XQueryColor(st->dpy, st->colormap, &bg); + bred = (bg.red >> 8); + bgreen = (bg.green >> 8); + bblue = (bg.blue >> 8); + + j = 0; + for (i = 0; i < st->ncolors+1; i++) { + XColor xcl; + double a = (double)i / st->ncolors; + int r = cinterp(a, bred, red); + int g = cinterp(a, bgreen, green); + int b = cinterp(a, bblue, blue); + + xcl.red = (unsigned short) ((r << 8) | r); + xcl.green = (unsigned short) ((g << 8) | g); + xcl.blue = (unsigned short) ((b << 8) | b); + xcl.flags = DoRed | DoGreen | DoBlue; + + XAllocColor(st->dpy, st->colormap, &xcl); + + st->ctab[j++] = (int) xcl.pixel; + } +} + + +static void +init_oily_colors(struct state *st) +{ + XColor *colors = NULL; + + if (st->ncolors < 2 || mono_p) + st->ncolors = 2; + if (st->ncolors <= 2) + mono_p = True; + colors = 0; + + if (!mono_p) { + colors = (XColor *)malloc(sizeof(*colors) * (st->ncolors+1)); + make_smooth_colormap(st->screen, st->visual, st->colormap, + colors, &st->ncolors, + True, /* allocate */ + False, /* not writable */ + True); /* verbose (complain about failure) */ + if (st->ncolors <= 2) { + if (colors) + free (colors); + colors = 0; + mono_p = True; + } + } + if (!mono_p) { + int i, j = 0; + for (i = 0; i < st->ncolors+1; i++) { + XAllocColor(st->dpy, st->colormap, colors+i); + st->ctab[j++] = (int) colors[i].pixel; + } + free (colors); + } else { + st->ncolors = 2; + //st->ctab[1] = get_pixel_resource(st->dpy, st->colormap, "foreground", "Foreground"); + //st->ctab[0] = get_pixel_resource(st->dpy, st->colormap, "background", "Background"); + st->ctab[1] = load_color(st->dpy, st->colormap, foreground); + st->ctab[0] = load_color(st->dpy, st->colormap, background); + } +} + + +/* ------------------------------------------- */ + + +static void +init_cos_tab(struct state *st) +{ + int i; + for (i = 0; i < TABLE; i++) + st->cos_tab[i] = cos(i * M_PI/2 / TABLE); +} + + +/* Shape of drop to add */ +static double +sinc(struct state *st, double x) +{ +#if 1 + /* cosine hump */ + int i; + i = (int)(x * TABLE + 0.5); + if (i >= TABLE) i = (TABLE-1) - (i-(TABLE-1)); + if (i < 0) return 0.; + return st->cos_tab[i]; +#elif 0 + return cos(x * M_PI/2); +#else + if (fabs(x) < 0.1) + return 1 - x*x; + else + return sin(x) / x; +#endif +} + + +static void +add_circle_drop(struct state *st, int x, int y, int radius, int dheight) +{ + int r, r2, cx, cy; + short *buf = (random()&1) ? st->bufferA : st->bufferB; + + r2 = radius * radius; + + + for (cy = -radius; cy <= radius; cy++) + for (cx = -radius; cx <= radius; cx++) { + int xx = x+cx; + int yy = y+cy; + if (xx < 0 || yy < 0 || xx >= st->width || yy >= st->height) {break;} + r = cx*cx + cy*cy; + if (r > r2) break; + buf[xx + yy*st->width] = + (short)(dheight * sinc(st, (radius > 0) ? sqrt(r)/radius : 0)); + } +} + + +static void +add_drop(struct state *st, ripple_mode mode, int drop) +{ + int newx, newy, dheight; + int radius = MIN(st->width, st->height) / 50; + /* Don't put drops too near the edge of the screen or they get stuck */ + int border = 8; + + switch (mode) { + default: + case ripple_drop: { + int x; + + dheight = 1 + (random() % drop); + newx = border + (random() % (st->width - 2*border)); + newy = border + (random() % (st->height - 2*border)); + x = newy * st->width + newx; + st->bufferA[x + 1] = st->bufferA[x] = st->bufferA[x + st->width] = st->bufferA[x + st->width + 1] = + st->bufferB[x + 1] = st->bufferB[x] = st->bufferB[x + st->width] = st->bufferB[x + st->width + 1] = + dheight; + } + break; + case ripple_blob: { + double power; + + int tmp_i, tmp_j; + power = drop_dist[random() % (sizeof(drop_dist)/sizeof(drop_dist[0]))]; /* clumsy */ + dheight = (int)(drop * (power + 0.01)); + tmp_i = (int)(st->width - 2*border - 2*radius*power); + tmp_j = (int)(st->height - 2*border - 2*radius*power); + newx = radius + border + ((tmp_i > 0) ? random() % tmp_i : 0); + newy = radius + border + ((tmp_j > 0) ? random() % tmp_j : 0); + add_circle_drop(st, newx, newy, radius, dheight); + } + break; + /* Adding too many boxes too quickly (-box 1) doesn't give the waves time + to disperse and the waves build up (and overflow) */ + case ripple_box: { + int x; + int cx, cy; + short *buf = (random()&1) ? st->bufferA : st->bufferB; + int tmp_i, tmp_j; + + radius = (1 + (random() % 5)) * (1 + (random() % 5)); + dheight = drop / 128; + if (random() & 1) dheight = -dheight; + tmp_i = st->width - 2*border - 2*radius; + tmp_j = st->height - 2*border - 2*radius; + newx = radius + border + ((tmp_i > 0) ? random() % tmp_i : 0); + newy = radius + border + ((tmp_j > 0) ? random() % tmp_j : 0); + x = newy * st->width + newx; + for (cy = -radius; cy <= radius; cy++) + for (cx = -radius; cx <= radius; cx++) + buf[x + cx + cy*st->width] = (short)(dheight); + } + break; + case ripple_stir: { + border += radius; + newx = border + (int)((st->width-2*border) * (1+cos(3*st->stir_ang)) / 2); + newy = border + (int)((st->height-2*border) * (1+sin(2*st->stir_ang)) / 2); + add_circle_drop(st, newx, newy, radius, drop / 10); + st->stir_ang += 0.02; + if (st->stir_ang > 12*M_PI) st->stir_ang = 0; + } + break; + } +} + + +static void +init_ripples(struct state *st, int ndrops, int splash) +{ + int i; + + st->bufferA = (short *)calloc(st->width * st->height, sizeof(*st->bufferA)); + st->bufferB = (short *)calloc(st->width * st->height, sizeof(*st->bufferB)); + st->temp = (short *)calloc(st->width * st->height, sizeof(*st->temp)); + + st->dirty_buffer = (char *)calloc(st->width * st->height, sizeof(*st->dirty_buffer)); + + for (i = 0; i < ndrops; i++) + add_drop(st, ripple_blob, splash); + + if (st->transparent) { + if (st->grayscale_p) + { + int across, down; + for (down = 0; down < st->bigheight; down++) + for (across = 0; across < st->bigwidth; across++) + XPutPixel(st->buffer_map, across, down, + grayscale(st, XGetPixel(st->orig_map, across, down))); + } + else + { + /* There's got to be a better way of doing this XCopyArea? */ + memcpy(st->buffer_map->data, st->orig_map->data, + st->bigheight * st->buffer_map->bytes_per_line); + } + } else { + int across, down, color; + + color = map_color(st, 0); /* background colour */ + for (down = 0; down < st->bigheight; down++) + for (across = 0; across < st->bigwidth; across++) + XPutPixel(st->buffer_map,across, down, color); + } + + DisplayImage(st); +} + + +/* + Explanation from hq_water.zip (Arturo R Montesinos (ARM) arami@fi.upm.es) + + Differential equation is: u = a ( u + u ) + tt xx yy + + Where a = tension * gravity / surface_density. + + Approximating second derivatives by central differences: + + [ u(t+1)-2u(t)+u(t-1) ] / dt = a [ u(x+1)+u(x-1)+u(y+1)+u(y-1)-4u ] / h + + where dt = time step squared, h = dx*dy = mesh resolution squared. + + From where u(t+1) may be calculated as: + + dt | 1 | dt + u(t+1) = a -- | 1 0 1 |u - u(t-1) + (2-4a --)u + h | 1 | h + + When a*dt/h = 1/2 last term vanishes, giving: + + 1 | 1 | + u(t+1) = - | 1 0 1 |u - u(t-1) + 2 | 1 | + + (note that u(t-1,x,y) is only used to calculate u(t+1,x,y) so + we can use the same array for both t-1 and t+1, needing only + two arrays, U[0] and U[1]) + + Dampening is simulated by subtracting 1/2^n of result. + n=4 gives best-looking result + n<4 (eg 2 or 3) thicker consistency, waves die out immediately + n>4 (eg 8 or 12) more fluid, waves die out slowly + */ + +static void +ripple(struct state *st) +{ + int across, down, pixel; + short *src, *dest; + + if (st->draw_toggle == 0) { + src = st->bufferA; + dest = st->bufferB; + st->draw_toggle = 1; + } else { + src = st->bufferB; + dest = st->bufferA; + st->draw_toggle = 0; + } + + switch (st->draw_count) { + case 0: case 1: + pixel = 1 * st->width + 1; + for (down = 1; down < st->height - 1; down++, pixel += 2 * 1) + for (across = 1; across < st->width - 1; across++, pixel++) { + st->temp[pixel] = + (((src[pixel - 1] + src[pixel + 1] + + src[pixel - st->width] + src[pixel + st->width]) / 2)) - dest[pixel]; + } + + /* Smooth the output */ + pixel = 1 * st->width + 1; + for (down = 1; down < st->height - 1; down++, pixel += 2 * 1) + for (across = 1; across < st->width - 1; across++, pixel++) { + if (st->temp[pixel] != 0) { /* Close enough for government work */ + int damp = + (st->temp[pixel - 1] + st->temp[pixel + 1] + + st->temp[pixel - st->width] + st->temp[pixel + st->width] + + st->temp[pixel - st->width - 1] + st->temp[pixel - st->width + 1] + + st->temp[pixel + st->width - 1] + st->temp[pixel + st->width + 1] + + st->temp[pixel]) / 9; + dest[pixel] = damp - (damp >> st->fluidity); + } else + dest[pixel] = 0; + } + break; + case 2: case 3: + pixel = 1 * st->width + 1; + for (down = 1; down < st->height - 1; down++, pixel += 2 * 1) + for (across = 1; across < st->width - 1; across++, pixel++) { + int damp = + (((src[pixel - 1] + src[pixel + 1] + + src[pixel - st->width] + src[pixel + st->width]) / 2)) - dest[pixel]; + dest[pixel] = damp - (damp >> st->fluidity); + } + break; + } + if (++st->draw_count > 3) st->draw_count = 0; + + if (st->transparent) + st->draw_transparent(st, dest); + else + draw_ripple(st, dest); +} + + +/* ------------------------------------------- */ + +static void * +ripples_init (Display *disp, Window win) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = disp; + st->window = win; + st->iterations = 0; +#if 1 + st->delay = delay; + st->duration = duration; + st->rate = rate; + st->box = box; + st->oily = oily; + st->stir = stir; + st->fluidity = fluidity; + st->transparent = water; + st->grayscale_p = grayscale_; +#else + st->delay = get_integer_resource(disp, "delay", "Integer"); + st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + st->rate = get_integer_resource(disp, "rate", "Integer"); + st->box = get_integer_resource(disp, "box", "Integer"); + st->oily = get_boolean_resource(disp, "oily", "Boolean"); + st->stir = get_boolean_resource(disp, "stir", "Boolean"); + st->fluidity = get_integer_resource(disp, "fluidity", "Integer"); + st->transparent = get_boolean_resource(disp, "water", "Boolean"); + st->grayscale_p = get_boolean_resource(disp, "grayscale", "Boolean"); +#endif + +#ifdef HAVE_XSHM_EXTENSION + st->use_shm = get_boolean_resource(disp, "useSHM", "Boolean"); +#endif /* HAVE_XSHM_EXTENSION */ + //st->light = get_integer_resource(disp, "light", "Integer"); + st->light = light; + + if (st->delay < 0) st->delay = 0; + if (st->duration < 1) st->duration = 1; + if (st->fluidity <= 1) st->fluidity = 1; + if (st->fluidity > 16) st->fluidity = 16; /* 16 = sizeof(short) */ + if (st->light < 0) st->light = 0; + + init_cos_tab(st); + setup_X(st); + + //st->ncolors = get_integer_resource (disp, "colors", "Colors"); + st->ncolors = colors; + //if (0 == st->ncolors) /* English spelling? */ + // st->ncolors = get_integer_resource (disp, "colours", "Colors"); + + if (st->ncolors > sizeof(st->ctab)/sizeof(*st->ctab)) + st->ncolors = sizeof(st->ctab)/sizeof(*st->ctab); + + if (st->oily) + init_oily_colors(st); + else + init_linear_colors(st); + + if (st->transparent && st->light > 0) { + int maxbits; + st->draw_transparent = draw_transparent_light; + set_mask(st->visual->red_mask, &st->rmask, &st->rshift); + set_mask(st->visual->green_mask, &st->gmask, &st->gshift); + set_mask(st->visual->blue_mask, &st->bmask, &st->bshift); + if (st->rmask == 0) st->draw_transparent = draw_transparent_vanilla; + + /* Adjust the shift value "light" when we don't have 8 bits per colour */ + maxbits = MIN(MIN(BITCOUNT(st->rmask), BITCOUNT(st->gmask)), BITCOUNT(st->bmask)); + st->light -= 8-maxbits; + if (st->light < 0) st->light = 0; + } else { + if (st->grayscale_p) + { + set_mask(st->visual->red_mask, &st->rmask, &st->rshift); + set_mask(st->visual->green_mask, &st->gmask, &st->gshift); + set_mask(st->visual->blue_mask, &st->bmask, &st->bshift); + } + st->draw_transparent = draw_transparent_vanilla; + } + + if (!st->transparent) + init_ripples(st, 0, -SPLASH); /* Start off without any drops */ + + return st; +} + +static unsigned long +ripples_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + 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 */ + XWindowAttributes xgwa; + XGetWindowAttributes(st->dpy, st->window, &xgwa); + st->start_time = time ((time_t) 0); + st->orig_map = XGetImage (st->dpy, st->window, 0, 0, + xgwa.width, xgwa.height, + ~0L, ZPixmap); + init_ripples(st, 0, -SPLASH); /* Start off without any drops */ + } + return st->delay; + } + + if (!st->img_loader && + st->start_time + st->duration < time ((time_t) 0)) { + XWindowAttributes xgwa; + XGetWindowAttributes(st->dpy, st->window, &xgwa); + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, + st->window, 0, 0); + st->start_time = time ((time_t) 0); + return st->delay; + } + + if (st->rate > 0 && (st->iterations % st->rate) == 0) + add_drop(st, ripple_blob, -SPLASH); + if (st->stir) + add_drop(st, ripple_stir, -SPLASH); + if (st->box > 0 && (random() % st->box) == 0) + add_drop(st, ripple_box, -SPLASH); + + ripple(st); + DisplayImage(st); + + st->iterations++; + + return st->delay; +} + + +static void +ripples_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + ripples_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +ripples_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +static const char *ripples_defaults[] = +{ + ".background: black", + ".foreground: #FFAF5F", + "*colors: 200", + "*dontClearRoot: True", + "*delay: 50000", + "*duration: 120", + "*rate: 5", + "*box: 0", + "*water: True", + "*oily: False", + "*stir: False", + "*fluidity: 6", + "*light: 4", + "*grayscale: False", +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#else + "*useSHM: False", +#endif +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec ripples_options[] = +{ + { "-colors", ".colors", XrmoptionSepArg, 0}, + { "-colours", ".colors", XrmoptionSepArg, 0}, + {"-delay", ".delay", XrmoptionSepArg, 0}, + {"-duration", ".duration", XrmoptionSepArg, 0 }, + {"-rate", ".rate", XrmoptionSepArg, 0}, + {"-box", ".box", XrmoptionSepArg, 0}, + {"-water", ".water", XrmoptionNoArg, "True"}, + {"-oily", ".oily", XrmoptionNoArg, "True"}, + {"-stir", ".stir", XrmoptionNoArg, "True"}, + {"-fluidity", ".fluidity", XrmoptionSepArg, 0}, + {"-light", ".light", XrmoptionSepArg, 0}, + {"-grayscale", ".grayscale", XrmoptionNoArg, "True"}, + {"-shm", ".useSHM", XrmoptionNoArg, "True"}, + {"-no-shm", ".useSHM", XrmoptionNoArg, "False"}, + {0, 0, 0, 0} +}; + + +XSCREENSAVER_MODULE ("Ripples", ripples) diff --git a/non-wgl/ripples.vcproj b/non-wgl/ripples.vcproj new file mode 100644 index 0000000..dbfe063 --- /dev/null +++ b/non-wgl/ripples.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/rocks.c b/non-wgl/rocks.c new file mode 100644 index 0000000..9debe28 --- /dev/null +++ b/non-wgl/rocks.c @@ -0,0 +1,593 @@ +/* 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. + */ + +/* 18-Sep-97: Johannes Keukelaar : Added some color. + * Using -mono gives the old behaviour. (Modified by jwz.) + */ +/* Flying through an asteroid field. Based on TI Explorer Lisp code by + John Nguyen + */ + +#include "screenhack.h" +#include +#include + +char *background = "Black"; +char *foreground = "#E9967A"; +int colors = 5; +int count = 100; +int delay = 50000; +int speed = 100; +Bool rotate = True; +Bool move = True; +Bool use3d = False; +char *left3d = "Blue"; +char *right3d = "Red"; +float delta3d = 1.5; + +static argtype vars[] = +{ + {&background, "background", NULL, "Black", t_String}, + {&foreground, "foreground", NULL, "#E9967A", t_String}, + {&colors, "colors", NULL, "5", t_Int}, + {&count, "count", NULL, "100", t_Int}, + {&delay, "delay", NULL, "50000", t_Int}, + {&speed, "speed", NULL, "100", t_Int}, + {&rotate, "rotate", NULL, "True", t_Bool}, + {&move, "move", NULL, "True", t_Bool}, + {&use3d, "speed", NULL, "False", t_Bool}, + {&left3d, "left3d", NULL, "Blue", t_String}, + {&right3d, "right3d", NULL, "Red", t_String}, + {&delta3d, "delta3d", NULL, "1.5", t_Float}, +}; + + +#define MIN_ROCKS 1 +#define MIN_DEPTH 2 /* rocks disappear when they get this close */ +#define MAX_DEPTH 60 /* this is where rocks appear */ +#define MIN_SIZE 3 /* how small where pixmaps are not used */ +#define MAX_SIZE 200 /* how big (in pixels) rocks are at depth 1 */ +#define DEPTH_SCALE 100 /* how many ticks there are between depths */ +#define SIN_RESOLUTION 1000 + +#define MAX_DEP 0.3 /* how far the displacement can be (percent) */ +#define DIRECTION_CHANGE_RATE 60 +#define MAX_DEP_SPEED 5 /* Maximum speed for movement */ +#define MOVE_STYLE 0 /* Only 0 and 1. Distinguishes the fact that + these are the rocks that are moving (1) + or the rocks source (0). */ + +/* there's not much point in the above being user-customizable, but those + numbers might want to be tweaked for displays with an order of magnitude + higher resolution or compute power. + */ + +struct state { + Display *dpy; + Window window; + + double sins [SIN_RESOLUTION]; + double coss [SIN_RESOLUTION]; + double depths [(MAX_DEPTH + 1) * DEPTH_SCALE]; + + int width, height, midx, midy; + int dep_x, dep_y; + int ncolors; + XColor *colors; + float max_dep; + GC erase_gc; + GC *draw_gcs; + Bool rotate_p; + Bool move_p; + int speed; + Bool threed; + GC threed_left_gc, threed_right_gc; + double threed_delta; + + struct rock *rocks; + int nrocks; + Pixmap pixmaps [MAX_SIZE]; + int delay; + + int move_current_dep[2]; + int move_speed[2]; + short move_direction[2]; + int move_limit[2]; + + int current_delta; /* observer Z rotation */ + int new_delta; + int dchange_tick; +}; + + + +#define GETZDIFF(z) \ + (st->threed_delta * 40.0 * \ + (1.0 - ((MAX_DEPTH * DEPTH_SCALE / 2) / \ + ((z) + 20.0 * DEPTH_SCALE)))) + +struct rock { + int real_size; + int r; + int theta; + int depth; + int size, x, y; + int diff; + int color; +}; + +static void rock_compute (struct state *, struct rock *); +static void rock_draw (struct state *, struct rock *, Bool draw_p); + +static void +rock_reset (struct state *st, struct rock *rock) +{ + rock->real_size = MAX_SIZE; + rock->r = (SIN_RESOLUTION * 0.7) + (random () % (30 * SIN_RESOLUTION)); + rock->theta = random () % SIN_RESOLUTION; + rock->depth = MAX_DEPTH * DEPTH_SCALE; + rock->color = random() % st->ncolors; + rock_compute (st, rock); + rock_draw (st, rock, True); +} + +static void +rock_tick (struct state *st, struct rock *rock, int d) +{ + if (rock->depth > 0) + { + rock_draw (st, rock, False); + rock->depth -= st->speed; + if (st->rotate_p) + { + rock->theta = (rock->theta + d) % SIN_RESOLUTION; + } + while (rock->theta < 0) + rock->theta += SIN_RESOLUTION; + if (rock->depth < (MIN_DEPTH * DEPTH_SCALE)) + rock->depth = 0; + else + { + rock_compute (st, rock); + rock_draw (st, rock, True); + } + } + else if ((random () % 40) == 0) + rock_reset (st, rock); +} + +static void +rock_compute (struct state *st, struct rock *rock) +{ + double factor = st->depths [rock->depth]; + double rsize = rock->real_size * factor; + + rock->size = (int) (rsize + 0.5); + rock->diff = (int) GETZDIFF(rock->depth); + rock->x = st->midx + (st->coss [rock->theta] * rock->r * factor); + rock->y = st->midy + (st->sins [rock->theta] * rock->r * factor); + + if (st->move_p) + { + double move_factor = (((double) MOVE_STYLE) - + (((double) rock->depth) / + (((double) (MAX_DEPTH + 1)) * + ((double) DEPTH_SCALE)))); + /* move_factor is 0 when the rock is close, 1 when far */ + rock->x += (((double) st->dep_x) * move_factor); + rock->y += (((double) st->dep_y) * move_factor); + } +} + +static void +rock_draw (struct state *st, struct rock *rock, Bool draw_p) +{ + GC gc = (draw_p + ? (st->threed ? st->erase_gc : st->draw_gcs[rock->color]) + : st->erase_gc); + + if (rock->x <= 0 || rock->y <= 0 || rock->x >= st->width || rock->y >= st->height) + { + /* this means that if a rock were to go off the screen at 12:00, but + would have been visible at 3:00, it won't come back once the observer + rotates around so that the rock would have been visible again. + Oh well. + */ + if (!st->move_p) + rock->depth = 0; + return; + } + if (rock->size <= 1) + { + if (st->threed) + { + if (draw_p) gc = st->threed_left_gc; + XDrawPoint (st->dpy, st->window, gc, rock->x - rock->diff, rock->y); + if (draw_p) gc = st->threed_right_gc; + XDrawPoint (st->dpy, st->window, gc, rock->x + rock->diff, rock->y); + } + else + { + XDrawPoint (st->dpy, st->window, gc, rock->x, rock->y); + } + } + else if (rock->size <= MIN_SIZE || !draw_p) + { + if (st->threed) + { + if (draw_p) gc = st->threed_left_gc; + XFillRectangle(st->dpy, st->window, gc, + rock->x - rock->size / 2 - rock->diff, + rock->y - rock->size / 2, + rock->size, rock->size); + if (draw_p) gc = st->threed_right_gc; + XFillRectangle(st->dpy, st->window, gc, + rock->x - rock->size / 2 + rock->diff, + rock->y - rock->size / 2, + rock->size, rock->size); + } + else + { + XFillRectangle (st->dpy, st->window, gc, + rock->x - rock->size/2, rock->y - rock->size/2, + rock->size, rock->size); + } + } + else if (rock->size < MAX_SIZE) + { + if (st->threed) + { + gc = st->threed_left_gc; + XCopyPlane(st->dpy, st->pixmaps[rock->size], st->window, gc, + 0, 0, rock->size, rock->size, + rock->x - rock->size / 2 - rock->diff, + rock->y - rock->size / 2, 1L); + gc = st->threed_right_gc; + XCopyPlane(st->dpy, st->pixmaps[rock->size], st->window, gc, + 0, 0, rock->size, rock->size, + rock->x - rock->size / 2 + rock->diff, + rock->y - rock->size / 2, 1L); + } + else + { + XCopyPlane (st->dpy, st->pixmaps [rock->size], st->window, gc, + 0, 0, rock->size, rock->size, + rock->x - rock->size/2, rock->y - rock->size/2, + 1L); + } + } +} + + +static void +init_pixmaps (struct state *st) +{ + int i; + XGCValues gcv; + GC fg_gc = 0, bg_gc = 0; + st->pixmaps [0] = st->pixmaps [1] = 0; + for (i = MIN_DEPTH; i < MAX_SIZE; i++) + { + int w = (1+(i/32))<<5; /* server might be faster if word-aligned */ + int h = i; + Pixmap p = XCreatePixmap (st->dpy, st->window, w, h, 1); + XPoint points [7]; + st->pixmaps [i] = p; + if (! p) + { + fprintf (stderr, "%s: couldn't allocate pixmaps", progname); + exit (1); + } + if (! fg_gc) + { /* must use drawable of pixmap, not window (fmh) */ + gcv.foreground = 1; + fg_gc = XCreateGC (st->dpy, p, GCForeground, &gcv); + gcv.foreground = 0; + bg_gc = XCreateGC (st->dpy, p, GCForeground, &gcv); + } + XFillRectangle (st->dpy, p, bg_gc, 0, 0, w, h); + points [0].x = i * 0.15; points [0].y = i * 0.85; + points [1].x = i * 0.00; points [1].y = i * 0.20; + points [2].x = i * 0.30; points [2].y = i * 0.00; + points [3].x = i * 0.40; points [3].y = i * 0.10; + points [4].x = i * 0.90; points [4].y = i * 0.10; + points [5].x = i * 1.00; points [5].y = i * 0.55; + points [6].x = i * 0.45; points [6].y = i * 1.00; + XFillPolygon (st->dpy, p, fg_gc, points, 7, Nonconvex, CoordModeOrigin); + } + XFreeGC (st->dpy, fg_gc); + XFreeGC (st->dpy, bg_gc); +} + + +static int +compute_move(struct state *st, int axe) /* 0 for x, 1 for y */ +{ + int change = 0; + + st->move_limit[0] = st->midx; + st->move_limit[1] = st->midy; + + st->move_current_dep[axe] += st->move_speed[axe]; /* We adjust the displacement */ + + if (st->move_current_dep[axe] > (int) (st->move_limit[axe] * st->max_dep)) + { + if (st->move_current_dep[axe] > st->move_limit[axe]) + st->move_current_dep[axe] = st->move_limit[axe]; + st->move_direction[axe] = -1; + } /* This is when we reach the upper screen limit */ + if (st->move_current_dep[axe] < (int) (-st->move_limit[axe] * st->max_dep)) + { + if (st->move_current_dep[axe] < -st->move_limit[axe]) + st->move_current_dep[axe] = -st->move_limit[axe]; + st->move_direction[axe] = 1; + } /* This is when we reach the lower screen limit */ + if (st->move_direction[axe] == 1) /* We adjust the speed */ + st->move_speed[axe] += 1; + else if (st->move_direction[axe] == -1) + st->move_speed[axe] -= 1; + + if (st->move_speed[axe] > MAX_DEP_SPEED) + st->move_speed[axe] = MAX_DEP_SPEED; + else if (st->move_speed[axe] < -MAX_DEP_SPEED) + st->move_speed[axe] = -MAX_DEP_SPEED; + + if (st->move_p && !(random() % DIRECTION_CHANGE_RATE)) + { + /* We change direction */ + change = random() & 1; + if (change != 1) + { + if (st->move_direction[axe] == 0) + st->move_direction[axe] = change - 1; /* 0 becomes either 1 or -1 */ + else + st->move_direction[axe] = 0; /* -1 or 1 become 0 */ + } + } + return (st->move_current_dep[axe]); +} + +static void +tick_rocks (struct state *st, int d) +{ + int i; + + if (st->move_p) + { + st->dep_x = compute_move(st, 0); + st->dep_y = compute_move(st, 1); + } + + for (i = 0; i < st->nrocks; i++) + rock_tick (st, &st->rocks [i], d); +} + + +static unsigned long +rocks_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->current_delta != st->new_delta) + { + if (st->dchange_tick++ == 5) + { + st->dchange_tick = 0; + if (st->current_delta < st->new_delta) + st->current_delta++; + else + st->current_delta--; + } + } + else + { + if (! (random() % 50)) + { + st->new_delta = ((random() % 11) - 5); + if (! (random() % 10)) + st->new_delta *= 5; + } + } + tick_rocks (st, st->current_delta); + + return st->delay; +} + +static void * +rocks_init (Display *d, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int i; + XGCValues gcv; + Colormap cmap; + XWindowAttributes xgwa; + unsigned int bg; + st->dpy = d; + st->window = w; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->width = xgwa.width; + st->height = xgwa.height; + st->midx = st->width/2; + st->midy = st->height/2; + + cmap = xgwa.colormap; + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay = delay; + if (st->delay < 0) st->delay = 0; + //st->speed = get_integer_resource (st->dpy, "speed", "Integer"); + st->speed = speed; + if (st->speed < 1) st->speed = 1; + if (st->speed > 100) st->speed = 100; + //st->rotate_p = get_boolean_resource (st->dpy, "rotate", "Boolean"); + //st->move_p = get_boolean_resource (st->dpy, "move", "Boolean"); + st->rotate_p = rotate; + st->move_p = move; + if (mono_p) + st->ncolors = 2; + else + //st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors = colors; + + if (st->ncolors < 2) + { + st->ncolors = 2; + mono_p = True; + } + + st->colors = (XColor *) malloc(st->ncolors * sizeof(*st->colors)); + st->draw_gcs = (GC *) malloc(st->ncolors * sizeof(*st->draw_gcs)); + + //bg = get_pixel_resource (st->dpy, cmap, "background", "Background"); + bg = load_color(st->dpy, cmap, background); + st->colors[0].pixel = bg; + st->colors[0].flags = DoRed|DoGreen|DoBlue; + XQueryColor(st->dpy, cmap, &st->colors[0]); + + st->ncolors--; + make_random_colormap(xgwa.screen, xgwa.visual, cmap, + st->colors+1, &st->ncolors, True, + True, 0, True); + st->ncolors++; + + if (st->ncolors < 2) + { + st->ncolors = 2; + mono_p = True; + } + + if (mono_p) + { + //unsigned int fg = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground"); + unsigned int fg = load_color(st->dpy, cmap, foreground); + st->colors[1].pixel = fg; + st->colors[1].flags = DoRed|DoGreen|DoBlue; + XQueryColor(st->dpy, cmap, &st->colors[1]); + gcv.foreground = fg; + gcv.background = bg; + st->draw_gcs[0] = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); + st->draw_gcs[1] = st->draw_gcs[0]; + } + else + for( i = 0; i < st->ncolors; i++ ) + { + gcv.foreground = st->colors[i].pixel; + gcv.background = bg; + st->draw_gcs[i] = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); + } + + gcv.foreground = bg; + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); + + st->max_dep = (st->move_p ? MAX_DEP : 0); + + for (i = 0; i < SIN_RESOLUTION; i++) + { + st->sins [i] = sin ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI); + st->coss [i] = cos ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI); + } + /* we actually only need i/speed of these, but wtf */ + for (i = 1; i < (sizeof (st->depths) / sizeof (st->depths[0])); i++) + st->depths [i] = atan (((double) 0.5) / (((double) i) / DEPTH_SCALE)); + st->depths [0] = M_PI/2; /* avoid division by 0 */ + + //sst->threed = get_boolean_resource(st->dpy, "use3d", "Boolean"); + st->threed = use3d; + if (st->threed) + { + gcv.background = bg; + //gcv.foreground = get_pixel_resource (st->dpy, cmap, "left3d", "Foreground"); + gcv.foreground = load_color(st->dpy, cmap, left3d); + st->threed_left_gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground,&gcv); + //gcv.foreground = get_pixel_resource (st->dpy, cmap, "right3d", "Foreground"); + gcv.foreground = load_color(st->dpy, cmap, right3d); + st->threed_right_gc = XCreateGC (st->dpy, st->window,GCForeground|GCBackground,&gcv); + //st->threed_delta = get_float_resource(st->dpy, "delta3d", "Integer"); + st->threed_delta = delta3d; + } + + /* don't want any exposure events from XCopyPlane */ + for( i = 0; i < st->ncolors; i++) + XSetGraphicsExposures (st->dpy, st->draw_gcs[i], False); + XSetGraphicsExposures (st->dpy, st->erase_gc, False); + + //st->nrocks = get_integer_resource (st->dpy, "count", "Count"); + st->nrocks = count; + if (st->nrocks < 1) st->nrocks = 1; + st->rocks = (struct rock *) calloc (st->nrocks, sizeof (struct rock)); + init_pixmaps (st); + XClearWindow (st->dpy, st->window); + return st; +} + +static void +rocks_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; + st->midx = st->width/2; + st->midy = st->height/2; +} + +#if 0 + static Bool + rocks_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +rocks_free (Display *dpy, Window window, void *closure) +{ +} + + + +static const char *rocks_defaults [] = { + ".background: Black", + ".foreground: #E9967A", + "*fpsSolid: true", + "*colors: 5", + "*count: 100", + "*delay: 50000", + "*speed: 100", + "*rotate: true", + "*move: true", + "*use3d: False", + "*left3d: Blue", + "*right3d: Red", + "*delta3d: 1.5", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec rocks_options [] = { + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-rotate", ".rotate", XrmoptionNoArg, "true" }, + { "-no-rotate", ".rotate", XrmoptionNoArg, "false" }, + { "-move", ".move", XrmoptionNoArg, "true" }, + { "-no-move", ".move", XrmoptionNoArg, "false" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + {"-3d", ".use3d", XrmoptionNoArg, "True"}, + {"-no-3d", ".use3d", XrmoptionNoArg, "False"}, + {"-left3d", ".left3d", XrmoptionSepArg, 0 }, + {"-right3d", ".right3d", XrmoptionSepArg, 0 }, + {"-delta3d", ".delta3d", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Rocks", rocks) diff --git a/non-wgl/rocks.vcproj b/non-wgl/rocks.vcproj new file mode 100644 index 0000000..a04ceca --- /dev/null +++ b/non-wgl/rocks.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/rorschach.c b/non-wgl/rorschach.c new file mode 100644 index 0000000..7b4d387 --- /dev/null +++ b/non-wgl/rorschach.c @@ -0,0 +1,244 @@ +/* xscreensaver, Copyright (c) 1992-2008 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. + * + * 19971004: Johannes Keukelaar : Use helix screen + * eraser. + */ + +#include "screenhack.h" +#include "erase.h" + +float eraseSeconds = 0; +char *eraseMode = NULL; + +char *background = "black"; +char *foreground = "white"; +Bool xsymmetry = True; +Bool ysymmetry = False; +int iterations = 4000; +int offset = 7; +int delay = 5; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&xsymmetry, "xsymmetry", NULL, "True", t_Bool}, + {&ysymmetry, "ysymmetry", NULL, "False", t_Bool}, + {&iterations, "iterations", NULL, "4000", t_Int}, + {&offset, "offset", NULL, "7", t_Int}, + {&delay, "delay", NULL, "5", t_Int}, +}; + +struct state { + GC draw_gc; + unsigned int default_fg_pixel; + int iterations, offset; + Bool xsym, ysym; + int sleep_time; + int xlim, ylim; + XColor color; + int current_x, current_y, remaining_iterations; + eraser_state *eraser; +}; + + +static void * +rorschach_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + Colormap cmap; + XWindowAttributes xgwa; + XGetWindowAttributes (dpy, window, &xgwa); + cmap = xgwa.colormap; + //gcv.foreground = st->default_fg_pixel = + // get_pixel_resource (dpy, cmap, "foreground", "Foreground"); + gcv.foreground = st->default_fg_pixel = load_color(dpy, cmap, foreground); + st->draw_gc = XCreateGC (dpy, window, GCForeground, &gcv); +#if 1 + gcv.foreground = load_color(dpy, cmap, background); + st->iterations = iterations; + st->offset = offset; +#else + gcv.foreground = get_pixel_resource (dpy, cmap, "background", "Background"); + st->iterations = get_integer_resource (dpy, "iterations", "Integer"); + st->offset = get_integer_resource (dpy, "offset", "Integer"); +#endif + if (st->offset <= 0) st->offset = 3; + if (st->iterations < 10) st->iterations = 10; +#if 1 + st->sleep_time = delay; + st->xsym = xsymmetry; + st->ysym = ysymmetry; +#else + st->sleep_time = get_integer_resource (dpy, "delay", "Delay"); + st->xsym = get_boolean_resource (dpy, "xsymmetry", "Symmetry"); + st->ysym = get_boolean_resource (dpy, "ysymmetry", "Symmetry"); +#endif + st->remaining_iterations = -1; + st->color.pixel = 0; + return st; +} + +static void +rorschach_reshape (Display *dpy, Window window, void *closure, + unsigned int width, unsigned int height) +{ + struct state *st = (struct state *) closure; + st->xlim = width; + st->ylim = height; +} + + +static void +rorschach_draw_start (Display *dpy, Window window, struct state *st) +{ + Colormap cmap; + XWindowAttributes xgwa; + + XGetWindowAttributes (dpy, window, &xgwa); + st->xlim = xgwa.width; + st->ylim = xgwa.height; + cmap = xgwa.colormap; + + if (st->color.pixel) XFreeColors (dpy, cmap, &st->color.pixel, 1, 0); + + if (! mono_p) + hsv_to_rgb (random()%360, 1.0, 1.0, &st->color.red, &st->color.green, &st->color.blue); + if ((!mono_p) && XAllocColor (dpy, cmap, &st->color)) + XSetForeground (dpy, st->draw_gc, st->color.pixel); + else + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); + + st->current_x = st->xlim/2; + st->current_y = st->ylim/2; + st->remaining_iterations = st->iterations; +} + + +static void +rorschach_draw_step (Display *dpy, Window window, struct state *st) +{ +# define ITER_CHUNK 300 + XPoint points [4 * ITER_CHUNK]; + int x = st->current_x; + int y = st->current_y; + int i, j = 0; + + int this_iterations = ITER_CHUNK; + if (this_iterations > st->remaining_iterations) + this_iterations = st->remaining_iterations; + + for (i = 0; i < this_iterations; i++) + { + x += ((random () % (1 + (st->offset << 1))) - st->offset); + y += ((random () % (1 + (st->offset << 1))) - st->offset); + points [j].x = x; + points [j].y = y; + j++; + if (st->xsym) + { + points [j].x = st->xlim - x; + points [j].y = y; + j++; + } + if (st->ysym) + { + points [j].x = x; + points [j].y = st->ylim - y; + j++; + } + if (st->xsym && st->ysym) + { + points [j].x = st->xlim - x; + points [j].y = st->ylim - y; + j++; + } + } + XDrawPoints (dpy, window, st->draw_gc, points, j, CoordModeOrigin); + st->remaining_iterations -= this_iterations; + if (st->remaining_iterations < 0) st->remaining_iterations = 0; + st->current_x = x; + st->current_y = y; +} + + +static unsigned long +rorschach_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + unsigned long delay = 20000; + + if (st->eraser) { + st->eraser = erase_window (dpy, window, st->eraser); + goto END; + } + + if (st->remaining_iterations > 0) + { + rorschach_draw_step (dpy, window, st); + if (st->remaining_iterations == 0) + delay = st->sleep_time * 1000000; + } + else + { + if (st->remaining_iterations == 0) + st->eraser = erase_window (dpy, window, st->eraser); + + rorschach_draw_start (dpy, window, st); + } + END: + return delay; +} + +#if 0 + static Bool + rorschach_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +rorschach_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *rorschach_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*xsymmetry: true", + "*ysymmetry: false", + "*iterations: 4000", + "*offset: 7", + "*delay: 5", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec rorschach_options [] = { + { "-iterations", ".iterations", XrmoptionSepArg, 0 }, + { "-offset", ".offset", XrmoptionSepArg, 0 }, + { "-xsymmetry", ".xsymmetry", XrmoptionNoArg, "true" }, + { "-ysymmetry", ".ysymmetry", XrmoptionNoArg, "true" }, + { "-no-xsymmetry", ".xsymmetry", XrmoptionNoArg, "false" }, + { "-no-ysymmetry", ".ysymmetry", XrmoptionNoArg, "false" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Rorschach", rorschach) diff --git a/non-wgl/rorschach.vcproj b/non-wgl/rorschach.vcproj new file mode 100644 index 0000000..4b2389a --- /dev/null +++ b/non-wgl/rorschach.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/rotor.c b/non-wgl/rotor.c new file mode 100644 index 0000000..3a38da4 --- /dev/null +++ b/non-wgl/rotor.c @@ -0,0 +1,410 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* rotor --- a swirly rotor */ + +#if 0 +static const char sccsid[] = "@(#)rotor.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1991 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. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 10-May-1997: Compatible with xscreensaver + * 08-Mar-1995: CAT stuff for ## was tripping up some C compilers. Removed. + * 01-Dec-1993: added patch for AIXV3 from Tom McConnell + * + * 11-Nov-1990: put into xlock by Steve Zellers + * 16-Oct-1990: Received from Tom Lawrence (tcl@cs.brown.edu: 'flight' + * simulator) + */ + +#define STANDALONE +#define NOARGS + +#define MODE_rotor +#define DELAY 10000 +#define COUNT 4 +#define CYCLES 20 +#define SIZE_ -6 +#define NCOLORS 200 +#define DEFAULTS "*delay: 10000 \n" \ + "*count: 4 \n" \ + "*cycles: 20 \n" \ + "*size: -6 \n" \ + "*ncolors: 200 \n" \ + "*fpsSolid: true \n" \ + +# define SMOOTH_COLORS +# define reshape_rotor 0 +# define rotor_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_rotor + +ENTRYPOINT ModeSpecOpt rotor_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct rotor_description = +{"rotor", "init_rotor", "draw_rotor", "release_rotor", + "refresh_rotor", "init_rotor", (char *) NULL, &rotor_opts, + 100, 4, 100, -6, 64, 0.3, "", + "Shows Tom's Roto-Rooter", 0, NULL}; + +#endif + +/*- + * A 'batchcount' of 3 or 4 works best! + */ + +#define MAXANGLE 3000.0 /* irrectangular (was 10000.0) */ + +/* How many segments to draw per cycle when redrawing */ +#define REDRAWSTEP 3 + +typedef struct { + float angle; + float radius; + float start_radius; + float end_radius; + float radius_drift_max; + float radius_drift_now; + + float ratio; + float start_ratio; + float end_ratio; + float ratio_drift_max; + float ratio_drift_now; +} elem; + +typedef struct { + int pix; + int lastx, lasty; + int num, rotor, prev; + int nsave; + float angle; + int centerx, centery; + int prevcenterx, prevcentery; + unsigned char firsttime; + unsigned char iconifiedscreen; /* for iconified view */ + unsigned char forward; + unsigned char unused; + elem *elements; + XPoint *save; + int redrawing, redrawpos; + int linewidth; +} rotorstruct; + +static rotorstruct *rotors = (rotorstruct *) NULL; + +static void +free_rotor(rotorstruct *rp) +{ + if (rp->elements != NULL) { + (void) free((void *) rp->elements); + rp->elements = (elem *) NULL; + } + if (rp->save != NULL) { + (void) free((void *) rp->save); + rp->save = (XPoint *) NULL; + } +} + +ENTRYPOINT void +init_rotor (ModeInfo * mi) +{ + int x; + elem *pelem; + unsigned char wasiconified; + rotorstruct *rp; + + if (rotors == NULL) { + if ((rotors = (rotorstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (rotorstruct))) == NULL) + return; + } + rp = &rotors[MI_SCREEN(mi)]; + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False); +#endif + + rp->prevcenterx = rp->centerx; + rp->prevcentery = rp->centery; + + rp->centerx = MI_WIDTH(mi) / 2; + rp->centery = MI_HEIGHT(mi) / 2; + + rp->redrawing = 0; + /* + * sometimes, you go into iconified view, only to see a really whizzy pattern + * that you would like to look more closely at. Normally, clicking in the + * icon reinitializes everything - but I don't, cuz I'm that kind of guy. + * HENCE, the wasiconified stuff you see here. + */ + + wasiconified = rp->iconifiedscreen; + rp->iconifiedscreen = MI_IS_ICONIC(mi); + + if (wasiconified && !rp->iconifiedscreen) + rp->firsttime = True; + else { + + /* This is a fudge is needed since prevcenter may not be set when it comes + from the the random mode and return is pressed (and its not the first + mode that was running). This assumes that the size of the lock screen + window / size of the icon window = 12 */ + if (!rp->prevcenterx) + rp->prevcenterx = rp->centerx * 12; + if (!rp->prevcentery) + rp->prevcentery = rp->centery * 12; + + rp->num = MI_COUNT(mi); + if (rp->num < 0) { + rp->num = NRAND(-rp->num) + 1; + if (rp->elements != NULL) { + (void) free((void *) rp->elements); + rp->elements = (elem *) NULL; + } + } + if (rp->elements == NULL) + if ((rp->elements = (elem *) calloc(rp->num, + sizeof (elem))) == NULL) { + free_rotor(rp); + return; + } + rp->nsave = MI_CYCLES(mi); + if (rp->nsave <= 1) + rp->nsave = 2; + if (rp->save == NULL) + if ((rp->save = (XPoint *) malloc(rp->nsave * + sizeof (XPoint))) == NULL) { + free_rotor(rp); + return; + } + for (x = 0; x < rp->nsave; x++) { + rp->save[x].x = rp->centerx; + rp->save[x].y = rp->centery; + } + + pelem = rp->elements; + + for (x = rp->num; --x >= 0; pelem++) { + pelem->radius_drift_max = 1.0; + pelem->radius_drift_now = 1.0; + + pelem->end_radius = 100.0; + + pelem->ratio_drift_max = 1.0; + pelem->ratio_drift_now = 1.0; + pelem->end_ratio = 10.0; + } + if (MI_NPIXELS(mi) > 2) + rp->pix = NRAND(MI_NPIXELS(mi)); + + rp->rotor = 0; + rp->prev = 1; + rp->lastx = rp->centerx; + rp->lasty = rp->centery; + rp->angle = (float) NRAND((long) MAXANGLE) / 3.0; + rp->forward = rp->firsttime = True; + } + rp->linewidth = MI_SIZE(mi); + + if (rp->linewidth == 0) + rp->linewidth = 1; + if (rp->linewidth < 0) + rp->linewidth = NRAND(-rp->linewidth) + 1; + + MI_CLEARWINDOW(mi); +} + +ENTRYPOINT void +draw_rotor (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + register elem *pelem; + int thisx, thisy; + int i; + int x_1, y_1, x_2, y_2; + rotorstruct *rp; + + if (rotors == NULL) + return; + rp = &rotors[MI_SCREEN(mi)]; + if (rp->elements == NULL) + return; + + MI_IS_DRAWN(mi) = True; + if (!rp->iconifiedscreen) { + thisx = rp->centerx; + thisy = rp->centery; + } else { + thisx = rp->prevcenterx; + thisy = rp->prevcentery; + } + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), rp->linewidth, + LineSolid, CapButt, JoinMiter); + for (i = rp->num, pelem = rp->elements; --i >= 0; pelem++) { + if (pelem->radius_drift_max <= pelem->radius_drift_now) { + pelem->start_radius = pelem->end_radius; + pelem->end_radius = (float) NRAND(40000) / 100.0 - 200.0; + pelem->radius_drift_max = (float) NRAND(100000) + 10000.0; + pelem->radius_drift_now = 0.0; + } + if (pelem->ratio_drift_max <= pelem->ratio_drift_now) { + pelem->start_ratio = pelem->end_ratio; + pelem->end_ratio = (float) NRAND(2000) / 100.0 - 10.0; + pelem->ratio_drift_max = (float) NRAND(100000) + 10000.0; + pelem->ratio_drift_now = 0.0; + } + pelem->ratio = pelem->start_ratio + + (pelem->end_ratio - pelem->start_ratio) / + pelem->ratio_drift_max * pelem->ratio_drift_now; + pelem->angle = rp->angle * pelem->ratio; + pelem->radius = pelem->start_radius + + (pelem->end_radius - pelem->start_radius) / + pelem->radius_drift_max * pelem->radius_drift_now; + + thisx += (int) (COSF(pelem->angle) * pelem->radius); + thisy += (int) (SINF(pelem->angle) * pelem->radius); + + pelem->ratio_drift_now += 1.0; + pelem->radius_drift_now += 1.0; + } + if (rp->firsttime) + rp->firsttime = False; + else { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + + x_1 = (int) rp->save[rp->rotor].x; + y_1 = (int) rp->save[rp->rotor].y; + x_2 = (int) rp->save[rp->prev].x; + y_2 = (int) rp->save[rp->prev].y; + + if (rp->iconifiedscreen) { + x_1 = x_1 * rp->centerx / rp->prevcenterx; + x_2 = x_2 * rp->centerx / rp->prevcenterx; + y_1 = y_1 * rp->centery / rp->prevcentery; + y_2 = y_2 * rp->centery / rp->prevcentery; + } + XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2); + + if (MI_NPIXELS(mi) > 2) { + XSetForeground(display, gc, MI_PIXEL(mi, rp->pix)); + if (++rp->pix >= MI_NPIXELS(mi)) + rp->pix = 0; + } else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + + x_1 = rp->lastx; + y_1 = rp->lasty; + x_2 = thisx; + y_2 = thisy; + + if (rp->iconifiedscreen) { + x_1 = x_1 * rp->centerx / rp->prevcenterx; + x_2 = x_2 * rp->centerx / rp->prevcenterx; + y_1 = y_1 * rp->centery / rp->prevcentery; + y_2 = y_2 * rp->centery / rp->prevcentery; + } + XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2); + } + rp->save[rp->rotor].x = rp->lastx = thisx; + rp->save[rp->rotor].y = rp->lasty = thisy; + + ++rp->rotor; + rp->rotor %= rp->nsave; + ++rp->prev; + rp->prev %= rp->nsave; + if (rp->forward) { + rp->angle += 0.01; + if (rp->angle >= MAXANGLE) { + rp->angle = MAXANGLE; + rp->forward = False; + } + } else { + rp->angle -= 0.1; + if (rp->angle <= 0) { + rp->angle = 0.0; + rp->forward = True; + } + } + if (rp->redrawing) { + int j; + + for (i = 0; i < REDRAWSTEP; i++) { + j = (rp->rotor - rp->redrawpos + rp->nsave) % rp->nsave; + + x_1 = (int) rp->save[j].x; + y_1 = (int) rp->save[j].y; + x_2 = (int) rp->save[(j - 1 + rp->nsave) % rp->nsave].x; + y_2 = (int) rp->save[(j - 1 + rp->nsave) % rp->nsave].y; + + if (rp->iconifiedscreen) { + x_1 = x_1 * rp->centerx / rp->prevcenterx; + x_2 = x_2 * rp->centerx / rp->prevcenterx; + y_1 = y_1 * rp->centery / rp->prevcentery; + y_2 = y_2 * rp->centery / rp->prevcentery; + } + XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2); + + if (++(rp->redrawpos) >= rp->nsave) { + rp->redrawing = 0; + break; + } + } + } + XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, + LineSolid, CapButt, JoinMiter); +} + +ENTRYPOINT void +release_rotor (ModeInfo * mi) +{ + if (rotors != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_rotor(&rotors[screen]); + (void) free((void *) rotors); + rotors = (rotorstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_rotor (ModeInfo * mi) +{ + rotorstruct *rp; + + if (rotors == NULL) + return; + rp = &rotors[MI_SCREEN(mi)]; + + MI_CLEARWINDOW(mi); + rp->redrawing = 1; + rp->redrawpos = 1; +} + +XSCREENSAVER_MODULE ("Rotor", rotor) + +#endif /* MODE_rotor */ diff --git a/non-wgl/rotor.vcproj b/non-wgl/rotor.vcproj new file mode 100644 index 0000000..d8d63d5 --- /dev/null +++ b/non-wgl/rotor.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/rotzoomer.c b/non-wgl/rotzoomer.c new file mode 100644 index 0000000..98807df --- /dev/null +++ b/non-wgl/rotzoomer.c @@ -0,0 +1,512 @@ +/* rotzoomer - creates a collage of rotated and scaled portions of the screen + * Copyright (C) 2001 Claudio Matsuoka + * + * 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. + */ + +/* + * Options: + * + * -shm enable MIT shared memory extension + * -no-shm disable MIT shared memory extension + * -n number of zoomboxes + * -move enable mobile zoomboxes + * -sweep enable sweep mode + * -anim enable snapshot mode + * -no-anim enable snapshot mode + * -delay delay in milliseconds + */ + +#include "screenhack.h" +#include + +#ifdef HAVE_XSHM_EXTENSION +#include "xshm.h" +#endif + +char *background = "black"; +char *foreground = "white"; +Bool anim = True; +char *mode = "stationary"; +int numboxes = 2; +int delay = 10000; +int duration = 120; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&anim, "anim", NULL, "True", t_Bool}, + {&mode, "mode", NULL, "stationary", t_String}, + {&numboxes, "numboxes", NULL, "2", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&duration, "duration", NULL, "120", t_Int}, +}; + +struct zoom_area { + int w, h; /* rectangle width and height */ + int inc1, inc2; /* rotation and zoom angle increments */ + int dx, dy; /* translation increments */ + int a1, a2; /* rotation and zoom angular variables */ + int ox, oy; /* origin in the background copy */ + int xx, yy; /* left-upper corner position (* 256) */ + int x, y; /* left-upper corner position */ + int ww, hh; /* valid area to place left-upper corner */ + int n; /* number of iteractions */ + int count; /* current iteraction */ +}; + +struct state { + Display *dpy; + Window window; + + GC gc; + Visual *visual; + XImage *orig_map, *buffer_map; + Colormap colormap; + + int width, height; + struct zoom_area **zoom_box; + int num_zoom; + int move; + int sweep; + int delay; + int anim; + int duration; + time_t start_time; + + async_load_state *img_loader; + +#ifdef HAVE_XSHM_EXTENSION + Bool use_shm; + XShmSegmentInfo shm_info; +#endif +}; + + +static void +rotzoom (struct state *st, struct zoom_area *za) +{ + int x, y, c, s, zoom, z; + int x2 = za->x + za->w - 1, y2 = za->y + za->h - 1; + int ox = 0, oy = 0; + + z = 8100 * sin (M_PI * za->a2 / 8192); + zoom = 8192 + z; + + c = zoom * cos (M_PI * za->a1 / 8192); + s = zoom * sin (M_PI * za->a1 / 8192); + for (y = za->y; y <= y2; y++) { + for (x = za->x; x <= x2; x++) { + ox = (x * c + y * s) >> 13; + oy = (-x * s + y * c) >> 13; + + while (ox < 0) + ox += st->width; + while (oy < 0) + oy += st->height; + while (ox >= st->width) + ox -= st->width; + while (oy >= st->height) + oy -= st->height; + + XPutPixel (st->buffer_map, x, y, XGetPixel (st->orig_map, ox, oy)); + } + } + + za->a1 += za->inc1; /* Rotation angle */ + za->a1 &= 0x3fff;; + + za->a2 += za->inc2; /* Zoom */ + za->a2 &= 0x3fff; + + za->ox = ox; /* Save state for next iteration */ + za->oy = oy; + + za->count++; +} + + +static void +reset_zoom (struct state *st, struct zoom_area *za) +{ + if (st->sweep) { + int speed = random () % 100 + 100; + switch (random () % 4) { + case 0: + za->w = st->width; + za->h = 10; + za->x = 0; + za->y = 0; + za->dx = 0; + za->dy = speed; + za->n = (st->height - 10) * 256 / speed; + break; + case 1: + za->w = 10; + za->h = st->height; + za->x = st->width - 10; + za->y = 0; + za->dx = -speed; + za->dy = 0; + za->n = (st->width - 10) * 256 / speed; + break; + case 2: + za->w = st->width; + za->h = 10; + za->x = 0; + za->y = st->height - 10; + za->dx = 0; + za->dy = -speed; + za->n = (st->height - 10) * 256 / speed; + break; + case 3: + za->w = 10; + za->h = st->height; + za->x = 0; + za->y = 0; + za->dx = speed; + za->dy = 0; + za->n = (st->width - 10) * 256 / speed; + break; + } + za->ww = st->width - za->w; + za->hh = st->height - za->h; + + /* We want smaller angle increments in sweep mode (looks better) */ + + za->a1 = 0; + za->a2 = 0; + za->inc1 = ((2 * (random() & 1)) - 1) * (1 + random () % 7); + za->inc2 = ((2 * (random() & 1)) - 1) * (1 + random () % 7); + } else { + za->w = 50 + random() % 300; + za->h = 50 + random() % 300; + + if (za->w > st->width / 3) + za->w = st->width / 3; + if (za->h > st->height / 3) + za->h = st->height / 3; + + za->ww = st->width - za->w; + za->hh = st->height - za->h; + + za->x = (za->ww ? random() % za->ww : 0); + za->y = (za->hh ? random() % za->hh : 0); + + za->dx = ((2 * (random() & 1)) - 1) * (100 + random() % 300); + za->dy = ((2 * (random() & 1)) - 1) * (100 + random() % 300); + + if (st->anim) { + za->n = 50 + random() % 1000; + za->a1 = 0; + za->a2 = 0; + } else { + za->n = 5 + random() % 10; + za->a1 = random (); + za->a2 = random (); + } + + za->inc1 = ((2 * (random() & 1)) - 1) * (random () % 30); + za->inc2 = ((2 * (random() & 1)) - 1) * (random () % 30); + } + + za->xx = za->x * 256; + za->yy = za->y * 256; + + za->count = 0; +} + + +static struct zoom_area * +create_zoom (struct state *st) +{ + struct zoom_area *za; + + za = malloc (sizeof (struct zoom_area)); + reset_zoom (st, za); + + return za; +} + + +static void +update_position (struct zoom_area *za) +{ + za->xx += za->dx; + za->yy += za->dy; + + za->x = za->xx >> 8; + za->y = za->yy >> 8; + + if (za->x < 0) { + za->x = 0; + za->dx = 100 + random() % 100; + } + + if (za->y < 0) { + za->y = 0; + za->dy = 100 + random() % 100; + } + + if (za->x > za->ww) { + za->x = za->ww; + za->dx = -(100 + random() % 100); + } + + if (za->y > za->hh) { + za->y = za->hh; + za->dy = -(100 + random() % 100); + } +} + + +static void +DisplayImage (struct state *st, int x, int y, int w, int h) +{ +#ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) + XShmPutImage (st->dpy, st->window, st->gc, st->buffer_map, x, y, x, y, + w, h, False); + else +#endif /* HAVE_XSHM_EXTENSION */ + XPutImage(st->dpy, st->window, st->gc, st->buffer_map, x, y, x, y, w, h); +} + + +static void +init_hack (struct state *st) +{ + int i; + + st->start_time = time ((time_t) 0); + st->zoom_box = calloc (st->num_zoom, sizeof (struct zoom_area *)); + for (i = 0; i < st->num_zoom; i++) { + st->zoom_box[i] = create_zoom (st); + } + + if (st->height && st->orig_map->data) + memcpy (st->buffer_map->data, st->orig_map->data, + st->height * st->buffer_map->bytes_per_line); + + DisplayImage(st, 0, 0, st->width, st->height); +} + + +static unsigned long +rotzoomer_draw (Display *disp, Window win, void *closure) +{ + struct state *st = (struct state *) closure; + int delay = st->delay; + int i; + + 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->orig_map = XGetImage (st->dpy, st->window, 0, 0, + st->width, st->height, ~0L, ZPixmap); + init_hack (st); + } + return st->delay; + } + + if (!st->img_loader && + st->start_time + st->duration < time ((time_t) 0)) { + XWindowAttributes xgwa; + XGetWindowAttributes(st->dpy, st->window, &xgwa); + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, + st->window, 0, 0); + st->start_time = time ((time_t) 0); + return st->delay; + } + + for (i = 0; i < st->num_zoom; i++) { + if (st->move || st->sweep) + update_position (st->zoom_box[i]); + + if (st->zoom_box[i]->n > 0) { + if (st->anim || st->zoom_box[i]->count == 0) { + rotzoom (st, st->zoom_box[i]); + } else { + delay = 1000000; + } + st->zoom_box[i]->n--; + } else { + reset_zoom (st, st->zoom_box[i]); + } + } + + for (i = 0; i < st->num_zoom; i++) { + DisplayImage(st, st->zoom_box[i]->x, st->zoom_box[i]->y, + st->zoom_box[i]->w, st->zoom_box[i]->h); + } + + return delay; +} + + +static void +setup_X (struct state *st) +{ + XWindowAttributes xgwa; + int depth; + XGCValues gcv; + long gcflags; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + depth = xgwa.depth; + st->colormap = xgwa.colormap; + st->width = xgwa.width; + st->height = xgwa.height; + st->visual = xgwa.visual; + + if (st->width % 2) + st->width--; + if (st->height % 2) + st->height--; + + gcv.function = GXcopy; + gcv.subwindow_mode = IncludeInferiors; + gcflags = GCFunction; + if (use_subwindow_mode_p (xgwa.screen, st->window)) /* see grabscreen.c */ + gcflags |= GCSubwindowMode; + st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv); + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, + st->window, 0, 0); + + st->buffer_map = 0; + +#ifdef HAVE_XSHM_EXTENSION + if (st->use_shm) { + st->buffer_map = create_xshm_image(st->dpy, xgwa.visual, depth, + ZPixmap, 0, &st->shm_info, st->width, st->height); + if (!st->buffer_map) { + st->use_shm = False; + fprintf(stderr, "create_xshm_image failed\n"); + } + } +#endif /* HAVE_XSHM_EXTENSION */ + + if (!st->buffer_map) { + st->buffer_map = XCreateImage(st->dpy, xgwa.visual, + depth, ZPixmap, 0, 0, st->width, st->height, 8, 0); + st->buffer_map->data = (char *)calloc (st->buffer_map->height, + st->buffer_map->bytes_per_line); + } +} + + +static void * +rotzoomer_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + char *s; + st->dpy = dpy; + st->window = window; +#ifdef HAVE_XSHM_EXTENSION + st->use_shm = get_boolean_resource (st->dpy, "useSHM", "Boolean"); +#endif + //st->num_zoom = get_integer_resource (st->dpy, "numboxes", "Integer"); + st->num_zoom = numboxes; + + //s = get_string_resource (dpy, "mode", "Mode"); + s = mode; + if (!s || !*s || !strcasecmp (s, "stationary")) + ; + else if (!strcasecmp (s, "move")) + st->move = True; + else if (!strcasecmp (s, "sweep")) + st->sweep = True; + else + fprintf (stderr, "%s: bogus mode: \"%s\"\n", progname, s); + + //st->anim = get_boolean_resource (st->dpy, "anim", "Boolean"); + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + //st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + st->anim = anim; + st->delay = delay; + st->duration = duration; + if (st->delay < 0) st->delay = 0; + if (st->duration < 1) st->duration = 1; + + /* In sweep or static mode, we want only one box */ + if (st->sweep || !st->anim) + st->num_zoom = 1; + + /* Can't have static sweep mode */ + if (!st->anim) + st->sweep = 0; + + st->start_time = time ((time_t) 0); + + setup_X (st); + + return st; +} + +static void +rotzoomer_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + rotzoomer_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +rotzoomer_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *rotzoomer_defaults[] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#else + "*useSHM: False", +#endif + "*anim: True", + "*mode: stationary", + "*numboxes: 2", + "*delay: 10000", + "*duration: 120", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + + +static XrmOptionDescRec rotzoomer_options[] = { + { "-shm", ".useSHM", XrmoptionNoArg, "True" }, + { "-no-shm", ".useSHM", XrmoptionNoArg, "False" }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-move", ".mode", XrmoptionNoArg, "move" }, + { "-sweep", ".mode", XrmoptionNoArg, "sweep" }, + { "-anim", ".anim", XrmoptionNoArg, "True" }, + { "-no-anim", ".anim", XrmoptionNoArg, "False" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + {"-duration", ".duration", XrmoptionSepArg, 0 }, + { "-n", ".numboxes", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("RotZoomer", rotzoomer) diff --git a/non-wgl/rotzoomer.vcproj b/non-wgl/rotzoomer.vcproj new file mode 100644 index 0000000..871bdfa --- /dev/null +++ b/non-wgl/rotzoomer.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/shadebobs.c b/non-wgl/shadebobs.c new file mode 100644 index 0000000..a51c320 --- /dev/null +++ b/non-wgl/shadebobs.c @@ -0,0 +1,497 @@ +/* shadebobs, Copyright (c) 1999 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 - "shadebobs.c" + * + * Description: + * There are two little shading circles (bobs) that zip around the screen. + * one of them shades up towards white, and the other shades down toward + * black. + * This keeps the screen in color balance at a chosen color. + * + * Its kinda like 'The Force' + * There is a light side, a dark side, and it keeps the world in balance. + * + * [05/23/99] - Shane Smit: Creation + * [05/26/99] - Shane Smit: Port to C/screenhack for use with XScreenSaver + * [06/11/99] - Shane Smit: Stopped trying to rape the palette. + * [06/20/99] - jwz: cleaned up ximage handling, gave resoources short names, + * introduced delay, made it restart after N iterations. + * [06/21/99] - Shane Smit: Modified default values slightly, color changes + * on cycle, and the extents of the sinus pattern change in + * real-time. + * [06/22/99] - Shane Smit: Fixed delay to be fast and use little CPU :). + * [09/17/99] - Shane Smit: Made all calculations based on the size of the + * window. Thus, it'll look the same at 100x100 as it does at + * 1600x1200 ( Only smaller :). + * [04/24/00] - Shane Smit: Revamped entire source code: + * Shade Bob movement is calculated very differently. + * Base color can be any color now. + */ + + +#include "screenhack.h" +#include + +/* #define VERBOSE */ + +char *background = "black"; +char *foreground = "white"; +int degrees = 0; +char *color = "random"; +int count = 4; +int cycles = 10; +int ncolors = 64; +int delay = 10000; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {°rees, "degrees", NULL, "0", t_Int}, + {&color, "color", NULL, "random", t_String}, + {&count, "count", NULL, "4", t_Int}, + {&cycles, "cycles", NULL, "10", t_Int}, + {&ncolors, "ncolors", NULL, "64", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, +}; + +static const char *shadebobs_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*degrees: 0", /* default: Automatic degree calculation */ + "*color: random", + "*count: 4", + "*cycles: 10", + "*ncolors: 64", /* changing this doesn't work particularly well */ + "*delay: 10000", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec shadebobs_options [] = { + { "-degrees", ".degrees", XrmoptionSepArg, 0 }, + { "-color", ".color", XrmoptionSepArg, 0 }, + { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-cycles", ".cycles", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +/* Ahem. Chocolate is a flavor; not a food. Thank you */ + + +typedef struct +{ + signed char *anDeltaMap; + double nAngle, nAngleDelta, nAngleInc; + double nPosX, nPosY; +} SShadeBob; + +struct state { + Display *dpy; + Window window; + unsigned short iDegreeCount; + double *anSinTable, *anCosTable; + unsigned short iWinWidth, iWinHeight; + unsigned short iWinCenterX, iWinCenterY; + char *sColor; + unsigned char iBobRadius, iBobDiameter; + unsigned char iVelocity; + + unsigned long *aiColorVals; + signed short iColorCount; + int cycles; + XImage *pImage; + unsigned char nShadeBobCount, iShadeBob; + SShadeBob *aShadeBobs; + GC gc; + int delay; + int draw_i; +}; + +#define RANDOM() ((int) (random() & 0X7FFFFFFFL)) + + + +static void ResetShadeBob( struct state *st, SShadeBob *pShadeBob ) +{ + pShadeBob->nPosX = RANDOM() % st->iWinWidth; + pShadeBob->nPosY = RANDOM() % st->iWinHeight; + pShadeBob->nAngle = RANDOM() % st->iDegreeCount; + pShadeBob->nAngleDelta = ( RANDOM() % st->iDegreeCount ) - ( st->iDegreeCount / 2.0F ); + pShadeBob->nAngleInc = pShadeBob->nAngleDelta / 50.0F; + if( pShadeBob->nAngleInc == 0.0F ) + pShadeBob->nAngleInc = ( pShadeBob->nAngleDelta > 0.0F ) ? 0.0001F : -0.0001F; +} + + +static void InitShadeBob( struct state *st, SShadeBob *pShadeBob, Bool bDark ) +{ + double nDelta; + int iWidth, iHeight; + + if( ( pShadeBob->anDeltaMap = calloc( st->iBobDiameter * st->iBobDiameter, sizeof(char) ) ) == NULL ) + { + fprintf( stderr, "%s: Could not allocate Delta Map!\n", progname ); + return; + } + + for( iHeight=-st->iBobRadius; iHeightiBobRadius; iHeight++ ) + for( iWidth=-st->iBobRadius; iWidthiBobRadius; iWidth++ ) + { + nDelta = 9 - ( ( sqrt( pow( iWidth+0.5, 2 ) + pow( iHeight+0.5, 2 ) ) / st->iBobRadius ) * 8 ); + if( nDelta < 0 ) nDelta = 0; + if( bDark ) nDelta = -nDelta; + pShadeBob->anDeltaMap[ ( iWidth + st->iBobRadius ) * st->iBobDiameter + iHeight + st->iBobRadius ] = (char)nDelta; + } + + ResetShadeBob( st, pShadeBob ); +} + + +/* A delta is calculated, and the shadebob turns at an increment. When the delta + * falls to 0, a new delta and increment are calculated. */ +static void MoveShadeBob( struct state *st, SShadeBob *pShadeBob ) +{ + pShadeBob->nAngle += pShadeBob->nAngleInc; + pShadeBob->nAngleDelta -= pShadeBob->nAngleInc; + + if( pShadeBob->nAngle >= st->iDegreeCount ) pShadeBob->nAngle -= st->iDegreeCount; + else if( pShadeBob->nAngle < 0 ) pShadeBob->nAngle += st->iDegreeCount; + + if( ( pShadeBob->nAngleInc>0.0F && pShadeBob->nAngleDeltanAngleInc ) || + ( pShadeBob->nAngleInc<=0.0F && pShadeBob->nAngleDelta>pShadeBob->nAngleInc ) ) + { + pShadeBob->nAngleDelta = ( RANDOM() % st->iDegreeCount ) - ( st->iDegreeCount / 2.0F ); + pShadeBob->nAngleInc = pShadeBob->nAngleDelta / 50.0F; + if( pShadeBob->nAngleInc == 0.0F ) + pShadeBob->nAngleInc = ( pShadeBob->nAngleDelta > 0.0F ) ? 0.0001F : -0.0001F; + } + + pShadeBob->nPosX = ( st->anSinTable[ (int)pShadeBob->nAngle ] * st->iVelocity ) + pShadeBob->nPosX; + pShadeBob->nPosY = ( st->anCosTable[ (int)pShadeBob->nAngle ] * st->iVelocity ) + pShadeBob->nPosY; + + /* This wraps it around the screen. */ + if( pShadeBob->nPosX >= st->iWinWidth ) pShadeBob->nPosX -= st->iWinWidth; + else if( pShadeBob->nPosX < 0 ) pShadeBob->nPosX += st->iWinWidth; + + if( pShadeBob->nPosY >= st->iWinHeight ) pShadeBob->nPosY -= st->iWinHeight; + else if( pShadeBob->nPosY < 0 ) pShadeBob->nPosY += st->iWinHeight; +} + + +static void Execute( struct state *st, SShadeBob *pShadeBob ) +{ + unsigned long iColor; + short iColorVal; + int iPixelX, iPixelY; + unsigned int iWidth, iHeight; + + MoveShadeBob( st, pShadeBob ); + + for( iHeight=0; iHeightiBobDiameter; iHeight++ ) + { + iPixelY = pShadeBob->nPosY + iHeight; + if( iPixelY >= st->iWinHeight ) iPixelY -= st->iWinHeight; + + for( iWidth=0; iWidthiBobDiameter; iWidth++ ) + { + iPixelX = pShadeBob->nPosX + iWidth; + if( iPixelX >= st->iWinWidth ) iPixelX -= st->iWinWidth; + + iColor = XGetPixel( st->pImage, iPixelX, iPixelY ); + + /* FIXME: Here is a loop I'd love to take out. */ + for( iColorVal=0; iColorValiColorCount; iColorVal++ ) + if( st->aiColorVals[ iColorVal ] == iColor ) + break; + + iColorVal += pShadeBob->anDeltaMap[ iWidth * st->iBobDiameter + iHeight ]; + if( iColorVal >= st->iColorCount ) iColorVal = st->iColorCount - 1; + if( iColorVal < 0 ) iColorVal = 0; + + XPutPixel( st->pImage, iPixelX, iPixelY, st->aiColorVals[ iColorVal ] ); + } + } + + /* FIXME: if it's next to the top or left sides of screen this will break. However, it's not noticable. */ + XPutImage( st->dpy, st->window, st->gc, st->pImage, + pShadeBob->nPosX, pShadeBob->nPosY, pShadeBob->nPosX, pShadeBob->nPosY, st->iBobDiameter, st->iBobDiameter ); +} + + +static void CreateTables( struct state *st, unsigned int nDegrees ) +{ + double nRadian; + unsigned int iDegree; + st->anSinTable = calloc( nDegrees, sizeof(double) ); + st->anCosTable = calloc( nDegrees, sizeof(double) ); + + for( iDegree=0; iDegreeanSinTable[ iDegree ] = sin( nRadian ); + st->anCosTable[ iDegree ] = cos( nRadian ); + } +} + + +static unsigned long * SetPalette(struct state *st ) +{ + XWindowAttributes XWinAttribs; + XColor Color, *aColors; + signed short iColor; + float nHalfColors; + + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + + Color.red = RANDOM() % 0xFFFF; + Color.green = RANDOM() % 0xFFFF; + Color.blue = RANDOM() % 0xFFFF; + + if( strcasecmp( st->sColor, "random" ) && !XParseColor( st->dpy, XWinAttribs.colormap, st->sColor, &Color ) ) + fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, st->sColor ); + +#ifdef VERBOSE + printf( "%s: Base color (RGB): <%d, %d, %d>\n", progname, Color.red, Color.green, Color.blue ); +#endif /* VERBOSE */ + + //st->iColorCount = get_integer_resource(st->dpy, "ncolors", "Integer" ); + st->iColorCount = ncolors; + if( st->iColorCount < 2 ) st->iColorCount = 2; + if( st->iColorCount > 255 ) st->iColorCount = 255; + + aColors = calloc( st->iColorCount, sizeof(XColor) ); + st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) ); + + for( iColor=0; iColoriColorCount; iColor++ ) + { + nHalfColors = st->iColorCount / 2.0F; + /* Black -> Base Color */ + if( iColor < (st->iColorCount/2) ) + { + aColors[ iColor ].red = ( Color.red / nHalfColors ) * iColor; + aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor; + aColors[ iColor ].blue = ( Color.blue / nHalfColors ) * iColor; + } + /* Base Color -> White */ + else + { + aColors[ iColor ].red = ( ( ( 0xFFFF - Color.red ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.red; + aColors[ iColor ].green = ( ( ( 0xFFFF - Color.green ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.green; + aColors[ iColor ].blue = ( ( ( 0xFFFF - Color.blue ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.blue; + } + + if( !XAllocColor( st->dpy, XWinAttribs.colormap, &aColors[ iColor ] ) ) + { + /* start all over with less colors */ + XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, iColor, 0 ); + free( aColors ); + free( st->aiColorVals ); + st->iColorCount--; + aColors = calloc( st->iColorCount, sizeof(XColor) ); + st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) ); + iColor = -1; + } + else + st->aiColorVals[ iColor ] = aColors[ iColor ].pixel; + } + + free( aColors ); + + XSetWindowBackground( st->dpy, st->window, st->aiColorVals[ 0 ] ); + + return st->aiColorVals; +} + + +static void Initialize( struct state *st ) +{ + XGCValues gcValues; + XWindowAttributes XWinAttribs; + /*int iBitsPerPixel;*/ + + /* Create the Image for drawing */ + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + +#if 0 + /* Find the preferred bits-per-pixel. (jwz) */ + { + int i, pfvc = 0; + XPixmapFormatValues *pfv = XListPixmapFormats( st->dpy, &pfvc ); + for( i=0; igc = XCreateGC( st->dpy, st->window, 0, &gcValues ); + + st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL, + XWinAttribs.width, XWinAttribs.height, 8 /*BitmapPad( st->dpy )*/, 0 ); + st->pImage->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height); + + st->iWinWidth = XWinAttribs.width; + st->iWinHeight = XWinAttribs.height; + + /* These are precalculations used in Execute(). */ + st->iBobDiameter = ( ( st->iWinWidth < st->iWinHeight ) ? st->iWinWidth : st->iWinHeight ) / 25; + st->iBobRadius = st->iBobDiameter / 2; +#ifdef VERBOSE + printf( "%s: Bob Diameter = %d\n", progname, st->iBobDiameter ); +#endif + + st->iWinCenterX = ( XWinAttribs.width / 2 ) - st->iBobRadius; + st->iWinCenterY = ( XWinAttribs.height / 2 ) - st->iBobRadius; + + st->iVelocity = ( ( st->iWinWidth < st->iWinHeight ) ? st->iWinWidth : st->iWinHeight ) / 150; + + /* Create the Sin and Cosine lookup tables. */ + //st->iDegreeCount = get_integer_resource(st->dpy, "degrees", "Integer" ); + st->iDegreeCount = degrees; + if( st->iDegreeCount == 0 ) st->iDegreeCount = ( XWinAttribs.width / 6 ) + 400; + else if( st->iDegreeCount < 90 ) st->iDegreeCount = 90; + else if( st->iDegreeCount > 5400 ) st->iDegreeCount = 5400; + CreateTables( st, st->iDegreeCount ); +#ifdef VERBOSE + printf( "%s: Using a %d degree circle.\n", progname, st->iDegreeCount ); +#endif /* VERBOSE */ + + /* Get the base color. */ + //st->sColor = get_string_resource(st->dpy, "color", "Color" ); + st->sColor = "color"; +} + + +static void * +shadebobs_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + +#ifdef VERBOSE + time_t nTime = time( NULL ); + unsigned short iFrame = 0; +#endif /* VERBOSE */ + + st->dpy = dpy; + st->window = window; + + //st->nShadeBobCount = get_integer_resource(st->dpy, "count", "Integer" ); + st->nShadeBobCount = count; + if( st->nShadeBobCount > 64 ) st->nShadeBobCount = 64; + if( st->nShadeBobCount < 1 ) st->nShadeBobCount = 1; + + if( ( st->aShadeBobs = calloc( st->nShadeBobCount, sizeof(SShadeBob) ) ) == NULL ) + { + fprintf( stderr, "%s: Could not allocate %d ShadeBobs\n", progname, st->nShadeBobCount ); + abort(); + } +#ifdef VERBOSE + printf( "%s: Allocated %d ShadeBobs\n", progname, st->nShadeBobCount ); +#endif /* VERBOSE */ + + Initialize( st ); + + for( st->iShadeBob=0; st->iShadeBobnShadeBobCount; st->iShadeBob++ ) + InitShadeBob( st, &st->aShadeBobs[ st->iShadeBob ], st->iShadeBob % 2 ); + + //st->delay = get_integer_resource(st->dpy, "delay", "Integer" ); + //st->cycles = get_integer_resource(st->dpy, "cycles", "Integer" ) * st->iDegreeCount; + st->delay = delay; + st->cycles = cycles * st->iDegreeCount; + + st->draw_i = 99999999; + return st; +} + +static unsigned long +shadebobs_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if( st->draw_i++ >= st->cycles ) + { + XWindowAttributes XWinAttribs; + XGetWindowAttributes( st->dpy, st->window, &XWinAttribs ); + + st->draw_i = 0; +#if 0 + memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height ); +#else + { + /* fill the image with the actual value of the black pixel, not 0. */ + unsigned long black = BlackPixelOfScreen (XWinAttribs.screen); + int x, y; + for (y = 0; y < XWinAttribs.height; y++) + for (x = 0; x < XWinAttribs.width; x++) + XPutPixel (st->pImage, x, y, black); + } +#endif + + for( st->iShadeBob=0; st->iShadeBobnShadeBobCount; st->iShadeBob++ ) + ResetShadeBob( st, &st->aShadeBobs[ st->iShadeBob ] ); + XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, st->iColorCount, 0 ); + free( st->aiColorVals ); + st->aiColorVals = SetPalette( st ); + XClearWindow( st->dpy, st->window ); + } + + for( st->iShadeBob=0; st->iShadeBobnShadeBobCount; st->iShadeBob++ ) + Execute( st, &st->aShadeBobs[ st->iShadeBob ] ); + + return st->delay; +} + +static void +shadebobs_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + shadebobs_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +shadebobs_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free( st->anSinTable ); + free( st->anCosTable ); + /* free( st->pImage->data ); */ + XDestroyImage( st->pImage ); + for( st->iShadeBob=0; st->iShadeBobnShadeBobCount; st->iShadeBob++ ) + free( st->aShadeBobs[ st->iShadeBob ].anDeltaMap ); + free( st->aShadeBobs ); + free( st->aiColorVals ); +} + + +XSCREENSAVER_MODULE ("ShadeBobs", shadebobs) + +/* End of Module - "shadebobs.c" */ + +/* vim: ts=4 + */ diff --git a/non-wgl/shadebobs.vcproj b/non-wgl/shadebobs.vcproj new file mode 100644 index 0000000..07c00df --- /dev/null +++ b/non-wgl/shadebobs.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/sierpinski.c b/non-wgl/sierpinski.c new file mode 100644 index 0000000..f552ebc --- /dev/null +++ b/non-wgl/sierpinski.c @@ -0,0 +1,238 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* sierpinski --- Sierpinski's triangle fractal */ + +#if 0 +static const char sccsid[] = "@(#)sierpinski.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 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. + * + * 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. + * + * Dots initially appear where they "should not". Later they get + * "focused". This is correct behavior. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 18-Sep-1997: 3D version Antti Kuntsi . + * 20-May-1997: Changed the name tri to sierpinski for more compatiblity + * 10-May-1997: Jamie Zawinski compatible with xscreensaver + * 05-Sep-1996: Desmond Daignault Datatimes Incorporated + * . + */ + +#define STANDALONE +#define NOARGS + +# define MODE_sierpinski +#define DELAY 400000 +#define COUNT 2000 +#define CYCLES 100 +#define NCOLORS 64 +# define DEFAULTS "*delay: 400000 \n" \ + "*count: 2000 \n" \ + "*cycles: 100 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define BRIGHT_COLORS +# define sierpinski_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_sierpinski + +ENTRYPOINT ModeSpecOpt sierpinski_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct sierpinski_description = +{"sierpinski", "init_sierpinski", "draw_sierpinski", "release_sierpinski", + "refresh_sierpinski", "init_sierpinski", (char *) NULL, &sierpinski_opts, + 400000, 2000, 100, 1, 64, 1.0, "", + "Shows Sierpinski's triangle", 0, NULL}; +#endif + +#define MAXCORNERS 4 + +typedef struct { + int width, height; + int time; + int px, py; + int total_npoints; + int corners; + int npoints[MAXCORNERS]; + unsigned long colors[MAXCORNERS]; + XPoint *pointBuffer[MAXCORNERS]; + XPoint vertex[MAXCORNERS]; +} sierpinskistruct; + +static sierpinskistruct *tris = (sierpinskistruct *) NULL; + +static void +startover(ModeInfo * mi) +{ + int j; + sierpinskistruct *sp = &tris[MI_SCREEN(mi)]; + + if (MI_NPIXELS(mi) > 2) { + if (sp->corners == 3) { + sp->colors[0] = (NRAND(MI_NPIXELS(mi))); + sp->colors[1] = (sp->colors[0] + MI_NPIXELS(mi) / 7 + + NRAND(2 * MI_NPIXELS(mi) / 7 + 1)) % MI_NPIXELS(mi); + sp->colors[2] = (sp->colors[0] + 4 * MI_NPIXELS(mi) / 7 + + NRAND(2 * MI_NPIXELS(mi) / 7 + 1)) % MI_NPIXELS(mi); + } else if (sp->corners == 4) { + sp->colors[0] = (NRAND(MI_NPIXELS(mi))); + sp->colors[1] = (sp->colors[0] + MI_NPIXELS(mi) / 7 + + NRAND(MI_NPIXELS(mi) / 7 + 1)) % MI_NPIXELS(mi); + sp->colors[2] = (sp->colors[0] + 3 * MI_NPIXELS(mi) / 7 + + NRAND(MI_NPIXELS(mi) / 7 + 1)) % MI_NPIXELS(mi); + sp->colors[3] = (sp->colors[0] + 5 * MI_NPIXELS(mi) / 7 + + NRAND(MI_NPIXELS(mi) / 7 + 1)) % MI_NPIXELS(mi); + } else { + (void) fprintf(stderr, "colors not set for %d corners\n", sp->corners); + } + } + for (j = 0; j < sp->corners; j++) { + sp->vertex[j].x = NRAND(sp->width); + sp->vertex[j].y = NRAND(sp->height); + } + sp->px = NRAND(sp->width); + sp->py = NRAND(sp->height); + sp->time = 0; + + MI_CLEARWINDOW(mi); +} + +static void +free_sierpinski(sierpinskistruct *sp) +{ + int corner; + + for (corner = 0; corner < MAXCORNERS; corner++) + if (sp->pointBuffer[corner] != NULL) { + (void) free((void *) sp->pointBuffer[corner]); + sp->pointBuffer[corner] = (XPoint *) NULL; + } +} + +ENTRYPOINT void +init_sierpinski(ModeInfo * mi) +{ + int i; + sierpinskistruct *sp; + + if (tris == NULL) { + if ((tris = (sierpinskistruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (sierpinskistruct))) == NULL) + return; + } + sp = &tris[MI_SCREEN(mi)]; + + sp->width = MI_WIDTH(mi); + sp->height = MI_HEIGHT(mi); + + sp->total_npoints = MI_COUNT(mi); + if (sp->total_npoints < 1) + sp->total_npoints = 1; + sp->corners = MI_SIZE(mi); + if (sp->corners < 3 || sp->corners > 4) { + sp->corners = (int) (LRAND() & 1) + 3; + } + for (i = 0; i < sp->corners; i++) { + if (!sp->pointBuffer[i]) + if ((sp->pointBuffer[i] = (XPoint *) malloc(sp->total_npoints * + sizeof (XPoint))) == NULL) { + free_sierpinski(sp); + return; + } + } + startover(mi); +} + +ENTRYPOINT void +draw_sierpinski(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + XPoint *xp[MAXCORNERS]; + int i, v; + sierpinskistruct *sp; + + if (tris == NULL) + return; + sp = &tris[MI_SCREEN(mi)]; + if (sp->pointBuffer[0] == NULL) + return; + + MI_IS_DRAWN(mi) = True; + if (MI_NPIXELS(mi) <= 2) + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + for (i = 0; i < sp->corners; i++) + xp[i] = sp->pointBuffer[i]; + for (i = 0; i < sp->total_npoints; i++) { + v = NRAND(sp->corners); + sp->px = (sp->px + sp->vertex[v].x) / 2; + sp->py = (sp->py + sp->vertex[v].y) / 2; + xp[v]->x = sp->px; + xp[v]->y = sp->py; + xp[v]++; + sp->npoints[v]++; + } + for (i = 0; i < sp->corners; i++) { + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, sp->colors[i])); + XDrawPoints(display, MI_WINDOW(mi), gc, sp->pointBuffer[i], sp->npoints[i], + CoordModeOrigin); + sp->npoints[i] = 0; + } + if (++sp->time >= MI_CYCLES(mi)) + startover(mi); +} + +ENTRYPOINT void +reshape_sierpinski(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_sierpinski (mi); +} + +ENTRYPOINT void +release_sierpinski(ModeInfo * mi) +{ + if (tris != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_sierpinski(&tris[screen]); + (void) free((void *) tris); + tris = (sierpinskistruct *) NULL; + } +} + +ENTRYPOINT void +refresh_sierpinski(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + +XSCREENSAVER_MODULE ("Sierpinski", sierpinski) + +#endif /* MODE_sierpinski */ diff --git a/non-wgl/sierpinski.vcproj b/non-wgl/sierpinski.vcproj new file mode 100644 index 0000000..4d69663 --- /dev/null +++ b/non-wgl/sierpinski.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/slip.c b/non-wgl/slip.c new file mode 100644 index 0000000..ef4620e --- /dev/null +++ b/non-wgl/slip.c @@ -0,0 +1,376 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* slip --- lots of slipping blits */ + +#if 0 +static const char sccsid[] = "@(#)slip.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1992 by Scott Draves + * + * 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. + * + * 01-Nov-2000: Allocation checks + * 10-May-1997: Jamie Zawinski compatible with xscreensaver + * 01-Dec-1995: Patched for VMS + */ + +#define STANDALONE +#define NOARGS + +# define MODE_slip +#define DELAY 50000 +#define COUNT 35 +#define CYCLES 50 +#define NCOLORS 200 +# define DEFAULTS "*delay: 50000 \n" \ + "*count: 35 \n" \ + "*cycles: 50 \n" \ + "*ncolors: 200 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define refresh_slip 0 +# define slip_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_slip + +ENTRYPOINT ModeSpecOpt slip_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct slip_description = +{"slip", "init_slip", "draw_slip", "release_slip", + "init_slip", "init_slip", (char *) NULL, &slip_opts, + 50000, 35, 50, 1, 64, 1.0, "", + "Shows slipping blits", 0, NULL}; + +#endif + +typedef struct { + int width, height; + int nblits_remaining; + int blit_width, blit_height; + int mode; + int first_time; + int backwards; + short lasthalf; + int stage; + unsigned long r; + Bool image_loading_p; +} slipstruct; +static slipstruct *slips = (slipstruct *) NULL; + +static short +halfrandom(slipstruct *sp, int mv) +{ + unsigned long r; + + if (sp->lasthalf) { + r = sp->lasthalf; + sp->lasthalf = 0; + } else { + r = LRAND(); + sp->lasthalf = (short) (r >> 16); + } + return r % mv; +} + +static int +erandom(slipstruct *sp, int mv) +{ + int res; + + if (0 == sp->stage) { + sp->r = LRAND(); + sp->stage = 7; + } + res = (int) (sp->r & 0xf); + sp->r = sp->r >> 4; + sp->stage--; + if (res & 8) + return res & mv; + else + return -(res & mv); +} + +#ifdef STANDALONE +static void +image_loaded_cb (Screen *screen, Window w, Drawable d, + const char *name, XRectangle *geom, + void *closure) +{ + ModeInfo *mi = (ModeInfo *) closure; + slipstruct *sp = &slips[MI_SCREEN(mi)]; + Display *dpy = DisplayOfScreen (screen); + XCopyArea (dpy, d, w, mi->gc, 0, 0, + sp->width, sp->height, 0, 0); + XFreePixmap (dpy, d); + sp->image_loading_p = False; +} +#endif /* STANDALONE */ + +static void +prepare_screen(ModeInfo * mi, slipstruct * sp) +{ + + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + int i, n, w = sp->width / 20; + int not_solid = halfrandom(sp, 10); + + sp->backwards = (int) (LRAND() & 1); /* jwz: go the other way sometimes */ + + if (sp->first_time || !halfrandom(sp, 10)) { + MI_CLEARWINDOW(mi); + n = 300; + } else { + if (halfrandom(sp, 5)) + return; + if (halfrandom(sp, 5)) + n = 100; + else + n = 2000; + } + + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi)))); + else if (halfrandom(sp, 2)) + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + else + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + + for (i = 0; i < n; i++) { + int ww = ((w / 2) + halfrandom(sp, MAX(w, 1))); + + if (not_solid) { + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi)))); + else if (halfrandom(sp, 2)) + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + else + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + } + XFillRectangle(display, MI_WINDOW(mi), gc, + halfrandom(sp, MAX(sp->width - ww, 1)), + halfrandom(sp, MAX(sp->height - ww, 1)), + ww, ww); + } + sp->first_time = 0; + + +#ifdef STANDALONE /* jwz -- sometimes hack the desktop image! */ + if (!sp->image_loading_p && + (1||halfrandom(sp, 2) == 0)) { + /* Load it into a pixmap so that the "Loading" message and checkerboard + don't show up on the window -- we keep running while the image is + in progress... */ + Pixmap p = XCreatePixmap (MI_DISPLAY(mi), MI_WINDOW(mi), + sp->width, sp->height, mi->xgwa.depth); + sp->image_loading_p = True; + load_image_async (ScreenOfDisplay (MI_DISPLAY(mi), 0/*####MI_SCREEN(mi)*/), + MI_WINDOW(mi), p, image_loaded_cb, mi); + } +#endif +} + +static int +quantize(double d) +{ + int i = (int) floor(d); + double f = d - i; + + if ((LRAND() & 0xff) < f * 0xff) + i++; + return i; +} + +ENTRYPOINT void +reshape_slip (ModeInfo * mi, int w, int h) +{ + slipstruct *sp = &slips[MI_SCREEN(mi)]; + sp->width = w; + sp->height = h; + sp->blit_width = sp->width / 25; + sp->blit_height = sp->height / 25; + + sp->mode = 0; + sp->nblits_remaining = 0; +} + +ENTRYPOINT void +init_slip (ModeInfo * mi) +{ + slipstruct *sp; + + if (slips == NULL) { + if ((slips = (slipstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (slipstruct))) == NULL) + return; + } + sp = &slips[MI_SCREEN(mi)]; + + sp->nblits_remaining = 0; + sp->mode = 0; + sp->first_time = 1; + + /* no "NoExpose" events from XCopyArea wanted */ + XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False); + + reshape_slip (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); +} + +ENTRYPOINT void +draw_slip (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + int timer; + slipstruct *sp; + + if (slips == NULL) + return; + sp = &slips[MI_SCREEN(mi)]; + + timer = MI_COUNT(mi) * MI_CYCLES(mi); + + MI_IS_DRAWN(mi) = True; + + while (timer--) { + int xi = halfrandom(sp, MAX(sp->width - sp->blit_width, 1)); + int yi = halfrandom(sp, MAX(sp->height - sp->blit_height, 1)); + double x, y, dx = 0, dy = 0, t, s1, s2; + + if (0 == sp->nblits_remaining--) { + static const int lut[] = {0, 0, 0, 1, 1, 1, 2}; + + prepare_screen(mi, sp); + sp->nblits_remaining = MI_COUNT(mi) * + (2000 + halfrandom(sp, 1000) + halfrandom(sp, 1000)); + if (sp->mode == 2) + sp->mode = halfrandom(sp, 2); + else + sp->mode = lut[halfrandom(sp, 7)]; + } + x = (2 * xi + sp->blit_width) / (double) sp->width - 1; + y = (2 * yi + sp->blit_height) / (double) sp->height - 1; + + /* (x,y) is in biunit square */ + switch (sp->mode) { + case 0: /* rotor */ + dx = x; + dy = y; + + if (dy < 0) { + dy += 0.04; + if (dy > 0) + dy = 0.00; + } + if (dy > 0) { + dy -= 0.04; + if (dy < 0) + dy = 0.00; + } + t = dx * dx + dy * dy + 1e-10; + s1 = 2 * dx * dx / t - 1; + s2 = 2 * dx * dy / t; + dx = s1 * 5; + dy = s2 * 5; + + if (sp->backwards) { /* jwz: go the other way sometimes */ + dx = -dx; + dy = -dy; + } + break; + case 1: /* shuffle */ + dx = erandom(sp, 3); + dy = erandom(sp, 3); + break; + case 2: /* explode */ + dx = x * 3; + dy = y * 3; + break; + } + { + int qx = xi + quantize(dx), qy = yi + quantize(dy); + int wrap; + + if (qx < 0 || qy < 0 || + qx >= sp->width - sp->blit_width || + qy >= sp->height - sp->blit_height) + continue; + +/*- +Seems to cause problems using Exceed +with PseudoColor +X Error of failed request: BadGC (invalid GC parameter) +with TrueColor +X Error of failed request: BadDrawable (invalid Pixmap or Window parameter) + Major opcode of failed request: 62 (X_CopyArea) + */ + XCopyArea(display, window, window, gc, xi, yi, + sp->blit_width, sp->blit_height, + qx, qy); + switch (sp->mode) { + case 0: + /* wrap */ + wrap = sp->width - (2 * sp->blit_width); + if (qx > wrap ) { + XCopyArea(display, window, window, gc, qx, qy, + sp->blit_width, sp->blit_height, + qx - wrap, qy); + } + if (qx < 2 * sp->blit_width) { + XCopyArea(display, window, window, gc, qx, qy, + sp->blit_width, sp->blit_height, + qx + wrap, qy); + } + wrap = sp->height - (2 * sp->blit_height); + if (qy > wrap) { + XCopyArea(display, window, window, gc, qx, qy, + sp->blit_width, sp->blit_height, + qx, qy - wrap); + } + if (qy < 2 * sp->blit_height) { + XCopyArea(display, window, window, gc, qx, qy, + sp->blit_width, sp->blit_height, + qx, qy + wrap); + } + break; + case 1: + case 2: + break; + } + } + } +} + +ENTRYPOINT void +release_slip (ModeInfo * mi) +{ + if (slips != NULL) { + (void) free((void *) slips); + slips = (slipstruct *) NULL; + } +} + +XSCREENSAVER_MODULE ("Slip", slip) + +#endif /* MODE_slip */ diff --git a/non-wgl/slip.vcproj b/non-wgl/slip.vcproj new file mode 100644 index 0000000..3b5b126 --- /dev/null +++ b/non-wgl/slip.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/speedmine.c b/non-wgl/speedmine.c new file mode 100644 index 0000000..753a73b --- /dev/null +++ b/non-wgl/speedmine.c @@ -0,0 +1,1726 @@ +/* -*- Mode: C; c-basic-offset: 4; tab-width: 4 -*- + * speedmine, Copyright (C) 2001 Conrad Parker + * + * 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. + */ + +/* + * Written mostly over the Easter holiday, 2001. Psychedelic option due to + * a night at Home nightclub, Sydney. Three all-nighters of solid partying + * were involved in the week this hack was written. + * + * Happy Birthday to WierdArms (17 April) and Pat (18 April) + */ + +/* + * Hacking notes + * + * This program generates a rectangular terrain grid and maps this onto + * a semi-circular tunnel. The terrain has length TERRAIN_LENGTH, which + * corresponds to length along the tunnel, and breadth TERRAIN_BREADTH, + * which corresponds to circumference around the tunnel. For each frame, + * the tunnel is perspective mapped onto a set of X and Y screen values. + * + * Throughout this code the following temporary variable names are used: + * + * i iterates along the tunnel in the direction of travel + * j iterates around the tunnel clockwise + * t iterates along the length of the perspective mapped values + * from the furthest to the nearest + * + * Thus, the buffers are used with these iterators: + * + * terrain[i][j] terrain map + * worldx[i][j], worldy[i][j] world coordinates (after wrapping) + * {x,y,z}curvature[i] tunnel curvature + * wideness[i] tunnel wideness + * bonuses[i] bonus values + * + * xvals[t][j], yvals[t][j] screen coordinates + * {min,max}{x,y}[t] bounding boxes of screen coords + */ + +/* Define or undefine NDEBUG to turn assert and abort debugging off or on */ +//#define NDEBUG + +#include "screenhack.h" +#include + +#include + +#include "erase.h" + +Bool verbose = False; +Bool worm = False; +Bool wire = False; +char *background = "black"; +char *foreground = "white"; +char *darkground = "#101010"; +char *lightground = "#a0a0a0"; +char *tunnelend = "#000000"; +int delay = 30000; +int maxspeed = 700; +float thrust = 1.0; +float gravity = 9.8; +float vertigo = 1.0; +Bool terrain = True; +int smoothness = 6; +float curviness = 1.0; +float twistiness = 1.0; +Bool widening = True; +Bool bumps = True; +Bool bonuses = True; +Bool crosshair = True; +Bool psychedelic = False; + +static argtype vars[] = +{ + {&verbose, "verbose", NULL, "False", t_Bool}, + {&worm, "worm", NULL, "False", t_Bool}, + {&wire, "wire", NULL, "False", t_Bool}, + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&darkground, "darkground", NULL, "#101010", t_String}, + {&lightground, "lightground", NULL, "#a0a0a0", t_String}, + {&tunnelend, "tunnelend", NULL, "#000000", t_String}, + {&delay, "delay", NULL, "30000", t_Int}, + {&maxspeed, "maxspeed", NULL, "700", t_Int}, + {&thrust, "thrust", NULL, "1.0", t_Float}, + {&gravity, "gravity", NULL, "9.8", t_Float}, + {&vertigo, "vertigo", NULL, "1.0", t_Float}, + {&terrain, "terrain", NULL, "True", t_Bool}, + {&smoothness, "smoothness", NULL, "6", t_Int}, + {&curviness, "curviness", NULL, "1.0", t_Float}, + {&twistiness, "twistiness", NULL, "1.0", t_Float}, + {&widening, "widening", NULL, "True", t_Bool}, + {&bumps, "bumps", NULL, "True", t_Bool}, + {&bonuses, "bonuses", NULL, "True", t_Bool}, + {&crosshair, "crosshair", NULL, "True", t_Bool}, + {&psychedelic, "psychedelic", NULL, "False", t_Bool}, +}; + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) + +#define RAND(r) (int)(((r)>0)?(random() % (long)(r)): -(random() % (long)(-r))) + +#define SIGN3(a) ((a)>0?1:((a)<0?-1:0)) + +#define MODULO(a,b) while ((a)<0) (a)+=(b); (a) %= (b); + +/* No. of shades of each color (ground, walls, bonuses) */ +#define MAX_COLORS 32 + +#ifdef NDEBUG +#define DEBUG_FLAG 0 +#else +#define DEBUG_FLAG 1 +#endif + + +#define FORWARDS 1 +#define BACKWARDS -1 +/* Apparently AIX's math.h bogusly defines `nearest' as a function, + in violation of the ANSI C spec. */ +#undef nearest +#define nearest n3arest + +#define wireframe (st->wire_flag||st->wire_bonus>8||st->wire_bonus%2==1) +#define effective_speed (st->direction*(st->speed+st->speed_bonus)) + +/* No. of levels of interpolation, for perspective */ +#define INTERP 32 + +/* These must be powers of 2 */ +#define TERRAIN_LENGTH 256 +#define TERRAIN_BREADTH 32 + +/* total "perspective distance" of terrain */ +#define TERRAIN_PDIST (INTERP*TERRAIN_LENGTH) + +#define ROTS 1024 +#define TB_MUL (ROTS/TERRAIN_BREADTH) + +#define random_elevation() (st->terrain_flag?(random() % 200):0) +#define random_curvature() (st->curviness>0.0?((double)(random() % 40)-20)*st->curviness:0.0) +#define random_twist() (st->twistiness>0.0?((double)(random() % 40)-20)*st->twistiness:0.0) +#define random_wideness() (st->widening_flag?(int)(random() % 1200):0) + +#define STEEL_ELEVATION 300 + +struct state { + Display *dpy; + Window window; + + Pixmap dbuf, stars_mask; + Colormap cmap; + Visual *visual; + Screen *screen; + unsigned int default_fg_pixel; + GC draw_gc, erase_gc, tunnelend_gc, stars_gc, stars_erase_gc; + + int ncolors, nr_ground_colors, nr_wall_colors, nr_bonus_colors; + XColor ground_colors[MAX_COLORS], wall_colors[MAX_COLORS]; + XColor bonus_colors[MAX_COLORS]; + GC ground_gcs[MAX_COLORS], wall_gcs[MAX_COLORS], bonus_gcs[MAX_COLORS]; + + int be_wormy; + + int width, height; + int delay; + + int smoothness; + int verbose_flag; + int wire_flag; + int terrain_flag; + int widening_flag; + int bumps_flag; + int bonuses_flag; + int crosshair_flag; + int psychedelic_flag; + + double maxspeed; + + double thrust, gravity; + + double vertigo; + double curviness; + double twistiness; + + double pos; + double speed; + double accel; + double step; + + int direction; + + int pindex, nearest; + int flipped_at; + int xoffset, yoffset; + + int bonus_bright; + int wire_bonus; + + double speed_bonus; + + int spin_bonus; + int backwards_bonus; + + double sintab[ROTS], costab[ROTS]; + + int orientation; + + int terrain[TERRAIN_LENGTH][TERRAIN_BREADTH]; + double xcurvature[TERRAIN_LENGTH]; + double ycurvature[TERRAIN_LENGTH]; + double zcurvature[TERRAIN_LENGTH]; + int wideness[TERRAIN_LENGTH]; + int bonuses[TERRAIN_LENGTH]; + int xvals[TERRAIN_LENGTH][TERRAIN_BREADTH]; + int yvals[TERRAIN_LENGTH][TERRAIN_BREADTH]; + double worldx[TERRAIN_LENGTH][TERRAIN_BREADTH]; + double worldy[TERRAIN_LENGTH][TERRAIN_BREADTH]; + int minx[TERRAIN_LENGTH], maxx[TERRAIN_LENGTH]; + int miny[TERRAIN_LENGTH], maxy[TERRAIN_LENGTH]; + + int total_nframes; + int nframes; + double fps; + double fps_start, fps_end; + struct timeval start_time; + + int rotation_offset; + int jamming; +}; + +/* a forward declaration ... */ +static void change_colors(struct state *st); + + + +/* + * get_time () + * + * returns the total time elapsed since the beginning of the demo + */ +static double get_time(struct state *st) { + struct timeval t; + float f; +#if GETTIMEOFDAY_TWO_ARGS + gettimeofday(&t, NULL); +#else + gettimeofday(&t); +#endif + t.tv_sec -= st->start_time.tv_sec; + f = ((double)t.tv_sec) + t.tv_usec*1e-6; + return f; +} + +/* + * init_time () + * + * initialises the timing structures + */ +static void init_time(struct state *st) { +#if GETTIMEOFDAY_TWO_ARGS + gettimeofday(&st->start_time, NULL); +#else + gettimeofday(&st->start_time); +#endif + st->fps_start = get_time(st); +} + + +/* + * perspective() + * + * perspective map the world coordinates worldx[i][j], worldy[i][j] onto + * screen coordinates xvals[t][j], yvals[t][j] + */ +static void +perspective (struct state *st) +{ + int i, j, jj, t=0, depth, view_pos; + int rotation_bias, r; + double xc=0.0, yc=0.0, zc=0.0; + double xcc=0.0, ycc=0.0, zcc=0.0; + double xx, yy; + double zfactor, zf; + + zf = 8.0*28.0 / (double)(st->width*TERRAIN_LENGTH); + if (st->be_wormy) zf *= 3.0; + + depth = TERRAIN_PDIST - INTERP + st->pindex; + + view_pos = (st->nearest+3*TERRAIN_LENGTH/4)%TERRAIN_LENGTH; + + st->xoffset += - st->xcurvature[view_pos]*st->curviness/8; + st->xoffset /= 2; + + st->yoffset += - st->ycurvature[view_pos]*st->curviness/4; + st->yoffset /= 2; + + st->rotation_offset += (int)((st->zcurvature[view_pos]-st->zcurvature[st->nearest])*ROTS/8); + st->rotation_offset /= 2; + rotation_bias = st->orientation + st->spin_bonus - st->rotation_offset; + + if (st->bumps_flag) { + if (st->be_wormy) { + st->yoffset -= ((st->terrain[view_pos][TERRAIN_BREADTH/4] * st->width /(8*1600))); + rotation_bias += (st->terrain[view_pos][TERRAIN_BREADTH/4+2] - + st->terrain[view_pos][TERRAIN_BREADTH/4-2])/8; + } else { + st->yoffset -= ((st->terrain[view_pos][TERRAIN_BREADTH/4] * st->width /(2*1600))); + rotation_bias += (st->terrain[view_pos][TERRAIN_BREADTH/4+2] - + st->terrain[view_pos][TERRAIN_BREADTH/4-2])/16; + } + } + + MODULO(rotation_bias, ROTS); + + for (t=0; t < TERRAIN_LENGTH; t++) { + i = st->nearest + t; MODULO(i, TERRAIN_LENGTH); + xc += st->xcurvature[i]; yc += st->ycurvature[i]; zc += st->zcurvature[i]; + xcc += xc; ycc += yc; zcc += zc; + st->maxx[i] = st->maxy[i] = 0; + st->minx[i] = st->width; st->miny[i] = st->height; + } + + for (t=0; t < TERRAIN_LENGTH; t++) { + i = st->nearest - 1 - t; MODULO(i, TERRAIN_LENGTH); + + zfactor = (double)depth* (12.0 - TERRAIN_LENGTH/8.0) * zf; + for (j=0; j < TERRAIN_BREADTH; j++) { + jj = st->direction * j; MODULO(jj, TERRAIN_BREADTH); + /* jwz: not totally sure if this is right, but it avoids div0 */ + if (zfactor != 0) { + xx = (st->worldx[i][jj]-(st->vertigo*xcc))/zfactor; + yy = (st->worldy[i][j]-(st->vertigo*ycc))/zfactor; + } else { + xx = 0; + yy = 0; + } + r = rotation_bias + (int)(st->vertigo*zcc); MODULO(r, ROTS); + + st->xvals[t][j] = st->xoffset + (st->width>>1) + + (int)(xx * st->costab[r] - yy * st->sintab[r]); + st->maxx[t] = MAX(st->maxx[t], st->xvals[t][j]); + st->minx[t] = MIN(st->minx[t], st->xvals[t][j]); + + st->yvals[t][j] = st->yoffset + st->height/2 + + (int)(xx * st->sintab[r] + yy * st->costab[r]); + st->maxy[t] = MAX(st->maxy[t], st->yvals[t][j]); + st->miny[t] = MIN(st->miny[t], st->yvals[t][j]); + } + xcc -= xc; ycc -= yc; zcc -= zc; + xc -= st->xcurvature[i]; yc -= st->ycurvature[i]; zc -= st->zcurvature[i]; + depth -= INTERP; + } +} + +/* + * wrap_tunnel (start, end) + * + * wrap the terrain terrain[i][j] around the semi-circular tunnel function + * + * x' = x/2 * cos(theta) - (y-k) * x * sin(theta) + * y' = x/4 * sin(theta) + y * cos(theta) + * + * between i=start and i=end inclusive, producing world coordinates + * worldx[i][j], worldy[i][j] + */ +static void +wrap_tunnel (struct state *st, int start, int end) +{ + int i, j, v; + double x, y; + + assert (start < end); + + for (i=start; i <= end; i++) { + for (j=0; j < TERRAIN_BREADTH; j++) { + x = j * (1.0/TERRAIN_BREADTH); + v = st->terrain[i][j]; + y = (double)(v==STEEL_ELEVATION?200:v) - st->wideness[i] - 1200; + + /* lower road */ + if (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8) y -= 300; + + st->worldx[i][j] = x/2 * st->costab[j*TB_MUL] - + (y-st->height/4.0)*x*st->sintab[j*TB_MUL]; + st->worldy[i][j] = x/4 * st->sintab[j*TB_MUL] + + y * st->costab[j*TB_MUL]; + } + } +} + +/* + * flip_direction() + * + * perform the state transitions and terrain transformation for the + * "look backwards/look forwards" bonus + */ +static void +flip_direction (struct state *st) +{ + int i, ip, in, j, t; + + st->direction = -st->direction; + + st->bonus_bright = 20; + + for (i=0; i < TERRAIN_LENGTH; i++) { + in = st->nearest + i; MODULO(in, TERRAIN_BREADTH); + ip = st->nearest - i; MODULO(ip, TERRAIN_BREADTH); + for (j=0; j < TERRAIN_BREADTH; j++) { + t = st->terrain[ip][j]; + st->terrain[ip][j] = st->terrain[in][j]; + st->terrain[in][j] = t; + } + } +} + +/* + * generate_smooth (start, end) + * + * generate smooth terrain between i=start and i=end inclusive + */ +static void +generate_smooth (struct state *st, int start, int end) +{ + int i,j, ii; + + assert (start < end); + + for (i=start; i <= end; i++) { + ii = i; MODULO(ii, TERRAIN_LENGTH); + for (j=0; j < TERRAIN_BREADTH; j++) { + st->terrain[i][j] = STEEL_ELEVATION; + } + } +} + +/* + * generate_straight (start, end) + * + * zero the curvature and wideness between i=start and i=end inclusive + */ +static void +generate_straight (struct state *st, int start, int end) +{ + int i,j, ii; + + assert (start < end); + + for (i=start; i <= end; i++) { + ii = i; MODULO(ii, TERRAIN_LENGTH); + for (j=0; j < TERRAIN_BREADTH; j++) { + st->xcurvature[ii] = 0; + st->ycurvature[ii] = 0; + st->zcurvature[ii] = 0; + st->wideness[ii] = 0; + } + } +} + +/* + * int generate_terrain_value (v1, v2, v3, v4, w) + * + * generate terrain value near the average of v1, v2, v3, v4, with + * perturbation proportional to w + */ +static int +generate_terrain_value (struct state *st, int v1, int v2, int v3, int v4, int w) +{ + int sum, ret; + int rval; + + if (!st->terrain_flag) return 0; + + sum = v1 + v2 + v3 + v4; + + rval = w*sum/st->smoothness; + if (rval == 0) rval = 2; + + ret = (sum/4 -(rval/2) + RAND(rval)); + + if (ret < -400 || ret > 400) { + ret = sum/4; + } + + return ret; +} + +/* + * generate_terrain (start, end, final) + * + * generate terrain[i][j] between i=start and i=end inclusive + * + * This is performed by successive subdivision of the terrain into + * rectangles of decreasing size. Subdivision continues until the + * the minimum width or height of these rectangles is 'final'; ie. + * final=1 indicates to subdivide as far as possible, final=2 indicates + * to stop one subdivision before that (leaving a checkerboard pattern + * uncalculated) etc. + */ +static void +generate_terrain (struct state *st, int start, int end, int final) +{ + int i,j,w,l; + int ip, jp, in, jn; /* prev, next values */ + int diff; + + assert (start < end); + assert (start >= 0 && start < TERRAIN_LENGTH); + assert (end >= 0 && end < TERRAIN_LENGTH); + + diff = end - start + 1; + + st->terrain[end][0] = random_elevation(); + st->terrain[end][TERRAIN_BREADTH/2] = random_elevation(); + + for (w= diff/2, l=TERRAIN_BREADTH/4; + w >= final || l >= final; w /= 2, l /= 2) { + + if (w<1) w=1; if (l<1) l=1; + + for (i=start+w-1; i < end; i += (w*2)) { + ip = i-w; MODULO(ip, TERRAIN_LENGTH); + in = i+w; MODULO(in, TERRAIN_LENGTH); + for (j=l-1; j < TERRAIN_BREADTH; j += (l*2)) { + jp = j-1; MODULO(jp, TERRAIN_BREADTH); + jn = j+1; MODULO(jn, TERRAIN_BREADTH); + st->terrain[i][j] = + generate_terrain_value (st, st->terrain[ip][jp], st->terrain[in][jp], + st->terrain[ip][jn], st->terrain[in][jn], w); + } + } + + for (i=start+(w*2)-1; i < end; i += (w*2)) { + ip = i-w; MODULO(ip, TERRAIN_LENGTH); + in = i+w; MODULO(in, TERRAIN_LENGTH); + for (j=l-1; j < TERRAIN_BREADTH; j += (l*2)) { + jp = j-1; MODULO(jp, TERRAIN_BREADTH); + jn = j+1; MODULO(jn, TERRAIN_BREADTH); + st->terrain[i][j] = + generate_terrain_value (st, st->terrain[ip][j], st->terrain[in][j], + st->terrain[i][jp], st->terrain[i][jn], w); + } + } + + for (i=start+w-1; i < end; i += (w*2)) { + ip = i-w; MODULO(ip, TERRAIN_LENGTH); + in = i+w; MODULO(in, TERRAIN_LENGTH); + for (j=2*l-1; j < TERRAIN_BREADTH; j += (l*2)) { + jp = j-1; MODULO(jp, TERRAIN_BREADTH); + jn = j+1; MODULO(jn, TERRAIN_BREADTH); + st->terrain[i][j] = + generate_terrain_value (st, st->terrain[ip][j], st->terrain[in][j], + st->terrain[i][jp], st->terrain[i][jn], w); + } + } + } +} + +/* + * double generate_curvature_value (v1, v2, w) + * + * generate curvature value near the average of v1 and v2, with perturbation + * proportional to w + */ +static double +generate_curvature_value (double v1, double v2, int w) +{ + double sum, avg, diff, ret; + int rval; + + //assert (!isnan(v1) && !isnan(v2)); + + sum = v1+v2; + avg = sum/2.0; + + diff = MIN(v1 - avg, v2 - avg); + + rval = (int)diff * w; + if (rval == 0.0) return avg; + + ret = (avg -((double)rval)/500.0 + ((double)RAND(rval))/1000.0); + + //assert (!isnan(ret)); + + return ret; +} + +/* + * generate_curves (start, end) + * + * generate xcurvature[i], ycurvature[i], zcurvature[i] and wideness[i] + * between start and end inclusive + */ +static void +generate_curves (struct state *st, int start, int end) +{ + int i, diff, ii, in, ip, w; + + assert (start < end); + + diff = end - start + 1; MODULO (diff, TERRAIN_LENGTH); + + if (random() % 100 == 0) + st->xcurvature[end] = 30 * random_curvature(); + else if (random() % 10 == 0) + st->xcurvature[end] = 20 * random_curvature(); + else + st->xcurvature[end] = 10 * random_curvature(); + + if (random() % 50 == 0) + st->ycurvature[end] = 20 * random_curvature(); + else if (random() % 25 == 0) + st->ycurvature[end] = 30 * random_curvature(); + else + st->ycurvature[end] = 10 * random_curvature(); + + if (random() % 3 == 0) + st->zcurvature[end] = random_twist(); + else + st->zcurvature[end] = + generate_curvature_value (st->zcurvature[end], random_twist(), 1); + + if (st->be_wormy) + st->wideness[end] = random_wideness(); + else + st->wideness[end] = + generate_curvature_value (st->wideness[end], random_wideness(), 1); + + for (w=diff/2; w >= 1; w /= 2) { + for (i=start+w-1; i < end; i+=(w*2)) { + ii = i; MODULO (ii, TERRAIN_LENGTH); + ip = i-w; MODULO (ip, TERRAIN_LENGTH); + in = i+w; MODULO (in, TERRAIN_LENGTH); + st->xcurvature[ii] = + generate_curvature_value (st->xcurvature[ip], st->xcurvature[in], w); + st->ycurvature[ii] = + generate_curvature_value (st->ycurvature[ip], st->ycurvature[in], w); + st->zcurvature[ii] = + generate_curvature_value (st->zcurvature[ip], st->zcurvature[in], w); + st->wideness[ii] = + generate_curvature_value (st->wideness[ip], st->wideness[in], w); + } + } +} + +/* + * do_bonus () + * + * choose a random bonus and perform its state transition + */ +static void +do_bonus (struct state *st) +{ + st->bonus_bright = 20; + + if (st->jamming > 0) { + st->jamming--; + st->nearest -= 2; MODULO(st->nearest, TERRAIN_LENGTH); + return; + } + + if (st->psychedelic_flag) change_colors(st); + + switch (random() % 7) { + case 0: /* switch to or from wireframe */ + st->wire_bonus = (st->wire_bonus?0:300); + break; + case 1: /* speedup */ + st->speed_bonus = 40.0; + break; + case 2: + st->spin_bonus += ROTS; + break; + case 3: + st->spin_bonus -= ROTS; + break; + case 4: /* look backwards / look forwards */ + st->flipped_at = st->nearest; + flip_direction (st); + st->backwards_bonus = (st->backwards_bonus?0:10); + break; + case 5: + change_colors(st); + break; + case 6: /* jam against the bonus a few times; deja vu! */ + st->nearest -= 2; MODULO(st->nearest, TERRAIN_LENGTH); + st->jamming = 3; + break; + default: + assert(0); + break; + } +} + +/* + * check_bonus () + * + * check if a bonus has been passed in the last frame, and handle it + */ +static void +check_bonuses (struct state *st) +{ + int i, ii, start, end; + + if (!st->bonuses_flag) return; + + if (st->step >= 0.0) { + start = st->nearest; end = st->nearest + (int)floor(st->step); + } else { + end = st->nearest; start = st->nearest + (int)floor(st->step); + } + + if (st->be_wormy) { + start += TERRAIN_LENGTH/4; + end += TERRAIN_LENGTH/4; + } + + for (i=start; i < end; i++) { + ii = i; MODULO(ii, TERRAIN_LENGTH); + if (st->bonuses[ii] == 1) do_bonus (st); + } +} + +/* + * decrement_bonuses (double time_per_frame) + * + * decrement timers associated with bonuses + */ +static void +decrement_bonuses (struct state *st, double time_per_frame) +{ + if (!st->bonuses_flag) return; + + if (st->bonus_bright > 0) st->bonus_bright-=4; + if (st->wire_bonus > 0) st->wire_bonus--; + if (st->speed_bonus > 0) st->speed_bonus -= 2.0; + + if (st->spin_bonus > 10) st->spin_bonus -= (int)(st->step*13.7); + else if (st->spin_bonus < -10) st->spin_bonus += (int)(st->step*11.3); + + if (st->backwards_bonus > 1) st->backwards_bonus--; + else if (st->backwards_bonus == 1) { + st->nearest += 2*(MAX(st->flipped_at, st->nearest) - MIN(st->flipped_at,st->nearest)); + MODULO(st->nearest, TERRAIN_LENGTH); + flip_direction (st); + st->backwards_bonus = 0; + } +} + +/* + * set_bonuses (start, end) + * + * choose if to and where to set a bonus between i=start and i=end inclusive + */ +static void +set_bonuses (struct state *st, int start, int end) +{ + int i, diff, ii; + + if (!st->bonuses_flag) return; + + assert (start < end); + + diff = end - start; + + for (i=start; i <= end; i++) { + ii = i; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH; + st->bonuses[ii] = 0; + } + if (random() % 4 == 0) { + i = start + RAND(diff-3); + ii = i; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH; + st->bonuses[ii] = 2; /* marker */ + ii = i+3; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH; + st->bonuses[ii] = 1; /* real thing */ + } +} + +/* + * regenerate_terrain () + * + * regenerate a portion of the terrain map of length TERRAIN_LENGTH/4 iff + * we just passed between two quarters of the terrain. + * + * choose the kind of terrain to produce, produce it and wrap the tunnel + */ +static void +regenerate_terrain (struct state *st) +{ + int start, end; + int passed; + + passed = st->nearest % (TERRAIN_LENGTH/4); + + if (st->speed == 0.0 || + (st->speed > 0.0 && passed > (int)st->step) || + (st->speed < 0.0 && (TERRAIN_LENGTH/4)-passed > (int)fabs(st->step))) { + + return; + } + + end = st->nearest - passed - 1; MODULO(end, TERRAIN_LENGTH); + start = end - TERRAIN_LENGTH/4 + 1; MODULO(start, TERRAIN_LENGTH); + + if (DEBUG_FLAG) printf ("Regenerating [%d - %d]\n", start, end); + + set_bonuses (st, start, end); + + switch (random() % 64) { + case 0: + case 1: + generate_terrain (st, start, end, 1); + generate_smooth (st, start, + start + TERRAIN_LENGTH/8 + (random() % TERRAIN_LENGTH/8)); + break; + case 2: + generate_smooth (st, start, end); + generate_terrain (st, start, end, 4); break; + case 3: + generate_smooth (st, start, end); + generate_terrain (st, start, end, 2); break; + default: + generate_terrain (st, start, end, 1); + } + + if (random() % 16 == 0) { + generate_straight (st, start, end); + } else { + generate_curves (st, start, end); + } + + wrap_tunnel (st, start, end); +} + +/* + * init_terrain () + * + * initialise the terrain map for the beginning of the demo + */ +static void +init_terrain (struct state *st) +{ + int i, j; + + for (i=0; i < TERRAIN_LENGTH; i++) { + for (j=0; j < TERRAIN_BREADTH; j++) { + st->terrain[i][j] = 0; + } + } + + st->terrain[TERRAIN_LENGTH-1][0] = - (random() % 300); + st->terrain[TERRAIN_LENGTH-1][TERRAIN_BREADTH/2] = - (random() % 300); + + generate_smooth (st, 0, TERRAIN_LENGTH-1); + generate_terrain (st, 0, TERRAIN_LENGTH/4 -1, 4); + generate_terrain (st, TERRAIN_LENGTH/4, TERRAIN_LENGTH/2 -1, 2); + generate_terrain (st, TERRAIN_LENGTH/2, 3*TERRAIN_LENGTH/4 -1, 1); + generate_smooth (st, 3*TERRAIN_LENGTH/4, TERRAIN_LENGTH-1); +} + +/* + * init_curves () + * + * initialise the curvatures and wideness for the beginning of the demo. + */ +static void +init_curves (struct state *st) +{ + int i; + + for (i=0; i < TERRAIN_LENGTH-1; i++) { + st->xcurvature[i] = 0.0; + st->ycurvature[i] = 0.0; + st->zcurvature[i] = 0.0; + } + + st->xcurvature[TERRAIN_LENGTH-1] = random_curvature(); + st->ycurvature[TERRAIN_LENGTH-1] = random_curvature(); + st->zcurvature[TERRAIN_LENGTH-1] = random_twist(); + + generate_straight (st, 0, TERRAIN_LENGTH/4-1); + generate_curves (st, TERRAIN_LENGTH/4, TERRAIN_LENGTH/2-1); + generate_curves (st, TERRAIN_LENGTH/2, 3*TERRAIN_LENGTH/4-1); + generate_straight (st, 3*TERRAIN_LENGTH/4, TERRAIN_LENGTH-1); + +} + +/* + * render_quads (dpy, d, t, dt, i) + * + * renders the quadrilaterals from perspective depth t to t+dt. + * i is passed as a hint, where i corresponds to t as asserted. + */ +static void +render_quads (struct state *st, Drawable d, int t, int dt, int i) +{ + int j, t2, j2, in; + int index; + XPoint points[4]; + GC gc; + + assert (i == (st->nearest - (t + dt) + TERRAIN_LENGTH) % TERRAIN_LENGTH); + + in = i + 1; MODULO(in, TERRAIN_LENGTH); + + for (j=0; j < TERRAIN_BREADTH; j+=dt) { + t2 = t+dt; if (t2 >= TERRAIN_LENGTH) t2 -= TERRAIN_LENGTH; + j2 = j+dt; if (j2 >= TERRAIN_BREADTH) j2 -= TERRAIN_BREADTH; + points[0].x = st->xvals[t][j]; points[0].y = st->yvals[t][j]; + points[1].x = st->xvals[t2][j]; points[1].y = st->yvals[t2][j]; + points[2].x = st->xvals[t2][j2]; points[2].y = st->yvals[t2][j2]; + points[3].x = st->xvals[t][j2]; points[3].y = st->yvals[t][j2]; + + index = st->bonus_bright + st->ncolors/3 + + t*(t*INTERP + st->pindex) * st->ncolors / + (3*TERRAIN_LENGTH*TERRAIN_PDIST); + if (!wireframe) { + index += (int)((points[0].y - points[3].y) / 8); + index += (int)((st->worldx[i][j] - st->worldx[in][j]) / 40); + index += (int)((st->terrain[in][j] - st->terrain[i][j]) / 100); + } + if (st->be_wormy && st->psychedelic_flag) index += st->ncolors/4; + + if (st->ncolors > MAX_COLORS) abort(); + index = MIN (index, st->ncolors-1); + index = MAX (index, 0); + + if (st->bonuses[i]) { + XSetClipMask (st->dpy, st->bonus_gcs[index], None); + } + + if (wireframe) { + if (st->bonuses[i]) gc = st->bonus_gcs[index]; + else gc = st->ground_gcs[index]; + XDrawLines (st->dpy, d, gc, points, 4, CoordModeOrigin); + } else { + if (st->bonuses[i]) + gc = st->bonus_gcs[index]; + else if ((st->direction>0 && j < TERRAIN_BREADTH/8) || + (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8-1) || + (st->direction < 0 && j > 3*TERRAIN_BREADTH/8-1 && + j < TERRAIN_BREADTH/2) || + st->terrain[i][j] == STEEL_ELEVATION || + st->wideness[in] - st->wideness[i] > 200) + gc = st->ground_gcs[index]; + else + gc = st->wall_gcs[index]; + + XFillPolygon (st->dpy, d, gc, points, 4, Nonconvex, CoordModeOrigin); + } + } +} + +/* + * render_pentagons (dpy, d, t, dt, i) + * + * renders the pentagons from perspective depth t to t+dt. + * i is passed as a hint, where i corresponds to t as asserted. + */ +static void +render_pentagons (struct state *st, Drawable d, int t, int dt, int i) +{ + int j, t2, j2, j3, in; + int index; + XPoint points[5]; + GC gc; + + assert (i == (st->nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH); + + in = i + 1; MODULO(in, TERRAIN_LENGTH); + + for (j=0; j < TERRAIN_BREADTH; j+=dt*2) { + t2 = t+(dt*2); if (t2 >= TERRAIN_LENGTH) t2 -= TERRAIN_LENGTH; + j2 = j+dt; if (j2 >= TERRAIN_BREADTH) j2 -= TERRAIN_BREADTH; + j3 = j+dt+dt; if (j3 >= TERRAIN_BREADTH) j3 -= TERRAIN_BREADTH; + points[0].x = st->xvals[t][j]; points[0].y = st->yvals[t][j]; + points[1].x = st->xvals[t2][j]; points[1].y = st->yvals[t2][j]; + points[2].x = st->xvals[t2][j2]; points[2].y = st->yvals[t2][j2]; + points[3].x = st->xvals[t2][j3]; points[3].y = st->yvals[t2][j3]; + points[4].x = st->xvals[t][j3]; points[4].y = st->yvals[t][j3]; + + index = st->bonus_bright + st->ncolors/3 + + t*(t*INTERP + st->pindex) * st->ncolors / + (3*TERRAIN_LENGTH*TERRAIN_PDIST); + if (!wireframe) { + index += (int)((points[0].y - points[3].y) / 8); + index += (int)((st->worldx[i][j] - st->worldx[in][j]) / 40); + index += (int)((st->terrain[in][j] - st->terrain[i][j]) / 100); + } + if (st->be_wormy && st->psychedelic_flag) index += st->ncolors/4; + + index = MIN (index, st->ncolors-1); + index = MAX (index, 0); + + if (st->bonuses[i]) { + XSetClipMask (st->dpy, st->bonus_gcs[index], None); + } + + if (wireframe) { + if (st->bonuses[i]) gc = st->bonus_gcs[index]; + else gc = st->ground_gcs[index]; + XDrawLines (st->dpy, d, gc, points, 5, CoordModeOrigin); + } else { + if (st->bonuses[i]) + gc = st->bonus_gcs[index]; + else if (j < TERRAIN_BREADTH/8 || + (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8-1) || + st->terrain[i][j] == STEEL_ELEVATION || + st->wideness[in] - st->wideness[i] > 200) + gc = st->ground_gcs[index]; + else + gc = st->wall_gcs[index]; + + XFillPolygon (st->dpy, d, gc, points, 5, Complex, CoordModeOrigin); + } + } +} + +/* + * render_block (dpy, d, gc, t) + * + * render a filled polygon at perspective depth t using the given GC + */ +static void +render_block (struct state *st, Drawable d, GC gc, int t) +{ + int i; + + XPoint erase_points[TERRAIN_BREADTH/2]; + + for (i=0; i < TERRAIN_BREADTH/2; i++) { + erase_points[i].x = st->xvals[t][i*2]; + erase_points[i].y = st->yvals[t][i*2]; + } + + XFillPolygon (st->dpy, d, gc, erase_points, + TERRAIN_BREADTH/2, Complex, CoordModeOrigin); +} + +/* + * regenerate_stars_mask (dpy, t) + * + * regenerate the clip mask 'stars_mask' for drawing the bonus stars at + * random positions within the bounding box at depth t + */ +static void +regenerate_stars_mask (struct state *st, int t) +{ + int i, w, h, a, b, l1, l2; + const int lim = st->width*TERRAIN_LENGTH/(300*(TERRAIN_LENGTH-t)); + + w = st->maxx[t] - st->minx[t]; + h = st->maxy[t] - st->miny[t]; + + if (w<6||h<6) return; + + XFillRectangle (st->dpy, st->stars_mask, st->stars_erase_gc, + 0, 0, st->width, st->height); + + l1 = (t>3*TERRAIN_LENGTH/4?2:1); + l2 = (t>7*TERRAIN_LENGTH/8?2:1); + + for (i=0; i < lim; i++) { + a = RAND(w); b = RAND(h); + XDrawLine (st->dpy, st->stars_mask, st->stars_gc, + st->minx[t]+a-l1, st->miny[t]+b, st->minx[t]+a+l1, st->miny[t]+b); + XDrawLine (st->dpy, st->stars_mask, st->stars_gc, + st->minx[t]+a, st->miny[t]+b-l1, st->minx[t]+a, st->miny[t]+b+l1); + } + for (i=0; i < lim; i++) { + a = RAND(w); b = RAND(h); + XDrawLine (st->dpy, st->stars_mask, st->stars_gc, + st->minx[t]+a-l2, st->miny[t]+b, st->minx[t]+a+l2, st->miny[t]+b); + XDrawLine (st->dpy, st->stars_mask, st->stars_gc, + st->minx[t]+a, st->miny[t]+b-l2, st->minx[t]+a, st->miny[t]+b+l2); + } +} + +/* + * render_bonus_block (dpy, d, t, i) + * + * draw the bonus stars at depth t. + * i is passed as a hint, where i corresponds to t as asserted. + */ +static void +render_bonus_block (struct state *st, Drawable d, int t, int i) +{ + int bt; + + assert (i == (st->nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH); + + if (!st->bonuses[i] || wireframe) return; + + regenerate_stars_mask (st, t); + + bt = t * st->nr_bonus_colors / (2*TERRAIN_LENGTH); + + XSetClipMask (st->dpy, st->bonus_gcs[bt], st->stars_mask); + + render_block (st, d, st->bonus_gcs[bt], t); +} + +static int +begin_at (struct state *st) +{ + int t; + int max_minx=0, min_maxx=st->width, max_miny=0, min_maxy=st->height; + + for (t=TERRAIN_LENGTH-1; t > 0; t--) { + max_minx = MAX (max_minx, st->minx[t]); + min_maxx = MIN (min_maxx, st->maxx[t]); + max_miny = MAX (max_miny, st->miny[t]); + min_maxy = MIN (min_maxy, st->maxy[t]); + + if (max_miny >= min_maxy || max_minx >= min_maxx) break; + } + + return t; +} + +/* + * render_speedmine (dpy, d) + * + * render the current frame. + */ +static void +render_speedmine (struct state *st, Drawable d) +{ + int t, i=st->nearest, dt=1; + GC gc; + + assert (st->nearest >= 0 && st->nearest < TERRAIN_LENGTH); + + if (st->be_wormy || wireframe) { + XFillRectangle (st->dpy, d, st->erase_gc, 0, 0, st->width, st->height); + + dt=4; + for (t=0; t < TERRAIN_LENGTH/4; t+=dt) { + render_bonus_block (st, d, t, i); + i -= dt; MODULO(i, TERRAIN_LENGTH); + render_quads (st, d, t, dt, i); + } + + assert (t == TERRAIN_LENGTH/4); + } else { + t = MAX(begin_at(st), TERRAIN_LENGTH/4); + /*t = TERRAIN_LENGTH/4; dt = 2; */ + /*dt = (t >= 3*TERRAIN_LENGTH/4 ? 1 : 2);*/ + i = (st->nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH; + render_block (st, d, st->tunnelend_gc, t); + } + + dt=2; + + if (t == TERRAIN_LENGTH/4) + render_pentagons (st, d, t, dt, i); + + for (; t < 3*TERRAIN_LENGTH/4; t+=dt) { + render_bonus_block (st, d, t, i); + i -= dt; MODULO(i, TERRAIN_LENGTH); + render_quads (st, d, t, dt, i); + } + + dt=1; + if (st->be_wormy) { + for (; t < TERRAIN_LENGTH-(1+(st->pindexpindexcrosshair_flag) { + gc = (wireframe ? st->bonus_gcs[st->nr_bonus_colors/2] : st->erase_gc); + XFillRectangle (st->dpy, d, gc, + st->width/2+(st->xoffset)-8, st->height/2+(st->yoffset*2)-1, 16, 3); + XFillRectangle (st->dpy, d, gc, + st->width/2+(st->xoffset)-1, st->height/2+(st->yoffset*2)-8, 3, 16); + } + +} + +/* + * move (step) + * + * move to the position for the next frame, and modify the state variables + * st->nearest, pindex, pos, speed + */ +static void +move (struct state *st) +{ + double dpos; + + st->pos += st->step; + dpos = SIGN3(st->pos) * floor(fabs(st->pos)); + + st->pindex += SIGN3(effective_speed) + INTERP; + while (st->pindex >= INTERP) { + st->nearest --; + st->pindex -= INTERP; + } + while (st->pindex < 0) { + st->nearest ++; + st->pindex += INTERP; + } + + st->nearest += dpos; MODULO(st->nearest, TERRAIN_LENGTH); + + st->pos -= dpos; + + st->accel = st->thrust + st->ycurvature[st->nearest] * st->gravity; + st->speed += st->accel; + if (st->speed > st->maxspeed) st->speed = st->maxspeed; + if (st->speed < -st->maxspeed) st->speed = -st->maxspeed; +} + +/* + * speedmine (dpy, window) + * + * do everything required for one frame of the demo + */ +static unsigned long +speedmine_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + double elapsed, time_per_frame = 0.04; + + regenerate_terrain (st); + + perspective (st); + + render_speedmine (st, st->dbuf); + if (st->dbuf != st->window) + XCopyArea (st->dpy, st->dbuf, st->window, st->draw_gc, 0, 0, st->width, st->height, 0, 0); + + st->fps_end = get_time(st); + st->nframes++; + st->total_nframes++; + + if (st->fps_end > st->fps_start + 0.5) { + elapsed = st->fps_end - st->fps_start; + st->fps_start = get_time(st); + + time_per_frame = elapsed / st->nframes - st->delay*1e-6; + st->fps = st->nframes / elapsed; + if (DEBUG_FLAG) { + printf ("%f s elapsed\t%3f s/frame\t%.1f FPS\n", elapsed, + time_per_frame, st->fps); + } + st->step = effective_speed * elapsed; + + st->nframes = 0; + } + + + move (st); + + decrement_bonuses (st, time_per_frame); + + check_bonuses (st); + + return st->delay; +} + +/* + * speedmine_color_ramp (dpy, gcs, colors, ncolors, s1, s2, v1, v2) + * + * generate a color ramp of up to *ncolors between randomly chosen hues, + * varying from saturation s1 to s2 and value v1 to v2, placing the colors + * in 'colors' and creating corresponding GCs in 'gcs'. + * + * The number of colors actually allocated is returned in ncolors. + */ +static void +speedmine_color_ramp (struct state *st, GC *gcs, XColor * colors, + int *ncolors, double s1, double s2, double v1, double v2) +{ + XGCValues gcv; + int h1, h2; + unsigned long flags; + int i; + + assert (st->ncolors >= 0); + assert (s1 >= 0.0 && s1 <= 1.0 && v1 >= 0.0 && v2 <= 1.0); + + if (st->psychedelic_flag) { + h1 = RAND(360); h2 = (h1 + 180) % 360; + } else { + h1 = h2 = RAND(360); + } + + make_color_ramp (st->screen, st->visual, st->cmap, + h1, s1, v1, h2, s2, v2, + colors, ncolors, False, True, False); + + flags = GCForeground; + for (i=0; i < *ncolors; i++) { + gcv.foreground = colors[i].pixel; + if (gcs[i]) XFreeGC (st->dpy, gcs[i]); + gcs[i] = XCreateGC (st->dpy, st->dbuf, flags, &gcv); + } + +} + +/* + * change_colors () + * + * perform the color changing bonus. New colors are allocated for the + * walls and bonuses, and if the 'psychedelic' option is set then new + * colors are also chosen for the ground. + */ +static void +change_colors (struct state *st) +{ + double s1, s2; + + if (st->psychedelic_flag) { + free_colors (st->screen, st->cmap, st->bonus_colors, st->nr_bonus_colors); + free_colors (st->screen, st->cmap, st->wall_colors, st->nr_wall_colors); + free_colors (st->screen, st->cmap, st->ground_colors, st->nr_ground_colors); + s1 = 0.4; s2 = 0.9; + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->ground_gcs, st->ground_colors, + &st->ncolors, 0.0, 0.8, 0.0, 0.9); + st->nr_ground_colors = st->ncolors; + } else { + free_colors (st->screen, st->cmap, st->bonus_colors, st->nr_bonus_colors); + free_colors (st->screen, st->cmap, st->wall_colors, st->nr_wall_colors); + st->ncolors = st->nr_ground_colors; + + s1 = 0.0; s2 = 0.6; + } + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->wall_gcs, st->wall_colors, &st->ncolors, + s1, s2, 0.0, 0.9); + st->nr_wall_colors = st->ncolors; + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->bonus_gcs, st->bonus_colors, &st->ncolors, + 0.6, 0.9, 0.4, 1.0); + st->nr_bonus_colors = st->ncolors; +} + +/* + * init_psychedelic_colors (dpy, window, cmap) + * + * initialise a psychedelic colormap + */ +static void +init_psychedelic_colors (struct state *st) +{ + XGCValues gcv; + + //gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "tunnelend", "TunnelEnd"); + gcv.foreground = load_color(st->dpy, st->cmap, tunnelend); + st->tunnelend_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->ground_gcs, st->ground_colors, &st->ncolors, + 0.0, 0.8, 0.0, 0.9); + st->nr_ground_colors = st->ncolors; + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->wall_gcs, st->wall_colors, &st->ncolors, + 0.0, 0.6, 0.0, 0.9); + st->nr_wall_colors = st->ncolors; + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->bonus_gcs, st->bonus_colors, &st->ncolors, + 0.6, 0.9, 0.4, 1.0); + st->nr_bonus_colors = st->ncolors; +} + +/* + * init_colors (dpy, window, cmap) + * + * initialise a normal colormap + */ +static void +init_colors (struct state *st) +{ + XGCValues gcv; + XColor dark, light; + int h1, h2; + double s1, s2, v1, v2; + unsigned long flags; + int i; + + //gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "tunnelend", "TunnelEnd"); + gcv.foreground = load_color(st->dpy, st->cmap, tunnelend); + st->tunnelend_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + + st->ncolors = MAX_COLORS; + + //dark.pixel = get_pixel_resource (st->dpy, st->cmap, "darkground", "DarkGround"); + dark.pixel = load_color(st->dpy, st->cmap, darkground); + XQueryColor (st->dpy, st->cmap, &dark); + + //light.pixel = get_pixel_resource (st->dpy, st->cmap, "lightground", "LightGround"); + light.pixel = load_color(st->dpy, st->cmap, lightground); + XQueryColor (st->dpy, st->cmap, &light); + + rgb_to_hsv (dark.red, dark.green, dark.blue, &h1, &s1, &v1); + rgb_to_hsv (light.red, light.green, light.blue, &h2, &s2, &v2); + make_color_ramp (st->screen, st->visual, st->cmap, + h1, s1, v1, h2, s2, v2, + st->ground_colors, &st->ncolors, False, True, False); + st->nr_ground_colors = st->ncolors; + + flags = GCForeground; + for (i=0; i < st->ncolors; i++) { + gcv.foreground = st->ground_colors[i].pixel; + st->ground_gcs[i] = XCreateGC (st->dpy, st->dbuf, flags, &gcv); + } + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->wall_gcs, st->wall_colors, &st->ncolors, + 0.0, 0.6, 0.0, 0.9); + st->nr_wall_colors = st->ncolors; + + st->ncolors = MAX_COLORS; + speedmine_color_ramp (st, st->bonus_gcs, st->bonus_colors, &st->ncolors, + 0.6, 0.9, 0.4, 1.0); + st->nr_bonus_colors = st->ncolors; +} + +/* + * print_stats () + * + * print out average FPS stats for the demo + */ +#if 0 +static void +print_stats (struct state *st) +{ + if (st->total_nframes >= 1) + printf ("Rendered %d frames averaging %f FPS\n", st->total_nframes, + st->total_nframes / get_time(st)); +} +#endif + +/* + * init_speedmine (dpy, window) + * + * initialise the demo + */ +static void * +speedmine_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + int i; + double th; + int wide; + + st->dpy = dpy; + st->window = window; + + st->speed = 1.1; + st->accel = 0.00000001; + st->direction = FORWARDS; + st->orientation = (17*ROTS)/22; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->cmap = xgwa.colormap; + st->visual = xgwa.visual; + st->screen = xgwa.screen; + st->width = xgwa.width; + st->height = xgwa.height; + + //st->verbose_flag = get_boolean_resource (st->dpy, "verbose", "Boolean"); + st->verbose_flag = verbose; + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + st->dbuf = st->window; +#else + st->dbuf = XCreatePixmap (st->dpy, st->window, st->width, st->height, xgwa.depth); +#endif + st->stars_mask = XCreatePixmap (st->dpy, st->window, st->width, st->height, 1); + + //gcv.foreground = st->default_fg_pixel = + // get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + gcv.foreground = st->default_fg_pixel = load_color(st->dpy, st->cmap, foreground); + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + gcv.foreground = 1; + st->stars_gc = XCreateGC (st->dpy, st->stars_mask, GCForeground, &gcv); + + //gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, st->cmap, background); + st->erase_gc = XCreateGC (st->dpy, st->dbuf, GCForeground, &gcv); + gcv.foreground = 0; + st->stars_erase_gc = XCreateGC (st->dpy, st->stars_mask, GCForeground, &gcv); + + //st->wire_flag = get_boolean_resource (st->dpy, "wire", "Boolean"); + st->wire_flag = wire; + + //st->psychedelic_flag = get_boolean_resource (st->dpy, "psychedelic", "Boolean"); + st->psychedelic_flag = psychedelic; + + //st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->delay = delay; + + //st->smoothness = get_integer_resource(st->dpy, "smoothness", "Integer"); + st->smoothness = smoothness; + if (st->smoothness < 1) st->smoothness = 1; + + //st->maxspeed = get_float_resource(st->dpy, "maxspeed", "Float"); + st->maxspeed = maxspeed; + st->maxspeed *= 0.01; + st->maxspeed = fabs(st->maxspeed); + + //st->thrust = get_float_resource(st->dpy, "thrust", "Float"); + st->thrust = thrust; + st->thrust *= 0.2; + + //st->gravity = get_float_resource(st->dpy, "gravity", "Float"); + st->gravity = gravity; + st->gravity *= 0.002/9.8; + + //st->vertigo = get_float_resource(st->dpy, "vertigo", "Float"); + st->vertigo = vertigo; + st->vertigo *= 0.2; + + //st->curviness = get_float_resource(st->dpy, "curviness", "Float"); + st->curviness = curviness; + st->curviness *= 0.25; + + //st->twistiness = get_float_resource(st->dpy, "twistiness", "Float"); + st->twistiness = twistiness; + st->twistiness *= 0.125; + +#if 1 + st->terrain_flag = terrain; + st->widening_flag = widening; + st->bumps_flag = bumps; + st->bonuses_flag = bonuses; + st->crosshair_flag = crosshair; + st->be_wormy = worm; +#else + st->terrain_flag = get_boolean_resource (st->dpy, "terrain", "Boolean"); + st->widening_flag = get_boolean_resource (st->dpy, "widening", "Boolean"); + st->bumps_flag = get_boolean_resource (st->dpy, "bumps", "Boolean"); + st->bonuses_flag = get_boolean_resource (st->dpy, "bonuses", "Boolean"); + st->crosshair_flag = get_boolean_resource (st->dpy, "crosshair", "Boolean"); + st->be_wormy = get_boolean_resource (st->dpy, "worm", "Boolean"); +#endif + if (st->be_wormy) { + st->maxspeed *= 1.43; + st->thrust *= 10; + st->gravity *= 3; + st->vertigo *= 0.5; + st->smoothness *= 2; + st->curviness *= 2; + st->twistiness *= 2; + st->psychedelic_flag = True; + st->crosshair_flag = False; + } + + if (st->psychedelic_flag) init_psychedelic_colors (st); + else init_colors (st); + + for (i=0; icostab[i] = cos(th); + st->sintab[i] = sin(th); + } + + wide = random_wideness(); + + for (i=0; i < TERRAIN_LENGTH; i++) { + st->wideness[i] = wide; + st->bonuses[i] = 0; + } + + init_terrain (st); + init_curves (st); + wrap_tunnel (st, 0, TERRAIN_LENGTH-1); + +#if 0 + if (DEBUG_FLAG || st->verbose_flag) atexit(print_stats); +#endif + + st->step = effective_speed; + + init_time (st); + + return st; +} + + +static void +speedmine_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; + if (st->dbuf != st->window) { + XWindowAttributes xgwa; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + XFreePixmap (dpy, st->dbuf); + st->dbuf = XCreatePixmap (st->dpy, st->window, + st->width, st->height, xgwa.depth); + } +} + +#if 0 + static Bool + speedmine_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +speedmine_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + +/* + * Down the speedmine, you'll find speed + * to satisfy your moving needs; + * So if you're looking for a blast + * then hit the speedmine, really fast. + */ + +/* + * Speedworm likes to choke and spit + * and chase his tail, and dance a bit + * he really is a funky friend; + * he's made of speed from end to end. + */ + + +static const char *speedmine_defaults [] = { + ".verbose: False", + "*worm: False", + "*wire: False", + ".background: black", + ".foreground: white", + "*darkground: #101010", + "*lightground: #a0a0a0", + "*tunnelend: #000000", + "*delay: 30000", + "*maxspeed: 700", + "*thrust: 1.0", + "*gravity: 9.8", + "*vertigo: 1.0", + "*terrain: True", + "*smoothness: 6", + "*curviness: 1.0", + "*twistiness: 1.0", + "*widening: True", + "*bumps: True", + "*bonuses: True", + "*crosshair: True", + "*psychedelic: False", + 0 +}; + +static XrmOptionDescRec speedmine_options [] = { + { "-verbose", ".verbose", XrmoptionNoArg, "True"}, + { "-worm", ".worm", XrmoptionNoArg, "True"}, + { "-wireframe", ".wire", XrmoptionNoArg, "True"}, + { "-no-wireframe", ".wire", XrmoptionNoArg, "False"}, + { "-darkground", ".darkground", XrmoptionSepArg, 0 }, + { "-lightground", ".lightground", XrmoptionSepArg, 0 }, + { "-tunnelend", ".tunnelend", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-maxspeed", ".maxspeed", XrmoptionSepArg, 0 }, + { "-thrust", ".thrust", XrmoptionSepArg, 0 }, + { "-gravity", ".gravity", XrmoptionSepArg, 0 }, + { "-vertigo", ".vertigo", XrmoptionSepArg, 0 }, + { "-terrain", ".terrain", XrmoptionNoArg, "True"}, + { "-no-terrain", ".terrain", XrmoptionNoArg, "False"}, + { "-smoothness", ".smoothness", XrmoptionSepArg, 0 }, + { "-curviness", ".curviness", XrmoptionSepArg, 0 }, + { "-twistiness", ".twistiness", XrmoptionSepArg, 0 }, + { "-widening", ".widening", XrmoptionNoArg, "True"}, + { "-no-widening", ".widening", XrmoptionNoArg, "False"}, + { "-bumps", ".bumps", XrmoptionNoArg, "True"}, + { "-no-bumps", ".bumps", XrmoptionNoArg, "False"}, + { "-bonuses", ".bonuses", XrmoptionNoArg, "True"}, + { "-no-bonuses", ".bonuses", XrmoptionNoArg, "False"}, + { "-crosshair", ".crosshair", XrmoptionNoArg, "True"}, + { "-no-crosshair", ".crosshair", XrmoptionNoArg, "False"}, + { "-psychedelic", ".psychedelic", XrmoptionNoArg, "True"}, + { "-no-psychedelic", ".psychedelic", XrmoptionNoArg, "False"}, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("SpeedMine", speedmine) + +/* vim: ts=4 + */ diff --git a/non-wgl/speedmine.vcproj b/non-wgl/speedmine.vcproj new file mode 100644 index 0000000..719dbfe --- /dev/null +++ b/non-wgl/speedmine.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/sphere.c b/non-wgl/sphere.c new file mode 100644 index 0000000..c8d8e67 --- /dev/null +++ b/non-wgl/sphere.c @@ -0,0 +1,316 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* sphere --- a bunch of shaded spheres */ + +#if 0 +static const char sccsid[] = "@(#)sphere.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1988 by Sun Microsystems + * + * 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 + * 30-May-1997: made it go vertically as well as horizontally. + * 27-May-1997: turned into a standalone program. + * 02-Sep-1993: xlock version David Bagley + * 1988: Revised to use SunView canvas instead of gfxsw Sun Microsystems + * 1982: Orignal Algorithm Tom Duff Lucasfilm Ltd. + */ + +/*- + * original copyright + * ************************************************************************** + * Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA. + * + * All Rights Reserved + * + * 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, and that the names of Sun or MIT not be used in advertising + * or publicity pertaining to distribution of the software without specific + * prior written permission. Sun and M.I.T. make no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without any express or implied warranty. + * + * SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * *************************************************************************** + */ + +#define STANDALONE +#define NOARGS + +# define MODE_sphere +#define DELAY 20000 +#define CYCLES 20 +#define SIZE_ 0 +#define NCOLORS 64 +#define DEFAULTS "*delay: 20000 \n" \ + "*cycles: 20 \n" \ + "*size: 0 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + +# define BRIGHT_COLORS +# define reshape_sphere 0 +# define sphere_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* from the xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +#endif /* !STANDALONE */ + +#ifdef MODE_sphere + +ENTRYPOINT ModeSpecOpt sphere_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct sphere_description = +{"sphere", "init_sphere", "draw_sphere", "release_sphere", + "refresh_sphere", "init_sphere", (char *) NULL, &sphere_opts, + 5000, 1, 20, 0, 64, 1.0, "", + "Shows a bunch of shaded spheres", 0, NULL}; + +#endif + +/*- + * (NX, NY, NZ) is the light source vector -- length should be 100 + */ +#define NX 48 +#define NY (-36) +#define NZ 80 +#define NR 100 +#define SQRT(a) ((int)sqrt((double)(a))) + +typedef struct { + int width, height; + int radius; + int x0; /* x center */ + int y0; /* y center */ + int color; + int x, y; + int dirx, diry; + int shadowx, shadowy; + int maxx, maxy; + XPoint *points; +} spherestruct; + +static spherestruct *spheres = (spherestruct *) NULL; + +ENTRYPOINT void +init_sphere(ModeInfo * mi) +{ + spherestruct *sp; + + if (spheres == NULL) { + if ((spheres = (spherestruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (spherestruct))) == NULL) + return; + } + sp = &spheres[MI_SCREEN(mi)]; + + if (sp->points != NULL) { + (void) free((void *) sp->points); + sp->points = (XPoint *) NULL; + } + sp->width = MAX(MI_WIDTH(mi), 4); + sp->height = MAX(MI_HEIGHT(mi), 4); + if ((sp->points = (XPoint *) malloc(MIN(sp->width, sp->height) * + sizeof (XPoint))) == NULL) { + return; + } + + MI_CLEARWINDOW(mi); + + sp->dirx = 1; + sp->x = sp->radius; + sp->shadowx = (LRAND() & 1) ? 1 : -1; + sp->shadowy = (LRAND() & 1) ? 1 : -1; +} + +ENTRYPOINT void +draw_sphere(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + int sqrd, nd; + register int minx = 0, maxx = 0, miny = 0, maxy = 0, npts = 0; + spherestruct *sp; + + if (spheres == NULL) + return; + sp = &spheres[MI_SCREEN(mi)]; + if (sp->points == NULL) + return; + + MI_IS_DRAWN(mi) = True; + if ((sp->dirx && ABS(sp->x) >= sp->radius) || + (sp->diry && ABS(sp->y) >= sp->radius)) { + sp->radius = NRAND(MIN(sp->width / 2, sp->height / 2) - 1) + 1; + + if (LRAND() & 1) { + sp->dirx = (int) (LRAND() & 1) * 2 - 1; + sp->diry = 0; + } else { + sp->dirx = 0; + sp->diry = (int) (LRAND() & 1) * 2 - 1; + } + sp->x0 = NRAND(sp->width); + sp->y0 = NRAND(sp->height); + + sp->x = -sp->radius * sp->dirx; + sp->y = -sp->radius * sp->diry; + + if (MI_NPIXELS(mi) > 2) + sp->color = NRAND(MI_NPIXELS(mi)); + } + if (sp->dirx == 1) { + if (sp->x0 + sp->x < 0) + sp->x = -sp->x0; + } else if (sp->dirx == -1) { + if (sp->x0 + sp->x >= sp->width) + sp->x = sp->width - sp->x0 - 1; + } + if (sp->diry == 1) { + if (sp->y0 + sp->y < 0) + sp->y = -sp->y0; + } else if (sp->diry == -1) { + if (sp->y0 + sp->y >= sp->height) + sp->y = sp->height - sp->y0 - 1; + } + if (sp->dirx) { + sp->maxy = SQRT(sp->radius * sp->radius - sp->x * sp->x); + miny = -sp->maxy; + if (sp->y0 - sp->maxy < 0) + miny = -sp->y0; + maxy = sp->maxy; + } + if (sp->diry) { + sp->maxx = SQRT(sp->radius * sp->radius - sp->y * sp->y); + minx = -sp->maxx; + if (sp->x0 - sp->maxx < 0) + minx = -sp->x0; + maxx = sp->maxx; + } + if (sp->dirx) { + if (sp->y0 + sp->maxy >= sp->height) + maxy = sp->height - sp->y0; + } + if (sp->diry) { + if (sp->x0 + sp->maxx >= sp->width) + maxx = sp->width - sp->x0; + } + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + + if (sp->dirx) + XDrawLine(display, MI_WINDOW(mi), gc, + sp->x0 + sp->x, sp->y0 + miny, sp->x0 + sp->x, sp->y0 + maxy); + if (sp->diry) + XDrawLine(display, MI_WINDOW(mi), gc, + sp->x0 + minx, sp->y0 + sp->y, sp->x0 + maxx, sp->y0 + sp->y); + + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, sp->color)); + else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + + if (sp->dirx) { + sqrd = sp->radius * sp->radius - sp->x * sp->x; + nd = NX * sp->shadowx * sp->x; + for (sp->y = miny; sp->y <= maxy; sp->y++) + if ((NRAND(sp->radius * NR)) <= nd + NY * sp->shadowy * sp->y + + NZ * SQRT(sqrd - sp->y * sp->y)) { + sp->points[npts].x = sp->x + sp->x0; + sp->points[npts].y = sp->y + sp->y0; + npts++; + } + } + if (sp->diry) { + sqrd = sp->radius * sp->radius - sp->y * sp->y; + nd = NY * sp->shadowy * sp->y; + for (sp->x = minx; sp->x <= maxx; sp->x++) + if ((NRAND(sp->radius * NR)) <= NX * sp->shadowx * sp->x + nd + + NZ * SQRT(sqrd - sp->x * sp->x)) { + sp->points[npts].x = sp->x + sp->x0; + sp->points[npts].y = sp->y + sp->y0; + npts++; + } + } + XDrawPoints(display, MI_WINDOW(mi), gc, sp->points, npts, CoordModeOrigin); + if (sp->dirx == 1) { + sp->x++; + if (sp->x0 + sp->x >= sp->width) + sp->x = sp->radius; + } else if (sp->dirx == -1) { + sp->x--; + if (sp->x0 + sp->x < 0) + sp->x = -sp->radius; + } + if (sp->diry == 1) { + sp->y++; + if (sp->y0 + sp->y >= sp->height) + sp->y = sp->radius; + } else if (sp->diry == -1) { + sp->y--; + if (sp->y0 + sp->y < 0) + sp->y = -sp->radius; + } +} + +ENTRYPOINT void +release_sphere(ModeInfo * mi) +{ + if (spheres != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + spherestruct *sp = &spheres[screen]; + + if (sp->points) { + (void) free((void *) sp->points); + /* sp->points = NULL; */ + } + } + (void) free((void *) spheres); + spheres = (spherestruct *) NULL; + } +} + +ENTRYPOINT void +refresh_sphere(ModeInfo * mi) +{ + spherestruct *sp; + + if (spheres == NULL) + return; + sp = &spheres[MI_SCREEN(mi)]; + + MI_CLEARWINDOW(mi); + + sp->x = -sp->radius; +} + +XSCREENSAVER_MODULE ("Sphere", sphere) + +#endif /* MODE_sphere */ diff --git a/non-wgl/sphere.vcproj b/non-wgl/sphere.vcproj new file mode 100644 index 0000000..43f435f --- /dev/null +++ b/non-wgl/sphere.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/spiral.c b/non-wgl/spiral.c new file mode 100644 index 0000000..843f0ff --- /dev/null +++ b/non-wgl/spiral.c @@ -0,0 +1,343 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* spiral --- spiraling dots */ + +#if 0 +static const char sccsid[] = "@(#)spiral.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1994 by Darrick Brown. + * + * 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: jwz@jwz.org: turned into a standalone program. + * 24-Jul-1995: Fix to allow cycles not to have an arbitrary value by + * Peter Schmitzberger (schmitz@coma.sbg.ac.at). + * 06-Mar-1995: Finished cleaning up and final testing. + * 03-Mar-1995: Cleaned up code. + * 12-Jul-1994: Written. + * + * Low CPU usage mode. + * Idea based on a graphics demo I saw a *LONG* time ago. + */ + +#define STANDALONE +#define NOARGS + +# define MODE_spiral +#define DELAY 50000 +#define COUNT 40 +#define CYCLES 350 +#define NCOLORS 64 +#define DEFAULTS "*delay: 50000 \n" \ + "*count: 40 \n" \ + "*cycles: 350 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + +# define SMOOTH_COLORS +# define reshape_spiral 0 +# define spiral_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* from the xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +#endif /* !STANDALONE */ + +#ifdef MODE_spiral + +ENTRYPOINT ModeSpecOpt spiral_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct spiral_description = +{"spiral", "init_spiral", "draw_spiral", "release_spiral", + "refresh_spiral", "init_spiral", (char *) NULL, &spiral_opts, + 5000, -40, 350, 1, 64, 1.0, "", + "Shows a helical locus of points", 0, NULL}; + +#endif + +#define MAXTRAIL 512 /* The length of the trail */ +#define MAXDOTS 40 +#define MINDOTS 1 +#define TWOPI (2.0*M_PI) /* for convienence */ +#define JAGGINESS 4 /* This sets the "Craziness" of the spiral (I like 4) */ +#define SPEED 2.0 + +/* How many segments to draw per cycle when redrawing */ +#define REDRAWSTEP 3 + + +typedef struct { + float hx, hy, ha, hr; +} Traildots; + +typedef struct { + Traildots *traildots; + float cx, cy; + float angle; + float radius; + float dr, da; + float dx, dy; + int erase; + int inc; + float colors; + int width, height; + float top, bottom, left, right; + int dots, nlength; + int redrawing, redrawpos; +} spiralstruct; + +static spiralstruct *spirals = (spiralstruct *) NULL; + +static void draw_dots(ModeInfo * mi, int in); + +#define TFX(sp,x) ((int)((x/sp->right)*(float)sp->width)) +#define TFY(sp,y) ((int)((y/sp->top)*(float)sp->height)) + +static void +draw_dots(ModeInfo * mi, int in) +{ + + float i, inc; + float x, y; + + spiralstruct *sp = &spirals[MI_SCREEN(mi)]; + + inc = TWOPI / (float) sp->dots; + for (i = 0.0; i < TWOPI; i += inc) { + x = sp->traildots[in].hx + COSF(i + sp->traildots[in].ha) * + sp->traildots[in].hr; + y = sp->traildots[in].hy + SINF(i + sp->traildots[in].ha) * + sp->traildots[in].hr; + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + TFX(sp, x), TFY(sp, y)); + } +} + +ENTRYPOINT void +init_spiral(ModeInfo * mi) +{ + spiralstruct *sp; + int i; + + if (spirals == NULL) { + if ((spirals = (spiralstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (spiralstruct))) == NULL) + return; + } + sp = &spirals[MI_SCREEN(mi)]; + +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False); +#endif + + sp->width = MI_WIDTH(mi); + sp->height = MI_HEIGHT(mi); + + MI_CLEARWINDOW(mi); + + /* Init */ + sp->nlength = MI_CYCLES(mi); + + if (!sp->traildots) + if ((sp->traildots = (Traildots *) malloc(sp->nlength * + sizeof (Traildots))) == NULL) { + return; + } + + /* initialize the allocated array */ + for (i = 0; i < sp->nlength; i++) { + sp->traildots[i].hx = 0.0; + sp->traildots[i].hy = 0.0; + sp->traildots[i].ha = 0.0; + sp->traildots[i].hr = 0.0; + } + sp->redrawing = 0; + + /* keep the window parameters proportional */ + sp->top = 10000.0; + sp->bottom = 0; + sp->right = (float) (sp->width) / (float) (sp->height) * (10000.0); + sp->left = 0; + + /* assign the initial values */ + sp->cx = (float) (5000.0 - NRAND(2000)) / 10000.0 * sp->right; + sp->cy = (float) (5000.0 - NRAND(2000)); + sp->radius = (float) (NRAND(200) + 200); + sp->angle = 0.0; + sp->dx = (float) (10 - NRAND(20)) * SPEED; + sp->dy = (float) (10 - NRAND(20)) * SPEED; + sp->dr = (float) ((NRAND(10) + 4) * (1 - (LRAND() & 1) * 2)); + sp->da = (float) NRAND(360) / 7200.0 + 0.01; + if (MI_NPIXELS(mi) > 2) + sp->colors = (float) NRAND(MI_NPIXELS(mi)); + sp->erase = 0; + sp->inc = 0; + sp->traildots[sp->inc].hx = sp->cx; + sp->traildots[sp->inc].hy = sp->cy; + sp->traildots[sp->inc].ha = sp->angle; + sp->traildots[sp->inc].hr = sp->radius; + sp->inc++; + + sp->dots = MI_COUNT(mi); + if (sp->dots < -MINDOTS) + sp->dots = NRAND(sp->dots - MINDOTS + 1) + MINDOTS; + /* Absolute minimum */ + if (sp->dots < MINDOTS) + sp->dots = MINDOTS; +} + +ENTRYPOINT void +draw_spiral(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + int i, j; + spiralstruct *sp; + + if (spirals == NULL) + return; + sp = &spirals[MI_SCREEN(mi)]; + if (sp->traildots == NULL) + return; + + MI_IS_DRAWN(mi) = True; + if (sp->erase == 1) { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + draw_dots(mi, sp->inc); + } + sp->cx += sp->dx; + sp->traildots[sp->inc].hx = sp->cx; + + if ((sp->cx > 9000.0) || (sp->cx < 1000.0)) + sp->dx *= -1.0; + + sp->cy += sp->dy; + sp->traildots[sp->inc].hy = sp->cy; + + if ((sp->cy > 9000.0) || (sp->cy < 1000.0)) + sp->dy *= -1.0; + + sp->radius += sp->dr; + sp->traildots[sp->inc].hr = sp->radius; + + if ((sp->radius > 2500.0) && (sp->dr > 0.0)) + sp->dr *= -1.0; + else if ((sp->radius < 50.0) && (sp->radius < 0.0)) + sp->dr *= -1.0; + + /* Randomly give some variations to: */ + + /* spiral direction (if it is within the boundaries) */ + if ((NRAND(3000) < 1 * JAGGINESS) && + (((sp->cx > 2000.0) && (sp->cx < 8000.0)) && + ((sp->cy > 2000.0) && (sp->cy < 8000.0)))) { + sp->dx = (float) (10 - NRAND(20)) * SPEED; + sp->dy = (float) (10 - NRAND(20)) * SPEED; + } + /* The speed of the change in size of the spiral */ + if (NRAND(3000) < 1 * JAGGINESS) { + if (LRAND() & 1) + sp->dr += (float) (NRAND(3) + 1); + else + sp->dr -= (float) (NRAND(3) + 1); + + /* don't let it get too wild */ + if (sp->dr > 18.0) + sp->dr = 18.0; + else if (sp->dr < 4.0) + sp->dr = 4.0; + } + /* The speed of rotation */ + if (NRAND(3000) < 1 * JAGGINESS) + sp->da = (float) NRAND(360) / 7200.0 + 0.01; + + /* Reverse rotation */ + if (NRAND(3000) < 1 * JAGGINESS) + sp->da *= -1.0; + + sp->angle += sp->da; + sp->traildots[sp->inc].ha = sp->angle; + + if (sp->angle > TWOPI) + sp->angle -= TWOPI; + else if (sp->angle < 0.0) + sp->angle += TWOPI; + + sp->colors += (float) MI_NPIXELS(mi) / ((float) (2 * sp->nlength)); + if (sp->colors >= (float) MI_NPIXELS(mi)) + sp->colors = 0.0; + + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, (int) sp->colors)); + else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + draw_dots(mi, sp->inc); + sp->inc++; + + if (sp->inc > sp->nlength - 1) { + sp->inc -= sp->nlength; + sp->erase = 1; + } + if (sp->redrawing) { + for (i = 0; i < REDRAWSTEP; i++) { + j = (sp->inc - sp->redrawpos + sp->nlength) % sp->nlength; + draw_dots(mi, j); + + if (++(sp->redrawpos) >= sp->nlength) { + sp->redrawing = 0; + break; + } + } + } +} + +ENTRYPOINT void +release_spiral(ModeInfo * mi) +{ + if (spirals != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + spiralstruct *sp = &spirals[screen]; + + if (sp->traildots) + (void) free((void *) sp->traildots); + } + (void) free((void *) spirals); + spirals = (spiralstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_spiral(ModeInfo * mi) +{ + spiralstruct *sp; + + if (spirals == NULL) + return; + sp = &spirals[MI_SCREEN(mi)]; + + MI_CLEARWINDOW(mi); + sp->redrawing = 1; + sp->redrawpos = 0; +} + +XSCREENSAVER_MODULE ("Spiral", spiral) + +#endif /* MODE_spiral */ diff --git a/non-wgl/spiral.vcproj b/non-wgl/spiral.vcproj new file mode 100644 index 0000000..70d2949 --- /dev/null +++ b/non-wgl/spiral.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/spline.c b/non-wgl/spline.c new file mode 100644 index 0000000..1a73ea6 --- /dev/null +++ b/non-wgl/spline.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 1987, 1988, 1989 Stanford University + * + * 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, and that the name of Stanford not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Stanford makes no representations about + * the suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* This code came with the InterViews distribution, and was translated + from C++ to C by Matthieu Devin some time in 1992. + */ + +#include "utils.h" +#include "spline.h" + +#define SMOOTHNESS 1.0 + +static void grow_spline_points (spline* s); +static void mid_point (double x0, double y0, double x1, double y1, + double *mx, double *my); +static int can_approx_with_line (double x0, double y0, double x2, + double y2, double x3, double y3); +static void add_line (spline* s, double x0, double y0, double x1, double y1); +static void add_bezier_arc (spline* s, + double x0, double y0, double x1, double y1, + double x2, double y2, double x3, double y3); +static void third_point (double x0, double y0, double x1, double y1, + double *tx, double *ty); +static void calc_section (spline* s, double cminus1x, double cminus1y, + double cx, double cy, double cplus1x, double cplus1y, + double cplus2x, double cplus2y); + +spline* +make_spline (unsigned int size) +{ + spline* s = (spline*)calloc (1, sizeof (spline)); + if (!s) abort(); + s->n_controls = size; + s->control_x = (double*)calloc (s->n_controls, sizeof (double)); + s->control_y = (double*)calloc (s->n_controls, sizeof (double)); + + s->n_points = 0; + s->allocated_points = s->n_controls; + s->points = (XPoint*)calloc (s->allocated_points, sizeof (XPoint)); + + if (!s->control_x || !s->control_y || !s->points) + abort(); + + return s; +} + +static void +grow_spline_points (spline *s) +{ + s->allocated_points = 10 + (s->allocated_points * 1.3); + s->points = + (XPoint*)realloc (s->points, s->allocated_points * sizeof (XPoint)); + if (!s->points) abort(); +} + +static void +mid_point (double x0, double y0, + double x1, double y1, + double *mx, double *my) +{ + *mx = (x0 + x1) / 2.0; + *my = (y0 + y1) / 2.0; +} + +static void +third_point (double x0, double y0, + double x1, double y1, + double *tx, double *ty) +{ + *tx = (2 * x0 + x1) / 3.0; + *ty = (2 * y0 + y1) / 3.0; +} + +static int +can_approx_with_line (double x0, double y0, + double x2, double y2, + double x3, double y3) +{ + double triangle_area, side_squared, dx, dy; + + triangle_area = x0 * y2 - x2 * y0 + x2 * y3 - x3 * y2 + x3 * y0 - x0 * y3; + /* actually 4 times the area. */ + triangle_area *= triangle_area; + dx = x3 - x0; + dy = y3 - y0; + side_squared = dx * dx + dy * dy; + return triangle_area <= SMOOTHNESS * side_squared; +} + +static void +add_line (spline *s, + double x0, double y0, + double x1, double y1) +{ + if (s->n_points >= s->allocated_points) + grow_spline_points (s); + + if (s->n_points == 0) + { + s->points [s->n_points].x = x0; + s->points [s->n_points].y = y0; + s->n_points += 1; + } + s->points [s->n_points].x = x1; + s->points [s->n_points].y = y1; + s->n_points += 1; +} + +static void +add_bezier_arc (spline *s, + double x0, double y0, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + double midx01, midx12, midx23, midlsegx, midrsegx, cx, + midy01, midy12, midy23, midlsegy, midrsegy, cy; + + mid_point (x0, y0, x1, y1, &midx01, &midy01); + mid_point (x1, y1, x2, y2, &midx12, &midy12); + mid_point (x2, y2, x3, y3, &midx23, &midy23); + mid_point (midx01, midy01, midx12, midy12, &midlsegx, &midlsegy); + mid_point (midx12, midy12, midx23, midy23, &midrsegx, &midrsegy); + mid_point (midlsegx, midlsegy, midrsegx, midrsegy, &cx, &cy); + + if (can_approx_with_line (x0, y0, midlsegx, midlsegy, cx, cy)) + add_line (s, x0, y0, cx, cy); + else if ((midx01 != x1) || (midy01 != y1) || (midlsegx != x2) + || (midlsegy != y2) || (cx != x3) || (cy != y3)) + add_bezier_arc (s, x0, y0, midx01, midy01, midlsegx, midlsegy, cx, cy); + + if (can_approx_with_line (cx, cy, midx23, midy23, x3, y3)) + add_line (s, cx, cy, x3, y3); + else if ((cx != x0) || (cy != y0) || (midrsegx != x1) || (midrsegy != y1) + || (midx23 != x2) || (midy23 != y2)) + add_bezier_arc (s, cx, cy, midrsegx, midrsegy, midx23, midy23, x3, y3); +} + +static void +calc_section (spline *s, + double cminus1x, double cminus1y, + double cx, double cy, + double cplus1x, double cplus1y, + double cplus2x, double cplus2y) +{ + double p0x, p1x, p2x, p3x, tempx, + p0y, p1y, p2y, p3y, tempy; + + third_point (cx, cy, cplus1x, cplus1y, &p1x, &p1y); + third_point (cplus1x, cplus1y, cx, cy, &p2x, &p2y); + third_point (cx, cy, cminus1x, cminus1y, &tempx, &tempy); + mid_point (tempx, tempy, p1x, p1y, &p0x, &p0y); + third_point (cplus1x, cplus1y, cplus2x, cplus2y, &tempx, &tempy); + mid_point (tempx, tempy, p2x, p2y, &p3x, &p3y); + add_bezier_arc (s, p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y); +} + +void +compute_spline (spline *s) +{ + int i; + s->n_points = 0; + + if (s->n_controls < 3) + return; + + calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0], + s->control_y [0], s->control_x [0], s->control_y [0], + s->control_x [1], s->control_y [1]); + calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0], + s->control_y [0], s->control_x [1], s->control_y [1], + s->control_x [2], s->control_y [2]); + + for (i = 1; i < s->n_controls - 2; i++) + calc_section (s, s->control_x [i - 1], s->control_y [i - 1], + s->control_x [i], s->control_y [i], + s->control_x [i + 1], s->control_y [i + 1], + s->control_x [i + 2], s->control_y [i + 2]); + + calc_section (s, s->control_x [i - 1], s->control_y [i - 1], + s->control_x [i], s->control_y [i], + s->control_x [i + 1], s->control_y [i + 1], + s->control_x [i + 1], s->control_y [i + 1]); + calc_section (s, s->control_x [i], s->control_y [i], + s->control_x [i + 1], s->control_y [i + 1], + s->control_x [i + 1], s->control_y [i + 1], + s->control_x [i + 1], s->control_y [i + 1]); +} + +void +compute_closed_spline (spline *s) +{ + int i; + s->n_points = 0; + + if (s->n_controls < 3) + return; + + calc_section (s, + s->control_x [s->n_controls - 1], + s->control_y [s->n_controls - 1], + s->control_x [0], s->control_y [0], + s->control_x [1], s->control_y [1], + s->control_x [2], s->control_y [2]); + + for (i = 1; i < s->n_controls - 2; i++) + calc_section (s, s->control_x [i - 1], s->control_y [i - 1], + s->control_x [i], s->control_y [i], + s->control_x [i + 1], s->control_y [i + 1], + s->control_x [i + 2], s->control_y [i + 2]); + + calc_section (s, s->control_x [i - 1], s->control_y [i - 1], + s->control_x [i], s->control_y [i], + s->control_x [i + 1], s->control_y [i + 1], + s->control_x [0], s->control_y [0]); + calc_section (s, s->control_x [i], s->control_y [i], + s->control_x [i + 1], s->control_y [i + 1], + s->control_x [0], s->control_y [0], + s->control_x [1], s->control_y [1]); +} + +void +just_fill_spline (spline *s) +{ + int i; + + while (s->allocated_points < s->n_controls + 1) + grow_spline_points (s); + + for (i = 0; i < s->n_controls; i++) + { + s->points [i].x = s->control_x [i]; + s->points [i].y = s->control_y [i]; + } + s->points [s->n_controls].x = s->control_x [0]; + s->points [s->n_controls].y = s->control_y [0]; + s->n_points = s->n_controls + 1; +} + +void +append_spline_points (spline *s1, spline *s2) +{ + int i; + while (s1->allocated_points < s1->n_points + s2->n_points) + grow_spline_points (s1); + for (i = s1->n_points; i < s1->n_points + s2->n_points; i++) + { + s1->points [i].x = s2->points [i - s1->n_points].x; + s1->points [i].y = s2->points [i - s1->n_points].y; + } + s1->n_points = s1->n_points + s2->n_points; +} + +void +spline_bounding_box (spline *s, XRectangle *rectangle_out) +{ + int min_x; + int max_x; + int min_y; + int max_y; + int i; + + if (s->n_points == 0) + { + rectangle_out->x = 0; + rectangle_out->y = 0; + rectangle_out->width = 0; + rectangle_out->height = 0; + } + + min_x = s->points [0].x; + max_x = min_x; + min_y = s->points [0].y; + max_y = min_y; + + for (i = 1; i < s->n_points; i++) + { + if (s->points [i].x < min_x) + min_x = s->points [i].x; + if (s->points [i].x > max_x) + max_x = s->points [i].x; + if (s->points [i].y < min_y) + min_y = s->points [i].y; + if (s->points [i].y > max_y) + max_y = s->points [i].y; + } + rectangle_out->x = min_x; + rectangle_out->y = min_y; + rectangle_out->width = max_x - min_x; + rectangle_out->height = max_y - min_y; +} + +void +free_spline(spline * s) +{ + free ((void *) s->control_x); + free ((void *) s->control_y); + free ((void *) s->points); + free ((void *) s); +} diff --git a/non-wgl/spline.h b/non-wgl/spline.h new file mode 100644 index 0000000..a5a366c --- /dev/null +++ b/non-wgl/spline.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1987, 1988, 1989 Stanford University + * + * 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, and that the name of Stanford not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Stanford makes no representations about + * the suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* This code came with the InterViews distribution, and was translated + from C++ to C by Matthieu Devin some time in 1992. + */ + +#ifndef _SPLINE_H_ +#define _SPLINE_H_ + +typedef struct _spline +{ + /* input */ + unsigned int n_controls; + double* control_x; + double* control_y; + + /* output */ + unsigned int n_points; + XPoint* points; + unsigned int allocated_points; +} spline; + +spline* make_spline (unsigned int size); +void compute_spline (spline* s); +void compute_closed_spline (spline* s); +void just_fill_spline (spline* s); +void append_spline_points (spline* s1, spline* s2); +void spline_bounding_box (spline* s, XRectangle* rectangle_out); +void free_spline(spline *s); + +#endif /* _SPLINE_H_ */ diff --git a/non-wgl/spotlight.c b/non-wgl/spotlight.c new file mode 100644 index 0000000..a4d7bff --- /dev/null +++ b/non-wgl/spotlight.c @@ -0,0 +1,360 @@ +/* + * spotlight - an xscreensaver module + * Copyright (c) 1999, 2001 Rick Schultz + * + * loosely based on the BackSpace module "StefView" by Darcy Brockbank + */ + +/* modified from a module from the xscreensaver distribution */ + +/* + * xscreensaver, Copyright (c) 1992-2006 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. + */ + + +/* #define DEBUG */ +#include "screenhack.h" +#include + +char *background = "black"; +char *foreground = "white"; +Bool dontClearRoot = True; +int delay = 10000; +int duration = 120; +int radius = 125; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&dontClearRoot, "dontClearRoot", NULL, "True", t_Bool}, + {&delay, "delay", NULL, "10000", t_Int}, + {&duration, "duration", NULL, "120", t_Int}, + {&radius, "radius", NULL, "125", t_Int}, +}; + + +#define MINX 0.0 +#define MINY 0.0 +#define X_PERIOD 15000.0 +#define Y_PERIOD 12000.0 + +struct state { + Display *dpy; + Window window; + Screen *screen; + + int sizex, sizey; /* screen size */ + int delay; + int duration; + time_t start_time; + int first_time; + GC window_gc; +#ifdef DEBUG + GC white_gc; +#endif + GC buffer_gc; /* draw in buffer, then flush to screen + to avoid flicker */ + int radius; /* radius of spotlight in pixels */ + + Pixmap pm; /* pixmap grabbed from screen */ + Pixmap buffer; /* pixmap for the buffer */ + + int x, y, s; /* x & y coords of buffer (upper left corner) */ + /* s is the width of the buffer */ + + int off; /* random offset from currentTimeInMs(), so that + two concurrent copies of spotlight have different + behavior. */ + + int oldx, oldy, max_x_speed, max_y_speed; + /* used to keep the new buffer position + over the old spotlight image to make sure + the old image is completely erased */ + + Bool first_p; + async_load_state *img_loader; +}; + + +/* The path the spotlight follows around the screen is sinusoidal. + This function is fed to sin() to get the x & y coords */ +static long +currentTimeInMs(struct state *st) +{ + struct timeval curTime; +#ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tz = {0,0}; + gettimeofday(&curTime, &tz); +#else + gettimeofday(&curTime); +#endif + return curTime.tv_sec*1000 + curTime.tv_usec/1000.0; +} + + +static void * +spotlight_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + long gcflags; + Colormap cmap; + unsigned long bg; + GC clip_gc; + Pixmap clip_pm; + + st->dpy = dpy; + st->window = window; + st->first_p = True; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->screen = xgwa.screen; + st->sizex = xgwa.width; + st->sizey = xgwa.height; + cmap = xgwa.colormap; + //bg = get_pixel_resource (st->dpy, cmap, "background", "Background"); + bg = load_color(st->dpy, cmap, background); + + /* read parameters, keep em sane */ + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay = delay; + if (st->delay < 1) st->delay = 1; + //st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + st->duration = duration; + if (st->duration < 1) st->duration = 1; + //st->radius = get_integer_resource (st->dpy, "radius", "Integer"); + st->radius = radius; + if (st->radius < 0) st->radius = 125; + + /* Don't let the spotlight be bigger than the window */ + while (st->radius > xgwa.width * 0.45) + st->radius /= 2; + while (st->radius > xgwa.height * 0.45) + st->radius /= 2; + + if (st->radius < 4) + st->radius = 4; + + /* do the dance */ + gcv.function = GXcopy; + gcv.subwindow_mode = IncludeInferiors; + gcflags = GCForeground | GCFunction; + gcv.foreground = bg; + +#ifdef NOPE + if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */ + gcflags |= GCSubwindowMode; +#endif + st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv); + + st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth); + XClearWindow(st->dpy, st->window); + + st->first_time = 1; + + /* create buffer to reduce flicker */ +#ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + st->buffer = 0; +#else + st->buffer = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth); +#endif + + st->buffer_gc = XCreateGC(st->dpy, (st->buffer ? st->buffer : window), gcflags, &gcv); + if (st->buffer) + XFillRectangle(st->dpy, st->buffer, st->buffer_gc, 0, 0, st->sizex, st->sizey); + + /* create clip mask (so it's a circle, not a square) */ + clip_pm = XCreatePixmap(st->dpy, st->window, st->radius*4, st->radius*4, 1); + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, st->pm, + 0, 0); + st->start_time = time ((time_t) 0); + + gcv.foreground = 0L; + clip_gc = XCreateGC(st->dpy, clip_pm, gcflags, &gcv); + XFillRectangle(st->dpy, clip_pm, clip_gc, 0, 0, st->radius*4, st->radius*4); + + XSetForeground(st->dpy, clip_gc, 1L); + XFillArc(st->dpy, clip_pm, clip_gc, st->radius , st->radius, + st->radius*2, st->radius*2, 0, 360*64); + + /* set buffer's clip mask to the one we just made */ + XSetClipMask(st->dpy, st->buffer_gc, clip_pm); + + /* free everything */ + XFreeGC(st->dpy, clip_gc); + XFreePixmap(st->dpy, clip_pm); + + /* avoid remants */ + st->max_x_speed = st->max_y_speed = st->radius; + + st->off = random(); + +#ifdef DEBUG + /* create GC with white fg */ + gcv.foreground = fg; + st->white_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv); +#endif + + /* blank out screen */ + XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey); + + return st; +} + + +/* + * perform one iteration + */ +static void +onestep (struct state *st, Bool first_p) +{ + long now; + + 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->start_time = time ((time_t) 0); + } + return; + } + + if (!st->img_loader && + st->start_time + st->duration < time ((time_t) 0)) { + st->img_loader = load_image_async_simple (0, st->screen, st->window, + st->pm, 0, 0); + return; + } + +#define nrnd(x) (random() % (x)) + + st->oldx = st->x; + st->oldy = st->y; + + st->s = st->radius *4 ; /* s = width of buffer */ + + now = currentTimeInMs(st) + st->off; + + /* find new x,y */ + st->x = ((1 + sin(((double)now) / X_PERIOD * 2. * M_PI))/2.0) + * (st->sizex - st->s/2) -st->s/4 + MINX; + st->y = ((1 + sin(((double)now) / Y_PERIOD * 2. * M_PI))/2.0) + * (st->sizey - st->s/2) -st->s/4 + MINY; + + if (!st->first_p) + { + /* limit change in x and y to buffer width */ + if ( st->x < (st->oldx - st->max_x_speed) ) st->x = st->oldx - st->max_x_speed; + if ( st->x > (st->oldx + st->max_x_speed) ) st->x = st->oldx + st->max_x_speed; + if ( st->y < (st->oldy - st->max_y_speed) ) st->y = st->oldy - st->max_y_speed; + if ( st->y > (st->oldy + st->max_y_speed) ) st->y = st->oldy + st->max_y_speed; + } + + if (! st->buffer) + { + XClearWindow (st->dpy, st->window); + XSetClipOrigin(st->dpy, st->buffer_gc, st->x,st->y); + XCopyArea(st->dpy, st->pm, st->window, st->buffer_gc, st->x, st->y, st->s, st->s, st->x, st->y); + } + else + { + /* clear buffer */ + XFillRectangle(st->dpy, st->buffer, st->buffer_gc, st->x, st->y, st->s, st->s); + + /* copy area of screen image (pm) to buffer + Clip to a circle */ + XSetClipOrigin(st->dpy, st->buffer_gc, st->x,st->y); + XCopyArea(st->dpy, st->pm, st->buffer, st->buffer_gc, st->x, st->y, st->s, st->s, st->x, st->y); + + if (st->first_time) { + /* blank out screen */ + XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey); + st->first_time = 0; + } + + /* copy buffer to screen (window) */ + XCopyArea(st->dpy, st->buffer, st->window, st->window_gc, st->x , st->y, st->s, st->s, st->x, st->y); + } + +#ifdef DEBUG + /* draw a box around the buffer */ + XDrawRectangle(st->dpy, st->window, st->white_gc, st->x , st->y, st->s, st->s); +#endif + +} + + +static unsigned long +spotlight_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + onestep(st, st->first_p); + st->first_p = False; + return st->delay; +} + +static void +spotlight_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + spotlight_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +spotlight_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XFreeGC (dpy, st->window_gc); + XFreeGC (dpy, st->buffer_gc); + if (st->pm) XFreePixmap (dpy, st->pm); + if (st->buffer) XFreePixmap (dpy, st->buffer); + free (st); +} + + + + +static const char *spotlight_defaults [] = { + ".background: black", + ".foreground: white", + "*dontClearRoot: True", + "*fpsSolid: true", + +#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */ + "*visualID: Best", +#endif + + "*delay: 10000", + "*duration: 120", + "*radius: 125", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec spotlight_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-radius", ".radius", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Spotlight", spotlight) diff --git a/non-wgl/spotlight.vcproj b/non-wgl/spotlight.vcproj new file mode 100644 index 0000000..fe4ad36 --- /dev/null +++ b/non-wgl/spotlight.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/squiral.c b/non-wgl/squiral.c new file mode 100644 index 0000000..ea2d5be --- /dev/null +++ b/non-wgl/squiral.c @@ -0,0 +1,324 @@ +/* squiral, by "Jeff Epler" , 18-mar-1999. + * + * 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 "erase.h" +#include "yarandom.h" + +char *background = "black"; +char *foreground = "white"; +int fill = 75; +int count = 0; +int ncolors = 100; +int delay = 10000; +float disorder = 0.005; +Bool cycle = False; +float handedness = 0.5; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&fill, "fill", NULL, "75", t_Int}, + {&count, "count", NULL, "0", t_Int}, + {&ncolors, "ncolors", NULL, "100", t_Int}, + {&delay, "delay", NULL, "10000", t_Int}, + {&disorder, "disorder", NULL, "0.005", t_Float}, + {&cycle, "cycle", NULL, "False", t_Bool}, + {&handedness, "handedness", NULL, "0.5", t_Float}, +}; + +#define R(x) (abs(random())%x) +#define PROB(x) (frand(1.0) < (x)) + +#define NCOLORSMAX 255 +#define STATES 8 + +/* 0- 3 left-winding */ +/* 4- 7 right-winding */ + +struct worm { + int h; + int v; + int s; + int c; + int cc; +}; + + +struct state { + Display *dpy; + Window window; + + int width, height, count, cycle; + double frac, disorder, handedness; + int ncolors; + GC draw_gc, erase_gc; + XColor colors[NCOLORSMAX]; + + int delay; + + int cov; + int dirh[4]; + int dirv[4]; + + int *fill; + + struct worm *worms; + int inclear; +}; + +#define CLEAR1(x,y) (!st->fill[((y)%st->height)*st->width+(x)%st->width]) +#define MOVE1(x,y) (st->fill[((y)%st->height)*st->width+(x)%st->width]=1, XDrawPoint(st->dpy, st->window, st->draw_gc, (x)%st->width,(y)%st->height), st->cov++) + +#define CLEARDXY(x,y,dx,dy) CLEAR1(x+dx, y+dy) && CLEAR1(x+dx+dx, y+dy+dy) +#define MOVEDXY(x,y,dx,dy) MOVE1 (x+dx, y+dy), MOVE1 (x+dx+dx, y+dy+dy) + +#define CLEAR(d) CLEARDXY(w->h,w->v, st->dirh[d],st->dirv[d]) +#define MOVE(d) (XSetForeground(st->dpy, st->draw_gc, st->colors[w->c].pixel), \ + MOVEDXY(w->h,w->v, st->dirh[d],st->dirv[d]), \ + w->h=w->h+st->dirh[d]*2, \ + w->v=w->v+st->dirv[d]*2, dir=d) + +#define RANDOM (void) (w->h = R(st->width), w->v = R(st->height), w->c = R(st->ncolors), \ + type=R(2), dir=R(4), (st->cycle && (w->cc=R(3)+st->ncolors))) + + + +#define SUCC(x) ((x+1)%4) +#define PRED(x) ((x+3)%4) +#define CCW PRED(dir) +#define CW SUCC(dir) +#define REV ((dir+2)%4) +#define STR (dir) +#define TRY(x) if (CLEAR(x)) { MOVE(x); break; } + +static void +do_worm(struct state *st, struct worm *w) +{ + int type = w->s / 4; + int dir = w->s % 4; + + w->c = (w->c+w->cc) % st->ncolors; + + if (PROB(st->disorder)) type=PROB(st->handedness); + switch(type) { + case 0: /* CCW */ + TRY(CCW) + TRY(STR) + TRY(CW) + RANDOM; + break; + case 1: /* CW */ + TRY(CW) + TRY(STR) + TRY(CCW) + RANDOM; + break; + } + w->s = type*4+dir; + w->h = w->h % st->width; + w->v = w->v % st->height; +} + +static void +squiral_init_1 (struct state *st) +{ + int i; + if (st->worms) free (st->worms); + if (st->fill) free (st->fill); + + st->worms=calloc(st->count, sizeof(struct worm)); + st->fill=calloc(st->width*st->height, sizeof(int)); + + st->dirh[0]=0; st->dirh[1]=1; st->dirh[2]=0; st->dirh[3]=st->width-1; + st->dirv[0]=st->height-1; st->dirv[1]=0; st->dirv[2]=1; st->dirv[3]=0; + for(i=0;icount;i++) { + st->worms[i].h=R(st->width); + st->worms[i].v=R(st->height); + st->worms[i].s=R(4)+4*PROB(st->handedness); + st->worms[i].c=R(st->ncolors); + if(st->cycle) { st->worms[i].cc=R(3)+st->ncolors; } + else st->worms[i].cc=0; + } +} + +static void * +squiral_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + Colormap cmap; + XWindowAttributes xgwa; + Bool writeable = False; + + st->dpy = dpy; + st->window = window; + + //st->delay= get_integer_resource(st->dpy, "delay", "Integer"); + st->delay= delay; + + XClearWindow(st->dpy, st->window); + XGetWindowAttributes(st->dpy, st->window, &xgwa); + st->width = xgwa.width; + st->height = xgwa.height; + + cmap = xgwa.colormap; +#if 1 + gcv.foreground = load_color(st->dpy, cmap, foreground); +#else + gcv.foreground = get_pixel_resource(st->dpy, cmap, "foreground", + "Foreground"); +#endif + st->draw_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + //gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, cmap, background); + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + cmap = xgwa.colormap; + if( st->ncolors ) { + free_colors(xgwa.screen, cmap, st->colors, st->ncolors); + st->ncolors = 0; + } + if( mono_p ) { + st->ncolors=1; + //st->colors[0].pixel=get_pixel_resource(st->dpy, cmap, "foreground","Foreground"); + st->colors[0].pixel=load_color(st->dpy, cmap, foreground); + } else { + //st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer"); + st->ncolors = ncolors; + if (st->ncolors < 0 || st->ncolors > NCOLORSMAX) + st->ncolors = NCOLORSMAX; + make_uniform_colormap(xgwa.screen, xgwa.visual, cmap, + st->colors, &st->ncolors, True, + &writeable, False); + if (st->ncolors <= 0) { + st->ncolors = 1; + //st->colors[0].pixel=get_pixel_resource(st->dpy, cmap, "foreground","Foreground"); + st->colors[0].pixel=load_color(st->dpy, cmap, foreground); + } + } +#if 1 + st->count= count; + st->frac = fill; + st->cycle= cycle; + st->disorder=disorder; + st->handedness=handedness; +#else + st->count= get_integer_resource(st->dpy, "count", "Integer"); + st->frac = get_integer_resource(st->dpy, "fill", "Integer")*0.01; + st->cycle= get_boolean_resource(st->dpy, "cycle", "Cycle"); + st->disorder=get_float_resource(st->dpy, "disorder", "Float"); + st->handedness=get_float_resource(st->dpy, "handedness", "Float"); +#endif + + if(st->frac<0.01) st->frac=0.01; + if(st->frac>0.99) st->frac=0.99; + if(st->count==0) st->count=st->width/32; + if(st->count<1) st->count=1; + if(st->count>1000) st->count=1000; + + if(st->worms) free(st->worms); + if(st->fill) free(st->fill); + + squiral_init_1 (st); + + return st; +} + +static unsigned long +squiral_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + + if(st->inclearheight) { + XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear); + memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width); + XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1, + st->height-st->inclear-1); + memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width); + st->inclear++; + XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear); + if (st->inclear < st->height) + memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width); + XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1, + st->height-st->inclear-1); + if (st->height - st->inclear >= 1) + memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width); + st->inclear++; + if(st->inclear>st->height/2) st->inclear=st->height; + } + else if(st->cov>(st->frac*st->width*st->height)) { + st->inclear=0; + st->cov=0; + } + for(i=0;icount;i++) do_worm(st, &st->worms[i]); + return st->delay; +} + +static void +squiral_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; + squiral_init_1 (st); + XClearWindow (dpy, window); +} + +#if 0 + static Bool + squiral_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +squiral_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *squiral_defaults[] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*fill: 75", + "*count: 0", + "*ncolors: 100", + "*delay: 10000", + "*disorder: 0.005", + "*cycle: False", + "*handedness: 0.5", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec squiral_options[] = { + {"-fill", ".fill", XrmoptionSepArg, 0}, + {"-count", ".count", XrmoptionSepArg, 0}, + {"-delay", ".delay", XrmoptionSepArg, 0}, + {"-disorder", ".disorder", XrmoptionSepArg, 0}, + {"-handedness", ".handedness", XrmoptionSepArg, 0}, + {"-ncolors", ".ncolors", XrmoptionSepArg, 0}, + {"-cycle", ".cycle", XrmoptionNoArg, "True"}, + {"-no-cycle", ".cycle", XrmoptionNoArg, "False"}, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Squiral", squiral) diff --git a/non-wgl/squiral.vcproj b/non-wgl/squiral.vcproj new file mode 100644 index 0000000..088122d --- /dev/null +++ b/non-wgl/squiral.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/src_only.bat b/non-wgl/src_only.bat new file mode 100644 index 0000000..6ebe2c3 --- /dev/null +++ b/non-wgl/src_only.bat @@ -0,0 +1,3 @@ +call clean.bat +if exist Debug rd /S /Q Debug +if exist Release rd /S /Q Release diff --git a/non-wgl/starfish.c b/non-wgl/starfish.c new file mode 100644 index 0000000..f2cf3ef --- /dev/null +++ b/non-wgl/starfish.c @@ -0,0 +1,591 @@ +/* xscreensaver, Copyright (c) 1997-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. + */ + +#include "screenhack.h" +#include +#include "spline.h" + +#define SCALE 1000 /* fixed-point math, for sub-pixel motion */ + + +#define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n)))) +#define RANDSIGN() ((random() & 1) ? 1 : -1) + + +char *background = "black"; +char *foreground = "white"; +int delay = 10000; +int thickness = 0; +int rotation = -1; +int colors = 200; +int duration = 30; +int delay2 = 5; +char *mode = "random"; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&thickness, "thickness", NULL, "0", t_Int}, + {&rotation, "rotation", NULL, "-1", t_Int}, + {&colors, "colors", NULL, "200", t_Int}, + {&duration, "duration", NULL, "30", t_Int}, + {&delay2, "delay2", NULL, "5", t_Int}, + {&mode, "mode", NULL, "random", t_String}, +}; + +enum starfish_mode { + pulse, + zoom +}; + +struct starfish { + enum starfish_mode mode; + Bool blob_p; + int skip; + long x, y; /* position of midpoint */ + double th; /* angle of rotation */ + double rotv; /* rotational velocity */ + double rota; /* rotational acceleration */ + long elasticity; /* how fast it deforms: radial velocity */ + double rot_max; + long min_r, max_r; /* radius range */ + int npoints; /* control points */ + long *r; /* radii */ + spline *spline; + XPoint *prev; + int n_prev; +}; + + +struct state { + Display *dpy; + Window window; + + Colormap cmap; + XColor *colors; + int ncolors; + int fg_index; + GC gc; + + int delay, delay2, duration, direction, blob_p; + + Bool done_once; + Bool initted; + unsigned long black, white; + + long tick; + time_t start_time; + + struct starfish *starfish; +}; + + +static struct starfish * +make_starfish (struct state *st, int maxx, int maxy, int size) +{ + struct starfish *s = (struct starfish *) calloc(1, sizeof(*s)); + int i; + int mid; + + s->blob_p = st->blob_p; + //s->elasticity = SCALE * get_float_resource (st->dpy, "thickness", "Thickness"); + s->elasticity = SCALE * thickness; + + if (s->elasticity == 0) + /* bell curve from 0-15, avg 7.5 */ + s->elasticity = RAND(5*SCALE) + RAND(5*SCALE) + RAND(5*SCALE); + + //s->rotv = get_float_resource (st->dpy, "rotation", "Rotation"); + s->rotv = rotation; + if (s->rotv == -1) + /* bell curve from 0-12 degrees, avg 6 */ + s->rotv = frand(4) + frand(4) + frand(4); + + s->rotv /= 360; /* convert degrees to ratio */ + + if (s->blob_p) + { + s->elasticity *= 3; + s->rotv *= 3; + } + + s->rot_max = s->rotv * 2; + s->rota = 0.0004 + frand(0.0002); + + + if (! (random() % 20)) + size *= frand(0.35) + frand(0.35) + 0.3; + + { + static const char skips[] = { 2, 2, 2, 2, + 3, 3, 3, + 6, 6, + 12 }; + s->skip = skips[random() % sizeof(skips)]; + } + + if (! (random() % (s->skip == 2 ? 3 : 12))) + s->mode = zoom; + else + s->mode = pulse; + + maxx *= SCALE; + maxy *= SCALE; + size *= SCALE; + + s->max_r = size; + s->min_r = 0; + + if (s->min_r < (5*SCALE)) s->min_r = (5*SCALE); + mid = ((s->min_r + s->max_r) / 2); + + s->x = maxx/2; + s->y = maxy/2; + + s->th = frand(M_PI+M_PI) * RANDSIGN(); + + { + static const char sizes[] = { 3, 3, 3, 3, 3, + 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, + 8, 8, 8, + 10, + 35 }; + int nsizes = sizeof(sizes); + if (s->skip > 3) + nsizes -= 4; + s->npoints = s->skip * sizes[random() % nsizes]; + } + + s->spline = make_spline (s->npoints); + s->r = (long *) malloc (sizeof(*s->r) * s->npoints); + + for (i = 0; i < s->npoints; i++) + s->r[i] = ((i % s->skip) == 0) ? 0 : size; + + return s; +} + + +static void +free_starfish (struct starfish *s) +{ + if (s->r) free (s->r); + if (s->prev) free (s->prev); + if (s->spline) + { + if (s->spline->control_x) free (s->spline->control_x); + if (s->spline->control_y) free (s->spline->control_y); + if (s->spline->points) free (s->spline->points); + free (s->spline); + } + free (s); +} + + +static void +throb_starfish (struct starfish *s) +{ + int i; + double frac = ((M_PI+M_PI) / s->npoints); + + for (i = 0; i < s->npoints; i++) + { + long r = s->r[i]; + long ra = (r > 0 ? r : -r); + double th = (s->th > 0 ? s->th : -s->th); + long x, y; + long elasticity = s->elasticity; + + /* place control points evenly around perimiter, shifted by theta */ + x = s->x + ra * cos (i * frac + th); + y = s->y + ra * sin (i * frac + th); + + s->spline->control_x[i] = x / SCALE; + s->spline->control_y[i] = y / SCALE; + + if (s->mode == zoom && ((i % s->skip) == 0)) + continue; + + /* Slow down near the end points: move fastest in the middle. */ + { + double ratio = (double)ra / (double)(s->max_r - s->min_r); + if (ratio > 0.5) ratio = 1-ratio; /* flip */ + ratio *= 2; /* normalize */ + ratio = (ratio * 0.9) + 0.1; /* fudge */ + elasticity *= ratio; + } + + + /* Increase/decrease radius by elasticity */ + ra += (r >= 0 ? elasticity : -elasticity); + if ((i % s->skip) == 0) + ra += (elasticity / 2); + + r = ra * (r >= 0 ? 1 : -1); + + /* If we've reached the end (too long or too short) reverse direction. */ + if ((ra > s->max_r && r >= 0) || + (ra < s->min_r && r < 0)) + r = -r; + + s->r[i] = r; + } +} + + +static void +spin_starfish (struct starfish *s) +{ + double th = s->th; + if (th < 0) + th = -(th + s->rotv); + else + th += s->rotv; + + if (th > (M_PI+M_PI)) + th -= (M_PI+M_PI); + else if (th < 0) + th += (M_PI+M_PI); + + s->th = (s->th > 0 ? th : -th); + + s->rotv += s->rota; + + if (s->rotv > s->rot_max || + s->rotv < -s->rot_max) + { + s->rota = -s->rota; + } + /* If it stops, start it going in the other direction. */ + else if (s->rotv < 0) + { + if (random() & 1) + { + /* keep going in the same direction */ + s->rotv = 0; + if (s->rota < 0) + s->rota = -s->rota; + } + else + { + /* reverse gears */ + s->rotv = -s->rotv; + s->rota = -s->rota; + s->th = -s->th; + } + } + + + /* Alter direction of rotational acceleration randomly. */ + if (! (random() % 120)) + s->rota = -s->rota; + + /* Change acceleration very occasionally. */ + if (! (random() % 200)) + { + if (random() & 1) + s->rota *= 1.2; + else + s->rota *= 0.8; + } +} + + +static void +draw_starfish (struct state *st, Drawable drawable, GC this_gc, struct starfish *s, + Bool fill_p) +{ + compute_closed_spline (s->spline); + if (s->prev) + { + XPoint *points = (XPoint *) + malloc (sizeof(XPoint) * (s->n_prev + s->spline->n_points + 2)); + int i = s->spline->n_points; + int j = s->n_prev; + memcpy (points, s->spline->points, (i * sizeof(*points))); + memcpy (points+i, s->prev, (j * sizeof(*points))); + + if (s->blob_p) + XClearWindow (st->dpy, drawable); + XFillPolygon (st->dpy, drawable, this_gc, points, i+j, Complex, CoordModeOrigin); + free (points); + + free (s->prev); + s->prev = 0; + } + + s->prev = (XPoint *) malloc (s->spline->n_points * sizeof(XPoint)); + memcpy (s->prev, s->spline->points, s->spline->n_points * sizeof(XPoint)); + s->n_prev = s->spline->n_points; + +#ifdef DEBUG + if (s->blob_p) + { + int i; + for (i = 0; i < s->npoints; i++) + XDrawLine (st->dpy, drawable, this_gc, s->x/SCALE, s->y/SCALE, + s->spline->control_x[i], s->spline->control_y[i]); + } +#endif +} + + +static struct starfish * +make_window_starfish (struct state *st) +{ + XWindowAttributes xgwa; + int size; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + size = (xgwa.width < xgwa.height ? xgwa.width : xgwa.height); + if (st->blob_p) size /= 2; + else size *= 1.3; + return make_starfish (st, xgwa.width, xgwa.height, size); +} + + +static struct starfish * +reset_starfish (struct state *st) +{ + XGCValues gcv; + unsigned int flags = 0; + XWindowAttributes xgwa; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->cmap = xgwa.colormap; + + if (st->done_once) + { + if (st->colors && st->ncolors) + free_colors (xgwa.screen, st->cmap, st->colors, st->ncolors); + if (st->colors) + free (st->colors); + st->colors = 0; + XFreeGC (st->dpy, st->gc); + st->gc = 0; + } + + //st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors = colors; + if (st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + + if (mono_p) + st->colors = 0; + else + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + + if (mono_p) + ; + else if (random() % 3) + make_smooth_colormap (xgwa.screen, xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + else + make_uniform_colormap (xgwa.screen, xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + + if (st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + + st->fg_index = 0; + + if (!mono_p && !st->blob_p) + { + flags |= GCForeground; + gcv.foreground = st->colors[st->fg_index].pixel; + XSetWindowBackground (st->dpy, st->window, gcv.foreground); + } + + if (!st->done_once) + { + XClearWindow (st->dpy, st->window); + st->done_once = 1; + } + + flags |= GCFillRule; + gcv.fill_rule = EvenOddRule; + st->gc = XCreateGC (st->dpy, st->window, flags, &gcv); + + return make_window_starfish (st); +} + + + +static void +run_starfish (struct state *st, struct starfish *s) +{ + throb_starfish (s); + spin_starfish (s); + draw_starfish (st, st->window, st->gc, s, False); + + if (mono_p) + { + if (!st->initted) + { +#if 1 + st->black = load_color(st->dpy, st->cmap, background); + st->white = load_color(st->dpy, st->cmap, foreground); +#else + st->black = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + st->white = get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); +#endif + st->initted = True; + st->fg_index = st->white; + XSetForeground (st->dpy, st->gc, st->fg_index); + } + else if (!s->blob_p) + { + st->fg_index = (st->fg_index == st->black ? st->white : st->black); + XSetForeground (st->dpy, st->gc, st->fg_index); + } + } + else + { + st->fg_index = (st->fg_index + 1) % st->ncolors; + XSetForeground (st->dpy, st->gc, st->colors [st->fg_index].pixel); + } +} + + +static void * +starfish_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + char *s; + st->dpy = dpy; + st->window = window; +#if 1 + st->delay = delay; + st->delay2 = delay2; + st->duration = duration; + st->direction = (random() & 1) ? 1 : -1; + s = mode; +#else + st->delay = get_integer_resource (st->dpy, "delay", "Delay"); + st->delay2 = get_integer_resource (st->dpy, "delay2", "Delay") * 1000000; +/* st->duration = get_seconds_resource (st->dpy, "duration", "Seconds");*/ + st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + st->direction = (random() & 1) ? 1 : -1; + s = get_string_resource (st->dpy, "mode", "Mode"); +#endif + if (s && !strcasecmp (s, "blob")) + st->blob_p = True; + else if (s && !strcasecmp (s, "zoom")) + st->blob_p = False; + else if (!s || !*s || !strcasecmp (s, "random")) + st->blob_p = !(random() % 3); + else + fprintf (stderr, "%s: mode must be blob, zoom, or random", progname); + + if (st->blob_p) + st->delay *= 3; + + st->starfish = reset_starfish (st); + return st; +} + +static unsigned long +starfish_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + struct starfish *s = st->starfish; + time_t now; + + run_starfish (st, s); + + if (st->duration > 0) + { + if (st->start_time == 0) + st->start_time = time ((time_t) 0); + now = time ((time_t) 0); + if (st->start_time + st->duration < now) + { + st->start_time = now; + + free_starfish (s); + + /* Every now and then, pick new colors; otherwise, just build + a new starfish with the current colors. */ + if (! (random () % 10)) + s = reset_starfish (st); + else + s = make_window_starfish (st); + + st->starfish = s; + } + } + + return st->delay; +} + +static void +starfish_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + free_starfish (st->starfish); + st->starfish = 0; + st->starfish = reset_starfish (st); +} + +#if 0 +static Bool + starfish_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +starfish_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + + +static const char *starfish_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 10000", + "*thickness: 0", /* pixels, 0 = random */ + "*rotation: -1", /* degrees, -1 = "random" */ + "*colors: 200", + "*duration: 30", + "*delay2: 5", + "*mode: random", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec starfish_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-delay2", ".delay2", XrmoptionSepArg, 0 }, + { "-thickness", ".thickness", XrmoptionSepArg, 0 }, + { "-rotation", ".rotation", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-blob", ".mode", XrmoptionNoArg, "blob" }, + { "-zoom", ".mode", XrmoptionNoArg, "zoom" }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Starfish", starfish) diff --git a/non-wgl/starfish.vcproj b/non-wgl/starfish.vcproj new file mode 100644 index 0000000..2e16253 --- /dev/null +++ b/non-wgl/starfish.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/strange.c b/non-wgl/strange.c new file mode 100644 index 0000000..9af0bec --- /dev/null +++ b/non-wgl/strange.c @@ -0,0 +1,707 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* strange --- strange attractors */ + +#if 0 +static const char sccsid[] = "@(#)strange.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- +* Copyright (c) 1997 by Massimino Pascal +* +* 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: jwz@jwz.org: turned into a standalone program. +* Made it render into an offscreen bitmap and then copy +* that onto the screen, to reduce flicker. +* +* strange attractors are not so hard to find... +*/ + +/* TODO: Bring over tweaks from 3.x version. +* For a good idea of what's missing, diff strange.c.20081107-good2 against strange.c-3.29 +* We forked from the 3.29 series at 20081107, so anything added since then may be missing. +*/ + +#define STANDALONE + +# define MODE_strange +#define DELAY 10000 +#define NCOLORS 100 +# define DEFAULTS "*delay: 10000 \n" \ + "*ncolors: 100 \n" \ + "*fpsSolid: True \n" \ + "*ignoreRotation: True \n" \ + +# define SMOOTH_COLORS +# define refresh_strange 0 +# define strange_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* from the xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +#endif /* !STANDALONE */ + +#ifdef MODE_strange +#define DEF_CURVE "10" +#define DEF_POINTS "5500" + +/*static int curve;*/ +static int points = 5500; + +static XrmOptionDescRec opts[] = +{ +/* {"-curve", ".strange.curve", XrmoptionSepArg, 0}, */ + {"-points", ".strange.points", XrmoptionSepArg, 0}, +}; +static argtype vars[] = +{ +/* {&curve, "curve", "Curve", DEF_CURVE, t_Int},*/ + {&points, "points", "Points", DEF_POINTS, t_Int}, +}; +static OptionStruct desc[] = +{ +/* {"-curve", "set the curve factor of the attractors"},*/ + {"-points", "change the number of points/iterations each frame"}, +}; +ENTRYPOINT ModeSpecOpt strange_opts = +{sizeof opts / sizeof opts[0], opts, +sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct strange_description = +{"strange", "init_strange", "draw_strange", "release_strange", +"init_strange", "init_strange", (char *) NULL, &strange_opts, +1000, 1, 1, 1, 64, 1.0, "", +"Shows strange attractors", 0, NULL}; +#endif + +#ifdef HAVE_COCOA +# define NO_DBUF +#endif + +typedef float DBL; +typedef int PRM; + +#define UNIT (1<<12) +#define UNIT2 (1<<14) +/* #define UNIT2 (3140*UNIT/1000) */ + +#define SKIP_FIRST 100 +#define DBL_To_PRM(x) (PRM)( (DBL)(UNIT)*(x) ) + + +#define DO_FOLD(a) (a)<0 ? -A->Fold[ (-(a))&(UNIT2-1) ] : A->Fold[ (a)&(UNIT2-1) ] + +#if 0 +#define DO_FOLD(a) (a)<-UNIT2 ? -A->Fold[(-(a))%UNIT2] : (a)<0 ? -A->Fold[ -(a) ] :\ +(a)>UNIT2 ? A->Fold[ (a)%UNIT2 ] : A->Fold[ (a) ] +#define DO_FOLD(a) DBL_To_PRM( sin( (DBL)(a)/UNIT ) ) +#define DO_FOLD(a) (a)<0 ? DBL_To_PRM( exp( 16.0*(a)/UNIT2 ) )-1.0 : \ +DBL_To_PRM( 1.0-exp( -16.0*(a)/UNIT2 ) ) +#endif + +/* useAccumulator performs two functions: +* If it is defined, then support for the accumulator will be compiled. +* It is also the condition for which the accumulator renderer will engage. +*/ +#define useAccumulator (Root->Max_Pt > 6000) +#define ACC_GAMMA 10.0 +#define NUM_COLS 150 +/* Extra options: */ +#define VARY_SPEED_TO_AVOID_BOREDOM +#define POINTS_HISTORY +#define MERGE_FRAMES 3 + +/******************************************************************/ + +#define MAX_PRM 3*5 + +typedef struct _ATTRACTOR { + DBL Prm1[MAX_PRM], Prm2[MAX_PRM]; + PRM Prm[MAX_PRM], *Fold; + void (*Iterate) (struct _ATTRACTOR *, PRM, PRM, PRM *, PRM *); + XPoint *Buffer1, *Buffer2; + int Cur_Pt, Max_Pt; + int Col, Count, Speed; + int Width, Height; + Pixmap dbuf; /* jwz */ + GC dbuf_gc; + #ifdef useAccumulator + int **accMap; + #endif +} ATTRACTOR; + +static ATTRACTOR *Root = (ATTRACTOR *) NULL; + +#ifdef useAccumulator +static XColor* cols; +#endif + +#ifdef POINTS_HISTORY +static int numOldPoints; +static int* oldPointsX; +static int* oldPointsY; +static int oldPointsIndex; +static int startedClearing; +#endif + +static DBL Amp_Prm[MAX_PRM] = +{ + 1.0, 3.5, 3.5, 2.5, 4.7, + 1.0, 3.5, 3.6, 2.5, 4.7, + 1.0, 1.5, 2.2, 2.1, 3.5 +}; +static DBL Mid_Prm[MAX_PRM] = +{ + 0.0, 1.5, 0.0, .5, 1.5, + 0.0, 1.5, 0.0, .5, 1.5, + 0.0, 1.5, -1.0, -.5, 2.5, +}; + +static DBL +Gauss_Rand(DBL c, DBL A, DBL S) +{ + DBL y; + + y = (DBL) LRAND() / MAXRAND; + y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S)); + if (NRAND(2)) + return (c + y); + else + return (c - y); +} + +static void +Random_Prm(DBL * Prm) +{ + int i; + + for (i = 0; i < MAX_PRM; ++i) + Prm[i] = Gauss_Rand(Mid_Prm[i], Amp_Prm[i], 4.0); +} + +/***************************************************************/ + + /* 2 examples of non-linear map */ + +static void +Iterate_X2(ATTRACTOR * A, PRM x, PRM y, PRM * xo, PRM * yo) +{ + PRM xx, yy, xy, x2y, y2x, Tmp; + + xx = (x * x) / UNIT; + x2y = (xx * y) / UNIT; + yy = (y * y) / UNIT; + y2x = (yy * x) / UNIT; + xy = (x * y) / UNIT; + + Tmp = A->Prm[1] * xx + A->Prm[2] * xy + A->Prm[3] * yy + A->Prm[4] * x2y; + Tmp = A->Prm[0] - y + (Tmp / UNIT); + *xo = DO_FOLD(Tmp); + Tmp = A->Prm[6] * xx + A->Prm[7] * xy + A->Prm[8] * yy + A->Prm[9] * y2x; + Tmp = A->Prm[5] + x + (Tmp / UNIT); + *yo = DO_FOLD(Tmp); +} + +static void +Iterate_X3(ATTRACTOR * A, PRM x, PRM y, PRM * xo, PRM * yo) +{ + PRM xx, yy, xy, x2y, y2x, Tmp_x, Tmp_y, Tmp_z; + + xx = (x * x) / UNIT; + x2y = (xx * y) / UNIT; + yy = (y * y) / UNIT; + y2x = (yy * x) / UNIT; + xy = (x * y) / UNIT; + + Tmp_x = A->Prm[1] * xx + A->Prm[2] * xy + A->Prm[3] * yy + A->Prm[4] * x2y; + Tmp_x = A->Prm[0] - y + (Tmp_x / UNIT); + Tmp_x = DO_FOLD(Tmp_x); + + Tmp_y = A->Prm[6] * xx + A->Prm[7] * xy + A->Prm[8] * yy + A->Prm[9] * y2x; + Tmp_y = A->Prm[5] + x + (Tmp_y / UNIT); + + Tmp_y = DO_FOLD(Tmp_y); + + Tmp_z = A->Prm[11] * xx + A->Prm[12] * xy + A->Prm[13] * yy + A->Prm[14] * y2x; + Tmp_z = A->Prm[10] + x + (Tmp_z / UNIT); + Tmp_z = UNIT + Tmp_z * Tmp_z / UNIT; + + *xo = (Tmp_x * UNIT) / Tmp_z; + *yo = (Tmp_y * UNIT) / Tmp_z; +} + +static void (*Funcs[2]) (ATTRACTOR *, PRM, PRM, PRM *, PRM *) = { + Iterate_X2, Iterate_X3 +}; + +/***************************************************************/ + +static void +free_strange(Display *display, ATTRACTOR *A) +{ + if (A->Buffer1 != NULL) { + (void) free((void *) A->Buffer1); + A->Buffer1 = (XPoint *) NULL; + } + if (A->Buffer2 != NULL) { + (void) free((void *) A->Buffer2); + A->Buffer2 = (XPoint *) NULL; + } + if (A->dbuf) { + XFreePixmap(display, A->dbuf); + A->dbuf = None; + } + if (A->dbuf_gc) { + XFreeGC(display, A->dbuf_gc); + A->dbuf_gc = None; + } + if (A->Fold != NULL) { + (void) free((void *) A->Fold); + A->Fold = (PRM *) NULL; + } +} + +ENTRYPOINT void +draw_strange(ModeInfo * mi) +{ + int i, j, n, Cur_Pt; + PRM x, y, xo, yo; + DBL u; + XPoint *Buf; + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + DBL Lx, Ly; + void (*Iterate) (ATTRACTOR *, PRM, PRM, PRM *, PRM *); + PRM xmin, xmax, ymin, ymax; + ATTRACTOR *A; + + if (Root == NULL) + return; + A = &Root[MI_SCREEN(mi)]; + if (A->Fold == NULL) + return; + + Cur_Pt = A->Cur_Pt; + Iterate = A->Iterate; + + u = (DBL) (A->Count) / 40000.0; + for (j = MAX_PRM - 1; j >= 0; --j) + A->Prm[j] = DBL_To_PRM((1.0 - u) * A->Prm1[j] + u * A->Prm2[j]); + + /* We collect the accumulation of the orbits in the 2d int array field. */ +#ifndef POINTS_HISTORY + #ifdef useAccumulator + if (useAccumulator) { + for (i=0;iWidth;i++) { + for (j=0;jHeight;j++) { + A->accMap[i][j] = 0; + + } + } + } + #endif +#endif + + x = y = DBL_To_PRM(.0); + for (n = SKIP_FIRST; n; --n) { + (*Iterate) (A, x, y, &xo, &yo); + x = xo + NRAND(8) - 4; + y = yo + NRAND(8) - 4; + } + + xmax = 0; + xmin = UNIT * 4; + ymax = 0; + ymin = UNIT * 4; + A->Cur_Pt = 0; + Buf = A->Buffer2; + Lx = (DBL) A->Width / UNIT / 2.2; + Ly = (DBL) A->Height / UNIT / 2.2; + for (n = A->Max_Pt; n; --n) { + (*Iterate) (A, x, y, &xo, &yo); + #ifdef useAccumulator + if (useAccumulator) { + int mx,my; + mx = (short) ( A->Width*0.1 + A->Width*0.8 * (xo - xmin) / (xmax - xmin) ); + my = (short) ( A->Width*0.1 + (A->Height - A->Width*0.2) * (yo - ymin) / (ymax - ymin) ); + if (mx>=0 && my>=0 && mxWidth && myHeight) { + A->accMap[mx][my]++; + } +#ifdef POINTS_HISTORY + /* #define clearOldPoint(i) { if (startedClearing) { field[oldPoints[i].x][oldPoints[i].y]--; } } + #define saveUnplot(X,Y) { clearOldPoint(oldPointsIndex) oldPoints[oldPointsIndex].x = X; oldPoints[oldPointsIndex].y = Y; oldPointsIndex = (oldPointsIndex + 1) % numOldPoints; if (oldPointsIndex==0) { startedClearing=1; } } + saveUnplot(mx,my) */ + if (startedClearing) { + int oldX = oldPointsX[oldPointsIndex]; + int oldY = oldPointsY[oldPointsIndex]; + if (oldX>=0 && oldY>=0 && oldXWidth && oldYHeight) { + A->accMap[oldX][oldY]--; + } + } + oldPointsX[oldPointsIndex] = mx; + oldPointsY[oldPointsIndex] = my; + oldPointsIndex = (oldPointsIndex + 1) % numOldPoints; + if (oldPointsIndex==0) { startedClearing=1; } +#endif + } else { + #endif + Buf->x = (int) (Lx * (x + DBL_To_PRM(1.1))); + Buf->y = (int) (Ly * (DBL_To_PRM(1.1) - y)); + Buf++; + A->Cur_Pt++; + #ifdef useAccumulator + } + #endif + /* (void) fprintf( stderr, "X,Y: %d %d ", Buf->x, Buf->y ); */ + if (xo > xmax) + xmax = xo; + else if (xo < xmin) + xmin = xo; + if (yo > ymax) + ymax = yo; + else if (yo < ymin) + ymin = yo; + x = xo + NRAND(8) - 4; + y = yo + NRAND(8) - 4; + } + + MI_IS_DRAWN(mi) = True; + + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + + #ifdef useAccumulator + if (useAccumulator) { + float colorScale; + int col; + #ifdef VARY_SPEED_TO_AVOID_BOREDOM + int pixelCount = 0; + #endif + colorScale = (A->Width*A->Height/640.0/480.0*800000.0/(float)A->Max_Pt*(float)NUM_COLS/256); + if (A->dbuf != None) { + XSetForeground(display, A->dbuf_gc, 0); + XFillRectangle(display, A->dbuf, A->dbuf_gc, 0, 0, A->Width, A->Height); + } else { + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + XFillRectangle(display, window, gc, 0, 0, A->Width, A->Height); + } + for (i=0;iWidth;i++) { + for (j=0;jHeight;j++) { + if (A->accMap[i][j]>0) { + col = (float)A->accMap[i][j] * colorScale; + if (col>NUM_COLS-1) { + col = NUM_COLS-1; + } + #ifdef VARY_SPEED_TO_AVOID_BOREDOM + if (col>0) { + if (colCol % MI_NPIXELS(mi)));*/ + XSetForeground(display, gc, cols[col].pixel); + if (A->dbuf != None) { + XSetForeground(display, A->dbuf_gc, cols[col].pixel); + XDrawPoint(display, A->dbuf, A->dbuf_gc, i, j); + } else { + XSetForeground(display, gc, cols[col].pixel); + XDrawPoint(display, window, gc, i, j); + } + } + } + } + if (A->dbuf != None) { + XCopyArea(display, A->dbuf, window, gc, 0, 0, A->Width, A->Height, 0, 0); + } + #ifdef VARY_SPEED_TO_AVOID_BOREDOM + /* Increaase the rate of change of the parameters if the attractor has become visually boring. */ + if ((xmax - xmin < DBL_To_PRM(.2)) && (ymax - ymin < DBL_To_PRM(.2))) { + A->Speed *= 1.25; + } else if (pixelCount>0 && pixelCountWidth*A->Height/1000) { + A->Speed *= 1.25; /* A->Count = 1000; */ + } else { + A->Speed = 4; /* reset to normal/default */ + } + if (A->Speed > 32) + A->Speed = 32; + A->Count += A->Speed; + if (A->Count >= 1000) { + for (i = MAX_PRM - 1; i >= 0; --i) + A->Prm1[i] = A->Prm2[i]; + Random_Prm(A->Prm2); + A->Count = 0; + } + #endif + } else { + #endif + + if (A->dbuf != None) { /* jwz */ + XSetForeground(display, A->dbuf_gc, 0); +/* XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer1, + Cur_Pt,CoordModeOrigin); */ + XFillRectangle(display, A->dbuf, A->dbuf_gc, 0, 0, A->Width, A->Height); + } else + XDrawPoints(display, window, gc, A->Buffer1, Cur_Pt, CoordModeOrigin); + + if (MI_NPIXELS(mi) < 2) + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + else + XSetForeground(display, gc, MI_PIXEL(mi, A->Col % MI_NPIXELS(mi))); + + if (A->dbuf != None) { + XSetForeground(display, A->dbuf_gc, 1); + XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer2, A->Cur_Pt, + CoordModeOrigin); + XCopyPlane(display, A->dbuf, window, gc, 0, 0, A->Width, A->Height, 0, 0, 1); + } else + XDrawPoints(display, window, gc, A->Buffer2, A->Cur_Pt, CoordModeOrigin); + + #ifdef useAccumulator + } + #endif + + Buf = A->Buffer1; + A->Buffer1 = A->Buffer2; + A->Buffer2 = Buf; + + if ((xmax - xmin < DBL_To_PRM(.2)) && (ymax - ymin < DBL_To_PRM(.2))) + A->Count += 4 * A->Speed; + else + A->Count += A->Speed; + if (A->Count >= 1000) { + for (i = MAX_PRM - 1; i >= 0; --i) + A->Prm1[i] = A->Prm2[i]; + Random_Prm(A->Prm2); + A->Count = 0; + } + A->Col++; + mi->recursion_depth = A->Count; +} + + +/***************************************************************/ + +ENTRYPOINT void +init_strange(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); +#ifndef NO_DBUF + GC gc = MI_GC(mi); +#endif + ATTRACTOR *Attractor; + +#ifdef POINTS_HISTORY + startedClearing=0; + oldPointsIndex=0; +#endif + + if (Root == NULL) { + if ((Root = (ATTRACTOR *) calloc(MI_NUM_SCREENS(mi), + sizeof (ATTRACTOR))) == NULL) + return; + } + Attractor = &Root[MI_SCREEN(mi)]; + + if (Attractor->Fold == NULL) { + int i; + + if ((Attractor->Fold = (PRM *) calloc(UNIT2 + 1, + sizeof (PRM))) == NULL) { + free_strange(display, Attractor); + return; + } + for (i = 0; i <= UNIT2; ++i) { + DBL x; + + /* x = ( DBL )(i)/UNIT2; */ + /* x = sin( M_PI/2.0*x ); */ + /* x = sqrt( x ); */ + /* x = x*x; */ + /* x = x*(1.0-x)*4.0; */ + x = (DBL) (i) / UNIT; + x = sin(x); + Attractor->Fold[i] = DBL_To_PRM(x); + } + } + + Attractor->Max_Pt = points; + + if (Attractor->Buffer1 == NULL) + if ((Attractor->Buffer1 = (XPoint *) calloc(Attractor->Max_Pt, + sizeof (XPoint))) == NULL) { + free_strange(display, Attractor); + return; + } + if (Attractor->Buffer2 == NULL) + if ((Attractor->Buffer2 = (XPoint *) calloc(Attractor->Max_Pt, + sizeof (XPoint))) == NULL) { + free_strange(display, Attractor); + return; + } + + Attractor->Width = MI_WIDTH(mi); + Attractor->Height = MI_HEIGHT(mi); + Attractor->Cur_Pt = 0; + Attractor->Count = 0; + Attractor->Col = NRAND(MI_NPIXELS(mi)); + Attractor->Speed = 4; + + Attractor->Iterate = Funcs[NRAND(2)]; + Random_Prm(Attractor->Prm1); + Random_Prm(Attractor->Prm2); +#ifndef NO_DBUF + if (Attractor->dbuf != None) + XFreePixmap(display, Attractor->dbuf); +#ifdef useAccumulator +#define colorDepth ( useAccumulator ? MI_DEPTH(mi) : 1 ) +#else +#define colorDepth 1 +#endif + Attractor->dbuf = XCreatePixmap(display, window, + Attractor->Width, Attractor->Height, colorDepth); + /* Allocation checked */ + if (Attractor->dbuf != None) { + XGCValues gcv; + + gcv.foreground = 0; + gcv.background = 0; +#ifndef HAVE_COCOA + gcv.graphics_exposures = False; +#endif /* HAVE_COCOA */ + gcv.function = GXcopy; + + if (Attractor->dbuf_gc != None) + XFreeGC(display, Attractor->dbuf_gc); + + if ((Attractor->dbuf_gc = XCreateGC(display, Attractor->dbuf, +#ifndef HAVE_COCOA + GCGraphicsExposures | +#endif /* HAVE_COCOA */ + GCFunction | GCForeground | GCBackground, + &gcv)) == None) { + XFreePixmap(display, Attractor->dbuf); + Attractor->dbuf = None; + } else { + XFillRectangle(display, Attractor->dbuf, Attractor->dbuf_gc, + 0, 0, Attractor->Width, Attractor->Height); + XSetBackground(display, gc, MI_BLACK_PIXEL(mi)); + XSetFunction(display, gc, GXcopy); + } + } +#endif + + +#ifdef useAccumulator + #define A Attractor + if (useAccumulator) { + XWindowAttributes xgwa; + int i,j; + XGetWindowAttributes (display, window, &xgwa); + /* cmap = xgwa.colormap; */ + /* cmap = XCreateColormap(display, window, MI_VISUAL(mi), AllocAll); */ + Attractor->accMap = (int**)calloc(Attractor->Width,sizeof(int*)); + for (i=0;iWidth;i++) { + Attractor->accMap[i] = (int*)calloc(Attractor->Height,sizeof(int)); + for (j=0;jHeight;j++) { + Attractor->accMap[i][j] = 0; + } + } +#ifdef POINTS_HISTORY + numOldPoints = A->Max_Pt * MERGE_FRAMES; + oldPointsX = (int*)calloc(numOldPoints,sizeof(int)); + oldPointsY = (int*)calloc(numOldPoints,sizeof(int)); +#endif + cols = (XColor*)calloc(NUM_COLS,sizeof(XColor)); + for (i=0;iWidth;i++) { + (void) free((void *) Root->accMap[i]); + } + (void) free((void *) Root->accMap); +#endif +#ifdef POINTS_HISTORY + free(oldPointsX); + free(oldPointsY); +#endif + for (screen = 0; screen < MI_NUM_SCREENS(mi); ++screen) + free_strange(MI_DISPLAY(mi), &Root[screen]); + (void) free((void *) Root); + Root = (ATTRACTOR *) NULL; + } +} + +XSCREENSAVER_MODULE ("Strange", strange) + +#endif /* MODE_strange */ diff --git a/non-wgl/strange.vcproj b/non-wgl/strange.vcproj new file mode 100644 index 0000000..cc48fe9 --- /dev/null +++ b/non-wgl/strange.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/substrate.c b/non-wgl/substrate.c new file mode 100644 index 0000000..07b86ae --- /dev/null +++ b/non-wgl/substrate.c @@ -0,0 +1,782 @@ +/* + * Substrate (dragorn@kismetwireless.net) + * Directly ported code from complexification.net Substrate art + * http://complexification.net/gallery/machines/substrate/applet_s/substrate_s.pde + * + * Substrate code: + * j.tarbell June, 2004 + * Albuquerque, New Mexico + * complexification.net + * + * CHANGES + * + * 1.1 dragorn Jan 04 2005 Fixed some indenting, typo in errors for parsing + * cmdline args + * 1.1 dagraz Jan 04 2005 Added option for circular cracks (David Agraz) + * Cleaned up issues with timeouts in start_crack (DA) + * 1.0 dragorn Oct 10 2004 First port done + * + * 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 + +/* 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 + +char *background = "white"; +char *foreground = "black"; +Bool wireFrame = False; +int maxCycles = 10000; +int growthDelay = 18000; +int initialCracks = 3; +int maxCracks = 100; +int sandGrains = 64; +int circlePercent = 33; + +static argtype vars[] = +{ + {&background, "background", NULL, "white", t_String}, + {&foreground, "foreground", NULL, "black", t_String}, + {&wireFrame, "wireFrame", NULL, "False", t_Bool}, + {&maxCycles, "maxCycles", NULL, "10000", t_Int}, + {&growthDelay, "growthDelay", NULL, "18000", t_Int}, + {&initialCracks, "initialCracks", NULL, "3", t_Int}, + {&maxCracks, "maxCracks", NULL, "100", t_Int}, + {&sandGrains, "sandGrains", NULL, "64", t_Int}, + {&circlePercent, "circlePercent", NULL, "33", t_Int}, +}; + +#define STEP 0.42 + +/* Raw colormap extracted from pollockEFF.gif */ +static const char *rgb_colormap[] = { + "#201F21", "#262C2E", "#352626", "#372B27", + "#302C2E", "#392B2D", "#323229", "#3F3229", + "#38322E", "#2E333D", "#333A3D", "#473329", + "#40392C", "#40392E", "#47402C", "#47402E", + "#4E402C", "#4F402E", "#4E4738", "#584037", + "#65472D", "#6D5D3D", "#745530", "#755532", + "#745D32", "#746433", "#7C6C36", "#523152", + "#444842", "#4C5647", "#655D45", "#6D5D44", + "#6C5D4E", "#746C43", "#7C6C42", "#7C6C4B", + "#6B734B", "#73734B", "#7B7B4A", "#6B6C55", + "#696D5E", "#7B6C5D", "#6B7353", "#6A745D", + "#727B52", "#7B7B52", "#57746E", "#687466", + "#9C542B", "#9D5432", "#9D5B35", "#936B36", + "#AA7330", "#C45A27", "#D95223", "#D85A20", + "#DB5A23", "#E57037", "#836C4B", "#8C6B4B", + "#82735C", "#937352", "#817B63", "#817B6D", + "#927B63", "#D9893B", "#E49832", "#DFA133", + "#E5A037", "#F0AB3B", "#8A8A59", "#B29A58", + "#89826B", "#9A8262", "#888B7C", "#909A7A", + "#A28262", "#A18A69", "#A99968", "#99A160", + "#99A168", "#CA8148", "#EB8D43", "#C29160", + "#C29168", "#D1A977", "#C9B97F", "#F0E27B", + "#9F928B", "#C0B999", "#E6B88F", "#C8C187", + "#E0C886", "#F2CC85", "#F5DA83", "#ECDE9D", + "#F5D294", "#F5DA94", "#F4E784", "#F4E18A", + "#F4E193", "#E7D8A7", "#F1D4A5", "#F1DCA5", + "#F4DBAD", "#F1DCAE", "#F4DBB5", "#F5DBBD", + "#F4E2AD", "#F5E9AD", "#F4E3BE", "#F5EABE", + "#F7F0B6", "#D9D1C1", "#E0D0C0", "#E7D8C0", + "#F1DDC6", "#E8E1C0", "#F3EDC7", "#F6ECCE", + "#F8F2C7", "#EFEFD0", 0 +}; + +typedef struct { + /* Synthesis of data from Crack:: and SandPainter:: */ + float x, y; + float t; + float ys, xs, t_inc; /* for curvature calculations */ + + int curved; + + unsigned long sandcolor; + float sandp, sandg; + + float degrees_drawn; + + int crack_num; + +} crack; + +struct field { + unsigned int height; + unsigned int width; + + unsigned int initial_cracks; + + unsigned int num; + unsigned int max_num; + + int grains; /* number of grains in the sand painting */ + + int circle_percent; + + crack *cracks; /* grid of cracks */ + int *cgrid; /* grid of actual crack placement */ + + /* Raw map of pixels we need to keep for alpha blending */ + unsigned long int *off_img; + + /* color parms */ + int numcolors; + unsigned long *parsedcolors; + unsigned long fgcolor; + unsigned long bgcolor; + int visdepth; + + unsigned int cycles; + + unsigned int wireframe; +}; + +struct state { + Display *dpy; + Window window; + + struct field *f; + unsigned int max_cycles; + int growth_delay; + GC fgc; + XWindowAttributes xgwa; + XGCValues gcv; +}; + + +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(void) +{ + struct field *f = xrealloc(NULL, sizeof(struct field)); + f->height = 0; + f->width = 0; + f->initial_cracks = 0; + f->num = 0; + f->max_num = 0; + f->cracks = NULL; + f->cgrid = NULL; + f->off_img = NULL; + f->numcolors = 0; + f->parsedcolors = NULL; + f->cycles = 0; + f->wireframe = 0; + f->fgcolor = 0; + f->bgcolor = 0; + f->visdepth = 0; + f->grains = 0; + f->circle_percent = 0; + return f; +} + +/* Quick references to pixels in the offscreen map and in the crack grid */ +#define ref_pixel(f, x, y) ((f)->off_img[(y) * (f)->width + (x)]) +#define ref_cgrid(f, x, y) ((f)->cgrid[(y) * (f)->width + (x)]) + +static inline void start_crack(struct field *f, crack *cr) +{ + /* synthesis of Crack::findStart() and crack::startCrack() */ + int px = 0; + int py = 0; + int found = 0; + int timeout = 0; + float a; + + /* shift until crack is found */ + while ((!found) && (timeout++ < 10000)) { + px = (int) (random() % f->width); + py = (int) (random() % f->height); + + if (ref_cgrid(f, px, py) < 10000) + found = 1; + } + + if ( !found ) { + /* We timed out. Use our default values */ + px = cr->x; + py = cr->y; + + /* Sanity check needed */ + if (px < 0) px = 0; + if (px >= f->width) px = f->width - 1; + if (py < 0) py = 0; + if (py >= f->height) py = f->height - 1; + + ref_cgrid(f, px, py) = cr->t; + } + + /* start a crack */ + a = ref_cgrid(f, px, py); + + if ((random() % 100) < 50) { + /* conversion of the java int(random(-2, 2.1)) */ + a -= 90 + (frand(4.1) - 2.0); + } else { + a += 90 + (frand(4.1) - 2.0); + } + + if ((random() % 100) < f->circle_percent) { + float r; /* radius */ + float radian_inc; + + cr->curved = 1; + cr->degrees_drawn = 0; + + r = 10 + (random() % ((f->width + f->height) / 2)); + + if ((random() % 100) < 50) { + r *= -1; + } + + /* arc length = r * theta => theta = arc length / r */ + radian_inc = STEP / r; + cr->t_inc = radian_inc * 360 / 2 / M_PI; + + cr->ys = r * sin(radian_inc); + cr->xs = r * ( 1 - cos(radian_inc)); + + } + else { + cr->curved = 0; + } + + /* Condensed from Crack::startCrack */ + cr->x = px + ((float) 0.61 * cos(a * M_PI / 180)); + cr->y = py + ((float) 0.61 * sin(a * M_PI / 180)); + cr->t = a; + +} + +static inline void make_crack(struct field *f) +{ + crack *cr; + + if (f->num < f->max_num) { + /* make a new crack */ + f->cracks = (crack *) xrealloc(f->cracks, sizeof(crack) * (f->num + 1)); + + cr = &(f->cracks[f->num]); + /* assign colors */ + cr->sandp = 0; + cr->sandg = (frand(0.2) - 0.01); + cr->sandcolor = f->parsedcolors[random() % f->numcolors]; + cr->crack_num = f->num; + cr->curved = 0; + cr->degrees_drawn = 0; + + /* We could use these values in the timeout case of start_crack */ + + cr->x = random() % f->width; + cr->y = random() % f->height; + cr->t = random() % 360; + + /* start it */ + start_crack(f, cr); + + f->num++; + } +} + +static inline void point2rgb(int depth, unsigned long c, int *r, int *g, int *b) +{ + switch(depth) { + case 32: + case 24: +#ifdef HAVE_COCOA + /* 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 inline unsigned long rgb2point(int depth, int r, int g, int b) +{ + unsigned long ret = 0; + + switch(depth) { + case 32: + case 24: +#ifdef HAVE_COCOA + /* 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; +} + +/* alpha blended point drawing -- this is Not Right and will likely fail on + * non-intel platforms as it is now, needs fixing */ +static inline unsigned long +trans_point(struct state *st, + int x1, int y1, unsigned long myc, float a, + struct field *f) +{ + if ((x1 >= 0) && (x1 < f->width) && (y1 >= 0) && (y1 < f->height)) { + if (a >= 1.0) { + ref_pixel(f, x1, y1) = myc; + } else { + int or = 0, og = 0, ob = 0; + int r = 0, g = 0, b = 0; + int nr, ng, nb; + unsigned long c; + + c = ref_pixel(f, x1, y1); + + point2rgb(f->visdepth, c, &or, &og, &ob); + point2rgb(f->visdepth, myc, &r, &g, &b); + + nr = or + (r - or) * a; + ng = og + (g - og) * a; + nb = ob + (b - ob) * a; + + c = rgb2point(f->visdepth, nr, ng, nb); + + ref_pixel(f, x1, y1) = c; + + return c; + } + } + + return f->bgcolor; +} + +static inline void +region_color(struct state *st, GC fgc, struct field *f, crack *cr) +{ + /* synthesis of Crack::regionColor() and SandPainter::render() */ + + float rx = cr->x; + float ry = cr->y; + int openspace = 1; + int cx, cy; + float maxg; + int grains, i; + float w; + float drawx, drawy; + unsigned long c; + + while (openspace) { + /* move perpendicular to crack */ + rx += (0.81 * sin(cr->t * M_PI/180)); + ry -= (0.81 * cos(cr->t * M_PI/180)); + + cx = (int) rx; + cy = (int) ry; + + if ((cx >= 0) && (cx < f->width) && (cy >= 0) && (cy < f->height)) { + /* safe to check */ + if (f->cgrid[cy * f->width + cx] > 10000) { + /* space is open */ + } else { + openspace = 0; + } + } else { + openspace = 0; + } + } + + /* SandPainter stuff here */ + + /* Modulate gain */ + cr->sandg += (frand(0.1) - 0.050); + maxg = 1.0; + + if (cr->sandg < 0) + cr->sandg = 0; + + if (cr->sandg > maxg) + cr->sandg = maxg; + + grains = f->grains; + + /* Lay down grains of sand */ + w = cr->sandg / (grains - 1); + + for (i = 0; i < grains; i++) { + drawx = (cr->x + (rx - cr->x) * sin(cr->sandp + sin((float) i * w))); + drawy = (cr->y + (ry - cr->y) * sin(cr->sandp + sin((float) i * w))); + + /* Draw sand bit */ + c = trans_point(st, drawx, drawy, cr->sandcolor, (0.1 - i / (grains * 10.0)), f); + + XSetForeground(st->dpy, fgc, c); + XDrawPoint(st->dpy, st->window, fgc, (int) drawx, (int) drawy); + XSetForeground(st->dpy, fgc, f->fgcolor); + } +} + +static void build_substrate(struct field *f) +{ + int tx; + /* int ty; */ + + f->cycles = 0; + + if (f->cgrid) { + free(f->cgrid); + f->cgrid = NULL; + } + + if (f->cracks) { + free(f->cracks); + f->cracks = NULL; + } + + f->num = 0; + + /* erase the crack grid */ + f->cgrid = (int *) xrealloc(f->cgrid, sizeof(int) * f->height * f->width); + memset(f->cgrid, 10001, f->height * f->width * sizeof(int)); + + /* Not necessary now that make_crack ensures we have usable default + * values in start_crack's timeout case + * make random crack seeds * + for (tx = 0; tx < 16; tx++) { + ty = (int) (random() % (f->width * f->height - 1)); + f->cgrid[ty] = (int) random() % 360; + } + */ + + /* make the initial cracks */ + for (tx = 0; tx < f->initial_cracks; tx++) + make_crack(f); +} + + +static inline void +movedrawcrack(struct state *st, GC fgc, struct field *f, int cracknum) +{ + /* Basically Crack::move() */ + + int cx, cy; + crack *cr = &(f->cracks[cracknum]); + + /* continue cracking */ + if ( !cr->curved ) { + cr->x += ((float) STEP * cos(cr->t * M_PI/180)); + cr->y += ((float) STEP * sin(cr->t * M_PI/180)); + } + else { + cr->x += ((float) cr->ys * cos(cr->t * M_PI/180)); + cr->y += ((float) cr->ys * sin(cr->t * M_PI/180)); + + cr->x += ((float) cr->xs * cos(cr->t * M_PI/180 - M_PI / 2)); + cr->y += ((float) cr->xs * sin(cr->t * M_PI/180 - M_PI / 2)); + + cr->t += cr->t_inc; + cr->degrees_drawn += abs(cr->t_inc); + } + + /* bounds check */ + /* modification of random(-0.33,0.33) */ + cx = (int) (cr->x + (frand(0.66) - 0.33)); + cy = (int) (cr->y + (frand(0.66) - 0.33)); + + + if ((cx >= 0) && (cx < f->width) && (cy >= 0) && (cy < f->height)) { + /* draw sand painter if we're not wireframe */ + if (!f->wireframe) + region_color(st, fgc, f, cr); + + /* draw fgcolor crack */ + ref_pixel(f, cx, cy) = f->fgcolor; + XDrawPoint(st->dpy, st->window, fgc, cx, cy); + + if ( cr->curved && (cr->degrees_drawn > 360) ) { + /* completed the circle, stop cracking */ + start_crack(f, cr); /* restart ourselves */ + make_crack(f); /* generate a new crack */ + } + /* safe to check */ + else if ((f->cgrid[cy * f->width + cx] > 10000) || + (abs(f->cgrid[cy * f->width + cx] - cr->t) < 5)) { + /* continue cracking */ + f->cgrid[cy * f->width + cx] = (int) cr->t; + } else if (abs(f->cgrid[cy * f->width + cx] - cr->t) > 2) { + /* crack encountered (not self), stop cracking */ + start_crack(f, cr); /* restart ourselves */ + make_crack(f); /* generate a new crack */ + } + } else { + /* out of bounds, stop cracking */ + + /* need these in case of timeout in start_crack */ + cr->x = random() % f->width; + cr->y = random() % f->height; + cr->t = random() % 360; + + start_crack(f, cr); /* restart ourselves */ + make_crack(f); /* generate a new crack */ + } + +} + + +static void build_img(Display *dpy, Window window, XWindowAttributes xgwa, GC fgc, + struct field *f) +{ + if (f->off_img) { + free(f->off_img); + f->off_img = NULL; + } + + f->off_img = (unsigned long *) xrealloc(f->off_img, sizeof(unsigned long) * + f->width * f->height); + + memset(f->off_img, f->bgcolor, sizeof(unsigned long) * f->width * f->height); +} + + +static void * +substrate_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XColor tmpcolor; + + st->dpy = dpy; + st->window = window; + st->f = init_field(); + +#if 1 + st->growth_delay = growthDelay; + st->max_cycles = maxCycles; + st->f->initial_cracks = initialCracks; + st->f->max_num = maxCracks; + st->f->wireframe = wireFrame; + st->f->grains = sandGrains; + st->f->circle_percent = circlePercent; +#else + st->growth_delay = (get_integer_resource(st->dpy, "growthDelay", "Integer")); + st->max_cycles = (get_integer_resource(st->dpy, "maxCycles", "Integer")); + st->f->initial_cracks = (get_integer_resource(st->dpy, "initialCracks", "Integer")); + st->f->max_num = (get_integer_resource(st->dpy, "maxCracks", "Integer")); + st->f->wireframe = (get_boolean_resource(st->dpy, "wireFrame", "Boolean")); + st->f->grains = (get_integer_resource(st->dpy, "sandGrains", "Integer")); + st->f->circle_percent = (get_integer_resource(st->dpy, "circlePercent", "Integer")); +#endif + + if (st->f->initial_cracks <= 2) { + fprintf(stderr, "%s: Initial cracks must be greater than 2\n", progname); + exit (1); + } + + if (st->f->max_num <= 10) { + fprintf(stderr, "%s: Maximum number of cracks must be less than 10\n", + progname); + exit (1); + } + + if (st->f->circle_percent < 0) { + fprintf(stderr, "%s: circle percent must be at least 0\n", progname); + exit (1); + } + + if (st->f->circle_percent > 100) { + fprintf(stderr, "%s: circle percent must be less than 100\n", progname); + exit (1); + } + + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + + /* Count the colors in our map and assign them in a horrifically inefficient + * manner but it only happens once */ + while (rgb_colormap[st->f->numcolors] != NULL) { + st->f->parsedcolors = (unsigned long *) xrealloc(st->f->parsedcolors, + sizeof(unsigned long) * + (st->f->numcolors + 1)); + if (!XParseColor(st->dpy, st->xgwa.colormap, rgb_colormap[st->f->numcolors], &tmpcolor)) { + fprintf(stderr, "%s: couldn't parse color %s\n", progname, + rgb_colormap[st->f->numcolors]); + exit(1); + } + + if (!XAllocColor(st->dpy, st->xgwa.colormap, &tmpcolor)) { + fprintf(stderr, "%s: couldn't allocate color %s\n", progname, + rgb_colormap[st->f->numcolors]); + exit(1); + } + + st->f->parsedcolors[st->f->numcolors] = tmpcolor.pixel; + + st->f->numcolors++; + } + +#if 1 + st->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, foreground); + st->gcv.background = load_color(st->dpy, st->xgwa.colormap, background); +#else + st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->gcv.background = get_pixel_resource(st->dpy, st->xgwa.colormap, + "background", "Background"); +#endif + st->fgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); + + st->f->fgcolor = st->gcv.foreground; + st->f->bgcolor = st->gcv.background; + + /* Initialize stuff */ + build_img(st->dpy, st->window, st->xgwa, st->fgc, st->f); + build_substrate(st->f); + + return st; +} + +static unsigned long +substrate_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int tempx; + + if ((st->f->cycles % 10) == 0) { + + /* Restart if the window size changes */ + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + + if (st->f->height != st->xgwa.height || st->f->width != st->xgwa.width) { + st->f->height = st->xgwa.height; + st->f->width = st->xgwa.width; + st->f->visdepth = st->xgwa.depth; + + build_substrate(st->f); + build_img(st->dpy, st->window, st->xgwa, st->fgc, st->f); + XSetForeground(st->dpy, st->fgc, st->gcv.background); + XFillRectangle(st->dpy, st->window, st->fgc, 0, 0, st->xgwa.width, st->xgwa.height); + XSetForeground(st->dpy, st->fgc, st->gcv.foreground); + } + } + + for (tempx = 0; tempx < st->f->num; tempx++) { + movedrawcrack(st, st->fgc, st->f, tempx); + } + + st->f->cycles++; + + if (st->f->cycles >= st->max_cycles && st->max_cycles != 0) { + build_substrate(st->f); + build_img(st->dpy, st->window, st->xgwa, st->fgc, st->f); + XSetForeground(st->dpy, st->fgc, st->gcv.background); + XFillRectangle(st->dpy, st->window, st->fgc, 0, 0, st->xgwa.width, st->xgwa.height); + XSetForeground(st->dpy, st->fgc, st->gcv.foreground); + } + + /* #### mi->recursion_depth = st->f->cycles; */ + return st->growth_delay; +} + + +static void +substrate_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + substrate_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +substrate_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +static const char *substrate_defaults[] = { + ".background: white", + ".foreground: black", + "*fpsSolid: true", + "*wireFrame: false", + "*maxCycles: 10000", + "*growthDelay: 18000", + "*initialCracks: 3", + "*maxCracks: 100", + "*sandGrains: 64", + "*circlePercent: 33", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec substrate_options[] = { + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-wireframe", ".wireFrame", XrmoptionNoArg, "true"}, + {"-max-cycles", ".maxCycles", XrmoptionSepArg, 0}, + {"-growth-delay", ".growthDelay", XrmoptionSepArg, 0}, + {"-initial-cracks", ".initialCracks", XrmoptionSepArg, 0}, + {"-max-cracks", ".maxCracks", XrmoptionSepArg, 0}, + {"-sand-grains", ".sandGrains", XrmoptionSepArg, 0}, + {"-circle-percent", ".circlePercent", XrmoptionSepArg, 0}, + {0, 0, 0, 0} +}; + +XSCREENSAVER_MODULE ("Substrate", substrate) diff --git a/non-wgl/substrate.vcproj b/non-wgl/substrate.vcproj new file mode 100644 index 0000000..fa7be54 --- /dev/null +++ b/non-wgl/substrate.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/swirl.c b/non-wgl/swirl.c new file mode 100644 index 0000000..39bcc90 --- /dev/null +++ b/non-wgl/swirl.c @@ -0,0 +1,1497 @@ +/* -*- Mode: C; tab-width: 4 -*- + * swirl --- swirly color-cycling patterns. + */ +#if 0 +static const char sccsid[] = "@(#)swirl.c 4.00 97/01/01 xlockmore"; +#endif + +/* Copyright (c) 1994 M.Dobie + * + * 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. + * + * 13-May-97: jwz@jwz.org: turned into a standalone program. + * 21-Apr-95: improved startup time for TrueColour displays + * (limited to 16bpp to save memory) S.Early + * 09-Jan-95: fixed colour maps (more colourful) and the image now spirals + * outwards from the centre with a fixed number of points drawn + * every iteration. Thanks to M.Dobie . + * 1994: written. Copyright (c) 1994 M.Dobie + * based on original code by R.Taylor + */ + +#define STANDALONE +#define NOARGS + +#define COUNT 5 +#define DELAY 10000 +#define NCOLORS 200 +# define DEFAULTS "*count: 5 \n" \ + "*delay: 10000 \n" \ + "*ncolors: 200 \n" \ + "*useSHM: True \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define SMOOTH_COLORS +# define WRITABLE_COLORS +# define swirl_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* from the xscreensaver distribution */ +# ifdef HAVE_XSHM_EXTENSION +# include "xshm.h" +# endif /* HAVE_XSHM_EXTENSION */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +# undef HAVE_XSHM_EXTENSION +#endif /* !STANDALONE */ + +#include "colors.h" + +ENTRYPOINT ModeSpecOpt swirl_opts = { + 0, NULL, 0, NULL, NULL }; + +#include + +/****************************************************************/ + +#define MASS 4 /* maximum mass of a knot */ +#define MIN_RES 5 /* minimim resolution (>= MIN_RES) */ +#define MAX_RES 1 /* maximum resolution (>0) */ +#define TWO_PLANE_PCNT 30 /* probability for two plane mode (0-100) */ +#define RESTART 2500 /* number of cycles before restart */ +#define BATCH_DRAW 100 /* points to draw per iteration */ + +/* knot types */ +typedef enum { + NONE = 0, + ORBIT = (1 << 0), + WHEEL = (1 << 1), + PICASSO = (1 << 2), + RAY = (1 << 3), + HOOK = (1 << 4), + ALL = (1 << 5) +} KNOT_T; + +/* a knot */ +typedef struct Knot { + int x, y; /* position */ + int m; /* mass */ + KNOT_T t; /* type in the first (or only) plane */ + KNOT_T T; /* type in second plane if there is one */ + int M; /* mass in second plane if there is one */ +} KNOT , *KNOT_P; + +/* a colour specification */ +typedef struct Colour { + unsigned short r, g, b; +} COLOUR , *COLOUR_P; + +/* drawing direction */ +typedef enum { + DRAW_RIGHT, DRAW_DOWN, DRAW_LEFT, DRAW_UP +} DIR_T; + +/****************************************************************/ + +/* data associated with a swirl window */ +typedef struct swirl_data { + /* window paramaters */ + Window win; /* the window */ + int width, height; /* window size */ + int depth; /* depth */ + int rdepth; /* real depth (for XImage) */ + Visual *visual; /* visual */ + + /* swirl drawing parameters */ + int n_knots; /* number of knots */ + KNOT_P knots; /* knot details */ + KNOT_T knot_type; /* general type of knots */ + int resolution; /* drawing resolution, 1..5 */ + int max_resolution; /* maximum resolution, MAX_RES */ + int r; /* pixel step */ + Bool two_plane; /* two plane mode? */ + Bool first_plane; /* doing first plane? */ + int start_again; /* when to restart */ + + /* spiral drawing parameters */ + int x, y; /* current point */ + DIR_T direction; /* current direction */ + int dir_todo, dir_done; /* how many points in current direction? */ + int batch_todo, batch_done; /* how many points in this batch */ + Bool started, drawing; /* are we drawing? */ + + /* image stuff */ + unsigned char *image; /* image data */ + XImage *ximage; + + /* colours stuff */ + int colours; /* how many colours possible */ + int dcolours; /* how many colours for shading */ +#ifndef STANDALONE + Bool fixed_colourmap; /* fixed colourmap? */ +#endif /* !STANDALONE */ + Bool monochrome; /* monochrome? */ + Colormap cmap; /* colour map for the window */ + XColor *rgb_values; /* colour definitions array */ +#ifndef STANDALONE + int current_map; /* current colour map, 0..dcolours-1 */ + unsigned long fg, bg, white, black; /* black and white pixel values */ + int shift; /* colourmap shift */ + int dshift; /* colourmap shift while drawing */ + XColor fgcol, bgcol; /* foreground and background colour specs */ +#endif /* !STANDALONE */ + Bool off_screen; +} SWIRL , *SWIRL_P; + +#define SWIRLCOLOURS 13 + +#ifndef STANDALONE +/* basic colours */ +static COLOUR basic_colours[SWIRLCOLOURS]; +#endif /* !STANDALONE */ + +/* an array of swirls for each screen */ +static SWIRL_P swirls = NULL; + +/* + random_no + + Return a random integer between 0 and n inclusive + + - n is the maximum number + + Returns a random integer */ + +static int +random_no(unsigned int n) +{ + return ((int) ((n + 1) * (double) LRAND() / MAXRAND)); +} + +/****************************************************************/ + +/* + initialise_swirl + + Initialise all the swirl data + + - swirl is the swirl data */ + +static void +initialise_swirl(ModeInfo * mi, SWIRL_P swirl) +{ +#ifndef STANDALONE + Display *display = MI_DISPLAY(mi); +#endif /* !STANDALONE */ + + swirl->width = 0; /* width and height of window */ + swirl->height = 0; + swirl->depth = 1; + swirl->rdepth = 1; + swirl->visual = NULL; + swirl->resolution = MIN_RES + 1; /* current resolution */ + swirl->max_resolution = MAX_RES; /* maximum resolution */ + swirl->n_knots = 0; /* number of knots */ + swirl->knot_type = ALL; /* general type of knots */ + swirl->two_plane = False; /* two plane mode? */ + swirl->first_plane = False; /* doing first plane? */ + swirl->start_again = -1; /* restart counter */ + + /* drawing parameters */ + swirl->x = 0; + swirl->y = 0; + swirl->started = False; + swirl->drawing = False; + + /* image stuff */ + swirl->image = NULL; /* image data */ + swirl->ximage = NULL; + + /* colours stuff */ + swirl->colours = 0; /* how many colours possible */ + swirl->dcolours = 0; /* how many colours for shading */ + swirl->cmap = (Colormap) NULL; + swirl->rgb_values = NULL; /* colour definitions array */ +#ifndef STANDALONE + swirl->current_map = 0; /* current colour map, 0..dcolours-1 */ + + /* set up fg fb colour specs */ + swirl->white = MI_WIN_WHITE_PIXEL(mi); + swirl->black = MI_WIN_BLACK_PIXEL(mi); +#endif /* !STANDALONE */ + + +#ifndef STANDALONE + swirl->fg = MI_FG_COLOR(mi); + swirl->bg = MI_BG_COLOR(mi); + swirl->fgcol.pixel = swirl->fg; + swirl->bgcol.pixel = swirl->bg; + XQueryColor(display, MI_COLORMAP(mi), &(swirl->fgcol)); + XQueryColor(display, MI_COLORMAP(mi), &(swirl->bgcol)); +#endif /* !STANDALONE */ +} + +/****************************************************************/ + +/* + * initialise_image + * + * Initialise the image for drawing to + * + * - swirl is the swirl data + */ +static void +initialise_image(ModeInfo * mi, SWIRL_P swirl) +{ + Display *dpy = MI_DISPLAY(mi); + + if (swirl->ximage != NULL) + XDestroyImage(swirl->ximage); + + swirl->ximage = 0; +#ifdef HAVE_XSHM_EXTENSION + if (mi->use_shm) + { + swirl->ximage = create_xshm_image(dpy, swirl->visual, swirl->rdepth, + ZPixmap, 0, &mi->shm_info, + swirl->width, swirl->height); + if (!swirl->ximage) + mi->use_shm = False; + } +#endif /* HAVE_XSHM_EXTENSION */ + + if (!swirl->ximage) + { + swirl->ximage = XCreateImage(dpy, swirl->visual, swirl->rdepth, ZPixmap, + 0, 0, swirl->width, swirl->height, + 8, 0); + swirl->image = (unsigned char *) + calloc(swirl->height, swirl->ximage->bytes_per_line); + swirl->ximage->data = (char *) swirl->image; + } +} + +/****************************************************************/ + +#ifndef STANDALONE +/* + * initialise_colours + * + * Initialise the list of colours from which the colourmaps are derived + * + * - colours is the array to initialise + * - saturation is the saturation value to use 0->grey, + * 1.0->full saturation + */ +static void +initialise_colours(COLOUR * colours, float saturate) +{ + int i; + + /* start off fully saturated, medium and bright colours */ + colours[0].r = 0xA000; + colours[0].g = 0x0000; + colours[0].b = 0x0000; + colours[1].r = 0xD000; + colours[1].g = 0x0000; + colours[1].b = 0x0000; + colours[2].r = 0x0000; + colours[2].g = 0x6000; + colours[2].b = 0x0000; + colours[3].r = 0x0000; + colours[3].g = 0x9000; + colours[3].b = 0x0000; + colours[4].r = 0x0000; + colours[4].g = 0x0000; + colours[4].b = 0xC000; + colours[5].r = 0x0000; + colours[5].g = 0x0000; + colours[5].b = 0xF000; + colours[6].r = 0xA000; + colours[6].g = 0x6000; + colours[6].b = 0x0000; + colours[7].r = 0xD000; + colours[7].g = 0x9000; + colours[7].b = 0x0000; + colours[8].r = 0xA000; + colours[8].g = 0x0000; + colours[8].b = 0xC000; + colours[9].r = 0xD000; + colours[9].g = 0x0000; + colours[9].b = 0xF000; + colours[10].r = 0x0000; + colours[10].g = 0x6000; + colours[10].b = 0xC000; + colours[11].r = 0x0000; + colours[11].g = 0x9000; + colours[11].b = 0xF000; + colours[12].r = 0xA000; + colours[12].g = 0xA000; + colours[12].b = 0xA000; + + /* add white for low saturation */ + for (i = 0; i < SWIRLCOLOURS - 1; i++) { + unsigned short max_rg, max; + + /* what is the max intensity for this colour? */ + max_rg = (colours[i].r > colours[i].g) ? colours[i].r : colours[i].g; + max = (max_rg > colours[i].b) ? max_rg : colours[i].b; + + /* bring elements up to max as saturation approaches 0.0 */ + colours[i].r += (unsigned short) ((float) (1.0 - saturate) * + ((float) max - colours[i].r)); + colours[i].g += (unsigned short) ((float) (1.0 - saturate) * + ((float) max - colours[i].g)); + colours[i].b += (unsigned short) ((float) (1.0 - saturate) * + ((float) max - colours[i].b)); + } +} +#endif /* !STANDALONE */ + +/****************************************************************/ + +#ifndef STANDALONE +/* + * set_black_and_white + * + * Set the entries for foreground & background pixels and + * WhitePixel & BlackPixel in an array of colour specifications. + * + * - swirl is the swirl data + * - values is the array of specifications + */ +static void +set_black_and_white(SWIRL_P swirl, XColor * values) +{ + unsigned long white, black; + + /* where is black and white? */ + white = swirl->white; + black = swirl->black; + + /* set black and white up */ + values[white].flags = DoRed | DoGreen | DoBlue; + values[white].pixel = white; + values[white].red = 0xFFFF; + values[white].green = 0xFFFF; + values[white].blue = 0xFFFF; + values[black].flags = DoRed | DoGreen | DoBlue; + values[black].pixel = black; + values[black].red = 0; + values[black].green = 0; + values[black].blue = 0; + + /* copy the colour specs from the original entries */ + values[swirl->fg] = swirl->fgcol; + values[swirl->bg] = swirl->bgcol; +} + +/****************************************************************/ + +/* + * set_colour + * + * Set an entry in an array of XColor specifications. The given entry will be + * set to the given colour. If the entry corresponds to the foreground, + * background, WhitePixel, or BlackPixel it is ignored and the given colour + * is is put in the next entry. + * + * Therefore, the given colour may be placed up to four places after the + * specified entry in the array, if foreground, background, white, or black + * intervene. + * + * - swirl is the swirl data + * - value points to a pointer to the array entry. It gets updated to + * point to the next free entry. + * - pixel points to the current pixel number. It gets updated. + * - c points to the colour to add + */ +static void +set_colour(SWIRL_P swirl, XColor ** value, unsigned long *pixel, COLOUR_P c) +{ + Bool done; + unsigned long fg, bg, white, black; + + /* where are foreground, background, white, and black? */ + fg = swirl->fg; + bg = swirl->bg; + white = swirl->white; + black = swirl->black; + + /* haven't set it yet */ + done = False; + + /* try and set the colour */ + while (!done) { + (**value).flags = DoRed | DoGreen | DoBlue; + (**value).pixel = *pixel; + + /* white, black, fg, bg, or a colour? */ + if ((*pixel != fg) && (*pixel != bg) && + (*pixel != white) && (*pixel != black)) { + (**value).red = c->r; + (**value).green = c->g; + (**value).blue = c->b; + + /* now we've done it */ + done = True; + } + /* next pixel */ + (*value)++; + (*pixel)++; + } +} + +/****************************************************************/ + +/* + * get_colour + * + * Get an entry from an array of XColor specifications. The next colour from + * the array will be returned. Foreground, background, WhitePixel, or + * BlackPixel will be ignored. + * + * - swirl is the swirl data + * - value points the array entry. It is updated to point to the entry + * following the one returned. + * - c is set to the colour found + */ +static void +get_colour(SWIRL_P swirl, XColor ** value, COLOUR_P c) +{ + Bool done; + unsigned long fg, bg, white, black; + + /* where is white and black? */ + fg = swirl->fg; + bg = swirl->bg; + white = swirl->white; + black = swirl->black; + + /* haven't set it yet */ + done = False; + + /* try and set the colour */ + while (!done) { + /* black, white or a colour? */ + if (((*value)->pixel != fg) && ((*value)->pixel != bg) && + ((*value)->pixel != white) && ((*value)->pixel != black)) { + c->r = (*value)->red; + c->g = (*value)->green; + c->b = (*value)->blue; + + /* now we've done it */ + done = True; + } + /* next value */ + (*value)++; + } +} +#endif /* !STANDALONE */ + +/****************************************************************/ + +#ifndef STANDALONE +/* + * interpolate + * + * Generate n colours between c1 and c2. n XColors at *value are set up with + * ascending pixel values. + * + * If the pixel range includes BlackPixel or WhitePixel they are set to black + * and white respectively but otherwise ignored. Therefore, up to n+2 colours + * may actually be set by this function. + * + * - swirl is the swirl data + * - values points a pointer to an array of XColors to update + * - pixel points to the pixel number to start at + * - k n is the number of colours to generate + * - c1, c2 are the colours to interpolate between + */ +static void +interpolate(SWIRL_P swirl, XColor ** values, unsigned long *pixel, int n, COLOUR_P c1, COLOUR_P c2) +{ + int i, r, g, b; + COLOUR c; + unsigned short maxv; + + /* maximum value */ + maxv = (255 << 8); + + for (i = 0; i < n / 2 && (int) *pixel < swirl->colours; i++) { + /* work out the colour */ + r = c1->r + 2 * i * ((int) c2->r) / n; + c.r = (r > (int) maxv) ? maxv : r; + g = c1->g + 2 * i * ((int) c2->g) / n; + c.g = (g > (int) maxv) ? maxv : g; + b = c1->b + 2 * i * ((int) c2->b) / n; + c.b = (b > (int) maxv) ? maxv : b; + + /* set it up */ + set_colour(swirl, values, pixel, &c); + } + for (i = n / 2; i >= 0 && (int) *pixel < swirl->colours; i--) { + r = c2->r + 2 * i * ((int) c1->r) / n; + c.r = (r > (int) maxv) ? maxv : r; + g = c2->g + 2 * i * ((int) c1->g) / n; + c.g = (g > (int) maxv) ? maxv : g; + b = c2->b + 2 * i * ((int) c1->b) / n; + c.b = (b > (int) maxv) ? maxv : b; + + /* set it up */ + set_colour(swirl, values, pixel, &c); + } +} + +/****************************************************************/ + +/* + * basic_map + * + * Generate a `random' closed loop colourmap that occupies the whole colour + * map. + * + * - swirl is the swirl data + * - values is the array of colour definitions to set up + */ +static void +basic_map(SWIRL_P swirl, XColor * values) +{ + COLOUR c[3]; + int i; + unsigned short r1, g1, b1, r2, g2, b2, r3, g3, b3; + int L1, L2, L3, L; + unsigned long pixel; + XColor *value; + + /* start at the beginning of the colour map */ + pixel = 0; + value = values; + + /* choose 3 different basic colours at random */ + for (i = 0; i < 3;) { + int j; + Bool same; + + /* choose colour i */ + c[i] = basic_colours[random_no(SWIRLCOLOURS - 1)]; + + /* assume different */ + same = False; + + /* different from the rest? */ + for (j = 0; j < i; j++) + if ((c[i].r == c[j].r) && + (c[i].g == c[j].g) && + (c[i].b == c[j].b)) + same = True; + + /* ready for the next colour? */ + if (!same) + i++; + } + + /* extract components into variables */ + r1 = c[0].r; + g1 = c[0].g; + b1 = c[0].b; + r2 = c[1].r; + g2 = c[1].g; + b2 = c[1].b; + r3 = c[2].r; + g3 = c[2].g; + b3 = c[2].b; + + /* work out the lengths of each side of the triangle */ + L1 = (int) sqrt((((double) r1 - r2) * ((double) r1 - r2) + + ((double) g1 - g2) * ((double) g1 - g2) + + ((double) b1 - b2) * ((double) b1 - b2))); + + L2 = (int) sqrt((((double) r3 - r2) * ((double) r3 - r2) + + ((double) g3 - g2) * ((double) g3 - g2) + + ((double) b3 - b2) * ((double) b3 - b2))); + + L3 = (int) sqrt((((double) r1 - r3) * ((double) r1 - r3) + + ((double) g1 - g3) * ((double) g1 - g3) + + ((double) b1 - b3) * ((double) b1 - b3))); + + L = L1 + L2 + L3; + + /* allocate colours in proportion to the lengths of the sides */ + interpolate(swirl, &value, &pixel, + (int) ((double) swirl->dcolours * ((double) L1 / (double) L)) + 1, c, c + 1); + interpolate(swirl, &value, &pixel, + (int) ((double) swirl->dcolours * ((double) L2 / (double) L)) + 1, c + 1, c + 2); + interpolate(swirl, &value, &pixel, + (int) ((double) swirl->dcolours * ((double) L3 / (double) L)) + 1, c + 2, c); + + /* fill up any remaining slots (due to rounding) */ + while ((int) pixel < swirl->colours) { + /* repeat the last colour */ + set_colour(swirl, &value, &pixel, c); + } + + /* ensure black and white are correct */ + if (!swirl->fixed_colourmap) + set_black_and_white(swirl, values); +} + +/****************************************************************/ + +/* + * pre_rotate + * + * Generate pre-rotated versions of the colour specifications + * + * - swirl is the swirl data + * - values is an array of colour specifications + */ +static void +pre_rotate(SWIRL_P swirl, XColor * values) +{ + int i, j; + XColor *src, *dest; + int dcolours; + unsigned long pixel; + + /* how many colours to display? */ + dcolours = swirl->dcolours; + + /* start at the first map */ + src = values; + dest = values + swirl->colours; + + /* generate dcolours-1 rotated maps */ + for (i = 0; i < dcolours - 1; i++) { + COLOUR first; + + /* start at the first pixel */ + pixel = 0; + + /* remember the first one and skip it */ + get_colour(swirl, &src, &first); + + /* put a rotated version of src at dest */ + for (j = 0; j < dcolours - 1; j++) { + COLOUR c; + + /* get the source colour */ + get_colour(swirl, &src, &c); + + /* set the colour */ + set_colour(swirl, &dest, &pixel, &c); + } + + /* put the first one at the end */ + set_colour(swirl, &dest, &pixel, &first); + + /* NB: src and dest should now be ready for the next table */ + + /* ensure black and white are properly set */ + set_black_and_white(swirl, src); + } +} + +/****************************************************************/ + +/* + * create_colourmap + * + * Create a read/write colourmap to use + * + * - swirl is the swirl data + */ + +static void +create_colourmap(ModeInfo * mi, SWIRL_P swirl) +{ + Display *display = MI_DISPLAY(mi); + int preserve; + int n_rotations; + int i; + Bool truecolor; + unsigned long redmask, greenmask, bluemask; + + swirl->fixed_colourmap = !setupColormap(mi, &(swirl->colours), + &truecolor, &redmask, &greenmask, &bluemask); + preserve = preserveColors(swirl->fg, swirl->bg, swirl->white, swirl->black); + + /* how many colours should we animate? */ + swirl->dcolours = (swirl->colours > preserve + 1) ? + swirl->colours - preserve : swirl->colours; + + if (MI_NPIXELS(mi) < 2) + return; + + /* how fast to shift the colourmap? */ + swirl->shift = (swirl->colours > 64) ? swirl->colours / 64 : 1; + swirl->dshift = (swirl->shift > 1) ? swirl->shift * 2 : 1; + + /* how may colour map rotations are there? */ + n_rotations = (swirl->fixed_colourmap) ? 1 : swirl->dcolours; + + /* allocate space for colour definitions (if not already there) */ + if (swirl->rgb_values == NULL) { + swirl->rgb_values = (XColor *) calloc((swirl->colours + 3) * n_rotations, + sizeof (XColor)); + + /* create a colour map */ + if (!swirl->fixed_colourmap) + swirl->cmap = + XCreateColormap(display, swirl->win, swirl->visual, AllocAll); + } + /* select a set of colours for the colour map */ + basic_map(swirl, swirl->rgb_values); + + /* are we rotating them? */ + if (!swirl->fixed_colourmap) { + /* generate rotations of the colour maps */ + pre_rotate(swirl, swirl->rgb_values); + + /* store the colours in the colour map */ + XStoreColors(display, swirl->cmap, swirl->rgb_values, swirl->colours); + } else { + if (truecolor) { + int rsh, gsh, bsh; + unsigned long int t; + + t = redmask; + for (i = 0; (int) t > 0; i++, t >>= 1); + rsh = 16 - i; + t = greenmask; + for (i = 0; (int) t > 0; i++, t >>= 1); + gsh = 16 - i; + t = bluemask; + for (i = 0; (int) t > 0; i++, t >>= 1); + bsh = 16 - i; + for (i = 0; i < swirl->colours; i++) + swirl->rgb_values[i].pixel = + ((rsh > 0 ? (swirl->rgb_values[i].red) >> rsh : + (swirl->rgb_values[i].red) << (-rsh)) & redmask) | + ((gsh > 0 ? (swirl->rgb_values[i].green) >> gsh : + (swirl->rgb_values[i].green) << (-gsh)) & greenmask) | + ((bsh > 0 ? (swirl->rgb_values[i].blue) >> bsh : + (swirl->rgb_values[i].blue) << (-bsh)) & bluemask); + } else { + /* lookup the colours in the fixed colour map */ + for (i = 0; i < swirl->colours; i++) + (void) XAllocColor(display, MI_COLORMAP(mi), + &(swirl->rgb_values[i])); + } + } +} + +/****************************************************************/ + +/* + * install_map + * + * Install a new set of colours into the colour map + * + * - dpy is the display + * - swirl is the swirl data + * - shift is the amount to rotate the colour map by + */ +static void +install_map(Display * dpy, SWIRL_P swirl, int shift) +{ + if (!swirl->fixed_colourmap) { + /* shift the colour map */ + swirl->current_map = (swirl->current_map + shift) % + swirl->dcolours; + + /* store it */ + XStoreColors(dpy, swirl->cmap, + swirl->rgb_values + + swirl->current_map * swirl->colours, + swirl->colours); + } +} +#endif /* !STANDALONE */ + +/****************************************************************/ + +/* + * create_knots + * + * Initialise the array of knot + * + * swirl is the swirl data + */ +static void +create_knots(SWIRL_P swirl) +{ + int k; + Bool orbit, wheel, picasso, ray, hook; + KNOT_P knot; + + /* create array for knots */ + if (swirl->knots) + (void) free((void *) swirl->knots); + swirl->knots = (KNOT_P) calloc(swirl->n_knots, sizeof (KNOT)); + + /* no knots yet */ + orbit = wheel = picasso = ray = hook = False; + + /* what types do we have? */ + if ((int) swirl->knot_type & (int) ALL) { + orbit = wheel = ray = hook = True; + } else { + if ((int) swirl->knot_type & (int) ORBIT) + orbit = True; + if ((int) swirl->knot_type & (int) WHEEL) + wheel = True; + if ((int) swirl->knot_type & (int) PICASSO) + picasso = True; + if ((int) swirl->knot_type & (int) RAY) + ray = True; + if ((int) swirl->knot_type & (int) HOOK) + hook = True; + } + + /* initialise each knot */ + knot = swirl->knots; + for (k = 0; k < swirl->n_knots; k++) { + /* position */ + knot->x = random_no((unsigned int) swirl->width); + knot->y = random_no((unsigned int) swirl->height); + + /* mass */ + knot->m = random_no(MASS) + 1; + + /* can be negative */ + if (random_no(100) > 50) + knot->m *= -1; + + /* type */ + knot->t = NONE; + while (knot->t == NONE) { + /* choose a random one from the types available */ + switch (random_no(4)) { + case 0: + if (orbit) + knot->t = ORBIT; + break; + case 1: + if (wheel) + knot->t = WHEEL; + break; + case 2: + if (picasso) + knot->t = PICASSO; + break; + case 3: + if (ray) + knot->t = RAY; + break; + case 4: + if (hook) + knot->t = HOOK; + break; + } + } + + /* if two planes, do same for second plane */ + if (swirl->two_plane) { + knot->T = NONE; + while (knot->T == NONE || knot->T == knot->t) { + /* choose a different type */ + switch (random_no(4)) { + case 0: + if (orbit) + knot->T = ORBIT; + break; + case 1: + if (wheel) + knot->T = WHEEL; + break; + case 2: + if (picasso) + knot->T = PICASSO; + break; + case 3: + if (ray) + knot->T = RAY; + break; + case 4: + if (hook) + knot->T = HOOK; + break; + } + } + } + /* next knot */ + knot++; + } +} + +/****************************************************************/ + +/* + * do_point + * + * Work out the pixel value at i, j. Ensure it does not clash with BlackPixel + * or WhitePixel. + * + * - swirl is the swirl data + * - i, j is the point to calculate + * + * Returns the value of the point + */ +static unsigned long +do_point(SWIRL_P swirl, int i, int j) +{ + int tT, k, value, add; + double dx, dy, theta, dist; + int dcolours, qcolours; + double rads; + KNOT_P knot; + + /* how many colours? */ + dcolours = swirl->dcolours; + qcolours = dcolours / 4; + + /* colour step round a circle */ + rads = (double) dcolours / (2.0 * M_PI); + + /* start at zero */ + value = 0; + + /* go through all the knots */ + knot = swirl->knots; + for (k = 0; k < swirl->n_knots; k++) { + dx = i - knot->x; + dy = j - knot->y; + + /* in two_plane mode get the appropriate knot type */ + if (swirl->two_plane) + tT = (int) ((swirl->first_plane) ? knot->t : knot->T); + else + tT = (int) knot->t; + + /* distance from knot */ + dist = sqrt(dx * dx + dy * dy); + + /* nothing to add at first */ + add = 0; + + /* work out the contribution (if close enough) */ + if (dist > 0.1) + switch (tT) { + case ORBIT: + add = (int) (dcolours / (1.0 + 0.01 * abs(knot->m) * dist)); + break; + case WHEEL: + /* Avoid atan2: DOMAIN error message */ + if (dy == 0.0 && dx == 0.0) + theta = 1.0; + else + theta = (atan2(dy, dx) + M_PI) / M_PI; + if (theta < 1.0) + add = (int) (dcolours * theta + + sin(0.1 * knot->m * dist) * + qcolours * exp(-0.01 * dist)); + else + add = (int) (dcolours * (theta - 1.0) + + sin(0.1 * knot->m * dist) * + qcolours * exp(-0.01 * dist)); + break; + case PICASSO: + add = (int) (dcolours * + fabs(cos(0.002 * knot->m * dist))); + break; + case RAY: + /* Avoid atan2: DOMAIN error message */ + if (dy == 0.0 && dx == 0.0) + add = 0; + else + add = (int) (dcolours * fabs(sin(2.0 * atan2(dy, dx)))); + + break; + case HOOK: + /* Avoid atan2: DOMAIN error message */ + if (dy == 0.0 && dx == 0.0) + add = (int) (0.05 * (abs(knot->m) - 1) * dist); + else + add = (int) (rads * atan2(dy, dx) + + 0.05 * (abs(knot->m) - 1) * dist); + break; + } + /* for a +ve mass add on the contribution else take it off */ + if (knot->m > 0) + value += add; + else + value -= add; + + /* next knot */ + knot++; + } + + /* toggle plane */ + swirl->first_plane = (!swirl->first_plane); + + /* make sure we handle -ve values properly */ + if (value >= 0) + value = (value % dcolours) + 2; + else + value = dcolours - (abs(value) % (dcolours - 1)); + +#ifndef STANDALONE + /* if fg and bg are 1 and 0 we should be OK, but just in case */ + while ((dcolours > 2) && + (((value % swirl->colours) == (int) swirl->fg) || + ((value % swirl->colours) == (int) swirl->bg) || + ((value % swirl->colours) == (int) swirl->white) || + ((value % swirl->colours) == (int) swirl->black))) { + value++; + } +#endif /* !STANDALONE */ + + /* definitely make sure it is in range */ + value = value % swirl->colours; + + /* lookup the pixel value if necessary */ +#ifndef STANDALONE + if (swirl->fixed_colourmap && swirl->dcolours > 2) +#endif + value = swirl->rgb_values[value].pixel; + + /* return it */ + return ((unsigned long) value); +} + +/****************************************************************/ + +/* + * draw_block + * + * Draw a square block of points with the same value. + * + * - ximage is the XImage to draw on. + * - x, y is the top left corner + * - s is the length of each side + * - v is the value + */ +static void +draw_block(XImage * ximage, int x, int y, int s, unsigned long v) +{ + int a, b; + + for (a = 0; a < s; a++) + for (b = 0; b < s; b++) { + XPutPixel(ximage, x + b, y + a, v); + } +} + +/****************************************************************/ + +/* + * draw_point Draw the current point in a swirl pattern onto the XImage + * + * - swirl is the swirl + * - win is the window to update + */ +static void +draw_point(ModeInfo * mi, SWIRL_P swirl) +{ + int r; + int x, y; + + /* get current point coordinates and resolution */ + x = swirl->x; + y = swirl->y; + r = swirl->r; + + /* check we are within the window */ + if ((x < 0) || (x > swirl->width - r) || (y < 0) || (y > swirl->height - r)) + return; + + /* what style are we drawing? */ + if (swirl->two_plane) { + int r2; + + /* halve the block size */ + r2 = r / 2; + + /* interleave blocks at half r */ + draw_block(swirl->ximage, x, y, r2, do_point(swirl, x, y)); + draw_block(swirl->ximage, x + r2, y, r2, do_point(swirl, x + r2, y)); + draw_block(swirl->ximage, x + r2, y + r2, r2, do_point(swirl, + x + r2, y + r2)); + draw_block(swirl->ximage, x, y + r2, r2, do_point(swirl, x, y + r2)); + } else + draw_block(swirl->ximage, x, y, r, do_point(swirl, x, y)); + + /* update the screen */ + +#ifdef HAVE_XSHM_EXTENSION + if (mi->use_shm) + XShmPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage, + x, y, x, y, r, r, False); + else +#endif /* !HAVE_XSHM_EXTENSION */ + /* PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 256 byte memory + leak on the next line. */ + XPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage, + x, y, x, y, r, r); +} + +/****************************************************************/ + +/* + * next_point Move to the next point in the spiral pattern + * - swirl is the swirl + * - win is the window to update + */ +static void +next_point(SWIRL_P swirl) +{ + /* more to do in this direction? */ + if (swirl->dir_done < swirl->dir_todo) { + /* move in the current direction */ + switch (swirl->direction) { + case DRAW_RIGHT: + swirl->x += swirl->r; + break; + case DRAW_DOWN: + swirl->y += swirl->r; + break; + case DRAW_LEFT: + swirl->x -= swirl->r; + break; + case DRAW_UP: + swirl->y -= swirl->r; + break; + } + + /* done another point */ + swirl->dir_done++; + } else { + /* none drawn yet */ + swirl->dir_done = 0; + + /* change direction - check and record if off screen */ + switch (swirl->direction) { + case DRAW_RIGHT: + swirl->direction = DRAW_DOWN; + if (swirl->x > swirl->width - swirl->r) { + /* skip these points */ + swirl->dir_done = swirl->dir_todo; + swirl->y += (swirl->dir_todo * swirl->r); + + /* check for finish */ + if (swirl->off_screen) + swirl->drawing = False; + swirl->off_screen = True; + } else + swirl->off_screen = False; + break; + case DRAW_DOWN: + swirl->direction = DRAW_LEFT; + swirl->dir_todo++; + if (swirl->y > swirl->height - swirl->r) { + /* skip these points */ + swirl->dir_done = swirl->dir_todo; + swirl->x -= (swirl->dir_todo * swirl->r); + + /* check for finish */ + if (swirl->off_screen) + swirl->drawing = False; + swirl->off_screen = True; + } else + swirl->off_screen = False; + break; + case DRAW_LEFT: + swirl->direction = DRAW_UP; + if (swirl->x < 0) { + /* skip these points */ + swirl->dir_done = swirl->dir_todo; + swirl->y -= (swirl->dir_todo * swirl->r); + + /* check for finish */ + if (swirl->off_screen) + swirl->drawing = False; + swirl->off_screen = True; + } else + swirl->off_screen = False; + break; + case DRAW_UP: + swirl->direction = DRAW_RIGHT; + swirl->dir_todo++; + if (swirl->y < 0) { + /* skip these points */ + swirl->dir_done = swirl->dir_todo; + swirl->x += (swirl->dir_todo * swirl->r); + + /* check for finish */ + if (swirl->off_screen) + swirl->drawing = False; + swirl->off_screen = True; + } else + swirl->off_screen = False; + break; + } + } +} + +/****************************************************************/ + +/* + * init_swirl + * + * Initialise things for swirling + * + * - win is the window to draw in + */ +ENTRYPOINT void +init_swirl(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + SWIRL_P swirl; + + /* does the swirls array exist? */ + if (swirls == NULL) { + /* allocate an array, one entry for each screen */ + swirls = (SWIRL_P) calloc(MI_NUM_SCREENS(mi), sizeof (SWIRL)); + } + /* get a pointer to this swirl */ + swirl = &(swirls[MI_SCREEN(mi)]); + initialise_swirl(mi, swirl); + + /* get window parameters */ + swirl->win = window; + swirl->width = MI_WIN_WIDTH(mi); + swirl->height = MI_WIN_HEIGHT(mi); + swirl->depth = MI_WIN_DEPTH(mi); + swirl->rdepth = swirl->depth; + swirl->visual = MI_VISUAL(mi); + + if (swirl->depth > 16) + swirl->depth = 16; + + /* initialise image for speeding up drawing */ + initialise_image(mi, swirl); + + /* clear the window (before setting the colourmap) */ + XClearWindow(display, MI_WINDOW(mi)); + +#ifdef STANDALONE + + swirl->rgb_values = mi->colors; + swirl->colours = mi->npixels; + swirl->dcolours = swirl->colours; +/* swirl->fixed_colourmap = !mi->writable_p;*/ + +#else /* !STANDALONE */ + + /* initialise the colours from which the colourmap is derived */ + initialise_colours(basic_colours, MI_SATURATION(mi)); + + /* set up the colour map */ + create_colourmap(mi, swirl); + + /* attach the colour map to the window (if we have one) */ + if (!swirl->fixed_colourmap) { +#if 1 + setColormap(display, window, swirl->cmap, MI_WIN_IS_INWINDOW(mi)); +#else + XSetWindowColormap(display, window, swirl->cmap); + (void) XSetWMColormapWindows(display, window, &window, 1); + XInstallColormap(display, swirl->cmap); +#endif + } +#endif /* STANDALONE */ + + /* resolution starts off chunky */ + swirl->resolution = MIN_RES + 1; + + /* calculate the pixel step for this resulution */ + swirl->r = (1 << (swirl->resolution - 1)); + + /* how many knots? */ + swirl->n_knots = random_no((unsigned int) MI_BATCHCOUNT(mi) / 2) + + MI_BATCHCOUNT(mi) + 1; + + /* what type of knots? */ + swirl->knot_type = ALL; /* for now */ + + /* use two_plane mode occaisionally */ + if (random_no(100) <= TWO_PLANE_PCNT) { + swirl->two_plane = swirl->first_plane = True; + swirl->max_resolution = 2; + } else + swirl->two_plane = False; + + /* fix the knot values */ + create_knots(swirl); + + /* we are off */ + swirl->started = True; + swirl->drawing = False; +} + +/****************************************************************/ + +/* + * draw_swirl + * + * Draw one iteration of swirling + * + * - win is the window to draw in + */ +ENTRYPOINT void +draw_swirl(ModeInfo * mi) +{ + SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]); + + /* are we going? */ + if (swirl->started) { + /* in the middle of drawing? */ + if (swirl->drawing) { +#ifdef STANDALONE + if (mi->writable_p) + rotate_colors(mi->xgwa.screen, MI_COLORMAP(mi), + swirl->rgb_values, swirl->colours, 1); +#else /* !STANDALONE */ + /* rotate the colours */ + install_map(MI_DISPLAY(mi), swirl, swirl->dshift); +#endif /* !STANDALONE */ + + /* draw a batch of points */ + swirl->batch_todo = BATCH_DRAW; + while ((swirl->batch_todo > 0) && swirl->drawing) { + /* draw a point */ + draw_point(mi, swirl); + + /* move to the next point */ + next_point(swirl); + + /* done a point */ + swirl->batch_todo--; + } + } else { +#ifdef STANDALONE + if (mi->writable_p) + rotate_colors(mi->xgwa.screen, MI_COLORMAP(mi), + swirl->rgb_values, swirl->colours, 1); +#else /* !STANDALONE */ + /* rotate the colours */ + install_map(MI_DISPLAY(mi), swirl, swirl->shift); +#endif /* !STANDALONE */ + + /* time for a higher resolution? */ + if (swirl->resolution > swirl->max_resolution) { + /* move to higher resolution */ + swirl->resolution--; + + /* calculate the pixel step for this resulution */ + swirl->r = (1 << (swirl->resolution - 1)); + + /* start drawing again */ + swirl->drawing = True; + + /* start in the middle of the screen */ + swirl->x = (swirl->width - swirl->r) / 2; + swirl->y = (swirl->height - swirl->r) / 2; + + /* initialise spiral drawing parameters */ + swirl->direction = DRAW_RIGHT; + swirl->dir_todo = 1; + swirl->dir_done = 0; + } else { + /* all done, decide when to restart */ + if (swirl->start_again == -1) { + /* start the counter */ + swirl->start_again = RESTART; + } else if (swirl->start_again == 0) { + /* reset the counter */ + swirl->start_again = -1; + +#ifdef STANDALONE + /* Pick a new colormap! */ + XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi)); + free_colors (mi->xgwa.screen, MI_COLORMAP(mi), + mi->colors, mi->npixels); + make_smooth_colormap (mi->xgwa.screen, MI_VISUAL(mi), + MI_COLORMAP(mi), + mi->colors, &mi->npixels, True, + &mi->writable_p, True); + swirl->colours = mi->npixels; +#endif /* STANDALONE */ + + /* start again */ + init_swirl(mi); + } else + /* decrement the counter */ + swirl->start_again--; + } + } + } +} + +ENTRYPOINT void +reshape_swirl(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_swirl (mi); +} + +/****************************************************************/ + +ENTRYPOINT void +release_swirl (ModeInfo * mi) +{ + /* does the swirls array exist? */ + if (swirls != NULL) { + int i; + + /* free them all */ + for (i = 0; i < MI_NUM_SCREENS(mi); i++) { + SWIRL_P swirl = &(swirls[i]); + +#ifndef STANDALONE + if (swirl->cmap != (Colormap) NULL) + XFreeColormap(MI_DISPLAY(mi), swirl->cmap); +#endif /* STANDALONE */ +#ifndef STANDALONE + if (swirl->rgb_values != NULL) + XFree((void *) swirl->rgb_values); +#endif /* !STANDALONE */ + if (swirl->ximage != NULL) + XDestroyImage(swirl->ximage); + if (swirl->knots) + (void) free((void *) swirl->knots); + } + /* deallocate an array, one entry for each screen */ + (void) free((void *) swirls); + swirls = NULL; + } +} + +/****************************************************************/ + +ENTRYPOINT void +refresh_swirl (ModeInfo * mi) +{ + SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]); + + if (swirl->started) { + if (swirl->drawing) + swirl->resolution = swirl->resolution + 1; + swirl->drawing = False; + } +} + +XSCREENSAVER_MODULE ("Swirl", swirl) diff --git a/non-wgl/swirl.vcproj b/non-wgl/swirl.vcproj new file mode 100644 index 0000000..4a8967b --- /dev/null +++ b/non-wgl/swirl.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/t3d.c b/non-wgl/t3d.c new file mode 100644 index 0000000..72f5b29 --- /dev/null +++ b/non-wgl/t3d.c @@ -0,0 +1,1016 @@ +/* t3d -- Flying Balls Clock Demo + by Bernd Paysan , paysan@informatik.tu-muenchen.de + + Copy, modify, and distribute T3D either under GPL version 2 or newer, + or under the standard MIT/X license notice. + + partly based on flying balls demo by Georg Acher, + acher@informatik.tu-muenchen.de + (developed on HP9000/720 (55 MIPS,20 MFLOPS) ) + NO warranty at all ! Complaints to /dev/null ! + + 4-Jan-99 jwz@jwz.org -- adapted to xscreensaver framework, to take advantage + of the command-line options provided by screenhack.c. +*/ + +#ifndef HAVE_COCOA +# define FASTDRAW +# define FASTCOPY +#endif /* !HAVE_COCOA */ + +#include "screenhack.h" +#include +#include +#include /* for localtime() and gettimeofday() */ + +char *background = "black"; +char *foreground = "white"; +float move = 0.5; +float wobble = 2.0; +float cycle = 10.0; +float mag = 1.0; +Bool minutes = False; +int delay = 40000; +int fast = 50; +Bool colcycle = False; +float hsvcycle = 0.0; +char *rgb = ""; +char *hsv = ""; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&move, "move", NULL, "0.5", t_Float}, + {&wobble, "wobble", NULL, "2.0", t_Float}, + {&cycle, "cycle", NULL, "10.0", t_Float}, + {&mag, "mag", NULL, "1.0", t_Float}, + {&minutes, "minutes", NULL, "False", t_Bool}, + {&delay, "delay", NULL, "40000", t_Int}, + {&fast, "fast", NULL, "50", t_Int}, + {&colcycle, "colcycle", NULL, "False", t_Bool}, + {&hsvcycle, "hsvcycle", NULL, "0.0", t_Float}, + {&rgb, "rgb", NULL, "", t_String}, + {&hsv, "sleep", NULL, "", t_String}, +}; + +#define WIDTH 200 +#define HEIGHT 200 +#define norm 20.0 + +#define ROOT 0x1 +#define PI M_PI +#define TWOPI 2*M_PI + +#define MIN(i,j) ((i)<(j)?(i):(j)) + +#define kmax ((st->minutes?60:24)) +/* Anzahl der Kugeln */ +#define sines 52 +/* Werte in der Sinus-Tabelle */ +/*-----------------------------------------------------------------*/ +#define setink(inkcolor) \ + XSetForeground (st->dpy,st->gc,inkcolor) + +#define drawline(xx1,yy1,xx2,yy2) \ + XDrawLine(st->dpy,st->win,st->gc,xx1,yy1,xx2,yy2) + +#define drawseg(segments,nr_segments) \ + XDrawSegments(st->dpy,st->win,st->gc,segments,nr_segments) + + +#define polyfill(ppts,pcount) \ + XFillPolygon(st->dpy,st->win,st->gc,ppts,pcount,Convex,CoordModeOrigin) + + +#define frac(argument) argument-floor(argument) + +#undef ABS +#define ABS(x) ((x)<0.0 ? -(x) : (x)) + +typedef struct { + double x,y,z,r,d,r1; + int x1,y1; +} kugeldat; + +/* Felder fuer 3D */ + + +struct state { + Display *dpy; + Window window; + + int maxk; + int timewait; + + Colormap cmap; + double r,g,b; + double hue,sat,val; + + kugeldat kugeln[100]; + + double a[3],am[3],x[3],y[3],v[3]; + double zoom,speed,zaehler,vspeed; + double vturn; + double sinus[sines]; + double cosinus[sines]; + + int startx,starty; + double mag; + int minutes; + int cycl; + double hsvcycl; + double movef, wobber, cycle; + + XWindowAttributes xgwa; + GC gc; + GC orgc; + GC andgc; + int scrnWidth, scrnHeight; + Pixmap buffer; + int fastch; + + int scrnW2,scrnH2; + XColor colors[64]; + struct tm *zeit; + + int planes; + + Window junk_win,in_win; + int px,py,junk; + unsigned int kb; + + int fastdraw; + int draw_color; + +# ifdef FASTDRAW +# ifdef FASTCOPY +# define sum1ton(a) (((a)*(a)+1)/2) +# define fastcw sum1ton(st->fastch) + Pixmap fastcircles; + Pixmap fastmask; +# else /* !FASTCOPY */ + XImage* fastcircles[maxfast]; + XImage* fastmask[maxfast]; +# endif /* !FASTCOPY */ +# endif /* FASTDRAW */ +}; + + + +#define maxfast 100 + +/* compute time */ + +static double +gettime (struct state *st) +{ + struct timeval time1; + struct tm *zeit; + time_t lt; + +#ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone zone1; + gettimeofday(&time1,&zone1); +#else + gettimeofday(&time1); +#endif + lt = time1.tv_sec; /* avoid type cast lossage */ + zeit=localtime(<); + + return (zeit->tm_sec+60*(zeit->tm_min+60*(zeit->tm_hour)) + + time1.tv_usec*1.0E-6); +} + +/* --------------------COLORMAP---------------------*/ + +static void +hsv2rgb (double h, double s, double v, double *r, double *g, double *b) +{ + h/=360.0; h=6*(h-floor(h)); + + if(s==0.0) + { + *r=*g=*b=v; + } + else + { int i=(int)h; + double t,u,w; + + h=h-floor(h); + + u=v*(s*(1.0-h)); + w=v*(1.0-s); + t=v*(s*h+1.0-s); + + switch(i) + { + case 0: *r=v; *g=t; *b=w; break; + case 1: *r=u; *g=v; *b=w; break; + case 2: *r=w; *g=v; *b=t; break; + case 3: *r=w; *g=u; *b=v; break; + case 4: *r=t; *g=w; *b=v; break; + case 5: *r=v; *g=w; *b=u; break; + } + } +#ifdef PRTDBX + printf("HSV: %f %f %f to\nRGB: %f %f %f\n",h,s,v,*r,*g,*b); +#endif +} + +static void +changeColor (struct state *st, double r, double g, double b) +{ + int n,n1; + + n1=0; + for(n=30;n<64;n+=3) + { + st->colors[n1].red =1023+ n*(int)(1024.*r); + st->colors[n1].blue =1023+ n*(int)(1024.*b); + st->colors[n1].green =1023+ n*(int)(1024.*g); + + n1++; + } + + XStoreColors (st->dpy, st->cmap, st->colors, 12); +} + +static void +initColor (struct state *st, double r, double g, double b) +{ + int n,n1; + unsigned long pixels[12]; + unsigned long dummy; + + st->cmap = st->xgwa.colormap; + + if(st->hsvcycl!=0.0 && XAllocColorCells(st->dpy, st->cmap, 0, &dummy, 0, pixels, 12)) + { + for(n1=0;n1<12;n1++) + { + st->colors[n1].pixel=pixels[n1]; + st->colors[n1].flags=DoRed | DoGreen | DoBlue; + } + + changeColor(st,r,g,b); + } + else + { + n1=0; + for(n=30;n<64;n+=3) + { + st->colors[n1].red =1023+ n*(int)(1024.*r); + st->colors[n1].blue =1023+ n*(int)(1024.*b); + st->colors[n1].green =1023+ n*(int)(1024.*g); + + if (!(XAllocColor (st->dpy, st->cmap, &st->colors[n1]))) { + fprintf (stderr, "Error: Cannot allocate colors\n"); + exit (1); + } + + n1++; + } + } +} + +/* ----------------WINDOW-------------------*/ + +static void +initialize (struct state *st) +{ + XGCValues *xgc; + XGCValues *xorgc; + XGCValues *xandgc; + + st->maxk=34; + st->r = st->g = st->b = 1; + st->hue = st->sat = 0; + st->val = 1; + st->mag = 10; + st->movef = 0.5; + st->wobber = 2; + st->cycle = 6; + st->scrnWidth = WIDTH; + st->scrnHeight = HEIGHT; + + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->scrnWidth = st->xgwa.width; + st->scrnHeight = st->xgwa.height; + + { + //float f = get_float_resource (st->dpy, "cycle", "Float"); + float f = cycle; + if (f <= 0 || f > 60) f = 6.0; + st->cycle = 60.0 / f; + } + //st->movef = get_float_resource (st->dpy, "move", "Float"); + //st->wobber = get_float_resource (st->dpy, "wobble", "Float"); + st->movef = move; + st->wobber = wobble; + + { + //double magfac = get_float_resource (st->dpy, "mag", "Float"); + double magfac = mag; + st->mag *= magfac; + st->fastch=(int)(st->fastch*magfac); + } + + //if (get_boolean_resource (st->dpy, "minutes", "Boolean")) + if (minutes) + { + st->minutes=1; st->maxk+=60-24; + } + +#if 1 + st->timewait = delay; + st->fastch = fast; + st->cycl = colcycle; + st->hsvcycl = hsvcycle; +#else + st->timewait = get_integer_resource (st->dpy, "delay", "Integer"); + st->fastch = get_integer_resource (st->dpy, "fast", "Integer"); + st->cycl = get_boolean_resource (st->dpy, "colcycle", "Integer"); + st->hsvcycl = get_float_resource (st->dpy, "hsvcycle", "Integer"); +#endif + + { + //char *s = get_string_resource (st->dpy, "rgb", "RGB"); + char *s = _strdup(rgb); + char dummy; + if (s && *s) + { + double rr, gg, bb; + if (3 == sscanf (s, "%lf %lf %lf %c", &rr, &gg, &bb, &dummy)) + st->r = rr, st->g = gg, st->b = bb; + } + if (s) free (s); + + //s = get_string_resource (st->dpy, "hsv", "HSV"); + s = _strdup(hsv); + if (s && *s) + { + double hh, ss, vv; + if (3 == sscanf (s, "%lf %lf %lf %c", &hh, &ss, &vv, &dummy)) { + st->hue = hh, st->sat = ss, st->val = vv; + hsv2rgb(st->hue,st->sat,st->val,&st->r,&st->g,&st->b); + } + } + if (s) free (s); + } + + if (st->fastch > maxfast) + st->fastch=maxfast; + + xgc=( XGCValues *) malloc(sizeof(XGCValues) ); + xorgc=( XGCValues *) malloc(sizeof(XGCValues) ); + xandgc=( XGCValues *) malloc(sizeof(XGCValues) ); + + st->planes=st->xgwa.depth; + +#ifdef HAVE_COCOA +# define GXandInverted GXcopy /* #### this can't be right, right? */ +#endif + st->gc = XCreateGC (st->dpy, st->window, 0, xgc); + xorgc->function =GXor; + st->orgc = XCreateGC (st->dpy, st->window, GCFunction, xorgc); + xandgc->function =GXandInverted; + st->andgc = XCreateGC (st->dpy, st->window, GCFunction, xandgc); + + st->buffer = XCreatePixmap (st->dpy, st->window, st->scrnWidth, st->scrnHeight, + st->xgwa.depth); + +#ifdef DEBUG + printf("Time 3D drawing "); +#ifdef FASTDRAW +# ifdef FASTCOPY + puts("fast by Pixmap copy"); +# else + puts("fast by XImage copy"); +# endif +#else + puts("slow"); +#endif +#endif /* DEBUG */ + +#ifdef FASTCOPY + st->fastcircles = XCreatePixmap (st->dpy, st->window, fastcw, st->fastch+1, st->xgwa.depth); + st->fastmask = XCreatePixmap (st->dpy, st->window, fastcw, st->fastch+1, st->xgwa.depth); +#endif + + setink(BlackPixelOfScreen (st->xgwa.screen)); + XFillRectangle (st->dpy, st->buffer , st->gc, 0, 0, st->scrnWidth, st->scrnHeight); + +#ifdef FASTCOPY + + setink(0); + XFillRectangle (st->dpy, st->fastcircles, st->gc, 0, 0, fastcw, st->fastch+1); + XFillRectangle (st->dpy, st->fastmask , st->gc, 0, 0, fastcw, st->fastch+1); + +#endif + +#ifdef PRTDBX + printf("move\t%.2f\nwobber\t%.2f\nmag\t%.2f\ncycle\t%.4f\n", + st->movef,st->wobber,st->mag/10,st->cycle); + printf("fast\t%i\nmarks\t%i\nwait\t%i\n",st->fastch,st->maxk,st->timewait); +#endif + +} + +static void fill_kugel(struct state *st, int i, Pixmap buf, int setcol); + + +/*------------------------------------------------------------------*/ +static void +init_kugel(struct state *st) +{ + +#ifdef FASTDRAW + int i; + + for(i=0; ifastch; i++) + { +# ifdef FASTCOPY + st->kugeln[i].r1=-((double) i)/2 -1; + st->kugeln[i].x1=sum1ton(i); + st->kugeln[i].y1=((double) i)/2 +1; + + fill_kugel(st,i,st->fastcircles,1); + setink((1<xgwa.depth))-1); + fill_kugel(st,i,st->fastmask,0); +# else + st->kugeln[i].r1=-((double) i)/2 -1; + st->kugeln[i].x1=st->kugeln[i].y1=((double) i)/2 +1; + + fill_kugel(i,st->buffer,1); + st->fastcircles[i]=XGetImage(st->dpy,st->buffer,0,0,i+2,i+2,(1<planes)-1,ZPixmap); + + setink((1<xgwa.depth))-1); + fill_kugel(i,st->buffer,0); + st->fastmask[i]=XGetImage(st->dpy,st->buffer,0,0,i+2,i+2,(1<planes)-1,ZPixmap); + + setink(0); + XFillRectangle (st->dpy, st->buffer , st->gc, 0, 0, st->scrnWidth, st->scrnHeight); +# endif + } + st->fastdraw=1; +#endif +} + +/* Zeiger zeichnen */ + +static void +zeiger(struct state *st, double dist,double rad, double z, double sec, int *q) +{ + int i,n; + double gratio=sqrt(2.0/(1.0+sqrt(5.0))); + + n = *q; + + for(i=0;i<3;i++) + { + st->kugeln[n].x=dist*cos(sec); + st->kugeln[n].y=-dist*sin(sec); + st->kugeln[n].z=z; + st->kugeln[n].r=rad; + n++; + + dist += rad; + rad = rad*gratio; + } + *q = n; +} + +/*-----------------------------------------------------------------* + * Uhr zeichnen * + *-----------------------------------------------------------------*/ + +static void +manipulate(struct state *st, double k) +{ + double i,l,/*xs,*/ys,zs,mod; + double /*persec,*/sec,min,hour; + int n; + + sec=TWOPI*modf(k/60,&mod); + min=TWOPI*modf(k/3600,&mod); + hour=TWOPI*modf(k/43200,&mod); + + l=TWOPI*modf(k/300,&mod); + i=0.0; + for (n=0;nkugeln[n].x=4.0*sin(i); + st->kugeln[n].y=4.0*cos(i); + st->kugeln[n].z=st->wobber* /* (sin(floor(2+2*l/(PI))*i)*sin(2*l)); */ + cos((i-sec)*floor(2+5*l/(PI)))*sin(5*l); + if(st->minutes) + { + st->kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */ + ((n % 5!=0) ? 0.3 : 0.6)* + ((n % 15 ==0) ? 1.25 : .75); + } + else + { + st->kugeln[n].r=/* (1.0+0.3*cos(floor(2+2*l/(PI))*i)*sin(2*l))* */ + ((n & 1) ? 0.5 : 1.0)* + ((n % 6==0) ? 1.25 : .75); + } + i+=TWOPI/kmax; + } + + st->kugeln[n].x=0.0; + st->kugeln[n].y=0.0; + st->kugeln[n].z=0.0; + st->kugeln[n].r=2.0+cos(TWOPI*modf(k,&mod))/2; + n++; + + zeiger(st,2.0,0.75,-2.0,sec,&n); + zeiger(st,1.0,1.0,-1.5,min,&n); + zeiger(st,0.0,1.5,-1.0,hour,&n); + + for(n=0;nmaxk;n++) + { + ys=st->kugeln[n].y*cos(st->movef*sin(st->cycle*sec))+ + st->kugeln[n].z*sin(st->movef*sin(st->cycle*sec)); + zs=-st->kugeln[n].y*sin(st->movef*sin(st->cycle*sec))+ + st->kugeln[n].z*cos(st->movef*sin(st->cycle*sec)); + st->kugeln[n].y=ys; + st->kugeln[n].z=zs; + } +} +/*------------------------------------------------------------------*/ +static void +t3d_sort(struct state *st, int l, int r) +{ + int i,j; + kugeldat ex; + double x; + + i=l;j=r; + x=st->kugeln[(l+r)/2].d; + while(1) + { + while(st->kugeln[i].d>x) i++; + while(x>st->kugeln[j].d) j--; + if (i<=j) + { + ex=st->kugeln[i];st->kugeln[i]=st->kugeln[j];st->kugeln[j]=ex; + i++;j--; + } + if (i>j) break; + } + if (lkugeln[i].r1)*2)); + if (d==0) d=1; + +#ifdef FASTDRAW + if(st->fastdraw && dfastch) + { +# ifdef FASTCOPY + XCopyArea(st->dpy, st->fastmask, buf, st->andgc, sum1ton(d)-(d+1)/2, 1,d,d, + (int)(st->kugeln[i].x1)-d/2, (int)(st->kugeln[i].y1)-d/2); + XCopyArea(st->dpy, st->fastcircles, buf, st->orgc, sum1ton(d)-(d+1)/2, 1,d,d, + (int)(st->kugeln[i].x1)-d/2, (int)(st->kugeln[i].y1)-d/2); +# else + XPutImage(st->dpy, buf, st->andgc, st->fastmask[d-1], 0, 0, + (int)(st->kugeln[i].x1)-d/2, (int)(st->kugeln[i].y1)-d/2, d, d); + XPutImage(st->dpy, buf, st->orgc, st->fastcircles[d-1], 0, 0, + (int)(st->kugeln[i].x1)-d/2, (int)(st->kugeln[i].y1)-d/2, d, d); +# endif + } + else +#endif + { + if(ABS(st->kugeln[i].r1)<6.0) inr=9; + + for (m=0;m<=28;m+=inr) + { + ra=st->kugeln[i].r1*sqrt(1-m*m/(28.0*28.0)); +#ifdef PRTDBX + printf("Radius: %f\n",ra); +#endif + if(-ra< 3.0) inc=14; + else if(-ra< 6.0) inc=8; + else if(-ra<20.0) inc=4; + else if(-ra<40.0) inc=2; + if(setcol) + { + if (m==27) col=33; + else + col=(int)(m); + if (col>33) col=33; col/=3; + setink(st->colors[col].pixel); + } + +#ifdef USE_POLYGON + { + int n, nr; + for (n=0,nr=0;n<=sines-1;n+=inc,nr++) + { + track[nr].x=st->kugeln[i].x1+(int)(ra*st->sinus[n])+(st->kugeln[i].r1-ra)/2; + track[nr].y=st->kugeln[i].y1+(int)(ra*st->cosinus[n])+(st->kugeln[i].r1-ra)/2; + } + XFillPolygon(st->dpy,buf,st->gc,track,nr,Convex,CoordModeOrigin); + } +#else /* Use XFillArc */ + XFillArc(st->dpy, buf, st->gc, + (int)(st->kugeln[i].x1+(st->kugeln[i].r1+ra)/2), + (int)(st->kugeln[i].y1+(st->kugeln[i].r1+ra)/2), + (int)-(2*ra+1), (int)-(2*ra+1), 0, 360*64); +#endif + } + } +} + +/*------------------------------------------------------------------*/ + +static void +init_3d(struct state *st) +{ + double i; + int n=0; + + st->a[0]=0.0; + st->a[1]=0.0; + st->a[2]=-10.0; + + st->x[0]=10.0; + st->x[1]=0.0; + st->x[2]=0.0; + + st->y[0]=0.0; + st->y[1]=10.0; + st->y[2]=0.0; + + + st->zoom=-10.0; + st->speed=.0; + + for (i=0.0;nsinus[n]=sin(i); + st->cosinus[n]=cos(i); + } +} +/*------------------------------------------------------------------*/ + + +static void +vektorprodukt(double feld1[], double feld2[], double feld3[]) +{ + feld3[0]=feld1[1]*feld2[2]-feld1[2]*feld2[1]; + feld3[1]=feld1[2]*feld2[0]-feld1[0]*feld2[2]; + feld3[2]=feld1[0]*feld2[1]-feld1[1]*feld2[0]; +} + + +/*------------------------------------------------------------------*/ +static void +turn(double feld1[], double feld2[], double winkel) +{ + double temp[3]; + double s,ca,sa,sx1,sx2,sx3; + + vektorprodukt(feld1,feld2,temp); + + s=feld1[0]*feld2[0]+feld1[1]*feld2[1]+feld1[2]*feld2[2]; + + sx1=s*feld2[0]; + sx2=s*feld2[1]; + sx3=s*feld2[2]; + sa=sin(winkel);ca=cos(winkel); + feld1[0]=ca*(feld1[0]-sx1)+sa*temp[0]+sx1; + feld1[1]=ca*(feld1[1]-sx2)+sa*temp[1]+sx2; + feld1[2]=ca*(feld1[2]-sx3)+sa*temp[2]+sx3; +} +/*------------------------------------------------------------------*/ + +/* 1: Blickrichtung v;3:Ebenenmittelpunkt m + double feld1[],feld3[]; */ +static void +viewpoint(struct state *st) +{ + st->am[0]=-st->zoom*st->v[0]; + st->am[1]=-st->zoom*st->v[1]; + st->am[2]=-st->zoom*st->v[2]; + + st->zaehler=norm*norm*st->zoom; +} + +/*------------------------------------------------------------------*/ +static void +projektion(struct state *st) +{ + double c1[3],c2[3],k[3],x1,y1; + double cno,cnorm/*,magnit*/; + int i; + + for (i=0;imaxk;i++) + { + c1[0]=st->kugeln[i].x-st->a[0]; + c1[1]=st->kugeln[i].y-st->a[1]; + c1[2]=st->kugeln[i].z-st->a[2]; + cnorm=sqrt(c1[0]*c1[0]+c1[1]*c1[1]+c1[2]*c1[2]); + + c2[0]=c1[0]; + c2[1]=c1[1]; + c2[2]=c1[2]; + + cno=c2[0]*st->v[0]+c2[1]*st->v[1]+c2[2]*st->v[2]; + st->kugeln[i].d=cnorm; + if (cno<0) st->kugeln[i].d=-20.0; + + + st->kugeln[i].r1=(st->mag*st->zoom*st->kugeln[i].r/cnorm); + + c2[0]=st->v[0]/cno; + c2[1]=st->v[1]/cno; + c2[2]=st->v[2]/cno; + + vektorprodukt(c2,c1,k); + + + x1=(st->startx+(st->x[0]*k[0]+st->x[1]*k[1]+st->x[2]*k[2])*st->mag); + y1=(st->starty-(st->y[0]*k[0]+st->y[1]*k[1]+st->y[2]*k[2])*st->mag); + if( (x1>-2000.0) + && (x1scrnWidth+2000.0) + && (y1>-2000.0) + && (y1scrnHeight+2000.0)) + { + st->kugeln[i].x1=(int)x1; + st->kugeln[i].y1=(int)y1; + } + else + { + st->kugeln[i].x1=0; + st->kugeln[i].y1=0; + st->kugeln[i].d=-20.0; + } + } +} + + +static void * +t3d_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + st->dpy = dpy; + st->window = window; + initialize(st); + + initColor(st,st->r,st->g,st->b); + init_3d(st); + st->zeit=(struct tm *)malloc(sizeof(struct tm)); + init_kugel(st); + + st->startx=st->scrnWidth/2; + st->starty=st->scrnHeight/2; + st->scrnH2=st->startx; + st->scrnW2=st->starty; + st->vspeed=0; + + + vektorprodukt(st->x,st->y,st->v); + viewpoint(st/*m,v*/); + + setink (BlackPixelOfScreen(st->xgwa.screen)); + XFillRectangle (st->dpy, st->window, st->gc, 0, 0, st->scrnWidth, st->scrnHeight); + XQueryPointer (st->dpy, st->window, &st->junk_win, &st->junk_win, &st->junk, &st->junk, + &st->px, &st->py, &st->kb); + + return st; +} + +static unsigned long +t3d_draw (Display *d, Window w, void *closure) +{ + struct state *st = (struct state *) closure; + double dtime; + double vnorm; + + + /*--------------- Zeichenteil --------------*/ + + vektorprodukt(st->x,st->y,st->v); + + vnorm=sqrt(st->v[0]*st->v[0]+st->v[1]*st->v[1]+st->v[2]*st->v[2]); + st->v[0]=st->v[0]*norm/vnorm; + st->v[1]=st->v[1]*norm/vnorm; + st->v[2]=st->v[2]*norm/vnorm; + vnorm=sqrt(st->x[0]*st->x[0]+st->x[1]*st->x[1]+st->x[2]*st->x[2]); + st->x[0]=st->x[0]*norm/vnorm; + st->x[1]=st->x[1]*norm/vnorm; + st->x[2]=st->x[2]*norm/vnorm; + vnorm=sqrt(st->y[0]*st->y[0]+st->y[1]*st->y[1]+st->y[2]*st->y[2]); + st->y[0]=st->y[0]*norm/vnorm; + st->y[1]=st->y[1]*norm/vnorm; + st->y[2]=st->y[2]*norm/vnorm; + + projektion(st); + t3d_sort (st,0,st->maxk-1); + + dtime=gettime(st); + + if(st->cycl) + { + st->draw_color=(int)(64.0*(dtime/60-floor(dtime/60)))-32; + + if(st->draw_color<0) + st->draw_color=-st->draw_color; + + setink(st->colors[st->draw_color/3].pixel); + } + else + setink(BlackPixelOfScreen (st->xgwa.screen)); + + XFillRectangle(st->dpy,st->buffer,st->gc,0,0,st->scrnWidth,st->scrnHeight); + + { + int i; + + manipulate(st,dtime); + + for (i=0;imaxk;i++) + { + if (st->kugeln[i].d>0.0) + fill_kugel(st,i,st->buffer,1); + } + } + + /* manipulate(gettime()); + var+=PI/500; + if (var>=TWOPI) var=PI/500; */ + + if(st->hsvcycl!=0.0) + { + dtime=st->hsvcycl*dtime/10.0+st->hue/360.0; + dtime=360*(dtime-floor(dtime)); + + hsv2rgb(dtime,st->sat,st->val,&st->r,&st->g,&st->b); + changeColor(st,st->r,st->g,st->b); + } + + XCopyArea (st->dpy, st->buffer, st->window, st->gc, 0, 0, st->scrnWidth, st->scrnHeight, 0, 0); + + + /*-------------------------------------------------*/ + + XQueryPointer (st->dpy, st->window, &st->junk_win, &st->in_win, &st->junk, &st->junk, + &st->px, &st->py, &st->kb); + + if ((st->px>0)&&(st->pxscrnWidth)&&(st->py>0)&&(st->pyscrnHeight) ) + { + if ((st->px !=st->startx)&&(st->kb&Button2Mask)) + { + /* printf("y=(%f,%f,%f)",y[0],y[1],y[2]);*/ + turn(st->y,st->x,((double)(st->px-st->startx))/(8000*st->mag)); + /* printf("->(%f,%f,%f)\n",y[0],y[1],y[2]);*/ + } + if ((st->py !=st->starty)&&(st->kb&Button2Mask)) + { + /* printf("x=(%f,%f,%f)",x[0],x[1],x[2]);*/ + turn(st->x,st->y,((double)(st->py-st->starty))/(-8000*st->mag)); + /* printf("->(%f,%f,%f)\n",x[0],x[1],x[2]);*/ + } + if ((st->kb&Button1Mask)) + { + if (st->vturn==0.0) st->vturn=.005; else if (st->vturn<2) st->vturn+=.01; + turn(st->x,st->v,.002*st->vturn); + turn(st->y,st->v,.002*st->vturn); + } + if ((st->kb&Button3Mask)) + { + if (st->vturn==0.0) st->vturn=.005; else if (st->vturn<2) st->vturn+=.01; + turn(st->x,st->v,-.002*st->vturn); + turn(st->y,st->v,-.002*st->vturn); + } + } + if (!(st->kb&Button1Mask)&&!(st->kb&Button3Mask)) + st->vturn=0; + + st->speed=st->speed+st->speed*st->vspeed; + if ((st->speed<0.0000001) &&(st->vspeed>0.000001)) st->speed=0.000001; + st->vspeed=.1*st->vspeed; + if (st->speed>0.01) st->speed=.01; + st->a[0]=st->a[0]+st->speed*st->v[0]; + st->a[1]=st->a[1]+st->speed*st->v[1]; + st->a[2]=st->a[2]+st->speed*st->v[2]; + + return st->timewait; +} + +static void +t3d_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + if (w != st->scrnWidth || + h != st->scrnHeight) + { + XFreePixmap (st->dpy, st->buffer); + st->scrnWidth = w; + st->scrnHeight = h; + st->buffer = XCreatePixmap (st->dpy, st->window, st->scrnWidth, st->scrnHeight, st->xgwa.depth); + + st->startx=st->scrnWidth/2; + st->starty=st->scrnHeight/2; + st->scrnH2=st->startx; + st->scrnW2=st->starty; + } +} + +#if 0 + static Bool + t3d_event (Display *dpy, Window window, void *closure, XEvent *event) + { + struct state *st = (struct state *) closure; + if (event->type == KeyPress) + { + KeySym keysym; + char kpr = 0; + XLookupString (&event->xkey, &kpr, 1, &keysym, 0); + switch (kpr) + { + case 's': case 'S': + st->vspeed = 0.5; + return True; + case 'a': case 'A': + st->vspeed = -0.3; + return True; + case '0': + st->speed = 0; + st->vspeed = 0; + return True; + case 'z': case 'Z': + st->mag *= 1.02; + return True; + case 'x': case 'X': + st->mag /= 1.02; + return True; + default: + break; + } + } + return False; + } +#endif + +static void +t3d_free (Display *dpy, Window window, void *closure) +{ +} + + + + +/*-------------------------------------------------*/ + +static const char *t3d_defaults [] = { + ".background: black", + ".foreground: white", + "*move: 0.5", + "*wobble: 2.0", + "*cycle: 10.0", + "*mag: 1.0", + "*minutes: False", + "*delay: 40000", + "*fast: 50", + "*colcycle: False", + "*hsvcycle: 0.0", + "*rgb: ", + "*hsv: ", + 0 +}; + +static XrmOptionDescRec t3d_options [] = { + { "-move", ".move", XrmoptionSepArg, 0 }, + { "-wobble", ".wobble", XrmoptionSepArg, 0 }, + { "-cycle", ".cycle", XrmoptionSepArg, 0 }, + { "-mag", ".mag", XrmoptionSepArg, 0 }, + { "-minutes", ".minutes", XrmoptionNoArg, "True" }, + { "-no-minutes", ".minutes", XrmoptionNoArg, "False" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-fast", ".fast", XrmoptionSepArg, 0 }, + { "-colcycle", ".colcycle", XrmoptionSepArg, 0 }, + { "-hsvcycle", ".hsvcycle", XrmoptionSepArg, 0 }, + { "-rgb", ".rgb", XrmoptionSepArg, 0 }, + { "-hsv", ".hsv", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("T3D", t3d) diff --git a/non-wgl/t3d.vcproj b/non-wgl/t3d.vcproj new file mode 100644 index 0000000..67314da --- /dev/null +++ b/non-wgl/t3d.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/thornbird.c b/non-wgl/thornbird.c new file mode 100644 index 0000000..1eaf70f --- /dev/null +++ b/non-wgl/thornbird.c @@ -0,0 +1,289 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* thornbird --- continuously varying Thornbird set */ + +#if 0 +static const char sccsid[] = "@(#)thornbird.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1996 by Tim Auckland + * + * 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. + * + * "thornbird" shows a view of the "Bird in a Thornbush" fractal, + * continuously varying the three free parameters. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 04-Jun-1999: 3D tumble added by Tim Auckland + * 31-Jul-1997: Adapted from discrete.c Copyright (c) 1996 by Tim Auckland + */ + +#define STANDALONE +#define NOARGS + +# define MODE_thornbird +#define DELAY 10000 +#define COUNT 100 +#define CYCLES 400 +#define NCOLORS 64 +#define DEFAULTS "*delay: 10000 \n" \ + "*count: 100 \n" \ + "*cycles: 400 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" \ + +# define BRIGHT_COLORS +# define thornbird_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_thornbird + +ENTRYPOINT ModeSpecOpt thornbird_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct thornbird_description = +{"thornbird", "init_thornbird", "draw_thornbird", "release_thornbird", + "refresh_thornbird", "init_thornbird", (char *) NULL, þbird_opts, + 1000, 800, 16, 1, 64, 1.0, "", + "Shows an animated Bird in a Thorn Bush fractal map", 0, NULL}; +#endif + +#define balance_rand(v) ((LRAND()/MAXRAND*(v))-((v)/2)) /* random around 0 */ + +typedef struct { + int maxx; + int maxy; /* max of the screen */ + double a; + double b; + double c; + double d; + double e; + double i; + double j; /* thornbird parameters */ + struct { + double f1; + double f2; + } liss; + struct { + double theta; + double dtheta; + double phi; + double dphi; + } tumble; + int inc; + int pix; + int count; + int nbuffers; + XPoint **pointBuffer; /* pointer for XDrawPoints */ +} thornbirdstruct; + +static thornbirdstruct *thornbirds = (thornbirdstruct *) NULL; + +static void +free_thornbird(thornbirdstruct *hp) +{ + if (hp->pointBuffer != NULL) { + int buffer; + + for (buffer = 0; buffer < hp->nbuffers; buffer++) + if (hp->pointBuffer[buffer] != NULL) + (void) free((void *) hp->pointBuffer[buffer]); + (void) free((void *) hp->pointBuffer); + hp->pointBuffer = (XPoint **) NULL; + } +} + +ENTRYPOINT void +init_thornbird (ModeInfo * mi) +{ + thornbirdstruct *hp; + + if (thornbirds == NULL) { + if ((thornbirds = + (thornbirdstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (thornbirdstruct))) == NULL) + return; + } + hp = þbirds[MI_SCREEN(mi)]; + + + hp->maxx = MI_WIDTH(mi); + hp->maxy = MI_HEIGHT(mi); + + hp->b = 0.1; + hp->i = hp->j = 0.1; + + hp->pix = 0; + hp->inc = 0; + + hp->nbuffers = MI_CYCLES(mi); + + if (hp->pointBuffer == NULL) + if ((hp->pointBuffer = (XPoint **) calloc(MI_CYCLES(mi), + sizeof (XPoint *))) == NULL) { + free_thornbird(hp); + return; + } + + if (hp->pointBuffer[0] == NULL) + if ((hp->pointBuffer[0] = (XPoint *) malloc(MI_COUNT(mi) * + sizeof (XPoint))) == NULL) { + free_thornbird(hp); + return; + } + + /* select frequencies for parameter variation */ + hp->liss.f1 = LRAND() % 5000; + hp->liss.f2 = LRAND() % 2000; + + /* choose random 3D tumbling */ + hp->tumble.theta = 0; + hp->tumble.phi = 0; + hp->tumble.dtheta = balance_rand(0.001); + hp->tumble.dphi = balance_rand(0.005); + + /* Clear the background. */ + MI_CLEARWINDOW(mi); + + hp->count = 0; +} + + +ENTRYPOINT void +draw_thornbird(ModeInfo * mi) +{ + Display *dsp = MI_DISPLAY(mi); + Window win = MI_WINDOW(mi); + double oldj, oldi; + int batchcount = MI_COUNT(mi); + int k; + XPoint *xp; + GC gc = MI_GC(mi); + int erase; + int current; + + double sint, cost, sinp, cosp; + thornbirdstruct *hp; + + if (thornbirds == NULL) + return; + hp = þbirds[MI_SCREEN(mi)]; + if (hp->pointBuffer == NULL) + return; + + erase = (hp->inc + 1) % MI_CYCLES(mi); + current = hp->inc % MI_CYCLES(mi); + k = batchcount; + + + xp = hp->pointBuffer[current]; + + /* vary papameters */ + hp->a = 1.99 + (0.4 * sin(hp->inc / hp->liss.f1) + + 0.05 * cos(hp->inc / hp->liss.f2)); + hp->c = 0.80 + (0.15 * cos(hp->inc / hp->liss.f1) + + 0.05 * sin(hp->inc / hp->liss.f2)); + + /* vary view */ + hp->tumble.theta += hp->tumble.dtheta; + hp->tumble.phi += hp->tumble.dphi; + sint = sin(hp->tumble.theta); + cost = cos(hp->tumble.theta); + sinp = sin(hp->tumble.phi); + cosp = cos(hp->tumble.phi); + + while (k--) { + oldj = hp->j; + oldi = hp->i; + + hp->j = oldi; + hp->i = (1 - hp->c) * cos(M_PI * hp->a * oldj) + hp->c * hp->b; + hp->b = oldj; + + xp->x = (short) + (hp->maxx / 2 * (1 + + sint*hp->j + cost*cosp*hp->i - cost*sinp*hp->b)); + xp->y = (short) + (hp->maxy / 2 * (1 + - cost*hp->j + sint*cosp*hp->i - sint*sinp*hp->b)); + xp++; + } + + MI_IS_DRAWN(mi) = True; + + if (hp->pointBuffer[erase] == NULL) { + if ((hp->pointBuffer[erase] = (XPoint *) malloc(MI_COUNT(mi) * + sizeof (XPoint))) == NULL) { + free_thornbird(hp); + return; + } + } else { + XSetForeground(dsp, gc, MI_BLACK_PIXEL(mi)); + XDrawPoints(dsp, win, gc, hp->pointBuffer[erase], + batchcount, CoordModeOrigin); + } + if (MI_NPIXELS(mi) > 2) { + XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix)); +#if 0 + if (erase == 0) /* change colours after "cycles" cycles */ +#else + if (!((hp->inc + 1) % (1 + (MI_CYCLES(mi) / 3)))) /* jwz: sooner */ +#endif + if (++hp->pix >= MI_NPIXELS(mi)) + hp->pix = 0; + } else + XSetForeground(dsp, gc, MI_WHITE_PIXEL(mi)); + + XDrawPoints(dsp, win, gc, hp->pointBuffer[current], + batchcount, CoordModeOrigin); + hp->inc++; +} + +ENTRYPOINT void +reshape_thornbird(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_thornbird (mi); +} + +ENTRYPOINT void +release_thornbird(ModeInfo * mi) +{ + if (thornbirds != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_thornbird(þbirds[screen]); + (void) free((void *) thornbirds); + thornbirds = (thornbirdstruct *) NULL; + } +} + +ENTRYPOINT void +refresh_thornbird (ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} + + +XSCREENSAVER_MODULE ("Thornbird", thornbird) + +#endif /* MODE_thornbird */ diff --git a/non-wgl/thornbird.vcproj b/non-wgl/thornbird.vcproj new file mode 100644 index 0000000..c576e22 --- /dev/null +++ b/non-wgl/thornbird.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/triangle.c b/non-wgl/triangle.c new file mode 100644 index 0000000..67d2daa --- /dev/null +++ b/non-wgl/triangle.c @@ -0,0 +1,377 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* triangle --- create a triangle-mountain */ + +#if 0 +static const char sccsid[] = "@(#)triangle.c 4.04 97/07/28 xlockmore"; +#endif + +/*- + * Copyright (c) 1995 by Tobias Gloth + * + * 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: + * 10-May-97: Compatible with xscreensaver + * 10-Mar-96: re-arranged and re-formatted the code for appearance and + * to make common subroutines. Simplified. + * Ron Hitchens + * 07-Mar-96: Removed internal delay code, set MI_PAUSE(mi) for inter-scene + * delays. No other delays are needed here. + * Made pause time sensitive to value of cycles (in 10ths of a + * second). Removed (hopefully) all references to globals. + * Ron Hitchens + * 27-Feb-96: Undid the changes listed below. Added ModeInfo argument. + * Implemented delay between scenes using the MI_PAUSE(mi) + * scheme. Ron Hitchens + * 27-Dec-95: Ron Hitchens + * Modified logic of draw_triangle() to provide a delay + * (sensitive to the value of cycles) between each iteration. + * Because this mode is so compute intensive, when the new + * event loop adjusted the delay to compensate, this mode had + * almost no delay time left. This change pauses between each + * new landscape, but could still be done better (it is not + * sensitive to input events while drawing, for example). + * 03-Nov-95: Many changes (hopefully some good ones) by David Bagley + * 01-Oct-95: Written by Tobias Gloth + */ + +#define STANDALONE +#define NOARGS + +#define DELAY 10000 +#define NCOLORS 128 +# define DEFAULTS "*delay: 10000 \n" \ + "*ncolors: 128 \n" \ + "*fpsSolid: true \n" \ + +# define SMOOTH_COLORS +# define triangle_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +ENTRYPOINT ModeSpecOpt triangle_opts = +{0, NULL, 0, NULL, NULL}; + +#define MAX_STEPS 8 +#define MAX_SIZE (1< 2) { /* color */ + int dmax, dmin; + long color; + + dmin = MIN(y_0, y_1); + dmin = MIN(dmin, y_2); + dmax = MAX(y_0, y_1); + dmax = MAX(dmax, y_2); + + if (dmax == 0) { + color = BLUE; + } else { + color = MI_NCOLORS(mi) - + (int) ((double) MI_NCOLORS(mi) / M_PI_2 * atan(dinv * (dmax - dmin))); + } + + XSetForeground(display, gc, mi->colors[color % MI_NCOLORS(mi)].pixel); + XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin); + } else { + /* mono */ +#ifdef BACKFACE_REMOVAL + XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi)); + XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin); +#endif + XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi)); + XDrawLine(display, window, gc, p[0].x, p[0].y, p[1].x, p[1].y); + XDrawLine(display, window, gc, p[1].x, p[1].y, p[2].x, p[2].y); + XDrawLine(display, window, gc, p[2].x, p[2].y, p[0].x, p[0].y); + } +} + +static +void +calc_points1(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p) +{ + *y0_p = tp->level[MAX(tp->h[tp->i][tp->j], 0)]; + *y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)]; + *y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)]; + + p[0].x = tp->xpos[2 * tp->i + tp->j]; + p[1].x = tp->xpos[2 * (tp->i + d) + tp->j]; + p[2].x = tp->xpos[2 * tp->i + (tp->j + d)]; + + p[0].y = tp->ypos[tp->j] - *y0_p; + p[1].y = tp->ypos[tp->j] - *y1_p; + p[2].y = tp->ypos[tp->j + d] - *y2_p; +} + +static +void +calc_points2(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p) +{ + *y0_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)]; + *y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j + d], 0)]; + *y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)]; + + p[0].x = tp->xpos[2 * (tp->i + d) + tp->j]; + p[1].x = tp->xpos[2 * (tp->i + d) + (tp->j + d)]; + p[2].x = tp->xpos[2 * tp->i + (tp->j + d)]; + + p[0].y = tp->ypos[tp->j] - *y0_p; + p[1].y = tp->ypos[tp->j + d] - *y1_p; + p[2].y = tp->ypos[tp->j + d] - *y2_p; +} + + +static +void +draw_mesh(ModeInfo * mi, trianglestruct * tp, int d, int count) +{ + XPoint p[3]; + int first = 1; + int y_0, y_1, y_2; + double dinv = 0.2 / d; + + if ((tp->j == 0) && (tp->i == 0)) { +#if 0 /* jwz */ + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); +#else + { + int x = 0; + int y = 0; + int x2 = MI_WIN_WIDTH(mi); + int y2 = tp->ypos[0]; + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi)); + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + x, y, x2, y2); + } +#endif + } + for (; (tp->j < tp->size) && (count > 0); tp->j += ((count) ? d : 0)) { + for (tp->i = (first) ? tp->i : 0, first = 0; + (tp->i < MAX_SIZE - tp->j) && (count > 0); + tp->i += d, count--) { + if (tp->i + tp->j < tp->size) { + calc_points1(tp, d, &y_0, &y_1, &y_2, p); + draw_atriangle(mi, p, y_0, y_1, y_2, dinv); + } + if (tp->i + tp->j + d < tp->size) { + calc_points2(tp, d, &y_0, &y_1, &y_2, p); + draw_atriangle(mi, p, y_0, y_1, y_2, dinv); + } + } + } + + if (tp->j == tp->size) { + tp->init_now = 1; + } +} + +ENTRYPOINT void +init_triangle (ModeInfo * mi) +{ + trianglestruct *tp; + short *tmp; + int i, dim, one; + + if (triangles == NULL) { + if ((triangles = (trianglestruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (trianglestruct))) == NULL) + return; + } + tp = &triangles[MI_SCREEN(mi)]; + + tp->width = MI_WIN_WIDTH(mi); + tp->height = MI_WIN_HEIGHT(mi); + tp->init_now = 1; + tp->fast = 2; + + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); + + + + tp->steps = MAX_STEPS; + do { + tp->size = 1 << --tp->steps; + } while (tp->size * 5 > tp->width); + tmp = tp->H; + for (i = 0; i < tp->size + 1; i++) { + tp->h[i] = tmp; + tmp += (tp->size) + 1 - i; + } + + tp->stage = -1; + dim = MIN(tp->width, tp->height); + + for (i = 0; i < 2 * tp->size + 1; i++) { + tp->xpos[i] = (short) ((((double) i) + / ((double) (2 * tp->size)) * (RIGHT - LEFT) + LEFT) + * dim) + (tp->width - dim) / 2; + } + + for (i = 0; i < (tp->size + 1); i++) { + tp->ypos[i] = (short) ((((double) i) + / ((double) tp->size) * (BOTTOM - TOP) + TOP) * dim) + + (tp->height - dim) / 2; + } + + for (i = 0; i < tp->steps; i++) { + tp->delta[i] = ((short) (DELTA * dim)) >> i; + } + + one = tp->delta[0]; + + if (one > 0) + for (i = 0; i < MAX_LEVELS; i++) { + tp->level[i] = (i * i) / one; + } +} + +ENTRYPOINT void +draw_triangle (ModeInfo * mi) +{ + trianglestruct *tp = &triangles[MI_SCREEN(mi)]; + int d, d2, i, j, delta; + + if (!tp->init_now) { + draw_mesh(mi, tp, tp->d / 2, MAX_SIZE / tp->d); + + /* The init_now flag will pop up when the scene is complete. + * Cycles specifies how long to wait, in 1/10 secs. + TODO: This is wrong for multi-screens *** + */ + if (tp->init_now) { +#ifndef STANDALONE + MI_PAUSE(mi) = 2000000; +#else + if (tp->stage == -1) + { + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); + //if (!mono_p) + if (0) + { + free_colors(mi->xgwa.screen, mi->xgwa.colormap, mi->colors, + mi->npixels); + //mi->npixels = + // get_integer_resource (mi->dpy, "ncolors", "Integer"); + mi->npixels = hack_ncolors; + make_smooth_colormap (mi->xgwa.screen, + mi->xgwa.visual, mi->xgwa.colormap, + mi->colors, &mi->npixels, + True, &mi->writable_p, True); + } + } +#endif + } + return; + } + if (tp->delta[0] > 0) { + if (!(++tp->stage)) { + tp->h[0][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0])); + tp->h[tp->size][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0])); + tp->h[0][tp->size] = (short int) MAX(0, DISPLACE(0, tp->delta[0])); + } else { + d = 2 << (tp->steps - tp->stage); + d2 = d / 2; + delta = tp->delta[tp->stage - 1]; + + for (i = 0; i < tp->size; i += d) { + for (j = 0; j < (tp->size - i); j += d) { + tp->h[i + d2][j] = (short int) DISPLACE(tp->h[i][j] + + tp->h[i + d][j], delta); + tp->h[i][j + d2] = (short int) DISPLACE(tp->h[i][j] + + tp->h[i][j + d], delta); + tp->h[i + d2][j + d2] = (short int) DISPLACE(tp->h[i + d][j] + + tp->h[i][j + d], delta); + } + + tp->init_now = 0; + tp->i = 0; + tp->j = 0; + tp->d = d; + } + } + } + if (tp->stage == tp->steps) { + tp->stage = -1; + } +} + +ENTRYPOINT void +reshape_triangle(ModeInfo * mi, int width, int height) +{ + XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi)); + init_triangle (mi); +} + +ENTRYPOINT void +release_triangle(ModeInfo * mi) +{ + if (triangles != NULL) { + (void) free((void *) triangles); + triangles = NULL; + } +} + +ENTRYPOINT void +refresh_triangle (ModeInfo * mi) +{ + /* Do nothing, it will refresh by itself */ +} + +XSCREENSAVER_MODULE ("Triangle", triangle) diff --git a/non-wgl/triangle.vcproj b/non-wgl/triangle.vcproj new file mode 100644 index 0000000..52525a6 --- /dev/null +++ b/non-wgl/triangle.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/truchet.c b/non-wgl/truchet.c new file mode 100644 index 0000000..f8d836d --- /dev/null +++ b/non-wgl/truchet.c @@ -0,0 +1,603 @@ +/* truchet --- curved and straight tilings + * Copyright (c) 1998 Adrian Likins + * + * 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 screensaver draws two varieties of truchet patterns, a curved one and + a straight one. There are lots and lots of command line options to play + with. + + If your running remotely or on a slow machine or slow xserver, some of the + settings will be way too much. The default settings should be okay though. + + This screensaver doesnt use anything bizarre or special at all, just a few + standard xlib calls. + + A few suggested commandline combos..All these were tested on a k6-200 + running XFree86 3.3 on a ark2000, so your mileage may vary... + + truchet -delay 200 -no-curves + truchet -delay 500 -no-curves -square -no-erase + truchet -delay 500 -no-erase -square -erase-count 5 + truchet -scroll + truchet -scroll -no-erase -anim-step-size 9 + truchet -delay 200 -no-angles -min-width 36 -max-width 36 + truchet -delay 200 -no-curves -min-width 12 -max-width 12 + truchet -delay 200 -no-curves -min-width 36 -max-width 36 -no-erase + truchet -delay 100 -min-width 256 -max-width 512 -no-erase \ + -min-linewidth 96 -root + truchet -min-width 64 -max-width 128 -no-erase -max-linewidth 4 \ + -root -no-angles + truchet -min-width 64 -max-width 128 -no-erase -max-linewidth 4 \ + -root -no-curves -delay 25 + */ + +#include "screenhack.h" + +#define MAXRATIO 2 + +char *background = "black"; +char *foreground = "white"; + +int minWidth = 40; +int minHeight = 40; +int max_Width = 150; +int max_Height = 150; +int maxLineWidth = 25; +int minLineWidth = 2; +Bool erase = True; +int eraseCount = 25; +Bool square = True; +int delay = 400000; +Bool curves = True; +Bool angles = True; +Bool scroll = False; +int scroll_overlap = 400; +int anim_delay = 100; +int anim_step_size = 3; +Bool randomize = True; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&minWidth, "minWidth", NULL, "40", t_Int}, + {&minHeight, "minHeight", NULL, "40", t_Int}, + {&max_Width, "max_Width", NULL, "150", t_Int}, + {&max_Height, "max_Height", NULL, "150", t_Int}, + {&maxLineWidth, "maxLineWidth", NULL, "25", t_Int}, + {&minLineWidth, "minLineWidth", NULL, "2", t_Int}, + {&erase, "erase", NULL, "True", t_Bool}, + {&eraseCount, "eraseCount", NULL, "25", t_Int}, + {&square, "square", NULL, "True", t_Bool}, + {&delay, "delay", NULL, "400000", t_Int}, + {&curves, "curves", NULL, "True", t_Bool}, + {&angles, "angles", NULL, "True", t_Bool}, + {&scroll, "scroll", NULL, "False", t_Bool}, + {&scroll_overlap, "scroll_overlap", NULL, "400", t_Int}, + {&anim_delay, "anim_delay", NULL, "100", t_Int}, + {&anim_step_size, "anim_step_size", NULL, "3", t_Int}, + {&randomize, "randomize", NULL, "True", t_Bool}, +}; + +static const char *truchet_defaults [] = { + "*minWidth: 40", + "*minHeight: 40", + "*max-Width: 150", + "*max-Height: 150", + "*maxLineWidth: 25", + "*minLineWidth: 2", + "*erase: True", + "*eraseCount: 25", + "*square: True", + "*delay: 400000", + "*curves: True", + "*angles: True", + "*scroll: False", + "*scroll-overlap: 400", + "*anim-delay: 100", + "*anim-step-size: 3", + "*randomize: true", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +/* options passed to this program */ +static XrmOptionDescRec truchet_options [] = { + { "-min-width", ".minWidth", XrmoptionSepArg, 0 }, + { "-max-height", ".max-Height", XrmoptionSepArg, 0 }, + { "-max-width", ".max-Width", XrmoptionSepArg, 0 }, + { "-min-height", ".minHeight", XrmoptionSepArg, 0 }, + { "-max-linewidth", ".maxLineWidth", XrmoptionSepArg, 0 }, + { "-min-linewidth", ".minLineWidth", XrmoptionSepArg, 0 }, + { "-erase", ".erase", XrmoptionNoArg, "True" }, + { "-no-erase", ".erase", XrmoptionNoArg, "False" }, + { "-erase-count", ".eraseCount", XrmoptionSepArg, 0 }, + { "-square", ".square", XrmoptionNoArg, "True" }, + { "-not-square", ".square", XrmoptionNoArg, "False" }, + { "-curves", ".curves", XrmoptionNoArg, "True" }, + { "-angles", ".angles", XrmoptionNoArg, "True" }, + { "-no-angles", ".angles", XrmoptionNoArg, "False" }, + { "-no-curves", ".curves", XrmoptionNoArg, "False" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-scroll", ".scroll", XrmoptionNoArg, "True" }, + { "-scroll-overlap", ".scroll-overlap", XrmoptionSepArg, 0 }, + { "-anim-delay", ".anim-delay", XrmoptionSepArg, 0 }, + { "-anim-step-size", ".anim-step-size", XrmoptionSepArg, 0 }, + { "-randomize", ".randomize", XrmoptionNoArg, "True" }, + { 0, 0, 0, 0 } +}; + +struct state { + Display *dpy; + Window window; + + XGCValues gcv; + GC agc, bgc; + int linewidth; + int width, height; + XWindowAttributes xgwa; + Pixmap frame; + int overlap; + + int maxlinewidth; + int minlinewidth; + int minwidth; + int minheight; + int max_height; + int max_width; + int delay; + int count; + int anim_delay; + int anim_step_size; + + Colormap cmap; + XColor fgc; + Bool curves; + Bool square; + Bool angles; + Bool erase; + Bool eraseCount; + Bool scroll; + int scrolling; +}; + +static void draw_truchet(struct state *st); +static void draw_angles(struct state *st); +static void scroll_area(struct state *st, int step_size); + +static void draw_angles(struct state *st) +{ + int cx = 0, cy = 0; + + while((st->xgwa.height+st->overlap) > cy*st->height) + { + while((st->xgwa.width+st->overlap) > cx*st->width) + { + if(random()%2) + { + /* block1 */ + XDrawLine(st->dpy,st->frame,st->agc, + (cx*st->width)+(st->width/2), + (cy*st->height), + (cx*st->width)+(st->width), + (cy*st->height)+(st->height/2)); + XDrawLine(st->dpy,st->frame,st->agc, + (cx*st->width), + (cy*st->height)+(st->height/2), + (cx*st->width)+(st->width/2), + (cy*st->height)+(st->height)); + } + else + { + /* block 2 */ + XDrawLine(st->dpy,st->frame,st->agc, + (cx*st->width)+(st->width/2), + (cy*st->height), + (cx*st->width), + (cy*st->height)+(st->height/2)); + XDrawLine(st->dpy,st->frame,st->agc, + (cx*st->width)+(st->width), + (cy*st->height)+(st->height/2), + (cx*st->width)+(st->width/2), + (cy*st->height)+(st->height)); + } + cx++; + } + cy++; + cx=0; + } +} + + +static void draw_truchet(struct state *st) +{ + int cx = 0, cy = 0; + + while(st->xgwa.height+st->overlap > cy*st->height) + { + while(st->xgwa.width+st->overlap > cx*st->width) + { + if(random()%2) + { + /* block1 */ + XDrawArc(st->dpy, st->frame, st->agc, + ((cx*st->width)-(st->width/2)), + ((cy*st->height)-(st->height/2)), + st->width, + st->height, + 0, -5760); + XDrawArc(st->dpy,st->frame, st->agc, + ((cx*st->width)+(st->width/2)), + ((cy*st->height)+(st->height/2)), + st->width, + st->height, + 11520, + -5760); + } + else + { + /* block 2 */ + XDrawArc(st->dpy,st->frame,st->agc, + ((cx*st->width)+(st->width/2)), + ((cy*st->height)-(st->height/2)), + st->width, + st->height, + 17280, + -5760); + XDrawArc(st->dpy,st->frame,st->agc, + ((cx*st->width)-(st->width/2)), + ((cy*st->height)+(st->height/2)), + st->width, + st->height, + 0, + 5760); + } + cx++; + } + cy++; + cx=0; + } +} + + +static void scroll_area(struct state *st, int step_size) +{ + int scrollcount_x; + int scrollcount_y; + int offset; + int scroll; + int direction; + int progress; + + offset=st->overlap/2; + scroll=st->overlap/4; + + /* This runs in a loop, starting with + * st->scrolling = (scroll / st->anim_step_size) * 4 - 1; + * and going all the way down to st->scrolling = 0. + */ + + /* if anyone knows a good way to generate + * a more random scrolling motion... */ + + direction = st->scrolling / (scroll / st->anim_step_size); + progress = (st->scrolling % (scroll / st->anim_step_size)) * st->anim_step_size; + + if (direction & 1) { + scrollcount_x = progress - scroll; + scrollcount_y = progress; + } else { + scrollcount_x = -progress; + scrollcount_y = progress - scroll; + } + + if (direction & 2) { + scrollcount_x = -scrollcount_x; + scrollcount_y = -scrollcount_y; + } + + XCopyArea(st->dpy, st->frame, st->window, st->agc,scrollcount_x+offset,scrollcount_y+offset, st->xgwa.width, st->xgwa.height, 0,0); +} + + +static void * +truchet_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + + st->dpy = dpy; + st->window = window; + +#if 1 + st->maxlinewidth = maxLineWidth; + st->minlinewidth = minLineWidth; + st->minwidth = minWidth; + st->minheight = minHeight; + st->max_width = max_Width; + st->max_height = max_Height; + st->delay = delay; + st->eraseCount = eraseCount; + st->square = square; + st->curves = curves; + st->angles = angles; + st->erase = erase; + st->scroll = scroll; + st->overlap = scroll_overlap; + st->anim_delay = anim_delay; + st->anim_step_size = anim_step_size; +#else + st->maxlinewidth = maxLineWidth", "Integer"); + st->minlinewidth = get_integer_resource (st->dpy, "minLineWidth", "Integer"); + st->minwidth = get_integer_resource (st->dpy, "minWidth", "Integer"); + st->minheight = get_integer_resource (st->dpy, "minHeight", "Integer"); + st->max_width = get_integer_resource (st->dpy, "max-Width", "Integer"); + st->max_height = get_integer_resource (st->dpy, "max-Height", "Integer" ); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->eraseCount = get_integer_resource (st->dpy, "eraseCount", "Integer"); + st->square = get_boolean_resource (st->dpy, "square", "Boolean"); + st->curves = get_boolean_resource (st->dpy, "curves", "Boolean"); + st->angles = get_boolean_resource (st->dpy, "angles", "Boolean"); + st->erase = get_boolean_resource (st->dpy, "erase", "Boolean"); + st->scroll = get_boolean_resource (st->dpy, "scroll", "Boolean"); + st->overlap = get_integer_resource (st->dpy, "scroll-overlap", "Integer"); + st->anim_delay = get_integer_resource (st->dpy, "anim-delay", "Integer"); + st->anim_step_size = get_integer_resource (st->dpy, "anim-step-size", "Integer"); +#endif + + //if (get_boolean_resource(st->dpy, "randomize", "Randomize")) + if (randomize) + { + int i = (random() % 12); + switch(i) { + case 0: + break; + case 1: + st->curves = False; + break; + case 2: + st->curves = False; + st->square = True; + st->erase = False; + break; + case 3: + st->square = True; + st->erase = False; + st->eraseCount = 5; + break; + case 4: + st->scroll = True; + break; + case 5: + st->scroll = True; + st->erase = False; + st->anim_step_size = 9; + break; + case 6: + st->angles = False; + st->minwidth = st->max_width = 36; + break; + case 7: + st->curves = False; + st->minwidth = st->max_width = 12; + break; + case 8: + st->curves = False; + st->erase = False; + st->minwidth = st->max_width = 36; + break; + case 9: + st->erase = False; + st->minwidth = 256; + st->max_width = 512; + st->minlinewidth = 96; + break; + case 10: + st->angles = False; + st->minwidth = 64; + st->max_width = 128; + st->maxlinewidth = 4; + break; + case 11: + st->curves = False; + st->minwidth = 64; + st->max_width = 128; + st->maxlinewidth = 4; + break; + default: + abort(); + break; + } + } + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->gcv.foreground = BlackPixel(st->dpy,0); + st->gcv.background = WhitePixel(st->dpy,0); + st->gcv.line_width = 25; + st->cmap = st->xgwa.colormap; + + //st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + // "background", "Background"); + st->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, background); + + st->bgc = XCreateGC (st->dpy, st->window, GCForeground, &st->gcv); + st->agc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); + + XFillRectangle(st->dpy, st->window, st->bgc, 0, 0, st->xgwa.width, st->xgwa.height); + + + st->width=60; + st->height=60; + st->linewidth=1; + st->count=0; + XSetForeground(st->dpy, st->agc, st->gcv.background); + + + st->frame = XCreatePixmap(st->dpy,st->window, st->xgwa.width+st->overlap, st->xgwa.height+st->overlap, st->xgwa.depth); + XFillRectangle(st->dpy, st->frame, st->bgc, 0, 0, + st->xgwa.width + st->overlap, + st->xgwa.height + st->overlap); + + return st; +} + +static unsigned long +truchet_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->scrolling) + { + st->scrolling--; + scroll_area(st, st->anim_step_size); + return st->anim_delay*1000; + } + + if (!mono_p) + { + /* XXX there are probably bugs with this. */ + /* could be...I just borrowed this code from munch */ + + st->fgc.red = random() % 65535; + st->fgc.green = random() % 65535; + st->fgc.blue = random() % 65535; + + if (XAllocColor(st->dpy, st->cmap, &st->fgc)) + { + XSetForeground(st->dpy, st->agc, st->fgc.pixel); + } + else + { + /* use white if all else fails */ + XSetForeground(st->dpy,st->agc, st->gcv.background); + } + } + + + + + /* generate a random line width */ + st->linewidth=(random()% st->maxlinewidth); + + /* check for lower bound */ + if(st->linewidth < st->minlinewidth) + st->linewidth = st->minlinewidth; + + /* try to get an odd linewidth as it seem to work a little better */ + if(st->linewidth%2) + st->linewidth++; + + /* grab a random height and width */ + st->width=(random()%st->max_width); + st->height=(random()%st->max_height); + + /* make sure we dont get a 0 height or width */ + if(st->width == 0 || st->height == 0) + { + st->height=st->max_height; + st->width=st->max_width; + } + + + /* check for min height and width */ + if(st->height < st->minheight) + { + st->height=st->minheight; + } + if(st->width < st->minwidth) + { + st->width=st->minwidth; + } + + /* if tiles need to be square, fix it... */ + if(st->square) + st->height=st->width; + + /* check for sane aspect ratios */ + if((st->width/st->height) > MAXRATIO) + st->height=st->width; + if((st->height/st->width) > MAXRATIO) + st->width=st->height; + + /* to avoid linewidths of zero */ + if(st->linewidth == 0 || st->linewidth < st->minlinewidth) + st->linewidth = st->minlinewidth; + + /* try to keep from getting line widths that would be too big */ + if(st->linewidth > 0 && st->linewidth >= (st->height/5)) + st->linewidth = st->height/5; + + XSetLineAttributes(st->dpy, st->agc, st->linewidth, LineSolid, CapRound, JoinRound); + + if(st->erase || (st->count >= st->eraseCount)) + { + /* XClearWindow(dpy,window); */ + XFillRectangle(st->dpy, st->frame, st->bgc, 0, 0, st->xgwa.width+st->overlap, st->xgwa.height+st->overlap); + st->count=0; + } + + if(!st->scroll) + st->overlap=0; + + /* do the fun stuff...*/ + if(st->curves && st->angles) + { + if(random()%2) + draw_truchet(st); + else + draw_angles(st); + } + else if(st->curves && !st->angles) + draw_truchet(st); + else if(!st->curves && st->angles) + draw_angles(st); + + + st->count++; + + if(st->scroll) + { + st->scrolling = ((st->overlap / 4) / st->anim_step_size) * 4; + return 0; + } + + XCopyArea(st->dpy,st->frame,st->window,st->agc,0,0,st->xgwa.width,st->xgwa.height,0,0); + + return st->delay; +} + +static void +truchet_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); +} + +#if 0 + static Bool + truchet_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +truchet_free (Display *dpy, Window window, void *closure) +{ +} + + +XSCREENSAVER_MODULE ("Truchet", truchet) + diff --git a/non-wgl/truchet.vcproj b/non-wgl/truchet.vcproj new file mode 100644 index 0000000..9964961 --- /dev/null +++ b/non-wgl/truchet.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/twang.c b/non-wgl/twang.c new file mode 100644 index 0000000..a22daa3 --- /dev/null +++ b/non-wgl/twang.c @@ -0,0 +1,839 @@ +/* twang, twist around screen bits, v1.3 + * 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 "screenhack.h" +#include + +#ifdef HAVE_XSHM_EXTENSION +#include "xshm.h" +#endif + +#define FLOAT double + +/* random float in the range (-1..1) */ +#define RAND_FLOAT_PM1 \ + (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000) * 2 - 1) + +/* random float in the range (0..1) */ +#define RAND_FLOAT_01 \ + (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000)) + +char *background = "black"; +char *foreground = "white"; +char *borderColor = "blue"; +int borderWidth = 3; +int delay = 10000; +int duration = 120; +float eventChance = 0.01; +float friction = 0.05; +int maxColumns = 0; +int maxRows = 0; +float springiness = 0.1; +int tileSize = 120; +float transference = 0.025; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&borderColor, "borderColor", NULL, "blue", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&duration, "duration", NULL, "120", t_Int}, + {&eventChance, "eventChance", NULL, "0.01", t_Float}, + {&friction, "friction", NULL, "0.05", t_Float}, + {&maxColumns, "maxColumns", NULL, "9", t_Int}, + {&maxRows, "maxRows", NULL, "0", t_Int}, + {&springiness, "springiness", NULL, "0.1", t_Float}, + {&tileSize, "tileSize", NULL, "120", t_Int}, + {&transference, "transference", NULL, "0.025", t_Float}, +}; + + +typedef struct +{ + int x; /* x coordinate of the center of the tile */ + int y; /* y coordinate of the center of the tile */ + FLOAT angle; /* angle of the tile (-pi..pi) */ + FLOAT zoom; /* log of the zoom of the tile (-1..1) */ + FLOAT vAngle; /* angular velocity (-pi/4..pi/4) */ + FLOAT vZoom; /* zoomular velocity (-0.25..0.25) */ +} +Tile; + + +struct state { + Display *dpy; + Window window; + + int delay; /* delay (usec) between iterations */ + int duration; /* time (sec) before loading new image */ + int maxColumns; /* the maximum number of columns of tiles */ + int maxRows; /* the maximum number of rows of tiles */ + int tileSize; /* the size (width and height) of a tile */ + int borderWidth; /* the width of the border around each tile */ + FLOAT eventChance; /* the chance, per iteration, of an interesting event happening */ + FLOAT friction; /* friction: the fraction (0..1) by which velocity decreased per iteration */ + FLOAT springiness; /* springiness: the fraction (0..1) of the orientation that turns into velocity towards the center */ + FLOAT transference; /* transference: the fraction (0..1) of the orientations of orthogonal neighbors that turns into velocity (in the same direction as the orientation) */ + int windowWidth; /* width and height of the window */ + int windowHeight; + Screen *screen; /* the screen to draw on */ + XImage *sourceImage; /* image source of stuff to draw */ + XImage *workImage; /* work area image, used when rendering */ + XImage *backgroundImage; /* image filled with background pixels */ + + GC backgroundGC; /* GC for the background color */ + GC foregroundGC; /* GC for the foreground color */ + GC borderGC; /* GC for the border color */ + unsigned long backgroundPixel; /* background color as a pixel value */ + unsigned long borderPixel; /* border color as a pixel value */ + + Tile *tiles; /* array of tiles (left->right, top->bottom, row major) */ + int rows; /* number of rows of tiles */ + int columns; /* number of columns of tiles */ + + Tile **sortedTiles; /* array of tile pointers, sorted by zoom */ + int tileCount; /* total number of tiles */ + + time_t start_time; + async_load_state *img_loader; + + Bool useShm; /* whether or not to use xshm */ +#ifdef HAVE_XSHM_EXTENSION + XShmSegmentInfo shmInfo; +#endif +}; + + +#define TILE_AT(col,row) (&st->tiles[(row) * st->columns + (col)]) + +#define MAX_VANGLE (M_PI / 4.0) +#define MAX_VZOOM 0.25 + +#define RAND_ANGLE (RAND_FLOAT_PM1 * M_PI) +#define RAND_ZOOM (RAND_FLOAT_PM1) +#define RAND_VANGLE (RAND_FLOAT_PM1 * MAX_VANGLE) +#define RAND_VZOOM (RAND_FLOAT_PM1 * MAX_VZOOM) + + + +/* + * overall setup stuff + */ + +/* grab the source image */ +static void +grabImage_start (struct state *st, XWindowAttributes *xwa) +{ + XFillRectangle (st->dpy, st->window, st->backgroundGC, 0, 0, + st->windowWidth, st->windowHeight); + st->backgroundImage = + XGetImage (st->dpy, st->window, 0, 0, st->windowWidth, st->windowHeight, + ~0L, ZPixmap); + + st->start_time = time ((time_t) 0); + st->img_loader = load_image_async_simple (0, xwa->screen, st->window, + st->window, 0, 0); +} + +static void +grabImage_done (struct state *st) +{ + XWindowAttributes xwa; + XGetWindowAttributes (st->dpy, st->window, &xwa); + + st->start_time = time ((time_t) 0); + if (st->sourceImage) XDestroyImage (st->sourceImage); + st->sourceImage = XGetImage (st->dpy, st->window, 0, 0, st->windowWidth, st->windowHeight, + ~0L, ZPixmap); + + if (st->workImage) XDestroyImage (st->workImage); + st->workImage = NULL; + +#ifdef HAVE_XSHM_EXTENSION + if (st->useShm) + { + st->workImage = create_xshm_image (st->dpy, xwa.visual, xwa.depth, + ZPixmap, 0, &st->shmInfo, + st->windowWidth, st->windowHeight); + if (!st->workImage) + { + st->useShm = False; + fprintf (stderr, "create_xshm_image failed\n"); + } + } + + if (st->workImage == NULL) +#endif /* HAVE_XSHM_EXTENSION */ + + /* just use XSubImage to acquire the right visual, depth, etc; + * easier than the other alternatives */ + st->workImage = XSubImage (st->sourceImage, 0, 0, st->windowWidth, st->windowHeight); +} + +/* set up the system */ +static void setup (struct state *st) +{ + XWindowAttributes xgwa; + XGCValues gcv; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->screen = xgwa.screen; + st->windowWidth = xgwa.width; + st->windowHeight = xgwa.height; + + gcv.line_width = st->borderWidth; + //gcv.foreground = get_pixel_resource (st->dpy, xgwa.colormap, + // "borderColor", "BorderColor"); + gcv.foreground = load_color(st->dpy, xgwa.colormap, borderColor); + st->borderPixel = gcv.foreground; + st->borderGC = XCreateGC (st->dpy, st->window, GCForeground | GCLineWidth, + &gcv); + + //gcv.foreground = get_pixel_resource (st->dpy, xgwa.colormap, + // "background", "Background"); + gcv.foreground = load_color(st->dpy, xgwa.colormap, background); + st->backgroundPixel = gcv.foreground; + st->backgroundGC = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + + //gcv.foreground = get_pixel_resource (st->dpy, xgwa.colormap, + // "foreground", "Foreground"); + gcv.foreground = load_color(st->dpy, xgwa.colormap, foreground); + st->foregroundGC = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + + grabImage_start (st, &xgwa); +} + + + +/* + * the simulation + */ + +/* event: randomize all the angular velocities */ +static void randomizeAllAngularVelocities (struct state *st) +{ + int c; + int r; + + for (r = 0; r < st->rows; r++) + { + for (c = 0; c < st->columns; c++) + { + TILE_AT (c, r)->vAngle = RAND_VANGLE; + } + } +} + +/* event: randomize all the zoomular velocities */ +static void randomizeAllZoomularVelocities (struct state *st) +{ + int c; + int r; + + for (r = 0; r < st->rows; r++) + { + for (c = 0; c < st->columns; c++) + { + TILE_AT (c, r)->vZoom = RAND_VZOOM; + } + } +} + +/* event: randomize all the velocities */ +static void randomizeAllVelocities (struct state *st) +{ + randomizeAllAngularVelocities (st); + randomizeAllZoomularVelocities (st); +} + +/* event: randomize all the angular orientations */ +static void randomizeAllAngularOrientations (struct state *st) +{ + int c; + int r; + + for (r = 0; r < st->rows; r++) + { + for (c = 0; c < st->columns; c++) + { + TILE_AT (c, r)->angle = RAND_ANGLE; + } + } +} + +/* event: randomize all the zoomular orientations */ +static void randomizeAllZoomularOrientations (struct state *st) +{ + int c; + int r; + + for (r = 0; r < st->rows; r++) + { + for (c = 0; c < st->columns; c++) + { + TILE_AT (c, r)->zoom = RAND_ZOOM; + } + } +} + +/* event: randomize all the orientations */ +static void randomizeAllOrientations (struct state *st) +{ + randomizeAllAngularOrientations (st); + randomizeAllZoomularOrientations (st); +} + +/* event: randomize everything */ +static void randomizeEverything (struct state *st) +{ + randomizeAllVelocities (st); + randomizeAllOrientations (st); +} + +/* event: pick one tile and randomize all its stats */ +static void randomizeOneTile (struct state *st) +{ + int c = RAND_FLOAT_01 * st->columns; + int r = RAND_FLOAT_01 * st->rows; + + Tile *t = TILE_AT (c, r); + t->angle = RAND_ANGLE; + t->zoom = RAND_ZOOM; + t->vAngle = RAND_VANGLE; + t->vZoom = RAND_VZOOM; +} + +/* event: pick one row and randomize everything about each of its tiles */ +static void randomizeOneRow (struct state *st) +{ + int c; + int r = RAND_FLOAT_01 * st->rows; + + for (c = 0; c < st->columns; c++) + { + Tile *t = TILE_AT (c, r); + t->angle = RAND_ANGLE; + t->zoom = RAND_ZOOM; + t->vAngle = RAND_VANGLE; + t->vZoom = RAND_VZOOM; + } +} + +/* event: pick one column and randomize everything about each of its tiles */ +static void randomizeOneColumn (struct state *st) +{ + int c = RAND_FLOAT_01 * st->columns; + int r; + + for (r = 0; r < st->rows; r++) + { + Tile *t = TILE_AT (c, r); + t->angle = RAND_ANGLE; + t->zoom = RAND_ZOOM; + t->vAngle = RAND_VANGLE; + t->vZoom = RAND_VZOOM; + } +} + +/* do model event processing */ +static void modelEvents (struct state *st) +{ + int which; + + if (RAND_FLOAT_01 > st->eventChance) + { + return; + } + + which = RAND_FLOAT_01 * 10; + + switch (which) + { + case 0: randomizeAllAngularVelocities (st); break; + case 1: randomizeAllZoomularVelocities (st); break; + case 2: randomizeAllVelocities (st); break; + case 3: randomizeAllAngularOrientations (st); break; + case 4: randomizeAllZoomularOrientations (st); break; + case 5: randomizeAllOrientations (st); break; + case 6: randomizeEverything (st); break; + case 7: randomizeOneTile (st); break; + case 8: randomizeOneColumn (st); break; + case 9: randomizeOneRow (st); break; + } +} + +/* update the model for one iteration */ +static void updateModel (struct state *st) +{ + int r; + int c; + + /* for each tile, decrease its velocities according to the friction, + * and increase them based on its current orientation and the orientations + * of its orthogonal neighbors */ + for (r = 0; r < st->rows; r++) + { + for (c = 0; c < st->columns; c++) + { + Tile *t = TILE_AT (c, r); + FLOAT a = t->angle; + FLOAT z = t->zoom; + FLOAT va = t->vAngle; + FLOAT vz = t->vZoom; + + va -= t->angle * st->springiness; + vz -= t->zoom * st->springiness; + + if (c > 0) + { + Tile *t2 = TILE_AT (c - 1, r); + va += (t2->angle - a) * st->transference; + vz += (t2->zoom - z) * st->transference; + } + + if (c < (st->columns - 1)) + { + Tile *t2 = TILE_AT (c + 1, r); + va += (t2->angle - a) * st->transference; + vz += (t2->zoom - z) * st->transference; + } + + if (r > 0) + { + Tile *t2 = TILE_AT (c, r - 1); + va += (t2->angle - a) * st->transference; + vz += (t2->zoom - z) * st->transference; + } + + if (r < (st->rows - 1)) + { + Tile *t2 = TILE_AT (c, r + 1); + va += (t2->angle - a) * st->transference; + vz += (t2->zoom - z) * st->transference; + } + + va *= (1.0 - st->friction); + vz *= (1.0 - st->friction); + + if (va > MAX_VANGLE) va = MAX_VANGLE; + else if (va < -MAX_VANGLE) va = -MAX_VANGLE; + t->vAngle = va; + + if (vz > MAX_VZOOM) vz = MAX_VZOOM; + else if (vz < -MAX_VZOOM) vz = -MAX_VZOOM; + t->vZoom = vz; + } + } + + /* for each tile, update its orientation based on its velocities */ + for (r = 0; r < st->rows; r++) + { + for (c = 0; c < st->columns; c++) + { + Tile *t = TILE_AT (c, r); + FLOAT a = t->angle + t->vAngle; + FLOAT z = t->zoom + t->vZoom; + + if (a > M_PI) a = M_PI; + else if (a < -M_PI) a = -M_PI; + t->angle = a; + + if (z > 1.0) z = 1.0; + else if (z < -1.0) z = -1.0; + t->zoom = z; + } + } +} + +/* the comparator to us to sort the tiles (used immediately below); it'd + * sure be nice if C allowed inner functions (or jeebus-forbid *real + * closures*!) */ +static int sortTilesComparator (const void *v1, const void *v2) +{ + Tile *t1 = *(Tile **) v1; + Tile *t2 = *(Tile **) v2; + + if (t1->zoom < t2->zoom) + { + return -1; + } + + if (t1->zoom > t2->zoom) + { + return 1; + } + + return 0; +} + +/* sort the tiles in sortedTiles by zoom */ +static void sortTiles (struct state *st) +{ + qsort (st->sortedTiles, st->tileCount, sizeof (Tile *), sortTilesComparator); +} + +/* render the given tile */ +static void renderTile (struct state *st, Tile *t) +{ + /* note: the zoom as stored per tile is log-based (centered on 0, with + * 0 being no zoom, but the range for zoom-as-drawn is 0.4..2.5, + * hence the alteration of t->zoom, below */ + + int x, y; + + int tx = t->x; + int ty = t->y; + + FLOAT zoom = pow (2.5, t->zoom); + FLOAT ang = -t->angle; + FLOAT sinAng = sin (ang); + FLOAT cosAng = cos (ang); + + FLOAT innerBorder = (st->tileSize - st->borderWidth) / 2.0; + FLOAT outerBorder = innerBorder + st->borderWidth; + + int maxCoord = outerBorder * zoom * (fabs (sinAng) + fabs (cosAng)); + int minX = tx - maxCoord; + int maxX = tx + maxCoord; + int minY = ty - maxCoord; + int maxY = ty + maxCoord; + + FLOAT prey; + + if (minX < 0) minX = 0; + if (maxX > st->windowWidth) maxX = st->windowWidth; + if (minY < 0) minY = 0; + if (maxY > st->windowHeight) maxY = st->windowHeight; + + sinAng /= zoom; + cosAng /= zoom; + + for (y = minY, prey = y - ty; y < maxY; y++, prey++) + { + FLOAT prex = minX - tx; + FLOAT srcx = prex * cosAng - prey * sinAng; + FLOAT srcy = prex * sinAng + prey * cosAng; + + for (x = minX; + x < maxX; + x++, srcx += cosAng, srcy += sinAng) + { + if ((srcx < -innerBorder) || (srcx >= innerBorder) || + (srcy < -innerBorder) || (srcy >= innerBorder)) + { + if ((srcx < -outerBorder) || (srcx >= outerBorder) || + (srcy < -outerBorder) || (srcy >= outerBorder)) + { + continue; + } + XPutPixel (st->workImage, x, y, st->borderPixel); + } + else + { + unsigned long p = + XGetPixel (st->sourceImage, srcx + tx, srcy + ty); + XPutPixel (st->workImage, x, y, p); + } + } + } +} + +/* render and display the current model */ +static void renderFrame (struct state *st) +{ + int n; + + memcpy (st->workImage->data, st->backgroundImage->data, + st->workImage->bytes_per_line * st->workImage->height); + + sortTiles (st); + + for (n = 0; n < st->tileCount; n++) + { + renderTile (st, st->sortedTiles[n]); + } + +#ifdef HAVE_XSHM_EXTENSION + if (st->useShm) + XShmPutImage (st->dpy, st->window, st->backgroundGC, st->workImage, 0, 0, 0, 0, + st->windowWidth, st->windowHeight, False); + else +#endif /* HAVE_XSHM_EXTENSION */ + XPutImage (st->dpy, st->window, st->backgroundGC, st->workImage, + 0, 0, 0, 0, st->windowWidth, st->windowHeight); +} + +/* set up the model */ +static void setupModel (struct state *st) +{ + int c; + int r; + + int leftX; /* x of the center of the top-left tile */ + int topY; /* y of the center of the top-left tile */ + + if (st->tileSize > (st->windowWidth / 2)) + { + st->tileSize = st->windowWidth / 2; + } + + if (st->tileSize > (st->windowHeight / 2)) + { + st->tileSize = st->windowHeight / 2; + } + + st->columns = st->tileSize ? st->windowWidth / st->tileSize : 0; + st->rows = st->tileSize ? st->windowHeight / st->tileSize : 0; + + if ((st->maxColumns != 0) && (st->columns > st->maxColumns)) + { + st->columns = st->maxColumns; + } + + if ((st->maxRows != 0) && (st->rows > st->maxRows)) + { + st->rows = st->maxRows; + } + + st->tileCount = st->rows * st->columns; + + leftX = (st->windowWidth - (st->columns * st->tileSize) + st->tileSize) / 2; + topY = (st->windowHeight - (st->rows * st->tileSize) + st->tileSize) / 2; + + st->tiles = calloc (st->tileCount, sizeof (Tile)); + st->sortedTiles = calloc (st->tileCount, sizeof (Tile *)); + + for (r = 0; r < st->rows; r++) + { + for (c = 0; c < st->columns; c++) + { + Tile *t = TILE_AT (c, r); + t->x = leftX + c * st->tileSize; + t->y = topY + r * st->tileSize; + st->sortedTiles[c + r * st->columns] = t; + } + } + + randomizeEverything (st); +} + +/* do one iteration */ + +static unsigned long +twang_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + 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 */ + grabImage_done (st); + } + return st->delay; + } + + if (!st->img_loader && + st->start_time + st->duration < time ((time_t) 0)) { + XWindowAttributes xgwa; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + grabImage_start (st, &xgwa); + return st->delay; + } + + modelEvents (st); + updateModel (st); + renderFrame (st); + return st->delay; +} + + +static void +twang_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + twang_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +twang_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + +/* main and options and stuff */ + +/* initialize the user-specifiable params */ +static void initParams (struct state *st) +{ + int problems = 0; + + //st->borderWidth = get_integer_resource (st->dpy, "borderWidth", "Integer"); + st->borderWidth = borderWidth; + if (st->borderWidth < 0) + { + fprintf (stderr, "error: border width must be at least 0\n"); + problems = 1; + } + + //st->delay = get_integer_resource (st->dpy, "delay", "Delay"); + st->delay = delay; + if (st->delay < 0) + { + fprintf (stderr, "error: delay must be at least 0\n"); + problems = 1; + } + + //st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + st->duration = duration; + if (st->duration < 1) st->duration = 1; + + //st->eventChance = get_float_resource (st->dpy, "eventChance", "Double"); + st->eventChance = eventChance; + if ((st->eventChance < 0.0) || (st->eventChance > 1.0)) + { + fprintf (stderr, "error: eventChance must be in the range 0..1\n"); + problems = 1; + } + + //st->friction = get_float_resource (st->dpy, "friction", "Double"); + st->friction = friction; + if ((st->friction < 0.0) || (st->friction > 1.0)) + { + fprintf (stderr, "error: friction must be in the range 0..1\n"); + problems = 1; + } + + //st->maxColumns = get_integer_resource (st->dpy, "maxColumns", "Integer"); + st->maxColumns = maxColumns; + if (st->maxColumns < 0) + { + fprintf (stderr, "error: max columns must be at least 0\n"); + problems = 1; + } + + //st->maxRows = get_integer_resource (st->dpy, "maxRows", "Integer"); + st->maxRows = maxRows; + if (st->maxRows < 0) + { + fprintf (stderr, "error: max rows must be at least 0\n"); + problems = 1; + } + + //st->springiness = get_float_resource (st->dpy, "springiness", "Double"); + st->springiness = springiness; + if ((st->springiness < 0.0) || (st->springiness > 1.0)) + { + fprintf (stderr, "error: springiness must be in the range 0..1\n"); + problems = 1; + } + + //st->tileSize = get_integer_resource (st->dpy, "tileSize", "Integer"); + st->tileSize = tileSize; + if (st->tileSize < 1) + { + fprintf (stderr, "error: tile size must be at least 1\n"); + problems = 1; + } + + //st->transference = get_float_resource (st->dpy, "transference", "Double"); + st->transference = transference; + if ((st->transference < 0.0) || (st->transference > 1.0)) + { + fprintf (stderr, "error: transference must be in the range 0..1\n"); + problems = 1; + } + +#ifdef HAVE_XSHM_EXTENSION + st->useShm = get_boolean_resource (st->dpy, "useSHM", "Boolean"); +#endif + + if (problems) + { + exit (1); + } +} + +static void * +twang_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; +} + + +static const char *twang_defaults [] = { + ".background: black", + ".foreground: white", + "*borderColor: blue", + "*borderWidth: 3", + "*delay: 10000", + "*duration: 120", + "*eventChance: 0.01", + "*friction: 0.05", + "*maxColumns: 0", + "*maxRows: 0", + "*springiness: 0.1", + "*tileSize: 120", + "*transference: 0.025", +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#else + "*useSHM: False", +#endif +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec twang_options [] = { + { "-border-color", ".borderColor", XrmoptionSepArg, 0 }, + { "-border-width", ".borderWidth", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-event-chance", ".eventChance", XrmoptionSepArg, 0 }, + { "-friction", ".friction", XrmoptionSepArg, 0 }, + { "-max-columns", ".maxColumns", XrmoptionSepArg, 0 }, + { "-max-rows", ".maxRows", XrmoptionSepArg, 0 }, + { "-springiness", ".springiness", XrmoptionSepArg, 0 }, + { "-tile-size", ".tileSize", XrmoptionSepArg, 0 }, + { "-transference", ".transference", XrmoptionSepArg, 0 }, + { "-shm", ".useSHM", XrmoptionNoArg, "True" }, + { "-no-shm", ".useSHM", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Twang", twang) diff --git a/non-wgl/twang.vcproj b/non-wgl/twang.vcproj new file mode 100644 index 0000000..73bc16c --- /dev/null +++ b/non-wgl/twang.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/vermiculate.c b/non-wgl/vermiculate.c new file mode 100644 index 0000000..7f41986 --- /dev/null +++ b/non-wgl/vermiculate.c @@ -0,0 +1,1242 @@ +/* + * @(#) vermiculate.c + * @(#) Copyright (C) 2001 Tyler Pierce (tyler@alumni.brown.edu) + * The full program, with documentation, is available at: + * http://freshmeat.net/projects/fdm + * + * 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. + */ + +#if 0 + #ifdef HAVE_CONFIG_H + # include "config.h" + #endif +#endif + +#include "screenhack.h" +#include +#include + +#define degs 360 +#define degs2 (degs/2) +#define degs4 (degs/4) +#define degs8 (degs/8) +#define dtor 0.0174532925 /* pi / degs2; */ +#define thrmax 120 +#define tailmax (thrmax * 2 + 1) +#define tmodes '7' +#define ymax (st->hei - 1) +#define ymin 0 +#define xmax (st->wid - 1) +#define xmin 0 +#define rlmax 200 +#define SPEEDINC 10 +#define SPEEDMAX 1000 +#define wraparound(VAL,LOWER,UPPER) { \ + if (VAL >= UPPER) \ + VAL -= UPPER - LOWER; \ + else if (VAL < LOWER) \ + VAL += UPPER - LOWER; } +#define arrcpy(DEST,SRC) memcpy (DEST, SRC, sizeof(DEST)) + +typedef double real; +typedef unsigned char banktype[thrmax]; + +char *background = "Black"; +int ticks = 20000; +int speed = 0; +char *instring = ""; + + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&ticks, "ticks", NULL, "20000", t_Int}, + {&speed, "speed", NULL, "0", t_Int}, + {&instring, "instring", NULL, "", t_String}, +}; + +typedef struct linedata +{ + int deg, spiturn, turnco, turnsize; + unsigned char col; + Bool dead; + + char orichar; + real x, y; + int tmode, tsc, tslen, tclim, otslen, ctinc, reclen, recpos, circturn, prey, + slice; + int xrec[rlmax + 1], yrec[rlmax + 1]; + int turnseq[50]; + Bool filled, killwalls, vhfollow, + selfbounce, tailfollow, realbounce, little; +} +linedata; + +static const struct stringAndSpeed +{ + char *str; + int speed; +} +sampleStrings[] = +{ +/* { "]]]]]]]]7ces123400-9-8#c123456#s9998880004#ma3#car9ma6#c-#r1", 600} , + { "bmarrrr#c1234#lc5678#lyet]", 600} , */ + { "AEBMN222222223#CAR9CAD4CAOV", 150} , + { "mn333#c23#f1#]]]]]]]]]]]3bc9#r9#c78#f9#ma4#", 600} , + { "AEBMN22222#CAD4CAORc1#f2#c1#r6", 100} , +/* { "mn6666666#c1i#f1#y2#sy2#vyety1#ry13i#l", 40} , */ + { "aebmnrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr#", 500} , +/* { "bg+++++++++++++++++++++++#mnrrrrrrrrrrrrrrrrrrrrrrr#y1#k", 500}, */ +/* { "BMN22222223#CAD4CAOVYAS", 150}, */ +/* { "aebmnrrrrrrrrrrrrrrrr#yaryakg--#", 100} , */ + { "mn6rrrrrrrrrrrrrrr#by1i#lcalc1#fnyav" , 200 } , + { "mn1rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr#by1i#lcalc1#fn", 2000 }, + { "baeMn333333333333333333333333#CerrYerCal", 800 }, + { "baeMn1111111111111111111111111111111111111111111111111111111111#Cer9YesYevYerCal", 1200 }, + { "baMn111111222222333333444444555555#Ct1#lCt2#lCt3#lCt4#lCt5#lCerrYerYet", 1400 }, + { "baMn111111222222333333444444555555#Ct1#lCt2#lCt3#lCt4#lCt5#lCerrYerYetYt1i#lYt1i#sYt1#v", 1400 } +}; + +struct state { + Display *dpy; + Window window; + + GC mygc; + Colormap mycmap; + XWindowAttributes xgwa; + XColor mycolors[tailmax]; + + int hei, wid, speed; + Bool erasing, cleared, autopal; + char *instring; + int max_ticks; + + real sinof[degs], cosof[degs], tanof[degs]; + unsigned char *point; + + linedata thread[thrmax]; + banktype bank; + int bnkt; + int boxw, boxh, curviness, gridden, ogd, bordcorn; + unsigned char bordcol, threads; + char ch, boolop; + + int reset_p; + int cyc; +}; + + + +static void +consume_instring(struct state *st); + +static Bool +wasakeypressed (struct state *st) +{ + if (*st->instring != 0) + return True; + else + return False; +} + +static char +readkey (struct state *st) +{ + char readkey_result; + if (*st->instring == 0) + { + readkey_result = '#'; + } + else + { + readkey_result = *st->instring; + st->instring++; + }; + return toupper (readkey_result); +} + +static unsigned int +random1 (unsigned int i) +{ + return (ya_random () % i); +} + +static unsigned long +waitabit (struct state *st) +{ + int result = 0; + st->cyc += st->threads; + while (st->cyc > st->speed) + { + result += 10000; + st->cyc -= st->speed; + } + return result; +} + +static void +clearscreen (struct state *st) +{ + XClearWindow (st->dpy, st->window); + memset (st->point, 0, st->wid * st->hei); +} + +static void +sp (struct state *st, int x, int y, int c) +{ + XSetForeground (st->dpy, st->mygc, st->mycolors[c].pixel); + XDrawPoint (st->dpy, st->window, st->mygc, x, y); + st->point[(st->wid * y) + x] = c; +} + +static int +gp (struct state *st, int x, int y) +{ + return st->point[(st->wid * y) + x]; +} + +static void +redraw (struct state *st, int x, int y, int width, int height) +{ + int xc, yc; + for (xc = x; xc <= x + width - 1; xc++) + for (yc = y; yc <= y + height - 1; yc++) + if (st->point[st->wid * yc + xc] != 0) + sp (st, xc, yc, st->point[st->wid * yc + xc]); +} + +static void +palupdate (struct state *st, Bool forceUpdate) +{ + if (forceUpdate || *st->instring == 0) + { + redraw (st, xmin, ymin, st->wid, st->hei); + } +} + +static void +randpal (struct state *st) +{ + int ncolors = tailmax - 1; + make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->mycmap, + &st->mycolors[1], &ncolors, True, True, 0, True); + if (ncolors < tailmax - 1) + { + int c; + for (c = 1; c < tailmax; c++) + st->mycolors[c].pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); + } +} + +static void +gridupdate (struct state *st, Bool interruptible) +{ + int x, y; + if (st->gridden > 0) + for (x = 0; x <= xmax && !(wasakeypressed (st) && interruptible); x += st->boxw) + for (y = 0; y <= ymax; y += st->boxh) + { + if (random1 (15) < st->gridden) + { +#define lesser(A,B) ( ((A)<(B)) ? (A) : (B) ) + int max = lesser (x + st->boxw, xmax); + int xc; + for (xc = x; xc <= max; xc++) + sp (st, xc, y, 1); + } + if (random1 (15) < st->gridden) + { + int max = lesser (y + st->boxh, ymax); + int yc; + for (yc = y; yc <= max; yc++) + sp (st, x, yc, 1); + } + } +} + +static void +bordupdate (struct state *st) +{ + int xbord, ybord; + + if (st->bordcorn == 0 || st->bordcorn == 1) + ybord = ymin; + else + ybord = ymax; + if (st->bordcorn == 0 || st->bordcorn == 3) + xbord = xmin; + else + xbord = xmax; + { + int x, y; + for (x = xmin; x <= xmax; x++) + sp (st, x, ybord, st->bordcol); + for (y = ymin; y <= ymax; y++) + sp (st, xbord, y, st->bordcol); + } +} + +static Bool +inbank (struct state *st, unsigned char thr) +{ + int c; + if (st->bnkt > 0) + for (c = 1; c <= st->bnkt; c++) + if (st->bank[c - 1] == thr) + return True; + return False; +} + +static void +pickbank (struct state *st) +{ + unsigned char thr = 1; + st->bnkt = 0; + st->ch = '\0'; + do + { + while (inbank (st, thr)) + thr = thr % st->threads + 1; + + palupdate (st, False); + st->ch = readkey (st); + palupdate (st, False); + switch (st->ch) + { + case '+': + case '-': + do + { + if (st->ch == '+') + thr++; + else + thr--; + wraparound (thr, 1, st->threads + 1); + } + while (inbank (st, thr)); + break; + case ' ': + st->bank[++st->bnkt - 1] = thr; + break; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + + st->bank[++st->bnkt - 1] = st->ch - '0'; + if (st->bank[st->bnkt - 1] > st->threads) + st->bnkt--; + break; + case 'I': + { + banktype tbank; + int tbankt = 0; + int c; + for (c = 1; c <= st->threads; c++) + if (!inbank (st, c)) + tbank[++tbankt - 1] = c; + st->bnkt = tbankt; + arrcpy (st->bank, tbank); + } + break; + case 'T': + st->ch = readkey (st); + switch (st->ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + + { + int c; + for (c = 1; c <= st->threads; c++) + if (st->thread[c - 1].tmode == st->ch - '0') + st->bank[++st->bnkt - 1] = c; + } + break; + } + break; + case 'A': + for (st->bnkt = 1; st->bnkt <= st->threads; st->bnkt++) + st->bank[st->bnkt - 1] = st->bnkt; + st->bnkt = st->threads; + break; + case 'E': + for (st->bnkt = 1; st->bnkt <= thrmax; st->bnkt++) + st->bank[st->bnkt - 1] = st->bnkt; + st->bnkt = thrmax; + break; + } + } + while (!(st->bnkt >= st->threads || st->ch == 'N' || st->ch == '\15' || st->ch == '#')); + if (st->bnkt == 0 && st->ch != 'N') + { + st->bnkt = 1; + st->bank[0] = thr; + } + palupdate (st, False); +} + +static void +bankmod (char boolop, Bool * Bool_) +{ + switch (boolop) + { + case 'T': + *Bool_ = !*Bool_; + break; + case 'Y': + *Bool_ = True; + break; + case 'N': + *Bool_ = False; + break; + } +} + +static void +newonscreen (struct state *st, unsigned char thr) +{ + linedata *LP = &st->thread[thr - 1]; + LP->filled = False; + LP->dead = False; + LP->reclen = (LP->little) ? + random1 (10) + 5 : random1 (rlmax - 30) + 30; + LP->deg = random1 (degs); + LP->y = random1 (st->hei); + LP->x = random1 (st->wid); + LP->recpos = 0; + LP->turnco = 2; + LP->turnsize = random1 (4) + 2; +} + +static void +firstinit (struct state *st, unsigned char thr) +{ + linedata *LP = &st->thread[thr - 1]; + LP->col = thr + 1; + LP->prey = 0; + LP->tmode = 1; + LP->slice = degs / 3; + LP->orichar = 'R'; + LP->spiturn = 5; + LP->selfbounce = False; + LP->realbounce = False; + LP->vhfollow = False; + LP->tailfollow = False; + LP->killwalls = False; + LP->little = False; + LP->ctinc = random1 (2) * 2 - 1; + LP->circturn = ((thr % 2) * 2 - 1) * ((thr - 1) % 7 + 1); + LP->tsc = 1; + LP->tslen = 6; + LP->turnseq[0] = 6; + LP->turnseq[1] = -6; + LP->turnseq[2] = 6; + LP->turnseq[3] = 6; + LP->turnseq[4] = -6; + LP->turnseq[5] = 6; + LP->tclim = (unsigned char) (((real) degs) / 2 / 12); +} + +static void +maininit (struct state *st) +{ + if (!st->instring) + { + int n = random1 (sizeof (sampleStrings) / sizeof (sampleStrings[0])); + st->instring = sampleStrings[n].str; + st->speed = sampleStrings[n].speed; + } + if (st->speed == 0) + { + st->speed = 200; + } + st->boxh = 10; + st->boxw = 10; + st->gridden = 0; + st->bordcorn = 0; + st->threads = 4; + st->curviness = 30; + st->bordcol = 1; + st->ogd = 8; + st->ch = '\0'; + st->erasing = True; + { + unsigned char thr; + for (thr = 1; thr <= thrmax; thr++) + { + firstinit (st, thr); + newonscreen (st, thr); + } + } + { + int d; + for (d = degs - 1; d >= 0; d--) + { + st->sinof[d] = sin (d * dtor); + st->cosof[d] = cos (d * dtor); + if (d % degs4 == 0) + st->tanof[d] = st->tanof[d + 1]; + else + st->tanof[d] = tan (d * dtor); + } + } + randpal (st); +} + +static Bool +move (struct state *st, unsigned char thr) +{ + linedata *LP = &st->thread[thr - 1]; + if (LP->dead) + return (False); + if (LP->prey == 0) + switch (LP->tmode) + { + case 1: + LP->deg += random1 (2 * LP->turnsize + 1) - LP->turnsize; + break; + case 2: + if (LP->slice == degs || LP->slice == degs2 || LP->slice == degs4) + { + if (LP->orichar == 'D') + { + if (LP->deg % degs4 != degs8) + LP->deg = degs4 * random1 (4) + degs8; + } + else if (LP->orichar == 'V') + if (LP->deg % degs4 != 0) + LP->deg = degs4 * random1 (4); + } + if (random1 (100) == 0) + { + if (LP->slice == 0) + LP->deg = LP->deg - degs4 + random1 (degs2); + else + LP->deg += (random1 (2) * 2 - 1) * LP->slice; + } + break; + case 3: + LP->deg += LP->circturn; + break; + case 4: + if (abs (LP->spiturn) > 11) + LP->spiturn = 5; + else + LP->deg += LP->spiturn; + if (random1 (15 - abs (LP->spiturn)) == 0) + { + LP->spiturn += LP->ctinc; + if (abs (LP->spiturn) > 10) + LP->ctinc *= -1; + } + break; + case 5: + LP->turnco = abs (LP->turnco) - 1; + if (LP->turnco == 0) + { + LP->turnco = st->curviness + random1 (10); + LP->circturn *= -1; + } + LP->deg += LP->circturn; + break; + case 6: + if (abs (LP->turnco) == 1) + LP->turnco *= -1 * (random1 (degs2 / abs (LP->circturn)) + 5); + else if (LP->turnco == 0) + LP->turnco = 2; + else if (LP->turnco > 0) + { + LP->turnco--; + LP->deg += LP->circturn; + } + else + LP->turnco++; + break; + case 7: + LP->turnco++; + if (LP->turnco > LP->tclim) + { + LP->turnco = 1; + LP->tsc = (LP->tsc % LP->tslen) + 1; + } + LP->deg += LP->turnseq[LP->tsc - 1]; + break; + } + else + { + int desdeg; + real dy, dx; + if (LP->tailfollow || LP->prey == thr) + { + dx = st->thread[LP->prey - 1].xrec[st->thread[LP->prey - 1].recpos] - LP->x; + dy = st->thread[LP->prey - 1].yrec[st->thread[LP->prey - 1].recpos] - LP->y; + } + else + { + dx = st->thread[LP->prey - 1].x - LP->x; + dy = st->thread[LP->prey - 1].y - LP->y; + } + desdeg = + (LP->vhfollow) ? + ((fabs (dx) > fabs (dy)) ? + ((dx > 0) ? + 0 * degs4 + : + 2 * degs4) + : + ((dy > 0) ? + 1 * degs4 + : + 3 * degs4)) + : + ((dx > 0) ? + ((dy > 0) ? + 1 * degs8 : 7 * degs8) : ((dy > 0) ? 3 * degs8 : 5 * degs8)); + if (desdeg - desdeg % degs4 != LP->deg - LP->deg % degs4 + || LP->vhfollow) + { + if (!LP->vhfollow) + { + /* Using atan2 here doesn't seem to slow things down: */ + desdeg = atan2 (dy, dx) / dtor; + wraparound (desdeg, 0, degs); + } + if (abs (desdeg - LP->deg) <= abs (LP->circturn)) + LP->deg = desdeg; + else + LP->deg += + (desdeg > LP->deg) ? + ((desdeg - LP->deg > degs2) ? + -abs (LP->circturn) : abs (LP->circturn)) + : ((LP->deg - desdeg > degs2) ? + abs (LP->circturn) : -abs (LP->circturn)); + } + else + LP->deg += + (st->tanof[LP->deg] > + dy / dx) ? -abs (LP->circturn) : abs (LP->circturn); + } + + wraparound (LP->deg, 0, degs); + { + unsigned char oldcol; + real oldy = LP->y, oldx = LP->x; + LP->x += st->cosof[LP->deg]; + wraparound (LP->x, xmin, xmax + 1); + LP->y += st->sinof[LP->deg]; + wraparound (LP->y, ymin, ymax + 1); +#define xi ((int) LP->x) +#define yi ((int) LP->y) + + oldcol = gp (st, xi, yi); + if (oldcol != 0) + { + Bool vertwall = False, horiwall = False; + if (oldcol == 1 && ((LP->killwalls && st->gridden > 0) || LP->realbounce)) + { + vertwall = (gp (st, xi, (int) oldy) == 1); + horiwall = (gp (st, (int) oldx, yi) == 1); + } + if (oldcol == 1 && LP->realbounce && (vertwall || horiwall)) + { + if (vertwall) + LP->deg = -LP->deg + degs2; + else + LP->deg = -LP->deg; + } + else + { + if ((oldcol != LP->col && LP->realbounce) + || (oldcol == LP->col && LP->selfbounce)) + LP->deg += degs4 * (random1 (2) * 2 - 1); + else if (oldcol != LP->col) + LP->deg += degs2; + } + if (LP->killwalls && st->gridden > 0 && oldcol == 1) + { + if (vertwall && xi + 1 <= xmax) + { + int yy; + for (yy = yi - yi % st->boxh; + yy <= yi - yi % st->boxh + st->boxh && yy <= ymax; yy++) + if (gp (st, xi + 1, yy) != 1 || yy == ymax) + sp (st, xi, yy, 0); + } + if (horiwall && yi + 1 <= ymax) + { + int xx; + for (xx = xi - xi % st->boxw; + xx <= xi - xi % st->boxw + st->boxw && xx <= xmax; xx++) + if (gp (st, xx, yi + 1) != 1 || xx == xmax) + sp (st, xx, yi, 0); + } + } + if (oldcol != LP->col || LP->selfbounce) + { + LP->x = oldx; + LP->y = oldy; + } + wraparound (LP->deg, 0, degs); + } + } + + sp (st, xi, yi, LP->col); + if (LP->filled) + { + if (st->erasing) + sp (st, LP->xrec[LP->recpos], LP->yrec[LP->recpos], 0); + else + sp (st, LP->xrec[LP->recpos], LP->yrec[LP->recpos], LP->col + thrmax); + } + LP->yrec[LP->recpos] = yi; + LP->xrec[LP->recpos] = xi; + if (LP->recpos == LP->reclen - 1) + LP->filled = True; + if (LP->filled && !st->erasing) + { + int co = LP->recpos; + LP->dead = True; + do + { + int nextco = co + 1; + wraparound (nextco, 0, LP->reclen); + if (LP->yrec[co] != LP->yrec[nextco] + || LP->xrec[co] != LP->xrec[nextco]) + LP->dead = False; + co = nextco; + } + while (!(!LP->dead || co == LP->recpos)); + } + LP->recpos++; + wraparound (LP->recpos, 0, LP->reclen); + return (!LP->dead); +} + +static unsigned long +vermiculate_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int had_instring = (st->instring != 0); + int tick = 0; + int this_delay = 0; + int loop = 0; + + + AGAIN: + if (st->reset_p) + { + st->reset_p = 0; + + clearscreen (st); + { + unsigned char thr; + for (thr = 1; thr <= st->threads; thr++) + newonscreen (st, thr); + } + if (st->autopal) + { + randpal (st); + palupdate (st, False); + } + bordupdate (st); + gridupdate (st, False); + } + + { + Bool alltrap = True; + unsigned char thr; + for (thr = 1; thr <= st->threads; thr++) + if (move (st, thr)) + alltrap = False; + if (alltrap) /* all threads are trapped */ + st->reset_p = True; + if (st->speed != SPEEDMAX) + this_delay = waitabit (st); + } + + if (tick++ > st->max_ticks && !had_instring) + { + tick = 0; + st->instring = 0; + maininit(st); + st->reset_p = True; + st->autopal = False; + } + + if (this_delay == 0 && loop++ < 1000) + goto AGAIN; + + return this_delay; +} + +static void * +vermiculate_init (Display *d, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = d; + st->window = w; + st->reset_p = 1; + //st->instring = get_string_resource (st->dpy, "instring", "Instring"); + st->instring = instring; + if (st->instring && !*st->instring) + st->instring = 0; + + //st->max_ticks = get_integer_resource (st->dpy, "ticks", "Integer"); + st->max_ticks = ticks; + { + //int temp = get_integer_resource (st->dpy, "speed", "Speed"); + int temp = speed; + if (temp != 0) + st->speed = temp; + } + + st->mycolors[0].pixel = BlackPixel (st->dpy, DefaultScreen (st->dpy)); + + XSetWindowBackground (st->dpy, st->window, + BlackPixel (st->dpy, DefaultScreen (st->dpy))); + { + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->wid = st->xgwa.width; + st->hei = st->xgwa.height; + st->mycmap = st->xgwa.colormap; + } + { + XGCValues mygcv; + st->mygc = XCreateGC (st->dpy, st->window, 0, &mygcv); + } + + st->point = (unsigned char *) calloc (1, st->wid * st->hei); + maininit (st); + palupdate (st, True); + consume_instring(st); + return st; +} + + +static void +vermiculate_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->wid = w; + st->hei = h; + free (st->point); + st->point = (unsigned char *) calloc (1, st->wid * st->hei); +} + +#if 0 + static Bool + vermiculate_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +consume_instring(struct state *st) +{ + char boolop; + + while (wasakeypressed (st)) + { + st->ch = readkey (st); + switch (st->ch) + { + case 'M': + st->ch = readkey (st); + switch (st->ch) + { + case 'A': + case 'N': + { + unsigned char othreads = st->threads; + if (st->ch == 'N') + st->threads = 0; + do + { + st->ch = readkey (st); + switch (st->ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + st->thread[++st->threads - 1].tmode = st->ch - '0'; + break; + case 'R': + st->thread[++st->threads - 1].tmode = + random1 (tmodes - '0') + 1; + break; + } + } + while (!(st->ch == '\15' || st->ch == '#' + || st->threads == thrmax)); + if (st->threads == 0) + st->threads = othreads; + st->reset_p = 1; + } + break; + } + break; + case 'C': + pickbank (st); + if (st->bnkt > 0) + { + st->ch = readkey (st); + switch (st->ch) + { + case 'D': + st->ch = readkey (st); + switch (st->ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': +/* Careful! The following macro needs to be at the beginning of any +block in which it's invoked, since it declares variables: */ +#define forallinbank(LDP) linedata *LDP; int bankc; \ + for (bankc = 1; \ + (LDP = &st->thread[st->bank[bankc - 1] - 1], \ + bankc <= st->bnkt); bankc++) + { + forallinbank (L) L->slice = degs / (st->ch - '0'); + } + break; + case 'M': + { + forallinbank (L) L->slice = 0; + } + break; + } + break; + case 'S': + { + forallinbank (L) + { + L->otslen = L->tslen; + L->tslen = 0; + } + } + do + { + char oldch = st->ch; + st->ch = readkey (st); + { + forallinbank (L) + { + switch (st->ch) + { + case '0': + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + L->tslen++; + L->turnseq[L->tslen - 1] = st->ch - '0'; + if (oldch == '-') + L->turnseq[L->tslen - 1] *= -1; + if (bankc % 2 == 0) + L->turnseq[L->tslen - 1] *= -1; + break; + } + } + } + } + while (!(st->ch == '\15' || st->ch == '#' + || st->thread[st->bank[0] - 1].tslen == 50)); + { + forallinbank (L) + { + int seqSum = 0, c; + + if (L->tslen == 0) + L->tslen = L->otslen; + for (c = 1; c <= L->tslen; c++) + seqSum += L->turnseq[c - 1]; + if (seqSum == 0) + L->tclim = 1; + else + L->tclim = + (int) (((real) degs2) / abs (seqSum)); + L->tsc = random1 (L->tslen) + 1; + } + } + break; + case 'T': + { + st->ch = readkey (st); + { + forallinbank (L) + { + switch (st->ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + L->tmode = st->ch - '0'; + break; + case 'R': + L->tmode = random1 (tmodes - '0') + 1; + break; + } + } + } + } + break; + case 'O': + st->ch = readkey (st); + { + forallinbank (L) L->orichar = st->ch; + } + break; + case 'F': + { + banktype fbank; + arrcpy (fbank, st->bank); + { + int fbnkt = st->bnkt; + int bankc; + pickbank (st); + for (bankc = 1; bankc <= fbnkt; bankc++) + { + linedata *L = &st->thread[fbank[bankc - 1] - 1]; + if (st->ch == 'N') + L->prey = 0; + else + L->prey = st->bank[0 + (bankc - 1) % st->bnkt]; + } + } + } + break; + case 'L': + { + forallinbank (L) L->prey = st->bank[bankc % st->bnkt]; + } + break; + case 'R': + st->ch = readkey (st); + { + forallinbank (L) switch (st->ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + L->circturn = 10 - (st->ch - '0'); + break; + case 'R': + L->circturn = random1 (7) + 1; + break; + } + } + break; + } + } + break; + case 'T': + case 'Y': + case 'N': + boolop = st->ch; + pickbank (st); + if (st->bnkt > 0) + { + st->ch = readkey (st); + { + forallinbank (L) + { + switch (st->ch) + { + case 'S': + bankmod (boolop, &L->selfbounce); + break; + case 'V': + bankmod (boolop, &L->vhfollow); + break; + case 'R': + bankmod (boolop, &L->realbounce); + break; + case 'L': + bankmod (boolop, &L->little); + st->cleared = True; + break; + case 'T': + bankmod (boolop, &L->tailfollow); + break; + case 'K': + bankmod (boolop, &L->killwalls); + break; + } + } + } + } + break; + case 'R': + if (st->bordcol == 1) + { + st->bordcol = 0; + bordupdate (st); + st->bordcorn = (st->bordcorn + 1) % 4; + st->bordcol = 1; + bordupdate (st); + } + break; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + { + int c; + for (c = 1; c <= thrmax; c++) + st->thread[c - 1].tmode = st->ch - '0'; + } + break; + case '\40': + st->cleared = True; + break; + case 'E': + st->erasing = !st->erasing; + break; + case 'P': + randpal (st); + palupdate (st, True); + break; + case 'G': + { + char dimch = 'B'; + Bool gridchanged = True; + if (st->gridden == 0) + st->gridden = st->ogd; + do + { + int msize = 0; + if (gridchanged) + { + clearscreen (st); + gridupdate (st, True); + } + st->ch = readkey (st); + gridchanged = True; + switch (st->ch) + { + case '+': + msize = 1; + break; + case '-': + msize = -1; + break; + case ']': + if (st->gridden < 15) + st->gridden++; + break; + case '[': + if (st->gridden > 0) + st->gridden--; + break; + case 'O': + st->ogd = st->gridden; + st->gridden = 0; + break; + case 'S': + st->boxw = st->boxh; + case 'W': + case 'H': + case 'B': + dimch = st->ch; + break; + default: + gridchanged = False; + } + if (dimch == 'W' || dimch == 'B') + st->boxw += msize; + if (dimch == 'H' || dimch == 'B') + st->boxh += msize; + if (st->boxw == 0) + st->boxw = 1; + if (st->boxh == 0) + st->boxh = 1; + } + while (!(st->ch == '\15' || st->ch == '#' || st->ch == 'O')); + st->cleared = True; + } + break; + case 'A': + st->autopal = !st->autopal; + break; + case 'B': + st->bordcol = 1 - st->bordcol; + bordupdate (st); + break; + case '-': + st->speed -= SPEEDINC; + if (st->speed < 1) + st->speed = 1; + break; + case '+': + st->speed += SPEEDINC; + if (st->speed > SPEEDMAX) + st->speed = SPEEDMAX; + break; + case '/': + if (st->curviness > 5) + st->curviness -= 5; + break; + case '*': + if (st->curviness < 50) + st->curviness += 5; + break; + case ']': + if (st->threads < thrmax) + newonscreen (st, ++st->threads); + break; + case '[': + if (st->threads > 1) + { + linedata *L = &st->thread[st->threads - 1]; + int lastpos = (L->filled) ? L->reclen - 1 : L->recpos; + int c; + for (c = 0; c <= lastpos; c++) + sp (st, L->xrec[c], L->yrec[c], 0); + st->threads--; + } + break; + } + } +} + +static void +vermiculate_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->point) + { + free(st->point); + } + free (st); +} + + +static const char *vermiculate_defaults[] = { + ".background: Black", + "*ticks: 20000", + "*fpsSolid: true", + "*speed: 0", + "*instring: ", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec vermiculate_options[] = { + {"-speed", ".speed", XrmoptionSepArg, 0}, + {"-instring", ".instring", XrmoptionSepArg, 0}, + {0, 0, 0, 0} +}; + + +XSCREENSAVER_MODULE ("Vermiculate", vermiculate) diff --git a/non-wgl/vermiculate.vcproj b/non-wgl/vermiculate.vcproj new file mode 100644 index 0000000..806b10b --- /dev/null +++ b/non-wgl/vermiculate.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/vines.c b/non-wgl/vines.c new file mode 100644 index 0000000..ee4758b --- /dev/null +++ b/non-wgl/vines.c @@ -0,0 +1,215 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* vines --- vine fractals */ + +#if 0 +static const char sccsid[] = "@(#)vines.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1997 by Tracy Camp campt@hurrah.com + * + * 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 you make a modification I would of course appreciate a copy. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 11-Jul-1997: David Hansen + * Changed names to vines and modified draw loop + * to honor batchcount so vines can be grown or plotted. + * 10-May-1997: Compatible with xscreensaver + * 21-Mar-1997: David Hansen + * Updated mode to draw complete patterns on every + * iteration instead of growing the vine. Also made + * adjustments to randomization and changed variable + * names to make logic easier to follow. + */ + +/*- + * This was modifed from a 'screen saver' that a friend and I + * wrote on our TI-8x calculators in high school physics one day + * Basically another geometric pattern generator, this ones claim + * to fame is a pseudo-fractal looking vine like pattern that creates + * nifty whorls and loops. + */ + +#define STANDALONE +#define NOARGS + +# define MODE_vines +#define DELAY 200000 +#define COUNT 0 +#define NCOLORS 64 +# define DEFAULTS "*delay: 200000 \n" \ + "*count: 0 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ +# define reshape_vines 0 +# define vines_handle_event 0 + + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +# include "erase.h" +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +char *background = "black"; +char *foreground = "white"; +char *eraseMode = NULL; +float eraseSeconds = 0; + +#ifdef MODE_vines + +ENTRYPOINT ModeSpecOpt vines_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct vines_description = +{"vines", "init_vines", "draw_vines", "release_vines", + "refresh_vines", "init_vines", (char *) NULL, &vines_opts, + 200000, 0, 1, 1, 64, 1.0, "", + "Shows fractals", 0, NULL}; + +#endif + +typedef struct { + int a; + int x1; + int y1; + int x2; + int y2; + int i; + int length; + int iterations; + int constant; + int ang; + int centerx; + int centery; +#ifdef STANDALONE + eraser_state *eraser; +#endif +} vinestruct; + +static vinestruct *vines = (vinestruct *) NULL; + +ENTRYPOINT void +refresh_vines(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} /* refresh_vines */ + +ENTRYPOINT void +init_vines(ModeInfo * mi) +{ + vinestruct *fp; + + if (vines == NULL) { + if ((vines = (vinestruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (vinestruct))) == NULL) { + return; + } + } + fp = &vines[MI_SCREEN(mi)]; + + fp->i = 0; + fp->length = 0; + fp->iterations = 30 + NRAND(100); + +#ifndef STANDALONE + MI_CLEARWINDOW(mi); +#endif +} /* init_vines */ + +ENTRYPOINT void +draw_vines(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + int count; + vinestruct *fp; + + if (vines == NULL) + return; + fp = &vines[MI_SCREEN(mi)]; + +#ifdef STANDALONE + if (fp->eraser) { + fp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), fp->eraser); + return; + } +#endif + + /* MI_IS_DRAWN(mi) = True; */ + if (fp->i >= fp->length) { + if (--(fp->iterations) == 0) { +#ifdef STANDALONE + fp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), fp->eraser); +#endif /* STANDALONE */ + init_vines(mi); + } + fp->centerx = NRAND(MI_WIDTH(mi)); + fp->centery = NRAND(MI_HEIGHT(mi)); + + fp->ang = 60 + NRAND(720); + fp->length = 100 + NRAND(3000); + fp->constant = fp->length * (10 + NRAND(10)); + + fp->i = 0; + fp->a = 0; + fp->x1 = 0; + fp->y1 = 0; + fp->x2 = 1; + fp->y2 = 0; + + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)))); + else + XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); + } + count = fp->i + MI_COUNT(mi); + if ((count <= fp->i) || (count > fp->length)) + count = fp->length; + + while (fp->i < count) { + XDrawLine(display, MI_WINDOW(mi), gc, + fp->centerx + (fp->x1 / fp->constant), + fp->centery - (fp->y1 / fp->constant), + fp->centerx + (fp->x2 / fp->constant), + fp->centery - (fp->y2 / fp->constant)); + + fp->a += (fp->ang * fp->i); + + fp->x1 = fp->x2; + fp->y1 = fp->y2; + + fp->x2 += (int) (fp->i * (cos((double) fp->a) * 360.0) / (2.0 * M_PI)); + fp->y2 += (int) (fp->i * (sin((double) fp->a) * 360.0) / (2.0 * M_PI)); + fp->i++; + } +} /* draw_vines */ + +ENTRYPOINT void +release_vines(ModeInfo * mi) +{ + if (vines != NULL) { + (void) free((void *) vines); + vines = (vinestruct *) NULL; + } +} /* release_vines */ + + +XSCREENSAVER_MODULE ("Vines", vines) + +#endif /* MODE_vines */ diff --git a/non-wgl/vines.vcproj b/non-wgl/vines.vcproj new file mode 100644 index 0000000..dccd4bc --- /dev/null +++ b/non-wgl/vines.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/wander.c b/non-wgl/wander.c new file mode 100644 index 0000000..57de2da --- /dev/null +++ b/non-wgl/wander.c @@ -0,0 +1,300 @@ +/* wander, by Rick Campbell , 19 December 1998. + * + * 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 + +#include "colors.h" +#include "erase.h" + +#define MAXIMUM_COLOR_COUNT (256) + +float eraseSeconds = 0; +char *eraseMode = NULL; + +char *background = "black"; +char *foreground = "white"; +int advance = 1; +int density = 2; +int length = 25000; +int delay = 20000; +int reset = 2500000; +Bool circles = False; +int size = 1; + + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&advance, "advance", NULL, "1", t_Int}, + {&density, "density", NULL, "2", t_Int}, + {&length, "length", NULL, "25000", t_Int}, + {&delay, "delay", NULL, "20000", t_Int}, + {&reset, "reset", NULL, "2500000", t_Int}, + {&circles, "circles", NULL, "False", t_Bool}, + {&size, "size", NULL, "1", t_Int}, +}; + +struct state { + Display *dpy; + Window window; + + unsigned int advance; + Bool circles; + Colormap color_map; + int color_count; + int color_index; + XColor colors [MAXIMUM_COLOR_COUNT]; + GC context; + unsigned int density; + int depth; + int height; + unsigned int length; + unsigned int reset; + unsigned int size; + int width; + int delay; + + int x, y, last_x, last_y, width_1, height_1, length_limit, reset_limit; + unsigned long color; + Pixmap pixmap; + + eraser_state *eraser; +}; + + +static void * +wander_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues values; + XWindowAttributes attributes; + + st->dpy = dpy; + st->window = window; + //st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay = delay; + + XClearWindow (st->dpy, st->window); + XGetWindowAttributes (st->dpy, st->window, &attributes); + st->width = attributes.width; + st->height = attributes.height; + st->depth = attributes.depth; + st->color_map = attributes.colormap; + if (st->color_count) + { + free_colors (attributes.screen, st->color_map, + st->colors, st->color_count); + st->color_count = 0; + } + st->context = XCreateGC (st->dpy, st->window, 0, &values); + st->color_count = MAXIMUM_COLOR_COUNT; + make_color_loop (attributes.screen, 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 = 2; + st->colors [0].red = st->colors [0].green = st->colors [0].blue = 0; + st->colors [1].red = st->colors [1].green = st->colors [1].blue = 0xFFFF; + XAllocColor (st->dpy, st->color_map, &st->colors [0]); + XAllocColor (st->dpy, st->color_map, &st->colors [1]); + } + st->color_index = random () % st->color_count; + + //st->advance = get_integer_resource (st->dpy, "advance", "Integer"); + //st->density = get_integer_resource (st->dpy, "density", "Integer"); + st->advance = advance; + st->density = density; + if (st->density < 1) st->density = 1; + //st->reset = get_integer_resource (st->dpy, "reset", "Integer"); + st->reset = reset; + if (st->reset < 100) st->reset = 100; + //st->circles = get_boolean_resource (st->dpy, "circles", "Boolean"); + //st->size = get_integer_resource (st->dpy, "size", "Integer"); + st->circles = circles; + st->size = size; + if (st->size < 1) st->size = 1; + st->width = st->width / st->size; + st->height = st->height / st->size; + //st->length = get_integer_resource (st->dpy, "length", "Integer"); + st->length = length; + if (st->length < 1) st->length = 1; + XSetForeground (st->dpy, st->context, st->colors [st->color_index].pixel); + + + st->x = random () % st->width; + st->y = random () % st->height; + st->last_x = st->x; + st->last_y = st->y; + st->width_1 = st->width - 1; + st->height_1 = st->height - 1; + st->length_limit = st->length; + st->reset_limit = st->reset; + st->color_index = random () % st->color_count; + st->color = st->colors [random () % st->color_count].pixel; + st->pixmap = XCreatePixmap (st->dpy, window, st->size, + st->size, st->depth); + + XSetForeground (st->dpy, st->context, + BlackPixel (st->dpy, DefaultScreen (st->dpy))); + XFillRectangle (st->dpy, st->pixmap, st->context, 0, 0, + st->width * st->size, st->height * st->size); + XSetForeground (st->dpy, st->context, st->color); + XFillArc (st->dpy, st->pixmap, st->context, 0, 0, st->size, st->size, 0, 360*64); + + return st; +} + + +static unsigned long +wander_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + + if (st->eraser) { + st->eraser = erase_window (st->dpy, st->window, st->eraser); + goto END; + } + + for (i = 0; i < 2000; i++) + { + if (random () % st->density) + { + st->x = st->last_x; + st->y = st->last_y; + } + else + { + st->last_x = st->x; + st->last_y = st->y; + st->x = (st->x + st->width_1 + (random () % 3)) % st->width; + st->y = (st->y + st->height_1 + (random () % 3)) % st->height; + } + + if ((random () % st->length_limit) == 0) + { + if (st->advance == 0) + { + st->color_index = random () % st->color_count; + } + else + { + st->color_index = (st->color_index + st->advance) % st->color_count; + } + st->color = st->colors [st->color_index].pixel; + XSetForeground (st->dpy, st->context, st->color); + if (st->circles) + { + XFillArc (st->dpy, st->pixmap, st->context, + 0, 0, st->size, st->size, 0, 360 * 64); + } + } + + if ((random () % st->reset_limit) == 0) + { + st->eraser = erase_window (st->dpy, st->window, st->eraser); + st->color = st->colors [random () % st->color_count].pixel; + st->x = random () % st->width; + st->y = random () % st->height; + st->last_x = st->x; + st->last_y = st->y; + if (st->circles) + { + XFillArc (st->dpy, st->pixmap, st->context, 0, 0, st->size, st->size, 0, 360*64); + } + } + + if (st->size == 1) + { + XDrawPoint (st->dpy, st->window, st->context, st->x, st->y); + } + else + { + if (st->circles) + { + XCopyArea (st->dpy, st->pixmap, st->window, st->context, 0, 0, st->size, st->size, + st->x * st->size, st->y * st->size); + } + else + { + XFillRectangle (st->dpy, st->window, st->context, st->x * st->size, st->y * st->size, + st->size, st->size); + } + } + } + + END: + return st->delay; +} + + +static void +wander_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->width = w / st->size; + st->height = h / st->size; + st->width_1 = st->width - 1; + st->height_1 = st->height - 1; +} + +#if 0 + static Bool + wander_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +wander_free (Display *dpy, Window window, void *closure) +{ +} + +static const char *wander_defaults [] = +{ + ".background: black", + ".foreground: white", + ".fpsSolid: true", + ".advance: 1", + ".density: 2", + ".length: 25000", + ".delay: 20000", + ".reset: 2500000", + ".circles: False", + ".size: 1", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec wander_options [] = +{ + { "-advance", ".advance", XrmoptionSepArg, 0 }, + { "-circles", ".circles", XrmoptionNoArg, "True" }, + { "-no-circles",".circles", XrmoptionNoArg, "False" }, + { "-density", ".density", XrmoptionSepArg, 0 }, + { "-length", ".length", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-reset", ".reset", XrmoptionSepArg, 0 }, + { "-size", ".size", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Wander", wander) diff --git a/non-wgl/wander.vcproj b/non-wgl/wander.vcproj new file mode 100644 index 0000000..f242637 --- /dev/null +++ b/non-wgl/wander.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/whirlwindwarp.c b/non-wgl/whirlwindwarp.c new file mode 100644 index 0000000..83a1687 --- /dev/null +++ b/non-wgl/whirlwindwarp.c @@ -0,0 +1,528 @@ +/* xscreensaver, Copyright (c) 2000 Paul "Joey" Clark + * + * 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. + * + * 19971004: Johannes Keukelaar : Use helix screen + * eraser. + */ + +/* WhirlwindWarp: moving stars. Ported from QBasic by Joey. + Version 1.3. Smooth with pretty colours. + + This code adapted from original program by jwz/jk above. + Freely distrubtable. Please keep this tag with + this code, and add your own if you contribute. + I would be delighted to hear if have made use of this code. + If you find this code useful or have any queries, please + contact me: pclark@cs.bris.ac.uk / joeyclark@usa.net + Paul "Joey" Clark, hacking for humanity, Feb 99 + www.cs.bris.ac.uk/~pclark | www.changetheworld.org.uk */ + +/* 15/May/05: Added colour rotation, limit on max FPS, scaling size dots, and smoother drivers. + 4/Mar/01: Star colours are cycled when new colour can not be allocated. + 4/Mar/01: Stars are plotted as squares with size relative to screen. + 28/Nov/00: Submitted to xscreensaver as "whirlwindwarp". + 10/Oct/00: Ported to xscreensaver as "twinkle". + 19/Feb/98: Meters and interaction added for Ivor's birthday "stars11f". + 11/Aug/97: Original QBasic program. */ + +#include "screenhack.h" +#include + +#include "erase.h" +#include "hsv.h" + +/* Maximum number of points, maximum tail length, and the number of forcefields/effects (hard-coded) */ +#define maxps 1000 +#define maxts 50 +#define fs 16 +/* TODO: change ps and ts arrays into pointers, for dynamic allocation at runtime. */ + + +char *background = "black"; +char *foreground = "white"; +int points = 400; +int tails = 8; +Bool meters = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&points, "points", NULL, "400", t_Int}, + {&tails, "tails", NULL, "8", t_Int}, + {&meters, "meters", NULL, "False", t_Bool}, +}; + +struct state { + Display *dpy; + Window window; + + GC draw_gc, erase_gc; + unsigned int default_fg_pixel; + + int scrwid,scrhei; + int starsize; + + float cx[maxps]; /* Current x,y of stars in realspace */ + float cy[maxps]; + int tx[maxps*maxts]; /* Previous x,y plots in pixelspace for removal later */ + int ty[maxps*maxts]; + char *name[fs]; /* The force fields and their parameters */ + + int fon[fs]; /* Is field on or off? */ + float var[fs]; /* Current parameter */ + float op[fs]; /* Optimum (central/mean) value */ + float acc[fs]; + float vel[fs]; + + int ps; /* Number of points and tail length */ + int ts; + + Bool meters; + + int initted; + XWindowAttributes xgwa; + int got_color; + XColor color[maxps]; /* The colour assigned to each star */ + XColor bgcolor; + int p,f,nt, sx,sy, resets,lastresets,cnt; + int colsavailable; + int hue; + + struct timeval lastframe; +}; + + +static void * +whirlwindwarp_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + Colormap cmap; + + st->dpy = dpy; + st->window = window; + + st->ps=500; + st->ts=5; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + cmap = st->xgwa.colormap; + //gcv.foreground = st->default_fg_pixel = get_pixel_resource (st->dpy, cmap, "foreground", "Foreground"); + gcv.foreground = st->default_fg_pixel = load_color(st->dpy, cmap, foreground); + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + //gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, cmap, background); + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + + //st->ps = get_integer_resource (st->dpy, "points", "Integer"); + //st->ts = get_integer_resource (st->dpy, "tails", "Integer"); + //st->meters = get_boolean_resource (st->dpy, "meters", "Show meters"); + st->ps = points; + st->ts = tails; + st->meters = meters; + if (st->ps > maxps) st->ps = maxps; + if (st->ts > maxts) st->ts = maxts; + + return st; +} + +static float myrnd(void) +{ /* between -1.0 (inclusive) and +1.0 (exclusive) */ + return 2.0*((float)((random()%10000000)/10000000.0)-0.5); +} + +#if 0 +static float mysgn(float x) +{ + return ( x < 0 ? -1 : + x > 0 ? +1 : + 0 ); +} +#endif + +static void stars_newp(struct state *st, int pp) +{ + st->cx[pp]=myrnd(); + st->cy[pp]=myrnd(); +} + +/* Adjust a variable var about optimum op, + with damp = dampening about op + force = force of random perturbation */ +/* float stars_perturb(float var,float op,float damp,float force) { + return op+damp*(var-op)+force*myrnd()/4.0; + }*/ +#define stars_perturb(var,op,damp,force) \ + ( (op) + (damp)*((var)-(op)) + (force)*myrnd()/4.0 ) + +/* Get pixel coordinates of a star */ +static int stars_scrpos_x(struct state *st, int pp) +{ + return st->scrwid*(st->cx[pp]+1.0)/2.0; +} + +static int stars_scrpos_y(struct state *st, int pp) +{ + return st->scrhei*(st->cy[pp]+1.0)/2.0; +} + +/* Draw a meter of a forcefield's parameter */ +static void stars_draw_meter(struct state *st, int ff) +{ + int x,y,w,h; + x=st->scrwid/2; + y=ff*10; + w=(st->var[ff]-st->op[ff])*st->scrwid*4; + h=7; + if (w<0) { + w=-w; + x=x-w; + } + if (st->fon[ff]) + XFillRectangle(st->dpy,st->window,st->draw_gc,x,y,w,h); + /* else + XDrawRectangle(dpy,window,draw_gc,x,y,w,h); */ +} + +/* Move a star according to acting forcefields */ +static void stars_move(struct state *st, int pp) +{ + float nx,ny; + float x=st->cx[pp]; + float y=st->cy[pp]; + + /* In theory all these if checks are unneccessary, + since each forcefield effect should do nothing when its var = op. + But the if's are good for efficiency because this function + is called once for every point. + + Squirge towards edges (makes a leaf shape, previously split the screen in 4 but now only 1 :) + These ones must go first, to avoid x+1.0 < 0 + */ + if (st->fon[6]) { + /* x = mysgn(x) * pow(fabs(x),var[6]); + y = mysgn(y) * pow(fabs(y),var[6]);*/ + x = -1.0 + 2.0*pow((x + 1.0)/2.0,st->var[6]); + } + if (st->fon[7]) { + y = -1.0 + 2.0*pow((y + 1.0)/2.0,st->var[7]); + } + + /* Warping in/out */ + if (st->fon[1]) { + x = x * st->var[1]; y = y * st->var[1]; + } + + /* Rotation */ + if (st->fon[2]) { + nx=x*cos(1.1*st->var[2])+y*sin(1.1*st->var[2]); + ny=-x*sin(1.1*st->var[2])+y*cos(1.1*st->var[2]); + x=nx; + y=ny; + } + + /* Asymptotes (looks like a plane with a horizon; equivalent to 1D warp) */ + if (st->fon[3]) { /* Horizontal asymptote */ + y=y*st->var[3]; + } + if (st->fon[4]) { /* Vertical asymptote */ + x=x+st->var[4]*x; /* this is the same maths as the last, but with op=0 */ + } + if (st->fon[5]) { /* Vertical asymptote at right of screen */ + x=(x-1.0)*st->var[5]+1.0; + } + + /* Splitting (whirlwind effect): */ + #define num_splits ( 2 + (int) (fabs(st->var[0]) * 1000) ) + /* #define thru ( (float)(pp%num_splits)/(float)(num_splits-1) ) */ + #define thru ( (float)((int)(num_splits*(float)(pp)/(float)(st->ps)))/(float)(num_splits-1) ) + if (st->fon[8]) { + x=x+0.5*st->var[8]*(-1.0+2.0*thru); + } + if (st->fon[9]) { + y=y+0.5*st->var[9]*(-1.0+2.0*thru); + } + + /* Waves */ + if (st->fon[10]) { + y = y + 0.4*st->var[10]*sin(300.0*st->var[12]*x + 600.0*st->var[11]); + } + if (st->fon[13]) { + x = x + 0.4*st->var[13]*sin(300.0*st->var[15]*y + 600.0*st->var[14]); + } + + st->cx[pp]=x; + st->cy[pp]=y; +} + +/* Turns a forcefield on, and ensures its vars are suitable. */ +static void turn_on_field(struct state *st, int ff) +{ + if (!st->fon[ff]) { + /* acc[ff]=0.0; */ + st->acc[ff]=0.02 * myrnd(); + st->vel[ff]=0.0; + st->var[ff]=st->op[ff]; + } + st->fon[ff] = 1; + if (ff == 10) { + turn_on_field(st, 11); + turn_on_field(st, 12); + } + if (ff == 13) { + turn_on_field(st, 14); + turn_on_field(st, 15); + } +} + +static unsigned long +whirlwindwarp_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + /* time_t lastframe = time((time_t) 0); */ + + if (!st->initted) { + st->initted = 1; + + XClearWindow (st->dpy, st->window); + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->scrwid = st->xgwa.width; + st->scrhei = st->xgwa.height; + + st->starsize=st->scrhei/480; + if (st->starsize<=0) + st->starsize=1; + + /* Setup colours */ + hsv_to_rgb (0.0, 0.0, 0.0, &st->bgcolor.red, &st->bgcolor.green, &st->bgcolor.blue); + st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, &st->bgcolor); + st->colsavailable=0; + for (st->p=0;st->pps;st->p++) { + if (!mono_p) + hsv_to_rgb (random()%360, .6+.4*myrnd(), .6+.4*myrnd(), &st->color[st->p].red, &st->color[st->p].green, &st->color[st->p].blue); + /* hsv_to_rgb (random()%360, 1.0, 1.0, &color[p].red, &color[p].green, &color[p].blue); for stronger colours! */ + if ((!mono_p) && (st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, &st->color[st->p]))) { + st->colsavailable=st->p; + } else { + if (st->colsavailable>0) /* assign colours from those already allocated */ + st->color[st->p]=st->color[ st->p % st->colsavailable ]; + else + st->color[st->p].pixel=st->default_fg_pixel; + } + } + + /* Set up central (optimal) points for each different forcefield */ + st->op[1] = 1; st->name[1] = "Warp"; + st->op[2] = 0; st->name[2] = "Rotation"; + st->op[3] = 1; st->name[3] = "Horizontal asymptote"; + st->op[4] = 0; st->name[4] = "Vertical asymptote"; + st->op[5] = 1; st->name[5] = "Vertical asymptote right"; + st->op[6] = 1; st->name[6] = "Squirge x"; + st->op[7] = 1; st->name[7] = "Squirge y"; + st->op[0] = 0; st->name[0] = "Split number (inactive)"; + st->op[8] = 0; st->name[8] = "Split velocity x"; + st->op[9] = 0; st->name[9] = "Split velocity y"; + st->op[10] = 0; st->name[10] = "Horizontal wave amplitude"; + st->op[11] = myrnd()*3.141; st->name[11] = "Horizontal wave phase (inactive)"; + st->op[12] = 0.01; st->name[12] = "Horizontal wave frequency (inactive)"; + st->op[13] = 0; st->name[13] = "Vertical wave amplitude"; + st->op[14] = myrnd()*3.141; st->name[14] = "Vertical wave phase (inactive)"; + st->op[15] = 0.01; st->name[15] = "Vertical wave frequency (inactive)"; + + /* Initialise parameters to optimum, all off */ + for (st->f=0;st->ff++) { + st->var[st->f]=st->op[st->f]; + st->fon[st->f]=( myrnd()>0.5 ? 1 : 0 ); + st->acc[st->f]=0.02 * myrnd(); + st->vel[st->f]=0; + } + + /* Initialise stars */ + for (st->p=0;st->pps;st->p++) + stars_newp(st, st->p); + + /* tx[nt],ty[nt] remember earlier screen plots (tails of stars) + which are deleted when nt comes round again */ + st->nt = 0; + st->resets = 0; + + st->hue = 180 + 180*myrnd(); + + gettimeofday(&st->lastframe, NULL); + + } + + + if (myrnd()>0.75) { + /* Change one of the allocated colours to something near the current hue. */ + /* By changing a random colour, we sometimes get a tight colour spread, sometime a diverse one. */ + int pp = st->colsavailable * (0.5+myrnd()/2); + hsv_to_rgb (st->hue, .6+.4*myrnd(), .6+.4*myrnd(), &st->color[pp].red, &st->color[pp].green, &st->color[pp].blue); + if ((!mono_p) && (st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, &st->color[pp]))) { + } + st->hue = st->hue + 0.5 + myrnd()*9.0; + if (st->hue<0) st->hue+=360; + if (st->hue>=360) st->hue-=360; + } + + /* Move current points */ + st->lastresets=st->resets; + st->resets=0; + for (st->p=0;st->pps;st->p++) { + /* Erase old */ + XSetForeground (st->dpy, st->draw_gc, st->bgcolor.pixel); + /* XDrawPoint(dpy,window,draw_gc,tx[nt],ty[nt]); */ + XFillRectangle(st->dpy,st->window,st->draw_gc,st->tx[st->nt],st->ty[st->nt],st->starsize,st->starsize); + + /* Move */ + stars_move(st, st->p); + /* If moved off screen, create a new one */ + if (st->cx[st->p]<=-0.9999 || st->cx[st->p]>=+0.9999 || + st->cy[st->p]<=-0.9999 || st->cy[st->p]>=+0.9999 || + fabs(st->cx[st->p])<.0001 || fabs(st->cy[st->p])<.0001) { + stars_newp(st, st->p); + st->resets++; + } else if (myrnd()>0.99) /* Reset at random */ + stars_newp(st, st->p); + + /* Draw point */ + st->sx=stars_scrpos_x(st, st->p); + st->sy=stars_scrpos_y(st, st->p); + XSetForeground (st->dpy, st->draw_gc, st->color[st->p].pixel); + /* XDrawPoint(dpy,window,draw_gc,sx,sy); */ + XFillRectangle(st->dpy,st->window,st->draw_gc,st->sx,st->sy,st->starsize,st->starsize); + + /* Remember it for removal later */ + st->tx[st->nt]=st->sx; + st->ty[st->nt]=st->sy; + st->nt=(st->nt+1)%(st->ps*st->ts); + } + + /* Adjust force fields */ + st->cnt=0; + for (st->f=0;st->ff++) { + + if (st->meters) { /* Remove meter from display */ + XSetForeground(st->dpy, st->draw_gc, st->bgcolor.pixel); + stars_draw_meter(st,st->f); + } + + /* Adjust forcefield's parameter */ + if (st->fon[st->f]) { + /* This configuration produces var[f]s usually below 0.01 */ + st->acc[st->f]=stars_perturb(st->acc[st->f],0,0.98,0.005); + st->vel[st->f]=stars_perturb(st->vel[st->f]+0.03*st->acc[st->f],0,0.995,0.0); + st->var[st->f]=st->op[st->f]+(st->var[st->f]-st->op[st->f])*0.9995+0.001*st->vel[st->f]; + } + /* fprintf(stderr,"f=%i fon=%i acc=%f vel=%f var=%f\n",f,fon[f],acc[f],vel[f],var[f]); */ + + /* Decide whether to turn this forcefield on or off. */ + /* prob_on makes the "splitting" effects less likely than the rest */ + #define prob_on ( st->f==8 || st->f==9 ? 0.999975 : 0.9999 ) + if ( st->fon[st->f]==0 && myrnd()>prob_on ) { + turn_on_field(st, st->f); + } else if ( st->fon[st->f]!=0 && myrnd()>0.99 && fabs(st->var[st->f]-st->op[st->f])<0.0005 && fabs(st->vel[st->f])<0.005 /* && fabs(acc[f])<0.01 */ ) { + /* We only turn it off if it has gently returned to its optimal (as opposed to rapidly passing through it). */ + st->fon[st->f] = 0; + } + + if (st->meters) { /* Redraw the meter */ + XSetForeground(st->dpy, st->draw_gc, st->color[st->f].pixel); + stars_draw_meter(st,st->f); + } + + if (st->fon[st->f]) + st->cnt++; + } + + /* Ensure at least three forcefields are on. + * BUG: Picking randomly might not be enough since 0,11,12,14 and 15 do nothing! + * But then what's wrong with a rare gentle twinkle?! + */ + if (st->cnt<3) { + st->f=random() % fs; + turn_on_field(st, st->f); + } + + if (st->meters) { + XSetForeground(st->dpy, st->draw_gc, st->bgcolor.pixel); + XDrawRectangle(st->dpy,st->window,st->draw_gc,0,0,st->lastresets*5,3); + XSetForeground(st->dpy, st->draw_gc, st->default_fg_pixel); + XDrawRectangle(st->dpy,st->window,st->draw_gc,0,0,st->resets*5,3); + } + + /* Cap frames per second; do not go above specified fps: */ + { + unsigned long this_delay = 0; + int maxfps = 200; + long utimeperframe = 1000000/maxfps; + struct timeval now; + long timediff; + gettimeofday(&now, NULL); + timediff = now.tv_sec*1000000 + now.tv_usec - st->lastframe.tv_sec*1000000 - st->lastframe.tv_usec; + if (timediff < utimeperframe) { + /* fprintf(stderr,"sleeping for %i\n",utimeperframe-timediff); */ + this_delay = (utimeperframe-timediff); + } + st->lastframe = now; + + return this_delay; + } +} + + +static void +whirlwindwarp_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->scrwid = w; + st->scrhei = h; +} + +#if 0 +static Bool + whirlwindwarp_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +whirlwindwarp_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *whirlwindwarp_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*points: 400", + "*tails: 8", + "*meters: false", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec whirlwindwarp_options [] = { + { "-points", ".points", XrmoptionSepArg, 0 }, + { "-tails", ".tails", XrmoptionSepArg, 0 }, + { "-meters", ".meters", XrmoptionNoArg, "true" }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("WhirlWindWarp", whirlwindwarp) diff --git a/non-wgl/whirlwindwarp.vcproj b/non-wgl/whirlwindwarp.vcproj new file mode 100644 index 0000000..447e7f3 --- /dev/null +++ b/non-wgl/whirlwindwarp.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/whirlygig.c b/non-wgl/whirlygig.c new file mode 100644 index 0000000..cf753f8 --- /dev/null +++ b/non-wgl/whirlygig.c @@ -0,0 +1,816 @@ +/* Whirlygig -- an experiment in X programming + * + * 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. + * + * When I was in trigonometry class as a kid, I remember being fascinated + * by the beauty of the shapes one receives when playing with sine waves + * Here is a little experiment to show that beauty is simple + */ + +#include "screenhack.h" +#include +#include + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# include "xdbe.h" +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +#define NCOLORS 100 +#define FULL_CYCLE 429496729 +#define START_ARC 0 +#define END_ARC 23040 + +char *background = "black"; +char *foreground = "white"; +float xspeed = 1.0; +float yspeed = 1.0; +float xamplitude = 1.0; +float yamplitude = 1.0; +int whirlies = -1; +int nlines = -1; +char *xmode = "change"; +char *ymode = "change"; +int speed = 1; +Bool trail = False; +int color_modifier = -1; +int start_time = -1; +Bool explain = False; +float xoffset = 1.0; +float yoffset = 1.0; +int offset_period = 1; +Bool wrap = False; +Bool doubleBuffer = True; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&xspeed, "xspeed", NULL, "1.0", t_Float}, + {&yspeed, "yspeed", NULL, "1.0", t_Float}, + {&xamplitude, "xamplitude", NULL, "1.0", t_Float}, + {&yamplitude, "yamplitude", NULL, "1.0", t_Float}, + {&whirlies, "whirlies", NULL, "-1", t_Int}, + {&nlines, "nlines", NULL, "-1", t_Int}, + {&xmode, "xmode", NULL, "change", t_String}, + {&ymode, "ymode", NULL, "change", t_String}, + {&speed, "speed", NULL, "1", t_Int}, + {&trail, "trail", NULL, "False", t_Bool}, + {&color_modifier, "color_modifier", NULL, "-1", t_Int}, + {&start_time, "start_time", NULL, "-1", t_Int}, + {&explain, "explain", NULL, "False", t_Bool}, + {&xoffset, "xoffset", NULL, "1.0", t_Float}, + {&yoffset, "yoffset", NULL, "1.0", t_Float}, + {&offset_period, "offset_period", NULL, "1", t_Int}, + {&wrap, "wrap", NULL, "False", t_Bool}, + {&doubleBuffer, "doubleBuffer", NULL, "True", t_Bool}, +}; + +struct info { +/* Bool writable; / * Is the screen writable */ + double xspeed; /* A factor to modify the horizontal movement */ + double yspeed; /* A factor to modify vertical movement */ + double xamplitude; + double yamplitude; + int whirlies; /* How many whirlies per line do you want? */ + int nlines; /* How many lines of whirlies do you want? */ + int half_width; /* 1/2 the width of the screen */ + int half_height; + int speed; + int trail; + int color_modifier; + double xoffset; + double yoffset; + double offset_period; + Bool wrap; +}; + +enum object_mode { + spin_mode, funky_mode, circle_mode, linear_mode, test_mode, fun_mode, innie_mode, lissajous_mode +}; + +struct state { + Display *dpy; + Window window; + + XGCValues gcv; /* The structure to hold the GC data */ + XWindowAttributes xgwa; /* A structure to hold window data */ + Pixmap b, ba; /* double-buffer to reduce flicker */ +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + Bool dbeclear_p; + XdbeBackBuffer backb; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + GC fgc, bgc; + int screen; + Bool dbuf; + + unsigned long int current_time; /* The global int telling the current time */ + unsigned long int start_time; + struct info *info; + char *xmode_str, *ymode_str; /* holds the current mode for x and y computation */ + + /* pos is the current position x,y -- last_x contains one cell of + every x coordinate for every position of every whirly in every + line up to 100 whirlies in 100 lines -- lasy_y and last_size hold + the same information for y and size respectively */ + + int pos[2], last_x[100][100], last_y[100][100], last_size[100][100]; + int current_color; + Bool wrap; + int xmode, ymode; + double modifier; /* for innie */ + + XColor colors[NCOLORS]; + int ncolors; + int explaining; +}; + +static void draw_explain_string(struct state *, int, int, Display *, Window, GC); +static void spin(struct state *, unsigned long int, struct info *, int *, int); +static void funky(struct state *, unsigned long int, struct info *, int *, int); +static void circle(struct state *, unsigned long int, struct info *, int *, int); +static void fun(struct state *, unsigned long int, struct info *, int *, int); +static void linear(struct state *, unsigned long int, struct info *, int *, int); +static void lissajous(struct state *, unsigned long int, struct info *, int *, int); +static void test(struct state *, unsigned long int, struct info *, int *, int); +static void innie(struct state *, unsigned long int, struct info *, int *, int, double); + + + +static const char spin_explanation[] = +"Spin mode is a simple sin/cos with every argument modified"; + +static const char funky_explanation[] = +"Funky mode is me goofing off."; + +static const char circle_explanation[] = +"Circle mode graphs the x and y positions as you trace the edge of a circle over time."; + +static const char linear_explanation[] = +"Linear mode draws a straight line"; + +static const char test_explanation[] = +"Test mode is a mode that I play around with ideas in."; + +static const char fun_explanation[] = +"Fun mode is the coolest."; + +static const char innie_explanation[] = +"Innie mode does something or other. Looks cool, though."; + +static const char lissajous_explanation[] = +"Lissajous mode draws a slightly modified lissajous curve"; + +static void +draw_explain_string(struct state *st, int mode, int offset, Display *dpy, Window window, GC fgc) +{ + switch(mode) { + case spin_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) spin_explanation, strlen(spin_explanation)); + break; + case funky_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) funky_explanation, strlen(funky_explanation)); + break; + case circle_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) circle_explanation, strlen(circle_explanation)); + break; + case linear_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) linear_explanation, strlen(linear_explanation)); + break; + case test_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) test_explanation, strlen(test_explanation)); + break; + case fun_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) fun_explanation, strlen(fun_explanation)); + break; + case innie_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) innie_explanation, strlen(innie_explanation)); + break; + case lissajous_mode: + XDrawString(st->dpy, st->window, st->fgc, 50, offset, + (char*) lissajous_explanation, strlen(linear_explanation)); + } +} + +static void +funky(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index) +{ + double new_time = ((the_time % 360 ) / 180.0) * M_PI; + if (index == 0) { + double time_modifier = cos(new_time / 180.0); + double the_cos = cos((new_time * (double)st->info->xspeed) + (time_modifier * 80.0)); + double dist_mod_x = cos(new_time) * (st->info->half_width - 50); + st->pos[index]= st->info->xamplitude * (the_cos * dist_mod_x) + st->info->half_width; + } + else { + double new_time = ((the_time % 360 ) / 180.0) * M_PI; + double time_modifier = sin(new_time / 180.0); + double the_sin = sin((new_time * (double)st->info->yspeed) + (time_modifier * 80.0)); + double dist_mod_y = sin(new_time) * (st->info->half_height - 50); + st->pos[index] = st->info->yamplitude * (the_sin * dist_mod_y) + st->info->half_height; + } +} + +static void +innie(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index, double modifier) +{ + double frequency = 2000000.0 + (st->modifier * cos(((double)the_time / 100.0))); + double arg = (double)the_time / frequency; + double amplitude = 200.0 * cos(arg); + double fun = 150.0 * cos((double)the_time / 2000.0); + int vert_mod, horiz_mod; + if (index == 0) { + horiz_mod = (int)(fun * cos((double)the_time / 100.0)) + st->info->half_width; + st->pos[index] = (amplitude * cos((double)the_time / 100.0 * st->info->xspeed)) + horiz_mod; + } + else { + vert_mod = (int)(fun * sin((double)the_time / 100.0)) + st->info->half_height; + st->pos[index] = (amplitude * sin((double)the_time / 100.0 * st->info->yspeed)) + vert_mod; + } +} + +static void +lissajous(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index) +{ + /* This is a pretty standard lissajous curve + x = a sin(nt + c) + y = b sin(t) + The n and c modifiers are cyclic as well, however... */ + int result; + double time = (double)the_time / 100.0; + double fun = 15.0 * cos((double)the_time / 800.0); + double weird = cos((time / 1100000.0) / 1000.0); + + if (index == 0) { + result = st->info->xamplitude * 200.0 * sin((weird * time) + fun) + st->info->half_width; + } + else { + result = st->info->yamplitude * 200.0 * sin(time) + st->info->half_height; + } + st->pos[index] = result; +} + +static void +circle(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index) +{ + int result; + if (index == 0) { + result = st->info->xamplitude * (cos((double)the_time / 100.0 * st->info->xspeed) * (st->info->half_width / 2)) + st->info->half_width; + } + else { + result = st->info->yamplitude * (sin((double)the_time / 100.0 * st->info->yspeed) * (st->info->half_height / 2)) + st->info->half_height; + } + st->pos[index] = result; +} + +#if 0 +static void +mod(unsigned long int the_time, struct info *info, int pos[], int index) +{ + int amplitude; + int max = st->info->half_width; + if ((the_time % (max * 2)) < max) + amplitude = max - ((the_time % (max * 2)) - max); + else + amplitude = the_time % (max * 2); + amplitude = amplitude - max; +} +#endif + +static void +spin(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index) +{ + double funky = (((the_time % 360) * 1.0) / 180.0) * M_PI; + if (index ==0) { + double the_cos = cos((double)the_time / (180.0 * st->info->xspeed)); + double dist_mod_x = cos((double)funky) * (st->info->half_width - 50); + st->pos[index] = st->info->xamplitude * (the_cos * dist_mod_x) + st->info->half_width; + } + else { + double the_sin = sin((double)the_time / (180.0 * st->info->yspeed)); + double dist_mod_y = sin((double)funky) * (st->info->half_height - 50); + st->pos[index] = st->info->yamplitude * (the_sin * dist_mod_y) + st->info->half_height; + } +} + +static void +fun(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index) +{ + int amplitude; + int max = st->info->half_width; + if ((the_time % (max * 2)) < max) + amplitude = max - ((the_time % (max * 2)) - max); + else + amplitude = the_time % (max * 2); + amplitude = amplitude - max; + if (index ==0) { + st->pos[index] = (amplitude * cos((double)the_time / 100.0 * st->info->xspeed)) + st->info->half_width; + } + else { + st->pos[index] = (amplitude * sin((double)the_time / 100.0 * st->info->yspeed)) + st->info->half_height; + } +} + +static void +linear(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index) +{ + if (index == 0) /* Calculate for the x axis */ + st->pos[index] = ((the_time / 2) % (st->info->half_width * 2)); + else + st->pos[index] = ((the_time / 2) % (st->info->half_height * 2)); +} + +static void +test(struct state *st, unsigned long int the_time, struct info *info, int pos[], int index) +{ + if (index == 0) { + st->pos[index] = st->info->xamplitude * (cos((double)the_time / 100.0 * st->info->xspeed) * (st->info->half_width / 2)) + st->info->half_width; + } + else { + st->pos[index] = st->info->yamplitude * (sin((double)the_time / 100.0 * st->info->yspeed) * (st->info->half_height / 2)) + st->info->half_height; + } +} + +static int preen(int current, int max) { + if (current > max) + current=current-max; + if (current < 0) + current=current+max; + return(current); +} + +#if 0 +static void +smoothen(struct state *st, int x, int lastx, int y, int lasty, int size, int last_color, XColor *colors, Display *dpy, Window window, GC bgc, int screen, struct info *info) +{ + double xdistance = abs((double)x-(double)lastx); + double ydistance = abs((double)y-(double)lasty); + double distance = sqrt(((xdistance * xdistance) + (ydistance * ydistance)) ); + double slope = (((double)y-(double)lasty) / ((double)x-(double)lastx)); + printf("Starting smoothen with values: %f, %f, %f, %f\n", xdistance, ydistance, distance, slope); + if (distance > 2.0) { + int newx = (int)((xdistance / distance) * slope); + int newy = (int)((ydistance / distance) * slope); + if (! st->info->trail) { + XSetForeground(st->dpy, st->bgc, BlackPixel(st->dpy, st->screen)); + XFillArc(st->dpy, st->window, st->bgc, lastx, lasty, size, size, START_ARC, END_ARC); + } + XSetForeground(st->dpy, st->bgc, st->colors[last_color].pixel); + XFillArc(st->dpy, st->window, st->bgc, newx, newy, size, size, START_ARC, END_ARC); + smoothen(st, newx, x, newy, y, size, last_color, st->colors, st->dpy, st->window, st->bgc, st->screen, st->info); + } +} +#endif + + +static void * +whirlygig_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + + st->ncolors = NCOLORS; + + //st->dbuf = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean"); + st->dbuf = doubleBuffer; + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + st->dbuf = False; +# endif + + st->start_time = st->current_time; + st->info = (struct info *)malloc(sizeof(struct info)); + + st->screen = DefaultScreen(st->dpy); + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + if (st->dbuf) + { +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + //if (get_boolean_resource(st->dpy,"useDBE","Boolean")) + if (True) + { + //st->dbeclear_p = get_boolean_resource (st->dpy, "useDBEClear", + // "Boolean"); + st->dbeclear_p = True; + if (st->dbeclear_p) + st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeBackground); + else + st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined); + st->backb = st->b; + } +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + if (!st->b) + { + st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth); + st->b = st->ba; + } + } + else + { + st->b = st->window; + } + + //st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, "foreground", "Foreground"); + st->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, foreground); + st->fgc = XCreateGC (st->dpy, st->b, GCForeground, &st->gcv); + //st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, "background", "Background"); + st->gcv.foreground = load_color(st->dpy, st->xgwa.colormap, background); + st->bgc = XCreateGC (st->dpy, st->b, GCForeground, &st->gcv); + +#ifdef HAVE_COCOA /* #### should turn off double-buffering instead */ + jwxyz_XSetAntiAliasing (dpy, st->fgc, False); + jwxyz_XSetAntiAliasing (dpy, st->bgc, False); +#endif + + { + Bool writable_p = False; + make_uniform_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, st->colors, &st->ncolors, + True, &writable_p, True); + } + + if (st->ba) XFillRectangle (st->dpy, st->ba, st->bgc, 0, 0, st->xgwa.width, st->xgwa.height); + + /* info is a structure holding all the random pieces of information I may want to + pass to my baby functions -- much of it I may never use, but it is nice to + have around just in case I want it to make a funky function funkier */ +/* info->writable = get_boolean_resource (dpy, "cycle", "Boolean"); */ +#if 1 + st->info->xspeed = xspeed; + st->info->yspeed = yspeed; + st->info->xamplitude = xamplitude; + st->info->yamplitude = yamplitude; + st->info->offset_period = offset_period; + st->info->whirlies = whirlies; + st->info->nlines = nlines; +#else + st->info->xspeed = get_float_resource(st->dpy, "xspeed" , "Float"); + st->info->yspeed = get_float_resource(st->dpy, "yspeed" , "Float"); + st->info->xamplitude = get_float_resource(st->dpy, "xamplitude", "Float"); + st->info->yamplitude = get_float_resource(st->dpy, "yamplitude", "Float"); + st->info->offset_period = get_float_resource(st->dpy, "offset_period", "Float"); + st->info->whirlies = get_integer_resource(st->dpy, "whirlies", "Integer"); + st->info->nlines = get_integer_resource(st->dpy, "nlines", "Integer"); +#endif + st->info->half_width = st->xgwa.width / 2; + st->info->half_height = st->xgwa.height / 2; +#if 1 + st->info->speed = speed; + st->info->trail = trail; + st->info->color_modifier = color_modifier; + st->info->xoffset = xoffset; + st->info->yoffset = yoffset; + st->xmode_str = xmode; + st->ymode_str = ymode; + st->wrap = wrap; +#else + st->info->speed = get_integer_resource(st->dpy, "speed" , "Integer"); + st->info->trail = get_boolean_resource(st->dpy, "trail", "Integer"); + st->info->color_modifier = get_integer_resource(st->dpy, "color_modifier", "Integer"); + st->info->xoffset = get_float_resource(st->dpy, "xoffset", "Float"); + st->info->yoffset = get_float_resource(st->dpy, "yoffset", "Float"); + st->xmode_str = get_string_resource(st->dpy, "xmode", "Mode"); + st->ymode_str = get_string_resource(st->dpy, "ymode", "Mode"); + st->wrap = get_boolean_resource(st->dpy, "wrap", "Boolean"); +#endif + st->modifier = 3000.0 + frand(1500.0); + if (! st->xmode_str) st->xmode = spin_mode; + else if (! strcmp (st->xmode_str, "spin")) st->xmode = spin_mode; + else if (! strcmp (st->xmode_str, "funky")) st->xmode = funky_mode; + else if (! strcmp (st->xmode_str, "circle")) st->xmode = circle_mode; + else if (! strcmp (st->xmode_str, "linear")) st->xmode = linear_mode; + else if (! strcmp (st->xmode_str, "test")) st->xmode = test_mode; + else if (! strcmp (st->xmode_str, "fun")) st->xmode = fun_mode; + else if (! strcmp (st->xmode_str, "innie")) st->xmode = innie_mode; + else if (! strcmp (st->xmode_str, "lissajous")) st->xmode = lissajous_mode; + else { + st->xmode = random() % (int) lissajous_mode; + } + if (! st->ymode_str) st->ymode = spin_mode; + else if (! strcmp (st->ymode_str, "spin")) st->ymode = spin_mode; + else if (! strcmp (st->ymode_str, "funky")) st->ymode = funky_mode; + else if (! strcmp (st->ymode_str, "circle")) st->ymode = circle_mode; + else if (! strcmp (st->ymode_str, "linear")) st->ymode = linear_mode; + else if (! strcmp (st->ymode_str, "test")) st->ymode = test_mode; + else if (! strcmp (st->ymode_str, "fun")) st->ymode = fun_mode; + else if (! strcmp (st->ymode_str, "innie")) st->ymode = innie_mode; + else if (! strcmp (st->ymode_str, "lissajous")) st->ymode = lissajous_mode; + else { + st->ymode = random() % (int) lissajous_mode; + } + +#if 1 + if (start_time == -1) + st->current_time = (unsigned long int)(random()); + else + st->current_time = start_time; +#else + if (get_integer_resource(st->dpy, "start_time", "Integer") == -1) + st->current_time = (unsigned long int)(random()); + else + st->current_time = get_integer_resource(st->dpy, "start_time", "Integer"); +#endif + if (st->info->whirlies == -1) + st->info->whirlies = 1 + (random() % 15); + if (st->info->nlines == -1) + st->info->nlines = 1 + (random() % 5); + if (st->info->color_modifier == -1) + st->info->color_modifier = 1 + (random() % 25); + //if (get_boolean_resource(st->dpy, "explain", "Integer")) + if (explain) + st->explaining = 1; + st->current_color = 1 + (random() % NCOLORS); + + return st; +} + +static unsigned long +whirlygig_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int wcount; /* wcount is a counter incremented for every whirly take note of + internal_time before you mess with it */ + int change_time = 4000; + + if (st->explaining == 1) { + XClearWindow (st->dpy, st->window); + draw_explain_string(st, st->xmode, st->info->half_height-100, + st->dpy, st->window, st->fgc); + st->explaining++; + return 3000000; + } else if (st->explaining == 2) { + XClearWindow (st->dpy, st->window); + st->explaining = 0; + } + + if (! strcmp (st->xmode_str, "change") && ! strcmp (st->ymode_str, "change")) { + if ((st->current_time - st->start_time) > change_time) { + st->start_time = st->current_time; + st->xmode = 1 + (random() % 4); + st->ymode = 1 + (random() % 4); + } + } + else if (! strcmp (st->xmode_str, "change")) { + if ((st->current_time - st->start_time) > change_time) { + st->start_time = st->current_time; + st->xmode = 1 + (random() % 4); + } + } + else if (! strcmp (st->ymode_str, "change")) { + if ((st->current_time - st->start_time) > change_time) { + st->start_time = st->current_time; + st->ymode = 1 + (random() % 3); + printf("Changing ymode to %d\n", st->ymode); + } + } + if (++st->current_color >= NCOLORS) + st->current_color = 0; + for (wcount = 0; wcount < st->info->whirlies; wcount++) { + int lcount; /* lcount is a counter for every line -- take note of the offsets changing */ + int internal_time = st->current_time; + int color_offset = (st->current_color + (st->info->color_modifier * wcount)) % NCOLORS; + if (st->current_time == 0) + internal_time = 0; + else + /* I want the distance between whirlies to increase more each whirly */ + internal_time = st->current_time + (10 * wcount) + (wcount * wcount); + switch (st->xmode) { + /* All these functions expect an int time, the struct info, + a pointer to an array of positions, and the index that the + the function will fill of the array */ + case spin_mode: + spin(st, internal_time, st->info, st->pos, 0); + break; + case funky_mode: + funky(st, internal_time, st->info, st->pos, 0); + break; + case circle_mode: + circle(st, internal_time, st->info, st->pos, 0); + break; + case linear_mode: + linear(st, internal_time, st->info, st->pos, 0); + break; + case fun_mode: + fun(st, internal_time, st->info, st->pos, 0); + break; + case test_mode: + test(st, internal_time, st->info, st->pos, 0); + break; + case innie_mode: + innie(st, internal_time, st->info, st->pos, 0, st->modifier); + break; + case lissajous_mode: + lissajous(st, internal_time, st->info, st->pos, 0); + break; + default: + spin(st, internal_time, st->info, st->pos, 0); + break; + } /* End of the switch for the x position*/ + switch (st->ymode) { + case spin_mode: + spin(st, internal_time, st->info, st->pos, 1); + break; + case funky_mode: + funky(st, internal_time, st->info, st->pos, 1); + break; + case circle_mode: + circle(st, internal_time, st->info, st->pos, 1); + break; + case linear_mode: + linear(st, internal_time, st->info, st->pos, 1); + break; + case fun_mode: + fun(st, internal_time, st->info, st->pos, 1); + break; + case test_mode: + test(st, internal_time, st->info, st->pos, 1); + break; + case innie_mode: + innie(st, internal_time, st->info, st->pos, 1, st->modifier); + break; + case lissajous_mode: + lissajous(st, internal_time, st->info, st->pos, 1); + break; + default: + spin(st, internal_time, st->info, st->pos, 1); + break; + } /* End of the switch for the y position*/ + for (lcount = 0; lcount < st->info->nlines; lcount++) { + double arg = (double)((internal_time * st->info->offset_period) / 90.0); + double line_offset = 20.0 * (double)lcount * sin(arg); + int size; + size = (int)(15.0 + 5.0 * sin((double)internal_time / 180.0)); + /* First delete the old circle... */ + if (!st->info->trail +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + && ( !st->dbeclear_p || !st->backb) +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + ) { + XSetForeground(st->dpy, st->bgc, BlackPixel(st->dpy, st->screen)); + XFillArc(st->dpy, st->b, st->bgc, st->last_x[wcount][lcount], st->last_y[wcount][lcount], st->last_size[wcount][lcount], st->last_size[wcount][lcount], START_ARC, END_ARC); + } + /* Now, lets draw in the new circle */ + { /* Starting new scope for local x_pos and y_pos */ + int xpos, ypos; + if (st->wrap) { + xpos = preen((int)(st->info->xoffset*line_offset)+st->pos[0], st->info->half_width * 2); + ypos = preen((int)(st->info->yoffset*line_offset)+st->pos[1], st->info->half_height * 2); + } + else { + xpos = (int)(st->info->xoffset*line_offset)+st->pos[0]; + ypos = (int)(st->info->yoffset*line_offset)+st->pos[1]; + } + if (st->start_time == st->current_time) { + /* smoothen should move from one mode to another prettily... */ + + /* Note: smoothen has not been modified to take the double + buffering code into account, and needs to be hacked on + before uncommenting. + */ + /* + smoothen(xpos, last_x[wcount][lcount], ypos, last_y[wcount][lcount], size, color_offset, colors, dpy, window, bgc, screen, info); + */ + } + st->last_x[wcount][lcount] = xpos; + st->last_y[wcount][lcount] = ypos; + st->last_size[wcount][lcount] = size; + XSetForeground(st->dpy, st->bgc, st->colors[color_offset].pixel); + XFillArc(st->dpy, st->b, st->bgc, xpos, ypos, size, size, START_ARC, END_ARC); + } /* End of my temporary scope for xpos and ypos */ + } /* End of the for each line in nlines */ + } /* End of the for each whirly in whirlies */ + + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (st->backb) + { + XdbeSwapInfo info[1]; + info[0].swap_window = st->window; + info[0].swap_action = (st->dbeclear_p ? XdbeBackground : XdbeUndefined); + XdbeSwapBuffers (st->dpy, info, 1); + } + else +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + if (st->dbuf) + { + XCopyArea (st->dpy, st->b, st->window, st->bgc, 0, 0, + st->xgwa.width, st->xgwa.height, 0, 0); + } + + if (st->current_time == FULL_CYCLE) + st->current_time = 1; + else + st->current_time = st->current_time + st->info->speed; + + return 10000; +} + + +static void +whirlygig_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + whirlygig_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +whirlygig_free (Display *dpy, Window window, void *closure) +{ +} + + +static const char *whirlygig_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*xspeed: 1.0", + "*yspeed: 1.0", + "*xamplitude: 1.0", + "*yamplitude: 1.0", + "*whirlies: -1", + "*nlines: -1", + "*xmode: change", + "*ymode: change", + "*speed: 1", + "*trail: false", + "*color_modifier: -1", + "*start_time: -1", + "*explain: False", + "*xoffset: 1.0", + "*yoffset: 1.0", + "*offset_period: 1", + "*wrap: False", + "*doubleBuffer: True", +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + "*useDBEClear: True", + "*useDBE: True", +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + 0 +}; + +static XrmOptionDescRec whirlygig_options [] = { + { "-xspeed", ".xspeed", XrmoptionSepArg, 0 }, + /* xspeed is a modifier of the argument to cos -- changing it thus + changes the frequency of cos */ + { "-yspeed", ".yspeed", XrmoptionSepArg, 0 }, + /* Similiarly, yspeed changes the frequency of sin */ + { "-xamplitude", ".xamplitude", XrmoptionSepArg, 0 }, + /* A factor by which to increase/decrease the amplitude of the sin */ + { "-yamplitude", ".yamplitude", XrmoptionSepArg, 0 }, + /* A factor by which to increase/decrease the amplitude of the cos */ + { "-whirlies", ".whirlies",XrmoptionSepArg, 0 }, + /* whirlies defines the number of circles to draw per line */ + { "-nlines", ".nlines",XrmoptionSepArg, 0 }, + /* nlines is the number of lines of whirlies to draw */ + { "-xmode", ".xmode", XrmoptionSepArg, 0 }, + /* There are a few different modes that I have written -- each mode + is in theory a different experiment with the possible modifiers to sin/cos */ + { "-ymode", ".ymode", XrmoptionSepArg, 0 }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + /* This will modify how often it should draw, changing it will probably suck */ + { "-trail", ".trail", XrmoptionNoArg, "True" }, + /* Control whether or not you want the old circles to be erased */ + { "-color_modifier", ".color_modifier", XrmoptionSepArg, 0 }, + /* How many colors away from the current should the next whirly be? */ + { "-start_time", ".start_time", XrmoptionSepArg, 0 }, + /* Specify exactly at what time to start graphing... */ + { "-xoffset", ".xoffset", XrmoptionSepArg, 0 }, + /* Tell the whirlies to be offset by this factor of a sin */ + { "-yoffset", ".yoffset", XrmoptionSepArg, 0 }, + /* Tell the whirlies to be offset by this factor of a cos */ + { "-offset_period", ".offset_period", XrmoptionSepArg, 0 }, + /* Change the period of an offset cycle */ + { "-explain", ".explain", XrmoptionNoArg, "True" }, + /* Specify whether or not to print an explanation of the function used. */ + { "-wrap", ".wrap", XrmoptionNoArg, "True" }, + { "-no-wrap", ".wrap", XrmoptionNoArg, "False" }, + /* Specify if you want whirlies which are out of the boundary of the screen to be + wrapped around to the other side */ + { "-db", ".doubleBuffer", XrmoptionNoArg, "True" }, + { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Whirlygig", whirlygig) diff --git a/non-wgl/whirlygig.vcproj b/non-wgl/whirlygig.vcproj new file mode 100644 index 0000000..42a13b9 --- /dev/null +++ b/non-wgl/whirlygig.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/worm.c b/non-wgl/worm.c new file mode 100644 index 0000000..7097869 --- /dev/null +++ b/non-wgl/worm.c @@ -0,0 +1,456 @@ + +/* -*- Mode: C; tab-width: 4 -*- */ +/* worm --- draw wiggly worms */ + +#if 0 +static const char sccsid[] = "@(#)worm.c 4.04 97/07/28 xlockmore"; +#endif + +/*- + * Copyright (c) 1991 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. + * + * Revision History: + * 10-May-97: Compatible with xscreensaver + * 03-Sep-96: fixed bug in allocation of space for worms, added 3d support + * Henrik Theiling + * 27-Sep-95: put back malloc + * 23-Sep-93: got rid of "rint". (David Bagley) + * 27-Sep-91: got rid of all malloc calls since there were no calls to free(). + * 25-Sep-91: Integrated into X11R5 contrib xlock. + * + * Adapted from a concept in the Dec 87 issue of Scientific American p. 142. + * + * SunView version: Brad Taylor + * X11 version: Dave Lemke + * xlock version: Boris Putanec + */ + +#define STANDALONE +#define NOARGS + +#define DELAY 17000 +#define COUNT -20 +#define CYCLES 10 +#define SIZE_ -3 +#define NCOLORS 150 +#undef MI_WIN_IS_USE3D +#define MI_WIN_IS_USE3D(mi) False +#undef MI_DELTA3D +#define MI_DELTA3D(mi) 1.5 + +# define DEFAULTS "*delay: 17000 \n" \ + "*count: -20 \n" \ + "*cycles: 10 \n" \ + "*size: -3 \n" \ + "*ncolors: 150 \n" \ + "*use3d: False \n" \ + "*delta3d: 1.5 \n" \ + "*right3d: red \n" \ + "*left3d: blue \n" \ + "*both3d: magenta \n" \ + "*none3d: black \n" \ + "*fpsSolid: true \n" \ + +# define SMOOTH_COLORS +# define reshape_worm 0 +# define worm_handle_event 0 + +#ifdef STANDALONE +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +ENTRYPOINT ModeSpecOpt worm_opts = +{0, NULL, 0, NULL, NULL}; + +#define MINSIZE 1 + +#define SEGMENTS 36 +#define MINWORMS 1 + +#define MAXZ 750 +#define MINZ 100 +#define SCREENZ 200 +#define GETZDIFF(z) (MI_DELTA3D(mi)*20.0*(1.0-(SCREENZ)/((float)(z)+MINZ))) +#define IRINT(x) ((int)(((x)>0.0)?(x)+0.5:(x)-0.5)) + +/* How many segments to draw per cycle when redrawing */ +#define REDRAWSTEP 3 + +typedef struct { + XPoint *circ; + int *diffcirc; + int dir, dir2; + int tail; + int x, y, z; + int redrawing, redrawpos; +} wormstuff; + +typedef struct { + int xsize, ysize, zsize; + int wormlength; + int nc; + int nw; + int circsize; + wormstuff *worm; + XRectangle *rects; /* [NUMCOLORS * batchcount/NUMCOLORS+1] */ + int maxsize; + int *size; + unsigned int chromo; +} wormstruct; + +static float sintab[SEGMENTS]; +static float costab[SEGMENTS]; +static int init_table = 0; + +static wormstruct *worms = NULL; + +static void +worm_doit(ModeInfo * mi, int which, unsigned long color) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + wormstruct *wp = &worms[MI_SCREEN(mi)]; + wormstuff *ws = &wp->worm[which]; + int x, y, z; + int diff; + + ws->tail++; + if (ws->tail == wp->wormlength) + ws->tail = 0; + + x = ws->circ[ws->tail].x; + y = ws->circ[ws->tail].y; + + if (MI_WIN_IS_USE3D(mi)) { + diff = ws->diffcirc[ws->tail]; + if (MI_WIN_IS_INSTALL(mi)) { + XSetForeground(display, gc, MI_NONE_COLOR(mi)); + XFillRectangle(display, window, gc, x - diff, y, + wp->circsize, wp->circsize); + XFillRectangle(display, window, gc, x + diff, y, + wp->circsize, wp->circsize); + } else { + XClearArea(display, window, x - diff, y, + wp->circsize, wp->circsize, False); + XClearArea(display, window, x + diff, y, + wp->circsize, wp->circsize, False); + } + } else + XClearArea(display, window, x, y, wp->circsize, wp->circsize, False); + + if (LRAND() & 1) + ws->dir = (ws->dir + 1) % SEGMENTS; + else + ws->dir = (ws->dir + SEGMENTS - 1) % SEGMENTS; + + x = (ws->x + IRINT((float) wp->circsize * costab[ws->dir]) + + wp->xsize) % wp->xsize; + y = (ws->y + IRINT((float) wp->circsize * sintab[ws->dir]) + + wp->ysize) % wp->ysize; + + ws->circ[ws->tail].x = x; + ws->circ[ws->tail].y = y; + ws->x = x; + ws->y = y; + + if (MI_WIN_IS_USE3D(mi)) { + if (LRAND() & 1) + ws->dir2 = (ws->dir2 + 1) % SEGMENTS; + else + ws->dir2 = (ws->dir2 + SEGMENTS - 1) % SEGMENTS; + /* for the z-axis the wrap-around looks bad, so worms should just turn around. */ + z = (int) (ws->z + wp->circsize * sintab[ws->dir2]); + if (z < 0 || z >= wp->zsize) + z = (int) (ws->z - wp->circsize * sintab[ws->dir2]); + + diff = (int) (GETZDIFF(z) + 0.5); /* ROUND */ + ws->diffcirc[ws->tail] = diff; + + ws->z = z; + + /* right eye */ + color = 0; + wp->rects[color * wp->maxsize + wp->size[color]].x = x + diff; + wp->rects[color * wp->maxsize + wp->size[color]].y = y; + wp->size[color]++; + + /* left eye */ + color = 1; + wp->rects[color * wp->maxsize + wp->size[color]].x = x - diff; + wp->rects[color * wp->maxsize + wp->size[color]].y = y; + wp->size[color]++; + +#if 0 + if (ws->redrawing) { /* Too hard for now */ + int j; + + for (j = 0; j < REDRAWSTEP; j++) { + int k = (ws->tail - ws->redrawpos + wp->wormlength) + % wp->wormlength; + + color = 0; + wp->rects[color * wp->maxsize + wp->size[color]].x = + ws->circ[k].x + ws->diffcirc[k]; + wp->rects[color * wp->maxsize + wp->size[color]].y = + ws->circ[k].y; + wp->size[color]++; + + color = 1; + wp->rects[color * wp->maxsize + wp->size[color]].x = + ws->circ[k].x - ws->diffcirc[k]; + wp->rects[color * wp->maxsize + wp->size[color]].y = + ws->circ[k].y; + wp->size[color]++; + + if (++(ws->redrawpos) >= wp->wormlength) { + ws->redrawing = 0; + break; + } + } + } +#endif + + } else { + + wp->rects[color * wp->maxsize + wp->size[color]].x = x; + wp->rects[color * wp->maxsize + wp->size[color]].y = y; + wp->size[color]++; + if (ws->redrawing) { + int j; + + ws->redrawpos++; + /* Compensates for the changed ws->tail + since the last callback. */ + + for (j = 0; j < REDRAWSTEP; j++) { + int k = (ws->tail - ws->redrawpos + wp->wormlength) + % wp->wormlength; + + wp->rects[color * wp->maxsize + wp->size[color]].x = ws->circ[k].x; + wp->rects[color * wp->maxsize + wp->size[color]].y = ws->circ[k].y; + wp->size[color]++; + + if (++(ws->redrawpos) >= wp->wormlength) { + ws->redrawing = 0; + break; + } + } + } + } +} + +static void +free_worms(wormstruct * wp) +{ + int wn; + + if (wp->worm) { + for (wn = 0; wn < wp->nw; wn++) { + if (wp->worm[wn].circ) + (void) free((void *) wp->worm[wn].circ); + if (wp->worm[wn].diffcirc) + (void) free((void *) wp->worm[wn].diffcirc); + } + (void) free((void *) wp->worm); + wp->worm = NULL; + } + if (wp->rects) { + (void) free((void *) wp->rects); + wp->rects = NULL; + } + if (wp->size) { + (void) free((void *) wp->size); + wp->size = NULL; + } +} + +ENTRYPOINT void +init_worm (ModeInfo * mi) +{ + wormstruct *wp; + int size = MI_SIZE(mi); + int i, j; + + if (worms == NULL) { + if ((worms = (wormstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (wormstruct))) == NULL) + return; + } + wp = &worms[MI_SCREEN(mi)]; + if (MI_NPIXELS(mi) <= 2 || MI_WIN_IS_USE3D(mi)) + wp->nc = 2; + else + wp->nc = MI_NPIXELS(mi); + if (wp->nc > NUMCOLORS) + wp->nc = NUMCOLORS; + + free_worms(wp); + wp->nw = MI_BATCHCOUNT(mi); + if (wp->nw < -MINWORMS) + wp->nw = NRAND(-wp->nw - MINWORMS + 1) + MINWORMS; + else if (wp->nw < MINWORMS) + wp->nw = MINWORMS; + if (!wp->worm) + wp->worm = (wormstuff *) malloc(wp->nw * sizeof (wormstuff)); + + if (!wp->size) + wp->size = (int *) malloc(NUMCOLORS * sizeof (int)); + + wp->maxsize = (REDRAWSTEP + 1) * wp->nw; /* / wp->nc + 1; */ + if (!wp->rects) + wp->rects = + (XRectangle *) malloc(wp->maxsize * NUMCOLORS * sizeof (XRectangle)); + + + if (!init_table) { + init_table = 1; + for (i = 0; i < SEGMENTS; i++) { + sintab[i] = SINF(i * 2.0 * M_PI / SEGMENTS); + costab[i] = COSF(i * 2.0 * M_PI / SEGMENTS); + } + } + wp->xsize = MI_WIN_WIDTH(mi); + wp->ysize = MI_WIN_HEIGHT(mi); + wp->zsize = MAXZ - MINZ + 1; + if (MI_NPIXELS(mi) > 2) + wp->chromo = NRAND(MI_NPIXELS(mi)); + + if (size < -MINSIZE) + wp->circsize = NRAND(-size - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) + wp->circsize = MINSIZE; + else + wp->circsize = size; + + for (i = 0; i < wp->nc; i++) { + for (j = 0; j < wp->maxsize; j++) { + wp->rects[i * wp->maxsize + j].width = wp->circsize; + wp->rects[i * wp->maxsize + j].height = wp->circsize; + + } + } + (void) memset((char *) wp->size, 0, wp->nc * sizeof (int)); + + wp->wormlength = (int) sqrt(wp->xsize + wp->ysize) * + MI_CYCLES(mi) / 8; /* Fudge this to something reasonable */ + for (i = 0; i < wp->nw; i++) { + wp->worm[i].circ = (XPoint *) malloc(wp->wormlength * sizeof (XPoint)); + wp->worm[i].diffcirc = (int *) malloc(wp->wormlength * sizeof (int)); + + for (j = 0; j < wp->wormlength; j++) { + wp->worm[i].circ[j].x = wp->xsize / 2; + wp->worm[i].circ[j].y = wp->ysize / 2; + if (MI_WIN_IS_USE3D(mi)) + wp->worm[i].diffcirc[j] = 0; + } + wp->worm[i].dir = NRAND(SEGMENTS); + wp->worm[i].dir2 = NRAND(SEGMENTS); + wp->worm[i].tail = 0; + wp->worm[i].x = wp->xsize / 2; + wp->worm[i].y = wp->ysize / 2; + wp->worm[i].z = SCREENZ - MINZ; + wp->worm[i].redrawing = 0; + } + + 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, wp->xsize, wp->ysize); + } else + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); +} + +ENTRYPOINT void +draw_worm (ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + wormstruct *wp = &worms[MI_SCREEN(mi)]; + unsigned long wcolor; + int i; + + (void) memset((char *) wp->size, 0, wp->nc * sizeof (int)); + + for (i = 0; i < wp->nw; i++) { + if (MI_NPIXELS(mi) > 2) { + wcolor = (i + wp->chromo) % wp->nc; + + worm_doit(mi, i, wcolor); + } else + worm_doit(mi, i, (unsigned long) 0); + } + + if (MI_WIN_IS_USE3D(mi)) { + if (MI_WIN_IS_INSTALL(mi)) + XSetFunction(display, gc, GXor); + XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); + XFillRectangles(display, window, gc, &(wp->rects[0]), wp->size[0]); + + XSetForeground(display, gc, MI_LEFT_COLOR(mi)); + XFillRectangles(display, window, gc, &(wp->rects[wp->maxsize]), wp->size[1]); + if (MI_WIN_IS_INSTALL(mi)) + XSetFunction(display, gc, GXcopy); + } else if (MI_NPIXELS(mi) > 2) { + for (i = 0; i < wp->nc; i++) { + XSetForeground(display, gc, MI_PIXEL(mi, i)); + XFillRectangles(display, window, gc, &(wp->rects[i * wp->maxsize]), wp->size[i]); + } + } else { + XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi)); + XFillRectangles(display, window, gc, + &(wp->rects[0]), wp->size[0]); + } + + if (++wp->chromo == (unsigned long) wp->nc) + wp->chromo = 0; +} + +ENTRYPOINT void +release_worm(ModeInfo * mi) +{ + if (worms != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_worms(&worms[screen]); + (void) free((void *) worms); + worms = NULL; + } +} + +ENTRYPOINT void +refresh_worm (ModeInfo * mi) +{ + if (MI_WIN_IS_USE3D(mi)) + /* The 3D code does drawing&clearing by XORing. We do not + want to go to too much trouble here to make it redraw + correctly. */ + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); + else if (worms != NULL) { + wormstruct *wp = &worms[MI_SCREEN(mi)]; + int i; + + for (i = 0; i < wp->nw; i++) { + wp->worm[i].redrawing = 1; + wp->worm[i].redrawpos = 0; + } + } +} + +XSCREENSAVER_MODULE ("Worm", worm) diff --git a/non-wgl/worm.vcproj b/non-wgl/worm.vcproj new file mode 100644 index 0000000..c96a557 --- /dev/null +++ b/non-wgl/worm.vcproj @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/wormhole.c b/non-wgl/wormhole.c new file mode 100644 index 0000000..b08325b --- /dev/null +++ b/non-wgl/wormhole.c @@ -0,0 +1,744 @@ +/* xscreensaver, Copyright (c) 1992-2011 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. + */ + +/* wormhole: + * Animation of moving through a wormhole. Based on my own code written + * a few years ago. + * author: Jon Rafkind + * date: 1/19/04 + */ + +#include "screenhack.h" +#include + +#ifndef debug +#define debug printf("File:%s Line:%d\n", __FILE__, __LINE__ ); +#endif + +char *background = "Black"; +char *foreground = "#E9967A"; +int delay = 10000; +int zspeed = 10; +int stars = 20; + +static argtype vars[] = +{ + {&background, "background", NULL, "Black", t_String}, + {&foreground, "foreground", NULL, "#E9967A", t_String}, + {&delay, "delay", NULL, "10000", t_Int}, + {&zspeed, "zspeed", NULL, "10", t_Int}, + {&stars, "stars", NULL, "20", t_Int}, +}; + +typedef struct STAR{ + int x, y; + int calc_x, calc_y; + int Z; + int center_x, center_y; +} star; + +typedef struct STARLINE{ + star begin, end; +} starline; + +/* +typedef struct RGBHANDLE{ + XColor mine; + unsigned short rwant, gwant, bwant; +} RGBHandle; +*/ + +typedef struct COLORCHANGER{ + XColor * shade; + int min, max; + int shade_use; + int shade_max; + int min_want; + /* RGBHandle handle_begin, handle_end; */ +} color_changer; + +typedef struct WORMHOLE{ + int diameter; + int diameter_change; + int actualx, actualy; + double virtualx, virtualy; + double speed; + int ang; + int want_ang; + int want_x, want_y; + int max_Z; + int addStar; + int spiral; + color_changer changer; + starline ** stars; + int num_stars; /* top of array we are using */ + XColor black; + Pixmap work; +} wormhole; + +struct state { + Display *dpy; + Window window; + + int SCREEN_X, SCREEN_Y; + int z_speed; + int make_stars; + + int delay; + wormhole worm; + GC gc; + Colormap cmap; +}; + + +/*inline*/ static int rnd( int q ) +{ + if (q < 1) q = 1; + return random() % q; + +} + +static int gang( int x1, int y1, int x2, int y2 ) +{ + + int tang = 0; + if ( x1 == x2 ) { + if ( y1 < y2 ) + tang = 90; + else + tang = 270; + } else if ( y1 == y2 ) { + + if ( x1 < x2 ) + tang = 0; + else + tang = 180; + + } else { + tang = (int)(0.5+atan2( -(y2-y1), x2 - x1 ) * 180.0 / M_PI ); + } + + while ( tang < 0 ) + tang += 360; + return tang % 360; + +} + +static void blend_palette( XColor * pal, int max, XColor * sc, XColor * ec ) +{ + + int q; + + int sc_r = sc->red; + int sc_g = sc->green; + int sc_b = sc->blue; + + int ec_r = ec->red; + int ec_g = ec->green; + int ec_b = ec->blue; + + for ( q = 0; q < max; q++ ) { + float j = (float)( q ) / (float)( max ); + int f_r = (int)( 0.5 + (float)( sc_r ) + (float)( ec_r-sc_r ) * j ); + int f_g = (int)( 0.5 + (float)( sc_g ) + (float)( ec_g-sc_g ) * j ); + int f_b = (int)( 0.5 + (float)( sc_b ) + (float)( ec_b-sc_b ) * j ); + /* pal[q] = makecol( f_r, f_g, f_b ); */ + pal[q].red = f_r; + pal[q].blue = f_b; + pal[q].green = f_g; + } + +} + + +/* +static void initHandle( RGBHandle * handle ) +{ + + handle->mine.red = rnd( 65536 ); + handle->mine.green = rnd( 65536 ); + handle->mine.blue = rnd( 65536 ); + handle->rwant = rnd( 65536 ); + handle->gwant = rnd( 65536 ); + handle->bwant = rnd( 65536 ); + +} +*/ + +static void initXColor( XColor * color ) +{ + color->red = rnd( 50000 ) + 10000; + color->blue = rnd( 50000 ) + 10000; + color->green = rnd( 50000 ) + 10000; +} + +static void initColorChanger( struct state *st, color_changer * ch ) +{ + + int q; + XColor old_color, new_color; + + ch->shade_max = 2048; + ch->shade_use = 128; + ch->min = 0; + ch->max = ch->shade_use; + ch->min_want = rnd( ch->shade_max - ch->shade_use ); + ch->shade = (XColor *)malloc( sizeof(XColor) * ch->shade_max ); + memset( ch->shade, 0, sizeof(XColor) * ch->shade_max ); + + initXColor( &old_color ); + initXColor( &new_color ); + + for ( q = 0; q < ch->shade_max; q += ch->shade_use ){ + blend_palette( ch->shade + q, ch->shade_use, &old_color, &new_color ); + old_color = new_color; + + initXColor( &new_color ); + } + + for ( q = 0; q < ch->shade_max; q++ ) + XAllocColor( st->dpy, st->cmap, &( ch->shade[q] ) ); + + /* + initHandle( &(ch->handle_begin) ); + initHandle( &(ch->handle_end) ); + ch->shade = (XColor *)malloc( sizeof(XColor) * MAX_COLORS ); + ch->max = MAX_COLORS; + memset( ch->shade, 0, sizeof(XColor) * ch->max ); + + blend_palette( ch->shade, ch->max, &(ch->handle_begin.mine), &(ch->handle_end.mine) ); + for ( q = 0; q < ch->max; q++ ) + XAllocColor( st->dpy, *cmap, &( ch->shade[q] ) ); + */ + +} + +/* +static void changeColor( unsigned short * col, unsigned short * change, int min, int max ) +{ + int RGB_GO_BLACK = 30; + if ( *col < *change ) *col++; + if ( *col > *change ) *col--; + if ( *col == *change ){ + if ( rnd( RGB_GO_BLACK ) == rnd( RGB_GO_BLACK ) ) + *change = 0; + else *change = rnd(max-min) + min; + } +} +*/ + +/* +static void moveRGBHandle( RGBHandle * handle, int min, int max ) +{ + + unsigned short * want[ 3 ]; + int q; + int cy = 0; + want[0] = &(handle->rwant); + want[1] = &(handle->gwant); + want[2] = &(handle->bwant); + + for ( q = 0; q < 10; q++ ){ + changeColor( &( handle->mine.red ), &handle->rwant, min, max ); + changeColor( &( handle->mine.green ), &handle->gwant, min, max ); + changeColor( &( handle->mine.blue ), &handle->bwant, min, max ); + } + + for ( q = 0; q < 3; q++ ) + cy = cy || (*(want[q]) >= min && *(want[q]) <= max); + if ( !cy ) *(want[rnd(3)]) = rnd(max-min)+min; + cy = 1; + for ( q = 0; q < 3; q++ ) + cy = cy && *(want[q]) == 0; + if ( cy ) *(want[rnd(3)]) = rnd(max-min)+min; + + if ( rnd( 30 ) == rnd( 30 ) ) + *(want[rnd(3)]) = rnd(max-min)+min; + +} +*/ + +static void moveColorChanger( color_changer * ch ) +{ + + /* int q; */ + + if ( ch->min < ch->min_want ){ + ch->min++; + ch->max++; + } + if ( ch->min > ch->min_want ) { + ch->min--; + ch->max--; + } + if ( ch->min == ch->min_want ) + ch->min_want = rnd( ch->shade_max - ch->shade_use ); + + /* + for ( q = 0; q < ch->max; q++ ) + XFreeColors( st->dpy, *cmap, &( ch->shade[q].pixel ), 1, 0 ); + + moveRGBHandle( &( ch->handle_begin ), 5000, 65500 ); + moveRGBHandle( &( ch->handle_end ), 5000, 65500 ); + + blend_palette( ch->shade, ch->max, &(ch->handle_begin.mine), &(ch->handle_end.mine) ); + for ( q = 0; q < ch->max; q++ ) + XAllocColor( st->dpy, *cmap, &( ch->shade[q] ) ); + */ + +} + +#if 0 +static void destroyColorChanger( color_changer * ch ) +{ + int q; + for ( q = 0; q < ch->max; q++ ) + XFreeColors( st->dpy, *cmap, &( ch->shade[q].pixel ), 1, 0 ); + free( ch->shade ); +} +#endif + +static void resizeWormhole( struct state *st, wormhole * worm ) +{ + + XWindowAttributes attr; + + XGetWindowAttributes( st->dpy, st->window, &attr ); + + st->cmap = attr.colormap; + + st->SCREEN_X = attr.width; + st->SCREEN_Y = attr.height; + +# ifndef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + XFreePixmap( st->dpy, worm->work ); + worm->work = XCreatePixmap( st->dpy, st->window, st->SCREEN_X, st->SCREEN_Y, attr.depth ); +# endif + +} + +static void initWormhole( struct state *st, wormhole * worm, Display * display, Window win ) +{ + + int i; + XWindowAttributes attr; + + XGetWindowAttributes( st->dpy, st->window, &attr ); + + st->cmap = attr.colormap; + + st->SCREEN_X = attr.width; + st->SCREEN_Y = attr.height; + +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + worm->work = st->window; +# else + worm->work = XCreatePixmap( st->dpy, st->window, st->SCREEN_X, st->SCREEN_Y, attr.depth ); +# endif + + worm->diameter = rnd( 10 ) + 15; + worm->diameter_change = rnd( 10 ) + 15; + /* worm->actualx = rnd( attr.width ); + worm->actualy = rnd( attr.height ); */ + worm->actualx = attr.width / 2; + worm->actualy = attr.height / 2; + worm->virtualx = worm->actualx; + worm->virtualy = worm->actualy; + worm->speed = (float)st->SCREEN_X / 180.0; + /* z_speed = SCREEN_X / 120; */ + worm->spiral = 0; + worm->addStar = st->make_stars; + worm->want_x = rnd( attr.width - 50 ) + 25; + worm->want_y = rnd( attr.height - 50 ) + 25; + worm->want_ang = gang( worm->actualx, worm->actualy, worm->want_x, worm->want_y ); + worm->ang = worm->want_ang; + worm->max_Z = 600; + worm->black.red = 0; + worm->black.green = 0; + worm->black.blue = 0; + XAllocColor( st->dpy, st->cmap, &worm->black ); + initColorChanger( st, &(worm->changer) ); + + worm->num_stars = 64; + worm->stars = (starline **)malloc( sizeof(starline *) * worm->num_stars ); + for ( i = 0; i < worm->num_stars; i++ ) + worm->stars[i] = NULL; + +} + +#if 0 +static void destroyWormhole( wormhole * worm ) +{ + destroyColorChanger( &(worm->changer), st->dpy, cmap ); + if (work->work != st->window) + XFreePixmap( st->dpy, worm->work ); + free( worm->stars ); +} +#endif + +static double Cos( int a ) +{ + return cos( a * 180.0 / M_PI ); +} + +static double Sine( int a ) +{ + return sin( a * 180.0 / M_PI ); +} + + + +static void calcStar( star * st ) +{ + if ( st->center_x == 0 || st->center_y == 0 ){ + st->Z = 0; + return; + } + if ( st->Z <= 0 ){ + st->calc_x = (st->x << 10) / st->center_x; + st->calc_y = (st->y << 10) / st->center_y; + } else { + st->calc_x = (st->x << 10 ) / st->Z + st->center_x; + st->calc_y = (st->y << 10 ) / st->Z + st->center_y; + } +} + +static void initStar( star * st, int Z, int ang, wormhole * worm ) +{ + + st->x = Cos( ang ) * worm->diameter; + st->y = Sine( ang ) * worm->diameter; + st->center_x = worm->actualx; + st->center_y = worm->actualy; + st->Z = Z; + calcStar( st ); + +} + +static void addStar( wormhole * worm ) +{ + + starline * star_new; + starline ** xstars; + int old_stars; + int q; + int ang; + star_new = (starline *)malloc( sizeof( starline ) ); + ang = rnd( 360 ); + initStar( &star_new->begin, worm->max_Z, ang, worm ); + initStar( &star_new->end, worm->max_Z+rnd(6)+4, ang, worm ); + + for ( q = 0; q < worm->num_stars; q++ ){ + if ( worm->stars[q] == NULL ){ + worm->stars[q] = star_new; + return; + } + } + + old_stars = worm->num_stars; + worm->num_stars = worm->num_stars << 1; + xstars = (starline **)malloc( sizeof(starline *) * worm->num_stars ); + for ( q = 0; q < worm->num_stars; q++ ) + xstars[q] = NULL; + + for ( q = 0; q < old_stars; q++ ) + if ( worm->stars[q] != NULL ) xstars[q] = worm->stars[q]; + free( worm->stars ); + worm->stars = xstars; + + worm->stars[ old_stars ] = star_new; + +} + +static int moveStar( struct state *st, starline * stl ) +{ + + stl->begin.Z -= st->z_speed; + stl->end.Z -= st->z_speed; + + calcStar( &stl->begin ); + calcStar( &stl->end ); + + return ( stl->begin.Z <= 0 || stl->end.Z <= 0 ); + +} + +static int dist( int x1, int y1, int x2, int y2 ) +{ + int xs, ys; + xs = x1-x2; + ys = y1-y2; + return (int)sqrt( xs*xs + ys*ys ); +} + +static void moveWormhole( struct state *st, wormhole * worm ) +{ + + int q; + double dx, dy; + /* int x1, y1, x2, y2; */ + int min_dist = 100; + int find = 0; + dx = Cos( worm->ang ) * worm->speed; + dy = Sine( worm->ang ) * worm->speed; + + worm->virtualx += dx; + worm->virtualy += dy; + worm->actualx = (int)worm->virtualx; + worm->actualy = (int)worm->virtualy; + + if ( worm->spiral ){ + + if ( worm->spiral % 5 == 0 ) + worm->ang = (worm->ang + 1 ) % 360; + worm->spiral--; + if ( worm->spiral <= 0 ) find = 1; + + } else { + + if ( dist( worm->actualx, worm->actualy, worm->want_x, worm->want_y ) < 20 ) + find = 1; + + if ( rnd( 20 ) == rnd( 20 ) ) + find = 1; + + if ( worm->actualx < min_dist ){ + worm->actualx = min_dist; + worm->virtualx = worm->actualx; + find = 1; + } + if ( worm->actualy < min_dist ){ + worm->actualy = min_dist; + worm->virtualy = worm->actualy; + find = 1; + } + if ( worm->actualx > st->SCREEN_X - min_dist ){ + worm->actualx = st->SCREEN_X - min_dist; + worm->virtualx = worm->actualx; + find = 1; + } + if ( worm->actualy > st->SCREEN_Y - min_dist ){ + worm->actualy = st->SCREEN_Y - min_dist; + worm->virtualy = worm->actualy; + find = 1; + } + + if ( rnd( 500 ) == rnd( 500 ) ) worm->spiral = rnd( 30 ) + 50; + } + + if ( find ){ + worm->want_x = rnd( st->SCREEN_X - min_dist * 2 ) + min_dist; + worm->want_y = rnd( st->SCREEN_Y - min_dist * 2 ) + min_dist; + worm->ang = gang( worm->actualx, worm->actualy, worm->want_x, worm->want_y ); + } + + + /* worm->ang = ( worm->ang + 360 + rnd( 30 ) - 15 ) % 360; */ + + /* + if ( worm->ang < worm->want_ang ) worm->ang++; + if ( worm->ang > worm->want_ang ) worm->ang--; + if ( worm->ang == worm->want_ang && rnd( 3 ) == rnd( 3 ) ) worm->want_ang = rnd( 360 ); + */ + + /* + if ( rnd( 25 ) == rnd( 25 ) ){ + x1 = worm->actualx; + y1 = worm->actualy; + x2 = SCREEN_X / 2 + rnd( 20 ) - 10; + y2 = SCREEN_Y / 2 + rnd( 20 ) - 10; + worm->want_ang = gang(x1,y1,x2,y2); + } + */ + + /* + if ( worm->actualx < min_dist || worm->actualx > SCREEN_X - min_dist || worm->actualy < min_dist || worm->actualy > SCREEN_Y - min_dist ){ + x1 = worm->actualx; + y1 = worm->actualy; + x2 = SCREEN_X / 2 + rnd( 20 ) - 10; + y2 = SCREEN_Y / 2 + rnd( 20 ) - 10; + / * worm->ang = gang( worm->actualx, worm->actualy, SCREEN_X/2+rnd(20)-10, SCREEN_Y/2+rnd(20)-10 ); * / + worm->ang = gang( x1, y1, x2, y2 ); + worm->want_ang = worm->ang; + / * printf("Angle = %d\n", worm->ang ); * / + + if ( worm->actualx < min_dist ) + worm->actualx = min_dist; + if ( worm->actualx > SCREEN_X - min_dist ) + worm->actualx = SCREEN_X - min_dist; + if ( worm->actualy < min_dist ) + worm->actualy = min_dist; + if ( worm->actualy > SCREEN_Y - min_dist ) + worm->actualy = SCREEN_Y - min_dist; + worm->virtualx = worm->actualx; + worm->virtualy = worm->actualy; + } + */ + + for ( q = 0; q < worm->num_stars; q++ ){ + if ( worm->stars[q] != NULL ){ + if ( moveStar( st, worm->stars[q] ) ){ + free( worm->stars[q] ); + worm->stars[q] = NULL; + } + } + } + + moveColorChanger( &worm->changer ); + + if ( worm->diameter < worm->diameter_change ) + worm->diameter++; + if ( worm->diameter > worm->diameter_change ) + worm->diameter--; + if ( rnd( 30 ) == rnd( 30 ) ) + worm->diameter_change = rnd( 35 ) + 5; + + for ( q = 0; q < worm->addStar; q++ ) + addStar( worm ); + +} + +static XColor * getColorShade( color_changer * ch ) +{ + return ch->shade + ch->min; +} + +static void drawWormhole( struct state *st, wormhole * worm ) +{ + + int i; + int color; + int z; + starline * current; + XColor * xcol; + XColor * shade; + + XSetForeground( st->dpy, st->gc, worm->black.pixel ); + XFillRectangle( st->dpy, worm->work, st->gc, 0, 0, st->SCREEN_X, st->SCREEN_Y ); + + for ( i = 0; i < worm->num_stars; i++ ) + if ( worm->stars[i] != NULL ){ + + current = worm->stars[i]; + z = current->begin.Z; + + color = z * worm->changer.shade_use / worm->max_Z; + shade = getColorShade( &worm->changer ); + /* xcol = &worm->changer.shade[ color ]; */ + xcol = &shade[ color ]; + + XSetForeground( st->dpy, st->gc, xcol->pixel ); + /* XDrawLine( st->dpy, st->window, *gc, current->begin.calc_x, current->begin.calc_y, current->end.calc_x, current->end.calc_y ); */ + XDrawLine( st->dpy, worm->work, st->gc, current->begin.calc_x, current->begin.calc_y, current->end.calc_x, current->end.calc_y ); + + } + if (worm->work != st->window) + XCopyArea( st->dpy, worm->work, st->window, st->gc, 0, 0, st->SCREEN_X, st->SCREEN_Y, 0, 0 ); +} + +/* +static void eraseWormhole( Display * display, Window * st->window, wormhole * worm ){ + starline * current; + int i; + XColor * xcol; + for ( i = 0; i < worm->num_stars; i++ ) + if ( worm->stars[i] != NULL ){ + xcol = &worm->black; + current = worm->stars[i]; + XSetForeground( st->dpy, *gc, xcol->pixel ); + XDrawLine( st->dpy, st->window, *gc, current->begin.calc_x, current->begin.calc_y, current->end.calc_x, current->end.calc_y ); + } +} +*/ + + + +static void * +wormhole_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes attr; + + st->dpy = dpy; + st->window = window; + //st->delay = get_integer_resource(st->dpy, "delay", "Integer" ); + //st->make_stars = get_integer_resource(st->dpy, "stars", "Integer" ); + //st->z_speed = get_integer_resource(st->dpy, "zspeed", "Integer" ); + st->delay = delay; + st->make_stars = stars; + st->z_speed = zspeed; + + initWormhole( st, &st->worm, st->dpy, st->window ); + + st->gc = XCreateGC( st->dpy, st->window, 0, &gcv ); + XGetWindowAttributes( st->dpy, st->window, &attr ); + st->cmap = attr.colormap; + + return st; +} + +static unsigned long +wormhole_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + moveWormhole( st, &st->worm ); + drawWormhole( st, &st->worm ); + return st->delay; +} + +static void +wormhole_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + resizeWormhole( st, &st->worm ); +} + +#if 0 + static Bool + wormhole_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +wormhole_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + + +static const char *wormhole_defaults [] = { + ".background: Black", + ".foreground: #E9967A", + "*delay: 10000", + "*zspeed: 10", + "*stars: 20", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec wormhole_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-zspeed", ".zspeed", XrmoptionSepArg, 0 }, + { "-stars", ".stars", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Wormhole", wormhole) diff --git a/non-wgl/wormhole.vcproj b/non-wgl/wormhole.vcproj new file mode 100644 index 0000000..1506b93 --- /dev/null +++ b/non-wgl/wormhole.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/xdbe.c b/non-wgl/xdbe.c new file mode 100644 index 0000000..fc04175 --- /dev/null +++ b/non-wgl/xdbe.c @@ -0,0 +1,20 @@ +#include "screenhack.h" +#include "xdbe.h" + +static Pixmap pixmap = NULL; + +XdbeBackBuffer +xdbe_get_backbuffer(Display *dpy, Window window, XdbeSwapAction action) +{ + pixmap = XCreatePixmap(dpy, window, ss.width, ss.height, 32); + return pixmap; +} + +void XdbeSwapBuffers(Display *dpy, XdbeSwapInfo *info, int count) +{ + HDC hdc = CreateCompatibleDC(dpy); + HGDIOBJ hbmOld = SelectObject(hdc, pixmap->hbm); + BitBlt(dpy, 0, 0, ss.width, ss.height, hdc, 0, 0, SRCCOPY); + SelectObject(hdc, hbmOld); + DeleteDC(hdc); +} diff --git a/non-wgl/xdbe.h b/non-wgl/xdbe.h new file mode 100644 index 0000000..fb5154e --- /dev/null +++ b/non-wgl/xdbe.h @@ -0,0 +1,17 @@ +typedef Pixmap XdbeBackBuffer; + +typedef enum +{ + XdbeUndefined, XdbeBackground +} XdbeSwapAction; + +typedef struct +{ + Window swap_window; + XdbeSwapAction swap_action; +} XdbeSwapInfo; + +XdbeBackBuffer +xdbe_get_backbuffer(Display *dpy, Window window, XdbeSwapAction action); + +void XdbeSwapBuffers(Display *dpy, XdbeSwapInfo *info, int count); diff --git a/non-wgl/xpm-pixmap.c b/non-wgl/xpm-pixmap.c new file mode 100644 index 0000000..6698d85 --- /dev/null +++ b/non-wgl/xpm-pixmap.c @@ -0,0 +1,368 @@ +/* xpm-pixmap.c --- converts XPM data to a Pixmap. + * xscreensaver, Copyright (c) 1998-2006 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. + */ + +#if 0 + #ifdef HAVE_CONFIG_H + # include "config.h" + #endif +#endif + +#include "xws2win.h" +#include +#include + +#if 0 + #ifdef HAVE_COCOA + # include "jwxyz.h" + #else + # include + # include + # include "visual.h" /* for screen_number() */ + #endif +#endif + +#include "xpm-pixmap.h" + +extern char *progname; + +#if defined(HAVE_GDK_PIXBUF) + +# include + +# ifdef HAVE_GTK2 +# include +# else /* !HAVE_GTK2 */ +# include +# endif /* !HAVE_GTK2 */ + + +/* Returns a Pixmap structure containing the bits of the given XPM image. + This is the gdk_pixbuf version of this function. + */ +static Pixmap +xpm_to_pixmap_1 (Display *dpy, Window window, + int *width_ret, int *height_ret, + Pixmap *mask_ret, + const char *filename, + /*const*/ char * const *xpm_data) +{ + GdkPixbuf *pb; + static int initted = 0; + XWindowAttributes xgwa; +#ifdef HAVE_GTK2 + GError *gerr = NULL; +#endif /* HAVE_GTK2 */ + XGetWindowAttributes (dpy, window, &xgwa); + + if (!initted) + { +#ifdef HAVE_GTK2 + g_type_init (); +#endif /* HAVE_GTK2 */ + gdk_pixbuf_xlib_init (dpy, screen_number (xgwa.screen)); + xlib_rgb_init (dpy, xgwa.screen); + initted = 1; + } + + pb = (filename +#ifdef HAVE_GTK2 + ? gdk_pixbuf_new_from_file (filename, &gerr) +#else /* !HAVE_GTK2 */ + ? gdk_pixbuf_new_from_file (filename) +#endif /* !HAVE_GTK2 */ + : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data)); + if (pb) + { + int w = gdk_pixbuf_get_width (pb); + int h = gdk_pixbuf_get_height (pb); + Pixmap pixmap = 0; + + /* #### Note that this always uses the default colormap! Morons! + Owen says that in Gnome 2.0, I should try using + gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead. + But I don't have Gnome 2.0 yet. + */ + gdk_pixbuf_xlib_render_pixmap_and_mask (pb, &pixmap, mask_ret, 128); + + if (!pixmap) + { + fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h); + exit (-1); + } + /* gdk_pixbuf_unref (pb); -- #### does doing this free colors? */ + + if (width_ret) *width_ret = w; + if (height_ret) *height_ret = h; + + return pixmap; + } + else if (filename) + { +#ifdef HAVE_GTK2 + fprintf (stderr, "%s: %s\n", progname, gerr->message); + g_error_free (gerr); +#else /* !HAVE_GTK2 */ + fprintf (stderr, "%s: unable to load %s\n", progname, filename); +#endif /* !HAVE_GTK2 */ + exit (-1); + } + else + { + fprintf (stderr, "%s: unable to initialize built-in images\n", progname); + exit (-1); + } +} + + +#elif defined(HAVE_XPM) + +#include +#include + +#ifdef HAVE_XMU +# ifndef VMS +# include +#else /* VMS */ +# include +# endif /* VMS */ +#endif + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + + +static int +handle_xpm_error (const char *filename, int status) +{ + if (!filename) filename = "builtin"; + switch (status) + { + case XpmSuccess: + return 0; + break; + case XpmColorError: + fprintf (stderr, "%s: %s: warning: color substitution performed\n", + progname, filename); + return 0; + break; + case XpmFileInvalid: + return 1; + break; + case XpmOpenFailed: + fprintf (stderr, "%s: %s: no such file\n", progname, filename); + break; + case XpmNoMemory: + fprintf (stderr, "%s: %s: out of memory\n", progname, filename); + break; + case XpmColorFailed: + fprintf (stderr, "%s: %s: color allocation failed\n", + progname, filename); + break; + default: + fprintf (stderr, "%s: %s: unknown XPM error %d\n", progname, + filename, status); + break; + } + exit (-1); +} + + +/* The libxpm version of this function... + */ +static Pixmap +xpm_to_pixmap_1 (Display *dpy, Window window, + int *width_ret, int *height_ret, + Pixmap *mask_ret, + const char *filename, + /*const*/ char * const *xpm_data) +{ + Pixmap pixmap = 0; + XpmAttributes xpmattrs; + XpmImage xpm_image; + XpmInfo xpm_info; + int status; + XWindowAttributes xgwa; + XGetWindowAttributes (dpy, window, &xgwa); + + memset (&xpm_image, 0, sizeof(xpm_image)); + memset (&xpm_info, 0, sizeof(xpm_info)); + + if (filename) + { + xpm_data = 0; + status = XpmReadFileToData ((char *) filename, &xpm_data); + if (handle_xpm_error (filename, status)) + goto TRY_XBM; + } + + xpmattrs.valuemask = 0; + +# ifdef XpmCloseness + xpmattrs.valuemask |= XpmCloseness; + xpmattrs.closeness = 40000; +# endif +# ifdef XpmVisual + xpmattrs.valuemask |= XpmVisual; + xpmattrs.visual = xgwa.visual; +# endif +# ifdef XpmDepth + xpmattrs.valuemask |= XpmDepth; + xpmattrs.depth = xgwa.depth; +# endif +# ifdef XpmColormap + xpmattrs.valuemask |= XpmColormap; + xpmattrs.colormap = xgwa.colormap; +# endif + + status = XpmCreatePixmapFromData (dpy, window, xpm_data, + &pixmap, mask_ret, &xpmattrs); + if (handle_xpm_error (filename, status)) + pixmap = 0; + else + { + if (width_ret) *width_ret = xpmattrs.width; + if (height_ret) *height_ret = xpmattrs.height; + } + + TRY_XBM: + +#ifdef HAVE_XMU + if (! pixmap) + { + unsigned long fg = BlackPixelOfScreen (xgwa.screen); + unsigned long bg = WhitePixelOfScreen (xgwa.screen); + int xh, yh; + Pixmap b2; + pixmap = XmuLocateBitmapFile (xgwa.screen, filename, + 0, 0, width_ret, height_ret, &xh, &yh); + if (! pixmap) + { + fprintf (stderr, "%s: couldn't find XBM %s\n", progname, + filename); + exit (-1); + } + b2 = XmuCreatePixmapFromBitmap (dpy, window, pixmap, + *width_ret, *height_ret, + xgwa.depth, fg, bg); + XFreePixmap (dpy, pixmap); + pixmap = b2; + + if (!pixmap) + { + fprintf (stderr, "%s: couldn't load XBM %s\n", progname, filename); + exit (-1); + } + } +#else /* !XMU */ + { + fprintf (stderr, + "%s: your vendor doesn't ship the standard Xmu library.\n", + progname); + fprintf (stderr, "\tWe can't load XBM files without it.\n"); + exit (-1); + } +#endif /* !XMU */ + + return pixmap; +} + +#else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */ + +/* If we don't have libXPM or Pixbuf, then use "minixpm". + This can read XPM data from memory, but can't read files. + */ + +#include "minixpm.h" + +static Pixmap +xpm_to_pixmap_1 (Display *dpy, Window window, + int *width_ret, int *height_ret, + Pixmap *mask_ret, + const char *filename, + /*const*/ char * const *xpm_data) +{ + XWindowAttributes xgwa; + XImage *ximage; + Pixmap pixmap, p2 = 0; + int iw, ih, npixels; + unsigned long *pixels = 0; + unsigned char *mask = 0; + XGCValues gcv; + GC gc; + + if (filename) + { + fprintf(stderr, + "%s: no files: not compiled with XPM or Pixbuf support.\n", + progname); + exit (1); + } + + if (! xpm_data) abort(); + + XGetWindowAttributes (dpy, window, &xgwa); + ximage = minixpm_to_ximage (dpy, xgwa.visual, xgwa.colormap, xgwa.depth, + BlackPixelOfScreen (xgwa.screen), + (const char * const *) + xpm_data, &iw, &ih, &pixels, &npixels, + (mask_ret ? &mask : 0)); + if (pixels) free (pixels); + + pixmap = XCreatePixmap (dpy, window, iw, ih, xgwa.depth); + gc = XCreateGC (dpy, pixmap, 0, &gcv); + XPutImage (dpy, pixmap, gc, ximage, 0, 0, 0, 0, iw, ih); + XFreeGC (dpy, gc); + XDestroyImage (ximage); + + if (mask) + { + p2 = XCreatePixmap (dpy, window, iw, ih, 1); + gcv.foreground = 1; + gcv.background = 0; + gc = XCreateGC (dpy, p2, GCForeground|GCBackground, &gcv); + ximage = XCreateImage (dpy, xgwa.visual, 1, XYBitmap, 0, (char *) mask, + iw, ih, 8, 0); + ximage->byte_order = ximage->bitmap_bit_order = LSBFirst; + if (!ximage) abort(); + XPutImage (dpy, p2, gc, ximage, 0, 0, 0, 0, iw, ih); + XFreeGC (dpy, gc); + XDestroyImage (ximage); + } + + if (width_ret) *width_ret = iw; + if (height_ret) *height_ret = ih; + if (mask_ret) *mask_ret = p2; + return pixmap; +} + +#endif /* minixpm */ + + +Pixmap +xpm_data_to_pixmap (Display *dpy, Window window, + /*const*/ char * const *xpm_data, + int *width_ret, int *height_ret, + Pixmap *mask_ret) +{ + return xpm_to_pixmap_1 (dpy, window, width_ret, height_ret, mask_ret, + 0, xpm_data); +} + + +Pixmap +xpm_file_to_pixmap (Display *dpy, Window window, const char *filename, + int *width_ret, int *height_ret, + Pixmap *mask_ret) +{ + return xpm_to_pixmap_1 (dpy, window, width_ret, height_ret, mask_ret, + filename, 0); +} diff --git a/non-wgl/xpm-pixmap.h b/non-wgl/xpm-pixmap.h new file mode 100644 index 0000000..7b6e133 --- /dev/null +++ b/non-wgl/xpm-pixmap.h @@ -0,0 +1,26 @@ +/* xpm-pixmap.h --- converts XPM data to Pixmaps. + * xscreensaver, Copyright (c) 1998-2006 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. + */ + +#ifndef _XPM_PIXMAP_H_ +#define _XPM_PIXMAP_H_ + +/* Returns a Pixmap structure containing the bits of the given XPM image. + */ +extern Pixmap xpm_data_to_pixmap (Display *, Window, + /*const*/ char * const *xpm_data, + int *width_ret, int *height_ret, + Pixmap *mask_ret); +extern Pixmap xpm_file_to_pixmap (Display *, Window, const char *filename, + int *width_ret, int *height_ret, + Pixmap *mask_ret); + +#endif /* _XPM_PIXMAP_H_ */ diff --git a/non-wgl/xrayswarm.c b/non-wgl/xrayswarm.c new file mode 100644 index 0000000..5757af9 --- /dev/null +++ b/non-wgl/xrayswarm.c @@ -0,0 +1,1241 @@ +/* + * Copyright (c) 2000 by Chris Leger (xrayjones@users.sourceforge.net) + * + * xrayswarm - a shameless ripoff of the 'swarm' screensaver on SGI + * boxes. + * + * Version 1.0 - initial release. doesn't read any special command-line + * options, and only supports the variable 'delay' via Xresources. + * (the delay resouces is most useful on systems w/o gettimeofday, in + * which case automagical level-of-detail for FPS maintainance can't + * be used.) + * + * The code isn't commented, but isn't too ugly. It should be pretty + * easy to understand, with the exception of the colormap stuff. + * + */ +/* +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. +*/ + +#include "screenhack.h" +#include + +#if 0 + #ifdef HAVE_CONFIG_H + # include "config.h" + #endif + + #include + + #ifdef HAVE_COCOA + # define HAVE_GETTIMEOFDAY 1 + #endif +#endif + +/********************************************************************** + * + * window crap + * + **********************************************************************/ + +char *background = "black"; +char *foreground = "white"; +int delay = 20000; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "20000", t_Int}, +}; + +static const char *xrayswarm_defaults [] ={ + ".background: black", + "*delay: 20000", + "*fpsSolid: true", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec xrayswarm_options [] = { + {"-delay",".delay",XrmoptionSepArg,0}, + {0,0,0,0} +}; + + +/********************************************************************** + * + * bug structs & variables + * + **********************************************************************/ +#define MAX_TRAIL_LEN 60 +#define MAX_BUGS 100 +#define MAX_TARGETS 10 +#define sq(x) ((x)*(x)) + +#define MAX_FPS 150 +#define MIN_FPS 16 +#define DESIRED_DT 0.2 + +typedef struct _sbug { + float pos[3]; + int hist[MAX_TRAIL_LEN][2]; + float vel[2]; + struct _sbug *closest; +} bug; + +#define GRAY_TRAILS 0 +#define GRAY_SCHIZO 1 +#define COLOR_TRAILS 2 +#define RANDOM_TRAILS 3 +#define RANDOM_SCHIZO 4 +#define COLOR_SCHIZO 5 +#define NUM_SCHEMES 6 /* too many schizos; don't use last 2 */ + + + +struct state { + Display *dpy; + Window win; + + unsigned char colors[768]; + + GC fgc[256]; + GC cgc; + int xsize, ysize; + int xc, yc; + unsigned long delay; + float maxx, maxy; + + float dt; + float targetVel; + float targetAcc; + float maxVel; + float maxAcc; + float noise; + float minVelMultiplier; + + int nbugs; + int ntargets; + int trailLen; + + float dtInv; + float halfDtSq; + float targetVelSq; + float maxVelSq; + float minVelSq; + float minVel; + + bug bugs[MAX_BUGS]; + bug targets[MAX_TARGETS]; + int head; + int tail; + int colorScheme; + float changeProb; + + int grayIndex[MAX_TRAIL_LEN]; + int redIndex[MAX_TRAIL_LEN]; + int blueIndex[MAX_TRAIL_LEN]; + int graySIndex[MAX_TRAIL_LEN]; + int redSIndex[MAX_TRAIL_LEN]; + int blueSIndex[MAX_TRAIL_LEN]; + int randomIndex[MAX_TRAIL_LEN]; + int numColors; + int numRandomColors; + + int checkIndex; + int rsc_callDepth; + int rbc_callDepth; + + float draw_fps; + float draw_timePerFrame, draw_elapsed; + int *draw_targetColorIndex, *draw_colorIndex; + int draw_targetStartColor, draw_targetNumColors; + int draw_startColor, draw_numColors; + double draw_start, draw_end; + int draw_cnt; + int draw_sleepCount; + int draw_delayAccum; + int draw_nframes; + + struct timeval startupTime; +}; + + +typedef struct { + float dt; + float targetVel; + float targetAcc; + float maxVel; + float maxAcc; + float noise; + + int nbugs; + int ntargets; + int trailLen; + int colorScheme; + int changeProb; +} bugParams; + +#if 0 +static const bugParams good1 = { + 0.3, /* dt */ + 0.03, /* targetVel */ + 0.02, /* targetAcc */ + 0.05, /* maxVel */ + 0.03, /* maxAcc */ + 0.01, /* noise */ + -1, /* nbugs */ + -1, /* ntargets */ + 60, /* trailLen */ + 2, /* colorScheme */ + 0.15 /* changeProb */ +}; + +static const bugParams *goodParams[] = { +&good1 +}; + +static int numParamSets = 1; +#endif + +static void initCMap(struct state *st) +{ + int i, n; + int temp; + + n = 0; + + /* color 0 is black */ + st->colors[n++] = 0; + st->colors[n++] = 0; + st->colors[n++] = 0; + + /* color 1 is red */ + st->colors[n++] = 255; + st->colors[n++] = 0; + st->colors[n++] = 0; + + /* color 2 is green */ + st->colors[n++] = 255; + st->colors[n++] = 0; + st->colors[n++] = 0; + + /* color 3 is blue */ + st->colors[n++] = 255; + st->colors[n++] = 0; + st->colors[n++] = 0; + + /* start greyscale colors at 4; 16 levels */ + for (i = 0; i < 16; i++) { + temp = i*16; + if (temp > 255) temp = 255; + st->colors[n++] = 255 - temp; + st->colors[n++] = 255 - temp; + st->colors[n++] = 255 - temp; + } + + /* start red fade at 20; 16 levels */ + for (i = 0; i < 16; i++) { + temp = i*16; + if (temp > 255) temp = 255; + st->colors[n++] = 255 - temp; + st->colors[n++] = 255 - pow(i/16.0+0.001, 0.3)*255; + st->colors[n++] = 65 - temp/4; + } + + /* start blue fade at 36; 16 levels */ + for (i = 0; i < 16; i++) { + temp = i*16; + if (temp > 255) temp = 255; + st->colors[n++] = 32 - temp/8; + st->colors[n++] = 180 - pow(i/16.0+0.001, 0.3)*180; + st->colors[n++] = 255 - temp; + } + + /* random colors start at 52 */ + st->numRandomColors = MAX_TRAIL_LEN; + + st->colors[n] = random()&255; n++; + st->colors[n] = random()&255; n++; + st->colors[n] = st->colors[n-2]/2 + st->colors[n-3]/2; n++; + + for (i = 0; i < st->numRandomColors; i++) { + st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++; + st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++; + st->colors[n] = st->colors[n-2]/(float)(i+2) + st->colors[n-3]/(float)(i+2); n++; + } + + st->numColors = n/3 + 1; +} + +static int initGraphics(struct state *st) +{ + XGCValues xgcv; + XWindowAttributes xgwa; +/* XSetWindowAttributes xswa;*/ + Colormap cmap; + XColor color; + int n, i; + + initCMap(st); + + XGetWindowAttributes(st->dpy,st->win,&xgwa); + cmap=xgwa.colormap; +/* xswa.backing_store=Always; + XChangeWindowAttributes(st->dpy,st->win,CWBackingStore,&xswa);*/ + xgcv.function=GXcopy; + + //st->delay = get_integer_resource(st->dpy, "delay","Integer"); + st->delay = delay; + + //xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background"); + xgcv.foreground=load_color(st->dpy, cmap, background); + st->fgc[0]=XCreateGC(st->dpy, st->win, GCForeground|GCFunction,&xgcv); +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (st->dpy, st->fgc[0], False); +#endif + + n=0; + if (mono_p) { + //xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground"); + xgcv.foreground=load_color(st->dpy, cmap, foreground); + st->fgc[1]=XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv); +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (st->dpy, st->fgc[1], False); +#endif + for (i=0;inumColors;i+=2) st->fgc[i]=st->fgc[0]; + for (i=1;inumColors;i+=2) st->fgc[i]=st->fgc[1]; + } else { + for (i = 0; i < st->numColors; i++) { + color.red=st->colors[n++]<<8; + color.green=st->colors[n++]<<8; + color.blue=st->colors[n++]<<8; + color.flags=DoRed|DoGreen|DoBlue; + XAllocColor(st->dpy,cmap,&color); + xgcv.foreground=color.pixel; + st->fgc[i] = XCreateGC(st->dpy, st->win, GCForeground | GCFunction,&xgcv); +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (st->dpy, st->fgc[i], False); +#endif + } + } + st->cgc = XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv); + XSetGraphicsExposures(st->dpy,st->cgc,False); +#ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (st->dpy, st->cgc, False); +#endif + + st->xsize = xgwa.width; + st->ysize = xgwa.height; + st->xc = st->xsize >> 1; + st->yc = st->ysize >> 1; + + st->maxx = 1.0; + st->maxy = st->ysize/(float)st->xsize; + + if (st->colorScheme < 0) st->colorScheme = random()%NUM_SCHEMES; + + return True; +} + +static void initBugs(struct state *st) +{ + register bug *b; + int i; + + st->head = st->tail = 0; + + memset((char *)st->bugs, 0,MAX_BUGS*sizeof(bug)); + memset((char *)st->targets, 0, MAX_TARGETS*sizeof(bug)); + + if (st->ntargets < 0) st->ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS; + if (st->ntargets < 1) st->ntargets = 1; + + if (st->nbugs < 0) st->nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS; + if (st->nbugs <= st->ntargets) st->nbugs = st->ntargets+1; + + if (st->trailLen < 0) { + st->trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN; + } + + if (st->nbugs > MAX_BUGS) st->nbugs = MAX_BUGS; + if (st->ntargets > MAX_TARGETS) st->ntargets = MAX_TARGETS; + if (st->trailLen > MAX_TRAIL_LEN) st->trailLen = MAX_TRAIL_LEN; + + b = st->bugs; + for (i = 0; i < st->nbugs; i++, b++) { + b->pos[0] = frand(st->maxx); + b->pos[1] = frand(st->maxy); + b->vel[0] = frand(st->maxVel/2); + b->vel[1] = frand(st->maxVel/2); + + b->hist[st->head][0] = b->pos[0]*st->xsize; + b->hist[st->head][1] = b->pos[1]*st->xsize; + b->closest = &st->targets[random()%st->ntargets]; + } + + b = st->targets; + for (i = 0; i < st->ntargets; i++, b++) { + b->pos[0] = frand(st->maxx); + b->pos[1] = frand(st->maxy); + + b->vel[0] = frand(st->targetVel/2); + b->vel[1] = frand(st->targetVel/2); + + b->hist[st->head][0] = b->pos[0]*st->xsize; + b->hist[st->head][1] = b->pos[1]*st->xsize; + } +} + +static void pickNewTargets(struct state *st) +{ + register int i; + register bug *b; + + b = st->bugs; + for (i = 0; i < st->nbugs; i++, b++) { + b->closest = &st->targets[random()%st->ntargets]; + } +} + +#if 0 +static void addBugs(int numToAdd) +{ + register bug *b; + int i; + + if (numToAdd + st->nbugs > MAX_BUGS) numToAdd = MAX_BUGS-st->nbugs; + else if (numToAdd < 0) numToAdd = 0; + + for (i = 0; i < numToAdd; i++) { + b = &st->bugs[random()%st->nbugs]; + memcpy((char *)&st->bugs[st->nbugs+i], (char *)b, sizeof(bug)); + b->closest = &st->targets[random()%st->ntargets]; + } + + st->nbugs += numToAdd; +} + +static void addTargets(int numToAdd) +{ + register bug *b; + int i; + + if (numToAdd + st->ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-st->ntargets; + else if (numToAdd < 0) numToAdd = 0; + + for (i = 0; i < numToAdd; i++) { + b = &st->targets[random()%st->ntargets]; + memcpy((char *)&st->targets[st->ntargets+i], (char *)b, sizeof(bug)); + b->closest = &st->targets[random()%st->ntargets]; + } + + st->ntargets += numToAdd; +} +#endif + +static void computeConstants(struct state *st) +{ + st->halfDtSq = st->dt*st->dt*0.5; + st->dtInv = 1.0/st->dt; + st->targetVelSq = st->targetVel*st->targetVel; + st->maxVelSq = st->maxVel*st->maxVel; + st->minVel = st->maxVel*st->minVelMultiplier; + st->minVelSq = st->minVel*st->minVel; +} + +static void computeColorIndices(struct state *st) +{ + int i; + int schizoLength; + + /* note: colors are used in *reverse* order! */ + + /* grayscale */ + for (i = 0; i < st->trailLen; i++) { + st->grayIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5; + if (st->grayIndex[st->trailLen-1-i] > 19) st->grayIndex[st->trailLen-1-i] = 19; + } + + /* red */ + for (i = 0; i < st->trailLen; i++) { + st->redIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5; + if (st->redIndex[st->trailLen-1-i] > 35) st->redIndex[st->trailLen-1-i] = 35; + } + + /* blue */ + for (i = 0; i < st->trailLen; i++) { + st->blueIndex[st->trailLen-1-i] = 36 + i*16.0/st->trailLen + 0.5; + if (st->blueIndex[st->trailLen-1-i] > 51) st->blueIndex[st->trailLen-1-i] = 51; + } + + /* gray schizo - same as gray*/ + for (i = 0; i < st->trailLen; i++) { + st->graySIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5; + if (st->graySIndex[st->trailLen-1-i] > 19) st->graySIndex[st->trailLen-1-i] = 19; + } + + /*schizoLength = st->trailLen/4; + if (schizoLength < 3) schizoLength = 3;*/ + /* red schizo */ + for (i = 0; i < st->trailLen; i++) { + /* redSIndex[trailLen-1-i] = + 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/ + st->redSIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5; + if (st->redSIndex[st->trailLen-1-i] > 35) st->redSIndex[st->trailLen-1-i] = 35; + } + + schizoLength = st->trailLen/2; + if (schizoLength < 3) schizoLength = 3; + /* blue schizo is next */ + for (i = 0; i < st->trailLen; i++) { + st->blueSIndex[st->trailLen-1-i] = + 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5; + if (st->blueSIndex[st->trailLen-1-i] > 51) st->blueSIndex[st->trailLen-1-i] = 51; + } + + /* random is next */ + for (i = 0; i < st->trailLen; i++) { + st->randomIndex[i] = 52 + random()%(st->numRandomColors); + } +} + +#if 0 +static void setParams(bugParams *p) +{ + st->dt = p->dt; + st->targetVel = p->targetVel; + st->targetAcc = p->targetAcc; + st->maxVel = p->maxVel; + st->maxAcc = p->maxAcc; + st->noise = p->noise; + + st->nbugs = p->nbugs; + st->ntargets = p->ntargets; + st->trailLen = p->trailLen; + st->colorScheme = p->colorScheme; + st->changeProb = p->changeProb; + computeConstants(); + computeColorIndices(); +} +#endif + +static void drawBugs(struct state *st, int *tColorIdx, int tci0, int tnc, + int *colorIdx, int ci0, int nc) +{ + register bug *b; + register int i, j; + int temp; + + if (((st->head+1)%st->trailLen) == st->tail) { + /* first, erase last segment of bugs if necessary */ + temp = (st->tail+1) % st->trailLen; + + b = st->bugs; + for (i = 0; i < st->nbugs; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[0], + b->hist[st->tail][0], b->hist[st->tail][1], + b->hist[temp][0], b->hist[temp][1]); + } + + b = st->targets; + for (i = 0; i < st->ntargets; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[0], + b->hist[st->tail][0], b->hist[st->tail][1], + b->hist[temp][0], b->hist[temp][1]); + } + st->tail = (st->tail+1)%st->trailLen; + } + + for (j = st->tail; j != st->head; j = temp) { + temp = (j+1)%st->trailLen; + + b = st->bugs; + for (i = 0; i < st->nbugs; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[colorIdx[ci0]], + b->hist[j][0], b->hist[j][1], + b->hist[temp][0], b->hist[temp][1]); + } + + b = st->targets; + for (i = 0; i < st->ntargets; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[tColorIdx[tci0]], + b->hist[j][0], b->hist[j][1], + b->hist[temp][0], b->hist[temp][1]); + } + ci0 = (ci0+1)%nc; + tci0 = (tci0+1)%tnc; + } +} + +static void clearBugs(struct state *st) +{ + register bug *b; + register int i, j; + int temp; + + st->tail = st->tail-1; + if (st->tail < 0) st->tail = st->trailLen-1; + + if (((st->head+1)%st->trailLen) == st->tail) { + /* first, erase last segment of bugs if necessary */ + temp = (st->tail+1) % st->trailLen; + + b = st->bugs; + for (i = 0; i < st->nbugs; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[0], + b->hist[st->tail][0], b->hist[st->tail][1], + b->hist[temp][0], b->hist[temp][1]); + } + + b = st->targets; + for (i = 0; i < st->ntargets; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[0], + b->hist[st->tail][0], b->hist[st->tail][1], + b->hist[temp][0], b->hist[temp][1]); + } + st->tail = (st->tail+1)%st->trailLen; + } + + for (j = st->tail; j != st->head; j = temp) { + temp = (j+1)%st->trailLen; + + b = st->bugs; + for (i = 0; i < st->nbugs; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[0], + b->hist[j][0], b->hist[j][1], + b->hist[temp][0], b->hist[temp][1]); + } + + b = st->targets; + for (i = 0; i < st->ntargets; i++, b++) { + XDrawLine(st->dpy, st->win, st->fgc[0], + b->hist[j][0], b->hist[j][1], + b->hist[temp][0], b->hist[temp][1]); + } + } +} + +static void updateState(struct state *st) +{ + register int i; + register bug *b; + register float ax, ay, temp; + float theta; + bug *b2; + int j; + + st->head = (st->head+1)%st->trailLen; + + for (j = 0; j < 5; j++) { + /* update closets bug for the bug indicated by checkIndex */ + st->checkIndex = (st->checkIndex+1)%st->nbugs; + b = &st->bugs[st->checkIndex]; + + ax = b->closest->pos[0] - b->pos[0]; + ay = b->closest->pos[1] - b->pos[1]; + temp = ax*ax + ay*ay; + for (i = 0; i < st->ntargets; i++) { + b2 = &st->targets[i]; + if (b2 == b->closest) continue; + ax = b2->pos[0] - b->pos[0]; + ay = b2->pos[1] - b->pos[1]; + theta = ax*ax + ay*ay; + if (theta < temp*2) { + b->closest = b2; + temp = theta; + } + } + } + + /* update target state */ + + b = st->targets; + for (i = 0; i < st->ntargets; i++, b++) { + theta = frand(6.28); + ax = st->targetAcc*cos(theta); + ay = st->targetAcc*sin(theta); + + b->vel[0] += ax*st->dt; + b->vel[1] += ay*st->dt; + + /* check velocity */ + temp = sq(b->vel[0]) + sq(b->vel[1]); + if (temp > st->targetVelSq) { + temp = st->targetVel/sqrt(temp); + /* save old vel for acc computation */ + ax = b->vel[0]; + ay = b->vel[1]; + + /* compute new velocity */ + b->vel[0] *= temp; + b->vel[1] *= temp; + + /* update acceleration */ + ax = (b->vel[0]-ax)*st->dtInv; + ay = (b->vel[1]-ay)*st->dtInv; + } + + /* update position */ + b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq; + b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq; + + /* check limits on targets */ + if (b->pos[0] < 0) { + /* bounce */ + b->pos[0] = -b->pos[0]; + b->vel[0] = -b->vel[0]; + } else if (b->pos[0] >= st->maxx) { + /* bounce */ + b->pos[0] = 2*st->maxx-b->pos[0]; + b->vel[0] = -b->vel[0]; + } + if (b->pos[1] < 0) { + /* bounce */ + b->pos[1] = -b->pos[1]; + b->vel[1] = -b->vel[1]; + } else if (b->pos[1] >= st->maxy) { + /* bounce */ + b->pos[1] = 2*st->maxy-b->pos[1]; + b->vel[1] = -b->vel[1]; + } + + b->hist[st->head][0] = b->pos[0]*st->xsize; + b->hist[st->head][1] = b->pos[1]*st->xsize; + } + + /* update bug state */ + b = st->bugs; + for (i = 0; i < st->nbugs; i++, b++) { + theta = atan2(b->closest->pos[1] - b->pos[1] + frand(st->noise), + b->closest->pos[0] - b->pos[0] + frand(st->noise)); + ax = st->maxAcc*cos(theta); + ay = st->maxAcc*sin(theta); + + b->vel[0] += ax*st->dt; + b->vel[1] += ay*st->dt; + + /* check velocity */ + temp = sq(b->vel[0]) + sq(b->vel[1]); + if (temp > st->maxVelSq) { + temp = st->maxVel/sqrt(temp); + + /* save old vel for acc computation */ + ax = b->vel[0]; + ay = b->vel[1]; + + /* compute new velocity */ + b->vel[0] *= temp; + b->vel[1] *= temp; + + /* update acceleration */ + ax = (b->vel[0]-ax)*st->dtInv; + ay = (b->vel[1]-ay)*st->dtInv; + } else if (temp < st->minVelSq) { + temp = st->minVel/sqrt(temp); + + /* save old vel for acc computation */ + ax = b->vel[0]; + ay = b->vel[1]; + + /* compute new velocity */ + b->vel[0] *= temp; + b->vel[1] *= temp; + + /* update acceleration */ + ax = (b->vel[0]-ax)*st->dtInv; + ay = (b->vel[1]-ay)*st->dtInv; + } + + /* update position */ + b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq; + b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq; + + /* check limits on targets */ + if (b->pos[0] < 0) { + /* bounce */ + b->pos[0] = -b->pos[0]; + b->vel[0] = -b->vel[0]; + } else if (b->pos[0] >= st->maxx) { + /* bounce */ + b->pos[0] = 2*st->maxx-b->pos[0]; + b->vel[0] = -b->vel[0]; + } + if (b->pos[1] < 0) { + /* bounce */ + b->pos[1] = -b->pos[1]; + b->vel[1] = -b->vel[1]; + } else if (b->pos[1] >= st->maxy) { + /* bounce */ + b->pos[1] = 2*st->maxy-b->pos[1]; + b->vel[1] = -b->vel[1]; + } + + b->hist[st->head][0] = b->pos[0]*st->xsize; + b->hist[st->head][1] = b->pos[1]*st->xsize; + } +} + +static void mutateBug(struct state *st, int which) +{ + int i, j; + + if (which == 0) { + /* turn bug into target */ + if (st->ntargets < MAX_TARGETS-1 && st->nbugs > 1) { + i = random() % st->nbugs; + memcpy((char *)&st->targets[st->ntargets], (char *)&st->bugs[i], sizeof(bug)); + memcpy((char *)&st->bugs[i], (char *)&st->bugs[st->nbugs-1], sizeof(bug)); + st->targets[st->ntargets].pos[0] = frand(st->maxx); + st->targets[st->ntargets].pos[1] = frand(st->maxy); + st->nbugs--; + st->ntargets++; + + for (i = 0; i < st->nbugs; i += st->ntargets) { + st->bugs[i].closest = &st->targets[st->ntargets-1]; + } + } + } else { + /* turn target into bug */ + if (st->ntargets > 1 && st->nbugs < MAX_BUGS-1) { + /* pick a target */ + i = random() % st->ntargets; + + /* copy state into a new bug */ + memcpy((char *)&st->bugs[st->nbugs], (char *)&st->targets[i], sizeof(bug)); + st->ntargets--; + + /* pick a target for the new bug */ + st->bugs[st->nbugs].closest = &st->targets[random()%st->ntargets]; + + for (j = 0; j < st->nbugs; j++) { + if (st->bugs[j].closest == &st->targets[st->ntargets]) { + st->bugs[j].closest = &st->targets[i]; + } else if (st->bugs[j].closest == &st->targets[i]) { + st->bugs[j].closest = &st->targets[random()%st->ntargets]; + } + } + st->nbugs++; + + /* copy the last ntarget into the one we just deleted */ + memcpy(&st->targets[i], (char *)&st->targets[st->ntargets], sizeof(bug)); + } + } +} + +static void mutateParam(float *param) +{ + *param *= 0.75+frand(0.5); +} + +static void randomSmallChange(struct state *st) +{ + int whichCase = 0; + + whichCase = random()%11; + + if (++st->rsc_callDepth > 10) { + st->rsc_callDepth--; + return; + } + + switch(whichCase) { + case 0: + /* acceleration */ + mutateParam(&st->maxAcc); + break; + + case 1: + /* target acceleration */ + mutateParam(&st->targetAcc); + break; + + case 2: + /* velocity */ + mutateParam(&st->maxVel); + break; + + case 3: + /* target velocity */ + mutateParam(&st->targetVel); + break; + + case 4: + /* noise */ + mutateParam(&st->noise); + break; + + case 5: + /* minVelMultiplier */ + mutateParam(&st->minVelMultiplier); + break; + + case 6: + case 7: + /* target to bug */ + if (st->ntargets < 2) break; + mutateBug(st, 1); + break; + + case 8: + /* bug to target */ + if (st->nbugs < 2) break; + mutateBug(st, 0); + if (st->nbugs < 2) break; + mutateBug(st, 0); + break; + + case 9: + /* color scheme */ + st->colorScheme = random()%NUM_SCHEMES; + if (st->colorScheme == RANDOM_SCHIZO || st->colorScheme == COLOR_SCHIZO) { + /* don't use these quite as much */ + st->colorScheme = random()%NUM_SCHEMES; + } + break; + + default: + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + } + + if (st->minVelMultiplier < 0.3) st->minVelMultiplier = 0.3; + else if (st->minVelMultiplier > 0.9) st->minVelMultiplier = 0.9; + if (st->noise < 0.01) st->noise = 0.01; + if (st->maxVel < 0.02) st->maxVel = 0.02; + if (st->targetVel < 0.02) st->targetVel = 0.02; + if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7; + if (st->maxAcc > st->maxVel*0.7) st->maxAcc = st->maxVel*0.7; + if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7; + if (st->maxAcc < 0.01) st->maxAcc = 0.01; + if (st->targetAcc < 0.005) st->targetAcc = 0.005; + + computeConstants(st); + st->rsc_callDepth--; +} + +static void randomBigChange(struct state *st) +{ + int whichCase = 0; + int temp; + + whichCase = random()%4; + + if (++st->rbc_callDepth > 3) { + st->rbc_callDepth--; + return; + } + + switch(whichCase) { + case 0: + /* trail length */ + temp = (random()%(MAX_TRAIL_LEN-25)) + 25; + clearBugs(st); + st->trailLen = temp; + computeColorIndices(st); + initBugs(st); + break; + + case 1: + /* Whee! */ + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + randomSmallChange(st); + break; + + case 2: + clearBugs(st); + initBugs(st); + break; + + case 3: + pickNewTargets(st); + break; + + default: + temp = random()%st->ntargets; + st->targets[temp].pos[0] += frand(st->maxx/4)-st->maxx/8; + st->targets[temp].pos[1] += frand(st->maxy/4)-st->maxy/8; + /* updateState() will fix bounds */ + break; + } + + st->rbc_callDepth--; +} + +static void updateColorIndex(struct state *st, + int **tColorIdx, int *tci0, int *tnc, + int **colorIdx, int *ci0, int *nc) +{ + switch(st->colorScheme) { + case COLOR_TRAILS: + *tColorIdx = st->redIndex; + *tci0 = 0; + *tnc = st->trailLen; + *colorIdx = st->blueIndex; + *ci0 = 0; + *nc = st->trailLen; + break; + + case GRAY_SCHIZO: + *tColorIdx = st->graySIndex; + *tci0 = st->head; + *tnc = st->trailLen; + *colorIdx = st->graySIndex; + *ci0 = st->head; + *nc = st->trailLen; + break; + + case COLOR_SCHIZO: + *tColorIdx = st->redSIndex; + *tci0 = st->head; + *tnc = st->trailLen; + *colorIdx = st->blueSIndex; + *ci0 = st->head; + *nc = st->trailLen; + break; + + case GRAY_TRAILS: + *tColorIdx = st->grayIndex; + *tci0 = 0; + *tnc = st->trailLen; + *colorIdx = st->grayIndex; + *ci0 = 0; + *nc = st->trailLen; + break; + + case RANDOM_TRAILS: + *tColorIdx = st->redIndex; + *tci0 = 0; + *tnc = st->trailLen; + *colorIdx = st->randomIndex; + *ci0 = 0; + *nc = st->trailLen; + break; + + case RANDOM_SCHIZO: + *tColorIdx = st->redIndex; + *tci0 = st->head; + *tnc = st->trailLen; + *colorIdx = st->randomIndex; + *ci0 = st->head; + *nc = st->trailLen; + break; + } +} + +#if HAVE_GETTIMEOFDAY +static void initTime(struct state *st) +{ +#if GETTIMEOFDAY_TWO_ARGS + gettimeofday(&st->startupTime, NULL); +#else + gettimeofday(&st->startupTime); +#endif +} + +static double getTime(struct state *st) +{ + struct timeval t; + float f; +#if GETTIMEOFDAY_TWO_ARGS + gettimeofday(&t, NULL); +#else + gettimeofday(&t); +#endif + t.tv_sec -= st->startupTime.tv_sec; + f = ((double)t.tv_sec) + t.tv_usec*1e-6; + return f; +} +#endif + +static void * +xrayswarm_init (Display *d, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int i; + + st->dpy = d; + st->win = w; + + st->dt = 0.3; + st->targetVel = 0.03; + st->targetAcc = 0.02; + st->maxVel = 0.05; + st->maxAcc = 0.03; + st->noise = 0.01; + st->minVelMultiplier = 0.5; + + st->nbugs = -1; + st->ntargets = -1; + st->trailLen = -1; + + st->colorScheme = /* -1 */ 2; + st->changeProb = 0.08; + + if (!initGraphics(st)) abort(); + + computeConstants(st); + initBugs(st); + initTime(st); + computeColorIndices(st); + + if (st->changeProb > 0) { + for (i = random()%5+5; i >= 0; i--) { + randomSmallChange(st); + } + } + + return st; +} + +static unsigned long +xrayswarm_draw (Display *d, Window w, void *closure) +{ + struct state *st = (struct state *) closure; + unsigned long this_delay = st->delay; + +#if HAVE_GETTIMEOFDAY + st->draw_start = getTime(st); +#endif + + if (st->delay > 0) { + st->draw_cnt = 2; + st->dt = DESIRED_DT/2; + } else { + st->draw_cnt = 1; + st->dt = DESIRED_DT; + } + + for (; st->draw_cnt > 0; st->draw_cnt--) { + updateState(st); + updateColorIndex(st, &st->draw_targetColorIndex, &st->draw_targetStartColor, &st->draw_targetNumColors, + &st->draw_colorIndex, &st->draw_startColor, &st->draw_numColors); + drawBugs(st, st->draw_targetColorIndex, st->draw_targetStartColor, st->draw_targetNumColors, + st->draw_colorIndex, st->draw_startColor, st->draw_numColors); + } +#if HAVE_GETTIMEOFDAY + st->draw_end = getTime(st); + st->draw_nframes++; + + if (st->draw_end > st->draw_start+0.5) { + if (frand(1.0) < st->changeProb) randomSmallChange(st); + if (frand(1.0) < st->changeProb*0.3) randomBigChange(st); + st->draw_elapsed = st->draw_end-st->draw_start; + + st->draw_timePerFrame = st->draw_elapsed/st->draw_nframes - st->delay*1e-6; + st->draw_fps = st->draw_nframes/st->draw_elapsed; + /* + printf("elapsed: %.3f\n", elapsed); + printf("fps: %.1f secs per frame: %.3f delay: %f\n", + fps, timePerFrame, delay); + */ + + if (st->draw_fps > MAX_FPS) { + st->delay = (1.0/MAX_FPS - (st->draw_timePerFrame + st->delay*1e-6))*1e6; + } else if (st->dt*st->draw_fps < MIN_FPS*DESIRED_DT) { + /* need to speed things up somehow */ + if (0 && st->nbugs > 10) { + /*printf("reducing bugs to improve speed.\n");*/ + clearBugs(st); + st->nbugs *= st->draw_fps/MIN_FPS; + if (st->ntargets >= st->nbugs/2) mutateBug(st, 1); + } else if (0 && st->dt < 0.3) { + /*printf("increasing dt to improve speed.\n");*/ + st->dt *= MIN_FPS/st->draw_fps; + computeConstants(st); + } else if (st->trailLen > 10) { + /*printf("reducing trail length to improve speed.\n");*/ + clearBugs(st); + st->trailLen = st->trailLen * (st->draw_fps/MIN_FPS); + if (st->trailLen < 10) st->trailLen = 10; + computeColorIndices(st); + initBugs(st); + } + } + + st->draw_start = getTime(st); + st->draw_nframes = 0; + } +#else + if (frand(1) < st->changeProb*2/100.0) randomSmallChange(st); + if (frand(1) < st->changeProb*0.3/100.0) randomBigChange(st); +#endif + + if (st->delay <= 10000) { + st->draw_delayAccum += st->delay; + if (st->draw_delayAccum > 10000) { + this_delay = st->draw_delayAccum; + st->draw_delayAccum = 0; + st->draw_sleepCount = 0; + } + if (++st->draw_sleepCount > 2) { + st->draw_sleepCount = 0; + this_delay = 10000; + } + } + + return this_delay; +} + +static void +xrayswarm_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->xsize = w; + st->ysize = h; + st->xc = st->xsize >> 1; + st->yc = st->ysize >> 1; + st->maxy = st->ysize/(float)st->xsize; +} + +#if 0 + static Bool + xrayswarm_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +xrayswarm_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +XSCREENSAVER_MODULE ("XRaySwarm", xrayswarm) diff --git a/non-wgl/xrayswarm.vcproj b/non-wgl/xrayswarm.vcproj new file mode 100644 index 0000000..96ab85d --- /dev/null +++ b/non-wgl/xrayswarm.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/xspirograph.c b/non-wgl/xspirograph.c new file mode 100644 index 0000000..5436485 --- /dev/null +++ b/non-wgl/xspirograph.c @@ -0,0 +1,365 @@ +/* The Spiral Generator, Copyright (c) 2000 + * by Rohit Singh + * + * Contains code from / To be used with: + * xscreensaver, Copyright (c) 1992, 1995, 1996, 1997 + * 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 notices appear in all copies and that both that + * copyright notices 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. + * + * Modified (Dec 2001) by Matthew Strait + * Added -subdelay and -alwaysfinish + * Prevented redrawing over existing lines + */ + +#include "screenhack.h" +#include +#include "erase.h" + +float eraseSeconds = 0; +char *eraseMode = NULL; + +char *background = "black"; +char *foreground = "white"; +int delay = 5; +int subdelay = 20000; +int layers = 2; +Bool alwaysfinish = False; + +static argtype vars[] = +{ + {&background, "background", NULL, "black", t_String}, + {&foreground, "foreground", NULL, "white", t_String}, + {&delay, "delay", NULL, "5", t_Int}, + {&subdelay, "subdelay", NULL, "20000", t_Int}, + {&layers, "layers", NULL, "2", t_Int}, + {&alwaysfinish, "alwaysfinish", NULL, "False", t_Bool}, +}; + +struct state { + Display *dpy; + Window window; + XWindowAttributes xgwa; + + GC draw_gc; + int long_delay; + int sub_sleep_time; + int num_layers; + unsigned int default_fg_pixel; + Bool always_finish_p; + XColor color; + int got_color; + + int theta; + float firstx, firsty; + int x1, y1, x2, y2; + + int counter; + int distance; + int radius1, radius2; + double divisor; + + enum curstate { NEW_LAYER, DRAW, ERASE1, ERASE2 } drawstate; + eraser_state *eraser; +}; + + +static void +init_tsg (struct state *st) +{ + XGCValues gcv; + Colormap cmap; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + cmap = st->xgwa.colormap; + //gcv.foreground = st->default_fg_pixel = + // get_pixel_resource (st->dpy, cmap, "foreground", "Foreground"); + gcv.foreground = st->default_fg_pixel = + load_color(st->dpy, cmap, foreground); + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + //gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background"); + gcv.foreground = load_color(st->dpy, cmap, background); +} + + +static Bool +go (struct state *st, int radius1, int radius2, int d) +{ + int width, height; + int xmid, ymid; + float tmpx, tmpy; + int delta; + + width = st->xgwa.width; + height = st->xgwa.height; + delta = 1; + xmid = width / 2; + ymid = height / 2; + + if (st->theta == 1) { + st->x1 = xmid + radius1 - radius2 + d; + st->y1 = ymid; + } + +/* for (theta = 1; / * theta < ( 360 * 100 ) * /; theta++) */ + /* see below about alwaysfinish */ + { + tmpx = xmid + (( radius1 /* * * * * */ + - radius2 ) /* This algo simulates */ + * cos(( st->theta /* the rotation of a */ + * M_PI ) /* circular disk inside */ + / 180 )) /* a hollow circular */ + + ( d /* rim. A point on the */ + * cos(((( radius1 /* disk dist d from the */ + * st->theta ) /* centre, traces the */ + - delta ) /* path given by this */ + / radius2 ) /* equation. */ + * M_PI /* A deviation (error) */ + / 180 ) /* of delta needs to be */ + ); /* given, which greatly */ + /* adds to the beauty */ + tmpy = ymid + ( /* of the figure. */ + ( radius1 - radius2 /* */ + ) * sin /* Imperfection adds to */ + ( /* beauty, symbolically */ + ( st->theta * M_PI /* ... */ + ) / 180 /* Algo deduced by */ + ) /* Rohit Singh, Jan'00 */ + ) + /* based on a toy he */ + ( d * sin /* used to play with */ + ( /* when he was a kid. */ + ( /* * * * * */ + ( + ( radius1 * st->theta + ) - delta + ) / radius2 + ) * M_PI / 180 + ) + ); + + /*makes integers from the calculated values to do the drawing*/ + st->x2 = tmpx; + st->y2 = tmpy; + + /*stores the first values for later reference*/ + if(st->theta == 1) + { + st->firstx = tmpx; + st->firsty = tmpy; + } + + if (st->theta != 1) + XDrawLine (st->dpy, st->window, st->draw_gc, + st->x1, st->y1, st->x2, st->y2); + + st->x1 = st->x2; + st->y1 = st->y2; + + /* compares the exact values calculated to the first + exact values calculated */ + /* this will break when nothing new is being drawn */ + if(tmpx == st->firstx && tmpy == st->firsty && st->theta != 1) { + st->firstx = st->firsty = 0; + st->theta = 1; + return True; + } + + /* this will break after 36000 iterations if + the -alwaysfinish option is not specified */ + if(!st->always_finish_p && st->theta > ( 360 * 100 ) ) { + st->firstx = st->firsty = 0; + st->theta = 1; + return True; + } + } + + st->theta++; + + return False; +} + + +#define min(a,b) ((a)<(b)?(a):(b)) + + +static void +pick_new (struct state *st) +{ + int radius = min (st->xgwa.width, st->xgwa.height) / 2; + st->divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1)); + st->radius1 = radius; + st->radius2 = radius / st->divisor + 5; + st->distance = 100 + (random() % 200); + st->theta = 1; +} + + +static void * +xspirograph_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; +#if 1 + st->long_delay = delay; + st->sub_sleep_time = subdelay; + st->num_layers = layers; + st->always_finish_p = alwaysfinish; +#else + st->long_delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->sub_sleep_time = get_integer_resource(st->dpy, "subdelay", "Integer"); + st->num_layers = get_integer_resource(st->dpy, "layers", "Integer"); + st->always_finish_p = get_boolean_resource (st->dpy, "alwaysfinish", "Boolean"); +#endif + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + init_tsg (st); + st->theta = 1; + st->drawstate = NEW_LAYER; + + return st; +} + + +static void +new_colors (struct state *st) +{ + if (mono_p) + XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel); + else + { + hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5, + &st->color.red, &st->color.green, &st->color.blue); + if ((st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, + &st->color))) + XSetForeground (st->dpy, st->draw_gc, st->color.pixel); + else + XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel); + } +} + + + +static unsigned long +xspirograph_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + Bool free_color = False; + Bool flip_p = (st->counter & 1); + int i; + + switch (st->drawstate) { + case ERASE1: + /* 5 sec delay before starting the erase */ + st->drawstate = ERASE2; + /* shouldn't this use the configured long_delay value??? */ + return (st->long_delay == 0 ? 0 : 5000000); + + case ERASE2: + /* erase, delaying 1/50th sec between frames */ + st->eraser = erase_window(st->dpy, st->window, st->eraser); + if (st->eraser) + /* shouldn't this be a configured pause??? */ + return 20000; + st->drawstate = NEW_LAYER; + /* just finished erasing -- leave screen black for 1 sec */ + return (st->long_delay == 0 ? 0 : 1000000); + + case DRAW: + /* most common case put in front */ + for (i = 0; i < 1000; i++) { + if (go(st, st->radius1, (flip_p ? st->radius2 : -st->radius2), + st->distance)) { + st->drawstate = NEW_LAYER; + break; + } + } + /* Next draw is delayed sleep_time (initialized value)*/ + return st->sub_sleep_time; + + case NEW_LAYER: + /* Increment counter */ + st->counter++; + if (st->counter > (2 * st->num_layers)) { + /* reset to zero, free, and erase next time through */ + st->counter = 0; + if (free_color) + XFreeColors (st->dpy, st->xgwa.colormap, &st->color.pixel, 1, 0); + st->drawstate = ERASE1; + } else { + /* first, third, fifth, ... time through */ + if (!flip_p) + pick_new (st); + + new_colors (st); + st->drawstate = DRAW; + } + /* No delay to the next draw */ + return 0; + + default: + /* OOPS!! */ + fprintf(stderr, "%s: invalid state\n", progname); + exit(1); + } + + return st->sub_sleep_time; + /* notreached */ +} + + +static void +xspirograph_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); +} + +#if 0 + static Bool + xspirograph_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +xspirograph_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *xspirograph_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 5", + "*subdelay: 20000", + "*layers: 2", + "*alwaysfinish: false", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec xspirograph_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-subdelay", ".subdelay", XrmoptionSepArg, 0 }, + { "-layers", ".layers", XrmoptionSepArg, 0 }, + { "-alwaysfinish", ".alwaysfinish", XrmoptionNoArg, "true"}, + { "-noalwaysfinish", ".alwaysfinish", XrmoptionNoArg, "false"}, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("XSpirograph", xspirograph) diff --git a/non-wgl/xspirograph.vcproj b/non-wgl/xspirograph.vcproj new file mode 100644 index 0000000..076f5bc --- /dev/null +++ b/non-wgl/xspirograph.vcproj @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/non-wgl/zoom.c b/non-wgl/zoom.c new file mode 100644 index 0000000..519f3d9 --- /dev/null +++ b/non-wgl/zoom.c @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2000 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. + */ + +#include "screenhack.h" +#include + +#ifndef MIN +#define MIN(a, b) (((a) < (b))?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b))?(a):(b)) +#endif + +#define MINX 0.0 +#define MINY 0.0 +/* This should be *way* slower than the spotlight hack was */ +#define X_PERIOD 45000.0 +#define Y_PERIOD 36000.0 + +Bool dontClearRoot = True; +char *foreground = "white"; +char *background = "#111111"; +Bool lenses = True; +int delay = 10000; +int duration = 120; +int pixwidth = 10; +int pixheight = 10; +int pixspacex = 2; +int pixspacey = 2; +int lensoffsetx = 5; +int lensoffsety = 5; + +static argtype vars[] = +{ + {&dontClearRoot, "dontClearRoot", NULL, "True", t_Bool}, + {&foreground, "foreground", NULL, "white", t_String}, + {&background, "background", NULL, "#111111", t_String}, + {&lenses, "lenses", NULL, "True", t_Bool}, + {&delay, "delay", NULL, "10000", t_Int}, + {&duration, "duration", NULL, "120", t_Int}, + {&pixwidth, "pixwidth", NULL, "10", t_Int}, + {&pixheight, "pixheight", NULL, "10", t_Int}, + {&pixspacex, "pixspacex", NULL, "2", t_Int}, + {&pixspacey, "pixspacey", NULL, "2", t_Int}, + {&lensoffsetx, "lensoffsetx", NULL, "5", t_Int}, + {&lensoffsety, "lensoffsety", NULL, "5", t_Int}, +}; + + +struct state { + Display *dpy; + Window window; + Screen *screen; + + int sizex, sizey; + + int delay; + int duration; + int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety; + Bool lenses; + + GC window_gc; + + XImage *orig_map; + Pixmap pm; + + int tlx, tly, s; + + int sinusoid_offset; + + time_t start_time; + async_load_state *img_loader; +}; + + +static long currentTimeInMs(struct state *st) +{ + struct timeval curTime; +#ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tz = {0,0}; + gettimeofday(&curTime, &tz); +#else + gettimeofday(&curTime); +#endif + return curTime.tv_sec*1000 + curTime.tv_usec/1000.0; +} + +static void * +zoom_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + Colormap cmap; + unsigned long bg; + long gcflags; + int nblocksx, nblocksy; + + st->dpy = dpy; + st->window = window; + XGetWindowAttributes(st->dpy, st->window, &xgwa); + st->screen = xgwa.screen; + st->sizex = xgwa.width; + st->sizey = xgwa.height; + cmap = xgwa.colormap; + //bg = get_pixel_resource(st->dpy, cmap, "background", "Background"); + bg = load_color(st->dpy, cmap, background); + + //st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->delay = delay; + if (st->delay < 1) + st->delay = 1; + //st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + st->duration = duration; + if (st->duration < 1) + st->duration = 1; + //st->pixwidth = get_integer_resource(st->dpy, "pixwidth", "Integer"); + st->pixwidth = pixwidth; + if (st->pixwidth < 1) + st->pixwidth = 1; + //st->pixheight = get_integer_resource(st->dpy, "pixheight", "Integer"); + st->pixheight = pixheight; + if (st->pixheight < 1) + st->pixheight = 1; + //st->pixspacex = get_integer_resource(st->dpy, "pixspacex", "Integer"); + st->pixspacex = pixspacex; + if (st->pixspacex < 0) + st->pixspacex = 0; + //st->pixspacey = get_integer_resource(st->dpy, "pixspacey", "Integer"); + st->pixspacey = pixspacey; + if (st->pixspacey < 0) + st->pixspacey = 0; +#if 1 + st->lenses = lenses; + st->lensoffsetx = lensoffsetx; + st->lensoffsetx = MAX(0, MIN(st->pixwidth, st->lensoffsetx)); + st->lensoffsety = lensoffsety; + st->lensoffsety = MAX(0, MIN(st->pixwidth, st->lensoffsety)); +#else + st->lenses = get_boolean_resource(st->dpy, "lenses", "Boolean"); + st->lensoffsetx = get_integer_resource(st->dpy, "lensoffsetx", "Integer"); + st->lensoffsetx = MAX(0, MIN(st->pixwidth, st->lensoffsetx)); + st->lensoffsety = get_integer_resource(st->dpy, "lensoffsety", "Integer"); + st->lensoffsety = MAX(0, MIN(st->pixwidth, st->lensoffsety)); +#endif + + gcv.function = GXcopy; + gcv.subwindow_mode = IncludeInferiors; + gcflags = GCForeground|GCFunction; + gcv.foreground = bg; + if (!st->lenses && use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */ + gcflags |= GCSubwindowMode; + st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv); + + + st->orig_map = NULL; + st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth); + + XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey); + XSetWindowBackground(st->dpy, st->window, bg); + + st->start_time = time ((time_t) 0); + st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, + st->pm, 0, 0); + + /* We might have needed this to grab the image, but if we leave this set + to GCSubwindowMode, then we'll *draw* right over subwindows too. */ + XSetSubwindowMode (st->dpy, st->window_gc, ClipByChildren); + + + nblocksx = (int)ceil((double)st->sizex / (double)(st->pixwidth + st->pixspacex)); + nblocksy = (int)ceil((double)st->sizey / (double)(st->pixheight + st->pixspacey)); + if (st->lenses) + st->s = MAX((nblocksx - 1) * st->lensoffsetx + st->pixwidth, + (nblocksy - 1) * st->lensoffsety + st->pixheight) * 2; + else + st->s = MAX(nblocksx, nblocksy) * 2; + + st->sinusoid_offset = random(); + + return st; +} + +static unsigned long +zoom_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + unsigned x, y, i, j; + + long now; + + 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 */ + XClearWindow (st->dpy, st->window); + st->start_time = time ((time_t) 0); + if (!st->lenses) { + st->orig_map = XGetImage(st->dpy, st->pm, 0, 0, st->sizex, st->sizey, ~0L, ZPixmap); +/* XFreePixmap(st->dpy, st->pm); + st->pm = 0;*/ + } + } + return st->delay; + } + + if (!st->img_loader && + st->start_time + st->duration < time ((time_t) 0)) { + st->img_loader = load_image_async_simple (0, st->screen, st->window, + st->pm, 0, 0); + return st->delay; + } + +#define nrnd(x) (random() % (x)) + + now = currentTimeInMs(st); + now += st->sinusoid_offset; /* don't run multiple screens in lock-step */ + + /* find new x,y */ + st->tlx = ((1. + sin(((double)now) / X_PERIOD * 2. * M_PI))/2.0) + * (st->sizex - st->s/2) /* -s/4 */ + MINX; + st->tly = ((1. + sin(((double)now) / Y_PERIOD * 2. * M_PI))/2.0) + * (st->sizey - st->s/2) /* -s/4 */ + MINY; + + if (st->lenses) { + for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i) + for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) { + XCopyArea(st->dpy, st->pm /* src */, st->window /* dest */, st->window_gc, + st->tlx + i * st->lensoffsetx /* src_x */, + st->tly + j * st->lensoffsety /* src_y */, + st->pixwidth, st->pixheight, + x /* dest_x */, y /* dest_y */); + } + } else { + for (x = i = 0; x < st->sizex; x += (st->pixwidth + st->pixspacex), ++i) + for (y = j = 0; y < st->sizey; y += (st->pixheight + st->pixspacey), ++j) { + XSetForeground(st->dpy, st->window_gc, XGetPixel(st->orig_map, st->tlx+i, st->tly+j)); + XFillRectangle(st->dpy, st->window, st->window_gc, + i * (st->pixwidth + st->pixspacex), + j * (st->pixheight + st->pixspacey), st->pixwidth, st->pixheight); + } + } + + return st->delay; +} + +static void +zoom_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +#if 0 + static Bool + zoom_event (Display *dpy, Window window, void *closure, XEvent *event) + { + return False; + } +#endif + +static void +zoom_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XFreeGC (st->dpy, st->window_gc); + if (st->orig_map) XDestroyImage (st->orig_map); + if (st->pm) XFreePixmap (st->dpy, st->pm); + free (st); +} + + +static const char *zoom_defaults[] = { + "*dontClearRoot: True", + ".foreground: white", + ".background: #111111", + "*fpsSolid: true", +#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */ + "*visualID: Best", +#endif + "*lenses: true", + "*delay: 10000", + "*duration: 120", + "*pixwidth: 10", + "*pixheight: 10", + "*pixspacex: 2", + "*pixspacey: 2", + "*lensoffsetx: 5", + "*lensoffsety: 5", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec zoom_options[] = { + { "-lenses", ".lenses", XrmoptionNoArg, "true" }, + { "-no-lenses", ".lenses", XrmoptionNoArg, "false" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-pixwidth", ".pixwidth", XrmoptionSepArg, 0 }, + { "-pixheight", ".pixheight", XrmoptionSepArg, 0 }, + { "-pixspacex", ".pixspacex", XrmoptionSepArg, 0 }, + { "-pixspacey", ".pixspacey", XrmoptionSepArg, 0 }, + { "-lensoffsetx", ".lensoffsetx", XrmoptionSepArg, 0 }, + { "-lensoffsety", ".lensoffsety", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Zoom", zoom) diff --git a/non-wgl/zoom.vcproj b/non-wgl/zoom.vcproj new file mode 100644 index 0000000..9104802 --- /dev/null +++ b/non-wgl/zoom.vcproj @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pixmap.c b/pixmap.c new file mode 100644 index 0000000..4624ee1 --- /dev/null +++ b/pixmap.c @@ -0,0 +1,76 @@ +#include "xws2win.h" + +Pixmap XCreatePixmap( + Display* dpy, Drawable d, + unsigned int width, unsigned int height, + unsigned int depth) +{ + BITMAPINFO bi; + DrawableData *data = (DrawableData *)calloc(1, sizeof(DrawableData)); + if (data == NULL) + return 0; + + ZeroMemory(&bi, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = width; + bi.bmiHeader.biHeight = -height; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + data->hbm = CreateDIBSection(dpy, &bi, DIB_RGB_COLORS, + (LPVOID *)&data->pbBits, NULL, 0); + return data; +} + +Pixmap XCreateBitmapFromData( + Display* dpy, Drawable d, + const char* data, + unsigned int width, unsigned int height) +{ + assert(0); + return 0; +} + +Pixmap XCreatePixmapFromBitmapData( + Display* dpy, Drawable d, + char* data, + unsigned int width, unsigned int height, + unsigned long fg, unsigned long bg, + unsigned int depth) +{ + Pixmap pixmap; + XImage *ximage; + GC gc; + + ximage = XCreateImage(dpy, NULL, depth, ZPixmap, + 0, data, width, height, 8, 0); + pixmap = XCreatePixmap(dpy, d, width, height, 32); + + gc = XCreateGC(dpy, pixmap, 0, NULL); + XPutImage(dpy, pixmap, gc, ximage, 0, 0, 0, 0, width, height); + XFreeGC(dpy, gc); + + return 0; +} + +int XFreePixmap(Display *dpy, Pixmap pixmap) +{ + DrawableData *data = XGetDrawableData_(pixmap); + DeleteObject(data->hbm); + free(data); + return 0; +} + +XPixmapFormatValues *XListPixmapFormats(Display *dpy, int *count) +{ + XPixmapFormatValues *values; + assert(count != NULL); + *count = 0; + values = (XPixmapFormatValues *)calloc(1, sizeof(XPixmapFormatValues)); + if (values != NULL) + { + values->depth = 32; + values->bits_per_pixel = 32; + *count = 1; + } + return values; +} diff --git a/screenhack.c b/screenhack.c new file mode 100644 index 0000000..91ce9d4 --- /dev/null +++ b/screenhack.c @@ -0,0 +1,717 @@ +#include "screenhack.h" +#include "resource.h" + +#ifdef _UNICODE + #pragma comment(lib, "scrnsavw.lib") +#else + #pragma comment(lib, "scrnsave.lib") +#endif + +////////////////////////////////////////////////////////////////////////////// + +SCREENSAVER ss; +Bool mono_p = False; + +static LPCSTR pszCompany = "Software\\Katayama Hirofumi MZ"; + +////////////////////////////////////////////////////////////////////////////// +// sz_trim + +void sz_trim(char *psz) +{ + int len; + char *pch = psz; + + while (*pch == ' ' || *pch == '\n') + pch++; + + memmove(psz, pch, strlen(pch) + 1); + + len = strlen(psz); + if (len == 0) + return; + + pch = psz + len; + do + { + pch--; + } while (psz <= pch && (*pch == ' ' || *pch == '\n')); + + pch[1] = '\0'; +} + +////////////////////////////////////////////////////////////////////////////// +// CenterDialog + +VOID CenterDialog(HWND hwnd) +{ + POINT pt; + HWND hwndOwner; + RECT rc, rcOwner; + BOOL bChild = !!(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD); + + if (bChild) + hwndOwner = GetParent(hwnd); + else + hwndOwner = GetWindow(hwnd, GW_OWNER); + + if (hwndOwner != NULL) + GetWindowRect(hwndOwner, &rcOwner); + else + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcOwner, 0); + + GetWindowRect(hwnd, &rc); + + pt.x = rcOwner.left + + ((rcOwner.right - rcOwner.left) - (rc.right - rc.left)) / 2; + pt.y = rcOwner.top + + ((rcOwner.bottom - rcOwner.top) - (rc.bottom - rc.top)) / 2; + + if (bChild && hwndOwner != NULL) + ScreenToClient(hwndOwner, &pt); + + SetWindowPos(hwnd, NULL, pt.x, pt.y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + SendMessage(hwnd, DM_REPOSITION, 0, 0); +} + +////////////////////////////////////////////////////////////////////////////// +// setting + +VOID LoadSetting(VOID) +{ + HKEY hCompanyKey, hSoftwareKey; + LONG result; + INT i; + CHAR szValue[256]; + DWORD cb; + + result = RegOpenKeyExA(HKEY_CURRENT_USER, pszCompany, 0, + KEY_READ, &hCompanyKey); + if (result != ERROR_SUCCESS) + return; + + result = RegOpenKeyExA(hCompanyKey, progname, 0, + KEY_READ, &hSoftwareKey); + if (result == ERROR_SUCCESS) + { + // load args + for (i = 0; i < hack_argcount; i++) + { + cb = 256 * sizeof(CHAR); + result = RegQueryValueExA(hSoftwareKey, + hack_arginfo[i].name, NULL, NULL, szValue, &cb); + if (result == ERROR_SUCCESS) + { + switch (hack_arginfo[i].type) + { + case t_Bool: + if (lstrcmpiA(szValue, "True") == 0 || lstrcmpiA(szValue, "1") == 0) + *(Bool *)hack_arginfo[i].data = True; + if (lstrcmpiA(szValue, "False") == 0 || lstrcmpiA(szValue, "0") == 0) + *(Bool *)hack_arginfo[i].data = False; + break; + + case t_Int: + *(INT *)hack_arginfo[i].data = strtol(szValue, NULL, 10); + break; + + case t_Float: + *(float *)hack_arginfo[i].data = strtod(szValue, NULL); + break; + + case t_String: + *(char **)hack_arginfo[i].data = _strdup(szValue); + break; + } + } + } + RegCloseKey(hSoftwareKey); + } + RegCloseKey(hCompanyKey); +} + +VOID GetSetting(HWND hwnd) +{ + int i; + CHAR buf[256]; + for (i = 0; i < hack_argcount; i++) + { + GetDlgItemTextA(hwnd, IDC_ARGVAL00 + i, buf, 256); + sz_trim(buf); + switch (hack_arginfo[i].type) + { + case t_Bool: + if (lstrcmpiA(buf, "True") == 0 || lstrcmpiA(buf, "1") == 0 ) + *(Bool *)hack_arginfo[i].data = True; + else if (lstrcmpiA(buf, "False") == 0 || lstrcmpiA(buf, "0") == 0 ) + *(Bool *)hack_arginfo[i].data = False; + break; + + case t_Int: + *(INT *)hack_arginfo[i].data = strtol(buf, NULL, 10); + break; + + case t_Float: + *(float *)hack_arginfo[i].data = strtod(buf, NULL); + break; + + case t_String: + *(char **)hack_arginfo[i].data = _strdup(buf); + break; + } + } +} + +VOID ResetSetting(HWND hwnd) +{ + HKEY hCompanyKey; + LONG result; + + result = RegOpenKeyExA(HKEY_CURRENT_USER, pszCompany, 0, + KEY_ALL_ACCESS, &hCompanyKey); + if (result != ERROR_SUCCESS) + return; + + RegDeleteKey(hCompanyKey, progname); + RegCloseKey(hCompanyKey); +} + +VOID SaveSetting(VOID) +{ + HKEY hCompanyKey, hSoftwareKey; + LONG result; + INT i, n; + DWORD dwDisp, dwSize; + float e; + CHAR szValue[256]; + + result = RegCreateKeyExA(HKEY_CURRENT_USER, pszCompany, 0, + NULL, 0, KEY_ALL_ACCESS, NULL, &hCompanyKey, &dwDisp); + if (result != ERROR_SUCCESS) + return; + + result = RegCreateKeyExA(hCompanyKey, progname, 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &hSoftwareKey, &dwDisp); + if (result == ERROR_SUCCESS) + { + for (i = 0; i < hack_argcount; i++) + { + switch (hack_arginfo[i].type) + { + case t_Bool: + if (*(Bool *)hack_arginfo[i].data) + strcpy(szValue, "True"); + else + strcpy(szValue, "False"); + break; + + case t_Int: + n = *(INT *)hack_arginfo[i].data; + sprintf(szValue, "%d", n); + break; + + case t_Float: + e = *(float *)hack_arginfo[i].data; + sprintf(szValue, "%g", e); + break; + + case t_String: + strcpy(szValue, *(char **)hack_arginfo[i].data); + break; + } + dwSize = (strlen(szValue) + 1) * sizeof(CHAR); + RegSetValueExA(hSoftwareKey, hack_arginfo[i].name, + 0, REG_SZ, (LPBYTE)szValue, dwSize); + } + RegCloseKey(hSoftwareKey); + } + RegCloseKey(hCompanyKey); +} + +////////////////////////////////////////////////////////////////////////////// +// GetScreenShotBitmap + +HBITMAP GetScreenShotBitmap(VOID) +{ + HWND hwnd; + HDC hdc, hdcMem; + HBITMAP hbm; + HGDIOBJ hbmOld; + BITMAPINFO bi; + INT y, cx, cy, count; + LPVOID pvBits; + LPBYTE pb, pbBits; + + cx = GetSystemMetrics(SM_CXSCREEN); + cy = GetSystemMetrics(SM_CYSCREEN); + + hwnd = GetDesktopWindow(); + hdc = GetWindowDC(hwnd); + hdcMem = CreateCompatibleDC(hdc); + + ZeroMemory(&bi, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = cx; + bi.bmiHeader.biHeight = cy; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + hbm = CreateDIBSection(hdcMem, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0); + if (hbm != NULL) + { + hbmOld = SelectObject(hdcMem, hbm); + SetStretchBltMode(hdcMem, COLORONCOLOR); + StretchBlt(hdcMem, 0, 0, cx, cy, hdc, 0, 0, cx, cy, SRCCOPY); + SelectObject(hdcMem, hbmOld); + GdiFlush(); + pbBits = (LPBYTE)pvBits; + count = cx * cy; + while (count--) + { + BYTE b = pbBits[0]; + pbBits[0] = pbBits[2]; + pbBits[2] = b; + pbBits++; + pbBits++; + pbBits++; + *pbBits++ = 0xFF; + } + pb = (LPBYTE)malloc(cx * 4); + pbBits = (LPBYTE)pvBits; + for (y = 0; y < cy / 2; y++) + { + memcpy(pb, &pbBits[y * cx * 4], cx * 4); + memcpy(&pbBits[y * cx * 4], &pbBits[(cy - y - 1) * cx * 4], cx * 4); + memcpy(&pbBits[(cy - y - 1) * cx * 4], pb, cx * 4); + } + free(pb); + } + + DeleteDC(hdcMem); + ReleaseDC(hwnd, hdc); + return hbm; +} + +////////////////////////////////////////////////////////////////////////////// +// SaveBitmapToFile + +typedef struct tagBITMAPINFOEX +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +} BITMAPINFOEX, *LPBITMAPINFOEX; + +BOOL SaveBitmapToFile(LPCTSTR pszFileName, HBITMAP hbm) +{ + BOOL f; + BITMAPFILEHEADER bf; + BITMAPINFOEX bi; + BITMAPINFOHEADER *pbmih; + DWORD cb; + DWORD cColors, cbColors; + HDC hDC; + HANDLE hFile; + LPVOID pBits; + BITMAP bm; + DWORD dwError = 0; + + if (!GetObject(hbm, sizeof(BITMAP), &bm)) + return FALSE; + + pbmih = &bi.bmiHeader; + ZeroMemory(pbmih, sizeof(BITMAPINFOHEADER)); + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = bm.bmWidth; + pbmih->biHeight = bm.bmHeight; + pbmih->biPlanes = 1; + pbmih->biBitCount = bm.bmBitsPixel; + pbmih->biCompression = BI_RGB; + pbmih->biSizeImage = bm.bmWidthBytes * bm.bmHeight; + + if (bm.bmBitsPixel < 16) + cColors = 1 << bm.bmBitsPixel; + else + cColors = 0; + cbColors = cColors * sizeof(RGBQUAD); + + bf.bfType = 0x4d42; + bf.bfReserved1 = 0; + bf.bfReserved2 = 0; + cb = sizeof(BITMAPFILEHEADER) + pbmih->biSize + cbColors; + bf.bfOffBits = cb; + bf.bfSize = cb + pbmih->biSizeImage; + + pBits = HeapAlloc(GetProcessHeap(), 0, pbmih->biSizeImage); + if (pBits == NULL) + return FALSE; + + f = FALSE; + hDC = GetDC(NULL); + if (hDC != NULL) + { + if (GetDIBits(hDC, hbm, 0, bm.bmHeight, pBits, (BITMAPINFO*)&bi, + DIB_RGB_COLORS)) + { + hFile = CreateFile(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_WRITE_THROUGH, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + f = WriteFile(hFile, &bf, sizeof(BITMAPFILEHEADER), &cb, NULL) && + WriteFile(hFile, &bi, sizeof(BITMAPINFOHEADER), &cb, NULL) && + WriteFile(hFile, bi.bmiColors, cbColors, &cb, NULL) && + WriteFile(hFile, pBits, pbmih->biSizeImage, &cb, NULL); + if (!f) + dwError = GetLastError(); + CloseHandle(hFile); + + if (!f) + DeleteFile(pszFileName); + } + else + dwError = GetLastError(); + } + else + dwError = GetLastError(); + ReleaseDC(NULL, hDC); + } + else + dwError = GetLastError(); + + HeapFree(GetProcessHeap(), 0, pBits); + SetLastError(dwError); + return f; +} + +////////////////////////////////////////////////////////////////////////////// +// screen saver + +BOOL ss_init(HWND hwnd) +{ + RECT rc; + + ss.hwnd = hwnd; + + GetClientRect(hwnd, &rc); + ss.x0 = rc.left; + ss.y0 = rc.top; + assert(ss.x0 == 0); + assert(ss.y0 == 0); + ss.width = rc.right - rc.left; + ss.height = rc.bottom - rc.top; + if (ss.width == 0 || ss.height == 0) + return FALSE; + + ss.hdc = GetWindowDC(hwnd); + if (ss.hdc == NULL) + return FALSE; + + if (!InitPixelFormat(&ss)) + { + ReleaseDC(hwnd, ss.hdc); + return FALSE; + } + + ss.hbmScreenShot = GetScreenShotBitmap(); + if (ss.hbmScreenShot == NULL) + { + ReleaseDC(hwnd, ss.hdc); + return FALSE; + } + //SaveBitmapToFile("screenshot.bmp", ss.hbmScreenShot); + + MakeCurrent(&ss); + ss.dpy = ss.hdc; + ss.window = 0; + ss.xgwa.width = ss.width; + ss.xgwa.height = ss.height; + ss.xgwa.depth = 32; + ss.xgwa.visual = NULL; + ss.xgwa.colormap = 0; + ss.xgwa.screen = 0; + + LoadSetting(); + +#undef ya_rand_init + ya_rand_init(0); + ss.closure = hack_init(ss.dpy, ss.window); + + return TRUE; +} + +BOOL WINAPI RegisterDialogClasses(HANDLE hInst) +{ + return TRUE; +} + +VOID OnInitDialog(HWND hwnd) +{ + int i, n; + double e; + char buf[64], *p; + HICON hIcon; + + // set big icon + hIcon = LoadIconA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1)); + SendMessageA(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + // set small icon + hIcon = (HICON)LoadImageA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); + SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + // set window title + SetWindowText(hwnd, progname); + + for (i = 0; i < hack_argcount; i++) + { + SetDlgItemTextA(hwnd, IDC_ARGNAME00 + i, hack_arginfo[i].name); + + switch (hack_arginfo[i].type) + { + case t_Bool: + if (*(Bool *)hack_arginfo[i].data) + SetDlgItemTextA(hwnd, IDC_ARGVAL00 + i, "True"); + else + SetDlgItemTextA(hwnd, IDC_ARGVAL00 + i, "False"); + break; + + case t_Int: + n = *(INT *)hack_arginfo[i].data; + SetDlgItemInt(hwnd, IDC_ARGVAL00 + i, n, TRUE); + break; + + case t_Float: + e = *(float *)hack_arginfo[i].data; + sprintf(buf, "%g", e); + SetDlgItemTextA(hwnd, IDC_ARGVAL00 + i, buf); + break; + + case t_String: + p = *(char **)hack_arginfo[i].data; + SetDlgItemTextA(hwnd, IDC_ARGVAL00 + i, p); + break; + } + } + + for (; i <= 23; i++) + { + ShowWindow(GetDlgItem(hwnd, IDC_ARGNAME00 + i), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, IDC_ARGVAL00 + i), SW_HIDE); + } + + ShowWindow(GetDlgItem(hwnd, IDC_COUNTNAME), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, IDC_COUNTVAL), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, IDC_CYCLESNAME), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, IDC_CYCLESVAL), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, IDC_SIZENAME), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, IDC_SIZEVAL), SW_HIDE); + + CenterDialog(hwnd); +} + +BOOL WINAPI ScreenSaverConfigureDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + LoadSetting(); + OnInitDialog(hWnd); + return TRUE; + + case WM_CLOSE: + EndDialog(hWnd, 0); + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + GetSetting(hWnd); + SaveSetting(); + EndDialog(hWnd, 0); + break; + + case IDC_RESET: + ResetSetting(hWnd); + EndDialog(hWnd, 0); + break; + + case IDCANCEL: + EndDialog(hWnd, 0); + break; + } + break; + } + return FALSE; +} + +LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + unsigned long ul; + switch(uMsg) + { + case WM_CREATE: + if (ss_init(hWnd) == 0) + return -1; + + SetTimer(hWnd, 999, 0, NULL); + break; + + case WM_DESTROY: + KillTimer(hWnd, 999); + ss_term(); + break; + + case WM_TIMER: + KillTimer(hWnd, 999); + ul = hack_draw(ss.dpy, ss.window, ss.closure); + SetTimer(hWnd, 999, ul / 1000, NULL); + break; + + default: + return DefScreenSaverProc(hWnd, uMsg, wParam, lParam); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +Display *DisplayOfScreen(Screen *s) +{ + return ss.dpy; +} + +extern unsigned long window_background; + +int XClearWindow(Display *dpy, Window w) +{ + RECT rc; + HDC hdc = (HDC)dpy; + HWND hwnd = WindowFromDC(hdc); + XColor color; + HBRUSH hbr; + + GetClientRect(hwnd, &rc); + color.pixel = window_background; + XQueryColor(dpy, DefaultColormap(dpy, DefaultScreenOfDisplay(dpy)), &color); + hbr = CreateSolidBrush(RGB(color.red / 255, color.green / 255, color.blue / 255)); + FillRect(hdc, &rc, hbr); + DeleteObject(hbr); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// misc + +#if 0 + void do_fps(ModeInfo *mi) + { + } +#endif + +float current_device_rotation(void) +{ + return 0.0; +} + +Bool has_writable_cells(Screen *s, Visual *v) +{ + return False; +} + +int ffs(int i) +{ + int j; + + if (i == 0) + return 0; + for (j = 1; (i & 1) == 0; j++) + i >>= 1; + return j; +} + +int visual_depth(Screen *screen, Visual *visual) +{ + return 32; +} + +////////////////////////////////////////////////////////////////////////////// + +BOOL InitPixelFormat(SCREENSAVER *ss) +{ + return TRUE; +} + +VOID MakeCurrent(SCREENSAVER *ss) +{ +} + +void ss_term(void) +{ + hack_free(ss.dpy, ss.window, ss.closure); + ReleaseDC(ss.hwnd, ss.hdc); + DeleteObject(ss.hbmScreenShot); +} + +void ss_clear(Display *d) +{ + XClearWindow(d, 0); +} + +Status XGetWindowAttributes(Display *dpy, Window w, XWindowAttributes *attr) +{ + *attr = ss.xgwa; + return 0; +} + +void gettimeofday(timeval *t, timezone *tz) +{ + DWORD dwTick = GetTickCount(); + t->tv_sec = dwTick / 1000; + t->tv_usec = (dwTick % 1000) * 1000; +} + +////////////////////////////////////////////////////////////////////////////// +// message box output + +#ifndef NOMSGBOXOUTPUT + #undef fprintf + #undef abort + #undef exit + + static CHAR s_szBuffer[2048] = ""; + + int __cdecl win32_fprintf(FILE *fp, const char *fmt, ...) + { + CHAR sz[512]; + va_list va; + int n; + va_start(va, fmt); + n = wvsprintf(sz, fmt, va); + va_end(va); + lstrcatA(s_szBuffer, sz); + return n; + } + + void __cdecl win32_abort(void) + { + keybd_event(VK_SHIFT, 0, 0, 0); + keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); + + MessageBoxA(NULL, s_szBuffer, progname, MB_ICONERROR); + exit(-1); + } + + int __cdecl win32_exit(int n) + { + keybd_event(VK_SHIFT, 0, 0, 0); + keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); + + MessageBoxA(NULL, s_szBuffer, progname, MB_ICONERROR); + exit(n); + } +#endif // def MSGBOXOUTPUT + +////////////////////////////////////////////////////////////////////////////// diff --git a/screenhack.h b/screenhack.h new file mode 100644 index 0000000..5060cee --- /dev/null +++ b/screenhack.h @@ -0,0 +1,133 @@ +#ifndef __SCREENHACK_H__ +#define __SCREENHACK_H__ + +#ifndef __XWS2WIN_H__ + #include "xws2win.h" +#endif + +#include +#include "yarandom.h" +#include "colors.h" +#include "hsv.h" + +extern const char *progname; +extern Bool mono_p; + +#ifndef NOMSGBOXOUTPUT + int __cdecl win32_fprintf(FILE *fp, const char *fmt, ...); + void __cdecl win32_abort(void); + int __cdecl win32_exit(int n); + + #define fprintf win32_fprintf + #define abort win32_abort + #define exit win32_exit +#endif + +#define inline /*empty*/ +#define GETTIMEOFDAY_TWO_ARGS 1 + +////////////////////////////////////////////////////////////////////////////// + +typedef struct screenhack_timeval +{ + DWORD tv_sec; + DWORD tv_usec; +} screenhack_timeval; + +typedef struct screenhack_timezone +{ + char dummy; +} screenhack_timezone; + +#define timeval screenhack_timeval +#define timezone screenhack_timezone + +#define HAVE_GETTIMEOFDAY 1 +void gettimeofday(timeval *t, timezone *tz); + +////////////////////////////////////////////////////////////////////////////// + +typedef enum +{ + t_Bool, t_Int, t_Float, t_String +} argdatatype; + +typedef struct +{ + void *data; + char *name; + char *text; + char *def; + argdatatype type; +} argtype; + +////////////////////////////////////////////////////////////////////////////// + +#define XSCREENSAVER_LINK(NAME) + +typedef void *(*HACK_INIT)(Display *, Window); +typedef unsigned long (*HACK_DRAW)(Display *, Window, void *); +typedef void (*HACK_RESHAPE)(Display *, Window, void *, unsigned int, unsigned int); +typedef void (*HACK_FREE)(Display *, Window, void *); + +extern HACK_INIT hack_init; +extern HACK_DRAW hack_draw; +extern HACK_RESHAPE hack_reshape; +extern HACK_FREE hack_free; +extern int hack_argcount; +extern argtype *hack_arginfo; + +#ifdef NOARGS + #define XSCREENSAVER_MODULE_2(CLASS,NAME,PREFIX) \ + const char *progname = #NAME; \ + HACK_INIT hack_init = PREFIX ## _init; \ + HACK_DRAW hack_draw = PREFIX ## _draw; \ + HACK_RESHAPE hack_reshape = PREFIX ## _reshape; \ + HACK_FREE hack_free = PREFIX ## _free; \ + int hack_argcount = 0; \ + argtype *hack_arginfo = NULL; +#else + #define XSCREENSAVER_MODULE_2(CLASS,NAME,PREFIX) \ + const char *progname = #NAME; \ + HACK_INIT hack_init = PREFIX ## _init; \ + HACK_DRAW hack_draw = PREFIX ## _draw; \ + HACK_RESHAPE hack_reshape = PREFIX ## _reshape; \ + HACK_FREE hack_free = PREFIX ## _free; \ + int hack_argcount = sizeof(vars) / sizeof(vars[0]); \ + argtype *hack_arginfo = vars; +#endif + +#define XSCREENSAVER_MODULE(CLASS,PREFIX) \ + XSCREENSAVER_MODULE_2(CLASS,PREFIX,PREFIX) + +////////////////////////////////////////////////////////////////////////////// +// screen saver + +typedef struct SCREENSAVER +{ + HWND hwnd; + HDC hdc; + HGLRC hglrc; + UINT x0, y0; + UINT width, height; + HBITMAP hbmScreenShot; + Display *dpy; + Window window; + XWindowAttributes xgwa; + void *closure; +} SCREENSAVER; + +extern SCREENSAVER ss; + +BOOL InitPixelFormat(SCREENSAVER *ss); +VOID MakeCurrent(SCREENSAVER *ss); +XImage *GetScreenShotXImage(void); +BOOL ss_init(HWND hwnd); +void ss_term(void); +void ss_clear(Display *d); +Bool has_writable_cells(Screen *s, Visual *v); +int visual_depth(Screen *screen, Visual *visual); + +////////////////////////////////////////////////////////////////////////////// + +#endif /* __SCREENHACK_H__ */ diff --git a/win32screensaver.rc b/screenhack.rc similarity index 100% rename from win32screensaver.rc rename to screenhack.rc diff --git a/src_only.bat b/src_only.bat new file mode 100644 index 0000000..c5260d7 --- /dev/null +++ b/src_only.bat @@ -0,0 +1,6 @@ +cd wgl +call src_only.bat +cd .. +cd non-wgl +call src_only.bat +cd .. diff --git a/wgl/antinspect.c b/wgl/antinspect.c index 23b9e0f..161a8bb 100644 --- a/wgl/antinspect.c +++ b/wgl/antinspect.c @@ -41,7 +41,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "sphere.h" #include "gltrackball.h" diff --git a/wgl/antinspect.vcproj b/wgl/antinspect.vcproj index f96119c..e493c63 100644 --- a/wgl/antinspect.vcproj +++ b/wgl/antinspect.vcproj @@ -191,7 +191,7 @@ > + + @@ -231,7 +235,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/antmaze.c b/wgl/antmaze.c index 55df714..fdee11b 100644 --- a/wgl/antmaze.c +++ b/wgl/antmaze.c @@ -49,7 +49,7 @@ static const char sccsid[] = "@(#)antmaze.c 5.01 2001/03/01 xlockmore"; #ifdef MODE_antmaze -#include "xws2win.h" +#include "xlockmore.h" #include "sphere.h" #include "tube.h" #include "rotator.h" diff --git a/wgl/antmaze.vcproj b/wgl/antmaze.vcproj index cdabe60..dab77af 100644 --- a/wgl/antmaze.vcproj +++ b/wgl/antmaze.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/antspotlight.c b/wgl/antspotlight.c index 934e356..fe31d08 100644 --- a/wgl/antspotlight.c +++ b/wgl/antspotlight.c @@ -42,7 +42,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "sphere.h" #include "tube.h" #include "rotator.h" diff --git a/wgl/antspotlight.vcproj b/wgl/antspotlight.vcproj index 1e072de..20c9621 100644 --- a/wgl/antspotlight.vcproj +++ b/wgl/antspotlight.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/atlantis.c b/wgl/atlantis.c index a75cfa6..51f0586 100644 --- a/wgl/atlantis.c +++ b/wgl/atlantis.c @@ -126,7 +126,7 @@ static const char sccsid[] = "@(#)atlantis.c 5.08 2003/04/09 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL @@ -182,16 +182,10 @@ static void parse_image_data(ModeInfo *mi) { atlantisstruct *ap = &atlantis[MI_SCREEN(mi)]; -#if 0 ap->texture = xpm_to_ximage (mi->dpy, mi->xgwa.visual, mi->xgwa.colormap, sea_texture); -#endif - ap->texture = xpm_to_ximage (mi->dpy, - NULL, - DefaultColormap(mi->dpy, mi->window), - sea_texture); } static void diff --git a/wgl/atlantis.h b/wgl/atlantis.h index 6d98f76..fd4e4da 100644 --- a/wgl/atlantis.h +++ b/wgl/atlantis.h @@ -89,7 +89,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #define RAD 57.295 #define RRAD 0.01745 diff --git a/wgl/atlantis.vcproj b/wgl/atlantis.vcproj index af5d22c..152dbd7 100644 --- a/wgl/atlantis.vcproj +++ b/wgl/atlantis.vcproj @@ -207,7 +207,7 @@ > + + @@ -263,7 +267,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/atunnel.c b/wgl/atunnel.c index 5252eeb..2280bfa 100644 --- a/wgl/atunnel.c +++ b/wgl/atunnel.c @@ -54,7 +54,7 @@ static const char sccsid[] = "@(#)atunnel.c 5.13 2004/05/25 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef MODE_atunnel /* whole file */ diff --git a/wgl/atunnel.vcproj b/wgl/atunnel.vcproj index e70ea1a..0a44a36 100644 --- a/wgl/atunnel.vcproj +++ b/wgl/atunnel.vcproj @@ -203,7 +203,7 @@ > + + @@ -267,7 +271,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/blinkbox.c b/wgl/blinkbox.c index 898873a..0132b18 100644 --- a/wgl/blinkbox.c +++ b/wgl/blinkbox.c @@ -22,7 +22,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "sphere.h" diff --git a/wgl/blinkbox.vcproj b/wgl/blinkbox.vcproj index b005012..746cead 100644 --- a/wgl/blinkbox.vcproj +++ b/wgl/blinkbox.vcproj @@ -199,7 +199,7 @@ > + + @@ -247,7 +251,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/blocktube.c b/wgl/blocktube.c index a1e0fba..09ff3ce 100644 --- a/wgl/blocktube.c +++ b/wgl/blocktube.c @@ -23,7 +23,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "colors.h" #include diff --git a/wgl/blocktube.vcproj b/wgl/blocktube.vcproj index 43e22cd..e1616a5 100644 --- a/wgl/blocktube.vcproj +++ b/wgl/blocktube.vcproj @@ -191,7 +191,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/boing.c b/wgl/boing.c index 3a1dc38..bffa890 100644 --- a/wgl/boing.c +++ b/wgl/boing.c @@ -31,7 +31,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "gltrackball.h" #include diff --git a/wgl/boing.vcproj b/wgl/boing.vcproj index 2e84173..dc5df60 100644 --- a/wgl/boing.vcproj +++ b/wgl/boing.vcproj @@ -187,7 +187,7 @@ > + + @@ -227,7 +231,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/bouncingcow.c b/wgl/bouncingcow.c index b9c6d94..8177301 100644 --- a/wgl/bouncingcow.c +++ b/wgl/bouncingcow.c @@ -31,7 +31,7 @@ #undef RANDSIGN #define RANDSIGN() ((random() & 1) ? 1 : -1) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "rotator.h" #include "gltrackball.h" diff --git a/wgl/bouncingcow.vcproj b/wgl/bouncingcow.vcproj index c8a2d3f..b4a9ce3 100644 --- a/wgl/bouncingcow.vcproj +++ b/wgl/bouncingcow.vcproj @@ -223,7 +223,7 @@ > + + @@ -283,7 +287,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/boxed.c b/wgl/boxed.c index b6cad7b..5c99348 100644 --- a/wgl/boxed.c +++ b/wgl/boxed.c @@ -32,7 +32,7 @@ static const char sccsid[] = "@(#)boxed.c 0.9 01/09/26 xlockmore"; * */ -#include "xws2win.h" +#include "xlockmore.h" #include "boxed.h" diff --git a/wgl/boxed.vcproj b/wgl/boxed.vcproj index 01c211d..eb7eb1e 100644 --- a/wgl/boxed.vcproj +++ b/wgl/boxed.vcproj @@ -187,7 +187,7 @@ > + + @@ -227,7 +231,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/buildlwo.c b/wgl/buildlwo.c index 7b63247..f93f97c 100644 --- a/wgl/buildlwo.c +++ b/wgl/buildlwo.c @@ -16,7 +16,7 @@ static const char sccsid[] = "@(#)buildlwo.c 4.02 97/04/20 xlockmore"; * */ -#include "xws2win.h" +#include "xlockmore.h" #if 0 #ifndef STANDALONE diff --git a/wgl/cage.c b/wgl/cage.c index 6688ce8..62ee5fe 100644 --- a/wgl/cage.c +++ b/wgl/cage.c @@ -94,7 +94,7 @@ static const char sccsid[] = "@(#)cage.c 5.01 2001/03/01 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef MODE_cage diff --git a/wgl/cage.vcproj b/wgl/cage.vcproj index 8eb7d6f..304fc32 100644 --- a/wgl/cage.vcproj +++ b/wgl/cage.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/chessmodels.c b/wgl/chessmodels.c index 3bc95a0..9a32c4e 100644 --- a/wgl/chessmodels.c +++ b/wgl/chessmodels.c @@ -44,7 +44,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "chessmodels.h" /* End of Data */ diff --git a/wgl/clean.bat b/wgl/clean.bat new file mode 100644 index 0000000..a0aa884 --- /dev/null +++ b/wgl/clean.bat @@ -0,0 +1,30 @@ +if exist *.user del *.user +if exist *.ncb del *.ncb +if exist *.suo del *.suo +if exist *.suo del /A:H *.suo + +if not exist Debug goto skip1 +cd Debug +if exist *.obj del *.obj +if exist *.pdb del *.pdb +if exist *.idb del *.idb +if exist *.ilk del *.ilk +if exist *.mani* del *.mani* +if exist *.res del *.res +if exist BuildLog.htm del BuildLog.htm +if exist mt.dep del mt.dep +cd .. +:skip1 + +if not exist Release goto skip2 +cd Release +if exist *.obj del *.obj +if exist *.pdb del *.pdb +if exist *.idb del *.idb +if exist *.ilk del *.ilk +if exist *.mani* del *.mani* +if exist *.res del *.res +if exist BuildLog.htm del BuildLog.htm +if exist mt.dep del mt.dep +cd .. +:skip2 diff --git a/wgl/companion.c b/wgl/companion.c index 59261eb..01fdda5 100644 --- a/wgl/companion.c +++ b/wgl/companion.c @@ -41,7 +41,7 @@ #undef RANDSIGN #define RANDSIGN() ((random() & 1) ? 1 : -1) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "rotator.h" #include "gltrackball.h" diff --git a/wgl/companion.vcproj b/wgl/companion.vcproj index 250d682..7194d5d 100644 --- a/wgl/companion.vcproj +++ b/wgl/companion.vcproj @@ -211,7 +211,7 @@ > + + @@ -271,7 +275,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/crackberg.c b/wgl/crackberg.c index 2dcbf54..70b1241 100644 --- a/wgl/crackberg.c +++ b/wgl/crackberg.c @@ -19,7 +19,7 @@ //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/crackberg.vcproj b/wgl/crackberg.vcproj index c52d102..d7a113f 100644 --- a/wgl/crackberg.vcproj +++ b/wgl/crackberg.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/cube21.c b/wgl/cube21.c index f681ccd..a105e0c 100644 --- a/wgl/cube21.c +++ b/wgl/cube21.c @@ -48,7 +48,7 @@ # define refresh_cube21 0 -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "gltrackball.h" diff --git a/wgl/cube21.vcproj b/wgl/cube21.vcproj index 8060d92..0d7f2cd 100644 --- a/wgl/cube21.vcproj +++ b/wgl/cube21.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/cubenetic.c b/wgl/cubenetic.c index 0748573..7b09425 100644 --- a/wgl/cubenetic.c +++ b/wgl/cubenetic.c @@ -23,7 +23,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "rotator.h" #include "gltrackball.h" diff --git a/wgl/cubenetic.vcproj b/wgl/cubenetic.vcproj index 4cfa3e6..822bd23 100644 --- a/wgl/cubenetic.vcproj +++ b/wgl/cubenetic.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/cubestorm.c b/wgl/cubestorm.c index 0a0fc5b..ffabf2c 100644 --- a/wgl/cubestorm.c +++ b/wgl/cubestorm.c @@ -24,7 +24,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "colors.h" #include "rotator.h" diff --git a/wgl/cubestorm.vcproj b/wgl/cubestorm.vcproj index f02229b..c6cad78 100644 --- a/wgl/cubestorm.vcproj +++ b/wgl/cubestorm.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/cubicgrid.c b/wgl/cubicgrid.c index fe7f6ed..6c64aa4 100644 --- a/wgl/cubicgrid.c +++ b/wgl/cubicgrid.c @@ -27,7 +27,7 @@ # define refresh_cubicgrid 0 //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/cubicgrid.vcproj b/wgl/cubicgrid.vcproj index 3fb7421..6841887 100644 --- a/wgl/cubicgrid.vcproj +++ b/wgl/cubicgrid.vcproj @@ -191,7 +191,7 @@ > + + @@ -231,7 +235,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/dangerball.c b/wgl/dangerball.c index 7e6ac2e..5bb7866 100644 --- a/wgl/dangerball.c +++ b/wgl/dangerball.c @@ -22,7 +22,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "sphere.h" #include "tube.h" diff --git a/wgl/dangerball.vcproj b/wgl/dangerball.vcproj index af1dfb6..5780349 100644 --- a/wgl/dangerball.vcproj +++ b/wgl/dangerball.vcproj @@ -207,7 +207,7 @@ > + + @@ -267,7 +271,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/dnalogo.c b/wgl/dnalogo.c index c058edf..1e1f457 100644 --- a/wgl/dnalogo.c +++ b/wgl/dnalogo.c @@ -68,7 +68,7 @@ # define cone dxf_cone #endif /* DXF_OUTPUT_HACK */ -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "normals.h" #include "tube.h" diff --git a/wgl/dnalogo.vcproj b/wgl/dnalogo.vcproj index 7f39d70..9795f45 100644 --- a/wgl/dnalogo.vcproj +++ b/wgl/dnalogo.vcproj @@ -195,7 +195,7 @@ > + + @@ -247,7 +251,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/dolphin.c b/wgl/dolphin.c index c1cfebc..31cad37 100644 --- a/wgl/dolphin.c +++ b/wgl/dolphin.c @@ -72,7 +72,7 @@ static const char sccsid[] = "@(#)dolphin.c 1.2 98/06/16 xlockmore"; * OpenGL(TM) is a trademark of Silicon Graphics, Inc. */ -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/endgame.c b/wgl/endgame.c index d74f297..3875a61 100644 --- a/wgl/endgame.c +++ b/wgl/endgame.c @@ -30,7 +30,7 @@ #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/endgame.vcproj b/wgl/endgame.vcproj index f0afd53..8efc998 100644 --- a/wgl/endgame.vcproj +++ b/wgl/endgame.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/extrusion.c b/wgl/extrusion.c index b45c2e6..83311cc 100644 --- a/wgl/extrusion.c +++ b/wgl/extrusion.c @@ -50,7 +50,7 @@ #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/extrusion.h b/wgl/extrusion.h index cffe4e9..278515a 100644 --- a/wgl/extrusion.h +++ b/wgl/extrusion.h @@ -39,7 +39,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include extern void InitStuff_helix2(void); diff --git a/wgl/extrusion.vcproj b/wgl/extrusion.vcproj index 7318cd1..0c2efc4 100644 --- a/wgl/extrusion.vcproj +++ b/wgl/extrusion.vcproj @@ -120,7 +120,7 @@ EnableIntrinsicFunctions="true" AdditionalIncludeDirectories=".." PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" - RuntimeLibrary="2" + RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" @@ -223,15 +223,15 @@ > + + @@ -283,7 +287,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/flipflop.c b/wgl/flipflop.c index 446523e..d79eba5 100644 --- a/wgl/flipflop.c +++ b/wgl/flipflop.c @@ -53,7 +53,7 @@ #endif /* STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/flipflop.vcproj b/wgl/flipflop.vcproj index c07456a..ea3c9f4 100644 --- a/wgl/flipflop.vcproj +++ b/wgl/flipflop.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/flipscreen3d.c b/wgl/flipscreen3d.c index df80a32..e15b452 100644 --- a/wgl/flipscreen3d.c +++ b/wgl/flipscreen3d.c @@ -31,7 +31,7 @@ #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" /* lifted from lament.c */ #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n)))) diff --git a/wgl/flipscreen3d.vcproj b/wgl/flipscreen3d.vcproj index 98d4614..d1550af 100644 --- a/wgl/flipscreen3d.vcproj +++ b/wgl/flipscreen3d.vcproj @@ -187,7 +187,7 @@ > + + @@ -227,7 +231,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/flurry.h b/wgl/flurry.h index fadfebb..d476184 100644 --- a/wgl/flurry.h +++ b/wgl/flurry.h @@ -51,7 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "yarandom.h" #include "rotator.h" diff --git a/wgl/flurry.vcproj b/wgl/flurry.vcproj index fa648dd..fb5d8b2 100644 --- a/wgl/flurry.vcproj +++ b/wgl/flurry.vcproj @@ -203,7 +203,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/flyingtoasters.c b/wgl/flyingtoasters.c index 15edc28..be11331 100644 --- a/wgl/flyingtoasters.c +++ b/wgl/flyingtoasters.c @@ -46,7 +46,7 @@ #undef BELLRAND #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "gltrackball.h" #include "xpm-ximage.h" diff --git a/wgl/flyingtoasters.vcproj b/wgl/flyingtoasters.vcproj index deb9a80..3da8a90 100644 --- a/wgl/flyingtoasters.vcproj +++ b/wgl/flyingtoasters.vcproj @@ -235,7 +235,7 @@ > + + @@ -291,7 +295,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/gears.c b/wgl/gears.c index 77d022a..af1be62 100644 --- a/wgl/gears.c +++ b/wgl/gears.c @@ -24,7 +24,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "involute.h" diff --git a/wgl/gears.vcproj b/wgl/gears.vcproj index 410b80b..f2c6bdd 100644 --- a/wgl/gears.vcproj +++ b/wgl/gears.vcproj @@ -203,7 +203,7 @@ > + + @@ -255,7 +259,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/gflux.c b/wgl/gflux.c index 54082cd..45eb8bb 100644 --- a/wgl/gflux.c +++ b/wgl/gflux.c @@ -54,7 +54,7 @@ #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/gflux.vcproj b/wgl/gflux.vcproj index 8e3131a..d1ac2e0 100644 --- a/wgl/gflux.vcproj +++ b/wgl/gflux.vcproj @@ -187,7 +187,7 @@ > + + @@ -227,7 +231,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glblur.c b/wgl/glblur.c index 11d8275..fd4fe00 100644 --- a/wgl/glblur.c +++ b/wgl/glblur.c @@ -38,7 +38,7 @@ #define SIGNOF(n) ((n)<0?-1:1) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "rotator.h" #include "gltrackball.h" diff --git a/wgl/glblur.vcproj b/wgl/glblur.vcproj index 89ffd5b..e886293 100644 --- a/wgl/glblur.vcproj +++ b/wgl/glblur.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glcells.c b/wgl/glcells.c index c81e31b..59ed9f5 100644 --- a/wgl/glcells.c +++ b/wgl/glcells.c @@ -26,7 +26,7 @@ //#include /* gettimeofday */ -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" diff --git a/wgl/glcells.vcproj b/wgl/glcells.vcproj index 6851482..a755d9a 100644 --- a/wgl/glcells.vcproj +++ b/wgl/glcells.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/gleidescope.c b/wgl/gleidescope.c index 6f8a99e..96f4aa3 100644 --- a/wgl/gleidescope.c +++ b/wgl/gleidescope.c @@ -87,7 +87,7 @@ #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/gleidescope.vcproj b/wgl/gleidescope.vcproj index 7070176..a51b238 100644 --- a/wgl/gleidescope.vcproj +++ b/wgl/gleidescope.vcproj @@ -193,7 +193,7 @@ > + + @@ -245,7 +249,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glforestfire.c b/wgl/glforestfire.c index 7766884..2c0e616 100644 --- a/wgl/glforestfire.c +++ b/wgl/glforestfire.c @@ -94,7 +94,7 @@ static const char sccsid[] = "@(#)fire.c 5.02 2001/09/26 xlockmore"; #include "visgl.h" #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef MODE_fire diff --git a/wgl/glforestfire.vcproj b/wgl/glforestfire.vcproj index 0bec6ed..c439497 100644 --- a/wgl/glforestfire.vcproj +++ b/wgl/glforestfire.vcproj @@ -191,7 +191,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glhanoi.c b/wgl/glhanoi.c index eb3a094..39f1ada 100644 --- a/wgl/glhanoi.c +++ b/wgl/glhanoi.c @@ -30,7 +30,7 @@ # define refresh_glhanoi 0 -#include "xws2win.h" +#include "xlockmore.h" #include "rotator.h" /* polygon resolution of poles and disks */ diff --git a/wgl/glhanoi.vcproj b/wgl/glhanoi.vcproj index b862d94..b022293 100644 --- a/wgl/glhanoi.vcproj +++ b/wgl/glhanoi.vcproj @@ -191,7 +191,7 @@ > + + @@ -231,7 +235,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glknots.c b/wgl/glknots.c index 2e014d9..2d67821 100644 --- a/wgl/glknots.c +++ b/wgl/glknots.c @@ -24,7 +24,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "tube.h" #include "rotator.h" diff --git a/wgl/glknots.vcproj b/wgl/glknots.vcproj index 049f9e5..db2fca4 100644 --- a/wgl/glknots.vcproj +++ b/wgl/glknots.vcproj @@ -203,7 +203,7 @@ > + + @@ -259,7 +263,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/gllist.h b/wgl/gllist.h index 0e178cf..de59fa2 100644 --- a/wgl/gllist.h +++ b/wgl/gllist.h @@ -15,7 +15,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" struct gllist{ GLenum format; diff --git a/wgl/glmatrix.c b/wgl/glmatrix.c index 884e585..a66ee67 100644 --- a/wgl/glmatrix.c +++ b/wgl/glmatrix.c @@ -29,7 +29,7 @@ #undef BELLRAND #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "xpm-ximage.h" diff --git a/wgl/glmatrix.vcproj b/wgl/glmatrix.vcproj index 4f2efdc..2e5532b 100644 --- a/wgl/glmatrix.vcproj +++ b/wgl/glmatrix.vcproj @@ -191,7 +191,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glplanet.c b/wgl/glplanet.c index 72898e6..cccef37 100644 --- a/wgl/glplanet.c +++ b/wgl/glplanet.c @@ -50,7 +50,7 @@ #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/glplanet.vcproj b/wgl/glplanet.vcproj index e5a2263..3a5b44f 100644 --- a/wgl/glplanet.vcproj +++ b/wgl/glplanet.vcproj @@ -199,7 +199,7 @@ > + + @@ -259,7 +263,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glschool.c b/wgl/glschool.c index 2a1e89d..14bae64 100644 --- a/wgl/glschool.c +++ b/wgl/glschool.c @@ -10,7 +10,7 @@ */ //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "glschool.h" #include "colors.h" diff --git a/wgl/glschool.vcproj b/wgl/glschool.vcproj index 6f639b8..81d377a 100644 --- a/wgl/glschool.vcproj +++ b/wgl/glschool.vcproj @@ -211,7 +211,7 @@ > + + @@ -279,7 +283,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/glschool_alg.c b/wgl/glschool_alg.c index a516b3f..6dfac57 100644 --- a/wgl/glschool_alg.c +++ b/wgl/glschool_alg.c @@ -9,7 +9,7 @@ * implied warranty. */ -#include "xws2win.h" +#include "xlockmore.h" #if 0 #ifdef HAVE_CONFIG_H diff --git a/wgl/glschool_gl.c b/wgl/glschool_gl.c index bac6314..b262df2 100644 --- a/wgl/glschool_gl.c +++ b/wgl/glschool_gl.c @@ -9,7 +9,7 @@ * implied warranty. */ -#include "xws2win.h" +#include "xlockmore.h" #include "sphere.h" #include "glschool_gl.h" #include "sphere.h" diff --git a/wgl/glschool_gl.h b/wgl/glschool_gl.h index 9048b46..000b0cd 100644 --- a/wgl/glschool_gl.h +++ b/wgl/glschool_gl.h @@ -32,7 +32,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "glschool_alg.h" diff --git a/wgl/glsnake.c b/wgl/glsnake.c index dcd2c5c..3b52954 100644 --- a/wgl/glsnake.c +++ b/wgl/glsnake.c @@ -29,7 +29,7 @@ #include #include -#include "xws2win.h" +#include "xlockmore.h" #if 0 /* HAVE_GLUT defined if we're building a standalone glsnake, diff --git a/wgl/glsnake.vcproj b/wgl/glsnake.vcproj index 7596364..93c93a1 100644 --- a/wgl/glsnake.vcproj +++ b/wgl/glsnake.vcproj @@ -179,7 +179,7 @@ > @@ -203,7 +203,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/hilbert.c b/wgl/hilbert.c index e32de86..4ad2755 100644 --- a/wgl/hilbert.c +++ b/wgl/hilbert.c @@ -27,7 +27,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "colors.h" diff --git a/wgl/hilbert.vcproj b/wgl/hilbert.vcproj index 099cc97..a54446d 100644 --- a/wgl/hilbert.vcproj +++ b/wgl/hilbert.vcproj @@ -207,7 +207,7 @@ > + + @@ -267,7 +271,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/hypertorus.c b/wgl/hypertorus.c index 308f267..1da0d19 100644 --- a/wgl/hypertorus.c +++ b/wgl/hypertorus.c @@ -98,7 +98,7 @@ static const char sccsid[] = "@(#)hypertorus.c 1.2 05/09/28 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/hypertorus.vcproj b/wgl/hypertorus.vcproj index 5c7bb9a..69c18ac 100644 --- a/wgl/hypertorus.vcproj +++ b/wgl/hypertorus.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/hypnowheel.c b/wgl/hypnowheel.c index 6f225ae..38b7f03 100644 --- a/wgl/hypnowheel.c +++ b/wgl/hypnowheel.c @@ -32,7 +32,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "rotator.h" diff --git a/wgl/hypnowheel.vcproj b/wgl/hypnowheel.vcproj index 407d8e9..c668b14 100644 --- a/wgl/hypnowheel.vcproj +++ b/wgl/hypnowheel.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/involute.c b/wgl/involute.c index af9461b..51379d2 100644 --- a/wgl/involute.c +++ b/wgl/involute.c @@ -28,7 +28,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "involute.h" #include "normals.h" diff --git a/wgl/jigglypuff.c b/wgl/jigglypuff.c index fef3c29..596d5ce 100644 --- a/wgl/jigglypuff.c +++ b/wgl/jigglypuff.c @@ -51,7 +51,7 @@ #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #if 0 #ifdef HAVE_CONFIG_H diff --git a/wgl/jigglypuff.vcproj b/wgl/jigglypuff.vcproj index d053476..c05cb83 100644 --- a/wgl/jigglypuff.vcproj +++ b/wgl/jigglypuff.vcproj @@ -191,7 +191,7 @@ > + + @@ -239,7 +243,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/kaleidocycle.c b/wgl/kaleidocycle.c index 4a4aa23..c284983 100644 --- a/wgl/kaleidocycle.c +++ b/wgl/kaleidocycle.c @@ -27,7 +27,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "normals.h" #include "rotator.h" diff --git a/wgl/kaleidocycle.vcproj b/wgl/kaleidocycle.vcproj index df943f6..9708f12 100644 --- a/wgl/kaleidocycle.vcproj +++ b/wgl/kaleidocycle.vcproj @@ -203,7 +203,7 @@ > + + @@ -259,7 +263,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/klein.c b/wgl/klein.c index 8d3267e..4f52e81 100644 --- a/wgl/klein.c +++ b/wgl/klein.c @@ -138,7 +138,7 @@ static const char sccsid[] = "@(#)klein.c 1.1 08/10/04 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/klein.vcproj b/wgl/klein.vcproj index b1fc874..6945a6f 100644 --- a/wgl/klein.vcproj +++ b/wgl/klein.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/lament.c b/wgl/lament.c index 9315e4e..274b113 100644 --- a/wgl/lament.c +++ b/wgl/lament.c @@ -59,14 +59,13 @@ duplicated on the "Unnatural History 2" compilation, WORLN M04699.) */ -#define HAVE_GLBINDTEXTURE #define DELAY 20000 #define DEFAULTS "*delay: 20000 \n" \ "*showFPS: False \n" \ "*wireframe: False \n" # define refresh_lament 0 # define release_lament 0 -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/lament.vcproj b/wgl/lament.vcproj index ab26e2b..91d57e3 100644 --- a/wgl/lament.vcproj +++ b/wgl/lament.vcproj @@ -199,7 +199,7 @@ > + + @@ -259,7 +263,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/lavalite.c b/wgl/lavalite.c index c87c36c..eb1a83e 100644 --- a/wgl/lavalite.c +++ b/wgl/lavalite.c @@ -91,7 +91,7 @@ #undef SIGNOF #define SIGNOF(n) ((n)<0?-1:1) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "marching.h" #include "rotator.h" diff --git a/wgl/lavalite.vcproj b/wgl/lavalite.vcproj index 7c0af32..6f6b115 100644 --- a/wgl/lavalite.vcproj +++ b/wgl/lavalite.vcproj @@ -203,7 +203,7 @@ > + + @@ -267,7 +271,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/lockward.c b/wgl/lockward.c index 6edb00c..521d8da 100644 --- a/wgl/lockward.c +++ b/wgl/lockward.c @@ -28,7 +28,7 @@ //#include //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" diff --git a/wgl/lockward.vcproj b/wgl/lockward.vcproj index b0b0692..eb9f5d8 100644 --- a/wgl/lockward.vcproj +++ b/wgl/lockward.vcproj @@ -195,7 +195,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/marching.c b/wgl/marching.c index c20ff01..975a29a 100644 --- a/wgl/marching.c +++ b/wgl/marching.c @@ -19,7 +19,7 @@ #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #include #include #include diff --git a/wgl/menger.c b/wgl/menger.c index 631f29b..2e0f38f 100644 --- a/wgl/menger.c +++ b/wgl/menger.c @@ -62,7 +62,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "rotator.h" #include "gltrackball.h" diff --git a/wgl/menger.vcproj b/wgl/menger.vcproj index 9f779f2..2360105 100644 --- a/wgl/menger.vcproj +++ b/wgl/menger.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/minixpm.c b/wgl/minixpm.c index 6f9175a..490e6d5 100644 --- a/wgl/minixpm.c +++ b/wgl/minixpm.c @@ -26,7 +26,7 @@ #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #include #include #include diff --git a/wgl/mirrorblob.c b/wgl/mirrorblob.c index d131a72..2f8373b 100644 --- a/wgl/mirrorblob.c +++ b/wgl/mirrorblob.c @@ -33,7 +33,7 @@ * */ -#include "xws2win.h" +#include "xlockmore.h" #include #define DEFAULTS "*delay: " DEF_DELAY "\n" \ diff --git a/wgl/mirrorblob.vcproj b/wgl/mirrorblob.vcproj index 4ea57e6..d6b506c 100644 --- a/wgl/mirrorblob.vcproj +++ b/wgl/mirrorblob.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/moebius.c b/wgl/moebius.c index e3e79f3..1d656a4 100644 --- a/wgl/moebius.c +++ b/wgl/moebius.c @@ -103,7 +103,7 @@ static const char sccsid[] = "@(#)moebius.c 5.01 2001/03/01 xlockmore"; #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef MODE_moebius diff --git a/wgl/moebius.vcproj b/wgl/moebius.vcproj index 2321c9b..873fb62 100644 --- a/wgl/moebius.vcproj +++ b/wgl/moebius.vcproj @@ -199,7 +199,7 @@ > + + @@ -247,7 +251,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/moebiusgears.c b/wgl/moebiusgears.c index 9b9a571..09fbb55 100644 --- a/wgl/moebiusgears.c +++ b/wgl/moebiusgears.c @@ -21,7 +21,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "involute.h" diff --git a/wgl/moebiusgears.vcproj b/wgl/moebiusgears.vcproj index b5de7dd..4a1b548 100644 --- a/wgl/moebiusgears.vcproj +++ b/wgl/moebiusgears.vcproj @@ -199,7 +199,7 @@ > + + @@ -247,7 +251,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/morph3d.c b/wgl/morph3d.c index 265339f..df74bcd 100644 --- a/wgl/morph3d.c +++ b/wgl/morph3d.c @@ -69,7 +69,7 @@ static const char sccsid[] = "@(#)morph3d.c 5.01 2001/03/01 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef MODE_moebius diff --git a/wgl/morph3d.vcproj b/wgl/morph3d.vcproj index c8f3694..edb49de 100644 --- a/wgl/morph3d.vcproj +++ b/wgl/morph3d.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/noof.c b/wgl/noof.c index 60153be..93dbf60 100644 --- a/wgl/noof.c +++ b/wgl/noof.c @@ -25,7 +25,7 @@ # define noof_handle_event 0 //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/noof.vcproj b/wgl/noof.vcproj index f5c1811..1e1ab6e 100644 --- a/wgl/noof.vcproj +++ b/wgl/noof.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/normals.c b/wgl/normals.c index 8520448..5e5a56b 100644 --- a/wgl/normals.c +++ b/wgl/normals.c @@ -17,7 +17,7 @@ #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #include "normals.h" diff --git a/wgl/pipeobjs.c b/wgl/pipeobjs.c index 080b686..e36de97 100644 --- a/wgl/pipeobjs.c +++ b/wgl/pipeobjs.c @@ -14,7 +14,7 @@ static const char sccsid[] = "@(#)pipeobjs.c 4.04 97/07/28 xlockmore"; #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/pipes.c b/wgl/pipes.c index 9687fc8..c2f7d6c 100644 --- a/wgl/pipes.c +++ b/wgl/pipes.c @@ -80,7 +80,7 @@ static const char sccsid[] = "@(#)pipes.c 4.07 97/11/24 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/pipes.vcproj b/wgl/pipes.vcproj index 5cc7b1e..4308121 100644 --- a/wgl/pipes.vcproj +++ b/wgl/pipes.vcproj @@ -207,7 +207,7 @@ > + + @@ -263,7 +267,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/polytopes.c b/wgl/polytopes.c index b2d6c79..3291a99 100644 --- a/wgl/polytopes.c +++ b/wgl/polytopes.c @@ -102,7 +102,7 @@ static const char sccsid[] = "@(#)polytopes.c 1.2 05/09/28 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/polytopes.vcproj b/wgl/polytopes.vcproj index 7b6c710..838f37e 100644 --- a/wgl/polytopes.vcproj +++ b/wgl/polytopes.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/providence.c b/wgl/providence.c index e4d9460..5a0087a 100644 --- a/wgl/providence.c +++ b/wgl/providence.c @@ -29,7 +29,7 @@ #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #include "gltrackball.h" diff --git a/wgl/providence.vcproj b/wgl/providence.vcproj index 7bbd1d7..2dcb355 100644 --- a/wgl/providence.vcproj +++ b/wgl/providence.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/pulsar.c b/wgl/pulsar.c index b5ae48a..47132b8 100644 --- a/wgl/pulsar.c +++ b/wgl/pulsar.c @@ -36,7 +36,7 @@ * */ -#include "xws2win.h" +#include "xlockmore.h" #include #include #include diff --git a/wgl/pulsar.vcproj b/wgl/pulsar.vcproj index a7aa7b8..78d203f 100644 --- a/wgl/pulsar.vcproj +++ b/wgl/pulsar.vcproj @@ -191,7 +191,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/quasicrystal.c b/wgl/quasicrystal.c index 6f4d86c..1778cc0 100644 --- a/wgl/quasicrystal.c +++ b/wgl/quasicrystal.c @@ -29,7 +29,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "colors.h" #include "rotator.h" diff --git a/wgl/quasicrystal.vcproj b/wgl/quasicrystal.vcproj index de45470..ae031c5 100644 --- a/wgl/quasicrystal.vcproj +++ b/wgl/quasicrystal.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/queens.c b/wgl/queens.c index fe42f94..fbd2da9 100644 --- a/wgl/queens.c +++ b/wgl/queens.c @@ -44,7 +44,7 @@ #endif /* HAVE_JWZGLES */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/queens.vcproj b/wgl/queens.vcproj index c15fac6..426a7d9 100644 --- a/wgl/queens.vcproj +++ b/wgl/queens.vcproj @@ -191,7 +191,7 @@ > + + @@ -231,7 +235,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/rubik.c b/wgl/rubik.c index de43bba..4ad3178 100644 --- a/wgl/rubik.c +++ b/wgl/rubik.c @@ -115,7 +115,7 @@ static const char sccsid[] = "@(#)rubik.c 5.01 2001/03/01 xlockmore"; "*size: -6 \n" # define refresh_rubik 0 -#include "xws2win.h" +#include "xlockmore.h" #if 0 #ifdef STANDALONE diff --git a/wgl/rubik.vcproj b/wgl/rubik.vcproj index a1fc364..c990ba5 100644 --- a/wgl/rubik.vcproj +++ b/wgl/rubik.vcproj @@ -187,7 +187,7 @@ > + + @@ -219,7 +223,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/rubikblocks.c b/wgl/rubikblocks.c index 0fac9fb..bf038c8 100644 --- a/wgl/rubikblocks.c +++ b/wgl/rubikblocks.c @@ -26,7 +26,7 @@ //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "rotator.h" #include "gltrackball.h" diff --git a/wgl/rubikblocks.vcproj b/wgl/rubikblocks.vcproj index e7c9067..b60a578 100644 --- a/wgl/rubikblocks.vcproj +++ b/wgl/rubikblocks.vcproj @@ -191,7 +191,7 @@ > + + @@ -231,7 +235,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/sballs.c b/wgl/sballs.c index a4fb8a7..07439f3 100644 --- a/wgl/sballs.c +++ b/wgl/sballs.c @@ -52,7 +52,7 @@ static const char sccsid[] = "@(#)sballs.c 5.02 2001/03/10 xlockmore"; # define refresh_sballs 0 #define MODE_sballs -#include "xws2win.h" +#include "xlockmore.h" #if 0 #ifdef STANDALONE /* xscreensaver mode */ #include "xlockmore.h" /* from the xscreensaver distribution */ diff --git a/wgl/sballs.vcproj b/wgl/sballs.vcproj index ea53067..047fa6b 100644 --- a/wgl/sballs.vcproj +++ b/wgl/sballs.vcproj @@ -191,7 +191,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/shark.c b/wgl/shark.c index 939e892..e5b7c81 100644 --- a/wgl/shark.c +++ b/wgl/shark.c @@ -72,7 +72,7 @@ static const char sccsid[] = "@(#)shark.c 1.2 98/06/16 xlockmore"; * OpenGL(TM) is a trademark of Silicon Graphics, Inc. */ -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/sierpinski3d.c b/wgl/sierpinski3d.c index b9fee03..b7b57e7 100644 --- a/wgl/sierpinski3d.c +++ b/wgl/sierpinski3d.c @@ -41,7 +41,7 @@ static const char sccsid[] = "@(#)sierpinski3D.c 00.01 99/11/04 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #ifdef USE_GL diff --git a/wgl/sierpinski3d.vcproj b/wgl/sierpinski3d.vcproj index b6b4bee..89a9792 100644 --- a/wgl/sierpinski3d.vcproj +++ b/wgl/sierpinski3d.vcproj @@ -199,7 +199,7 @@ > + + @@ -251,7 +255,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/skytentacles.c b/wgl/skytentacles.c index 2d3f4f8..01834ed 100644 --- a/wgl/skytentacles.c +++ b/wgl/skytentacles.c @@ -21,7 +21,7 @@ #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "colors.h" #include "normals.h" diff --git a/wgl/skytentacles.vcproj b/wgl/skytentacles.vcproj index feae0c0..a06ea95 100644 --- a/wgl/skytentacles.vcproj +++ b/wgl/skytentacles.vcproj @@ -199,7 +199,7 @@ > + + @@ -259,7 +263,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/sproingies.c b/wgl/sproingies.c index 607a7b1..d50999d 100644 --- a/wgl/sproingies.c +++ b/wgl/sproingies.c @@ -36,7 +36,7 @@ static const char sccsid[] = "@(#)sproingies.c 4.04 97/07/28 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/sproingies.vcproj b/wgl/sproingies.vcproj index f29dff4..a0f33de 100644 --- a/wgl/sproingies.vcproj +++ b/wgl/sproingies.vcproj @@ -223,7 +223,7 @@ > + + @@ -267,7 +271,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/sproingiewrap.c b/wgl/sproingiewrap.c index a7a5df5..e176597 100644 --- a/wgl/sproingiewrap.c +++ b/wgl/sproingiewrap.c @@ -66,7 +66,7 @@ static const char sccsid[] = "@(#)sproingiewrap.c 4.07 97/11/24 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/src_only.bat b/wgl/src_only.bat new file mode 100644 index 0000000..6ebe2c3 --- /dev/null +++ b/wgl/src_only.bat @@ -0,0 +1,3 @@ +call clean.bat +if exist Debug rd /S /Q Debug +if exist Release rd /S /Q Release diff --git a/wgl/stairs.c b/wgl/stairs.c index 7819151..79d5a4e 100644 --- a/wgl/stairs.c +++ b/wgl/stairs.c @@ -70,7 +70,7 @@ static const char sccsid[] = "@(#)stairs.c 4.07 97/11/24 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/stairs.vcproj b/wgl/stairs.vcproj index dd56522..2fd692a 100644 --- a/wgl/stairs.vcproj +++ b/wgl/stairs.vcproj @@ -191,7 +191,7 @@ > + + @@ -235,7 +239,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/stonerview.c b/wgl/stonerview.c index 3f83c82..f0e5ff3 100644 --- a/wgl/stonerview.c +++ b/wgl/stonerview.c @@ -31,7 +31,7 @@ //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/stonerview.vcproj b/wgl/stonerview.vcproj index a3a8709..608d058 100644 --- a/wgl/stonerview.vcproj +++ b/wgl/stonerview.vcproj @@ -199,7 +199,7 @@ > + + @@ -247,7 +251,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/superquadrics.c b/wgl/superquadrics.c index 68846ff..7d9e2d0 100644 --- a/wgl/superquadrics.c +++ b/wgl/superquadrics.c @@ -89,7 +89,7 @@ static const char sccsid[] = "@(#)superquadrics.c 4.07 97/11/24 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/superquadrics.vcproj b/wgl/superquadrics.vcproj index 6e21073..2e682a3 100644 --- a/wgl/superquadrics.vcproj +++ b/wgl/superquadrics.vcproj @@ -187,7 +187,7 @@ > + + @@ -223,7 +227,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/surfaces.c b/wgl/surfaces.c index 0b44e96..6ded8cf 100644 --- a/wgl/surfaces.c +++ b/wgl/surfaces.c @@ -55,7 +55,7 @@ #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/surfaces.vcproj b/wgl/surfaces.vcproj index 32c62a7..ed530bd 100644 --- a/wgl/surfaces.vcproj +++ b/wgl/surfaces.vcproj @@ -191,7 +191,7 @@ > + + @@ -231,7 +235,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/swim.c b/wgl/swim.c index 624acc3..19ad9d4 100644 --- a/wgl/swim.c +++ b/wgl/swim.c @@ -81,7 +81,7 @@ static const char sccsid[] = "@(#)swim.c 1.3 98/06/18 xlockmore"; #endif /* !STANDALONE */ #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/teapot.c b/wgl/teapot.c index 2012b11..778a6af 100644 --- a/wgl/teapot.c +++ b/wgl/teapot.c @@ -50,7 +50,7 @@ OpenGL(TM) is a trademark of Silicon Graphics, Inc. #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #include "teapot.h" #if 0 diff --git a/wgl/timetunnel.c b/wgl/timetunnel.c index bd397ea..216465b 100644 --- a/wgl/timetunnel.c +++ b/wgl/timetunnel.c @@ -12,7 +12,7 @@ #define GL_GLEXT_PROTOTYPES 1 -#include "xws2win.h" +#include "xlockmore.h" //#include /* for log2 */ #define DELAY 30000 @@ -32,7 +32,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "rotator.h" #include "gltrackball.h" diff --git a/wgl/timetunnel.vcproj b/wgl/timetunnel.vcproj index 240f2d2..75c9e10 100644 --- a/wgl/timetunnel.vcproj +++ b/wgl/timetunnel.vcproj @@ -191,7 +191,7 @@ > + + @@ -235,7 +239,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/topblock.c b/wgl/topblock.c index aae0549..6db5faf 100644 --- a/wgl/topblock.c +++ b/wgl/topblock.c @@ -39,7 +39,7 @@ History #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) -#include "xws2win.h" +#include "xlockmore.h" //#include "xlockmore.h" #include "topblock.h" diff --git a/wgl/topblock.vcproj b/wgl/topblock.vcproj index 23bf3a7..2a7476f 100644 --- a/wgl/topblock.vcproj +++ b/wgl/topblock.vcproj @@ -195,7 +195,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/tronbit.c b/wgl/tronbit.c index 1824301..217ee79 100644 --- a/wgl/tronbit.c +++ b/wgl/tronbit.c @@ -21,7 +21,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "sphere.h" #include "rotator.h" diff --git a/wgl/tronbit.vcproj b/wgl/tronbit.vcproj index 03e348b..65fef24 100644 --- a/wgl/tronbit.vcproj +++ b/wgl/tronbit.vcproj @@ -219,7 +219,7 @@ > + + @@ -275,7 +279,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/tunnel_draw.c b/wgl/tunnel_draw.c index b69d488..d75c607 100644 --- a/wgl/tunnel_draw.c +++ b/wgl/tunnel_draw.c @@ -40,7 +40,7 @@ static const char sccsid[] = "@(#)tunnel_draw.c 5.13 2004/05/25 xlockmore"; #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL /* whole file */ diff --git a/wgl/unknownpleasures.c b/wgl/unknownpleasures.c index fdc2cd2..1fa8281 100644 --- a/wgl/unknownpleasures.c +++ b/wgl/unknownpleasures.c @@ -47,7 +47,7 @@ #define countof(x) (sizeof((x))/sizeof((*x))) //#include "xlockmore.h" -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" #include "gltrackball.h" #include diff --git a/wgl/unknownpleasures.vcproj b/wgl/unknownpleasures.vcproj index 9bb1e82..7bb4b68 100644 --- a/wgl/unknownpleasures.vcproj +++ b/wgl/unknownpleasures.vcproj @@ -187,7 +187,7 @@ > + + @@ -227,7 +231,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/voronoi.c b/wgl/voronoi.c index 5302fda..26ff98d 100644 --- a/wgl/voronoi.c +++ b/wgl/voronoi.c @@ -21,7 +21,7 @@ #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) -#include "xws2win.h" +#include "xlockmore.h" #include "colors.h" //#include "xlockmore.h" diff --git a/wgl/voronoi.vcproj b/wgl/voronoi.vcproj index a128eb4..51d04b1 100644 --- a/wgl/voronoi.vcproj +++ b/wgl/voronoi.vcproj @@ -195,7 +195,7 @@ > + + @@ -243,7 +247,7 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/wgl/wgl.c b/wgl/wgl.c index 5cf4ec3..75b68c2 100644 --- a/wgl/wgl.c +++ b/wgl/wgl.c @@ -1,4 +1,4 @@ -#include "xws2win.h" +#include "xlockmore.h" PIXELFORMATDESCRIPTOR pfd = { @@ -37,13 +37,11 @@ VOID MakeCurrent(SCREENSAVER *ss) void ss_term(void) { - XFreeGC(ss.modeinfo.dpy, ss.modeinfo.gc); + free(ss.modeinfo.colors); + free(ss.modeinfo.pixels); hack_free(&ss.modeinfo); - wglMakeCurrent(NULL, NULL); ReleaseDC(ss.hwnd, ss.hdc); - wglDeleteContext(ss.hglrc); DeleteObject(ss.hbmScreenShot); - ss.hbmScreenShot = NULL; } void ss_clear(Display *d) @@ -62,7 +60,7 @@ XImage *GetScreenShotXImage(void) cx = bm.bmWidth; cy = bm.bmHeight; - image = XCreateImage(NULL, NULL, 32, RGBAPixmap, 0, NULL, cx, cy, 32, 0); + image = XCreateImage(NULL, NULL, 32, RGBAPixmap_, 0, NULL, cx, cy, 32, 0); if (image) { size = image->bytes_per_line * image->height; @@ -81,7 +79,7 @@ XImage *GetScreenShotXImage(void) void CreateTextureFromImage(XImage *ximage, GLuint texid) { - assert(ximage->format == RGBAPixmap); + assert(ximage->format == RGBAPixmap_); glBindTexture(GL_TEXTURE_2D, texid); glPixelStorei(GL_UNPACK_ALIGNMENT, ximage->bitmap_pad / 8); diff --git a/wgl/whale.c b/wgl/whale.c index 6beb3da..ecdc73c 100644 --- a/wgl/whale.c +++ b/wgl/whale.c @@ -72,7 +72,7 @@ static const char sccsid[] = "@(#)whale.c 1.3 98/06/18 xlockmore"; * OpenGL(TM) is a trademark of Silicon Graphics, Inc. */ -#include "xws2win.h" +#include "xlockmore.h" #ifdef USE_GL diff --git a/wgl/xpm-ximage.c b/wgl/xpm-ximage.c index 5bdda67..fd3387b 100644 --- a/wgl/xpm-ximage.c +++ b/wgl/xpm-ximage.c @@ -18,7 +18,7 @@ #endif #endif -#include "xws2win.h" +#include "xlockmore.h" #include #include @@ -567,7 +567,7 @@ xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap, } free (data); - ximage->format = RGBAPixmap; + ximage->format = RGBAPixmap_; if (filename) { diff --git a/xcolor.c b/xcolor.c index 9eefe2a..85d7d9e 100644 --- a/xcolor.c +++ b/xcolor.c @@ -1,4 +1,4 @@ -#include "xws2win.h" +#include "xlockmore.h" typedef struct { @@ -1076,11 +1076,8 @@ int XParseColor(Display *d, Colormap cmap, const char *name, XColor *c) } Bool XAllocNamedColor( - Display *d, - Colormap cmap, - const char *name, - XColor *near_color, - XColor *true_color) + Display *d, Colormap cmap, const char *name, + XColor *near_color, XColor *true_color) { WORD red, green, blue; WORD true_red, true_green, true_blue; @@ -1286,12 +1283,28 @@ unsigned long load_color(Display *dpy, Colormap cmap, const char *name) return color.pixel; } +int XSetBackground(Display *dpy, GC gc, unsigned long background) +{ + XColor color; + XGCValues *values; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + values->background = background; + color.pixel = background; + XQueryColor(dpy, DefaultColormap(dpy, DefaultScreenOfDisplay(dpy)), &color); + values->background_rgb = RGB(color.red / 256, color.green / 256, color.blue / 256); + return 0; +} + int XSetForeground(Display *dpy, GC gc, unsigned long foreground) { XColor color; XGCValues *values; - values = XGetGCValues0(gc); + values = XGetGCValues_(gc); if (values == NULL) return BadGC; @@ -1301,3 +1314,11 @@ int XSetForeground(Display *dpy, GC gc, unsigned long foreground) values->foreground_rgb = RGB(color.red / 256, color.green / 256, color.blue / 256); return 0; } + +unsigned long window_background = 0; + +int XSetWindowBackground(Display *dpy, Window w, unsigned long pixel) +{ + window_background = pixel; + return 0; +} diff --git a/ximage.c b/ximage.c index 82adb3b..aa15915 100644 --- a/ximage.c +++ b/ximage.c @@ -1,8 +1,8 @@ -#include "xws2win.h" +#include "xlockmore.h" void XInitImage(XImage *image) { - int width = image->width, depth = image->depth; + int width = image->width, depth = image->depth; assert(image != NULL); @@ -72,7 +72,7 @@ XImage *XCreateImage(Display *dpy, Visual *visual, int depth, int format, case XYBitmap: case XYPixmap: case ZPixmap: - case RGBAPixmap: + case RGBAPixmap_: break; default: @@ -163,7 +163,7 @@ unsigned long XGetPixel(XImage *ximage, int x, int y) } } - if (ximage->format == RGBAPixmap && ximage->bits_per_pixel == 32) + if (ximage->format == RGBAPixmap_ && ximage->bits_per_pixel == 32) { addr = &((unsigned char *)ximage->data)[y * ximage->bytes_per_line + (x << 2)]; return addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[2] << 24); @@ -233,7 +233,7 @@ int XPutPixel(XImage *ximage, int x, int y, unsigned long pixel) return 1; } - if (ximage->format == RGBAPixmap && ximage->bits_per_pixel == 32) + if (ximage->format == RGBAPixmap_ && ximage->bits_per_pixel == 32) { addr = &((unsigned char *)ximage->data)[y * ximage->bytes_per_line + (x << 2)]; if (ximage->byte_order == MSBFirst) @@ -256,8 +256,3 @@ int XPutPixel(XImage *ximage, int x, int y, unsigned long pixel) assert(0); return 0; } - -int XFreePixmap(Display *dpy, Pixmap pixmap) -{ - return 0; -} diff --git a/win32screensaver.c b/xlockmore.c similarity index 92% rename from win32screensaver.c rename to xlockmore.c index f229e25..e2d790f 100644 --- a/win32screensaver.c +++ b/xlockmore.c @@ -1,5 +1,4 @@ -#include "xws2win.h" -#include +#include "xlockmore.h" #include "resource.h" #ifdef _UNICODE @@ -357,7 +356,7 @@ typedef struct tagBITMAPINFOEX { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[256]; -} BITMAPINFOEX, FAR * LPBITMAPINFOEX; +} BITMAPINFOEX, *LPBITMAPINFOEX; BOOL SaveBitmapToFile(LPCTSTR pszFileName, HBITMAP hbm) { @@ -453,12 +452,14 @@ BOOL ss_init(HWND hwnd) GetClientRect(hwnd, &rc); ss.x0 = rc.left; ss.y0 = rc.top; - ss.w = rc.right - ss.x0; - ss.h = rc.bottom - ss.y0; - if (ss.w == 0 || ss.h == 0) + assert(ss.x0 == 0); + assert(ss.y0 == 0); + ss.width = rc.right - rc.left; + ss.height = rc.bottom - rc.top; + if (ss.width == 0 || ss.height == 0) return FALSE; - ss.hdc = GetDC(hwnd); + ss.hdc = GetWindowDC(hwnd); if (ss.hdc == NULL) return FALSE; @@ -480,23 +481,22 @@ BOOL ss_init(HWND hwnd) ss.modeinfo.dpy = ss.hdc; ss.modeinfo.window = 0; - ss.modeinfo.gc = XCreateGC(ss.hdc, 0, 0, NULL); + ss.modeinfo.width = ss.width; + ss.modeinfo.height = ss.height; ss.modeinfo.num_screen = 1; ss.modeinfo.screen_number = 0; - ss.modeinfo.width = ss.w; - ss.modeinfo.height = ss.h; ss.modeinfo.polygon_count = 0; ss.modeinfo.fps_p = False; ss.modeinfo.is_drawn = True; ss.modeinfo.count = hack_count; ss.modeinfo.cycles = hack_cycles; ss.modeinfo.size = hack_size; - ss.modeinfo.xgwa.width = ss.w; - ss.modeinfo.xgwa.height = ss.h; + ss.modeinfo.xgwa.width = ss.width; + ss.modeinfo.xgwa.height = ss.height; ss.modeinfo.xgwa.depth = 32; ss.modeinfo.xgwa.visual = NULL; ss.modeinfo.xgwa.colormap = 0; - ss.modeinfo.xgwa.screen = hwnd; + ss.modeinfo.xgwa.screen = 0; LoadSetting(&ss.modeinfo); @@ -526,6 +526,8 @@ VOID OnInitDialog(HWND hwnd) hIcon = (HICON)LoadImageA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + // set window title + SetWindowText(hwnd, progname); for (i = 0; i < hack_argcount; i++) { @@ -667,11 +669,10 @@ LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara } ////////////////////////////////////////////////////////////////////////////// -// X Window-related Display *DisplayOfScreen(Screen *s) { - return GetWindowDC(s); + return ss.modeinfo.dpy; } int XClearWindow(Display *dpy, Window w) @@ -683,66 +684,6 @@ int XClearWindow(Display *dpy, Window w) return FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); } -static int gc_count = 0; -static XGCValues *gc_buffer[MAX_GC_BUFFER] = {NULL}; - -XGCValues *XGetGCValues0(GC gc) -{ - assert(gc_buffer[gc] != NULL); - return gc_buffer[gc]; -} - -Status XGetGCValues( - Display *dpy, - GC gc, - unsigned long valuemask, - XGCValues *values_return) -{ - XGCValues *values = XGetGCValues0(gc); - CopyMemory(values_return, values, sizeof(XGCValues)); - return 1; -} - -GC XCreateGC( - Display *dpy, - Drawable d, - unsigned long valuemask, - XGCValues *values) -{ - int i; - - if (gc_count < MAX_GC_BUFFER) - { - values = (XGCValues *)calloc(1, sizeof(XGCValues)); - if (values != NULL) - { - for (i = 0; i < MAX_GC_BUFFER; i++) - { - if (gc_buffer[i] == NULL) - { - gc_buffer[i] = values; - gc_count++; - return i; - } - } - assert(0); - } - assert(0); - } - assert(0); - return 0; -} - -int XFreeGC(Display *dpy, GC gc) -{ - assert(gc_buffer[gc] != NULL); - free(gc_buffer[gc]); - gc_buffer[gc] = NULL; - gc_count--; - assert(gc_count >= 0); - return 0; -} - ////////////////////////////////////////////////////////////////////////////// // trackball @@ -804,7 +745,7 @@ int visual_depth(Screen *screen, Visual *visual) ////////////////////////////////////////////////////////////////////////////// // message box output -#ifdef MSGBOXOUTPUT +#ifndef NOMSGBOXOUTPUT #undef fprintf #undef abort #undef exit @@ -825,12 +766,18 @@ int visual_depth(Screen *screen, Visual *visual) void __cdecl win32_abort(void) { + keybd_event(VK_SHIFT, 0, 0, 0); + keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); + MessageBoxA(NULL, s_szBuffer, progname, MB_ICONERROR); exit(-1); } int __cdecl win32_exit(int n) { + keybd_event(VK_SHIFT, 0, 0, 0); + keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); + MessageBoxA(NULL, s_szBuffer, progname, MB_ICONERROR); exit(n); } diff --git a/xlockmore.h b/xlockmore.h new file mode 100644 index 0000000..8691ca5 --- /dev/null +++ b/xlockmore.h @@ -0,0 +1,408 @@ +#ifndef __XLOCKMORE_H__ +#define __XLOCKMORE_H__ + +#ifndef __XWS2WIN_H__ + #include "xws2win.h" +#endif +#include + +#define MAX_COLORS 256 + +#define inline /*empty*/ + +////////////////////////////////////////////////////////////////////////////// + +#define ENTRYPOINT static + +#ifndef NOMSGBOXOUTPUT + int __cdecl win32_fprintf(FILE *fp, const char *fmt, ...); + void __cdecl win32_abort(void); + int __cdecl win32_exit(int n); + + #define fprintf win32_fprintf + #define abort win32_abort + #define exit win32_exit +#endif + +////////////////////////////////////////////////////////////////////////////// + +typedef enum +{ + t_Bool, t_Int, t_Float, t_String +} argdatatype; + +typedef struct +{ + void *data; + char *name; + char *text; + char *def; + argdatatype type; +} argtype; + +typedef struct +{ + char *opt; + char *desc; +} OptionStruct; + +typedef struct +{ + int nopts; + XrmOptionDescRec *opts; + int nargs; + argtype *args; + OptionStruct *desc; +} ModeSpecOpt; + +typedef struct +{ + char *ignore0; + char *ignore1; + char *ignore2; + char *ignore3; + char *ignore4; + char *ignore5; + char *ignore6; + void *ignore7; + int ignore8; + int ignore9; + int ignore10; + int ignore11; + int ignore12; + float ignore13; + char *ignore14; + char *ignore15; + int ignore16; + void *ignore17; +} ModStruct; + +////////////////////////////////////////////////////////////////////////////// +// ModeInfo + +typedef struct +{ + Display *dpy; + Window window; + GC gc; + int num_screen; + int screen_number; + int width; + int height; + int polygon_count; + int recursion_depth; + Bool fps_p; + Bool is_drawn; + int pause; + int count; + int cycles; + int size; + XWindowAttributes xgwa; + int npixels; + XColor *colors; + unsigned long *pixels; + Bool writable_p; + unsigned long white_pixel; + unsigned long black_pixel; + Bool threed; + float threed_delta; + unsigned long threed_right_color; + unsigned long threed_left_color; + unsigned long threed_both_color; + unsigned long threed_none_color; + Bool install_p; +} ModeInfo; + +#define MI_DISPLAY(mi) (mi)->dpy +#define MI_WINDOW(mi) 0 +#define MI_GC(mi) (mi)->gc +#define MI_NUM_SCREENS(mi) 1 +#define MI_SCREEN(mi) 0 +#define MI_WIDTH(mi) (mi)->width +#define MI_HEIGHT(mi) (mi)->height +#define MI_WIN_WIDTH(mi) (mi)->width +#define MI_WIN_HEIGHT(mi) (mi)->height +#define MI_NCOLORS(mi) (mi)->npixels +#define MI_IS_DRAWN(mi) (mi)->is_drawn +#define MI_IS_FPS(mi) FALSE +#define MI_IS_MONO(mi) FALSE +#define MI_CLEARWINDOW(mi) ss_clear(MI_DISPLAY(mi)) +#define MI_IS_WIREFRAME(mi) FALSE +#define MI_COUNT(MI) (mi)->count +#define MI_BATCHCOUNT(MI) MI_COUNT(MI) +#define MI_IS_ICONIC(mi) FALSE +#define MI_CYCLES(mi) (mi)->cycles +#define MI_SIZE(mi) (mi)->size +#ifdef NDEBUG + #define MI_IS_DEBUG(mi) FALSE + #define MI_IS_VERBOSE(mi) FALSE +#else + #define MI_IS_DEBUG(mi) TRUE + #define MI_IS_VERBOSE(mi) TRUE +#endif +#define MI_NAME(mi) progname +#define MI_DELAY(mi) DELAY +#define MI_VISUAL(mi) NULL +#define MI_COLORMAP(mi) 0 +#define MI_PIXEL(mi,n) ((mi)->pixels[n]) +#define MI_NPIXELS(mi) (mi)->npixels +#define MI_IS_FULLRANDOM(mi) True +#define MI_WHITE_PIXEL(mi) (mi)->white_pixel +#define MI_BLACK_PIXEL(mi) (mi)->black_pixel +#define MI_WIN_WHITE_PIXEL(mi) (mi)->white_pixel +#define MI_WIN_BLACK_PIXEL(mi) (mi)->black_pixel +#define MI_PAUSE(mi) hack_delay +#define MI_WIN_DEPTH(mi) 32 +#define MI_WIN_IS_USE3D(mi) ((mi)->threed) +#define MI_LEFT_COLOR(mi) ((mi)->threed_left_color) +#define MI_RIGHT_COLOR(mi) ((mi)->threed_right_color) +#define MI_BOTH_COLOR(mi) ((mi)->threed_both_color) +#define MI_NONE_COLOR(mi) ((mi)->threed_none_color) +#define MI_DELTA3D(mi) ((mi)->threed_delta) +#define MI_WIN_IS_INSTALL(mi) ((mi)->install_p) +#define MI_IS_INSTALL(mi) MI_WIN_IS_INSTALL(mi) +#define MI_DEPTH(mi) 32 + +#define FreeAllGL(mi) /**/ + +////////////////////////////////////////////////////////////////////////////// + +#define SINF(n) ((float)sin((double)(n))) +#define COSF(n) ((float)cos((double)(n))) +#define FABSF(n) ((float)fabs((double)(n))) + +#undef MAX +#undef MIN +#undef ABS +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define ABS(a) ((a)<0 ? -(a) : (a)) + +////////////////////////////////////////////////////////////////////////////// + +#undef NUMCOLORS +#define NUMCOLORS 256 + +////////////////////////////////////////////////////////////////////////////// + +#include "yarandom.h" + +#define LRAND() ((long) (random() & 0x7fffffff)) +#define NRAND(n) ((int) (LRAND() % (n))) +#define MAXRAND (2147483648.0) /* unsigned 1<<31 as a float */ +#define SRAND(n) /* already seeded by screenhack.c */ + +////////////////////////////////////////////////////////////////////////////// + +typedef enum COLOR_SCHEME { + color_scheme_default, color_scheme_uniform, + color_scheme_smooth, color_scheme_bright +}; + +#ifdef WRITABLE_COLORS +# undef WRITABLE_COLORS +# define WRITABLE_COLORS 1 +#else +# define WRITABLE_COLORS 0 +#endif + +////////////////////////////////////////////////////////////////////////////// + +#if defined(UNIFORM_COLORS) +# define XLOCKMORE_COLOR_SCHEME color_scheme_uniform +#elif defined(SMOOTH_COLORS) +# define XLOCKMORE_COLOR_SCHEME color_scheme_smooth +#elif defined(BRIGHT_COLORS) +# define XLOCKMORE_COLOR_SCHEME color_scheme_bright +#else +# define XLOCKMORE_COLOR_SCHEME color_scheme_default +#endif + +typedef void (*HACK_INIT)(ModeInfo *); +typedef void (*HACK_DRAW)(ModeInfo *); +typedef void (*HACK_REFRESH)(ModeInfo *); +typedef void (*HACK_FREE)(ModeInfo *); + +extern char *progname; +extern DWORD hack_delay; +extern int hack_count; +extern int hack_count_enabled; +extern int hack_cycles; +extern int hack_cycles_enabled; +extern int hack_size; +extern int hack_size_enabled; +extern int hack_ncolors; +extern int hack_ncolors_enabled; +extern int hack_color_scheme; + +extern int hack_argcount; +extern argtype *hack_arginfo; + +#ifdef COUNT + #define HACK_COUNT \ + int hack_count = COUNT; \ + int hack_count_enabled = True +#else + #define HACK_COUNT \ + int hack_count = 0; \ + int hack_count_enabled = False +#endif +#ifdef CYCLES + #define HACK_CYCLES \ + int hack_cycles = CYCLES; \ + int hack_cycles_enabled = True +#else + #define HACK_CYCLES \ + int hack_cycles = 0; \ + int hack_cycles_enabled = False +#endif +#ifdef SIZE_ + #define HACK_SIZE \ + int hack_size = SIZE_; \ + int hack_size_enabled = True +#else + #define HACK_SIZE \ + int hack_size = 0; \ + int hack_size_enabled = False +#endif +#ifdef NCOLORS + #define HACK_NCOLORS \ + int hack_ncolors = NCOLORS; \ + int hack_ncolors_enabled = True +#else + #define HACK_NCOLORS \ + int hack_ncolors = 0; \ + int hack_ncolors_enabled = False +#endif + +#ifdef NOARGS + #define XSCREENSAVER_MODULE_2(CLASS,NAME,PREFIX) \ + HACK_INIT hack_init = init_ ## PREFIX; \ + HACK_DRAW hack_draw = draw_ ## PREFIX; \ + HACK_REFRESH hack_refresh = refresh_ ## PREFIX; \ + HACK_FREE hack_free = release_ ## PREFIX; \ + DWORD hack_delay = DELAY; \ + char *progname = CLASS; \ + HACK_COUNT; \ + HACK_CYCLES; \ + HACK_SIZE; \ + HACK_NCOLORS; \ + argtype *hack_arginfo = NULL; \ + int hack_argcount = 0; \ + int hack_color_scheme = XLOCKMORE_COLOR_SCHEME; +#else + #define XSCREENSAVER_MODULE_2(CLASS,NAME,PREFIX) \ + HACK_INIT hack_init = init_ ## PREFIX; \ + HACK_DRAW hack_draw = draw_ ## PREFIX; \ + HACK_REFRESH hack_refresh = refresh_ ## PREFIX; \ + HACK_FREE hack_free = release_ ## PREFIX; \ + DWORD hack_delay = DELAY; \ + char *progname = CLASS; \ + HACK_COUNT; \ + HACK_CYCLES; \ + HACK_SIZE; \ + HACK_NCOLORS; \ + argtype *hack_arginfo = vars; \ + int hack_argcount = sizeof(vars) / sizeof(vars[0]); \ + int hack_color_scheme = XLOCKMORE_COLOR_SCHEME; +#endif + +#define XSCREENSAVER_MODULE(CLASS,PREFIX) \ + XSCREENSAVER_MODULE_2(CLASS,PREFIX,PREFIX) + +extern HACK_INIT hack_init; +extern HACK_DRAW hack_draw; +extern HACK_REFRESH hack_refresh; +extern HACK_FREE hack_free; + +////////////////////////////////////////////////////////////////////////////// +// OpenGL-related + +#include +#include + +#define GL_UNSIGNED_INT_8_8_8_8_REV GL_UNSIGNED_BYTE + +#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT +# define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#endif +#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT +# define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +#ifndef GL_LIGHT_MODEL_COLOR_CONTROL +# define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#endif +#ifndef GL_SEPARATE_SPECULAR_COLOR +# define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#endif + +HGLRC *init_GL(ModeInfo *mi); +void glXMakeCurrent(Display *d, Window w, GLXContext context); +void glXSwapBuffers(Display *d, Window w); +void check_gl_error(const char *name); +void clear_gl_error(void); + +////////////////////////////////////////////////////////////////////////////// +// trackball + +#define trackball_state char* // Not implemented yet + +trackball_state *gltrackball_init(void); +void gltrackball_rotate(trackball_state *trackball); +void gltrackball_get_quaternion(char **ppch, float q[4]); +void gltrackball_start(trackball_state* trackball, int n1, int n2, int n3, int n4); +void gltrackball_track(trackball_state* trackball, int n1, int n2, int n3, int n4); + +////////////////////////////////////////////////////////////////////////////// +// misc + +void do_fps(ModeInfo *mi); +extern Bool has_writable_cells(Screen *s, Visual *v); +float current_device_rotation(void); +int ffs(int i); +int visual_cells(Screen *screen, Visual *visual); +int visual_depth(Screen *screen, Visual *visual); +void load_texture_async( + Screen *screen, Window window, GLXContext glx_context, + int desired_width, int desired_height, Bool mipmap_p, GLuint texid, + void (*callback) (const char *filename, + XRectangle *geometry, + int image_width, + int image_height, + int texture_width, + int texture_height, + void *closure), + void *closure); + +////////////////////////////////////////////////////////////////////////////// +// screen saver + +typedef struct SCREENSAVER +{ + HWND hwnd; + HDC hdc; + HGLRC hglrc; + UINT x0, y0; + UINT width, height; + ModeInfo modeinfo; + HBITMAP hbmScreenShot; +} SCREENSAVER; + +extern SCREENSAVER ss; + +BOOL InitPixelFormat(SCREENSAVER *ss); +VOID MakeCurrent(SCREENSAVER *ss); +XImage *GetScreenShotXImage(void); +void CreateTextureFromImage(XImage *ximage, GLuint texid); +BOOL ss_init(HWND hwnd); +void ss_term(void); +void ss_clear(Display *d); + +////////////////////////////////////////////////////////////////////////////// + +#include "colors.h" + +////////////////////////////////////////////////////////////////////////////// + +#endif // __XLOCKMORE_H__ diff --git a/xlockmore.rc b/xlockmore.rc new file mode 100644 index 0000000..5691f36 --- /dev/null +++ b/xlockmore.rc @@ -0,0 +1,76 @@ +#include +#include "resource.h" + +#ifndef IDC_STATIC +#define IDC_STATIC -1 +#endif + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT +#pragma code_page(65001) // UTF-8 + +1 ICON "XScreenSaver.ico" + +// Dialog +DLG_SCRNSAVECONFIGURE DIALOG DISCARDABLE 0, 0, 425, 285 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX +CAPTION "XScreenSaver for Windows" +FONT 8, "Arial" +{ + CONTROL "arg0", IDC_ARGNAME00, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 7, 60, 12 + CONTROL "", IDC_ARGVAL00, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 5, 135, 14 + CONTROL "arg1", IDC_ARGNAME01, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 27, 60, 12 + CONTROL "", IDC_ARGVAL01, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 25, 135, 14 + CONTROL "arg2", IDC_ARGNAME02, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 47, 60, 12 + CONTROL "", IDC_ARGVAL02, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 45, 135, 14 + CONTROL "arg3", IDC_ARGNAME03, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 67, 60, 12 + CONTROL "", IDC_ARGVAL03, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 65, 135, 14 + CONTROL "arg4", IDC_ARGNAME04, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 87, 60, 12 + CONTROL "", IDC_ARGVAL04, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 85, 135, 14 + CONTROL "arg5", IDC_ARGNAME05, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 107, 60, 12 + CONTROL "", IDC_ARGVAL05, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 105, 135, 14 + CONTROL "arg6", IDC_ARGNAME06, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 127, 60, 12 + CONTROL "", IDC_ARGVAL06, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 125, 135, 14 + CONTROL "arg7", IDC_ARGNAME07, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 147, 60, 12 + CONTROL "", IDC_ARGVAL07, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 145, 135, 14 + CONTROL "arg8", IDC_ARGNAME08, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 167, 60, 12 + CONTROL "", IDC_ARGVAL08, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 165, 135, 14 + CONTROL "arg9", IDC_ARGNAME09, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 187, 60, 12 + CONTROL "", IDC_ARGVAL09, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 185, 135, 14 + CONTROL "arg10", IDC_ARGNAME10, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 207, 60, 12 + CONTROL "", IDC_ARGVAL10, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 205, 135, 14 + CONTROL "arg11", IDC_ARGNAME11, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 227, 60, 12 + CONTROL "", IDC_ARGVAL11, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 75, 225, 135, 14 + CONTROL "arg12", IDC_ARGNAME12, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 7, 60, 12 + CONTROL "", IDC_ARGVAL12, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 5, 135, 14 + CONTROL "arg13", IDC_ARGNAME13, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 27, 60, 12 + CONTROL "", IDC_ARGVAL13, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 25, 135, 14 + CONTROL "arg14", IDC_ARGNAME14, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 47, 60, 12 + CONTROL "", IDC_ARGVAL14, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 45, 135, 14 + CONTROL "arg15", IDC_ARGNAME15, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 67, 60, 12 + CONTROL "", IDC_ARGVAL15, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 65, 135, 14 + CONTROL "arg16", IDC_ARGNAME16, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 87, 60, 12 + CONTROL "", IDC_ARGVAL16, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 85, 135, 14 + CONTROL "arg17", IDC_ARGNAME17, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 107, 60, 12 + CONTROL "", IDC_ARGVAL17, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 105, 135, 14 + CONTROL "arg18", IDC_ARGNAME18, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 127, 60, 12 + CONTROL "", IDC_ARGVAL18, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 125, 135, 14 + CONTROL "arg19", IDC_ARGNAME19, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 147, 60, 12 + CONTROL "", IDC_ARGVAL19, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 145, 135, 14 + CONTROL "arg20", IDC_ARGNAME20, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 167, 60, 12 + CONTROL "", IDC_ARGVAL20, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 165, 135, 14 + CONTROL "arg21", IDC_ARGNAME21, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 187, 60, 12 + CONTROL "", IDC_ARGVAL21, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 185, 135, 14 + CONTROL "arg22", IDC_ARGNAME22, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 207, 60, 12 + CONTROL "", IDC_ARGVAL22, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 205, 135, 14 + CONTROL "arg23", IDC_ARGNAME23, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 227, 60, 12 + CONTROL "", IDC_ARGVAL23, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 285, 225, 135, 14 + CONTROL "count", IDC_COUNTNAME, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 247, 40, 14 + CONTROL "", IDC_COUNTVAL, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 50, 245, 60, 14 + CONTROL "cycles", IDC_CYCLESNAME, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 135, 247, 40, 14 + CONTROL "", IDC_CYCLESVAL, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 185, 245, 60, 14 + CONTROL "size", IDC_SIZENAME, "STATIC", SS_RIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP, 280, 247, 40, 14 + CONTROL "", IDC_SIZEVAL, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 330, 245, 60, 14 + CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 215, 265, 100, 14 + CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 320, 265, 100, 14 + CONTROL "&Reset Setting", IDC_RESET, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 265, 100, 14 +} diff --git a/xws2win.c b/xws2win.c new file mode 100644 index 0000000..75b7974 --- /dev/null +++ b/xws2win.c @@ -0,0 +1,982 @@ +#include "xws2win.h" +#include "colors.h" + +////////////////////////////////////////////////////////////////////////////// + +DrawableData* XGetDrawableData_(Drawable d) +{ + return d; +} + +HDC XCreateDrawableDC_(Display *dpy, Drawable d) +{ + HDC hdc; + DrawableData* data; + + if (d != NULL) + { + hdc = CreateCompatibleDC(dpy); + if (hdc != NULL) + { + data = XGetDrawableData_(d); + data->hbmOld = SelectObject(hdc, data->hbm); + } + } + else + { + hdc = dpy; + } + return hdc; +} + +int XDeleteDrawableDC_(Display *dpy, Drawable d, HDC hdc) +{ + DrawableData *data; + if (d != NULL) + { + data = XGetDrawableData_(d); + SelectObject(hdc, data->hbmOld); + DeleteDC(hdc); + } + return 0; +} + +GC XCreateGC(Display *dpy, Drawable d, + unsigned long valuemask, XGCValues *values) +{ + XGCValues *newvalues; + + newvalues = (XGCValues *)calloc(1, sizeof(XGCValues)); + if (newvalues == NULL) + return NULL; + + newvalues->foreground = 0; + newvalues->foreground_rgb = RGB(0, 0, 0); + newvalues->background = 255; + newvalues->background_rgb = RGB(255, 255, 255); + newvalues->function = GXcopy; + newvalues->fill_style = FillSolid; + newvalues->cap_style = CapButt; + newvalues->join_style = JoinMiter; + newvalues->line_style = LineSolid; + if (values != NULL) + XChangeGC(dpy, newvalues, valuemask, values); + + if (d != NULL) + { + DrawableData *data = XGetDrawableData_(d); + newvalues->hbmOld = SelectObject(dpy, data->hbm); + } + + return newvalues; +} + +int XChangeGC(Display* dpy, GC gc, unsigned long valuemask, XGCValues* values) +{ + XColor color; + XGCValues* newvalues = XGetGCValues_(gc); + if (newvalues == NULL) + return BadGC; + + if (valuemask & GCForeground) + { + color.pixel = newvalues->foreground = values->foreground; + XQueryColor(dpy, DefaultColormap(dpy, DefaultScreenOfDisplay(dpy)), + &color); + newvalues->foreground_rgb = + RGB(color.red / 256, color.green / 256, color.blue / 256); + } + + if (valuemask & GCBackground) + { + color.pixel = newvalues->background = values->background; + XQueryColor(dpy, DefaultColormap(dpy, DefaultScreenOfDisplay(dpy)), + &color); + newvalues->background_rgb = + RGB(color.red / 256, color.green / 256, color.blue / 256); + } + + if (valuemask & GCFillStyle) + newvalues->fill_style = values->fill_style; + + if (valuemask & GCFunction) + newvalues->function = values->function; + + if (valuemask & GCLineWidth) + newvalues->line_width = values->line_width; + + if (valuemask & GCCapStyle) + newvalues->cap_style = values->cap_style; + + if (valuemask & GCJoinStyle) + newvalues->join_style = values->join_style; + + if (valuemask & GCLineStyle) + newvalues->line_style = values->line_style; + + if (valuemask & GCStipple) + newvalues->stipple = values->stipple; + + return 0; +} + +int XFreeGC(Display *dpy, GC gc) +{ + XGCValues* values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + if (values->hbmOld) + SelectObject(dpy, values->hbmOld); + + free(gc); + return 0; +} + +static void get_2_skewed_angles(double *skewed1, double *skewed2, + int width, int height, int angle1, int angle2) +{ +#define M_PI_PER_180_PER_64 (M_PI / 180.0 / 64.0) +#define M_PI_3_PER_2 (3.0 * M_PI / 2.0) + double radian1, radian2; + + angle1 = angle1 % (360 * 64); + angle2 = angle2 % (360 * 64); + angle2 += angle1; + radian1 = angle1 * M_PI_PER_180_PER_64; + radian2 = angle2 * M_PI_PER_180_PER_64; + *skewed1 = atan(tan(radian1) * width / height); + if (M_PI_2 <= radian1 && radian1 < M_PI_3_PER_2) + *skewed1 += M_PI; + else if (M_PI_3_PER_2 <= radian1 && radian1 <= M_2_PI) + *skewed1 += 2.0 * M_PI; + *skewed2 = atan(tan(radian2) * width / height); + if (M_PI_2 <= radian2 && radian2 < M_PI_3_PER_2) + *skewed2 += M_PI; + else if (M_PI_3_PER_2 <= radian2 && radian2 <= M_2_PI) + *skewed2 += M_2_PI; +} + +int XSetLineAttributes(Display *dpy, GC gc, + unsigned int line_width, int line_style, + int cap_style, int join_style) +{ + XGCValues *values; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + values->line_width = line_width; + values->line_style = line_style; + values->cap_style = cap_style; + values->join_style = join_style; + return 0; +} + +int XDrawPoint(Display *dpy, Drawable d, GC gc, + int x, int y) +{ + XGCValues *values; + HDC hdc; + COLORREF rgb; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hdc = XCreateDrawableDC_(dpy, d); + rgb = values->foreground_rgb; + SetPixelV(hdc, x, y, rgb); + XDeleteDrawableDC_(dpy, d, hdc); + return 0; +} + +int XDrawPoints(Display *dpy, Drawable d, GC gc, + XPoint *points, int npoints, int CoordMode) +{ + XGCValues *values; + HDC hdc; + COLORREF rgb; + int i; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hdc = XCreateDrawableDC_(dpy, d); + rgb = values->foreground_rgb; + if (CoordMode == CoordModeOrigin) + { + for (i = 0; i < npoints; i++) + { + SetPixelV(hdc, points[i].x, points[i].y, rgb); + } + } + else + { + int x = points[0].x, y = points[0].y; + SetPixelV(dpy, x, y, rgb); + for (i = 1; i < npoints; i++) + { + x += points[i].x; + y += points[i].y; + SetPixelV(hdc, x, y, rgb); + } + } + XDeleteDrawableDC_(dpy, d, hdc); + return 0; +} + +HPEN XCreateWinPen(XGCValues *values) +{ + LOGBRUSH lb; + lb.lbColor = values->foreground_rgb; + lb.lbStyle = BS_SOLID; + return ExtCreatePen( + PS_GEOMETRIC | values->line_style | values->cap_style | values->join_style, + values->line_width, &lb, 0, NULL); +} + +LPVOID XCreatePackedDIBFromPixmap(Pixmap pixmap) +{ + BITMAP bm; + LPBYTE pb; + DWORD size = sizeof(BITMAPINFOHEADER); + LPBITMAPINFO lpbi = (LPBITMAPINFO)calloc(1, size); + assert(lpbi != NULL); + + GetObject(pixmap->hbm, sizeof(BITMAP), &bm); + GetDIBits(NULL, pixmap->hbm, 0, bm.bmHeight, NULL, lpbi, DIB_RGB_COLORS); + size += lpbi->bmiHeader.biSizeImage; + lpbi = (LPBITMAPINFO)realloc(lpbi, size); + assert(lpbi != NULL); + pb = (LPBYTE)lpbi; + pb += sizeof(BITMAPINFOHEADER); + GetDIBits(NULL, pixmap->hbm, 0, bm.bmHeight, pb, lpbi, DIB_RGB_COLORS); + return lpbi; +} + +HBRUSH XCreateWinBrush(XGCValues *values) +{ + HBRUSH hbr; + LOGBRUSH lb; + if (values->fill_style == FillSolid) + { + lb.lbColor = values->foreground_rgb; + lb.lbStyle = BS_SOLID; + return CreateBrushIndirect(&lb); + } + else if (values->fill_style == FillStippled) + { + LPVOID lpPackedDIB = XCreatePackedDIBFromPixmap(values->stipple); + hbr = CreateDIBPatternBrushPt(lpPackedDIB, DIB_RGB_COLORS); + free(lpPackedDIB); + return hbr; + } + return NULL; +} + +HFONT XCreateWinFont(XGCValues *values) +{ + return (HFONT)GetStockObject(DEFAULT_GUI_FONT); +} + +int XDrawLine(Display *dpy, Drawable d, GC gc, + int x1, int y1, int x2, int y2) +{ + XGCValues *values; + HDC hdc; + HPEN hPen; + HGDIOBJ hPenOld; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hPen = XCreateWinPen(values); + assert(hPen); + if (hPen == NULL) + return BadAlloc; + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hPenOld = SelectObject(hdc, hPen); + MoveToEx(hdc, x1, y1, NULL); + LineTo(hdc, x2, y2); + SelectObject(hdc, hPenOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hPen); + return 0; +} + +int XDrawLines(Display *dpy, Drawable d, GC gc, + XPoint *points, int npoints, int mode) +{ + XGCValues *values; + LPPOINT lpPoints = NULL; + HDC hdc; + HPEN hPen; + HGDIOBJ hPenOld; + int i, x, y; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + lpPoints = (LPPOINT)calloc(npoints, sizeof(POINT)); + if (lpPoints == NULL) + return BadAlloc; + + hPen = XCreateWinPen(values); + assert(hPen); + if (hPen == NULL) + { + free(lpPoints); + return BadAlloc; + } + + if (mode == CoordModeOrigin) + { + for (i = 0; i < npoints; i++) + { + lpPoints[i].x = points[i].x; + lpPoints[i].y = points[i].y; + } + } + else + { + lpPoints[0].x = x = points[0].x; + lpPoints[0].y = y = points[0].y; + for (i = 1; i < npoints; i++) + { + x += points[i].x; + y += points[i].y; + lpPoints[i].x = x; + lpPoints[i].y = y; + } + } + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hPenOld = SelectObject(hdc, hPen); + Polyline(hdc, lpPoints, npoints); + free(lpPoints); + SelectObject(hdc, hPenOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hPen); + + return 0; +} + +int XDrawRectangle( + Display *dpy, Drawable d, GC gc, + int x, int y, unsigned int width, unsigned int height) +{ + XGCValues *values; + HDC hdc; + HPEN hPen; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hPen = XCreateWinPen(values); + assert(hPen); + if (hPen == NULL) + return BadAlloc; + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + Rectangle(hdc, x, y, x + width, y + height); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hPen); + return 0; +} + +int XDrawSegments(Display *dpy, Drawable d, GC gc, + XSegment *segments, int nsegments) +{ + XGCValues *values; + HDC hdc; + HPEN hPen; + HGDIOBJ hPenOld; + int i; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hPen = XCreateWinPen(values); + assert(hPen); + if (hPen == NULL) + return BadAlloc; + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hPenOld = SelectObject(hdc, hPen); + for (i = 0; i < nsegments; i++) + { + MoveToEx(hdc, segments[i].x1, segments[i].y1, NULL); + LineTo(hdc, segments[i].x2, segments[i].y2); + } + SelectObject(hdc, hPenOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hPen); + return 0; +} + +int XDrawArc(Display *dpy, Drawable d, GC gc, + int x, int y, unsigned int width, unsigned int height, + int angle1, int angle2) +{ + XGCValues *values; + HDC hdc; + HPEN hPen; + HGDIOBJ hPenOld; + double skewed1, skewed2; + int xStartArc, yStartArc, xEndArc, yEndArc; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hPen = XCreateWinPen(values); + assert(hPen); + if (hPen == NULL) + return BadAlloc; + + get_2_skewed_angles(&skewed1, &skewed2, width, height, angle1, angle2); + xStartArc = x + width / 2.0 + (width / 2.0) * cos(skewed1); + yStartArc = y + height / 2.0 + (height / 2.0) * sin(skewed1); + xEndArc = x + width / 2.0 + (width / 2.0) * cos(skewed2); + yEndArc = y + height / 2.0 + (height / 2.0) * sin(skewed2); + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hPenOld = SelectObject(hdc, hPen); + Arc(hdc, x, y, x + width, y + height, + xStartArc, yStartArc, xEndArc, yEndArc); + SelectObject(hdc, hPenOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hPen); + return 0; +} + +int XDrawArcs(Display *dpy, Drawable d, GC gc, + XArc *arcs, int n_arcs) +{ + XGCValues *values; + HDC hdc; + HPEN hPen; + HGDIOBJ hPenOld; + int i, x, y; + unsigned int width, height; + short angle1, angle2; + double skewed1, skewed2; + int xStartArc, yStartArc, xEndArc, yEndArc; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hPen = XCreateWinPen(values); + if (hPen == NULL) + return BadAlloc; + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hPenOld = SelectObject(hdc, hPen); + for (i = 0; i < n_arcs; i++) + { + x = arcs[i].x; y = arcs[i].y; + width = arcs[i].width; height = arcs[i].height; + angle1 = arcs[i].angle1; angle2 = arcs[i].angle2; + + get_2_skewed_angles(&skewed1, &skewed2, width, height, angle1, angle2); + xStartArc = x + width / 2.0 + (width / 2.0) * cos(skewed1); + yStartArc = y + height / 2.0 + (height / 2.0) * sin(skewed1); + xEndArc = x + width / 2.0 + (width / 2.0) * cos(skewed2); + yEndArc = y + height / 2.0 + (height / 2.0) * sin(skewed2); + + BeginPath(hdc); + Arc(hdc, x, y, x + width, y + height, + xStartArc, yStartArc, xEndArc, yEndArc); + EndPath(hdc); + FillPath(hdc); + } + SelectObject(hdc, hPenOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hPen); + return 0; +} + +int XDrawString(Display *dpy, Drawable d, GC gc, + int x, int y, const char *string, int length) +{ + XGCValues *values; + HFONT hFont; + HGDIOBJ hFontOld; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hFont = XCreateWinFont(values); + if (hFont == NULL) + return BadAlloc; + + hFontOld = SelectObject(dpy, hFont); + TextOut(dpy, x, y, string, length); + SelectObject(dpy, hFontOld); + + DeleteObject(hFont); + return 0; +} + +int XDrawImageString(Display *dpy, Drawable d, GC gc, + int x, int y, const char *string, int length) +{ + assert(0); + return 0; +} + +int XFillRectangle( + Display *dpy, Drawable d, GC gc, + int x, int y, unsigned int width, unsigned int height) +{ + XGCValues *values; + HDC hdc; + HBRUSH hbr; + RECT rc; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hbr = XCreateWinBrush(values); + if (hbr == NULL) + return BadAlloc; + + SetRect(&rc, x, y, x + width, y + height); + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + FillRect(hdc, &rc, hbr); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hbr); + return 0; +} + +int XFillRectangles( + Display *dpy, Drawable d, GC gc, + XRectangle *rectangles, int n_rects) +{ + XGCValues *values; + HDC hdc; + HBRUSH hbr; + RECT rc; + int i; + short x, y; + unsigned short width, height; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hbr = XCreateWinBrush(values); + if (hbr == NULL) + return BadAlloc; + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + for (i = 0; i < n_rects; i++) + { + x = rectangles[i].x; + y = rectangles[i].x; + width = rectangles[i].width; + height = rectangles[i].height; + SetRect(&rc, x, y, x + width, y + height); + FillRect(hdc, &rc, hbr); + } + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hbr); + return 0; +} + +int XFillPolygon(Display *dpy, Drawable d, GC gc, + XPoint *points, int n_points, int shape, int mode) +{ + XGCValues *values; + HDC hdc; + HBRUSH hbr; + HGDIOBJ hbrOld; + LPPOINT lpPoints; + int i, x, y; + int nR2; + + assert(shape == Convex); + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + lpPoints = calloc(n_points, sizeof(POINT)); + if (lpPoints == NULL) + return BadAlloc; + + if (mode == CoordModeOrigin) + { + for (i = 0; i < n_points; i++) + { + lpPoints[i].x = points[i].x; + lpPoints[i].y = points[i].y; + } + } + else + { + lpPoints[0].x = x = points[0].x; + lpPoints[0].y = y = points[0].y; + for (i = 1; i < n_points; i++) + { + x += points[i].x; + y += points[i].y; + lpPoints[i].x = x; + lpPoints[i].y = y; + } + } + + hbr = XCreateWinBrush(values); + if (hbr == NULL) + { + free(lpPoints); + return BadAlloc; + } + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hbrOld = SelectObject(hdc, hbr); + BeginPath(hdc); + Polygon(hdc, lpPoints, n_points); + EndPath(hdc); + FillPath(hdc); + SelectObject(hdc, hbrOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + free(lpPoints); + DeleteObject(hbr); + return 0; +} + +int XFillArc(Display *dpy, Drawable d, GC gc, + int x, int y, unsigned int width, unsigned int height, + int angle1, int angle2) +{ + XGCValues *values; + HDC hdc; + HBRUSH hbr; + HGDIOBJ hbrOld; + double skewed1, skewed2; + int xStartArc, yStartArc, xEndArc, yEndArc; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hbr = XCreateWinBrush(values); + if (hbr == NULL) + return BadAlloc; + + get_2_skewed_angles(&skewed1, &skewed2, width, height, angle1, angle2); + xStartArc = x + width / 2.0 + (width / 2.0) * cos(skewed1); + yStartArc = y + height / 2.0 + (height / 2.0) * sin(skewed1); + xEndArc = x + width / 2.0 + (width / 2.0) * cos(skewed2); + yEndArc = y + height / 2.0 + (height / 2.0) * sin(skewed2); + + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hbrOld = SelectObject(hdc, hbr); + BeginPath(hdc); + Arc(hdc, x, y, x + width, y + height, + xStartArc, yStartArc, xEndArc, yEndArc); + EndPath(hdc); + FillPath(hdc); + SelectObject(hdc, hbrOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hbr); + return 0; +} + +int XFillArcs(Display *dpy, Drawable d, GC gc, + XArc *arcs, int n_arcs) +{ + XGCValues *values; + HDC hdc; + HBRUSH hbr; + HGDIOBJ hbrOld; + int i, x, y; + unsigned int width, height; + short angle1, angle2; + double skewed1, skewed2; + int xStartArc, yStartArc, xEndArc, yEndArc; + int nR2; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + hbr = XCreateWinBrush(values); + if (hbr == NULL) + return BadAlloc; + + hdc = XCreateDrawableDC_(dpy, d); + nR2 = SetROP2(hdc, values->function); + hbrOld = SelectObject(hdc, hbr); + for (i = 0; i < n_arcs; i++) + { + x = arcs[i].x; y = arcs[i].y; + width = arcs[i].width; height = arcs[i].height; + angle1 = arcs[i].angle1; angle2 = arcs[i].angle2; + + get_2_skewed_angles(&skewed1, &skewed2, width, height, angle1, angle2); + xStartArc = x + width / 2.0 + (width / 2.0) * cos(skewed1); + yStartArc = y + height / 2.0 + (height / 2.0) * sin(skewed1); + xEndArc = x + width / 2.0 + (width / 2.0) * cos(skewed2); + yEndArc = y + height / 2.0 + (height / 2.0) * sin(skewed2); + + BeginPath(hdc); + Arc(hdc, x, y, x + width, y + height, + xStartArc, yStartArc, xEndArc, yEndArc); + EndPath(hdc); + FillPath(hdc); + } + SelectObject(hdc, hbrOld); + SetROP2(hdc, nR2); + XDeleteDrawableDC_(dpy, d, hdc); + + DeleteObject(hbr); + return 0; +} + +int XCopyArea(Display *dpy, + Drawable src_drawable, Drawable dst_drawable, GC gc, + int src_x, int src_y, + unsigned int width, unsigned int height, + int dst_x, int dst_y) +{ + HDC hdcSrc = XCreateDrawableDC_(dpy, src_drawable); + HDC hdcDst = XCreateDrawableDC_(dpy, dst_drawable); + BitBlt(hdcDst, dst_x, dst_y, width, height, hdcSrc, src_x, src_y, SRCCOPY); + XDeleteDrawableDC_(dpy, src_drawable, hdcSrc); + XDeleteDrawableDC_(dpy, dst_drawable, hdcDst); + return 0; +} + +int XSync(Display *dpy, Bool b) +{ + GdiFlush(); + return 0; +} + +int XSetFunction(Display *dpy, GC gc, int function) +{ + XGCValues *values; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + values->function = function; + return 0; +} + +int XSetFillStyle(Display *dpy, GC gc, int fill) +{ + XGCValues *values; + + values = XGetGCValues_(gc); + if (values == NULL) + return BadGC; + + assert(fill == FillSolid); + values->fill_style = fill; + return 0; +} + +typedef struct tagBITMAPINFOEX +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +} BITMAPINFOEX, * LPBITMAPINFOEX; + +#define WIDTHBYTES(i) (((i) + 31) / 32 * 4) + +HBITMAP XCreateWinBitmapFromXImage(XImage *ximage) +{ + BITMAPINFOEX bi; + HBITMAP hbm; + LPBYTE pbBits; + unsigned int i, x, y, widthbytes; + XColor color; + + ZeroMemory(&bi, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = ximage->width; + bi.bmiHeader.biHeight = ximage->height; + bi.bmiHeader.biPlanes = 1; + if ((ximage->bits_per_pixel | ximage->depth) == 1) + { + bi.bmiHeader.biBitCount = 1; + bi.bmiColors[0].rgbBlue = 0; + bi.bmiColors[0].rgbGreen = 0; + bi.bmiColors[0].rgbRed = 0; + bi.bmiColors[0].rgbReserved = 0; + bi.bmiColors[1].rgbBlue = 255; + bi.bmiColors[1].rgbGreen = 255; + bi.bmiColors[1].rgbRed = 255; + bi.bmiColors[1].rgbReserved = 0; + hbm = CreateDIBSection(NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS, + (LPVOID *)&pbBits, NULL, 0); + widthbytes = WIDTHBYTES(ximage->width * 1); + for (y = 0; y < ximage->height; y++) + { + for (x = 0; x < (ximage->width + 7) / 8; x++) + { + pbBits[y * widthbytes + x] = ximage->data[(ximage->height - y - 1) * ximage->bytes_per_line + x]; + } + } + return hbm; + } + + if (ximage->format == ZPixmap && ximage->bits_per_pixel == 8) + { + bi.bmiHeader.biBitCount = 8; + for (i = 0; i < 256; i++) + { + color.pixel = i; + XQueryColor(NULL, 0, &color); + bi.bmiColors[i].rgbBlue = color.blue / 256; + bi.bmiColors[i].rgbGreen = color.green / 256; + bi.bmiColors[i].rgbRed = color.red / 256; + bi.bmiColors[i].rgbReserved = 0; + } + hbm = CreateDIBSection(NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS, + (LPVOID *)&pbBits, NULL, 0); + widthbytes = WIDTHBYTES(ximage->width * 8); + for (y = 0; y < ximage->height; y++) + { + for (x = 0; x < ximage->width; x++) + { + pbBits[y * widthbytes + x] = ximage->data[(ximage->height - y - 1) * ximage->bytes_per_line + x]; + } + } + return hbm; + } + + if (ximage->format == ZPixmap && ximage->bits_per_pixel == 32) + { + bi.bmiHeader.biBitCount = 32; + hbm = CreateDIBSection(NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS, + (LPVOID *)&pbBits, NULL, 0); + widthbytes = WIDTHBYTES(ximage->width * 32); + for (y = 0; y < ximage->height; y++) + { + for (x = 0; x < ximage->width; x++) + { + color.pixel = *(LPDWORD)&ximage->data[(ximage->height - y - 1) * ximage->bytes_per_line + x * 4]; + XQueryColor(NULL, 0, &color); + pbBits[y * widthbytes + x * 4 + 0] = color.blue / 256; + pbBits[y * widthbytes + x * 4 + 1] = color.green / 256; + pbBits[y * widthbytes + x * 4 + 2] = color.red / 256; + pbBits[y * widthbytes + x * 4 + 3] = 0xFF; + } + } + return hbm; + } + + return NULL; +} + +// NOTE: too slow!!! +int XPutImage(Display *dpy, Drawable d, GC gc, + XImage *image, int req_xoffset, int req_yoffset, + int x, int y, unsigned int req_width, unsigned int req_height) +{ + HBITMAP hbm; + int width = req_width, height = req_height; + + if (req_xoffset < 0) + { + width += req_xoffset; + req_xoffset = 0; + } + if (req_yoffset < 0) + { + height += req_yoffset; + req_yoffset = 0; + } + + if (req_xoffset + width > (int)image->width) + width = image->width - req_xoffset; + if (req_yoffset + height > (int)image->height) + height = image->height - req_yoffset; + if (width <= 0 || height <= 0) + return 0; + + hbm = XCreateWinBitmapFromXImage(image); + if (hbm == NULL) + return 0; + + if (d == 0) + { + HDC hdcSrc = CreateCompatibleDC(dpy); + HGDIOBJ hbmOld = SelectObject(hdcSrc, hbm); + BitBlt(dpy, req_xoffset, req_yoffset, width, height, hdcSrc, x, y, SRCCOPY); + SelectObject(hdcSrc, hbmOld); + DeleteDC(hdcSrc); + } + else + { + HDC hdc = XCreateDrawableDC_(dpy, d); + HDC hdcSrc = CreateCompatibleDC(dpy); + HGDIOBJ hbmOld = SelectObject(hdcSrc, hbm); + BitBlt(hdc, req_xoffset, req_yoffset, width, height, hdcSrc, x, y, SRCCOPY); + SelectObject(hdcSrc, hbmOld); + DeleteDC(hdcSrc); + XDeleteDrawableDC_(dpy, d, hdc); + } + + DeleteObject(hbm); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// diff --git a/xws2win.h b/xws2win.h index b71b61d..d67fc81 100644 --- a/xws2win.h +++ b/xws2win.h @@ -1,5 +1,5 @@ -#ifndef __XSCREENSAVER_WIN32_H__ -#define __XSCREENSAVER_WIN32_H__ +#ifndef __XWS2WIN_H__ +#define __XWS2WIN_H__ ////////////////////////////////////////////////////////////////////////////// @@ -9,8 +9,6 @@ #define _CRT_SECURE_NO_WARNINGS #include -#include -#include #include #include #include @@ -19,12 +17,18 @@ #include #include +#undef min +#undef max +#undef far +#undef hyper + ////////////////////////////////////////////////////////////////////////////// #define USE_GL 1 -#define HAVE_GLBINDTEXTURE -#define inline -#define ENTRYPOINT static +#define XWS2WIN_SPEED 1 + +#define HAVE_GLBINDTEXTURE 1 +#define HAVE_DOUBLE_BUFFER_EXTENSION 1 #define strcasecmp _stricmp #define strncasecmp _strnicmp @@ -34,41 +38,15 @@ #define Xrealloc realloc #define Xfree free +#define XFree free + typedef BYTE CARD8; typedef WORD CARD16; typedef DWORD CARD32; -#define GL_UNSIGNED_INT_8_8_8_8_REV GL_UNSIGNED_BYTE - -#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT -# define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#endif -#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT -# define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#endif - -#ifndef GL_LIGHT_MODEL_COLOR_CONTROL -# define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#endif -#ifndef GL_SEPARATE_SPECULAR_COLOR -# define GL_SEPARATE_SPECULAR_COLOR 0x81FA -#endif - #define None NULL -#ifdef MSGBOXOUTPUT - int __cdecl win32_fprintf(FILE *fp, const char *fmt, ...); - void __cdecl win32_abort(void); - int __cdecl win32_exit(int n); - #define fprintf win32_fprintf - #define abort win32_abort - #define exit win32_exit -#endif - -enum { CoordModeOrigin, CoordModePrevious }; -enum { Convex }; -enum { OK = 0, BadAlloc, BadGC, BadValue, BadFont, BadMatch, BadPixmap }; -enum { GXcopy = R2_COPYPEN, GXxor = R2_XORPEN }; +#define rint(e) ((int)(e + 0.5)) ////////////////////////////////////////////////////////////////////////////// // Bool @@ -78,28 +56,32 @@ typedef BOOL Bool; #define True TRUE ////////////////////////////////////////////////////////////////////////////// -// Drawable - -typedef INT Drawable; -typedef INT Pixmap; -typedef INT Window; - -////////////////////////////////////////////////////////////////////////////// -// Visual - -#define Visual int - -////////////////////////////////////////////////////////////////////////////// -// Colormap +typedef struct +{ + HBITMAP hbm; + LPBYTE pbBits; + HBITMAP hbmOld; +} DrawableData; + +typedef DrawableData* Drawable; +typedef DrawableData* Pixmap; +typedef DrawableData* Window; +typedef int Visual; typedef unsigned long Colormap; +DrawableData* XGetDrawableData_(Drawable d); + ////////////////////////////////////////////////////////////////////////////// // XPoint, XSegment, XRectangle, XArc -typedef struct { - short x, y; -} XPoint; +#if XWS2WIN_SPEED + typedef POINT XPoint; +#else + typedef struct { + short x, y; + } XPoint; +#endif typedef struct { short x1, y1, x2, y2; @@ -122,18 +104,18 @@ typedef int Status; #ifdef STRICT #define Display struct HDC__ - #define Screen struct HWND__ #else #define Display void - #define Screen void #endif +typedef int Screen; typedef HGLRC GLXContext; ////////////////////////////////////////////////////////////////////////////// // XWindowAttributes -typedef struct { +typedef struct +{ int width; int height; int depth; @@ -142,6 +124,14 @@ typedef struct { Screen *screen; } XWindowAttributes; +////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int depth; + int bits_per_pixel; +} XPixmapFormatValues; + ////////////////////////////////////////////////////////////////////////////// // XrmOptionDescRec, argtype, OptionStruct, ModeSpecOpt, ModStruct @@ -159,68 +149,34 @@ typedef struct char *def; } XrmOptionDescRec; -typedef enum -{ - t_Bool, t_Int, t_Float, t_String -} argdatatype; - -typedef struct -{ - void *data; - char *name; - char *text; - char *def; - argdatatype type; -} argtype; - -typedef struct -{ - char *opt; - char *desc; -} OptionStruct; - -typedef struct -{ - int nopts; - XrmOptionDescRec *opts; - int nargs; - argtype *args; - OptionStruct *desc; -} ModeSpecOpt; +////////////////////////////////////////////////////////////////////////////// -typedef struct -{ - char *ignore0; - char *ignore1; - char *ignore2; - char *ignore3; - char *ignore4; - char *ignore5; - char *ignore6; - void *ignore7; - int ignore8; - int ignore9; - int ignore10; - int ignore11; - int ignore12; - float ignore13; - char *ignore14; - char *ignore15; - int ignore16; - void *ignore17; -} ModStruct; +enum { CoordModeOrigin, CoordModePrevious }; +enum { Convex }; +enum { BadAlloc = 1, BadGC, BadValue, BadFont, BadMatch, BadPixmap }; +enum { + GXcopy = R2_COPYPEN, GXor = R2_MERGEPEN, GXxor = R2_XORPEN, + GXandInverted = R2_NOTMASKPEN +}; ////////////////////////////////////////////////////////////////////////////// // GC -#define GCForeground 0 -#define GCBackground 1 +#define GCForeground (1 << 0) +#define GCBackground (1 << 1) +#define GCFillStyle (1 << 2) +#define GCFunction (1 << 3) +#define GCStipple (1 << 4) +#define GCLineWidth (1 << 5) +#define GCCapStyle (1 << 6) +#define GCJoinStyle (1 << 7) +#define GCLineStyle (1 << 8) +#define GCFillRule (1 << 9) enum // line_style { LineSolid = PS_SOLID, LineOnOffDash = PS_DASH, - LineDoubleDash = PS_DASHDOT }; enum // cap_style @@ -228,7 +184,7 @@ enum // cap_style CapNotLast = PS_ENDCAP_FLAT, CapButt = PS_ENDCAP_SQUARE, CapRound = PS_ENDCAP_ROUND, - CapProjecting + CapProjecting = CapButt }; enum // join_style @@ -238,7 +194,11 @@ enum // join_style JoinBevel = PS_JOIN_BEVEL }; -typedef unsigned long GC; +enum // fill_style +{ + FillSolid = BS_SOLID, FillStippled = BS_DIBPATTERN, + FillOpaqueStippled = BS_DIBPATTERN +}; typedef struct { @@ -250,31 +210,32 @@ typedef struct int line_style; int cap_style; int join_style; + int function; + int fill_style; + Pixmap stipple; + int fill_rule; + HBITMAP hbmOld; } XGCValues; -#define MAX_GC_BUFFER 32 +typedef XGCValues *GC; -XGCValues *XGetGCValues0(GC gc); +#define XGetGCValues_(gc) gc +HDC XCreateDrawableDC_(Display *dpy, Drawable d); +int XDeleteDrawableDC_(Display *dpy, Drawable d, HDC hdc); -Status XGetGCValues( - Display *dpy, - GC gc, - unsigned long valuemask, - XGCValues *values_return); - -GC XCreateGC( - Display *dpy, - Drawable d, +GC XCreateGC(Display *dpy, Drawable d, unsigned long valuemask, XGCValues *values); +int XChangeGC(Display* dpy, GC gc, unsigned long valuemask, XGCValues* values); int XFreeGC(Display *dpy, GC gc); HPEN XCreateWinPen(XGCValues *values); HBRUSH XCreateWinBrush(XGCValues *values); HFONT XCreateWinFont(XGCValues *values); - int XSetForeground(Display *dpy, GC gc, unsigned long foreground); +int XSetBackground(Display *dpy, GC gc, unsigned long background); +int XSetWindowBackground(Display *dpy, Window w, unsigned long pixel); int XCopyArea( Display *dpy, @@ -286,9 +247,9 @@ int XCopyArea( ////////////////////////////////////////////////////////////////////////////// // XColor -#define DoRed (1<<0) -#define DoGreen (1<<1) -#define DoBlue (1<<2) +#define DoRed (1 << 0) +#define DoGreen (1 << 1) +#define DoBlue (1 << 2) typedef struct { @@ -299,6 +260,11 @@ typedef struct } XColor; Bool XAllocColor(Display *d, Colormap cmap, XColor *color); + +Bool XAllocNamedColor( + Display *d, Colormap cmap, const char *name, + XColor *near_color, XColor *true_color); + Status XAllocColorCells( Display* d, Colormap cmap, @@ -307,294 +273,30 @@ Status XAllocColorCells( unsigned int nplanes, unsigned long* pixels_return, unsigned int npixels); + int XFreeColors( Display* d, Colormap cmap, unsigned long* pixels, int npixels, unsigned long planes); + int XStoreColors( Display* display, Colormap cmap, XColor* color, int ncolors); -int XFlush(Display *d); + int XQueryColor(Display *dpy, Colormap cmap, XColor *def); int XParseColor(Display *d, Colormap cmap, const char *name, XColor *c); -unsigned long load_color(Display *dpy, Colormap cmap, const char *name); - -////////////////////////////////////////////////////////////////////////////// -// ModeInfo - -typedef struct -{ - Display *dpy; - Window window; - GC gc; - int num_screen; - int screen_number; - int width; - int height; - int polygon_count; - int recursion_depth; - Bool fps_p; - Bool is_drawn; - int pause; - int count; - int cycles; - int size; - XWindowAttributes xgwa; - int npixels; - XColor *colors; - unsigned long *pixels; - Bool writable_p; -} ModeInfo; - -#define MI_DISPLAY(mi) (mi)->dpy -#define MI_WINDOW(mi) 0 -#define MI_GC(mi) (mi)->gc -#define MI_NUM_SCREENS(mi) 1 -#define MI_SCREEN(mi) 0 -#define MI_WIDTH(mi) (mi)->width -#define MI_HEIGHT(mi) (mi)->height -#define MI_WIN_WIDTH(mi) (mi)->width -#define MI_WIN_HEIGHT(mi) (mi)->height -#define MI_NCOLORS(mi) (256 - 20) -#define MI_IS_DRAWN(mi) (mi)->is_drawn -#define MI_IS_FPS(mi) FALSE -#define MI_IS_MONO(mi) FALSE -#define MI_CLEARWINDOW(mi) ss_clear(MI_DISPLAY(mi)) -#define MI_IS_WIREFRAME(mi) FALSE -#define MI_COUNT(MI) (mi)->count -#define MI_BATCHCOUNT(MI) MI_COUNT(MI) -#define MI_IS_ICONIC(mi) FALSE -#define MI_CYCLES(mi) (mi)->cycles -#define MI_SIZE(mi) (mi)->size -#ifdef NDEBUG - #define MI_IS_DEBUG(mi) FALSE - #define MI_IS_VERBOSE(mi) FALSE -#else - #define MI_IS_DEBUG(mi) TRUE - #define MI_IS_VERBOSE(mi) TRUE -#endif -#define MI_NAME(mi) progname -#define MI_DELAY(mi) DELAY -#define MI_VISUAL(mi) NULL -#define MI_COLORMAP(mi) 0 -#define MI_WIN_BLACK_PIXEL(mi) 0 -#define MI_PIXEL(mi,n) ((mi)->pixels[n]) -#define MI_BLACK_PIXEL(mi) 0 -#define MI_WHITE_PIXEL(mi) 255 -#define MI_NPIXELS(mi) (mi)->npixels -#define MI_IS_FULLRANDOM(mi) TRUE -#define MI_IS_INSTALL(mi) TRUE - -#define FreeAllGL(mi) /**/ - -////////////////////////////////////////////////////////////////////////////// - -#define SINF(n) ((float)sin((double)(n))) -#define COSF(n) ((float)cos((double)(n))) -#define FABSF(n) ((float)fabs((double)(n))) - -#undef MAX -#undef MIN -#undef ABS -#define MAX(a,b) ((a)>(b)?(a):(b)) -#define MIN(a,b) ((a)<(b)?(a):(b)) -#define ABS(a) ((a)<0 ? -(a) : (a)) - -////////////////////////////////////////////////////////////////////////////// - -#undef NUMCOLORS -#define NUMCOLORS 256 - -////////////////////////////////////////////////////////////////////////////// - -#include "yarandom.h" - -#define LRAND() ((long) (random() & 0x7fffffff)) -#define NRAND(n) ((int) (LRAND() % (n))) -#define MAXRAND (2147483648.0) /* unsigned 1<<31 as a float */ -#define SRAND(n) /* already seeded by screenhack.c */ - -////////////////////////////////////////////////////////////////////////////// - -typedef enum COLOR_SCHEME { - color_scheme_default, color_scheme_uniform, - color_scheme_smooth, color_scheme_bright -}; - -#ifdef WRITABLE_COLORS -# undef WRITABLE_COLORS -# define WRITABLE_COLORS 1 -#else -# define WRITABLE_COLORS 0 -#endif - -////////////////////////////////////////////////////////////////////////////// - -#define MAX_COLORS 0x1000 - -# define XSCREENSAVER_LINK(NAME) \ - struct xscreensaver_function_table *xscreensaver_function_table = &NAME; - -#if defined(UNIFORM_COLORS) -# define XLOCKMORE_COLOR_SCHEME color_scheme_uniform -#elif defined(SMOOTH_COLORS) -# define XLOCKMORE_COLOR_SCHEME color_scheme_smooth -#elif defined(BRIGHT_COLORS) -# define XLOCKMORE_COLOR_SCHEME color_scheme_bright -#else -# define XLOCKMORE_COLOR_SCHEME color_scheme_default -#endif - -typedef void (*HACK_INIT)(ModeInfo *); -typedef void (*HACK_DRAW)(ModeInfo *); -typedef void (*HACK_REFRESH)(ModeInfo *); -typedef void (*HACK_FREE)(ModeInfo *); - -extern char *progname; -extern DWORD hack_delay; -extern int hack_count; -extern int hack_count_enabled; -extern int hack_cycles; -extern int hack_cycles_enabled; -extern int hack_size; -extern int hack_size_enabled; -extern int hack_ncolors; -extern int hack_ncolors_enabled; -extern int hack_color_scheme; - -extern int hack_argcount; -extern argtype *hack_arginfo; - -#ifdef COUNT - #define HACK_COUNT \ - int hack_count = COUNT; \ - int hack_count_enabled = True -#else - #define HACK_COUNT \ - int hack_count = 0; \ - int hack_count_enabled = False -#endif -#ifdef CYCLES - #define HACK_CYCLES \ - int hack_cycles = CYCLES; \ - int hack_cycles_enabled = True -#else - #define HACK_CYCLES \ - int hack_cycles = 0; \ - int hack_cycles_enabled = False -#endif -#ifdef SIZE_ - #define HACK_SIZE \ - int hack_size = SIZE_; \ - int hack_size_enabled = True -#else - #define HACK_SIZE \ - int hack_size = 0; \ - int hack_size_enabled = False -#endif -#ifdef NCOLORS - #define HACK_NCOLORS \ - int hack_ncolors = NCOLORS; \ - int hack_ncolors_enabled = True -#else - #define HACK_NCOLORS \ - int hack_ncolors = 0; \ - int hack_ncolors_enabled = False -#endif - -#ifdef NOARGS - #define XSCREENSAVER_MODULE_2(CLASS,NAME,PREFIX) \ - HACK_INIT hack_init = init_ ## PREFIX; \ - HACK_DRAW hack_draw = draw_ ## PREFIX; \ - HACK_REFRESH hack_refresh = refresh_ ## PREFIX; \ - HACK_FREE hack_free = release_ ## PREFIX; \ - DWORD hack_delay = DELAY; \ - char *progname = CLASS; \ - HACK_COUNT; \ - HACK_CYCLES; \ - HACK_SIZE; \ - HACK_NCOLORS; \ - argtype *hack_arginfo = NULL; \ - int hack_argcount = 0; \ - int hack_color_scheme = XLOCKMORE_COLOR_SCHEME; -#else - #define XSCREENSAVER_MODULE_2(CLASS,NAME,PREFIX) \ - HACK_INIT hack_init = init_ ## PREFIX; \ - HACK_DRAW hack_draw = draw_ ## PREFIX; \ - HACK_REFRESH hack_refresh = refresh_ ## PREFIX; \ - HACK_FREE hack_free = release_ ## PREFIX; \ - DWORD hack_delay = DELAY; \ - char *progname = CLASS; \ - HACK_COUNT; \ - HACK_CYCLES; \ - HACK_SIZE; \ - HACK_NCOLORS; \ - argtype *hack_arginfo = vars; \ - int hack_argcount = sizeof(vars) / sizeof(vars[0]); \ - int hack_color_scheme = XLOCKMORE_COLOR_SCHEME; -#endif - -#define XSCREENSAVER_MODULE(CLASS,PREFIX) \ - XSCREENSAVER_MODULE_2(CLASS,PREFIX,PREFIX) - -extern HACK_INIT hack_init; -extern HACK_DRAW hack_draw; -extern HACK_REFRESH hack_refresh; -extern HACK_FREE hack_free; - -////////////////////////////////////////////////////////////////////////////// -// OpenGL-related - -HGLRC *init_GL(ModeInfo *mi); -void glXMakeCurrent(Display *d, Window w, GLXContext context); -void glXSwapBuffers(Display *d, Window w); -void check_gl_error(const char *name); -void clear_gl_error(void); - -////////////////////////////////////////////////////////////////////////////// -// trackball - -#define trackball_state char* // Not implemented yet - -trackball_state *gltrackball_init(void); -void gltrackball_rotate(trackball_state *trackball); -void gltrackball_get_quaternion(char **ppch, float q[4]); -void gltrackball_start(trackball_state* trackball, int n1, int n2, int n3, int n4); -void gltrackball_track(trackball_state* trackball, int n1, int n2, int n3, int n4); -////////////////////////////////////////////////////////////////////////////// -// misc - -void do_fps(ModeInfo *mi); -extern Bool has_writable_cells(Screen *s, Visual *v); -float current_device_rotation(void); -int ffs(int i); -int visual_cells(Screen *screen, Visual *visual); -int visual_depth(Screen *screen, Visual *visual); -void -load_texture_async(Screen *screen, Window window, - GLXContext glx_context, - int desired_width, int desired_height, - Bool mipmap_p, - GLuint texid, - void (*callback) (const char *filename, - XRectangle *geometry, - int image_width, - int image_height, - int texture_width, - int texture_height, - void *closure), - void *closure); +unsigned long load_color(Display *dpy, Colormap cmap, const char *name); ////////////////////////////////////////////////////////////////////////////// // XImage // format -enum { XYBitmap, XYPixmap, ZPixmap, RGBAPixmap }; +enum { XYBitmap, XYPixmap, ZPixmap, RGBAPixmap_ }; // byte_order/bitmap_bit_order enum { MSBFirst, LSBFirst }; @@ -630,26 +332,40 @@ unsigned long XGetPixel(XImage *image, int x, int y); int XPutPixel(XImage *ximage, int x, int y, unsigned long pixel); Pixmap XCreatePixmap( - Display *dpy, - Drawable d, - unsigned int width, - unsigned int height, + Display* dpy, Drawable d, + unsigned int width, unsigned int height, + unsigned int depth); +Pixmap XCreateBitmapFromData( + Display* dpy, Drawable d, + const char* data, + unsigned int width, unsigned int height); +Pixmap XCreatePixmapFromBitmapData( + Display* dpy, Drawable d, + char* data, + unsigned int width, unsigned int height, + unsigned long fg, unsigned long bg, unsigned int depth); int XFreePixmap(Display *dpy, Pixmap pixmap); + int XSync(Display *dpy, Bool b); +XPixmapFormatValues *XListPixmapFormats(Display *dpy, int *count); + ////////////////////////////////////////////////////////////////////////////// // X Window Display *DisplayOfScreen(Screen *s); -#define DefaultScreenOfDisplay(dpy) dpy +#define DefaultScreenOfDisplay(dpy) 0 +#define DefaultScreen(dpy) 0 #define BlackPixelOfScreen(s) 0 +#define WhitePixelOfScreen(s) 255 #define DefaultColormap(dpy,scr) 0 +#define BlackPixel(dpy,scr) 0 +#define WhitePixel(dpy,scr) 255 +#define BitmapPad(dpy) 32 +#define ImageByteOrder(dpy) LSBFirst -Status XGetWindowAttributes( - Display *dpy, - Window w, - XWindowAttributes *attr); +Status XGetWindowAttributes(Display *dpy, Window w, XWindowAttributes *attr); int XSetLineAttributes(Display *dpy, GC gc, unsigned int line_width, int line_style, int cap_style, int join_style); @@ -658,7 +374,7 @@ int XClearWindow(Display *dpy, Window w); int XDrawPoint(Display *dpy, Drawable d, GC gc, int x, int y); -int XDrawPoints(Display *dpy, Drawable w, GC gc, +int XDrawPoints(Display *dpy, Drawable d, GC gc, XPoint *points, int npoints, int CoordMode); int XDrawLine(Display *dpy, Drawable d, GC gc, @@ -666,12 +382,18 @@ int XDrawLine(Display *dpy, Drawable d, GC gc, int XDrawLines(Display *dpy, Drawable d, GC gc, XPoint *points, int npoints, int mode); +int XDrawRectangle( + Display *dpy, Drawable d, GC gc, + int x, int y, unsigned int width, unsigned int height); + int XDrawSegments(Display *dpy, Drawable d, GC gc, XSegment *segments, int nsegments); int XDrawArc(Display *dpy, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height, int angle1, int angle2); +int XDrawArcs(Display *dpy, Drawable d, GC gc, + XArc *arcs, int n_arcs); int XDrawString(Display *dpy, Drawable d, GC gc, int x, int y, const char *string, int length); @@ -696,29 +418,17 @@ int XFillArc(Display *dpy, Drawable d, GC gc, int XFillArcs(Display *dpy, Drawable d, GC gc, XArc *arcs, int n_arcs); -////////////////////////////////////////////////////////////////////////////// -// screen saver +int XSetFunction(Display *dpy, GC gc, int function); +int XSetFillStyle(Display *dpy, GC gc, int fill); -typedef struct SCREENSAVER -{ - HWND hwnd; - HDC hdc; - HGLRC hglrc; - UINT x0, y0; - UINT w, h; - ModeInfo modeinfo; - HBITMAP hbmScreenShot; -} SCREENSAVER; - -extern SCREENSAVER ss; - -BOOL InitPixelFormat(SCREENSAVER *ss); -VOID MakeCurrent(SCREENSAVER *ss); -XImage *GetScreenShotXImage(void); -void CreateTextureFromImage(XImage *ximage, GLuint texid); -void ss_term(void); -void ss_clear(Display *d); +int XPutImage(Display *dpy, Drawable d, GC gc, + XImage *image, int req_xoffset, int req_yoffset, + int x, int y, unsigned int req_width, unsigned int req_height); + +int XFlush(Display *d); + +#define XMaxRequestSize(dpy) 100 ////////////////////////////////////////////////////////////////////////////// -#endif // ndef __XSCREENSAVER_WIN32_H__ +#endif // ndef __XWS2WIN_H__ diff --git a/yarandom.c b/yarandom.c index cc73559..07755b4 100644 --- a/yarandom.c +++ b/yarandom.c @@ -62,7 +62,7 @@ #include /* for gettimeofday() */ #endif -#include "xws2win.h" +#include "xlockmore.h" #include "yarandom.h" # undef ya_rand_init @@ -129,8 +129,11 @@ ya_rand_init(unsigned int seed) //seed += (1003 * getpid()); //seed = ROT (seed, 13); - seed = - (DWORD)(GetTickCount() ^ GetCurrentProcessId() ^ (DWORD_PTR)GetForegroundWindow()); + seed = GetCurrentProcessId(); + seed <<= 16; + seed ^= (DWORD)(DWORD_PTR)GetForegroundWindow(); + seed <<= 8; + seed ^= GetTickCount(); } a[0] += seed;