971 lines
40 KiB
HTML
971 lines
40 KiB
HTML
<!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://github.com/ioccc-src/winner/blob/master/2024/endoh1/prog.orig.c">Original C</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="award-presentation">Award presentation:</h2>
|
||
<p>Watch the <a href="https://www.youtube.com/@OurFavoriteUniverse">Our Favorite Universe</a>
|
||
YouTube show for this entry:</p>
|
||
<blockquote>
|
||
<p><a href="https://www.youtube.com/watch?v=-BORKHexSPM">IOCCC28 - 2024/endoh1 - Prize in patient pointillism</a></p>
|
||
</blockquote>
|
||
<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 purpose 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, an 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 of <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-2048x2048">Be first to build images larger than 2048x2048</h3>
|
||
</div>
|
||
<h4 id="on-the-2048x2048-rendering">On the 2048x2048 rendering:</h4>
|
||
<p><a href="../../thanks-for-help.html#bisqwit">Joel Yliluoma</a> rendered:</p>
|
||
<ul>
|
||
<li><a href="endoh1-2048.png">2048x2048 image</a></li>
|
||
</ul>
|
||
<p>Here is the fun saga of how the above image was rendered.</p>
|
||
<blockquote>
|
||
<p>The above image was started on <strong>Thu Sep 11 10:14:24 AM UTC 2025</strong>
|
||
using 118 parallel jobs, then was suspended for 1 hour at the <code>Y=217</code> mark,
|
||
was interrupted accidentally at the <code>Y=254</code> mark. After a quick
|
||
edit to his version of the <code>try.sh</code> script so that it will not delete
|
||
existing work when restarted, he started again a minute later, at the
|
||
<strong>Thu Sep 11 01:36:08 PM UTC 2025</strong>. The rendering was interrupted again
|
||
at the <code>Y=972</code> mark for a couple of minutes, and interrupted again
|
||
on <code>Y=1017</code> mark, due to a system crash (due to memory exhaustion not
|
||
entirely related to the rendering). The rendering resumed 4 hours later,
|
||
this time using 49 parallel jobs, on <strong>Fri Sep 12 09:23:04 PM UTC 2025</strong>
|
||
when the rendering was finished on <strong>Sat Sep 13 06:24:39 PM UTC 2025</strong>.
|
||
However files at <code>Y=1017</code> were corrupt by the system crash, so rendering
|
||
re-resumed on <strong>Sat Sep 13 06:25:56 PM UTC 2025</strong> and truly finished on:
|
||
<strong>Sat Sep 13 06:29:51 PM UTC 2025</strong>! :-)</p>
|
||
</blockquote>
|
||
<p>The hardware used to render was:</p>
|
||
<pre><code> CPU: AMD Ryzen Threadripper 3960X 24-Core Processor
|
||
between 49 and 118 threads
|
||
GCC 14.2.0-19 14.2.0
|
||
Debian Testing (currently Debian 14…ish?)
|
||
GNU Make 4.4.1</code></pre>
|
||
<p>A summary of <a href="../../thanks-for-help.html#bisqwit">Joel Yliluoma</a> valiant effort
|
||
to render the above image is as follows:</p>
|
||
<p>User time: <strong>22 days 9 hours 13 minutes 54.094 seconds</strong><br>
|
||
Sys time: <strong>18 days 18 hours 58 minutes 30.936 seconds</strong></p>
|
||
<h4 id="on-the-1024x1024-rendering">On the 1024x1024 rendering:</h4>
|
||
<p><a href="../../thanks-for-help.html#bisqwit">Joel Yliluoma</a> rendered:</p>
|
||
<ul>
|
||
<li><a href="endoh1-1024.png">1024x1024 image</a></li>
|
||
</ul>
|
||
<p>The above image was rendered between <strong>Wed Sep 10 21:21:22 UTC 2025</strong> and
|
||
<strong>Thu Sep 11 09:48:40 UTC 2025</strong> using 78 jobs in parallel on:</p>
|
||
<pre><code> CPU: AMD Ryzen Threadripper 3960X 24-Core Processor
|
||
48 threads
|
||
GCC 14.2.0-19 14.2.0
|
||
Debian Testing (currently Debian 14…ish?)
|
||
GNU Make 4.4.1</code></pre>
|
||
<h4 id="question">Question</h4>
|
||
<p><strong>QUESTION</strong>: Do you have the patience to build an even larger 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/endoh1-1024.png">endoh1-1024.png</a> - 1024x1024 image in PNG form</li>
|
||
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/endoh1/endoh1-2048.png">endoh1-2048.png</a> - 2048x2048 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 -->
|