release winning entries of IOCCC28 under the year 2024
Congratulations to: * 2024/anders - Prize in sound coding - layered music generator * 2024/burton - Prize in pentagrammatology - wordle hard mode solver * 2024/cable1 - Prize in bot talk - LLM inference engine * 2024/cable2 - Prize in murky waters - salmon recipe * 2024/carlini - Prize in perfect timing - Intel 4004 emulation * 2024/codemeow - Prize in tray planting - bonsai generator * 2024/endoh1 - Prize in patient pointillism - slow ray tracer in CPP * 2024/endoh2 - Prize in solid body physics - rotating rigid body simulation * 2024/ferguson1 - Prize in diabolical logistics - Oregon trail pact with the devil * 2024/ferguson2 - Prize in yil-tas - Navajo code talker translator * 2024/howe - Nice accent eh-ward - mini vi * 2024/kramer - Prize in linguistic arithmetic - natural language numerical calculator * 2024/kurdyukov1 - Prize in phased periodicity - phase of the Moon * 2024/kurdyukov2 - Prize in art restoration - JPEG artifact removal * 2024/kurdyukov3 - Prize in virtual quietus - gaming VM and doom * 2024/kurdyukov4 - Prize in embiggening - encode without literals * 2024/maffiodo - Prize in creative interpretation - Jav\*script interpreter * 2024/mills - Prize in ℤ₃ - Infocom v3 story interpreter * 2024/stedolan - Best one liner - icon from MD5 * 2024/straadt - Prize in imitative rebooting - OpenRISC CPU and Linux * 2024/tmarrec - Prize in cyclonic coding - 3D tornado simulation * 2024/tompng - Prize in quasi bijection - vortex encryptor decryptor * 2024/weaver - Sur prize - rickroll Ran `make update` to perform the above. new file: 2024/burton/.entry.json
This commit is contained in:
1 parent
10512e6c79
commit
09750f8899
443 files changed
+182938
-231
No files matched your search
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
|
||||
"entry_JSON_format_version" : "1.2 2024-09-25",
|
||||
"award" : "Prize in patient pointillism",
|
||||
"year" : 2024,
|
||||
"dir" : "endoh1",
|
||||
"entry_id" : "2024_endoh1",
|
||||
"title" : "raytrace-in-macros",
|
||||
"abstract" : "slow ray tracer in CPP",
|
||||
"author_set" : [
|
||||
{
|
||||
"author_handle" : "Yusuke_Endoh"
|
||||
}
|
||||
],
|
||||
"manifest" : [
|
||||
{
|
||||
"file_path" : "prog.c",
|
||||
"inventory_order" : 20,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "c",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "entry source code"
|
||||
},
|
||||
{
|
||||
"file_path" : "Makefile",
|
||||
"inventory_order" : 30,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "makefile",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "entry Makefile"
|
||||
},
|
||||
{
|
||||
"file_path" : "prog.orig.c",
|
||||
"inventory_order" : 50,
|
||||
"OK_to_edit" : false,
|
||||
"display_as" : "c",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "original source code"
|
||||
},
|
||||
{
|
||||
"file_path" : "ref.8.png",
|
||||
"inventory_order" : 100,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "image",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "8x8 image in PNG form"
|
||||
},
|
||||
{
|
||||
"file_path" : "try.sh",
|
||||
"inventory_order" : 100,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "shellscript",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "script to try entry"
|
||||
},
|
||||
{
|
||||
"file_path" : "ref.32.png",
|
||||
"inventory_order" : 110,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "image",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "32x32 image in PNG form"
|
||||
},
|
||||
{
|
||||
"file_path" : "ref.128.png",
|
||||
"inventory_order" : 120,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "image",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "128x128 image in PNG form"
|
||||
},
|
||||
{
|
||||
"file_path" : "ref.512.png",
|
||||
"inventory_order" : 130,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "image",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "512x512 image in PNG form"
|
||||
},
|
||||
{
|
||||
"file_path" : "ref.512-variant.png",
|
||||
"inventory_order" : 140,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "image",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "variant of 512x512 image in PNG form"
|
||||
},
|
||||
{
|
||||
"file_path" : "2024_endoh1.tar.bz2",
|
||||
"inventory_order" : 1415926535,
|
||||
"OK_to_edit" : false,
|
||||
"display_as" : "tbz2",
|
||||
"display_via_github" : false,
|
||||
"entry_text" : "download entry tarball"
|
||||
},
|
||||
{
|
||||
"file_path" : ".entry.json",
|
||||
"inventory_order" : 4000000000,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "json",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "entry summary and manifest in JSON"
|
||||
},
|
||||
{
|
||||
"file_path" : ".gitignore",
|
||||
"inventory_order" : 4000000000,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "gitignore",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "list of files that should not be committed under git"
|
||||
},
|
||||
{
|
||||
"file_path" : ".path",
|
||||
"inventory_order" : 4000000000,
|
||||
"OK_to_edit" : false,
|
||||
"display_as" : "path",
|
||||
"display_via_github" : false,
|
||||
"entry_text" : "directory path from top level directory"
|
||||
},
|
||||
{
|
||||
"file_path" : "README.md",
|
||||
"inventory_order" : 4000000000,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "markdown",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "markdown source for this web page"
|
||||
},
|
||||
{
|
||||
"file_path" : "index.html",
|
||||
"inventory_order" : 4294967295,
|
||||
"OK_to_edit" : false,
|
||||
"display_as" : "html",
|
||||
"display_via_github" : false,
|
||||
"entry_text" : "this web page"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
128.ppm
|
||||
32.ppm
|
||||
512.ppm
|
||||
8.ppm
|
||||
out.ppm
|
||||
pixel
|
||||
rt.c
|
||||
@@ -0,0 +1 @@
|
||||
2024/endoh1
|
||||
Binary file not shown.
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env make
|
||||
#
|
||||
# 2024/endoh1
|
||||
|
||||
#############################
|
||||
# shell used by this Makefile
|
||||
#############################
|
||||
|
||||
SHELL= bash
|
||||
|
||||
|
||||
#######################
|
||||
# common tool locations
|
||||
#######################
|
||||
|
||||
include ../../var.mk
|
||||
|
||||
|
||||
#####################
|
||||
# C compiler settings
|
||||
#####################
|
||||
|
||||
# Common C compiler warnings to silence
|
||||
#
|
||||
# Example: CSILENCE= -Wno-poison-system-directories
|
||||
#
|
||||
CSILENCE=
|
||||
|
||||
# Attempt to silence unknown warning options
|
||||
#
|
||||
CUNKNOWN= -Wno-unknown-warning-option
|
||||
|
||||
# Common C compiler warning flags
|
||||
#
|
||||
# NOTE: The addition of -pedantic to CWARN is a challenge that
|
||||
# You may wish to avoid if it proves too problematic.
|
||||
# There is NO penalty for removing -pedantic from CWARN.
|
||||
#
|
||||
CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
|
||||
|
||||
# Compiler standard
|
||||
#
|
||||
CSTD= -std=gnu17
|
||||
|
||||
# Compiler bit architecture
|
||||
#
|
||||
# Example for 32-bitness: ARCH= -m32
|
||||
# Example for 64-bitness: ARCH= -m64
|
||||
#
|
||||
# NOTE: Normally one should NOT specify a specific architecture.
|
||||
#
|
||||
ARCH=
|
||||
|
||||
# Defines that are needed to compile
|
||||
#
|
||||
# Example: -Dfoo -Dbar=baz
|
||||
#
|
||||
CDEFINE=
|
||||
|
||||
# Include files that are needed to compile
|
||||
#
|
||||
# Example: CINCLUDE= -include stdio.h
|
||||
#
|
||||
CINCLUDE=
|
||||
|
||||
# Other flags to pass to the C compiler
|
||||
#
|
||||
# Example: COTHER= -fno-math-errno
|
||||
#
|
||||
COTHER=
|
||||
|
||||
# Optimization
|
||||
#
|
||||
# NOTE: Feel free to change the level of compiler optimization.
|
||||
# The "-O3" is just a friendly default you might wish to try.
|
||||
#
|
||||
# Example: OPT= -O0 -g
|
||||
#
|
||||
OPT= -O3
|
||||
|
||||
# Default flags for ANSI C compilation
|
||||
#
|
||||
CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
|
||||
|
||||
# Libraries needed to build
|
||||
#
|
||||
# Example: LDFLAGS= -lncurses -lm
|
||||
#
|
||||
LDFLAGS=
|
||||
|
||||
# C compiler to use
|
||||
#
|
||||
# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
|
||||
# and NOT set it to clang, or gcc, or something else
|
||||
# unless you have a STRONG reason to do so.
|
||||
#
|
||||
# Setting CC to something other than "cc" makes your
|
||||
# code less portable to those who do not have your
|
||||
# particular C compiler. **hint**
|
||||
#
|
||||
# If you want to test your code with a particular C compiler,
|
||||
# use the make command line. For example:
|
||||
#
|
||||
# make all CC=clang
|
||||
# make all CC=gcc
|
||||
#
|
||||
CC= cc
|
||||
|
||||
# Compiler add-ons or replacements for clang only
|
||||
#
|
||||
ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
|
||||
#
|
||||
# NOTE: This code is only invoked when CC is "clang"
|
||||
# such as when you use the make command line:
|
||||
#
|
||||
# make all CC=clang
|
||||
#
|
||||
CSILENCE+= -Wno-poison-system-directories
|
||||
#
|
||||
CWARN+= -Weverything
|
||||
#
|
||||
endif
|
||||
|
||||
# Specific add-ons or replacements for gcc only
|
||||
#
|
||||
ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
|
||||
#
|
||||
# NOTE: This code is only invoked when CC is "gcc"
|
||||
# such as when you use the make command line:
|
||||
#
|
||||
# make all CC=gcc
|
||||
#
|
||||
CSILENCE+=
|
||||
#
|
||||
CWARN+=
|
||||
#
|
||||
endif
|
||||
|
||||
|
||||
###########################################
|
||||
# Special Makefile variables for this entry
|
||||
###########################################
|
||||
|
||||
ENTRY= prog
|
||||
PROG= ${ENTRY}
|
||||
#
|
||||
OBJ= ${PROG}.o
|
||||
TARGET= ${PROG} rt.c
|
||||
#
|
||||
ALT_OBJ=
|
||||
ALT_TARGET=
|
||||
|
||||
# list any data files supplied with your submission
|
||||
#
|
||||
# Example: DATA= curds whey
|
||||
#
|
||||
DATA=
|
||||
|
||||
# default width
|
||||
#
|
||||
W= 32
|
||||
|
||||
# default height
|
||||
#
|
||||
H= 32
|
||||
|
||||
|
||||
#################
|
||||
# build the entry
|
||||
#################
|
||||
|
||||
all: data ${TARGET}
|
||||
@${TRUE}
|
||||
|
||||
.PHONY: all alt data everything clean clobber
|
||||
|
||||
# how to compile
|
||||
#
|
||||
${PROG}: ${PROG}.c
|
||||
${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
|
||||
|
||||
rt.c: ${PROG}
|
||||
${RM} -f $@
|
||||
./${PROG} > $@
|
||||
|
||||
%.txt: rt.c
|
||||
@${RM} -f $@
|
||||
@F="$@" ; E="$${F%%.txt}" ; \
|
||||
X="$${E##*-}" ; TX="$${X%%[!0]*}" ; X="$${X#$$TX}" ; X="$${X:-0}" ; \
|
||||
Y="$${E#*-}" ; Y="$${Y%-*}" ; TY="$${Y%%[!0]*}" ; Y="$${Y#$$TY}" ; Y="$${Y:-0}" ; \
|
||||
echo ${CC} -E -P -DX="$$X" -DY="$$Y" -DW="${W}" -DH="${H}" rt.c ">" $@
|
||||
@F="$@" ; E="$${F%%.txt}" ; \
|
||||
X="$${E##*-}" ; TX="$${X%%[!0]*}" ; X="$${X#$$TX}" ; X="$${X:-0}" ; \
|
||||
Y="$${E#*-}" ; Y="$${Y%-*}" ; TY="$${Y%%[!0]*}" ; Y="$${Y#$$TY}" ; Y="$${Y:-0}" ; \
|
||||
${CC} -E -P -DX="$$X" -DY="$$Y" -DW="${W}" -DH="${H}" rt.c > $@
|
||||
|
||||
targets= $(shell \
|
||||
for y in $$(${SEQ} -w 0 $$((${H}-1))); do \
|
||||
for x in $$(${SEQ} -w 0 $$((${W}-1))); do \
|
||||
echo "pixel/pixel-$$y-$$x.txt"; \
|
||||
done; \
|
||||
done)
|
||||
|
||||
pixel:
|
||||
${MKDIR} -p pixel
|
||||
|
||||
out.ppm: pixel ${targets}
|
||||
echo P3 ${W} ${H} > $@
|
||||
echo 255 >> $@
|
||||
${FIND} pixel -type f -print | LANG=C ${SORT} | ${XARGS} cat >> $@
|
||||
|
||||
# alternative executable
|
||||
#
|
||||
alt: data ${ALT_TARGET}
|
||||
@${TRUE}
|
||||
|
||||
${PROG}.alt: ${PROG}.alt.c
|
||||
${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
|
||||
|
||||
# data files
|
||||
#
|
||||
data: ${DATA}
|
||||
@${TRUE}
|
||||
|
||||
# both all and alt
|
||||
#
|
||||
everything: all alt
|
||||
@${TRUE}
|
||||
|
||||
|
||||
###############
|
||||
# utility rules
|
||||
###############
|
||||
#
|
||||
clean:
|
||||
${RM} -f ${OBJ} ${ALT_OBJ}
|
||||
${RM} -f out.ppm
|
||||
|
||||
clobber: clean
|
||||
${RM} -f ${TARGET} ${ALT_TARGET}
|
||||
${RM} -rf *.dSYM
|
||||
${RM} -rf pixel 128.ppm 32.ppm 512.ppm 8.ppm
|
||||
|
||||
|
||||
######################################
|
||||
# optional include of 1337 hacker rulz
|
||||
######################################
|
||||
|
||||
-include 1337.mk ../1337.mk ../../1337.mk
|
||||
@@ -0,0 +1,516 @@
|
||||
## To build:
|
||||
|
||||
``` <!---sh-->
|
||||
make all
|
||||
```
|
||||
|
||||
|
||||
## Try:
|
||||
|
||||
``` <!---sh-->
|
||||
./try.sh
|
||||
```
|
||||
|
||||
**HINT**: You have to be **VERY** patient while the above script runs to completion.
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
When you `make all` you see what looks like a C program, `rt.c`.
|
||||
However if you try to compile `rt.c`, you will fail: even if you try to
|
||||
define the symbols `X`, `Y`, `W`, and `H`.
|
||||
|
||||
Well, the propose of the C program, `rt.c` is to generate the red, green, and blue colors of
|
||||
a single pixel, in the C Preprocessor!!!
|
||||
|
||||
For the patient, a image may be rendered a slow pixel at a time.
|
||||
Think of this as digital [Pointillism](https://en.wikipedia.org/wiki/Pointillism). :-)
|
||||
|
||||
For the truly impatient who wishes to get right to the point without trying to dot around
|
||||
waiting for the [try.sh](%%REPO_URL%%/2024/endoh1/try.sh) to finish, you may view these images:
|
||||
|
||||
* [tiny 8x8 image](ref.8.png)
|
||||
* [small 32x32 image](ref.32.png)
|
||||
* [medium 128x128 image](ref.128.png)
|
||||
* [large 512x512 image](ref.512.png)
|
||||
|
||||
**FUN FACT**: We were able to determine on an "_x86-64 processor_" running
|
||||
"_RHEL 9.6_" using "_gcc version 11.5.0_", one could theoretically render
|
||||
a **2147483647 x 2147483647** pixel image. At the rate it took to render
|
||||
the **512 x 512** pixel image, and without using any parallelism, such an
|
||||
image would take about **169 billion years** to fully render on a single
|
||||
CPU core! Fully rendering such large images is **NOT** recommended. :-)
|
||||
|
||||
|
||||
### Parallel make
|
||||
|
||||
**SUGGESTION**: The [2024/endoh1/Makefile](%%REPO_URL%%/2024/endoh1/Makefile),
|
||||
by default, uses a single CPU core, can make use of parallel operations.
|
||||
If you have access to a "_parallel make_", can achieve the above in a shorter
|
||||
around of time. If you have "_n_" CPU cores available, consider running
|
||||
a parallel make with "_n-1_" jobs that run simultaneously. For example:
|
||||
|
||||
``` <!---sh-->
|
||||
RESERVE="-2"
|
||||
NPROC=$(nproc)
|
||||
((JOBS=NPROC-RESERVE))
|
||||
SIZE=512
|
||||
make clobber all
|
||||
nohup time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE" > make.out 2>&1 < /dev/null &
|
||||
```
|
||||
|
||||
Where `SIZE` is the size of the image to generate.
|
||||
|
||||
Where `RESERVE` is the number of CPU cores to reserve for other things
|
||||
such as the operating system, daemons, terminal window, etc. You can even
|
||||
"_oversubscribe_" by setting RESERVE to a negative number (e.g., `RESERVE="-2"`).
|
||||
|
||||
**NOTE**: The [try.sh](%%REPO_URL%%/2024/endoh1/try.sh) script follows the above
|
||||
example for `SIZE` values of 8, 32, 128, and then 512.
|
||||
|
||||
The optimal `RESERVE` will depend on your hardware, operating system,
|
||||
a C compiler. Making `RESERVE` too small (i.e., too negative) may slow
|
||||
down the result. We recommend that experiment various values pf `RESERVE`
|
||||
with moderate `SIZE` of **32** in order to try to find an optimal `JOBS`
|
||||
value before attempting to try a larger size such as **512** and beyond.
|
||||
|
||||
|
||||
<div id="larger">
|
||||
### Be first to build images larger than 512x512
|
||||
</div>
|
||||
|
||||
**QUESTION**: Do you have the patience to build an even larger than a 512x512 image?
|
||||
If you do, **using the program as it is written of course**, please [send the IOCCC](../../judges.html)
|
||||
the following:
|
||||
|
||||
* Image Height x Width in pixels
|
||||
* URL of the fully rendered image (in PPM form or better yet converted to PNG)
|
||||
* How long it took (perhaps using the time(1) command or using the `time` shell builtin)
|
||||
* The starting and ending dates (using `date -u`) of your rendering
|
||||
* Number of CPU cores, Operating system, Compiler, Compiler version, and make version
|
||||
* The number of jobs you ran in parallel
|
||||
* Anything else you may have done to optimize
|
||||
* Your name, (GitHub handle (optional)), (Mastodon handle (optional)), (home page URL (optional)), Country (or XX to be anonymous)
|
||||
|
||||
**PLEASE** do not attempt to optimize the general algorithm used by this entry to build PPM images.
|
||||
Please remain "_faithful to the spirit_" of this wonderful entry when attempting to build larger PPM images.
|
||||
|
||||
The first people to render a new record sized image **using the general algorithm used by this entry**,
|
||||
will be given credit in the [thanks for the help](../../thanks-for-help.html) web page.
|
||||
|
||||
|
||||
## Author's remarks:
|
||||
|
||||
|
||||
### A Ray Tracer in the C Preprocessor
|
||||
|
||||
Ever since the iconic 1988 IOCCC winning entry [1988/applin](../../1988/applin/index.html),
|
||||
bending the C preprocessor to one's will has been a time-honored tradition in the IOCCC.
|
||||
This entry sets out to be the culmination of that legacy: a ray tracer implemented entirely with C macros!
|
||||
|
||||
|
||||
#### How to Run
|
||||
|
||||
The initial program, `./prog` (compiled from `prog.c`), outputs the main code, `rt.c`.
|
||||
To get started, compile and execute it:
|
||||
|
||||
``` <!---sh-->
|
||||
make all
|
||||
```
|
||||
|
||||
Note: `rt.c` is not a valid C program -- it's written for C preprocessor.
|
||||
|
||||
To get the color of a single pixel at position (16, 16) in a 32 x 32 image, run:
|
||||
|
||||
``` <!---sh-->
|
||||
cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```
|
||||
129
|
||||
62
|
||||
129
|
||||
```
|
||||
|
||||
These three values represent the red, green, and blue components respectively.
|
||||
|
||||
* Red = 129 (0x81)
|
||||
* Green = 62 (0x3e)
|
||||
* Blue = 129 (0x81)
|
||||
|
||||
In other words, this indicates that the pixel at position (16, 16) has the color #813e81.
|
||||
|
||||
|
||||
#### How to Generate the Full Image
|
||||
|
||||
To generate the entire image, you need to run the preprocessor for every pixel.
|
||||
For example, to form a 32x32 image:
|
||||
|
||||
``` <!---sh-->
|
||||
mkdir -p pixel
|
||||
cc -E -P -DX=0 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-00.txt
|
||||
cc -E -P -DX=1 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-01.txt
|
||||
cc -E -P -DX=2 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-02.txt
|
||||
...
|
||||
cc -E -P -DX=30 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-30.txt
|
||||
cc -E -P -DX=31 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-31.txt
|
||||
cc -E -P -DX=0 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-00.txt
|
||||
cc -E -P -DX=1 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-01.txt
|
||||
cc -E -P -DX=2 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-02.txt
|
||||
...
|
||||
cc -E -P -DX=30 -DY=31 -DW=32 -DH=32 rt.c > pixel/pixel-31-30.txt
|
||||
cc -E -P -DX=31 -DY=31 -DW=32 -DH=32 rt.c > pixel/pixel-31-31.txt
|
||||
```
|
||||
|
||||
Then, concatenate the results with a PPM header to create the image:
|
||||
|
||||
``` <!---sh-->
|
||||
echo P3 32 32 > out.ppm
|
||||
echo 255 >> out.ppm
|
||||
find pixel -type f -print | LANG=C sort | xargs cat >> out.ppm
|
||||
```
|
||||
|
||||
Now open `out.ppm` with any image viewer that supports the PPM format.
|
||||
|
||||
|
||||
#### Automating with Makefile
|
||||
|
||||
To form a 32x32 image:
|
||||
|
||||
``` <!---sh-->
|
||||
make clean targets out.ppm H=32 W=32
|
||||
```
|
||||
|
||||
Now open `out.ppm` with any image viewer that supports the PPM format.
|
||||
|
||||
|
||||
#### Generating a Larger Image
|
||||
|
||||
To form a 256x256 image:
|
||||
|
||||
``` <!---sh-->
|
||||
make clean targets out.ppm H=256 W=256
|
||||
```
|
||||
|
||||
Now open `out.ppm` with any image viewer that supports the PPM format.
|
||||
|
||||
For reference, the 512x512 image took about 10 hours to render.
|
||||
|
||||
|
||||
#### Technical Challenges
|
||||
|
||||
Below is a technical explanation of the implementation.
|
||||
|
||||
|
||||
##### Copying a Macro Definition
|
||||
|
||||
One core challenges was how to "copy" the value of a macro.
|
||||
|
||||
For example, in C macros:
|
||||
|
||||
``` <!---c-->
|
||||
#define X 10
|
||||
#define Y X
|
||||
|
||||
#undef X
|
||||
#define X 20
|
||||
|
||||
Y // expands to "20", not "10"
|
||||
```
|
||||
|
||||
The C preprocessor uses lazy evaluation, meaning macro values are always resolved at the time of use.
|
||||
With this observation, some people claim it's impossible to copy a macro's value.
|
||||
|
||||
One known workaround is encoding one bit by whether or not a macro is defined (as seen in `applin.c` from IOCCC 1988 and `vik2.c` from IOCCC 2004).
|
||||
However, this approach is too inefficient for our purposes -- ray tracing requires operations like multiplication, and even square root.
|
||||
|
||||
Instead, we discovered an efficient way to "copy" a macro's value.
|
||||
The key observation is that `#if` eagerly evaluates the definition of a macro at that point in preprocessing.
|
||||
For example:
|
||||
|
||||
``` <!---c-->
|
||||
#if X % 2
|
||||
# define X_b0 1 // The LSB of X is 1
|
||||
#else
|
||||
# define X_b0 0 // The LSB of X is 0
|
||||
#endif
|
||||
```
|
||||
|
||||
This technique copies the least significant bit of `X`.
|
||||
By applying this for each bit, we can reconstruct the full value:
|
||||
|
||||
``` <!---c-->
|
||||
#define X 10
|
||||
|
||||
#if X % 2
|
||||
# define X_b0 1
|
||||
#else
|
||||
# define X_b0 0
|
||||
#endif
|
||||
|
||||
#if X / 2 % 2
|
||||
# define X_b1 2
|
||||
#else
|
||||
# define X_b1 0
|
||||
#endif
|
||||
|
||||
#if X / 4 % 2
|
||||
# define X_b2 4
|
||||
#else
|
||||
# define X_b2 0
|
||||
#endif
|
||||
|
||||
...
|
||||
|
||||
#define Y (X_b0 + X_b1 + X_b2 + ...)
|
||||
|
||||
#undef X
|
||||
#define X 20
|
||||
|
||||
Y // replaced with "0 + 2 + 0 + 8 + ..." = 10
|
||||
```
|
||||
|
||||
Even if `X` is later redefined, `Y` remains unchanged.
|
||||
|
||||
This technique resembles ["information flow"][information-flow] in the information security.
|
||||
To our best knowledge, there has been no literature that mentions this technique in terms of the C preprocessor programming.
|
||||
|
||||
[information-flow]: https://en.wikipedia.org/wiki/Information_flow_(information_theory)
|
||||
|
||||
|
||||
##### Macro Expansion Explosion
|
||||
|
||||
Using macros for complex expressions often causes memory issues.
|
||||
|
||||
For instance, consider this Newton's method implementation for square roots:
|
||||
|
||||
``` <!---c-->
|
||||
#define sqrt0(x, guess) (guess ? (x/guess+guess)/2 : 0)
|
||||
#define sqrt(x) sqrt0(x,sqrt0(x,sqrt0(x,sqrt0(x,sqrt0(x,10000)))))
|
||||
```
|
||||
|
||||
The subroutine `sqrt0` is one step of Newton's method, and `sqrt` applies it five times.
|
||||
There are three occurences of the argument `guess` in the body of `sqrt0`.
|
||||
Thus, applying `sqrt` repeats its argument expression at least 5^3 = 243 times.
|
||||
This easily leads to the explosion of macro expansion.
|
||||
|
||||
We avoid this issue by using the earlier "copy" trick -- reducing the size of macro expansions by materializing their values.
|
||||
|
||||
|
||||
##### Encoding Vectors
|
||||
|
||||
In theory, it is trivial to encode a 3D vector in the C preprocessor: you can just define three macros for x, y, and z components.
|
||||
However, it creates bloated code -- unsuitable for IOCCC size limits.
|
||||
|
||||
Instead, we encode vectors as simple tuples:
|
||||
|
||||
``` <!---c-->
|
||||
#define vec 1,2,3
|
||||
```
|
||||
|
||||
The vector projection can be implemented as follows.
|
||||
|
||||
``` <!---c-->
|
||||
#define fst(x,y,z) x
|
||||
#define snd(x,y,z) y
|
||||
#define thd(x,y,z) z
|
||||
#define call(f,a) f(a)
|
||||
```
|
||||
|
||||
Example usage:
|
||||
|
||||
``` <!---c-->
|
||||
call(fst, vec) // expands to 1
|
||||
call(snd, vec) // expands to 2
|
||||
call(thd, vec) // expands to 3
|
||||
```
|
||||
|
||||
The auxiliary macro `call` is required.
|
||||
This is a hassle of the C preprocessor, but, `call(fst, vec)` is expanded to `fst(1,2,3)`, which results in `1`.
|
||||
|
||||
We can define a vector addition by using the projections.
|
||||
|
||||
``` <!---c-->
|
||||
#define vec3_add(a,b) fst(a)+fst(b),snd(a)+snd(b),thd(a)+thd(b)
|
||||
```
|
||||
|
||||
Now, we can simply write `vec3_add(v1, v2)` to add two vectors.
|
||||
One identifier represents one vector.
|
||||
It is also elegantly possible to nest expressions like `vec3_add(v1, vec3_add(v1, v2))`.
|
||||
|
||||
``` <!---c-->
|
||||
#define v1 0,1,2
|
||||
#define v2 2,1,0
|
||||
|
||||
int main() {
|
||||
printf("(%d %d %d)\n", vec3_add(v1, v2)); // prints "(2 2 2)"
|
||||
printf("(%d %d %d)\n", vec3_add(v1, vec3_add(v1, v2))); // prints "(2 3 4)"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##### Ray Tracing via Self-Inclusion
|
||||
|
||||
Ray tracing involves recursive calls for reflection.
|
||||
In `rt.c`, this is done via:
|
||||
|
||||
``` <!---c-->
|
||||
#include __FILE__
|
||||
```
|
||||
|
||||
In the implementation, only spheres reflect rays, and only one sphere exists.
|
||||
Thus, the recursion depth is limited to one.
|
||||
|
||||
Theoretically, it is possible to support multiple reflections, but this would require implementing a "stack" to keep "local variables" in a stack frame.
|
||||
|
||||
|
||||
##### Outputting a Pixel
|
||||
|
||||
The preprocessed result of `rt.c` contains some preprocessor directives (starting with `#`) and three integers (red, green, and blue).
|
||||
|
||||
``` <!---sh-->
|
||||
cc -E -DX=16 -DY=16 -DW=32 -DH=32 rt.c
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
``` <!---c-->
|
||||
# 0 "rt.c"
|
||||
# 0 "<built-in>"
|
||||
# 0 "<command-line>"
|
||||
# 1 "/usr/include/stdc-predef.h" 1 3 4
|
||||
# 0 "<command-line>" 2
|
||||
# 1 "rt.c"
|
||||
# 3481 "rt.c"
|
||||
# 1 "rt.c" 1
|
||||
# 2090 "rt.c"
|
||||
# 1 "rt.c" 1
|
||||
# 2091 "rt.c" 2
|
||||
# 3482 "rt.c" 2
|
||||
# 3582 "rt.c"
|
||||
129
|
||||
# 3684 "rt.c"
|
||||
62
|
||||
# 3786 "rt.c"
|
||||
129
|
||||
```
|
||||
|
||||
Interestingly, these are valid in the PPM format (lines starting with `#` are commments in PPM).
|
||||
Thus, just concatenating the results for all pixels (and prefixing a small header) will work to create a PPM image file.
|
||||
|
||||
When render a large image, we recommend use the `-E -P` flags as in:
|
||||
|
||||
``` <!---sh-->
|
||||
cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c
|
||||
```
|
||||
|
||||
This will only produce:
|
||||
|
||||
```
|
||||
129
|
||||
62
|
||||
129
|
||||
```
|
||||
|
||||
Note that values appear as expressions like `(0 + 2 + 0 + 8 + ...)` because we use the "copy" trick.
|
||||
To print them as to ordinary decimal values, we use macro logic like:
|
||||
|
||||
``` <!---c-->
|
||||
// assume red is (0 + 2 + 0 + 8)
|
||||
|
||||
#if red / 100 % 10 == 0
|
||||
# define digit0(digits) 0##digits
|
||||
#elif red / 100 % 10 == 1
|
||||
# define digit0(digits) 1##digits
|
||||
#else
|
||||
# define digit0(digits) 2##digits
|
||||
#endif
|
||||
|
||||
#if red / 10 % 10 == 0
|
||||
# define digit1(digits) digits0(0##digits)
|
||||
#elif red / 10 % 10 == 1
|
||||
# define digit1(digits) digits0(1##digits)
|
||||
#elif ...
|
||||
...
|
||||
#endif
|
||||
|
||||
#if red % 10 == 0
|
||||
# define digits digit1(0)
|
||||
#elif red % 10 == 1
|
||||
# define digits digit1(1)
|
||||
#elif ...
|
||||
...
|
||||
#endif
|
||||
|
||||
digits // outputs "10"
|
||||
```
|
||||
|
||||
|
||||
#### Customizing the Scene
|
||||
|
||||
You can modify the scene by editing the top of `rt.c`.
|
||||
|
||||
|
||||
##### Example Defaults
|
||||
|
||||
``` <!---c-->
|
||||
#define p 0,500,4000 // sphere center position
|
||||
#define q 2000 // sphere radius
|
||||
#define r 300,300,300 // sphere color (default: light gray)
|
||||
#define s(x) 900,200+K*7100,900 // plane color (default: checkered colors of white for K=1 and purple for K=0)
|
||||
#define t -2000,4000,1000 // light position
|
||||
#define u 50000,50000,50000 // light color (default: white)
|
||||
#define v(x) 500-x,500-x,500 // background color (default: gradation from blue to white)
|
||||
```
|
||||
|
||||
|
||||
##### Variant Example
|
||||
|
||||
``` <!---c-->
|
||||
#define p 0,0,8000
|
||||
#define q 2000
|
||||
#define r 300,300,900
|
||||
#define s(x) 200,500-x*300,200+x*800
|
||||
#define t 2000,4000,3000
|
||||
#define u 30000,40000,30000
|
||||
#define v(x) 500,x,10
|
||||
```
|
||||
|
||||
Features:
|
||||
|
||||
* Grounded blue sphere
|
||||
* Blue and green checkered floor
|
||||
* Sunset-style lighting
|
||||
|
||||
See `ref.512-variant.png` for the rendered result.
|
||||
|
||||
|
||||
#### Limitations
|
||||
|
||||
Currently, this program supports:
|
||||
|
||||
* One sphere
|
||||
* One floor
|
||||
* One light
|
||||
|
||||
Adding more lights is relatively simple.
|
||||
Adding multiple spheres would require stack support for recursive ray tracing (see "Ray Tracing by Self-Inclusion" section).
|
||||
|
||||
Note: we recommend GCC for performance; Clang is slower for C preprocessor-heavy tasks like this one.
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. All Rights Reserved.
|
||||
|
||||
You are free to share and adapt this file under the terms of this license:
|
||||
|
||||
Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
|
||||
|
||||
For more information, see:
|
||||
|
||||
https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
-->
|
||||
@@ -0,0 +1,916 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<!-- START: two lines up starts content from: inc/top.default.html -->
|
||||
|
||||
<!-- END: this line ends content from: inc/top.default.html -->
|
||||
<!-- START: this line starts content from: inc/head.default.html -->
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../ioccc.css">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap" rel="stylesheet">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<title>2024/endoh1 - Prize in patient pointillism</title>
|
||||
<link rel="icon" type="image/x-icon" href="../../favicon.ico">
|
||||
<meta name="description" content="2024 IOCCC entry endoh1 - Prize in patient pointillism">
|
||||
<meta name="keywords" content="IOCCC, 2024, IOCCC 2024, IOCCC entry, endoh1, Prize in patient pointillism">
|
||||
</head>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
|
||||
<!-- END: this line ends content from: inc/head.default.html -->
|
||||
|
||||
<!-- -->
|
||||
<!-- This web page was formed via the tool: bin/readme2index.sh -->
|
||||
<!-- The content of main section of this web page came from: 2024/endoh1/README.md -->
|
||||
<!-- -->
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<!-- !!! Do not modify this web page, instead modify the file: 2024/endoh1/README.md !!! -->
|
||||
<!-- !!! Do not modify this web page, instead modify the file: 2024/endoh1/README.md !!! -->
|
||||
<!-- !!! Do not modify this web page, instead modify the file: 2024/endoh1/README.md !!! -->
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
|
||||
<!-- Markdown content was converted into HTML via the tool: bin/md2html.sh -->
|
||||
|
||||
<!-- START: this line starts content from: inc/body.default.html -->
|
||||
|
||||
<body>
|
||||
|
||||
<!-- END: this line ends content from: inc/body.default.html -->
|
||||
<!-- START: this line starts content from: inc/topbar.default.html -->
|
||||
|
||||
<div class="theader">
|
||||
<nav class="topbar">
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<a href="../../index.html" class="logo-link">
|
||||
IOCCC
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="topbar-items">
|
||||
<div class="item">
|
||||
<span class="item-header">
|
||||
Entries
|
||||
</span>
|
||||
|
||||
<div class="sub-item">
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../years.html" class="sub-item-link">
|
||||
Winning entries
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../authors.html" class="sub-item-link">
|
||||
Winning authors
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../location.html" class="sub-item-link">
|
||||
Location of authors
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../bugs.html" class="sub-item-link">
|
||||
Bugs and (mis)features
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../faq.html#fix_an_entry" class="sub-item-link">
|
||||
Fixing entries
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../faq.html#fix_author" class="sub-item-link">
|
||||
Updating author info
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<span class="item-header">
|
||||
Status
|
||||
</span>
|
||||
|
||||
<div class="sub-item">
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../news.html" class="sub-item-link">
|
||||
News
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../status.html" class="sub-item-link">
|
||||
Contest status
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../next/rules.html" class="sub-item-link">
|
||||
IOCCC rules
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../next/guidelines.html" class="sub-item-link">
|
||||
IOCCC guidelines
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../markdown.html" class="sub-item-link">
|
||||
Markdown guidelines
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../SECURITY.html" class="sub-item-link">
|
||||
Security policy
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<span class="item-header">
|
||||
FAQ
|
||||
</span>
|
||||
|
||||
<div class="sub-item">
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../faq.html" class="sub-item-link">
|
||||
Frequently asked questions
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../quick-start.html#enter" class="sub-item-link">
|
||||
Enter the IOCCC
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../faq.html#compiling" class="sub-item-link">
|
||||
Compiling entries
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../faq.html#running_entries" class="sub-item-link">
|
||||
Running entries
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../faq.html#help" class="sub-item-link">
|
||||
How to help
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<span class="item-header">
|
||||
About
|
||||
</span>
|
||||
|
||||
<div class="sub-item">
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../index.html" class="sub-item-link">
|
||||
Home page
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../social.html" class="sub-item-link">
|
||||
IOCCC social media
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../about.html" class="sub-item-link">
|
||||
About the IOCCC
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../judges.html" class="sub-item-link">
|
||||
The judges
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../thanks-for-help.html" class="sub-item-link">
|
||||
Thanks for the help
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="outfit-font">
|
||||
<a href="../../contact.html" class="sub-item-link">
|
||||
Contact us
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="header-mobile-menu">
|
||||
<noscript>
|
||||
<a href="../../nojs-menu.html" class="topbar-js-label">
|
||||
Please Enable JavaScript
|
||||
</a>
|
||||
</noscript>
|
||||
|
||||
<button id="header-open-menu-button" class="topbar-mobile-menu">
|
||||
<img
|
||||
src="../../png/hamburger-icon-open.png"
|
||||
alt="hamburger style menu icon - open state"
|
||||
width=48
|
||||
height=48>
|
||||
</button>
|
||||
|
||||
<button id="header-close-menu-button" class="hide-content">
|
||||
<img
|
||||
src="../../png/hamburger-icon-closed.png"
|
||||
alt="hamburger style menu icon - closed state"
|
||||
width=48
|
||||
height=48>
|
||||
</button>
|
||||
|
||||
<div id="mobile-menu-panel" class="hide-content">
|
||||
<div class="mobile-menu-container">
|
||||
|
||||
<div class="mobile-menu-wrapper">
|
||||
<div class="mobile-menu-item">
|
||||
Entries
|
||||
</div>
|
||||
<div class="mobile-submenu-wrapper">
|
||||
|
||||
<a class="mobile-submenu-item" href="../../years.html">
|
||||
Winning entries
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../authors.html">
|
||||
Winning authors
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../location.html">
|
||||
Location of authors
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../bugs.html">
|
||||
Bugs and (mis)features
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../faq.html#fix_an_entry">
|
||||
Fixing entries
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../faq.html#fix_author">
|
||||
Updating author info
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../thanks-for-help.html">
|
||||
Thanks for the help
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mobile-menu-wrapper">
|
||||
|
||||
<div class="mobile-menu-item">
|
||||
Status
|
||||
</div>
|
||||
<div class="mobile-submenu-wrapper">
|
||||
|
||||
<a class="mobile-submenu-item" href="../../news.html">
|
||||
News
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../status.html">
|
||||
Contest status
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../next/rules.html">
|
||||
IOCCC rules
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../next/guidelines.html">
|
||||
IOCCC guidelines
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../markdown.html">
|
||||
Markdown guidelines
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../SECURITY.html">
|
||||
Security policy
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mobile-menu-wrapper">
|
||||
<div class="mobile-menu-item">
|
||||
FAQ
|
||||
</div>
|
||||
<div class="mobile-submenu-wrapper">
|
||||
|
||||
<a class="mobile-submenu-item" href="../../faq.html">
|
||||
Frequently asked questions
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../quick-start.html#enter">
|
||||
Enter the IOCCC
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../faq.html#compiling">
|
||||
Compiling entries
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../faq.html#running_entries">
|
||||
Running entries
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../faq.html#help">
|
||||
How to help
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mobile-menu-wrapper">
|
||||
<div class="mobile-menu-item">
|
||||
About
|
||||
</div>
|
||||
<div class="mobile-submenu-wrapper">
|
||||
|
||||
<a class="mobile-submenu-item" href="../../index.html">
|
||||
Home page
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../social.html">
|
||||
IOCCC social media
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../about.html">
|
||||
About the IOCCC
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../judges.html">
|
||||
The judges
|
||||
</a>
|
||||
|
||||
<a class="mobile-submenu-item" href="../../contact.html">
|
||||
Contact us
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var headerOpenMenuButton = document.getElementById("header-open-menu-button");
|
||||
var headerCloseMenuButton = document.getElementById("header-close-menu-button");
|
||||
var mobileMenuPanel = document.getElementById("mobile-menu-panel");
|
||||
|
||||
headerOpenMenuButton.addEventListener("click", () => {
|
||||
headerOpenMenuButton.classList.remove("topbar-mobile-menu");
|
||||
headerOpenMenuButton.classList.add("hide-content");
|
||||
|
||||
headerCloseMenuButton.classList.remove("hide-content");
|
||||
headerCloseMenuButton.classList.add("topbar-mobile-menu");
|
||||
|
||||
mobileMenuPanel.classList.remove("hide-content");
|
||||
mobileMenuPanel.classList.add("topbar-mobile-panel");
|
||||
});
|
||||
|
||||
headerCloseMenuButton.addEventListener("click", () => {
|
||||
headerCloseMenuButton.classList.remove("topbar-mobile-menu");
|
||||
headerCloseMenuButton.classList.add("hide-content");
|
||||
|
||||
mobileMenuPanel.classList.add("hide-content");
|
||||
mobileMenuPanel.classList.remove("topbar-mobile-panel");
|
||||
|
||||
headerOpenMenuButton.classList.add("topbar-mobile-menu");
|
||||
headerOpenMenuButton.classList.remove("hide-content");
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- END: this line ends content from: inc/topbar.default.html -->
|
||||
<!-- START: this line starts content from: inc/header.default.html -->
|
||||
|
||||
<div class="header">
|
||||
<a href="../../2011/zucker/index.html">
|
||||
<img src="../../png/ioccc.png"
|
||||
alt="IOCCC image by Matt Zucker"
|
||||
width=300
|
||||
height=110>
|
||||
</a>
|
||||
<h1>The International Obfuscated C Code Contest</h1>
|
||||
<h2>2024/endoh1 - Prize in patient pointillism</h2>
|
||||
<h3>slow ray tracer in CPP</h3>
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/header.default.html -->
|
||||
<!-- START: this line starts content from: inc/navbar.mid.html -->
|
||||
|
||||
<div class="navbar">
|
||||
<a class="Left" href="../codemeow/index.html">← 2024/codemeow</a>
|
||||
<a class="Left" href="../index.html">↑ 2024 ↑</a>
|
||||
<a class="Left" href="../endoh2/index.html">2024/endoh2 →</a>
|
||||
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/prog.c">C code</a>
|
||||
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/Makefile">Makefile</a>
|
||||
<a class="Right" href="#inventory">Inventory</a>
|
||||
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fendoh1%2Findex.html">✓</a>
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/navbar.mid.html -->
|
||||
<!-- START: this line starts content from: inc/before-content.default.html -->
|
||||
|
||||
<div class="content" id="content">
|
||||
|
||||
<!-- END: this line ends content from: inc/before-content.default.html -->
|
||||
<!-- START: this line starts content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
|
||||
|
||||
<!-- START: this line starts content generated by: bin/output-index-author.sh -->
|
||||
|
||||
<h2 id="author">Author:</h2>
|
||||
<ul>
|
||||
<li>Name: <a href="../../authors.html#Yusuke_Endoh">Yusuke Endoh</a><br>
|
||||
Location: <a href="../../location.html#JP">JP</a> - <em>Japan</em></li>
|
||||
</ul>
|
||||
|
||||
<!-- END: next line ends content generated by: bin/output-index-author.sh -->
|
||||
|
||||
<!-- END: this line ends content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
|
||||
<!-- START: this line starts content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
|
||||
|
||||
<!-- BEFORE: 1st line of markdown file: 2024/endoh1/README.md -->
|
||||
<h2 id="to-build">To build:</h2>
|
||||
<pre><code> make all</code></pre>
|
||||
<h2 id="try">Try:</h2>
|
||||
<pre><code> ./try.sh</code></pre>
|
||||
<p><strong>HINT</strong>: You have to be <strong>VERY</strong> patient while the above script runs to completion.</p>
|
||||
<h2 id="judges-remarks">Judges’ remarks:</h2>
|
||||
<p>When you <code>make all</code> you see what looks like a C program, <code>rt.c</code>.
|
||||
However if you try to compile <code>rt.c</code>, you will fail: even if you try to
|
||||
define the symbols <code>X</code>, <code>Y</code>, <code>W</code>, and <code>H</code>.</p>
|
||||
<p>Well, the propose of the C program, <code>rt.c</code> is to generate the red, green, and blue colors of
|
||||
a single pixel, in the C Preprocessor!!!</p>
|
||||
<p>For the patient, a image may be rendered a slow pixel at a time.
|
||||
Think of this as digital <a href="https://en.wikipedia.org/wiki/Pointillism">Pointillism</a>. :-)</p>
|
||||
<p>For the truly impatient who wishes to get right to the point without trying to dot around
|
||||
waiting for the <a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/try.sh">try.sh</a> to finish, you may view these images:</p>
|
||||
<ul>
|
||||
<li><a href="ref.8.png">tiny 8x8 image</a></li>
|
||||
<li><a href="ref.32.png">small 32x32 image</a></li>
|
||||
<li><a href="ref.128.png">medium 128x128 image</a></li>
|
||||
<li><a href="ref.512.png">large 512x512 image</a></li>
|
||||
</ul>
|
||||
<p><strong>FUN FACT</strong>: We were able to determine on an “<em>x86-64 processor</em>” running
|
||||
“<em>RHEL 9.6</em>” using “<em>gcc version 11.5.0</em>”, one could theoretically render
|
||||
a <strong>2147483647 x 2147483647</strong> pixel image. At the rate it took to render
|
||||
the <strong>512 x 512</strong> pixel image, and without using any parallelism, such an
|
||||
image would take about <strong>169 billion years</strong> to fully render on a single
|
||||
CPU core! Fully rendering such large images is <strong>NOT</strong> recommended. :-)</p>
|
||||
<h3 id="parallel-make">Parallel make</h3>
|
||||
<p><strong>SUGGESTION</strong>: The <a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/Makefile">2024/endoh1/Makefile</a>,
|
||||
by default, uses a single CPU core, can make use of parallel operations.
|
||||
If you have access to a “<em>parallel make</em>”, can achieve the above in a shorter
|
||||
around of time. If you have “<em>n</em>” CPU cores available, consider running
|
||||
a parallel make with “<em>n-1</em>” jobs that run simultaneously. For example:</p>
|
||||
<pre><code> RESERVE="-2"
|
||||
NPROC=$(nproc)
|
||||
((JOBS=NPROC-RESERVE))
|
||||
SIZE=512
|
||||
make clobber all
|
||||
nohup time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE" > make.out 2>&1 < /dev/null &</code></pre>
|
||||
<p>Where <code>SIZE</code> is the size of the image to generate.</p>
|
||||
<p>Where <code>RESERVE</code> is the number of CPU cores to reserve for other things
|
||||
such as the operating system, daemons, terminal window, etc. You can even
|
||||
“<em>oversubscribe</em>” by setting RESERVE to a negative number (e.g., <code>RESERVE="-2"</code>).</p>
|
||||
<p><strong>NOTE</strong>: The <a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/try.sh">try.sh</a> script follows the above
|
||||
example for <code>SIZE</code> values of 8, 32, 128, and then 512.</p>
|
||||
<p>The optimal <code>RESERVE</code> will depend on your hardware, operating system,
|
||||
a C compiler. Making <code>RESERVE</code> too small (i.e., too negative) may slow
|
||||
down the result. We recommend that experiment various values pf <code>RESERVE</code>
|
||||
with moderate <code>SIZE</code> of <strong>32</strong> in order to try to find an optimal <code>JOBS</code>
|
||||
value before attempting to try a larger size such as <strong>512</strong> and beyond.</p>
|
||||
<div id="larger">
|
||||
<h3 id="be-first-to-build-images-larger-than-512x512">Be first to build images larger than 512x512</h3>
|
||||
</div>
|
||||
<p><strong>QUESTION</strong>: Do you have the patience to build an even larger than a 512x512 image?
|
||||
If you do, <strong>using the program as it is written of course</strong>, please <a href="../../judges.html">send the IOCCC</a>
|
||||
the following:</p>
|
||||
<ul>
|
||||
<li>Image Height x Width in pixels</li>
|
||||
<li>URL of the fully rendered image (in PPM form or better yet converted to PNG)</li>
|
||||
<li>How long it took (perhaps using the time(1) command or using the <code>time</code> shell builtin)</li>
|
||||
<li>The starting and ending dates (using <code>date -u</code>) of your rendering</li>
|
||||
<li>Number of CPU cores, Operating system, Compiler, Compiler version, and make version</li>
|
||||
<li>The number of jobs you ran in parallel</li>
|
||||
<li>Anything else you may have done to optimize</li>
|
||||
<li>Your name, (GitHub handle (optional)), (Mastodon handle (optional)), (home page URL (optional)), Country (or XX to be anonymous)</li>
|
||||
</ul>
|
||||
<p><strong>PLEASE</strong> do not attempt to optimize the general algorithm used by this entry to build PPM images.
|
||||
Please remain “<em>faithful to the spirit</em>” of this wonderful entry when attempting to build larger PPM images.</p>
|
||||
<p>The first people to render a new record sized image <strong>using the general algorithm used by this entry</strong>,
|
||||
will be given credit in the <a href="../../thanks-for-help.html">thanks for the help</a> web page.</p>
|
||||
<h2 id="authors-remarks">Author’s remarks:</h2>
|
||||
<h3 id="a-ray-tracer-in-the-c-preprocessor">A Ray Tracer in the C Preprocessor</h3>
|
||||
<p>Ever since the iconic 1988 IOCCC winning entry <a href="../../1988/applin/index.html">1988/applin</a>,
|
||||
bending the C preprocessor to one’s will has been a time-honored tradition in the IOCCC.
|
||||
This entry sets out to be the culmination of that legacy: a ray tracer implemented entirely with C macros!</p>
|
||||
<h4 id="how-to-run">How to Run</h4>
|
||||
<p>The initial program, <code>./prog</code> (compiled from <code>prog.c</code>), outputs the main code, <code>rt.c</code>.
|
||||
To get started, compile and execute it:</p>
|
||||
<pre><code> make all</code></pre>
|
||||
<p>Note: <code>rt.c</code> is not a valid C program – it’s written for C preprocessor.</p>
|
||||
<p>To get the color of a single pixel at position (16, 16) in a 32 x 32 image, run:</p>
|
||||
<pre><code> cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c</code></pre>
|
||||
<p>This will produce:</p>
|
||||
<pre><code> 129
|
||||
62
|
||||
129</code></pre>
|
||||
<p>These three values represent the red, green, and blue components respectively.</p>
|
||||
<ul>
|
||||
<li>Red = 129 (0x81)</li>
|
||||
<li>Green = 62 (0x3e)</li>
|
||||
<li>Blue = 129 (0x81)</li>
|
||||
</ul>
|
||||
<p>In other words, this indicates that the pixel at position (16, 16) has the color #813e81.</p>
|
||||
<h4 id="how-to-generate-the-full-image">How to Generate the Full Image</h4>
|
||||
<p>To generate the entire image, you need to run the preprocessor for every pixel.
|
||||
For example, to form a 32x32 image:</p>
|
||||
<pre><code> mkdir -p pixel
|
||||
cc -E -P -DX=0 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-00.txt
|
||||
cc -E -P -DX=1 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-01.txt
|
||||
cc -E -P -DX=2 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-02.txt
|
||||
...
|
||||
cc -E -P -DX=30 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-30.txt
|
||||
cc -E -P -DX=31 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-31.txt
|
||||
cc -E -P -DX=0 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-00.txt
|
||||
cc -E -P -DX=1 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-01.txt
|
||||
cc -E -P -DX=2 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-02.txt
|
||||
...
|
||||
cc -E -P -DX=30 -DY=31 -DW=32 -DH=32 rt.c > pixel/pixel-31-30.txt
|
||||
cc -E -P -DX=31 -DY=31 -DW=32 -DH=32 rt.c > pixel/pixel-31-31.txt</code></pre>
|
||||
<p>Then, concatenate the results with a PPM header to create the image:</p>
|
||||
<pre><code> echo P3 32 32 > out.ppm
|
||||
echo 255 >> out.ppm
|
||||
find pixel -type f -print | LANG=C sort | xargs cat >> out.ppm</code></pre>
|
||||
<p>Now open <code>out.ppm</code> with any image viewer that supports the PPM format.</p>
|
||||
<h4 id="automating-with-makefile">Automating with Makefile</h4>
|
||||
<p>To form a 32x32 image:</p>
|
||||
<pre><code> make clean targets out.ppm H=32 W=32</code></pre>
|
||||
<p>Now open <code>out.ppm</code> with any image viewer that supports the PPM format.</p>
|
||||
<h4 id="generating-a-larger-image">Generating a Larger Image</h4>
|
||||
<p>To form a 256x256 image:</p>
|
||||
<pre><code> make clean targets out.ppm H=256 W=256</code></pre>
|
||||
<p>Now open <code>out.ppm</code> with any image viewer that supports the PPM format.</p>
|
||||
<p>For reference, the 512x512 image took about 10 hours to render.</p>
|
||||
<h4 id="technical-challenges">Technical Challenges</h4>
|
||||
<p>Below is a technical explanation of the implementation.</p>
|
||||
<h5 id="copying-a-macro-definition">Copying a Macro Definition</h5>
|
||||
<p>One core challenges was how to “copy” the value of a macro.</p>
|
||||
<p>For example, in C macros:</p>
|
||||
<pre><code> #define X 10
|
||||
#define Y X
|
||||
|
||||
#undef X
|
||||
#define X 20
|
||||
|
||||
Y // expands to "20", not "10"</code></pre>
|
||||
<p>The C preprocessor uses lazy evaluation, meaning macro values are always resolved at the time of use.
|
||||
With this observation, some people claim it’s impossible to copy a macro’s value.</p>
|
||||
<p>One known workaround is encoding one bit by whether or not a macro is defined (as seen in <code>applin.c</code> from IOCCC 1988 and <code>vik2.c</code> from IOCCC 2004).
|
||||
However, this approach is too inefficient for our purposes – ray tracing requires operations like multiplication, and even square root.</p>
|
||||
<p>Instead, we discovered an efficient way to “copy” a macro’s value.
|
||||
The key observation is that <code>#if</code> eagerly evaluates the definition of a macro at that point in preprocessing.
|
||||
For example:</p>
|
||||
<pre><code> #if X % 2
|
||||
# define X_b0 1 // The LSB of X is 1
|
||||
#else
|
||||
# define X_b0 0 // The LSB of X is 0
|
||||
#endif</code></pre>
|
||||
<p>This technique copies the least significant bit of <code>X</code>.
|
||||
By applying this for each bit, we can reconstruct the full value:</p>
|
||||
<pre><code> #define X 10
|
||||
|
||||
#if X % 2
|
||||
# define X_b0 1
|
||||
#else
|
||||
# define X_b0 0
|
||||
#endif
|
||||
|
||||
#if X / 2 % 2
|
||||
# define X_b1 2
|
||||
#else
|
||||
# define X_b1 0
|
||||
#endif
|
||||
|
||||
#if X / 4 % 2
|
||||
# define X_b2 4
|
||||
#else
|
||||
# define X_b2 0
|
||||
#endif
|
||||
|
||||
...
|
||||
|
||||
#define Y (X_b0 + X_b1 + X_b2 + ...)
|
||||
|
||||
#undef X
|
||||
#define X 20
|
||||
|
||||
Y // replaced with "0 + 2 + 0 + 8 + ..." = 10</code></pre>
|
||||
<p>Even if <code>X</code> is later redefined, <code>Y</code> remains unchanged.</p>
|
||||
<p>This technique resembles <a href="https://en.wikipedia.org/wiki/Information_flow_(information_theory)">“information flow”</a> in the information security.
|
||||
To our best knowledge, there has been no literature that mentions this technique in terms of the C preprocessor programming.</p>
|
||||
<h5 id="macro-expansion-explosion">Macro Expansion Explosion</h5>
|
||||
<p>Using macros for complex expressions often causes memory issues.</p>
|
||||
<p>For instance, consider this Newton’s method implementation for square roots:</p>
|
||||
<pre><code> #define sqrt0(x, guess) (guess ? (x/guess+guess)/2 : 0)
|
||||
#define sqrt(x) sqrt0(x,sqrt0(x,sqrt0(x,sqrt0(x,sqrt0(x,10000)))))</code></pre>
|
||||
<p>The subroutine <code>sqrt0</code> is one step of Newton’s method, and <code>sqrt</code> applies it five times.
|
||||
There are three occurences of the argument <code>guess</code> in the body of <code>sqrt0</code>.
|
||||
Thus, applying <code>sqrt</code> repeats its argument expression at least 5^3 = 243 times.
|
||||
This easily leads to the explosion of macro expansion.</p>
|
||||
<p>We avoid this issue by using the earlier “copy” trick – reducing the size of macro expansions by materializing their values.</p>
|
||||
<h5 id="encoding-vectors">Encoding Vectors</h5>
|
||||
<p>In theory, it is trivial to encode a 3D vector in the C preprocessor: you can just define three macros for x, y, and z components.
|
||||
However, it creates bloated code – unsuitable for IOCCC size limits.</p>
|
||||
<p>Instead, we encode vectors as simple tuples:</p>
|
||||
<pre><code> #define vec 1,2,3</code></pre>
|
||||
<p>The vector projection can be implemented as follows.</p>
|
||||
<pre><code> #define fst(x,y,z) x
|
||||
#define snd(x,y,z) y
|
||||
#define thd(x,y,z) z
|
||||
#define call(f,a) f(a)</code></pre>
|
||||
<p>Example usage:</p>
|
||||
<pre><code> call(fst, vec) // expands to 1
|
||||
call(snd, vec) // expands to 2
|
||||
call(thd, vec) // expands to 3</code></pre>
|
||||
<p>The auxiliary macro <code>call</code> is required.
|
||||
This is a hassle of the C preprocessor, but, <code>call(fst, vec)</code> is expanded to <code>fst(1,2,3)</code>, which results in <code>1</code>.</p>
|
||||
<p>We can define a vector addition by using the projections.</p>
|
||||
<pre><code> #define vec3_add(a,b) fst(a)+fst(b),snd(a)+snd(b),thd(a)+thd(b)</code></pre>
|
||||
<p>Now, we can simply write <code>vec3_add(v1, v2)</code> to add two vectors.
|
||||
One identifier represents one vector.
|
||||
It is also elegantly possible to nest expressions like <code>vec3_add(v1, vec3_add(v1, v2))</code>.</p>
|
||||
<pre><code> #define v1 0,1,2
|
||||
#define v2 2,1,0
|
||||
|
||||
int main() {
|
||||
printf("(%d %d %d)\n", vec3_add(v1, v2)); // prints "(2 2 2)"
|
||||
printf("(%d %d %d)\n", vec3_add(v1, vec3_add(v1, v2))); // prints "(2 3 4)"
|
||||
}</code></pre>
|
||||
<h5 id="ray-tracing-via-self-inclusion">Ray Tracing via Self-Inclusion</h5>
|
||||
<p>Ray tracing involves recursive calls for reflection.
|
||||
In <code>rt.c</code>, this is done via:</p>
|
||||
<pre><code> #include __FILE__</code></pre>
|
||||
<p>In the implementation, only spheres reflect rays, and only one sphere exists.
|
||||
Thus, the recursion depth is limited to one.</p>
|
||||
<p>Theoretically, it is possible to support multiple reflections, but this would require implementing a “stack” to keep “local variables” in a stack frame.</p>
|
||||
<h5 id="outputting-a-pixel">Outputting a Pixel</h5>
|
||||
<p>The preprocessed result of <code>rt.c</code> contains some preprocessor directives (starting with <code>#</code>) and three integers (red, green, and blue).</p>
|
||||
<pre><code> cc -E -DX=16 -DY=16 -DW=32 -DH=32 rt.c</code></pre>
|
||||
<p>This will produce:</p>
|
||||
<pre><code> # 0 "rt.c"
|
||||
# 0 "<built-in>"
|
||||
# 0 "<command-line>"
|
||||
# 1 "/usr/include/stdc-predef.h" 1 3 4
|
||||
# 0 "<command-line>" 2
|
||||
# 1 "rt.c"
|
||||
# 3481 "rt.c"
|
||||
# 1 "rt.c" 1
|
||||
# 2090 "rt.c"
|
||||
# 1 "rt.c" 1
|
||||
# 2091 "rt.c" 2
|
||||
# 3482 "rt.c" 2
|
||||
# 3582 "rt.c"
|
||||
129
|
||||
# 3684 "rt.c"
|
||||
62
|
||||
# 3786 "rt.c"
|
||||
129</code></pre>
|
||||
<p>Interestingly, these are valid in the PPM format (lines starting with <code>#</code> are commments in PPM).
|
||||
Thus, just concatenating the results for all pixels (and prefixing a small header) will work to create a PPM image file.</p>
|
||||
<p>When render a large image, we recommend use the <code>-E -P</code> flags as in:</p>
|
||||
<pre><code> cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c</code></pre>
|
||||
<p>This will only produce:</p>
|
||||
<pre><code> 129
|
||||
62
|
||||
129</code></pre>
|
||||
<p>Note that values appear as expressions like <code>(0 + 2 + 0 + 8 + ...)</code> because we use the “copy” trick.
|
||||
To print them as to ordinary decimal values, we use macro logic like:</p>
|
||||
<pre><code> // assume red is (0 + 2 + 0 + 8)
|
||||
|
||||
#if red / 100 % 10 == 0
|
||||
# define digit0(digits) 0##digits
|
||||
#elif red / 100 % 10 == 1
|
||||
# define digit0(digits) 1##digits
|
||||
#else
|
||||
# define digit0(digits) 2##digits
|
||||
#endif
|
||||
|
||||
#if red / 10 % 10 == 0
|
||||
# define digit1(digits) digits0(0##digits)
|
||||
#elif red / 10 % 10 == 1
|
||||
# define digit1(digits) digits0(1##digits)
|
||||
#elif ...
|
||||
...
|
||||
#endif
|
||||
|
||||
#if red % 10 == 0
|
||||
# define digits digit1(0)
|
||||
#elif red % 10 == 1
|
||||
# define digits digit1(1)
|
||||
#elif ...
|
||||
...
|
||||
#endif
|
||||
|
||||
digits // outputs "10"</code></pre>
|
||||
<h4 id="customizing-the-scene">Customizing the Scene</h4>
|
||||
<p>You can modify the scene by editing the top of <code>rt.c</code>.</p>
|
||||
<h5 id="example-defaults">Example Defaults</h5>
|
||||
<pre><code> #define p 0,500,4000 // sphere center position
|
||||
#define q 2000 // sphere radius
|
||||
#define r 300,300,300 // sphere color (default: light gray)
|
||||
#define s(x) 900,200+K*7100,900 // plane color (default: checkered colors of white for K=1 and purple for K=0)
|
||||
#define t -2000,4000,1000 // light position
|
||||
#define u 50000,50000,50000 // light color (default: white)
|
||||
#define v(x) 500-x,500-x,500 // background color (default: gradation from blue to white)</code></pre>
|
||||
<h5 id="variant-example">Variant Example</h5>
|
||||
<pre><code> #define p 0,0,8000
|
||||
#define q 2000
|
||||
#define r 300,300,900
|
||||
#define s(x) 200,500-x*300,200+x*800
|
||||
#define t 2000,4000,3000
|
||||
#define u 30000,40000,30000
|
||||
#define v(x) 500,x,10</code></pre>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Grounded blue sphere</li>
|
||||
<li>Blue and green checkered floor</li>
|
||||
<li>Sunset-style lighting</li>
|
||||
</ul>
|
||||
<p>See <code>ref.512-variant.png</code> for the rendered result.</p>
|
||||
<h4 id="limitations">Limitations</h4>
|
||||
<p>Currently, this program supports:</p>
|
||||
<ul>
|
||||
<li>One sphere</li>
|
||||
<li>One floor</li>
|
||||
<li>One light</li>
|
||||
</ul>
|
||||
<p>Adding more lights is relatively simple.
|
||||
Adding multiple spheres would require stack support for recursive ray tracing (see “Ray Tracing by Self-Inclusion” section).</p>
|
||||
<p>Note: we recommend GCC for performance; Clang is slower for C preprocessor-heavy tasks like this one.</p>
|
||||
<!--
|
||||
|
||||
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. All Rights Reserved.
|
||||
|
||||
You are free to share and adapt this file under the terms of this license:
|
||||
|
||||
Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
|
||||
|
||||
For more information, see:
|
||||
|
||||
https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
-->
|
||||
<!-- AFTER: last line of markdown file: 2024/endoh1/README.md -->
|
||||
|
||||
<!-- END: this line ends content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
|
||||
<!-- START: this line starts content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
|
||||
|
||||
<!-- START: this line starts content generated by: bin/output-index-inventory.sh -->
|
||||
|
||||
<div id="inventory">
|
||||
<h1 id="inventory-for-2024endoh1">Inventory for 2024/endoh1</h1>
|
||||
</div>
|
||||
<h2 id="primary-files">Primary files</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/prog.c">prog.c</a> - entry source code</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/Makefile">Makefile</a> - entry Makefile</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/prog.orig.c">prog.orig.c</a> - original source code</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/ref.8.png">ref.8.png</a> - 8x8 image in PNG form</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/try.sh">try.sh</a> - script to try entry</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/ref.32.png">ref.32.png</a> - 32x32 image in PNG form</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/ref.128.png">ref.128.png</a> - 128x128 image in PNG form</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/ref.512.png">ref.512.png</a> - 512x512 image in PNG form</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/ref.512-variant.png">ref.512-variant.png</a> - variant of 512x512 image in PNG form</li>
|
||||
</ul>
|
||||
<h2 id="secondary-files">Secondary files</h2>
|
||||
<ul>
|
||||
<li><a href="2024_endoh1.tar.bz2">2024_endoh1.tar.bz2</a> - download entry tarball</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/README.md">README.md</a> - markdown source for this web page</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/.entry.json">.entry.json</a> - entry summary and manifest in JSON</li>
|
||||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/.gitignore">.gitignore</a> - list of files that should not be committed under git</li>
|
||||
<li><a href=".path">.path</a> - directory path from top level directory</li>
|
||||
<li><a href="index.html">index.html</a> - this web page</li>
|
||||
</ul>
|
||||
<hr style="width:10%;text-align:left;margin-left:0">
|
||||
<h4>
|
||||
Jump to: <a href="#">top</a>
|
||||
</h4>
|
||||
|
||||
<!-- END: next line ends content generated by: bin/output-index-inventory.sh -->
|
||||
|
||||
<!-- END: this line ends content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
|
||||
<!-- START: this line starts content from: inc/after-content.default.html -->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/after-content.default.html -->
|
||||
<!-- START: this line starts content from: inc/footer.inventory.html -->
|
||||
|
||||
<!--
|
||||
|
||||
Copyright © 1984-2025 by Landon Curt Noll. All Rights Reserved.
|
||||
|
||||
You are free to share and adapt this file under the terms of this license:
|
||||
|
||||
Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
|
||||
|
||||
For more information, see:
|
||||
|
||||
https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
-->
|
||||
|
||||
<div class="footer">
|
||||
|
||||
<div id="copyright"><h3>Copyright © 1984-2025 by Landon Curt Noll:
|
||||
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
|
||||
target="_blank"
|
||||
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
|
||||
<p>
|
||||
This work is <b>licensed by Landon Curt Noll</b> under
|
||||
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1"
|
||||
target="_blank"
|
||||
rel="license noopener noreferrer"
|
||||
style="display:inline-block;">CC BY-SA 4.0</a></b>.
|
||||
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
|
||||
src="../../png/cc.png"
|
||||
alt="cc inside circle symbol">
|
||||
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
|
||||
src="../../png/by.png"
|
||||
alt="person inside circle symbol">
|
||||
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
|
||||
src="../../png/sa.png"
|
||||
alt="arrow looping back on itself inside circle symbol"><br>
|
||||
You should <b>carefully review</b> the
|
||||
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.en"
|
||||
target="_blank"
|
||||
rel="license noopener noreferrer">CC BY-SA 4.0 LEGAL CODE</a></b>
|
||||
before using the licensed material.<br>
|
||||
You may wish to review the
|
||||
<b><a href="../../license.html"
|
||||
target="_blank"
|
||||
rel="license noopener noreferrer">highlights of some of the key features and terms</a></b>
|
||||
of <b>CC BY-SA 4.0</b>.<br>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="coda"><h3>Coda</h3>
|
||||
<p>
|
||||
<a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fendoh1%2Findex.html" rel="nofollow">Nu HTML check this web page</a><br>
|
||||
<a href="#top">Jump to top</a> <a href="#content">Jump to Content</a> <a href="#inventory">Jump to Inventory</a><br>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/footer.inventory.html -->
|
||||
<!-- START: this line starts content from: inc/bottom.default.html -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- END: this line ends content from: inc/bottom.default.html -->
|
||||
@@ -0,0 +1,177 @@
|
||||
#include <stdio.h>
|
||||
int main(void){
|
||||
int i,j;
|
||||
#define G "#define "
|
||||
#define L p("#include __FILE__");
|
||||
#define p puts
|
||||
#define t printf
|
||||
#define d(s,a)p(G#s" "#a);
|
||||
#define g(s,a)p(G#s"(a,b) "#a);
|
||||
#define e(s,x,y,z)p(G#s" "#x","#y","#z);
|
||||
#define b(s)p("#if "#s);
|
||||
#define u(s)p("#undef "#s);
|
||||
#define l p("#else")
|
||||
#define n p("#endif")
|
||||
#define f(s)\
|
||||
d(s##30,0) \
|
||||
for(i=31; --i; n) { \
|
||||
t("#if ("#s")/%d&1\n",1<<i); \
|
||||
t(G#s"%d "#s"%d|%d\n",i-1,i,1<<i); \
|
||||
l; \
|
||||
t(G#s"%d "#s"%d\n",i-1,i); \
|
||||
} \
|
||||
b(s>0); \
|
||||
u(s)\
|
||||
d(s,(s##0)) \
|
||||
l; \
|
||||
u(s)\
|
||||
d(s,-(s##0)) \
|
||||
n;
|
||||
#define r(s) \
|
||||
u(s) \
|
||||
for(i=31;i--;) \
|
||||
t("#undef "#s"%d\n",i);
|
||||
#define F(s) \
|
||||
d(s##A,c(A,s)); f(s##A); \
|
||||
d(s##B,c(B,s)); f(s##B); \
|
||||
d(s##C,c(C,s)); f(s##C); \
|
||||
u(s); e(s,s##A,s##B,s##C);
|
||||
#define I(d,m,e) \
|
||||
t("#if (c(%c,Z))/"#d"%%"#m"==%d\n",j,e)
|
||||
#define J(a,b) \
|
||||
for(i=10; i--; n){ \
|
||||
I(a,10,i); \
|
||||
t(G b"\n",i); \
|
||||
}
|
||||
#define X(v,p,q,r) \
|
||||
e(v(x,a,b),x(A(a),p(b)),x(B(a),q(b)),x(C(a),r(b)))
|
||||
#define T(x)\
|
||||
d(i,N(o,t,h)) \
|
||||
d(M,m(d(i,i))) \
|
||||
f(M); \
|
||||
d(j,d(g,O(U,i,M))) \
|
||||
b(j<0) \
|
||||
e(x,0,0,0) \
|
||||
l; \
|
||||
d(x,O(U,O(k,u,j),d(i,i))); \
|
||||
n; \
|
||||
F(x) \
|
||||
u(i) \
|
||||
r(M); \
|
||||
u(j) \
|
||||
n;
|
||||
e(p,0,500,4000)
|
||||
d(q,2000)
|
||||
e(r,300,300,300)
|
||||
e(s(x),900,200+x*700,900)
|
||||
e(t,-2000,4000,1000)
|
||||
e(u,50000,50000,50000)
|
||||
e(v(x),500-x,500-x,500)
|
||||
b(S)
|
||||
d(V,N(o,P,p))
|
||||
d(G,d(Q,Q))
|
||||
d(f,d(V,Q))
|
||||
d(Z,l(f)-k(G,(d(V,V)-l(q))))
|
||||
b(Z>0)
|
||||
d(M,m(Z))
|
||||
f(M);
|
||||
d(R,U(-M-f,G))
|
||||
b(R<0)
|
||||
u(R)
|
||||
d(R,U(M-f,G))
|
||||
b(R<0)
|
||||
u(R)
|
||||
n;
|
||||
n;
|
||||
n;
|
||||
b(R)
|
||||
f(R);
|
||||
r(M);
|
||||
d(h,N(K,P,O(k,Q,R)))
|
||||
d(g,O(U,N(o,h,p),q))
|
||||
T(D);
|
||||
r(M);
|
||||
u(V)
|
||||
u(G)
|
||||
u(f)
|
||||
u(Z)
|
||||
b(R>10)
|
||||
d(F,N(K,O(k,g,10),h))
|
||||
d(I,N(o,Q,O(k,g,d(g,Q)*2)))
|
||||
F(F);
|
||||
F(I);
|
||||
u(P)
|
||||
u(Q)
|
||||
d(P,F)
|
||||
d(Q,I)
|
||||
u(h)
|
||||
u(g)
|
||||
r(R);
|
||||
L
|
||||
u(V)
|
||||
d(V,N(k,N(K,D,w),r))
|
||||
l;
|
||||
u(h)
|
||||
u(g)
|
||||
r(R);
|
||||
b(c(B,Q))
|
||||
d(R,U(-2*S-c(B,P),c(B,Q)))
|
||||
b(R<0||20000<R)
|
||||
u(R)
|
||||
n;
|
||||
n;
|
||||
b(R)
|
||||
f(R);
|
||||
d(h,N(K,P,O(k,Q,R)))
|
||||
e(g,0,S,0)
|
||||
T(E);
|
||||
b(R>10)
|
||||
d(w,N(k,O(k,E,l(c(A,h))+l((c(C,h)-c(C,p)))<l(q)?100:S),s((T(c(A,h))==T(c(C,h))))))
|
||||
l;
|
||||
d(w,v(c(B,Q)/2))
|
||||
n;
|
||||
F(w);
|
||||
d(V,w)
|
||||
n;
|
||||
l;
|
||||
d(S,1000)
|
||||
g(K,(a+b))
|
||||
g(o,(a-(b)))
|
||||
g(k,((a)*(b)/S))
|
||||
g(U,((a)*S/(b)))
|
||||
d(l(a),k(a,a))
|
||||
g(n,(b?(U(a,b)+b)/2:0))
|
||||
d(m(x),n(x,n(x,n(x,n(x,n(x,(x)/2))))))
|
||||
d(T(x),(x>0?x:S-x)/S%2)
|
||||
d(A(x,y,z),x)
|
||||
d(B(x,y,z),y)
|
||||
d(C(x,y,z),z)
|
||||
g(c,a(b))
|
||||
e(L(a,b),a(A(b)),a(B(b)),a(C(b)))
|
||||
X(N,A,B,C)
|
||||
X(O,,,)
|
||||
g(d,(k(A(a),A(b))+k(B(a),B(b))+k(C(a),C(b))))
|
||||
e(Q,(S*X/W*2-S),(S-S*Y/H*2),S)
|
||||
e(P,0,0,0)
|
||||
L
|
||||
d(e(x),m(x<0?0:x>S?S:x)*255/S)
|
||||
d(Z,L(e,V))
|
||||
for(j=64; j++<67; ){
|
||||
I(100,10,0);
|
||||
d(x(a),a)
|
||||
l;
|
||||
J(100,"x(a) %d##a")
|
||||
n;
|
||||
I(10,100,0);
|
||||
d(y(a),a)
|
||||
l;
|
||||
J(10,"y(a) x(%d##a)");
|
||||
n;
|
||||
J(1,"z y(%d)");
|
||||
p("z");
|
||||
u(z)
|
||||
u(y)
|
||||
u(x)
|
||||
}
|
||||
n;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
#include <stdio.h>
|
||||
int main(){
|
||||
int i,j;
|
||||
#define G "#define "
|
||||
#define L p("#include __FILE__");
|
||||
#define p puts
|
||||
#define t printf
|
||||
#define d(s,a)p(G#s" "#a);
|
||||
#define g(s,a)p(G#s"(a,b) "#a);
|
||||
#define e(s,x,y,z)p(G#s" "#x","#y","#z);
|
||||
#define b(s)p("#if "#s);
|
||||
#define u(s)p("#undef "#s);
|
||||
#define l p("#else")
|
||||
#define n p("#endif")
|
||||
#define f(s)\
|
||||
d(s##30,0) \
|
||||
for(i=31; --i; n) { \
|
||||
t("#if ("#s")/%d&1\n",1<<i); \
|
||||
t(G#s"%d "#s"%d|%d\n",i-1,i,1<<i); \
|
||||
l; \
|
||||
t(G#s"%d "#s"%d\n",i-1,i); \
|
||||
} \
|
||||
b(s>0); \
|
||||
u(s)\
|
||||
d(s,(s##0)) \
|
||||
l; \
|
||||
u(s)\
|
||||
d(s,-(s##0)) \
|
||||
n;
|
||||
#define r(s) \
|
||||
u(s) \
|
||||
for(i=31;i--;) \
|
||||
t("#undef "#s"%d\n",i);
|
||||
#define F(s) \
|
||||
d(s##A,c(A,s)); f(s##A); \
|
||||
d(s##B,c(B,s)); f(s##B); \
|
||||
d(s##C,c(C,s)); f(s##C); \
|
||||
u(s); e(s,s##A,s##B,s##C);
|
||||
#define I(d,m,e) \
|
||||
t("#if (c(%c,Z))/"#d"%%"#m"==%d\n",j,e)
|
||||
#define J(a,b) \
|
||||
for(i=10; i--; n){ \
|
||||
I(a,10,i); \
|
||||
t(G b"\n",i); \
|
||||
}
|
||||
#define X(v,p,q,r) \
|
||||
e(v(x,a,b),x(A(a),p(b)),x(B(a),q(b)),x(C(a),r(b)))
|
||||
#define T(x)\
|
||||
d(i,N(o,t,h)) \
|
||||
d(M,m(d(i,i))) \
|
||||
f(M); \
|
||||
d(j,d(g,O(U,i,M))) \
|
||||
b(j<0) \
|
||||
e(x,0,0,0) \
|
||||
l; \
|
||||
d(x,O(U,O(k,u,j),d(i,i))); \
|
||||
n; \
|
||||
F(x) \
|
||||
u(i) \
|
||||
r(M); \
|
||||
u(j) \
|
||||
n;
|
||||
e(p,0,500,4000)
|
||||
d(q,2000)
|
||||
e(r,300,300,300)
|
||||
e(s(x),900,200+x*700,900)
|
||||
e(t,-2000,4000,1000)
|
||||
e(u,50000,50000,50000)
|
||||
e(v(x),500-x,500-x,500)
|
||||
b(S)
|
||||
d(V,N(o,P,p))
|
||||
d(G,d(Q,Q))
|
||||
d(f,d(V,Q))
|
||||
d(Z,l(f)-k(G,(d(V,V)-l(q))))
|
||||
b(Z>0)
|
||||
d(M,m(Z))
|
||||
f(M);
|
||||
d(R,U(-M-f,G))
|
||||
b(R<0)
|
||||
u(R)
|
||||
d(R,U(M-f,G))
|
||||
b(R<0)
|
||||
u(R)
|
||||
n;
|
||||
n;
|
||||
n;
|
||||
b(R)
|
||||
f(R);
|
||||
r(M);
|
||||
d(h,N(K,P,O(k,Q,R)))
|
||||
d(g,O(U,N(o,h,p),q))
|
||||
T(D);
|
||||
r(M);
|
||||
u(V)
|
||||
u(G)
|
||||
u(f)
|
||||
u(Z)
|
||||
b(R>10)
|
||||
d(F,N(K,O(k,g,10),h))
|
||||
d(I,N(o,Q,O(k,g,d(g,Q)*2)))
|
||||
F(F);
|
||||
F(I);
|
||||
u(P)
|
||||
u(Q)
|
||||
d(P,F)
|
||||
d(Q,I)
|
||||
u(h)
|
||||
u(g)
|
||||
r(R);
|
||||
L
|
||||
u(V)
|
||||
d(V,N(k,N(K,D,w),r))
|
||||
l;
|
||||
u(h)
|
||||
u(g)
|
||||
r(R);
|
||||
b(c(B,Q))
|
||||
d(R,U(-2*S-c(B,P),c(B,Q)))
|
||||
b(R<0||20000<R)
|
||||
u(R)
|
||||
n;
|
||||
n;
|
||||
b(R)
|
||||
f(R);
|
||||
d(h,N(K,P,O(k,Q,R)))
|
||||
e(g,0,S,0)
|
||||
T(E);
|
||||
b(R>10)
|
||||
d(w,N(k,O(k,E,l(c(A,h))+l((c(C,h)-c(C,p)))<l(q)?100:S),s((T(c(A,h))==T(c(C,h))))))
|
||||
l;
|
||||
d(w,v(c(B,Q)/2))
|
||||
n;
|
||||
F(w);
|
||||
d(V,w)
|
||||
n;
|
||||
l;
|
||||
d(S,1000)
|
||||
g(K,(a+b))
|
||||
g(o,(a-(b)))
|
||||
g(k,((a)*(b)/S))
|
||||
g(U,((a)*S/(b)))
|
||||
d(l(a),k(a,a))
|
||||
g(n,(b?(U(a,b)+b)/2:0))
|
||||
d(m(x),n(x,n(x,n(x,n(x,n(x,(x)/2))))))
|
||||
d(T(x),(x>0?x:S-x)/S%2)
|
||||
d(A(x,y,z),x)
|
||||
d(B(x,y,z),y)
|
||||
d(C(x,y,z),z)
|
||||
g(c,a(b))
|
||||
e(L(a,b),a(A(b)),a(B(b)),a(C(b)))
|
||||
X(N,A,B,C)
|
||||
X(O,,,)
|
||||
g(d,(k(A(a),A(b))+k(B(a),B(b))+k(C(a),C(b))))
|
||||
e(Q,(S*X/W*2-S),(S-S*Y/H*2),S)
|
||||
e(P,0,0,0)
|
||||
L
|
||||
d(e(x),m(x<0?0:x>S?S:x)*255/S)
|
||||
d(Z,L(e,V))
|
||||
for(j=64; j++<67; ){
|
||||
I(100,10,0);
|
||||
d(x(a),a)
|
||||
l;
|
||||
J(100,"x(a) %d##a")
|
||||
n;
|
||||
I(10,100,0);
|
||||
d(y(a),a)
|
||||
l;
|
||||
J(10,"y(a) x(%d##a)");
|
||||
n;
|
||||
J(1,"z y(%d)");
|
||||
p("z");
|
||||
u(z)
|
||||
u(y)
|
||||
u(x)
|
||||
}
|
||||
n;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 258 B |
Executable
+170
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# try.sh - demonstrate 2024/endoh1
|
||||
|
||||
# make sure CC is set so that when we do make CC="$CC" it isn't empty. Doing it
|
||||
# this way allows us to have the user specify a different compiler in an easy way.
|
||||
#
|
||||
if [[ -z "$CC" ]]; then
|
||||
CC="cc"
|
||||
fi
|
||||
|
||||
|
||||
# make sure the program has been built
|
||||
#
|
||||
make CC="$CC" all >/dev/null || exit 1
|
||||
|
||||
|
||||
# clear the screen
|
||||
#
|
||||
clear
|
||||
|
||||
|
||||
# determine of make support -j2
|
||||
#
|
||||
make -j 2 prog.c >/dev/null 2>&1 < /dev/null
|
||||
status="$?"
|
||||
if [[ $status -ne 0 ]]; then
|
||||
JOBS="1"
|
||||
echo "NOTE: make dues not support -j 2, so make out.ppm will only use a single CPU job." 1>&2
|
||||
|
||||
else
|
||||
# determine how parallel we want to make
|
||||
#
|
||||
export RESERVE="-2" # our best guess is to oversubscribing by 2 cores
|
||||
if [[ $RESERVE -lt 0 ]]; then
|
||||
echo "NOTE: We will oversubscribe by $((-RESERVE)) CPU cores." 1>&2
|
||||
else
|
||||
echo "NOTE: We will reserve $RESERVE CPU cores." 1>&2
|
||||
fi
|
||||
NPROC_TOOL=$(type -P nproc)
|
||||
export RESERVE NPROC_TOOL NPROC JOBS SIZE
|
||||
if [[ -z "$NPROC_TOOL" ]]; then
|
||||
NPROC="4" # we lack nproc so we just guess
|
||||
echo "NOTE: The nproc utility was not found so we simply guess you have $NPROC CPU cores." 1>&2
|
||||
else
|
||||
NPROC=$(nproc)
|
||||
echo "NOTE: The nproc utility found $NPROC CPU cores." 1>&2
|
||||
fi
|
||||
((JOBS=NPROC-RESERVE))
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
echo "NOTE: We will make out.ppm using $JOBS parallel make jobs." 1>&2
|
||||
else
|
||||
JOBS="1"
|
||||
echo "NOTE: We will make out.ppm using just a single CPU." 1>&2
|
||||
fi
|
||||
fi
|
||||
echo 1>&2
|
||||
|
||||
|
||||
# build an 8x8 image
|
||||
#
|
||||
SIZE="8"
|
||||
echo "NOTE: This next step will take a bit (about 75 seconds on a single CPU core) to build the ${SIZE}x${SIZE} image." 1>&2
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
echo 1>&2
|
||||
echo "NOTE: With $JOBS make jobs in parallel your time will be less." 1>&2
|
||||
echo "NOTE: For example, with 6 jobs in parallel, this might complete in about 20 seconds" 1>&2
|
||||
fi
|
||||
echo 1>&2
|
||||
read -r -n 1 -p "Press any key to build an ${SIZE}x${SIZE} image: " 1>&2
|
||||
echo 1>&2
|
||||
rm -f "$SIZE.ppm"
|
||||
rm -rf pixel
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE"
|
||||
else
|
||||
time make out.ppm H="$SIZE" W="$SIZE"
|
||||
fi
|
||||
mv -f -v out.ppm "$SIZE.ppm"
|
||||
echo 1>&2
|
||||
echo "Now open $SIZE.ppm in a graphics viewer in a separate window." 1>&2
|
||||
echo 1>&2
|
||||
echo 'NOTE: You may have to magnify it to see it: do not worry: better images will be created in the next steps.' 1>&2
|
||||
echo 1>&2
|
||||
|
||||
|
||||
# build a 32x32 image
|
||||
#
|
||||
SIZE="32"
|
||||
echo "NOTE: This next step will take a while (about 20 minutes using a single CPU core) to build the ${SIZE}x${SIZE} image." 1>&2
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
echo 1>&2
|
||||
echo "NOTE: With $JOBS make jobs in parallel your time will be less." 1>&2
|
||||
echo "NOTE: For example, with 6 jobs in parallel, this might complete in about 5.5 minutes" 1>&2
|
||||
fi
|
||||
echo 1>&2
|
||||
echo 'NOTE: The files, ref.32.png, ref.128.png, and ref.512.png, contains a copies of what the next 3 steps will produce,' 1>&2
|
||||
echo 'NOTE: in case you wish to abort.' 1>&2
|
||||
echo 1>&2
|
||||
read -r -n 1 -p "Press any key to build an ${SIZE}x${SIZE} image: " 1>&2
|
||||
echo 1>&2
|
||||
rm -f "$SIZE.ppm"
|
||||
rm -rf pixel
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE"
|
||||
else
|
||||
time make out.ppm H="$SIZE" W="$SIZE"
|
||||
fi
|
||||
mv -f -v out.ppm "$SIZE.ppm"
|
||||
echo 1>&2
|
||||
echo "Now open $SIZE.ppm in a graphics viewer in a separate window." 1>&2
|
||||
echo 1>&2
|
||||
echo 'NOTE: For an even better images, complete the next 2 steps.' 1>&2
|
||||
echo 1>&2
|
||||
|
||||
|
||||
# build a 128x128 image
|
||||
#
|
||||
SIZE="128"
|
||||
echo "NOTE: This next step will take LONG TIME (about of 5.5 hours on 1 CPU core) to build the ${SIZE}x${SIZE} image!" 1>&2
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
echo 1>&2
|
||||
echo "NOTE: With $JOBS make jobs in parallel your time will be less." 1>&2
|
||||
echo "NOTE: For example, with 6 jobs in parallel, this might complete in about 1.5 hours" 1>&2
|
||||
fi
|
||||
echo 1>&2
|
||||
echo 'NOTE: The files, ref.128.png, and ref.512.png, contains a copies of what the next 2 steps will produce,' 1>&2
|
||||
echo 'NOTE: in case you wish to abort.' 1>&2
|
||||
echo 1>&2
|
||||
read -r -n 1 -p "Press any key to build an ${SIZE}x${SIZE} image: " 1>&2
|
||||
echo 1>&2
|
||||
rm -f "$SIZE.ppm"
|
||||
rm -rf pixel
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE"
|
||||
else
|
||||
time make out.ppm H="$SIZE" W="$SIZE"
|
||||
fi
|
||||
mv -f -v out.ppm "$SIZE.ppm"
|
||||
echo 1>&2
|
||||
echo "Now open $SIZE.ppm in a graphics viewer in a separate window." 1>&2
|
||||
echo 1>&2
|
||||
|
||||
# build a 512x512 image
|
||||
#
|
||||
SIZE="512"
|
||||
echo "NOTE: This next step will take VERY LONG TIME (on the order of 3.5 days using just 1 core) to build the ${SIZE}x${SIZE} image!!!" 1>&2
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
echo 1>&2
|
||||
echo "NOTE: With $JOBS make jobs in parallel your time will be less." 1>&2
|
||||
echo "NOTE: For example, with 6 jobs in parallel, this might complete in about 23.5 hours" 1>&2
|
||||
fi
|
||||
echo 1>&2
|
||||
read -r -n 1 -p "Press any key to build an ${SIZE}x${SIZE} image: " 1>&2
|
||||
echo 1>&2
|
||||
rm -f "$SIZE.ppm"
|
||||
rm -rf pixel
|
||||
if [[ $JOBS -ge 2 ]]; then
|
||||
time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE"
|
||||
else
|
||||
time make out.ppm H="$SIZE" W="$SIZE"
|
||||
fi
|
||||
mv -f -v out.ppm "$SIZE.ppm"
|
||||
echo 1>&2
|
||||
echo "Now open $SIZE.ppm in a graphics viewer in a separate window." 1>&2
|
||||
echo 1>&2
|
||||
|
||||
# All Done !!! -- Jessica Noll, Age 2
|
||||
#
|
||||
exit 0
|
||||
Reference in new issue
Block a user