|
1741 | 1741 |
|
1742 | 1742 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
1743 | 1743 | #include "rtweekend.h" |
| 1744 | + #include "rtw_stb_image.h" |
| 1745 | + |
| 1746 | + #include <iostream> |
1744 | 1747 |
|
1745 | 1748 | class image_texture : public texture { |
1746 | 1749 | public: |
1747 | | - image_texture() {} |
1748 | | - image_texture(unsigned char *pixels, int A, int B) |
1749 | | - : data(pixels), nx(A), ny(B) {} |
| 1750 | + const static int bytes_per_pixel = 3; |
| 1751 | + |
| 1752 | + image_texture() |
| 1753 | + : data(nullptr), width(0), height(0), bytes_per_scanline(0) {} |
| 1754 | + |
| 1755 | + image_texture(const char* filename) { |
| 1756 | + auto components_per_pixel = bytes_per_pixel; |
| 1757 | + |
| 1758 | + data = stbi_load( |
| 1759 | + filename, &width, &height, &components_per_pixel, components_per_pixel); |
| 1760 | + |
| 1761 | + if (!data) { |
| 1762 | + std::cerr << "ERROR: Could not load texture image file '" << filename << "'.\n"; |
| 1763 | + width = height = 0; |
| 1764 | + } |
| 1765 | + |
| 1766 | + bytes_per_scanline = bytes_per_pixel * width; |
| 1767 | + } |
1750 | 1768 |
|
1751 | 1769 | ~image_texture() { |
1752 | 1770 | delete data; |
1753 | 1771 | } |
1754 | 1772 |
|
1755 | | - virtual color value(double u, double v, const point3& p) const { |
1756 | | - // If we have no texture data, then always emit cyan (as a debugging aid). |
| 1773 | + virtual color value(double u, double v, const vec3& p) const { |
| 1774 | + // If we have no texture data, then return solid cyan as a debugging aid. |
1757 | 1775 | if (data == nullptr) |
1758 | 1776 | return color(0,1,1); |
1759 | 1777 |
|
1760 | | - auto i = static_cast<int>(( u)*nx); |
1761 | | - auto j = static_cast<int>((1-v)*ny-0.001); |
| 1778 | + // Clamp input texture coordinates to [0,1] x [1,0] |
| 1779 | + u = clamp(u, 0.0, 1.0); |
| 1780 | + v = 1.0 - clamp(v, 0.0, 1.0); // Flip V to image coordinates |
1762 | 1781 |
|
1763 | | - if (i < 0) i = 0; |
1764 | | - if (j < 0) j = 0; |
1765 | | - if (i > nx-1) i = nx-1; |
1766 | | - if (j > ny-1) j = ny-1; |
| 1782 | + auto i = static_cast<int>(u * width); |
| 1783 | + auto j = static_cast<int>(v * height); |
1767 | 1784 |
|
1768 | | - auto r = static_cast<int>(data[3*i + 3*nx*j+0]) / 255.0; |
1769 | | - auto g = static_cast<int>(data[3*i + 3*nx*j+1]) / 255.0; |
1770 | | - auto b = static_cast<int>(data[3*i + 3*nx*j+2]) / 255.0; |
| 1785 | + // Clamp integer mapping, since actual coordinates should be less than 1.0 |
| 1786 | + if (i >= width) i = width-1; |
| 1787 | + if (j >= height) j = height-1; |
1771 | 1788 |
|
1772 | | - return color(r, g, b); |
| 1789 | + const auto color_scale = 1.0 / 255.0; |
| 1790 | + auto pixel = data + j*bytes_per_scanline + i*bytes_per_pixel; |
| 1791 | + |
| 1792 | + return color(color_scale*pixel[0], color_scale*pixel[1], color_scale*pixel[2]); |
1773 | 1793 | } |
1774 | 1794 |
|
1775 | | - public: |
| 1795 | + private: |
1776 | 1796 | unsigned char *data; |
1777 | | - int nx, ny; |
| 1797 | + int width, height; |
| 1798 | + int bytes_per_scanline; |
1778 | 1799 | }; |
| 1800 | + |
1779 | 1801 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1780 | 1802 | [Listing [img-texture]: <kbd>[texture.h]</kbd> Image texture class] |
1781 | 1803 |
|
|
1809 | 1831 |
|
1810 | 1832 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
1811 | 1833 | hittable_list earth() { |
1812 | | - int nx, ny, nn; |
1813 | | - unsigned char* texture_data = stbi_load("earthmap.jpg", &nx, &ny, &nn, 0); |
1814 | | - |
1815 | | - auto earth_surface = |
1816 | | - make_shared<lambertian>(make_shared<image_texture>(texture_data, nx, ny)); |
| 1834 | + auto earth_texture = make_shared<image_texture>("earthmap.jpg"); |
| 1835 | + auto earth_surface = make_shared<lambertian>(earth_texture); |
1817 | 1836 | auto globe = make_shared<sphere>(point3(0,0,0), 2, earth_surface); |
1818 | 1837 |
|
1819 | 1838 | return hittable_list(globe); |
|
2861 | 2880 | objects.add(make_shared<constant_medium>( |
2862 | 2881 | boundary, .0001, make_shared<constant_texture>(color(1,1,1)))); |
2863 | 2882 |
|
2864 | | - int nx, ny, nn; |
2865 | | - auto tex_data = stbi_load("earthmap.jpg", &nx, &ny, &nn, 0); |
2866 | | - auto emat = make_shared<lambertian>(make_shared<image_texture>(tex_data, nx, ny)); |
| 2883 | + auto emat = make_shared<lambertian>(make_shared<image_texture>("earthmap.jpg")); |
2867 | 2884 | objects.add(make_shared<sphere>(point3(400,200,400), 100, emat)); |
2868 | 2885 | auto pertext = make_shared<noise_texture>(0.1); |
2869 | 2886 | objects.add(make_shared<sphere>(point3(220,280,300), 80, make_shared<lambertian>(pertext))); |
|
0 commit comments