release 0ab7db4c08fe cached
77 files
1.1 MB
286.0k tokens
389 symbols
1 requests
Download .txt
Showing preview only (1,123K chars total). Download the full file or copy to clipboard to get everything.
Repository: RayTracing/raytracing.github.io
Branch: release
Commit: 0ab7db4c08fe
Files: 77
Total size: 1.1 MB

Directory structure:
gitextract_58la6ck5/

├── .gitignore
├── CHANGELOG.md
├── CMakeLists.txt
├── CONTRIBUTING.md
├── COPYING.txt
├── PRINTING.md
├── README.md
├── books/
│   ├── RayTracingInOneWeekend.html
│   ├── RayTracingTheNextWeek.html
│   ├── RayTracingTheRestOfYourLife.html
│   └── acknowledgments.md.html
├── images/
│   ├── cover/
│   │   ├── CoverRTW1.psd
│   │   ├── CoverRTW2.psd
│   │   └── CoverRTW3.psd
│   └── test.ppm
├── index.html
├── src/
│   ├── InOneWeekend/
│   │   ├── camera.h
│   │   ├── color.h
│   │   ├── hittable.h
│   │   ├── hittable_list.h
│   │   ├── interval.h
│   │   ├── main.cc
│   │   ├── material.h
│   │   ├── ray.h
│   │   ├── rtweekend.h
│   │   ├── sphere.h
│   │   └── vec3.h
│   ├── TheNextWeek/
│   │   ├── aabb.h
│   │   ├── bvh.h
│   │   ├── camera.h
│   │   ├── color.h
│   │   ├── constant_medium.h
│   │   ├── hittable.h
│   │   ├── hittable_list.h
│   │   ├── interval.h
│   │   ├── main.cc
│   │   ├── material.h
│   │   ├── perlin.h
│   │   ├── quad.h
│   │   ├── ray.h
│   │   ├── rtw_stb_image.h
│   │   ├── rtweekend.h
│   │   ├── sphere.h
│   │   ├── texture.h
│   │   └── vec3.h
│   ├── TheRestOfYourLife/
│   │   ├── aabb.h
│   │   ├── bvh.h
│   │   ├── camera.h
│   │   ├── color.h
│   │   ├── constant_medium.h
│   │   ├── cos_cubed.cc
│   │   ├── cos_density.cc
│   │   ├── estimate_halfway.cc
│   │   ├── hittable.h
│   │   ├── hittable_list.h
│   │   ├── integrate_x_sq.cc
│   │   ├── interval.h
│   │   ├── main.cc
│   │   ├── material.h
│   │   ├── onb.h
│   │   ├── pdf.h
│   │   ├── perlin.h
│   │   ├── pi.cc
│   │   ├── quad.h
│   │   ├── ray.h
│   │   ├── rtw_stb_image.h
│   │   ├── rtweekend.h
│   │   ├── sphere.h
│   │   ├── sphere_importance.cc
│   │   ├── sphere_plot.cc
│   │   ├── texture.h
│   │   └── vec3.h
│   └── external/
│       ├── stb_image.h
│       └── stb_image_write.h
└── style/
    ├── book-highlight-test.css
    ├── book.css
    └── website.css

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Git Ignore Rules for raytracing.github.io

build/
/*.ppm


================================================
FILE: CHANGELOG.md
================================================
Change Log / Ray Tracing in One Weekend
====================================================================================================

# v4.0.2 (2025-04-24)

### Common
  - Fix    -- Fixed some dangling references to `random_in_unit_sphere()` (#1637)
  - Fix    -- Clarify `uniform_real_distribution` usage for `random_double()` (#1680)
  - Update -- CMake minimum required version max now at 4.0.0.

### In One Weekend
  - Fix    -- Fix equation for refracted rays of non-unit length (#1644)
  - Fix    -- Typo "trigonometric qualities" -> "trigonometric identities"

### The Rest of Your Life
  - Fix    -- Typo in equation in book 3, section 12.3 (#1686)


----------------------------------------------------------------------------------------------------
# v4.0.1 (2024-08-31)

### Common
  - Change -- Include hittable.h from material.h; drop `hit_record` forward declaration (#1609)
  - Change -- Refactor sphere to use ray representation for animate center (#1621)
  - Change -- All headers assume implicit rtweekend.h include (#1628)
  - Fix    -- Big improvement to print version listing font size (#1595) and more compact line
              height for code listings in both print and browser.
  - Fix    -- Slight improvement to `rotate_y::hit()` function (#1484)
  - Fix    -- Fixed possible bogus values from `random_unit_vector()` due to underflow (#1606)

### In One Weekend
  - Fix    -- Fixed usage of the term "unit cube" for a cube of diameter two (#1555, #1603)
  - Fix    -- Fixed broken highlighting on some code listings (#1600)

### The Next Week
  - Fix    -- Add missing ellipsis in listing 2.62 (#1612)

### The Rest of Your Life
  - Fix    -- Fix typo of "arbitrary" (#1589)
  - Fix    -- Fix X-axis label for figure 3.08 (Approximating the nonuniform f()) (#1532)
  - Fix    -- Corrected scatter angle theta range in section 3.5.3 (The Scattering PDF) (#1331)
  - Fix    -- Clarify the distinction between average and expected value (#1535)
  - New    -- Added a bit more explanation of Buffon's needle problem (#1529)


----------------------------------------------------------------------------------------------------
# v4.0.0 (2024-07-26)

From our last official v3.2.3 release (three and a half years ago!), this major release includes all
changes in the v4.0.0-alpha.1 and v4.0.0-alpha.2 releases, plus the changes listed immediately
below. Generally, this represents a large overhaul of all three books and their code, and will
require large changes to any code you've based on the prior v3.2.3 version. Going forward, we plan
to avoid such massive, long-running development branches, at the expense of more frequent minor and
major releases.

There's still a fair amount of work remaining on book three, which we'll work on after this release.

### Common
  - Change -- Use delegating constructors where helpful (#1489)
  - Change -- Standardized our use of `begin`/`end` standard C++ iterators (#1551)
  - Fix    -- CSS reformatting and fixes (#1567)
  - Fix    -- Add workaround for image and figure captions using latest Markdeep versions (#1583)
  - New    -- Add DOCTYPE declaration to all Markdeep documents (#1566)
  - New    -- Add explicit std:: namespacing almost everywhere (#1487)

### The Next Week
  - Delete -- Remove debug output code from `constant_medium::hit()` function (#1495)
  - Change -- Convert `perlin` class to use static arrays instead of dynamically allocated (#1483)
  - Fix    -- Workaround Markdeep issue for code listings with tag-like tokens (#1463)

### The Rest of Your Life
  - Change -- Simplified the `onb` class, and renamed or deleted functions (#1080)
  - Change -- Many small updates following walkthrough of book 3 (#988, #1317)
  - Change -- Use plain array for `estimate_halfway` program (#1523)
  - Change -- Refactored the ONB class to remove unused methods and generally simplify (#1088)
  - Change -- Use `ICD(d)` instead of `f(d)` for inverse cumulative distribution for clarity (#1537)
  - Fix    -- Add missing signature updates for `material::scatter()` functions
  - Fix    -- Avoid `hittable_list` of lights in book until code is ready (#1318)


----------------------------------------------------------------------------------------------------
# v4.0.0-alpha.2 (2024-04-07)

This alpha wraps up most of the major changes we expect to make to book 2 for the impending v4.0.0
release, along with a bunch of updates to the other two books. Since the alpha.1 release last
August, we've been lucky to have onboarded two new contributors: Arman Uguray and Nate Rupsis.
They've been helping out a ton with this release, and Arman is also developing his GPU Ray Tracing
book at the same time!

This release is a bit faster, thanks to some new BVH optimizations. We've eliminated the negative
radius sphere hack to model hollow spheres, instead accomplishing this with refraction indices. This
eliminates a bunch of places in the code where we had to accomodate this, and probably a bunch of
bugs we still haven't found. We now load texture images in linear color space, fixing a long-running
bug where we were gamma-correcting our textures twice -- you'll notice object texture maps look a
bit darker and less washed out. Refraction text has gotten a bit of an overhaul, and a better
example of total internal reflection. Of course, this also includes a load of small fixes, tweaks,
and improvements.

Our current plan is to get the final v4.0.0 release out the door by SIGGRAPH 2024, targeting July
28. With that, here are the latest changes since our alpha.1 release:

### Common
  - Delete -- Removed `rtw_stb_image.h` header from book 1 source, as it's unused there.
  - Change -- Increase compile warning levels for MSVC, and corrected newly-flagged code.
  - Change -- Default to using post-increment everywhere
  - Change -- We've removed the few cases where we used C++ default constructors. Instead, we either
              require all parameters, or use operator overloading to use default values.
  - Change -- For clarity across audiences with broad programming backgrounds, we now use
              `double(x)` instead of `static_cast<double>(x)`, and similarly for other types, for
              easier readability for non-C++ programmers.
  - Change -- The `ray` class constructors no longer use C++ default parameter values
  - Change -- Remove pixel sampling knowledge from `write_color()`. This simplifies `write_color()`
              to take only the desired output color, and made each phase in color computation easier
              to understand.
  - Change -- `ray::origin()` and `ray::direction()` getters now return const references, avoiding
              unnecessary copies.
  - Change -- Cleaned up the use of the `hit_record` class in `material.h`
  - Change -- All books now point to the project wiki instead of the in1weekend blog for further
              reading links.
  - Change -- New BVH optimization splits the bounds according to the longest bounding box
              dimension, yielding a 15-20% speedup (#1007)
  - Change -- Reversed the ray-sphere direction and calculations throughout equations and code for
              all books. This ended up simplifying equations and code in several places (#1191)
  - Change -- Pass `vec3`, `point3`, `ray`, and `color` parameters by const reference where
              possible (#1250)
  - Change -- Changed BVH construction (removed const qualifer for objects vector) so sorting is
              done in place, and copying of vector is avoided, yielding better BVH build performance
              (#1327, #1388, #1391)
  - Change -- Implement hollow spheres using refraction index instead of negative radii.
              Additionally, we now block negative radius spheres. This fixes a bunch of corner
              cases with inverted spheres (#1420)
  - Change -- Refactor pixel subsampling to make the sampling functions simpler and better focused
              in scope (#1421)
  - Change -- All constructor parameter names now match their member names if assigned directly. C++
              can handle this without ambiguity, and it means we don't have to come up with
              alternate names for everything (#1427)
  - Change -- `material::scatter()` gets a trivial default implementation (#1455)
  - Fix    -- Fixed section describing total internal reflection. It turns out that spheres with
              refraction index greater than the surrounding atmosphere cannot exhibit total internal
              reflection. Changed example to instead model a bubble of air in water, and updated the
              rendered images to match (#900)
  - Fix    -- Fix references from `random_in_hemisphere()` to `random_on_hemisphere()` (#1198)
  - Fix    -- The `linear_to_gamma()` function has been hardened against negative inputs (#1202)
  - Fix    -- Fixed default camera look-from and look-at values (#1341)
  - Fix    -- The `quad` bounding box now considers all four vertices instead of erroneously only
              using two (#1402)
  - New    -- Added PRINTING.md to give information about how to print these books to PDF or paper.
              We will also be including PDFs of each book with each new GitHub release going
              forward.

### In One Weekend
  - Change -- Update reference to "Fundamentals of Interactive Computer Graphics" to "Computer
              Graphics: Principles and Practice". This is the name used by newer editions of the
              book.
  - Change -- Updated the "Next Steps" section at the end of book 1 (#1209)
  - Change -- Update rtweekend.h header introduction and use (#1473)
  - Fix    -- Fix code listing ordering bug with `lambertian` texture support (#1258)
  - New    -- Improved help for the very first build and run.
  - New    -- Define albedo prior to first use (#1430)

### The Next Week
  - Change -- Lots of miscellaneous edits and clarifications to book two as we encountered them.
              This also includes various improvements to code listings to provide better context and
              address discrepancies between the listings and the actual source code.
  - Change -- `perlin::turb()` no longer defaults the value for the depth parameter.
  - Change -- AABB automatically pads to mininmum size for any dimension; no longer requires
              primitives to call aabb::pad() function.
  - Change -- Switch from ray = A + tb to ray = Q + td in AABB text.
  - Change -- Update checker scale to 0.32
  - Change -- Refactor AABB class. Renamed `aabb::axis()` to `aabb::axis_interval()`. Minor
              refactoring of `aabb::hit()` function. (#927, #1270)
  - Change -- Reworked the AABB chapter. Created skippable sections for planar coordinates
              derivation (#1236)
  - Fix    -- Updated book 2 images to match the latest code.
  - Fix    -- Images loaded for texture mapping are now converted from their original gamma to
              linear color space for use. Rendered images are still gamma corrected to 2.0 on
              output (#842)
  - Fix    -- Fix regression in calls to Perlin `turb()` functions with scaled points (these should
              be unscaled). (#1286)
  - New    -- Add section on alternative 2D primitives such as triangle, ellipse and annulus (#1204,
              #1205)

### The Rest of Your Life
  - Fix    -- Add missing backslash for LaTeX `operatorname` (#1311)
  - Fix    -- Fix LaTeX functions with underscore (#1330)


----------------------------------------------------------------------------------------------------
# v4.0.0-alpha.1 (2023-08-06)

It's been quite a while since our last release of v3.2.3 at the end of 2020. For this cycle, we've
tackled a load of significant backlog items, including rewrites of much of our underlying code. As
always, the primary idea isn't to provide the best or most optimal implementation, but instead to put
out simple, sometimes crude first approximations of the main components of writing a ray tracer.

Highlights include large rewrites and expansions of the book text, a large refactoring of our camera
class, folding `moving_sphere` functionality into `sphere`, adding a new `interval` class for use in
multiple contexts, creating a new general `quad` primitive to replace the old `*_rect` primitives,
and the addressing of hundreds of issues and requested features. The line-item changes below should
give you an idea of v4 includes.

In order to drive this release to resolution, we're releasing our alpha.1 version to coincide with
the start of SIGGRAPH 2023. We've pretty much finished with book one, though there's a fair amount
left for books two and three. Our plan is to keep crunching for a final v4.0.0 release by the end of
2023.

Since this is an alpha, we would greatly appreciate any feedback you might have. Let us know by
creating issues up on the GitHub project.

### Common
  - Delete -- `box`, `xy_rect`, `yz_rect`, `xz_rect` classes. These are replaced with new `quad`
              primitive (#292, #780, #681)
  - Change -- Use `class` instead of `struct` throughout for simpler C++ (#781)
  - Change -- Moved all class method definitions inside class definition (#802)
  - Change -- Class public/private access labels get consistent two-space indents (#782)
  - Change -- Updated classes to use private access for class-private variables (#869)
  - Change -- Made our code `inline` clean. We now use `inline` in all header function definitions
              to guard against copies in multiple C++ translation units (#803)
  - Change -- Retired the `src/common/` directory. Each book now has complete source in one
              directory
  - Change -- Significant rewrite and expansion of the `camera` class
  - Change -- `aabb` class constructor treats two params as extreme points in any orientation (#733)
  - Change -- `hittable:hit()` methods use new interval class for ray-t parameter
  - Change -- `interval::clamp()` replaces standalone `clamp` utility function
  - Change -- `aabb` class uses intervals for each axis (#796)
  - Change -- `hittable` member variable `ptr` renamed to `object`
  - Change -- General rename of `mat_ptr` to `mat` (material)
  - Change -- `hittable::bounding_box()` signature has changed to always return a value (#859)
  - Change -- Replaced random vector in `isotropic` with `random_unit_vector`
  - Change -- Use std::clog instead of std::cerr to log scanline progress (#935)
  - Change -- Updated figures throughout for improved clarity when possible
  - Change -- Generated images are now output gamma-corrected rather than in linear space
              (#980, #1033)
  - Change -- The `camera` class now handles images with width or height of one (#682, #1040)
  - Fix    -- CSS fix for cases where code listing overflows; change to fit content (#826)
  - Fix    -- Enabled compiler warnings for MSVC, Clang, GNU. Cleaned up warnings as fit (#865)
  - Fix    -- Remove redundant `virtual` keyword for methods with `override` (#805)
  - Fix    -- `rect` hit returning NaNs and infinities (#681)
  - Fix    -- Add `\mathit` to italic math variables to fix slight kerning issues in equations
              (#839)
  - Fix    -- Fixed issues in Bib(La)TeX entries.
  - New    -- Introduce new `interval` class used throughout codebase (#777)
  - New    -- `rtw_image` class for easier image data loading, better texture file search (#807)
  - New    -- 2D `quad` primitive of arbitrary orientation (#756)
  - New    -- `box()` utility function returns `hittable_list` of new `quad` primitives (#780)

### In One Weekend
  - Change -- Updated all rendered images in text
  - Change -- Significant update to the diffuse reflection section (#696, #992)
  - Change -- Updated and clarified text around ray generation and the camera model
  - New    -- More commentary about the choice between `double` and `float` (#752)
  - New    -- Software context around the shadow acne listing

### The Next Week
  - Delete -- The `moving_sphere` class is deprecated, and functionality moved to `sphere` (#1125)
  - Change -- Rearranged the texture-mapping presentation. The three types (solid, spatial, image)
              are now sequenced in that order, and the checker texture presented more explicitly as
              an illustration of a spatial texture.
  - Change -- Broad rewrite of time management for moving objects, primarily `camera` and
              `sphere`, but also impacting the API for `hittable::bounding_box()` (#799)
  - Change -- The `sphere` class now includes animation capability originally in `moving_sphere`
              (#1125)
  - Fix    -- Fixed `bvh_node` constructor definition signature (#872)
  - Fix    -- Fixed scaling for final Perlin noise texture (#896).
  - New    -- Add listing to use new `bvh_node` class in the `random_spheres` scene (#715).

### The Rest of Your Life
  - Fix    -- Added missing functionality for `isotropic` (#664)
  - Fix    -- Variable `direction` was used without being defined in listing 11 (#831)
  - Fix    -- Fixed uniform sampling (#934)


----------------------------------------------------------------------------------------------------
# v3.2.3 (2020-12-07)

### Common
  - Change -- Markdeep library URL updated to new location

### The Next Week
  - Fix    -- Correct parameter name typo for `bvh_node` constructor parameter `src_objects`


----------------------------------------------------------------------------------------------------
# v3.2.2 (2020-10-31)

### Common
  - Change -- Refactor `sphere::hit()` method to reuse common blocks of code.
  - Change -- Improved the explanation and calculation of sphere UV coordinates (#533)
  - Fix    -- Added `fmin` to book text for `cos_theta` of `refract` (#732)
  - Fix    -- Standardized naming for ray-t and time parameters (#746)
  - Fix    -- `random_unit_vector()` was incorrect (#697)
  - Fix    -- Synchronize text and copies of `hittable.h`
  - Fix    -- Synchronize copies of `hittable_list.h`, `material.h`, `sphere.h`

### In One Weekend
  - Change -- Wrote brief explanation waving away negative t values in initial normal sphere
  - Fix    -- Catch cases where `lambertian::scatter()` yields degenerate scatter rays (#619)
  - Fix    -- Syntax error in listing 58 (Dielectric material class with reflection) (#768)
  - Fix    -- Correct wording for ray traversal text (#766)

### The Next Week
  - Fix    -- Catch cases where `lambertian::scatter()` yields degenerate scatter rays (#619)

### The Rest of Your Life
  - Fix    -- Missing `override` keyword for `xz_rect::pdf_value()` and `xz_rect::random()` methods
              (#748)
  - Fix    -- Synchronize book and source for `cornell_box()` function.
  - Fix    -- Introduction of light code was introduced out of sequence (#738, #740)
  - Fix    -- `ray_color()` was creating a new light for every ray bounce (#759)


----------------------------------------------------------------------------------------------------
# v3.2.1 (2020-10-03)

### Common
  - Change -- Refactored dielectric class for clarity
  - Fix    -- Update local Markdeep library (for offline reading) to v1.11. The prior version had
              incorrect content (#712)
  - Fix    -- Image texture destructor should call `STBI_FREE` instead of delete (#734)

### In One Weekend
  - Delete -- Remove premature `cstdlib` include; not needed until we use `rand()` (#687)
  - Fix    -- Replace old anti-alias result image with before-and-after image (#679)
  - Fix    -- Listing 29: Added missing `rtweekend.h` include (#691)
  - Fix    -- Undefined `vup` variable in camera definition (#686)
  - Fix    -- Listing 51: Add missing `hittable.h`, `rtweekend.h` includes (#693)
  - Fix    -- Listing 59: ["Full glass material"] Diverged from source
  - Fix    -- Fix error in citation section (#721)
  - Fix    -- Listings 33, 39: Add  consistent function signature for `trilinear_interp` (#722)

### The Next Week
  - Delete -- Remove unused u,v,w variables in initial `perlin::noise()` function (#684)
  - Change -- `bvh_node` no longer reorders the source vector of scene objects; uses local copy
              instead (#701)
  - Fix    -- Listing  5: Neglected to add ray time for metal and dielectric materials (#133)
  - Fix    -- Listing 15: In `bvh.h`, add missing `hittable_list.h` include (#690)
  - Fix    -- Listing 33, 34, 38: Change implicit casts to explicit ones (#692)
  - Fix    -- Listing 40: Change `perlin.h` in the caption to `texture.h` (#698)
  - Fix    -- Listing 70: Add missing `bvh.h` (#694)
  - Fix    -- Listing 70 and `main.cc`: Change a fuzz value of a metal sphere to 1.0 which is the
              maximum value (#694)
  - Fix    -- Fix error in citation section (#721)

### The Rest of Your Life
  - Fix    -- Fix errors in citation section (#721)
  - Fix    -- Area equation in section 3.3 Constructing a PDF and nearby text (#735)
  - New    -- Listing 36: Add missing updates to dielectric class for updating specular in scatter
              record


----------------------------------------------------------------------------------------------------
# v3.2.0 (2020-07-18)

We're still chasing that elusive stable project state where we're mostly done with large changes,
yet we keep finding more and more to tweak and improve. Besides the usual batch of corrections and
small improvements, for this change we plodded through the complete code progression for both books
one and two (_In One Weekend_ and _The Next Week_). This caught a _lot_ of issues (to our dismay),
and allowed us to generate a complete set of new render images for both books, to catch up with all
of the changes we've been making. The end result is that readers should find a significantly better
agreement between the book and their code as they progress, and their renders should also generally
match.

Besides the new rendered images, we also much improved the image parameters, which were frequently
missing from the previous version, leaving readers to guess at their values, or go to the code to
try to figure out how we created some of the images. In general, our working renders are now 400
pixels wide, usually 16:9 aspect ratio. We now use an explicit aspect ratio and deduce the image
height and other camera values, so you can tweak your render size just by changing the image width
(instead of updating a bunch of dependent parameters).

One interesting late change we made was adding explicit C++ `override` labels to subclass methods.
We did this mostly to aid code readers, but were surprised to find that it actually caught a pretty
significant bug hiding in our code (see entry in common changes below).

You'll also see a new citation section at the end of the books, to encourage uniform citations out
in the world, making it easier for people to refer to and track these books.

As is typical, though we roughly follow [semantic versioning](https://semver.org/), we're
considering this release a minor change instead of a major one. It's a common reflex, because people
generally have a (misguided) aversion to bumping the major version a lot. We consider it minor
because most of the changes are quite local, some classes get new constructors and any variances
should be quite simple and easy to fix up. Still, one might consider this more properly a major
version bump.

For our next larger-than-patch release, we're beginning a large revisit of book 3,
_Ray Tracing: The Rest of Your Life_. There's a lot of work to do, and this will likely be a
significant change and improvement. We're hoping that changes to books one and two will be small,
but that's never worked out for us before. Ah, dreams.

### Common
  - Delete -- Vestigial `vec3::write_color()` method (now in color.h)
  - Change -- All images and figures renamed to follow more logical convention, using the following
              pattern: `{fig,img}-<book>.<sequence>-<title>.<filetype>` (#495)
  - Change -- `main()` function gets organized into image, world, camera, and render chunks
  - Change -- Added header guards to the text of all three books whenever a new header file was
              introduced, consistent with source code (#645)
  - Change -- Added `override` keywords throughout. This keyword marks a subclass method as one that
              is intended to override a superclass method. It makes the code a bit easier to
              understand, and ensures that your function is actually overriding the method you think
              it is. Which is good, because it already caught an existing bug in _The Rest of Your
              Life_ source. This change includes commenting out the book 3 `isotropic::scatter()`
              method, which was accidentally ignored anyway. (#639, #669)
  - Fix    -- Found a bug in book 3 source `isotropic::scatter()` method. Commented out, using
              default (as it was previously). (#669)
  - New    -- Added constructors that take `color` arguments in addition to the constructors
              taking `shared_ptr<texture>` arguments, simplifying calling code. Applies to
              `checker_texture`, `constant_medium`, `diffuse_light`, `lambertian`, and `isotropic`
              (#516, #644)
  - New    -- Each book gets a section of recommended citation examples (#500)

### In One Weekend
  - Change -- Updated all rendered images except for 1.13, 1.14 (#179, #547, #548, #549, #550, #551,
              #552, #553, #554, #555, #556, #557, #560, #561, #562, #563, #564, #565, #566)
  - Change -- Standard working render width changed to 400 pixels
  - Change -- Image 6 is now a before-and-after pair to illustrate antialiasing
  - Change -- Listing 48: Refactored material and geometry declarations
  - Change -- Listing 52: Refactored assignment of `etai_over_etat`
  - Change -- Listing 56: Refactored material declarations
  - Change -- Listing 61: Refactored material and geometry declarations
  - Fix    -- Corrected various missed change highlights in code listings
  - Fix    -- Listing 7: Added missing `color.h`, `vec3.h` includes
  - Fix    -- Listing 18: Add missing `double t` member of struct `hit_record` (#428)
  - Fix    -- Listing 24: Add missing `color.h` include
  - Fix    -- Listing 30: Add missing `camera.h` include
  - Fix    -- Listing 42: Don't need to include `ray.h` when using `rtweekend.h`
  - Fix    -- Listing 48: Add missing `material.h` include
  - Fix    -- Listing 51: `refract()` function was missing `fabs()` on `sqrt()` argument (#559)
  - Fix    -- Listing 61: Include updated `cam` declaration, show context w/highlighting
  - Fix    -- Listing 62: Highlight rename of `camera::get_ray()` parameters to s, t (#616)
  - Fix    -- Listing 63: Show reverted scene declarations
  - Fix    -- Listing 68: Show final scene render parameters with highlighting
  - Fix    -- Rewrote refracted ray perpendicular and parallel components for correctness (#526)
  - New    -- Listing 50: Show the updated material definitions

### The Next Week
  - Delete -- Deleted the section covering the old `flip_face` class, renumbered images as this
              eliminated the rendering with missing Cornell box faces (#270, #482, #661)
  - Delete -- Scenes 7 & 9 from the original (`cornell_balls` and `cornell_final`), as these were
              not covered in the book. Made the source and book consistent with each other. There
              are now a total of eight scenes for the second book (#653, #620)
  - Change -- Listing 10: Separate out world & camera definitions in main (#646)
  - Change -- Updated most rendered images for book 2: 2.01-2.03, 2.07-2.13, 2.15-2.22.
  - Change -- Scenes get custom image parameters (#650)
  - Fix    -- Reduced code duplication in `dielectric::scatter()` function
  - Fix    -- "Intance" typo in Chapter 8.1 to "Instance" (#629)
  - Fix    -- Listing 7: Show reverted viewing parameters from book 1 final scene
  - Fix    -- Typo in listing caption for filename `moving-sphere.h`

### The Rest of Your Life
  - Change -- Use `vup` for camera, as in other two books
  - Fix    -- World and camera setup in `main()`, and include full body in book listing (#646)
  - New    -- `flip_face` moved to book 3, where it's needed for the light source (#661)


----------------------------------------------------------------------------------------------------
# v3.1.2 (2020-06-03)

### In One Weekend
  - Fix    -- Correct typo: "Intance Translation" -> "Instance Translation"
  - Fix    -- Corrected geometry type when computing distance between two points, final scene (#609)

### The Rest of Your Life
  - Fix    -- Missing closing parenthesis in listing 10 (#603)
  - Fix    -- Tiny improvements to the lambertian::scatter() development (#604)
  - Fix    -- Correct geometry type and unit vector method in `ray_color()`, listing 20 (#606)
  - Fix    -- Listing 26: alternate `random_double()` switched `distribution`, `generator` (#621)
  - Fix    -- Listing 28, 30: `light_shape` should have default material, not `0` (#607)
  - Fix    -- Listing 30: `mixture_pdf` needs `shared_ptr` arguments (#608)


----------------------------------------------------------------------------------------------------
# v3.1.1 (2020-05-16)

### Common
  - Change -- Camera code improvements to make it more robust when any particular value changes.
              Also, the code develops in a smoother series of iterations as the book progresses.
              (#536)
  - Fix    -- Refactoring the camera code in v3.1.0 missed updating the viewport to match, resulting
              in distorted renders (#536)

### In One Weekend
  - Change -- The C++ `<random>` version of `random_double()` no longer depends on `<functional>`
              header.
  - Change -- Refactored `random_scene()`. More named intermediate values, sync'ed with source.
              (#489)
  - Fix    -- Camera initialization with explicit up vector (#537)
  - Fix    -- Changed some text around the camera model and the camera defocus blur model (#536)

### The Next Week
  - Change -- Refactored `random_scene()`. Added more named intermediate values, sync'ed with
              version in _In One Weekend_ and with source. Added highlight for update from last
              version in book 1. (#489)
  - Change -- The C++ `<random>` version of `random_double()` no longer depends on `<functional>`
              header.
  - Fix    -- Added clarification about updating lambertian variables from `color` to `solid_color`.
  - Fix    -- Corrected for-loop indices (they differed from the version in book 1) in
              `random_scene()`.
  - Fix    -- Introduce "Texture Coordinates for Spheres" in Chapter 4 to support (u,v) coordinates
              in `hit_record` (#496)
  - Fix    -- Small correction: we now use `std::sort` instead of `qsort` (#490)


----------------------------------------------------------------------------------------------------
# v3.1.0 (2020-05-03)

This minor upgrade adds some fixes and changes that are a bit more than just patches. The text now
has subchapter headings to help readers browse content and get a bit more context. We're introducing
new type aliases `point3` and `color` for `vec3` to better indicate the underlying mathematical
types of parameters and variables. Overall, a bunch of small improvements that we'd recommend
adopting, but may warrant comparison with any current projects.

### Common
  - Change -- Minor change to use new `point3` and `color` type aliases for `vec3` (#422)
  - Change -- Renamed `constant_texture` to `solid_color`, add RGB constructor (#452)
  - Change -- Moved `vec3::write_color()` method to utility function in `color.h` header (#502)
  - Change -- Switch from `ffmin`/`ffmax` to standard `fmin`/`fmax` (#444, #491)
  - Change -- Math notation to bold uppercase points, bold lowercase no-barb vectors (#412)
  - Change -- Books use Markdeep's image class=pixel for rendered image fidelity (#498)
  - Fix    -- Include cmath in vec3.h (#501)
  - Fix    -- Scattered improvements to the text
  - New    -- Subchapters throughout all three books (#267)
  - New    -- Add explanation for padding `aarect` in the zero dimension (#488)

### In One Weekend
  - Change -- Define image aspect ratio up front, then image height from that and the image width
  - Change -- Default image sizes changed from 200x100 to 384x216
  - Change -- First image size changed to 256x256
  - Fix    -- Improve image size and aspect ratio calculation to make size changes easier
  - Fix    -- Added `t` parameter back into `hit_record` at correct place
  - Fix    -- Image basic vectors off by one
  - Fix    -- Update image and size for first PPM image
  - Fix    -- Update image and size for blue-to-white gradient image
  - Fix    -- Update image and size for simple red sphere render
  - Fix    -- Update image and size for sphere with normal-vector coloring
  - Fix    -- Correct typo in "What's next?" list to rejoin split paragraph on "Lights." Adjust
              numbering in rest of list.

### The Next Week
  - Change -- Large rewrite of the `image_texture` class. Now handles image loading too. (#434)


----------------------------------------------------------------------------------------------------
# v3.0.2 (2020-04-11)

### Common
  - Change -- Every book source now includes from a single common acknowledgments document
  - Fix    -- Code styling for source code both inline and in fenced blocks (#430)

### In One Weekend
  - Fix    -- Correct typo: "consine" to "cosine"

### The Next Week
  - Fix    -- `shared_ptr` dereference and simplify code in `hittable_list::bounding_box()` (#435)
  - Fix    -- Erroneous en-dash in code block. Replace `–>` with `->` (#439)
  - Fix    -- Introduce `u`,`v` surface coordinates to `hit_record` (#441)
  - Fix    -- Add highlight to new `hittable::bounding_box()` method (#442)

### The Rest of Your Life
  - Fix    -- Unitialized variable in first version of `integrate_x_sq.cc`
  - Fix    -- Remove unreferenced variables in several sample programs
  - Fix    -- Correct program computation of the integral of x^2 (#438)


----------------------------------------------------------------------------------------------------
# v3.0.1 (2020-03-31)

### Common
  - Delete -- Delete old README files specific to each book (#410)
  - Fix    -- Display rendered images as pixelated instead of smoothed (#179)

### In One Weekend
  - Fix    -- Remove duplicated text and reword on the camera up vector (#420)


----------------------------------------------------------------------------------------------------
# v3.0.0 (2020-03-23)

With the migration to a web format accomplished in v2.0.0, we immediately began work on a new major
release: v3.0.0. This release tackles the following key themes:

  - Establishing a common build system for the three projects. We chose CMake for its broad support
    for multiple platforms, as well as multiple build tools and IDEs. This change includes a
    reorganization of the project source files, and unifying a lot of code across projects.

  - A major upgrade of the project source code, addressing a number of large changes that we had
    deferred for later.

  - A number of larger changes to the book content, refining some approaches and ideas, and
    addressing some areas in the text that needed improvement.

Following this release, we expect to switch to a much more incremental approach, mostly with
patch-level (fix) changes and some minor-level (addition) changes.

### Common to All Project Source
  - Change -- Default floating-point type changed from `float` to `double` (#150)
  - Change -- Materials are now referenced with `std::shared_ptr` pointers
  - Change -- Complete elimination of bare pointers and `new`/`delete`
  - Change -- `hittable_list` uses `std::vector` plus `std::shared_ptr` pointers
  - Change -- Header cleanup across the source code (#218, #220)
  - Change -- Cleaned up standard C++ header use (#19)
  - Change -- Improved random number generator utilities
  - Change -- Replace MAXFLOAT with (portable) infinity (#195, #216)
  - Change -- A _lot_ of code cleanup, refactoring, renaming (#192)
  - Change -- Disable compile warnings for external `stb_image.h` on Windows
  - Change -- Replace pi with portable version (#207)
  - Change -- `ray_color()` function now has max depth passed in, rather than hard-coding it (#143)
  - Change -- Added `random_in_unit_sphere()`, `random_unit_vector()`, `random_in_hemisphere()` to
              vec3.h. Fixed places where we were using one but should have been using another.
              (#145)
  - Change -- General rework of the `vec3` header (#153, #156, #215)
  - Change -- Clarify sphere intersection code, plus slight perf improvement (#113)
  - Change -- `ray::point_at_parameter()` renamed to `ray::at()`
  - Change -- Moved `ffmin()`, `ffmax()` from `aabb.h` to `rtweekend.h`
  - Change -- Move low-level utility functions to more appropriate headers
  - Change -- `squared_length()` renamed to `length_squared()`
  - Change -- Update `sphere::hit()` function.
  - Change -- Refraction variables renamed to match reflection variable names
  - Change -- Simplify lambertian scatter direction calculation
  - Fix    -- Diffuse PDF computation uses random point _on_ sphere, rather than _inside_
  - Fix    -- Improve color [0,1] -> [0,255] mapping
  - New    -- CMake configuration & build
  - New    -- Added progress output for main programs (#139)
  - New    -- `src/common` directory for code shared across books
  - New    -- Common project-wide header: `src/common/rtweekend.h`
  - New    -- File constants.h with portable math constants (#151)
  - New    -- `vec3::write_color` - provides a robust output method for color data (#93)
  - New    -- `degrees_to_radians()` utility function (#217)
  - New    -- `random_int()`, `random_double()`, and `vec3::random()` utility functions
  - New    -- Added safety value when surface texture has null data
  - New    -- Main programs now define and handle parameterized background color

### Common to All Books
  - Change -- Code in source and in book reformatted to a consistent 96-column line length (#219)
  - Change -- Lots more highlighting of changed code in books to aid reading
  - Change -- Math typesetting fixes throughout the books (#13)
  - Change -- Books now use Markdeep's chapter indirection syntax
  - Change -- Updated several output images to match code updates
  - Change -- Books general styling improvements (#197)
  - Change -- Refactored acknowledgements. These are now moved to and duplicated in each book
  - Fix    -- Fixed various minor problems in the text
  - New    -- Added code listing captions, including source file name, for all books (#238)
  - New    -- Added captions to all figures (#238)
  - New    -- Local copy of `markdeep.min.js` for offline reading

### In One Weekend
  - Change -- Reworked Lambertian reflection text (#155)
  - Change -- Revised the figure for computing a random reflection vector (#142)
  - Fix    -- Update `ray_color()` code blocks to match current source (#391)
  - New    -- Clarified text around the ideal Lambertian distribution (#155)
  - New    -- Additional explanatory text to the dielectric chapter
  - New    -- Image for hemispherical rendering
  - New    -- Image for dealing with front and back faces (#326)

### The Next Week
  - Change -- Added proper handling of front vs back face intersection (#270)
  - Fix    -- Fixed bug in `noise_texture::value()` (#396)
  - Fix    -- Correct first Perlin noise() function in "The Next Week".
  - Fix    -- Fix OCR error in `texture::value()` function (#399)
  - Fix    -- Remove premature declaration of `moving_sphere::bounding_box()` (#405)
  - New    -- "The Next Week" main program added swtich statement for different scenes
  - New    -- "The Next Week" main program now defines all image/camera parameters for each scene

### The Rest of Your Life
  - Delete -- Several unused source files from `src/TheRestOfYourLife`
  - Change -- Improved naming of auxilliary programs in _The Rest of Your Life_ source
  - Fix    -- Delete unused variable `p` in main() (#317)


----------------------------------------------------------------------------------------------------
# v2.0.0 (2019-10-07)

This major release marks an overhaul of the entire series, moving from a primarily PDF format to a
web accessible format using Markdeep (https://casual-effects.com/markdeep/). This represents a huge
overhaul to the contents, particularly around source code blocks in the text, mathematical
typesetting and source-code cleanup.

### Common
  - Delete -- Deprecated existing _InOneWeekend_, _TheNextWeek_, _TheRestOfYourLife_ repos
  - Change -- Moved existing _InOneWeekend_, _TheNextWeek_, _TheRestOfYourLife_ content to io repo
  - Change -- Rewrote vec3.h `cross` function for clarity
  - Fix    -- All instances of `hitable` have become `hittable`
  - Fix    -- Replaced `drand48()` with portable `random_double` number generation
  - New    -- General release to web
  - New    -- Created single monolithic raytracing.github.io repo
  - New    -- License change to CC0 in COPYING.txt
  - New    -- CHANGELOG.md
  - New    -- CONTRIBUTING.md
  - New    -- COPYING.txt
  - New    -- README.md
  - New    -- Raytracing.github.io links to all the three books
  - New    -- CSS for all books
  - New    -- CSS for the print variant of the books

### In One Weekend
  - Delete -- Code, `vec3 p = r.point_at_parameter(2.0);` in main.cc
  - Change -- README files updated for top level, source, and books
  - Change -- Text, Chapter 0 Overview has become Chapter 1, all subsequent chapters incremented
  - Change -- Text, Syntax highlighting of source modifications
  - Change -- Text, Chapter 3, Reorder include files in code blocks to match src conventions
  - Change -- Text, Chapter 3, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 3, Reordered `vec3` class functions to + - * /
  - Change -- Text, Chapter 4, Reorder include files in code blocks to match src conventions
  - Change -- Text, Chapter 6, Reorder include files in code blocks to match src conventions
  - Change -- Text, Chapter 6, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 7, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 9, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 9, Put function signatures and `{` on the same line
  - Change -- Text, Chapter 10, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 10, Put function signatures and `{` on the same line
  - Change -- Text, Chapter 11, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 13, Put function signatures and `{` on the same line
  - Fix    -- Text, Chapter 7, Add `#include "random.h"` in code blocks
  - Fix    -- Text, Chapter 10, Added metal fuzziness parameter for initial dielectric
  - Fix    -- Text, Chapter 13, Added metal fuzziness parameter
  - Fix    -- Code, Removed extraneous `;` from `vec3::&operator[]` signature
  - New    -- Markdeep page created for entire body of text
  - New    -- Markdeep MathJax for formulae and equations for body of text
  - New    -- Raytracing.github.io/books/RayTracingInOneWeekend.html

### The Next Week
  - Change -- Text, Chapter 0 Overview has become Chapter 1, all subsequent chapters incremented
  - Change -- Text, Syntax highlighting of source modifications
  - Change -- Text, Chapter 2, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 3, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 4, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 5, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 5, added "texture" to "We can use that texture on some spheres"
  - Change -- Text, Chapter 7, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 7, "This is yz and xz" changed to "This is xz and yz"
  - Change -- Text, Chapter 8, Changed "And the changes to Cornell is" to "... Cornell are"
  - Change -- Text, Chapter 9, Changed short `if` statements to two lines for Consistency
  - Change -- Text, Chapter 10, Consistent use of spaces in code blocks
  - Change -- Code and Text, Chapter 9, cleaned up implementation of `constant_medium::hit`
  - Change -- Code and Text, Chapter 9, Rewrote debug functionality in `constant_medium::hit`
  - Fix    -- Text, Chapter 2, The `lambertian` class definition now uses `vec3` instead of `texture`
  - Fix    -- Text, Chapter 7, Changed `cornell_box` hittable array size to 5
  - Fix    -- Code and Text, Chapter 3, Changed `List[0]` to `List[i]` in
          `hittable_list::bounding_box()`.
  - Fix    -- Code and Text, Chapter 3, Replaced `fmax` and `fmin` with `ffmax` and `ffmin`
  - Fix    -- Code, Add missing headers to `constant_medium.h` to fix g++ compiler error
  - New    -- Raytracing.github.io/books/RayTracingTheNextWeek.html
  - New    -- README.md, source README.md
  - New    -- Markdeep page created for entire body of text
  - New    -- Markdeep MathJax created for formulae and equations for body of text
  - New    -- Earth map picture for use in rendering

### The Rest of Your Life
  - Change -- Text, Chapter 0 Overview has become Chapter 1, all subsequent chapters incremented
  - Change -- Text, Syntax highlighting of source modifications
  - Change -- Text, Chapter 2, Reorder include files in code blocks to match src conventions
  - Change -- Text, Chapter 3, Reorder include files in code blocks to match src conventions
  - Change -- Text, Chapter 6, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 6, Consistent use of spaces in code blocks
  - Change -- Text, Chapter 8, Changed calculation of `a` axis to pseudocode
  - Change -- Text, Chapter 8, Consistent use of spaces in code blocks
  - Fix    -- Text, Chapter order starting from chapter 2
  - Fix    -- Text, Renamed figures and images to match new chapter numbering
  - Fix    -- Text, Chapter 4, Rewrote formula for "Color" to "Color = A * color(direction"
  - Fix    -- Code and Text, Chapter 6, `material::scattering_pdf` now returns type float
  - Fix    -- Code and Text, Chapter 6, removal of factor of 2 to `random_cosine_direction`
              calculation
  - New    -- Raytracing.github.io/books/RayTracingTheRestOfYourLife.html
  - New    -- README.md, source README.md
  - New    -- Markdeep page created for entire body of text
  - New    -- Markdeep MathJax created for formulae and equations for body of text


----------------------------------------------------------------------------------------------------
# v1.123.0  (2018-08-26)

  - New    -- First GitHub release of _Ray Tracing: The Rest of Your Life_.


----------------------------------------------------------------------------------------------------
# v1.54.0  (2018-08-26)

  - New    -- First GitHub release of _Ray Tracing in One Weekend_.


----------------------------------------------------------------------------------------------------
# v1.42.0  (2018-08-26)

  - New    -- First GitHub release of _Ray Tracing: The Next Week_.


================================================
FILE: CMakeLists.txt
================================================
#---------------------------------------------------------------------------------------------------
# CMake Build Configuration for the Ray Tracing Weekend Series
#
# See README.md for guidance.
#---------------------------------------------------------------------------------------------------

cmake_minimum_required ( VERSION 3.1.0...4.0.0 )

project ( RTWeekend LANGUAGES CXX )

# Set to C++11
set ( CMAKE_CXX_STANDARD          11 )
set ( CMAKE_CXX_STANDARD_REQUIRED ON )
set ( CMAKE_CXX_EXTENSIONS        OFF )

# Source

set ( EXTERNAL
  src/external/stb_image.h
)

set ( SOURCE_ONE_WEEKEND
  src/InOneWeekend/main.cc
  src/InOneWeekend/camera.h
  src/InOneWeekend/color.h
  src/InOneWeekend/hittable.h
  src/InOneWeekend/hittable_list.h
  src/InOneWeekend/interval.h
  src/InOneWeekend/material.h
  src/InOneWeekend/ray.h
  src/InOneWeekend/rtweekend.h
  src/InOneWeekend/sphere.h
  src/InOneWeekend/vec3.h
)

set ( SOURCE_NEXT_WEEK
  src/TheNextWeek/main.cc
  src/TheNextWeek/aabb.h
  src/TheNextWeek/bvh.h
  src/TheNextWeek/camera.h
  src/TheNextWeek/color.h
  src/TheNextWeek/constant_medium.h
  src/TheNextWeek/hittable.h
  src/TheNextWeek/hittable_list.h
  src/TheNextWeek/interval.h
  src/TheNextWeek/material.h
  src/TheNextWeek/perlin.h
  src/TheNextWeek/quad.h
  src/TheNextWeek/ray.h
  src/TheNextWeek/rtw_stb_image.h
  src/TheNextWeek/rtweekend.h
  src/TheNextWeek/sphere.h
  src/TheNextWeek/texture.h
  src/TheNextWeek/vec3.h
)

set ( SOURCE_REST_OF_YOUR_LIFE
  src/TheRestOfYourLife/main.cc
  src/TheRestOfYourLife/aabb.h
  src/TheRestOfYourLife/camera.h
  src/TheRestOfYourLife/color.h
  src/TheRestOfYourLife/constant_medium.h
  src/TheRestOfYourLife/hittable.h
  src/TheRestOfYourLife/hittable_list.h
  src/TheRestOfYourLife/interval.h
  src/TheRestOfYourLife/material.h
  src/TheRestOfYourLife/onb.h
  src/TheRestOfYourLife/pdf.h
  src/TheRestOfYourLife/perlin.h
  src/TheRestOfYourLife/quad.h
  src/TheRestOfYourLife/ray.h
  src/TheRestOfYourLife/rtw_stb_image.h
  src/TheRestOfYourLife/rtweekend.h
  src/TheRestOfYourLife/sphere.h
  src/TheRestOfYourLife/texture.h
  src/TheRestOfYourLife/vec3.h
)

include_directories(src)

# Specific compiler flags below. We're not going to add options for all possible compilers, but if
# you're new to CMake (like we are), the following may be a helpful example if you're using a
# different compiler or want to set different compiler options.

message (STATUS "Compiler ID: " ${CMAKE_CXX_COMPILER_ID})
message (STATUS "Release flags: " ${CMAKE_CXX_FLAGS_RELEASE})
message (STATUS "Debug flags: " ${CMAKE_CXX_FLAGS_DEBUG})

if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    # /wd #### - Disable warning
    # /we #### - treat warning as error
    add_compile_options("/W4")      # Enable level-4 warnings
    add_compile_options("/we 4265") # Class has virtual functions, but its non-trivial destructor is not virtual
    add_compile_options("/we 5204") # Class has virtual functions, but its trivial destructor is not virtual
    add_compile_options("/wd 4100") # unreferenced formal parameter
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    add_compile_options(-Wnon-virtual-dtor) # Class has virtual functions, but its destructor is not virtual
    add_compile_options(-Wreorder) # Data member will be initialized after [other] data member
    add_compile_options(-Wmaybe-uninitialized) # Variable improperly initialized
    add_compile_options(-Wunused-variable) # Variable is defined but unused
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    add_compile_options(-Wnon-virtual-dtor) # Class has virtual functions, but its destructor is not virtual
    add_compile_options(-Wreorder) # Data member will be initialized after [other] data member
    add_compile_options(-Wsometimes-uninitialized) # Variable improperly initialized
    add_compile_options(-Wunused-variable) # Variable is defined but unused
endif()

# Executables
add_executable(inOneWeekend      ${EXTERNAL} ${SOURCE_ONE_WEEKEND})
add_executable(theNextWeek       ${EXTERNAL} ${SOURCE_NEXT_WEEK})
add_executable(theRestOfYourLife ${EXTERNAL} ${SOURCE_REST_OF_YOUR_LIFE})
add_executable(cos_cubed         src/TheRestOfYourLife/cos_cubed.cc         )
add_executable(cos_density       src/TheRestOfYourLife/cos_density.cc       )
add_executable(integrate_x_sq    src/TheRestOfYourLife/integrate_x_sq.cc    )
add_executable(pi                src/TheRestOfYourLife/pi.cc                )
add_executable(estimate_halfway  src/TheRestOfYourLife/estimate_halfway.cc  )
add_executable(sphere_importance src/TheRestOfYourLife/sphere_importance.cc )
add_executable(sphere_plot       src/TheRestOfYourLife/sphere_plot.cc       )


================================================
FILE: CONTRIBUTING.md
================================================
Contributing To The Ray Tracing in One Weekend Series
====================================================================================================

The _Ray Tracing in One Weekend_ series is intended to be lightweight and accessible for all who
want to learn about ray tracing and related graphics topics. To that end, we welcome feedback,
proposals, and improvements.

In particular, we are now a dedicated GitHub organization. The books are now available in HTML from
https://raytracing.github.io/, so we can keep the content up-to-date with the latest corrections and
improvements.


Development Branches
---------------------
We use `release` as our release branch. _Generally, changes should never go directly to the release
branch_. All ongoing development work (and all of the latest changes) will be in the `dev-patch`,
`dev-minor`, `dev-major`, or feature branches. The appropriate target branch for any pull requests
you want to make will be determined in the associated issue first (all pull requests should have an
associated issue).


Issues
-------
The easiest way to help out is to log any issues you find in the books. Unclear passages, errors of
all kinds, even better ways to present something -- just go to the [issues page][].

1. First ensure that the issue is still outstanding (check `dev-patch`, `dev-minor` or `dev-major`
   as appropriate). Often the issue has already been addressed or no longer applies to the latest
   in-development version. Admittedly, that's a bit of a hassle, but at least step two should help
   you avoid duplicate issues.

2. **Before creating a new issue**, please review existing issues to see if someone has already
   submitted the same one. Chances are you're not the first to encounter something, so a little
   quick research can save everyone some hassle. If you have new information, please continue the
   thread in the existing issue.

3. When entering a new issue, please include all relevant information. For content issues, include
   the book or books this applies to, and specific locations that should be reviewed. Similarly for
   code: please include the file, function/class, and line number(s) if that applies.

4. Finally, _please keep issues focused on a single problem or suggestion_. If discussion prompts
   you to think of a related issue, create a separate issue for that topic and add a link back to
   the original discussion or issue (just use the "#NNN" syntax for issue/discussion/pull-request
   NNN -- GitHub will automatically make this a link).


Pull Requests
--------------
To contribute a change to the project, *please follow these steps*:

  1. [Create a new GitHub issue](https://github.com/RayTracing/raytracing.github.io/issues).

  2. Let us know if you're willing to make the fix yourself.

  3. Participate in the discussion as needed. We'll ensure that the work doesn't conflict with or
     duplicate other work planned or in progress, and decide which development branch is correct
     for the release type and release schedule.

  4. Once you've received instructions to proceed with your change, create a new feature branch (or
     fork) from the assigned development branch (usually `dev-patch`, `dev-minor`, or `dev-major`).

  5. Follow the existing code style.

  6. Ensure that the change is complete:

     - Update all relevant source code for all three books (`src/*`). Since the code is developed as
       the books proceed, you may need to update many historical code listings as well, _and this
       may require corresponding updates to the book text_.

     - Update all relevant code listings and text in all three books (`books/RayTracing*.html`).
       Follow existing style for the Markdeep source (for example, text should be wrapped to 100
       characters).

     - Provide clear and full commit descriptions: title line (50 characters max), followed by a
       blank line, and then a descriptive body with lines not exceeding 72 characters. If a commit
       is expected to completely resolve an outstanding issue, add a line "Resolves #NNN" to the
       bottom of your commit message, where NNN is the existing GitHub issue number. You may provide
       multiple such lines if applicable.

     - Include a one-line summary change at the bottom of the current development section in the
       changelog (`CHANGELOG.md`). Include a reference to the associated GitHub issue.

     - For an example of the above, see
       [issue #1262](https://github.com/RayTracing/raytracing.github.io/issues/1262) and
       [PR #1263](https://github.com/RayTracing/raytracing.github.io/pull/1263).

  7. When ready, create your pull request (PR) and request a review from "RayTracing/reviewers".

  8. Congratulate yourself for having been part of the 1% of contributors who actually read and
     followed these guidelines.

Note the code philosophy outlined in the first section of the first book. In short, the code is
intended to be clear for everyone, using simple C/C++ idioms as much as possible. We have chosen to
adopt _some_ modern conventions where we feel it makes the code more accessible to non-C++
programmers. Please follow the existing coding style and simplicity when offering your suggested
changes.

If anything above sounds daunting, note that you'll get _**massive**_ credit for actually reading
the CONTRIBUTING.md and following the process above -- so we'd be delighted to answer any questions
and guide you through the process.


Questions
----------
If you have any questions, feel free to ping me at steve@hollasch.net.



[issues page]: https://github.com/RayTracing/raytracing.github.io/issues/


================================================
FILE: COPYING.txt
================================================
Creative Commons Legal Code

CC0 1.0 Universal

    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
    HEREUNDER.

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.

For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:

  i. the right to reproduce, adapt, distribute, perform, display,
     communicate, and translate a Work;
 ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
     likeness depicted in a Work;
 iv. rights protecting against unfair competition in regards to a Work,
     subject to the limitations in paragraph 4(a), below;
  v. rights protecting the extraction, dissemination, use and reuse of data
     in a Work;
 vi. database rights (such as those arising under Directive 96/9/EC of the
     European Parliament and of the Council of 11 March 1996 on the legal
     protection of databases, and under any national implementation
     thereof, including any amended or successor version of such
     directive); and
vii. other similar, equivalent or corresponding rights throughout the
     world based on applicable law or treaty, and any national
     implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.

4. Limitations and Disclaimers.

 a. No trademark or patent rights held by Affirmer are waived, abandoned,
    surrendered, licensed or otherwise affected by this document.
 b. Affirmer offers the Work as-is and makes no representations or
    warranties of any kind concerning the Work, express, implied,
    statutory or otherwise, including without limitation warranties of
    title, merchantability, fitness for a particular purpose, non
    infringement, or the absence of latent or other defects, accuracy, or
    the present or absence of errors, whether or not discoverable, all to
    the greatest extent permissible under applicable law.
 c. Affirmer disclaims responsibility for clearing rights of other persons
    that may apply to the Work or any use thereof, including without
    limitation any person's Copyright and Related Rights in the Work.
    Further, Affirmer disclaims responsibility for obtaining any necessary
    consents, permissions or other rights required for any use of the
    Work.
 d. Affirmer understands and acknowledges that Creative Commons is not a
    party to this document and has no duty or obligation with respect to
    this CC0 or use of the Work.


================================================
FILE: PRINTING.md
================================================
Printing These Books
====================================================================================================

These books have been formatted to be print friendly (using CSS media queries). That means that you
should be able to print them directly from your browser of choice (usually Ctrl-P on Windows and
Linux, or Cmd-P on Mac).

We've taken some care to set up sensible page breaks in the printed versions, though you still may
find a few odd artifacts here and there. For example, the latest version of Markdeep can let
images/figures and their captions land on different pages. This issue has been reported, and there
may be a fix in the works for this.


Pre-Printed Books
------------------
I've gone back and created PDFs for each book for versions since v2.0.0. You can find
these in the assets section of each release on the [GitHub releases page][releases]. We will include
PDFs for all books with all future releases.


Creating PDFs of These Books
-----------------------------
If you wish to create your own PDF of any of these books (like for a version currently in
development, or to test the results on your own changes), the easiest way is to use a save-to-PDF
print driver. When viewing a book in your browser, issue your browser's print command, and look
through the available destination printers. Hopefully you'll find a save-to-PDF printer already set
up and available. If not, you should be able to search for and find such a print driver for your
particular operating system.



[releases]: https://github.com/RayTracing/raytracing.github.io/releases


================================================
FILE: README.md
================================================
Ray Tracing in One Weekend Book Series
====================================================================================================

| ![RT in One Weekend][cover1] | ![RT The Next Week][cover2] | ![RT The Rest of Your Life][cover3] |
|:----------------------------:|:---------------------------:|:-----------------------------------:|
|   [In One Weekend][book1]    |   [The Next Week][book2]    |   [The Rest of Your Life][book3]    |


Getting the Books
------------------
The _Ray Tracing in One Weekend_ series of books are now available to the public for free directly
from the web.

### Version 4.0.1

  - [Ray Tracing in One Weekend][web1]
  - [Ray Tracing: The Next Week][web2]
  - [Ray Tracing: The Rest of Your Life][web3]

These books have been formatted for both screen and print. For more information about printing your
own copies, or on getting PDFs of the books, see [PRINTING.md][] for more information.


Contributing
-------------
If you'd like to contribute a PR _**please read our [contribution guidelines][CONTRIBUTING]
first**_.


Project Status
---------------
If you'd like to check out the latest updates and watch our progress, we're on the `dev-patch`,
`dev-minor`, and `dev-major` branches. You can also browse our issues and milestones to see what
we're planning.

If you're interested in contributing, email us! You can find our contact info at the head of each
book. Or just start [a new discussion][discussions] or [issue][issues].


GitHub Discussions
------------------
Do you have general questions about raytracing code, issues with your own implmentation, or general
raytracing ideas you'd like to share? Check out our [GitHub discussions][discussions] forum!


Directory Structure
-------------------
The organization of this repository is meant to be simple and self-evident at a glance:

  - `books/` --
    This folder contains the three raytracing books (in HTML), and some supporting material.

  - `images/` --
    Contains all of the images and figures of the books. Can also be used to compare your
    results.

  - `style/` --
    Contains the css for the books and the site.

  - `src/` --
    Contains the source.

  - `src/<book>/` --
    Contains the final source code for each book.


Source Code
-----------
### Intent
This repository is not meant to act as its own tutorial. The source is provided so you can compare
your work when progressing through the book. We strongly recommend reading and following along with
the book to understand the source. Ideally, you'll be developing your own implementation as you go,
in order to deeply understand how a raytracer works.

### Downloading The Source Code
The [GitHub home][] for this project contains all source and documentation associated with the _Ray
Tracing in One Weekend_ book series. To clone or download the source code, see the green "Clone or
download" button in the upper right of the project home page.

### Programming Language
This book is written in C++, and uses some modern features of C++11. The language and features were
chosen to be broadly understood by the largest collection of programmers. It is not meant to
represent ideal (or optimized) C++ code.

### Implementations in Other Languages
The _Ray Tracing in One Weekend_ series has a long history of implementations in other programming
languages (see [Implementations in Other Languages][implementations]), and across different
operating systems. Feel free to add your own implementation to the list!

### Branches
In general, ongoing development, with all of the latest changes, can be found in the `dev-patch`,
`dev-minor`, and `dev-major` branches, minor and major changes, depending on the change level and
release in progress. We try to keep CHANGELOG.md up to date, so you can easily browse what's new in
each development branch. We may from time to time use additional development branches, so stay up to
date by reviewing the [CONTRIBUTING][] page.

The `release` branch contains the latest released (and live) assets. This is the branch from which
GitHub pages serves up https://raytracing.github.io/.


Building and Running
---------------------
Copies of the source are provided for you to check your work and compare against. If you wish to
build the provided source, this project uses CMake. To build, go to the root of the project
directory and run the following commands to create the debug version of every executable:

    $ cmake -B build
    $ cmake --build build

You should run `cmake -B build` whenever you change your project `CMakeLists.txt` file (like when
adding a new source file).

You can specify the target with the `--target <program>` option, where the program may be
`inOneWeekend`, `theNextWeek`, `theRestOfYourLife`, or any of the demonstration programs. By default
(with no `--target` option), CMake will build all targets.

    $ cmake --build build --target inOneWeekend

### Optimized Builds
CMake supports Release and Debug configurations. These require slightly different invocations
across Windows (MSVC) and Linux/macOS (using GCC or Clang). The following instructions will place
optimized binaries under `build/Release` and debug binaries (unoptimized and containing debug
symbols) under `build/Debug`:

On Windows:

```shell
$ cmake -B build
$ cmake --build build --config Release  # Create release binaries in `build\Release`
$ cmake --build build --config Debug    # Create debug binaries in `build\Debug`
```

On Linux / macOS:

```shell
# Configure and build release binaries under `build/Release`
$ cmake -B build/Release -DCMAKE_BUILD_TYPE=Release
$ cmake --build build/Release

# Configure and build debug binaries under `build/Debug`
$ cmake -B build/Debug -DCMAKE_BUILD_TYPE=Debug
$ cmake --build build/Debug
```

We recommend building and running the `Release` version (especially before the final render) for
the fastest results, unless you need the extra debug information provided by the (default) debug
build.

### CMake GUI on Windows
You may choose to use the CMake GUI when building on windows.

1. Open CMake GUI on Windows
2. For "Where is the source code:", set to location of the copied directory. For example,
   `C:\Users\Peter\raytracing.github.io`.
3. Add the folder "build" within the location of the copied directory. For example,
   `C:\Users\Peter\raytracing.github.io\build`.
4. For "Where to build the binaries", set this to the newly-created "build" directory.
5. Click "Configure".
6. For "Specify the generator for this project", set this to your version of Visual Studio.
7. Click "Done".
8. Click "Configure" again.
9. Click "Generate".
10. In File Explorer, navigate to build directory and double click the newly-created `.sln` project.
11. Build in Visual Studio.

If the project is succesfully cloned and built, you can then use the native terminal of your
operating system to simply print the image to file.

### Running The Programs

You can run the programs by executing the binaries placed in the build directory:

    $ build\Debug\inOneWeekend > image.ppm

or, run the optimized version (if you compiled with the release configuration):

    $ build\Release\inOneWeekend > image.ppm

The generated PPM file can be viewed directly as a regular computer image, if your operating system
supports this image type. If your system doesn't handle PPM files, then you should be able to find
PPM file viewers online. We like [ImageMagick][].


Corrections & Contributions
----------------------------
If you spot errors, have suggested corrections, or would like to help out with the project,
_**please review the [CONTRIBUTING][] document for the most effective way to proceed.**_



[book1]:           books/RayTracingInOneWeekend.html
[book2]:           books/RayTracingTheNextWeek.html
[book3]:           books/RayTracingTheRestOfYourLife.html
[CONTRIBUTING]:    CONTRIBUTING.md
[cover1]:          images/cover/CoverRTW1-small.jpg
[cover2]:          images/cover/CoverRTW2-small.jpg
[cover3]:          images/cover/CoverRTW3-small.jpg
[discussions]:     https://github.com/RayTracing/raytracing.github.io/discussions/
[GitHub home]:     https://github.com/RayTracing/raytracing.github.io/
[ImageMagick]:     https://imagemagick.org/
[implementations]: https://github.com/RayTracing/raytracing.github.io/wiki/Implementations
[issues]:          https://github.com/RayTracing/raytracing.github.io/issues/
[PRINTING.md]:     PRINTING.md
[web1]:            https://raytracing.github.io/books/RayTracingInOneWeekend.html
[web2]:            https://raytracing.github.io/books/RayTracingTheNextWeek.html
[web3]:            https://raytracing.github.io/books/RayTracingTheRestOfYourLife.html


================================================
FILE: books/RayTracingInOneWeekend.html
================================================
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="icon" type="image/png" href="../favicon.png">
<!-- Markdeep: https://casual-effects.com/markdeep/ -->



                                   **Ray Tracing in One Weekend**
                   [Peter Shirley][], [Trevor David Black][], [Steve Hollasch][]
                                                <br>
                                     Version 4.0.2, 2025-04-25
                                                <br>
                      Copyright 2018-2024 Peter Shirley. All rights reserved.



Overview
====================================================================================================
I’ve taught many graphics classes over the years. Often I do them in ray tracing, because you are
forced to write all the code, but you can still get cool images with no API. I decided to adapt my
course notes into a how-to, to get you to a cool program as quickly as possible. It will not be a
full-featured ray tracer, but it does have the indirect lighting which has made ray tracing a staple
in movies. Follow these steps, and the architecture of the ray tracer you produce will be good for
extending to a more extensive ray tracer if you get excited and want to pursue that.

When somebody says “ray tracing” it could mean many things. What I am going to describe is
technically a path tracer, and a fairly general one. While the code will be pretty simple (let the
computer do the work!) I think you’ll be very happy with the images you can make.

I’ll take you through writing a ray tracer in the order I do it, along with some debugging tips. By
the end, you will have a ray tracer that produces some great images. You should be able to do this
in a weekend. If you take longer, don’t worry about it. I use C++ as the driving language, but you
don’t need to. However, I suggest you do, because it’s fast, portable, and most production movie and
video game renderers are written in C++. Note that I avoid most “modern features” of C++, but
inheritance and operator overloading are too useful for ray tracers to pass on.

> I do not provide the code online, but the code is real and I show all of it except for a few
> straightforward operators in the `vec3` class. I am a big believer in typing in code to learn it,
> but when code is available I use it, so I only practice what I preach when the code is not
> available. So don’t ask!

I have left that last part in because it is funny what a 180 I have done. Several readers ended up
with subtle errors that were helped when we compared code. So please do type in the code, but you
can find the finished source for each book in the [RayTracing project on GitHub][repo].

A note on the implementing code for these books -- our philosophy for the included code prioritizes
the following goals:

  - The code should implement the concepts covered in the books.

  - We use C++, but as simple as possible. Our programming style is very C-like, but we take
    advantage of modern features where it makes the code easier to use or understand.

  - Our coding style continues the style established from the original books as much as possible,
    for continuity.

  - Line length is kept to 96 characters per line, to keep lines consistent between the codebase and
    code listings in the books.

The code thus provides a baseline implementation, with tons of improvements left for the reader to
enjoy. There are endless ways one can optimize and modernize the code; we prioritize the simple
solution.

We assume a little bit of familiarity with vectors (like dot product and vector addition). If you
don’t know that, do a little review. If you need that review, or to learn it for the first time,
check out the online [_Graphics Codex_][gfx-codex] by Morgan McGuire, _Fundamentals of Computer
Graphics_ by Steve Marschner and Peter Shirley, or _Computer Graphics: Principles and Practice_
by J.D. Foley and Andy Van Dam.

See the [project README][readme] file for information about this project, the repository on GitHub,
directory structure, building & running, and how to make or reference corrections and contributions.

See [our Further Reading wiki page][wiki-further] for additional project related resources.

These books have been formatted to print well directly from your browser. We also include PDFs of
each book [with each release][releases], in the "Assets" section.

If you want to communicate with us, feel free to send us an email at:

  - Peter Shirley, ptrshrl@gmail.com
  - Steve Hollasch, steve@hollasch.net
  - Trevor David Black, trevordblack@trevord.black

Finally, if you run into problems with your implementation, have general questions, or would like to
share your own ideas or work, see [the GitHub Discussions forum][discussions] on the GitHub project.

Thanks to everyone who lent a hand on this project. You can find them in the acknowledgments section
at the end of this book.

Let’s get on with it!



Output an Image
====================================================================================================

The PPM Image Format
---------------------
Whenever you start a renderer, you need a way to see an image. The most straightforward way is to
write it to a file. The catch is, there are so many formats. Many of those are complex. I always
start with a plain text ppm file. Here’s a nice description from Wikipedia:

  ![Figure [ppm]: PPM Example](../images/fig-1.01-ppm.jpg)

<div class='together'>
Let’s make some C++ code to output such a thing:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include <iostream>

    int main() {

        // Image

        int image_width = 256;
        int image_height = 256;

        // Render

        std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

        for (int j = 0; j < image_height; j++) {
            for (int i = 0; i < image_width; i++) {
                auto r = double(i) / (image_width-1);
                auto g = double(j) / (image_height-1);
                auto b = 0.0;

                int ir = int(255.999 * r);
                int ig = int(255.999 * g);
                int ib = int(255.999 * b);

                std::cout << ir << ' ' << ig << ' ' << ib << '\n';
            }
        }
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-initial]: <kbd>[main.cc]</kbd> Creating your first image]

</div>

There are some things to note in this code:

  1. The pixels are written out in rows.

  2. Every row of pixels is written out left to right.

  3. These rows are written out from top to bottom.

  4. By convention, each of the red/green/blue components are represented internally by real-valued
     variables that range from 0.0 to 1.0. These must be scaled to integer values between 0 and 255
     before we print them out.

  5. Red goes from fully off (black) to fully on (bright red) from left to right, and green goes
     from fully off at the top (black) to fully on at the bottom (bright green). Adding red and
     green light together make yellow so we should expect the bottom right corner to be yellow.


Creating an Image File
-----------------------
Because the file is written to the standard output stream, you'll need to redirect it to an image
file. Typically this is done from the command-line by using the `>` redirection operator.

On Windows, you'd get the debug build from CMake running this command:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    cmake -B build
    cmake --build build
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Then run your newly-built program like so:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    build\Debug\inOneWeekend.exe > image.ppm
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Later, it will be better to run optimized builds for speed. In that case, you would build like this:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    cmake --build build --config release
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

and would run the optimized program like this:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    build\Release\inOneWeekend.exe > image.ppm
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The examples above assume that you are building with CMake, using the same approach as the
`CMakeLists.txt` file in the included source. Use whatever build environment (and language) you're
most comfortable with.

On Mac or Linux, release build, you would launch the program like this:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    build/inOneWeekend > image.ppm
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Complete building and running instructions can be found in the [project README][readme].

Opening the output file (in `ToyViewer` on my Mac, but try it in your favorite image viewer and
Google “ppm viewer” if your viewer doesn’t support it) shows this result:

  ![<span class='num'>Image 1:</span> First PPM image
  ](../images/img-1.01-first-ppm-image.png class='pixel')

Hooray! This is the graphics “hello world”. If your image doesn’t look like that, open the output
file in a text editor and see what it looks like. It should start something like this:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    P3
    256 256
    255
    0 0 0
    1 0 0
    2 0 0
    3 0 0
    4 0 0
    5 0 0
    6 0 0
    7 0 0
    8 0 0
    9 0 0
    10 0 0
    11 0 0
    12 0 0
    ...
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [first-img]: First image output]

If your PPM file doesn't look like this, then double-check your formatting code. If it _does_ look
like this but fails to render, then you may have line-ending differences or something similar that
is confusing your image viewer. To help debug this, you can find a file `test.ppm` in the `images`
directory of the Github project. This should help to ensure that your viewer can handle the PPM
format and to use as a comparison against your generated PPM file.

Some readers have reported problems viewing their generated files on Windows. In this case, the
problem is often that the PPM is written out as UTF-16, often from PowerShell. If you run into this
problem, see [Discussion 1114](https://github.com/RayTracing/raytracing.github.io/discussions/1114)
for help with this issue.

If everything displays correctly, then you're pretty much done with system and IDE issues --
everything in the remainder of this series uses this same simple mechanism for generated rendered
images.

If you want to produce other image formats, I am a fan of `stb_image.h`, a header-only image library
available on GitHub at <https://github.com/nothings/stb>.


Adding a Progress Indicator
----------------------------
Before we continue, let's add a progress indicator to our output. This is a handy way to track the
progress of a long render, and also to possibly identify a run that's stalled out due to an infinite
loop or other problem.

<div class='together'>
Our program outputs the image to the standard output stream (`std::cout`), so leave that alone and
instead write to the logging output stream (`std::clog`):

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
        for (int j = 0; j < image_height; ++j) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            for (int i = 0; i < image_width; i++) {
                auto r = double(i) / (image_width-1);
                auto g = double(j) / (image_height-1);
                auto b = 0.0;

                int ir = int(255.999 * r);
                int ig = int(255.999 * g);
                int ib = int(255.999 * b);

                std::cout << ir << ' ' << ig << ' ' << ib << '\n';
            }
        }


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        std::clog << "\rDone.                 \n";
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-progress]: <kbd>[main.cc]</kbd> Main render loop with progress reporting]

</div>

Now when running, you'll see a running count of the number of scanlines remaining. Hopefully this
runs so fast that you don't even see it! Don't worry -- you'll have lots of time in the future to
watch a slowly updating progress line as we expand our ray tracer.


The vec3 Class
====================================================================================================
Almost all graphics programs have some class(es) for storing geometric vectors and colors. In many
systems these vectors are 4D (3D position plus a homogeneous coordinate for geometry, or RGB plus an
alpha transparency component for colors). For our purposes, three coordinates suffice. We’ll use the
same class `vec3` for colors, locations, directions, offsets, whatever. Some people don’t like this
because it doesn’t prevent you from doing something silly, like subtracting a position from a color.
They have a good point, but we’re going to always take the “less code” route when not obviously
wrong. In spite of this, we do declare two aliases for `vec3`: `point3` and `color`. Since these two
types are just aliases for `vec3`, you won't get warnings if you pass a `color` to a function
expecting a `point3`, and nothing is stopping you from adding a `point3` to a `color`, but it makes
the code a little bit easier to read and to understand.

We define the `vec3` class in the top half of a new `vec3.h` header file, and define a set of useful
vector utility functions in the bottom half:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef VEC3_H
    #define VEC3_H

    #include <cmath>
    #include <iostream>

    class vec3 {
      public:
        double e[3];

        vec3() : e{0,0,0} {}
        vec3(double e0, double e1, double e2) : e{e0, e1, e2} {}

        double x() const { return e[0]; }
        double y() const { return e[1]; }
        double z() const { return e[2]; }

        vec3 operator-() const { return vec3(-e[0], -e[1], -e[2]); }
        double operator[](int i) const { return e[i]; }
        double& operator[](int i) { return e[i]; }

        vec3& operator+=(const vec3& v) {
            e[0] += v.e[0];
            e[1] += v.e[1];
            e[2] += v.e[2];
            return *this;
        }

        vec3& operator*=(double t) {
            e[0] *= t;
            e[1] *= t;
            e[2] *= t;
            return *this;
        }

        vec3& operator/=(double t) {
            return *this *= 1/t;
        }

        double length() const {
            return std::sqrt(length_squared());
        }

        double length_squared() const {
            return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
        }
    };

    // point3 is just an alias for vec3, but useful for geometric clarity in the code.
    using point3 = vec3;


    // Vector Utility Functions

    inline std::ostream& operator<<(std::ostream& out, const vec3& v) {
        return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2];
    }

    inline vec3 operator+(const vec3& u, const vec3& v) {
        return vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]);
    }

    inline vec3 operator-(const vec3& u, const vec3& v) {
        return vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]);
    }

    inline vec3 operator*(const vec3& u, const vec3& v) {
        return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]);
    }

    inline vec3 operator*(double t, const vec3& v) {
        return vec3(t*v.e[0], t*v.e[1], t*v.e[2]);
    }

    inline vec3 operator*(const vec3& v, double t) {
        return t * v;
    }

    inline vec3 operator/(const vec3& v, double t) {
        return (1/t) * v;
    }

    inline double dot(const vec3& u, const vec3& v) {
        return u.e[0] * v.e[0]
             + u.e[1] * v.e[1]
             + u.e[2] * v.e[2];
    }

    inline vec3 cross(const vec3& u, const vec3& v) {
        return vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],
                    u.e[2] * v.e[0] - u.e[0] * v.e[2],
                    u.e[0] * v.e[1] - u.e[1] * v.e[0]);
    }

    inline vec3 unit_vector(const vec3& v) {
        return v / v.length();
    }

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [vec3-class]: <kbd>[vec3.h]</kbd> vec3 definitions and helper functions]

We use `double` here, but some ray tracers use `float`. `double` has greater precision and range,
but is twice the size compared to `float`. This increase in size may be important if you're
programming in limited memory conditions (such as hardware shaders). Either one is fine -- follow
your own tastes.


Color Utility Functions
------------------------
Using our new `vec3` class, we'll create a new `color.h` header file and define a utility function
that writes a single pixel's color out to the standard output stream.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef COLOR_H
    #define COLOR_H

    #include "vec3.h"

    #include <iostream>

    using color = vec3;

    void write_color(std::ostream& out, const color& pixel_color) {
        auto r = pixel_color.x();
        auto g = pixel_color.y();
        auto b = pixel_color.z();

        // Translate the [0,1] component values to the byte range [0,255].
        int rbyte = int(255.999 * r);
        int gbyte = int(255.999 * g);
        int bbyte = int(255.999 * b);

        // Write out the pixel color components.
        out << rbyte << ' ' << gbyte << ' ' << bbyte << '\n';
    }

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [color]: <kbd>[color.h]</kbd> color utility functions]

<div class='together'>
Now we can change our main to use both of these:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include "color.h"
    #include "vec3.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

    #include <iostream>

    int main() {

        // Image

        int image_width = 256;
        int image_height = 256;

        // Render

        std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

        for (int j = 0; j < image_height; j++) {
            std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
            for (int i = 0; i < image_width; i++) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                auto pixel_color = color(double(i)/(image_width-1), double(j)/(image_height-1), 0);
                write_color(std::cout, pixel_color);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            }
        }

        std::clog << "\rDone.                 \n";
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ppm-2]: <kbd>[main.cc]</kbd> Final code for the first PPM image]

</div>

And you should get the exact same picture as before.



Rays, a Simple Camera, and Background
====================================================================================================

The ray Class
--------------
The one thing that all ray tracers have is a ray class and a computation of what color is seen along
a ray. Let’s think of a ray as a function $\mathbf{P}(t) = \mathbf{A} + t \mathbf{b}$. Here
$\mathbf{P}$ is a 3D position along a line in 3D. $\mathbf{A}$ is the ray origin and $\mathbf{b}$ is
the ray direction. The ray parameter $t$ is a real number (`double` in the code). Plug in a
different $t$ and $\mathbf{P}(t)$ moves the point along the ray. Add in negative $t$ values and you
can go anywhere on the 3D line. For positive $t$, you get only the parts in front of $\mathbf{A}$,
and this is what is often called a half-line or a ray.

  ![Figure [lerp]: Linear interpolation](../images/fig-1.02-lerp.jpg)

<div class='together'>
We can represent the idea of a ray as a class, and represent the function $\mathbf{P}(t)$ as a
function that we'll call `ray::at(t)`:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef RAY_H
    #define RAY_H

    #include "vec3.h"

    class ray {
      public:
        ray() {}

        ray(const point3& origin, const vec3& direction) : orig(origin), dir(direction) {}

        const point3& origin() const  { return orig; }
        const vec3& direction() const { return dir; }

        point3 at(double t) const {
            return orig + t*dir;
        }

      private:
        point3 orig;
        vec3 dir;
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-initial]: <kbd>[ray.h]</kbd> The ray class]

</div>

(For those unfamiliar with C++, the functions `ray::origin()` and `ray::direction()` both return an
immutable reference to their members. Callers can either just use the reference directly, or make a
mutable copy depending on their needs.)


Sending Rays Into the Scene
----------------------------
Now we are ready to turn the corner and make a ray tracer. At its core, a ray tracer sends rays
through pixels and computes the color seen in the direction of those rays. The involved steps are

    1. Calculate the ray from the “eye” through the pixel,
    2. Determine which objects the ray intersects, and
    3. Compute a color for the closest intersection point.

When first developing a ray tracer, I always do a simple camera for getting the code up and running.

I’ve often gotten into trouble using square images for debugging because I transpose $x$ and $y$ too
often, so we’ll use a non-square image. A square image has a 1&ratio;1 aspect ratio, because its
width is the same as its height. Since we want a non-square image, we'll choose 16&ratio;9 because
it's so common. A 16&ratio;9 aspect ratio means that the ratio of image width to image height is
16&ratio;9. Put another way, given an image with a 16&ratio;9 aspect ratio,

  $$\text{width} / \text{height} = 16 / 9 = 1.7778$$

For a practical example, an image 800 pixels wide by 400 pixels high has a 2&ratio;1 aspect ratio.

The image's aspect ratio can be determined from the ratio of its width to its height. However, since
we have a given aspect ratio in mind, it's easier to set the image's width and the aspect ratio, and
then using this to calculate for its height. This way, we can scale up or down the image by changing
the image width, and it won't throw off our desired aspect ratio. We do have to make sure that when
we solve for the image height the resulting height is at least 1.

In addition to setting up the pixel dimensions for the rendered image, we also need to set up a
virtual _viewport_ through which to pass our scene rays. The viewport is a virtual rectangle in the
3D world that contains the grid of image pixel locations. If pixels are spaced the same distance
horizontally as they are vertically, the viewport that bounds them will have the same aspect ratio
as the rendered image. The distance between two adjacent pixels is called the pixel spacing, and
square pixels is the standard.

To start things off, we'll choose an arbitrary viewport height of 2.0, and scale the viewport width
to give us the desired aspect ratio. Here's a snippet of what this code will look like:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    auto aspect_ratio = 16.0 / 9.0;
    int image_width = 400;

    // Calculate the image height, and ensure that it's at least 1.
    int image_height = int(image_width / aspect_ratio);
    image_height = (image_height < 1) ? 1 : image_height;

    // Viewport widths less than one are ok since they are real valued.
    auto viewport_height = 2.0;
    auto viewport_width = viewport_height * (double(image_width)/image_height);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [image-setup]: Rendered image setup]

If you're wondering why we don't just use `aspect_ratio` when computing `viewport_width`, it's
because the value set to `aspect_ratio` is the ideal ratio, it may not be the _actual_ ratio between
`image_width` and `image_height`. If `image_height` was allowed to be real valued--rather than just
an integer--then it would be fine to use `aspect_ratio`. But the _actual_ ratio between
`image_width` and `image_height` can vary based on two parts of the code. First, `image_height` is
rounded down to the nearest integer, which can increase the ratio. Second, we don't allow
`image_height` to be less than one, which can also change the actual aspect ratio.

Note that `aspect_ratio` is an ideal ratio, which we approximate as best as possible with the
integer-based ratio of image width over image height. In order for our viewport proportions to
exactly match our image proportions, we use the calculated image aspect ratio to determine our final
viewport width.

Next we will define the camera center: a point in 3D space from which all scene rays will originate
(this is also commonly referred to as the _eye point_). The vector from the camera center to the
viewport center will be orthogonal to the viewport. We'll initially set the distance between the
viewport and the camera center point to be one unit. This distance is often referred to as the
_focal length_.

For simplicity we'll start with the camera center at $(0,0,0)$. We'll also have the y-axis go up,
the x-axis to the right, and the negative z-axis pointing in the viewing direction. (This is
commonly referred to as _right-handed coordinates_.)

  ![Figure [camera-geom]: Camera geometry](../images/fig-1.03-cam-geom.jpg)

Now the inevitable tricky part. While our 3D space has the conventions above, this conflicts with
our image coordinates, where we want to have the zeroth pixel in the top-left and work our way down
to the last pixel at the bottom right. This means that our image coordinate Y-axis is inverted: Y
increases going down the image.

As we scan our image, we will start at the upper left pixel (pixel $0,0$), scan left-to-right across
each row, and then scan row-by-row, top-to-bottom. To help navigate the pixel grid, we'll use a
vector from the left edge to the right edge ($\mathbf{V_u}$), and a vector from the upper edge to
the lower edge ($\mathbf{V_v}$).

Our pixel grid will be inset from the viewport edges by half the pixel-to-pixel distance. This way,
our viewport area is evenly divided into width &times; height identical regions. Here's what our
viewport and pixel grid look like:

  ![Figure [pixel-grid]: Viewport and pixel grid](../images/fig-1.04-pixel-grid.jpg)

In this figure, we have the viewport, the pixel grid for a 7&times;5 resolution image, the viewport
upper left corner $\mathbf{Q}$, the pixel $\mathbf{P_{0,0}}$ location, the viewport vector
$\mathbf{V_u}$ (`viewport_u`), the viewport vector $\mathbf{V_v}$ (`viewport_v`), and the pixel
delta vectors $\mathbf{\Delta u}$ and $\mathbf{\Delta v}$.

<div class='together'>
Drawing from all of this, here's the code that implements the camera. We'll stub in a function
`ray_color(const ray& r)` that returns the color for a given scene ray -- which we'll set to always
return black for now.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include "color.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include "ray.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include "vec3.h"

    #include <iostream>


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    color ray_color(const ray& r) {
        return color(0,0,0);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

    int main() {

        // Image


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        auto aspect_ratio = 16.0 / 9.0;
        int image_width = 400;

        // Calculate the image height, and ensure that it's at least 1.
        int image_height = int(image_width / aspect_ratio);
        image_height = (image_height < 1) ? 1 : image_height;

        // Camera

        auto focal_length = 1.0;
        auto viewport_height = 2.0;
        auto viewport_width = viewport_height * (double(image_width)/image_height);
        auto camera_center = point3(0, 0, 0);

        // Calculate the vectors across the horizontal and down the vertical viewport edges.
        auto viewport_u = vec3(viewport_width, 0, 0);
        auto viewport_v = vec3(0, -viewport_height, 0);

        // Calculate the horizontal and vertical delta vectors from pixel to pixel.
        auto pixel_delta_u = viewport_u / image_width;
        auto pixel_delta_v = viewport_v / image_height;

        // Calculate the location of the upper left pixel.
        auto viewport_upper_left = camera_center
                                 - vec3(0, 0, focal_length) - viewport_u/2 - viewport_v/2;
        auto pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        // Render

        std::cout << "P3\n" << image_width << " " << image_height << "\n255\n";

        for (int j = 0; j < image_height; j++) {
            std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
            for (int i = 0; i < image_width; i++) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);
                auto ray_direction = pixel_center - camera_center;
                ray r(camera_center, ray_direction);

                color pixel_color = ray_color(r);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                write_color(std::cout, pixel_color);
            }
        }

        std::clog << "\rDone.                 \n";
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [creating-rays]: <kbd>[main.cc]</kbd> Creating scene rays]

</div>

Notice that in the code above, I didn't make `ray_direction` a unit vector, because I think not
doing that makes for simpler and slightly faster code.

Now we'll fill in the `ray_color(ray)` function to implement a simple gradient. This function will
linearly blend white and blue depending on the height of the $y$ coordinate _after_ scaling the ray
direction to unit length (so $-1.0 < y < 1.0$). Because we're looking at the $y$ height after
normalizing the vector, you'll notice a horizontal gradient to the color in addition to the vertical
gradient.

I'll use a standard graphics trick to linearly scale $0.0 ≤ a ≤ 1.0$. When $a = 1.0$, I want blue.
When $a = 0.0$, I want white. In between, I want a blend. This forms a “linear blend”, or “linear
interpolation”. This is commonly referred to as a _lerp_ between two values. A lerp is always of the
form

  $$ \mathit{blendedValue} = (1-a)\cdot\mathit{startValue} + a\cdot\mathit{endValue}, $$

with $a$ going from zero to one.

<div class='together'>
Putting all this together, here's what we get:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include "color.h"
    #include "ray.h"
    #include "vec3.h"

    #include <iostream>


    color ray_color(const ray& r) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        vec3 unit_direction = unit_vector(r.direction());
        auto a = 0.5*(unit_direction.y() + 1.0);
        return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    }

    ...
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-blue-white-blend]: <kbd>[main.cc]</kbd> Rendering a blue-to-white gradient]

</div>

<div class='together'>
In our case this produces:

  ![<span class='num'>Image 2:</span> A blue-to-white gradient depending on ray Y coordinate
  ](../images/img-1.02-blue-to-white.png class='pixel')

</div>



Adding a Sphere
====================================================================================================
Let’s add a single object to our ray tracer. People often use spheres in ray tracers because
calculating whether a ray hits a sphere is relatively simple.


Ray-Sphere Intersection
------------------------
The equation for a sphere of radius $r$ that is centered at the origin is an important mathematical
equation:

    $$ x^2 + y^2 + z^2 = r^2 $$

You can also think of this as saying that if a given point $(x,y,z)$ is on the surface of the
sphere, then $x^2 + y^2 + z^2 = r^2$. If a given point $(x,y,z)$ is _inside_ the sphere, then
$x^2 + y^2 + z^2 < r^2$, and if a given point $(x,y,z)$ is _outside_ the sphere, then
$x^2 + y^2 + z^2 > r^2$.

If we want to allow the sphere center to be at an arbitrary point $(C_x, C_y, C_z)$, then the
equation becomes a lot less nice:

  $$ (C_x - x)^2 + (C_y - y)^2 + (C_z - z)^2 = r^2 $$

In graphics, you almost always want your formulas to be in terms of vectors so that all the
$x$/$y$/$z$ stuff can be simply represented using a `vec3` class. You might note that the vector
from point $\mathbf{P} = (x,y,z)$ to center $\mathbf{C} = (C_x, C_y, C_z)$ is
$(\mathbf{C} - \mathbf{P})$.

If we use the definition of the dot product:

  $$ (\mathbf{C} - \mathbf{P}) \cdot (\mathbf{C} - \mathbf{P})
     = (C_x - x)^2 + (C_y - y)^2 + (C_z - z)^2
  $$

Then we can rewrite the equation of the sphere in vector form as:

  $$ (\mathbf{C} - \mathbf{P}) \cdot (\mathbf{C} - \mathbf{P}) = r^2 $$

We can read this as “any point $\mathbf{P}$ that satisfies this equation is on the sphere”. We want
to know if our ray $\mathbf{P}(t) = \mathbf{Q} + t\mathbf{d}$ ever hits the sphere anywhere. If it
does hit the sphere, there is some $t$ for which $\mathbf{P}(t)$ satisfies the sphere equation. So
we are looking for any $t$ where this is true:

  $$ (\mathbf{C} - \mathbf{P}(t)) \cdot (\mathbf{C} - \mathbf{P}(t)) = r^2 $$

which can be found by replacing $\mathbf{P}(t)$ with its expanded form:

  $$ (\mathbf{C} - (\mathbf{Q} + t \mathbf{d}))
      \cdot (\mathbf{C} - (\mathbf{Q} + t \mathbf{d})) = r^2 $$

We have three vectors on the left dotted by three vectors on the right. If we solved for the full
dot product we would get nine vectors. You can definitely go through and write everything out, but
we don't need to work that hard. If you remember, we want to solve for $t$, so we'll separate the
terms based on whether there is a $t$ or not:

  $$ (-t \mathbf{d} + (\mathbf{C} - \mathbf{Q})) \cdot (-t \mathbf{d} + (\mathbf{C} - \mathbf{Q}))
     = r^2
  $$

And now we follow the rules of vector algebra to distribute the dot product:

  $$ t^2 \mathbf{d} \cdot \mathbf{d}
     - 2t \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q})
     + (\mathbf{C} - \mathbf{Q}) \cdot (\mathbf{C} - \mathbf{Q}) = r^2
  $$

Move the square of the radius over to the left hand side:

  $$ t^2 \mathbf{d} \cdot \mathbf{d}
     - 2t \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q})
     + (\mathbf{C} - \mathbf{Q}) \cdot (\mathbf{C} - \mathbf{Q}) - r^2 = 0
  $$

It's hard to make out what exactly this equation is, but the vectors and $r$ in that equation are
all constant and known. Furthermore, the only vectors that we have are reduced to scalars by dot
product. The only unknown is $t$, and we have a $t^2$, which means that this equation is quadratic.
You can solve for a quadratic equation $ax^2 + bx + c = 0$ by using the quadratic formula:

  $$ \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$

So solving for $t$ in the ray-sphere intersection equation gives us these values for $a$, $b$, and
$c$:

  $$ a = \mathbf{d} \cdot \mathbf{d} $$
  $$ b = -2 \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) $$
  $$ c = (\mathbf{C} - \mathbf{Q}) \cdot (\mathbf{C} - \mathbf{Q}) - r^2 $$

Using all of the above you can solve for $t$, but there is a square root part that can be either
positive (meaning two real solutions), negative (meaning no real solutions), or zero (meaning one
real solution). In graphics, the algebra almost always relates very directly to the geometry. What
we have is:

  ![Figure [ray-sphere]: Ray-sphere intersection results](../images/fig-1.05-ray-sphere.jpg)


Creating Our First Raytraced Image
-----------------------------------
If we take that math and hard-code it into our program, we can test our code by placing a small
sphere at -1 on the z-axis and then coloring red any pixel that intersects it.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    bool hit_sphere(const point3& center, double radius, const ray& r) {
        vec3 oc = center - r.origin();
        auto a = dot(r.direction(), r.direction());
        auto b = -2.0 * dot(r.direction(), oc);
        auto c = dot(oc, oc) - radius*radius;
        auto discriminant = b*b - 4*a*c;
        return (discriminant >= 0);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    color ray_color(const ray& r) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        if (hit_sphere(point3(0,0,-1), 0.5, r))
            return color(1, 0, 0);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        vec3 unit_direction = unit_vector(r.direction());
        auto a = 0.5*(unit_direction.y() + 1.0);
        return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-red-sphere]: <kbd>[main.cc]</kbd> Rendering a red sphere]

<div class='together'>
What we get is this:

  ![<span class='num'>Image 3:</span> A simple red sphere
  ](../images/img-1.03-red-sphere.png class='pixel')

</div>

Now this lacks all sorts of things -- like shading, reflection rays, and more than one object -- but
we are closer to halfway done than we are to our start! One thing to be aware of is that we are
testing to see if a ray intersects with the sphere by solving the quadratic equation and seeing if a
solution exists, but solutions with negative values of $t$ work just fine. If you change your sphere
center to $z = +1$ you will get exactly the same picture because this solution doesn't distinguish
between objects _in front of the camera_ and objects _behind the camera_. This is not a feature!
We’ll fix those issues next.



Surface Normals and Multiple Objects
====================================================================================================

Shading with Surface Normals
-----------------------------
First, let’s get ourselves a surface normal so we can shade. This is a vector that is perpendicular
to the surface at the point of intersection.

We have a key design decision to make for normal vectors in our code: whether normal vectors will
have an arbitrary length, or will be normalized to unit length.

It is tempting to skip the expensive square root operation involved in normalizing the vector, in
case it's not needed. In practice, however, there are three important observations. First, if a
unit-length normal vector is _ever_ required, then you might as well do it up front once, instead of
over and over again "just in case" for every location where unit-length is required. Second, we _do_
require unit-length normal vectors in several places. Third, if you require normal vectors to be
unit length, then you can often efficiently generate that vector with an understanding of the
specific geometry class, in its constructor, or in the `hit()` function. For example, sphere normals
can be made unit length simply by dividing by the sphere radius, avoiding the square root entirely.

Given all of this, we will adopt the policy that all normal vectors will be of unit length.

For a sphere, the outward normal is in the direction of the hit point minus the center:

  ![Figure [sphere-normal]: Sphere surface-normal geometry](../images/fig-1.06-sphere-normal.jpg)

On the earth, this means that the vector from the earth’s center to you points straight up. Let’s
throw that into the code now, and shade it. We don’t have any lights or anything yet, so let’s just
visualize the normals with a color map. A common trick used for visualizing normals (because it’s
easy and somewhat intuitive to assume $\mathbf{n}$ is a unit length vector -- so each component is
between -1 and 1) is to map each component to the interval from 0 to 1, and then map $(x, y, z)$ to
$(\mathit{red}, \mathit{green}, \mathit{blue})$. For the normal, we need the hit point, not just
whether we hit or not (which is all we're calculating at the moment). We only have one sphere in the
scene, and it's directly in front of the camera, so we won't worry about negative values of $t$ yet.
We'll just assume the closest hit point (smallest $t$) is the one that we want. These changes in the
code let us compute and visualize $\mathbf{n}$:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    double hit_sphere(const point3& center, double radius, const ray& r) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
        vec3 oc = center - r.origin();
        auto a = dot(r.direction(), r.direction());
        auto b = -2.0 * dot(r.direction(), oc);
        auto c = dot(oc, oc) - radius*radius;
        auto discriminant = b*b - 4*a*c;


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        if (discriminant < 0) {
            return -1.0;
        } else {
            return (-b - std::sqrt(discriminant) ) / (2.0*a);
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    }

    color ray_color(const ray& r) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        auto t = hit_sphere(point3(0,0,-1), 0.5, r);
        if (t > 0.0) {
            vec3 N = unit_vector(r.at(t) - vec3(0,0,-1));
            return 0.5*color(N.x()+1, N.y()+1, N.z()+1);
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        vec3 unit_direction = unit_vector(r.direction());
        auto a = 0.5*(unit_direction.y() + 1.0);
        return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [render-surface-normal]: <kbd>[main.cc]</kbd> Rendering surface normals on a sphere]

<div class='together'>
And that yields this picture:

  ![<span class='num'>Image 4:</span> A sphere colored according to its normal vectors
  ](../images/img-1.04-normals-sphere.png class='pixel')

</div>


Simplifying the Ray-Sphere Intersection Code
---------------------------------------------
Let’s revisit the ray-sphere function:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    double hit_sphere(const point3& center, double radius, const ray& r) {
        vec3 oc = center - r.origin();
        auto a = dot(r.direction(), r.direction());
        auto b = -2.0 * dot(r.direction(), oc);
        auto c = dot(oc, oc) - radius*radius;
        auto discriminant = b*b - 4*a*c;

        if (discriminant < 0) {
            return -1.0;
        } else {
            return (-b - std::sqrt(discriminant) ) / (2.0*a);
        }
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-sphere-before]: <kbd>[main.cc]</kbd> Ray-sphere intersection code (before)]

First, recall that a vector dotted with itself is equal to the squared length of that vector.

Second, notice how the equation for `b` has a factor of negative two in it. Consider what happens to
the quadratic equation if $b = -2h$:

  $$ \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$

  $$ = \frac{-(-2h) \pm \sqrt{(-2h)^2 - 4ac}}{2a} $$

  $$ = \frac{2h \pm 2\sqrt{h^2 - ac}}{2a} $$

  $$ = \frac{h \pm \sqrt{h^2 - ac}}{a} $$

This simplifies nicely, so we'll use it. So solving for $h$:

  $$ b = -2 \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) $$
  $$ b = -2h $$
  $$ h = \frac{b}{-2} = \mathbf{d} \cdot (\mathbf{C} - \mathbf{Q}) $$

<div class='together'>
Using these observations, we can now simplify the sphere-intersection code to this:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    double hit_sphere(const point3& center, double radius, const ray& r) {
        vec3 oc = center - r.origin();
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        auto a = r.direction().length_squared();
        auto h = dot(r.direction(), oc);
        auto c = oc.length_squared() - radius*radius;
        auto discriminant = h*h - a*c;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        if (discriminant < 0) {
            return -1.0;
        } else {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            return (h - std::sqrt(discriminant)) / a;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
        }
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-sphere-after]: <kbd>[main.cc]</kbd> Ray-sphere intersection code (after)]

</div>


An Abstraction for Hittable Objects
------------------------------------
Now, how about more than one sphere? While it is tempting to have an array of spheres, a very clean
solution is to make an “abstract class” for anything a ray might hit, and make both a sphere and a
list of spheres just something that can be hit. What that class should be called is something of a
quandary -- calling it an “object” would be good if not for “object oriented” programming. “Surface”
is often used, with the weakness being maybe we will want volumes (fog, clouds, stuff like that).
“hittable” emphasizes the member function that unites them. I don’t love any of these, but we'll go
with “hittable”.

This `hittable` abstract class will have a `hit` function that takes in a ray. Most ray tracers have
found it convenient to add a valid interval for hits $t_{\mathit{min}}$ to $t_{\mathit{max}}$, so
the hit only “counts” if $t_{\mathit{min}} < t < t_{\mathit{max}}$. For the initial rays this is
positive $t$, but as we will see, it can simplify our code to have an interval $t_{\mathit{min}}$ to
$t_{\mathit{max}}$. One design question is whether to do things like compute the normal if we hit
something. We might end up hitting something closer as we do our search, and we will only need the
normal of the closest thing. I will go with the simple solution and compute a bundle of stuff I will
store in some structure. Here’s the abstract class:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef HITTABLE_H
    #define HITTABLE_H

    #include "ray.h"

    class hit_record {
      public:
        point3 p;
        vec3 normal;
        double t;
    };

    class hittable {
      public:
        virtual ~hittable() = default;

        virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const = 0;
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [hittable-initial]: <kbd>[hittable.h]</kbd> The hittable class]

<div class='together'>
And here’s the sphere:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef SPHERE_H
    #define SPHERE_H

    #include "hittable.h"
    #include "vec3.h"

    class sphere : public hittable {
      public:
        sphere(const point3& center, double radius) : center(center), radius(std::fmax(0,radius)) {}

        bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const override {
            vec3 oc = center - r.origin();
            auto a = r.direction().length_squared();
            auto h = dot(r.direction(), oc);
            auto c = oc.length_squared() - radius*radius;

            auto discriminant = h*h - a*c;
            if (discriminant < 0)
                return false;

            auto sqrtd = std::sqrt(discriminant);

            // Find the nearest root that lies in the acceptable range.
            auto root = (h - sqrtd) / a;
            if (root <= ray_tmin || ray_tmax <= root) {
                root = (h + sqrtd) / a;
                if (root <= ray_tmin || ray_tmax <= root)
                    return false;
            }

            rec.t = root;
            rec.p = r.at(rec.t);
            rec.normal = (rec.p - center) / radius;

            return true;
        }

      private:
        point3 center;
        double radius;
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [sphere-initial]: <kbd>[sphere.h]</kbd> The sphere class]

(Note here that we use the C++ standard function `std::fmax()`, which returns the maximum of the two
floating-point arguments. Similarly, we will later use `std::fmin()`, which returns the minimum of
the two floating-point arguments.)
</div>


Front Faces Versus Back Faces
------------------------------
The second design decision for normals is whether they should always point out. At present, the
normal found will always be in the direction of the center to the intersection point (the normal
points out). If the ray intersects the sphere from the outside, the normal points against the ray.
If the ray intersects the sphere from the inside, the normal (which always points out) points with
the ray. Alternatively, we can have the normal always point against the ray. If the ray is outside
the sphere, the normal will point outward, but if the ray is inside the sphere, the normal will
point inward.

  ![Figure [normal-sides]: Possible directions for sphere surface-normal geometry
  ](../images/fig-1.07-normal-sides.jpg)

We need to choose one of these possibilities because we will eventually want to determine which side
of the surface that the ray is coming from. This is important for objects that are rendered
differently on each side, like the text on a two-sided sheet of paper, or for objects that have an
inside and an outside, like glass balls.

If we decide to have the normals always point out, then we will need to determine which side the ray
is on when we color it. We can figure this out by comparing the ray with the normal. If the ray and
the normal face in the same direction, the ray is inside the object, if the ray and the normal face
in the opposite direction, then the ray is outside the object. This can be determined by taking the
dot product of the two vectors, where if their dot is positive, the ray is inside the sphere.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    if (dot(ray_direction, outward_normal) > 0.0) {
        // ray is inside the sphere
        ...
    } else {
        // ray is outside the sphere
        ...
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-normal-comparison]: Comparing the ray and the normal]

<div class='together'>
If we decide to have the normals always point against the ray, we won't be able to use the dot
product to determine which side of the surface the ray is on. Instead, we would need to store that
information:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    bool front_face;
    if (dot(ray_direction, outward_normal) > 0.0) {
        // ray is inside the sphere
        normal = -outward_normal;
        front_face = false;
    } else {
        // ray is outside the sphere
        normal = outward_normal;
        front_face = true;
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [normals-point-against]: Remembering the side of the surface]

</div>

We can set things up so that normals always point “outward” from the surface, or always point
against the incident ray. This decision is determined by whether you want to determine the side of
the surface at the time of geometry intersection or at the time of coloring. In this book we have
more material types than we have geometry types, so we'll go for less work and put the determination
at geometry time. This is simply a matter of preference, and you'll see both implementations in the
literature.

We add the `front_face` bool to the `hit_record` class. We'll also add a function to solve this
calculation for us: `set_face_normal()`. For convenience we will assume that the vector passed to
the new `set_face_normal()` function is of unit length. We could always normalize the parameter
explicitly, but it's more efficient if the geometry code does this, as it's usually easier when you
know more about the specific geometry.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class hit_record {
      public:
        point3 p;
        vec3 normal;
        double t;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        bool front_face;

        void set_face_normal(const ray& r, const vec3& outward_normal) {
            // Sets the hit record normal vector.
            // NOTE: the parameter `outward_normal` is assumed to have unit length.

            front_face = dot(r.direction(), outward_normal) < 0;
            normal = front_face ? outward_normal : -outward_normal;
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [front-face-tracking]: <kbd>[hittable.h]</kbd> Adding front-face tracking to hit_record]

<div class='together'>
And then we add the surface side determination to the class:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class sphere : public hittable {
      public:
        ...
        bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const {
            ...

            rec.t = root;
            rec.p = r.at(rec.t);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            vec3 outward_normal = (rec.p - center) / radius;
            rec.set_face_normal(r, outward_normal);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

            return true;
        }
        ...
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [sphere-final]: <kbd>[sphere.h]</kbd> The sphere class with normal determination]

</div>


A List of Hittable Objects
---------------------------
We have a generic object called a `hittable` that the ray can intersect with. We now add a class
that stores a list of `hittable`s:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef HITTABLE_LIST_H
    #define HITTABLE_LIST_H

    #include "hittable.h"

    #include <memory>
    #include <vector>

    using std::make_shared;
    using std::shared_ptr;

    class hittable_list : public hittable {
      public:
        std::vector<shared_ptr<hittable>> objects;

        hittable_list() {}
        hittable_list(shared_ptr<hittable> object) { add(object); }

        void clear() { objects.clear(); }

        void add(shared_ptr<hittable> object) {
            objects.push_back(object);
        }

        bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const override {
            hit_record temp_rec;
            bool hit_anything = false;
            auto closest_so_far = ray_tmax;

            for (const auto& object : objects) {
                if (object->hit(r, ray_tmin, closest_so_far, temp_rec)) {
                    hit_anything = true;
                    closest_so_far = temp_rec.t;
                    rec = temp_rec;
                }
            }

            return hit_anything;
        }
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [hittable-list-initial]: <kbd>[hittable_list.h]</kbd> The hittable_list class]


Some New C++ Features
----------------------
The `hittable_list` class code uses some C++ features that may trip you up if you're not normally a
C++ programmer: `vector`, `shared_ptr`, and `make_shared`.

`shared_ptr<type>` is a pointer to some allocated type, with reference-counting semantics. Every
time you assign its value to another shared pointer (usually with a simple assignment), the
reference count is incremented. As shared pointers go out of scope (like at the end of a block or
function), the reference count is decremented. Once the count goes to zero, the object is safely
deleted.

<div class='together'>
Typically, a shared pointer is first initialized with a newly-allocated object, something like this:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    shared_ptr<double> double_ptr = make_shared<double>(0.37);
    shared_ptr<vec3>   vec3_ptr   = make_shared<vec3>(1.414214, 2.718281, 1.618034);
    shared_ptr<sphere> sphere_ptr = make_shared<sphere>(point3(0,0,0), 1.0);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [shared-ptr]: An example allocation using shared_ptr]

</div>

`make_shared<thing>(thing_constructor_params ...)` allocates a new instance of type `thing`, using
the constructor parameters. It returns a `shared_ptr<thing>`.

<div class='together'>
Since the type can be automatically deduced by the return type of `make_shared<type>(...)`, the
above lines can be more simply expressed using C++'s `auto` type specifier:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    auto double_ptr = make_shared<double>(0.37);
    auto vec3_ptr   = make_shared<vec3>(1.414214, 2.718281, 1.618034);
    auto sphere_ptr = make_shared<sphere>(point3(0,0,0), 1.0);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [shared-ptr-auto]: An example allocation using shared_ptr with auto type]

</div>

We'll use shared pointers in our code, because it allows multiple geometries to share a common
instance (for example, a bunch of spheres that all use the same color material), and because it
makes memory management automatic and easier to reason about.

`std::shared_ptr` is included with the `<memory>` header.

The second C++ feature you may be unfamiliar with is `std::vector`. This is a generic array-like
collection of an arbitrary type. Above, we use a collection of pointers to `hittable`. `std::vector`
automatically grows as more values are added: `objects.push_back(object)` adds a value to the end of
the `std::vector` member variable `objects`.

`std::vector` is included with the `<vector>` header.

Finally, the `using` statements in listing [hittable-list-initial] tell the compiler that we'll be
getting `shared_ptr` and `make_shared` from the `std` library, so we don't need to prefix these with
`std::` every time we reference them.


Common Constants and Utility Functions
---------------------------------------
We need some math constants that we conveniently define in their own header file. For now we only
need infinity, but we will also throw our own definition of pi in there, which we will need later.
We'll also throw common useful constants and future utility functions in here. This new header,
`rtweekend.h`, will be our general main header file.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef RTWEEKEND_H
    #define RTWEEKEND_H

    #include <cmath>
    #include <iostream>
    #include <limits>
    #include <memory>


    // C++ Std Usings

    using std::make_shared;
    using std::shared_ptr;

    // Constants

    const double infinity = std::numeric_limits<double>::infinity();
    const double pi = 3.1415926535897932385;

    // Utility Functions

    inline double degrees_to_radians(double degrees) {
        return degrees * pi / 180.0;
    }

    // Common Headers

    #include "color.h"
    #include "ray.h"
    #include "vec3.h"

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [rtweekend-initial]: <kbd>[rtweekend.h]</kbd> The rtweekend.h common header]

Program files will include `rtweekend.h` first, so all other header files (where the bulk of our
code will reside) can implicitly assume that `rtweekend.h` has already been included. Header files
still need to explicitly include any other necessary header files. We'll make some updates with
these assumptions in mind.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    #include <iostream>
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [assume-rtw-color]: <kbd>[color.h]</kbd> Assume rtweekend.h inclusion for color.h]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    #include "ray.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [assume-rtw-hittable]: <kbd>[hittable.h]</kbd> Assume rtweekend.h inclusion for hittable.h]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    #include <memory>
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include <vector>


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    using std::make_shared;
    using std::shared_ptr;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [assume-rtw-hittable-list]: <kbd>[hittable_list.h]</kbd> Assume rtweekend.h inclusion for hittable_list.h]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    #include "vec3.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [assume-rtw-sphere]: <kbd>[sphere.h]</kbd> Assume rtweekend.h inclusion for sphere.h]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    #include <cmath>
    #include <iostream>
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [assume-rtw-vec3]: <kbd>[vec3.h]</kbd> Assume rtweekend.h inclusion for vec3.h]

<div class='together'>
And now the new main:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include "rtweekend.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    #include "color.h"
    #include "ray.h"
    #include "vec3.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include "hittable.h"
    #include "hittable_list.h"
    #include "sphere.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    #include <iostream>
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    double hit_sphere(const point3& center, double radius, const ray& r) {
        ...
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    color ray_color(const ray& r, const hittable& world) {
        hit_record rec;
        if (world.hit(r, 0, infinity, rec)) {
            return 0.5 * (rec.normal + color(1,1,1));
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        vec3 unit_direction = unit_vector(r.direction());
        auto a = 0.5*(unit_direction.y() + 1.0);
        return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
    }

    int main() {

        // Image

        auto aspect_ratio = 16.0 / 9.0;
        int image_width = 400;

        // Calculate the image height, and ensure that it's at least 1.
        int image_height = int(image_width / aspect_ratio);
        image_height = (image_height < 1) ? 1 : image_height;


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        // World

        hittable_list world;

        world.add(make_shared<sphere>(point3(0,0,-1), 0.5));
        world.add(make_shared<sphere>(point3(0,-100.5,-1), 100));
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        // Camera

        auto focal_length = 1.0;
        auto viewport_height = 2.0;
        auto viewport_width = viewport_height * (double(image_width)/image_height);
        auto camera_center = point3(0, 0, 0);

        // Calculate the vectors across the horizontal and down the vertical viewport edges.
        auto viewport_u = vec3(viewport_width, 0, 0);
        auto viewport_v = vec3(0, -viewport_height, 0);

        // Calculate the horizontal and vertical delta vectors from pixel to pixel.
        auto pixel_delta_u = viewport_u / image_width;
        auto pixel_delta_v = viewport_v / image_height;

        // Calculate the location of the upper left pixel.
        auto viewport_upper_left = camera_center
                                 - vec3(0, 0, focal_length) - viewport_u/2 - viewport_v/2;
        auto pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);

        // Render

        std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

        for (int j = 0; j < image_height; j++) {
            std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
            for (int i = 0; i < image_width; i++) {
                auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);
                auto ray_direction = pixel_center - camera_center;
                ray r(camera_center, ray_direction);


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                color pixel_color = ray_color(r, world);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                write_color(std::cout, pixel_color);
            }
        }

        std::clog << "\rDone.                 \n";
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-with-rtweekend-h]: <kbd>[main.cc]</kbd> The new main with hittables]

</div>

This yields a picture that is really just a visualization of where the spheres are located along
with their surface normal. This is often a great way to view any flaws or specific characteristics
of a geometric model.

  ![<span class='num'>Image 5:</span> Resulting render of normals-colored sphere with ground
  ](../images/img-1.05-normals-sphere-ground.png class='pixel')


An Interval Class
------------------
Before we continue, we'll implement an interval class to manage real-valued intervals with a minimum
and a maximum. We'll end up using this class quite often as we proceed.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef INTERVAL_H
    #define INTERVAL_H

    class interval {
      public:
        double min, max;

        interval() : min(+infinity), max(-infinity) {} // Default interval is empty

        interval(double min, double max) : min(min), max(max) {}

        double size() const {
            return max - min;
        }

        bool contains(double x) const {
            return min <= x && x <= max;
        }

        bool surrounds(double x) const {
            return min < x && x < max;
        }

        static const interval empty, universe;
    };

    const interval interval::empty    = interval(+infinity, -infinity);
    const interval interval::universe = interval(-infinity, +infinity);

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [interval-initial]: <kbd>[interval.h]</kbd> Introducing the new interval class]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    // Common Headers

    #include "color.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include "interval.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include "ray.h"
    #include "vec3.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [interval-rtweekend]: <kbd>[rtweekend.h]</kbd> Including the new interval class]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class hittable {
      public:
        ...
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [hittable-with-interval]: <kbd>[hittable.h]</kbd> hittable::hit() using interval]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class hittable_list : public hittable {
      public:
        ...
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            hit_record temp_rec;
            bool hit_anything = false;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            auto closest_so_far = ray_t.max;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

            for (const auto& object : objects) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                if (object->hit(r, interval(ray_t.min, closest_so_far), temp_rec)) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                    hit_anything = true;
                    closest_so_far = temp_rec.t;
                    rec = temp_rec;
                }
            }

            return hit_anything;
        }
        ...
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [hittable-list-with-interval]: <kbd>[hittable_list.h]</kbd> hittable_list::hit() using interval]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class sphere : public hittable {
      public:
        ...
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            ...

            // Find the nearest root that lies in the acceptable range.
            auto root = (h - sqrtd) / a;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            if (!ray_t.surrounds(root)) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                root = (h + sqrtd) / a;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                if (!ray_t.surrounds(root))
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                    return false;
            }
            ...
        }
        ...
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [sphere-with-interval]: <kbd>[sphere.h]</kbd> sphere using interval]


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    color ray_color(const ray& r, const hittable& world) {
        hit_record rec;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        if (world.hit(r, interval(0, infinity), rec)) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            return 0.5 * (rec.normal + color(1,1,1));
        }

        vec3 unit_direction = unit_vector(r.direction());
        auto a = 0.5*(unit_direction.y() + 1.0);
        return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-with-interval]: <kbd>[main.cc]</kbd> The new main using interval]



Moving Camera Code Into Its Own Class
====================================================================================================
Before continuing, now is a good time to consolidate our camera and scene-render code into a single
new class: the `camera` class. The camera class will be responsible for two important jobs:

  1. Construct and dispatch rays into the world.
  2. Use the results of these rays to construct the rendered image.

In this refactoring, we'll collect the `ray_color()` function, along with the image, camera, and
render sections of our main program. The new camera class will contain two public methods
`initialize()` and `render()`, plus two private helper methods `get_ray()` and `ray_color()`.

Ultimately, the camera will follow the simplest usage pattern that we could think of: it will be
default constructed no arguments, then the owning code will modify the camera's public variables
through simple assignment, and finally everything is initialized by a call to the `initialize()`
function. This pattern is chosen instead of the owner calling a constructor with a ton of parameters
or by defining and calling a bunch of setter methods. Instead, the owning code only needs to set
what it explicitly cares about. Finally, we could either have the owning code call `initialize()`,
or just have the camera call this function automatically at the start of `render()`. We'll use the
second approach.

After main creates a camera and sets default values, it will call the `render()` method. The
`render()` method will prepare the camera for rendering and then execute the render loop.

<div class='together'>
Here's the skeleton of our new `camera` class:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #ifndef CAMERA_H
    #define CAMERA_H

    #include "hittable.h"

    class camera {
      public:
        /* Public Camera Parameters Here */

        void render(const hittable& world) {
            ...
        }

      private:
        /* Private Camera Variables Here */

        void initialize() {
            ...
        }

        color ray_color(const ray& r, const hittable& world) const {
            ...
        }
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [camera-skeleton]: <kbd>[camera.h]</kbd> The camera class skeleton]

</div>

<div class='together'>
To begin with, let's fill in the `ray_color()` function from `main.cc`:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
      ...

      private:
        ...


        color ray_color(const ray& r, const hittable& world) const {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            hit_record rec;

            if (world.hit(r, interval(0, infinity), rec)) {
                return 0.5 * (rec.normal + color(1,1,1));
            }

            vec3 unit_direction = unit_vector(r.direction());
            auto a = 0.5*(unit_direction.y() + 1.0);
            return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
        }
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [camera-ray-color]: <kbd>[camera.h]</kbd> The camera::ray_color function]

</div>

<div class='together'>
Now we move almost everything from the `main()` function into our new camera class. The only thing
remaining in the `main()` function is the world construction. Here's the camera class with newly
migrated code:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
      public:
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        double aspect_ratio = 1.0;  // Ratio of image width over height
        int    image_width  = 100;  // Rendered image width in pixel count

        void render(const hittable& world) {
            initialize();

            std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

            for (int j = 0; j < image_height; j++) {
                std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
                for (int i = 0; i < image_width; i++) {
                    auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);
                    auto ray_direction = pixel_center - center;
                    ray r(center, ray_direction);

                    color pixel_color = ray_color(r, world);
                    write_color(std::cout, pixel_color);
                }
            }

            std::clog << "\rDone.                 \n";
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

      private:
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        int    image_height;   // Rendered image height
        point3 center;         // Camera center
        point3 pixel00_loc;    // Location of pixel 0, 0
        vec3   pixel_delta_u;  // Offset to pixel to the right
        vec3   pixel_delta_v;  // Offset to pixel below

        void initialize() {
            image_height = int(image_width / aspect_ratio);
            image_height = (image_height < 1) ? 1 : image_height;

            center = point3(0, 0, 0);

            // Determine viewport dimensions.
            auto focal_length = 1.0;
            auto viewport_height = 2.0;
            auto viewport_width = viewport_height * (double(image_width)/image_height);

            // Calculate the vectors across the horizontal and down the vertical viewport edges.
            auto viewport_u = vec3(viewport_width, 0, 0);
            auto viewport_v = vec3(0, -viewport_height, 0);

            // Calculate the horizontal and vertical delta vectors from pixel to pixel.
            pixel_delta_u = viewport_u / image_width;
            pixel_delta_v = viewport_v / image_height;

            // Calculate the location of the upper left pixel.
            auto viewport_upper_left =
                center - vec3(0, 0, focal_length) - viewport_u/2 - viewport_v/2;
            pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        color ray_color(const ray& r, const hittable& world) const {
            ...
        }
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [camera-working]: <kbd>[camera.h]</kbd> The working camera class]

</div>

<div class='together'>
And here's the much reduced main:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include "rtweekend.h"


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include "camera.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include "hittable.h"
    #include "hittable_list.h"
    #include "sphere.h"


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
    color ray_color(const ray& r, const hittable& world) {
        ...
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

    int main() {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        hittable_list world;

        world.add(make_shared<sphere>(point3(0,0,-1), 0.5));
        world.add(make_shared<sphere>(point3(0,-100.5,-1), 100));

        camera cam;

        cam.aspect_ratio = 16.0 / 9.0;
        cam.image_width  = 400;

        cam.render(world);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-with-new-camera]: <kbd>[main.cc]</kbd> The new main, using the new camera]

</div>

Running this newly refactored program should give us the same rendered image as before.



Antialiasing
====================================================================================================
If you zoom into the rendered images so far, you might notice the harsh "stair step" nature of edges
in our rendered images. This stair-stepping is commonly referred to as "aliasing", or "jaggies".
When a real camera takes a picture, there are usually no jaggies along edges, because the edge
pixels are a blend of some foreground and some background. Consider that unlike our rendered images,
a true image of the world is continuous. Put another way, the world (and any true image of it) has
effectively infinite resolution. We can get the same effect by averaging a bunch of samples for each
pixel.

With a single ray through the center of each pixel, we are performing what is commonly called _point
sampling_. The problem with point sampling can be illustrated by rendering a small checkerboard far
away. If this checkerboard consists of an 8&times;8 grid of black and white tiles, but only four
rays hit it, then all four rays might intersect only white tiles, or only black, or some odd
combination. In the real world, when we perceive a checkerboard far away with our eyes, we perceive
it as a gray color, instead of sharp points of black and white. That's because our eyes are
naturally doing what we want our ray tracer to do: integrate the (continuous function of) light
falling on a particular (discrete) region of our rendered image.

Clearly we don't gain anything by just resampling the same ray through the pixel center multiple
times -- we'd just get the same result each time. Instead, we want to sample the light falling
_around_ the pixel, and then integrate those samples to approximate the true continuous result. So,
how do we integrate the light falling around the pixel?

We'll adopt the simplest model: sampling the square region centered at the pixel that extends
halfway to each of the four neighboring pixels. This is not the optimal approach, but it is the most
straight-forward. (See [_A Pixel is Not a Little Square_][square-pixels] for a deeper dive into this
topic.)

  ![Figure [pixel-samples]: Pixel samples](../images/fig-1.08-pixel-samples.jpg)


Some Random Number Utilities
-----------------------------
We're going to need a random number generator that returns real random numbers. This function should
return a canonical random number, which by convention falls in the range $0 ≤ n < 1$. The “less
than” before the 1 is important, as we will sometimes take advantage of that.

A simple approach to this is to use the `std::rand()` function that can be found in `<cstdlib>`,
which returns a random integer in the range 0 and `RAND_MAX`. Hence we can get a real random number
as desired with the following code snippet, added to `rtweekend.h`:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include <cmath>
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include <cstdlib>
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include <iostream>
    #include <limits>
    #include <memory>
    ...

    // Utility Functions

    inline double degrees_to_radians(double degrees) {
        return degrees * pi / 180.0;
    }


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    inline double random_double() {
        // Returns a random real in [0,1).
        return std::rand() / (RAND_MAX + 1.0);
    }

    inline double random_double(double min, double max) {
        // Returns a random real in [min,max).
        return min + (max-min)*random_double();
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [random-double]: <kbd>[rtweekend.h]</kbd> random_double() functions]

C++ did not traditionally have a standard random number generator, but newer versions of C++ have
addressed this issue with the `<random>` header (if imperfectly according to some experts). If you
want to use this, you can obtain a random number with the conditions we need as follows:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    ...


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include <random>
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

    ...


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    inline double random_double() {
        static std::uniform_real_distribution<double> distribution(0.0, 1.0);
        static std::mt19937 generator;
        return distribution(generator);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

    inline double random_double(double min, double max) {
        // Returns a random real in [min,max).
        return min + (max-min)*random_double();
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++


    ...

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [random-double-alt]: <kbd>[rtweekend.h]</kbd> random_double(), alternate implementation]


Generating Pixels with Multiple Samples
----------------------------------------
For a single pixel composed of multiple samples, we'll select samples from the area surrounding the
pixel and average the resulting light (color) values together.

First we'll update the `write_color()` function to account for the number of samples we use: we need
to find the average across all of the samples that we take. To do this, we'll add the full color
from each iteration, and then finish with a single division (by the number of samples) at the end,
before writing out the color. To ensure that the color components of the final result remain within
the proper $[0,1]$ bounds, we'll add and use a small helper function: `interval::clamp(x)`.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class interval {
      public:
        ...

        bool surrounds(double x) const {
            return min < x && x < max;
        }


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        double clamp(double x) const {
            if (x < min) return min;
            if (x > max) return max;
            return x;
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
        ...
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [clamp]: <kbd>[interval.h]</kbd> The interval::clamp() utility function]

Here's the updated `write_color()` function that incorporates the interval clamping function:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    #include "interval.h"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    #include "vec3.h"

    using color = vec3;

    void write_color(std::ostream& out, const color& pixel_color) {
        auto r = pixel_color.x();
        auto g = pixel_color.y();
        auto b = pixel_color.z();

        // Translate the [0,1] component values to the byte range [0,255].
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        static const interval intensity(0.000, 0.999);
        int rbyte = int(256 * intensity.clamp(r));
        int gbyte = int(256 * intensity.clamp(g));
        int bbyte = int(256 * intensity.clamp(b));
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        // Write out the pixel color components.
        out << rbyte << ' ' << gbyte << ' ' << bbyte << '\n';
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [write-color-clamped]: <kbd>[color.h]</kbd> The multi-sample write_color() function]

Now let's update the camera class to define and use a new `camera::get_ray(i,j)` function, which
will generate different samples for each pixel. This function will use a new helper function
`sample_square()` that generates a random sample point within the unit square centered at the
origin. We then transform the random sample from this ideal square back to the particular pixel
we're currently sampling.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
      public:
        double aspect_ratio      = 1.0;  // Ratio of image width over height
        int    image_width       = 100;  // Rendered image width in pixel count
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        int    samples_per_pixel = 10;   // Count of random samples for each pixel
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        void render(const hittable& world) {
            initialize();

            std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

            for (int j = 0; j < image_height; j++) {
                std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
                for (int i = 0; i < image_width; i++) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                    color pixel_color(0,0,0);
                    for (int sample = 0; sample < samples_per_pixel; sample++) {
                        ray r = get_ray(i, j);
                        pixel_color += ray_color(r, world);
                    }
                    write_color(std::cout, pixel_samples_scale * pixel_color);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                }
            }

            std::clog << "\rDone.                 \n";
        }
        ...
      private:
        int    image_height;         // Rendered image height
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        double pixel_samples_scale;  // Color scale factor for a sum of pixel samples
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
        point3 center;               // Camera center
        point3 pixel00_loc;          // Location of pixel 0, 0
        vec3   pixel_delta_u;        // Offset to pixel to the right
        vec3   pixel_delta_v;        // Offset to pixel below

        void initialize() {
            image_height = int(image_width / aspect_ratio);
            image_height = (image_height < 1) ? 1 : image_height;


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            pixel_samples_scale = 1.0 / samples_per_pixel;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

            center = point3(0, 0, 0);
            ...
        }


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        ray get_ray(int i, int j) const {
            // Construct a camera ray originating from the origin and directed at randomly sampled
            // point around the pixel location i, j.

            auto offset = sample_square();
            auto pixel_sample = pixel00_loc
                              + ((i + offset.x()) * pixel_delta_u)
                              + ((j + offset.y()) * pixel_delta_v);

            auto ray_origin = center;
            auto ray_direction = pixel_sample - ray_origin;

            return ray(ray_origin, ray_direction);
        }

        vec3 sample_square() const {
            // Returns the vector to a random point in the [-.5,-.5]-[+.5,+.5] unit square.
            return vec3(random_double() - 0.5, random_double() - 0.5, 0);
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        color ray_color(const ray& r, const hittable& world) const {
            ...
        }
    };

    #endif
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [camera-spp]: <kbd>[camera.h]</kbd> Camera with samples-per-pixel parameter]

</div>

(In addition to the new `sample_square()` function above, you'll also find the function
`sample_disk()` in the Github source code. This is included in case you'd like to experiment with
non-square pixels, but we won't be using it in this book. `sample_disk()` depends on the function
`random_in_unit_disk()` which is defined later on.)

<div class='together'>
Main is updated to set the new camera parameter.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    int main() {
        ...

        camera cam;

        cam.aspect_ratio      = 16.0 / 9.0;
        cam.image_width       = 400;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        cam.samples_per_pixel = 100;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        cam.render(world);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-spp]: <kbd>[main.cc]</kbd> Setting the new samples-per-pixel parameter]

</div>

<div class='together'>
Zooming into the image that is produced, we can see the difference in edge pixels.

  ![<span class='num'>Image 6:</span> Before and after antialiasing
  ](../images/img-1.06-antialias-before-after.png class='pixel')

</div>



Diffuse Materials
====================================================================================================
Now that we have objects and multiple rays per pixel, we can make some realistic looking materials.
We’ll start with diffuse materials (also called _matte_). One question is whether we mix and match
geometry and materials (so that we can assign a material to multiple spheres, or vice versa) or if
geometry and materials are tightly bound (which could be useful for procedural objects where the
geometry and material are linked). We’ll go with separate -- which is usual in most renderers -- but
do be aware that there are alternative approaches.

A Simple Diffuse Material
--------------------------
Diffuse objects that don’t emit their own light merely take on the color of their surroundings, but
they do modulate that with their own intrinsic color. Light that reflects off a diffuse surface has
its direction randomized, so, if we send three rays into a crack between two diffuse surfaces they
will each have different random behavior:

  ![Figure [light-bounce]: Light ray bounces](../images/fig-1.09-light-bounce.jpg)

They might also be absorbed rather than reflected. The darker the surface, the more likely the ray
is absorbed (that’s why it's dark!). Really any algorithm that randomizes direction will produce
surfaces that look matte. Let's start with the most intuitive: a surface that randomly bounces a ray
equally in all directions. For this material, a ray that hits the surface has an equal probability
of bouncing in any direction away from the surface.

  ![Figure [random-vec-hor]: Equal reflection above the horizon
  ](../images/fig-1.10-random-vec-horizon.jpg)

This very intuitive material is the simplest kind of diffuse and -- indeed -- many of the first
raytracing papers used this diffuse method (before adopting a more accurate method that we'll be
implementing a little bit later). We don't currently have a way to randomly reflect a ray, so we'll
need to add a few functions to our vector utility header. The first thing we need is the ability to
generate arbitrary random vectors:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class vec3 {
      public:
        ...

        double length_squared() const {
            return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
        }


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        static vec3 random() {
            return vec3(random_double(), random_double(), random_double());
        }

        static vec3 random(double min, double max) {
            return vec3(random_double(min,max), random_double(min,max), random_double(min,max));
        }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [vec-rand-util]: <kbd>[vec3.h]</kbd> vec3 random utility functions]

Then we need to figure out how to manipulate a random vector so that we only get results that are on
the surface of a hemisphere. There are analytical methods of doing this, but they are actually
surprisingly complicated to understand, and quite a bit complicated to implement. Instead, we'll use
what is typically the easiest algorithm: A rejection method. A rejection method works by repeatedly
generating random samples until we produce a sample that meets the desired criteria. In other words,
keep rejecting bad samples until you find a good one.

There are many equally valid ways of generating a random vector on a hemisphere using the rejection
method, but for our purposes we will go with the simplest, which is:

1. Generate a random vector inside the unit sphere
2. Normalize this vector to extend it to the sphere surface
3. Invert the normalized vector if it falls onto the wrong hemisphere

<div class='together'>
First, we will use a rejection method to generate the random vector inside the unit sphere (that is,
a sphere of radius 1). Pick a random point inside the cube enclosing the unit sphere (that is, where
$x$, $y$, and $z$ are all in the range $[-1,+1]$). If this point lies outside the unit
sphere, then generate a new one until we find one that lies inside or on the unit sphere.

  ![Figure [sphere-vec]: Two vectors were rejected before finding a good one (pre-normalization)
  ](../images/fig-1.11-sphere-vec.jpg)

  ![Figure [sphere-vec]: The accepted random vector is normalized to produce a unit vector
  ](../images/fig-1.12-sphere-unit-vec.jpg)

Here's our first draft of the function:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    ...

    inline vec3 unit_vector(const vec3& v) {
        return v / v.length();
    }


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    inline vec3 random_unit_vector() {
        while (true) {
            auto p = vec3::random(-1,1);
            auto lensq = p.length_squared();
            if (lensq <= 1)
                return p / sqrt(lensq);
        }
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [random-unit-vector-1]: <kbd>[vec3.h]</kbd> The random_unit_vector() function, version one]

</div>

Sadly, we have a small floating-point abstraction leak to deal with. Since floating-point numbers
have finite precision, a very small value can underflow to zero when squared. So if all three
coordinates are small enough (that is, very near the center of the sphere), the norm of the vector
will be zero, and thus normalizing will yield the bogus vector $[\pm\infty, \pm\infty, \pm\infty]$.
To fix this, we'll also reject points that lie inside this "black hole" around the center. With
double precision (64-bit floats), we can safely support values greater than $10^{-160}$.

Here's our more robust function:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    inline vec3 random_unit_vector() {
        while (true) {
            auto p = vec3::random(-1,1);
            auto lensq = p.length_squared();
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            if (1e-160 < lensq && lensq <= 1)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                return p / sqrt(lensq);
        }
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [random-unit-vector-2]: <kbd>[vec3.h]</kbd> The random_unit_vector() function, version two]

<div class='together'>
Now that we have a random unit vector, we can determine if it is on the correct hemisphere by
comparing against the surface normal:

  ![Figure [normal-hor]: The normal vector tells us which hemisphere we need
  ](../images/fig-1.13-surface-normal.jpg)

</div>

<div class='together'>
We can take the dot product of the surface normal and our random vector to determine if it's in the
correct hemisphere. If the dot product is positive, then the vector is in the correct hemisphere. If
the dot product is negative, then we need to invert the vector.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    ...

    inline vec3 random_unit_vector() {
        while (true) {
            auto p = vec3::random(-1,1);
            auto lensq = p.length_squared();
            if (1e-160 < lensq && lensq <= 1)
                return p / sqrt(lensq);
        }
    }


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
    inline vec3 random_on_hemisphere(const vec3& normal) {
        vec3 on_unit_sphere = random_unit_vector();
        if (dot(on_unit_sphere, normal) > 0.0) // In the same hemisphere as the normal
            return on_unit_sphere;
        else
            return -on_unit_sphere;
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [random-in-hemisphere]: <kbd>[vec3.h]</kbd> The random_on_hemisphere() function]

</div>

If a ray bounces off of a material and keeps 100% of its color, then we say that the material is
_white_. If a ray bounces off of a material and keeps 0% of its color, then we say that the material
is black. As a first demonstration of our new diffuse material we'll set the `ray_color` function to
return 50% of the color from a bounce. We should expect to get a nice gray color.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
      ...
      private:
        ...
        color ray_color(const ray& r, const hittable& world) const {
            hit_record rec;

            if (world.hit(r, interval(0, infinity), rec)) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                vec3 direction = random_on_hemisphere(rec.normal);
                return 0.5 * ray_color(ray(rec.p, direction), world);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            }

            vec3 unit_direction = unit_vector(r.direction());
            auto a = 0.5*(unit_direction.y() + 1.0);
            return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
        }
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-color-random-unit]: <kbd>[camera.h]</kbd> ray_color() using a random ray direction]

<div class='together'>
... Indeed we do get rather nice gray spheres:

  ![<span class='num'>Image 7:</span> First render of a diffuse sphere
  ](../images/img-1.07-first-diffuse.png class='pixel')

</div>


Limiting the Number of Child Rays
----------------------------------
There's one potential problem lurking here. Notice that the `ray_color` function is recursive. When
will it stop recursing? When it fails to hit anything. In some cases, however, that may be a long
time -- long enough to blow the stack. To guard against that, let's limit the maximum recursion
depth, returning no light contribution at the maximum depth:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
      public:
        double aspect_ratio      = 1.0;  // Ratio of image width over height
        int    image_width       = 100;  // Rendered image width in pixel count
        int    samples_per_pixel = 10;   // Count of random samples for each pixel
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        int    max_depth         = 10;   // Maximum number of ray bounces into scene
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        void render(const hittable& world) {
            initialize();

            std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

            for (int j = 0; j < image_height; j++) {
                std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
                for (int i = 0; i < image_width; i++) {
                    color pixel_color(0,0,0);
                    for (int sample = 0; sample < samples_per_pixel; sample++) {
                        ray r = get_ray(i, j);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                        pixel_color += ray_color(r, max_depth, world);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                    }
                    write_color(std::cout, pixel_samples_scale * pixel_color);
                }
            }

            std::clog << "\rDone.                 \n";
        }
        ...
      private:
        ...
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        color ray_color(const ray& r, int depth, const hittable& world) const {
            // If we've exceeded the ray bounce limit, no more light is gathered.
            if (depth <= 0)
                return color(0,0,0);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

            hit_record rec;

            if (world.hit(r, interval(0, infinity), rec)) {
                vec3 direction = random_on_hemisphere(rec.normal);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                return 0.5 * ray_color(ray(rec.p, direction), depth-1, world);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            }

            vec3 unit_direction = unit_vector(r.direction());
            auto a = 0.5*(unit_direction.y() + 1.0);
            return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
        }
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-color-depth]: <kbd>[camera.h]</kbd> camera::ray_color() with depth limiting]

<div class='together'>
Update the main() function to use this new depth limit:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    int main() {
        ...

        camera cam;

        cam.aspect_ratio      = 16.0 / 9.0;
        cam.image_width       = 400;
        cam.samples_per_pixel = 100;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
        cam.max_depth         = 50;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++

        cam.render(world);
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [main-ray-depth]: <kbd>[main.cc]</kbd> Using the new ray depth limiting]

</div>

<div class='together'>
For this very simple scene we should get basically the same result:

  ![<span class='num'>Image 8:</span> Second render of a diffuse sphere with limited bounces
  ](../images/img-1.08-second-diffuse.png class='pixel')

</div>


Fixing Shadow Acne
-------------------
There’s also a subtle bug that we need to address. A ray will attempt to accurately calculate the
intersection point when it intersects with a surface. Unfortunately for us, this calculation is
susceptible to floating point rounding errors which can cause the intersection point to be ever so
slightly off. This means that the origin of the next ray, the ray that is randomly scattered off of
the surface, is unlikely to be perfectly flush with the surface. It might be just above the surface.
It might be just below the surface. If the ray's origin is just below the surface then it could
intersect with that surface again. Which means that it will find the nearest surface at
$t=0.00000001$ or whatever floating point approximation the hit function gives us. The simplest hack
to address this is just to ignore hits that are very close to the calculated intersection point:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
      ...
      private:
        ...
        color ray_color(const ray& r, int depth, const hittable& world) const {
            // If we've exceeded the ray bounce limit, no more light is gathered.
            if (depth <= 0)
                return color(0,0,0);

            hit_record rec;


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
            if (world.hit(r, interval(0.001, infinity), rec)) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                vec3 direction = random_on_hemisphere(rec.normal);
                return 0.5 * ray_color(ray(rec.p, direction), depth-1, world);
            }

            vec3 unit_direction = unit_vector(r.direction());
            auto a = 0.5*(unit_direction.y() + 1.0);
            return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
        }
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [reflect-tolerance]: <kbd>[camera.h]</kbd> Calculating reflected ray origins with tolerance]

<div class='together'>
This gets rid of the shadow acne problem. Yes it is really called that. Here's the result:

  ![<span class='num'>Image 9:</span> Diffuse sphere with no shadow acne
  ](../images/img-1.09-no-acne.png class='pixel')

</div>


True Lambertian Reflection
---------------------------
Scattering reflected rays evenly about the hemisphere produces a nice soft diffuse model, but we can
definitely do better. A more accurate representation of real diffuse objects is the _Lambertian_
distribution. This distribution scatters reflected rays in a manner that is proportional to $\cos
(\phi)$, where $\phi$ is the angle between the reflected ray and the surface normal. This means that
a reflected ray is most likely to scatter in a direction near the surface normal, and less likely to
scatter in directions away from the normal. This non-uniform Lambertian distribution does a better
job of modeling material reflection in the real world than our previous uniform scattering.

We can create this distribution by adding a random unit vector to the normal vector. At the point of
intersection on a surface there is the hit point, $\mathbf{p}$, and there is the normal of the
surface, $\mathbf{n}$. At the point of intersection, this surface has exactly two sides, so there
can only be two unique unit spheres tangent to any intersection point (one unique sphere for each
side of the surface). These two unit spheres will be displaced from the surface by the length of
their radius, which is exactly one for a unit sphere.

One sphere will be displaced in the direction of the surface's normal ($\mathbf{n}$) and one sphere
will be displaced in the opposite direction ($\mathbf{-n}$). This leaves us with two spheres of unit
size that will only be _just_ touching the surface at the intersection point. From this, one of the
spheres will have its center at $(\mathbf{P} + \mathbf{n})$ and the other sphere will have its
center at $(\mathbf{P} - \mathbf{n})$. The sphere with a center at $(\mathbf{P} - \mathbf{n})$ is
considered _inside_ the surface, whereas the sphere with center $(\mathbf{P} + \mathbf{n})$ is
considered _outside_ the surface.

We want to select the tangent unit sphere that is on the same side of the surface as the ray origin.
Pick a random point $\mathbf{S}$ on this unit radius sphere and send a ray from the hit point
$\mathbf{P}$ to the random point $\mathbf{S}$ (this is the vector $(\mathbf{S}-\mathbf{P})$):

  ![Figure [rand-unitvec]: Randomly generating a vector according to Lambertian distribution
  ](../images/fig-1.14-rand-unitvec.jpg)

<div class='together'>
The change is actually fairly minimal:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
        ...
        color ray_color(const ray& r, int depth, const hittable& world) const {
            // If we've exceeded the ray bounce limit, no more light is gathered.
            if (depth <= 0)
                return color(0,0,0);

            hit_record rec;

            if (world.hit(r, interval(0.001, infinity), rec)) {
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                vec3 direction = rec.normal + random_unit_vector();
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
                return 0.5 * ray_color(ray(rec.p, direction), depth-1, world);
            }

            vec3 unit_direction = unit_vector(r.direction());
            auto a = 0.5*(unit_direction.y() + 1.0);
            return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
        }
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-color-unit-sphere]: <kbd>[camera.h]</kbd> ray_color() with replacement diffuse]

</div>

<div class='together'>
After rendering we get a similar image:

  ![<span class='num'>Image 10:</span> Correct rendering of Lambertian spheres
  ](../images/img-1.10-correct-lambertian.png class='pixel')

</div>

It's hard to tell the difference between these two diffuse methods, given that our scene of two
spheres is so simple, but you should be able to notice two important visual differences:

  1. The shadows are more pronounced after the change
  2. Both spheres are tinted blue from the sky after the change

Both of these changes are due to the less uniform scattering of the light rays--more rays are
scattering toward the normal. This means that for diffuse objects, they will appear _darker_ because
less light bounces toward the camera. For the shadows, more light bounces straight-up, so the area
underneath the sphere is darker.

Not a lot of common, everyday objects are perfectly diffuse, so our visual intuition of how these
objects behave under light can be poorly formed. As scenes become more complicated over the course
of the book, you are encouraged to switch between the different diffuse renderers presented here.
Most scenes of interest will contain a large amount of diffuse materials. You can gain valuable
insight by understanding the effect of different diffuse methods on the lighting of a scene.


Using Gamma Correction for Accurate Color Intensity
----------------------------------------------------
Note the shadowing under the sphere. The picture is very dark, but our spheres only absorb half the
energy of each bounce, so they are 50% reflectors. The spheres should look pretty bright (in real
life, a light grey) but they appear to be rather dark. We can see this more clearly if we walk
through the full brightness gamut for our diffuse material. We start by setting the reflectance of
the `ray_color` function from `0.5` (50%) to `0.1` (10%):

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
    class camera {
        ...
        color ray_color(const ray& r, int depth, const hittable& world) const {
            // If we've exceeded the ray bounce limit, no more light is gathered.
            if (depth <= 0)
                return color(0,0,0);

            hit_record rec;

            if (world.hit(r, interval(0.001, infinity), rec)) {
                vec3 direction = rec.normal + random_unit_vector();
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
                return 0.1 * ray_color(ray(rec.p, direction), depth-1, world);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
            }

            vec3 unit_direction = unit_vector(r.direction());
            auto a = 0.5*(unit_direction.y() + 1.0);
            return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
        }
    };
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [Listing [ray-color-gamut]: <kbd>[camera.h]</kbd> ray_color() with 10% reflectance]

We render out at this new 10% reflectance. We then set reflectance to 30% and render again. We
repeat for 50%, 70%, and finally 90%. You can overlay these images from left to right in the photo
editor of your choice and you should get a very nice visual representation of the increasing
brightness of your chosen gamut. This is the one that we've been working with so far: 

![<span class='num'>Image 11:</span> The gamut of our renderer so far
](../images/img-1.11-linear-gamut.png class='pixel')

If you look closely, or if you use a color picker, you should notice that the 50% reflectance render
(the one in the middle) is far too dark to be half-way between white and black (middle-gray).
Indeed, the 70% reflector is closer to middle-gray. The reason for this is that almost all computer
programs assume that an image is “gamma corrected” before being written into an image file. This
means that the 0 to 1 values have some transform applied before being stored as a byte. Images with
data that are written without being transformed are said to be in _linear space_, whereas images
that are transformed are said to be in _gamma space_. It is likely that the image viewer you are
using is expecting an image in gamma space, but we are giving it an image in linear space. This is
the reason why our image appears inaccur
Download .txt
gitextract_58la6ck5/

├── .gitignore
├── CHANGELOG.md
├── CMakeLists.txt
├── CONTRIBUTING.md
├── COPYING.txt
├── PRINTING.md
├── README.md
├── books/
│   ├── RayTracingInOneWeekend.html
│   ├── RayTracingTheNextWeek.html
│   ├── RayTracingTheRestOfYourLife.html
│   └── acknowledgments.md.html
├── images/
│   ├── cover/
│   │   ├── CoverRTW1.psd
│   │   ├── CoverRTW2.psd
│   │   └── CoverRTW3.psd
│   └── test.ppm
├── index.html
├── src/
│   ├── InOneWeekend/
│   │   ├── camera.h
│   │   ├── color.h
│   │   ├── hittable.h
│   │   ├── hittable_list.h
│   │   ├── interval.h
│   │   ├── main.cc
│   │   ├── material.h
│   │   ├── ray.h
│   │   ├── rtweekend.h
│   │   ├── sphere.h
│   │   └── vec3.h
│   ├── TheNextWeek/
│   │   ├── aabb.h
│   │   ├── bvh.h
│   │   ├── camera.h
│   │   ├── color.h
│   │   ├── constant_medium.h
│   │   ├── hittable.h
│   │   ├── hittable_list.h
│   │   ├── interval.h
│   │   ├── main.cc
│   │   ├── material.h
│   │   ├── perlin.h
│   │   ├── quad.h
│   │   ├── ray.h
│   │   ├── rtw_stb_image.h
│   │   ├── rtweekend.h
│   │   ├── sphere.h
│   │   ├── texture.h
│   │   └── vec3.h
│   ├── TheRestOfYourLife/
│   │   ├── aabb.h
│   │   ├── bvh.h
│   │   ├── camera.h
│   │   ├── color.h
│   │   ├── constant_medium.h
│   │   ├── cos_cubed.cc
│   │   ├── cos_density.cc
│   │   ├── estimate_halfway.cc
│   │   ├── hittable.h
│   │   ├── hittable_list.h
│   │   ├── integrate_x_sq.cc
│   │   ├── interval.h
│   │   ├── main.cc
│   │   ├── material.h
│   │   ├── onb.h
│   │   ├── pdf.h
│   │   ├── perlin.h
│   │   ├── pi.cc
│   │   ├── quad.h
│   │   ├── ray.h
│   │   ├── rtw_stb_image.h
│   │   ├── rtweekend.h
│   │   ├── sphere.h
│   │   ├── sphere_importance.cc
│   │   ├── sphere_plot.cc
│   │   ├── texture.h
│   │   └── vec3.h
│   └── external/
│       ├── stb_image.h
│       └── stb_image_write.h
└── style/
    ├── book-highlight-test.css
    ├── book.css
    └── website.css
Download .txt
SYMBOL INDEX (389 symbols across 58 files)

FILE: src/InOneWeekend/camera.h
  function class (line 18) | class camera {

FILE: src/InOneWeekend/color.h
  function linear_to_gamma (line 20) | inline double linear_to_gamma(double linear_component)
  function write_color (line 29) | void write_color(std::ostream& out, const color& pixel_color) {

FILE: src/InOneWeekend/hittable.h
  function class (line 17) | class hit_record {
  function class (line 35) | class hittable {

FILE: src/InOneWeekend/hittable_list.h
  function class (line 19) | class hittable_list : public hittable {

FILE: src/InOneWeekend/interval.h
  function class (line 12) | class interval {
  function contains (line 24) | bool contains(double x) const {
  function surrounds (line 28) | bool surrounds(double x) const {
  function clamp (line 32) | double clamp(double x) const {

FILE: src/InOneWeekend/main.cc
  function main (line 21) | int main() {

FILE: src/InOneWeekend/material.h
  function class (line 17) | class material {
  function class (line 29) | class lambertian : public material {
  function class (line 51) | class metal : public material {
  function class (line 70) | class dielectric : public material {

FILE: src/InOneWeekend/ray.h
  function class (line 17) | class ray {

FILE: src/InOneWeekend/rtweekend.h
  function degrees_to_radians (line 33) | inline double degrees_to_radians(double degrees) {
  function random_double (line 37) | inline double random_double() {
  function random_double (line 42) | inline double random_double(double min, double max) {

FILE: src/InOneWeekend/sphere.h
  function class (line 17) | class sphere : public hittable {

FILE: src/InOneWeekend/vec3.h
  function class (line 14) | class vec3 {
  function near_zero (line 55) | bool near_zero() const {
  function vec3 (line 65) | static vec3 random(double min, double max) {
  function dot (line 100) | inline double dot(const vec3& u, const vec3& v) {
  function vec3 (line 106) | inline vec3 cross(const vec3& u, const vec3& v) {
  function vec3 (line 112) | inline vec3 unit_vector(const vec3& v) {
  function vec3 (line 116) | inline vec3 random_in_unit_disk() {
  function vec3 (line 124) | inline vec3 random_unit_vector() {
  function vec3 (line 133) | inline vec3 random_on_hemisphere(const vec3& normal) {
  function vec3 (line 141) | inline vec3 reflect(const vec3& v, const vec3& n) {
  function vec3 (line 145) | inline vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat) {

FILE: src/TheNextWeek/aabb.h
  function class (line 15) | class aabb {

FILE: src/TheNextWeek/bvh.h
  function class (line 21) | class bvh_node : public hittable {
  function hit (line 58) | bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
  function box_compare (line 75) | static bool box_compare(
  function box_x_compare (line 83) | static bool box_x_compare (const shared_ptr<hittable> a, const shared_pt...
  function box_y_compare (line 87) | static bool box_y_compare (const shared_ptr<hittable> a, const shared_pt...
  function box_z_compare (line 91) | static bool box_z_compare (const shared_ptr<hittable> a, const shared_pt...

FILE: src/TheNextWeek/camera.h
  function class (line 18) | class camera {

FILE: src/TheNextWeek/color.h
  function linear_to_gamma (line 21) | inline double linear_to_gamma(double linear_component)
  function write_color (line 30) | void write_color(std::ostream& out, const color& pixel_color) {

FILE: src/TheNextWeek/constant_medium.h
  function class (line 19) | class constant_medium : public hittable {

FILE: src/TheNextWeek/hittable.h
  function class (line 20) | class hit_record {
  function class (line 40) | class hittable {
  function class (line 50) | class translate : public hittable {
  function class (line 81) | class rotate_y : public hittable {

FILE: src/TheNextWeek/hittable_list.h
  function clear (line 27) | void clear() { objects.clear(); }
  function add (line 29) | void add(shared_ptr<hittable> object) {

FILE: src/TheNextWeek/interval.h
  function class (line 13) | class interval {
  function contains (line 31) | bool contains(double x) const {
  function surrounds (line 35) | bool surrounds(double x) const {
  function clamp (line 39) | double clamp(double x) const {
  function interval (line 45) | interval expand(double delta) const {

FILE: src/TheNextWeek/main.cc
  function bouncing_spheres (line 25) | void bouncing_spheres() {
  function checkered_spheres (line 91) | void checkered_spheres() {
  function earth (line 118) | void earth() {
  function perlin_spheres (line 142) | void perlin_spheres() {
  function quads (line 168) | void quads() {
  function simple_light (line 204) | void simple_light() {
  function cornell_box (line 234) | void cornell_box() {
  function cornell_smoke (line 278) | void cornell_smoke() {
  function final_scene (line 323) | void final_scene(int image_width, int samples_per_pixel, int max_depth) {
  function main (line 403) | int main() {

FILE: src/TheNextWeek/material.h
  function class (line 18) | class material {
  function class (line 34) | class lambertian : public material {
  function class (line 57) | class metal : public material {
  function class (line 76) | class dielectric : public material {
  function class (line 115) | class diffuse_light : public material {
  function class (line 129) | class isotropic : public material {

FILE: src/TheNextWeek/perlin.h
  function class (line 15) | class perlin {

FILE: src/TheNextWeek/quad.h
  function class (line 16) | class quad : public hittable {
  function shared_ptr (line 92) | inline shared_ptr<hittable_list> box(const point3& a, const point3& b, s...

FILE: src/TheNextWeek/ray.h
  function class (line 17) | class ray {

FILE: src/TheNextWeek/rtw_stb_image.h
  function class (line 25) | class rtw_image {

FILE: src/TheNextWeek/rtweekend.h
  function degrees_to_radians (line 33) | inline double degrees_to_radians(double degrees) {
  function random_double (line 37) | inline double random_double() {
  function random_double (line 42) | inline double random_double(double min, double max) {
  function random_int (line 47) | inline int random_int(int min, int max) {

FILE: src/TheNextWeek/sphere.h
  function class (line 17) | class sphere : public hittable {
  function hit (line 38) | bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
  function get_sphere_uv (line 77) | static void get_sphere_uv(const point3& p, double& u, double& v) {

FILE: src/TheNextWeek/texture.h
  function class (line 18) | class texture {
  function class (line 26) | class solid_color : public texture {
  function class (line 41) | class checker_texture : public texture {
  function class (line 66) | class image_texture : public texture {
  function class (line 91) | class noise_texture : public texture {

FILE: src/TheNextWeek/vec3.h
  function class (line 15) | class vec3 {
  function near_zero (line 56) | bool near_zero() const {
  function vec3 (line 66) | static vec3 random(double min, double max) {
  function dot (line 101) | inline double dot(const vec3& u, const vec3& v) {
  function vec3 (line 107) | inline vec3 cross(const vec3& u, const vec3& v) {
  function vec3 (line 113) | inline vec3 unit_vector(const vec3& v) {
  function vec3 (line 117) | inline vec3 random_in_unit_disk() {
  function vec3 (line 125) | inline vec3 random_unit_vector() {
  function vec3 (line 134) | inline vec3 random_on_hemisphere(const vec3& normal) {
  function vec3 (line 142) | inline vec3 reflect(const vec3& v, const vec3& n) {
  function vec3 (line 146) | inline vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat) {

FILE: src/TheRestOfYourLife/aabb.h
  function class (line 15) | class aabb {

FILE: src/TheRestOfYourLife/bvh.h
  function class (line 21) | class bvh_node : public hittable {
  function hit (line 58) | bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
  function box_compare (line 75) | static bool box_compare(
  function box_x_compare (line 83) | static bool box_x_compare (const shared_ptr<hittable> a, const shared_pt...
  function box_y_compare (line 87) | static bool box_y_compare (const shared_ptr<hittable> a, const shared_pt...
  function box_z_compare (line 91) | static bool box_z_compare (const shared_ptr<hittable> a, const shared_pt...

FILE: src/TheRestOfYourLife/camera.h
  function class (line 19) | class camera {

FILE: src/TheRestOfYourLife/color.h
  function linear_to_gamma (line 21) | inline double linear_to_gamma(double linear_component)
  function write_color (line 30) | void write_color(std::ostream& out, const color& pixel_color) {

FILE: src/TheRestOfYourLife/constant_medium.h
  function class (line 19) | class constant_medium : public hittable {

FILE: src/TheRestOfYourLife/cos_cubed.cc
  function f (line 18) | double f(double r2) {
  function pdf (line 27) | double pdf() {
  function main (line 32) | int main() {

FILE: src/TheRestOfYourLife/cos_density.cc
  function f (line 18) | double f(const vec3& d) {
  function pdf (line 24) | double pdf(const vec3& d) {
  function main (line 29) | int main() {

FILE: src/TheRestOfYourLife/estimate_halfway.cc
  type sample (line 18) | struct sample {
  function compare_by_x (line 24) | bool compare_by_x(const sample& a, const sample& b) {
  function main (line 29) | int main() {

FILE: src/TheRestOfYourLife/hittable.h
  function class (line 20) | class hit_record {
  function virtual (line 46) | virtual aabb bounding_box() const = 0;
  function class (line 89) | class rotate_y : public hittable {

FILE: src/TheRestOfYourLife/hittable_list.h
  function clear (line 27) | void clear() { objects.clear(); }
  function add (line 29) | void add(shared_ptr<hittable> object) {

FILE: src/TheRestOfYourLife/integrate_x_sq.cc
  function icd (line 18) | double icd(double d) {
  function pdf (line 23) | double pdf(double x) {
  function main (line 28) | int main() {

FILE: src/TheRestOfYourLife/interval.h
  function class (line 13) | class interval {
  function contains (line 31) | bool contains(double x) const {
  function surrounds (line 35) | bool surrounds(double x) const {
  function clamp (line 39) | double clamp(double x) const {
  function interval (line 45) | interval expand(double delta) const {

FILE: src/TheRestOfYourLife/main.cc
  function main (line 21) | int main() {

FILE: src/TheRestOfYourLife/material.h
  function class (line 19) | class scatter_record {
  function class (line 28) | class material {
  function class (line 49) | class lambertian : public material {
  function class (line 72) | class metal : public material {
  function class (line 94) | class dielectric : public material {
  function class (line 134) | class diffuse_light : public material {
  function class (line 151) | class isotropic : public material {

FILE: src/TheRestOfYourLife/onb.h
  function class (line 15) | class onb {
  function vec3 (line 28) | vec3 transform(const vec3& v) const {

FILE: src/TheRestOfYourLife/pdf.h
  function class (line 18) | class pdf {
  function value (line 31) | double value(const vec3& direction) const override {
  function vec3 (line 35) | vec3 generate() const override {
  function class (line 59) | class hittable_pdf : public pdf {
  function class (line 79) | class mixture_pdf : public pdf {

FILE: src/TheRestOfYourLife/perlin.h
  function class (line 15) | class perlin {

FILE: src/TheRestOfYourLife/pi.cc
  function main (line 18) | int main() {

FILE: src/TheRestOfYourLife/quad.h
  function class (line 16) | class quad : public hittable {
  function shared_ptr (line 111) | inline shared_ptr<hittable_list> box(const point3& a, const point3& b, s...

FILE: src/TheRestOfYourLife/ray.h
  function class (line 17) | class ray {

FILE: src/TheRestOfYourLife/rtw_stb_image.h
  function class (line 25) | class rtw_image {

FILE: src/TheRestOfYourLife/rtweekend.h
  function degrees_to_radians (line 33) | inline double degrees_to_radians(double degrees) {
  function random_double (line 37) | inline double random_double() {
  function random_double (line 42) | inline double random_double(double min, double max) {
  function random_int (line 47) | inline int random_int(int min, int max) {

FILE: src/TheRestOfYourLife/sphere.h
  function class (line 18) | class sphere : public hittable {
  function hit (line 39) | bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
  function pdf_value (line 72) | double pdf_value(const point3& origin, const vec3& direction) const over...
  function vec3 (line 86) | vec3 random(const point3& origin) const override {
  function get_sphere_uv (line 99) | static void get_sphere_uv(const point3& p, double& u, double& v) {
  function vec3 (line 114) | static vec3 random_to_sphere(double radius, double distance_squared) {

FILE: src/TheRestOfYourLife/sphere_importance.cc
  function f (line 18) | double f(const vec3& d) {
  function pdf (line 24) | double pdf(const vec3& d) {
  function main (line 29) | int main() {

FILE: src/TheRestOfYourLife/sphere_plot.cc
  function main (line 18) | int main() {

FILE: src/TheRestOfYourLife/texture.h
  function class (line 18) | class texture {
  function class (line 26) | class solid_color : public texture {
  function class (line 41) | class checker_texture : public texture {
  function class (line 66) | class image_texture : public texture {
  function class (line 91) | class noise_texture : public texture {

FILE: src/TheRestOfYourLife/vec3.h
  function class (line 15) | class vec3 {
  function near_zero (line 56) | bool near_zero() const {
  function vec3 (line 66) | static vec3 random(double min, double max) {
  function dot (line 101) | inline double dot(const vec3& u, const vec3& v) {
  function vec3 (line 107) | inline vec3 cross(const vec3& u, const vec3& v) {
  function vec3 (line 113) | inline vec3 unit_vector(const vec3& v) {
  function vec3 (line 117) | inline vec3 random_in_unit_disk() {
  function vec3 (line 125) | inline vec3 random_unit_vector() {
  function vec3 (line 134) | inline vec3 random_on_hemisphere(const vec3& normal) {
  function vec3 (line 142) | inline vec3 reflect(const vec3& v, const vec3& n) {
  function vec3 (line 146) | inline vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat) {
  function vec3 (line 153) | inline vec3 random_cosine_direction() {

FILE: src/external/stb_image.h
  type stbi_uc (line 403) | typedef unsigned char stbi_uc;
  type stbi_io_callbacks (line 424) | typedef struct
  type stbi__uint16 (line 591) | typedef unsigned short stbi__uint16;
  type stbi__int16 (line 592) | typedef   signed short stbi__int16;
  type stbi__uint32 (line 593) | typedef unsigned int   stbi__uint32;
  type stbi__int32 (line 594) | typedef   signed int   stbi__int32;
  type stbi__uint16 (line 597) | typedef uint16_t stbi__uint16;
  type stbi__int16 (line 598) | typedef int16_t  stbi__int16;
  type stbi__uint32 (line 599) | typedef uint32_t stbi__uint32;
  type stbi__int32 (line 600) | typedef int32_t  stbi__int32;
  function stbi__cpuid3 (line 675) | static int stbi__cpuid3(void)
  function stbi__sse2_available (line 696) | static int stbi__sse2_available()
  function stbi__sse2_available (line 704) | static int stbi__sse2_available()
  type stbi__context (line 739) | typedef struct
  function stbi__start_mem (line 759) | static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int...
  function stbi__start_callbacks (line 768) | static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c...
  function stbi__stdio_read (line 780) | static int stbi__stdio_read(void *user, char *data, int size)
  function stbi__stdio_skip (line 785) | static void stbi__stdio_skip(void *user, int n)
  function stbi__stdio_eof (line 790) | static int stbi__stdio_eof(void *user)
  function stbi__start_file (line 802) | static void stbi__start_file(stbi__context *s, FILE *f)
  function stbi__rewind (line 811) | static void stbi__rewind(stbi__context *s)
  function STBIDEF (line 876) | STBIDEF const char *stbi_failure_reason(void)
  function stbi__err (line 881) | static int stbi__err(const char *str)
  function STBIDEF (line 907) | STBIDEF void stbi_image_free(void *retval_from_stbi_load)
  function STBIDEF (line 922) | STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
  function stbi__float_postprocess (line 992) | static void stbi__float_postprocess(float *result, int *x, int *y, int *...
  function FILE (line 1016) | static FILE *stbi__fopen(char const *filename, char const *mode)
  function STBIDEF (line 1029) | STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *co...
  function STBIDEF (line 1039) | STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp,...
  function STBIDEF (line 1053) | STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, i...
  function STBIDEF (line 1060) | STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk,...
  function STBIDEF (line 1085) | STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, in...
  function STBIDEF (line 1092) | STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, ...
  function STBIDEF (line 1100) | STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *com...
  function STBIDEF (line 1110) | STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, ...
  function STBIDEF (line 1124) | STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
  function STBIDEF (line 1138) | STBIDEF int      stbi_is_hdr          (char const *filename)
  function STBIDEF (line 1149) | STBIDEF int      stbi_is_hdr_from_file(FILE *f)
  function STBIDEF (line 1161) | STBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clb...
  function STBIDEF (line 1176) | STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = ga...
  function STBIDEF (line 1177) | STBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = sc...
  function STBIDEF (line 1180) | STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = ...
  function STBIDEF (line 1181) | STBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = ...
  function stbi__refill_buffer (line 1196) | static void stbi__refill_buffer(stbi__context *s)
  function stbi_inline (line 1212) | stbi_inline static stbi_uc stbi__get8(stbi__context *s)
  function stbi_inline (line 1223) | stbi_inline static int stbi__at_eof(stbi__context *s)
  function stbi__skip (line 1235) | static void stbi__skip(stbi__context *s, int n)
  function stbi__getn (line 1252) | static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
  function stbi__get16be (line 1276) | static int stbi__get16be(stbi__context *s)
  function stbi__uint32 (line 1282) | static stbi__uint32 stbi__get32be(stbi__context *s)
  function stbi__get16le (line 1288) | static int stbi__get16le(stbi__context *s)
  function stbi__uint32 (line 1294) | static stbi__uint32 stbi__get32le(stbi__context *s)
  function stbi_uc (line 1314) | static stbi_uc stbi__compute_y(int r, int g, int b)
  function stbi_uc (line 1384) | static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)
  type stbi__huffman (line 1436) | typedef struct
  type stbi__jpeg (line 1447) | typedef struct
  function stbi__build_huffman (line 1498) | static int stbi__build_huffman(stbi__huffman *h, int *count)
  function stbi__build_fast_ac (line 1541) | static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
  function stbi__grow_buffer_unsafe (line 1566) | static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
  function stbi_inline (line 1587) | stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffm...
  function stbi_inline (line 1641) | stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
  function stbi_inline (line 1657) | stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
  function stbi_inline (line 1668) | stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
  function stbi__jpeg_decode_block (line 1696) | static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__...
  function stbi__jpeg_decode_block_prog_dc (line 1748) | static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64]...
  function stbi__jpeg_decode_block_prog_ac (line 1775) | static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64]...
  function stbi_inline (line 1895) | stbi_inline static stbi_uc stbi__clamp(int x)
  function stbi__idct_block (line 1946) | static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
  function stbi__idct_simd (line 2009) | static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
  function stbi__idct_simd (line 2190) | static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
  function stbi_uc (line 2398) | static stbi_uc stbi__get_marker(stbi__jpeg *j)
  function stbi__jpeg_reset (line 2415) | static void stbi__jpeg_reset(stbi__jpeg *j)
  function stbi__parse_entropy_coded_data (line 2428) | static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
  function stbi__jpeg_dequantize (line 2552) | static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant)
  function stbi__jpeg_finish (line 2559) | static void stbi__jpeg_finish(stbi__jpeg *z)
  function stbi__process_marker (line 2578) | static int stbi__process_marker(stbi__jpeg *z, int m)
  function stbi__process_scan_header (line 2642) | static int stbi__process_scan_header(stbi__jpeg *z)
  function stbi__process_frame_header (line 2681) | static int stbi__process_frame_header(stbi__jpeg *z, int scan)
  function stbi__decode_jpeg_header (line 2772) | static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
  function stbi__decode_jpeg_image (line 2795) | static int stbi__decode_jpeg_image(stbi__jpeg *j)
  type stbi_uc (line 2834) | typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_u...
  function stbi_uc (line 2839) | static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *...
  function stbi_uc (line 2848) | static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, s...
  function stbi_uc (line 2858) | static stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, ...
  function stbi_uc (line 2888) | static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, ...
  function stbi_uc (line 2913) | static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_n...
  function stbi_uc (line 3029) | static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_nea...
  function stbi__YCbCr_to_RGB_row (line 3044) | static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const...
  function stbi__YCbCr_to_RGB_row (line 3072) | static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const...
  function stbi__YCbCr_to_RGB_simd (line 3099) | static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi...
  function stbi__setup_jpeg (line 3234) | static void stbi__setup_jpeg(stbi__jpeg *j)
  function stbi__cleanup_jpeg (line 3260) | static void stbi__cleanup_jpeg(stbi__jpeg *j)
  type stbi__resample (line 3281) | typedef struct
  function stbi_uc (line 3291) | static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, i...
  function stbi__jpeg_test (line 3396) | static int stbi__jpeg_test(stbi__context *s)
  function stbi__jpeg_info_raw (line 3407) | static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
  function stbi__jpeg_info (line 3419) | static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
  type stbi__zhuffman (line 3442) | typedef struct
  function stbi_inline (line 3452) | stbi_inline static int stbi__bitreverse16(int n)
  function stbi_inline (line 3461) | stbi_inline static int stbi__bit_reverse(int v, int bits)
  function stbi__zbuild_huffman (line 3469) | static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, in...
  type stbi__zbuf (line 3522) | typedef struct
  function stbi_inline (line 3536) | stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
  function stbi__fill_bits (line 3542) | static void stbi__fill_bits(stbi__zbuf *z)
  function stbi__zreceive (line 3551) | int stbi__zreceive(stbi__zbuf *z, int n)
  function stbi__zhuffman_decode_slowpath (line 3561) | static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
  function stbi_inline (line 3579) | stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffm...
  function stbi__zexpand (line 3593) | static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to m...
  function stbi__parse_huffman_block (line 3625) | static int stbi__parse_huffman_block(stbi__zbuf *a)
  function stbi__compute_huffman_codes (line 3667) | static int stbi__compute_huffman_codes(stbi__zbuf *a)
  function stbi__parse_uncomperssed_block (line 3713) | static int stbi__parse_uncomperssed_block(stbi__zbuf *a)
  function stbi__parse_zlib_header (line 3742) | static int stbi__parse_zlib_header(stbi__zbuf *a)
  function stbi__init_zdefaults (line 3757) | static void stbi__init_zdefaults(void)
  function stbi__parse_zlib (line 3768) | static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
  function stbi__do_zlib (line 3797) | static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, i...
  function STBIDEF (line 3807) | STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int ...
  function STBIDEF (line 3823) | STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *...
  function STBIDEF (line 3828) | STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *b...
  function STBIDEF (line 3844) | STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const ...
  function STBIDEF (line 3855) | STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int l...
  function STBIDEF (line 3871) | STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, co...
  type stbi__pngchunk (line 3894) | typedef struct
  function stbi__pngchunk (line 3900) | static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
  function stbi__check_png_header (line 3908) | static int stbi__check_png_header(stbi__context *s)
  type stbi__png (line 3917) | typedef struct
  function stbi__paeth (line 3944) | static int stbi__paeth(int a, int b, int c)
  function stbi__create_png_image_raw (line 3958) | static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__...
  function stbi__create_png_image (line 4136) | static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stb...
  function stbi__compute_transparency (line 4178) | static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int o...
  function stbi__expand_png_palette (line 4203) | static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int ...
  function STBIDEF (line 4243) | STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpr...
  function STBIDEF (line 4248) | STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_conv...
  function stbi__de_iphone (line 4253) | static void stbi__de_iphone(stbi__png *z)
  function stbi__parse_png_file (line 4297) | static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
  function stbi__png_test (line 4484) | static int stbi__png_test(stbi__context *s)
  function stbi__png_info_raw (line 4492) | static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
  function stbi__png_info (line 4504) | static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__bmp_test_raw (line 4515) | static int stbi__bmp_test_raw(stbi__context *s)
  function stbi__bmp_test (line 4530) | static int stbi__bmp_test(stbi__context *s)
  function stbi__high_bit (line 4539) | static int stbi__high_bit(unsigned int z)
  function stbi__bitcount (line 4551) | static int stbi__bitcount(unsigned int a)
  function stbi__shiftsigned (line 4561) | static int stbi__shiftsigned(int v, int shift, int bits)
  function stbi_uc (line 4578) | static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *co...
  function stbi__tga_info (line 4784) | static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__tga_test (line 4821) | static int stbi__tga_test(stbi__context *s)
  function stbi_uc (line 4846) | static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *co...
  function stbi__psd_test (line 5045) | static int stbi__psd_test(stbi__context *s)
  function stbi_uc (line 5052) | static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *co...
  function stbi__pic_is4 (line 5221) | static int stbi__pic_is4(stbi__context *s,const char *str)
  function stbi__pic_test_core (line 5231) | static int stbi__pic_test_core(stbi__context *s)
  type stbi__pic_packet (line 5247) | typedef struct
  function stbi_uc (line 5252) | static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
  function stbi__copyval (line 5266) | static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
  function stbi_uc (line 5275) | static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int heigh...
  function stbi_uc (line 5386) | static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *com...
  function stbi__pic_test (line 5419) | static int stbi__pic_test(stbi__context *s)
  type stbi__gif_lzw (line 5431) | typedef struct
  type stbi__gif (line 5438) | typedef struct
  function stbi__gif_test_raw (line 5455) | static int stbi__gif_test_raw(stbi__context *s)
  function stbi__gif_test (line 5465) | static int stbi__gif_test(stbi__context *s)
  function stbi__gif_parse_colortable (line 5472) | static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256...
  function stbi__gif_header (line 5483) | static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, i...
  function stbi__gif_info_raw (line 5511) | static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
  function stbi__out_gif_code (line 5523) | static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
  function stbi_uc (line 5557) | static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
  function stbi__fill_gif_background (line 5637) | static void stbi__fill_gif_background(stbi__gif *g)
  function stbi_uc (line 5652) | static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int ...
  function stbi_uc (line 5752) | static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *co...
  function stbi__gif_info (line 5768) | static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__hdr_test_core (line 5778) | static int stbi__hdr_test_core(stbi__context *s)
  function stbi__hdr_test (line 5788) | static int stbi__hdr_test(stbi__context* s)
  function stbi__hdr_convert (line 5818) | static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
  function stbi__hdr_info (line 5956) | static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__bmp_info (line 5997) | static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__psd_info (line 6027) | static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__pic_info (line 6060) | static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__pnm_test (line 6120) | static int      stbi__pnm_test(stbi__context *s)
  function stbi_uc (line 6132) | static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *co...
  function stbi__pnm_isspace (line 6152) | static int      stbi__pnm_isspace(char c)
  function stbi__pnm_skip_whitespace (line 6157) | static void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)
  function stbi__pnm_isdigit (line 6163) | static int      stbi__pnm_isdigit(char c)
  function stbi__pnm_getinteger (line 6168) | static int      stbi__pnm_getinteger(stbi__context *s, char *c)
  function stbi__pnm_info (line 6180) | static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
  function stbi__info_main (line 6215) | static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
  function STBIDEF (line 6258) | STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
  function STBIDEF (line 6268) | STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
  function STBIDEF (line 6280) | STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x...
  function STBIDEF (line 6287) | STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *u...

FILE: src/external/stb_image_write.h
  type stbiw_uint32 (line 129) | typedef unsigned int stbiw_uint32;
  function writefv (line 132) | static void writefv(FILE *f, const char *fmt, va_list v)
  function write3 (line 152) | static void write3(FILE *f, unsigned char a, unsigned char b, unsigned c...
  function write_pixels (line 159) | static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, i...
  function outfile (line 206) | static int outfile(char const *filename, int rgb_dir, int vdir, int x, i...
  function stbi_write_bmp (line 222) | int stbi_write_bmp(char const *filename, int x, int y, int comp, const v...
  function stbi_write_tga (line 231) | int stbi_write_tga(char const *filename, int x, int y, int comp, const v...
  function stbiw__linear_to_rgbe (line 245) | void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
  function stbiw__write_run_data (line 262) | void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
  function stbiw__write_dump_data (line 270) | void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
  function stbiw__write_hdr_scanline (line 278) | void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned ch...
  function stbi_write_hdr (line 367) | int stbi_write_hdr(char const *filename, int x, int y, int comp, const f...
  function stbiw__zlib_bitrev (line 425) | static int stbiw__zlib_bitrev(int code, int codebits)
  function stbiw__zlib_countm (line 435) | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *...
  function stbiw__zhash (line 443) | static unsigned int stbiw__zhash(unsigned char *data)
  function stbiw__crc32 (line 572) | unsigned int stbiw__crc32(unsigned char *buffer, int len)
  function stbiw__wpcrc (line 590) | static void stbiw__wpcrc(unsigned char **data, int len)
  function stbiw__paeth (line 596) | static unsigned char stbiw__paeth(int a, int b, int c)
  function stbi_write_png (line 696) | int stbi_write_png(char const *filename, int x, int y, int comp, const v...
Condensed preview — 77 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,150K chars).
[
  {
    "path": ".gitignore",
    "chars": 59,
    "preview": "# Git Ignore Rules for raytracing.github.io\n\nbuild/\n/*.ppm\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 47135,
    "preview": "Change Log / Ray Tracing in One Weekend\n================================================================================"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 4654,
    "preview": "#---------------------------------------------------------------------------------------------------\n# CMake Build Confi"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 5657,
    "preview": "Contributing To The Ray Tracing in One Weekend Series\n=================================================================="
  },
  {
    "path": "COPYING.txt",
    "chars": 7169,
    "preview": "Creative Commons Legal Code\r\n\r\nCC0 1.0 Universal\r\n\r\n    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROV"
  },
  {
    "path": "PRINTING.md",
    "chars": 1590,
    "preview": "Printing These Books\n==================================================================================================="
  },
  {
    "path": "README.md",
    "chars": 8659,
    "preview": "Ray Tracing in One Weekend Book Series\n================================================================================="
  },
  {
    "path": "books/RayTracingInOneWeekend.html",
    "chars": 204947,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link rel=\"icon\" type=\"image/png\" href=\"../favicon.png\">\n<!-- Markdeep: https://c"
  },
  {
    "path": "books/RayTracingTheNextWeek.html",
    "chars": 187012,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link rel=\"icon\" type=\"image/png\" href=\"../favicon.png\">\n<!-- Markdeep: https://c"
  },
  {
    "path": "books/RayTracingTheRestOfYourLife.html",
    "chars": 184648,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link rel=\"icon\" type=\"image/png\" href=\"../favicon.png\">\n<!-- Markdeep: https://c"
  },
  {
    "path": "books/acknowledgments.md.html",
    "chars": 3413,
    "preview": "<meta charset=\"utf-8\">\n<!-- Markdeep: https://casual-effects.com/markdeep/ -->\n\nAcknowledgments\n========================"
  },
  {
    "path": "images/test.ppm",
    "chars": 19915,
    "preview": "P3\r\n40 40\r\n255\r\n220 235 255\r\n220 235 255\r\n220 235 255\r\n220 235 255\r\n220 235 255\r\n220 235 255\r\n220 235 255\r\n220 235 255\r\n"
  },
  {
    "path": "index.html",
    "chars": 4636,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<title>Ray Tracing in One Weekend Series</title>\n<link rel='stylesheet' href='sty"
  },
  {
    "path": "src/InOneWeekend/camera.h",
    "chars": 6440,
    "preview": "#ifndef CAMERA_H\n#define CAMERA_H\n//===================================================================================="
  },
  {
    "path": "src/InOneWeekend/color.h",
    "chars": 1593,
    "preview": "#ifndef COLOR_H\n#define COLOR_H\n//======================================================================================"
  },
  {
    "path": "src/InOneWeekend/hittable.h",
    "chars": 1345,
    "preview": "#ifndef HITTABLE_H\n#define HITTABLE_H\n//================================================================================"
  },
  {
    "path": "src/InOneWeekend/hittable_list.h",
    "chars": 1574,
    "preview": "#ifndef HITTABLE_LIST_H\n#define HITTABLE_LIST_H\n//======================================================================"
  },
  {
    "path": "src/InOneWeekend/interval.h",
    "chars": 1373,
    "preview": "#ifndef INTERVAL_H\n#define INTERVAL_H\n//================================================================================"
  },
  {
    "path": "src/InOneWeekend/main.cc",
    "chars": 2985,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/InOneWeekend/material.h",
    "chars": 3510,
    "preview": "#ifndef MATERIAL_H\n#define MATERIAL_H\n//================================================================================"
  },
  {
    "path": "src/InOneWeekend/ray.h",
    "chars": 1073,
    "preview": "#ifndef RAY_H\n#define RAY_H\n//=========================================================================================="
  },
  {
    "path": "src/InOneWeekend/rtweekend.h",
    "chars": 1406,
    "preview": "#ifndef RTWEEKEND_H\n#define RTWEEKEND_H\n//=============================================================================="
  },
  {
    "path": "src/InOneWeekend/sphere.h",
    "chars": 1881,
    "preview": "#ifndef SPHERE_H\n#define SPHERE_H\n//===================================================================================="
  },
  {
    "path": "src/InOneWeekend/vec3.h",
    "chars": 4339,
    "preview": "#ifndef VEC3_H\n#define VEC3_H\n//========================================================================================"
  },
  {
    "path": "src/TheNextWeek/aabb.h",
    "chars": 3556,
    "preview": "#ifndef AABB_H\n#define AABB_H\n//========================================================================================"
  },
  {
    "path": "src/TheNextWeek/bvh.h",
    "chars": 3565,
    "preview": "#ifndef BVH_H\n#define BVH_H\n//=========================================================================================="
  },
  {
    "path": "src/TheNextWeek/camera.h",
    "chars": 6605,
    "preview": "#ifndef CAMERA_H\n#define CAMERA_H\n//===================================================================================="
  },
  {
    "path": "src/TheNextWeek/color.h",
    "chars": 1594,
    "preview": "#ifndef COLOR_H\n#define COLOR_H\n//======================================================================================"
  },
  {
    "path": "src/TheNextWeek/constant_medium.h",
    "chars": 2494,
    "preview": "#ifndef CONSTANT_MEDIUM_H\n#define CONSTANT_MEDIUM_H\n//=================================================================="
  },
  {
    "path": "src/TheNextWeek/hittable.h",
    "chars": 4893,
    "preview": "#ifndef HITTABLE_H\n#define HITTABLE_H\n//================================================================================"
  },
  {
    "path": "src/TheNextWeek/hittable_list.h",
    "chars": 1727,
    "preview": "#ifndef HITTABLE_LIST_H\n#define HITTABLE_LIST_H\n//======================================================================"
  },
  {
    "path": "src/TheNextWeek/interval.h",
    "chars": 1973,
    "preview": "#ifndef INTERVAL_H\n#define INTERVAL_H\n//================================================================================"
  },
  {
    "path": "src/TheNextWeek/main.cc",
    "chars": 14189,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheNextWeek/material.h",
    "chars": 4623,
    "preview": "#ifndef MATERIAL_H\n#define MATERIAL_H\n//================================================================================"
  },
  {
    "path": "src/TheNextWeek/perlin.h",
    "chars": 3210,
    "preview": "#ifndef PERLIN_H\n#define PERLIN_H\n//===================================================================================="
  },
  {
    "path": "src/TheNextWeek/quad.h",
    "chars": 4187,
    "preview": "#ifndef QUAD_H\n#define QUAD_H\n//========================================================================================"
  },
  {
    "path": "src/TheNextWeek/ray.h",
    "chars": 1248,
    "preview": "#ifndef RAY_H\n#define RAY_H\n//=========================================================================================="
  },
  {
    "path": "src/TheNextWeek/rtw_stb_image.h",
    "chars": 5271,
    "preview": "#ifndef RTW_STB_IMAGE_H\n#define RTW_STB_IMAGE_H\n//======================================================================"
  },
  {
    "path": "src/TheNextWeek/rtweekend.h",
    "chars": 1540,
    "preview": "#ifndef RTWEEKEND_H\n#define RTWEEKEND_H\n//=============================================================================="
  },
  {
    "path": "src/TheNextWeek/sphere.h",
    "chars": 3350,
    "preview": "#ifndef SPHERE_H\n#define SPHERE_H\n//===================================================================================="
  },
  {
    "path": "src/TheNextWeek/texture.h",
    "chars": 3195,
    "preview": "#ifndef TEXTURE_H\n#define TEXTURE_H\n//=================================================================================="
  },
  {
    "path": "src/TheNextWeek/vec3.h",
    "chars": 4340,
    "preview": "#ifndef VEC3_H\n#define VEC3_H\n//========================================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/aabb.h",
    "chars": 3556,
    "preview": "#ifndef AABB_H\n#define AABB_H\n//========================================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/bvh.h",
    "chars": 3565,
    "preview": "#ifndef BVH_H\n#define BVH_H\n//=========================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/camera.h",
    "chars": 7998,
    "preview": "#ifndef CAMERA_H\n#define CAMERA_H\n//===================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/color.h",
    "chars": 1711,
    "preview": "#ifndef COLOR_H\n#define COLOR_H\n//======================================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/constant_medium.h",
    "chars": 2494,
    "preview": "#ifndef CONSTANT_MEDIUM_H\n#define CONSTANT_MEDIUM_H\n//=================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/cos_cubed.cc",
    "chars": 1343,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheRestOfYourLife/cos_density.cc",
    "chars": 1222,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheRestOfYourLife/estimate_halfway.cc",
    "chars": 1989,
    "preview": "//==============================================================================================\n// To the extent possib"
  },
  {
    "path": "src/TheRestOfYourLife/hittable.h",
    "chars": 5091,
    "preview": "#ifndef HITTABLE_H\n#define HITTABLE_H\n//================================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/hittable_list.h",
    "chars": 2190,
    "preview": "#ifndef HITTABLE_LIST_H\n#define HITTABLE_LIST_H\n//======================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/integrate_x_sq.cc",
    "chars": 1218,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheRestOfYourLife/interval.h",
    "chars": 1973,
    "preview": "#ifndef INTERVAL_H\n#define INTERVAL_H\n//================================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/main.cc",
    "chars": 2714,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheRestOfYourLife/material.h",
    "chars": 5312,
    "preview": "#ifndef MATERIAL_H\n#define MATERIAL_H\n//================================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/onb.h",
    "chars": 1324,
    "preview": "#ifndef ONB_H\n#define ONB_H\n//=========================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/pdf.h",
    "chars": 2452,
    "preview": "#ifndef PDF_H\n#define PDF_H\n//=========================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/perlin.h",
    "chars": 3210,
    "preview": "#ifndef PERLIN_H\n#define PERLIN_H\n//===================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/pi.cc",
    "chars": 1564,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheRestOfYourLife/quad.h",
    "chars": 4816,
    "preview": "#ifndef QUAD_H\n#define QUAD_H\n//========================================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/ray.h",
    "chars": 1248,
    "preview": "#ifndef RAY_H\n#define RAY_H\n//=========================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/rtw_stb_image.h",
    "chars": 5271,
    "preview": "#ifndef RTW_STB_IMAGE_H\n#define RTW_STB_IMAGE_H\n//======================================================================"
  },
  {
    "path": "src/TheRestOfYourLife/rtweekend.h",
    "chars": 1540,
    "preview": "#ifndef RTWEEKEND_H\n#define RTWEEKEND_H\n//=============================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/sphere.h",
    "chars": 4531,
    "preview": "#ifndef SPHERE_H\n#define SPHERE_H\n//===================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/sphere_importance.cc",
    "chars": 1180,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheRestOfYourLife/sphere_plot.cc",
    "chars": 1077,
    "preview": "//==============================================================================================\n// Originally written i"
  },
  {
    "path": "src/TheRestOfYourLife/texture.h",
    "chars": 3195,
    "preview": "#ifndef TEXTURE_H\n#define TEXTURE_H\n//=================================================================================="
  },
  {
    "path": "src/TheRestOfYourLife/vec3.h",
    "chars": 4615,
    "preview": "#ifndef VEC3_H\n#define VEC3_H\n//========================================================================================"
  },
  {
    "path": "src/external/stb_image.h",
    "chars": 220334,
    "preview": "/* stb_image - v2.06 - public domain image loader - http://nothings.org/stb_image.h\n                                    "
  },
  {
    "path": "src/external/stb_image_write.h",
    "chars": 25646,
    "preview": "/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h\n   writes out PNG/BMP/TGA images "
  },
  {
    "path": "style/book-highlight-test.css",
    "chars": 2421,
    "preview": "/* -------------------------------------------------------------------------------------------------\n** Code Highlightin"
  },
  {
    "path": "style/book.css",
    "chars": 4647,
    "preview": "/* -------------------------------------------------------------------------------------------------\n** General Body Sty"
  },
  {
    "path": "style/website.css",
    "chars": 892,
    "preview": "body {\n    margin: 3em 8%;\n    font-family: Helvetica, Arial, sans-serif;\n    color: black;\n    background-color: #f0eee"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the RayTracing/raytracing.github.io GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 77 files (1.1 MB), approximately 286.0k tokens, and a symbol index with 389 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!