Display a preview
This commit is contained in:
parent
6d5e1d53c1
commit
a0f71067a7
Binary file not shown.
|
@ -17,6 +17,11 @@ 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")
|
||||
|
@ -25,6 +30,7 @@ if(WIN32)
|
|||
else()
|
||||
find_package(ImageMagick 6.9 EXACT REQUIRED COMPONENTS Magick++ )
|
||||
endif(WIN32)
|
||||
find_package(SDL2 REQUIRED)
|
||||
|
||||
# directories
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/bin/debug)
|
||||
|
@ -40,16 +46,18 @@ add_library(${PROJECT_NAME} src/Common.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})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${ImageMagick_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
|
||||
# Application Picture
|
||||
add_executable(Picture src/App_Picture.cpp)
|
||||
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} ${PROJECT_NAME})
|
||||
target_link_libraries(Picture ${ImageMagick_LIBRARIES} ${SDL2_LIBRARIES} ${PROJECT_NAME})
|
||||
set_property(TARGET Picture PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG})
|
||||
|
||||
# Application Tile
|
||||
|
@ -62,14 +70,8 @@ set_property(TARGET Tile PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPU
|
|||
|
||||
# Windows only: copy dlls
|
||||
if(WIN32)
|
||||
if(CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
string (REPLACE "/" "\\" WIN_BIN_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG})
|
||||
add_custom_command(TARGET Picture POST_BUILD COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/scripts/copy_im_db_dlls.bat ${WIN_BIN_DIR})
|
||||
add_custom_command(TARGET Tile POST_BUILD COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/scripts/copy_im_db_dlls.bat ${WIN_BIN_DIR})
|
||||
else()
|
||||
string (REPLACE "/" "\\" WIN_BIN_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE})
|
||||
add_custom_command(TARGET Picture POST_BUILD COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/scripts/copy_im_rl_dlls.bat ${WIN_BIN_DIR})
|
||||
add_custom_command(TARGET Tile POST_BUILD COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/scripts/copy_im_rl_dlls.bat ${WIN_BIN_DIR})
|
||||
endif()
|
||||
|
||||
endif(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 "$<$<CONFIG:debug>:${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}>$<$<CONFIG:release>:${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}>")
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND "$<$<CONFIG:debug>:${DEBUG_EXE_PATH}>$<$<CONFIG:release>:${RELEASE_EXE_PATH}>" ${WIN_BIN_DIR})
|
||||
endif(WIN32)
|
||||
|
|
|
@ -7,3 +7,4 @@ copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_DB_jpeg_.dll %1
|
|||
copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_DB_png_.dll %1
|
||||
copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_DB_tiff_.dll %1
|
||||
copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_DB_webp_.dll %1
|
||||
copy "%SDL2_HOME%\lib\x64\SDL2.dll" %1
|
||||
|
|
|
@ -7,3 +7,4 @@ copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_RL_jpeg_.dll %1
|
|||
copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_RL_png_.dll %1
|
||||
copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_RL_tiff_.dll %1
|
||||
copy %MAGICK_HOME%\VisualMagick\bin\IM_MOD_RL_webp_.dll %1
|
||||
copy "%SDL2_HOME%\lib\x64\SDL2.dll" %1
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "ImageQuantized.h"
|
||||
#include "Picture.h"
|
||||
#include "Tile.h"
|
||||
#include "Display.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace RgbToHires;
|
||||
|
@ -77,6 +78,10 @@ int main( int argc, char *argv[] )
|
|||
const auto bytes = imageHiRes.getBlob();
|
||||
output.write(reinterpret_cast<const char*>(bytes.get()), bytes->size());
|
||||
}
|
||||
|
||||
const auto bytes = imageHiRes.getBlob();
|
||||
Display::Display(bytes->data());
|
||||
|
||||
}
|
||||
|
||||
//Fatal error
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
#include <iostream>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace RgbToHires
|
||||
{
|
||||
namespace Display
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
struct rgba8Bits_t
|
||||
{
|
||||
uint8_t r = 0;
|
||||
uint8_t g = 0;
|
||||
uint8_t b = 0;
|
||||
uint8_t a = 0xff;
|
||||
};
|
||||
|
||||
|
||||
constexpr std::array<rgba8Bits_t, 7> Palette = {
|
||||
rgba8Bits_t{0x00,0x00,0x00, 0xFF}, // black
|
||||
rgba8Bits_t{0xFF,0xFF,0xFF, 0xFF}, // white
|
||||
rgba8Bits_t{0x07,0xA8,0xE0, 0xFF}, // blue
|
||||
rgba8Bits_t{0xF9,0x56,0x1D, 0xFF}, // orange
|
||||
rgba8Bits_t{0x43,0xC8,0x00, 0xFF}, // green
|
||||
rgba8Bits_t{0xBB,0x36,0xFF, 0xFF}, // black
|
||||
rgba8Bits_t{0x80,0x80,0x80, 0xFF} // dummy as AppleWin's code can overflow :( (no time to correct it)
|
||||
};
|
||||
|
||||
|
||||
//===========================================================================
|
||||
// RGB videocards HGR
|
||||
|
||||
//! @brief Output the colors from a 14-dot block
|
||||
//! @details Adapted from AppleWin: https://github.com/AppleWin/AppleWin
|
||||
//! A 14-dot block is used to draw a 7-pixel block (2 * 3.5-pixel blocks)
|
||||
//! Each dot of a 3.5-pixel block can be delayed so we draw on 2 subdots.
|
||||
//! 28 subdots = 14 dots = 7 pixels (in 2 * 3.5-pixel blocks)
|
||||
//! @param x Vertical position of the 14-dot block
|
||||
//! @param pLineAddr pointer to the start of the line
|
||||
//! @param pOut pointer to the 28-subdot block to draw
|
||||
void UpdateHiResRGBCell(const int x, uint8_t* pLineAddr, rgba8Bits_t* pOut)
|
||||
{
|
||||
const int xpixel = x * 14;
|
||||
int xoffset = x & 1; // offset to start of the 2 bytes
|
||||
pLineAddr -= xoffset;
|
||||
|
||||
// We need all 28 bits because each pixel needs a three bit evaluation
|
||||
uint8_t byteval1 = (x < 2 ? 0 : *(pLineAddr - 1));
|
||||
uint8_t byteval2 = *pLineAddr;
|
||||
uint8_t byteval3 = *(pLineAddr + 1);
|
||||
uint8_t byteval4 = (x >= 38 ? 0 : *(pLineAddr + 2));
|
||||
|
||||
// all 28 bits chained
|
||||
uint32_t dwordval = (byteval1 & 0x7F) | ((byteval2 & 0x7F) << 7) | ((byteval3 & 0x7F) << 14) | ((byteval4 & 0x7F) << 21);
|
||||
|
||||
// Extraction of 14 color pixels
|
||||
rgba8Bits_t colors[14];
|
||||
int idxColor = 0;
|
||||
uint32_t dwordval_tmp = dwordval;
|
||||
dwordval_tmp = dwordval_tmp >> 7;
|
||||
bool offset = (byteval2 & 0x80) ? true : false;
|
||||
for (int i = 0; i < 14; i++)
|
||||
{
|
||||
if (i == 7) offset = (byteval3 & 0x80) ? true : false;
|
||||
idxColor = dwordval_tmp & 0x3;
|
||||
// Two cases because AppleWin's palette is in a strange order
|
||||
if (offset)
|
||||
colors[i] = Palette[1 + idxColor];
|
||||
else
|
||||
colors[i] = Palette[6 - idxColor];
|
||||
if (i % 2) dwordval_tmp >>= 2;
|
||||
}
|
||||
// Black and White
|
||||
rgba8Bits_t bw[2];
|
||||
bw[0] = Palette[0];
|
||||
bw[1] = Palette[1];
|
||||
|
||||
constexpr uint32_t mask = 0x01C0; // 00|000001 1|1000000
|
||||
constexpr uint32_t chck1 = 0x0140; // 00|000001 0|1000000
|
||||
constexpr uint32_t chck2 = 0x0080; // 00|000000 1|0000000
|
||||
|
||||
// HIRES render in RGB works on a pixel-basis (1-bit data in framebuffer)
|
||||
// The pixel can be 'color', if it makes a 101 or 010 pattern with the two neighbour bits
|
||||
// In all other cases, it's black if 0 and white if 1
|
||||
// The value of 'color' is defined on a 2-bits basis
|
||||
if (xoffset)
|
||||
{
|
||||
// Second byte of the 14 pixels block
|
||||
dwordval = dwordval >> 7;
|
||||
xoffset = 7;
|
||||
}
|
||||
|
||||
for (int i = xoffset; i < xoffset + 7; i++)
|
||||
{
|
||||
if (((dwordval & mask) == chck1) || ((dwordval & mask) == chck2))
|
||||
{
|
||||
// Color pixel
|
||||
*(pOut) = colors[i];
|
||||
*(pOut + 1) = *(pOut);
|
||||
pOut += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// B&W pixel
|
||||
*(pOut) = bw[(dwordval & chck2 ? 1 : 0)];
|
||||
*(pOut + 1) = *(pOut);
|
||||
pOut += 2;
|
||||
}
|
||||
// Next pixel
|
||||
dwordval = dwordval >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Display(uint8_t* blob)
|
||||
{
|
||||
|
||||
using Block = std::array<rgba8Bits_t, 14>;
|
||||
using Line = std::array<Block, 40>;
|
||||
using Screen = std::array<Line, 192 * 2>;
|
||||
|
||||
// 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 lineOffset : LineOffsets)
|
||||
{
|
||||
uint8_t* pHires = blob + lineBlockOffset + lineOffset; // interleaved HIRES source line
|
||||
for (std::size_t x = 0; x < itLine->size(); ++x)
|
||||
{
|
||||
auto& block = (*itLine)[x];
|
||||
UpdateHiResRGBCell(static_cast<int>(x), pHires++, block.data());
|
||||
}
|
||||
*(itLine + 1) = *itLine; // Doubling the destination lines
|
||||
itLine += 2; // Next dest line
|
||||
}
|
||||
}
|
||||
|
||||
// Display with SDL
|
||||
constexpr int scale = 1;
|
||||
// init
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
SdlError("cannot initialise the preview window.");
|
||||
}
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // nearest neighbor
|
||||
|
||||
// window
|
||||
SDL_Window* pWindow = SDL_CreateWindow("Preview", SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
560 * scale,
|
||||
384 * scale,
|
||||
SDL_WINDOW_SHOWN
|
||||
);
|
||||
if (pWindow == nullptr) {
|
||||
SdlError("cannot initialise the preview window.");
|
||||
}
|
||||
// renderer
|
||||
SDL_Renderer* pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (pRenderer == nullptr) {
|
||||
SdlError("cannot initialise the preview window.", pWindow);
|
||||
}
|
||||
// texture
|
||||
SDL_Texture* pTexture = SDL_CreateTexture(pRenderer, SDL_PIXELFORMAT_BGR888, SDL_TEXTUREACCESS_STATIC, 560, 384);
|
||||
if (pTexture == nullptr) {
|
||||
SdlError("cannot initialise the preview window.", pWindow, pRenderer);
|
||||
}
|
||||
// display
|
||||
SDL_UpdateTexture(pTexture, nullptr, pViewport->data(), sizeof(rgba8Bits_t) * 560);
|
||||
SDL_RenderClear(pRenderer);
|
||||
SDL_RenderCopy(pRenderer, pTexture, NULL, NULL);
|
||||
SDL_RenderPresent(pRenderer);
|
||||
// event loop
|
||||
while (true)
|
||||
{
|
||||
SDL_Event e;
|
||||
if (SDL_WaitEvent(&e))
|
||||
{
|
||||
if (e.type == SDL_QUIT) { break; }
|
||||
}
|
||||
}
|
||||
// free
|
||||
SDL_DestroyTexture(pTexture);
|
||||
SDL_DestroyRenderer(pRenderer);
|
||||
SDL_DestroyWindow(pWindow);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/* Rgb2Hires
|
||||
* Copyright (C) 2021 Christophe Meneboeuf <christophe@xtof.info>
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DISPLAY_H_
|
||||
#define _DISPLAY_H_
|
||||
|
||||
#include "ImageQuantized.h"
|
||||
#include "HiRes.h"
|
||||
|
||||
namespace RgbToHires
|
||||
{
|
||||
namespace Display
|
||||
{
|
||||
|
||||
void Display(uint8_t* blob);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -28,7 +28,18 @@
|
|||
#include "Common.h"
|
||||
|
||||
|
||||
namespace RgbToHires {
|
||||
namespace RgbToHires
|
||||
{
|
||||
|
||||
constexpr std::array<const uint16_t, 192 / 8> LineAdresses = {
|
||||
0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
|
||||
0x0028, 0x00a8, 0x0128, 0x01a8, 0x0228, 0x02a8, 0x0328, 0x03a8,
|
||||
0x0050, 0x00d0, 0x0150, 0x01d0, 0x0250, 0x02d0, 0x0350, 0x03d0
|
||||
};
|
||||
|
||||
constexpr std::array<const uint16_t, 8> LineOffsets = {
|
||||
0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800, 0x1c00
|
||||
};
|
||||
|
||||
using BlockPixel = std::array<Magick::PixelPacket, 7u>;
|
||||
|
||||
|
|
|
@ -6,16 +6,6 @@ using namespace std;
|
|||
namespace RgbToHires
|
||||
{
|
||||
|
||||
const std::array<const uint16_t, 192 / 8> Picture::_lineAdresses = {
|
||||
0x2000, 0x2080, 0x2100, 0x2180, 0x2200, 0x2280, 0x2300, 0x2380,
|
||||
0x2028, 0x20a8, 0x2128, 0x21a8, 0x2228, 0x22a8, 0x2328, 0x23a8,
|
||||
0x2050, 0x20d0, 0x2150, 0x21d0, 0x2250, 0x22d0, 0x2350, 0x23d0
|
||||
};
|
||||
|
||||
const std::array<const uint16_t, 8> Picture::_lineOffsets = {
|
||||
0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800, 0x1c00
|
||||
};
|
||||
|
||||
Picture::Picture(const ImageQuantized& source)
|
||||
{
|
||||
auto pixel_src = source.getConstPixels(0u, 0u, WIDTH, HEIGHT);
|
||||
|
@ -34,7 +24,7 @@ namespace RgbToHires
|
|||
//Constructing the map used to interleave the lines
|
||||
auto i = 0u;
|
||||
for (const auto& line : _blob) {
|
||||
auto addr_interleaved = _lineAdresses[i / 8] + _lineOffsets[i % 8];
|
||||
auto addr_interleaved = LineAdresses[i / 8] + LineOffsets[i % 8];
|
||||
_hrOrderedLines.insert(pair<const uint16_t, const LineHr*>(addr_interleaved, &line));
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -47,8 +47,6 @@ namespace RgbToHires
|
|||
using Blob = std::array<LineHr, NB_LINES_PER_SCREEN>;
|
||||
|
||||
Blob _blob; ///< A frame ordered buffer of hires data
|
||||
static const std::array<const uint16_t, 192 / 8> _lineAdresses;
|
||||
static const std::array<const uint16_t, 8> _lineOffsets;
|
||||
std::map<const uint16_t, const LineHr*> _hrOrderedLines; ///< map<adress,line's data>
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue