From fac2212661c455f2d43a6c5d5c3494695c696ac7 Mon Sep 17 00:00:00 2001 From: Godzil Date: Fri, 14 Feb 2020 16:04:28 +0000 Subject: [PATCH] Canvas implementation and add build of LodePNG --- CMakeLists.txt | 6 +++++ source/CMakeLists.txt | 8 +++--- source/canvas.cpp | 57 +++++++++++++++++++++++++++++++++++++++++ source/include/canvas.h | 32 +++++++++++++++++++++++ tests/CMakeLists.txt | 2 +- tests/canvas_test.cpp | 53 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 source/canvas.cpp create mode 100644 source/include/canvas.h create mode 100644 tests/canvas_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c20685..b490d34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,12 @@ ExternalProject_Add(googletest TEST_COMMAND "" ) +# LodePNG don't make a .a or .so, so let's build a library here +add_library(LodePNG STATIC) +set(LODEPNG_INCLUDE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/external/lodepng) +target_sources(LodePNG PRIVATE external/lodepng/lodepng.cpp external/lodepng/lodepng.h) + + # Main app add_subdirectory(source) # Unit Tests diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 7559696..79757f0 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -3,14 +3,14 @@ # First most is build as a library add_library(rayonnement STATIC) -set(RAY_HEADERS include/tuples.h include/math_helper.h include/colour.h) -set(RAY_SOURCES tuples.cpp math_helper.cpp colour.cpp) +set(RAY_HEADERS include/tuples.h include/math_helper.h include/colour.h include/canvas.h) +set(RAY_SOURCES tuples.cpp math_helper.cpp colour.cpp canvas.cpp) target_include_directories(rayonnement PUBLIC include) target_sources(rayonnement PRIVATE ${RAY_HEADERS} ${RAY_SOURCES}) - +target_link_libraries(rayonnement LodePNG) # Second we build the main executable add_executable(dorayme main.cpp) -target_include_directories(rayonnement PUBLIC include) +target_include_directories(rayonnement PUBLIC include ${LODEPNG_INCLUDE_FOLDER}) target_link_libraries(dorayme rayonnement) \ No newline at end of file diff --git a/source/canvas.cpp b/source/canvas.cpp new file mode 100644 index 0000000..0a210af --- /dev/null +++ b/source/canvas.cpp @@ -0,0 +1,57 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Canvas implementation + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ + +#include +#include + +#define BPP (24) +#define BytePP (BPP / 8) + +#define MIN(_a, _b) ((_a)<(_b)?(_a):(_b)) +#define MAX(_a, _b) ((_a)>(_b)?(_a):(_b)) + +Canvas::Canvas(uint32_t width, uint32_t height) : width(width), height(height) +{ + this->bitmap = (uint8_t *)calloc(4, width * height); + this->stride = BytePP * width; +} + +Canvas::~Canvas() +{ + if (this->bitmap != nullptr) + { + free(this->bitmap); + } +} + +void Canvas::put_pixel(uint32_t x, uint32_t y, Colour c) +{ + uint32_t offset = y * this->stride + x * BytePP; + this->bitmap[offset + 0] = MAX(MIN(c.red() * 255, 255), 0); + this->bitmap[offset + 1] = MAX(MIN(c.green() * 255, 255), 0); + this->bitmap[offset + 2] = MAX(MIN(c.blue() * 255, 255), 0); +} + +Colour Canvas::get_pixel(uint32_t x, uint32_t y) +{ + uint32_t offset = y * this->stride + x * BytePP; + return Colour(this->bitmap[offset + 0] / 255, this->bitmap[offset + 1] / 255, this->bitmap[offset + 2] / 255); +} + +bool Canvas::SaveAsPNG(const char *filename) +{ + uint32_t ret = lodepng_encode24_file(filename, this->bitmap, this->width, this->height); + + if (ret > 0) + { + printf("lodepng_encode_file returned %d!\n", ret); + } + + return ret == 0; +} \ No newline at end of file diff --git a/source/include/canvas.h b/source/include/canvas.h new file mode 100644 index 0000000..5911a2e --- /dev/null +++ b/source/include/canvas.h @@ -0,0 +1,32 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Canvas header + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#ifndef DORAYME_CANVAS_H +#define DORAYME_CANVAS_H + +#include +#include + +class Canvas +{ +private: + uint8_t *bitmap; + uint32_t stride; +public: + uint32_t width, height; + + Canvas(uint32_t width, uint32_t height); + ~Canvas(); + + void put_pixel(uint32_t x, uint32_t y, Colour c); + Colour get_pixel(uint32_t x, uint32_t y); + + bool SaveAsPNG(const char *filename); +}; + +#endif /* DORAYME_CANVAS_H */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6080bec..fd7ebc7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,7 +3,7 @@ project(DoRayTested) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -set(TESTS_SRC tuples_test.cpp colour_test.cpp) +set(TESTS_SRC tuples_test.cpp colour_test.cpp canvas_test.cpp) add_executable(testMyRays) target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) diff --git a/tests/canvas_test.cpp b/tests/canvas_test.cpp new file mode 100644 index 0000000..e95f210 --- /dev/null +++ b/tests/canvas_test.cpp @@ -0,0 +1,53 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Canvas unit tests + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#include +#include +#include +#include + +TEST(CanvasTest, Creating_a_canvas) +{ + Canvas c = Canvas(10, 20); + int x, y; + ASSERT_EQ(c.width, 10); + ASSERT_EQ(c.height, 20); + for(y = 0; y < 20; y++) + { + for(x = 0; x < 10; x++) + { + ASSERT_EQ(c.get_pixel(x, y), Colour(0, 0, 0)); + } + } +} + +TEST(CanvasTest, Test_Writing_pixels_to_a_canvas_Test) +{ + Canvas c = Canvas(10, 20); + Colour red = Colour(1, 0, 0); + + c.put_pixel(2, 3, red); + + ASSERT_EQ(c.get_pixel(2, 3), red); + +} + +TEST(CanvasTest, Save_a_PNG_file) +{ + Canvas c = Canvas(5, 3); + Colour c1 = Colour(1.5, 0, 0); + Colour c2 = Colour(0, 0.5, 0); + Colour c3 = Colour(-0.5, 0, 1); + + c.put_pixel(0, 0, c1); + c.put_pixel(2, 1, c2); + c.put_pixel(4, 2, c3); + + ASSERT_TRUE(c.SaveAsPNG("Save_a_PNG_file.png")); + +} \ No newline at end of file