diff --git a/example02/.gitignore b/example02/.gitignore new file mode 100644 index 0000000..eb32573 --- /dev/null +++ b/example02/.gitignore @@ -0,0 +1,3 @@ +build*/ +compile_commands.json +.cache/ diff --git a/example02/CMakeLists.txt b/example02/CMakeLists.txt new file mode 100644 index 0000000..9dc6796 --- /dev/null +++ b/example02/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.9) +project(Example02) + +set(Example02_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/argParse.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/rayTracer.cpp") + +set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic") +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") + +if(NOT CMAKE_BUILD_TYPE OR "${CMAKE_BUILD_TYPE}" MATCHES ^$) + set(CMAKE_BUILD_TYPE "Debug") + message("CMAKE_BUILD_TYPE is set to Debug by default") +endif() + +add_executable(Example02 + ${Example02_SOURCES}) + +target_link_libraries(Example02 PUBLIC pthread) +target_compile_features(Example02 PUBLIC cxx_std_17) diff --git a/example02/src/argParse.cpp b/example02/src/argParse.cpp new file mode 100644 index 0000000..6187e6c --- /dev/null +++ b/example02/src/argParse.cpp @@ -0,0 +1,35 @@ +#include "argParse.hpp" + +#include + +Ex02::ArgParse::ParseResult Ex02::ArgParse::parseArgs( + int argc, + char **argv, + const Ex02::ArgParse::ArgsType &singleArgs, + const Ex02::ArgParse::ArgsType &doubleArgs) { + ParseResult result; + bool found; + --argc; ++argv; + while(argc > 0) { + found = false; + for(const std::string &singleArg : singleArgs) { + if(std::strcmp(argv[0], singleArg.c_str()) == 0) { + result.insert({singleArg, EX02_ARG_PARSE_SINGLE_ARG_PLACEHOLDER}); + found = true; + break; + } + } + if(!found && argc > 1) { + for(const std::string &doubleArg: doubleArgs) { + if(std::strcmp(argv[0], doubleArg.c_str()) == 0) { + result.insert({doubleArg, argv[1]}); + --argc; ++argv; + break; + } + } + } + --argc; ++argv; + } + + return result; +} diff --git a/example02/src/argParse.hpp b/example02/src/argParse.hpp new file mode 100644 index 0000000..f7d6aab --- /dev/null +++ b/example02/src/argParse.hpp @@ -0,0 +1,21 @@ +#ifndef EXAMPLE_02_ARG_PARSE_HPP +#define EXAMPLE_02_ARG_PARSE_HPP + +#define EX02_ARG_PARSE_SINGLE_ARG_PLACEHOLDER "SINGLE_ARG_PLACEHOLDER" + +#include +#include +#include + +namespace Ex02 { +namespace ArgParse { + +typedef std::unordered_set ArgsType; +typedef std::unordered_map ParseResult; + +ParseResult parseArgs(int argc, char **argv, const ArgsType &singleArgs, const ArgsType &doubleArgs); + +} // namespace ArgParse +} // namespace Ex02 + +#endif diff --git a/example02/src/main.cpp b/example02/src/main.cpp new file mode 100644 index 0000000..dfbded3 --- /dev/null +++ b/example02/src/main.cpp @@ -0,0 +1,72 @@ +#include +#include + +#include "argParse.hpp" + +void printHelp() { + std::cout << "Usage:\n" + "-h | --help Display this help message\n" + "-t \n" + " | --threads Set the number of threads to use (default 1)" + << std::endl; +} + +int main(int argc, char **argv) { + int threadCount = 1; + + { + auto results = Ex02::ArgParse::parseArgs( + argc, + argv, + { // single args + "-h", + "--help", + }, + { // double args + "-t", + "--threads", + }); + + if(auto iter = results.find("-h"); iter != results.end()) { + printHelp(); + return 0; + } else if(auto iter = results.find("--help"); iter != results.end()) { + printHelp(); + return 0; + } + + const auto setThreadCount = [&threadCount] (auto iter) { + try { + threadCount = std::stoi(iter->second); + } catch (const std::invalid_argument &e) { + std::cout << "ERROR: Failed to parse thread count (invalid)" + << std::endl; + return 1; + } catch (const std::out_of_range &e) { + std::cout << "ERROR: Failed to parse thread count (out of range)" + << std::endl; + return 2; + } + return 0; + }; + if(auto iter = results.find("-t"); iter != results.end()) { + if(int result = setThreadCount(iter); result != 0) { + return result; + } + } else if(auto iter = results.find("--threads"); iter != results.end()) { + if(int result = setThreadCount(iter); result != 0) { + return result; + } + } + + if(threadCount <= 0) { + std::cout << "ERROR: Thread count set to invalid value (" + << threadCount + << ')' + << std::endl; + return 3; + } + } + + return 0; +} diff --git a/example02/src/rayTracer.cpp b/example02/src/rayTracer.cpp new file mode 100644 index 0000000..7b847f9 --- /dev/null +++ b/example02/src/rayTracer.cpp @@ -0,0 +1,52 @@ +#include "rayTracer.hpp" + +#include + +#include +#include +#include + +const float PI = std::acos(-1.0f); + +glm::vec3 Ex02::RT::Internal::defaultSpherePos() { + // the default model matrix pushes everything back 2 units, + // so it should be ok to define the sphere at location 0 + return glm::vec3{0.0f, 0.0f, 0.0f}; +} + +glm::vec3 Ex02::RT::Internal::defaultLightPos() { + return glm::vec3{1.0f, 1.0f, 1.0f}; +} + +glm::mat4x4 Ex02::RT::Internal::defaultMVP() { + glm::mat4x4 mvp = glm::perspective( + PI / 2.0f, + 1.0f, + EX02_RAY_TRACER_DEFAULT_NEAR_PLANE, + EX02_RAY_TRACER_DEFAULT_FAR_PLANE); + + mvp *= glm::lookAt( + glm::vec3{0.0f, 0.0f, 0.0f}, + glm::vec3{0.0f, 0.0f, -1.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}); + + // model pushes back by 2 units + mvp *= glm::translate( + glm::identity(), + glm::vec3{0.0f, 0.0f, -2.0f}); + + return mvp; +} + +std::vector Ex02::RT::renderGraySphere( + unsigned int outputWidth, + unsigned int outputHeight, + float sphereRadius, + int threadCount, + glm::vec3 spherePos, + glm::vec3 lightPos, + glm::mat4x4 mvp) { + std::vector grayscalePixels; + + return grayscalePixels; +} diff --git a/example02/src/rayTracer.hpp b/example02/src/rayTracer.hpp new file mode 100644 index 0000000..021752f --- /dev/null +++ b/example02/src/rayTracer.hpp @@ -0,0 +1,36 @@ +#ifndef EX02_RAY_TRACER_HPP +#define EX02_RAY_TRACER_HPP + +#define EX02_RAY_TRACER_DEFAULT_NEAR_PLANE 0.2f +#define EX02_RAY_TRACER_DEFAULT_FAR_PLANE 4.0f +#define EX02_RAY_TRACER_COLL_INCREMENT 2.0f + +#include + +#include +#include +#include + +namespace Ex02 { +namespace RT { + +namespace Internal { + glm::vec3 defaultSpherePos(); + glm::vec3 defaultLightPos(); + glm::mat4x4 defaultMVP(); +} + +std::vector renderGraySphere( + unsigned int outputWidth, + unsigned int outputHeight, + float sphereRadius, + int threadCount = 1, + glm::vec3 spherePos = Internal::defaultSpherePos(), + glm::vec3 lightPos = Internal::defaultLightPos(), + glm::mat4x4 mvp = Internal::defaultMVP() +); + +} // namespace RT +} // namespace Ex02 + +#endif