diff --git a/CMakeLists.txt b/CMakeLists.txt index 64c722b..ba0bc48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,9 +25,9 @@ else() if (CMAKE_COMPILER_IS_GNUCC) message(STATUS "Enabling code coverage") set(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage") - set(GCC_COVERAGE_LINK_FLAGS "-lgcov") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}") + set(GCC_COVERAGE_LINK_FLAGS "-lgcov -fprofile-arcs") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}") endif() endif() endif() diff --git a/src/base/core/file_utilities/Directory.cpp b/src/base/core/file_utilities/Directory.cpp index 3492d91..49aac5a 100644 --- a/src/base/core/file_utilities/Directory.cpp +++ b/src/base/core/file_utilities/Directory.cpp @@ -20,3 +20,21 @@ std::vector Directory::getFilesWithExtension(const Path& path, const std:: } return paths; } + +void Directory::createIfNotExisting(const Path& path) +{ + Path working_path; + if (std::filesystem::is_directory(path)) + { + working_path = path; + } + else + { + working_path = path.parent_path(); + } + + if (!std::filesystem::exists(working_path)) + { + std::filesystem::create_directories(working_path); + } +} diff --git a/src/base/core/file_utilities/Directory.h b/src/base/core/file_utilities/Directory.h index e038078..a225f32 100644 --- a/src/base/core/file_utilities/Directory.h +++ b/src/base/core/file_utilities/Directory.h @@ -8,6 +8,7 @@ using Path = std::filesystem::path; class Directory { public: + static void createIfNotExisting(const Path& path); static std::vector getFilesWithExtension(const Path& path, const std::string& extension, bool recursive=false); }; diff --git a/src/media/image/win32/Win32WicImageWriter.cpp b/src/media/image/win32/Win32WicImageWriter.cpp index 6612a42..f1f9e3e 100644 --- a/src/media/image/win32/Win32WicImageWriter.cpp +++ b/src/media/image/win32/Win32WicImageWriter.cpp @@ -4,6 +4,7 @@ #include "Win32WicInterface.h" #include "Win32WicImage.h" #include "StringUtils.h" +#include "Directory.h" #include #include @@ -16,6 +17,8 @@ Win32WicImageWriter::Win32WicImageWriter(ImgFormat format) void Win32WicImageWriter::write(const Path& path, Image* image) { + Directory::createIfNotExisting(path); + Win32WicInterface wic_interface; Microsoft::WRL::ComPtr pStream; diff --git a/src/rendering/graphics/directx/DirectX2dPainter.cpp b/src/rendering/graphics/directx/DirectX2dPainter.cpp index c885be2..d0c5dea 100644 --- a/src/rendering/graphics/directx/DirectX2dPainter.cpp +++ b/src/rendering/graphics/directx/DirectX2dPainter.cpp @@ -57,6 +57,10 @@ void DirectX2dPainter::paint(SceneModel* model) { paintPath(model); } + else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::LINE) + { + paintLine(model); + } } void DirectX2dPainter::paintRect(SceneModel* model) @@ -107,8 +111,6 @@ void DirectX2dPainter::paintRect(SceneModel* model) void DirectX2dPainter::paintCircle(SceneModel* model) { - auto rt = mD2dInterface->getRenderTarget(); - const auto loc = model->getTransform().getLocation(); const auto scale_x = model->getTransform().getScaleX(); const auto scale_y = model->getTransform().getScaleY(); @@ -120,6 +122,7 @@ void DirectX2dPainter::paintCircle(SceneModel* model) D2D1_POINT_2F d2d_centre{ static_cast(loc.getX()), static_cast(loc.getY()) }; D2D1_ELLIPSE ellipse{ d2d_centre, static_cast(radius), static_cast(radiusy) }; + auto rt = mD2dInterface->getRenderTarget(); if (model->hasFillColor()) { mSolidBrush->SetColor(toD2dColor(model->getFillColor())); @@ -137,6 +140,44 @@ D2D_POINT_2F DirectX2dPainter::toD2dPoint(const Point& point) return D2D1::Point2F(static_cast(point.getX()), static_cast(point.getY())); } +void DirectX2dPainter::paintLine(SceneModel* model) +{ + Microsoft::WRL::ComPtr path_geom; + mD2dInterface->getFactory()->CreatePathGeometry(&path_geom); + + Microsoft::WRL::ComPtr path_sink; + + path_geom->Open(&path_sink); + + auto line = dynamic_cast(model->getGeometry()); + + path_sink->BeginFigure(toD2dPoint(line->getFirstPoint()), D2D1_FIGURE_BEGIN_FILLED); + + onLine(line, path_sink.Get()); + + path_sink->EndFigure(D2D1_FIGURE_END_CLOSED); + path_sink->Close(); + + auto rt = mD2dInterface->getRenderTarget(); + + const auto loc = model->getTransform().getLocation(); + D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(static_cast(loc.getX()), static_cast(loc.getY())); + rt->SetTransform(translation); + + if (model->hasFillColor()) + { + mSolidBrush->SetColor(toD2dColor(model->getFillColor())); + rt->FillGeometry(path_geom.Get(), mSolidBrush.Get()); + } + if (model->hasOutlineColor()) + { + mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); + rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f); + } + + rt->SetTransform(D2D1::Matrix3x2F::Identity()); +} + void DirectX2dPainter::paintPath(SceneModel* model) { Microsoft::WRL::ComPtr path_geom; @@ -185,6 +226,11 @@ void DirectX2dPainter::paintPath(SceneModel* model) path_sink->Close(); auto rt = mD2dInterface->getRenderTarget(); + + const auto loc = model->getTransform().getLocation(); + D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(static_cast(loc.getX()), static_cast(loc.getY())); + rt->SetTransform(translation); + if (model->hasFillColor()) { mSolidBrush->SetColor(toD2dColor(model->getFillColor())); @@ -195,6 +241,8 @@ void DirectX2dPainter::paintPath(SceneModel* model) mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f); } + + rt->SetTransform(D2D1::Matrix3x2F::Identity()); } void DirectX2dPainter::onArc(Curve* element, ID2D1GeometrySink* sink) diff --git a/src/rendering/graphics/directx/DirectX2dPainter.h b/src/rendering/graphics/directx/DirectX2dPainter.h index 621c9ea..f7ebcf1 100644 --- a/src/rendering/graphics/directx/DirectX2dPainter.h +++ b/src/rendering/graphics/directx/DirectX2dPainter.h @@ -50,6 +50,8 @@ private: void paintPath(SceneModel* model); + void paintLine(SceneModel* model); + static D2D1::ColorF toD2dColor(const Color& color); static D2D_POINT_2F toD2dPoint(const Point& point); diff --git a/src/rendering/visual_elements/BasicMaterial.cpp b/src/rendering/visual_elements/BasicMaterial.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/rendering/visual_elements/BasicMaterial.h b/src/rendering/visual_elements/BasicMaterial.h new file mode 100644 index 0000000..e69de29 diff --git a/src/rendering/visual_elements/CMakeLists.txt b/src/rendering/visual_elements/CMakeLists.txt index ac6a6c5..0561e49 100644 --- a/src/rendering/visual_elements/CMakeLists.txt +++ b/src/rendering/visual_elements/CMakeLists.txt @@ -50,6 +50,9 @@ list(APPEND visual_elements_LIB_INCLUDES nodes/GeometryNode.cpp nodes/AbstractVisualNode.h nodes/AbstractVisualNode.cpp + Material.h + BasicMaterial.h + BasicMaterial.cpp Texture.cpp ) diff --git a/src/rendering/visual_elements/Material.h b/src/rendering/visual_elements/Material.h new file mode 100644 index 0000000..e69de29 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4a787b5..bbd19e8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(test_utils) add_subdirectory(geometry) +add_subdirectory(graphics) add_subdirectory(ui_controls) file(COPY data/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_data) @@ -12,7 +13,6 @@ set(TEST_MODULES core database fonts - graphics image ipc network diff --git a/test/graphics/CMakeLists.txt b/test/graphics/CMakeLists.txt index 832dc7a..378c581 100644 --- a/test/graphics/CMakeLists.txt +++ b/test/graphics/CMakeLists.txt @@ -1,38 +1,40 @@ +set(MODULE_NAME graphics) + set(PLATFORM_UNIT_TEST_FILES) set(OpenGL_GL_PREFERENCE "GLVND") find_package(OpenGL QUIET) if (OpenGL_FOUND) -set(PLATFORM_UNIT_TEST_FILES - graphics/TestOpenGlRendering.cpp - ) + set(PLATFORM_UNIT_TEST_FILES + TestOpenGlRendering.cpp + ) endif() if(WIN32) - -list(APPEND PLATFORM_UNIT_TEST_FILES - graphics/TestD2DOffScreenRendering.cpp -) -set(GRAPHICS_UI_TEST_FILES - graphics/TestDirectXRendering.cpp - graphics/TestD2DRendering.cpp - PARENT_SCOPE - ) + list(APPEND PLATFORM_UNIT_TEST_FILES + TestD2DOffScreenRendering.cpp + ) + set(UI_TEST_FILES + TestDirectXRendering.cpp + TestD2DRendering.cpp + ) endif() - -set(GRAPHICS_UNIT_TEST_DEPENDENCIES - graphics client - PARENT_SCOPE - ) - -set(GRAPHICS_UI_TEST_DEPENDENCIES - graphics client - PARENT_SCOPE - ) - -set(GRAPHICS_UNIT_TEST_FILES - graphics/TestRasterizer.cpp + +set(UNIT_TEST_FILES + TestRasterizer.cpp ${PLATFORM_UNIT_TEST_FILES} - PARENT_SCOPE - ) \ No newline at end of file + ) + +set(UNIT_TEST_TARGET_NAME ${MODULE_NAME}_unit_tests) +add_executable(${UNIT_TEST_TARGET_NAME} ${CMAKE_SOURCE_DIR}/test/test_runner.cpp ${UNIT_TEST_FILES}) +target_link_libraries(${UNIT_TEST_TARGET_NAME} PUBLIC test_utils graphics client) +set_property(TARGET ${UNIT_TEST_TARGET_NAME} PROPERTY FOLDER test/${MODULE_NAME}) + + +set(UI_TEST_TARGET_NAME ${MODULE_NAME}_ui_tests) +add_executable(${UI_TEST_TARGET_NAME} WIN32 ${CMAKE_SOURCE_DIR}/test/ui_test_runner.cpp ${UI_TEST_FILES}) +target_link_libraries(${UI_TEST_TARGET_NAME} PUBLIC test_utils graphics client) +set_property(TARGET ${UI_TEST_TARGET_NAME} PROPERTY FOLDER test/${MODULE_NAME}) + + diff --git a/test/graphics/TestD2dOffScreenRendering.cpp b/test/graphics/TestD2dOffScreenRendering.cpp index 1b3a09b..34f607c 100644 --- a/test/graphics/TestD2dOffScreenRendering.cpp +++ b/test/graphics/TestD2dOffScreenRendering.cpp @@ -3,17 +3,74 @@ #include "TestRenderUtils.h" #include "RectangleNode.h" +#include "CircleNode.h" +#include "LineNode.h" +#include "PathNode.h" +void addRect(const Point& loc, std::vector >& nodes, double radius = 0.0) +{ + auto node = std::make_unique(loc, 150.0, 100.0); + node->setRadius(radius); + nodes.push_back(std::move(node)); +} + +void addCircle(const Point& loc, std::vector >& nodes, double minorRadius = 0.0) +{ + const auto radius = 50.0; + auto centre_loc = loc; + centre_loc.move(0.0, radius); + + auto node = std::make_unique(centre_loc, radius); + + if (minorRadius != 0.0) + { + node->setMinorRadius(minorRadius); + } + + nodes.push_back(std::move(node)); +} + +void addLine(const Point& loc, std::vector >& nodes) +{ + std::vector points = { Point(150.0, 100.0) }; + auto node = std::make_unique(loc, points); + nodes.push_back(std::move(node)); +} + +void addPath(const Point& loc, const std::string& path, std::vector >& nodes) +{ + auto node = std::make_unique(loc, path); + nodes.push_back(std::move(node)); +} TEST_CASE(TestD2dOffScreenRendering, "graphics") { TestRenderer renderer(800, 800); - auto rect = std::make_unique(Point(10, 10), 200.0, 200.0); + std::vector > nodes; + + auto loc = Point(10, 10); + addRect(loc, nodes); + + loc.move(250, 0); + addCircle(loc, nodes); + + loc.move(100, 0); + addLine(loc, nodes); + + loc = Point(10, 150); + addRect(loc, nodes, 10.0); + + loc.move(250, 0); + addCircle(loc, nodes, 75.0); + + loc.move(100, 0); + addPath(loc, "M0 0 h150 v100 h-150Z", nodes); auto scene = renderer.getScene(); - //scene->setBackgroundColor(Color(100, 100, 0)); - scene->addNode(rect.get()); - + for (const auto& node : nodes) + { + scene->addNode(node.get()); + } renderer.write(TestUtils::getTestOutputDir(__FILE__) / "out.png"); }; \ No newline at end of file