From db072ad4dc181eca5a1458656b130beb43f475bf Mon Sep 17 00:00:00 2001 From: 53hornet <53hornet@gmail.com> Date: Sat, 2 Feb 2019 23:33:15 -0500 Subject: Init. --- hw3/.gitignore | 5 + hw3/CMakeLists.txt | 71 + hw3/bin/HW1.cpp | 38 + hw3/bin/HW2.cpp | 112 ++ hw3/bin/HW3.cpp | 90 ++ hw3/bin/helloworld.cpp | 9 + hw3/bin/image_compare.cpp | 90 ++ hw3/data/HW3-scene1.xml | 23 + hw3/data/HW3-scene2.xml | 24 + hw3/data/HW3-scene3.xml | 18 + hw3/data/HW3-scene4.xml | 19 + hw3/data/HW3-scene5.xml | 22 + hw3/data/HW3-scene6.xml | 22 + hw3/data/HW3-scene7.xml | 19 + hw3/data/HW3-scene8.xml | 20 + hw3/data/cube.obj | 26 + hw3/data/sphere.obj | 1834 ++++++++++++++++++++++ hw3/include/.directory | 4 + hw3/include/boundedCompound.h | 55 + hw3/include/boundedPrimitive.h | 67 + hw3/include/boundedTriangle.h | 46 + hw3/include/boundingBox.h | 77 + hw3/include/brdf_base.h | 47 + hw3/include/camera.h | 80 + hw3/include/color.h | 105 ++ hw3/include/compoundShader.h | 51 + hw3/include/constants.h | 16 + hw3/include/coordinateTransform.h | 31 + hw3/include/diffuseBrdf.h | 59 + hw3/include/diffuseReflectanceShader.h | 45 + hw3/include/directionalLightsource.h | 55 + hw3/include/errorMessage.h | 17 + hw3/include/image.h | 89 ++ hw3/include/imageIO.h | 19 + hw3/include/imageIO.pfm.h | 18 + hw3/include/imageIO.ppm.h | 18 + hw3/include/importOBJ.h | 18 + hw3/include/intersectionPoint.h | 110 ++ hw3/include/intersector_base.h | 34 + hw3/include/intersector_factory_base.h | 29 + hw3/include/interval.h | 77 + hw3/include/lightSample.h | 75 + hw3/include/lightsource_base.h | 51 + hw3/include/linear_intersector.h | 62 + hw3/include/mat3d.h | 112 ++ hw3/include/phongBrdf.h | 60 + hw3/include/phongReflectanceShader.h | 46 + hw3/include/random_number.h | 50 + hw3/include/ray.h | 69 + hw3/include/reflectanceParameter.h | 106 ++ hw3/include/reflectanceShader_base.h | 45 + hw3/include/scene.h | 59 + hw3/include/sceneGraphNode.h | 45 + hw3/include/sceneIO.h | 17 + hw3/include/sceneIO_basis.h | 22 + hw3/include/sceneIO_cache.h | 52 + hw3/include/sceneIO_cache.inline.h | 66 + hw3/include/sceneIO_core.h | 24 + hw3/include/sceneIO_geometry.h | 23 + hw3/include/sceneIO_light.h | 25 + hw3/include/sceneIO_material.h | 22 + hw3/include/sceneIO_xml.h | 51 + hw3/include/shaderProperties.h | 38 + hw3/include/shader_base.h | 59 + hw3/include/shadingFrameTransformation.h | 57 + hw3/include/texture_base.h | 67 + hw3/include/tinyxml2.h | 2102 +++++++++++++++++++++++++ hw3/include/transformation3d.h | 77 + hw3/include/triangle.h | 115 ++ hw3/include/triangleMesh.h | 51 + hw3/include/util.h | 19 + hw3/include/vec2d.h | 117 ++ hw3/include/vec3d.h | 120 ++ hw3/src/.directory | 4 + hw3/src/boundedCompound.cpp | 93 ++ hw3/src/boundedPrimitive.cpp | 50 + hw3/src/boundedTriangle.cpp | 53 + hw3/src/boundingBox.cpp | 185 +++ hw3/src/camera.cpp | 150 ++ hw3/src/color.cpp | 233 +++ hw3/src/compoundShader.cpp | 60 + hw3/src/coordinateTransform.cpp | 67 + hw3/src/diffuseBrdf.cpp | 88 ++ hw3/src/diffuseReflectanceShader.cpp | 35 + hw3/src/directionalLightsource.cpp | 38 + hw3/src/errorMessage.cpp | 34 + hw3/src/image.cpp | 122 ++ hw3/src/imageIO.cpp | 46 + hw3/src/imageIO.pfm.cpp | 87 ++ hw3/src/imageIO.ppm.cpp | 106 ++ hw3/src/importOBJ.cpp | 152 ++ hw3/src/intersectionPoint.cpp | 309 ++++ hw3/src/interval.cpp | 154 ++ hw3/src/lightSample.cpp | 121 ++ hw3/src/linear_intersector.cpp | 49 + hw3/src/mat3d.cpp | 260 ++++ hw3/src/phongBrdf.cpp | 99 ++ hw3/src/phongReflectanceShader.cpp | 36 + hw3/src/ray.cpp | 83 + hw3/src/reflectanceParameter.cpp | 140 ++ hw3/src/reflectanceShader_base.cpp | 39 + hw3/src/scene.cpp | 42 + hw3/src/sceneGraphNode.cpp | 39 + hw3/src/sceneIO.cpp | 87 ++ hw3/src/sceneIO_basis.cpp | 51 + hw3/src/sceneIO_core.cpp | 99 ++ hw3/src/sceneIO_geometry.cpp | 153 ++ hw3/src/sceneIO_light.cpp | 51 + hw3/src/sceneIO_material.cpp | 147 ++ hw3/src/sceneIO_xml.cpp | 109 ++ hw3/src/shaderProperties.cpp | 59 + hw3/src/tinyxml2.cpp | 2466 ++++++++++++++++++++++++++++++ hw3/src/transformation3d.cpp | 174 +++ hw3/src/triangle.cpp | 465 ++++++ hw3/src/triangleMesh.cpp | 57 + hw3/src/util.cpp | 45 + hw3/src/vec2d.cpp | 258 ++++ hw3/src/vec3d.cpp | 287 ++++ 118 files changed, 14995 insertions(+) create mode 100644 hw3/.gitignore create mode 100644 hw3/CMakeLists.txt create mode 100644 hw3/bin/HW1.cpp create mode 100644 hw3/bin/HW2.cpp create mode 100644 hw3/bin/HW3.cpp create mode 100644 hw3/bin/helloworld.cpp create mode 100644 hw3/bin/image_compare.cpp create mode 100644 hw3/data/HW3-scene1.xml create mode 100644 hw3/data/HW3-scene2.xml create mode 100644 hw3/data/HW3-scene3.xml create mode 100644 hw3/data/HW3-scene4.xml create mode 100644 hw3/data/HW3-scene5.xml create mode 100644 hw3/data/HW3-scene6.xml create mode 100644 hw3/data/HW3-scene7.xml create mode 100644 hw3/data/HW3-scene8.xml create mode 100644 hw3/data/cube.obj create mode 100644 hw3/data/sphere.obj create mode 100644 hw3/include/.directory create mode 100644 hw3/include/boundedCompound.h create mode 100644 hw3/include/boundedPrimitive.h create mode 100644 hw3/include/boundedTriangle.h create mode 100644 hw3/include/boundingBox.h create mode 100644 hw3/include/brdf_base.h create mode 100644 hw3/include/camera.h create mode 100644 hw3/include/color.h create mode 100644 hw3/include/compoundShader.h create mode 100644 hw3/include/constants.h create mode 100644 hw3/include/coordinateTransform.h create mode 100644 hw3/include/diffuseBrdf.h create mode 100644 hw3/include/diffuseReflectanceShader.h create mode 100644 hw3/include/directionalLightsource.h create mode 100644 hw3/include/errorMessage.h create mode 100644 hw3/include/image.h create mode 100644 hw3/include/imageIO.h create mode 100644 hw3/include/imageIO.pfm.h create mode 100644 hw3/include/imageIO.ppm.h create mode 100644 hw3/include/importOBJ.h create mode 100644 hw3/include/intersectionPoint.h create mode 100644 hw3/include/intersector_base.h create mode 100644 hw3/include/intersector_factory_base.h create mode 100644 hw3/include/interval.h create mode 100644 hw3/include/lightSample.h create mode 100644 hw3/include/lightsource_base.h create mode 100644 hw3/include/linear_intersector.h create mode 100644 hw3/include/mat3d.h create mode 100644 hw3/include/phongBrdf.h create mode 100644 hw3/include/phongReflectanceShader.h create mode 100644 hw3/include/random_number.h create mode 100644 hw3/include/ray.h create mode 100644 hw3/include/reflectanceParameter.h create mode 100644 hw3/include/reflectanceShader_base.h create mode 100644 hw3/include/scene.h create mode 100644 hw3/include/sceneGraphNode.h create mode 100644 hw3/include/sceneIO.h create mode 100644 hw3/include/sceneIO_basis.h create mode 100644 hw3/include/sceneIO_cache.h create mode 100644 hw3/include/sceneIO_cache.inline.h create mode 100644 hw3/include/sceneIO_core.h create mode 100644 hw3/include/sceneIO_geometry.h create mode 100644 hw3/include/sceneIO_light.h create mode 100644 hw3/include/sceneIO_material.h create mode 100644 hw3/include/sceneIO_xml.h create mode 100644 hw3/include/shaderProperties.h create mode 100644 hw3/include/shader_base.h create mode 100644 hw3/include/shadingFrameTransformation.h create mode 100644 hw3/include/texture_base.h create mode 100644 hw3/include/tinyxml2.h create mode 100644 hw3/include/transformation3d.h create mode 100644 hw3/include/triangle.h create mode 100644 hw3/include/triangleMesh.h create mode 100644 hw3/include/util.h create mode 100644 hw3/include/vec2d.h create mode 100644 hw3/include/vec3d.h create mode 100644 hw3/src/.directory create mode 100644 hw3/src/boundedCompound.cpp create mode 100644 hw3/src/boundedPrimitive.cpp create mode 100644 hw3/src/boundedTriangle.cpp create mode 100644 hw3/src/boundingBox.cpp create mode 100644 hw3/src/camera.cpp create mode 100644 hw3/src/color.cpp create mode 100644 hw3/src/compoundShader.cpp create mode 100644 hw3/src/coordinateTransform.cpp create mode 100644 hw3/src/diffuseBrdf.cpp create mode 100644 hw3/src/diffuseReflectanceShader.cpp create mode 100644 hw3/src/directionalLightsource.cpp create mode 100644 hw3/src/errorMessage.cpp create mode 100644 hw3/src/image.cpp create mode 100644 hw3/src/imageIO.cpp create mode 100644 hw3/src/imageIO.pfm.cpp create mode 100644 hw3/src/imageIO.ppm.cpp create mode 100644 hw3/src/importOBJ.cpp create mode 100644 hw3/src/intersectionPoint.cpp create mode 100644 hw3/src/interval.cpp create mode 100644 hw3/src/lightSample.cpp create mode 100644 hw3/src/linear_intersector.cpp create mode 100644 hw3/src/mat3d.cpp create mode 100644 hw3/src/phongBrdf.cpp create mode 100644 hw3/src/phongReflectanceShader.cpp create mode 100644 hw3/src/ray.cpp create mode 100644 hw3/src/reflectanceParameter.cpp create mode 100644 hw3/src/reflectanceShader_base.cpp create mode 100644 hw3/src/scene.cpp create mode 100644 hw3/src/sceneGraphNode.cpp create mode 100644 hw3/src/sceneIO.cpp create mode 100644 hw3/src/sceneIO_basis.cpp create mode 100644 hw3/src/sceneIO_core.cpp create mode 100644 hw3/src/sceneIO_geometry.cpp create mode 100644 hw3/src/sceneIO_light.cpp create mode 100644 hw3/src/sceneIO_material.cpp create mode 100644 hw3/src/sceneIO_xml.cpp create mode 100644 hw3/src/shaderProperties.cpp create mode 100644 hw3/src/tinyxml2.cpp create mode 100644 hw3/src/transformation3d.cpp create mode 100644 hw3/src/triangle.cpp create mode 100644 hw3/src/triangleMesh.cpp create mode 100644 hw3/src/util.cpp create mode 100644 hw3/src/vec2d.cpp create mode 100644 hw3/src/vec3d.cpp (limited to 'hw3') diff --git a/hw3/.gitignore b/hw3/.gitignore new file mode 100644 index 0000000..f64613c --- /dev/null +++ b/hw3/.gitignore @@ -0,0 +1,5 @@ +Debug +Release +Reference +*.ppm + diff --git a/hw3/CMakeLists.txt b/hw3/CMakeLists.txt new file mode 100644 index 0000000..984cdf2 --- /dev/null +++ b/hw3/CMakeLists.txt @@ -0,0 +1,71 @@ +################## +# Initialization # +################## +# Project name is not mandatory, but you should use it +project(CSCI427) + +# States that CMake required version must be >= 2.6 +cmake_minimum_required(VERSION 2.6) + +##################### +# Setup Environment # +##################### +# set to include custom modules +set(CMAKE_MODULE_PATH $ENV{CMAKE_MODULE_PATH} ${CSCI427_SOURCE_DIR}/cmake) + +# set build type if specified by environment +if((NOT CMAKE_BUILD_TYPE) AND (NOT $ENV{CMAKE_BUILD_TYPE} STREQUAL "")) + set(CMAKE_BUILD_TYPE $ENV{CMAKE_BUILD_TYPE}) +endif() + +# Set include directories +include_directories(${CSCI427_SOURCE_DIR}/include) + +# Get CPP files +file(GLOB SRC ${CSCI427_SOURCE_DIR}/src/*cpp) + +# Get executable files +file(GLOB EXECLIST ${CSCI427_SOURCE_DIR}/bin/*cpp) + + +############### +# C++ Options # +############### +# Enable C++11 +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +# determine build type based on directory name. Do not allow for in source building +# +if(${CSCI427_SOURCE_DIR} STREQUAL ${CSCI427_BINARY_DIR}) + message(FATAL_ERROR " *** In-source building not allowed. Please create a subdir 'Release' or 'Debug', and run cmake from within this directory 'cmake ..' ***") +else() + get_filename_component(TYPE ${CSCI427_BINARY_DIR} NAME) + string(TOUPPER "${TYPE}" TYPE) + if(${TYPE} STREQUAL "RELEASE") + set(CMAKE_BUILD_TYPE Release) + else() + set(CMAKE_BUILD_TYPE Debug) + endif() + message("-- Build type set to: ${TYPE}") +endif() + +####################### +# Set Compile Targets # +####################### +# src libraries +if(NOT SRC STREQUAL "") + set(LIBNAME "427_core") + add_library(${LIBNAME} ${SRC}) +endif() + +# executables +foreach(EXEC ${EXECLIST}) + get_filename_component(EXECNAME ${EXEC} NAME_WE) + add_executable(${EXECNAME} ${EXEC}) + + if(NOT SRC STREQUAL "") + target_link_libraries(${EXECNAME} LINK_PUBLIC ${LIBNAME}) + endif() + + message("-- Adding executable: ${EXECNAME}") +endforeach(EXEC) diff --git a/hw3/bin/HW1.cpp b/hw3/bin/HW1.cpp new file mode 100644 index 0000000..8e66297 --- /dev/null +++ b/hw3/bin/HW1.cpp @@ -0,0 +1,38 @@ +#include +#include "vec3d.h" + +int main(int argc, char** argv) +{ + std::cout << "CSCI-427/527 Homework 1: Vectors" << std::endl; + + vec3d a(1.0f, 0.0f, -1.0f); + vec3d b(-1.0f, 1.0f, 1.0f); + + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + std::cout << "a+b = " << a+b << std::endl; + std::cout << "a-b = " << a-b << std::endl; + std::cout << "a*b = " << a*b << std::endl; + std::cout << "a/b = " << a/b << std::endl; + std::cout << "a*2 = " << a*2.0f << std::endl; + std::cout << "b/2 = " << b/2.0f << std::endl; + + std::cout << "a.dot(b) = " << a.dot(b) << std::endl; + std::cout << "b.dot(a) = " << b.dot(a) << std::endl; + std::cout << "a.squared_length() = " << a.squared_length() << std::endl; + std::cout << "b.length() = " << b.length() << std::endl; + std::cout << "a.distance(b) = " << a.distance(b) << std::endl; + std::cout << "a.cross(b) = " << a.cross(b) << std::endl; + std::cout << "b.cross(a) = " << b.cross(a) << std::endl; + std::cout << "normalize(a) = " << normalize(a) << std::endl; + std::cout << "abs(a) = " << abs(a) << std::endl; + std::cout << "b.normalize() = " << b.normalize() << std::endl; + std::cout << "b.abs() = " << b.abs() << std::endl; + + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + // Done. + return 0; +} diff --git a/hw3/bin/HW2.cpp b/hw3/bin/HW2.cpp new file mode 100644 index 0000000..70be45b --- /dev/null +++ b/hw3/bin/HW2.cpp @@ -0,0 +1,112 @@ +#include + +#include "image.h" +#include "camera.h" +#include "imageIO.h" +#include "triangle.h" + +image generateImage(const camera& cam, const triangle& tri) +{ + float t; + vec3d barycentricCoord; + image result(cam.width(), cam.height()); + + // for each pixel + for(image::size_type y=0; y < result.height(); y++) + for(image::size_type x=0; x < result.width(); x++) + { + // generate view ray + ray r = cam(x,y); + + // intersect triangle + bool hit = tri.intersect(r, barycentricCoord, t); + + // draw pixel + if(hit) + result(x,y) = color(barycentricCoord.x, barycentricCoord.y, barycentricCoord.z); + else + result(x,y) = color(0.0f, 0.0f, 0.0f); + } + + // Done. + return result; +} + +int main(int argc, char** argv) +{ + // setup camera + camera cam( vec3d(0.0f, 0.0f, 0.0f), + vec3d(0.0f, 0.0f, -1.0f), + vec3d(0.0f, 1.0f, 0.0f), + 60.0f, + 512, 512 ); + + // Image 1 + std::cout << "Generating image 1." << std::endl; + + triangle t1( vec3d(1.0f, -1.0f, -2.0f), + vec3d(0.0f, 1.0f, -2.0f), + vec3d(-1.0f, -1.0f, -2.0f) ); + + image result1 = generateImage(cam, t1); + exportImage("hw2-result1.ppm", result1); + + + // Image 2 + std::cout << "Generating image 2." << std::endl; + + triangle t2( vec3d(1.0f, -1.0f, 2.0f), + vec3d(0.0f, 1.0f, 2.0f), + vec3d(-1.0f, -1.0f, 2.0f) ); + + image result2 = generateImage(cam, t2); + exportImage("hw2-result2.ppm", result2); + + + // Image 3 + std::cout << "Generating image 3." << std::endl; + + triangle t3( vec3d(-1.0f, -1.0f, -2.0f), + vec3d(1.0f, -1.0f, -2.0f), + vec3d(0.0f, 1.0f, -2.0f) ); + + image result3 = generateImage(cam, t3); + exportImage("hw2-result3.ppm", result3); + + + // Image 4 + std::cout << "Generating image 4." << std::endl; + + triangle t4( vec3d(-1.0f, -1.0f, 2.0f), + vec3d(0.0f, 1.0f, 2.0f), + vec3d(1.0f, -1.0f, 2.0f) ); + + image result4 = generateImage(cam, t4); + exportImage("hw2-result4.ppm", result4); + + + // Image 5 + std::cout << "Generating image 5." << std::endl; + + triangle t5( vec3d(-1.0f, -1.0f, -1.0f), + vec3d(1.0f, -1.0f, -1.0f), + vec3d(1.0f, 1.0f, -1.0f) ); + + image result5 = generateImage(cam, t5); + exportImage("hw2-result5.ppm", result5); + + + // Image 6 + std::cout << "Generating image 6." << std::endl; + + triangle t6( vec3d(-1.0f, 2.0f, -1.0f), + vec3d(0.0f, 2.0f, 1.0f), + vec3d(1.0f, 2.0f, -1.0f) ); + + image result6 = generateImage(cam, t6); + exportImage("hw2-result6.ppm", result6); + + + // Done. + return 0; +} diff --git a/hw3/bin/HW3.cpp b/hw3/bin/HW3.cpp new file mode 100644 index 0000000..4dbb9e6 --- /dev/null +++ b/hw3/bin/HW3.cpp @@ -0,0 +1,90 @@ +#include +#include +#include + +#include "util.h" +#include "image.h" +#include "scene.h" +#include "imageIO.h" +#include "sceneIO.h" + +image generateImage(const scene& s) +{ + image result(s.getCamera().width(), s.getCamera().height()); + + // for every pixel + for(image::size_type y=0; y < result.height(); y++) + for(image::size_type x=0; x < result.width(); x++) + + // For debugging -- render a single delinquent pixel. + // for (image::size_type y=41; y < 42; y++) + // for (image::size_type x=126; x < 127; x++) + { + // generate view ray + ray r = s.getCamera()(x,y); + + // intersect scene + intersectionPoint ip = s.intersect(r); + + // shade pixel + if(ip.isHit()) + { + // for each light source + for(unsigned int l=0; l < s.numberOfLightsources(); l++) + { + // connect to light source + lightSample ls = s.getLightsource(l).intensityAt(ip.position()); + + // shade + result(x,y) += ip.shade(ls); + } + } + else result(x,y) = color(0.0f, 0.0f, 0.0f); + } + + + // Done. + return result; +} + + + +int main(int argc, char** argv) +{ + // parse command line + if(argc < 2) + { + std::cout << "Usage: " << argv[0] << " [scene2.xml ...]" << std::endl; + return -1; + } + + // for each filename, import scene and render + unsigned int pos=1; + while(pos < argc) + { + // get filename + std::string filename = argv[pos++]; + + // import + std::cerr << " * Reading " << filename << std::endl; + scene s; + importScene(filename, s); + + // render + std::cerr << " * Rendering... "; + auto startTime = std::chrono::system_clock::now(); + + image result = generateImage(s); + + auto endTime = std::chrono::system_clock::now(); + std::chrono::duration duration = endTime - startTime; + std::cerr << duration.count() << " seconds." << std::endl; + + // save image + std::cerr << " * Writing result." << std::endl; + exportImage(getFilename(filename) + ".ppm", result); + } + + // Done. + return 0; +} diff --git a/hw3/bin/helloworld.cpp b/hw3/bin/helloworld.cpp new file mode 100644 index 0000000..4911d87 --- /dev/null +++ b/hw3/bin/helloworld.cpp @@ -0,0 +1,9 @@ +#include +#include + +int main(int argc, char** argv) +{ + /////////////////////////// + std::cout << "Hello World." << std::endl; + return(0); +} diff --git a/hw3/bin/image_compare.cpp b/hw3/bin/image_compare.cpp new file mode 100644 index 0000000..4f1a798 --- /dev/null +++ b/hw3/bin/image_compare.cpp @@ -0,0 +1,90 @@ +#include +#include + +#include "util.h" +#include "image.h" +#include "imageIO.h" +#include "constants.h" +#include "errorMessage.h" + +int main(int argc, char** argv) +{ + // parse command line + if(argc != 3) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + std::string nameA(argv[1]); + std::string nameB(argv[2]); + + // get image extensions + std::string extA = getExtension(nameA); + std::string extB = getExtension(nameB); + + // check if both images have the same extension + if(extA != extB) errorMessage(" => different image types (PPM vs PFM)."); + + // load images + image imgA, imgB; + importImage(nameA, imgA); + importImage(nameB, imgB); + + // check if both have the same dimension + if(imgA.width() != imgB.width() || imgA.height() != imgB.height()) + errorMessage(" => different images sizes (%dx%d) vs (%dx%d).", imgA.width(), imgA.height(), imgB.width(), imgB.height()); + + // compute the difference image + image diff(imgA.width(), imgA.height()); + color avgDiff, maxDiff; + unsigned long diffCount = 0; + + for(image::size_type y=0; y < diff.height(); y++) + for(image::size_type x=0; x < diff.width(); x++) + { + // per pixel difference + color diffColor = imgA(x,y) - imgB(x,y); + diff(x,y) = (extA == "ppm") ? abs(diffColor) : diffColor; + + // if different => update average and max (abs value) + diffColor.abs(); + if(diffColor.r > EPSILON || diffColor.g > EPSILON || diffColor.b > EPSILON) + { + diffCount++; + avgDiff += diffColor; + maxDiff = color(std::max(maxDiff.r, diffColor.r), std::max(maxDiff.g, diffColor.g), std::max(maxDiff.b, diffColor.b)); + } + } + + // output results if different + if(extA == "ppm" && diffCount != 0) + { + avgDiff /= diffCount; + std::cout << " => There are " << diffCount << " pixels that differ." << std::endl; + std::cout << " Average difference: " << avgDiff << " [base 256: " << (avgDiff * 256.0f) << "]" << std::endl; + std::cout << " Maximum difference: " << maxDiff << " [base 256: " << (maxDiff * 256.0f) << "]" << std::endl; + + // write out difference image + exportImage("diff.ppm", diff); + } + + else if(extA == "pfm" && diffCount != 0) + { + avgDiff /= diffCount; + std::cout << " => There are " << diffCount << " pixels that differ." << std::endl; + std::cout << " Average difference: " << avgDiff << std::endl; + std::cout << " Maximum difference: " << maxDiff << std::endl; + + // write out difference image + exportImage("diff.pfm", diff); + } + + // if equal, let the user know + else { + std::cout << " => Both images are equal.\r\n"; + } + + // Done. + return 0; +} diff --git a/hw3/data/HW3-scene1.xml b/hw3/data/HW3-scene1.xml new file mode 100644 index 0000000..ee1a846 --- /dev/null +++ b/hw3/data/HW3-scene1.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw3/data/HW3-scene2.xml b/hw3/data/HW3-scene2.xml new file mode 100644 index 0000000..be71e94 --- /dev/null +++ b/hw3/data/HW3-scene2.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw3/data/HW3-scene3.xml b/hw3/data/HW3-scene3.xml new file mode 100644 index 0000000..efa843b --- /dev/null +++ b/hw3/data/HW3-scene3.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw3/data/HW3-scene4.xml b/hw3/data/HW3-scene4.xml new file mode 100644 index 0000000..ed765f8 --- /dev/null +++ b/hw3/data/HW3-scene4.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/hw3/data/HW3-scene5.xml b/hw3/data/HW3-scene5.xml new file mode 100644 index 0000000..fa6d4d6 --- /dev/null +++ b/hw3/data/HW3-scene5.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw3/data/HW3-scene6.xml b/hw3/data/HW3-scene6.xml new file mode 100644 index 0000000..c3df17a --- /dev/null +++ b/hw3/data/HW3-scene6.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw3/data/HW3-scene7.xml b/hw3/data/HW3-scene7.xml new file mode 100644 index 0000000..4183e81 --- /dev/null +++ b/hw3/data/HW3-scene7.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw3/data/HW3-scene8.xml b/hw3/data/HW3-scene8.xml new file mode 100644 index 0000000..52c3ad8 --- /dev/null +++ b/hw3/data/HW3-scene8.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw3/data/cube.obj b/hw3/data/cube.obj new file mode 100644 index 0000000..89afe94 --- /dev/null +++ b/hw3/data/cube.obj @@ -0,0 +1,26 @@ +v 0.0 0.0 0.0 +v 0.0 0.0 1.0 +v 0.0 1.0 0.0 +v 0.0 1.0 1.0 +v 1.0 0.0 0.0 +v 1.0 0.0 1.0 +v 1.0 1.0 0.0 +v 1.0 1.0 1.0 +vn 0.0 0.0 1.0 +vn 0.0 0.0 -1.0 +vn 0.0 1.0 0.0 +vn 0.0 -1.0 0.0 +vn 1.0 0.0 0.0 +vn -1.0 0.0 0.0 +f 1//2 7//2 5//2 +f 1//2 3//2 7//2 +f 1//6 4//6 3//6 +f 1//6 2//6 4//6 +f 3//3 8//3 7//3 +f 3//3 4//3 8//3 +f 5//5 7//5 8//5 +f 5//5 8//5 6//5 +f 1//4 5//4 6//4 +f 1//4 6//4 2//4 +f 2//1 6//1 8//1 +f 2//1 8//1 4//1 diff --git a/hw3/data/sphere.obj b/hw3/data/sphere.obj new file mode 100644 index 0000000..5dd7bde --- /dev/null +++ b/hw3/data/sphere.obj @@ -0,0 +1,1834 @@ +mtllib sphere.mtl +v -1 0 1.40385e-007 +v -0.983024 -0.156077 0.0964607 +v -0.983024 0.156077 -0.0964604 +v -0.978148 -0.185961 -0.0929805 +v -0.978148 0 0.207911 +v -0.978148 0 -0.207911 +v -0.978148 0.185961 0.0929807 +v -0.939205 -0.343331 0.00428931 +v -0.939205 -0.157379 0.305166 +v -0.939205 0.157379 -0.305166 +v -0.939205 0.343331 -0.00428905 +v -0.934172 -0.187593 -0.303531 +v -0.934172 0.187593 0.303531 +v -0.93267 -0.306855 0.189647 +v -0.93267 0.306855 -0.189647 +v -0.913545 -0.363797 -0.181898 +v -0.913545 0 0.406737 +v -0.913545 0 -0.406737 +v -0.913545 0.363797 0.181899 +v -0.866018 -0.490334 0.0979075 +v -0.866018 -0.306855 0.394783 +v -0.866018 0.306855 -0.394782 +v -0.866018 0.490334 -0.0979072 +v -0.851981 -0.516806 -0.0839041 +v -0.851981 -0.156077 0.499769 +v -0.851981 0.156077 -0.499768 +v -0.851981 0.516806 0.0839044 +v -0.850651 -0.447214 0.276393 +v -0.850651 0.447214 -0.276393 +v -0.845991 -0.363797 -0.389809 +v -0.845991 -0.185961 -0.499718 +v -0.845991 0.185961 0.499718 +v -0.845991 0.363797 0.38981 +v -0.809017 -0.525731 -0.262865 +v -0.809017 0 0.587785 +v -0.809017 0 -0.587785 +v -0.809017 0.525731 0.262866 +v -0.762354 -0.644208 0.0617517 +v -0.762354 -0.343331 0.548581 +v -0.762354 0.343331 -0.548581 +v -0.762354 0.644208 -0.0617515 +v -0.758172 -0.60373 0.246345 +v -0.758172 -0.490334 0.429824 +v -0.758172 0.490334 -0.429824 +v -0.758172 0.60373 -0.246345 +v -0.757312 -0.343331 -0.555521 +v -0.757311 0.343331 0.555521 +v -0.738585 -0.516806 -0.432902 +v -0.738585 -0.156077 -0.655845 +v -0.738585 0.156077 0.655845 +v -0.738585 0.516806 0.432902 +v -0.736686 -0.664689 -0.124433 +v -0.736686 0.185961 -0.650164 +v -0.736685 -0.185961 0.650164 +v -0.736685 0.664689 0.124433 +v -0.669131 -0.664689 -0.332344 +v -0.669131 0 0.743144 +v -0.669131 0 -0.743144 +v -0.669131 0.664689 0.332344 +v -0.653054 -0.644208 0.398142 +v -0.653054 0.644208 -0.398142 +v -0.643075 -0.490334 -0.588241 +v -0.643075 -0.306855 -0.701637 +v -0.643075 0.306855 0.701637 +v -0.643075 0.490334 0.588241 +v -0.639949 -0.739749 0.207932 +v -0.639949 -0.516806 0.568662 +v -0.639949 0.516806 -0.568662 +v -0.639949 0.739749 -0.207932 +v -0.632156 -0.774597 0.0194389 +v -0.632156 -0.363797 0.684127 +v -0.632156 0.363797 -0.684127 +v -0.632156 0.774597 -0.0194387 +v -0.580461 -0.644208 -0.498058 +v -0.580461 -0.157379 -0.798935 +v -0.58046 0.157379 0.798935 +v -0.58046 0.644208 0.498058 +v -0.57735 -0.794654 -0.187592 +v -0.57735 -0.187593 0.794655 +v -0.57735 0.187593 -0.794654 +v -0.57735 0.794654 0.187593 +v -0.525731 -0.447214 -0.723607 +v -0.525731 0.447214 0.723607 +v -0.522851 -0.774597 0.355846 +v -0.522851 -0.664689 0.533682 +v -0.522851 0.664689 -0.533681 +v -0.522851 0.774597 -0.355846 +v -0.5 -0.850651 0.16246 +v -0.5 -0.525731 0.688191 +v -0.5 0.525731 -0.688191 +v -0.5 0.850651 -0.16246 +v -0.499999 -0.774597 -0.387298 +v -0.499999 0 0.866026 +v -0.499999 0 -0.866026 +v -0.499999 0.774597 0.387299 +v -0.468576 -0.60373 -0.644939 +v -0.468576 -0.306855 -0.828418 +v -0.468576 0.306855 0.828418 +v -0.468576 0.60373 0.644939 +v -0.455297 -0.889527 -0.0380263 +v -0.455297 -0.363797 0.812623 +v -0.455297 0.363797 -0.812623 +v -0.455297 0.889527 0.0380264 +v -0.395511 -0.739749 -0.544373 +v -0.395511 -0.156077 -0.905103 +v -0.39551 0.156077 0.905103 +v -0.39551 0.739749 0.544373 +v -0.390694 -0.889527 -0.236853 +v -0.390694 -0.185961 0.901541 +v -0.390694 0.185961 -0.901541 +v -0.390694 0.889527 0.236853 +v -0.36073 -0.490334 -0.793377 +v -0.36073 0.490334 0.793377 +v -0.356822 -0.794654 0.491123 +v -0.356822 0.794655 -0.491123 +v -0.345991 -0.889527 0.298381 +v -0.345991 -0.664689 0.662178 +v -0.345991 0.664689 -0.662178 +v -0.345991 0.889527 -0.298381 +v -0.343074 -0.93267 0.111472 +v -0.343074 -0.516806 0.784354 +v -0.343074 0.516806 -0.784354 +v -0.343074 0.93267 -0.111472 +v -0.309017 -0.850651 -0.425325 +v -0.309017 0 0.951057 +v -0.309017 0 -0.951056 +v -0.309017 0.850651 0.425325 +v -0.29431 -0.644208 -0.705959 +v -0.29431 -0.343331 -0.891911 +v -0.294309 0.343331 0.891911 +v -0.294309 0.644208 0.705959 +v -0.286151 -0.953663 -0.092976 +v -0.286151 -0.343331 0.894562 +v -0.286151 0.343331 -0.894562 +v -0.286151 0.953663 0.0929761 +v -0.213835 -0.774597 -0.595209 +v -0.213835 -0.185961 -0.959006 +v -0.213834 0.185961 0.959006 +v -0.213834 0.774597 0.595209 +v -0.212032 -0.93267 -0.291836 +v -0.212032 0.156077 -0.964719 +v -0.212032 0.93267 0.291836 +v -0.212031 -0.156077 0.964719 +v -0.183479 -0.516806 -0.83621 +v -0.183479 0.516806 0.83621 +v -0.17686 -0.889527 0.421262 +v -0.17686 -0.774597 0.607223 +v -0.17686 0.774597 -0.607223 +v -0.17686 0.889527 -0.421262 +v -0.176851 -0.953663 0.243415 +v -0.176851 -0.644208 0.744124 +v -0.176851 0.644208 -0.744124 +v -0.176851 0.953663 -0.243415 +v -0.174499 -0.983024 0.0566981 +v -0.174499 -0.490334 0.853887 +v -0.174499 0.490334 -0.853887 +v -0.174499 0.983024 -0.0566981 +v -0.109305 -0.664689 -0.739082 +v -0.109305 -0.363797 -0.925043 +v -0.109305 0.363797 0.925043 +v -0.109305 0.664689 0.739082 +v -0.107846 -0.983024 -0.148438 +v -0.107846 -0.306855 0.945626 +v -0.107846 0.306855 -0.945626 +v -0.107846 0.983024 0.148438 +v -0.104529 -0.889527 -0.444764 +v -0.104529 0 0.994522 +v -0.104529 0 -0.994522 +v -0.104529 0.889527 0.444764 +v -7.96122e-008 -0.525731 -0.850651 +v -5.98336e-008 -0.187593 -0.982247 +v -5.68148e-008 -0.794655 -0.607062 +v -3.18213e-008 0.157379 -0.987538 +v -2.8159e-008 -0.953663 -0.300877 +v 0 -1 -0 +v 0 0.447214 -0.894427 +v 0 0.60373 -0.797189 +v 0 0.739749 -0.672883 +v 0 0.850651 -0.525731 +v 0 0.93267 -0.36073 +v 0 0.983024 -0.183479 +v 0 1 -0 +v 1.71718e-008 -0.983024 0.183479 +v 2.8159e-008 0.953663 0.300877 +v 3.37606e-008 -0.93267 0.36073 +v 4.92031e-008 -0.850651 0.525731 +v 5.68148e-008 0.794654 0.607062 +v 6.29749e-008 -0.739749 0.672883 +v 7.46087e-008 -0.60373 0.797189 +v 7.96122e-008 0.525731 0.850651 +v 8.37093e-008 -0.447214 0.894427 +v 9.19283e-008 0.187593 0.982247 +v 9.24235e-008 -0.157379 0.987538 +v 0.104529 -0.889527 -0.444764 +v 0.104529 0 0.994522 +v 0.104529 0 -0.994522 +v 0.104529 0.889527 0.444764 +v 0.107846 -0.983024 -0.148438 +v 0.107846 -0.306855 0.945626 +v 0.107846 0.306855 -0.945626 +v 0.107846 0.983024 0.148438 +v 0.109305 -0.664689 -0.739082 +v 0.109305 -0.363797 -0.925043 +v 0.109305 0.363797 0.925043 +v 0.109305 0.664689 0.739082 +v 0.174499 -0.983024 0.0566981 +v 0.174499 -0.490334 0.853887 +v 0.174499 0.490334 -0.853887 +v 0.174499 0.983024 -0.0566981 +v 0.176851 -0.953663 0.243415 +v 0.176851 -0.644208 0.744124 +v 0.176851 0.644208 -0.744124 +v 0.176851 0.953663 -0.243415 +v 0.17686 -0.889527 0.421262 +v 0.17686 -0.774597 0.607223 +v 0.17686 0.774597 -0.607223 +v 0.17686 0.889527 -0.421262 +v 0.183479 -0.516806 -0.83621 +v 0.183479 0.516806 0.83621 +v 0.212032 -0.93267 -0.291836 +v 0.212032 -0.156077 0.964719 +v 0.212032 0.156077 -0.964719 +v 0.212032 0.93267 0.291836 +v 0.213834 -0.774597 -0.595209 +v 0.213834 -0.185961 -0.959006 +v 0.213834 0.774597 0.595209 +v 0.213835 0.185961 0.959006 +v 0.286151 -0.953663 -0.0929761 +v 0.286151 -0.343331 0.894562 +v 0.286151 0.343331 -0.894562 +v 0.286151 0.953663 0.0929761 +v 0.294309 -0.644208 -0.705959 +v 0.294309 -0.343331 -0.891911 +v 0.29431 0.343331 0.891911 +v 0.29431 0.644208 0.705959 +v 0.309017 -0.850651 -0.425325 +v 0.309017 0 0.951056 +v 0.309017 0 -0.951057 +v 0.309017 0.850651 0.425325 +v 0.343074 -0.93267 0.111472 +v 0.343074 -0.516806 0.784354 +v 0.343074 0.516806 -0.784354 +v 0.343074 0.93267 -0.111472 +v 0.345991 -0.889527 0.298381 +v 0.345991 -0.664689 0.662178 +v 0.345991 0.664689 -0.662178 +v 0.345991 0.889527 -0.298381 +v 0.356822 -0.794654 0.491123 +v 0.356822 0.794654 -0.491123 +v 0.36073 -0.490334 -0.793377 +v 0.36073 0.490334 0.793377 +v 0.390694 -0.889527 -0.236853 +v 0.390694 -0.185961 0.901541 +v 0.390694 0.185961 -0.901541 +v 0.390694 0.889527 0.236853 +v 0.39551 -0.739749 -0.544373 +v 0.39551 -0.156077 -0.905103 +v 0.39551 0.739749 0.544373 +v 0.395511 0.156077 0.905103 +v 0.455297 -0.889527 -0.0380264 +v 0.455297 -0.363797 0.812623 +v 0.455297 0.363797 -0.812623 +v 0.455297 0.889527 0.0380263 +v 0.468576 -0.60373 -0.644939 +v 0.468576 -0.306855 -0.828418 +v 0.468576 0.306855 0.828418 +v 0.468576 0.60373 0.644939 +v 0.499999 -0.774597 -0.387298 +v 0.499999 0 0.866026 +v 0.499999 0 -0.866026 +v 0.499999 0.774597 0.387298 +v 0.5 -0.850651 0.16246 +v 0.5 -0.525731 0.688191 +v 0.5 0.525731 -0.688191 +v 0.5 0.850651 -0.16246 +v 0.522851 -0.774597 0.355846 +v 0.522851 -0.664689 0.533681 +v 0.522851 0.664689 -0.533682 +v 0.522851 0.774597 -0.355846 +v 0.525731 -0.447214 -0.723607 +v 0.525731 0.447214 0.723607 +v 0.57735 -0.794654 -0.187592 +v 0.57735 -0.187593 0.794654 +v 0.57735 0.187593 -0.794654 +v 0.57735 0.794654 0.187592 +v 0.58046 -0.644208 -0.498058 +v 0.58046 -0.157379 -0.798935 +v 0.58046 0.644208 0.498058 +v 0.580461 0.157379 0.798935 +v 0.632156 -0.774597 0.0194388 +v 0.632156 -0.363797 0.684127 +v 0.632156 0.363797 -0.684127 +v 0.632156 0.774597 -0.0194389 +v 0.639949 -0.739749 0.207932 +v 0.639949 -0.516806 0.568662 +v 0.639949 0.516806 -0.568662 +v 0.639949 0.739749 -0.207932 +v 0.643075 -0.490334 -0.588241 +v 0.643075 -0.306855 -0.701637 +v 0.643075 0.306855 0.701637 +v 0.643075 0.490334 0.588241 +v 0.653054 -0.644208 0.398142 +v 0.653054 0.644208 -0.398142 +v 0.669131 -0.664689 -0.332344 +v 0.669131 0 0.743144 +v 0.669131 0 -0.743144 +v 0.669131 0.664689 0.332344 +v 0.736685 -0.664689 -0.124433 +v 0.736686 -0.185961 0.650164 +v 0.736686 0.185961 -0.650164 +v 0.736686 0.664689 0.124433 +v 0.738585 -0.516806 -0.432902 +v 0.738585 -0.156077 -0.655845 +v 0.738585 0.156077 0.655845 +v 0.738585 0.516806 0.432902 +v 0.757311 -0.343331 -0.555521 +v 0.757312 0.343331 0.555521 +v 0.758172 -0.60373 0.246345 +v 0.758172 -0.490334 0.429824 +v 0.758172 0.490334 -0.429824 +v 0.758172 0.60373 -0.246345 +v 0.762354 -0.644208 0.0617515 +v 0.762354 -0.343331 0.548581 +v 0.762354 0.343331 -0.548581 +v 0.762354 0.644208 -0.0617516 +v 0.809017 -0.525731 -0.262866 +v 0.809017 0 0.587785 +v 0.809017 0 -0.587785 +v 0.809017 0.525731 0.262865 +v 0.845991 -0.363797 -0.389809 +v 0.845991 -0.185961 -0.499718 +v 0.845991 0.185961 0.499718 +v 0.845991 0.363797 0.389809 +v 0.850651 -0.447214 0.276393 +v 0.850651 0.447214 -0.276393 +v 0.851981 -0.516806 -0.0839043 +v 0.851981 -0.156077 0.499768 +v 0.851981 0.156077 -0.499769 +v 0.851981 0.516806 0.0839042 +v 0.866018 -0.490334 0.0979073 +v 0.866018 -0.306855 0.394782 +v 0.866018 0.306855 -0.394782 +v 0.866018 0.490334 -0.0979074 +v 0.913545 -0.363797 -0.181898 +v 0.913545 0 0.406737 +v 0.913545 0 -0.406737 +v 0.913545 0.363797 0.181898 +v 0.93267 -0.306855 0.189647 +v 0.93267 0.306855 -0.189647 +v 0.934172 -0.187593 -0.303531 +v 0.934172 0.187593 0.303531 +v 0.939205 -0.343331 0.00428914 +v 0.939205 -0.157379 0.305166 +v 0.939205 0.157379 -0.305166 +v 0.939205 0.343331 -0.00428922 +v 0.978148 -0.185961 -0.0929806 +v 0.978148 0 0.207911 +v 0.978148 0 -0.207911 +v 0.978148 0.185961 0.0929806 +v 0.983024 -0.156077 0.0964605 +v 0.983024 0.156077 -0.0964606 +v 1 0 -4.67949e-008 +vt -0.05 0.0972793 +vt -0.05 0.941264 +vt -0.0156234 0.327121 +vt -0.0150836 0.44046 +vt -0.0132618 0.151034 +vt -0.0128636 0.722813 +vt -0.00489247 0.782047 +vt -0.000726819 0.611555 +vt 2.2343e-008 0.5 +vt 0.000726849 0.388445 +vt 0.0048925 0.217953 +vt 0.0128637 0.277187 +vt 0.0132618 0.848966 +vt 0.0150836 0.55954 +vt 0.0155675 0.450115 +vt 0.0156234 0.672879 +vt 0.0179172 0.336875 +vt 0.0266314 0.731436 +vt 0.0312808 0.61852 +vt 0.0319269 0.400723 +vt 0.0333332 0.5 +vt 0.0499999 0.0587359 +vt 0.05 0.352416 +vt 0.05 0.449696 +vt 0.05 0.234944 +vt 0.05 0.293681 +vt 0.05 0.902721 +vt 0.05 0.560069 +vt 0.05 0.176208 +vt 0.0500001 0.676208 +vt 0.0500001 0.792348 +vt 0.0500002 1 +vt 0.0500002 0.117472 +vt 0.0666667 0.5 +vt 0.0680732 0.400723 +vt 0.0687194 0.61852 +vt 0.0733685 0.731436 +vt 0.0820829 0.336875 +vt 0.0843766 0.672879 +vt 0.0844326 0.450115 +vt 0.0849164 0.55954 +vt 0.0867383 0.848966 +vt 0.0871363 0.277187 +vt 0.0951076 0.217953 +vt 0.0992732 0.388445 +vt 0.1 0.5 +vt 0.100727 0.611555 +vt 0.104893 0.782047 +vt 0.112864 0.722813 +vt 0.113262 0.151034 +vt 0.115084 0.44046 +vt 0.115567 0.549885 +vt 0.115623 0.327121 +vt 0.117917 0.663125 +vt 0.126632 0.268564 +vt 0.131281 0.38148 +vt 0.131927 0.599277 +vt 0.133333 0.5 +vt 0.15 0.882528 +vt 0.15 0.70632 +vt 0.15 0.823792 +vt 0.15 0.207652 +vt 0.15 0 +vt 0.15 0.323792 +vt 0.15 0.765056 +vt 0.15 0.550304 +vt 0.15 0.647584 +vt 0.15 0.439931 +vt 0.15 0.0972794 +vt 0.15 0.941264 +vt 0.166667 0.5 +vt 0.168073 0.599277 +vt 0.168719 0.38148 +vt 0.173369 0.268564 +vt 0.182083 0.663125 +vt 0.184377 0.327121 +vt 0.184433 0.549885 +vt 0.184916 0.44046 +vt 0.186738 0.151034 +vt 0.187136 0.722813 +vt 0.195108 0.782047 +vt 0.199273 0.611555 +vt 0.2 0.5 +vt 0.200727 0.388445 +vt 0.204892 0.217953 +vt 0.212864 0.277187 +vt 0.213262 0.848966 +vt 0.215084 0.55954 +vt 0.215568 0.450115 +vt 0.215623 0.672879 +vt 0.217917 0.336875 +vt 0.226632 0.731436 +vt 0.231281 0.61852 +vt 0.231927 0.400723 +vt 0.233333 0.5 +vt 0.25 0.0587359 +vt 0.25 0.117472 +vt 0.25 0.176208 +vt 0.25 0.234944 +vt 0.25 0.293681 +vt 0.25 0.352416 +vt 0.25 0.449696 +vt 0.25 0.560069 +vt 0.25 0.676208 +vt 0.25 0.792348 +vt 0.25 0.902721 +vt 0.25 1 +vt 0.266667 0.5 +vt 0.268073 0.400723 +vt 0.268719 0.61852 +vt 0.273369 0.731436 +vt 0.282083 0.336875 +vt 0.284377 0.672879 +vt 0.284433 0.450115 +vt 0.284916 0.55954 +vt 0.286738 0.848966 +vt 0.287136 0.277187 +vt 0.295108 0.217953 +vt 0.299273 0.388445 +vt 0.3 0.5 +vt 0.300727 0.611555 +vt 0.304892 0.782047 +vt 0.312864 0.722813 +vt 0.313262 0.151034 +vt 0.315084 0.44046 +vt 0.315568 0.549885 +vt 0.315623 0.327121 +vt 0.317917 0.663125 +vt 0.326631 0.268564 +vt 0.331281 0.38148 +vt 0.331927 0.599277 +vt 0.333333 0.5 +vt 0.35 0.941264 +vt 0.35 0.0972794 +vt 0.35 0.647584 +vt 0.35 0.765056 +vt 0.35 0.323792 +vt 0.35 0 +vt 0.35 0.439931 +vt 0.35 0.207652 +vt 0.35 0.70632 +vt 0.35 0.823792 +vt 0.35 0.550304 +vt 0.35 0.882528 +vt 0.366667 0.5 +vt 0.368073 0.599277 +vt 0.368719 0.38148 +vt 0.373369 0.268564 +vt 0.382083 0.663125 +vt 0.384377 0.327121 +vt 0.384433 0.549885 +vt 0.384916 0.44046 +vt 0.386738 0.151034 +vt 0.387136 0.722813 +vt 0.395108 0.782047 +vt 0.399273 0.611555 +vt 0.4 0.5 +vt 0.400727 0.388445 +vt 0.404892 0.217953 +vt 0.412864 0.277187 +vt 0.413262 0.848966 +vt 0.415084 0.55954 +vt 0.415568 0.450115 +vt 0.415623 0.672879 +vt 0.417917 0.336875 +vt 0.426631 0.731436 +vt 0.431281 0.61852 +vt 0.431927 0.400723 +vt 0.433333 0.5 +vt 0.45 0.117472 +vt 0.45 1 +vt 0.45 0.176208 +vt 0.45 0.293681 +vt 0.45 0.560069 +vt 0.45 0.902721 +vt 0.45 0.234944 +vt 0.45 0.449696 +vt 0.45 0.0587359 +vt 0.45 0.352416 +vt 0.45 0.676208 +vt 0.45 0.792348 +vt 0.466667 0.5 +vt 0.468073 0.400723 +vt 0.468719 0.61852 +vt 0.473369 0.731436 +vt 0.482083 0.336875 +vt 0.484377 0.672879 +vt 0.484433 0.450115 +vt 0.484916 0.55954 +vt 0.486738 0.848966 +vt 0.487136 0.277187 +vt 0.495108 0.217953 +vt 0.499273 0.388445 +vt 0.5 0.5 +vt 0.500727 0.611555 +vt 0.504893 0.782047 +vt 0.512864 0.722813 +vt 0.513262 0.151034 +vt 0.515084 0.44046 +vt 0.515567 0.549885 +vt 0.515623 0.327121 +vt 0.517917 0.663125 +vt 0.526631 0.268564 +vt 0.531281 0.38148 +vt 0.531927 0.599277 +vt 0.533333 0.5 +vt 0.55 0.207652 +vt 0.55 0.550304 +vt 0.55 0.647584 +vt 0.55 0.941264 +vt 0.55 0.0972793 +vt 0.55 0.439931 +vt 0.55 0.706319 +vt 0.55 0.765056 +vt 0.55 0.323792 +vt 0.55 0.823792 +vt 0.55 0 +vt 0.55 0.882528 +vt 0.566667 0.5 +vt 0.568073 0.599277 +vt 0.568719 0.38148 +vt 0.573369 0.268564 +vt 0.582083 0.663125 +vt 0.584377 0.327121 +vt 0.584433 0.549885 +vt 0.584916 0.44046 +vt 0.586738 0.151034 +vt 0.587136 0.722813 +vt 0.595108 0.782047 +vt 0.599273 0.611555 +vt 0.6 0.5 +vt 0.600727 0.388445 +vt 0.604892 0.217953 +vt 0.612864 0.277187 +vt 0.613262 0.848966 +vt 0.615084 0.55954 +vt 0.615567 0.450115 +vt 0.615623 0.672879 +vt 0.617917 0.336875 +vt 0.626631 0.731436 +vt 0.631281 0.61852 +vt 0.631927 0.400723 +vt 0.633333 0.5 +vt 0.65 0.117472 +vt 0.65 0.176208 +vt 0.65 0.29368 +vt 0.65 0.792348 +vt 0.65 0.560069 +vt 0.65 0.676208 +vt 0.65 1 +vt 0.65 0.234944 +vt 0.65 0.352416 +vt 0.65 0.449696 +vt 0.65 0.902721 +vt 0.65 0.058736 +vt 0.666667 0.5 +vt 0.668073 0.400723 +vt 0.668719 0.61852 +vt 0.673369 0.731436 +vt 0.682083 0.336875 +vt 0.684377 0.672879 +vt 0.684433 0.450115 +vt 0.684916 0.55954 +vt 0.686738 0.848966 +vt 0.687136 0.277187 +vt 0.695108 0.217953 +vt 0.699273 0.388445 +vt 0.7 0.5 +vt 0.700727 0.611555 +vt 0.704892 0.782047 +vt 0.712864 0.722813 +vt 0.713262 0.151034 +vt 0.715084 0.44046 +vt 0.715567 0.549885 +vt 0.715623 0.327121 +vt 0.717917 0.663125 +vt 0.726632 0.268564 +vt 0.731281 0.38148 +vt 0.731927 0.599277 +vt 0.733333 0.5 +vt 0.75 0 +vt 0.75 0.0972794 +vt 0.75 0.207652 +vt 0.75 0.323792 +vt 0.75 0.439931 +vt 0.75 0.550304 +vt 0.75 0.647584 +vt 0.75 0.706319 +vt 0.75 0.765056 +vt 0.75 0.823792 +vt 0.75 0.882528 +vt 0.75 0.941264 +vt 0.766667 0.5 +vt 0.768073 0.599277 +vt 0.768719 0.38148 +vt 0.773368 0.268564 +vt 0.782083 0.663125 +vt 0.784377 0.327121 +vt 0.784433 0.549885 +vt 0.784917 0.44046 +vt 0.786738 0.151034 +vt 0.787136 0.722813 +vt 0.795108 0.782047 +vt 0.799273 0.611555 +vt 0.8 0.5 +vt 0.800727 0.388445 +vt 0.804893 0.217953 +vt 0.812864 0.277187 +vt 0.813262 0.848966 +vt 0.815084 0.55954 +vt 0.815568 0.450115 +vt 0.815623 0.672879 +vt 0.817917 0.336875 +vt 0.826631 0.731436 +vt 0.831281 0.61852 +vt 0.831927 0.400723 +vt 0.833333 0.5 +vt 0.85 0.058736 +vt 0.85 0.902721 +vt 0.85 0.352416 +vt 0.85 0.560069 +vt 0.85 0.676208 +vt 0.85 1 +vt 0.85 0.176208 +vt 0.85 0.29368 +vt 0.85 0.449696 +vt 0.85 0.792348 +vt 0.85 0.234944 +vt 0.85 0.117472 +vt 0.866667 0.5 +vt 0.868073 0.400723 +vt 0.868719 0.61852 +vt 0.873369 0.731436 +vt 0.882083 0.336875 +vt 0.884377 0.672879 +vt 0.884433 0.450115 +vt 0.884916 0.55954 +vt 0.886738 0.848966 +vt 0.887136 0.277187 +vt 0.895108 0.217953 +vt 0.899273 0.388445 +vt 0.9 0.5 +vt 0.900727 0.611555 +vt 0.904892 0.782047 +vt 0.912864 0.722813 +vt 0.913262 0.151034 +vt 0.915084 0.44046 +vt 0.915568 0.549885 +vt 0.915623 0.327121 +vt 0.917917 0.663125 +vt 0.926631 0.268564 +vt 0.931281 0.38148 +vt 0.931927 0.599277 +vt 0.933333 0.5 +vt 0.95 0 +vt 0.95 0.882528 +vt 0.95 0.823792 +vt 0.95 0.439931 +vt 0.95 0.706319 +vt 0.95 0.765056 +vt 0.95 0.0972793 +vt 0.95 0.550304 +vt 0.95 0.647584 +vt 0.95 0.941264 +vt 0.95 0.207652 +vt 0.95 0.323792 +vt 0.966667 0.5 +vt 0.968073 0.599277 +vt 0.968719 0.38148 +vt 0.973369 0.268564 +vt 0.982083 0.663125 +vt 0.984377 0.327121 +vt 0.984433 0.549885 +vt 0.984916 0.44046 +vt 0.986738 0.151034 +vt 0.987136 0.722813 +vt 0.995108 0.782047 +vt 0.999273 0.611555 +vt 1 0.5 +vt 1.00073 0.388445 +vt 1.00489 0.217953 +vt 1.01286 0.277187 +vt 1.01326 0.848966 +vt 1.01508 0.55954 +vt 1.01562 0.672879 +vt 1.05 0.0587359 +vt 1.05 0.902721 +vn -1 1.00021e-008 4.62596e-008 +vn -0.981591 -0.162468 0.100411 +vn -0.981591 0.162468 -0.100411 +vn -0.978376 -0.180943 -0.100195 +vn -0.978376 0.180943 0.100195 +vn -0.978376 -0.00869708 -0.206649 +vn -0.978376 0.0086971 0.20665 +vn -0.939218 -0.157292 0.30517 +vn -0.939218 -0.343297 0.00421013 +vn -0.939218 0.343297 -0.0042102 +vn -0.939218 0.157293 -0.305171 +vn -0.934172 0.187592 0.303531 +vn -0.934172 -0.187593 -0.303531 +vn -0.929022 -0.314761 0.194533 +vn -0.929022 0.314761 -0.194533 +vn -0.912988 0.360941 0.190194 +vn -0.912988 0.00869702 0.407893 +vn -0.912988 -0.360942 -0.190194 +vn -0.912988 -0.00869627 -0.407893 +vn -0.865939 0.31476 -0.388685 +vn -0.865939 -0.31476 0.388684 +vn -0.865939 -0.488415 0.107705 +vn -0.865939 0.488415 -0.107705 +vn -0.853145 0.162466 -0.49573 +vn -0.853145 -0.516052 -0.0763834 +vn -0.853144 -0.162466 0.495732 +vn -0.853144 0.516053 0.0763836 +vn -0.850652 0.447212 -0.276392 +vn -0.850652 -0.447213 0.276392 +vn -0.850417 -0.180942 -0.494015 +vn -0.850417 -0.360941 -0.382769 +vn -0.850416 0.180942 0.494016 +vn -0.850416 0.360941 0.382772 +vn -0.809018 -0.52573 -0.262865 +vn -0.809017 2.413e-007 -0.587785 +vn -0.809017 0.525732 0.262865 +vn -0.809017 -4.85101e-007 0.587786 +vn -0.763866 0.488416 -0.421851 +vn -0.763866 -0.488417 0.421851 +vn -0.763865 0.595742 -0.248195 +vn -0.763865 -0.595742 0.248195 +vn -0.762317 0.343296 -0.548653 +vn -0.762317 -0.644257 0.0616893 +vn -0.762317 0.644257 -0.0616879 +vn -0.762316 -0.343296 0.548655 +vn -0.757369 -0.343296 -0.555464 +vn -0.757368 0.343296 0.555465 +vn -0.735105 -0.516054 -0.439669 +vn -0.735104 -0.162466 -0.658199 +vn -0.735104 0.162467 0.6582 +vn -0.735104 0.516054 0.439671 +vn -0.73263 -0.667785 -0.131592 +vn -0.73263 0.180943 -0.656135 +vn -0.73263 -0.180942 0.656135 +vn -0.73263 0.667785 0.131592 +vn -0.670058 -0.00869553 0.742258 +vn -0.670058 0.00869665 -0.742258 +vn -0.670057 0.667785 0.324169 +vn -0.670057 -0.667786 -0.324169 +vn -0.652987 -0.644257 0.398171 +vn -0.652987 0.644257 -0.398172 +vn -0.645311 -0.734582 0.209674 +vn -0.645311 0.734582 -0.209674 +vn -0.645311 -0.516052 0.563262 +vn -0.64531 0.516053 -0.563262 +vn -0.637252 0.488417 0.59612 +vn -0.637252 0.31476 0.703446 +vn -0.637251 -0.488416 -0.596121 +vn -0.637251 -0.31476 -0.703447 +vn -0.62683 -0.360942 0.690511 +vn -0.62683 0.77903 -0.0140296 +vn -0.626829 -0.779031 0.0140304 +vn -0.626829 0.360942 -0.690512 +vn -0.580469 -0.157292 -0.798946 +vn -0.580468 0.157292 0.798947 +vn -0.580468 -0.644257 -0.497986 +vn -0.580467 0.644257 0.497987 +vn -0.57735 -0.187593 0.794654 +vn -0.57735 0.794655 0.187592 +vn -0.57735 0.187593 -0.794655 +vn -0.577349 -0.794656 -0.187593 +vn -0.525731 -0.447214 -0.723607 +vn -0.525731 0.447214 0.723607 +vn -0.515363 0.667784 -0.537089 +vn -0.515363 0.77903 -0.35709 +vn -0.515363 -0.667785 0.537089 +vn -0.515362 -0.77903 0.35709 +vn -0.500001 0.52573 -0.688191 +vn -0.5 -0.525729 0.688192 +vn -0.5 0.850651 -0.16246 +vn -0.5 -0.850651 0.16246 +vn -0.49887 -0.00869475 0.866633 +vn -0.49887 0.00869757 -0.866633 +vn -0.498869 -0.77903 -0.379791 +vn -0.498869 0.77903 0.379793 +vn -0.472095 -0.31476 -0.823439 +vn -0.472095 -0.595742 -0.649783 +vn -0.472095 0.314759 0.82344 +vn -0.472095 0.595743 0.649782 +vn -0.463014 0.360941 -0.80953 +vn -0.463014 -0.885484 -0.0391978 +vn -0.463014 0.885484 0.0391977 +vn -0.463013 -0.360942 0.80953 +vn -0.398825 -0.734582 -0.548934 +vn -0.398824 0.162469 0.90252 +vn -0.398824 0.734581 0.548935 +vn -0.398824 -0.162467 -0.902521 +vn -0.397626 -0.885484 -0.240441 +vn -0.397626 0.180943 -0.89953 +vn -0.397625 0.885484 0.240441 +vn -0.397625 -0.180944 0.89953 +vn -0.370023 -0.488416 -0.790274 +vn -0.370022 0.488416 0.790274 +vn -0.356821 0.794655 -0.491122 +vn -0.356821 -0.794656 0.491122 +vn -0.351546 0.667784 -0.656109 +vn -0.351546 -0.885484 0.303865 +vn -0.351546 0.885484 -0.303863 +vn -0.351546 -0.667785 0.656109 +vn -0.336281 -0.935402 0.109265 +vn -0.336281 -0.516052 0.787785 +vn -0.336281 0.516052 -0.787785 +vn -0.336281 0.935402 -0.109265 +vn -0.309017 -0.850651 -0.425325 +vn -0.309017 6.87643e-008 -0.951056 +vn -0.309017 4.8135e-007 0.951057 +vn -0.309017 0.850651 0.425326 +vn -0.29424 -0.644257 -0.705943 +vn -0.294239 0.644258 0.705943 +vn -0.294238 -0.343295 -0.891948 +vn -0.294238 0.343295 0.891949 +vn -0.286232 -0.953636 -0.0930024 +vn -0.286232 0.953636 0.0930024 +vn -0.286231 0.343296 -0.89455 +vn -0.286231 -0.343296 0.89455 +vn -0.207833 -0.935402 -0.286058 +vn -0.207833 0.935402 0.286058 +vn -0.207833 0.162468 -0.964577 +vn -0.207832 -0.162469 0.964577 +vn -0.207046 -0.77903 -0.591814 +vn -0.207046 -0.180943 -0.961453 +vn -0.207045 0.77903 0.591814 +vn -0.207045 0.180944 0.961453 +vn -0.190993 0.516052 0.834992 +vn -0.190992 -0.516052 -0.834992 +vn -0.180359 -0.885484 0.42824 +vn -0.180358 -0.779031 0.600485 +vn -0.180358 0.885484 -0.428239 +vn -0.180357 0.77903 -0.600486 +vn -0.176901 0.953636 -0.243484 +vn -0.176901 -0.953636 0.243484 +vn -0.1769 0.644256 -0.74407 +vn -0.1769 -0.644256 0.74407 +vn -0.165158 -0.984806 0.0536629 +vn -0.165158 0.984806 -0.0536629 +vn -0.165157 0.488415 -0.856839 +vn -0.165157 -0.488415 0.856839 +vn -0.105801 -0.00869593 -0.994349 +vn -0.105801 -0.885484 -0.452464 +vn -0.1058 0.885484 0.452465 +vn -0.1058 0.0086958 0.994349 +vn -0.102073 -0.984806 -0.140492 +vn -0.102073 0.984806 0.140492 +vn -0.102072 -0.31476 0.943667 +vn -0.102071 0.31476 -0.943667 +vn -0.101246 0.360941 0.927077 +vn -0.101246 -0.667784 -0.737437 +vn -0.101245 0.667785 0.737436 +vn -0.101245 -0.360941 -0.927077 +vn -1.38907e-007 0.187592 0.982247 +vn -1.37495e-007 -0.157294 0.987552 +vn -2.50052e-008 -0.52573 -0.850651 +vn -1.24996e-008 -0.953636 -0.300962 +vn -8.74969e-009 0.157294 -0.987552 +vn -1.25026e-009 0.850651 -0.52573 +vn -1.24987e-009 0.984806 -0.173657 +vn -1.24987e-009 0.595741 -0.803177 +vn -1.24987e-009 0.734582 -0.67852 +vn -1.24986e-009 0.935402 -0.353587 +vn 0 -1 1.49983e-008 +vn 0 0.447212 -0.894428 +vn 0 1 -1.34985e-008 +vn 3.74961e-009 -0.984806 0.173657 +vn 1.24987e-008 -0.935402 0.353587 +vn 1.24996e-008 0.953636 0.300962 +vn 2.00227e-008 0.794656 0.60706 +vn 2.12544e-008 -0.850651 0.52573 +vn 2.7497e-008 -0.734582 0.67852 +vn 2.8756e-008 0.52573 0.850651 +vn 3.37465e-008 -0.595741 0.803177 +vn 3.89956e-008 -0.447212 0.894428 +vn 1.45164e-007 -0.187592 -0.982247 +vn 1.45164e-007 -0.794656 -0.60706 +vn 0.101245 0.667785 0.737436 +vn 0.101245 0.360941 0.927077 +vn 0.101246 -0.360941 -0.927077 +vn 0.101246 -0.667784 -0.737437 +vn 0.102071 0.31476 -0.943667 +vn 0.102072 -0.31476 0.943667 +vn 0.102073 -0.984806 -0.140492 +vn 0.102073 0.984806 0.140492 +vn 0.1058 -0.00869608 -0.994349 +vn 0.1058 0.885484 0.452465 +vn 0.105801 -0.885484 -0.452464 +vn 0.105801 0.00869592 0.994349 +vn 0.165157 0.488415 -0.856839 +vn 0.165157 -0.488415 0.856839 +vn 0.165158 0.984806 -0.0536629 +vn 0.165158 -0.984806 0.0536629 +vn 0.1769 -0.644256 0.74407 +vn 0.1769 0.644256 -0.74407 +vn 0.176901 -0.953636 0.243484 +vn 0.176901 0.953636 -0.243484 +vn 0.180358 -0.779031 0.600485 +vn 0.180358 0.779031 -0.600485 +vn 0.180359 0.885484 -0.42824 +vn 0.180359 -0.885484 0.42824 +vn 0.190992 0.516052 0.834992 +vn 0.190993 -0.516052 -0.834992 +vn 0.207045 -0.180944 -0.961453 +vn 0.207045 0.77903 0.591814 +vn 0.207046 0.180943 0.961453 +vn 0.207047 -0.77903 -0.591814 +vn 0.207832 0.162469 -0.964577 +vn 0.207833 -0.162468 0.964577 +vn 0.207833 -0.935402 -0.286058 +vn 0.207833 0.935402 0.286058 +vn 0.286231 -0.343296 0.89455 +vn 0.286231 0.343296 -0.89455 +vn 0.286232 -0.953636 -0.0930024 +vn 0.286232 0.953636 0.0930024 +vn 0.294238 -0.343295 -0.891949 +vn 0.294238 0.343295 0.891948 +vn 0.294239 -0.644258 -0.705943 +vn 0.29424 0.644258 0.705943 +vn 0.309017 -8.52678e-007 -0.951057 +vn 0.309017 -6.87643e-008 0.951056 +vn 0.309017 -0.850651 -0.425326 +vn 0.309017 0.850651 0.425326 +vn 0.336281 -0.935402 0.109265 +vn 0.336281 -0.516052 0.787785 +vn 0.336281 0.516052 -0.787785 +vn 0.336281 0.935402 -0.109265 +vn 0.351546 0.667785 -0.656109 +vn 0.351546 -0.885484 0.303865 +vn 0.351546 0.885484 -0.303865 +vn 0.351546 -0.667785 0.656108 +vn 0.356821 0.794656 -0.491122 +vn 0.356822 -0.794655 0.491122 +vn 0.370022 -0.488416 -0.790274 +vn 0.370023 0.488416 0.790274 +vn 0.397626 -0.180943 0.89953 +vn 0.397626 -0.885484 -0.240442 +vn 0.397626 0.885484 0.240442 +vn 0.397626 0.180944 -0.899529 +vn 0.398824 0.162467 0.902521 +vn 0.398824 -0.162469 -0.90252 +vn 0.398824 -0.734582 -0.548934 +vn 0.398825 0.734582 0.548934 +vn 0.463014 -0.885484 -0.0391978 +vn 0.463014 0.885484 0.0391978 +vn 0.463014 -0.360941 0.80953 +vn 0.463014 0.360941 -0.80953 +vn 0.472095 -0.595743 -0.649782 +vn 0.472095 -0.314759 -0.82344 +vn 0.472095 0.595743 0.649782 +vn 0.472095 0.31476 0.823439 +vn 0.498869 -0.77903 -0.379792 +vn 0.498869 0.77903 0.379792 +vn 0.49887 -0.00869757 0.866633 +vn 0.498871 0.00869589 -0.866633 +vn 0.5 -0.850651 0.16246 +vn 0.5 0.850651 -0.16246 +vn 0.5 0.525729 -0.688192 +vn 0.500001 -0.52573 0.688191 +vn 0.515362 -0.77903 0.357091 +vn 0.515362 0.77903 -0.35709 +vn 0.515363 -0.667785 0.537089 +vn 0.515363 0.667785 -0.537089 +vn 0.525731 -0.447214 -0.723607 +vn 0.525731 0.447214 0.723607 +vn 0.577349 0.794656 0.187593 +vn 0.57735 -0.794655 -0.187592 +vn 0.57735 -0.187593 0.794655 +vn 0.57735 0.187593 -0.794655 +vn 0.580467 -0.644258 -0.497986 +vn 0.580467 0.644258 0.497986 +vn 0.580468 -0.157292 -0.798947 +vn 0.580469 0.157292 0.798946 +vn 0.626829 -0.360942 0.690512 +vn 0.626829 0.360942 -0.690512 +vn 0.626829 0.779031 -0.0140304 +vn 0.62683 -0.77903 0.0140295 +vn 0.637251 0.488417 0.596121 +vn 0.637251 0.31476 0.703447 +vn 0.637252 -0.488417 -0.59612 +vn 0.637252 -0.31476 -0.703446 +vn 0.64531 -0.516053 0.563262 +vn 0.645311 0.516052 -0.563262 +vn 0.645311 -0.734582 0.209674 +vn 0.645311 0.734582 -0.209674 +vn 0.652987 -0.644257 0.398172 +vn 0.652987 0.644257 -0.398171 +vn 0.670057 -0.667786 -0.324169 +vn 0.670057 0.667785 0.32417 +vn 0.670057 0.00869565 -0.742258 +vn 0.670058 -0.00869665 0.742258 +vn 0.732629 0.180942 -0.656136 +vn 0.732629 -0.667786 -0.131592 +vn 0.73263 0.667785 0.131592 +vn 0.73263 -0.180943 0.656135 +vn 0.735104 -0.162467 -0.6582 +vn 0.735104 -0.516053 -0.439671 +vn 0.735104 0.516054 0.43967 +vn 0.735104 0.162466 0.658199 +vn 0.757369 -0.343296 -0.555465 +vn 0.757369 0.343296 0.555464 +vn 0.762317 -0.644257 0.0616879 +vn 0.762317 0.343297 -0.548653 +vn 0.762317 0.644257 -0.0616893 +vn 0.762317 -0.343296 0.548653 +vn 0.763865 -0.595742 0.248195 +vn 0.763865 0.595742 -0.248195 +vn 0.763866 -0.488416 0.421851 +vn 0.763866 0.488416 -0.421851 +vn 0.809017 -5.86372e-007 -0.587785 +vn 0.809017 -0.525731 -0.262865 +vn 0.809017 -2.413e-007 0.587785 +vn 0.809018 0.52573 0.262865 +vn 0.850416 -0.180943 -0.494016 +vn 0.850416 -0.360941 -0.382771 +vn 0.850417 0.180942 0.494015 +vn 0.850417 0.360942 0.382769 +vn 0.850652 -0.447212 0.276392 +vn 0.850652 0.447212 -0.276393 +vn 0.853144 -0.516053 -0.0763836 +vn 0.853145 0.516052 0.0763834 +vn 0.853145 0.162466 -0.495731 +vn 0.853145 -0.162466 0.49573 +vn 0.865939 -0.488415 0.107705 +vn 0.865939 0.488415 -0.107705 +vn 0.865939 -0.31476 0.388685 +vn 0.865939 0.31476 -0.388684 +vn 0.912988 0.360942 0.190194 +vn 0.912988 0.00869627 0.407893 +vn 0.912988 -0.360941 -0.190194 +vn 0.912988 -0.00869702 -0.407893 +vn 0.929022 -0.314761 0.194533 +vn 0.929022 0.314761 -0.194533 +vn 0.934172 -0.187593 -0.303531 +vn 0.934172 0.187593 0.303531 +vn 0.939218 -0.157293 0.305171 +vn 0.939218 -0.343297 0.00421008 +vn 0.939218 0.343297 -0.0042101 +vn 0.939218 0.157293 -0.305171 +vn 0.978376 -0.0086971 -0.20665 +vn 0.978376 0.00869708 0.20665 +vn 0.978376 -0.180943 -0.100195 +vn 0.978376 0.180943 0.100195 +vn 0.981591 -0.162468 0.100411 +vn 0.981591 0.162468 -0.100411 +vn 1 -8.75182e-009 -1.62534e-008 +usemtl Default_Smoothing +s 1 +f 181/292/176 182/250/182 209/210/208 +f 213/254/213 209/210/208 243/218/243 +f 181/292/176 213/254/213 180/291/179 +f 181/292/176 209/210/208 213/254/213 +f 247/235/246 243/218/243 275/216/273 +f 217/264/216 213/254/213 247/235/246 +f 180/291/179 217/264/216 179/290/175 +f 213/254/213 243/218/243 247/235/246 +f 180/291/179 213/254/213 217/264/216 +f 279/229/277 275/216/273 297/214/301 +f 249/247/248 247/235/246 279/229/277 +f 217/264/216 249/247/248 216/270/215 +f 179/290/175 216/270/215 178/289/178 +f 247/235/246 275/216/273 279/229/277 +f 217/264/216 247/235/246 249/247/248 +f 179/290/175 217/264/216 216/270/215 +f 303/228/303 297/214/301 321/213/323 +f 278/240/279 279/229/277 303/228/303 +f 246/259/244 249/247/248 278/240/279 +f 216/270/215 246/259/244 212/271/211 +f 178/289/178 212/271/211 177/288/177 +f 279/229/277 297/214/301 303/228/303 +f 249/247/248 279/229/277 278/240/279 +f 216/270/215 249/247/248 246/259/244 +f 178/289/178 216/270/215 212/271/211 +f 320/223/325 321/213/323 335/209/335 +f 296/238/299 303/228/303 320/223/325 +f 274/249/274 278/240/279 296/238/299 +f 246/259/244 274/249/274 242/261/242 +f 212/271/211 242/261/242 208/276/206 +f 177/288/177 208/276/206 176/287/181 +f 303/228/303 321/213/323 320/223/325 +f 278/240/279 303/228/303 296/238/299 +f 246/259/244 278/240/279 274/249/274 +f 212/271/211 246/259/244 242/261/242 +f 177/288/177 212/271/211 208/276/206 +f 209/210/208 182/171/182 201/133/201 +f 231/175/231 201/133/201 223/144/227 +f 209/210/208 231/175/231 243/218/243 +f 209/210/208 201/133/201 231/175/231 +f 255/161/254 223/144/227 239/142/239 +f 263/190/261 231/175/231 255/161/254 +f 243/218/243 263/190/261 275/216/273 +f 231/175/231 223/144/227 255/161/254 +f 243/218/243 231/175/231 263/190/261 +f 271/155/269 239/142/239 258/136/259 +f 285/181/282 255/161/254 271/155/269 +f 263/190/261 285/181/282 293/196/292 +f 275/216/273 293/196/292 297/214/301 +f 255/161/254 239/142/239 271/155/269 +f 263/190/261 255/161/254 285/181/282 +f 275/216/273 263/190/261 293/196/292 +f 288/154/287 258/136/259 267/141/266 +f 307/166/305 271/155/269 288/154/287 +f 311/185/310 285/181/282 307/166/305 +f 293/196/292 311/185/310 325/197/320 +f 297/214/301 325/197/320 321/213/323 +f 271/155/269 258/136/259 288/154/287 +f 285/181/282 271/155/269 307/166/305 +f 293/196/292 285/181/282 311/185/310 +f 297/214/301 293/196/292 325/197/320 +f 301/149/294 267/141/266 281/135/281 +f 315/164/314 288/154/287 301/149/294 +f 329/180/329 307/166/305 315/164/314 +f 311/185/310 329/180/329 339/187/337 +f 325/197/320 339/187/337 343/202/341 +f 321/213/323 343/202/341 335/209/335 +f 288/154/287 267/141/266 301/149/294 +f 307/166/305 288/154/287 315/164/314 +f 311/185/310 307/166/305 329/180/329 +f 325/197/320 311/185/310 339/187/337 +f 321/213/323 325/197/320 343/202/341 +f 201/133/201 182/107/182 165/70/163 +f 184/106/185 165/70/163 142/59/137 +f 201/133/201 184/106/185 223/144/227 +f 201/133/201 165/70/163 184/106/185 +f 169/87/160 142/59/137 127/61/127 +f 197/116/203 184/106/185 169/87/160 +f 223/144/227 197/116/203 239/142/239 +f 184/106/185 142/59/137 169/87/160 +f 223/144/227 184/106/185 197/116/203 +f 139/81/142 127/61/127 107/65/106 +f 187/105/186 169/87/160 139/81/142 +f 197/116/203 187/105/186 226/122/221 +f 239/142/239 226/122/221 258/136/259 +f 169/87/160 127/61/127 139/81/142 +f 197/116/203 169/87/160 187/105/186 +f 239/142/239 197/116/203 226/122/221 +f 131/80/129 107/65/106 99/60/99 +f 161/92/168 139/81/142 131/80/129 +f 205/111/194 187/105/186 161/92/168 +f 226/122/221 205/111/194 235/123/235 +f 258/136/259 235/123/235 267/141/266 +f 139/81/142 107/65/106 131/80/129 +f 187/105/186 139/81/142 161/92/168 +f 226/122/221 187/105/186 205/111/194 +f 258/136/259 226/122/221 235/123/235 +f 113/75/113 99/60/99 83/67/83 +f 145/90/144 131/80/129 113/75/113 +f 190/104/189 161/92/168 145/90/144 +f 205/111/194 190/104/189 219/113/218 +f 235/123/235 219/113/218 251/128/251 +f 267/141/266 251/128/251 281/135/281 +f 131/80/129 99/60/99 113/75/113 +f 161/92/168 131/80/129 145/90/144 +f 205/111/194 161/92/168 190/104/189 +f 235/123/235 205/111/194 219/113/218 +f 267/141/266 235/123/235 251/128/251 +f 182/32/182 157/2/155 165/70/163 +f 135/387/133 157/364/155 123/356/123 +f 165/70/163 135/27/133 142/59/137 +f 165/70/163 157/2/155 135/27/133 +f 103/383/102 123/356/123 91/357/90 +f 135/27/133 103/13/102 111/42/110 +f 142/59/137 111/42/110 127/61/127 +f 135/387/133 123/356/123 103/383/102 +f 142/59/137 135/27/133 111/42/110 +f 73/377/71 91/357/90 69/360/63 +f 81/31/79 103/13/102 73/7/71 +f 111/42/110 81/31/79 95/48/95 +f 127/61/127 95/48/95 107/65/106 +f 103/383/102 91/357/90 73/377/71 +f 111/42/110 103/13/102 81/31/79 +f 127/61/127 111/42/110 95/48/95 +f 41/376/44 69/360/63 45/359/40 +f 55/18/55 73/7/71 41/6/44 +f 81/31/79 55/18/55 59/37/58 +f 95/48/95 59/37/58 77/49/77 +f 107/65/106 77/49/77 99/60/99 +f 73/377/71 69/360/63 41/376/44 +f 81/31/79 73/7/71 55/18/55 +f 95/48/95 81/31/79 59/37/58 +f 107/65/106 95/48/95 77/49/77 +f 23/371/23 45/359/40 29/363/28 +f 27/385/27 41/376/44 23/371/23 +f 37/30/36 55/18/55 27/16/27 +f 59/37/58 37/30/36 51/39/51 +f 77/49/77 51/39/51 65/54/66 +f 99/60/99 65/54/66 83/67/83 +f 41/376/44 45/359/40 23/371/23 +f 55/18/55 41/6/44 27/16/27 +f 59/37/58 55/18/55 37/30/36 +f 77/49/77 59/37/58 51/39/51 +f 99/60/99 77/49/77 65/54/66 +f 182/323/182 181/292/176 157/364/155 +f 153/319/150 181/292/176 180/291/179 +f 157/364/155 153/319/150 123/356/123 +f 157/364/155 181/292/176 153/319/150 +f 149/309/148 180/291/179 179/290/175 +f 153/319/150 149/309/148 119/338/118 +f 123/356/123 119/338/118 91/357/90 +f 153/319/150 180/291/179 149/309/148 +f 123/356/123 153/319/150 119/338/118 +f 148/303/149 179/290/175 178/289/178 +f 115/327/114 149/309/148 148/303/149 +f 119/338/118 115/327/114 87/344/85 +f 91/357/90 87/344/85 69/360/63 +f 149/309/148 179/290/175 148/303/149 +f 119/338/118 149/309/148 115/327/114 +f 91/357/90 119/338/118 87/344/85 +f 152/302/152 178/289/178 177/288/177 +f 118/314/116 148/303/149 152/302/152 +f 115/327/114 118/314/116 86/333/84 +f 87/344/85 86/333/84 61/345/61 +f 69/360/63 61/345/61 45/359/40 +f 148/303/149 178/289/178 152/302/152 +f 115/327/114 148/303/149 118/314/116 +f 87/344/85 115/327/114 86/333/84 +f 69/360/63 87/344/85 61/345/61 +f 156/297/156 177/288/177 176/287/181 +f 122/312/122 152/302/152 156/297/156 +f 90/322/88 118/314/116 122/312/122 +f 86/333/84 90/322/88 68/335/65 +f 61/345/61 68/335/65 44/350/38 +f 45/359/40 44/350/38 29/363/28 +f 152/302/152 177/288/177 156/297/156 +f 118/314/116 152/302/152 122/312/122 +f 86/333/84 118/314/116 90/322/88 +f 61/345/61 86/333/84 68/335/65 +f 45/359/40 61/345/61 44/350/38 +f 198/255/200 206/178/209 175/217/180 +f 220/244/226 228/211/230 198/255/200 +f 228/211/230 240/170/240 206/178/209 +f 198/255/200 228/211/230 206/178/209 +f 236/245/238 252/227/253 220/244/226 +f 252/227/253 260/198/260 228/211/230 +f 260/198/260 272/172/272 240/170/240 +f 220/244/226 252/227/253 228/211/230 +f 260/198/260 240/170/240 228/211/230 +f 256/251/258 268/233/268 236/245/238 +f 268/233/268 282/207/283 252/227/253 +f 282/207/283 290/192/293 260/198/260 +f 290/192/293 294/176/300 272/172/272 +f 236/245/238 268/233/268 252/227/253 +f 252/227/253 282/207/283 260/198/260 +f 290/192/293 272/172/272 260/198/260 +f 264/246/264 286/234/286 256/251/258 +f 286/234/286 304/222/304 268/233/268 +f 304/222/304 308/203/309 282/207/283 +f 308/203/309 322/191/318 290/192/293 +f 322/191/318 318/173/322 294/176/300 +f 256/251/258 286/234/286 268/233/268 +f 268/233/268 304/222/304 282/207/283 +f 308/203/309 290/192/293 282/207/283 +f 322/191/318 294/176/300 290/192/293 +f 280/252/280 298/239/296 264/246/264 +f 298/239/296 312/224/313 286/234/286 +f 312/224/313 326/215/327 304/222/304 +f 326/215/327 336/201/336 308/203/309 +f 336/201/336 340/186/340 322/191/318 +f 340/186/340 334/179/334 318/173/322 +f 264/246/264 298/239/296 286/234/286 +f 286/234/286 312/224/313 304/222/304 +f 304/222/304 326/215/327 308/203/309 +f 336/201/336 322/191/318 308/203/309 +f 340/186/340 318/173/322 322/191/318 +f 206/178/209 183/96/183 175/138/180 +f 240/170/240 210/134/212 206/178/209 +f 210/134/212 185/97/184 183/96/183 +f 206/178/209 210/134/212 183/96/183 +f 272/172/272 244/153/245 240/170/240 +f 244/153/245 214/124/217 210/134/212 +f 214/124/217 186/98/187 185/97/184 +f 240/170/240 244/153/245 210/134/212 +f 214/124/217 185/97/184 210/134/212 +f 294/176/300 276/159/276 272/172/272 +f 276/159/276 248/140/249 244/153/245 +f 248/140/249 215/118/214 214/124/217 +f 215/118/214 188/99/188 186/98/187 +f 272/172/272 276/159/276 244/153/245 +f 244/153/245 248/140/249 214/124/217 +f 215/118/214 186/98/187 214/124/217 +f 318/173/322 302/160/302 294/176/300 +f 302/160/302 277/148/278 276/159/276 +f 277/148/278 245/129/247 248/140/249 +f 245/129/247 211/117/210 215/118/214 +f 211/117/210 189/100/190 188/99/188 +f 294/176/300 302/160/302 276/159/276 +f 276/159/276 277/148/278 248/140/249 +f 245/129/247 215/118/214 248/140/249 +f 211/117/210 188/99/188 215/118/214 +f 334/179/334 319/165/324 318/173/322 +f 319/165/324 295/150/298 302/160/302 +f 295/150/298 273/137/275 277/148/278 +f 273/137/275 241/127/241 245/129/247 +f 241/127/241 207/112/207 211/117/210 +f 207/112/207 191/101/191 189/100/190 +f 318/173/322 319/165/324 302/160/302 +f 302/160/302 295/150/298 277/148/278 +f 277/148/278 273/137/275 245/129/247 +f 241/127/241 211/117/210 245/129/247 +f 207/112/207 189/100/190 211/117/210 +f 183/96/183 154/22/154 175/63/180 +f 185/97/184 150/69/151 183/96/183 +f 150/69/151 120/33/120 154/22/154 +f 150/69/151 154/22/154 183/96/183 +f 186/98/187 146/79/146 185/97/184 +f 146/79/146 116/50/117 150/69/151 +f 116/50/117 88/29/91 120/33/120 +f 185/97/184 146/79/146 150/69/151 +f 116/50/117 120/33/120 150/69/151 +f 188/99/188 147/85/147 186/98/187 +f 147/85/147 114/62/115 146/79/146 +f 114/62/115 84/44/87 116/50/117 +f 84/44/87 66/25/62 88/29/91 +f 186/98/187 147/85/147 146/79/146 +f 114/62/115 116/50/117 146/79/146 +f 84/44/87 88/29/91 116/50/117 +f 189/100/190 151/86/153 188/99/188 +f 151/86/153 117/74/119 147/85/147 +f 117/74/119 85/55/86 114/62/115 +f 85/55/86 60/43/60 84/44/87 +f 60/43/60 42/26/41 66/25/62 +f 188/99/188 151/86/153 147/85/147 +f 147/85/147 117/74/119 114/62/115 +f 85/55/86 84/44/87 114/62/115 +f 60/43/60 66/25/62 84/44/87 +f 191/101/191 155/91/157 189/100/190 +f 155/91/157 121/76/121 151/86/153 +f 121/76/121 89/64/89 117/74/119 +f 89/64/89 67/53/64 85/55/86 +f 67/53/64 43/38/39 60/43/60 +f 43/38/39 28/23/29 42/26/41 +f 189/100/190 155/91/157 151/86/153 +f 151/86/153 121/76/121 117/74/119 +f 89/64/89 85/55/86 117/74/119 +f 67/53/64 60/43/60 85/55/86 +f 43/38/39 42/26/41 60/43/60 +f 154/386/154 162/318/162 175/355/180 +f 120/33/120 132/1/132 154/22/154 +f 132/361/132 140/329/136 162/318/162 +f 132/361/132 162/318/162 154/386/154 +f 88/29/91 100/5/101 120/33/120 +f 100/375/101 108/346/108 132/361/132 +f 108/346/108 124/324/124 140/329/136 +f 120/33/120 100/5/101 132/1/132 +f 108/346/108 140/329/136 132/361/132 +f 66/25/62 70/11/72 88/29/91 +f 70/381/72 78/365/81 100/375/101 +f 78/365/81 92/340/94 108/346/108 +f 92/340/94 104/328/104 124/324/124 +f 88/29/91 70/11/72 100/5/101 +f 78/365/81 108/346/108 100/375/101 +f 92/340/94 124/324/124 108/346/108 +f 42/26/41 38/12/43 66/25/62 +f 38/382/43 52/370/52 70/381/72 +f 52/370/52 56/351/59 78/365/81 +f 56/351/59 74/339/76 92/340/94 +f 74/339/76 96/325/97 104/328/104 +f 66/25/62 38/12/43 70/11/72 +f 70/381/72 52/370/52 78/365/81 +f 56/351/59 92/340/94 78/365/81 +f 74/339/76 104/328/104 92/340/94 +f 28/23/29 20/17/22 42/26/41 +f 20/17/22 24/3/25 38/12/43 +f 24/372/25 34/366/34 52/370/52 +f 34/366/34 48/349/48 56/351/59 +f 48/349/48 62/334/68 74/339/76 +f 62/334/68 82/320/82 96/325/97 +f 42/26/41 20/17/22 38/12/43 +f 38/382/43 24/372/25 52/370/52 +f 34/366/34 56/351/59 52/370/52 +f 48/349/48 74/339/76 56/351/59 +f 62/334/68 96/325/97 74/339/76 +f 162/318/162 198/255/200 175/281/180 +f 140/329/136 174/282/173 162/318/162 +f 174/282/173 220/244/226 198/255/200 +f 174/282/173 198/255/200 162/318/162 +f 124/324/124 166/301/159 140/329/136 +f 166/301/159 194/272/204 174/282/173 +f 194/272/204 236/245/238 220/244/226 +f 140/329/136 166/301/159 174/282/173 +f 194/272/204 220/244/226 174/282/173 +f 104/328/104 136/307/140 124/324/124 +f 136/307/140 172/283/193 166/301/159 +f 172/283/193 224/266/223 194/272/204 +f 224/266/223 256/251/258 236/245/238 +f 124/324/124 136/307/140 166/301/159 +f 172/283/193 194/272/204 166/301/159 +f 224/266/223 236/245/238 194/272/204 +f 96/325/97 128/308/128 104/328/104 +f 128/308/128 158/296/167 136/307/140 +f 158/296/167 202/277/197 172/283/193 +f 202/277/197 232/265/234 224/266/223 +f 232/265/234 264/246/264 256/251/258 +f 104/328/104 128/308/128 136/307/140 +f 136/307/140 158/296/167 172/283/193 +f 202/277/197 224/266/223 172/283/193 +f 232/265/234 256/251/258 224/266/223 +f 82/320/82 112/313/112 96/325/97 +f 112/313/112 144/298/145 128/308/128 +f 144/298/145 170/284/172 158/296/167 +f 170/284/172 218/275/219 202/277/197 +f 218/275/219 250/260/250 232/265/234 +f 250/260/250 280/252/280 264/246/264 +f 96/325/97 112/313/112 128/308/128 +f 128/308/128 144/298/145 158/296/167 +f 158/296/167 170/284/172 202/277/197 +f 218/275/219 232/265/234 202/277/197 +f 250/260/250 264/246/264 232/265/234 +f 176/287/181 208/276/206 200/279/198 +f 208/276/206 242/261/242 230/269/229 +f 200/279/198 230/269/229 222/274/224 +f 208/276/206 230/269/229 200/279/198 +f 242/261/242 274/249/274 262/258/263 +f 230/269/229 262/258/263 254/263/255 +f 222/274/224 254/263/255 238/268/236 +f 242/261/242 262/258/263 230/269/229 +f 230/269/229 254/263/255 222/274/224 +f 274/249/274 296/238/299 292/241/291 +f 262/258/263 292/241/291 284/248/285 +f 254/263/255 284/248/285 270/256/271 +f 238/268/236 270/256/271 257/262/257 +f 262/258/263 274/249/274 292/241/291 +f 262/258/263 284/248/285 254/263/255 +f 238/268/236 254/263/255 270/256/271 +f 296/238/299 320/223/325 324/230/319 +f 292/241/291 324/230/319 310/236/308 +f 284/248/285 310/236/308 306/243/306 +f 270/256/271 306/243/306 287/253/288 +f 257/262/257 287/253/288 265/257/265 +f 292/241/291 296/238/299 324/230/319 +f 284/248/285 292/241/291 310/236/308 +f 270/256/271 284/248/285 306/243/306 +f 257/262/257 270/256/271 287/253/288 +f 320/223/325 335/209/335 342/220/343 +f 324/230/319 342/220/343 338/225/338 +f 310/236/308 338/225/338 328/231/326 +f 306/243/306 328/231/326 313/237/312 +f 287/253/288 313/237/312 299/242/297 +f 265/257/265 299/242/297 280/252/280 +f 324/230/319 320/223/325 342/220/343 +f 310/236/308 324/230/319 338/225/338 +f 306/243/306 310/236/308 328/231/326 +f 306/243/306 313/237/312 287/253/288 +f 265/257/265 287/253/288 299/242/297 +f 335/209/335 343/202/341 349/205/349 +f 343/202/341 339/187/337 355/195/354 +f 349/205/349 355/195/354 361/200/361 +f 343/202/341 355/195/354 349/205/349 +f 339/187/337 329/180/329 347/184/344 +f 355/195/354 347/184/344 359/189/359 +f 361/200/361 359/189/359 362/194/362 +f 339/187/337 347/184/344 355/195/354 +f 355/195/354 359/189/359 361/200/361 +f 329/180/329 315/164/314 333/167/333 +f 347/184/344 333/167/333 351/174/351 +f 359/189/359 351/174/351 357/182/357 +f 362/194/362 357/182/357 360/188/360 +f 347/184/344 329/180/329 333/167/333 +f 347/184/344 351/174/351 359/189/359 +f 362/194/362 359/189/359 357/182/357 +f 315/164/314 301/149/294 317/156/317 +f 333/167/333 317/156/317 332/162/332 +f 351/174/351 332/162/332 345/169/345 +f 357/182/357 345/169/345 353/177/352 +f 360/188/360 353/177/352 348/183/348 +f 333/167/333 315/164/314 317/156/317 +f 351/174/351 333/167/333 332/162/332 +f 357/182/357 351/174/351 345/169/345 +f 360/188/360 357/182/357 353/177/352 +f 301/149/294 281/135/281 300/146/295 +f 317/156/317 300/146/295 314/151/315 +f 332/162/332 314/151/315 327/157/328 +f 345/169/345 327/157/328 337/163/339 +f 353/177/352 337/163/339 341/168/342 +f 348/183/348 341/168/342 334/179/334 +f 317/156/317 301/149/294 300/146/295 +f 332/162/332 317/156/317 314/151/315 +f 345/169/345 332/162/332 327/157/328 +f 345/169/345 337/163/339 353/177/352 +f 348/183/348 353/177/352 341/168/342 +f 281/135/281 251/128/251 266/131/267 +f 251/128/251 219/113/218 234/121/233 +f 266/131/267 234/121/233 259/126/256 +f 251/128/251 234/121/233 266/131/267 +f 219/113/218 190/104/189 204/110/195 +f 234/121/233 204/110/195 227/115/222 +f 259/126/256 227/115/222 237/120/237 +f 219/113/218 204/110/195 234/121/233 +f 234/121/233 227/115/222 259/126/256 +f 190/104/189 145/90/144 160/93/166 +f 204/110/195 160/93/166 192/103/170 +f 227/115/222 192/103/170 195/108/205 +f 237/120/237 195/108/205 221/114/225 +f 204/110/195 190/104/189 160/93/166 +f 204/110/195 192/103/170 227/115/222 +f 237/120/237 227/115/222 195/108/205 +f 145/90/144 113/75/113 130/82/131 +f 160/93/166 130/82/131 138/88/143 +f 192/103/170 138/88/143 167/95/161 +f 195/108/205 167/95/161 193/102/171 +f 221/114/225 193/102/171 199/109/199 +f 160/93/166 145/90/144 130/82/131 +f 192/103/170 160/93/166 138/88/143 +f 195/108/205 192/103/170 167/95/161 +f 221/114/225 195/108/205 193/102/171 +f 113/75/113 83/67/83 98/72/98 +f 130/82/131 98/72/98 106/77/105 +f 138/88/143 106/77/105 125/83/126 +f 167/95/161 125/83/126 143/89/139 +f 193/102/171 143/89/139 163/94/164 +f 199/109/199 163/94/164 191/101/191 +f 130/82/131 113/75/113 98/72/98 +f 138/88/143 130/82/131 106/77/105 +f 138/88/143 125/83/126 167/95/161 +f 167/95/161 143/89/139 193/102/171 +f 199/109/199 193/102/171 163/94/164 +f 83/67/83 65/54/66 64/57/67 +f 65/54/66 51/39/51 47/47/47 +f 64/57/67 47/47/47 50/52/50 +f 65/54/66 47/47/47 64/57/67 +f 51/39/51 37/30/36 33/36/33 +f 47/47/47 33/36/33 32/41/32 +f 50/52/50 32/41/32 35/46/37 +f 51/39/51 33/36/33 47/47/47 +f 47/47/47 32/41/32 50/52/50 +f 37/30/36 27/16/27 19/19/16 +f 33/36/33 19/19/16 13/28/12 +f 32/41/32 13/28/12 17/34/17 +f 35/46/37 17/34/17 25/40/26 +f 37/30/36 19/19/16 33/36/33 +f 33/36/33 13/28/12 32/41/32 +f 32/41/32 17/34/17 35/46/37 +f 27/385/27 23/371/23 11/378/10 +f 19/19/16 11/8/10 7/14/5 +f 13/28/12 7/14/5 5/21/7 +f 17/34/17 5/21/7 9/24/8 +f 25/40/26 9/24/8 21/35/21 +f 19/19/16 27/16/27 11/8/10 +f 13/28/12 19/19/16 7/14/5 +f 13/28/12 5/21/7 17/34/17 +f 25/40/26 17/34/17 9/24/8 +f 23/371/23 29/363/28 15/368/15 +f 11/378/10 15/368/15 3/373/3 +f 7/384/5 3/373/3 1/379/1 +f 5/21/7 1/9/1 2/15/2 +f 9/24/8 2/15/2 14/20/14 +f 21/35/21 14/20/14 28/23/29 +f 11/378/10 23/371/23 15/368/15 +f 7/384/5 11/378/10 3/373/3 +f 7/14/5 1/9/1 5/21/7 +f 5/21/7 2/15/2 9/24/8 +f 9/24/8 14/20/14 21/35/21 +f 29/363/28 44/350/38 22/353/20 +f 44/350/38 68/335/65 40/343/42 +f 22/353/20 40/343/42 26/348/24 +f 44/350/38 40/343/42 22/353/20 +f 68/335/65 90/322/88 72/332/73 +f 40/343/42 72/332/73 53/337/53 +f 26/348/24 53/337/53 36/342/35 +f 68/335/65 72/332/73 40/343/42 +f 40/343/42 53/337/53 26/348/24 +f 90/322/88 122/312/122 102/315/100 +f 72/332/73 102/315/100 80/321/80 +f 53/337/53 80/321/80 58/330/57 +f 36/342/35 58/330/57 49/336/49 +f 90/322/88 102/315/100 72/332/73 +f 72/332/73 80/321/80 53/337/53 +f 53/337/53 58/330/57 36/342/35 +f 122/312/122 156/297/156 134/304/134 +f 102/315/100 134/304/134 110/310/109 +f 80/321/80 110/310/109 94/317/93 +f 58/330/57 94/317/93 75/326/74 +f 49/336/49 75/326/74 63/331/69 +f 102/315/100 122/312/122 134/304/134 +f 80/321/80 102/315/100 110/310/109 +f 80/321/80 94/317/93 58/330/57 +f 49/336/49 58/330/57 75/326/74 +f 156/297/156 176/287/181 164/294/165 +f 134/304/134 164/294/165 141/299/138 +f 110/310/109 141/299/138 126/305/125 +f 94/317/93 126/305/125 105/311/107 +f 75/326/74 105/311/107 97/316/96 +f 63/331/69 97/316/96 82/320/82 +f 134/304/134 156/297/156 164/294/165 +f 110/310/109 134/304/134 141/299/138 +f 110/310/109 126/305/125 94/317/93 +f 94/317/93 105/311/107 75/326/74 +f 75/326/74 97/316/96 63/331/69 +f 348/183/348 334/179/334 340/186/340 +f 352/193/353 340/186/340 336/201/336 +f 360/188/360 348/183/348 352/193/353 +f 352/193/353 348/183/348 340/186/340 +f 344/204/346 336/201/336 326/215/327 +f 356/199/358 352/193/353 344/204/346 +f 362/194/362 360/188/360 356/199/358 +f 344/204/346 352/193/353 336/201/336 +f 356/199/358 360/188/360 352/193/353 +f 312/224/313 330/221/331 326/215/327 +f 330/221/331 350/212/350 344/204/346 +f 358/206/356 356/199/358 350/212/350 +f 358/206/356 361/200/361 362/194/362 +f 330/221/331 344/204/346 326/215/327 +f 350/212/350 356/199/358 344/204/346 +f 358/206/356 362/194/362 356/199/358 +f 298/239/296 316/232/316 312/224/313 +f 316/232/316 331/226/330 330/221/331 +f 331/226/330 346/219/347 350/212/350 +f 346/219/347 354/208/355 358/206/356 +f 354/208/355 349/205/349 361/200/361 +f 316/232/316 330/221/331 312/224/313 +f 331/226/330 350/212/350 330/221/331 +f 346/219/347 358/206/356 350/212/350 +f 354/208/355 361/200/361 358/206/356 +f 280/252/280 299/242/297 298/239/296 +f 299/242/297 313/237/312 316/232/316 +f 313/237/312 328/231/326 331/226/330 +f 328/231/326 338/225/338 346/219/347 +f 342/220/343 354/208/355 338/225/338 +f 342/220/343 335/209/335 349/205/349 +f 299/242/297 316/232/316 298/239/296 +f 313/237/312 331/226/330 316/232/316 +f 328/231/326 346/219/347 331/226/330 +f 338/225/338 354/208/355 346/219/347 +f 342/220/343 349/205/349 354/208/355 +f 199/109/199 191/101/191 207/112/207 +f 229/119/228 207/112/207 241/127/241 +f 221/114/225 199/109/199 229/119/228 +f 229/119/228 199/109/199 207/112/207 +f 261/130/262 241/127/241 273/137/275 +f 253/125/252 229/119/228 261/130/262 +f 237/120/237 221/114/225 253/125/252 +f 261/130/262 229/119/228 241/127/241 +f 253/125/252 221/114/225 229/119/228 +f 295/150/298 291/147/290 273/137/275 +f 291/147/290 283/139/284 261/130/262 +f 269/132/270 253/125/252 283/139/284 +f 269/132/270 259/126/256 237/120/237 +f 291/147/290 261/130/262 273/137/275 +f 283/139/284 253/125/252 261/130/262 +f 269/132/270 237/120/237 253/125/252 +f 319/165/324 323/158/321 295/150/298 +f 323/158/321 309/152/311 291/147/290 +f 309/152/311 305/145/307 283/139/284 +f 305/145/307 289/143/289 269/132/270 +f 289/143/289 266/131/267 259/126/256 +f 323/158/321 291/147/290 295/150/298 +f 309/152/311 283/139/284 291/147/290 +f 305/145/307 269/132/270 283/139/284 +f 289/143/289 259/126/256 269/132/270 +f 334/179/334 341/168/342 319/165/324 +f 341/168/342 337/163/339 323/158/321 +f 337/163/339 327/157/328 309/152/311 +f 327/157/328 314/151/315 305/145/307 +f 300/146/295 289/143/289 314/151/315 +f 300/146/295 281/135/281 266/131/267 +f 341/168/342 323/158/321 319/165/324 +f 337/163/339 309/152/311 323/158/321 +f 327/157/328 305/145/307 309/152/311 +f 314/151/315 289/143/289 305/145/307 +f 300/146/295 266/131/267 289/143/289 +f 21/35/21 28/23/29 43/38/39 +f 39/45/45 43/38/39 67/53/64 +f 25/40/26 21/35/21 39/45/45 +f 39/45/45 21/35/21 43/38/39 +f 71/56/70 67/53/64 89/64/89 +f 54/51/54 39/45/45 71/56/70 +f 35/46/37 25/40/26 54/51/54 +f 71/56/70 39/45/45 67/53/64 +f 54/51/54 25/40/26 39/45/45 +f 121/76/121 101/73/103 89/64/89 +f 79/68/78 71/56/70 101/73/103 +f 57/58/56 54/51/54 79/68/78 +f 50/52/50 35/46/37 57/58/56 +f 101/73/103 71/56/70 89/64/89 +f 79/68/78 54/51/54 71/56/70 +f 57/58/56 35/46/37 54/51/54 +f 155/91/157 133/84/135 121/76/121 +f 133/84/135 109/78/111 101/73/103 +f 109/78/111 93/71/92 79/68/78 +f 76/66/75 57/58/56 93/71/92 +f 76/66/75 64/57/67 50/52/50 +f 133/84/135 101/73/103 121/76/121 +f 109/78/111 79/68/78 101/73/103 +f 93/71/92 57/58/56 79/68/78 +f 76/66/75 50/52/50 57/58/56 +f 191/101/191 163/94/164 155/91/157 +f 163/94/164 143/89/139 133/84/135 +f 143/89/139 125/83/126 109/78/111 +f 106/77/105 93/71/92 125/83/126 +f 98/72/98 76/66/75 106/77/105 +f 83/67/83 64/57/67 98/72/98 +f 163/94/164 133/84/135 155/91/157 +f 143/89/139 109/78/111 133/84/135 +f 125/83/126 93/71/92 109/78/111 +f 106/77/105 76/66/75 93/71/92 +f 98/72/98 64/57/67 76/66/75 +f 63/331/69 82/320/82 62/334/68 +f 46/341/46 62/334/68 48/349/48 +f 49/336/49 63/331/69 46/341/46 +f 46/341/46 63/331/69 62/334/68 +f 30/352/31 48/349/48 34/366/34 +f 31/347/30 46/341/46 30/352/31 +f 36/342/35 49/336/49 31/347/30 +f 30/352/31 46/341/46 48/349/48 +f 31/347/30 49/336/49 46/341/46 +f 24/372/25 16/369/18 34/366/34 +f 12/358/13 30/352/31 16/369/18 +f 18/354/19 31/347/30 12/358/13 +f 26/348/24 36/342/35 18/354/19 +f 16/369/18 30/352/31 34/366/34 +f 12/358/13 31/347/30 30/352/31 +f 18/354/19 36/342/35 31/347/30 +f 20/17/22 8/10/9 24/3/25 +f 8/380/9 4/374/4 16/369/18 +f 4/374/4 6/367/6 12/358/13 +f 10/362/11 18/354/19 6/367/6 +f 10/362/11 22/353/20 26/348/24 +f 8/380/9 16/369/18 24/372/25 +f 4/374/4 12/358/13 16/369/18 +f 6/367/6 18/354/19 12/358/13 +f 10/362/11 26/348/24 18/354/19 +f 28/23/29 14/20/14 20/17/22 +f 14/20/14 2/15/2 8/10/9 +f 2/15/2 1/9/1 4/4/4 +f 3/373/3 6/367/6 1/379/1 +f 15/368/15 10/362/11 3/373/3 +f 29/363/28 22/353/20 15/368/15 +f 14/20/14 8/10/9 20/17/22 +f 2/15/2 4/4/4 8/10/9 +f 1/379/1 6/367/6 4/374/4 +f 3/373/3 10/362/11 6/367/6 +f 15/368/15 22/353/20 10/362/11 +f 265/257/265 280/252/280 250/260/250 +f 233/267/232 250/260/250 218/275/219 +f 257/262/257 265/257/265 233/267/232 +f 233/267/232 265/257/265 250/260/250 +f 203/278/196 218/275/219 170/284/172 +f 225/273/220 233/267/232 203/278/196 +f 238/268/236 257/262/257 225/273/220 +f 203/278/196 233/267/232 218/275/219 +f 225/273/220 257/262/257 233/267/232 +f 144/298/145 159/295/169 170/284/172 +f 159/295/169 171/285/192 203/278/196 +f 196/280/202 225/273/220 171/285/192 +f 196/280/202 222/274/224 238/268/236 +f 159/295/169 203/278/196 170/284/172 +f 171/285/192 225/273/220 203/278/196 +f 196/280/202 238/268/236 225/273/220 +f 112/313/112 129/306/130 144/298/145 +f 129/306/130 137/300/141 159/295/169 +f 137/300/141 168/293/158 171/285/192 +f 168/293/158 173/286/174 196/280/202 +f 173/286/174 200/279/198 222/274/224 +f 129/306/130 159/295/169 144/298/145 +f 137/300/141 171/285/192 159/295/169 +f 168/293/158 196/280/202 171/285/192 +f 173/286/174 222/274/224 196/280/202 +f 82/320/82 97/316/96 112/313/112 +f 97/316/96 105/311/107 129/306/130 +f 105/311/107 126/305/125 137/300/141 +f 141/299/138 168/293/158 126/305/125 +f 164/294/165 173/286/174 141/299/138 +f 164/294/165 176/287/181 200/279/198 +f 97/316/96 129/306/130 112/313/112 +f 105/311/107 137/300/141 129/306/130 +f 126/305/125 168/293/158 137/300/141 +f 141/299/138 173/286/174 168/293/158 +f 164/294/165 200/279/198 173/286/174 diff --git a/hw3/include/.directory b/hw3/include/.directory new file mode 100644 index 0000000..f009e80 --- /dev/null +++ b/hw3/include/.directory @@ -0,0 +1,4 @@ +[Dolphin] +Timestamp=2016,2,3,13,45,20 +Version=3 +ViewMode=1 diff --git a/hw3/include/boundedCompound.h b/hw3/include/boundedCompound.h new file mode 100644 index 0000000..ab396f3 --- /dev/null +++ b/hw3/include/boundedCompound.h @@ -0,0 +1,55 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _BOUNDED_COMPOUND_H_ +#define _BOUNDED_COMPOUND_H_ + +#include "intersector_base.h" +#include "transformation3d.h" +#include "boundedPrimitive.h" + +class boundedCompound : public boundedPrimitive { + public: + ///////////////// + // Constructor // + ///////////////// + boundedCompound(void); + boundedCompound(const transformation3d& transform, const std::shared_ptr& shader=nullptr); + boundedCompound(const boundedCompound&) = delete; + + /////////////// + // Operators // + /////////////// + boundedCompound& operator=(const boundedCompound&) = delete; + + ///////////// + // Methods // + ///////////// + void initialize(const class intersector_factory_base& ifb); + + virtual bool hasShader(void) const override; + + virtual intersectionPoint intersect(const ray& r) const final override; + + virtual const std::vector>& compounds(void) const = 0; + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + void initializeBoundingBox(void); + virtual void _print(std::ostream& s) const override; + + ////////////////// + // Data Members // + ////////////////// + transformation3d _transform; + std::unique_ptr _intersector; +}; + +#endif /* _BOUNDED_COMPOUND_H_ */ diff --git a/hw3/include/boundedPrimitive.h b/hw3/include/boundedPrimitive.h new file mode 100644 index 0000000..ef467a2 --- /dev/null +++ b/hw3/include/boundedPrimitive.h @@ -0,0 +1,67 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _BOUNDED_PRIMITIVE_H_ +#define _BOUNDED_PRIMITIVE_H_ + +#include +#include +#include + +#include "ray.h" +#include "shader_base.h" +#include "boundingBox.h" +#include "intersectionPoint.h" + +class boundedPrimitive { + public: + ///////////////// + // Constructor // + ///////////////// + boundedPrimitive(void); + boundedPrimitive(const boundingBox& bb, const std::shared_ptr& shader); + boundedPrimitive(const boundedPrimitive&) = delete; + + /////////////// + // Operators // + /////////////// + boundedPrimitive& operator=(const boundedPrimitive& ) = delete; + + ///////////// + // Methods // + ///////////// + const boundingBox& boundingbox(void) const; + bool hitBoundingBox(const ray& r) const; + virtual bool hasShader(void) const; + + virtual intersectionPoint intersect(const ray& r) const = 0; + + ///////////// + // Friends // + ///////////// + friend std::ostream& operator<<(std::ostream& s, const boundedPrimitive& bp) + { + bp._print(s); + return s; + } + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual void _print(std::ostream& s) const; + + ////////////////// + // Data Members // + ////////////////// + boundingBox _bb; + std::shared_ptr _shader; +}; + +#endif /* _BOUNDED_PRIMITIVE_H_ */ + diff --git a/hw3/include/boundedTriangle.h b/hw3/include/boundedTriangle.h new file mode 100644 index 0000000..965c0ff --- /dev/null +++ b/hw3/include/boundedTriangle.h @@ -0,0 +1,46 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _BOUNDEDTRIANGLE_H_ +#define _BOUNDEDTRIANGLE_H_ + +#include "triangle.h" +#include "boundedPrimitive.h" + +class boundedTriangle : public boundedPrimitive { + public: + ////////////////// + // Constructors // + ////////////////// + boundedTriangle(void); + boundedTriangle(const triangle& tri, const std::shared_ptr& shader); + boundedTriangle(const boundedTriangle&) = delete; + + /////////////// + // Operators // + /////////////// + boundedTriangle& operator=(const boundedTriangle&) = delete; + + ///////////// + // Methods // + ///////////// + virtual intersectionPoint intersect(const ray& r) const final override; + + private: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual void _print(std::ostream& s) const override; + + ////////////////// + // Data Members // + ////////////////// + triangle _triangle; +}; + +#endif /* _BOUNDEDTRIANGLE_H_ */ diff --git a/hw3/include/boundingBox.h b/hw3/include/boundingBox.h new file mode 100644 index 0000000..522672e --- /dev/null +++ b/hw3/include/boundingBox.h @@ -0,0 +1,77 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _BOUNDINGBOX_H_ +#define _BOUNDINGBOX_H_ + +#include + +#include "ray.h" +#include "vec3d.h" +#include "transformation3d.h" + +class boundingBox { + public: + ///////////////// + // Constructor // + ///////////////// + boundingBox(void); + boundingBox(const vec3d& lfb, const vec3d& rbt); + boundingBox(const boundingBox& bb); + + ////////////// + // Operator // + ////////////// + boundingBox& operator=(const boundingBox& src); + + boundingBox& operator+=(const boundingBox& bb); + boundingBox& operator+=(const vec3d& point); + + boundingBox operator+(const boundingBox& bb) const; + + ///////////// + // Methods // + ///////////// + bool isHit(const ray& r) const; + + vec3d center(void) const; + vec3d corner(bool left, bool front, bool bottom) const; + + ////////////// + // Mutators // + ////////////// + boundingBox& transform(const transformation3d& t); + boundingBox& inverseTransform(const transformation3d& t); + + ///////////// + // Friends // + ///////////// + friend void swap(boundingBox& a, boundingBox& b) { a._swap(b); } + friend boundingBox transform(const boundingBox& bb, const transformation3d& t) { return boundingBox(bb).transform(t); } + friend boundingBox inverseTransform(const boundingBox& bb, const transformation3d& t) { return boundingBox(bb).inverseTransform(t); } + friend std::ostream& operator<<(std::ostream& s, const boundingBox& bb) + { + s << bb._lfb << " - " << bb._rbt; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _swap(boundingBox& bb); + void _assign(const boundingBox& bb); + + ////////////////// + // Data Members // + ////////////////// + vec3d _lfb, _rbt; +}; + + +#endif /* _BOUNDINGBOX_H_ */ diff --git a/hw3/include/brdf_base.h b/hw3/include/brdf_base.h new file mode 100644 index 0000000..e0d8009 --- /dev/null +++ b/hw3/include/brdf_base.h @@ -0,0 +1,47 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _BRDF_BASE_H_ +#define _BRDF_BASE_H_ + +#include +#include "vec3d.h" +#include "color.h" + +class brdf_base { + public: + ///////////// + // Methods // + ///////////// + + // Note: 'in' and 'out' point away from the surface point + // Note: 'in' and 'out' are specified in the local shading frame, + // where the normal=(0.0, 0.0, 1.0). + virtual color shade(const vec3d& in, const vec3d& out) const = 0; + + // returns true if BRDF has a specular/diffuse component + virtual bool isSpecular(void) const = 0; + virtual bool isDiffuse(void) const = 0; + + ///////////// + // Friends // + ///////////// + friend std::ostream& operator<<(std::ostream& s, const brdf_base& b) + { + b._print(s); + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + virtual void _print(std::ostream& s) const = 0; +}; + +#endif /* _BRDF_BASE_H_ */ diff --git a/hw3/include/camera.h b/hw3/include/camera.h new file mode 100644 index 0000000..9e3be04 --- /dev/null +++ b/hw3/include/camera.h @@ -0,0 +1,80 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + +#include + +#include "ray.h" +#include "vec2d.h" +#include "boundingBox.h" + +/**************************************************************/ +/* Note: Field of View (fov) is expressed in degrees, and */ +/* represents the angular spread in the horizontal direction. */ +/**************************************************************/ +class camera { + public: + ///////////////// + // Constructor // + ///////////////// + camera(void); + camera(const vec3d& eye, const vec3d& viewDirection, const vec3d& up, float fov, size_t xres, size_t yres); + camera(const camera& cam); + + /////////////// + // Operators // + /////////////// + camera& operator=(const camera& cam); + + ray operator()(float x, float y) const; + + //////////////// + // Inspectors // + //////////////// + size_t width(void) const { return _width; } + size_t height(void) const { return _height; } + + ////////////// + // Mutators // + ////////////// + void frameBoundingBox(const boundingBox& bb); + + ///////////// + // Friends // + ///////////// + friend void swap(camera& a, camera& b) { a._swap(b); } + friend std::ostream& operator<<(std::ostream& s, const camera& cam) + { + s << "Camera: {"; + s << "eye=" << cam._eye << ", "; + s << "view=" << cam._view << ", "; + s << "up=" << cam._up << "}, "; + s << "fov=" << cam._fov << ", "; + s << "resolution=[" << cam._width << "x" << cam._height << "]"; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _swap(camera& cam); + void _assign(const camera& cam); + + ////////////////// + // Data Members // + ////////////////// + vec3d _eye, _view, _up; + float _fov; + size_t _width, _height; +}; + +#endif /* _CAMERA_H_ */ + diff --git a/hw3/include/color.h b/hw3/include/color.h new file mode 100644 index 0000000..b2ca490 --- /dev/null +++ b/hw3/include/color.h @@ -0,0 +1,105 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _COLOR_H_ +#define _COLOR_H_ + +#include + +class color { + public: + ///////////// + // Typedef // + ///////////// + typedef float value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + ////////////////// + // Data Members // + ////////////////// + union { + struct { value_type r, g, b; }; + struct { value_type red, green, blue; }; + value_type data[3]; + }; + + public: + ///////////////// + // Constructor // + ///////////////// + explicit color(const_reference value=0.0f); + color(const_reference r, const_reference g, const_reference b); + color(const color& col); + + //////////////// + // Inspectors // + //////////////// + const_reference operator[](size_t index) const; + reference operator[](size_t index); + + size_t size(void) const { return 3; } + + iterator begin(void); + const_iterator begin(void) const; + iterator end(void); + const_iterator end(void) const; + + /////////////// + // Operators // + /////////////// + color& operator=(const color& col); + + bool operator==(const color& col) const; + bool operator!=(const color& col) const; + + color operator+(const color& col) const; + color operator-(const color& col) const; + color operator*(const color& col) const; + color operator*(const_reference scale) const; + color operator/(const color& col) const; + color operator/(const_reference scale) const; + + color& operator+=(const color& col); + color& operator-=(const color& col); + color& operator*=(const color& col); + color& operator*=(const_reference scale); + color& operator/=(const color& col); + color& operator/=(const_reference scale); + + /////////////// + // Modifiers // + /////////////// + color& abs(void); + color& clamp(const_reference lowerBound=0.0f, const_reference upperBounds=1.0f); + + ///////////// + // Friends // + ///////////// + friend void swap(color& a, color& b) { return a._swap(b); } + friend color abs(const color& c) { return color(c).abs(); } + friend color clamp(const color& c, const_reference lowerBound=0.0f, const_reference upperBound=1.0f) { return color(c).clamp(lowerBound, upperBound); } + friend color operator*(const_reference scale, const color& col) { return (col*scale); } + + friend std::ostream& operator<<(std::ostream& s, const color& col) + { + s << "(" << col.r << "," << col.g << "," << col.b << ")"; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const color& col); + void _swap(color& col); +}; + +#endif /* _COLOR_H_ */ diff --git a/hw3/include/compoundShader.h b/hw3/include/compoundShader.h new file mode 100644 index 0000000..293e7d6 --- /dev/null +++ b/hw3/include/compoundShader.h @@ -0,0 +1,51 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _COMPOUND_SHADER_H_ +#define _COMPOUND_SHADER_H_ + +#include +#include + +#include "shader_base.h" + +class compoundShader : public shader_base { + public: + ////////////////// + // Constructors // + ////////////////// + compoundShader(const std::vector>& shader_list); + compoundShader(const compoundShader&) = delete; + + /////////////// + // Operators // + /////////////// + compoundShader& operator=(const compoundShader&) = delete; + + ///////////// + // Methods // + ///////////// + virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const override; + + virtual shaderProperties properties(const intersectionPoint& ip) const override; + + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual void _print(std::ostream& s) const override; + + private: + ////////////////// + // Data Members // + ////////////////// + std::vector> _compound; +}; + +#endif /* _COMPOUND_SHADER_H_ */ diff --git a/hw3/include/constants.h b/hw3/include/constants.h new file mode 100644 index 0000000..daa1c45 --- /dev/null +++ b/hw3/include/constants.h @@ -0,0 +1,16 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _CONSTANTS_H_ +#define _CONSTANTS_H_ + +static const float EPSILON = 10e-6; +static const float LARGE = 10e10; +static const float PI = 3.14159265359; + +#endif /* _CONSTANTS_H_ */ diff --git a/hw3/include/coordinateTransform.h b/hw3/include/coordinateTransform.h new file mode 100644 index 0000000..008cba7 --- /dev/null +++ b/hw3/include/coordinateTransform.h @@ -0,0 +1,31 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _COORDINATETRANSFORMATION3D_H_ +#define _COORDINATETRANSFORMATION3D_H_ + +#include "transformation3d.h" + +/////////////////////////////////////////////// +// Transformation between coordinate systems // +// forward transform: from local to global // +// inverse transform: from global to local // +/////////////////////////////////////////////// +class coordinateTransformation : public transformation3d { + public: + ////////////////// + // Constructors // + ////////////////// + coordinateTransformation(void); + coordinateTransformation(const vec3d& normal); + coordinateTransformation(const vec3d& normal, const vec3d& other); + coordinateTransformation(const vec3d& X, const vec3d& Y, const vec3d& Z); +}; + +#endif /* _COORDINATETRANSFORMATION3D_H_ */ + diff --git a/hw3/include/diffuseBrdf.h b/hw3/include/diffuseBrdf.h new file mode 100644 index 0000000..e4ab19f --- /dev/null +++ b/hw3/include/diffuseBrdf.h @@ -0,0 +1,59 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _DIFFUSEBRDF_H_ +#define _DIFFUSEBRDF_H_ + +#include "brdf_base.h" + +class diffuseBrdf : public brdf_base { + public: + ////////////////// + // Constructors // + ////////////////// + diffuseBrdf(const color& albedo); + diffuseBrdf(const diffuseBrdf& src); + + /////////////// + // Operators // + /////////////// + diffuseBrdf& operator=(const diffuseBrdf& src); + + ///////////// + // Methods // + ///////////// + virtual color shade(const vec3d& in, const vec3d& out) const final override; + + virtual bool isSpecular(void) const final override; + virtual bool isDiffuse(void) const final override; + + ///////////// + // Friends // + ///////////// + friend void swap(diffuseBrdf& a, diffuseBrdf& b) { a._swap(b); } + friend std::ostream& operator<<(std::ostream& s, const diffuseBrdf& b) + { + b._print(s); + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const diffuseBrdf& src); + void _swap(diffuseBrdf& src); + virtual void _print(std::ostream& s) const override; + + ////////////////// + // Data Members // + ////////////////// + color _albedo; +}; + +#endif /* _DIFFUSEBRDF_H_ */ diff --git a/hw3/include/diffuseReflectanceShader.h b/hw3/include/diffuseReflectanceShader.h new file mode 100644 index 0000000..bee9d8d --- /dev/null +++ b/hw3/include/diffuseReflectanceShader.h @@ -0,0 +1,45 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _DIFFUSEREFLECTANCESHADER_H_ +#define _DIFFUSEREFLECTANCESHADER_H_ + +#include "diffuseBrdf.h" +#include "reflectanceParameter.h" +#include "reflectanceShader_base.h" + +class diffuseReflectanceShader : public reflectanceShader_base { + public: + ///////////////// + // Constructor // + ///////////////// + diffuseReflectanceShader(const colorReflectanceParameter& albedo=colorReflectanceParameter(color(1.0f, 1.0f, 1.0f))); + diffuseReflectanceShader(const diffuseReflectanceShader& ) = delete; + + /////////////// + // Operators // + /////////////// + diffuseReflectanceShader& operator=(const diffuseReflectanceShader&) = delete; + +protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual std::unique_ptr make_brdf(const vec2d& textureCoord) const override; + + virtual void _print(std::ostream& s) const override; + +private: + ////////////////// + // Data Members // + ////////////////// + colorReflectanceParameter _albedo; +}; + +#endif /* _DIFFUSEREFLECTANCESHADER_H_ */ + diff --git a/hw3/include/directionalLightsource.h b/hw3/include/directionalLightsource.h new file mode 100644 index 0000000..b33dfaf --- /dev/null +++ b/hw3/include/directionalLightsource.h @@ -0,0 +1,55 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _DIRECTIONALLIGHTSOURCE_H_ +#define _DIRECTIONALLIGHTSOURCE_H_ + +#include "lightsource_base.h" + +class directionalLightsource : public lightsource_base { + public: + ////////////////// + // Constructors // + ////////////////// + directionalLightsource(const vec3d& direction=vec3d(0.0f, 0.0f, 1.0f), const color& power=color(1.0f, 1.0f, 1.0f)); + directionalLightsource(const directionalLightsource&) = delete; + + /////////////// + // Operators // + /////////////// + directionalLightsource& operator=(const directionalLightsource&) = delete; + + ///////////// + // Methods // + ///////////// + virtual lightSample intensityAt(const vec3d& point) const override; + + ///////////// + // Friends // + ///////////// + friend std::ostream& operator<<(std::ostream& s, const directionalLightsource& d) + { + d._print(s); + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + virtual void _print(std::ostream& s) const override; + + private: + ////////////////// + // Data Members // + ////////////////// + vec3d _direction; + color _power; +}; + +#endif /* _DIRECTIONALLIGHTSOURCE_H_ */ diff --git a/hw3/include/errorMessage.h b/hw3/include/errorMessage.h new file mode 100644 index 0000000..7ec99d1 --- /dev/null +++ b/hw3/include/errorMessage.h @@ -0,0 +1,17 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _ERROR_MESSAGE_H_ +#define _ERROR_MESSAGE_H_ + +#include + +void errorMessage(const char* msg, ...); +void warningMessage(const char* msg, ...); + +#endif /* _ERROR_MESSAGE_H_ */ diff --git a/hw3/include/image.h b/hw3/include/image.h new file mode 100644 index 0000000..938e6c0 --- /dev/null +++ b/hw3/include/image.h @@ -0,0 +1,89 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + +#include +#include +#include + +#include "color.h" + +class image { + public: + ////////////// + // Typedefs // + ////////////// + typedef color value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::unique_ptr::pointer iterator; + typedef std::unique_ptr::pointer const_iterator; + typedef size_t difference_type; + typedef size_t size_type; + + ////////////////// + // Constructors // + ////////////////// + image(size_type width=0, size_type height=0); + image(size_type width, size_type height, const_reference col); + image(const image& src); + image(image&& src); + + virtual ~image(void) { _data.reset(); } + + //////////////// + // Inspectors // + //////////////// + iterator begin(void); + const_iterator begin(void) const; + + iterator end(void); + const_iterator end(void) const; + + size_type size(void) const { return width()*height(); } + size_type width(void) const { return _width; } + size_type height(void) const { return _height; } + + + /////////////// + // Operators // + /////////////// + image& operator=(const image& src); + image& operator=(image&& src); + + reference operator()(size_type x, size_type y); + const_reference operator()(size_type x, size_type y) const; + + ///////////// + // Friends // + ///////////// + friend void swap(image& a, image& b) { a._swap(b); } + friend std::ostream& operator<<(std::ostream& s, const image& img) + { + s << "Image: (" << img.width() << ", " << img.height() << ")"; + return s; + } + +protected: + ///////////////////// + // Private Methods // + ///////////////////// + void _swap(image& img); + void _assign(const image& src); + +private: + ////////////////////////// + // Private Data Members // + ////////////////////////// + size_type _width, _height; + std::unique_ptr _data; +}; + +#endif /* _IMAGE_H_ */ diff --git a/hw3/include/imageIO.h b/hw3/include/imageIO.h new file mode 100644 index 0000000..9e1ecfa --- /dev/null +++ b/hw3/include/imageIO.h @@ -0,0 +1,19 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _IMAGEIO_H_ +#define _IMAGEIO_H_ + +#include +#include "image.h" + +void importImage(const std::string& name, image& img); +void exportImage(const std::string& name, const image& img); + +#endif /* _IMAGEIO_H_ */ + diff --git a/hw3/include/imageIO.pfm.h b/hw3/include/imageIO.pfm.h new file mode 100644 index 0000000..d09531a --- /dev/null +++ b/hw3/include/imageIO.pfm.h @@ -0,0 +1,18 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _IMAGEIO_PFM_H_ +#define _IMAGEIO_PFM_H_ + +#include +#include "image.h" + +void importPFM(const std::string& name, image& img); +void exportPFM(const std::string& name, const image& img); + +#endif /* _IMAGEIO_PFM_H_ */ diff --git a/hw3/include/imageIO.ppm.h b/hw3/include/imageIO.ppm.h new file mode 100644 index 0000000..7a8db42 --- /dev/null +++ b/hw3/include/imageIO.ppm.h @@ -0,0 +1,18 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _IMAGEIO_PPM_H_ +#define _IMAGEIO_PPM_H_ + +#include +#include "image.h" + +void importPPM(const std::string& name, image& img); +void exportPPM(const std::string& name, const image& img); + +#endif /* _IMAGEIO_PPM_H_ */ diff --git a/hw3/include/importOBJ.h b/hw3/include/importOBJ.h new file mode 100644 index 0000000..056a420 --- /dev/null +++ b/hw3/include/importOBJ.h @@ -0,0 +1,18 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _IMPORTOBJ_H_ +#define _IMPORTOBJ_H_ + +#include +#include +#include "triangle.h" + +void importOBJ(const std::string filename, std::vector& triangle_list); + +#endif /* _IMPORTOBJ_H_ */ diff --git a/hw3/include/intersectionPoint.h b/hw3/include/intersectionPoint.h new file mode 100644 index 0000000..a4d8888 --- /dev/null +++ b/hw3/include/intersectionPoint.h @@ -0,0 +1,110 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _INTERSECTIONPOINT_H_ +#define _INTERSECTIONPOINT_H_ + +#include +#include + +#include "ray.h" +#include "vec3d.h" +#include "vec2d.h" +#include "color.h" +#include "constants.h" +#include "lightSample.h" +#include "transformation3d.h" +#include "shaderProperties.h" +#include "coordinateTransform.h" + + +class intersectionPoint +{ + public: + ///////////////// + // Constructor // + ///////////////// + intersectionPoint(void); + intersectionPoint(const ray& r, float rayParameter=+LARGE, const std::shared_ptr& shader=nullptr, const vec3d& normal=vec3d(0.0f, 0.0f, 1.0f), const vec3d& U=vec3d(1.0f, 0.0f, 0.0f), const vec2d& textureCoordinate=vec2d(0.0f, 0.0f)); + intersectionPoint(const intersectionPoint& ip); + + /////////////// + // Operators // + /////////////// + intersectionPoint& operator=(const intersectionPoint& ip); + + bool operator<(const intersectionPoint& ip) const; + bool operator>(const intersectionPoint& ip) const; + bool operator<(const lightSample& ls) const; + bool operator>(const lightSample& ls) const; + + //////////////// + // Inspectors // + //////////////// + bool isHit(void) const; + bool hasShader(void) const; + shaderProperties getShaderProperties(void) const; + float distance(const intersectionPoint& ip) const; + const vec3d& position(void) const; + const vec3d& direction(void) const; + const vec2d& textureCoordinate(void) const; + const vec3d& normal(void) const; + coordinateTransformation shadingFrame(void) const; + + ////////////// + // Mutators // + ////////////// + void transform(const transformation3d& t); + void inverseTransform(const transformation3d& t); + + void transformShadingFrame(const transformation3d& sft); + void inverseTransformShadingFrame(const transformation3d& sft); + + void setShader(const std::shared_ptr& shader); + + ///////////// + // Methods // + ///////////// + color shade(const vec3d& out) const; + color shade(const lightSample& ls) const; + + ///////////// + // Friends // + ///////////// + friend void swap(intersectionPoint& a, intersectionPoint& b) { a._swap(b); } + + friend bool operator<(const lightSample& ls, const intersectionPoint& ip) { return (ip > ls); } + friend bool operator>(const lightSample& ls, const intersectionPoint& ip) { return (ip < ls); } + + friend std::ostream& operator<<(std::ostream& s, const intersectionPoint& ip) + { + if(ip._hit) s << "IntersectionPoint: ray=" << ip._ray << ", position=" << ip._position << " (parameter=" << ip._rayParameter << ", normal=" << ip._normal << ", shading axis=" << ip._U << ", texture coordinate=" << ip._textureCoordinate; + else s << "IntersectionPoint: empty"; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const intersectionPoint& ip); + void _swap(intersectionPoint& ip); + + ////////////////// + // Data Members // + ////////////////// + ray _ray; + bool _hit; + float _rayParameter; + vec3d _position; + vec3d _normal, _U; + vec2d _textureCoordinate; + std::shared_ptr _shader; +}; + +#endif /* _INTERSECTIONPOINT_H_ */ diff --git a/hw3/include/intersector_base.h b/hw3/include/intersector_base.h new file mode 100644 index 0000000..64fb05e --- /dev/null +++ b/hw3/include/intersector_base.h @@ -0,0 +1,34 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _INTERSECTOR_BASE_H_ +#define _INTERSECTOR_BASE_H_ + +#include "ray.h" +#include "intersectionPoint.h" + +class intersector_base { + public: + ////////////////// + // Constructors // + ////////////////// + intersector_base(void) {} + intersector_base(const intersector_base&) = delete; + + /////////////// + // Operators // + /////////////// + intersector_base& operator=(const intersector_base&) = delete; + + ///////////// + // Methods // + ///////////// + virtual intersectionPoint intersect(const ray& r) const = 0; +}; + +#endif /* _INTERSECTOR_BASE_H_ */ diff --git a/hw3/include/intersector_factory_base.h b/hw3/include/intersector_factory_base.h new file mode 100644 index 0000000..c6e9e98 --- /dev/null +++ b/hw3/include/intersector_factory_base.h @@ -0,0 +1,29 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _INTERSECTOR_FACTORY_BASE_H_ +#define _INTERSECTOR_FACTORY_BASE_H_ + +#include +#include "boundedCompound.h" +#include "intersector_base.h" + +class intersector_factory_base { +public: + ///////////////// + // Constructor // + ///////////////// + intersector_factory_base(void) {} + + ////////////// + // Operator // + ////////////// + virtual std::unique_ptr operator()(const boundedCompound& bc) const = 0; +}; + +#endif /* _INTERSECTOR_FACTORY_BASE_H_ */ diff --git a/hw3/include/interval.h b/hw3/include/interval.h new file mode 100644 index 0000000..ccb720a --- /dev/null +++ b/hw3/include/interval.h @@ -0,0 +1,77 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _INTERVAL_H_ +#define _INTERVAL_H_ + +#include + +#include "constants.h" + +class interval +{ + public: + ////////////////// + // Constrructor // + ////////////////// + interval(float lower=-LARGE, float upper=+LARGE); + interval(const interval& i); + + /////////////// + // Operators // + /////////////// + interval& operator=(const interval& i); + + interval operator+(float v) const; + interval operator-(float v) const; + interval operator*(float v) const; + interval operator/(float v) const; + + interval& operator+=(float v); + interval& operator-=(float v); + interval& operator*=(float v); + interval& operator/=(float v); + + //////////////// + // Inspectors // + //////////////// + float lower(void) const; + float upper(void) const; + + bool empty(void) const; + + ////////////// + // Mutators // + ////////////// + void intersect(const interval& i); + + ///////////// + // Friends // + ///////////// + friend void swap(interval& a, interval& b) { a._swap(b); } + + friend std::ostream& operator<<(std::ostream& s, const interval& i) + { + s << "[" << i.lower() << ", " << i.upper() << "]"; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const interval& i); + void _swap(interval& i); + + ////////////////////////// + // Private Data Members // + ////////////////////////// + float _lower, _upper; +}; + +#endif /* _INTERVAL_H_ */ diff --git a/hw3/include/lightSample.h b/hw3/include/lightSample.h new file mode 100644 index 0000000..3dd76b5 --- /dev/null +++ b/hw3/include/lightSample.h @@ -0,0 +1,75 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _LIGHTSAMPLE_H_ +#define _LIGHTSAMPLE_H_ + +#include "vec3d.h" +#include "color.h" +#include "constants.h" + +class lightSample { + public: + ////////////////// + // Constructors // + ////////////////// + lightSample(const vec3d& direction=vec3d(0.0f, 0.0f, 0.0f), + const color& emittance=color(0.0f, 0.0f, 0.0f), + float distance=+LARGE, + float pdf=1.0f, + float foreshortening=1.0f); + + lightSample(const lightSample& ls); + + /////////////// + // Operators // + /////////////// + lightSample& operator=(const lightSample& ls); + + const color& operator()(void) const; + + //////////////// + // Inspectors // + //////////////// + const vec3d& directionToPoint(void) const; + vec3d directionToLight(void) const; + + const color& emittance(void) const; + float distance(void) const; + + float pdf(void) const; + float foreshortening(void) const; + + ///////////// + // Friends // + ///////////// + friend void swap(lightSample& a, lightSample& b) { a._swap(b); } + friend std::ostream& operator<<(std::ostream& s, const lightSample& ls) + { + s << "LightSample: direction=" << ls.directionToPoint() << ", emittance=" << ls() << ", distance=" << ls.distance() << ", pdf=" << ls.pdf() << ", foreshortening=" << ls.foreshortening(); + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const lightSample& ls); + void _swap(lightSample& ls); + + ////////////////// + // Data Members // + ////////////////// + vec3d _direction; + color _emittance; + float _distance; + float _pdf; + float _foreshortening; +}; + +#endif /* _LIGHTSAMPLE_H_ */ diff --git a/hw3/include/lightsource_base.h b/hw3/include/lightsource_base.h new file mode 100644 index 0000000..0a2f0df --- /dev/null +++ b/hw3/include/lightsource_base.h @@ -0,0 +1,51 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _LIGHTSOURCE_BASE_H_ +#define _LIGHTSOURCE_BASE_H_ + +#include + +#include "vec3d.h" +#include "lightSample.h" + +class lightsource_base { + public: + ////////////////// + // Constructors // + ////////////////// + lightsource_base(void) {} + lightsource_base(const lightsource_base&) = delete; + + /////////////// + // Operators // + /////////////// + lightsource_base& operator=(const lightsource_base&) = delete; + + ///////////// + // Methods // + ///////////// + virtual lightSample intensityAt(const vec3d& point) const = 0; + + ///////////// + // Friends // + ///////////// + friend std::ostream& operator<<(std::ostream& s, const lightsource_base& lsb) + { + lsb._print(s); + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + virtual void _print(std::ostream& s) const = 0; +}; + +#endif /* _LIGHTSOURCE_BASE_H_ */ diff --git a/hw3/include/linear_intersector.h b/hw3/include/linear_intersector.h new file mode 100644 index 0000000..221e5fe --- /dev/null +++ b/hw3/include/linear_intersector.h @@ -0,0 +1,62 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _LINEAR_INTERSECTOR_H_ +#define _LINEAR_INTERSECTOR_H_ + +#include + +#include "boundedPrimitive.h" +#include "intersector_base.h" +#include "intersector_factory_base.h" + +class linear_intersector : public intersector_base { + public: + ////////////////// + // Constructors // + ////////////////// + linear_intersector(void); + linear_intersector(const std::vector>& compounds); + linear_intersector(const linear_intersector&) = delete; + + /////////////// + // Operators // + /////////////// + linear_intersector& operator=(const linear_intersector&) = delete; + + ///////////// + // Methods // + ///////////// + virtual intersectionPoint intersect(const ray& r) const final override; + + private: + ////////////////// + // Data Members // + ////////////////// + std::vector> _compounds; +}; + + +class linear_intersector_factory : public intersector_factory_base { + public: + ///////////////// + // Constructor // + ///////////////// + linear_intersector_factory(void) {} + + /////////////// + // Operators // + /////////////// + std::unique_ptr operator()(const boundedCompound& boundedCompound) const final override + { + return std::unique_ptr(new linear_intersector(boundedCompound.compounds())); + } +}; + +#endif /* _LINEAR_INTERSECTOR_H_ */ + diff --git a/hw3/include/mat3d.h b/hw3/include/mat3d.h new file mode 100644 index 0000000..e70ece4 --- /dev/null +++ b/hw3/include/mat3d.h @@ -0,0 +1,112 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _MAT3D_H_ +#define _MAT3D_H_ + +#include +#include + +#include "vec3d.h" + +class mat3d { + public: + ///////////// + // Typedef // + ///////////// + typedef float value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::array::iterator iterator; + typedef std::array::const_iterator const_iterator; + typedef std::size_t difference; + typedef std::size_t size_type; + + ///////////////// + // Constructor // + ///////////////// + mat3d(void); // all elements are set to 0 + explicit mat3d(value_type diag); // all elements are set to 0, the diagonal elements are set to 'diag' + mat3d(const vec3d& X, const vec3d& Y, const vec3d& Z); // set columns to X, Y, and Z + mat3d(const mat3d& m); // copy constructor + + //////////////// + // Inspectors // + //////////////// + static size_type width(void) { return 3; } + static size_type height(void) { return 3; } + static size_type size(void) { return 9; } + + iterator begin(void); + const_iterator begin(void) const; + iterator end(void); + const_iterator end(void) const; + + ////////////// + // Mutators // + ////////////// + void clear(value_type value=0.0f); + void setDiagonal(value_type value=1.0f); + + mat3d& transpose(void); + + /////////////// + // Operators // + /////////////// + mat3d& operator=(const mat3d& m); + + reference operator()(size_type row, size_type col); + const_reference operator()(size_type row, size_type col) const; + + mat3d operator+(const mat3d& m) const; + mat3d operator-(const mat3d& m) const; + mat3d operator*(const mat3d& m) const; + vec3d operator*(const vec3d& v) const; + mat3d operator*(value_type scale) const; + mat3d operator/(value_type scale) const; + + mat3d& operator+=(const mat3d& m); + mat3d& operator-=(const mat3d& m); + mat3d& operator*=(const mat3d& m); + mat3d& operator*=(value_type scale); + mat3d& operator/=(value_type scale); + + ///////////// + // Friends // + ///////////// + friend void swap(mat3d& a, mat3d& b) { a._swap(b); } + + friend vec3d operator*(const vec3d& v, const mat3d& m) { return m._premultiply(v); } + friend mat3d operator*(value_type scale, const mat3d& m) { return (m * scale); } + + friend mat3d transpose(mat3d& m) { mat3d n(m); return n.transpose(); } + + friend std::ostream& operator<<(std::ostream& s, const mat3d& m) + { + s << "[[" << m(0,0) << ", " << m(0,1) << ", " << m(0,2) << "],["; + s << m(1,0) << ", " << m(1,1) << ", " << m(1,2) << "],["; + s << m(2,0) << ", " << m(2,1) << ", " << m(2,2) << "]]"; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _swap(mat3d& m); + void _assign(const mat3d& m); + + vec3d _premultiply(const vec3d& v) const; + + ////////////////////////// + // Private Data Members // + ////////////////////////// + std::array _data; +}; + +#endif /* _MAT3D_H_ */ diff --git a/hw3/include/phongBrdf.h b/hw3/include/phongBrdf.h new file mode 100644 index 0000000..588efa2 --- /dev/null +++ b/hw3/include/phongBrdf.h @@ -0,0 +1,60 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _PHONGBRDF_H_ +#define _PHONGBRDF_H_ + +#include "brdf_base.h" + +class phongBrdf : public brdf_base { + public: + ////////////////// + // Constructors // + ////////////////// + phongBrdf(const color& albedo, float sharpness); + phongBrdf(const phongBrdf& src); + + /////////////// + // Operators // + /////////////// + phongBrdf& operator=(const phongBrdf& src); + + ///////////// + // Methods // + ///////////// + virtual color shade(const vec3d& in, const vec3d& out) const override; + + virtual bool isSpecular(void) const final override; + virtual bool isDiffuse(void) const final override; + + ///////////// + // Friends // + ///////////// + friend void swap(phongBrdf& a, phongBrdf& b) { a._swap(b); } + friend std::ostream& operator<<(std::ostream& s, const phongBrdf& b) + { + b._print(s); + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const phongBrdf& src); + void _swap(phongBrdf& src); + virtual void _print(std::ostream& s) const override; + + ////////////////// + // Data Members // + ////////////////// + color _albedo; + float _sharpness; +}; + +#endif /* _PHONGBRDF_H_ */ diff --git a/hw3/include/phongReflectanceShader.h b/hw3/include/phongReflectanceShader.h new file mode 100644 index 0000000..13291f2 --- /dev/null +++ b/hw3/include/phongReflectanceShader.h @@ -0,0 +1,46 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _PHONGREFLECTANCESHADER_H_ +#define _PHONGREFLECTANCESHADER_H_ + +#include "phongBrdf.h" +#include "reflectanceParameter.h" +#include "reflectanceShader_base.h" + +class phongReflectanceShader : public reflectanceShader_base { + public: + ///////////////// + // Constructor // + ///////////////// + phongReflectanceShader(const colorReflectanceParameter& albedo=colorReflectanceParameter(color(1.0f, 1.0f, 1.0f)), const scalarReflectanceParameter& sharpness=20.0f); + phongReflectanceShader(const phongReflectanceShader& ) = delete; + + /////////////// + // Operators // + /////////////// + phongReflectanceShader& operator=(const phongReflectanceShader&) = delete; + +protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual void _print(std::ostream& s) const override; + + virtual std::unique_ptr make_brdf(const vec2d& textureCoord) const override; + +private: + ////////////////// + // Data Members // + ////////////////// + colorReflectanceParameter _albedo; + scalarReflectanceParameter _sharpness; +}; + +#endif /* _PHONGREFLECTANCESHADER_H_ */ + diff --git a/hw3/include/random_number.h b/hw3/include/random_number.h new file mode 100644 index 0000000..328de25 --- /dev/null +++ b/hw3/include/random_number.h @@ -0,0 +1,50 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _RANDOM_NUMBER_H_ +#define _RANDOM_NUMBER_H_ + +#include +#include "vec3d.h" +#include "constants.h" +#include "coordinateTransform.h" + +static std::random_device rd; +static std::mt19937 rnd; + +static unsigned int random_int(unsigned int up=std::numeric_limits::max()) +{ + std::uniform_int_distribution dist(0, up); + return dist(rnd); +} + + +static float random_float(float up=1.0f) +{ + std::uniform_real_distribution dist(0, up); + return dist(rnd); +} + + +static vec3d random_direction(const vec3d& normal, float r1=random_float(), float r2=random_float()) +{ + // generate in standard coordinate system (i.e., Z=(0,0,1)) + vec3d out(cos(2.0f*PI*r1) * sqrt(std::max(1.0f-r2*r2, 0.0f)), + sin(2.0f*PI*r1) * sqrt(std::max(1.0f-r2*r2, 0.0f)), + r2); + + // transform to global coordinates + coordinateTransformation trans(normal); + out = trans.transformDirection(out); + + // Done (PDF = 1/(2.0f*PI)) + return out; +} + + +#endif /* _RANDOM_NUMBER_H_ */ diff --git a/hw3/include/ray.h b/hw3/include/ray.h new file mode 100644 index 0000000..743375f --- /dev/null +++ b/hw3/include/ray.h @@ -0,0 +1,69 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _RAY_H_ +#define _RAY_H_ + +#include +#include "vec3d.h" +#include "transformation3d.h" + +class ray { + public: + ////////////////// + // Constructors // + ////////////////// + ray(const vec3d& origin = vec3d(), const vec3d& direction = vec3d()); + ray(const ray& src); + + //////////////// + // Inspectors // + //////////////// + const vec3d& origin(void) const { return _origin; } + const vec3d& direction(void) const { return _direction; } + + /////////////// + // Operators // + /////////////// + ray& operator=(const ray& r); + vec3d operator()(float t) const; + float operator()(const vec3d& point) const; + + ////////////// + // Mutators // + ////////////// + ray& transform(const transformation3d& t); + ray& inverseTransform(const transformation3d& t); + + ///////////// + // Friends // + ///////////// + friend void swap(ray& a, ray& b) { a._swap(b); } + friend ray transform(const ray& r, const transformation3d& t) { return ray(r).transform(t); } + friend ray inverseTransform(const ray& r, const transformation3d& t) { return ray(r).inverseTransform(t); } + friend std::ostream& operator<<(std::ostream& s, const ray& r) + { + s << r.origin() << "->" << r.direction(); + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _swap(ray& r); + void _assign(const ray& r); + + ////////////////// + // Data Members // + ////////////////// + vec3d _origin; + vec3d _direction; +}; + +#endif /* _RAY_H_ */ diff --git a/hw3/include/reflectanceParameter.h b/hw3/include/reflectanceParameter.h new file mode 100644 index 0000000..c924653 --- /dev/null +++ b/hw3/include/reflectanceParameter.h @@ -0,0 +1,106 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _REFLECTANCEPARAMETER_H_ +#define _REFLECTANCEPARAMETER_H_ + +#include +#include + +#include "vec2d.h" +#include "vec3d.h" +#include "color.h" +#include "texture_base.h" + +class scalarReflectanceParameter { + public: + ///////////////// + // Constructor // + ///////////////// + scalarReflectanceParameter(float value=0.0f); + scalarReflectanceParameter(const std::shared_ptr& texture, unsigned int channel=0); + scalarReflectanceParameter(const scalarReflectanceParameter& src); + + ////////////// + // Operator // + ////////////// + scalarReflectanceParameter& operator=(const scalarReflectanceParameter& src); + + float operator()(const vec2d& textureCoord) const; + + ///////////// + // Friends // + ///////////// + friend void swap(scalarReflectanceParameter& a, scalarReflectanceParameter& b) { a._swap(b); } + + friend std::ostream& operator<<(std::ostream& s, const scalarReflectanceParameter& param) + { + if(param._texture) s << param._texture << "(channel=" << param._channel << ")"; + else s << param._value; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const scalarReflectanceParameter& src); + void _swap(scalarReflectanceParameter& swp); + + ////////////////// + // Data Members // + ////////////////// + float _value; + unsigned int _channel; + std::shared_ptr _texture; +}; + + +class colorReflectanceParameter { + public: + ///////////////// + // Constructor // + ///////////////// + colorReflectanceParameter(color value=color(0.0f)); + colorReflectanceParameter(const std::shared_ptr& texture); + colorReflectanceParameter(const colorReflectanceParameter& src); + + ////////////// + // Operator // + ////////////// + colorReflectanceParameter& operator=(const colorReflectanceParameter& src); + + color operator()(const vec2d& textureCoord) const; + + ///////////// + // Friends // + ///////////// + friend void swap(colorReflectanceParameter& a, colorReflectanceParameter& b) { a._swap(b); } + + friend std::ostream& operator<<(std::ostream& s, const colorReflectanceParameter& param) + { + if(param._texture) s << param._texture; + else s << param._value; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const colorReflectanceParameter& src); + void _swap(colorReflectanceParameter& swp); + + ////////////////// + // Data Members // + ////////////////// + color _value; + std::shared_ptr _texture; +}; + +#endif /* _REFLECTANCEPARAMETER_BASE_H_ */ diff --git a/hw3/include/reflectanceShader_base.h b/hw3/include/reflectanceShader_base.h new file mode 100644 index 0000000..ad91137 --- /dev/null +++ b/hw3/include/reflectanceShader_base.h @@ -0,0 +1,45 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _REFLECTANCESHADER_BASE_H_ +#define _REFLECTANCESHADER_BASE_H_ + +#include +#include "brdf_base.h" +#include "shader_base.h" + +class reflectanceShader_base : public shader_base { + public: + ////////////////// + // Constructors // + ////////////////// + reflectanceShader_base(void) {} + reflectanceShader_base(const reflectanceShader_base&) = delete; + + /////////////// + // Operators // + /////////////// + reflectanceShader_base& operator=(const reflectanceShader_base&) = delete; + + ///////////// + // Methods // + ///////////// + virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const final override; + + virtual shaderProperties properties(const intersectionPoint& ip) const final override; + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual void _print(std::ostream& s) const = 0; + + virtual std::unique_ptr make_brdf(const vec2d& textureCoord) const = 0; +}; + +#endif /* _REFLECTANCE_SHADER_BASE_H_ */ diff --git a/hw3/include/scene.h b/hw3/include/scene.h new file mode 100644 index 0000000..ee3e416 --- /dev/null +++ b/hw3/include/scene.h @@ -0,0 +1,59 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENE_H_ +#define _SCENE_H_ + +#include +#include +#include + +#include "ray.h" +#include "image.h" +#include "camera.h" +#include "boundedCompound.h" +#include "lightsource_base.h" +#include "intersectionPoint.h" + +class scene { + friend void importScene(const std::string&, scene&); + public: + ////////////////// + // Constructors // + ////////////////// + scene(void) {} + scene(const scene&) = delete; + + /////////////// + // Operators // + /////////////// + camera& operator=(const camera&) = delete; + + //////////////// + // Inspectors // + //////////////// + const camera& getCamera(void) const; + + const lightsource_base& getLightsource(size_t idx) const; + size_t numberOfLightsources(void) const; + + ///////////// + // Methods // + ///////////// + intersectionPoint intersect(const ray& r) const; + + private: + ////////////////// + // Data Members // + ////////////////// + camera _camera; + std::unique_ptr _sceneGraphRoot; + std::vector> _lightsources; +}; + +#endif /* _SCENE_H_ */ diff --git a/hw3/include/sceneGraphNode.h b/hw3/include/sceneGraphNode.h new file mode 100644 index 0000000..38e7de1 --- /dev/null +++ b/hw3/include/sceneGraphNode.h @@ -0,0 +1,45 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEGRAPHNODE_H_ +#define _SCENEGRAPHNODE_H_ + +#include +#include + +#include "shader_base.h" +#include "boundedCompound.h" +#include "transformation3d.h" + +class sceneGraphNode : public boundedCompound { + public: + ////////////////// + // Constructors // + ////////////////// + sceneGraphNode(void); + sceneGraphNode(const std::vector>& nodes, const transformation3d& transform=transformation3d(), const std::shared_ptr& shader=nullptr); + sceneGraphNode(const sceneGraphNode&) = delete; + + /////////////// + // Operators // + /////////////// + sceneGraphNode& operator=(sceneGraphNode&) = delete; + + ///////////// + // Methods // + ///////////// + virtual const std::vector>& compounds(void) const final override; + + private: + ////////////////// + // Data Members // + ////////////////// + std::vector> _nodes; +}; + +#endif /* _SCENEGRAPHNODE_H_ */ diff --git a/hw3/include/sceneIO.h b/hw3/include/sceneIO.h new file mode 100644 index 0000000..59fc6cd --- /dev/null +++ b/hw3/include/sceneIO.h @@ -0,0 +1,17 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENE_IO_H_ +#define _SCENE_IO_H_ + +#include +#include "scene.h" + +void importScene(const std::string& filename, scene& s); + +#endif /* _SCENE_IO_H_ */ diff --git a/hw3/include/sceneIO_basis.h b/hw3/include/sceneIO_basis.h new file mode 100644 index 0000000..5f67172 --- /dev/null +++ b/hw3/include/sceneIO_basis.h @@ -0,0 +1,22 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEIO_BASIS_H_ +#define _SCENEIO_BASIS_H_ + +#include +#include +#include + +#include "camera.h" +#include "intersector_factory_base.h" + +bool importCamera(const XMLNode& node, camera& cam); +void importIntersector(const XMLNode& node, std::unique_ptr& intersector); + +#endif /* _SCENEIO_BASIS_H_ */ diff --git a/hw3/include/sceneIO_cache.h b/hw3/include/sceneIO_cache.h new file mode 100644 index 0000000..3807c86 --- /dev/null +++ b/hw3/include/sceneIO_cache.h @@ -0,0 +1,52 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEIO_CACHE_H_ +#define _SCENEIO_CACHE_H_ + +#include +#include +#include +#include + +template +class nodeCache { + public: + ////////////////// + // Constructors // + ////////////////// + nodeCache(void) {} + nodeCache(const nodeCache&) = delete; + + /////////////// + // Operators // + /////////////// + nodeCache& operator=(const nodeCache& ) = delete; + + ///////////// + // Methods // + ///////////// + std::shared_ptr get(const std::string& name) const; + bool add(const std::string& name, const std::shared_ptr& node); + + std::vector> unusedNodes(unsigned int maxCount=1) const; + std::vector> allNodes(void) const; + + private: + ////////////////////////// + // Private Data Members // + ////////////////////////// + std::map> _cache; +}; + +//////////////////// +// Inline Methods // +//////////////////// +#include "sceneIO_cache.inline.h" + +#endif /* _SCENEIO_CACHE_H_ */ diff --git a/hw3/include/sceneIO_cache.inline.h b/hw3/include/sceneIO_cache.inline.h new file mode 100644 index 0000000..27d9cf0 --- /dev/null +++ b/hw3/include/sceneIO_cache.inline.h @@ -0,0 +1,66 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#if defined(_SCENEIO_CACHE_H_) && !defined(_SCENEIO_CACHE_INLINE_H_) +#define _SCENEIO_CACHE_INLINE_H_ + +#include +#include +#include + +#include "errorMessage.h" + +template +std::shared_ptr nodeCache::get(const std::string& name) const +{ + // see if node exists + auto ref_node = _cache.find(name); + + // return nullptr if not. + if(ref_node == _cache.end()) return nullptr; + + // return node. + else return ref_node->second; +} + + +template +bool nodeCache::add(const std::string& name, const std::shared_ptr& node) +{ + _cache[name] = node; +} + +template +std::vector> nodeCache::unusedNodes(unsigned int maxCount) const +{ + std::vector> result; + + // check each node if unique + for(auto itr=_cache.begin(); itr != _cache.end(); itr++) + if(itr->second.use_count() <= maxCount) + result.push_back(itr->second); + + // done. + return result; +} + + +template +std::vector> nodeCache::allNodes(void) const +{ + std::vector> result; + + // check each node if unique + for(auto itr=_cache.begin(); itr != _cache.end(); itr++) + result.push_back(itr->second); + + // done. + return result; +} + +#endif /* _SCENEIO_CACHE_INLINE_H_ */ diff --git a/hw3/include/sceneIO_core.h b/hw3/include/sceneIO_core.h new file mode 100644 index 0000000..8aa726a --- /dev/null +++ b/hw3/include/sceneIO_core.h @@ -0,0 +1,24 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEIO_CORE_H_ +#define _SCENEIO_CORE_H_ + +#include "sceneIO_xml.h" +#include "color.h" +#include "vec2d.h" +#include "vec3d.h" + +color getColor(const XMLNode& node, const std::string& name, const color& default_value=color()); +vec3d getVec3d(const XMLNode& node, const std::string& name, const vec3d& default_value=vec3d()); +vec2d getVec2d(const XMLNode& node, const std::string& name, const vec2d& default_value=vec2d()); +std::string getString(const XMLNode& node, const std::string& name, const std::string& default_value=std::string("")); +float getFloat(const XMLNode& node, const std::string& name, float default_value=0.0f); +unsigned int getInteger(const XMLNode& node, const std::string& name, unsigned int default_value=0); + +#endif /* _SCENEIO_CORE_H_ */ diff --git a/hw3/include/sceneIO_geometry.h b/hw3/include/sceneIO_geometry.h new file mode 100644 index 0000000..fc4d80b --- /dev/null +++ b/hw3/include/sceneIO_geometry.h @@ -0,0 +1,23 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEIO_GEOMETRY_H_ +#define _SCENEIO_GEOMETRY_H_ + +#include + +#include "sceneIO_xml.h" +#include "sceneIO_cache.h" + +#include "shader_base.h" +#include "texture_base.h" +#include "boundedPrimitive.h" + +std::shared_ptr importGeometry(const XMLNode& node, nodeCache& shape_cache, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir); + +#endif /* _SCENEIO_GEOMETRY_H_ */ diff --git a/hw3/include/sceneIO_light.h b/hw3/include/sceneIO_light.h new file mode 100644 index 0000000..e2745a2 --- /dev/null +++ b/hw3/include/sceneIO_light.h @@ -0,0 +1,25 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEIO_LIGHT_H_ +#define _SCENEIO_LIGHT_H_ + +#include + +#include "sceneIO_xml.h" +#include "sceneIO_cache.h" + +#include "shader_base.h" +#include "texture_base.h" +#include "boundedPrimitive.h" + +#include "lightsource_base.h" + +std::shared_ptr importLight(const XMLNode& node, nodeCache& shape_cache, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir); + +#endif /* _SCENEIO_LIGHT_H_ */ diff --git a/hw3/include/sceneIO_material.h b/hw3/include/sceneIO_material.h new file mode 100644 index 0000000..9c0852b --- /dev/null +++ b/hw3/include/sceneIO_material.h @@ -0,0 +1,22 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEIO_MATERIAL_H_ +#define _SCENEIO_MATERIAL_H_ + +#include + +#include "sceneIO_xml.h" +#include "sceneIO_cache.h" + +#include "shader_base.h" +#include "texture_base.h" + +std::shared_ptr importMaterial(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir); + +#endif /* _SCENEIO_MATERIAL_H_ */ diff --git a/hw3/include/sceneIO_xml.h b/hw3/include/sceneIO_xml.h new file mode 100644 index 0000000..5df35a2 --- /dev/null +++ b/hw3/include/sceneIO_xml.h @@ -0,0 +1,51 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SCENEIO_XML_H_ +#define _SCENEIO_XML_H_ + +#include +#include +#include "tinyxml2.h" + +class XMLNode { + public: + ///////////////// + // Constructor // + ///////////////// + XMLNode(const std::string& filename); + XMLNode(const tinyxml2::XMLElement* element, const std::shared_ptr& xml); + XMLNode(const XMLNode& node); + + ///////////// + // Methods // + ///////////// + XMLNode firstChild(void) const; + XMLNode findChild(const std::string& name) const; + + bool isValid(void) const; + std::string name(void) const; + std::string attribute(const std::string& attribute) const; + + /////////////// + // Operators // + /////////////// + XMLNode& operator++(void); + XMLNode& operator++(int); + XMLNode& operator=(const XMLNode& src); + + protected: + ////////////////// + // Data Members // + ////////////////// + const tinyxml2::XMLElement* _element; + std::shared_ptr _xml; +}; + + +#endif /* _SCENEIO_XML_H_ */ diff --git a/hw3/include/shaderProperties.h b/hw3/include/shaderProperties.h new file mode 100644 index 0000000..859aaac --- /dev/null +++ b/hw3/include/shaderProperties.h @@ -0,0 +1,38 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SHADERPROPERTIES_H_ +#define _SHADERPROPERTIES_H_ + +class shaderProperties { + public: + ///////////////// + // Constructor // + ///////////////// + shaderProperties(bool diff=true, bool spec=true) : diffuse(diff), specular(spec) {} + + ////////////// + // Operator // + ////////////// + bool operator==(const shaderProperties& sp) const; + bool operator!=(const shaderProperties& sp) const; + + shaderProperties& operator&=(const shaderProperties& sp); + shaderProperties& operator|=(const shaderProperties& sp); + shaderProperties& operator~(void); + + shaderProperties operator&(const shaderProperties& sp) const; + shaderProperties operator|(const shaderProperties& sp) const; + + ///////////////////////// + // Public data members // + ///////////////////////// + bool diffuse, specular; +}; + +#endif /* _SHADERPROPERTIES_H_ */ diff --git a/hw3/include/shader_base.h b/hw3/include/shader_base.h new file mode 100644 index 0000000..b96cc33 --- /dev/null +++ b/hw3/include/shader_base.h @@ -0,0 +1,59 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SHADER_BASE_H_ +#define _SHADER_BASE_H_ + +#include +#include + +#include "vec2d.h" +#include "vec3d.h" +#include "color.h" +#include "shaderProperties.h" +#include "intersectionPoint.h" + + +class shader_base +{ + public: + ////////////////// + // Constructors // + ////////////////// + shader_base(void) {} + shader_base(const shader_base&) = delete; + + /////////////// + // Operators // + /////////////// + shader_base& operator=(const shader_base&) = delete; + + ///////////// + // Methods // + ///////////// + virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const = 0; + + virtual shaderProperties properties(const intersectionPoint& ip) const = 0; + + ///////////// + // Friends // + ///////////// + friend std::ostream& operator<<(std::ostream& s, const shader_base& shader) + { + shader._print(s); + return s; + } + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual void _print(std::ostream& s) const = 0; +}; + +#endif /* _SHADER_BASE_H_ */ diff --git a/hw3/include/shadingFrameTransformation.h b/hw3/include/shadingFrameTransformation.h new file mode 100644 index 0000000..2d8bd34 --- /dev/null +++ b/hw3/include/shadingFrameTransformation.h @@ -0,0 +1,57 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _SHADINGFRAMETRANSFORMATION_H_ +#define _SHADINGFRAMETRANSFORMATION_H_ + +#include + +#include "vec2d.h" +#include "shader_base.h" +#include "transformation3d.h" + +class shadingFrameTransformation : public shader_base { + public: + ////////////////// + // Constructors // + ////////////////// + shadingFrameTransformation(const std::shared_ptr& shader); + shadingFrameTransformation(const shadingFrameTransformation&) = delete; + + /////////////// + // Operators // + /////////////// + shadingFrameTransformation& operator=(const shadingFrameTransformation&) = delete; + + ///////////// + // Methods // + ///////////// + virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const final override; + + virtual color reflectance(const intersectionPoint& ip, const vec3d& light_dir, const shaderProperties& properties=shaderProperties()) const final override; + virtual brdfSample sample(const intersectionPoint& ip, float r1, float r2, const shaderProperties& properties=shaderProperties()) const final override; + virtual float reflectivity(const intersectionPoint& ip, const shaderProperties& properties=shaderProperties()) const final override; + virtual color emittance(const intersectionPoint& ip) const final override; + + virtual shaderProperties properties(const intersectionPoint& ip) const final override; + + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual transformation3d _transformation(const vec2d& textureCoord) const = 0; + virtual void _print(std::ostream& s) const = 0; + + ////////////////// + // Data Members // + ////////////////// + std::shared_ptr _shader; +}; + +#endif /* _SHADINGFRAMETRANSFORMATION_H_ */ diff --git a/hw3/include/texture_base.h b/hw3/include/texture_base.h new file mode 100644 index 0000000..919ab53 --- /dev/null +++ b/hw3/include/texture_base.h @@ -0,0 +1,67 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _TEXTURE_BASE_H_ +#define _TEXTURE_BASE_H_ + +#include "vec2d.h" +#include "image.h" + +class texture_base : public image { + public: + ////////////////// + // Constructors // + ////////////////// + texture_base(bool repeat=true); + texture_base(const texture_base& src); + + /////////////// + // Operators // + /////////////// + texture_base& operator=(const texture_base& src); + + virtual image::value_type operator()(const vec2d& textureCoord) const = 0; + + //////////////// + // Inspectors // + //////////////// + bool repeatEdge(void) const { return _repeat; } + bool wrapEdge(void) const { return !_repeat; } + + ///////////// + // Friends // + ///////////// + friend void swap(texture_base& a, texture_base& b) { a._swap(b); } + + friend std::ostream& operator<<(std::ostream& s, const texture_base& t) + { + t._print(s); + return s; + } + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + virtual void _assign(const texture_base& src); + color& _at(signed int x, signed int y); + const color& _at(signed int x, signed int y) const; + + private: + ///////////////////// + // Private Methods // + ///////////////////// + virtual void _print(std::ostream& s) const=0; + + ////////////////// + // Data Members // + ////////////////// + bool _repeat; +}; + +#endif /* _TEXTURE_BASE_H_ */ diff --git a/hw3/include/tinyxml2.h b/hw3/include/tinyxml2.h new file mode 100644 index 0000000..fb7464a --- /dev/null +++ b/hw3/include/tinyxml2.h @@ -0,0 +1,2102 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +#endif + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) +# ifndef DEBUG +# define DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#else +# define TINYXML2_LIB +#endif + + +#if defined(DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 3; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 0; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] +*/ +class StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + +private: + void Reset(); + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template +class DynArray +{ +public: + DynArray() { + _mem = _pool; + _allocated = INITIAL_SIZE; + _size = 0; + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size++] = t; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + return _mem[--_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; + virtual void Clear() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* b = _blockPtrs.Pop(); + delete b; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + for( int i=0; ichunk[i].next = &block->chunk[i+1]; + } + block->chunk[COUNT-1].next = 0; + _root = block->chunk; + } + void* result = _root; + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + _nAllocs++; + _nUntracked++; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Chunk* chunk = static_cast( mem ); +#ifdef DEBUG + memset( chunk, 0xfe, sizeof(Chunk) ); +#endif + chunk->next = _root; + _root = chunk; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + _nUntracked--; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Chunk { + Chunk* next; + char mem[SIZE]; + }; + struct Block { + Chunk chunk[COUNT]; + }; + DynArray< Block*, 10 > _blockPtrs; + Chunk* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ERROR = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_ELEMENT_MISMATCH, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_IDENTIFYING_TAG, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p ) { + TIXMLASSERT( p ); + while( IsWhiteSpace(*p) ) { + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* p ) { + return const_cast( SkipWhiteSpace( const_cast(p) ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + +protected: + XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char*, StrPair* ); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLBase; + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char*, StrPair* endTag ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i=0; + QueryIntValue( &i ); + return i; + } + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_NO_ERROR on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities ); + + mutable StrPair _name; + mutable StrPair _value; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLBase; + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. 0 will be + returned if there is an error. For a method with error + checking, see QueryIntAttribute() + */ + int IntAttribute( const char* name ) const { + int i=0; + QueryIntAttribute( name, &i ); + return i; + } + /// See IntAttribute() + unsigned UnsignedAttribute( const char* name ) const { + unsigned i=0; + QueryUnsignedAttribute( name, &i ); + return i; + } + /// See IntAttribute() + bool BoolAttribute( const char* name ) const { + bool b=false; + QueryBoolAttribute( name, &b ); + return b; + } + /// See IntAttribute() + double DoubleAttribute( const char* name ) const { + double d=0; + QueryDoubleAttribute( name, &d ); + return d; + } + /// See IntAttribute() + float FloatAttribute( const char* name ) const { + float f=0; + QueryFloatAttribute( name, &f ); + return f; + } + + /** Given an attribute name, QueryIntAttribute() returns + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + + /** Given an attribute name, QueryAttribute() returns + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + int QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + int QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + int QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + int QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + int QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + This is text + fooElement->SetText( "Hullaballoo!" ); + Hullaballoo! + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + Hullaballoo!This is text + @endverbatim + + For this XML: + @verbatim + + @endverbatim + SetText() will generate + @verbatim + Hullaballoo! + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + // internal: + enum { + OPEN, // + CLOSED, // + CLOSING // + }; + int ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* endTag ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindAttribute( const char* name ) { + return const_cast(const_cast(this)->FindAttribute( name )); + } + XMLAttribute* FindOrCreateAttribute( const char* name ); + //void LinkAttribute( XMLAttribute* attrib ); + char* ParseAttributes( char* p ); + static void DeleteAttribute( XMLAttribute* attribute ); + + enum { BUF_SIZE = 200 }; + int _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_NO_ERROR (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + + /** + Load an XML file from disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_NO_ERROR (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespace; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + void SetError( XMLError error, const char* str1, const char* str2 ); + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_NO_ERROR; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + + /// Return a possibly helpful diagnostic location or string. + const char* GetErrorStr1() const { + return _errorStr1; + } + /// Return a possibly helpful secondary diagnostic location or string. + const char* GetErrorStr2() const { + return _errorStr2; + } + /// If there is an error, print it to stdout. + void PrintError() const; + + /// Clear the document, resetting it to the initial state. + void Clear(); + + // internal + char* Identify( char* p, XMLNode** node ); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespace; + const char* _errorStr1; + const char* _errorStr2; + char* _charBuffer; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); +}; + + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + XMLHandle( XMLNode* node ) { + _node = node; + } + /// Create a handle from a node. + XMLHandle( XMLNode& node ) { + _node = &node; + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) { + _node = ref._node; + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( ( _node == 0 ) ? 0 : _node->ToText() ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + XMLConstHandle( const XMLNode* node ) { + _node = node; + } + XMLConstHandle( const XMLNode& node ) { + _node = &node; + } + XMLConstHandle( const XMLConstHandle& ref ) { + _node = ref._node; + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + } + const XMLText* ToText() const { + return ( ( _node == 0 ) ? 0 : _node->ToText() ); + } + const XMLUnknown* ToUnknown() const { + return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + } + const XMLDeclaration* ToDeclaration() const { + return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer() { + _buffer.Clear(); + _buffer.Push(0); + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + void Print( const char* format, ... ); + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; +}; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED diff --git a/hw3/include/transformation3d.h b/hw3/include/transformation3d.h new file mode 100644 index 0000000..7b61ecc --- /dev/null +++ b/hw3/include/transformation3d.h @@ -0,0 +1,77 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _TRANSFORMATION3D_H_ +#define _TRANSFORMATION3D_H_ + +#include "vec3d.h" +#include "mat3d.h" + +class transformation3d { + public: + ////////////////// + // Constructors // + ////////////////// + transformation3d(void); + transformation3d(const vec3d& translation, const mat3d& transformation, const mat3d& inverseTransform); + transformation3d(const transformation3d& t); + + ////////////// + // Operator // + ////////////// + transformation3d& operator=(const transformation3d& t); + + transformation3d operator*(const transformation3d& t) const; + transformation3d& operator*=(const transformation3d& t); + + ////////////// + // Mutators // + ////////////// + transformation3d& invert(void); + + ///////////// + // Methods // + ///////////// + vec3d transformPoint(const vec3d& p) const; + vec3d transformDirection(const vec3d& d) const; + vec3d transformNormal(const vec3d& n) const; + + vec3d inverseTransformPoint(const vec3d& p) const; + vec3d inverseTransformDirection(const vec3d& d) const; + vec3d inverseTransformNormal(const vec3d& n) const; + + ///////////// + // Friends // + ///////////// + friend void swap(transformation3d& a, transformation3d& b) { a._swap(b); } + + friend transformation3d inverse(const transformation3d& t) { transformation3d i(t); return i.invert(); } + + friend std::ostream& operator<<(std::ostream& s, const transformation3d& t) + { + t._print(s); + return s; + } + + protected: + /////////////////////// + // Protected Methods // + /////////////////////// + void _swap(transformation3d& t); + void _assign(const transformation3d& t); + virtual void _print(std::ostream& s) const; + + //////////////////////////// + // Protected Data Members // + //////////////////////////// + vec3d _translation; + mat3d _transformation; + mat3d _inverseTransformation; +}; + +#endif /* _TRANSFORMATION3D_H_ */ diff --git a/hw3/include/triangle.h b/hw3/include/triangle.h new file mode 100644 index 0000000..f7d85bf --- /dev/null +++ b/hw3/include/triangle.h @@ -0,0 +1,115 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _TRIANGLE_H_ +#define _TRIANGLE_H_ + +#include +#include +#include +#include + +#include "ray.h" +#include "vec2d.h" +#include "vec3d.h" +#include "boundingBox.h" + +class triangle { + public: + ////////////////// + // Constructors // + ////////////////// + triangle(void); + triangle(const triangle& t); + triangle(triangle&& t); + + triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3); + triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list); + + triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3, + const vec3d& n1, const vec3d& n2, const vec3d& n3); + triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list, + size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr>& normal_list); + + triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3, + const vec2d& t1, const vec2d& t2, const vec2d& t3); + triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list, + size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr>& texcoord_list); + + triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3, + const vec3d& n1, const vec3d& n2, const vec3d& n3, + const vec2d& t1, const vec2d& t2, const vec2d& t3); + triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list, + size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr>& normal_list, + size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr>& texcoord_list); + + //////////////// + // Inspectors // + //////////////// + const vec3d& vertex(size_t index) const; + const vec3d& normal(size_t index) const; + const vec2d& textureCoordinate(size_t index) const; + + bool hasPerVertexNormals(void) const; + bool hasPerVertexTextureCoordinates(void) const; + + /////////////// + // Operators // + /////////////// + triangle& operator=(const triangle& t); + triangle& operator=(triangle&& t); + + ///////////// + // Methods // + ///////////// + bool intersect(const ray& r, vec3d& barycentricCoord, float& t) const; + + boundingBox boundingbox(void) const; + vec3d vertex(const vec3d& barycentricCoord) const; + vec3d normal(void) const; + vec3d shadingAxis(void) const; + vec3d normal(const vec3d& barycentricCoord) const; + vec2d textureCoordinate(const vec3d& barycentricCoord) const; + + vec3d sample(float r1, float r2, vec3d& barycentricCoord, float& pdf) const; + float area(void) const; + + ///////////// + // Friends // + ///////////// + friend void swap(triangle& a, triangle& b) { a._swap(b); } + + friend std::ostream& operator<<(std::ostream& s, const triangle& t) + { + s << "Triangle: v=(" << t.vertex(0) << "," << t.vertex(1) << "," << t.vertex(2) << ")"; + if(t._normal_list) + s << ", n=(" << t.normal(0) << "," << t.normal(1) << "," << t.normal(2) << ")"; + if(t._textureCoord_list) + s << ", t=(" << t.textureCoordinate(0) << "," << t.textureCoordinate(1) << "," << t.textureCoordinate(2) << ")"; + return s; + } + +private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const triangle& t); + void _swap(triangle& t); + + ////////////////// + // Data Members // + ////////////////// + std::array _vertex_idx; + std::array _normal_idx; + std::array _textureCoord_idx; + std::shared_ptr> _vertex_list; + std::shared_ptr> _normal_list; + std::shared_ptr> _textureCoord_list; +}; + +#endif /* _TRIANGLE_H_ */ diff --git a/hw3/include/triangleMesh.h b/hw3/include/triangleMesh.h new file mode 100644 index 0000000..9558602 --- /dev/null +++ b/hw3/include/triangleMesh.h @@ -0,0 +1,51 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _TRIANGLEMESH_H_ +#define _TRIANGLEMESH_H_ + +#include "vec2d.h" +#include "vec3d.h" +#include "shader_base.h" +#include "boundedTriangle.h" +#include "boundedCompound.h" + +class triangleMesh : public boundedCompound { + public: + ////////////////// + // Constructors // + ////////////////// + triangleMesh(void); + triangleMesh(const std::vector& triangle_list, const std::shared_ptr& shader, const transformation3d& transform=transformation3d()); + triangleMesh(const triangleMesh&) = delete; + + /////////////// + // Operators // + /////////////// + triangleMesh& operator=(const triangleMesh&) = delete; + + ///////////// + // Methods // + ///////////// + virtual const std::vector>& compounds(void) const final override; + + virtual bool hasShader(void) const override; + + private: + ///////////////////// + // Private Methods // + ///////////////////// + virtual void _print(std::ostream& s) const override; + + ////////////////// + // Data Members // + ////////////////// + std::vector> _triangles; +}; + +#endif /* _TRIANGLEMESH_H_ */ diff --git a/hw3/include/util.h b/hw3/include/util.h new file mode 100644 index 0000000..2146464 --- /dev/null +++ b/hw3/include/util.h @@ -0,0 +1,19 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include + +std::string getFilename(const std::string& path); +std::string getExtension(const std::string& path); +std::string getDirectory(const std::string& path); + +#endif /* _UTIL_H_ */ diff --git a/hw3/include/vec2d.h b/hw3/include/vec2d.h new file mode 100644 index 0000000..36e0e5c --- /dev/null +++ b/hw3/include/vec2d.h @@ -0,0 +1,117 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _VEC2D_H_ +#define _VEC2D_H_ + +#include +#include + +class vec2d { + public: + ///////////// + // Typedef // + ///////////// + typedef float value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + ////////////////// + // Data Members // + ////////////////// + union { + struct { value_type x, y; }; + struct { value_type u, v; }; + value_type data[2]; + }; + + public: + ///////////////// + // Constructor // + ///////////////// + explicit vec2d(const_reference value=0.0f); + vec2d(const_reference x, const_reference y); + vec2d(const vec2d& v); + + //////////////// + // Inspectors // + //////////////// + static size_t size(void) { return 2; } + + iterator begin(void); + const_iterator begin(void) const; + iterator end(void); + const_iterator end(void) const; + + const_reference operator[](size_t index) const; + reference operator[](size_t index); + + /////////////// + // Operators // + /////////////// + vec2d& operator=(const vec2d& v); + + bool operator==(const vec2d& v) const; + bool operator!=(const vec2d& v) const; + + vec2d operator-(void) const; + + vec2d operator+(const vec2d& v) const; + vec2d operator-(const vec2d& v) const; + vec2d operator*(const vec2d& v) const; + vec2d operator*(const_reference scale) const; + vec2d operator/(const vec2d& v) const; + vec2d operator/(const_reference scale) const; + + vec2d& operator+=(const vec2d& v); + vec2d& operator-=(const vec2d& v); + vec2d& operator*=(const vec2d& v); + vec2d& operator*=(const_reference scale); + vec2d& operator/=(const vec2d& v); + vec2d& operator/=(const_reference scale); + + ///////////// + // Methods // + ///////////// + value_type dot(const vec2d& v) const; + value_type squared_length(void) const; + value_type length(void) const; + value_type squared_distance(const vec2d& v) const; + value_type distance(const vec2d& v) const; + + /////////////// + // Modifiers // + /////////////// + vec2d& abs(void); + vec2d& normalize(void); + + ///////////// + // Friends // + ///////////// + friend void swap(vec2d& a, vec2d& b) { return a._swap(b); } + friend vec2d normalize(const vec2d& v) { return vec2d(v).normalize(); } + friend vec2d abs(const vec2d& v) { return vec2d(v).abs(); } + friend vec2d operator*(const_reference scale, const vec2d& v) { return (v*scale); } + + friend std::ostream& operator<<(std::ostream& s, const vec2d& v) + { + s << "[" << v.x << "," << v.y << "]"; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const vec2d& v); + void _swap(vec2d& v); +}; + +#endif /* _VEC2D_H_ */ diff --git a/hw3/include/vec3d.h b/hw3/include/vec3d.h new file mode 100644 index 0000000..50d918f --- /dev/null +++ b/hw3/include/vec3d.h @@ -0,0 +1,120 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#ifndef _VEC3D_H_ +#define _VEC3D_H_ + +#include +#include + +class vec3d { + public: + ///////////// + // Typedef // + ///////////// + typedef float value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + ////////////////// + // Data Members // + ////////////////// + union { + struct { value_type x, y, z; }; + value_type data[3]; + }; + + public: + ///////////////// + // Constructor // + ///////////////// + explicit vec3d(const_reference value=0.0f); + vec3d(const_reference x, const_reference y, const_reference z); + vec3d(const vec3d& v); + + //////////////// + // Inspectors // + //////////////// + static size_t size(void) { return 3; } + + iterator begin(void); + const_iterator begin(void) const; + iterator end(void); + const_iterator end(void) const; + + const_reference operator[](size_t index) const; + reference operator[](size_t index); + + /////////////// + // Operators // + /////////////// + vec3d& operator=(const vec3d& v); + + bool operator==(const vec3d& v) const; + bool operator!=(const vec3d& v) const; + + vec3d operator-(void) const; + + vec3d operator+(const vec3d& v) const; + vec3d operator-(const vec3d& v) const; + vec3d operator*(const vec3d& v) const; + vec3d operator*(const_reference scale) const; + vec3d operator/(const vec3d& v) const; + vec3d operator/(const_reference scale) const; + + vec3d& operator+=(const vec3d& v); + vec3d& operator-=(const vec3d& v); + vec3d& operator*=(const vec3d& v); + vec3d& operator*=(const_reference scale); + vec3d& operator/=(const vec3d& v); + vec3d& operator/=(const_reference scale); + + ///////////// + // Methods // + ///////////// + value_type dot(const vec3d& v) const; + value_type squared_length(void) const; + value_type length(void) const; + value_type squared_distance(const vec3d& v) const; + value_type distance(const vec3d& v) const; + + vec3d cross(const vec3d& v) const; + + /////////////// + // Modifiers // + /////////////// + vec3d& abs(void); + vec3d& clamp(value_type lower=0.0f, value_type upper=1.0f); + vec3d& normalize(void); + + ///////////// + // Friends // + ///////////// + friend void swap(vec3d& a, vec3d& b) { return a._swap(b); } + friend vec3d normalize(const vec3d& v) { return vec3d(v).normalize(); } + friend vec3d abs(const vec3d& v) { return vec3d(v).abs(); } + friend vec3d clamp(const vec3d& v, value_type lower=0.0f, value_type upper=1.0f) { return vec3d(v).clamp(lower, upper); } + friend vec3d operator*(const_reference scale, const vec3d& v) { return (v*scale); } + + friend std::ostream& operator<<(std::ostream& s, const vec3d& v) + { + s << "[" << v.x << "," << v.y << "," << v.z << "]"; + return s; + } + + private: + ///////////////////// + // Private Methods // + ///////////////////// + void _assign(const vec3d& v); + void _swap(vec3d& v); +}; + +#endif /* _VEC3D_H_ */ diff --git a/hw3/src/.directory b/hw3/src/.directory new file mode 100644 index 0000000..dbba490 --- /dev/null +++ b/hw3/src/.directory @@ -0,0 +1,4 @@ +[Dolphin] +Timestamp=2016,2,3,13,46,28 +Version=3 +ViewMode=1 diff --git a/hw3/src/boundedCompound.cpp b/hw3/src/boundedCompound.cpp new file mode 100644 index 0000000..1f43a82 --- /dev/null +++ b/hw3/src/boundedCompound.cpp @@ -0,0 +1,93 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include + +#include "boundedCompound.h" +#include "intersector_factory_base.h" + +///////////////// +// Constructor // +///////////////// +boundedCompound::boundedCompound(void) + : boundedPrimitive() +{ + _transform = transformation3d(); + _intersector = nullptr; +} + + +boundedCompound::boundedCompound(const transformation3d& transform, const std::shared_ptr& shader) + + : boundedPrimitive(boundingBox(), shader) +{ + _transform = transform; + _intersector = nullptr; +} + + +///////////// +// Methods // +///////////// +intersectionPoint boundedCompound::intersect(const ray& r) const +{ + // sanity check + assert(_intersector); + + // HW5: Implement this + // Incorporate _transformation in the intersection computation. + // Returns: intersectionPoint + // Modifies: nothing. + + // pass intersection computation to _intersector + intersectionPoint ip = _intersector->intersect(r); + + // Done. + return ip; +} + + +void boundedCompound::initialize(const intersector_factory_base& ifb) +{ + // create the _intersector + _intersector = ifb(*this); +} + + +void boundedCompound::initializeBoundingBox(void) +{ + // compute the bounding box in world coordinates + _bb = boundingBox(); + for_each(compounds().begin(), compounds().end(), [&](const std::shared_ptr& prim) + { + _bb += transform(prim->boundingbox(), _transform); + }); +} + + +bool boundedCompound::hasShader(void) const +{ + // check if this has a shader + if(boundedPrimitive::hasShader()) return true; + + // check if each child has a shader + for(auto itr = compounds().begin(); itr != compounds().end(); itr++) + { + if(!(*itr)->hasShader()) return false; + } + + // Done. + return true; +} + + +void boundedCompound::_print(std::ostream& s) const +{ + s << "boundedCompound (" << _bb << ", " << compounds().size() << " compounds)"; +} diff --git a/hw3/src/boundedPrimitive.cpp b/hw3/src/boundedPrimitive.cpp new file mode 100644 index 0000000..d328b16 --- /dev/null +++ b/hw3/src/boundedPrimitive.cpp @@ -0,0 +1,50 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "boundedPrimitive.h" + +///////////////// +// Constructor // +///////////////// +boundedPrimitive::boundedPrimitive(void) +{ + _bb = boundingBox(); + _shader = nullptr; +} + +boundedPrimitive::boundedPrimitive(const boundingBox& bb, const std::shared_ptr& shader) +{ + _bb = bb; + _shader = shader; +} + + +///////////// +// Methods // +///////////// +const boundingBox& boundedPrimitive::boundingbox(void) const +{ + return _bb; +} + + +bool boundedPrimitive::hitBoundingBox(const ray& r) const +{ + return _bb.isHit(r); +} + + +bool boundedPrimitive::hasShader(void) const +{ + return (_shader != nullptr); +} + +void boundedPrimitive::_print(std::ostream& s) const +{ + s << "boundedPrimitive (" << _bb << ")"; +} diff --git a/hw3/src/boundedTriangle.cpp b/hw3/src/boundedTriangle.cpp new file mode 100644 index 0000000..bf8a367 --- /dev/null +++ b/hw3/src/boundedTriangle.cpp @@ -0,0 +1,53 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include "boundedTriangle.h" + + +////////////////// +// Constructors // +////////////////// +boundedTriangle::boundedTriangle(void) + : boundedPrimitive() +{ + // Nothing +} + +boundedTriangle::boundedTriangle(const triangle& tri, const std::shared_ptr& shader) + : boundedPrimitive(tri.boundingbox(), shader) +{ + _triangle = tri; +} + + +///////////// +// Methods // +///////////// +intersectionPoint boundedTriangle::intersect(const ray& r) const +{ + // intersect triangle + float t; + vec3d bc; + bool hit = _triangle.intersect(r, bc, t); + + // empty ip if not hit + if(!hit) return intersectionPoint(); + + // if hit, create intersectionPoint record. + else return intersectionPoint(r, t, _shader, + _triangle.normal(bc), + _triangle.shadingAxis(), + _triangle.textureCoordinate(bc)); +} + + +void boundedTriangle::_print(std::ostream& s) const +{ + s << "boundedTriangle (" << _bb << ", " << _triangle << ")"; +} diff --git a/hw3/src/boundingBox.cpp b/hw3/src/boundingBox.cpp new file mode 100644 index 0000000..9708093 --- /dev/null +++ b/hw3/src/boundingBox.cpp @@ -0,0 +1,185 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include "interval.h" +#include "constants.h" +#include "boundingBox.h" + + +///////////////// +// Constructor // +///////////////// +boundingBox::boundingBox(void) +{ + // create an empty box (i.e., 'left' lies right of 'right') + _lfb = vec3d(+LARGE); + _rbt = vec3d(-LARGE); +} + + +boundingBox::boundingBox(const vec3d& lfb, const vec3d& rbt) +{ + _lfb = lfb; + _rbt = rbt; + + // Make sure each component in _lfb is smaller than _rbt + for(unsigned int i=0; i < vec3d::size(); i++) + if(_rbt[i] < _lfb[i]) std::swap(_rbt[i], _lfb[i]); + + // Done. +} + + +boundingBox::boundingBox(const boundingBox& bb) +{ + _lfb = bb._lfb; + _rbt = bb._rbt; +} + + +////////////// +// Operator // +////////////// +boundingBox& boundingBox::operator=(const boundingBox& src) +{ + _assign(src); + return *this; +} + + +boundingBox& boundingBox::operator+=(const boundingBox& bb) +{ + // compute the union of two bounding boxes + for(unsigned int i=0; i < vec3d::size(); i++) + { + if(_lfb[i] > bb._lfb[i]) _lfb[i] = bb._lfb[i]; + if(_rbt[i] < bb._rbt[i]) _rbt[i] = bb._rbt[i]; + } + + return *this; +} + + +boundingBox boundingBox::operator+(const boundingBox& bb) const +{ + boundingBox result(*this); + result += bb; + return result; +} + + +boundingBox& boundingBox::operator+=(const vec3d& point) +{ + // expand the bounding box to include 'point' (+ a small epsilon) + for(unsigned int i=0; i < vec3d::size(); i++) + { + if(_lfb[i] > point[i]-EPSILON) _lfb[i] = point[i]-EPSILON; + if(_rbt[i] < point[i]+EPSILON) _rbt[i] = point[i]+EPSILON; + } +} + + +///////////// +// Methods // +///////////// +bool boundingBox::isHit(const ray& r) const +{ + // init + interval boxInterval(0, +LARGE); + + // for every slab + for(unsigned int i=0; i != vec3d::size(); i++) + { + // compute the slab + interval slab(_lfb[i], _rbt[i]); + slab -= r.origin()[i]; + + // check for the case where the ray is parallel to the slab + if(fabs(r.direction()[i]) < EPSILON) + { + // if identical signs => no hit + if((slab.lower() < 0.0f) == (slab.upper() < 0.0f)) + return false; + + // skip remainder to this iteration + continue; + } + else + slab /= r.direction()[i]; + + // intersect + boxInterval.intersect(slab); + if(boxInterval.empty()) + return false; + } + + // Done. + return true; +} + + +vec3d boundingBox::center(void) const +{ + return 0.5f * (_lfb + _rbt); +} + + +vec3d boundingBox::corner(bool left, bool front, bool bottom) const +{ + return vec3d( left ? _lfb.x : _rbt.x, + front ? _lfb.y : _rbt.y, + bottom ? _lfb.z : _rbt.z ); +} + + +////////////// +// Mutators // +////////////// +boundingBox& boundingBox::transform(const transformation3d& t) +{ + boundingBox result; + for(unsigned int i=0; i <= 1; i++) + for(unsigned int j=0; j <= 1; j++) + for(unsigned int k=0; k <= 1; k++) + result += t.transformPoint(corner(i,j,k)); + + // Done. + _swap(result); + return *this; +} + + +boundingBox& boundingBox::inverseTransform(const transformation3d& t) +{ + boundingBox result; + for(unsigned int i=0; i <= 1; i++) + for(unsigned int j=0; j <= 1; j++) + for(unsigned int k=0; k <= 1; k++) + result += t.inverseTransformPoint(corner(i,j,k)); + + // Done. + _swap(result); + return *this; +} + +///////////////////// +// Private Methods // +///////////////////// +void boundingBox::_swap(boundingBox& bb) +{ + swap(_lfb, bb._lfb); + swap(_rbt, bb._rbt); +} + + +void boundingBox::_assign(const boundingBox& bb) +{ + _lfb = bb._lfb; + _rbt = bb._rbt; +} diff --git a/hw3/src/camera.cpp b/hw3/src/camera.cpp new file mode 100644 index 0000000..3393dc9 --- /dev/null +++ b/hw3/src/camera.cpp @@ -0,0 +1,150 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include + +#include "constants.h" +#include "camera.h" + +///////////////// +// Constructor // +///////////////// +camera::camera(void) +{ + _eye = vec3d(); + _view = vec3d(0.0f, 0.0f, -1.0f); + _up = vec3d(0.0f, 1.0f, 0.0f); + _fov = 60.0f; + _width = _height = 256; +} + + +camera::camera(const vec3d& eye, const vec3d& viewDirection, const vec3d& up, float fov, size_t xres, size_t yres) +{ + _eye = eye; + _view = normalize(viewDirection); + _up = normalize(up); + _fov = fov; + _width = xres; + _height = yres; + + // fix up if needed + vec3d right = _view.cross(up).normalize(); + _up = right.cross(_view).normalize(); +} + + +camera::camera(const camera& cam) +{ + _eye = cam._eye; + _view = cam._view; + _up = cam._up; + _fov = cam._fov; + _width = cam._width; + _height = cam._height; +} + + +/////////////// +// Operators // +/////////////// +camera& camera::operator=(const camera& cam) +{ + _assign(cam); + return *this; +} + + +ray camera::operator()(float x, float y) const +{ + vec3d right = _view.cross(_up).normalize(); + + // aspect ratio + float aspect = (float)(_height) / (float)(_width); + float tanFov = tan(_fov / 180.0f * PI); + + // compute view plane center, and U and V unnormalized axes. + vec3d center = _eye + _view; + vec3d U = 2.0f * tanFov * right; + vec3d V = -2.0f * tanFov * aspect * _up; // y runs from top to bottom (opposite direction of up) + + // get point on view plane + vec3d p = center + (x / (float)(_width) - 0.5f) * U + (y / (float)(_height) - 0.5f) * V; + + // Done. + return ray(_eye, p - _eye); +} + + +////////////// +// Mutators // +////////////// +void camera::frameBoundingBox(const boundingBox& bb) +{ + // determine the best eye location, given the other parameters and a bounding box such that the bounding box maximally occupies the view + vec3d right = _view.cross(_up).normalize(); + _eye = 0.5f * (bb.corner(true,true,true) + bb.corner(false,false,false)); + + // => find max projection in up and right direction. + float maxRight=-LARGE, maxUp=-LARGE, maxDepth=-LARGE; + for(unsigned int i=0; i < 8; i++) + { + vec3d c = bb.corner( (i&1)==1, (i&2)==2, (i&4)==4 ) - _eye; + + float r = fabs(c.dot(right)); + float u = fabs(c.dot(_up)); + float d = fabs(c.dot(_view)); + + maxRight = std::max(maxRight, r); + maxUp = std::max(maxUp, u); + maxDepth = std::max(maxDepth, d); + } + + // => compute optimal distance for up and right + float aspect = (float)(_height) / (float)(_width); + float tanFov = tan(_fov / 180.0f * PI); + float optDistUp = fabs(maxUp / tanFov); + float optDistRight = fabs(maxRight / (tanFov * aspect)); + + // => move _eye back based on (max) optimal distance + _eye -= _view * (std::max(optDistUp, optDistRight) + maxDepth); +} + + +///////////////////// +// Private Methods // +///////////////////// +void camera::_swap(camera& cam) +{ + // sanity check + if(&cam == this) return; + + // swap + swap(_eye, cam._eye); + swap(_view, cam._view); + swap(_up, cam._up); + std::swap(_fov, cam._fov); + std::swap(_width, cam._width); + std::swap(_height, cam._height); +} + + +void camera::_assign(const camera& cam) +{ + // sanity check + if(&cam == this) return; + + // copy + _eye = cam._eye; + _view = cam._view; + _up = cam._up; + _fov = cam._fov; + _width = cam._width; + _height = cam._height; +} diff --git a/hw3/src/color.cpp b/hw3/src/color.cpp new file mode 100644 index 0000000..b2b720f --- /dev/null +++ b/hw3/src/color.cpp @@ -0,0 +1,233 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include +#include +#include "color.h" + +////////////////// +// Constructors // +////////////////// +color::color(color::const_reference value) +{ + r = g = b = value; +} + + +color::color(color::const_reference r, color::const_reference g, color::const_reference b) +{ + this->r = r; + this->g = g; + this->b = b; +} + + +color::color(const color& col) +{ + r = col.r; + g = col.g; + b = col.b; +} + + +//////////////// +// Inspectors // +//////////////// +color::const_reference color::operator[](size_t index) const +{ + assert(index < size()); + return data[index]; +} + + +color::reference color::operator[](size_t index) +{ + assert(index < size()); + return data[index]; +} + + +color::iterator color::begin(void) +{ + return data; +} + + +color::const_iterator color::begin(void) const +{ + return data; +} + + +color::iterator color::end(void) +{ + return begin() + size(); +} + + +color::const_iterator color::end(void) const +{ + return begin() + size(); +} + + +/////////////// +// Operators // +/////////////// +color& color::operator=(const color& col) +{ + _assign(col); + return *this; +} + + +bool color::operator==(const color& col) const +{ + return (r == col.r) && (g == col.g) && (b == col.b); +} + + +bool color::operator!=(const color& col) const +{ + return (r != col.r) || (g != col.g) || (b != col.b); +} + + +color color::operator+(const color& col) const +{ + return color(r + col.r, g + col.g, b + col.b); +} + + +color color::operator-(const color& col) const +{ + return color(r - col.r, g - col.g, b - col.b); +} + + +color color::operator*(const color& col) const +{ + return color(r * col.r, g * col.g, b * col.b); +} + + +color color::operator*(color::const_reference scale) const +{ + return color(r * scale, g * scale, b * scale); +} + + +color color::operator/(const color& col) const +{ + return color(r / col.r, g / col.g, b / col.b); +} + + +color color::operator/(color::const_reference scale) const +{ + return color(r / scale, g / scale, b / scale); +} + + +color& color::operator+=(const color& col) +{ + r += col.r; + g += col.g; + b += col.b; + return *this; +} + + +color& color::operator-=(const color& col) +{ + r -= col.r; + g -= col.g; + b -= col.b; + return *this; +} + + +color& color::operator*=(const color& col) +{ + r *= col.r; + g *= col.g; + b *= col.b; + return *this; +} + + +color& color::operator*=(color::const_reference scale) +{ + r *= scale; + g *= scale; + b *= scale; + return *this; +} + + +color& color::operator/=(const color& col) +{ + r /= col.r; + g /= col.g; + b /= col.b; + return *this; +} + + +color& color::operator/=(color::const_reference scale) +{ + r /= scale; + g /= scale; + b /= scale; + return *this; +} + + + +/////////////// +// Modifiers // +/////////////// +color& color::abs(void) +{ + std::for_each(begin(), end(), [](reference val) + { + if(val<0) val = -val; + }); + return *this; +} + + +color& color::clamp(const_reference lowerBound, const_reference upperBound) +{ + std::for_each(begin(), end(), [&](reference val) + { + if(val < lowerBound) val = lowerBound; + else if(val > upperBound) val = upperBound; + }); + return *this; +} + + +///////////////////// +// Private Methods // +///////////////////// +void color::_assign(const color& col) +{ + r = col.r; + g = col.g; + b = col.b; +} + + +void color::_swap(color& col) +{ + std::swap(r, col.r); + std::swap(g, col.g); + std::swap(b, col.b); +} diff --git a/hw3/src/compoundShader.cpp b/hw3/src/compoundShader.cpp new file mode 100644 index 0000000..5e19f1f --- /dev/null +++ b/hw3/src/compoundShader.cpp @@ -0,0 +1,60 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include +#include "compoundShader.h" + +////////////////// +// Constructors // +////////////////// +compoundShader::compoundShader(const std::vector>& shader_list) + : shader_base() +{ + _compound = shader_list; +} + + +///////////// +// Methods // +///////////// +color compoundShader::shade(const intersectionPoint& ip, const vec3d& light_dir) const +{ + color result(0.0f, 0.0f, 0.0f); + for_each(_compound.begin(), _compound.end(), [&](const std::shared_ptr& shader) + { + result += shader->shade(ip, light_dir); + }); + + // Done. + return result; +} + + +shaderProperties compoundShader::properties(const intersectionPoint& ip) const +{ + // if any component has a property set, then set it for the compound + shaderProperties result(false, false); + for(unsigned int i=0; i < _compound.size(); i++) + result |= _compound[i]->properties(ip); + + // Done. + return result; +} + + +void compoundShader::_print(std::ostream& s) const +{ + s << "Compound Shader (" << _compound.size() << " components): {"; + for(unsigned int i=0; i < _compound.size(); i++) + { + s << *_compound[i]; + if(i != _compound.size()-1) s << ", "; + } + s << "}"; +} diff --git a/hw3/src/coordinateTransform.cpp b/hw3/src/coordinateTransform.cpp new file mode 100644 index 0000000..29e19f4 --- /dev/null +++ b/hw3/src/coordinateTransform.cpp @@ -0,0 +1,67 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "coordinateTransform.h" + +////////////////// +// Constructors // +////////////////// +coordinateTransformation::coordinateTransformation(void) +{ + // do nothing +} + + +coordinateTransformation::coordinateTransformation(const vec3d& normal) +{ + // normal == Z axis + vec3d X, Y, Z = normalize(normal); + + // select Y axis + if(fabs(Z.x) < fabs(Z.y) && fabs(Z.x) < fabs(Z.z)) + Y = normalize(vec3d(0.0f, Z.z, -Z.y)); + else if(fabs(Z.y) < fabs(Z.z)) + Y = normalize(vec3d(Z.z, 0.0f, -Z.x)); + else + Y = normalize(vec3d(Z.y, -Z.x, 0.0f)); + + // create other axis + X = Y.cross(Z).normalize(); + + // copy + _transformation = mat3d(X, Y, Z); + _inverseTransformation = transpose(_transformation); + + // Done. +} + + +coordinateTransformation::coordinateTransformation(const vec3d& normal, const vec3d& axis) +{ + // normal == Z axis + vec3d Z = normalize(normal); + + // create other axis + vec3d axis_normalized = normalize(axis); + vec3d Y = Z.cross(axis_normalized).normalize(); + vec3d X = Y.cross(Z).normalize(); + + // copy + _transformation = mat3d(X, Y, Z); + _inverseTransformation = transpose(_transformation); + + // Done. +} + + +coordinateTransformation::coordinateTransformation(const vec3d& X, const vec3d& Y, const vec3d& Z) +{ + // trust user to provide an orthogonal set of vectors. + _transformation = mat3d(X, Y, Z); + _inverseTransformation = transpose(_transformation); +} diff --git a/hw3/src/diffuseBrdf.cpp b/hw3/src/diffuseBrdf.cpp new file mode 100644 index 0000000..849e341 --- /dev/null +++ b/hw3/src/diffuseBrdf.cpp @@ -0,0 +1,88 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "constants.h" +#include "diffuseBrdf.h" + +////////////////// +// Constructors // +////////////////// +diffuseBrdf::diffuseBrdf(const color& albedo) +{ + _albedo = albedo; +} + + +diffuseBrdf::diffuseBrdf(const diffuseBrdf& src) +{ + _albedo = src._albedo; +} + + +/////////////// +// Operators // +/////////////// +diffuseBrdf& diffuseBrdf::operator=(const diffuseBrdf& src) +{ + _assign(src); + return *this; +} + + +///////////// +// Methods // +///////////// +color diffuseBrdf::shade(const vec3d& in, const vec3d& out) const +{ + // HW3: Implement this. + // Returns the shaded color from a diffuse surface for an + // incident lighting direction of 'in'. The surface normal = (0,0,1). + // Returns: shaded color + // Modifies: nothing. + if (out.z < EPSILON) { return color(0.0f); } + + vec3d normal; + float normal_dot_in; + + normal = vec3d(0, 0, 1); + normal_dot_in = normal.dot(in); + return color(_albedo * normal_dot_in); +} + + +bool diffuseBrdf::isSpecular(void) const +{ + return false; +} + + +bool diffuseBrdf::isDiffuse(void) const +{ + return true; +} + + +///////////////////// +// Private Methods // +///////////////////// +void diffuseBrdf::_assign(const diffuseBrdf& src) +{ + _albedo = src._albedo; +} + + +void diffuseBrdf::_swap(diffuseBrdf& src) +{ + swap(_albedo, src._albedo); +} + +void diffuseBrdf::_print(std::ostream& s) const +{ + s << "Diffuse BRDF: albedo=" << _albedo; +} diff --git a/hw3/src/diffuseReflectanceShader.cpp b/hw3/src/diffuseReflectanceShader.cpp new file mode 100644 index 0000000..3fc9d99 --- /dev/null +++ b/hw3/src/diffuseReflectanceShader.cpp @@ -0,0 +1,35 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include "diffuseReflectanceShader.h" + + +///////////////// +// Constructor // +///////////////// +diffuseReflectanceShader::diffuseReflectanceShader(const colorReflectanceParameter& albedo) + : reflectanceShader_base() +{ + _albedo = albedo; +} + + +/////////////////////// +// Protected Methods // +/////////////////////// +std::unique_ptr diffuseReflectanceShader::make_brdf(const vec2d& textureCoord) const +{ + return std::unique_ptr(new diffuseBrdf( _albedo(textureCoord) )); +} + + +void diffuseReflectanceShader::_print(std::ostream& s) const +{ + s << "Diffuse Reflectance: albedo=" << _albedo; +} diff --git a/hw3/src/directionalLightsource.cpp b/hw3/src/directionalLightsource.cpp new file mode 100644 index 0000000..4c53895 --- /dev/null +++ b/hw3/src/directionalLightsource.cpp @@ -0,0 +1,38 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include "constants.h" +#include "directionalLightsource.h" + +////////////////// +// Constructors // +////////////////// +directionalLightsource::directionalLightsource(const vec3d& direction, const color& power) +{ + _direction = normalize(direction); + _power = power; +} + + +///////////// +// Methods // +///////////// +lightSample directionalLightsource::intensityAt(const vec3d& point) const +{ + return lightSample(_direction, _power, +LARGE); +} + + +///////////////////// +// Private Methods // +///////////////////// +void directionalLightsource::_print(std::ostream& s) const +{ + s << "Directional Lightsource: direction=" << _direction << ", power=" << _power; +} diff --git a/hw3/src/errorMessage.cpp b/hw3/src/errorMessage.cpp new file mode 100644 index 0000000..3eddb6a --- /dev/null +++ b/hw3/src/errorMessage.cpp @@ -0,0 +1,34 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "errorMessage.h" + +#include +#include + +void errorMessage(const char* msg, ...) +{ + printf("ERROR: "); + va_list args; + va_start(args, msg); + vprintf(msg, args); + va_end(args); + printf("\r\n"); + exit(-1); +} + + +void warningMessage(const char* msg, ...) +{ + printf("WARNING: "); + va_list args; + va_start(args, msg); + vprintf(msg, args); + va_end(args); + printf("\r\n"); +} diff --git a/hw3/src/image.cpp b/hw3/src/image.cpp new file mode 100644 index 0000000..59434cc --- /dev/null +++ b/hw3/src/image.cpp @@ -0,0 +1,122 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "image.h" + +#include +#include + +////////////////// +// Constructors // +////////////////// +image::image(image::size_type width, image::size_type height) : _width(width), _height(height), _data() +{ + if(width != 0 && height != 0) + _data.reset(new value_type[width*height]); +} + + +image::image(image::size_type width, image::size_type height, const_reference col) : image(width, height) +{ + std::fill(begin(), end(), col); +} + + +image::image(const image& src) : image(src.width(), src.height()) +{ + std::copy(src.begin(), src.end(), begin()); +} + + +image::image(image&& src) +{ + _swap(src); +} + + +//////////////// +// Inspectors // +//////////////// +image::iterator image::begin(void) +{ + return _data.get(); +} + + +image::const_iterator image::begin(void) const +{ + return _data.get(); +} + + +image::iterator image::end(void) +{ + return begin() + size(); +} + + +image::const_iterator image::end(void) const +{ + return begin() + size(); +} + + +/////////////// +// Operators // +/////////////// +image& image::operator=(const image& src) +{ + _assign(src); + return *this; +} + + +image& image::operator=(image&& src) +{ + _swap(src); + return *this; +} + +image::reference image::operator()(image::size_type x, image::size_type y) +{ + assert(x >= 0 && x < width()); + assert(y >= 0 && y < height()); + return begin()[y*width() + x]; +} + + +image::const_reference image::operator()(image::size_type x, image::size_type y) const +{ + assert(x >= 0 && x < width()); + assert(y >= 0 && y < height()); + return begin()[y*width() + x]; +} + + +///////////////////// +// Private Methods // +///////////////////// +void image::_swap(image& img) +{ + std::swap(_width, img._width); + std::swap(_height, img._height); + std::swap(_data, img._data); +} + + +void image::_assign(const image& src) +{ + // sanity check + if(&src == this) return; + + // make copy + image temp(src); + _swap(temp); + + // Done +} diff --git a/hw3/src/imageIO.cpp b/hw3/src/imageIO.cpp new file mode 100644 index 0000000..cee716b --- /dev/null +++ b/hw3/src/imageIO.cpp @@ -0,0 +1,46 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "util.h" +#include "imageIO.h" +#include "imageIO.ppm.h" +#include "imageIO.pfm.h" +#include "errorMessage.h" + + +//////////// +// Import // +//////////// +void importImage(const std::string& name, image& img) +{ + // get extension + std::string ext = getExtension(name); + if(ext == "") errorMessage("Unable to determine extension in '%s'.", name.c_str()); + + // call image format handler based on extension + if(ext == "PPM" || ext == "ppm") importPPM(name, img); + else if(ext == "PFM" || ext == "pfm") importPFM(name, img); + else errorMessage("Unknown image format: '%s'.", ext.c_str()); +} + + +//////////// +// Export // +//////////// +void exportImage(const std::string& name, const image& img) +{ + // get extension + std::string ext = getExtension(name); + if(ext == "") errorMessage("Unable to determine extension in '%s'.", name.c_str()); + + // call image format handler based on extension + if(ext == "PPM" || ext == "ppm") exportPPM(name, img); + else if(ext == "PFM" || ext == "pfm") exportPFM(name, img); + else errorMessage("Unknown image format: '%s'.", ext.c_str()); +} + diff --git a/hw3/src/imageIO.pfm.cpp b/hw3/src/imageIO.pfm.cpp new file mode 100644 index 0000000..85604a0 --- /dev/null +++ b/hw3/src/imageIO.pfm.cpp @@ -0,0 +1,87 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "imageIO.pfm.h" +#include "errorMessage.h" + +#include +#include +#include + +////////////////////// +// Helper functions // +////////////////////// +static void skipToNewline(std::ifstream& ifs) +{ + while(ifs.get() != '\n' && ifs.good()); +} + +static void skipComments(std::ifstream& ifs) +{ + while(!ifs.eof() && ifs.peek() == '#') skipToNewline(ifs); +} + + +//////////////// +// Import PFM // +//////////////// +void importPFM(const std::string& name, image& img) +{ + // open file + std::ifstream ifs(name.c_str()); + if(!ifs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str()); + + // read header + std::string magicMark; + ifs >> magicMark; + skipToNewline(ifs); + if(magicMark != "PF") errorMessage("Unsupported PFM format (%s).", magicMark.c_str()); + + // read width and height + image::size_type width, height; + skipComments(ifs); + ifs >> width >> height; + skipToNewline(ifs); + + // allocate + img = image(width, height); + + // check magic number (again) + skipComments(ifs); + ifs >> magicMark; + skipToNewline(ifs); + if(magicMark != "-1.000000") errorMessage("Unsupported byte-order in PFM."); + + // read directly in float image + ifs.read((char *)(img.begin()), img.size() * sizeof(color)); + + // Done. +} + + +//////////////// +// Export PFM // +//////////////// +void exportPFM(const std::string& name, const image& img) +{ + // sanity check + assert(img.width() != 0 && img.height() != 0); + + // open file + std::ofstream ofs(name.c_str(), std::ofstream::binary); + if(!ofs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str()); + + // write header + ofs << "PF\n" << img.width() << " " << img.height() << "\n-1.000000\n"; + + // write float buffer + ofs.write((const char*)(img.begin()), img.size() * sizeof(color)); + + // Done. +} + diff --git a/hw3/src/imageIO.ppm.cpp b/hw3/src/imageIO.ppm.cpp new file mode 100644 index 0000000..8a92acb --- /dev/null +++ b/hw3/src/imageIO.ppm.cpp @@ -0,0 +1,106 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "imageIO.ppm.h" +#include "errorMessage.h" + +#include +#include +#include +#include +#include + +////////////////////// +// Helper functions // +////////////////////// +static void skipToNewline(std::ifstream& ifs) +{ + while(ifs.get() != '\n' && ifs.good()); +} + +static void skipComments(std::ifstream& ifs) +{ + while(!ifs.eof() && ifs.peek() == '#') skipToNewline(ifs); +} + + +//////////////// +// Import PPM // +//////////////// +void importPPM(const std::string& name, image& img) +{ + // open file + std::ifstream ifs(name.c_str()); + if(!ifs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str()); + + // read header + std::string magicMark; + ifs >> magicMark; + skipToNewline(ifs); + if(magicMark != "P6") errorMessage("Unsupported PPM format (%s).", magicMark.c_str()); + + // read width & height + image::size_type width, height; + skipComments(ifs); + ifs >> width >> height; + skipToNewline(ifs); + + // allocate + img = image(width, height); + + // check magic number (again) + skipComments(ifs); + ifs >> magicMark; + skipToNewline(ifs); + if(magicMark != "255") errorMessage("Unsupported bit-depth in PPM file (%s).", magicMark.c_str()); + + // read char buffer + std::unique_ptr tempBuffer(new uint8_t[img.size() * 3]); + ifs.read((char *)(tempBuffer.get()), img.size() * 3); + + // convert to image + std::transform(tempBuffer.get(), tempBuffer.get() + (img.size()*3), img.begin()->begin(), [](uint8_t val) + { + return (float)(val) / 255.0f; + }); + + // Done. +} + + +//////////////// +// Export PPM // +//////////////// +void exportPPM(const std::string& name, const image& img) +{ + // sanity check + assert(img.width() != 0 && img.height() != 0); + + // open file + std::ofstream ofs(name.c_str(), std::ofstream::binary); + if(!ofs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str()); + + // write header + ofs << "P6\n" << img.width() << " " << img.height() << "\n" << "255\n"; + + // convert to char buffer + std::unique_ptr tempBuffer(new uint8_t[img.size() * 3]); + std::transform(img.begin()->begin(), img.end()->begin(), tempBuffer.get(), [](float val) + { + return (val < 0.0f) ? 0 : + (val > 1.0f) ? 255 : + uint8_t(val*255); + }); + + // write body + ofs.write((const char*)(tempBuffer.get()), img.size() * 3); + + // Done. +} + + diff --git a/hw3/src/importOBJ.cpp b/hw3/src/importOBJ.cpp new file mode 100644 index 0000000..31df7a1 --- /dev/null +++ b/hw3/src/importOBJ.cpp @@ -0,0 +1,152 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include +#include +#include +#include + +#include "vec3d.h" +#include "vec2d.h" +#include "importOBJ.h" +#include "errorMessage.h" + +void importOBJ(const std::string filename, std::vector& triangle_list) +{ + // define buffers + auto vertex_list = std::make_shared>(); + auto normal_list = std::make_shared>(); + auto textureCoord_list = std::make_shared>(); + + // open obj file + std::ifstream ifs(filename); + if(!ifs.is_open()) + errorMessage("Unable to import OBJ (%s).", filename.c_str()); + + // read line by line + unsigned char key; + while(ifs.good()) + { + // get key + key = ifs.get(); + + // COMMENTS: + if(key == '#' || key == ' ') + { + std::string comment; + ifs >> comment; // comment: skip line + } + + // VERTEX DATA: + else if(key == 'v') + { + // get vertex data + key = ifs.get(); + + // Vertex Coordinate + if(key == ' ') + { + vec3d v; + ifs >> v.x >> v.y >> v.z; + vertex_list->push_back(v); + } + + // Texture Coordinate + else if(key == 't') + { + vec2d t; + ifs >> t.u >> t.v; + textureCoord_list->push_back(t); + } + + // Normal + else if(key == 'n') + { + vec3d n; + ifs >> n.x >> n.y >> n.z; + normal_list->push_back(n); + } + + // Unknown => ERROR + else errorMessage("Unknown OBJ vertex-key: v%c.", key); + } + + // POLYGON: + else if(key == 'f') + { + // temp data structures + std::vector vidx; + std::vector nidx; + std::vector tidx; + + + // get polygon data + // can be either: + // 1) v0 v1 .. vn + // 2) v0//n0 v1//n1 .. vn//nn + // 3) v0/t0 v1/t1 ... vn/tn + // 4) v0/t0/n0 ... vn/tn/nn + bool done=false; + while(!done) + { + // read entry + signed int vi, vt=-1, vn=-1; + ifs >> vi; + unsigned char c = ifs.get(); + + if(c == '/') + { + c = ifs.get(); + if(c != '/') { ifs.unget(); ifs >> vt; c = ifs.get(); } + if(c == '/') { ifs >> vn; } + } + + // store in polygon + if(vt != -1) tidx.push_back(vt-1); + if(vn != -1) nidx.push_back(vn-1); + if(vi != -1) vidx.push_back(vi-1); + + // check if we did not eat the end-of-line chararters + ifs.unget(); + c = ifs.get(); + if(c == '\r' || c == '\n') done = true; + + // eat remaining spaces + c = ifs.get(); + while(c == ' ') + c = ifs.get(); + + // check again for end + if(c == '\r' || c == '\n') done = true; + ifs.unget(); + + // sanity check + assert(tidx.empty() || tidx.size() == vidx.size()); + assert(nidx.empty() || nidx.size() == vidx.size()); + + // store triangle + if(vidx.size() >= 3) + { + size_t m=vidx.size() - 2; + size_t l=vidx.size() - 1; + if(tidx.empty() && nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list) ); + if(tidx.empty() && !nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list, + nidx[0], nidx[m], nidx[l], normal_list) ); + if(!tidx.empty() && nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list, + tidx[0], tidx[m], tidx[l], textureCoord_list) ); + if(!tidx.empty() && !nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list, + nidx[0], nidx[m], nidx[l], normal_list, + tidx[0], tidx[m], tidx[l], textureCoord_list) ); + } + } + } + } + + // Done. +} diff --git a/hw3/src/intersectionPoint.cpp b/hw3/src/intersectionPoint.cpp new file mode 100644 index 0000000..5cec67a --- /dev/null +++ b/hw3/src/intersectionPoint.cpp @@ -0,0 +1,309 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "shader_base.h" +#include "intersectionPoint.h" + +///////////////// +// Constructor // +///////////////// +intersectionPoint::intersectionPoint(void) +{ + _hit = false; +} + + +intersectionPoint::intersectionPoint(const ray& r, float rayParameter, const std::shared_ptr& shader, const vec3d& normal, const vec3d& U, const vec2d& textureCoordinate) +{ + // copy + _ray = r; + _rayParameter = rayParameter; + _hit = true; + _shader = shader; + _normal = normalize(normal); + _U = normalize(U); + _textureCoordinate = textureCoordinate; + + // compute position + _position = _ray(_rayParameter); +} + + +intersectionPoint::intersectionPoint(const intersectionPoint& ip) +{ + _hit = ip._hit; + + // copy remainder if hit + if(_hit) + { + _ray = ip._ray; + _rayParameter = ip._rayParameter; + _shader = ip._shader; + _normal = ip._normal; + _position = ip._position; + _U = ip._U; + _textureCoordinate = ip._textureCoordinate; + } + else _shader = nullptr; +} + +/////////////// +// Operators // +/////////////// +intersectionPoint& intersectionPoint::operator=(const intersectionPoint& ip) +{ + _assign(ip); + return *this; +} + + +bool intersectionPoint::operator<(const intersectionPoint& ip) const +{ + // handle case where either one of the intersectionPoints is not a hit + // => assume no-hit equals a hit at infinity + if(!_hit) return false; + if(!ip._hit) return true; + + // decide based on rayParameter + return _rayParameter < ip._rayParameter; +} + + +bool intersectionPoint::operator>(const intersectionPoint& ip) const +{ + // handle case where either one of the intersectionPoints is not a hit + // => assume no-hit equals a hit at infinity + if(!_hit) return true; + if(!ip._hit) return false; + + // decide based on rayParameter + return _rayParameter > ip._rayParameter; +} + + +bool intersectionPoint::operator<(const lightSample& ls) const +{ + // handle case where this is not a hit + if(!_hit) return false; + + // decide based on rayParameter + return _rayParameter < ls.distance(); +} + + +bool intersectionPoint::operator>(const lightSample& ls) const +{ + // handle case where this is not a hit + if(!_hit) return true; + + // decide based on rayParameter + return _rayParameter > ls.distance(); +} + +//////////////// +// Inspectors // +//////////////// +bool intersectionPoint::isHit(void) const +{ + return _hit; +} + + +shaderProperties intersectionPoint::getShaderProperties(void) const +{ + assert(hasShader()); + return _shader->properties(*this); +} + + +bool intersectionPoint::hasShader(void) const +{ + return (_shader != nullptr); +} + + +float intersectionPoint::distance(const intersectionPoint& ip) const +{ + // set distance to infinity of one of the two points is not a hit + if(!_hit || !ip._hit) return +LARGE; + + // compute distance + return _position.distance(ip._position); +} + + +const vec3d& intersectionPoint::position(void) const +{ + return _position; +} + + +const vec3d& intersectionPoint::direction(void) const +{ + return _ray.direction(); +} + + +const vec2d& intersectionPoint::textureCoordinate(void) const +{ + return _textureCoordinate; +} + + +const vec3d& intersectionPoint::normal(void) const +{ + return _normal; +} + + +coordinateTransformation intersectionPoint::shadingFrame(void) const +{ + // transform => to global shading frame + // inverseTransform => to local shading frame + return coordinateTransformation(_normal, _U); +} + + +////////////// +// Mutators // +////////////// +void intersectionPoint::transform(const transformation3d& t) +{ + // sanity check + if(!_hit) return; + + /// transform + _ray.transform(t); + _position = t.transformPoint(_position); + _normal = t.transformNormal(_normal); + _U = t.transformNormal(_U); + + // recompute the ray parameter (to account for potential scaling) + _rayParameter = _ray(_position); +} + + +void intersectionPoint::inverseTransform(const transformation3d& t) +{ + // sanity check + if(!_hit) return; + + // inverse transform + _ray.inverseTransform(t); + _position = t.inverseTransformPoint(_position); + _normal = t.inverseTransformNormal(_normal); + _U = t.inverseTransformNormal(_U); + + // recompute the ray parameter (to account for potential scaling) + _rayParameter = _ray(_position); +} + + +void intersectionPoint::transformShadingFrame(const transformation3d& sft) +{ + // sanity check + if(!_hit) return; + + // Note: shading frame transformation are defined + // with respect to the local shading frame (i.e., N=Z, U=X) + transformation3d t = shadingFrame(); + + // transform + _normal = t.transformNormal( sft.transformNormal(vec3d(0.0f, 0.0f, 1.0f)) ); + _U = t.transformNormal( sft.transformNormal(vec3d(1.0f, 0.0f, 0.0f)) ); + + // Done. +} + + +void intersectionPoint::inverseTransformShadingFrame(const transformation3d& sft) +{ + // sanity check + if(!_hit) return; + + // Note: shading frame transformation are defined + // with respect to the local shading frame (i.e., N=Z, U=X) + // Note: this transformation will not undo the effects of + // transformShadingFrame since the local shading frame + // is altered by the transformation (and thus the frame + // with respect to which the inverseTransformation is + // applied) + transformation3d t = shadingFrame(); + + // transform + _normal = t.transformNormal( sft.inverseTransformNormal(vec3d(0.0f, 0.0f, 1.0f)) ); + _U = t.transformNormal( sft.inverseTransformNormal(vec3d(1.0f, 0.0f, 0.0f)) ); + + // Done. +} + + +void intersectionPoint::setShader(const std::shared_ptr& shader) +{ + _shader = shader; +} + + +///////////// +// Methods // +///////////// +color intersectionPoint::shade(const vec3d& out) const +{ + assert(hasShader()); + if(!_hit) return color(0.0f); + return _shader->shade(*this, out); +} + +color intersectionPoint::shade(const lightSample& ls) const +{ + // HW3: Implement this. + // Returns the color of shading the intersectionPoint with the light source ls. + // Returns: shaded color + // Modifies: nothing. + assert(_shader); + if (!_hit) { return color(0.0f); } + return _shader->shade(*this, ls.directionToLight()) * ls.emittance(); +} + + +///////////////////// +// Private Methods // +///////////////////// +void intersectionPoint::_assign(const intersectionPoint& ip) +{ + // sanity check + if(&ip == this) return; + + // copy if hit + _hit = ip._hit; + if(_hit) + { + _ray = ip._ray; + _rayParameter = ip._rayParameter; + _position = ip._position; + _normal = ip._normal; + _U = ip._U; + _textureCoordinate = ip._textureCoordinate; + _shader = ip._shader; + } + else _shader = nullptr; +} + + +void intersectionPoint::_swap(intersectionPoint& ip) +{ + swap(_ray, ip._ray); + std::swap(_hit, ip._hit); + std::swap(_rayParameter, ip._rayParameter); + swap(_position, ip._position); + swap(_normal, ip._normal); + swap(_U, ip._U); + swap(_textureCoordinate, ip._textureCoordinate); + std::swap(_shader, ip._shader); +} diff --git a/hw3/src/interval.cpp b/hw3/src/interval.cpp new file mode 100644 index 0000000..4323cbd --- /dev/null +++ b/hw3/src/interval.cpp @@ -0,0 +1,154 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "interval.h" +#include "constants.h" + +////////////////// +// Constrructor // +////////////////// +interval::interval(float lower, float upper) +{ + _lower = lower; + _upper = upper; + + // ensure that _lower < _upper + if(_upper < _lower) std::swap(_upper, _lower); +} + + +interval::interval(const interval& i) +{ + _lower = i._lower; + _upper = i._upper; +} + + + +/////////////// +// Operators // +/////////////// +interval& interval::operator=(const interval& i) +{ + _assign(i); + return *this; +} + + +interval interval::operator+(float v) const +{ + return interval(_lower + v, _upper + v); +} + + +interval interval::operator-(float v) const +{ + return interval(_lower - v, _upper - v); +} + + +interval interval::operator*(float v) const +{ + return interval(_lower * v, _upper * v); +} + + +interval interval::operator/(float v) const +{ + return interval(_lower / v, _upper / v); +} + + +interval& interval::operator+=(float v) +{ + _lower += v; + _upper += v; + return *this; +} + +interval& interval::operator-=(float v) +{ + _lower -= v; + _upper -= v; + return *this; +} + + +interval& interval::operator*=(float v) +{ + _lower *= v; + _upper *= v; + + // ensure that _lower < _upper + if(_upper < _lower) std::swap(_upper, _lower); + + // Done. + return *this; +} + +interval& interval::operator/=(float v) +{ + _lower /= v; + _upper /= v; + + // ensure that _lower < _upper + if(_upper < _lower) std::swap(_upper, _lower); + + // Done. + return *this; +} + + +//////////////// +// Inspectors // +//////////////// +float interval::lower(void) const +{ + return _lower; +} + + +float interval::upper(void) const +{ + return _upper; +} + + +bool interval::empty(void) const +{ + return (_upper - _lower < EPSILON); +} + + + +////////////// +// Mutators // +////////////// +void interval::intersect(const interval& i) +{ + _lower = std::max(_lower, i._lower); + _upper = std::min(_upper, i._upper); +} + + + +///////////////////// +// Private Methods // +///////////////////// +void interval::_assign(const interval& i) +{ + _lower = i._lower; + _upper = i._upper; +} + + +void interval::_swap(interval& i) +{ + std::swap(_lower, i._lower); + std::swap(_upper, i._upper); +} diff --git a/hw3/src/lightSample.cpp b/hw3/src/lightSample.cpp new file mode 100644 index 0000000..5304a9d --- /dev/null +++ b/hw3/src/lightSample.cpp @@ -0,0 +1,121 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "lightSample.h" + + +////////////////// +// Constructors // +////////////////// +lightSample::lightSample(const vec3d& direction, + const color& emittance, + float distance, + float pdf, + float foreshortening) +{ + float length = direction.length(); + _direction = (length < EPSILON) ? vec3d(0.0f, 0.0f, 0.0f) : direction / length; + _emittance = emittance; + _distance = distance; + _pdf = std::max(pdf, 0.0f); + _foreshortening = std::max(foreshortening, 0.0f); +} + + +lightSample::lightSample(const lightSample& ls) +{ + _direction = ls._direction; + _emittance = ls._emittance; + _distance = ls._distance; + _pdf = ls._pdf; + _foreshortening = ls._foreshortening; +} + + +/////////////// +// Operators // +/////////////// +lightSample& lightSample::operator=(const lightSample& ls) +{ + _assign(ls); + return(*this); +} + + +const color& lightSample::operator()(void) const +{ + return _emittance; +} + + +//////////////// +// Inspectors // +//////////////// +const vec3d& lightSample::directionToPoint(void) const +{ + return _direction; +} + + +vec3d lightSample::directionToLight(void) const +{ + return -_direction; +} + + +const color& lightSample::emittance(void) const +{ + return _emittance; +} + + +float lightSample::distance(void) const +{ + return _distance; +} + + +float lightSample::pdf(void) const +{ + return _pdf; +} + + +float lightSample::foreshortening(void) const +{ + return _foreshortening; +} + + +///////////////////// +// Private Methods // +///////////////////// +void lightSample::_assign(const lightSample& ls) +{ + // sanity check + if(&ls == this) return; + + // copy + _direction = ls._direction; + _emittance = ls._emittance; + _distance = ls._distance; + _pdf = ls._pdf; + _foreshortening = ls._foreshortening; +} + + +void lightSample::_swap(lightSample& ls) +{ + swap(_direction, ls._direction); + swap(_emittance, ls._emittance); + std::swap(_distance, ls._distance); + std::swap(_pdf, ls._pdf); + std::swap(_foreshortening, ls._foreshortening); +} + diff --git a/hw3/src/linear_intersector.cpp b/hw3/src/linear_intersector.cpp new file mode 100644 index 0000000..aa0d767 --- /dev/null +++ b/hw3/src/linear_intersector.cpp @@ -0,0 +1,49 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "linear_intersector.h" + +////////////////// +// Constructors // +////////////////// +linear_intersector::linear_intersector(void) + : intersector_base() +{ + // Do nothing +} + + +linear_intersector::linear_intersector(const std::vector>& compounds) + : intersector_base() +{ + _compounds = compounds; +} + + +///////////// +// Methods // +///////////// +intersectionPoint linear_intersector::intersect(const ray& r) const +{ + // HW3: Implement this. + // Returns the nearest intersections point of the ray 'r' with the primitives in '_compounds'. + // Returns: intersection point + // Modifies: nothing + intersectionPoint ip, current; + + for (auto itr = _compounds.begin(); itr != _compounds.end(); itr++) { + + if ((*itr)->hasShader()) { + current = (*itr)->intersect(r); + if (current < ip) { ip = current; } + } + + } + + return ip; +} diff --git a/hw3/src/mat3d.cpp b/hw3/src/mat3d.cpp new file mode 100644 index 0000000..7674777 --- /dev/null +++ b/hw3/src/mat3d.cpp @@ -0,0 +1,260 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include + +#include "mat3d.h" + + +///////////////// +// Constructor // +///////////////// +mat3d::mat3d(void) +{ + clear(0.0f); +} + + +mat3d::mat3d(mat3d::value_type diag) + : mat3d() +{ + setDiagonal(diag); +} + + +mat3d::mat3d(const vec3d& X, const vec3d& Y, const vec3d& Z) +{ + for(size_type i=0; i < 3; i++) + { + this->operator()(i,0) = X[i]; + this->operator()(i,1) = Y[i]; + this->operator()(i,2) = Z[i]; + } +} + + +mat3d::mat3d(const mat3d& m) +{ + _data = m._data; +} + + +//////////////// +// Inspectors // +//////////////// +mat3d::iterator mat3d::begin(void) +{ + return _data.begin(); +} + + +mat3d::const_iterator mat3d::begin(void) const +{ + return _data.begin(); +} + + +mat3d::iterator mat3d::end(void) +{ + return _data.end(); +} + + +mat3d::const_iterator mat3d::end(void) const +{ + return _data.end(); +} + + +////////////// +// Mutators // +////////////// +void mat3d::clear(mat3d::value_type value) +{ + std::fill(begin(), end(), value); +} + + +void mat3d::setDiagonal(mat3d::value_type value) +{ + (*this)(0,0) = (*this)(1,1) = (*this)(2,2) = value; +} + + +mat3d& mat3d::transpose(void) +{ + for(size_type row=0; row < height(); row++) + for(size_type column=row+1; column < width(); column++) + std::swap( (*this)(row,column), (*this)(column,row) ); + return *this; +} + + + +/////////////// +// Operators // +/////////////// +mat3d& mat3d::operator=(const mat3d& m) +{ + _assign(m); + return *this; +} + + +mat3d::reference mat3d::operator()(mat3d::size_type row, mat3d::size_type col) +{ + assert(row < height() && col < width()); + return _data[ row*width() + col]; +} + + +mat3d::const_reference mat3d::operator()(mat3d::size_type row, mat3d::size_type col) const +{ + assert(row < height() && col < width()); + return _data[ row*width() + col]; +} + + +mat3d mat3d::operator+(const mat3d& m) const +{ + mat3d result; + std::transform(begin(), end(), m.begin(), result.begin(), [](const_reference a, const_reference b) + { + return a+b; + }); + return result; +} + + +mat3d mat3d::operator-(const mat3d& m) const +{ + mat3d result; + std::transform(begin(), end(), m.begin(), result.begin(), [](const_reference a, const_reference b) + { + return a-b; + }); + return result; +} + + +mat3d mat3d::operator*(const mat3d& m) const +{ + mat3d result; + for(size_type i=0; i < result.height(); i++) + for(size_type j=0; j < result.width(); j++) + for(size_type k=0; k < width(); k++) + result(i,j) += (*this)(i,k) * m(k, j); + return result; +} + + +vec3d mat3d::operator*(const vec3d& v) const +{ + vec3d result; + for(size_type i=0; i < height(); i++) + for(size_type j=0; j < width(); j++) + result[i] += v[j] * (*this)(i,j); + return result; +} + + +mat3d mat3d::operator*(mat3d::value_type scale) const +{ + mat3d result; + std::transform(begin(), end(), result.begin(), [&](const_reference v) + { + return v * scale; + }); + return result; +} + +mat3d mat3d::operator/(mat3d::value_type scale) const +{ + mat3d result; + std::transform(begin(), end(), result.begin(), [&](const_reference v) + { + return v / scale; + }); + return result; +} + + +mat3d& mat3d::operator+=(const mat3d& m) +{ + std::transform(begin(), end(), m.begin(), begin(), [](const_reference a, const_reference b) + { + return a+b; + }); + return *this; +} + + +mat3d& mat3d::operator-=(const mat3d& m) +{ + std::transform(begin(), end(), m.begin(), begin(), [](const_reference a, const_reference b) + { + return a-b; + }); + return *this; +} + + +mat3d& mat3d::operator*=(const mat3d& m) +{ + *this = *this * m; + return *this; +} + + +mat3d& mat3d::operator*=(mat3d::value_type scale) +{ + std::for_each(begin(), end(), [&](reference v) + { + v *= scale; + }); + return *this; +} + + +mat3d& mat3d::operator/=(mat3d::value_type scale) +{ + std::for_each(begin(), end(), [&](reference v) + { + v /= scale; + }); + return *this; +} + + +///////////////////// +// Private Methods // +///////////////////// +void mat3d::_swap(mat3d& m) +{ + if(&m == this) return; + std::swap(_data, m._data); +} + + +void mat3d::_assign(const mat3d& m) +{ + if(&m == this) return; + _data = m._data; +} + + +vec3d mat3d::_premultiply(const vec3d& v) const +{ + // result = v * *this + vec3d result; + for(size_type i=0; i < height(); i++) + for(size_type j=0; j < width(); j++) + result[j] += v[i] * (*this)(i,j); + return result; +} diff --git a/hw3/src/phongBrdf.cpp b/hw3/src/phongBrdf.cpp new file mode 100644 index 0000000..40f730a --- /dev/null +++ b/hw3/src/phongBrdf.cpp @@ -0,0 +1,99 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "constants.h" +#include "phongBrdf.h" + +////////////////// +// Constructors // +////////////////// +phongBrdf::phongBrdf(const color& albedo, float sharpness) +{ + _albedo = albedo; + _sharpness = sharpness; +} + + +phongBrdf::phongBrdf(const phongBrdf& src) +{ + _albedo = src._albedo; + _sharpness = src._sharpness; +} + + +/////////////// +// Operators // +/////////////// +phongBrdf& phongBrdf::operator=(const phongBrdf& src) +{ + _assign(src); + return *this; +} + + +///////////// +// Methods // +///////////// +color phongBrdf::shade(const vec3d& in, const vec3d& out) const +{ + // HW3: Implement this. + // Returns the phong shaded color from a specular surface for an + // incident lighting direction of 'in', and view direction of 'out'. + // The surface normal = (0,0,1). + // Returns: shaded color + // Modifies: nothing. + if (out.z < EPSILON) { return color(0.0f); } + + vec3d normal, r; + float r_dot_out; + + normal = vec3d(0, 0, 1); + r = (2 * normal.dot(in) * normal) - in; + r_dot_out = r.dot(out); + if (r_dot_out < EPSILON) { return color(0.0f); } + else if (r_dot_out > EPSILON + 1) { r_dot_out = 1; } + return color(_albedo * pow(r_dot_out, _sharpness)); +} + + +bool phongBrdf::isSpecular(void) const +{ + // Consider low roughness to be diffuse. + // Use 5.0f as an arbitrary threshold. + return (_sharpness > 5.0f); +} + + +bool phongBrdf::isDiffuse(void) const +{ + return !isSpecular(); +} + + +///////////////////// +// Private Methods // +///////////////////// +void phongBrdf::_assign(const phongBrdf& src) +{ + _albedo = src._albedo; + _sharpness = src._sharpness; +} + + +void phongBrdf::_swap(phongBrdf& src) +{ + swap(_albedo, src._albedo); + std::swap(_sharpness, src._sharpness); +} + + +void phongBrdf::_print(std::ostream& s) const +{ + s << "Phong BRDF: albedo=" << _albedo << ", sharpness=" << _sharpness; +} diff --git a/hw3/src/phongReflectanceShader.cpp b/hw3/src/phongReflectanceShader.cpp new file mode 100644 index 0000000..c5ac57c --- /dev/null +++ b/hw3/src/phongReflectanceShader.cpp @@ -0,0 +1,36 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include "phongReflectanceShader.h" + + +///////////////// +// Constructor // +///////////////// +phongReflectanceShader::phongReflectanceShader(const colorReflectanceParameter& albedo, const scalarReflectanceParameter& sharpness) + : reflectanceShader_base() +{ + _albedo = albedo; + _sharpness = sharpness; +} + + +/////////////////////// +// Protected Methods // +/////////////////////// +std::unique_ptr phongReflectanceShader::make_brdf(const vec2d& textureCoord) const +{ + return std::unique_ptr(new phongBrdf( _albedo(textureCoord), _sharpness(textureCoord) )); +} + + +void phongReflectanceShader::_print(std::ostream& s) const +{ + s << "Phong Reflectance: albedo=" << _albedo << ", sharpness=" << _sharpness; +} diff --git a/hw3/src/ray.cpp b/hw3/src/ray.cpp new file mode 100644 index 0000000..18c839d --- /dev/null +++ b/hw3/src/ray.cpp @@ -0,0 +1,83 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include "ray.h" + +////////////////// +// Constructors // +////////////////// +ray::ray(const vec3d& origin, const vec3d& direction) +{ + _origin = origin; + _direction = normalize(direction); +} + +ray::ray(const ray& r) +{ + _origin = r._origin; + _direction = r._direction; +} + + +/////////////// +// Operators // +/////////////// +ray& ray::operator=(const ray& r) +{ + _assign(r); + return *this; +} + + +vec3d ray::operator()(float t) const +{ + return _origin + t*_direction; +} + + +float ray::operator()(const vec3d& point) const +{ + return _direction.dot(point - _origin); +} + + +////////////// +// Mutators // +////////////// +ray& ray::transform(const transformation3d& t) +{ + _origin = t.transformPoint(_origin); + _direction = t.transformDirection(_direction); + return *this; +} + + +ray& ray::inverseTransform(const transformation3d& t) +{ + _origin = t.inverseTransformPoint(_origin); + _direction = t.inverseTransformDirection(_direction); + return *this; +} + + +///////////////////// +// Private Methods // +///////////////////// +void ray::_swap(ray& r) +{ + swap(_origin, r._origin); + swap(_direction, r._direction); +} + + +void ray::_assign(const ray& r) +{ + _origin = r._origin; + _direction = r._direction; +} diff --git a/hw3/src/reflectanceParameter.cpp b/hw3/src/reflectanceParameter.cpp new file mode 100644 index 0000000..5b918fb --- /dev/null +++ b/hw3/src/reflectanceParameter.cpp @@ -0,0 +1,140 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "reflectanceParameter.h" + +/******************************/ +/* scalarReflectanceParameter */ +/******************************/ + +///////////////// +// Constructor // +///////////////// +scalarReflectanceParameter::scalarReflectanceParameter(float value) +{ + _value = value; + _texture = nullptr; + _channel = 0.0f; +} + + +scalarReflectanceParameter::scalarReflectanceParameter(const std::shared_ptr& texture, unsigned int channel) +{ + _value = 0.0f; + _texture = texture; + _channel = channel; +} + + +scalarReflectanceParameter::scalarReflectanceParameter(const scalarReflectanceParameter& src) +{ + _value = src._value; + _texture = src._texture; + _channel = src._channel; +} + + +////////////// +// Operator // +////////////// +scalarReflectanceParameter& scalarReflectanceParameter::operator=(const scalarReflectanceParameter& src) +{ + _assign(src); + return *this; +} + + +float scalarReflectanceParameter::operator()(const vec2d& textureCoord) const +{ + if(_texture) return (*_texture)(textureCoord)[_channel]; + else return _value; +} + + +///////////////////// +// Private Methods // +///////////////////// +void scalarReflectanceParameter::_assign(const scalarReflectanceParameter& src) +{ + _value = src._value; + _texture = src._texture; + _channel = src._channel; +} + + +void scalarReflectanceParameter::_swap(scalarReflectanceParameter& swp) +{ + std::swap(_value, swp._value); + std::swap(_texture, swp._texture); + std::swap(_channel, swp._channel); +} + + + +/*****************************/ +/* colorReflectanceParameter */ +/*****************************/ + +///////////////// +// Constructor // +///////////////// +colorReflectanceParameter::colorReflectanceParameter(color value) +{ + _value = value; + _texture = nullptr; +} + + +colorReflectanceParameter::colorReflectanceParameter(const std::shared_ptr& texture) +{ + _value = color(0.0f); + _texture = texture; +} + + +colorReflectanceParameter::colorReflectanceParameter(const colorReflectanceParameter& src) +{ + _value = src._value; + _texture = src._texture; +} + + +////////////// +// Operator // +////////////// +colorReflectanceParameter& colorReflectanceParameter::operator=(const colorReflectanceParameter& src) +{ + _assign(src); + return *this; +} + + +color colorReflectanceParameter::operator()(const vec2d& textureCoord) const +{ + if(_texture) return (*_texture)(textureCoord); + else return _value; +} + + +///////////////////// +// Private Methods // +///////////////////// +void colorReflectanceParameter::_assign(const colorReflectanceParameter& src) +{ + _value = src._value; + _texture = src._texture; +} + + +void colorReflectanceParameter::_swap(colorReflectanceParameter& swp) +{ + std::swap(_value, swp._value); + std::swap(_texture, swp._texture); +} + + diff --git a/hw3/src/reflectanceShader_base.cpp b/hw3/src/reflectanceShader_base.cpp new file mode 100644 index 0000000..8ff81fc --- /dev/null +++ b/hw3/src/reflectanceShader_base.cpp @@ -0,0 +1,39 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "reflectanceShader_base.h" +#include "coordinateTransform.h" + +///////////// +// Methods // +///////////// +color reflectanceShader_base::shade(const intersectionPoint& ip, const vec3d& light_dir) const +{ + // create shading frame (note: in and out point away!) + coordinateTransformation ct = ip.shadingFrame(); + vec3d local_out = ct.inverseTransformDirection(-ip.direction()); + vec3d local_in = ct.inverseTransformDirection(light_dir); + + // get brdf + std::unique_ptr brdf = make_brdf(ip.textureCoordinate()); + + // eval + return brdf->shade(local_in, local_out); +} + + +shaderProperties reflectanceShader_base::properties(const intersectionPoint& ip) const +{ + // get brdf + std::unique_ptr brdf = make_brdf(ip.textureCoordinate()); + + // get properties + return shaderProperties(brdf->isDiffuse(), brdf->isSpecular()); +} + + diff --git a/hw3/src/scene.cpp b/hw3/src/scene.cpp new file mode 100644 index 0000000..4491c03 --- /dev/null +++ b/hw3/src/scene.cpp @@ -0,0 +1,42 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "scene.h" + +//////////////// +// Inspectors // +//////////////// +const camera& scene::getCamera(void) const +{ + return _camera; +} + + +const lightsource_base& scene::getLightsource(size_t idx) const +{ + assert(idx < _lightsources.size()); + return *(_lightsources[idx]); +} + + +size_t scene::numberOfLightsources(void) const +{ + return _lightsources.size(); +} + + +///////////// +// Methods // +///////////// +intersectionPoint scene::intersect(const ray& r) const +{ + return _sceneGraphRoot->intersect(r); +} + + diff --git a/hw3/src/sceneGraphNode.cpp b/hw3/src/sceneGraphNode.cpp new file mode 100644 index 0000000..1a0f600 --- /dev/null +++ b/hw3/src/sceneGraphNode.cpp @@ -0,0 +1,39 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "sceneGraphNode.h" + +////////////////// +// Constructors // +////////////////// +sceneGraphNode::sceneGraphNode(void) + : boundedCompound() +{ + // Do nothing +} + +sceneGraphNode::sceneGraphNode(const std::vector>& nodes, const transformation3d& transform, const std::shared_ptr& shader) + : boundedCompound(transform, shader) +{ + // copy nodes + _nodes = nodes; + + // init bounding box + initializeBoundingBox(); +} + + +///////////// +// Methods // +///////////// +const std::vector>& sceneGraphNode::compounds(void) const +{ + return _nodes; +} + diff --git a/hw3/src/sceneIO.cpp b/hw3/src/sceneIO.cpp new file mode 100644 index 0000000..bffff8e --- /dev/null +++ b/hw3/src/sceneIO.cpp @@ -0,0 +1,87 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "util.h" +#include "scene.h" +#include "sceneGraphNode.h" +#include "linear_intersector.h" + +#include "sceneIO_xml.h" +#include "sceneIO_core.h" +#include "sceneIO_cache.h" +#include "sceneIO_basis.h" +#include "sceneIO_light.h" +#include "sceneIO_geometry.h" +#include "sceneIO_material.h" + + +void importScene(const std::string& filename, scene& s) +{ + // get root + std::string rootDir = getDirectory(filename); + + // open xml + XMLNode sceneNode(filename); + + // check if valid scene node + if(!sceneNode.isValid()) + errorMessage("Failed to find 'scene' in %s.", filename.c_str()); + + // create sceneGraphNode, texture, and shader cache + nodeCache shape_cache; + nodeCache shader_cache; + nodeCache texture_cache; + + // init scene data + bool autoTuneCamera = false; + std::unique_ptr intersector(new linear_intersector_factory()); + + // process sceneNode + for(XMLNode node = sceneNode.firstChild(); node.isValid(); node++) + { + // check for general node-types + if(importMaterial(node, shader_cache, texture_cache, rootDir)) continue; + if(importGeometry(node, shape_cache, shader_cache, texture_cache, rootDir)) continue; + + // check for scene-root specific nodes + std::string nodeName = node.name(); + if(nodeName == "camera") autoTuneCamera = importCamera(node, s._camera); + else if(nodeName == "light") s._lightsources.push_back( importLight(node, shape_cache, shader_cache, texture_cache, rootDir) ); + else if(nodeName == "intersector") importIntersector(node, intersector); + else errorMessage("Unknown node in scene xml: '%s'", nodeName.c_str()); + } + + // initialize all node's intersectors + auto nodeList = shape_cache.allNodes(); + for(auto itr=nodeList.begin(); itr != nodeList.end(); itr++) + static_cast(itr->get())->initialize(*intersector); + nodeList.clear(); + + // add all unreferences nodes to the _sceneGraphRoot. + // Note: remove any node without a shader + decltype(nodeList) unusedNodes; + nodeList = shape_cache.unusedNodes(); + while(!nodeList.empty()) + { + auto bck = nodeList.back(); + if(bck->hasShader()) unusedNodes.push_back(bck); + nodeList.pop_back(); + } + + // -> init + add + std::unique_ptr root(new sceneGraphNode( *(reinterpret_cast< std::vector>* >(&unusedNodes)) )); + root->initialize(*intersector); + s._sceneGraphRoot = std::unique_ptr(root.release()); + + // Auto Tune Camera is requested + if(autoTuneCamera) + s._camera.frameBoundingBox( s._sceneGraphRoot->boundingbox() ); + + // Done. +} + diff --git a/hw3/src/sceneIO_basis.cpp b/hw3/src/sceneIO_basis.cpp new file mode 100644 index 0000000..9149ba2 --- /dev/null +++ b/hw3/src/sceneIO_basis.cpp @@ -0,0 +1,51 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include + +#include "errorMessage.h" +#include "sceneIO_core.h" +#include "sceneIO_basis.h" +#include "sceneIO_cache.h" + +#include "linear_intersector.h" + +bool importCamera(const XMLNode& node, camera& cam) +{ + // sanity check + assert(node.name() == "camera"); + + // import camera + cam = camera( getVec3d(node, "eye", vec3d(0.0f, 0.0f, 0.0f)), + getVec3d(node, "view", vec3d(0.0f, 0.0f, -1.0f)), + getVec3d(node, "up", vec3d(0.0f, 1.0f, 0.0f)), + getFloat(node, "fov", 60), + getInteger(node, "width", 256), + getInteger(node, "height", 256) ); + + // Done. + return( getString(node, "auto", "false") == "true"); +} + + +void importIntersector(const XMLNode& node, std::unique_ptr& intersector) +{ + // sanity check + assert(node.name() == "intersector"); + + // get intersector type + std::string type = getString(node, "type", "linear"); + + // create intersector + if(type == "linear") intersector = std::unique_ptr( new linear_intersector_factory()); + else errorMessage("Unknown intersector type (%s)", type.c_str()); + + // Done. +} + + diff --git a/hw3/src/sceneIO_core.cpp b/hw3/src/sceneIO_core.cpp new file mode 100644 index 0000000..123287e --- /dev/null +++ b/hw3/src/sceneIO_core.cpp @@ -0,0 +1,99 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include + +#include "sceneIO_core.h" +#include "errorMessage.h" + +color getColor(const XMLNode& node, const std::string& name, const color& default_value) +{ + std::string value = node.attribute(name); + + // if defined, process.. + if(value != "") + { + color result; + int s = sscanf(value.c_str(), "%f %f %f", &result.r, &result.g, &result.b); + + // check if only 1 value is given or 3. + if(s == 1) return color(result.r, result.r, result.r); + else if(s == 3) return result; + else errorMessage("Failed to parse color value (%s)", value.c_str()); + } + + // else return default + return default_value; +} + + +vec3d getVec3d(const XMLNode& node, const std::string& name, const vec3d& default_value) +{ + std::string value = node.attribute(name); + + // if defined, process.. + if(value != "") + { + vec3d result; + int s = sscanf(value.c_str(), "%f %f %f", &result.x, &result.y, &result.z); + + // check if only 1 value is given or 3. + if(s == 1) return vec3d(result.x, result.x, result.x); + else if(s == 3) return result; + else errorMessage("Failed to parse vec3d value (%s)", value.c_str()); + } + + // else return default + return default_value; +} + + +vec2d getVec2d(const XMLNode& node, const std::string& name, const vec2d& default_value) +{ + std::string value = node.attribute(name); + + // if defined, process.. + if(value != "") + { + vec2d result; + int s = sscanf(value.c_str(), "%f %f", &result.x, &result.y); + + // check if only 1 value is given or 2. + if(s == 1) return vec2d(result.x, result.x); + else if(s == 2) return result; + else errorMessage("Failed to parse vec2d value (%s)", value.c_str()); + } + + // else returnd default + return default_value; +} + + +std::string getString(const XMLNode& node, const std::string& name, const std::string& default_value) +{ + std::string value = node.attribute(name); + if(value != "") return std::string(value); + else return default_value; +} + + +float getFloat(const XMLNode& node, const std::string& name, float default_value) +{ + std::string value = node.attribute(name); +if(value != "") return atof(value.c_str()); + else return default_value; +} + + +unsigned int getInteger(const XMLNode& node, const std::string& name, unsigned int default_value) +{ + std::string value = node.attribute(name); +if(value != "") return atoi(value.c_str()); + else return default_value; +} diff --git a/hw3/src/sceneIO_geometry.cpp b/hw3/src/sceneIO_geometry.cpp new file mode 100644 index 0000000..dd15ddb --- /dev/null +++ b/hw3/src/sceneIO_geometry.cpp @@ -0,0 +1,153 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include +#include +#include +#include + +#include "sceneIO_xml.h" +#include "sceneIO_core.h" +#include "sceneIO_cache.h" +#include "sceneIO_geometry.h" +#include "sceneIO_material.h" + +#include "util.h" +#include "vec2d.h" +#include "vec3d.h" +#include "triangle.h" +#include "constants.h" +#include "importOBJ.h" +#include "errorMessage.h" +#include "triangleMesh.h" +#include "random_number.h" +#include "sceneGraphNode.h" + +static void importTriangle(const XMLNode& node, std::vector& triangle_list) +{ + // sanity check + assert(node.name() == "triangle" || node.name() == "polygon"); + + // allocate temp data + unsigned int idx=0; + vec3d v[3], n[3]; + vec2d t[3]; + + // for each child node, parse all vertices + for(XMLNode child = node.firstChild(); child.isValid(); child++) + { + std::string name = child.name(); + if(name == "vertex") + { + v[idx] = getVec3d(child, "v", vec3d(+LARGE)); + n[idx] = getVec3d(child, "n", vec3d(0.0f)); + t[idx] = getVec2d(child, "t", vec2d(+LARGE)); + + // check if valid vertex + if(v[idx].x >= +LARGE || v[idx].y >= +LARGE || v[idx].z >= +LARGE) + errorMessage("Invalid vertex in %s definition.", node.name().c_str()); + + // create triangle + if(idx == 2) + { + // determine which attributes are defined on the triangle + bool hasNormals = (n[0].squared_length() > +EPSILON) && (n[0].squared_length() > +EPSILON) && (n[0].squared_length() > +EPSILON); + bool hasTextureCoord = (fabs(t[0].x) < +LARGE && fabs(t[0].y) < +LARGE) && (fabs(t[1].x) < +LARGE && fabs(t[1].y) < +LARGE) && (fabs(t[2].x) < +LARGE && fabs(t[2].y) < +LARGE); + + if(!hasNormals && !hasTextureCoord) triangle_list.push_back(triangle(v[0], v[1], v[2])); + else if(hasNormals && !hasTextureCoord) triangle_list.push_back(triangle(v[0], v[1], v[2], n[1], n[2], n[3])); + else if(!hasNormals && hasTextureCoord) triangle_list.push_back(triangle(v[0], v[1], v[2], t[0], t[1], t[2])); + else triangle_list.push_back(triangle(v[0], v[1], v[2], n[1], n[2], n[3], t[0], t[1], t[2])); + + // cycle (to support polygons) + v[1] = v[2]; + n[1] = v[2]; + t[1] = t[2]; + } + else idx++; + } + else errorMessage("Unknown child element in %s node (%s).", node.name().c_str(), name.c_str()); + } + + // check if at least one full triangle was found + if(idx != 2) + errorMessage("%s requires at least 3 vertices.", node.name().c_str()); + + // Done. + } + + +///////////////////////////////////////////////////////////////// +static std::shared_ptr importTriangleMesh(const XMLNode& node, nodeCache& shape_cache, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) +{ + // sanity check + assert(node.name() == "triangleMesh"); + + // allocate node properties + transformation3d transform; + std::shared_ptr material; + std::vector triangle_list; + + // import OBJ triangles + std::string objname = getString(node, "filename"); + if(objname != "") + { + std::string path = getDirectory(objname); + if(path == "") objname = rootDir + objname; + importOBJ(objname, triangle_list); + } + + // check child nodes + for(XMLNode child = node.firstChild(); child.isValid(); child++) + { + std::string name = child.name(); + + // general child nodes + auto tempmat = importMaterial(child, shader_cache, texture_cache, rootDir); + if(tempmat) material = tempmat; + + // specialized child nodes + else if(name == "triangle" || name == "polygon") importTriangle(child, triangle_list); + else errorMessage("Unknown child-node in triangleMesh (%s).", name.c_str()); + } + + // Done. + return std::shared_ptr(new triangleMesh(triangle_list, material, transform)); +} + +///////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////// +std::shared_ptr importGeometry(const XMLNode& node, nodeCache& shape_cache, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) +{ + // check if geometry type + if(node.name() != "sceneGraphNode" && node.name() != "triangleMesh") return std::shared_ptr(nullptr); + + // check if reference + std::string ref = getString(node, "ref"); + std::shared_ptr shape = shape_cache.get(ref); + if(shape) return shape; + else if(ref != "") errorMessage("Unknown %s name (%s).", node.name().c_str(), ref.c_str()); + + // generate default name & get id + char defaultname[32]; sprintf(defaultname, "noname-%u", random_int()); + std::string id = getString(node, "id", defaultname); + + if(shape_cache.get(id)) + errorMessage("%s-node id is not unique (%s).", node.name().c_str(), id.c_str()); + + // process primitive based on type + else if(node.name() == "triangleMesh") shape = importTriangleMesh(node, shape_cache, shader_cache, texture_cache, rootDir); + + // update cache + if(id != "") shape_cache.add(id, shape); + + // Done. + return shape; +} diff --git a/hw3/src/sceneIO_light.cpp b/hw3/src/sceneIO_light.cpp new file mode 100644 index 0000000..bb9e399 --- /dev/null +++ b/hw3/src/sceneIO_light.cpp @@ -0,0 +1,51 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include + +#include "errorMessage.h" +#include "random_number.h" + +#include "sceneIO_core.h" +#include "sceneIO_basis.h" +#include "sceneIO_light.h" +#include "sceneIO_material.h" +#include "sceneIO_geometry.h" + +#include "directionalLightsource.h" + +static std::shared_ptr importDirectionalLight(const XMLNode& node) +{ + // get properties + vec3d direction = getVec3d(node, "direction", vec3d(0.0f, 0.0f, 1.0f)); + color power = getColor(node, "power", color(1.0f, 1.0f, 1.0f)); + + // Done. + return std::shared_ptr( new directionalLightsource( direction, power)); +} + + +std::shared_ptr importLight(const XMLNode& node, nodeCache& shape_cache, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) +{ + // sanity check + assert(node.name() == "light"); + + // get light source type + std::string type = getString(node, "type", "directional"); + + // create light source + std::shared_ptr ls; + if(type == "directional") ls = importDirectionalLight(node); + else errorMessage("Unknown light source type (%s)", type.c_str()); + + // Done. + return ls; +} + + + diff --git a/hw3/src/sceneIO_material.cpp b/hw3/src/sceneIO_material.cpp new file mode 100644 index 0000000..018e913 --- /dev/null +++ b/hw3/src/sceneIO_material.cpp @@ -0,0 +1,147 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include + +#include "sceneIO_xml.h" +#include "sceneIO_core.h" +#include "sceneIO_material.h" + +#include "compoundShader.h" +#include "reflectanceParameter.h" +#include "phongReflectanceShader.h" +#include "diffuseReflectanceShader.h" + +////////////////////////////////////////////////////////////// +static colorReflectanceParameter importColorReflectanceParameter(const XMLNode& node, nodeCache& texture_cache, const std::string& rootDir) +{ + // get parameter + color value = getColor(node, "value", color(0.0f, 0.0f, 0.0f)); + + // create & return parameter, give preference to textured parameters + return colorReflectanceParameter(value); + + // Done. +} + +////////////////////////////////////////////////////////////// +static scalarReflectanceParameter importScalarReflectanceParameter(const XMLNode& node, nodeCache& texture_cache, const std::string& rootDir) +{ + // get parameters + float value = getFloat(node, "value", 0.0f); + unsigned int channel = getInteger(node, "channel", 0); + + // create & return parameter, give preference to textured parameters + return scalarReflectanceParameter(value); + + // Done. +} + +////////////////////////////////////////////////////////////// +static std::shared_ptr importDiffuse(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) +{ + // sanity check + assert(node.name() == "diffuse"); + + // parameter storage + colorReflectanceParameter albedo; + + // check child nodes + for(XMLNode child=node.firstChild(); child.isValid(); child++) + { + std::string name = child.name(); + if(name == "albedo") albedo = importColorReflectanceParameter(child, texture_cache, rootDir); + else errorMessage("Unknown parameter in diffuse-node (%s).", name.c_str()); + } + + // Done. + return std::shared_ptr(new diffuseReflectanceShader(albedo)); +} + +////////////////////////////////////////////////////////////// +static std::shared_ptr importPhong(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) +{ + // sanity check + assert(node.name() == "phong"); + + // parameter storage + colorReflectanceParameter albedo; + scalarReflectanceParameter sharpness; + + // check child nodes + for(XMLNode child=node.firstChild(); child.isValid(); child++) + { + std::string name = child.name(); + if(name == "albedo") albedo = importColorReflectanceParameter(child, texture_cache, rootDir); + else if(name == "sharpness") sharpness = importScalarReflectanceParameter(child, texture_cache, rootDir); + else errorMessage("Unknown parameter in phong-node (%s).", name.c_str()); + } + + // Done. + return std::shared_ptr(new phongReflectanceShader(albedo, sharpness)); +} + +////////////////////////////////////////////////////////////// +static std::shared_ptr importCompoundMaterial(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) +{ + // sanity check + assert(node.isValid() && node.name() == "material"); + + // storage for child material nodes + std::vector> shader_list; + + // for each child + for(XMLNode child = node.firstChild(); child.isValid(); child++) + { + // try to import material + std::shared_ptr shader = importMaterial(child, shader_cache, texture_cache, rootDir); + + // add to list if successful. + if(shader) shader_list.push_back(shader); + else errorMessage("Unknown material-node (%s).", child.name().c_str()); + } + + // Done. + return std::shared_ptr(new compoundShader(shader_list)); +} + + +////////////////////////////////////////////////////////////// +std::shared_ptr importMaterial(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) +{ + std::string name = node.name(); + + // check material type + if(name != "material" && + name != "diffuse" && + name != "phong") return std::shared_ptr(nullptr); + + // check if reference + std::string ref = getString(node, "ref"); + std::shared_ptr shader = shader_cache.get(ref); + if(shader) return shader; + else if(ref != "") errorMessage("Unknown %s name (%s).", name.c_str(), ref.c_str()); + + // get id + std::string id = getString(node, "id"); + if(shader_cache.get(id)) + errorMessage("%s-id is not unique (%s).", name.c_str(), id.c_str()); + + // process primitives based on type + if(name == "material") shader = importCompoundMaterial(node, shader_cache, texture_cache, rootDir); + else if(name == "diffuse") shader = importDiffuse(node, shader_cache, texture_cache, rootDir); + else if(name == "phong") shader = importPhong(node, shader_cache, texture_cache, rootDir); + else errorMessage("Unknown material-node (%s).", name.c_str()); + + // update cache + if(id != "") shader_cache.add(id, shader); + + // Done. + return shader; +} + diff --git a/hw3/src/sceneIO_xml.cpp b/hw3/src/sceneIO_xml.cpp new file mode 100644 index 0000000..6f96480 --- /dev/null +++ b/hw3/src/sceneIO_xml.cpp @@ -0,0 +1,109 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "sceneIO_xml.h" +#include "errorMessage.h" + +///////////////// +// Constructor // +///////////////// +XMLNode::XMLNode(const std::string& filename) +{ + // open xml + _xml = std::make_shared(); + _xml->LoadFile(filename.c_str()); + + // check if open successful + if(_xml->ErrorID() != tinyxml2::XML_SUCCESS) + errorMessage("Failed to open scene file: '%s'.", filename.c_str()); + + // set first node. + _element = _xml->FirstChildElement("scene"); +} + + +XMLNode::XMLNode(const XMLNode& node) +{ + _element = node._element; + _xml = node._xml; +} + +XMLNode::XMLNode(const tinyxml2::XMLElement* element, const std::shared_ptr& xml) +{ + _element = element; + _xml = xml; +} + + +///////////// +// Methods // +///////////// +XMLNode XMLNode::firstChild(void) const +{ + assert(isValid()); + return XMLNode(_element->FirstChildElement(), _xml); +} + + +XMLNode XMLNode::findChild(const std::string& name) const +{ + assert(isValid()); + return XMLNode(_element->FirstChildElement(name.c_str()), _xml); +} + + +bool XMLNode::isValid(void) const +{ + return (_element != NULL); +} + + +std::string XMLNode::name(void) const +{ + assert(isValid()); + return std::string(_element->Name()); +} + + +std::string XMLNode::attribute(const std::string& attribute) const +{ + assert(isValid()); + + const char* str = _element->Attribute(attribute.c_str()); + if(str == NULL) return std::string(""); + + // Done. + return std::string(str); +} + + +/////////////// +// Operators // +/////////////// +XMLNode& XMLNode::operator=(const XMLNode& src) +{ + _element = src._element; + _xml = src._xml; +} + + +XMLNode& XMLNode::operator++(int) +{ + assert(_element != NULL); + _element = _element->NextSiblingElement(); +} + + +XMLNode& XMLNode::operator++(void) +{ + assert(_element != NULL); + _element = _element->NextSiblingElement(); +} + + diff --git a/hw3/src/shaderProperties.cpp b/hw3/src/shaderProperties.cpp new file mode 100644 index 0000000..aad680b --- /dev/null +++ b/hw3/src/shaderProperties.cpp @@ -0,0 +1,59 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "shaderProperties.h" + + +////////////// +// Operator // +////////////// +bool shaderProperties::operator==(const shaderProperties& sp) const +{ + return (diffuse == sp.diffuse) && (specular == sp.specular); +} + + +bool shaderProperties::operator!=(const shaderProperties& sp) const +{ + return !(*this == sp); +} + + +shaderProperties& shaderProperties::operator&=(const shaderProperties& sp) +{ + diffuse &= sp.diffuse; + specular &= sp.specular; +} + + +shaderProperties& shaderProperties::operator|=(const shaderProperties& sp) +{ + diffuse |= sp.diffuse; + specular |= sp.specular; +} + + +shaderProperties& shaderProperties::operator~(void) +{ + diffuse = ~diffuse; + specular = ~specular; +} + + +shaderProperties shaderProperties::operator&(const shaderProperties& sp) const +{ + return shaderProperties(diffuse & sp.diffuse, + specular & sp.specular); +} + + +shaderProperties shaderProperties::operator|(const shaderProperties& sp) const +{ + return shaderProperties(diffuse | sp.diffuse, + specular | sp.specular); +} diff --git a/hw3/src/tinyxml2.cpp b/hw3/src/tinyxml2.cpp new file mode 100644 index 0000000..c4ea7cd --- /dev/null +++ b/hw3/src/tinyxml2.cpp @@ -0,0 +1,2466 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml2.h" + +#include // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__QNXNTO__) +# include +# include +#else +# include +# include +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + + +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::TransferTo( StrPair* other ) +{ + if ( this == other ) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT( other->_flags == 0 ); + TIXMLASSERT( other->_start == 0 ); + TIXMLASSERT( other->_end == 0 ); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; +} + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + delete [] _start; + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + TIXMLASSERT( str ); + Reset(); + size_t len = strlen( str ); + TIXMLASSERT( _start == 0 ); + _start = new char[ len+1 ]; + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) +{ + TIXMLASSERT( endTag && *endTag ); + + char* start = p; + char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } + ++p; + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + if ( !p || !(*p) ) { + return 0; + } + if ( !XMLUtil::IsNameStartChar( *p ) ) { + return 0; + } + + char* const start = p; + ++p; + while ( *p && XMLUtil::IsNameChar( *p ) ) { + ++p; + } + + Set( start, p, 0 ); + return p; +} + + +void StrPair::CollapseWhitespace() +{ + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start ); + + if ( *_start ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q++ = LF; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } + } + else { + bool entityFound = false; + for( int i = 0; i < NUM_ENTITIES; ++i ) { + const Entity& entity = entities[i]; + if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 + && *( p + entity.length + 1 ) == ';' ) { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if ( !entityFound ) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT( _start ); + return _start; +} + + + + +// --------- XMLUtil ----------- // + +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( bom ); + *bom = false; + const unsigned char* pu = reinterpret_cast(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + TIXMLASSERT( p ); + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs. + switch (*length) { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT( false ); + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + const char* q = p+3; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != 'x' ) { + unsigned int digit = 0; + + if ( *q >= '0' && *q <= '9' ) { + digit = *q - '0'; + } + else if ( *q >= 'a' && *q <= 'f' ) { + digit = *q - 'a' + 10; + } + else if ( *q >= 'A' && *q <= 'F' ) { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT( digit >= 0 && digit < 16); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p+2; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit >= 0 && digit < 10); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT( mult <= UINT_MAX / 10 ); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 ); +} + +/* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 +*/ +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); +} + + +bool XMLUtil::ToInt( const char* str, int* value ) +{ + if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) +{ + if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + if ( StringEqual( str, "true" ) ) { + *value = true; + return true; + } + else if ( StringEqual( str, "false" ) ) { + *value = false; + return true; + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( p ); + char* const start = p; + p = XMLUtil::SkipWhiteSpace( p ); + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "_memPool = &_commentPool; + p += xmlHeaderLen; + } + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); + returnNode = new (_commentPool.Alloc()) XMLComment( this ); + returnNode->_memPool = &_commentPool; + p += commentHeaderLen; + } + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + XMLText* text = new (_textPool.Alloc()) XMLText( this ); + returnNode = text; + returnNode->_memPool = &_textPool; + p += cdataHeaderLen; + text->SetCData( true ); + } + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); + returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); + returnNode->_memPool = &_commentPool; + p += dtdHeaderLen; + } + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { + TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); + returnNode = new (_elementPool.Alloc()) XMLElement( this ); + returnNode->_memPool = &_elementPool; + p += elementHeaderLen; + } + else { + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + returnNode = new (_textPool.Alloc()) XMLText( this ); + returnNode->_memPool = &_textPool; + p = start; // Back it up, all the text counts. + } + + TIXMLASSERT( returnNode ); + TIXMLASSERT( p ); + *node = returnNode; + return p; +} + + +bool XMLDocument::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLNode ----------- // + +XMLNode::XMLNode( XMLDocument* doc ) : + _document( doc ), + _parent( 0 ), + _firstChild( 0 ), _lastChild( 0 ), + _prev( 0 ), _next( 0 ), + _memPool( 0 ) +{ +} + + +XMLNode::~XMLNode() +{ + DeleteChildren(); + if ( _parent ) { + _parent->Unlink( this ); + } +} + +const char* XMLNode::Value() const +{ + // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr. + if ( this->ToDocument() ) + return 0; + return _value.GetStr(); +} + +void XMLNode::SetValue( const char* str, bool staticMem ) +{ + if ( staticMem ) { + _value.SetInternedStr( str ); + } + else { + _value.SetStr( str ); + } +} + + +void XMLNode::DeleteChildren() +{ + while( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_document == _document ); + XMLNode* node = _firstChild; + Unlink( node ); + + DeleteNode( node ); + } + _firstChild = _lastChild = 0; +} + + +void XMLNode::Unlink( XMLNode* child ) +{ + TIXMLASSERT( child ); + TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); + if ( child == _firstChild ) { + _firstChild = _firstChild->_next; + } + if ( child == _lastChild ) { + _lastChild = _lastChild->_prev; + } + + if ( child->_prev ) { + child->_prev->_next = child->_next; + } + if ( child->_next ) { + child->_next->_prev = child->_prev; + } + child->_parent = 0; +} + + +void XMLNode::DeleteChild( XMLNode* node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( node->_document == _document ); + TIXMLASSERT( node->_parent == this ); + Unlink( node ); + DeleteNode( node ); +} + + +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _lastChild ) { + TIXMLASSERT( _firstChild ); + TIXMLASSERT( _lastChild->_next == 0 ); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT( _firstChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_prev == 0 ); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT( _lastChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + + TIXMLASSERT( afterThis ); + + if ( afterThis->_parent != this ) { + TIXMLASSERT( false ); + return 0; + } + + if ( afterThis->_next == 0 ) { + // The last node or the only node. + return InsertEndChild( addThis ); + } + InsertChildPreamble( addThis ); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; +} + + + + +const XMLElement* XMLNode::FirstChildElement( const char* name ) const +{ + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElement(); + if ( element ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + } + } + return 0; +} + + +const XMLElement* XMLNode::LastChildElement( const char* name ) const +{ + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElement(); + if ( element ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + } + } + return 0; +} + + +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _next; node; node = node->_next ) { + const XMLElement* element = node->ToElement(); + if ( element + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _prev; node; node = node->_prev ) { + const XMLElement* element = node->ToElement(); + if ( element + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + return element; + } + } + return 0; +} + + +char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) +{ + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // + // + // + // With a special case: + // + // + // + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + if ( node == 0 ) { + break; + } + + StrPair endTag; + p = node->ParseDeep( p, &endTag ); + if ( !p ) { + DeleteNode( node ); + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, 0, 0 ); + } + break; + } + + XMLDeclaration* decl = node->ToDeclaration(); + if ( decl ) { + // A declaration can only be the first child of a document. + // Set error, if document already has children. + if ( !_document->NoChildren() ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0); + DeleteNode( decl ); + break; + } + } + + XMLElement* ele = node->ToElement(); + if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEnd ) { + ele->_value.TransferTo( parentEnd ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } + } + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { + mismatch = true; + } + } + if ( mismatch ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 ); + DeleteNode( node ); + break; + } + } + InsertEndChild( node ); + } + return 0; +} + +void XMLNode::DeleteNode( XMLNode* node ) +{ + if ( node == 0 ) { + return; + } + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free( node ); +} + +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if ( insertThis->_parent ) + insertThis->_parent->Unlink( insertThis ); + else + insertThis->_memPool->SetTracked(); +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair* ) +{ + const char* start = p; + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText( p, "<", flags ); + if ( p && *p ) { + return p-1; + } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + const XMLText* text = compare->ToText(); + return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair* ) +{ + // Comment parses as text. + const char* start = p; + p = _value.ParseText( p, "-->", StrPair::COMMENT ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLComment* comment = compare->ToComment(); + return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair* ) +{ + // Declaration parses as text. + const char* start = p; + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair* ) +{ + // Unknown parses as text. + const char* start = p; + + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLUnknown* unknown = compare->ToUnknown(); + return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // + +const char* XMLAttribute::Name() const +{ + return _name.GetStr(); +} + +const char* XMLAttribute::Value() const +{ + return _value.GetStr(); +} + +char* XMLAttribute::ParseDeep( char* p, bool processEntities ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_NO_ERROR; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( 0 ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute( _rootAttribute ); + _rootAttribute = next; + } +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + + +const char* XMLElement::GetText() const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + return FirstChild()->Value(); + } + return 0; +} + + +void XMLElement::SetText( const char* inText ) +{ + if ( FirstChild() && FirstChild()->ToText() ) + FirstChild()->SetValue( inText ); + else { + XMLText* theText = GetDocument()->NewText( inText ); + InsertFirstChild( theText ); + } +} + + +void XMLElement::SetText( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + if ( last ) { + last->_next = attrib; + } + else { + _rootAttribute = attrib; + } + attrib->SetName( name ); + attrib->_memPool->SetTracked(); // always created and linked. + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p ) +{ + const char* start = p; + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p ); + if ( !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar( *p ) ) { + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + + p = attrib->ParseDeep( p, _document->ProcessEntities() ); + if ( !p || Attribute( attrib->Name() ) ) { + DeleteAttribute( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + prevAttribute->_next = attrib; + } + else { + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); + return 0; + } + } + return p; +} + +void XMLElement::DeleteAttribute( XMLAttribute* attribute ) +{ + if ( attribute == 0 ) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free( attribute ); +} + +// +// +// foobar +// +char* XMLElement::ParseDeep( char* p, StrPair* strPair ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p ); + + // The closing element is the form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p ); + if ( !p || !*p || _closingType ) { + return p; + } + + p = XMLNode::ParseDeep( p, strPair ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // + +// Warning: List must match 'enum XMLError' +const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "XML_ERROR_ELEMENT_MISMATCH", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "XML_ERROR_IDENTIFYING_TAG", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE" +}; + + +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID( XML_NO_ERROR ), + _whitespace( whitespace ), + _errorStr1( 0 ), + _errorStr2( 0 ), + _charBuffer( 0 ) +{ + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; +} + + +XMLDocument::~XMLDocument() +{ + Clear(); +} + + +void XMLDocument::Clear() +{ + DeleteChildren(); + +#ifdef DEBUG + const bool hadError = Error(); +#endif + _errorID = XML_NO_ERROR; + _errorStr1 = 0; + _errorStr2 = 0; + + delete [] _charBuffer; + _charBuffer = 0; + +#if 0 + _textPool.Trace( "text" ); + _elementPool.Trace( "element" ); + _commentPool.Trace( "comment" ); + _attributePool.Trace( "attribute" ); +#endif + +#ifdef DEBUG + if ( !hadError ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); + XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this ); + ele->_memPool = &_elementPool; + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); + XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this ); + comment->_memPool = &_commentPool; + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); + XMLText* text = new (_textPool.Alloc()) XMLText( this ); + text->_memPool = &_textPool; + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); + XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this ); + dec->_memPool = &_commentPool; + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); + XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this ); + unk->_memPool = &_commentPool; + unk->SetValue( str ); + return unk; +} + +static FILE* callfopen( const char* filepath, const char* mode ) +{ + TIXMLASSERT( filepath ); + TIXMLASSERT( mode ); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filepath, mode ); + if ( err ) { + return 0; + } +#else + FILE* fp = fopen( filepath, mode ); +#endif + return fp; +} + +void XMLDocument::DeleteNode( XMLNode* node ) { + TIXMLASSERT( node ); + TIXMLASSERT(node->_document == this ); + if (node->_parent) { + node->_parent->DeleteChild( node ); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + Clear(); + FILE* fp = callfopen( filename, "rb" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + +// This is likely overengineered template art to have a check that unsigned long value incremented +// by one still fits into size_t. If size_t type is larger than unsigned long type +// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit +// -Wtype-limits warning. This piece makes the compiler select code with a check when a check +// is useful and code with no check when a check is redundant depending on how size_t and unsigned long +// types sizes relate to each other. +template += sizeof(size_t))> +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long value ) + { + return value < (size_t)-1; + } +}; + +template <> +bool LongFitsIntoSizeTMinusOne::Fits( unsigned long /*value*/ ) +{ + return true; +} + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + Clear(); + + fseek( fp, 0, SEEK_SET ); + if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + fseek( fp, 0, SEEK_END ); + const long filelength = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + if ( filelength == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + const size_t size = filelength; + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[size+1]; + size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + FILE* fp = callfopen( filename, "w" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + SetError( XML_NO_ERROR, 0, 0 ); + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + Clear(); + + if ( len == 0 || !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == (size_t)(-1) ) { + len = strlen( p ); + } + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[ len+1 ]; + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + Parse(); + if ( Error() ) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) const +{ + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); + } +} + + +void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) +{ + TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + _errorID = error; + _errorStr1 = str1; + _errorStr2 = str2; +} + +const char* XMLDocument::ErrorName() const +{ + TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); + const char* errorName = _errorNames[_errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; +} + +void XMLDocument::PrintError() const +{ + if ( Error() ) { + static const int LEN = 20; + char buf1[LEN] = { 0 }; + char buf2[LEN] = { 0 }; + + if ( _errorStr1 ) { + TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); + } + if ( _errorStr2 ) { + TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); + } + + // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that + // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning + TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX ); + printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n", + static_cast( _errorID ), ErrorName(), buf1, buf2 ); + } +} + +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p ); + p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0 ); +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : + _elementJustOpened( false ), + _firstElement( true ), + _fp( file ), + _depth( depth ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ) +{ + for( int i=0; i'] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + const int len = TIXML_VSCPRINTF( format, va ); + // Close out and re-start the va-args + va_end( va ); + TIXMLASSERT( len >= 0 ); + va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); + char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. + TIXML_VSNPRINTF( p, len+1, format, va ); + } + va_end( va ); +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[(unsigned char)(*q)] ) { + while ( p < q ) { + const size_t delta = q - p; + // %.*s accepts type int as "precision" + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + Print( "%.*s", toPrint, p ); + p += toPrint; + } + bool entityPatternPrinted = false; + for( int i=0; i" ); + } + else { + if ( _textDepth < 0 && !compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + Print( "", name ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !compactMode) { + Print( "\n" ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElementIfJustOpened() +{ + if ( !_elementJustOpened ) { + return; + } + _elementJustOpened = false; + Print( ">" ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + SealElementIfJustOpened(); + if ( cdata ) { + Print( "", text ); + } + else { + PrintString( text, true ); + } +} + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", comment ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", value ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Print( "\n" ); + PrintSpace( _depth ); + } + _firstElement = false; + Print( "", value ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; + OpenElement( element.Name(), compactMode ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& element ) +{ + CloseElement( CompactMode(element) ); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 + diff --git a/hw3/src/transformation3d.cpp b/hw3/src/transformation3d.cpp new file mode 100644 index 0000000..bde9caa --- /dev/null +++ b/hw3/src/transformation3d.cpp @@ -0,0 +1,174 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "transformation3d.h" + + +////////////////// +// Constructors // +////////////////// +transformation3d::transformation3d(void) +{ + _translation = vec3d(); + _transformation = mat3d(1.0f); + _inverseTransformation = mat3d(1.0f); +} + + +transformation3d::transformation3d(const vec3d& translation, const mat3d& transformation, const mat3d& inverseTransformation) +{ + _translation = translation; + _transformation = transformation; + _inverseTransformation = inverseTransformation; +} + + +transformation3d::transformation3d(const transformation3d& t) +{ + _translation = t._translation; + _transformation = t._transformation; + _inverseTransformation = t._inverseTransformation; +} + + +////////////// +// Operator // +////////////// +transformation3d& transformation3d::operator=(const transformation3d& t) +{ + _assign(t); + return *this; +} + + +transformation3d transformation3d::operator*(const transformation3d& t) const +{ + return transformation3d( transformPoint(t._translation), + _transformation * t._transformation, + t._inverseTransformation * _inverseTransformation); +} + + +transformation3d& transformation3d::operator*=(const transformation3d& t) +{ + *this = *this * t; + return *this; +} + + +////////////// +// Mutators // +////////////// +transformation3d& transformation3d::invert(void) +{ + _translation = _inverseTransformation * (-_translation); + swap(_transformation, _inverseTransformation); + return *this; +} + +///////////// +// Methods // +///////////// +vec3d transformation3d::transformPoint(const vec3d& p) const +{ + // first transform, then translate + vec3d transformed = _transformation * p; + transformed += _translation; + + // Done. + return transformed; +} + + +vec3d transformation3d::transformDirection(const vec3d& d) const +{ + // Only apply transformation + vec3d transformed = _transformation * d; + + // Done. + return transformed.normalize(); +} + + +vec3d transformation3d::transformNormal(const vec3d& n) const +{ + // Don't apply translation. + // n' = (_transformation^T)^-1 * n + // n'^T = n^T * _transformation^-1 + // n'^T = n^T * _inverseTransformation + vec3d transformed = n * _inverseTransformation; + + // Done. + return transformed.normalize(); +} + + +vec3d transformation3d::inverseTransformPoint(const vec3d& p) const +{ + // for undo translation, then invert the transformation + vec3d transformed = p - _translation; + transformed = _inverseTransformation * transformed; + + // Done. + return transformed; +} + + +vec3d transformation3d::inverseTransformDirection(const vec3d& d) const +{ + // Only invert the transformation + vec3d transformed = _inverseTransformation * d; + + // Done. + return transformed.normalize(); +} + + +vec3d transformation3d::inverseTransformNormal(const vec3d& n) const +{ + // Don't apply translation. Undo (transformation^T)^-1 + vec3d transformed = n * _transformation; + + // Done. + return transformed.normalize(); +} + + +/////////////////////// +// Protected Methods // +/////////////////////// +void transformation3d::_swap(transformation3d& t) +{ + std::swap(_translation, t._translation); + std::swap(_transformation, t._transformation); + std::swap(_inverseTransformation, t._inverseTransformation); +} + + +void transformation3d::_assign(const transformation3d& t) +{ + // avoid copying when self-assigning + if(&t == this) return; + + // Copy + _translation = t._translation; + _transformation = t._transformation; + _inverseTransformation = t._inverseTransformation; + + // Done. +} + + +void transformation3d::_print(std::ostream& s) const +{ + s << "{"; + s << "Translation = " << _translation << ", "; + s << "Transformation = " << _transformation << ", "; + s << "Inverse Trans. = " << _inverseTransformation; + s << "}"; +} diff --git a/hw3/src/triangle.cpp b/hw3/src/triangle.cpp new file mode 100644 index 0000000..3abe113 --- /dev/null +++ b/hw3/src/triangle.cpp @@ -0,0 +1,465 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include +#include + +#include "triangle.h" +#include "constants.h" + +////////////////// +// Constructors // +////////////////// +triangle::triangle(void) +{ + _vertex_list = nullptr; + _normal_list = nullptr; + _textureCoord_list = nullptr; +} + + +////////////////////// +// Copy Constructor // +////////////////////// +triangle::triangle(const triangle& t) + : triangle() +{ + // share ptr to list + _vertex_list = t._vertex_list; + _normal_list = t._normal_list; + _textureCoord_list = t._textureCoord_list; + + // copy indices + _vertex_idx = t._vertex_idx; + _normal_idx = t._normal_idx; + _textureCoord_idx = t._textureCoord_idx; +} + + +////////////////////// +// Move Constructor // +////////////////////// +triangle::triangle(triangle&& t) + : triangle() +{ + // swap list (no need to increment ref-count) + std::swap(_vertex_list, t._vertex_list); + std::swap(_normal_list, t._normal_list); + std::swap(_textureCoord_list, t._textureCoord_list); + + // copy indices + _vertex_idx = t._vertex_idx; + _normal_idx = t._normal_idx; + _textureCoord_idx = t._textureCoord_idx; +} + + +////////////////////////// +// General Constructors // +////////////////////////// +triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3) + : triangle() +{ + // create a list of three vertices + auto vertex_list = std::make_shared>(3); + _vertex_list = vertex_list; + + // copy values + (*vertex_list)[0] = v1; + (*vertex_list)[1] = v2; + (*vertex_list)[2] = v3; + + // set indices + _vertex_idx = {0,1,2}; +} + + +triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list) + : triangle() +{ + // share vertex list + _vertex_list = vertex_list; + + // copy indices + _vertex_idx[0] = v1_idx; + _vertex_idx[1] = v2_idx; + _vertex_idx[2] = v3_idx; +} + + + +triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3, + const vec3d& n1, const vec3d& n2, const vec3d& n3) + : triangle(v1, v2, v3) +{ + // create a list of three normals + auto normal_list = std::make_shared>(3); + _normal_list = normal_list; + + // copy values + (*normal_list)[0] = n1; + (*normal_list)[1] = n2; + (*normal_list)[2] = n3; + + // set indices + _normal_idx = {0,1,2}; +} + + +triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list, + size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr>& normal_list) + : triangle(v1_idx, v2_idx, v3_idx, vertex_list) +{ + // share normal list + _normal_list = normal_list; + + // copy indices + _normal_idx[0] = n1_idx; + _normal_idx[1] = n2_idx; + _normal_idx[2] = n3_idx; +} + + + +triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3, + const vec2d& t1, const vec2d& t2, const vec2d& t3) + : triangle(v1, v2, v3) +{ + // create a list of three texture coordinates + auto textureCoord_list = std::make_shared>(3); + _textureCoord_list = textureCoord_list; + + // copy values + (*textureCoord_list)[0] = t1; + (*textureCoord_list)[1] = t2; + (*textureCoord_list)[2] = t3; + + // set indices + _textureCoord_idx = {0,1,2}; +} + + +triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list, + size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr>& texcoord_list) + : triangle(v1_idx, v2_idx, v3_idx, vertex_list) +{ + // share normal list + _textureCoord_list = texcoord_list; + + // copy indices + _textureCoord_idx[0] = t1_idx; + _textureCoord_idx[1] = t2_idx; + _textureCoord_idx[2] = t3_idx; +} + + + +triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3, + const vec3d& n1, const vec3d& n2, const vec3d& n3, + const vec2d& t1, const vec2d& t2, const vec2d& t3) + : triangle(v1, v2, v3, n1, n2, n3) +{ + // create a list of three texture coordinates + auto textureCoord_list = std::make_shared>(3); + _textureCoord_list = textureCoord_list; + + // copy values + (*textureCoord_list)[0] = t1; + (*textureCoord_list)[1] = t2; + (*textureCoord_list)[2] = t3; + + // set indices + _textureCoord_idx = {0,1,2}; +} + + +triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr>& vertex_list, + size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr>& normal_list, + size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr>& texcoord_list) + : triangle(v1_idx, v2_idx, v3_idx, vertex_list, + n1_idx, n2_idx, n3_idx, normal_list) +{ + // share normal list + _textureCoord_list = texcoord_list; + + // copy indices + _textureCoord_idx[0] = t1_idx; + _textureCoord_idx[1] = t2_idx; + _textureCoord_idx[2] = t3_idx; +} + + + +//////////////// +// Inspectors // +//////////////// +const vec3d& triangle::vertex(size_t index) const +{ + // bounds check + assert(_vertex_list && index < 3); + + // Done. + return (*_vertex_list)[_vertex_idx[index]]; +} + + +const vec3d& triangle::normal(size_t index) const +{ + // bounds check + assert(_normal_list && index < 3); + + // Done. + return (*_normal_list)[_normal_idx[index]]; +} + + +const vec2d& triangle::textureCoordinate(size_t index) const +{ + // bounds check + assert(_textureCoord_list && index < 3); + + // Done. + return (*_textureCoord_list)[_textureCoord_idx[index]]; +} + + +bool triangle::hasPerVertexNormals(void) const +{ + return (bool)(_normal_list); +} + + +bool triangle::hasPerVertexTextureCoordinates(void) const +{ + return (bool)(_textureCoord_list); +} + + +/////////////// +// Operators // +/////////////// +triangle& triangle::operator=(const triangle& t) +{ + _assign(t); + return *this; +} + + +triangle& triangle::operator=(triangle&& t) +{ + // swap list (no need to increment ref-count) + std::swap(_vertex_list, t._vertex_list); + std::swap(_normal_list, t._normal_list); + std::swap(_textureCoord_list, t._textureCoord_list); + + // copy indices + _vertex_idx = t._vertex_idx; + _normal_idx = t._normal_idx; + _textureCoord_idx = t._textureCoord_idx; + + // Done. + return *this; +} + + +///////////// +// Methods // +///////////// +bool triangle::intersect(const ray& r, vec3d& barycentricCoord, float& t) const +{ + // Ray-Triangle intersection [Moller and Trumbore 1997] + // + // [t ] 1 [ ((r.origin-v0) x (v1-v0)).(v2-v0) ] + // [barycenter.y] = -------------------------- [ (r.dir x (v2-v0)).(r.origin-v0) ] + // [barycenter.z] ((r.dir x (v2-vo)).(v1-v0) [ ((r.origin-v0) x (v1-v0)).r.dir ] + // + + // compute denominator + vec3d e1 = vertex(1) - vertex(0); + vec3d e2 = vertex(2) - vertex(0); + vec3d p = r.direction().cross(e2); + float denom = p.dot(e1); + + // check if parallel (denominator == 0) + if(fabs(denom) < EPSILON) return false; + denom = 1.0f / denom; + + // compute barycentricCoord.y + vec3d diff = r.origin() - vertex(0); + barycentricCoord.y = denom * p.dot(diff); + + // check if barycenter.y inside triangle + if(barycentricCoord.y < -EPSILON || barycentricCoord.y > 1.0f+EPSILON) return false; + + // compute barycentricCoord.z + vec3d diffXe1 = diff.cross(e1); + barycentricCoord.z = denom * diffXe1.dot(r.direction()); + + // check if barycenter.z inside triangle + if(barycentricCoord.z < -EPSILON || barycentricCoord.z > 1.0f+EPSILON) return false; + + // compute barycenter.x and check if inside + barycentricCoord.x = 1.0f - barycentricCoord.y - barycentricCoord.z; + if(barycentricCoord.y + barycentricCoord.z > 1.0f+EPSILON) return false; + + // compute t + t = denom * diffXe1.dot(e2); + + // check if in front (i.e., t>0) + if(t < EPSILON) return false; + + // Clamp (to compensate for roundoff errors) + barycentricCoord.clamp(0.0f, 1.0f); + + // Done. + return true; +} + + +boundingBox triangle::boundingbox(void) const +{ + boundingBox bb; + for(unsigned int i=0; i < 3; i++) + bb += vertex(i); + return bb; +} + + +vec3d triangle::vertex(const vec3d& barycentricCoord) const +{ + vec3d result(0.0f); + for(unsigned int i=0; i < 3; i++) + result += vertex(i) * barycentricCoord[i]; + return result; +} + + +vec3d triangle::normal(void) const +{ + vec3d e1 = vertex(1) - vertex(0); + vec3d e2 = vertex(2) - vertex(0); + return e1.cross(e2).normalize(); +} + +vec3d triangle::shadingAxis(void) const +{ + // follow texture coordinates if defined, otherwise, return the first axis. + if(!_textureCoord_list) return normalize(vertex(1)-vertex(0)); + + // find the vector that follows the U-axis of the texture coordinates + // solve: + // [ (t1-t0) (t2-t0) ] [ delta_beta delta_gamma ]^T = [1 0]^T + // for delta_beta and delta_gamma. + vec3d v1 = vertex(1) - vertex(0); + vec3d v2 = vertex(2) - vertex(0); + vec2d t1 = textureCoordinate(1) - textureCoordinate(0); + vec2d t2 = textureCoordinate(2) - textureCoordinate(0); + + // check special cases where U or V is aligned with a vertex + if( fabs(t1.v) < EPSILON ) return normalize(t1.u*v1); + if( fabs(t2.v) < EPSILON ) return normalize(t2.u*v2); + + // compute delta_beta + float inv_delta_beta = t1.u - t1.v*t2.u/t2.v; + + // => degenrate case + if(fabs(inv_delta_beta) < EPSILON) return normalize(v1); + + float delta_beta = 1.0f / inv_delta_beta; + float delta_gamma = -delta_beta * t1.v / t2.v; + + // compute U + return normalize( delta_beta*v1 + delta_gamma*v2 ); +} + + +vec3d triangle::normal(const vec3d& barycentricCoord) const +{ + // sanity check + if(!hasPerVertexNormals()) return normal(); + + // interpolate + vec3d result(0.0f); + for(unsigned int i=0; i < 3; i++) + result += normal(i) * barycentricCoord[i]; + return result.normalize(); +} + + +vec2d triangle::textureCoordinate(const vec3d& barycentricCoord) const +{ + // sanity check + if(!hasPerVertexTextureCoordinates()) return vec2d(); + + // interpolate + vec2d result(0.0f); + for(unsigned int i=0; i < 3; i++) + result += textureCoordinate(i) * barycentricCoord[i]; + return result; +} + + +float triangle::area(void) const +{ + vec3d e1 = vertex(1) - vertex(0); + vec3d e2 = vertex(2) - vertex(0); + return 0.5f * sqrt( e1.squared_length() * e2.squared_length() ); +} + + +vec3d triangle::sample(float r1, float r2, vec3d& barycentricCoord, float& pdf) const +{ + r2 = sqrt(r2); + + // compute barycentric coordinate + barycentricCoord.x = r1*r2; + barycentricCoord.y = (1.0f - r2); + barycentricCoord.z = 1.0f - barycentricCoord.x - barycentricCoord.y; + + // compute pdf + pdf = 1.0f / area(); + + // Done. + return vertex(barycentricCoord); +} + + +///////////////////// +// Private Methods // +///////////////////// +void triangle::_assign(const triangle& t) +{ + // avoid self-assign + if(&t == this) return; + + // share ptr to list + _vertex_list = t._vertex_list; + _normal_list = t._normal_list; + _textureCoord_list = t._textureCoord_list; + + // copy indices + _vertex_idx = t._vertex_idx; + _normal_idx = t._normal_idx; + _textureCoord_idx = t._textureCoord_idx; +} + + +void triangle::_swap(triangle& t) +{ + // copy list ptr + std::swap(_vertex_list, t._vertex_list); + std::swap(_normal_list, t._normal_list); + std::swap(_textureCoord_list, t._textureCoord_list); + + // copy indices + std::swap(_vertex_idx, t._vertex_idx); + std::swap(_normal_idx, t._normal_idx); + std::swap(_textureCoord_idx, t._textureCoord_idx); +} + diff --git a/hw3/src/triangleMesh.cpp b/hw3/src/triangleMesh.cpp new file mode 100644 index 0000000..5507a9c --- /dev/null +++ b/hw3/src/triangleMesh.cpp @@ -0,0 +1,57 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include +#include "triangleMesh.h" + +///////////////// +// Constructors // +////////////////// +triangleMesh::triangleMesh(void) + : boundedCompound() +{ + // Nothing. +} + + +triangleMesh::triangleMesh(const std::vector& triangle_list, const std::shared_ptr& shader, const transformation3d& transform) + : boundedCompound(transform, shader) +{ + // allocate sufficient memory + _triangles.reserve(triangle_list.size()); + + // construct vector of boundedTriangles + for_each(triangle_list.begin(), triangle_list.end(), [&](const triangle& tri) + { + _triangles.push_back( std::make_shared(tri, shader) ); + }); + + // Done. + initializeBoundingBox(); +} + + +///////////// +// Methods // +///////////// +const std::vector>& triangleMesh::compounds(void) const +{ + return _triangles; +} + + +bool triangleMesh::hasShader(void) const +{ + return boundedPrimitive::hasShader(); +} + + +void triangleMesh::_print(std::ostream& s) const +{ + s << "triangleMesh (" << _bb << ", " << _triangles.size() << " compounds)"; +} diff --git a/hw3/src/util.cpp b/hw3/src/util.cpp new file mode 100644 index 0000000..917eef4 --- /dev/null +++ b/hw3/src/util.cpp @@ -0,0 +1,45 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ +#include "util.h" + + +std::string getFilename(const std::string& path) +{ +#ifdef _WIN32 + unsigned char pathSep = '\\'; +#else + unsigned char pathSep = '/'; +#endif + size_t start = path.find_last_of(pathSep); + size_t end = path.find_last_of("."); + if(start == std::string::npos) start = -1; + if(end == std::string::npos) end = path.size(); + return path.substr(start+1, end-start-1); +} + + +std::string getExtension(const std::string& path) +{ + size_t lastidx = path.find_last_of("."); + if(lastidx == std::string::npos) return std::string(); + else return path.substr(lastidx+1, std::string::npos); +} + + +std::string getDirectory(const std::string& path) +{ +#ifdef _WIN32 + unsigned char pathSep = '\\'; +#else + unsigned char pathSep = '/'; +#endif + size_t lastidx = path.find_last_of(pathSep); + if(lastidx == std::string::npos) return std::string(); + return path.substr(0, lastidx+1); +} diff --git a/hw3/src/vec2d.cpp b/hw3/src/vec2d.cpp new file mode 100644 index 0000000..ae12e41 --- /dev/null +++ b/hw3/src/vec2d.cpp @@ -0,0 +1,258 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include +#include +#include "vec2d.h" + +////////////////// +// Constructors // +////////////////// +vec2d::vec2d(vec2d::const_reference value) +{ + x = y = value; +} + + +vec2d::vec2d(vec2d::const_reference x, vec2d::const_reference y) +{ + this->x = x; + this->y = y; +} + + +vec2d::vec2d(const vec2d& v) +{ + x = v.x; + y = v.y; +} + + +//////////////// +// Inspectors // +//////////////// +vec2d::const_reference vec2d::operator[](size_t index) const +{ + assert(index < size()); + return data[index]; +} + + +vec2d::reference vec2d::operator[](size_t index) +{ + assert(index < size()); + return data[index]; +} + + +vec2d::iterator vec2d::begin(void) +{ + return data; +} + + +vec2d::const_iterator vec2d::begin(void) const +{ + return data; +} + + +vec2d::iterator vec2d::end(void) +{ + return begin() + size(); +} + + +vec2d::const_iterator vec2d::end(void) const +{ + return begin() + size(); +} + + +/////////////// +// Operators // +/////////////// +vec2d& vec2d::operator=(const vec2d& v) +{ + _assign(v); + return *this; +} + + +bool vec2d::operator==(const vec2d& v) const +{ + return (x == v.x) && (y == v.y); +} + + +bool vec2d::operator!=(const vec2d& v) const +{ + return (x != v.x) || (y != v.y); +} + + +vec2d vec2d::operator-(void) const +{ + return vec2d(-x, -y); +} + + +vec2d vec2d::operator+(const vec2d& v) const +{ + return vec2d(x + v.x, y + v.y); +} + + +vec2d vec2d::operator-(const vec2d& v) const +{ + return vec2d(x - v.x, y - v.y); +} + + +vec2d vec2d::operator*(const vec2d& v) const +{ + return vec2d(x * v.x, y * v.y); +} + + +vec2d vec2d::operator*(vec2d::const_reference scale) const +{ + return vec2d(x * scale, y * scale); +} + + +vec2d vec2d::operator/(const vec2d& v) const +{ + return vec2d(x / v.x, y / v.y); +} + + +vec2d vec2d::operator/(vec2d::const_reference scale) const +{ + return vec2d(x / scale, y / scale); +} + + +vec2d& vec2d::operator+=(const vec2d& v) +{ + x += v.x; + y += v.y; + return *this; +} + + +vec2d& vec2d::operator-=(const vec2d& v) +{ + x -= v.x; + y -= v.y; + return *this; +} + + +vec2d& vec2d::operator*=(const vec2d& v) +{ + x *= v.x; + y *= v.y; + return *this; +} + + +vec2d& vec2d::operator*=(vec2d::const_reference scale) +{ + x *= scale; + y *= scale; + return *this; +} + + +vec2d& vec2d::operator/=(const vec2d& v) +{ + x /= v.x; + y /= v.y; + return *this; +} + + +vec2d& vec2d::operator/=(vec2d::const_reference scale) +{ + x /= scale; + y /= scale; + return *this; +} + + + +/////////////// +// Modifiers // +/////////////// +vec2d::value_type vec2d::dot(const vec2d& v) const +{ + return (x*v.x + y*v.y); +} + + +vec2d::value_type vec2d::squared_length(void) const +{ + return dot(*this); +} + + +vec2d::value_type vec2d::length(void) const +{ + return sqrt(squared_length()); +} + + +vec2d::value_type vec2d::squared_distance(const vec2d& v) const +{ + return (*this - v).squared_length(); +} + + +vec2d::value_type vec2d::distance(const vec2d& v) const +{ + return sqrt(squared_distance(v)); +} + + +/////////////// +// Modifiers // +/////////////// +vec2d& vec2d::abs(void) +{ + std::for_each(begin(), end(), [](reference val) + { + if(val < 0) val = -val; + }); + return *this; +} + + +vec2d& vec2d::normalize(void) +{ + *this /= length(); + return *this; +} + + +///////////////////// +// Private Methods // +///////////////////// +void vec2d::_assign(const vec2d& v) +{ + x = v.x; + y = v.y; +} + + +void vec2d::_swap(vec2d& v) +{ + std::swap(x, v.x); + std::swap(y, v.y); +} diff --git a/hw3/src/vec3d.cpp b/hw3/src/vec3d.cpp new file mode 100644 index 0000000..3b20ad5 --- /dev/null +++ b/hw3/src/vec3d.cpp @@ -0,0 +1,287 @@ +/******************************************************************/ +/* This file is part of the homework assignments for CSCI-427/527 */ +/* at The College of William & Mary and authored by Pieter Peers. */ +/* No part of this file, whether altered or in original form, can */ +/* be distributed or used outside the context of CSCI-427/527 */ +/* without consent of either the College of William & Mary or */ +/* Pieter Peers. */ +/******************************************************************/ + +#include +#include +#include "vec3d.h" + +////////////////// +// Constructors // +////////////////// +vec3d::vec3d(vec3d::const_reference value) +{ + x = y = z = value; +} + + +vec3d::vec3d(vec3d::const_reference x, vec3d::const_reference y, vec3d::const_reference z) +{ + this->x = x; + this->y = y; + this->z = z; +} + + +vec3d::vec3d(const vec3d& v) +{ + x = v.x; + y = v.y; + z = v.z; +} + + +//////////////// +// Inspectors // +//////////////// +vec3d::const_reference vec3d::operator[](size_t index) const +{ + assert(index < size()); + return data[index]; +} + + +vec3d::reference vec3d::operator[](size_t index) +{ + assert(index < size()); + return data[index]; +} + + +vec3d::iterator vec3d::begin(void) +{ + return data; +} + + +vec3d::const_iterator vec3d::begin(void) const +{ + return data; +} + + +vec3d::iterator vec3d::end(void) +{ + return begin() + size(); +} + + +vec3d::const_iterator vec3d::end(void) const +{ + return begin() + size(); +} + + +/////////////// +// Operators // +/////////////// +vec3d& vec3d::operator=(const vec3d& v) +{ + _assign(v); + return *this; +} + + +bool vec3d::operator==(const vec3d& v) const +{ + return (x == v.x) && (y == v.y) && (z == v.z); +} + + +bool vec3d::operator!=(const vec3d& v) const +{ + return (x != v.x) || (y != v.y) || (z != v.z); +} + + +vec3d vec3d::operator-(void) const +{ + return vec3d(-x, -y, -z); +} + + +vec3d vec3d::operator+(const vec3d& v) const +{ + return vec3d(x + v.x, y + v.y, z + v.z); +} + + +vec3d vec3d::operator-(const vec3d& v) const +{ + return vec3d(x - v.x, y - v.y, z - v.z); +} + + +vec3d vec3d::operator*(const vec3d& v) const +{ + return vec3d(x * v.x, y * v.y, z * v.z); +} + + +vec3d vec3d::operator*(vec3d::const_reference scale) const +{ + return vec3d(x * scale, y * scale, z * scale); +} + + +vec3d vec3d::operator/(const vec3d& v) const +{ + return vec3d(x / v.x, y / v.y, z / v.z); +} + + +vec3d vec3d::operator/(vec3d::const_reference scale) const +{ + return vec3d(x / scale, y / scale, z / scale); +} + + +vec3d& vec3d::operator+=(const vec3d& v) +{ + x += v.x; + y += v.y; + z += v.z; + return *this; +} + + +vec3d& vec3d::operator-=(const vec3d& v) +{ + x -= v.x; + y -= v.y; + z -= v.z; + return *this; +} + + +vec3d& vec3d::operator*=(const vec3d& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + return *this; +} + + +vec3d& vec3d::operator*=(vec3d::const_reference scale) +{ + x *= scale; + y *= scale; + z *= scale; + return *this; +} + + +vec3d& vec3d::operator/=(const vec3d& v) +{ + x /= v.x; + y /= v.y; + z /= v.z; + return *this; +} + + +vec3d& vec3d::operator/=(vec3d::const_reference scale) +{ + x /= scale; + y /= scale; + z /= scale; + return *this; +} + + + +/////////////// +// Modifiers // +/////////////// +vec3d::value_type vec3d::dot(const vec3d& v) const +{ + return (x*v.x + y*v.y + z*v.z); +} + + +vec3d::value_type vec3d::squared_length(void) const +{ + return dot(*this); +} + + +vec3d::value_type vec3d::length(void) const +{ + return sqrt(squared_length()); +} + + +vec3d::value_type vec3d::squared_distance(const vec3d& v) const +{ + return (*this - v).squared_length(); +} + + +vec3d::value_type vec3d::distance(const vec3d& v) const +{ + return sqrt(squared_distance(v)); +} + + +vec3d vec3d::cross(const vec3d& v) const +{ + return vec3d(y*v.z - z*v.y, + z*v.x - x*v.z, + x*v.y - y*v.x); +} + + +/////////////// +// Modifiers // +/////////////// +vec3d& vec3d::abs(void) +{ + std::for_each(begin(), end(), [](reference val) + { + if(val < 0) val = -val; + }); + return *this; +} + + +vec3d& vec3d::clamp(vec3d::value_type lower, vec3d::value_type upper) +{ + std::for_each(begin(), end(), [&](reference val) + { + if(val < lower) val = lower; + else if(val > upper) val = upper; + }); + return *this; +} + + +vec3d& vec3d::normalize(void) +{ + *this /= length(); + return *this; +} + + +///////////////////// +// Private Methods // +///////////////////// +void vec3d::_assign(const vec3d& v) +{ + x = v.x; + y = v.y; + z = v.z; +} + + +void vec3d::_swap(vec3d& v) +{ + std::swap(x, v.x); + std::swap(y, v.y); + std::swap(z, v.z); +} -- cgit v1.2.3