Add alt code, PDF + format/typo checks 2011/zucker
The alt code is based on the author's remarks - it sets binary mode on stdout. The PDF is about sphere tracing. Added it in case the link ever dies. Format/typo check README.md file. Updated .gitignore.
This commit is contained in:
1 parent
e639c38c76
commit
48b9f83db9
5 files changed
+170
-78
No files matched your search
@@ -1,6 +1,7 @@
|
||||
image.ppm
|
||||
hello.ppm
|
||||
image2.ppm
|
||||
ioccc2011.ppm
|
||||
zucker
|
||||
zucker.orig
|
||||
prog.orig
|
||||
@@ -114,8 +114,8 @@ OBJ= ${PROG}.o
|
||||
DATA=
|
||||
TARGET= ${PROG}
|
||||
#
|
||||
ALT_OBJ=
|
||||
ALT_TARGET=
|
||||
ALT_OBJ= ${PROG}.alt.o
|
||||
ALT_TARGET= ${PROG}.alt
|
||||
|
||||
|
||||
#################
|
||||
@@ -138,6 +138,9 @@ ${PROG}: ${PROG}.c
|
||||
alt: data ${ALT_TARGET}
|
||||
@${TRUE}
|
||||
|
||||
${PROG}.alt: ${PROG}.alt.c
|
||||
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS}
|
||||
|
||||
# data files
|
||||
#
|
||||
data: ${DATA}
|
||||
|
||||
+118
-76
@@ -4,6 +4,9 @@
|
||||
make
|
||||
```
|
||||
|
||||
There is an alternate version which should work for Windows which distinguishes
|
||||
binary mode from text mode. See [alternate code](#alternate-code) below.
|
||||
|
||||
|
||||
## To use:
|
||||
|
||||
@@ -21,14 +24,29 @@ make
|
||||
|
||||
Display the PPM image with your favorite image viewer.
|
||||
|
||||
The author gave options for macOS but we note that you can just do:
|
||||
|
||||
## Alternate code:
|
||||
|
||||
This version uses the Windows functions `_setmode()` and `_fileno()` to set
|
||||
binary mode on `stdout` which the author noted would be necessary for systems
|
||||
that distinguish binary and text.
|
||||
|
||||
|
||||
### Alternate build:
|
||||
|
||||
```sh
|
||||
open image.ppm
|
||||
make alt
|
||||
```
|
||||
|
||||
which will open `Preview.app` which will let you look at the image no problem.
|
||||
No need to install additional software.
|
||||
|
||||
### Alternate use:
|
||||
|
||||
Use `zucker.alt` as you would `zucker` above.
|
||||
|
||||
|
||||
### Alternate try:
|
||||
|
||||
Try `zucker.alt` instead of `zucker` above.
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
@@ -49,18 +67,40 @@ This program makes pretty pictures. To see the default output, try
|
||||
running
|
||||
|
||||
```sh
|
||||
./zucker > image.ppm
|
||||
./zucker > ioccc2011.ppm
|
||||
```
|
||||
|
||||
On the author's 2.5 GHz MacBook Pro, this command takes approximately
|
||||
1 minute and 18 seconds to run -- your runtime may vary. You will
|
||||
need an image viewer capable of displaying Netpbm images in order to
|
||||
display the output. On the Mac, [Xee](http://wakaba.c3.cx/s/apps/xee)
|
||||
works well; otherwise [ImageMagick](http://www.imagemagick.org/)
|
||||
and/or [GraphicsMagick](http://www.graphicsmagick.org/) are both
|
||||
capable of displaying Netpbm files, and are available on multiple
|
||||
platforms. (Using Xee is particularly nice because it periodically
|
||||
reloads the image as it is rendered.)
|
||||
On the author's 2.5 GHz MacBook Pro, this command takes approximately 1 minute
|
||||
and 18 seconds to run -- your runtime may vary. You will need an image viewer
|
||||
capable of displaying [Netpbm images](https://en.wikipedia.org/wiki/Netpbm) in
|
||||
order to display the output. On the Mac, the system supplied `Preview.app` works
|
||||
well; otherwise [ImageMagick](http://www.imagemagick.org/) and/or
|
||||
[GraphicsMagick](http://www.graphicsmagick.org/) are both capable of displaying
|
||||
Netpbm files, and are available on multiple platforms.
|
||||
|
||||
With macOS you can type at the command line:
|
||||
|
||||
```sh
|
||||
open ioccc2021.ppm
|
||||
```
|
||||
|
||||
and it will open image in the default application Preview.app.
|
||||
|
||||
To use ImageMagick you might do something like:
|
||||
|
||||
```sh
|
||||
convert ioccc2011.ppm ioccc2011.png
|
||||
```
|
||||
|
||||
and then open `ioccc2011.png` in your viewer of choice.
|
||||
|
||||
To use GraphicsMagick you might do something like:
|
||||
|
||||
```sh
|
||||
gm convert ioccc2011.ppm ioccc2011.png
|
||||
```
|
||||
|
||||
and then open `ioccc2011.png` in your viewer of choice.
|
||||
|
||||
Aside from the default image, you may create your own by running the
|
||||
program as follows:
|
||||
@@ -76,71 +116,75 @@ mode by appending `-preview` to the command line arguments, like so:
|
||||
./zucker faster\! -preview > image.ppm
|
||||
```
|
||||
|
||||
If your platform distinguishes between binary and text streams, you
|
||||
may need to insert some code to reopen standard output in binary mode
|
||||
at the start of `main`. An ASCII platform is assumed.
|
||||
If your platform distinguishes between binary and text streams, you may need to
|
||||
insert some code to reopen standard output in binary mode at the start of
|
||||
`main()` (the provided [alternate version](#alternate-code) will set binary mode
|
||||
on `stdout` in Windows). An ASCII platform is assumed.
|
||||
|
||||
|
||||
#### Pedagogical value:
|
||||
|
||||
This program is quite suitable for the inexperienced programmer, due
|
||||
to a number of considerations:
|
||||
|
||||
* It is fairly short: just 4 preprocessor directives followed by 29
|
||||
lines of source.
|
||||
* It is fairly short: just 4 preprocessor directives followed by 29
|
||||
lines of source.
|
||||
|
||||
* It compiles cleanly as ANSI C under gcc 4.2.1 with very strict
|
||||
compilation flags.
|
||||
* It compiles cleanly as ANSI C under gcc 4.2.1 with very strict
|
||||
compilation flags.
|
||||
|
||||
* It uses a very small subset of the keywords available in C, namely
|
||||
`char`, `float`, `int`, `typedef`, `struct`, `for`, and `return`.
|
||||
More difficult concepts such as `void`, `if`, `switch`, and
|
||||
`while` are eschewed for simplicity's sake.
|
||||
* It uses a very small subset of the keywords available in C, namely
|
||||
`char`, `float`, `int`, `typedef`, `struct`, `for`, and `return`.
|
||||
More difficult concepts such as `void`, `if`, `switch`, and
|
||||
`while` are eschewed for simplicity's sake.
|
||||
|
||||
* It also uses a very small number of library functions: just `putchar`,
|
||||
`cos`, `sin`, `atan2`, `sqrt`, and `pow`.
|
||||
* It also uses a very small number of library functions: just `putchar(3)`,
|
||||
`cos(3)`, `sin(3)`, `atan2(3)`, `sqrt(3)`, and `pow(3)`.
|
||||
|
||||
* New programmers often prefer to use global variables when
|
||||
possible. Hence, *all* variables in this program (aside from
|
||||
function parameters) have global scope.
|
||||
|
||||
* An important aspect of the computation is graphically illustrated
|
||||
by the source code itself: the geometric construction of a
|
||||
reflection ray at an object's surface, given the incoming
|
||||
direction and surface normal.
|
||||
|
||||
* New programmers often prefer to use global variables when
|
||||
possible. Hence, *all* variables in this program (aside from
|
||||
function parameters) have global scope.
|
||||
|
||||
* An important aspect of the computation is graphically illustrated
|
||||
by the source code itself: the geometric construction of a
|
||||
reflection ray at an object's surface, given the incoming
|
||||
direction and surface normal.
|
||||
\
|
||||
#### Further details (contains spoilers):
|
||||
|
||||
The program is not quite a traditional ray tracer, but a "sphere
|
||||
tracer" which uses distance fields to encode proximity to objects in
|
||||
the scene. Using sphere tracing to compute visibility instead of
|
||||
analytic ray tracing provides two advantages: first, it greatly eases
|
||||
the computation of ray-torus intersection (which would otherwise
|
||||
require solving a quartic polynomial), and second, it makes it
|
||||
possible to compute ambient occlusion (which is used to generate soft
|
||||
shadows). Unlike many traditional ray tracers and sphere tracers, this
|
||||
one uses iteration instead of recursion to compute the effect of
|
||||
reflections. This, unfortunately, resulted in the programmer going
|
||||
insane; however, program size was reduced and readability
|
||||
hindered. Neither the plaintext for the program's default output nor
|
||||
for the Netpbm header appears in the program source, which hinders
|
||||
readability as well. Also, unlike some previous IOCCC entries which
|
||||
render ASCII text, this one uses a vector (as opposed to raster)
|
||||
font. Although the program does not generate uppercase letters, it
|
||||
handles them in a reasonable manner when they appear in the input.
|
||||
The program is not quite a traditional [ray
|
||||
tracer](https://en.wikipedia.org/wiki/Ray_tracing_(graphics)), but a "[sphere
|
||||
tracer](sphere-tracing.pdf)" which uses distance fields to encode proximity to
|
||||
objects in the scene. Using sphere tracing to compute visibility instead of
|
||||
analytic ray tracing provides two advantages: first, it greatly eases the
|
||||
computation of [ray-torus](https://en.wikipedia.org/wiki/Toric_lens#Torus)
|
||||
intersection (which would otherwise require solving a quartic polynomial), and
|
||||
second, it makes it possible to compute [ambient
|
||||
occlusion](https://en.wikipedia.org/wiki/Ambient_occlusion) (which is used to
|
||||
generate soft shadows). Unlike many traditional ray tracers and sphere tracers,
|
||||
this one uses iteration instead of recursion to compute the effect of
|
||||
reflections. This, unfortunately, resulted in the programmer going insane;
|
||||
however, program size was reduced and readability hindered. Neither the
|
||||
plaintext for the program's default output nor for the Netpbm header appears in
|
||||
the program source, which hinders readability as well. Also, unlike some
|
||||
previous IOCCC entries which render ASCII text, this one uses a vector (as
|
||||
opposed to raster) font. Although the program does not generate uppercase
|
||||
letters, it handles them in a reasonable manner when they appear in the input.
|
||||
|
||||
Even when the program is pretty-printed and preprocessor macros are
|
||||
expanded, it should be fairly resistant to analysis due to reckless
|
||||
reuse of global variables, to the inherently opaque nature of the
|
||||
math, and to its overall density. Global variables are used to store
|
||||
translated, it should be fairly resistant to analysis due to reckless
|
||||
reuse of global variables, the inherently opaque nature of the
|
||||
math, and its overall density. Global variables are used to store
|
||||
the results of intermediate computation. As a result, seemingly simple
|
||||
functions have important side effects. Although some of the global
|
||||
variables are simply constants, their use is overloaded. For instance,
|
||||
the variable `X` is used both as the number 40 and as the ASCII
|
||||
the variable `X` is used both as the number `40` and as the ASCII
|
||||
character `'('`. Maintainability is hindered due to hardcoding
|
||||
several aspects of the program in multiple locations. As an example,
|
||||
it is impossible to modify either the image width or height without
|
||||
changing the source in at least three different places, including
|
||||
inside the large string literal.
|
||||
inside the large string literal `J`.
|
||||
|
||||
Some of the functions are simple vector algebraic operations such as
|
||||
vector construction, dot product, and normalization. However, it was
|
||||
@@ -153,26 +197,24 @@ get as much mileage as possible out of statements inside of loop
|
||||
declarations. Between `for` loops, the comma operator, and the ternary
|
||||
operator, it was possible to avoid `if` and `while` altogether.
|
||||
|
||||
Bitwise and arithmetic operators are used instead of logical operators
|
||||
whenever gcc doesn't warn about it. Conversely, integer
|
||||
multiplication, division, and modulus are sometimes used in place of
|
||||
traditional bitwise operators just to keep the reader on his or her
|
||||
toes. Automatic casting between characters, integers, and floats is
|
||||
performed just about everywhere. Fascinatingly, this doesn't seem to
|
||||
affect performance too badly. Sometimes when an explicit cast
|
||||
(i.e. from float to int) is needed, the program instead simply assigns
|
||||
to a free variable of the desired type instead. Both the `array[index]`
|
||||
and `index[array]` notations are used interchangeably throughout the
|
||||
program.
|
||||
Bitwise and arithmetic operators are used instead of logical operators whenever
|
||||
gcc doesn't warn about it. Conversely, integer multiplication, division, and
|
||||
modulus are sometimes used in place of traditional bitwise operators just to
|
||||
keep the reader on his or her toes. Automatic casting between characters,
|
||||
integers, and floats is performed just about everywhere. Fascinatingly, this
|
||||
doesn't seem to affect performance too badly. Sometimes when an explicit cast
|
||||
(i.e. from `float` to `int`) is needed, the program instead simply assigns to a
|
||||
free variable of the desired type instead. Both the `array[index]` and
|
||||
`index[array]` notations are used interchangeably throughout the program.
|
||||
|
||||
Two other programs were written to support development of this
|
||||
program. The first used a randomized search algorithm to deduce the
|
||||
most compact encoding of the vector font instructions into ASCII; the
|
||||
second used a modified form of the Knuth-Plass algorithm to layout the
|
||||
final text on top of a hand-generated ASCII "stencil". The programs
|
||||
were not submitted as entries for this year's IOCCC, not because they
|
||||
lack obfuscation, but because neither is written in C (they are in C++
|
||||
and Python, respectively).
|
||||
Two other programs were written to support development of this program. The
|
||||
first used a randomized search algorithm to deduce the most compact encoding of
|
||||
the vector font instructions into ASCII; the second used a modified form of the
|
||||
[Knuth-Plass](https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap) algorithm
|
||||
to layout the final text on top of a hand-generated ASCII "stencil". The
|
||||
programs were not submitted as entries for this year's IOCCC, not because they
|
||||
lack obfuscation, but because neither is written in C (they are in C++ and
|
||||
Python, respectively).
|
||||
|
||||
|
||||
## Copyright and CC BY-SA 4.0 License:
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#define E return
|
||||
#define S for
|
||||
char*J="LJFFF%7544x^H^XXHZZXHZ]]2#( #@@DA#(.@@%(0CAaIqDCI$IDEH%P@T@qL%PEaIpBJCA\
|
||||
I%KBPBEP%CBPEaIqBAI%CAaIqBqDAI%U@PE%AAaIqBcDAI%ACaIaCqDCI%(aHCcIpBBH%E@aIqBAI%A\
|
||||
AaIqB%AAaIqBEH%AAPBaIqB%PCDHxL%H@hIcBBI%E@qJBH#C@@D%aIBI@D%E@QB2P#E@'C@qJBHqJBH\
|
||||
%C@qJBH%AAaIqBAI%C@cJ%" "cJ" "CH%C@qJ%aIqB1I%PCDI`I%BAaICH%KH+@'JH+@KP*@%S@\
|
||||
3P%H@ABhIaBBI%P@S@PC#", *j ,*e;typedef float x;x U(x a){E a<0?0:a>1?1:a; }
|
||||
typedef struct{x c,a,t; } y;y W={1,1,1},Z={0,0,0},B[99],P,C,M,N,K,p,s,d,h
|
||||
;y G(x t,x a,x c){K.c=t ; K.t=c; K.a=a;E K;}int T=-1,b=0,r,F=-111,(*m)(i\
|
||||
nt)=putchar,X=40,z=5,o, a, c,t=0 ,n,R;y A(y a,y b,x c){E G(a.c+b.c*c,a.a
|
||||
+c*b.a,b.t*c+a.t);}x H= .5,Y =.66 ,I,l=0,q,w,u,i,g;x O(y a,y b){E q=a.t*
|
||||
b.t+b.c*a.c+a.a*b.a;}x Q(){E A(P,M,T ),O(K,K)<I?C=M,I=q:0;}y V(y a){E A(Z,
|
||||
a,pow(O(a,a),-H));}x D(y p){S(I=X,P =p,b=T; M=B[++b],p=B[M.c+=8.8-l*.45,
|
||||
++b],b<=r;Q())M=p.t?q =M_PI*H,w=atan2( P.a-M.a,P.c-M.c) /q,o=p.c-2,a=p.a+1,t=
|
||||
o+a,w=q*(w>t+H*a?o: w>t?t:w<o-H*a?t :w<o?o:w),A( M,G(cos(w),sin(w),0),
|
||||
1):A(M,p,U(O(A(P,M,T) ,p)/O(p,p))); M=P;M.a=- .9;o=P.c/8+8;o^=a=P.t
|
||||
/8+8; M=Q ()?o&1 ?G(Y,0,0):W :G(Y,Y,1);E sqrt (I)-.45;}
|
||||
int main(int L,char**k){_setmode(_fileno(stdin),_O_BINARY);S(e=L>1?1[z=0,k]:J ;*e &&l<24 ;
|
||||
++e)S(o=a =0,j =J+9;(c= *++j)&& !(o&&c< X&&(q=l+=w) );o ?o=*j++/
|
||||
32,b++[B] =G(q +=*j/8&3,* j&7,0 ),B[r =b++]=G((c/8& 3)*( o<2?
|
||||
T:1), (c& 7)+ 1e-4,o>2),1: (o =(a =(c-=X)<0?w=c+6 ,t= a+1:c?(t
|
||||
?0:m(c),a ):*++j)==((*e|32 ) ^z)&&1[j]-X));S(z =3*( L<3);++
|
||||
F<110;)S(L=-301;p=Z,++L<300;m( p.c),m(p.a),m(p.t))S(c=T;++c<=z;)S(h
|
||||
=G(-4,4.6,29),d=V(A(A(A(Z,V(G(5,0 ,2)),L+L+c/2),V(G(2,-73,0)),F+F+c%2),G
|
||||
(30.75,-6,-75),20)),g=R=255-(n=z)*64; R*n+R;g*=H){S(u=i=R=0;!R&&94>(u+=i=D(h=
|
||||
A(h,d,i)));R=i<.01);S(N=V(A(P,C, T)),q=d.t*d.t,s=M,u=1;++i<6*R;u-=
|
||||
U(i/3-D(A(h,N,i/3)))/pow( 2,i));s=R?i=pow(U(O(N,V(A(
|
||||
M=V(G(T,1,2)),d,T)))) ,X),p=A(p,W,g*i),u*=U(
|
||||
O(N,M))*H*Y+Y,g*= n--?Y-Y*i:1-i,s:G(
|
||||
q,q,1); p=A(p,s ,g*u);h=A(h,N,.1
|
||||
);d=A(d,N,-2*O (d,N));}E 0;}
|
||||
@@ -3268,6 +3268,17 @@ the author's comments (along with looking up the function for the right header
|
||||
file). To build try the alt rule of the Makefile.
|
||||
|
||||
|
||||
## [2011/zucker](2011/zucker/zucker.c) ([README.md](2011/zucker/README.md]))
|
||||
|
||||
Cody added [alt code](2011/zucker/README.md#alternate-code) that should work on
|
||||
Windows, based on the author's remarks that if the system distinguishes binary
|
||||
and text then `stdout` needs to be set to binary mode.
|
||||
|
||||
Cody also added the PDF file
|
||||
[sphere-tracing.pdf](2011/zucker/sphere-tracing.pdf) in case the link eventually
|
||||
dies.
|
||||
|
||||
|
||||
# <a name="2012"></a>2012
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user