SDL2 port: Picture with live preview

This commit is contained in:
Christophe Meneboeuf 2022-06-16 23:08:58 +02:00
parent 20f85a2dc5
commit ed03b6a48f
10 changed files with 88 additions and 107 deletions

View File

@ -30,12 +30,6 @@ add_library(${PROJECT_NAME} src/Common.h
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
)
## dependencies
conan_set_find_library_paths(${PROJECT_NAME})
@ -43,7 +37,10 @@ conan_target_link_libraries(${PROJECT_NAME})
# Application Picture
add_executable( Picture src/App_Picture.cpp)
add_executable( Picture src/App_Picture.cpp
src/Display.h
src/Display.cpp
)
if(NOT WIN32)
set_target_properties(Picture PROPERTIES COMPILE_FLAGS -pthread LINK_FLAGS -pthread)
endif()
@ -58,23 +55,24 @@ target_link_libraries(Picture ${PROJECT_NAME})
set_property(TARGET Picture PROPERTY
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG})
## Application Tile
#add_executable(Tile src/App_Tile.cpp)
#add_executable(Tile src/App_Tile.cpp
# src/Tile.h
# src/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()
#conan_set_find_library_paths(Tile)
#conan_target_link_libraries(Tile)
#target_link_libraries(Picture ${PROJECT_NAME})
### output
#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}
# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}
#)
#
#
#

View File

@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define SDL_MAIN_HANDLED
#include <exception>
#include <iostream>
@ -27,9 +28,7 @@
#include <tclap/CmdLine.h>
#include "ImageQuantized.h"
//#include "Picture.h"
//#include "Tile.h"
//#include "Display.h"
#include "Display.h"
using namespace std;
using namespace RgbToHires;
@ -108,21 +107,23 @@ int main( int argc, char *argv[] )
}
const ImageQuantized imageHiRes{ surfaceRgb };
if (assembly.getValue() == true) { //Ouput in ASM
ofstream output(outputPath.getValue());
output << imageHiRes.getAsm();
if (preview.getValue()) {
const auto bytes = imageHiRes.getHiresBuffer();
Display::Window::GetInstance()->display(filepath, bytes->data());
}
else { //Binary output
ofstream output(outputPath.getValue(), ios::binary);
const auto bytes = imageHiRes.getBlob();
output.write(reinterpret_cast<const char*>(bytes.get()), bytes->size());
else
{
if (assembly.getValue() == true) { //Ouput in ASM
ofstream output(outputPath.getValue());
output << imageHiRes.getHiresAsm();
}
else { //Binary output
ofstream output(outputPath.getValue(), ios::binary);
const auto bytes = imageHiRes.getHiresBuffer();
output.write(reinterpret_cast<const char*>(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);

View File

@ -82,7 +82,7 @@ int main( int argc, char *argv[] )
// Always output in asm
ofstream output(outputPath.getValue());
output << tileHiRes.getAsm();
output << tileHiRes.getHiresAsm();
}

View File

@ -1,10 +1,10 @@
#include <filesystem>
#include <stdexcept>
#include <iostream>
#include <chrono>
#define SDL_MAIN_HANDLED
#include <SDL.h>
#include <SDL_image.h>
#include "Picture.h"
#include "Display.h"
@ -12,8 +12,6 @@
using namespace std;
namespace RgbToHires
{
namespace Display
{
@ -118,24 +116,29 @@ namespace RgbToHires
{
bool isDone = false;
int nbErrors = 0;
std::vector<SDL_Surface*> surfaces;
while (!isDone) // several attempts as the file may be marked modified before being written
{
try
{
this_thread::sleep_for(std::chrono::milliseconds(500)); // 500ms between each attempt
// update hires image
const auto imageRgb = Magick::Image{ path };
auto imageQuantized = ImageQuantized{ imageRgb };
const auto imageHiRes = Picture{ imageQuantized };
SDL_Surface* surfaceRgb = IMG_Load(path.c_str());
surfaces.push_back(surfaceRgb);
if (surfaceRgb == nullptr)
{
throw("Cannot decode " + path);
}
const RgbToHires::ImageQuantized imageHiRes{ surfaceRgb };
// rgb conversion from hires data
std::lock_guard<std::mutex> lock{ this->_mutex }; // protecting pViewport
pViewport = ComputeRgbBuffer(imageHiRes.getBlob()->data());
pViewport = ComputeRgbBuffer(imageHiRes.getHiresBuffer()->data());
isDone = true;
timeModified = std::filesystem::last_write_time(path);
this->_isFileModified.store(isImgModified);
}
catch (Magick::Error& e)
catch (std::exception& e)
{
++nbErrors;
if (nbErrors >= 5) { // 5 atttemps
@ -146,6 +149,7 @@ namespace RgbToHires
}
}
}
for(auto surface : surfaces) { SDL_FreeSurface(surface); }
}
}
}); // thread
@ -179,24 +183,6 @@ namespace RgbToHires
}
void SdlError(const std::string& error,
SDL_Window* const pWindow = nullptr,
SDL_Renderer* const pRenderer = nullptr
)
{
std::cout << "Error: " << error << '\n';
if (pRenderer != nullptr) {
SDL_DestroyRenderer(pRenderer);
}
if (pWindow != nullptr) {
SDL_DestroyWindow(pWindow);
}
SDL_Quit();
exit(1);
}
constexpr std::array<rgba8Bits_t, 7> Palette = {
rgba8Bits_t{0x00,0x00,0x00, 0xFF}, // black
@ -299,9 +285,9 @@ namespace RgbToHires
// Converting line per line, pixel-block per pixel-block
auto pViewport = make_unique<Screen>();
auto itLine = std::begin(*pViewport);
for (const auto lineBlockOffset : LineAdresses)
for (const auto lineBlockOffset : RgbToHires::LineAdresses)
{
for (const auto lineOffset : LineOffsets)
for (const auto lineOffset : RgbToHires::LineOffsets)
{
const uint8_t* pHires = hires + lineBlockOffset + lineOffset; // interleaved HIRES source line
for (std::size_t x = 0; x < itLine->size(); ++x)
@ -317,6 +303,4 @@ namespace RgbToHires
return pViewport;
}
}
}

View File

@ -29,51 +29,48 @@ struct SDL_Window;
struct SDL_Renderer;
struct SDL_Texture;
namespace RgbToHires
{
namespace Display
{
namespace Display
{
struct rgba8Bits_t
{
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
uint8_t a = 0xff;
};
struct rgba8Bits_t
{
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
uint8_t a = 0xff;
};
using Block = std::array<rgba8Bits_t, 14>;
using Line = std::array<Block, 40>;
using Screen = std::array<Line, 192 * 2>;
using Block = std::array<rgba8Bits_t, 14>;
using Line = std::array<Block, 40>;
using Screen = std::array<Line, 192 * 2>;
class Window
{
public:
Window() = default;
~Window();
class Window
{
public:
Window() = default;
~Window();
static Window* GetInstance();
static Window* GetInstance();
void display(const std::string& path, const uint8_t* hiresblob);
void display(const std::string& path, const uint8_t* hiresblob);
private:
bool init();
void sdlError(const std::string& msg);
private:
bool init();
void sdlError(const std::string& msg);
std::thread* _pThread = nullptr; //< to survey filechange
std::mutex _mutex;
std::atomic_bool _isFileModified = false;
std::atomic_bool _stopFileSurvey = false;
std::thread* _pThread = nullptr; //< to survey filechange
std::mutex _mutex;
std::atomic_bool _isFileModified = false;
std::atomic_bool _stopFileSurvey = false;
static Window* S_pInstance;
static const int SCALE = 2;
static Window* S_pInstance;
static const int SCALE = 2;
SDL_Window* _pWindow = nullptr;
SDL_Renderer* _pRenderer = nullptr;
SDL_Texture* _pTexture = nullptr;
};
SDL_Window* _pWindow = nullptr;
SDL_Renderer* _pRenderer = nullptr;
SDL_Texture* _pTexture = nullptr;
};
}
}
#endif

View File

@ -78,7 +78,7 @@ namespace RgbToHires {
}
unique_ptr<array<uint8_t, ImageQuantized::FRAME_SIZE>> ImageQuantized::getBlob() const
unique_ptr<array<uint8_t, ImageQuantized::FRAME_SIZE>> ImageQuantized::getHiresBuffer() const
{
auto blob = unique_ptr<array<uint8_t, FRAME_SIZE>>{ new array<uint8_t, FRAME_SIZE> };
auto byte_blob = begin(*blob);
@ -97,7 +97,7 @@ namespace RgbToHires {
string ImageQuantized::getAsm() const
string ImageQuantized::getHiresAsm() const
{
string assembly{ "Picture:\n" };
for (const auto& line : _hrOrderedLines)
@ -155,6 +155,7 @@ namespace RgbToHires {
const auto distOrange = Distance(ORANGE, color);
if (distMin > distOrange) { distMin = distOrange; }
const auto distViolet = Distance(VIOLET, color);
if (distMin > distViolet) { distMin = distViolet; }
if (distMin == distBlack) {
return BLACK;

View File

@ -49,11 +49,11 @@ namespace RgbToHires {
ImageQuantized(SDL_Surface* const source);
~ImageQuantized() = default;
/// @brief Returns the binary hires picture
std::unique_ptr <std::array<uint8_t, FRAME_SIZE>> getBlob() const;
std::unique_ptr <std::array<uint8_t, FRAME_SIZE>> getHiresBuffer() const;
/// @brief Returns asm code corresponding to the image in memory (CA65 format)
std::string getAsm() const;
std::string getHiresAsm() const;
/// @brief Returns an HIRES block
private:
Color Quantize(const Color& color);

View File

@ -41,7 +41,7 @@ namespace RgbToHires
/// @brief Returns the binary hires picture
std::unique_ptr <std::array<uint8_t, FRAME_SIZE>> getBlob() const;
/// @brief Returns asm code corresponding to the image in memory (CA65 format)
std::string getAsm() const;
std::string getHiresAsm() const;
private:

View File

@ -23,7 +23,7 @@ RgbToHires::Tile::Tile(const ImageQuantized& source, const unsigned col, const u
}
std::string RgbToHires::Tile::getAsm() const
std::string RgbToHires::Tile::getHiresAsm() const
{
std::string assembly;
for (const auto& line : _blob)

View File

@ -19,7 +19,7 @@ namespace RgbToHires
~Tile() = default;
/// @brief Returns asm code corresponding to the tile: the lines are not interleaved!
std::string getAsm() const;
std::string getHiresAsm() const;
private:
using LineHr = std::vector<BlockHr>;