From 20f85a2dc59aebafd54f677d89447cf572a6c900 Mon Sep 17 00:00:00 2001 From: Christophe Meneboeuf Date: Wed, 15 Jun 2022 23:38:13 +0200 Subject: [PATCH] SDL2 port: Picture executable --- Loader_Apple2/disk.dsk | Bin 143360 -> 143360 bytes Rgb2Hires_PC/CMakeLists.txt | 92 +++++++-------- Rgb2Hires_PC/conanfile.txt | 8 ++ Rgb2Hires_PC/src/App_Picture.cpp | 104 +++++++++++------ Rgb2Hires_PC/src/Common.h | 35 +++--- Rgb2Hires_PC/src/HiRes.cpp | 6 +- Rgb2Hires_PC/src/HiRes.h | 9 +- Rgb2Hires_PC/src/ImageQuantized.cpp | 170 +++++++++++++++++++--------- Rgb2Hires_PC/src/ImageQuantized.h | 41 +++++-- Rgb2Hires_PC/src/Picture.cpp | 97 ++++++++++++++-- Rgb2Hires_PC/src/Picture.h | 4 +- 11 files changed, 392 insertions(+), 174 deletions(-) create mode 100644 Rgb2Hires_PC/conanfile.txt diff --git a/Loader_Apple2/disk.dsk b/Loader_Apple2/disk.dsk index 39b57def891e50250057d0fd8043eb7cd7077478..25c565ce7d65bfa8cc2ea2202e6fced21c4fb08e 100644 GIT binary patch delta 4245 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 delta 3303 zcmaJ@dvH|M89)0-Hv0&6Qjogrp37L*&+SH5|n?*}+aV*n6oJotUD1s|uLkl$h&IV9s zobKbE?|!fIeZTLV@0`F?USKM3xXQ^5aA@Vi(qe>8S@IY`S37UXzs5m?5u?q{@Xv(h zGxaDGO~~0%7WhK)s#{0ZD$!AHq`bX6S}rd<8jD#^$I=nW_~OtQDXvaLa@upEIkNG0 z71hP1jAhcelnC~>(7s21xYK zdQ&KpXlLMCL+yzuy}$O>`+E7I13bi+e32h|i4m$*c-g6--MKp|SV)jM*pZwn|ZESu1hemd$#B$*}7j`J`Y#*ytXS7Fdn1 zR5T)Ki21jZZjWkX4?Bb8H-%Hkn3F<=L(Pf7H<;6s--PqG;Y_Z+n0)A}Q}c)~UuZ2z zH5&OEQnuqWN(0slo-^)DZ8uyb?2;o`X{U{Au&IG6YfAkQJk*X!wHIuJP5H^$*9xy3 z#fprRv%ZUln(!A0yVtRuMtiyHE&s3|Z>e^5Ke@eIz`Qnwj)rGZwh_2Or7YN25#53z8C zd*_h-F7T%`;%F0&Zlg_WvA+o`+we$N>iJAbsxDKM+L3Xmwq){BLdKeU#&GI0@^%dN zf;cC-6KlJa2-YBL#!5Y9%wZ_(VsSKMhSbwwRBtTOP!i%WYb5zAHr%D`z@*vL*Rt3- zxC7vg?!xDHV%5RmrTJ@a^EcoOU)^>MFjx{%JS1Z%nb5_zN+j$iAG;EgFz)`&i?^^^ z%^B-Ny-#6@o30CWw(V!Dw5zR~4LxnWIyw~ZnS|d+kKE0(XAhs~3Q37>*dS=6E8|Sv zk+Dr0-=w?g8|&tpWctCnGEWyzmbeBCrKrz|w_i+d$A+8L3vVLe{56fU_-Yg4&1_0b{|9%J8 z#7X;X^JMKb3ppYeJi@SDbzO%tz@Ri|p|ss7O78Wdu%)P4;{p9Ri_-sXO~_`z=;lgj zGY7~bA30J)Zs)YQdLH>XcXx1t{DjlY6)we$Y`xLZ=cX+07?&{rv z3FZuf3VES2kmYCD)xwa2rf-JTlug#(1j*|bSQ0{tQ8v~5U3`IaO3jG}V9Zr>vm=7F z>+@NNV%@1|(3vJhriFvEbYZc(Y} zmtM-5&uu(rOzVXj62~9p;R($okPc)_VtTJw4QG8I)FQznSSPG>NBeMcA3sFdftm>P z@AWnGu`a>RbI_Cqq!Ecppq-GCqQO24R|wrC?51x%QS)Qyo1g~mQ+S<|DP~G?Csy|3 zM5Mo6?!rnp?$N9y&Bv@M!Eiv2OZMQQUiyGovT3E8ReZ9V-6F(mZrIHMVwK{NjD6CW zPKVR&##f0*R;(c=$>dEM|4xU`7#Dl8-0K#ZqJi;;iWitOxsl4xrsC41aW)+`KBZ&g zJzKDcyyj*1Fi}U)$+`ZH%>3M7dCS7`aP?6o5kB1!%L|3;PAk>vV4Y-q5|YHMc-VSW zfeW6J4ob#(V8UkUX3aNyBS<3OkjY2JITm_O*swtzu4o(c{k)N%kbDhSc=-w+X}HSE zS9!QuRKtM>tgAe0S~BwKS0HzwOg^0l07ylC@(Mq6l^4l~XL!@V*q?aF<*~@(+Zk1r zDN-ob|Eie*%Hb9I@mXRiTx!(!g?Bvta8*)zu-uDtBGh=coICB&ZNeQc;fF50EF|eZ zn%nZok*#@!)NU@WRLvQiepvId3zJsz+rUAqk8K9?_yx*pJjcJl@8Jb#@$iuk^U5GEAK{fzUK*R3k$*os{EmY`c~`% z+BzkTy7pZ%QR|77w5F5LZ6`!}qVouC{qUpF4PA#p@VDdiL=P}d0^`783)%gGg%lw4 zeDj@8*q&hi>MV7&HiUkPc9a#M-F|xe%PZ$ME?jG3soeMwzaNBUtM>SptlCpc<7aQB zqc1;7t>K2Dqy set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_VERBOSE_MAKEFILE ON) - -# dependencies -if(WIN32) - # sdl2 - if(NOT DEFINED ENV{SDL2_HOME}) - message(FATAL_ERROR "Please set a SDL2_HOME environment variable to the root directory of SDL2") - endif() - set(sdl2_DIR $ENV{SDL2_HOME}) - # imagemagik - if(NOT DEFINED ENV{MAGICK_HOME}) - message(FATAL_ERROR "Please set a MAGICK_HOME environment variable to the root directory of ImageMagick6") - endif() - find_package(ImageMagick HINTS $ENV{MAGICK_HOME} REQUIRED COMPONENTS Magick++) -else() - find_package(ImageMagick REQUIRED COMPONENTS Magick++ ) -endif(WIN32) -find_package(sdl2 REQUIRED) -find_package(Threads REQUIRED) +# Conan init +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup(TARGETS) # directories set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/bin/debug) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/bin/release) -# library +# Library add_library(${PROJECT_NAME} src/Common.h src/HiRes.cpp src/HiRes.h src/ImageQuantized.cpp src/ImageQuantized.h - src/Picture.h - src/Picture.cpp - src/Tile.h - src/Tile.cpp - src/Display.h - src/Display.cpp + # src/Picture.h + # src/Picture.cpp + # src/Tile.h + # src/Tile.cpp + #src/Display.h + #src/Display.cpp ) -target_compile_definitions(${PROJECT_NAME} PRIVATE MAGICKCORE_QUANTUM_DEPTH=16 MAGICKCORE_HDRI_ENABLE=0) -target_include_directories(${PROJECT_NAME} PRIVATE ${ImageMagick_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}) +## dependencies +conan_set_find_library_paths(${PROJECT_NAME}) +conan_target_link_libraries(${PROJECT_NAME}) # Application Picture -add_executable(Picture src/App_Picture.cpp) +add_executable( Picture src/App_Picture.cpp) if(NOT WIN32) set_target_properties(Picture PROPERTIES COMPILE_FLAGS -pthread LINK_FLAGS -pthread) endif() -target_compile_definitions(Picture PUBLIC MAGICKCORE_QUANTUM_DEPTH=16 MAGICKCORE_HDRI_ENABLE=0) -target_include_directories(Picture PRIVATE src ${ImageMagick_INCLUDE_DIRS}) -target_link_libraries(Picture ${ImageMagick_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${PROJECT_NAME} ${SDL2_LIBRARIES}) # SDL2 must be at the end +## dependencies if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "9") target_link_libraries(Picture stdc++fs) # filesystem lib not included in stdc++ for gcc < 9 endif() -set_property(TARGET Picture PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}) +conan_set_find_library_paths(Picture) +conan_target_link_libraries(Picture) +target_link_libraries(Picture ${PROJECT_NAME}) +## output +set_property(TARGET Picture PROPERTY + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}) -# Application Tile -add_executable(Tile src/App_Tile.cpp) -target_compile_definitions(Tile PUBLIC MAGICKCORE_QUANTUM_DEPTH=16 MAGICKCORE_HDRI_ENABLE=0) -target_include_directories(Tile PRIVATE src ${ImageMagick_INCLUDE_DIRS}) -target_link_libraries(Tile ${ImageMagick_LIBRARIES} ${PROJECT_NAME}) -set_property(TARGET Tile PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}) - - -# Windows only: copy dlls -if(WIN32) - set(DEBUG_EXE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts/copy_im_db_dlls.bat") - set(RELEASE_EXE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts/copy_im_rl_dlls.bat") - string (REPLACE "/" "\\" WIN_BIN_DIR "$<$:${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}>$<$:${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}>") - add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND "$<$:${DEBUG_EXE_PATH}>$<$:${RELEASE_EXE_PATH}>" ${WIN_BIN_DIR}) -endif(WIN32) +## Application Tile +#add_executable(Tile src/App_Tile.cpp) +### custom definitions +#target_compile_definitions(Tile PRIVATE cimg_use_png) +### dependencies +#if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "9") +# target_link_libraries(Tile stdc++fs) # filesystem lib not included in stdc++ for gcc < 9 +#endif() +#set_property(TARGET Tile PROPERTY +# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}) +#target_include_directories(Tile PRIVATE +# ${CONAN_INCLUDE_DIRS_SDL} +# ${CONAN_INCLUDE_DIRS_TCLAP}) +#target_link_libraries(Tile PRIVATE +# CONAN_PKG::sdl +# ${PROJECT_NAME} +#) +# +# +# \ No newline at end of file diff --git a/Rgb2Hires_PC/conanfile.txt b/Rgb2Hires_PC/conanfile.txt new file mode 100644 index 0000000..d7eb219 --- /dev/null +++ b/Rgb2Hires_PC/conanfile.txt @@ -0,0 +1,8 @@ +[requires] +sdl/2.0.20 +sdl_image/2.0.5 +tclap/1.2.4 + +[generators] +cmake + diff --git a/Rgb2Hires_PC/src/App_Picture.cpp b/Rgb2Hires_PC/src/App_Picture.cpp index bd39fc9..037efa3 100644 --- a/Rgb2Hires_PC/src/App_Picture.cpp +++ b/Rgb2Hires_PC/src/App_Picture.cpp @@ -23,13 +23,13 @@ #include #include -#include +#include #include #include "ImageQuantized.h" -#include "Picture.h" -#include "Tile.h" -#include "Display.h" +//#include "Picture.h" +//#include "Tile.h" +//#include "Display.h" using namespace std; using namespace RgbToHires; @@ -41,10 +41,39 @@ inline bool exists(const std::string& path) return (stat(path.c_str(), &buffer) == 0); } +void ExitOnError(const std::string& message, + std::vector surfaces = {}) +{ + std::cout << "Error\n" << message << '\n'; + + for (auto surface : surfaces) + { + SDL_FreeSurface(surface); + } + + SDL_Quit(); + IMG_Quit(); + exit(-1); +} + + /// @brief Program entry point int main( int argc, char *argv[] ) { - Magick::InitializeMagick(*argv); + + // Init + int inited = IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG); + if (inited != (IMG_INIT_JPG | IMG_INIT_PNG)) + { + std::cerr << "IMG_Init: Failed to init required jpg and png support!\n" + << "IMG_Init: " << IMG_GetError() << '\n'; + return -1; + } + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + std::cerr << "There was an error initing SDL2: " << SDL_GetError() << std::endl; + return -1; + } //Parsing command line TCLAP::CmdLine cmd("Picture - by Christophe Meneboeuf ", ' ', "0"); @@ -59,41 +88,48 @@ int main( int argc, char *argv[] ) cmd.parse(argc, argv); if (imagePath.getValue().size() == 0 || outputPath.getValue().size() == 0) { - std::cout << "No input or output path provided." << std::endl; + std::cout << "No input or output path provided." << std::endl; + IMG_Quit(); return -1; } - try - { - const auto filepath = imagePath.getValue(); - if (!exists(filepath)) { - throw runtime_error("Cannot read " + filepath); - } - const auto imageRgb = Magick::Image{ filepath }; - auto imageQuantized = ImageQuantized{ imageRgb }; - const auto imageHiRes = Picture{ imageQuantized }; - if (assembly.getValue() == true) { //Ouput in ASM - ofstream output(outputPath.getValue()); - output << imageHiRes.getAsm(); - } - else { //Binary output - ofstream output(outputPath.getValue(), ios::binary); - const auto bytes = imageHiRes.getBlob(); - output.write(reinterpret_cast(bytes.get()), bytes->size()); - } - - if (preview.getValue()) { - const auto bytes = imageHiRes.getBlob(); - Display::Window::GetInstance()->display(filepath, bytes->data()); - } - + + const auto filepath = imagePath.getValue(); + if (!exists(filepath)) { + ExitOnError("Cannot read " + filepath); } - //Fatal error - catch (const exception& e) { - cout << e.what(); - return -1; + std::vector surfaces; + SDL_Surface* surfaceRgb = IMG_Load(filepath.c_str()); + surfaces.push_back(surfaceRgb); + if (surfaceRgb == nullptr) + { + ExitOnError("Cannot decode " + filepath, surfaces); } + const ImageQuantized imageHiRes{ surfaceRgb }; + + if (assembly.getValue() == true) { //Ouput in ASM + ofstream output(outputPath.getValue()); + output << imageHiRes.getAsm(); + } + else { //Binary output + ofstream output(outputPath.getValue(), ios::binary); + const auto bytes = imageHiRes.getBlob(); + output.write(reinterpret_cast(bytes.get()), bytes->size()); + } + + //if (preview.getValue()) { + // const auto bytes = imageHiRes.getBlob(); + // Display::Window::GetInstance()->display(filepath, bytes->data()); + //} + + for (auto surface : surfaces) + { + SDL_FreeSurface(surface); + } + + SDL_Quit(); + IMG_Quit(); return 0; } diff --git a/Rgb2Hires_PC/src/Common.h b/Rgb2Hires_PC/src/Common.h index 9c51d2a..95b430b 100644 --- a/Rgb2Hires_PC/src/Common.h +++ b/Rgb2Hires_PC/src/Common.h @@ -20,25 +20,32 @@ #ifndef __COMMON_H__ #define __COMMON_H__ - -#include - -#define MAGICKCORE_ZERO_CONFIGURATION_SUPPORT 1 +#include +#include namespace RgbToHires { - constexpr std::size_t SHIFT = sizeof(Magick::Quantum)*8 - 8; + struct Color : public SDL_Color + { + inline bool operator==(const Color& rhs) const + { + return r == rhs.r && g == rhs.g && b == rhs.b; + } + inline bool operator==(const SDL_Color& rhs) const + { + return r == rhs.r && g == rhs.g && b == rhs.b; + } + }; - #define WHITE Magick::Color{0xFF << SHIFT, 0xFF << SHIFT, 0xFF << SHIFT} - #define BLACK Magick::Color{0x00 << SHIFT, 0x00 << SHIFT, 0x00 << SHIFT} - #define BLUE Magick::Color{0x07 << SHIFT, 0xA8 << SHIFT, 0xE0 << SHIFT} - #define GREEN Magick::Color{0x43 << SHIFT, 0xC8 << SHIFT, 0x00 << SHIFT} - #define ORANGE Magick::Color{0xF9 << SHIFT, 0x56 << SHIFT,0x1D << SHIFT} - #define VIOLET Magick::Color{0xBB << SHIFT, 0x36 << SHIFT, 0xFF << SHIFT} +constexpr Color WHITE {0xFF, 0xFF, 0xFF, 0xFF}; +constexpr Color BLACK {0x00, 0x00, 0x00, 0xFF}; +constexpr Color BLUE {0x07, 0xA8, 0xE0, 0xFF}; +constexpr Color GREEN {0x43, 0xC8, 0x00, 0xFF}; +constexpr Color ORANGE{0xF9, 0x56, 0x1D, 0xFF}; +constexpr Color VIOLET{0xBB, 0x36, 0xFF, 0xFF}; - - constexpr unsigned WIDTH = 140u; - constexpr unsigned HEIGHT = 192u; +constexpr unsigned WIDTH = 140u; +constexpr unsigned HEIGHT = 192u; } diff --git a/Rgb2Hires_PC/src/HiRes.cpp b/Rgb2Hires_PC/src/HiRes.cpp index c119493..ccbc91d 100644 --- a/Rgb2Hires_PC/src/HiRes.cpp +++ b/Rgb2Hires_PC/src/HiRes.cpp @@ -17,7 +17,7 @@ */ #include -#include "ImageQuantized.h" +//#include "ImageQuantized.h" #include "HiRes.h" @@ -96,7 +96,7 @@ namespace RgbToHires { } - uint8_t BlockHr::getDibit(const Magick::Color& color) const + uint8_t BlockHr::getDibit(const Color& color) const { if (color == WHITE) { return 3; @@ -112,7 +112,7 @@ namespace RgbToHires { } else { auto msg = string("Unsupported color used as input for hires pixel\nRGB:"); - msg = msg + to_string(color.redQuantum()) + to_string(color.greenQuantum()) + to_string(color.blueQuantum()); + msg = msg + to_string(color.r) + to_string(color.g) + to_string(color.b); throw(runtime_error(msg)); } } diff --git a/Rgb2Hires_PC/src/HiRes.h b/Rgb2Hires_PC/src/HiRes.h index fa27845..2c84781 100644 --- a/Rgb2Hires_PC/src/HiRes.h +++ b/Rgb2Hires_PC/src/HiRes.h @@ -31,6 +31,11 @@ namespace RgbToHires { + + static constexpr unsigned NB_PIXEL_PER_BLOCK = 7u; + static constexpr unsigned NB_BLOCK_PER_LINE = 20u; + static constexpr unsigned NB_LINES_PER_SCREEN = 192u; + constexpr std::array LineAdresses = { 0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, 0x0028, 0x00a8, 0x0128, 0x01a8, 0x0228, 0x02a8, 0x0328, 0x03a8, @@ -41,7 +46,7 @@ namespace RgbToHires 0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800, 0x1c00 }; - using BlockPixel = std::array; + using BlockPixel = std::array; /// @brief A block of 7 pixels class BlockHr @@ -69,7 +74,7 @@ namespace RgbToHires /// @brief Returns the color group of these two 3.5 pixel blocks std::pair getGroup(const BlockPixel&) const; /// @brief Returns the bit pait corresponding to the given color - uint8_t getDibit(const Magick::Color&) const; + uint8_t getDibit(const Color&) const; std::array _data; }; diff --git a/Rgb2Hires_PC/src/ImageQuantized.cpp b/Rgb2Hires_PC/src/ImageQuantized.cpp index 6198980..945984e 100644 --- a/Rgb2Hires_PC/src/ImageQuantized.cpp +++ b/Rgb2Hires_PC/src/ImageQuantized.cpp @@ -1,6 +1,6 @@ -/* Rgb2Hires -* Copyright (C) 2016 Christophe Meneboeuf +/*Rgb2Hires +* Copyright (C) 2016-2022 Christophe Meneboeuf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include #include + #include "ImageQuantized.h" using namespace std; @@ -25,60 +26,69 @@ using namespace std; namespace RgbToHires { - ImageQuantized::ImageQuantized(const Magick::Image& src): - Magick::Image(src) + ImageQuantized::ImageQuantized(SDL_Surface* const src) : + _format(SDL_PIXELFORMAT_BGRX8888) { - const auto dim = size(); - if (dim.height() != HEIGHT || dim.width() != WIDTH) { + if (src->h != HEIGHT || src->w != WIDTH) { throw std::runtime_error("Image dimension must be 140x192 pixels."); } - auto pixelpacket = getPixels(0u, 0u, WIDTH, HEIGHT); - for (auto i = 0u; i < HEIGHT; ++i) - { - for (auto j = 0u; j < WIDTH; ++j) - { - auto color =*pixelpacket; - const auto distBlack = Distance(BLACK, color); - const auto distWhite = Distance(WHITE, color); - const auto distBlue = Distance(BLUE, color); - const auto distGreen = Distance(GREEN, color); - const auto distOrange = Distance(ORANGE, color); - const auto distViolet = Distance(VIOLET, color); - const auto distMin = std::min({ distBlack, distWhite, distBlue, \ - distGreen, distOrange, distViolet }); - if (distMin == distBlack) { - *pixelpacket++ = BLACK; + SDL_Surface* rgb = SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_BGRX8888, 0); + + SDL_LockSurface(rgb); + auto srcPx = reinterpret_cast(rgb->pixels); + SDL_UnlockSurface(rgb); + + // Construct HIRES image: lines are not properly ordered + for (auto& line : _blobHr) + { + for (auto blockNr = 0u; blockNr < NB_BLOCK_PER_LINE; ++blockNr) + { + BlockRgb blockRgb; + for (auto& pixel : blockRgb) + { + Color color; + SDL_GetRGB(*srcPx, rgb->format, &color.r, &color.g, &color.b); + pixel = Quantize(color); + srcPx++; + } + line.emplace_back(BlockHr{ blockRgb }); + } + } + + //Constructing the map used to interleave the lines + auto i = 0u; + for (const auto& line : _blobHr) + { + uint16_t addr_interleaved = LineAdresses[i / 8] + LineOffsets[i % 8]; + _hrOrderedLines.insert(std::pair(addr_interleaved, &line)); + ++i; + } + //Adding the 8 byte "memory holes" + for (auto line : _hrOrderedLines) + { + if ((line.first & 0xFF) == 0x50 || (line.first & 0xFF) == 0xD0) + { + for (auto i = 0u; i < 4u; ++i) + { + const_cast(line.second)->emplace_back(BlockHr{}); } - else if (distMin == distWhite) { - *pixelpacket++ = WHITE; - } - else if (distMin == distBlue) { - *pixelpacket++ = BLUE; - } - else if (distMin == distGreen) { - *pixelpacket++ = GREEN; - } - else if (distMin == distOrange) { - *pixelpacket++ = ORANGE; - } - else { - *pixelpacket++ = VIOLET; - } } } - syncPixels(); } - std::unique_ptr ImageQuantized::getBlob() const + unique_ptr> ImageQuantized::getBlob() const { - auto blob = std::unique_ptr(new Blob); - auto pixels = getConstPixels(0u, 0u, WIDTH, HEIGHT); - for (auto& line : *blob) { - for (auto& block : line) { - for (auto pixel: block ) { - pixel = *pixels++; + auto blob = unique_ptr>{ new array }; + auto byte_blob = begin(*blob); + for (const auto& line : _hrOrderedLines) + { + for (const auto& block : *(line.second)) + { + for (const auto byte_block : block) + { + *byte_blob++ = byte_block; } } } @@ -87,20 +97,42 @@ namespace RgbToHires { + string ImageQuantized::getAsm() const + { + string assembly{ "Picture:\n" }; + for (const auto& line : _hrOrderedLines) + { + assembly += "\t.byte\t"; + for (const auto& block : *(line.second)) + { + for (const auto byte : block) + { + assembly += to_string(byte) + ", "; + } + } + assembly.pop_back(); //removing the last coma + assembly.pop_back(); + assembly += "\n"; + } + return assembly; + } - double ImageQuantized::Distance(const Magick::Color& color1, const Magick::Color& color2) + + + + double ImageQuantized::Distance(const Color& color1, const Color& color2) { static constexpr double LUMA_RED = 0.299; static constexpr double LUMA_GREEN = 0.587; static constexpr double LUMA_BLUE = 0.114; - const auto y1 = LUMA_RED * color1.redQuantum() + LUMA_GREEN * color1.greenQuantum() + LUMA_BLUE * color1.blueQuantum(); - const auto u1 = 0.492 * (color1.blueQuantum() - y1); - const auto v1 = 0.877 * (color1.redQuantum() - y1); - const auto y2 = LUMA_RED * color2.redQuantum() + LUMA_GREEN * color2.greenQuantum() + LUMA_BLUE * color2.blueQuantum(); - const auto u2 = 0.492 * (color2.blueQuantum() - y2); - const auto v2 = 0.877 * (color2.redQuantum() - y2); + const auto y1 = LUMA_RED * color1.r + LUMA_GREEN * color1.g + LUMA_BLUE * color1.b; + const auto u1 = 0.492 * (color1.b - y1); + const auto v1 = 0.877 * (color1.r - y1); + const auto y2 = LUMA_RED * color2.r + LUMA_GREEN * color2.g + LUMA_BLUE * color2.b; + const auto u2 = 0.492 * (color2.b - y2); + const auto v2 = 0.877 * (color2.r - y2); const auto dy = (y1 - y2); const auto du = (u1 - u2); @@ -110,4 +142,38 @@ namespace RgbToHires { } + inline Color ImageQuantized::Quantize(const Color& color) + { + const auto distBlack = Distance(BLACK, color); + auto distMin = distBlack; + const auto distWhite = Distance(WHITE, color); + if (distMin > distWhite) { distMin = distWhite; } + const auto distBlue = Distance(BLUE, color); + if (distMin > distBlue) { distMin = distBlue; } + const auto distGreen = Distance(GREEN, color); + if (distMin > distGreen) { distMin = distGreen; } + const auto distOrange = Distance(ORANGE, color); + if (distMin > distOrange) { distMin = distOrange; } + const auto distViolet = Distance(VIOLET, color); + + if (distMin == distBlack) { + return BLACK; + } + else if (distMin == distWhite) { + return WHITE; + } + else if (distMin == distBlue) { + return BLUE; + } + else if (distMin == distGreen) { + return GREEN; + } + else if (distMin == distOrange) { + return ORANGE; + } + else { + return VIOLET; + } + } + } \ No newline at end of file diff --git a/Rgb2Hires_PC/src/ImageQuantized.h b/Rgb2Hires_PC/src/ImageQuantized.h index b1bac78..dadb3df 100644 --- a/Rgb2Hires_PC/src/ImageQuantized.h +++ b/Rgb2Hires_PC/src/ImageQuantized.h @@ -22,32 +22,49 @@ #include #include -#include "Common.h" +#include +#include +#include "Common.h" +#include "HiRes.h" namespace RgbToHires { /// @brief Image quantized to the HIRES colors. /// @details Quantization works with a nearest distance algorithm. - class ImageQuantized : - public Magick::Image + class ImageQuantized { public: - using Block = std::array; - using Line = std::array; - using Blob = std::array; + // rgb + using BlockRgb = std::array; + using Line = std::array; + using BlobRgb = std::array; + // hires + using LineHr = std::vector; + using BlobHr = std::array; - ImageQuantized(const Magick::Image& src); - ~ImageQuantized()=default; + static constexpr unsigned FRAME_SIZE = 192 * 40 + 512; ///< Frame size in byte - /// @brief Returns an array of bytes forming the RGB quantized image - std::unique_ptr getBlob() const; + ImageQuantized(SDL_Surface* const source); + ~ImageQuantized() = default; + + + /// @brief Returns the binary hires picture + std::unique_ptr > getBlob() const; + /// @brief Returns asm code corresponding to the image in memory (CA65 format) + std::string getAsm() const; private: - /// @brief Computes the euclidian distance between two colors - double Distance(const Magick::Color&, const Magick::Color&); + Color Quantize(const Color& color); + /// @brief Computes the euclidian distance between two colors + double Distance(const Color&, const Color&); + + private: + const SDL_PixelFormatEnum _format; + BlobHr _blobHr; + std::map _hrOrderedLines; ///< map }; } diff --git a/Rgb2Hires_PC/src/Picture.cpp b/Rgb2Hires_PC/src/Picture.cpp index 1d85b82..572c192 100644 --- a/Rgb2Hires_PC/src/Picture.cpp +++ b/Rgb2Hires_PC/src/Picture.cpp @@ -1,3 +1,5 @@ +#include + #include "Picture.h" @@ -6,24 +8,35 @@ using namespace std; namespace RgbToHires { - Picture::Picture(const ImageQuantized& source) + Picture::Picture(const CImg& source) { - auto pixel_src = source.getConstPixels(0u, 0u, WIDTH, HEIGHT); //Filling the storage with BlockHrs - for (auto& line : _blob) { + int lineNr = 0; + for (auto& line : _blobRgb) + { + int colNr = 0; line.reserve(NB_BLOCKS_PER_LINE); //Useful data - for (auto blockNr = 0u; blockNr < NB_BLOCKS_PER_LINE; ++blockNr) { + for (auto blockNr = 0u; blockNr < NB_BLOCKS_PER_LINE; ++blockNr) + { BlockPixel blockPxRgb; - for (auto& pxRgb : blockPxRgb) { - pxRgb = *pixel_src++; + for (auto& pxRgb : blockPxRgb) + { + pxRgb = { + source(colNr, lineNr, 0, 0), + source(colNr, lineNr, 0, 1), + source(colNr, lineNr, 0, 2) + }; + ++colNr; } line.emplace_back(BlockHr{ blockPxRgb }); } + ++lineNr; } + //Constructing the map used to interleave the lines auto i = 0u; - for (const auto& line : _blob) { + for (const auto& line : _blobRgb) { auto addr_interleaved = LineAdresses[i / 8] + LineOffsets[i % 8]; _hrOrderedLines.insert(pair(addr_interleaved, &line)); ++i; @@ -73,4 +86,74 @@ namespace RgbToHires return assembly; } + + + + void Picture::Quantize() + { + /*const auto dim = size(); + if (dim.height() != HEIGHT || dim.width() != WIDTH) { + throw std::runtime_error("Image dimension must be 140x192 pixels."); + } + auto pixelpacket = getPixels(0u, 0u, WIDTH, HEIGHT); + for (auto i = 0u; i < HEIGHT; ++i) + { + for (auto j = 0u; j < WIDTH; ++j) + { + auto color = *pixelpacket; + const auto distBlack = Distance(BLACK, color); + const auto distWhite = Distance(WHITE, color); + const auto distBlue = Distance(BLUE, color); + const auto distGreen = Distance(GREEN, color); + const auto distOrange = Distance(ORANGE, color); + const auto distViolet = Distance(VIOLET, color); + const auto distMin = std::min({ distBlack, distWhite, distBlue, \ + distGreen, distOrange, distViolet }); + + if (distMin == distBlack) { + *pixelpacket++ = BLACK; + } + else if (distMin == distWhite) { + *pixelpacket++ = WHITE; + } + else if (distMin == distBlue) { + *pixelpacket++ = BLUE; + } + else if (distMin == distGreen) { + *pixelpacket++ = GREEN; + } + else if (distMin == distOrange) { + *pixelpacket++ = ORANGE; + } + else { + *pixelpacket++ = VIOLET; + } + } + }*/ + } + + + + + double Picture::Distance(const RGB_t& color1, const RGB_t& color2) + { + + static constexpr double LUMA_RED = 0.299; + static constexpr double LUMA_GREEN = 0.587; + static constexpr double LUMA_BLUE = 0.114; + + const auto y1 = LUMA_RED * color1.r + LUMA_GREEN * color1.g + LUMA_BLUE * color1.b; + const auto u1 = 0.492 * (color1.b - y1); + const auto v1 = 0.877 * (color1.r - y1); + const auto y2 = LUMA_RED * color2.r + LUMA_GREEN * color2.g + LUMA_BLUE * color2.b; + const auto u2 = 0.492 * (color2.b - y2); + const auto v2 = 0.877 * (color2.r - y2); + + const auto dy = (y1 - y2); + const auto du = (u1 - u2); + const auto dv = (v1 - v2); + + return (dy * dy + du * du + dv * dv); + } + } diff --git a/Rgb2Hires_PC/src/Picture.h b/Rgb2Hires_PC/src/Picture.h index 63dda0e..d39b9cb 100644 --- a/Rgb2Hires_PC/src/Picture.h +++ b/Rgb2Hires_PC/src/Picture.h @@ -18,6 +18,8 @@ #ifndef _PICTURE_H_ #define _PICTURE_H_ +#include + #include "ImageQuantized.h" #include "HiRes.h" @@ -46,7 +48,7 @@ namespace RgbToHires using LineHr = std::vector; using Blob = std::array; - Blob _blob; ///< A frame ordered buffer of hires data + Blob _blobRgb; ///< A frame ordered buffer of hires data std::map _hrOrderedLines; ///< map };