diff --git a/.ci/clang-tidy.sh b/.ci/clang-tidy.sh new file mode 100755 index 0000000..71994b5 --- /dev/null +++ b/.ci/clang-tidy.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +echo "Doing clang-tidy..." +bool=false +# explicitly set IFS to contain only a line feed +IFS=' +' +filelist="$(find . -not \( -path './*build*' -prune \) -not \( -path './include' -prune \) -type f ! -name "$(printf "*\n*")")" +for file in $filelist; do + if echo "$file" | grep -q -E ".*(\.cpp|\.hpp)$" ; then + #Extra check missing dependencies due to clang-tidy doesn't toggle exit code. + clang_tidy_lib_check="$(clang-tidy -warnings-as-errors='*' -header-filter='.*,-cpptoml.hpp' "$file" -- -I. -std=c++14 2>&1)" + for tidy_line in $clang_tidy_lib_check; do + echo "$tidy_line" | grep -q -v -E "^Error while processing*" + if [ $? -eq 1 ]; then + bool=true + fi + echo "$tidy_line" | grep -q -v -E ".* error: .*" + if [ $? -eq 1 ]; then + bool=true + fi + echo "$tidy_line" + done + fi +done +if $bool; then + exit 1 +else + echo "No clang-tidy errors found." +fi + +exit 0 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..6e8db98 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,2 @@ +Checks: '*,-llvm-header-guard,-fuchsia*,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-constant-array-index,-bugprone-narrowing-conversions,-cppcoreguidelines-narrowing-conversions,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-hicpp-signed-bitwise,-bugprone-exception-escape,-cppcoreguidelines-pro-type-member-init,-cppcoreguidelines-pro-type-cstyle-cast,-hicpp-member-init,-google-readability-namespace-comments,-llvm-namespace-comment,-cppcoreguidelines-pro-type-vararg,-hicpp-vararg,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers' +WarningsAsErrors: 'true' diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..f5f6d89 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,76 @@ +--- + +image: samueldebruyn/debian-git:latest + +stages: + - style + - test + - build + + +clang_tidy: + image: joethei/clang_tidy + stage: style + tags: + - docker-ci + script: + - mkdir current + - ls -d .[!.]* | grep -v current | xargs mv -t current + - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.repo.digitech.hs-emden-leer.de/link/projekte/ws19/vkvm-new/library.git + - mkdir library/build + - cd library/build + - cmake .. + - make + - cd ../../current/.ci + - sh clang-tidy.sh + +make_test: + stage: test + tags: + - docker-ci + script: + - apt-get update + - apt-get install -y g++ make cmake clang-tidy + - mkdir current + - ls | grep -v current | xargs mv -t current + - git clone https://github.com/catchorg/Catch2.git + - cd Catch2 + - cmake -Bbuild -H. -DBUILD_TESTING=OFF + - cmake --build build/ --target install + - cd .. + - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.repo.digitech.hs-emden-leer.de/link/projekte/ws19/vkvm-new/library.git + - mkdir library/build + - cd library/build + - cmake .. + - make + - cd ../../current + - mkdir build + - cd build + - cmake .. + - make + - make test + +cmake_build: + stage: build + tags: + - docker-ci + script: + - apt-get update + - apt-get install -y g++ make cmake clang-tidy + - mkdir current + - ls | grep -v current | xargs mv -t current + - git clone https://github.com/catchorg/Catch2.git + - cd Catch2 + - cmake -Bbuild -H. -DBUILD_TESTING=OFF + - cmake --build build/ --target install + - cd .. + - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.repo.digitech.hs-emden-leer.de/link/projekte/ws19/vkvm-new/library.git + - mkdir library/build + - cd library/build + - cmake .. + - make + - cd ../../current + - mkdir build + - cd build + - cmake .. + - make \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a166fc..c5c769d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,11 +12,11 @@ project(TextRenderer) set(CMAKE_CXX_STANDARD 14) # enable clang_tidy -set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*") -set(CMAKE_CXX_CLANG_TIDY clang-tidy;-header-filter=.;-checks=*;) +set(CMAKE_CXX_CLANG_TIDY "clang-tidy") +set(CMAKE_CXX_CLANG_TIDY clang-tidy;-header-filter=.;) file(GLOB_RECURSE SOURCES src/*.cpp) -file(GLOB_RECURSE HEADERS src/*.h) +file(GLOB_RECURSE HEADERS src/*.hpp) file(GLOB_RECURSE TESTS test/*.cpp) include_directories(src) include_directories(test) @@ -30,12 +30,14 @@ include_directories(${LIB_PATH}/include) add_executable(TextRenderer ${SOURCES} ${HEADERS} main/main.cpp) target_link_libraries(TextRenderer ${LIB_PATH}/lib/liblibrary.a) - +target_link_libraries(TextRenderer pthread) enable_testing() find_package(Catch2 REQUIRED) add_executable(UnitTests ${SOURCES} ${HEADERS} ${TESTS}) +target_link_libraries(UnitTests ${LIB_PATH}/lib/liblibrary.a) target_link_libraries(UnitTests Catch2::Catch2) +target_link_libraries(UnitTests pthread) include(CTest) include(Catch) diff --git a/README.md b/README.md index cdadfe7..39b4cf8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ -# vKVM TextRenderer +# vKVM Text Renderer + +The Text Renderer gets the string from the text area in the Shared Memory and writes it +into pixelarea. + +To convert a string the Text Renderer uses a font, which is loaded from a bitmap-file. + ## Installation @@ -6,36 +12,3 @@ Use the installation script provided in the Scripts repository to install the full package. Installing a single component is currently not supported. - -## Target - -TextRender build exports an interface target TextRender::TextRender. - -This means that if TextRender has been installed on the Project Path, it -should be enough to do. - -translate a string from terminal to the readable form of shared memory . - -## Usage - - mkdir build - cd build - cmake .. - make - -## Description - -TextRender has two class, Bitmap class and Font class. - -res/font.bmp (bitmap data, used by Bitmap::load() function) - -res/font.toml (configuration file, it configure how to read the font.bmp) - -src/Bitmap class, it used to read the font.bmp file. - -src/Font class, it read the font.bmp data by Bitmap class, -translate a string to a bitmap. - -test folder used to test. - -main folder is only used to test now. \ No newline at end of file diff --git a/main/main.cpp b/main/main.cpp index e7b311b..cc5f9d6 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,36 +1,117 @@ -#include "add.h" -#include "Bitmap.h" -#include "Font.h" - +#include "Font.hpp" +#include "internal.hpp" +#include "vkvm.hpp" +#include #include +int cursorPosX = 0; +int cursorPosY = 0; +bool showCursor = false; + /** * @author: Julian Hinxlage * @since: v0.0.0 * @brief: An image is loaded and used as a font. - * A string is converted and displayed in the console. - * Currently only to test. */ -int main() { - Font font("../res/font2.bmp","../res/font2.toml"); - std::string str; - std::cout << "string to draw: "; - std::getline(std::cin, str); +void threadHandler(Font &font){ + static bool cursorState{false}; - for (int i = 0; i < font.height(); i++) { - for (char c : str) { - for (int j = 0; j < font.width(); j++) { - if (font.getPixel(c,j,i)) { - std::cout << "█"; + int start = 0; + int end = font.height(); + auto bc = vkvm::getBackgroundColor(); + auto fc = vkvm::getForegroundColor(); + + while(true){ + if(showCursor) { + int x = cursorPosX - 1; + if (x < 0) { + x = 0; + } + + for (int i = start; i < end; i++) { + if (cursorState) { + vkvm::setPixel(x, cursorPosY + i, bc); } else { - std::cout << " "; + vkvm::setPixel(x, cursorPosY + i, fc); } } - std::cout << " "; + vkvm::callEvent(vkvm::EventType::Redraw); + cursorState = !cursorState; } - std::cout << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(800)); } - - return 0; } + +int main() { + vkvm::initialize(0); + vkvm::setLogLevel(vkvm::DEBUG); + + Font font( + std::string() + "../res/font" + + std::to_string(static_cast(vkvm::getFont())) + ".bmp", + std::string() + "../res/font" + + std::to_string(static_cast(vkvm::getFont())) + ".toml"); + + std::thread thread(std::bind(threadHandler, font)); + + vkvm::registerEvent(vkvm::EventType::RenderText, [&font]() { + std::string currentText = vkvm::getText(); + int perRow = vkvm::getWidth() / font.width(); + auto bc = vkvm::getBackgroundColor(); + auto fc = vkvm::getForegroundColor(); + + //clear area + for(int y = 0; y < vkvm::getHeight();y++){ + for(int x = 0; x < vkvm::getWidth();x++) { + vkvm::setPixel(x,y,bc); + } + } + + showCursor = false; + int x = 0; + int y = 0; + for(char c : currentText){ + if(c == '\n'){ + y++; + x = 0; + }else if(c == -127){ + cursorPosX = x * font.width(); + cursorPosY = y * font.height(); + showCursor = true; + } + else{ + if(x == perRow){ + y++; + x = 0; + } + + for(int i = 0; i < font.height();i++){ + for(int j = 0; j < font.width();j++){ + if(font.getPixel(c, j, i)){ + vkvm::setPixel(x * font.width() + j, y * font.height() + i, fc); + }else{ + vkvm::setPixel(x * font.width() + j, y * font.height() + i, bc); + } + } + } + x++; + } + } + + vkvm::callEvent(vkvm::EventType::Redraw); + }); + + vkvm::registerEvent(vkvm::EventType::UpdateControlRegisters, [&font]() { + font.load( + std::string() + "../res/font" + + std::to_string(static_cast(vkvm::getFont())) + ".bmp", + std::string() + "../res/font" + + std::to_string(static_cast(vkvm::getFont())) + ".toml"); + }); + + while (true) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + return 0; +} \ No newline at end of file diff --git a/res/font3.bmp b/res/font3.bmp new file mode 100644 index 0000000..c7eb8ec Binary files /dev/null and b/res/font3.bmp differ diff --git a/res/font3.toml b/res/font3.toml new file mode 100644 index 0000000..102a09f --- /dev/null +++ b/res/font3.toml @@ -0,0 +1,12 @@ +xOffset = 6 +yOffset = 6 +xSize = 18 +ySize = 27 +xCount = 32 +yCount = 9 +xStart = 7 +yStart = 9 +fillValue = 4294967295 +firstChar = 25 +pixelSize = 1 +invertedColors = 1 diff --git a/res/font4.bmp b/res/font4.bmp new file mode 100644 index 0000000..8b34cda Binary files /dev/null and b/res/font4.bmp differ diff --git a/res/font4.toml b/res/font4.toml new file mode 100644 index 0000000..fb1adf0 --- /dev/null +++ b/res/font4.toml @@ -0,0 +1,12 @@ +xOffset = 6 +yOffset = 2 +xSize = 10 +ySize = 14 +xCount = 255 +yCount = 255 +xStart = 33 +yStart = 65 +fillValue = 0 +firstChar = 0 +pixelSize = 1 +invertedColors = 0 diff --git a/src/Bitmap.cpp b/src/Bitmap.cpp index a264e50..252a969 100644 --- a/src/Bitmap.cpp +++ b/src/Bitmap.cpp @@ -1,4 +1,4 @@ -#include "Bitmap.h" +#include "Bitmap.hpp" #include #include @@ -26,11 +26,10 @@ void Bitmap::load(const std::string &file) { for(int i = 0; i < str.size();i++){ data[i] = str[i]; } - - offset = (int)*(unsigned int*)(&data[10]); - width = (int)*(unsigned int*)(&data[18]); - height = (int)*(unsigned int*)(&data[22]); - bpp = (int)*(unsigned short*)(&data[28]); + offset = *reinterpret_cast(&data[10]); + width = *reinterpret_cast(&data[18]); + height = *reinterpret_cast(&data[22]); + bpp = *reinterpret_cast(&data[28]); } } @@ -52,12 +51,18 @@ int Bitmap::getBitsPerPixel() { unsigned int Bitmap::getPixel(int x, int y) { unsigned int pixel = 0; + + if(bpp == 1){ + int index = (getHeight() - 1 - y) * getWidth() + x; + char *ptr = getData() + (index / 8); + bool value = (ptr[0] >> (7 - (index % 8))) & 1u; + return (int)value; + } + char *ptr = getData() + ((getHeight() - 1 - y) * getWidth() + x) * (getBitsPerPixel() / 8); for(int i = 0; i < getBitsPerPixel() / 8;i++){ - *((char*)&pixel+i) = ptr[i]; - } - if(pixel != 0){ - return pixel; + auto value = reinterpret_cast(&pixel)+i; + *value = ptr[i]; } return pixel; } diff --git a/src/Bitmap.h b/src/Bitmap.hpp similarity index 89% rename from src/Bitmap.h rename to src/Bitmap.hpp index 7c82032..6314810 100644 --- a/src/Bitmap.h +++ b/src/Bitmap.hpp @@ -1,5 +1,5 @@ -#ifndef TEXTRENDERER_BITMAP_H -#define TEXTRENDERER_BITMAP_H +#ifndef TEXTRENDERER_BITMAP_HPP +#define TEXTRENDERER_BITMAP_HPP #include #include @@ -19,7 +19,7 @@ public: * @since: v0.0.0 * @brief: Used to load a Bitmap from a file. */ - void load(const std::string &file); + void load(const std::string &file); /** * @author: Julian Hinxlage @@ -65,4 +65,4 @@ private: }; -#endif //TEXTRENDERER_BITMAP_H +#endif //TEXTRENDERER_BITMAP_HPP diff --git a/src/Font.cpp b/src/Font.cpp index f0d6318..8bcb062 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -2,8 +2,8 @@ // Copyright (c) 2019 Julian Hinxlage. All rights reserved. // -#include "Font.h" -#include +#include "Font.hpp" +#include "../lib/toml/cpptoml.h" Font::Font() { xOffset = 0; @@ -16,6 +16,9 @@ Font::Font() { yStart = 0; fillValue = 0; firstChar = ' '; + pixelSize = 1; + gap = -1; + invertedColors = false; } Font::Font(const std::string &file, const std::string &configFile) : Font() { @@ -34,9 +37,10 @@ void Font::load(const std::string &file, const std::string &configFile) { xStart = config->get_as("xStart").value_or(0); yStart = config->get_as("yStart").value_or(0); fillValue = config->get_as("fillValue").value_or(0); - firstChar = (char)config->get_as("firstChar").value_or(0); + firstChar = config->get_as("firstChar").value_or(0); pixelSize = config->get_as("pixelSize").value_or(0); gap = config->get_as("gap").value_or(-1); + invertedColors = static_cast(config->get_as("invertedColors").value_or(0)); } int Font::width() { @@ -69,6 +73,7 @@ bool Font::getPixel(char character, int x, int y) { int xPos = xIndex * (xSize + xOffset) + xStart; int yPos = yIndex * (ySize + yOffset) + yStart; - return bitmap.getPixel((xPos + x) * pixelSize, (yPos + y) * pixelSize) == fillValue; + bool value = bitmap.getPixel((xPos + x) * pixelSize, (yPos + y) * pixelSize) == fillValue; + return invertedColors != value; } diff --git a/src/Font.h b/src/Font.hpp similarity index 84% rename from src/Font.h rename to src/Font.hpp index 30789d5..e97d4ac 100644 --- a/src/Font.h +++ b/src/Font.hpp @@ -2,10 +2,10 @@ // Copyright (c) 2019 Julian Hinxlage. All rights reserved. // -#ifndef TEXTRENDERER_FONT_H -#define TEXTRENDERER_FONT_H +#ifndef TEXTRENDERER_FONT_HPP +#define TEXTRENDERER_FONT_HPP -#include "Bitmap.h" +#include "Bitmap.hpp" /** * @author: Julian Hinxlage @@ -13,7 +13,7 @@ * @brief: this class provides pixel access based on characters */ class Font { -public: +private: Bitmap bitmap; //space between characters @@ -38,6 +38,10 @@ public: int pixelSize; int gap; + bool invertedColors; + +public: + Font(); explicit Font(const std::string &file, const std::string &configFile); void load(const std::string &file, const std::string &configFile); @@ -48,4 +52,4 @@ public: }; -#endif //TEXTRENDERER_FONT_H +#endif //TEXTRENDERER_FONT_HPP diff --git a/test/test_bitmap.cpp b/test/test_bitmap.cpp index 1746a06..40951b8 100644 --- a/test/test_bitmap.cpp +++ b/test/test_bitmap.cpp @@ -1,6 +1,6 @@ +#include "Bitmap.hpp" +#include "Font.hpp" #include -#include "Bitmap.h" -#include "Font.h" TEST_CASE("default values") { Bitmap bitmap = Bitmap(); @@ -20,7 +20,7 @@ TEST_CASE("Font") { Font font("../res/font1.bmp", "../res/font1.toml"); REQUIRE(font.width() == 5); REQUIRE(font.height() == 7); - REQUIRE(!font.getPixel('a', 1,1)); + REQUIRE_FALSE(font.getPixel('a', 1,1)); REQUIRE(font.getPixel('a', 1,2)); }