From af150e7b987ab691bd7bb16a613fbf1cd614dad7 Mon Sep 17 00:00:00 2001 From: Rahim Hentabli Date: Sun, 28 Apr 2024 18:25:31 -0700 Subject: [PATCH] added precommit (#30) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .clang-format | 2 + .github/workflows/ci.yaml | 24 +- .github/workflows/pcm.yaml | 23 + .pre-commit-config.yaml | 5 + .../acceleration_structures/bounding_box.hpp | 41 +- include/acceleration_structures/box.hpp | 30 +- include/acceleration_structures/hierarchy.hpp | 37 +- include/camera.hpp | 99 +- include/lights/direction_light.hpp | 23 +- include/lights/light.hpp | 29 +- include/lights/point_light.hpp | 23 +- include/lights/spot_light.hpp | 43 +- include/misc.hpp | 8 +- include/objects/mesh.hpp | 24 +- include/objects/object.hpp | 75 +- include/objects/plane.hpp | 20 +- include/objects/sphere.hpp | 20 +- include/ray.hpp | 23 +- include/render_world.hpp | 52 +- include/shaders/flat_shader.hpp | 17 +- include/shaders/phong_shader.hpp | 31 +- include/shaders/reflective_shader.hpp | 24 +- include/shaders/shader.hpp | 18 +- include/vec.hpp | 276 ++--- src/acceleration_structures/box.cpp | 84 +- src/acceleration_structures/hierarchy.cpp | 69 +- src/camera.cpp | 133 ++- src/objects/mesh.cpp | 203 ++-- src/objects/plane.cpp | 36 +- src/objects/sphere.cpp | 46 +- src/render_world.cpp | 138 ++- src/shaders/flat_shader.cpp | 8 +- src/shaders/phong_shader.cpp | 72 +- src/shaders/reflective_shader.cpp | 43 +- tools/benchmark/include/hierarchy_bench.hpp | 188 ++-- tools/benchmark/source/main.cpp | 1 + tools/common/dump_mp4.cpp | 963 +++++++++--------- tools/common/dump_mp4.hpp | 4 +- tools/common/dump_png.cpp | 145 +-- tools/common/dump_png.hpp | 7 +- tools/common/parse.cpp | 306 +++--- tools/common/parse.hpp | 5 +- tools/demos/image/main.cpp | 210 ++-- tools/demos/video/CMakeLists.txt | 8 - tools/demos/video/main.cpp | 24 +- tools/test/include/test_file.hpp | 336 +++--- 46 files changed, 1981 insertions(+), 2015 deletions(-) create mode 100644 .clang-format create mode 100644 .github/workflows/pcm.yaml create mode 100644 .pre-commit-config.yaml diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..9f3e95c --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: Google diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f13016a..0fe5467 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,21 +8,19 @@ jobs: Build-And-test: runs-on: ubuntu-latest steps: - - name: Check out - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: submodules: 'true' - - name: install ffmpeg + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libavutil58 libavcodec-dev libavformat-dev libswscale-dev libswresample-dev + version: 1.2 + execute_install_scripts: true + - name: CMake config & build run: | - sudo apt-get update - sudo apt-get install ffmpeg - - run: mkdir build - - run: cd build - - name: Run Cmake Config step - run: cmake -DCMAKE_BUILD_TYPE=Release ../ray-tracing - - name: Run build - run: cmake --build . --parallel 2 + cmake -B build -DCMAKE_BUILD_TYPE=Release . + cmake --build build --parallel 4 - name: Run test - run: ./tools/test/tests + run: ./build/tools/test/tests - name: Run benchmark - run: ./tools/benchmark/benchmarks + run: ./build/tools/benchmark/benchmarks diff --git a/.github/workflows/pcm.yaml b/.github/workflows/pcm.yaml new file mode 100644 index 0000000..4d45779 --- /dev/null +++ b/.github/workflows/pcm.yaml @@ -0,0 +1,23 @@ +name: pre-commit + +on: + pull_request: + +jobs: + Build-And-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libavutil58 libavcodec-dev libavformat-dev libswscale-dev libswresample-dev + version: 1.2 + execute_install_scripts: true + - name: CMake config & build + run: | + cmake -B build -DCMAKE_BUILD_TYPE=Release . + cmake --build build --parallel 4 + - name: Run test + run: ./build/tools/test/tests diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e321fd5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: '' # Use the sha / tag you want to point at + hooks: + - id: clang-format diff --git a/include/acceleration_structures/bounding_box.hpp b/include/acceleration_structures/bounding_box.hpp index 90a9dd7..4586d6b 100644 --- a/include/acceleration_structures/bounding_box.hpp +++ b/include/acceleration_structures/bounding_box.hpp @@ -1,38 +1,35 @@ #ifndef __BOUNDING_BOX_H__ #define __BOUNDING_BOX_H__ -//##################################################################### -// Function #in -//##################################################################### +// ##################################################################### +// Function #in +// ##################################################################### #include "objects/object.hpp" #include "ray.hpp" #include "vec.hpp" -template -vec componentwise_max(const vec& a, const vec& b) -{ - vec r; - for(int i=0; i +vec componentwise_max(const vec &a, const vec &b) { + vec r; + for (int i = 0; i < d; i++) r[i] = std::max(a[i], b[i]); + return r; } -template -vec componentwise_min(const vec& a, const vec& b) -{ - vec r; - for(int i=0; i +vec componentwise_min(const vec &a, const vec &b) { + vec r; + for (int i = 0; i < d; i++) r[i] = std::min(a[i], b[i]); + return r; } -class Bounding_Box -{ -public: - // lowermost and uppermost corners of bounding box - vec3 lo,hi; +class Bounding_Box { + public: + // lowermost and uppermost corners of bounding box + vec3 lo, hi; - bool Intersection(const Ray& ray, double& dist); + bool Intersection(const Ray &ray, double &dist); - Bounding_Box Union(const Bounding_Box& bb) const; + Bounding_Box Union(const Bounding_Box &bb) const; }; #endif diff --git a/include/acceleration_structures/box.hpp b/include/acceleration_structures/box.hpp index e4f3508..51c0b78 100644 --- a/include/acceleration_structures/box.hpp +++ b/include/acceleration_structures/box.hpp @@ -1,26 +1,26 @@ #ifndef __BOX_H__ #define __BOX_H__ -#include "ray.hpp" -#include "misc.hpp" #include -class Box -{ -public: - // lowermost and uppermost corners of bounding box - vec3 lo,hi; +#include "misc.hpp" +#include "ray.hpp" + +class Box { + public: + // lowermost and uppermost corners of bounding box + vec3 lo, hi; - // Return whether the ray intersects this box. - bool Intersection(const Ray& ray) const; + // Return whether the ray intersects this box. + bool Intersection(const Ray &ray) const; - // Compute the smallest box that contains both *this and bb. - Box Union(const Box& bb) const; + // Compute the smallest box that contains both *this and bb. + Box Union(const Box &bb) const; - // Enlarge this box (if necessary) so that pt also lies inside it. - void Include_Point(const vec3& pt); + // Enlarge this box (if necessary) so that pt also lies inside it. + void Include_Point(const vec3 &pt); - // Create a box to which points can be correctly added using Include_Point. - void Make_Empty(); + // Create a box to which points can be correctly added using Include_Point. + void Make_Empty(); }; #endif diff --git a/include/acceleration_structures/hierarchy.hpp b/include/acceleration_structures/hierarchy.hpp index 337f4f5..9c20c12 100644 --- a/include/acceleration_structures/hierarchy.hpp +++ b/include/acceleration_structures/hierarchy.hpp @@ -24,30 +24,29 @@ The last n elements of tree correspond to the elements of entries (in order). */ -struct Entry -{ - Object* obj; - int part; - Box box; +struct Entry { + Object *obj; + int part; + Box box; }; -class Hierarchy -{ -public: - // List of primitives (or parts of primitives) that can be intersected - std::vector entries; +class Hierarchy { + public: + // List of primitives (or parts of primitives) that can be intersected + std::vector entries; - // Flattened hierarchy - std::vector tree; + // Flattened hierarchy + std::vector tree; - // Reorder the entries vector so that adjacent entries tend to be nearby. - void Reorder_Entries(); + // Reorder the entries vector so that adjacent entries tend to be nearby. + void Reorder_Entries(); - // Populate tree from entries. - void Build_Tree(); + // Populate tree from entries. + void Build_Tree(); - // Return a list of candidates (indices into the entries list) whose - // bounding boxes intersect the ray. - void Intersection_Candidates(const Ray& ray, std::vector& candidates) const; + // Return a list of candidates (indices into the entries list) whose + // bounding boxes intersect the ray. + void Intersection_Candidates(const Ray &ray, + std::vector &candidates) const; }; #endif diff --git a/include/camera.hpp b/include/camera.hpp index b48ea5c..414cb14 100644 --- a/include/camera.hpp +++ b/include/camera.hpp @@ -2,69 +2,68 @@ #define __CAMERA_H__ #include -#include "vec.hpp" + #include "misc.hpp" +#include "vec.hpp" typedef unsigned int Pixel; -inline Pixel Pixel_Color(const vec3& color) -{ - unsigned int r=std::min(color[0],1.0)*255; - unsigned int g=std::min(color[1],1.0)*255; - unsigned int b=std::min(color[2],1.0)*255; - return (r<<24)|(g<<16)|(b<<8)|0xff; +inline Pixel Pixel_Color(const vec3 &color) { + unsigned int r = std::min(color[0], 1.0) * 255; + unsigned int g = std::min(color[1], 1.0) * 255; + unsigned int b = std::min(color[2], 1.0) * 255; + return (r << 24) | (g << 16) | (b << 8) | 0xff; } -inline vec3 From_Pixel(Pixel color) -{ - return vec3(color>>24,(color>>16)&0xff,(color>>8)&0xff)/255.; +inline vec3 From_Pixel(Pixel color) { + return vec3(color >> 24, (color >> 16) & 0xff, (color >> 8) & 0xff) / 255.; } -class Camera -{ -public: - // Describes camera in space - vec3 position; // camera position - vec3 film_position; // where (0.0, 0.0) in the image plane is located in space - vec3 look_vector; // points from the position to the focal point - normalized - vec3 vertical_vector; // point up in the image plane - normalized - vec3 horizontal_vector; // points to the right on the image plane - normalized +class Camera { + public: + // Describes camera in space + vec3 position; // camera position + vec3 + film_position; // where (0.0, 0.0) in the image plane is located in space + vec3 look_vector; // points from the position to the focal point - normalized + vec3 vertical_vector; // point up in the image plane - normalized + vec3 + horizontal_vector; // points to the right on the image plane - normalized - // Describes the coordinate system of the image plane - vec2 min,max; // coordinates of film corners: min = (left,bottom), max = (right,top) - vec2 image_size; // physical dimensions of film - vec2 pixel_size; // physical dimensions of a pixel + // Describes the coordinate system of the image plane + vec2 min, max; // coordinates of film corners: min = (left,bottom), max = + // (right,top) + vec2 image_size; // physical dimensions of film + vec2 pixel_size; // physical dimensions of a pixel - // Describes the pixels of the image - ivec2 number_pixels; // number of pixels: x and y direction - Pixel* colors; // Pixel data; row-major order - - Camera(); - ~Camera(); - Camera(const Camera& other); - Camera& operator=(const Camera &other); + // Describes the pixels of the image + ivec2 number_pixels; // number of pixels: x and y direction + Pixel *colors; // Pixel data; row-major order + Camera(); + ~Camera(); + Camera(const Camera &other); + Camera &operator=(const Camera &other); - // Used for setting up camera parameters - void Position_And_Aim_Camera(const vec3& position_input, - const vec3& look_at_point,const vec3& pseudo_up_vector); - void Focus_Camera(double focal_distance,double aspect_ratio, - double field_of_view); - void Set_Resolution(const ivec2& number_pixels_input); + // Used for setting up camera parameters + void Position_And_Aim_Camera(const vec3 &position_input, + const vec3 &look_at_point, + const vec3 &pseudo_up_vector); + void Focus_Camera(double focal_distance, double aspect_ratio, + double field_of_view); + void Set_Resolution(const ivec2 &number_pixels_input); - // Used for determining the where pixels are - vec3 World_Position(const ivec2& pixel_index); - vec2 Cell_Center(const ivec2& index) const - { - return min+(vec2(index)+vec2(.5,.5))*pixel_size; - } + // Used for determining the where pixels are + vec3 World_Position(const ivec2 &pixel_index); + vec2 Cell_Center(const ivec2 &index) const { + return min + (vec2(index) + vec2(.5, .5)) * pixel_size; + } - // Call to set the color of a pixel - void Set_Pixel(const ivec2& pixel_index,const Pixel& color) - { - int i=pixel_index[0]; - int j=pixel_index[1]; - colors[j*number_pixels[0]+i]=color; - } + // Call to set the color of a pixel + void Set_Pixel(const ivec2 &pixel_index, const Pixel &color) { + int i = pixel_index[0]; + int j = pixel_index[1]; + colors[j * number_pixels[0] + i] = color; + } }; #endif diff --git a/include/lights/direction_light.hpp b/include/lights/direction_light.hpp index 05731aa..5f7dc08 100644 --- a/include/lights/direction_light.hpp +++ b/include/lights/direction_light.hpp @@ -2,22 +2,21 @@ #define __DIRECTION_LIGHT_H__ #include -#include + #include #include -#include "vec.hpp" +#include + #include "light.hpp" +#include "vec.hpp" -class Direction_Light : public Light -{ -public: - Direction_Light(const vec3& direction,const vec3& color,double brightness) - :Light(direction.normalized()*1e10,color,brightness) - {} +class Direction_Light : public Light { + public: + Direction_Light(const vec3 &direction, const vec3 &color, double brightness) + : Light(direction.normalized() * 1e10, color, brightness) {} - vec3 Emitted_Light(const vec3& vector_to_light) const - { - return color*brightness; - } + vec3 Emitted_Light(const vec3 &vector_to_light) const { + return color * brightness; + } }; #endif diff --git a/include/lights/light.hpp b/include/lights/light.hpp index 626907c..32c09cf 100644 --- a/include/lights/light.hpp +++ b/include/lights/light.hpp @@ -2,31 +2,28 @@ #define __LIGHT_H__ #include -#include + #include #include +#include + #include "vec.hpp" class Ray; -class Light -{ -public: - vec3 position; - vec3 color; // RGB color components - double brightness; +class Light { + public: + vec3 position; + vec3 color; // RGB color components + double brightness; - Light() - :position(),color(1,1,1),brightness(1) - {} + Light() : position(), color(1, 1, 1), brightness(1) {} - Light(const vec3& position,const vec3& color,double brightness) - :position(position),color(color),brightness(brightness) - {} + Light(const vec3 &position, const vec3 &color, double brightness) + : position(position), color(color), brightness(brightness) {} - virtual ~Light() - {} + virtual ~Light() {} - virtual vec3 Emitted_Light(const vec3& vector_to_light) const=0; + virtual vec3 Emitted_Light(const vec3 &vector_to_light) const = 0; }; #endif diff --git a/include/lights/point_light.hpp b/include/lights/point_light.hpp index f33d676..0d9381e 100644 --- a/include/lights/point_light.hpp +++ b/include/lights/point_light.hpp @@ -2,22 +2,21 @@ #define __POINT_LIGHT_H__ #include -#include + #include #include -#include "vec.hpp" +#include + #include "light.hpp" +#include "vec.hpp" -class Point_Light : public Light -{ -public: - Point_Light(const vec3& position,const vec3& color,double brightness) - :Light(position,color,brightness) - {} +class Point_Light : public Light { + public: + Point_Light(const vec3 &position, const vec3 &color, double brightness) + : Light(position, color, brightness) {} - vec3 Emitted_Light(const vec3& vector_to_light) const - { - return color*brightness/(4*pi*vector_to_light.magnitude_squared()); - } + vec3 Emitted_Light(const vec3 &vector_to_light) const { + return color * brightness / (4 * pi * vector_to_light.magnitude_squared()); + } }; #endif diff --git a/include/lights/spot_light.hpp b/include/lights/spot_light.hpp index 082d5a7..fc2ed46 100644 --- a/include/lights/spot_light.hpp +++ b/include/lights/spot_light.hpp @@ -2,32 +2,33 @@ #define __SPOT_LIGHT_H__ #include -#include + #include #include -#include "vec.hpp" +#include + #include "light.hpp" +#include "vec.hpp" -class Spot_Light : public Light -{ -public: - double min_cos_angle; // cos(theta), where theta is the angle of the - // spotlight's cone. - double falloff_exponent; // exponent that controls how quickly the spotlight - // falls off with angle from the cone's axis. - vec3 direction; // Direction of the cone's axis. +class Spot_Light : public Light { + public: + double min_cos_angle; // cos(theta), where theta is the angle of the + // spotlight's cone. + double falloff_exponent; // exponent that controls how quickly the spotlight + // falls off with angle from the cone's axis. + vec3 direction; // Direction of the cone's axis. - Spot_Light(const vec3& position,const vec3& color,double brightness, - double max_angle,double falloff_exponent,const vec3& direction) - :Light(position,color,brightness),min_cos_angle(cos(max_angle*pi/180)), - falloff_exponent(falloff_exponent),direction(direction.normalized()) - {} + Spot_Light(const vec3 &position, const vec3 &color, double brightness, + double max_angle, double falloff_exponent, const vec3 &direction) + : Light(position, color, brightness), + min_cos_angle(cos(max_angle * pi / 180)), + falloff_exponent(falloff_exponent), + direction(direction.normalized()) {} - vec3 Emitted_Light(const vec3& vector_to_light) const - { - TODO; // compute the emitted light for the spotlight. Don't forget the - // factor of 4*pi and the falloff (same as point light). - return vec3(); - } + vec3 Emitted_Light(const vec3 &vector_to_light) const { + TODO; // compute the emitted light for the spotlight. Don't forget the + // factor of 4*pi and the falloff (same as point light). + return vec3(); + } }; #endif diff --git a/include/misc.hpp b/include/misc.hpp index 0ad8d95..374d789 100644 --- a/include/misc.hpp +++ b/include/misc.hpp @@ -4,7 +4,11 @@ #include // Prints out a TODO message at most once. -#define TODO {static std::ostream& todo=std::cout<<"TODO: "<<__FUNCTION__<<" in "<<__FILE__<=-weight_tol static const double weight_tol = 1e-4; -class Mesh : public Object -{ - std::vector vertices; - std::vector triangles; - Box box; +class Mesh : public Object { + std::vector vertices; + std::vector triangles; + Box box; -public: - Mesh() - {} + public: + Mesh() {} - virtual Hit Intersection(const Ray& ray, int part) const override; - virtual vec3 Normal(const vec3& point, int part) const override; - bool Intersect_Triangle(const Ray& ray, int tri, double& dist) const; - void Read_Obj(const char* file); - Box Bounding_Box(int part) const override; + virtual Hit Intersection(const Ray &ray, int part) const override; + virtual vec3 Normal(const vec3 &point, int part) const override; + bool Intersect_Triangle(const Ray &ray, int tri, double &dist) const; + void Read_Obj(const char *file); + Box Bounding_Box(int part) const override; }; #endif diff --git a/include/objects/object.hpp b/include/objects/object.hpp index 95d0c38..4e269dd 100644 --- a/include/objects/object.hpp +++ b/include/objects/object.hpp @@ -2,6 +2,7 @@ #define __OBJECT_H__ #include + #include "acceleration_structures/box.hpp" #include "vec.hpp" @@ -15,45 +16,43 @@ class Ray; class Shader; class Object; -struct Hit -{ - const Object* object; // object that was intersected - double dist; // distance along ray to intersection location - int part; // which part was intersected (eg, for meshes) +struct Hit { + const Object *object; // object that was intersected + double dist; // distance along ray to intersection location + int part; // which part was intersected (eg, for meshes) }; -class Object -{ -public: - Shader* material_shader; - - // the number of parts that this object contains. - int number_parts; - - Object() :material_shader(0), number_parts(1) {} - virtual ~Object() {} - - // Check for an intersection against the ray. If there was an - // intersection, record the distance to the first intersection. - // If an intersection was found, the object structure member - // should be set to this. If no intersection was found, the - // object member should be set to NULL. - // Do not return intersections where dist=0 only test for intersections against the specified part. - // If part<0 intersect against all parts. - // For meshes, the part structure attribute should be set to the - // index of the triangle that was intersected. For other types of - // objects, the part attribute can be ignored. - virtual Hit Intersection(const Ray& ray, int part) const=0; - - // Return the normal. For objects with multiple parts (meshes), you - // will need to use part to determine which piece was intersected. - // It will be set to the part structure entry returned from the - // intersection routine. - virtual vec3 Normal(const vec3& point, int part) const=0; - - // If part>=0, return the bounding box for the specified part. - // If part<0, return the bounding box for the whole object. - virtual Box Bounding_Box(int part) const=0; +class Object { + public: + Shader *material_shader; + + // the number of parts that this object contains. + int number_parts; + + Object() : material_shader(0), number_parts(1) {} + virtual ~Object() {} + + // Check for an intersection against the ray. If there was an + // intersection, record the distance to the first intersection. + // If an intersection was found, the object structure member + // should be set to this. If no intersection was found, the + // object member should be set to NULL. + // Do not return intersections where dist=0 only test for intersections against the specified part. + // If part<0 intersect against all parts. + // For meshes, the part structure attribute should be set to the + // index of the triangle that was intersected. For other types of + // objects, the part attribute can be ignored. + virtual Hit Intersection(const Ray &ray, int part) const = 0; + + // Return the normal. For objects with multiple parts (meshes), you + // will need to use part to determine which piece was intersected. + // It will be set to the part structure entry returned from the + // intersection routine. + virtual vec3 Normal(const vec3 &point, int part) const = 0; + + // If part>=0, return the bounding box for the specified part. + // If part<0, return the bounding box for the whole object. + virtual Box Bounding_Box(int part) const = 0; }; #endif diff --git a/include/objects/plane.hpp b/include/objects/plane.hpp index 9ad031c..0feb192 100644 --- a/include/objects/plane.hpp +++ b/include/objects/plane.hpp @@ -3,18 +3,16 @@ #include "objects/object.hpp" -class Plane : public Object -{ -public: - vec3 x1; - vec3 normal; +class Plane : public Object { + public: + vec3 x1; + vec3 normal; - Plane(const vec3& point,const vec3& normal) - :x1(point),normal(normal.normalized()) - {} + Plane(const vec3 &point, const vec3 &normal) + : x1(point), normal(normal.normalized()) {} - virtual Hit Intersection(const Ray& ray, int part) const override; - virtual vec3 Normal(const vec3& point, int part) const override; - virtual Box Bounding_Box(int part) const override; + virtual Hit Intersection(const Ray &ray, int part) const override; + virtual vec3 Normal(const vec3 &point, int part) const override; + virtual Box Bounding_Box(int part) const override; }; #endif diff --git a/include/objects/sphere.hpp b/include/objects/sphere.hpp index 91961e8..dc2b32b 100644 --- a/include/objects/sphere.hpp +++ b/include/objects/sphere.hpp @@ -3,18 +3,16 @@ #include "objects/object.hpp" -class Sphere : public Object -{ - vec3 center; - double radius; +class Sphere : public Object { + vec3 center; + double radius; -public: - Sphere(const vec3& center_input,double radius_input) - :center(center_input),radius(radius_input) - {} + public: + Sphere(const vec3 ¢er_input, double radius_input) + : center(center_input), radius(radius_input) {} - virtual Hit Intersection(const Ray& ray, int part) const override; - virtual vec3 Normal(const vec3& point, int part) const override; - virtual Box Bounding_Box(int part) const override; + virtual Hit Intersection(const Ray &ray, int part) const override; + virtual vec3 Normal(const vec3 &point, int part) const override; + virtual Box Bounding_Box(int part) const override; }; #endif diff --git a/include/ray.hpp b/include/ray.hpp index 31bb7f9..2c5c7a8 100644 --- a/include/ray.hpp +++ b/include/ray.hpp @@ -4,23 +4,16 @@ #include "vec.hpp" class Object; -class Ray -{ -public: - vec3 endpoint; // endpoint of the ray where t=0 - vec3 direction; // direction the ray sweeps out - unit vector +class Ray { + public: + vec3 endpoint; // endpoint of the ray where t=0 + vec3 direction; // direction the ray sweeps out - unit vector - Ray() - :endpoint(0,0,0),direction(0,0,1) - {} + Ray() : endpoint(0, 0, 0), direction(0, 0, 1) {} - Ray(const vec3& endpoint_input,const vec3& direction_input) - :endpoint(endpoint_input),direction(direction_input.normalized()) - {} + Ray(const vec3 &endpoint_input, const vec3 &direction_input) + : endpoint(endpoint_input), direction(direction_input.normalized()) {} - vec3 Point(double t) const - { - return endpoint+direction*t; - } + vec3 Point(double t) const { return endpoint + direction * t; } }; #endif diff --git a/include/render_world.hpp b/include/render_world.hpp index 9905684..74e017e 100644 --- a/include/render_world.hpp +++ b/include/render_world.hpp @@ -2,45 +2,45 @@ #define __RENDER_WORLD_H__ #include -#include "camera.hpp" + #include "acceleration_structures/hierarchy.hpp" +#include "camera.hpp" #include "objects/object.hpp" class Light; class Shader; class Ray; -class Render_World -{ -public: - Camera camera; +class Render_World { + public: + Camera camera; - Shader *background_shader; - std::vector objects; - std::vector lights; - vec3 ambient_color; - double ambient_intensity; + Shader *background_shader; + std::vector objects; + std::vector lights; + vec3 ambient_color; + double ambient_intensity; - bool enable_shadows; - int recursion_depth_limit; + bool enable_shadows; + int recursion_depth_limit; - Hierarchy hierarchy; - bool hierarchy_initialized = false; + Hierarchy hierarchy; + bool hierarchy_initialized = false; - Render_World(); - ~Render_World(); - Render_World(Render_World&& other) = default; - Render_World& operator=(Render_World&& other) = default; + Render_World(); + ~Render_World(); + Render_World(Render_World &&other) = default; + Render_World &operator=(Render_World &&other) = default; - Render_World(const Render_World& other) = delete; - Render_World& operator=(const Render_World& other) = delete; + Render_World(const Render_World &other) = delete; + Render_World &operator=(const Render_World &other) = delete; - void Render_Pixel(const ivec2& pixel_index); - void Render(); - void Initialize_Hierarchy(); - void Clear_Hierarchy(); + void Render_Pixel(const ivec2 &pixel_index); + void Render(); + void Initialize_Hierarchy(); + void Clear_Hierarchy(); - vec3 Cast_Ray(const Ray& ray,int recursion_depth); - Hit Closest_Intersection(const Ray& ray); + vec3 Cast_Ray(const Ray &ray, int recursion_depth); + Hit Closest_Intersection(const Ray &ray); }; #endif diff --git a/include/shaders/flat_shader.hpp b/include/shaders/flat_shader.hpp index fc18537..a7aa6f1 100644 --- a/include/shaders/flat_shader.hpp +++ b/include/shaders/flat_shader.hpp @@ -3,16 +3,15 @@ #include "shaders/shader.hpp" -class Flat_Shader : public Shader -{ -public: - vec3 color; +class Flat_Shader : public Shader { + public: + vec3 color; - Flat_Shader(Render_World& world_input,const vec3& color=vec3(1,1,1)) - :Shader(world_input),color(color) - {} + Flat_Shader(Render_World &world_input, const vec3 &color = vec3(1, 1, 1)) + : Shader(world_input), color(color) {} - virtual vec3 Shade_Surface(const Ray& ray,const vec3& intersection_point, - const vec3& normal,int recursion_depth) const override; + virtual vec3 Shade_Surface(const Ray &ray, const vec3 &intersection_point, + const vec3 &normal, + int recursion_depth) const override; }; #endif diff --git a/include/shaders/phong_shader.hpp b/include/shaders/phong_shader.hpp index 7111a61..042ec27 100644 --- a/include/shaders/phong_shader.hpp +++ b/include/shaders/phong_shader.hpp @@ -3,23 +3,22 @@ #include "shaders/shader.hpp" -class Phong_Shader : public Shader -{ -public: - vec3 color_ambient,color_diffuse,color_specular; - double specular_power; +class Phong_Shader : public Shader { + public: + vec3 color_ambient, color_diffuse, color_specular; + double specular_power; - Phong_Shader(Render_World& world_input, - const vec3& color_ambient, - const vec3& color_diffuse, - const vec3& color_specular, - double specular_power) - :Shader(world_input),color_ambient(color_ambient), - color_diffuse(color_diffuse),color_specular(color_specular), - specular_power(specular_power) - {} + Phong_Shader(Render_World &world_input, const vec3 &color_ambient, + const vec3 &color_diffuse, const vec3 &color_specular, + double specular_power) + : Shader(world_input), + color_ambient(color_ambient), + color_diffuse(color_diffuse), + color_specular(color_specular), + specular_power(specular_power) {} - virtual vec3 Shade_Surface(const Ray& ray,const vec3& intersection_point, - const vec3& normal,int recursion_depth) const override; + virtual vec3 Shade_Surface(const Ray &ray, const vec3 &intersection_point, + const vec3 &normal, + int recursion_depth) const override; }; #endif diff --git a/include/shaders/reflective_shader.hpp b/include/shaders/reflective_shader.hpp index 623e06c..1e511cd 100644 --- a/include/shaders/reflective_shader.hpp +++ b/include/shaders/reflective_shader.hpp @@ -2,20 +2,22 @@ #define __REFLECTIVE_SHADER_H__ #include + #include "shaders/shader.hpp" -class Reflective_Shader : public Shader -{ -public: - Shader* shader; - double reflectivity; +class Reflective_Shader : public Shader { + public: + Shader *shader; + double reflectivity; - Reflective_Shader(Render_World& world_input,Shader* shader_input,double reflectivity) - :Shader(world_input),shader(shader_input), - reflectivity(std::max(0.0,std::min(1.0,reflectivity))) - {} + Reflective_Shader(Render_World &world_input, Shader *shader_input, + double reflectivity) + : Shader(world_input), + shader(shader_input), + reflectivity(std::max(0.0, std::min(1.0, reflectivity))) {} - virtual vec3 Shade_Surface(const Ray& ray,const vec3& intersection_point, - const vec3& normal,int recursion_depth) const override; + virtual vec3 Shade_Surface(const Ray &ray, const vec3 &intersection_point, + const vec3 &normal, + int recursion_depth) const override; }; #endif diff --git a/include/shaders/shader.hpp b/include/shaders/shader.hpp index e33ba55..1e355cc 100644 --- a/include/shaders/shader.hpp +++ b/include/shaders/shader.hpp @@ -7,19 +7,15 @@ class Ray; extern bool debug_pixel; -class Shader -{ -public: - Render_World& world; +class Shader { + public: + Render_World &world; - Shader(Render_World& world_input) - :world(world_input) - {} + Shader(Render_World &world_input) : world(world_input) {} - virtual ~Shader() - {} + virtual ~Shader() {} - virtual vec3 Shade_Surface(const Ray& ray,const vec3& intersection_point, - const vec3& normal,int recursion_depth) const=0; + virtual vec3 Shade_Surface(const Ray &ray, const vec3 &intersection_point, + const vec3 &normal, int recursion_depth) const = 0; }; #endif diff --git a/include/vec.hpp b/include/vec.hpp index aeb3c77..3a96bdd 100644 --- a/include/vec.hpp +++ b/include/vec.hpp @@ -1,162 +1,196 @@ #ifndef __vec__ #define __vec__ +#include #include #include -#include static const double pi = 4 * atan(1.0); -template struct vec; -template T dot(const vec& u,const vec& v); - -template -struct vec -{ - T x[n]; - - vec() - {make_zero();} - - explicit vec(const T& a) - {assert(n == 1);x[0]=a;} - - vec(const T& a, const T& b) - {assert(n == 2);x[0]=a;x[1]=b;} - - vec(const T& a, const T& b, const T& c) - {assert(n == 3);x[0]=a;x[1]=b;x[2]=c;} - - template - explicit vec(const vec& v) - {for(int i = 0; i < n; i++) x[i] = (T)v.x[i];} - - void make_zero() - {fill(0);} - - void fill(T value) - {for(int i = 0; i < n; i++) x[i] = value;} - - vec& operator += (const vec& v) - {for(int i = 0; i < n; i++) x[i] += v.x[i]; return *this;} - - vec& operator -= (const vec& v) - {for(int i = 0; i < n; i++) x[i] -= v.x[i]; return *this;} - - vec& operator *= (const vec& v) - {for(int i = 0; i < n; i++) x[i] *= v.x[i]; return *this;} - - vec& operator /= (const vec& v) - {for(int i = 0; i < n; i++) x[i] /= v.x[i]; return *this;} - - vec& operator *= (const T& c) - {for(int i = 0; i < n; i++) x[i] *= c; return *this;} - - vec& operator /= (const T& c) - {for(int i = 0; i < n; i++) x[i] /= c; return *this;} - - vec operator + () const - {return *this;} +template +struct vec; +template +T dot(const vec &u, const vec &v); - vec operator - () const - {vec r; for(int i = 0; i < n; i++) r[i] = -x[i]; return r;} +template +struct vec { + T x[n]; + + vec() { make_zero(); } + + explicit vec(const T &a) { + assert(n == 1); + x[0] = a; + } + + vec(const T &a, const T &b) { + assert(n == 2); + x[0] = a; + x[1] = b; + } + + vec(const T &a, const T &b, const T &c) { + assert(n == 3); + x[0] = a; + x[1] = b; + x[2] = c; + } + + template + explicit vec(const vec &v) { + for (int i = 0; i < n; i++) x[i] = (T)v.x[i]; + } + + void make_zero() { fill(0); } + + void fill(T value) { + for (int i = 0; i < n; i++) x[i] = value; + } + + vec &operator+=(const vec &v) { + for (int i = 0; i < n; i++) x[i] += v.x[i]; + return *this; + } + + vec &operator-=(const vec &v) { + for (int i = 0; i < n; i++) x[i] -= v.x[i]; + return *this; + } + + vec &operator*=(const vec &v) { + for (int i = 0; i < n; i++) x[i] *= v.x[i]; + return *this; + } + + vec &operator/=(const vec &v) { + for (int i = 0; i < n; i++) x[i] /= v.x[i]; + return *this; + } + + vec &operator*=(const T &c) { + for (int i = 0; i < n; i++) x[i] *= c; + return *this; + } + + vec &operator/=(const T &c) { + for (int i = 0; i < n; i++) x[i] /= c; + return *this; + } + + vec operator+() const { return *this; } + + vec operator-() const { + vec r; + for (int i = 0; i < n; i++) r[i] = -x[i]; + return r; + } - vec operator + (const vec& v) const - {vec r; for(int i = 0; i < n; i++) r[i] = x[i] + v.x[i]; return r;} + vec operator+(const vec &v) const { + vec r; + for (int i = 0; i < n; i++) r[i] = x[i] + v.x[i]; + return r; + } - vec operator - (const vec& v) const - {vec r; for(int i = 0; i < n; i++) r[i] = x[i] - v.x[i]; return r;} + vec operator-(const vec &v) const { + vec r; + for (int i = 0; i < n; i++) r[i] = x[i] - v.x[i]; + return r; + } - vec operator * (const vec& v) const - {vec r; for(int i = 0; i < n; i++) r[i] = x[i] * v.x[i]; return r;} + vec operator*(const vec &v) const { + vec r; + for (int i = 0; i < n; i++) r[i] = x[i] * v.x[i]; + return r; + } - vec operator / (const vec& v) const - {vec r; for(int i = 0; i < n; i++) r[i] = x[i] / v.x[i]; return r;} + vec operator/(const vec &v) const { + vec r; + for (int i = 0; i < n; i++) r[i] = x[i] / v.x[i]; + return r; + } - vec operator * (const T& c) const - {vec r; for(int i = 0; i < n; i++) r[i] = x[i] * c; return r;} + vec operator*(const T &c) const { + vec r; + for (int i = 0; i < n; i++) r[i] = x[i] * c; + return r; + } - vec operator / (const T& c) const - {vec r; for(int i = 0; i < n; i++) r[i] = x[i] / c; return r;} + vec operator/(const T &c) const { + vec r; + for (int i = 0; i < n; i++) r[i] = x[i] / c; + return r; + } - const T& operator[] (int i) const - {return x[i];} + const T &operator[](int i) const { return x[i]; } - T& operator[] (int i) - {return x[i];} + T &operator[](int i) { return x[i]; } - T magnitude_squared() const - {return dot(*this, *this);} + T magnitude_squared() const { return dot(*this, *this); } - T magnitude() const - {return sqrt(magnitude_squared());} + T magnitude() const { return sqrt(magnitude_squared()); } - // Be careful to handle the zero vector gracefully - vec normalized() const - {T mag = magnitude(); if(mag) return *this / mag; vec r; r[0] = 1; return r;}; + // Be careful to handle the zero vector gracefully + vec normalized() const { + T mag = magnitude(); + if (mag) return *this / mag; + vec r; + r[0] = 1; + return r; + }; }; template -vec operator * (const T& c, const vec& v) -{return v*c;} +vec operator*(const T &c, const vec &v) { + return v * c; +} template -T dot(const vec & u, const vec & v) -{ - T r = 0; - for(int i = 0; i < n; i++) r += u.x[i] * v.x[i]; - return r; +T dot(const vec &u, const vec &v) { + T r = 0; + for (int i = 0; i < n; i++) r += u.x[i] * v.x[i]; + return r; } -template -vec cross(const vec & u, const vec & v) -{ - return vec ( - u[1] * v[2] - u[2] * v[1], - u[2] * v[0] - u[0] * v[2], - u[0] * v[1] - u[1] * v[0]); +template +vec cross(const vec &u, const vec &v) { + return vec(u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0]); } -template -vec componentwise_max(const vec& a, const vec& b) -{ - vec r; - for(int i=0; i +vec componentwise_max(const vec &a, const vec &b) { + vec r; + for (int i = 0; i < d; i++) r[i] = std::max(a[i], b[i]); + return r; } -template -vec componentwise_min(const vec& a, const vec& b) -{ - vec r; - for(int i=0; i +vec componentwise_min(const vec &a, const vec &b) { + vec r; + for (int i = 0; i < d; i++) r[i] = std::min(a[i], b[i]); + return r; } template -std::ostream& operator << (std::ostream& out, const vec & u) -{ - for(int i = 0; i < n; i++) - { - if(i) out << ' '; - out << u[i]; - } - return out; +std::ostream &operator<<(std::ostream &out, const vec &u) { + for (int i = 0; i < n; i++) { + if (i) out << ' '; + out << u[i]; + } + return out; } template -std::istream& operator >> (std::istream& in, vec & u) -{ - for(int i = 0; i < n; i++) - { - in >> u[i]; - } - return in; +std::istream &operator>>(std::istream &in, vec &u) { + for (int i = 0; i < n; i++) { + in >> u[i]; + } + return in; } -typedef vec vec2; -typedef vec vec3; -typedef vec ivec2; -typedef vec ivec3; +typedef vec vec2; +typedef vec vec3; +typedef vec ivec2; +typedef vec ivec3; #endif diff --git a/src/acceleration_structures/box.cpp b/src/acceleration_structures/box.cpp index 61a86a6..16eb2b1 100644 --- a/src/acceleration_structures/box.cpp +++ b/src/acceleration_structures/box.cpp @@ -3,65 +3,61 @@ #include // Return whether the ray intersects this box. -bool Box::Intersection(const Ray& ray) const -{ - double tmin = (lo[0] - ray.endpoint[0]) / ray.direction[0]; - double tmax = (hi[0] - ray.endpoint[0]) / ray.direction[0]; +bool Box::Intersection(const Ray &ray) const { + double tmin = (lo[0] - ray.endpoint[0]) / ray.direction[0]; + double tmax = (hi[0] - ray.endpoint[0]) / ray.direction[0]; - if (tmin > tmax) { - std::swap(tmin, tmax); - } + if (tmin > tmax) { + std::swap(tmin, tmax); + } - double tymin = (lo[1] - ray.endpoint[1]) / ray.direction[1]; - double tymax = (hi[1] - ray.endpoint[1]) / ray.direction[1]; + double tymin = (lo[1] - ray.endpoint[1]) / ray.direction[1]; + double tymax = (hi[1] - ray.endpoint[1]) / ray.direction[1]; - if (tymin > tymax) { - std::swap(tymin, tymax); - } - if ((tmin > tymax) || (tymin > tmax)) { - return false; - } + if (tymin > tymax) { + std::swap(tymin, tymax); + } + if ((tmin > tymax) || (tymin > tmax)) { + return false; + } - tmin = std::max(tmin,tymin); - tmax = std::min(tmax,tymax); + tmin = std::max(tmin, tymin); + tmax = std::min(tmax, tymax); - double tzmin = (lo[2] - ray.endpoint[2]) / ray.direction[2]; - double tzmax = (hi[2] - ray.endpoint[2]) / ray.direction[2]; + double tzmin = (lo[2] - ray.endpoint[2]) / ray.direction[2]; + double tzmax = (hi[2] - ray.endpoint[2]) / ray.direction[2]; - if (tzmin > tzmax) { - std::swap(tzmin, tzmax); - } + if (tzmin > tzmax) { + std::swap(tzmin, tzmax); + } - if ((tmin > tzmax) || (tzmin > tmax)) { - return false; - } + if ((tmin > tzmax) || (tzmin > tmax)) { + return false; + } - return true; + return true; } // Compute the smallest box that contains both *this and bb. -Box Box::Union(const Box& bb) const -{ - Box box; - for(int axis = 0; axis < 3; axis++){ - box.hi[axis] = std::max(hi[axis], bb.hi[axis]); - box.lo[axis] = std::min(lo[axis], bb.lo[axis]); - } - return box; +Box Box::Union(const Box &bb) const { + Box box; + for (int axis = 0; axis < 3; axis++) { + box.hi[axis] = std::max(hi[axis], bb.hi[axis]); + box.lo[axis] = std::min(lo[axis], bb.lo[axis]); + } + return box; } // Enlarge this box (if necessary) so that pt also lies inside it. -void Box::Include_Point(const vec3& pt) -{ - for(int axis = 0; axis < 3; axis++){ - hi[axis] = std::max(hi[axis], pt[axis]); - lo[axis] = std::min(lo[axis], pt[axis]); - } +void Box::Include_Point(const vec3 &pt) { + for (int axis = 0; axis < 3; axis++) { + hi[axis] = std::max(hi[axis], pt[axis]); + lo[axis] = std::min(lo[axis], pt[axis]); + } } // Create a box to which points can be correctly added using Include_Point. -void Box::Make_Empty() -{ - lo.fill(std::numeric_limits::infinity()); - hi=-lo; +void Box::Make_Empty() { + lo.fill(std::numeric_limits::infinity()); + hi = -lo; } diff --git a/src/acceleration_structures/hierarchy.cpp b/src/acceleration_structures/hierarchy.cpp index c1b4edd..8f6e71e 100644 --- a/src/acceleration_structures/hierarchy.cpp +++ b/src/acceleration_structures/hierarchy.cpp @@ -6,47 +6,46 @@ // Reorder the entries vector so that adjacent entries tend to be nearby. // You may want to implement box.cpp first. -void Hierarchy::Reorder_Entries() -{ - if(!entries.size()) return; - // sort based on bounding box lo, kinda stupid. But a start - std::sort(entries.begin(), entries.end(), [](Entry first, Entry second) {return first.box.lo[1] < second.box.lo[1];}); +void Hierarchy::Reorder_Entries() { + if (!entries.size()) return; + // sort based on bounding box lo, kinda stupid. But a start + std::sort(entries.begin(), entries.end(), [](Entry first, Entry second) { + return first.box.lo[1] < second.box.lo[1]; + }); } // Populate tree from entries. -void Hierarchy::Build_Tree() -{ - int n = entries.size(); - if(!n) return; - tree = std::vector(2 * n -1); - for (int i = 0 ; i < n; i++) { - tree[ n-1 + i] = entries[i].box; - } - for(int i = n-2; i >=0; i--){ - tree[i] = tree[2*i+1].Union(tree[2*i+2]); - } +void Hierarchy::Build_Tree() { + int n = entries.size(); + if (!n) return; + tree = std::vector(2 * n - 1); + for (int i = 0; i < n; i++) { + tree[n - 1 + i] = entries[i].box; + } + for (int i = n - 2; i >= 0; i--) { + tree[i] = tree[2 * i + 1].Union(tree[2 * i + 2]); + } } // Return a list of candidates (indices into the entries list) whose // bounding boxes intersect the ray. -void Hierarchy::Intersection_Candidates(const Ray& ray, std::vector& candidates) const -{ - int n = entries.size(); - if(!n) return; - std::queue check_nodes; - check_nodes.push(0); - int temp; - while(!check_nodes.empty()){ - temp = check_nodes.front(); - if(tree[temp].Intersection(ray)){ - if (temp >= n-1) { - candidates.push_back(temp - (n-1)); - } - else { - check_nodes.push(temp * 2 + 1); - check_nodes.push(temp * 2 + 2); - } - } - check_nodes.pop(); +void Hierarchy::Intersection_Candidates(const Ray &ray, + std::vector &candidates) const { + int n = entries.size(); + if (!n) return; + std::queue check_nodes; + check_nodes.push(0); + int temp; + while (!check_nodes.empty()) { + temp = check_nodes.front(); + if (tree[temp].Intersection(ray)) { + if (temp >= n - 1) { + candidates.push_back(temp - (n - 1)); + } else { + check_nodes.push(temp * 2 + 1); + check_nodes.push(temp * 2 + 2); + } } + check_nodes.pop(); + } } diff --git a/src/camera.cpp b/src/camera.cpp index 3c4be88..ff91c2c 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -1,88 +1,83 @@ #include "camera.hpp" -Camera::Camera() - :colors(0) -{ -} +Camera::Camera() : colors(0) {} -Camera::~Camera() -{ - if (colors) { - delete[] colors; - } +Camera::~Camera() { + if (colors) { + delete[] colors; + } } -Camera::Camera(const Camera& other){ - position = other.position; - film_position = other.film_position; - look_vector = other.look_vector; - vertical_vector = other.vertical_vector; - horizontal_vector = other.horizontal_vector; - - min = other.min; - max = other.max; - - image_size = other.image_size; - pixel_size = other.pixel_size; - number_pixels = other.number_pixels; +Camera::Camera(const Camera &other) { + position = other.position; + film_position = other.film_position; + look_vector = other.look_vector; + vertical_vector = other.vertical_vector; + horizontal_vector = other.horizontal_vector; + + min = other.min; + max = other.max; + + image_size = other.image_size; + pixel_size = other.pixel_size; + number_pixels = other.number_pixels; - colors=new Pixel[number_pixels[0]*number_pixels[1]]; + colors = new Pixel[number_pixels[0] * number_pixels[1]]; } -Camera& Camera::operator=(const Camera &other){ - position = other.position; - film_position = other.film_position; - look_vector = other.look_vector; - vertical_vector = other.vertical_vector; - horizontal_vector = other.horizontal_vector; - - min = other.min; - max = other.max; - - image_size = other.image_size; - pixel_size = other.pixel_size; - number_pixels = other.number_pixels; +Camera &Camera::operator=(const Camera &other) { + position = other.position; + film_position = other.film_position; + look_vector = other.look_vector; + vertical_vector = other.vertical_vector; + horizontal_vector = other.horizontal_vector; + + min = other.min; + max = other.max; + + image_size = other.image_size; + pixel_size = other.pixel_size; + number_pixels = other.number_pixels; + + if (colors) { + delete[] colors; + } + colors = new Pixel[number_pixels[0] * number_pixels[1]]; - if (colors) { - delete[] colors; - } - colors=new Pixel[number_pixels[0]*number_pixels[1]]; - - return *this; + return *this; } -void Camera::Position_And_Aim_Camera(const vec3& position_input, - const vec3& look_at_point,const vec3& pseudo_up_vector) -{ - position=position_input; - look_vector=(look_at_point-position).normalized(); - horizontal_vector=cross(look_vector,pseudo_up_vector).normalized(); - vertical_vector=cross(horizontal_vector,look_vector).normalized(); +void Camera::Position_And_Aim_Camera(const vec3 &position_input, + const vec3 &look_at_point, + const vec3 &pseudo_up_vector) { + position = position_input; + look_vector = (look_at_point - position).normalized(); + horizontal_vector = cross(look_vector, pseudo_up_vector).normalized(); + vertical_vector = cross(horizontal_vector, look_vector).normalized(); } -void Camera::Focus_Camera(double focal_distance,double aspect_ratio, - double field_of_view) -{ - film_position=position+look_vector*focal_distance; - double width=2.0*focal_distance*tan(.5*field_of_view); - double height=width/aspect_ratio; - image_size=vec2(width,height); +void Camera::Focus_Camera(double focal_distance, double aspect_ratio, + double field_of_view) { + film_position = position + look_vector * focal_distance; + double width = 2.0 * focal_distance * tan(.5 * field_of_view); + double height = width / aspect_ratio; + image_size = vec2(width, height); } -void Camera::Set_Resolution(const ivec2& number_pixels_input) -{ - number_pixels=number_pixels_input; - if(colors) delete[] colors; - colors=new Pixel[number_pixels[0]*number_pixels[1]]; - min=-0.5*image_size; - max=0.5*image_size; - pixel_size = image_size/vec2(number_pixels); +void Camera::Set_Resolution(const ivec2 &number_pixels_input) { + number_pixels = number_pixels_input; + if (colors) delete[] colors; + colors = new Pixel[number_pixels[0] * number_pixels[1]]; + min = -0.5 * image_size; + max = 0.5 * image_size; + pixel_size = image_size / vec2(number_pixels); } // Find the world position of the input pixel -vec3 Camera::World_Position(const ivec2& pixel_index) -{ - vec2 cellCenterScreenSpace = Cell_Center(pixel_index); - vec3 result = film_position + ((cellCenterScreenSpace[0] * horizontal_vector) + cellCenterScreenSpace[1] * vertical_vector); - return result; +vec3 Camera::World_Position(const ivec2 &pixel_index) { + vec2 cellCenterScreenSpace = Cell_Center(pixel_index); + vec3 result = + film_position + ((cellCenterScreenSpace[0] * horizontal_vector) + + cellCenterScreenSpace[1] * vertical_vector); + return result; } diff --git a/src/objects/mesh.cpp b/src/objects/mesh.cpp index 64af8f8..4f1d8ff 100644 --- a/src/objects/mesh.cpp +++ b/src/objects/mesh.cpp @@ -1,8 +1,8 @@ #include "objects/mesh.hpp" #include -#include #include +#include #include "directories.hpp" @@ -12,85 +12,76 @@ static const double weight_tolerance = 1e-4; // Read in a mesh from an obj file. Populates the bounding box and registers // one part per triangle (by setting number_parts). -void Mesh::Read_Obj(const char* file) -{ - std::ifstream fin(getObjectsDir() + file); - if(!fin) - { - exit(EXIT_FAILURE); +void Mesh::Read_Obj(const char *file) { + std::ifstream fin(getObjectsDir() + file); + if (!fin) { + exit(EXIT_FAILURE); + } + std::string line; + ivec3 e; + vec3 v; + box.Make_Empty(); + while (fin) { + getline(fin, line); + + if (sscanf(line.c_str(), "v %lg %lg %lg", &v[0], &v[1], &v[2]) == 3) { + vertices.push_back(v); + box.Include_Point(v); } - std::string line; - ivec3 e; - vec3 v; - box.Make_Empty(); - while(fin) - { - getline(fin,line); - - if(sscanf(line.c_str(), "v %lg %lg %lg", &v[0], &v[1], &v[2]) == 3) - { - vertices.push_back(v); - box.Include_Point(v); - } - if(sscanf(line.c_str(), "f %d %d %d", &e[0], &e[1], &e[2]) == 3) - { - for(int i=0;i<3;i++) e[i]--; - triangles.push_back(e); - } + if (sscanf(line.c_str(), "f %d %d %d", &e[0], &e[1], &e[2]) == 3) { + for (int i = 0; i < 3; i++) e[i]--; + triangles.push_back(e); } - number_parts=triangles.size(); + } + number_parts = triangles.size(); } // Check for an intersection against the ray. See the base class for details. -Hit Mesh::Intersection(const Ray& ray, int part) const -{ - double dist; - if(part >= 0){ - if(part >= number_parts){ - return {}; - } - if(!Bounding_Box(part).Intersection(ray)){ - return {}; - } - if(Intersect_Triangle(ray,part,dist)){ - return {this, dist, part}; - } +Hit Mesh::Intersection(const Ray &ray, int part) const { + double dist; + if (part >= 0) { + if (part >= number_parts) { + return {}; } - else{ - if(!box.Intersection(ray)){ - return {}; - } - int min_part = -1; - double min_dist = std::numeric_limits::infinity(); - for(int i = 0; i < number_parts; i++){ - if(Intersect_Triangle(ray,i,dist)){ - if(dist < min_dist){ - min_dist = dist; - min_part = i; - } - } - } - if(min_part == -1){ - return {}; - } - else{ - return {this,min_dist,min_part}; + if (!Bounding_Box(part).Intersection(ray)) { + return {}; + } + if (Intersect_Triangle(ray, part, dist)) { + return {this, dist, part}; + } + } else { + if (!box.Intersection(ray)) { + return {}; + } + int min_part = -1; + double min_dist = std::numeric_limits::infinity(); + for (int i = 0; i < number_parts; i++) { + if (Intersect_Triangle(ray, i, dist)) { + if (dist < min_dist) { + min_dist = dist; + min_part = i; } + } } - return {}; + if (min_part == -1) { + return {}; + } else { + return {this, min_dist, min_part}; + } + } + return {}; } // Compute the normal direction for the triangle with index part. -vec3 Mesh::Normal(const vec3& point, int part) const -{ - assert(part>=0); - vec3 point0 = vertices[triangles[part][0]]; - vec3 point1 = vertices[triangles[part][1]]; - vec3 point2 = vertices[triangles[part][2]]; - - vec3 normal = cross(point1 - point0, point2 - point0).normalized(); - return normal; +vec3 Mesh::Normal(const vec3 &point, int part) const { + assert(part >= 0); + vec3 point0 = vertices[triangles[part][0]]; + vec3 point1 = vertices[triangles[part][1]]; + vec3 point2 = vertices[triangles[part][2]]; + + vec3 normal = cross(point1 - point0, point2 - point0).normalized(); + return normal; } // This is a helper routine whose purpose is to simplify the implementation @@ -105,57 +96,55 @@ vec3 Mesh::Normal(const vec3& point, int part) const // larger than -weight_tolerance. The use of small_t avoid the self-shadowing // bug, and the use of weight_tolerance prevents rays from passing in between // two triangles. -bool Mesh::Intersect_Triangle(const Ray& ray, int tri, double& dist) const -{ - ivec3 triangle = triangles[tri]; - vec3 point0 = vertices[triangle[0]]; - vec3 point1 = vertices[triangle[1]]; - vec3 point2 = vertices[triangle[2]]; +bool Mesh::Intersect_Triangle(const Ray &ray, int tri, double &dist) const { + ivec3 triangle = triangles[tri]; + vec3 point0 = vertices[triangle[0]]; + vec3 point1 = vertices[triangle[1]]; + vec3 point2 = vertices[triangle[2]]; - vec3 normal = cross(point1 - point0, point2 - point0); + vec3 normal = cross(point1 - point0, point2 - point0); - double bespoke_weight_tolerance = normal.magnitude_squared() * - weight_tol; + double bespoke_weight_tolerance = normal.magnitude_squared() * -weight_tol; - if(abs(dot(normal,ray.direction)) < -1e-4) { - return false; - } + if (abs(dot(normal, ray.direction)) < -1e-4) { + return false; + } - double d = -dot(normal, point0); + double d = -dot(normal, point0); - double t = -(dot(normal, ray.endpoint) + d) / dot(normal,ray.direction); - if (t < small_t){ - return false; - } + double t = -(dot(normal, ray.endpoint) + d) / dot(normal, ray.direction); + if (t < small_t) { + return false; + } - vec3 p = ray.endpoint + t * ray.direction; + vec3 p = ray.endpoint + t * ray.direction; - vec3 c = cross(point1 - point0, p - point0); - if (dot(normal,c) < bespoke_weight_tolerance) { - return false; - } + vec3 c = cross(point1 - point0, p - point0); + if (dot(normal, c) < bespoke_weight_tolerance) { + return false; + } - c = cross(point2 - point1, p - point1); - if (dot(normal, c) < bespoke_weight_tolerance){ - return false; - } - c = cross(point0 - point2, p - point2); - if (dot(normal, c) < bespoke_weight_tolerance) { - return false; - } + c = cross(point2 - point1, p - point1); + if (dot(normal, c) < bespoke_weight_tolerance) { + return false; + } + c = cross(point0 - point2, p - point2); + if (dot(normal, c) < bespoke_weight_tolerance) { + return false; + } - dist = t; + dist = t; - return true; + return true; } // Compute the bounding box. Return the bounding box of only the triangle whose // index is part. -Box Mesh::Bounding_Box(int part) const -{ - Box b; - b.Make_Empty(); - b.Include_Point(vertices[triangles[part][0]]); - b.Include_Point(vertices[triangles[part][1]]); - b.Include_Point(vertices[triangles[part][2]]); - return b; +Box Mesh::Bounding_Box(int part) const { + Box b; + b.Make_Empty(); + b.Include_Point(vertices[triangles[part][0]]); + b.Include_Point(vertices[triangles[part][1]]); + b.Include_Point(vertices[triangles[part][2]]); + return b; } diff --git a/src/objects/plane.cpp b/src/objects/plane.cpp index c738fbc..de3037b 100644 --- a/src/objects/plane.cpp +++ b/src/objects/plane.cpp @@ -1,34 +1,30 @@ #include "objects/plane.hpp" -#include "ray.hpp" #include #include +#include "ray.hpp" + // Intersect with the half space defined by the plane. The plane's normal // points outside. If the ray starts on the "inside" side of the plane, be sure // to record a hit with t=0 as the first entry in hits. -Hit Plane::Intersection(const Ray& ray, int part) const -{ - double product = dot(normal, ray.direction); - if (product < -1e-6) { - vec3 second_vec = x1 - ray.endpoint; - double t = dot(second_vec, normal) / product; - return {this, t, 0}; - } - return {0,0,0}; +Hit Plane::Intersection(const Ray &ray, int part) const { + double product = dot(normal, ray.direction); + if (product < -1e-6) { + vec3 second_vec = x1 - ray.endpoint; + double t = dot(second_vec, normal) / product; + return {this, t, 0}; + } + return {0, 0, 0}; } -vec3 Plane::Normal(const vec3& point, int part) const -{ - return normal; -} +vec3 Plane::Normal(const vec3 &point, int part) const { return normal; } // There is not a good answer for the bounding box of an infinite object. // The safe thing to do is to return a box that contains everything. -Box Plane::Bounding_Box(int part) const -{ - Box b; - b.hi.fill(std::numeric_limits::max()); - b.lo=-b.hi; - return b; +Box Plane::Bounding_Box(int part) const { + Box b; + b.hi.fill(std::numeric_limits::max()); + b.lo = -b.hi; + return b; } diff --git a/src/objects/sphere.cpp b/src/objects/sphere.cpp index 1ac5dfc..0e61560 100644 --- a/src/objects/sphere.cpp +++ b/src/objects/sphere.cpp @@ -1,35 +1,33 @@ #include "objects/sphere.hpp" + #include "ray.hpp" // Determine if the ray intersects with the sphere -Hit Sphere::Intersection(const Ray& ray, int part) const -{ - vec3 L = center - ray.endpoint; - double tc = dot(L, ray.direction); - if (tc < 0.0){ - return {0,0,0}; - } - float dist_to_center_squared = L.magnitude_squared() - tc * tc; - if(abs(dist_to_center_squared) > radius * radius){ - return {0,0,0}; - } +Hit Sphere::Intersection(const Ray &ray, int part) const { + vec3 L = center - ray.endpoint; + double tc = dot(L, ray.direction); + if (tc < 0.0) { + return {0, 0, 0}; + } + float dist_to_center_squared = L.magnitude_squared() - tc * tc; + if (abs(dist_to_center_squared) > radius * radius) { + return {0, 0, 0}; + } - float t1c = sqrt(radius * radius - dist_to_center_squared); + float t1c = sqrt(radius * radius - dist_to_center_squared); - return {this,tc - t1c,0}; + return {this, tc - t1c, 0}; } -vec3 Sphere::Normal(const vec3& point, int part) const -{ - vec3 normal = point - center; - return normal.normalized(); +vec3 Sphere::Normal(const vec3 &point, int part) const { + vec3 normal = point - center; + return normal.normalized(); } -Box Sphere::Bounding_Box(int part) const -{ - Box box; - vec3 radius_vector = {radius, radius, radius}; - box.hi = center + radius_vector; - box.lo = center - radius_vector; - return box; +Box Sphere::Bounding_Box(int part) const { + Box box; + vec3 radius_vector = {radius, radius, radius}; + box.hi = center + radius_vector; + box.lo = center - radius_vector; + return box; } diff --git a/src/render_world.cpp b/src/render_world.cpp index 3819c6a..46b27e2 100644 --- a/src/render_world.cpp +++ b/src/render_world.cpp @@ -1,100 +1,96 @@ +#include "render_world.hpp" + #include -#include "render_world.hpp" -#include "shaders/flat_shader.hpp" -#include "objects/object.hpp" -#include "lights/light.hpp" #include "acceleration_structures/hierarchy.hpp" +#include "lights/light.hpp" +#include "objects/object.hpp" #include "ray.hpp" +#include "shaders/flat_shader.hpp" Render_World::Render_World() - :background_shader(0),ambient_intensity(0),enable_shadows(true), - recursion_depth_limit(3) -{} + : background_shader(0), + ambient_intensity(0), + enable_shadows(true), + recursion_depth_limit(3) {} -Render_World::~Render_World() -{ - if(!background_shader) - delete background_shader; - for(size_t i=0;i=small_t. -Hit Render_World::Closest_Intersection(const Ray& ray) -{ - Hit temp; - Hit output {nullptr, std::numeric_limits::max(), 0}; - std::vector candidates; - hierarchy.Intersection_Candidates(ray, candidates); - for (int candidate : candidates){ - temp = hierarchy.entries[candidate].obj->Intersection(ray,hierarchy.entries[candidate].part); - if (temp.object != nullptr) { - if(temp.dist < output.dist){ - output = temp; - } - } +Hit Render_World::Closest_Intersection(const Ray &ray) { + Hit temp; + Hit output{nullptr, std::numeric_limits::max(), 0}; + std::vector candidates; + hierarchy.Intersection_Candidates(ray, candidates); + for (int candidate : candidates) { + temp = hierarchy.entries[candidate].obj->Intersection( + ray, hierarchy.entries[candidate].part); + if (temp.object != nullptr) { + if (temp.dist < output.dist) { + output = temp; + } } - return output; + } + return output; } - // set up the initial view ray and call -void Render_World::Render_Pixel(const ivec2& pixel_index) -{ - Ray ray = Ray(camera.position, camera.World_Position(pixel_index) - camera.position); - vec3 color=Cast_Ray(ray,1); - camera.Set_Pixel(pixel_index,Pixel_Color(color)); +void Render_World::Render_Pixel(const ivec2 &pixel_index) { + Ray ray = Ray(camera.position, + camera.World_Position(pixel_index) - camera.position); + vec3 color = Cast_Ray(ray, 1); + camera.Set_Pixel(pixel_index, Pixel_Color(color)); } -void Render_World::Render() -{ - if (!hierarchy_initialized) { - Initialize_Hierarchy(); - } +void Render_World::Render() { + if (!hierarchy_initialized) { + Initialize_Hierarchy(); + } - for(int j=0;jmaterial_shader->Shade_Surface(ray, point, closest.object->Normal(point, closest.part), recursion_depth); - } - else{ - return background_shader->Shade_Surface(ray, {0,0,0}, -ray.direction, recursion_depth); - } +vec3 Render_World::Cast_Ray(const Ray &ray, int recursion_depth) { + vec3 color; + Hit closest = Closest_Intersection(ray); + if (closest.object != nullptr) { + vec3 point = ray.endpoint + closest.dist * ray.direction; + return closest.object->material_shader->Shade_Surface( + ray, point, closest.object->Normal(point, closest.part), + recursion_depth); + } else { + return background_shader->Shade_Surface(ray, {0, 0, 0}, -ray.direction, + recursion_depth); + } } -void Render_World::Initialize_Hierarchy() -{ - if (hierarchy_initialized){ - return; - } - hierarchy_initialized = true; - // Fill in hierarchy.entries; there should be one entry for - // each part of each object. - for(Object* object: objects){ - for(int i = 0; i < object->number_parts; i++){ - hierarchy.entries.push_back({object,i,object->Bounding_Box(i)}); - } +void Render_World::Initialize_Hierarchy() { + if (hierarchy_initialized) { + return; + } + hierarchy_initialized = true; + // Fill in hierarchy.entries; there should be one entry for + // each part of each object. + for (Object *object : objects) { + for (int i = 0; i < object->number_parts; i++) { + hierarchy.entries.push_back({object, i, object->Bounding_Box(i)}); } - hierarchy.Reorder_Entries(); - hierarchy.Build_Tree(); + } + hierarchy.Reorder_Entries(); + hierarchy.Build_Tree(); } -void Render_World::Clear_Hierarchy() -{ - hierarchy_initialized = false; +void Render_World::Clear_Hierarchy() { + hierarchy_initialized = false; - hierarchy.entries.clear(); - hierarchy.tree.clear(); + hierarchy.entries.clear(); + hierarchy.tree.clear(); } diff --git a/src/shaders/flat_shader.cpp b/src/shaders/flat_shader.cpp index 4969560..7e2c814 100644 --- a/src/shaders/flat_shader.cpp +++ b/src/shaders/flat_shader.cpp @@ -1,8 +1,6 @@ #include "shaders/flat_shader.hpp" -vec3 Flat_Shader:: -Shade_Surface(const Ray& ray,const vec3& intersection_point, - const vec3& normal,int recursion_depth) const -{ - return color; +vec3 Flat_Shader::Shade_Surface(const Ray &ray, const vec3 &intersection_point, + const vec3 &normal, int recursion_depth) const { + return color; } diff --git a/src/shaders/phong_shader.cpp b/src/shaders/phong_shader.cpp index 240e2b5..cf08a57 100644 --- a/src/shaders/phong_shader.cpp +++ b/src/shaders/phong_shader.cpp @@ -1,46 +1,50 @@ #include "shaders/phong_shader.hpp" #include "lights/light.hpp" +#include "objects/object.hpp" #include "ray.hpp" #include "render_world.hpp" -#include "objects/object.hpp" -vec3 Phong_Shader:: -Shade_Surface(const Ray& ray, const vec3& intersection_point, - const vec3& normal,int recursion_depth) const -{ - vec3 specular = {0,0,0}; - vec3 diffuse = {0,0,0}; +vec3 Phong_Shader::Shade_Surface(const Ray &ray, const vec3 &intersection_point, + const vec3 &normal, + int recursion_depth) const { + vec3 specular = {0, 0, 0}; + vec3 diffuse = {0, 0, 0}; - vec3 currentLightIntensity; - vec3 currentLightDir; - vec3 reflectionDir; - vec3 normalizedLightDir; + vec3 currentLightIntensity; + vec3 currentLightDir; + vec3 reflectionDir; + vec3 normalizedLightDir; - for (Light *light: world.lights){ - currentLightDir = light->position - intersection_point; - normalizedLightDir = currentLightDir.normalized(); - if(world.enable_shadows){ - Hit closest = world.Closest_Intersection(Ray(intersection_point,normalizedLightDir)); - if (closest.object != nullptr){ - if(closest.dist < currentLightDir.magnitude()){ - continue; - } - } - } - if (dot(currentLightDir, normal) < 1e-6) { - continue; + for (Light *light : world.lights) { + currentLightDir = light->position - intersection_point; + normalizedLightDir = currentLightDir.normalized(); + if (world.enable_shadows) { + Hit closest = world.Closest_Intersection( + Ray(intersection_point, normalizedLightDir)); + if (closest.object != nullptr) { + if (closest.dist < currentLightDir.magnitude()) { + continue; } - else { - normalizedLightDir = currentLightDir.normalized(); - currentLightIntensity = light->Emitted_Light(currentLightDir); - diffuse += currentLightIntensity * std::max(0.0, dot(normal,normalizedLightDir)); - - reflectionDir = 2 * dot(normalizedLightDir, normal) * normal - normalizedLightDir; - specular += currentLightIntensity * std::pow(std::max(0.0,dot(reflectionDir, -ray.direction)),specular_power); + } + } + if (dot(currentLightDir, normal) < 1e-6) { + continue; + } else { + normalizedLightDir = currentLightDir.normalized(); + currentLightIntensity = light->Emitted_Light(currentLightDir); + diffuse += currentLightIntensity * + std::max(0.0, dot(normal, normalizedLightDir)); - } + reflectionDir = + 2 * dot(normalizedLightDir, normal) * normal - normalizedLightDir; + specular += currentLightIntensity * + std::pow(std::max(0.0, dot(reflectionDir, -ray.direction)), + specular_power); } - vec3 color = specular * color_specular + world.ambient_intensity * color_ambient * world.ambient_color + diffuse * color_diffuse; - return color; + } + vec3 color = specular * color_specular + + world.ambient_intensity * color_ambient * world.ambient_color + + diffuse * color_diffuse; + return color; } diff --git a/src/shaders/reflective_shader.cpp b/src/shaders/reflective_shader.cpp index b7042c3..a507ffd 100644 --- a/src/shaders/reflective_shader.cpp +++ b/src/shaders/reflective_shader.cpp @@ -1,23 +1,32 @@ #include "shaders/reflective_shader.hpp" + #include "ray.hpp" #include "render_world.hpp" -vec3 Reflective_Shader:: -Shade_Surface(const Ray& ray,const vec3& intersection_point, - const vec3& normal,int recursion_depth) const -{ - vec3 color = (1-reflectivity) * shader->Shade_Surface(ray, intersection_point, normal, recursion_depth);; - if(recursion_depth >= world.recursion_depth_limit){ - return color; - } - vec3 reflectionDir = ray.direction - 2 * dot(ray.direction, normal) * normal ; - Hit closest = world.Closest_Intersection(Ray(intersection_point,reflectionDir)); - if (closest.object != nullptr){ - vec3 point = intersection_point + closest.dist * reflectionDir; - color += reflectivity * closest.object->material_shader->Shade_Surface(Ray(intersection_point,reflectionDir),point,closest.object->Normal(point, closest.part),recursion_depth+1); - } - else { - color += reflectivity * world.background_shader->Shade_Surface(Ray(intersection_point,reflectionDir),{0,0,0},{0,0,0},0); - } +vec3 Reflective_Shader::Shade_Surface(const Ray &ray, + const vec3 &intersection_point, + const vec3 &normal, + int recursion_depth) const { + vec3 color = + (1 - reflectivity) * + shader->Shade_Surface(ray, intersection_point, normal, recursion_depth); + ; + if (recursion_depth >= world.recursion_depth_limit) { return color; + } + vec3 reflectionDir = ray.direction - 2 * dot(ray.direction, normal) * normal; + Hit closest = + world.Closest_Intersection(Ray(intersection_point, reflectionDir)); + if (closest.object != nullptr) { + vec3 point = intersection_point + closest.dist * reflectionDir; + color += reflectivity * closest.object->material_shader->Shade_Surface( + Ray(intersection_point, reflectionDir), point, + closest.object->Normal(point, closest.part), + recursion_depth + 1); + } else { + color += reflectivity * world.background_shader->Shade_Surface( + Ray(intersection_point, reflectionDir), + {0, 0, 0}, {0, 0, 0}, 0); + } + return color; } diff --git a/tools/benchmark/include/hierarchy_bench.hpp b/tools/benchmark/include/hierarchy_bench.hpp index f04fe0e..89ef4a0 100644 --- a/tools/benchmark/include/hierarchy_bench.hpp +++ b/tools/benchmark/include/hierarchy_bench.hpp @@ -2,134 +2,140 @@ #define __BENCHMARK_HIERARCHY_HPP__ #include + #include "acceleration_structures/hierarchy.hpp" #include "directories.hpp" -#include "render_world.hpp" -#include "parse.hpp" #include "lights/point_light.hpp" #include "objects/mesh.hpp" +#include "parse.hpp" +#include "render_world.hpp" #include "shaders/flat_shader.hpp" #include "shaders/phong_shader.hpp" +Render_World SetupBenchmarkWorld(int width, int height, vec3 cameraP, + vec3 cameraL, vec3 cameraU) { + Render_World world; -Render_World SetupBenchmarkWorld(int width, int height, vec3 cameraP, vec3 cameraL, vec3 cameraU) { - Render_World world; - - // Setup world - world.enable_shadows = false; - world.recursion_depth_limit = 1; - world.background_shader=new Flat_Shader(world,vec3()); + // Setup world + world.enable_shadows = false; + world.recursion_depth_limit = 1; + world.background_shader = new Flat_Shader(world, vec3()); - // Setup objects - Mesh* o=new Mesh; - o->Read_Obj("sphere.obj"); - o->material_shader = new Phong_Shader(world, {1,1,1}, {1,1,1}, {1,1,1}, 50); - world.objects.push_back(o); + // Setup objects + Mesh *o = new Mesh; + o->Read_Obj("sphere.obj"); + o->material_shader = + new Phong_Shader(world, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}, 50); + world.objects.push_back(o); - // Setup lights - world.lights.push_back(new Point_Light(vec3(.8, .8, 4), vec3(1,1,1), 100)); - world.ambient_color = {1,1,1}; - world.ambient_intensity = 0; + // Setup lights + world.lights.push_back(new Point_Light(vec3(.8, .8, 4), vec3(1, 1, 1), 100)); + world.ambient_color = {1, 1, 1}; + world.ambient_intensity = 0; - // Setup Camera - world.camera.Position_And_Aim_Camera(cameraP,cameraL,cameraU); - world.camera.Focus_Camera(1,(double)width/height,70*(pi/180)); + // Setup Camera + world.camera.Position_And_Aim_Camera(cameraP, cameraL, cameraU); + world.camera.Focus_Camera(1, (double)width / height, 70 * (pi / 180)); - world.camera.Set_Resolution(ivec2(width,height)); + world.camera.Set_Resolution(ivec2(width, height)); - return world; + return world; } -static void BM_setupHierarchy(benchmark::State& state) { - int width=0; - int height=0; - Render_World world = std::move(SetupBenchmarkWorld(640,480, vec3(0,0,1), vec3(0,0,0), vec3(0,1,0))); +static void BM_setupHierarchy(benchmark::State &state) { + int width = 0; + int height = 0; + Render_World world = std::move(SetupBenchmarkWorld( + 640, 480, vec3(0, 0, 1), vec3(0, 0, 0), vec3(0, 1, 0))); - for (auto _ : state) { - world.Initialize_Hierarchy(); - world.Clear_Hierarchy(); - } + for (auto _ : state) { + world.Initialize_Hierarchy(); + world.Clear_Hierarchy(); + } } BENCHMARK(BM_setupHierarchy); class IntersectionCandidatesFixture : public benchmark::Fixture { -public: - void SetUp(::benchmark::State& state) { - Camera tempCamera; - vec3 look = {0,0,0}; - vec3 up = {0,1,0}; - - // Parse test scene file - world = std::move(SetupBenchmarkWorld(width,height, vec3(0,0,2), look, up)); - world.Initialize_Hierarchy(); + public: + void SetUp(::benchmark::State &state) { + Camera tempCamera; + vec3 look = {0, 0, 0}; + vec3 up = {0, 1, 0}; - cardinal_directions = std::vector(6); - direction_names = std::vector(6); + // Parse test scene file + world = + std::move(SetupBenchmarkWorld(width, height, vec3(0, 0, 2), look, up)); + world.Initialize_Hierarchy(); - cardinal_directions[0] = {0,0,2}; - direction_names[0] = "north"; + cardinal_directions = std::vector(6); + direction_names = std::vector(6); - cardinal_directions[1] = {2,0,0}; - direction_names[1] = "east"; + cardinal_directions[0] = {0, 0, 2}; + direction_names[0] = "north"; - cardinal_directions[2] = {0,0,-2}; - direction_names[2] = "south"; + cardinal_directions[1] = {2, 0, 0}; + direction_names[1] = "east"; - cardinal_directions[3] = {-2,0,0}; - direction_names[3] = "west"; + cardinal_directions[2] = {0, 0, -2}; + direction_names[2] = "south"; - cardinal_directions[4] = {0,2,0}; - direction_names[4] = "up"; + cardinal_directions[3] = {-2, 0, 0}; + direction_names[3] = "west"; - cardinal_directions[5] = {0,-2,0}; - direction_names[5] = "down"; + cardinal_directions[4] = {0, 2, 0}; + direction_names[4] = "up"; - for(int i = 0; i < cardinal_directions.size(); i++){ - vec3 direction = cardinal_directions[i]; - if (i > 3){ - look = {0,0,1}; - } - tempCamera = Camera(); - tempCamera.Position_And_Aim_Camera(direction, look, up); - tempCamera.Focus_Camera(1,(double)width/height,f0*(pi/180)); - tempCamera.Set_Resolution(ivec2(width,height)); + cardinal_directions[5] = {0, -2, 0}; + direction_names[5] = "down"; - nominal_direction_cameras.push_back(tempCamera); - } + for (int i = 0; i < cardinal_directions.size(); i++) { + vec3 direction = cardinal_directions[i]; + if (i > 3) { + look = {0, 0, 1}; + } + tempCamera = Camera(); + tempCamera.Position_And_Aim_Camera(direction, look, up); + tempCamera.Focus_Camera(1, (double)width / height, f0 * (pi / 180)); + tempCamera.Set_Resolution(ivec2(width, height)); + nominal_direction_cameras.push_back(tempCamera); } - - void TearDown(::benchmark::State& state) { } -public: - std::vector cardinal_directions; - std::vector direction_names; - int width=640; - int height=480; - Render_World world; - std::vector nominal_direction_cameras; - double f0 = 70; -}; + void TearDown(::benchmark::State &state) {} -BENCHMARK_DEFINE_F(IntersectionCandidatesFixture, NominalDirections)(benchmark::State& state) { - Ray ray; - int current_camera_index = state.range(0); - state.SetLabel(direction_names[current_camera_index]); - - world.camera = nominal_direction_cameras[current_camera_index]; + public: + std::vector cardinal_directions; + std::vector direction_names; + int width = 640; + int height = 480; + Render_World world; + std::vector nominal_direction_cameras; + double f0 = 70; +}; - for (auto _ : state) { - for(int j=0;jName("IntersectionCandidatesByDirection")->DenseRange(0,5,1); +BENCHMARK_REGISTER_F(IntersectionCandidatesFixture, NominalDirections) + ->Name("IntersectionCandidatesByDirection") + ->DenseRange(0, 5, 1); -#endif // __BENCHMARK_HIERARCHY_HPP__ +#endif // __BENCHMARK_HIERARCHY_HPP__ diff --git a/tools/benchmark/source/main.cpp b/tools/benchmark/source/main.cpp index bd70ee7..e28c49a 100644 --- a/tools/benchmark/source/main.cpp +++ b/tools/benchmark/source/main.cpp @@ -1,4 +1,5 @@ #include + #include "hierarchy_bench.hpp" BENCHMARK_MAIN(); \ No newline at end of file diff --git a/tools/common/dump_mp4.cpp b/tools/common/dump_mp4.cpp index 06162ac..dc37523 100644 --- a/tools/common/dump_mp4.cpp +++ b/tools/common/dump_mp4.cpp @@ -25,572 +25,597 @@ #include extern "C" { +#include +#include #include #include -#include #include +#include #include -#include -#include -#include #include +#include } -#define STREAM_DURATION 10.0 +#undef av_err2str +#define av_err2str(errnum) \ + av_make_error_string((char *)__builtin_alloca(AV_ERROR_MAX_STRING_SIZE), \ + AV_ERROR_MAX_STRING_SIZE, errnum) + +#define STREAM_DURATION 10.0 #define STREAM_FRAME_RATE 25 /* 25 images/s */ // a wrapper around a single output AVStream typedef struct OutputStream { - AVStream *st; - AVCodecContext *enc; + AVStream *st; + AVCodecContext *enc; - /* pts of the next frame that will be generated */ - int64_t next_pts; - int samples_count; + /* pts of the next frame that will be generated */ + int64_t next_pts; + int samples_count; - AVFrame *frame; - AVFrame *tmp_frame; + AVFrame *frame; + AVFrame *tmp_frame; - AVPacket *tmp_pkt; + AVPacket *tmp_pkt; - float t, tincr, tincr2; + float t, tincr, tincr2; - struct SwsContext *sws_ctx; - struct SwrContext *swr_ctx; + struct SwsContext *sws_ctx; + struct SwrContext *swr_ctx; } OutputStream; static int write_frame(AVFormatContext *fmt_ctx, AVCodecContext *c, - AVStream *st, AVFrame *frame, AVPacket *pkt) -{ - int ret; - - // send the frame to the encoder - ret = avcodec_send_frame(c, frame); - if (ret < 0) { - fprintf(stderr, "Error sending a frame to the encoder: %s\n", - av_err2str(ret)); - exit(1); + AVStream *st, AVFrame *frame, AVPacket *pkt) { + int ret; + + // send the frame to the encoder + ret = avcodec_send_frame(c, frame); + if (ret < 0) { + fprintf(stderr, "Error sending a frame to the encoder: %s\n", + av_err2str(ret)); + exit(1); + } + + while (ret >= 0) { + ret = avcodec_receive_packet(c, pkt); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + else if (ret < 0) { + fprintf(stderr, "Error encoding a frame: %s\n", av_err2str(ret)); + exit(1); } - while (ret >= 0) { - ret = avcodec_receive_packet(c, pkt); - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) - break; - else if (ret < 0) { - fprintf(stderr, "Error encoding a frame: %s\n", av_err2str(ret)); - exit(1); - } + /* rescale output packet timestamp values from codec to stream timebase */ + av_packet_rescale_ts(pkt, c->time_base, st->time_base); + pkt->stream_index = st->index; - /* rescale output packet timestamp values from codec to stream timebase */ - av_packet_rescale_ts(pkt, c->time_base, st->time_base); - pkt->stream_index = st->index; - - /* Write the compressed frame to the media file. */ - ret = av_interleaved_write_frame(fmt_ctx, pkt); - /* pkt is now blank (av_interleaved_write_frame() takes ownership of - * its contents and resets pkt), so that no unreferencing is necessary. - * This would be different if one used av_write_frame(). */ - if (ret < 0) { - fprintf(stderr, "Error while writing output packet: %s\n", av_err2str(ret)); - exit(1); - } + /* Write the compressed frame to the media file. */ + ret = av_interleaved_write_frame(fmt_ctx, pkt); + /* pkt is now blank (av_interleaved_write_frame() takes ownership of + * its contents and resets pkt), so that no unreferencing is necessary. + * This would be different if one used av_write_frame(). */ + if (ret < 0) { + fprintf(stderr, "Error while writing output packet: %s\n", + av_err2str(ret)); + exit(1); } + } - return ret == AVERROR_EOF ? 1 : 0; + return ret == AVERROR_EOF ? 1 : 0; } /* Add an output stream. */ static void add_stream(OutputStream *ost, AVFormatContext *oc, - const AVCodec **codec, - enum AVCodecID codec_id) -{ - AVCodecContext *c; - int i; - - /* find the encoder */ - *codec = avcodec_find_encoder(codec_id); - if (!(*codec)) { - fprintf(stderr, "Could not find encoder for '%s'\n", - avcodec_get_name(codec_id)); - exit(1); - } - - ost->tmp_pkt = av_packet_alloc(); - if (!ost->tmp_pkt) { - fprintf(stderr, "Could not allocate AVPacket\n"); - exit(1); - } - - ost->st = avformat_new_stream(oc, NULL); - if (!ost->st) { - fprintf(stderr, "Could not allocate stream\n"); - exit(1); - } - ost->st->id = oc->nb_streams-1; - c = avcodec_alloc_context3(*codec); - if (!c) { - fprintf(stderr, "Could not alloc an encoding context\n"); - exit(1); - } - ost->enc = c; - - const AVChannelLayout temp = AV_CHANNEL_LAYOUT_STEREO; - switch ((*codec)->type) { + const AVCodec **codec, enum AVCodecID codec_id) { + AVCodecContext *c; + int i; + + /* find the encoder */ + *codec = avcodec_find_encoder(codec_id); + if (!(*codec)) { + fprintf(stderr, "Could not find encoder for '%s'\n", + avcodec_get_name(codec_id)); + exit(1); + } + + ost->tmp_pkt = av_packet_alloc(); + if (!ost->tmp_pkt) { + fprintf(stderr, "Could not allocate AVPacket\n"); + exit(1); + } + + ost->st = avformat_new_stream(oc, NULL); + if (!ost->st) { + fprintf(stderr, "Could not allocate stream\n"); + exit(1); + } + ost->st->id = oc->nb_streams - 1; + c = avcodec_alloc_context3(*codec); + if (!c) { + fprintf(stderr, "Could not alloc an encoding context\n"); + exit(1); + } + ost->enc = c; + +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 0) + const AVChannelLayout temp = AV_CHANNEL_LAYOUT_STEREO; +#endif + + switch ((*codec)->type) { case AVMEDIA_TYPE_AUDIO: - c->sample_fmt = (*codec)->sample_fmts ? - (*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP; - c->bit_rate = 64000; - c->sample_rate = 44100; - if ((*codec)->supported_samplerates) { - c->sample_rate = (*codec)->supported_samplerates[0]; - for (i = 0; (*codec)->supported_samplerates[i]; i++) { - if ((*codec)->supported_samplerates[i] == 44100) - c->sample_rate = 44100; - } + c->sample_fmt = + (*codec)->sample_fmts ? (*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP; + c->bit_rate = 64000; + c->sample_rate = 44100; + if ((*codec)->supported_samplerates) { + c->sample_rate = (*codec)->supported_samplerates[0]; + for (i = 0; (*codec)->supported_samplerates[i]; i++) { + if ((*codec)->supported_samplerates[i] == 44100) + c->sample_rate = 44100; } - - av_channel_layout_copy(&c->ch_layout, &temp); - ost->st->time_base = (AVRational){ 1, c->sample_rate }; - break; + } + +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 0) + av_channel_layout_copy(&c->ch_layout, &temp); +#else + c->channels = av_get_channel_layout_nb_channels(c->channel_layout); + c->channel_layout = AV_CH_LAYOUT_STEREO; + if ((*codec)->channel_layouts) { + c->channel_layout = (*codec)->channel_layouts[0]; + for (i = 0; (*codec)->channel_layouts[i]; i++) { + if ((*codec)->channel_layouts[i] == AV_CH_LAYOUT_STEREO) + c->channel_layout = AV_CH_LAYOUT_STEREO; + } + } + c->channels = av_get_channel_layout_nb_channels(c->channel_layout); +#endif + ost->st->time_base = (AVRational){1, c->sample_rate}; + break; case AVMEDIA_TYPE_VIDEO: - c->codec_id = codec_id; - - c->bit_rate = 8388608; - /* Resolution must be a multiple of two. */ - c->width = 1440; - c->height = 1080; - /* timebase: This is the fundamental unit of time (in seconds) in terms - * of which frame timestamps are represented. For fixed-fps content, - * timebase should be 1/framerate and timestamp increments should be - * identical to 1. */ - ost->st->time_base = (AVRational){ 1, STREAM_FRAME_RATE }; - c->time_base = ost->st->time_base; - - c->gop_size = 12; /* emit one intra frame every twelve frames at most */ - c->pix_fmt = AV_PIX_FMT_YUV420P; - if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - /* just for testing, we also add B-frames */ - c->max_b_frames = 2; - } - if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) { - /* Needed to avoid using macroblocks in which some coeffs overflow. - * This does not happen with normal video, it just happens here as - * the motion of the chroma plane does not match the luma plane. */ - c->mb_decision = 2; - } - break; + c->codec_id = codec_id; + + c->bit_rate = 8388608; + /* Resolution must be a multiple of two. */ + c->width = 1440; + c->height = 1080; + /* timebase: This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. For fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identical to 1. */ + ost->st->time_base = (AVRational){1, STREAM_FRAME_RATE}; + c->time_base = ost->st->time_base; + + c->gop_size = 12; /* emit one intra frame every twelve frames at most */ + c->pix_fmt = AV_PIX_FMT_YUV420P; + if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + /* just for testing, we also add B-frames */ + c->max_b_frames = 2; + } + if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + /* Needed to avoid using macroblocks in which some coeffs overflow. + * This does not happen with normal video, it just happens here as + * the motion of the chroma plane does not match the luma plane. */ + c->mb_decision = 2; + } + break; default: - break; - } + break; + } - /* Some formats want stream headers to be separate. */ - if (oc->oformat->flags & AVFMT_GLOBALHEADER) - c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + /* Some formats want stream headers to be separate. */ + if (oc->oformat->flags & AVFMT_GLOBALHEADER) + c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } /**************************************************************/ /* audio output */ +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 0) static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt, const AVChannelLayout *channel_layout, - int sample_rate, int nb_samples) -{ - AVFrame *frame = av_frame_alloc(); - if (!frame) { - fprintf(stderr, "Error allocating an audio frame\n"); - exit(1); - } - - frame->format = sample_fmt; - av_channel_layout_copy(&frame->ch_layout, channel_layout); - frame->sample_rate = sample_rate; - frame->nb_samples = nb_samples; - - if (nb_samples) { - if (av_frame_get_buffer(frame, 0) < 0) { - fprintf(stderr, "Error allocating an audio buffer\n"); - exit(1); - } + int sample_rate, int nb_samples) { +#else +static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt, + uint64_t channel_layout, int sample_rate, + int nb_samples) { +#endif + AVFrame *frame = av_frame_alloc(); + if (!frame) { + fprintf(stderr, "Error allocating an audio frame\n"); + exit(1); + } + + frame->format = sample_fmt; +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 0) + av_channel_layout_copy(&frame->ch_layout, channel_layout); +#else + frame->channel_layout = channel_layout; +#endif + + frame->sample_rate = sample_rate; + frame->nb_samples = nb_samples; + + if (nb_samples) { + if (av_frame_get_buffer(frame, 0) < 0) { + fprintf(stderr, "Error allocating an audio buffer\n"); + exit(1); } + } - return frame; + return frame; } static void open_audio(AVFormatContext *oc, const AVCodec *codec, - OutputStream *ost, AVDictionary *opt_arg) -{ - AVCodecContext *c; - int nb_samples; - int ret; - AVDictionary *opt = NULL; - - c = ost->enc; - - /* open it */ - av_dict_copy(&opt, opt_arg, 0); - ret = avcodec_open2(c, codec, &opt); - av_dict_free(&opt); - if (ret < 0) { - fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret)); - exit(1); - } - - /* init signal generator */ - ost->t = 0; - ost->tincr = 2 * M_PI * 110.0 / c->sample_rate; - /* increment frequency by 110 Hz per second */ - ost->tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate; - - if (c->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) - nb_samples = 10000; - else - nb_samples = c->frame_size; - - ost->frame = alloc_audio_frame(c->sample_fmt, &c->ch_layout, - c->sample_rate, nb_samples); - ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, &c->ch_layout, - c->sample_rate, nb_samples); - - /* copy the stream parameters to the muxer */ - ret = avcodec_parameters_from_context(ost->st->codecpar, c); - if (ret < 0) { - fprintf(stderr, "Could not copy the stream parameters\n"); - exit(1); - } - - /* create resampler context */ - ost->swr_ctx = swr_alloc(); - if (!ost->swr_ctx) { - fprintf(stderr, "Could not allocate resampler context\n"); - exit(1); - } - - /* set options */ - av_opt_set_chlayout (ost->swr_ctx, "in_chlayout", &c->ch_layout, 0); - av_opt_set_int (ost->swr_ctx, "in_sample_rate", c->sample_rate, 0); - av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); - av_opt_set_chlayout (ost->swr_ctx, "out_chlayout", &c->ch_layout, 0); - av_opt_set_int (ost->swr_ctx, "out_sample_rate", c->sample_rate, 0); - av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0); - - /* initialize the resampling context */ - if ((ret = swr_init(ost->swr_ctx)) < 0) { - fprintf(stderr, "Failed to initialize the resampling context\n"); - exit(1); - } + OutputStream *ost, AVDictionary *opt_arg) { + AVCodecContext *c; + int nb_samples; + int ret; + AVDictionary *opt = NULL; + + c = ost->enc; + + /* open it */ + av_dict_copy(&opt, opt_arg, 0); + ret = avcodec_open2(c, codec, &opt); + av_dict_free(&opt); + if (ret < 0) { + fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret)); + exit(1); + } + + /* init signal generator */ + ost->t = 0; + ost->tincr = 2 * M_PI * 110.0 / c->sample_rate; + /* increment frequency by 110 Hz per second */ + ost->tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate; + + if (c->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) + nb_samples = 10000; + else + nb_samples = c->frame_size; + +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 0) + ost->frame = alloc_audio_frame(c->sample_fmt, &c->ch_layout, c->sample_rate, + nb_samples); + ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, &c->ch_layout, + c->sample_rate, nb_samples); +#else + ost->frame = alloc_audio_frame(c->sample_fmt, c->channel_layout, + c->sample_rate, nb_samples); + ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, c->channel_layout, + c->sample_rate, nb_samples); +#endif + + /* copy the stream parameters to the muxer */ + ret = avcodec_parameters_from_context(ost->st->codecpar, c); + if (ret < 0) { + fprintf(stderr, "Could not copy the stream parameters\n"); + exit(1); + } + + /* create resampler context */ + ost->swr_ctx = swr_alloc(); + if (!ost->swr_ctx) { + fprintf(stderr, "Could not allocate resampler context\n"); + exit(1); + } + + /* set options */ +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 0) + av_opt_set_chlayout(ost->swr_ctx, "in_chlayout", &c->ch_layout, 0); + av_opt_set_chlayout(ost->swr_ctx, "out_chlayout", &c->ch_layout, 0); +#else + av_opt_set_int(ost->swr_ctx, "in_channel_count", c->channels, 0); + av_opt_set_int(ost->swr_ctx, "out_channel_count", c->channels, 0); +#endif + av_opt_set_int(ost->swr_ctx, "in_sample_rate", c->sample_rate, 0); + av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); + av_opt_set_int(ost->swr_ctx, "out_sample_rate", c->sample_rate, 0); + av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0); + + /* initialize the resampling context */ + if ((ret = swr_init(ost->swr_ctx)) < 0) { + fprintf(stderr, "Failed to initialize the resampling context\n"); + exit(1); + } } /* Prepare a 16 bit dummy audio frame of 'frame_size' samples and * 'nb_channels' channels. */ -static AVFrame *get_audio_frame(OutputStream *ost) -{ - AVFrame *frame = ost->tmp_frame; - int j, i, v; - int16_t *q = (int16_t*)frame->data[0]; - - /* check if we want to generate more frames */ - if (av_compare_ts(ost->next_pts, ost->enc->time_base, - STREAM_DURATION, (AVRational){ 1, 1 }) > 0) - return NULL; - - for (j = 0; j nb_samples; j++) { - v = (int)(sin(ost->t) * 10000); - for (i = 0; i < ost->enc->ch_layout.nb_channels; i++) - *q++ = v; - ost->t += ost->tincr; - ost->tincr += ost->tincr2; - } - - frame->pts = ost->next_pts; - ost->next_pts += frame->nb_samples; - - return frame; +static AVFrame *get_audio_frame(OutputStream *ost) { + AVFrame *frame = ost->tmp_frame; + int j, i, v; + int16_t *q = (int16_t *)frame->data[0]; + + /* check if we want to generate more frames */ + if (av_compare_ts(ost->next_pts, ost->enc->time_base, STREAM_DURATION, + (AVRational){1, 1}) > 0) + return NULL; + + for (j = 0; j < frame->nb_samples; j++) { + v = (int)(sin(ost->t) * 10000); +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 0) + for (i = 0; i < ost->enc->ch_layout.nb_channels; i++) *q++ = v; +#else + for (i = 0; i < ost->enc->channels; i++) *q++ = v; +#endif + ost->t += ost->tincr; + ost->tincr += ost->tincr2; + } + + frame->pts = ost->next_pts; + ost->next_pts += frame->nb_samples; + + return frame; } /* * encode one audio frame and send it to the muxer * return 1 when encoding is finished, 0 otherwise */ -static int write_audio_frame(AVFormatContext *oc, OutputStream *ost) -{ - AVCodecContext *c; - AVFrame *frame; - int ret; - int dst_nb_samples; - - c = ost->enc; - - frame = get_audio_frame(ost); - - if (frame) { - /* convert samples from native format to destination codec format, using the resampler */ - /* compute destination number of samples */ - dst_nb_samples = av_rescale_rnd(swr_get_delay(ost->swr_ctx, c->sample_rate) + frame->nb_samples, - c->sample_rate, c->sample_rate, AV_ROUND_UP); - av_assert0(dst_nb_samples == frame->nb_samples); - - /* when we pass a frame to the encoder, it may keep a reference to it - * internally; - * make sure we do not overwrite it here - */ - ret = av_frame_make_writable(ost->frame); - if (ret < 0) - exit(1); - - /* convert to destination format */ - ret = swr_convert(ost->swr_ctx, - ost->frame->data, dst_nb_samples, - (const uint8_t **)frame->data, frame->nb_samples); - if (ret < 0) { - fprintf(stderr, "Error while converting\n"); - exit(1); - } - frame = ost->frame; +static int write_audio_frame(AVFormatContext *oc, OutputStream *ost) { + AVCodecContext *c; + AVFrame *frame; + int ret; + int dst_nb_samples; - frame->pts = av_rescale_q(ost->samples_count, (AVRational){1, c->sample_rate}, c->time_base); - ost->samples_count += dst_nb_samples; + c = ost->enc; + + frame = get_audio_frame(ost); + + if (frame) { + /* convert samples from native format to destination codec format, using the + * resampler */ + /* compute destination number of samples */ + dst_nb_samples = av_rescale_rnd( + swr_get_delay(ost->swr_ctx, c->sample_rate) + frame->nb_samples, + c->sample_rate, c->sample_rate, AV_ROUND_UP); + av_assert0(dst_nb_samples == frame->nb_samples); + + /* when we pass a frame to the encoder, it may keep a reference to it + * internally; + * make sure we do not overwrite it here + */ + ret = av_frame_make_writable(ost->frame); + if (ret < 0) exit(1); + + /* convert to destination format */ + ret = swr_convert(ost->swr_ctx, ost->frame->data, dst_nb_samples, + (const uint8_t **)frame->data, frame->nb_samples); + if (ret < 0) { + fprintf(stderr, "Error while converting\n"); + exit(1); } + frame = ost->frame; + + frame->pts = av_rescale_q(ost->samples_count, + (AVRational){1, c->sample_rate}, c->time_base); + ost->samples_count += dst_nb_samples; + } - return write_frame(oc, c, ost->st, frame, ost->tmp_pkt); + return write_frame(oc, c, ost->st, frame, ost->tmp_pkt); } /**************************************************************/ /* video output */ -static AVFrame *alloc_frame(enum AVPixelFormat pix_fmt, int width, int height) -{ - AVFrame *frame; - int ret; +static AVFrame *alloc_frame(enum AVPixelFormat pix_fmt, int width, int height) { + AVFrame *frame; + int ret; - frame = av_frame_alloc(); - if (!frame) - return NULL; + frame = av_frame_alloc(); + if (!frame) return NULL; - frame->format = pix_fmt; - frame->width = width; - frame->height = height; + frame->format = pix_fmt; + frame->width = width; + frame->height = height; - /* allocate the buffers for the frame data */ - ret = av_frame_get_buffer(frame, 0); - if (ret < 0) { - fprintf(stderr, "Could not allocate frame data.\n"); - exit(1); - } + /* allocate the buffers for the frame data */ + ret = av_frame_get_buffer(frame, 0); + if (ret < 0) { + fprintf(stderr, "Could not allocate frame data.\n"); + exit(1); + } - return frame; + return frame; } static void open_video(AVFormatContext *oc, const AVCodec *codec, - OutputStream *ost, AVDictionary *opt_arg) -{ - int ret; - AVCodecContext *c = ost->enc; - AVDictionary *opt = NULL; - - av_dict_copy(&opt, opt_arg, 0); - - /* open the codec */ - ret = avcodec_open2(c, codec, &opt); - av_dict_free(&opt); - if (ret < 0) { - fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret)); - exit(1); - } - - /* allocate and init a re-usable frame */ - ost->frame = alloc_frame(c->pix_fmt, c->width, c->height); - if (!ost->frame) { - fprintf(stderr, "Could not allocate video frame\n"); - exit(1); - } - - /* If the output format is not YUV420P, then a temporary YUV420P - * picture is needed too. It is then converted to the required - * output format. */ - ost->tmp_frame = NULL; - if (c->pix_fmt != AV_PIX_FMT_YUV420P) { - ost->tmp_frame = alloc_frame(AV_PIX_FMT_YUV420P, c->width, c->height); - if (!ost->tmp_frame) { - fprintf(stderr, "Could not allocate temporary video frame\n"); - exit(1); - } - } - - /* copy the stream parameters to the muxer */ - ret = avcodec_parameters_from_context(ost->st->codecpar, c); - if (ret < 0) { - fprintf(stderr, "Could not copy the stream parameters\n"); - exit(1); + OutputStream *ost, AVDictionary *opt_arg) { + int ret; + AVCodecContext *c = ost->enc; + AVDictionary *opt = NULL; + + av_dict_copy(&opt, opt_arg, 0); + + /* open the codec */ + ret = avcodec_open2(c, codec, &opt); + av_dict_free(&opt); + if (ret < 0) { + fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret)); + exit(1); + } + + /* allocate and init a re-usable frame */ + ost->frame = alloc_frame(c->pix_fmt, c->width, c->height); + if (!ost->frame) { + fprintf(stderr, "Could not allocate video frame\n"); + exit(1); + } + + /* If the output format is not YUV420P, then a temporary YUV420P + * picture is needed too. It is then converted to the required + * output format. */ + ost->tmp_frame = NULL; + if (c->pix_fmt != AV_PIX_FMT_YUV420P) { + ost->tmp_frame = alloc_frame(AV_PIX_FMT_YUV420P, c->width, c->height); + if (!ost->tmp_frame) { + fprintf(stderr, "Could not allocate temporary video frame\n"); + exit(1); } + } + + /* copy the stream parameters to the muxer */ + ret = avcodec_parameters_from_context(ost->st->codecpar, c); + if (ret < 0) { + fprintf(stderr, "Could not copy the stream parameters\n"); + exit(1); + } } /* Prepare a dummy image. */ -static void fill_yuv_image(AVFrame *pict, int frame_index, - int width, int height) -{ - int x, y, i; - - i = frame_index; - - /* Y */ - for (y = 0; y < height; y++) - for (x = 0; x < width; x++) - pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3; - - /* Cb and Cr */ - for (y = 0; y < height / 2; y++) { - for (x = 0; x < width / 2; x++) { - pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2; - pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5; - } +static void fill_yuv_image(AVFrame *pict, int frame_index, int width, + int height) { + int x, y, i; + + i = frame_index; + + /* Y */ + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) + pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3; + + /* Cb and Cr */ + for (y = 0; y < height / 2; y++) { + for (x = 0; x < width / 2; x++) { + pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2; + pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5; } + } } -static AVFrame *get_video_frame(OutputStream *ost) -{ - AVCodecContext *c = ost->enc; - - /* check if we want to generate more frames */ - if (av_compare_ts(ost->next_pts, c->time_base, - STREAM_DURATION, (AVRational){ 1, 1 }) > 0) - return NULL; - - /* when we pass a frame to the encoder, it may keep a reference to it - * internally; make sure we do not overwrite it here */ - if (av_frame_make_writable(ost->frame) < 0) +static AVFrame *get_video_frame(OutputStream *ost) { + AVCodecContext *c = ost->enc; + + /* check if we want to generate more frames */ + if (av_compare_ts(ost->next_pts, c->time_base, STREAM_DURATION, + (AVRational){1, 1}) > 0) + return NULL; + + /* when we pass a frame to the encoder, it may keep a reference to it + * internally; make sure we do not overwrite it here */ + if (av_frame_make_writable(ost->frame) < 0) exit(1); + + if (c->pix_fmt != AV_PIX_FMT_YUV420P) { + /* as we only generate a YUV420P picture, we must convert it + * to the codec pixel format if needed */ + if (!ost->sws_ctx) { + ost->sws_ctx = + sws_getContext(c->width, c->height, AV_PIX_FMT_YUV420P, c->width, + c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); + if (!ost->sws_ctx) { + fprintf(stderr, "Could not initialize the conversion context\n"); exit(1); - - if (c->pix_fmt != AV_PIX_FMT_YUV420P) { - /* as we only generate a YUV420P picture, we must convert it - * to the codec pixel format if needed */ - if (!ost->sws_ctx) { - ost->sws_ctx = sws_getContext(c->width, c->height, - AV_PIX_FMT_YUV420P, - c->width, c->height, - c->pix_fmt, - SWS_BICUBIC, NULL, NULL, NULL); - if (!ost->sws_ctx) { - fprintf(stderr, - "Could not initialize the conversion context\n"); - exit(1); - } - } - fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height); - sws_scale(ost->sws_ctx, (const uint8_t * const *) ost->tmp_frame->data, - ost->tmp_frame->linesize, 0, c->height, ost->frame->data, - ost->frame->linesize); - } else { - fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height); + } } + fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height); + sws_scale(ost->sws_ctx, (const uint8_t *const *)ost->tmp_frame->data, + ost->tmp_frame->linesize, 0, c->height, ost->frame->data, + ost->frame->linesize); + } else { + fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height); + } - ost->frame->pts = ost->next_pts++; + ost->frame->pts = ost->next_pts++; - return ost->frame; + return ost->frame; } /* * encode one video frame and send it to the muxer * return 1 when encoding is finished, 0 otherwise */ -static int write_video_frame(AVFormatContext *oc, OutputStream *ost) -{ - return write_frame(oc, ost->enc, ost->st, get_video_frame(ost), ost->tmp_pkt); +static int write_video_frame(AVFormatContext *oc, OutputStream *ost) { + return write_frame(oc, ost->enc, ost->st, get_video_frame(ost), ost->tmp_pkt); } -static void close_stream(AVFormatContext *oc, OutputStream *ost) -{ - avcodec_free_context(&ost->enc); - av_frame_free(&ost->frame); - av_frame_free(&ost->tmp_frame); - av_packet_free(&ost->tmp_pkt); - sws_freeContext(ost->sws_ctx); - swr_free(&ost->swr_ctx); +static void close_stream(AVFormatContext *oc, OutputStream *ost) { + avcodec_free_context(&ost->enc); + av_frame_free(&ost->frame); + av_frame_free(&ost->tmp_frame); + av_packet_free(&ost->tmp_pkt); + sws_freeContext(ost->sws_ctx); + swr_free(&ost->swr_ctx); } -int Dump_mp4(Pixel* data,int width,int height,const char* filename){ - OutputStream video_st = { 0 }, audio_st = { 0 }; - const AVOutputFormat *fmt; - AVFormatContext *oc; - const AVCodec *audio_codec, *video_codec; - int ret; - int have_video = 0, have_audio = 0; - int encode_video = 0, encode_audio = 0; - AVDictionary *opt = NULL; - int i; - - /* allocate the output media context */ - avformat_alloc_output_context2(&oc, NULL, NULL, filename); - if (!oc) - return 1; - - fmt = oc->oformat; - - /* Add the audio and video streams using the default format codecs - * and initialize the codecs. */ - if (fmt->video_codec != AV_CODEC_ID_NONE) { - add_stream(&video_st, oc, &video_codec, fmt->video_codec); - have_video = 1; - encode_video = 1; - } - if (fmt->audio_codec != AV_CODEC_ID_NONE) { - add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec); - have_audio = 1; - encode_audio = 1; - } - - /* Now that all the parameters are set, we can open the audio and - * video codecs and allocate the necessary encode buffers. */ - if (have_video) - open_video(oc, video_codec, &video_st, opt); - - if (have_audio) - open_audio(oc, audio_codec, &audio_st, opt); - - av_dump_format(oc, 0, filename, 1); - - /* open the output file, if needed */ - if (!(fmt->flags & AVFMT_NOFILE)) { - ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE); - if (ret < 0) { - fprintf(stderr, "Could not open '%s': %s\n", filename, - av_err2str(ret)); - return 1; - } - } - - /* Write the stream header, if any. */ - ret = avformat_write_header(oc, &opt); +int Dump_mp4(Pixel *data, int width, int height, const char *filename) { + OutputStream video_st = {0}, audio_st = {0}; + const AVOutputFormat *fmt; + AVFormatContext *oc; + const AVCodec *audio_codec, *video_codec; + int ret; + int have_video = 0, have_audio = 0; + int encode_video = 0, encode_audio = 0; + AVDictionary *opt = NULL; + int i; + + /* allocate the output media context */ + avformat_alloc_output_context2(&oc, NULL, NULL, filename); + if (!oc) return 1; + + fmt = oc->oformat; + + /* Add the audio and video streams using the default format codecs + * and initialize the codecs. */ + if (fmt->video_codec != AV_CODEC_ID_NONE) { + add_stream(&video_st, oc, &video_codec, fmt->video_codec); + have_video = 1; + encode_video = 1; + } + if (fmt->audio_codec != AV_CODEC_ID_NONE) { + add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec); + have_audio = 1; + encode_audio = 1; + } + + /* Now that all the parameters are set, we can open the audio and + * video codecs and allocate the necessary encode buffers. */ + if (have_video) open_video(oc, video_codec, &video_st, opt); + + if (have_audio) open_audio(oc, audio_codec, &audio_st, opt); + + av_dump_format(oc, 0, filename, 1); + + /* open the output file, if needed */ + if (!(fmt->flags & AVFMT_NOFILE)) { + ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE); if (ret < 0) { - fprintf(stderr, "Error occurred when opening output file: %s\n", - av_err2str(ret)); - return 1; + fprintf(stderr, "Could not open '%s': %s\n", filename, av_err2str(ret)); + return 1; } - - while (encode_video || encode_audio) { - /* select the stream to encode */ - if (encode_video && - (!encode_audio || av_compare_ts(video_st.next_pts, video_st.enc->time_base, - audio_st.next_pts, audio_st.enc->time_base) <= 0)) { - encode_video = !write_video_frame(oc, &video_st); - } else { - encode_audio = !write_audio_frame(oc, &audio_st); - } + } + + /* Write the stream header, if any. */ + ret = avformat_write_header(oc, &opt); + if (ret < 0) { + fprintf(stderr, "Error occurred when opening output file: %s\n", + av_err2str(ret)); + return 1; + } + + while (encode_video || encode_audio) { + /* select the stream to encode */ + if (encode_video && + (!encode_audio || + av_compare_ts(video_st.next_pts, video_st.enc->time_base, + audio_st.next_pts, audio_st.enc->time_base) <= 0)) { + encode_video = !write_video_frame(oc, &video_st); + } else { + encode_audio = !write_audio_frame(oc, &audio_st); } + } - av_write_trailer(oc); + av_write_trailer(oc); - /* Close each codec. */ - if (have_video) - close_stream(oc, &video_st); - if (have_audio) - close_stream(oc, &audio_st); + /* Close each codec. */ + if (have_video) close_stream(oc, &video_st); + if (have_audio) close_stream(oc, &audio_st); - if (!(fmt->flags & AVFMT_NOFILE)) - /* Close the output file. */ - avio_closep(&oc->pb); + if (!(fmt->flags & AVFMT_NOFILE)) /* Close the output file. */ + avio_closep(&oc->pb); - /* free the stream */ - avformat_free_context(oc); - return 0; + /* free the stream */ + avformat_free_context(oc); + return 0; } diff --git a/tools/common/dump_mp4.hpp b/tools/common/dump_mp4.hpp index 583981e..6853e8d 100644 --- a/tools/common/dump_mp4.hpp +++ b/tools/common/dump_mp4.hpp @@ -3,6 +3,6 @@ typedef unsigned int Pixel; -int Dump_mp4(Pixel* data,int width,int height,const char* filename); +int Dump_mp4(Pixel *data, int width, int height, const char *filename); -#endif // DUMP_MP4_HPP +#endif // DUMP_MP4_HPP diff --git a/tools/common/dump_png.cpp b/tools/common/dump_png.cpp index 57d5c2e..608a1a9 100644 --- a/tools/common/dump_png.cpp +++ b/tools/common/dump_png.cpp @@ -1,92 +1,95 @@ +#include "dump_png.hpp" + #include -#include -#include "dump_png.hpp" +#include -void Dump_png(Pixel* data,int width,int height,const char* filename) -{ - FILE* file=fopen(filename,"wb"); - assert(file); - - png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); - assert(png_ptr); - png_infop info_ptr=png_create_info_struct(png_ptr); - assert(info_ptr); - bool result=setjmp(png_jmpbuf(png_ptr)); - assert(!result); - png_init_io(png_ptr,file); - int color_type=PNG_COLOR_TYPE_RGBA; - png_set_IHDR(png_ptr,info_ptr,width,height,8,color_type,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); - - Pixel** row_pointers=new Pixel*[height]; - for(int j=0;j #include #include + #include "lights/direction_light.hpp" -#include "shaders/flat_shader.hpp" +#include "lights/point_light.hpp" +#include "lights/spot_light.hpp" #include "objects/mesh.hpp" -#include "shaders/phong_shader.hpp" #include "objects/plane.hpp" -#include "lights/point_light.hpp" -#include "shaders/reflective_shader.hpp" #include "objects/sphere.hpp" -#include "lights/spot_light.hpp" +#include "shaders/flat_shader.hpp" +#include "shaders/phong_shader.hpp" +#include "shaders/reflective_shader.hpp" -void Parse(Render_World& world,int& width,int& height,const char* test_file) -{ - FILE* F = fopen(test_file,"r"); - if(!F) - { - std::cout<<"Failed to open file '"< colors; - std::map objects; - std::map shaders; + std::map colors; + std::map objects; + std::map shaders; - while(fgets(buff, sizeof(buff), F)) - { - std::stringstream ss(buff); - std::string item,name; - if(!(ss>>item) || !item.size() || item[0]=='#') continue; - if(item=="size") - { - ss>>width>>height; - assert(ss); - } - else if(item=="color") - { - ss>>name>>u; - assert(ss); - colors[name]=u; - } - else if(item=="plane") - { - ss>>name>>u>>v>>s0; - assert(ss); - Object* o=new Plane(u,v); - std::map::const_iterator sh=shaders.find(s0); - assert(sh!=shaders.end()); - o->material_shader=sh->second; - if(name=="-") world.objects.push_back(o); - else objects[name]=o; - } - else if(item=="sphere") - { - ss>>name>>u>>f0>>s0; - assert(ss); - Object* o=new Sphere(u,f0); - std::map::const_iterator sh=shaders.find(s0); - assert(sh!=shaders.end()); - o->material_shader=sh->second; - if(name=="-") world.objects.push_back(o); - else objects[name]=o; - } - else if(item=="mesh") - { - ss>>name>>s0>>s1; - assert(ss); - Mesh* o=new Mesh; - o->Read_Obj(s0.c_str()); - std::map::const_iterator sh=shaders.find(s1); - assert(sh!=shaders.end()); - o->material_shader=sh->second; - if(name=="-") world.objects.push_back(o); - else objects[name]=o; - } - else if(item=="flat_shader") - { - ss>>name>>s0; - assert(ss); - std::map::const_iterator c0=colors.find(s0); - assert(c0!=colors.end()); - shaders[name]=new Flat_Shader(world,c0->second); - } - else if(item=="phong_shader") - { - ss>>name>>s0>>s1>>s2>>f0; - assert(ss); - std::map::const_iterator c0=colors.find(s0); - std::map::const_iterator c1=colors.find(s1); - std::map::const_iterator c2=colors.find(s2); - assert(c0!=colors.end()); - assert(c1!=colors.end()); - assert(c2!=colors.end()); - shaders[name]=new Phong_Shader(world,c0->second,c1->second,c2->second,f0); - } - else if(item=="reflective_shader") - { - ss>>name>>s0>>f0; - assert(ss); - std::map::const_iterator sh=shaders.find(s0); - assert(sh!=shaders.end()); - shaders[name]=new Reflective_Shader(world,sh->second,f0); - } - else if(item=="point_light") - { - ss>>u>>s0>>f0; - assert(ss); - std::map::const_iterator c0=colors.find(s0); - assert(c0!=colors.end()); - world.lights.push_back(new Point_Light(u,c0->second,f0)); - } - else if(item=="direction_light") - { - ss>>u>>s0>>f0; - assert(ss); - std::map::const_iterator c0=colors.find(s0); - assert(c0!=colors.end()); - world.lights.push_back(new Direction_Light(u,c0->second,f0)); - } - else if(item=="spot_light") - { - double max_angle,exponent; - vec3 direction; - ss>>u>>s0>>f0>>max_angle>>exponent>>direction; - assert(ss); - std::map::const_iterator c0=colors.find(s0); - assert(c0!=colors.end()); - world.lights.push_back(new Spot_Light(u,c0->second,f0,max_angle,exponent,direction)); - } - else if(item=="ambient_light") - { - ss>>s0>>f0; - assert(ss); - std::map::const_iterator c0=colors.find(s0); - assert(c0!=colors.end()); - world.ambient_color=c0->second; - world.ambient_intensity=f0; - } - else if(item=="camera") - { - ss>>u>>v>>w>>f0; - assert(ss); - world.camera.Position_And_Aim_Camera(u,v,w); - world.camera.Focus_Camera(1,(double)width/height,f0*(pi/180)); - } - else if(item=="background") - { - ss>>s0; - assert(ss); - std::map::const_iterator sh=shaders.find(s0); - assert(sh!=shaders.end()); - world.background_shader=sh->second; - } - else if(item=="enable_shadows") - { - ss>>world.enable_shadows; - assert(ss); - } - else if(item=="recursion_depth_limit") - { - ss>>world.recursion_depth_limit; - assert(ss); - } - else - { - std::cout<<"Failed to parse: "<> item) || !item.size() || item[0] == '#') continue; + if (item == "size") { + ss >> width >> height; + assert(ss); + } else if (item == "color") { + ss >> name >> u; + assert(ss); + colors[name] = u; + } else if (item == "plane") { + ss >> name >> u >> v >> s0; + assert(ss); + Object *o = new Plane(u, v); + std::map::const_iterator sh = shaders.find(s0); + assert(sh != shaders.end()); + o->material_shader = sh->second; + if (name == "-") + world.objects.push_back(o); + else + objects[name] = o; + } else if (item == "sphere") { + ss >> name >> u >> f0 >> s0; + assert(ss); + Object *o = new Sphere(u, f0); + std::map::const_iterator sh = shaders.find(s0); + assert(sh != shaders.end()); + o->material_shader = sh->second; + if (name == "-") + world.objects.push_back(o); + else + objects[name] = o; + } else if (item == "mesh") { + ss >> name >> s0 >> s1; + assert(ss); + Mesh *o = new Mesh; + o->Read_Obj(s0.c_str()); + std::map::const_iterator sh = shaders.find(s1); + assert(sh != shaders.end()); + o->material_shader = sh->second; + if (name == "-") + world.objects.push_back(o); + else + objects[name] = o; + } else if (item == "flat_shader") { + ss >> name >> s0; + assert(ss); + std::map::const_iterator c0 = colors.find(s0); + assert(c0 != colors.end()); + shaders[name] = new Flat_Shader(world, c0->second); + } else if (item == "phong_shader") { + ss >> name >> s0 >> s1 >> s2 >> f0; + assert(ss); + std::map::const_iterator c0 = colors.find(s0); + std::map::const_iterator c1 = colors.find(s1); + std::map::const_iterator c2 = colors.find(s2); + assert(c0 != colors.end()); + assert(c1 != colors.end()); + assert(c2 != colors.end()); + shaders[name] = + new Phong_Shader(world, c0->second, c1->second, c2->second, f0); + } else if (item == "reflective_shader") { + ss >> name >> s0 >> f0; + assert(ss); + std::map::const_iterator sh = shaders.find(s0); + assert(sh != shaders.end()); + shaders[name] = new Reflective_Shader(world, sh->second, f0); + } else if (item == "point_light") { + ss >> u >> s0 >> f0; + assert(ss); + std::map::const_iterator c0 = colors.find(s0); + assert(c0 != colors.end()); + world.lights.push_back(new Point_Light(u, c0->second, f0)); + } else if (item == "direction_light") { + ss >> u >> s0 >> f0; + assert(ss); + std::map::const_iterator c0 = colors.find(s0); + assert(c0 != colors.end()); + world.lights.push_back(new Direction_Light(u, c0->second, f0)); + } else if (item == "spot_light") { + double max_angle, exponent; + vec3 direction; + ss >> u >> s0 >> f0 >> max_angle >> exponent >> direction; + assert(ss); + std::map::const_iterator c0 = colors.find(s0); + assert(c0 != colors.end()); + world.lights.push_back( + new Spot_Light(u, c0->second, f0, max_angle, exponent, direction)); + } else if (item == "ambient_light") { + ss >> s0 >> f0; + assert(ss); + std::map::const_iterator c0 = colors.find(s0); + assert(c0 != colors.end()); + world.ambient_color = c0->second; + world.ambient_intensity = f0; + } else if (item == "camera") { + ss >> u >> v >> w >> f0; + assert(ss); + world.camera.Position_And_Aim_Camera(u, v, w); + world.camera.Focus_Camera(1, (double)width / height, f0 * (pi / 180)); + } else if (item == "background") { + ss >> s0; + assert(ss); + std::map::const_iterator sh = shaders.find(s0); + assert(sh != shaders.end()); + world.background_shader = sh->second; + } else if (item == "enable_shadows") { + ss >> world.enable_shadows; + assert(ss); + } else if (item == "recursion_depth_limit") { + ss >> world.recursion_depth_limit; + assert(ss); + } else { + std::cout << "Failed to parse: " << buff << std::endl; + exit(EXIT_FAILURE); } - if(!world.background_shader) - world.background_shader=new Flat_Shader(world,vec3()); - world.camera.Set_Resolution(ivec2(width,height)); + } + if (!world.background_shader) + world.background_shader = new Flat_Shader(world, vec3()); + world.camera.Set_Resolution(ivec2(width, height)); } diff --git a/tools/common/parse.hpp b/tools/common/parse.hpp index 39e3f23..d6675ca 100644 --- a/tools/common/parse.hpp +++ b/tools/common/parse.hpp @@ -3,7 +3,6 @@ #include "render_world.hpp" -void Parse(Render_World& world,int& width,int& height,const char* test_file); +void Parse(Render_World &world, int &width, int &height, const char *test_file); - -#endif \ No newline at end of file +#endif \ No newline at end of file diff --git a/tools/demos/image/main.cpp b/tools/demos/image/main.cpp index 985ff84..1ac8a57 100644 --- a/tools/demos/image/main.cpp +++ b/tools/demos/image/main.cpp @@ -1,16 +1,18 @@ -#include -#include #include + +#include +#include // ray_tracer -#include "render_world.hpp" #include "objects/object.hpp" +#include "render_world.hpp" // tool_common -#include "parse.hpp" #include "dump_png.hpp" +#include "parse.hpp" /* - Usage: ./ray_tracer -i [ -s ] [ -o ] [ -x -y ] + Usage: ./ray_tracer -i [ -s ] [ -o ] + [ -x -y ] Examples: @@ -47,110 +49,116 @@ */ // Indicates that we are debugging one pixel; can be accessed everywhere. -bool debug_pixel=false; +bool debug_pixel = false; // This can be used to quickly disable the hierarchy for testing purposes. // Though this is not required, it is highly recommended that you implement // this, as it will make debugging your hierarchy much easier. -bool disable_hierarchy=false; - -void Usage(const char* exec) -{ - std::cerr<<"Usage: "< [ -s ] [ -o ] [ -x -y ]"< [ -s ] [ -o ] [ " + "-x -y ]" + << std::endl; + exit(1); } -int main(int argc, char** argv) -{ - const char* solution_file = 0; - const char* input_file = 0; - const char* statistics_file = 0; - int test_x=-1, test_y=-1; - - // Parse commandline options - while(1) - { - int opt = getopt(argc, argv, "s:i:m:o:x:y:h"); - if(opt==-1) break; - switch(opt) - { - case 's': solution_file = optarg; break; - case 'i': input_file = optarg; break; - case 'o': statistics_file = optarg; break; - case 'x': test_x = atoi(optarg); break; - case 'y': test_y = atoi(optarg); break; - case 'h': disable_hierarchy=true; break; - } +int main(int argc, char **argv) { + const char *solution_file = 0; + const char *input_file = 0; + const char *statistics_file = 0; + int test_x = -1, test_y = -1; + + // Parse commandline options + while (1) { + int opt = getopt(argc, argv, "s:i:m:o:x:y:h"); + if (opt == -1) break; + switch (opt) { + case 's': + solution_file = optarg; + break; + case 'i': + input_file = optarg; + break; + case 'o': + statistics_file = optarg; + break; + case 'x': + test_x = atoi(optarg); + break; + case 'y': + test_y = atoi(optarg); + break; + case 'h': + disable_hierarchy = true; + break; } - if(!input_file) Usage(argv[0]); - - int width=0; - int height=0; - Render_World world; - - // Parse test scene file - Parse(world,width,height,input_file); - - // Render the image - world.Render(); - - // For debugging. Render only the pixel specified on the commandline. - // Useful for printing out information about a single pixel. - if(test_x>=0 && test_y>=0) - { - // Set a global variable to indicate that we are debugging one pixel. - // This way you can do: if(debug_pixel) cout<= 0 && test_y >= 0) { + // Set a global variable to indicate that we are debugging one pixel. + // This way you can do: if(debug_pixel) cout< -#include #include + +#include +#include // ray_tracer -#include "render_world.hpp" #include "objects/object.hpp" +#include "render_world.hpp" // tool_common -#include "parse.hpp" #include "dump_mp4.hpp" +#include "parse.hpp" -void Usage(const char* exec) { - std::cerr<<"Usage: "< [ -s ] [ -o ] [ -x -y ]"< [ -s ] [ -o ] [ " + "-x -y ]" + << std::endl; + exit(1); } -int main(int argc, char** argv) { - Pixel* data = nullptr; - Dump_mp4(data, 352, 288, "output.mp4"); +int main(int argc, char **argv) { + Pixel *data = nullptr; + Dump_mp4(data, 352, 288, "output.mp4"); } diff --git a/tools/test/include/test_file.hpp b/tools/test/include/test_file.hpp index b7c5f4f..ede5420 100644 --- a/tools/test/include/test_file.hpp +++ b/tools/test/include/test_file.hpp @@ -1,218 +1,154 @@ #ifndef TEST_FILE_HPP #define TEST_FILE_HPP -#include "gtest/gtest.h" +#include "directories.hpp" #include "dump_png.hpp" -#include "parse.hpp" +#include "gtest/gtest.h" +#include "lights/point_light.hpp" #include "objects/mesh.hpp" +#include "parse.hpp" #include "shaders/flat_shader.hpp" #include "shaders/phong_shader.hpp" -#include "lights/point_light.hpp" - -#include "directories.hpp" void test_file(std::string case_name) { - int width=0; - int height=0; - Render_World world; - - // Parse test scene file - Parse(world,width,height, (getCasesDir() + case_name + ".txt").c_str()); - - // Render the image - world.Render(); - - int width2 = 0, height2 = 0; - Pixel* data_sol = 0; - - // Read solution from disk - Read_png(data_sol,width2,height2,(getTestSolutionsDir() + case_name + ".png").c_str()); - assert(width==width2); - assert(height==height2); - - // For each pixel, check to see if it matches solution - double error = 0, total = 0; - for(int i=0; iRead_Obj("sphere.obj"); - o->material_shader = new Phong_Shader(world, {1,1,1}, {1,1,1}, {1,1,1}, 50); - world.objects.push_back(o); - - // Setup lights - world.lights.push_back(new Point_Light(vec3(.8, .8, 4), vec3(1,1,1), 100)); - world.ambient_color = {1,1,1}; - world.ambient_intensity = 0; - - // Setup Camera - world.camera.Position_And_Aim_Camera(cameraP,cameraL,cameraU); - world.camera.Focus_Camera(1,(double)width/height,70*(pi/180)); - - world.camera.Set_Resolution(ivec2(width,height)); - - return world; + data_sol[i] = Pixel_Color(b); + } + + double diff = error / total * 100; + EXPECT_NEAR(0.00, diff, 1e-3); + + delete[] data_sol; +} + +TEST(simple, test_0) { test_file("00"); } +TEST(simple, test_1) { test_file("01"); } +TEST(simple, test_2) { test_file("02"); } +TEST(simple, test_3) { test_file("03"); } +TEST(simple, test_4) { test_file("04"); } +TEST(simple, test_5) { test_file("05"); } +TEST(simple, test_6) { test_file("06"); } +TEST(simple, test_7) { test_file("07"); } +TEST(simple, test_8) { test_file("08"); } +TEST(simple, test_9) { test_file("09"); } +TEST(simple, test_10) { test_file("10"); } +TEST(simple, test_11) { test_file("11"); } +TEST(simple, test_12) { test_file("12"); } +TEST(simple, test_13) { test_file("13"); } +TEST(simple, test_14) { test_file("14"); } +TEST(simple, test_15) { test_file("15"); } +TEST(simple, test_16) { test_file("16"); } +TEST(simple, test_17) { test_file("17"); } +TEST(simple, test_18) { test_file("18"); } +TEST(simple, test_19) { test_file("19"); } +TEST(simple, test_20) { test_file("20"); } +TEST(simple, test_21) { test_file("21"); } +TEST(simple, test_22) { test_file("22"); } +TEST(simple, test_23) { test_file("23"); } +TEST(simple, test_24) { test_file("24"); } +TEST(simple, test_25) { test_file("25"); } +TEST(simple, test_26) { test_file("26"); } +TEST(simple, test_27) { test_file("27"); } +TEST(simple, test_28) { test_file("28"); } +TEST(simple, test_29) { test_file("29"); } + +Render_World SetupBenchmarkWorld(int width, int height, vec3 cameraP, + vec3 cameraL, vec3 cameraU) { + Render_World world; + + // Setup world + world.enable_shadows = false; + world.recursion_depth_limit = 1; + world.background_shader = new Flat_Shader(world, vec3()); + + // Setup objects + Mesh *o = new Mesh; + o->Read_Obj("sphere.obj"); + o->material_shader = + new Phong_Shader(world, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}, 50); + world.objects.push_back(o); + + // Setup lights + world.lights.push_back(new Point_Light(vec3(.8, .8, 4), vec3(1, 1, 1), 100)); + world.ambient_color = {1, 1, 1}; + world.ambient_intensity = 0; + + // Setup Camera + world.camera.Position_And_Aim_Camera(cameraP, cameraL, cameraU); + world.camera.Focus_Camera(1, (double)width / height, 70 * (pi / 180)); + + world.camera.Set_Resolution(ivec2(width, height)); + + return world; } void test_benchmark() { - int width = 640; - int height = 480; - Render_World world = SetupBenchmarkWorld(width,height, vec3(0,0,2), vec3(0,0,0), vec3(0,1,0)); - - // Render the image - world.Render(); - - // Compare agains stored image for test - int width2 = 0, height2 = 0; - Pixel* data_sol = 0; - - // Read solution from disk - Read_png(data_sol,width2,height2,(getTestSolutionsDir() + "bench.png").c_str()); - assert(width==width2); - assert(height==height2); - - // For each pixel, check to see if it matches solution - double error = 0, total = 0; - for(int i=0; i