mirror of
https://github.com/Pixinn/Rgb2Hires.git
synced 2024-06-02 07:41:33 +00:00
Adding the memory holes
This commit is contained in:
parent
6b68e7bc84
commit
d7cd5f8cef
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,4 +1,9 @@
|
||||||
./x64
|
./x64
|
||||||
./x86
|
./x86
|
||||||
|
./RgbToHiRes.vcxproj.user
|
||||||
|
*.sln
|
||||||
|
*.bin
|
||||||
|
*.asm
|
||||||
|
**/.vs
|
||||||
**/Debug
|
**/Debug
|
||||||
**/Release
|
**/Release
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<LocalDebuggerCommandArguments>-i D:\Chris.ARES\Dropbox\_Partages\_Macbook\Green.png</LocalDebuggerCommandArguments>
|
|
||||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<LocalDebuggerCommandArguments>-i D:\Chris.ARES\Dropbox\_Partages\_Macbook\Green.png</LocalDebuggerCommandArguments>
|
|
||||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
|
@ -9,6 +9,8 @@ using namespace std;
|
||||||
namespace RgbToHires {
|
namespace RgbToHires {
|
||||||
|
|
||||||
|
|
||||||
|
/************************* CLASS BlockHr **********************/
|
||||||
|
|
||||||
BlockHr::BlockHr()
|
BlockHr::BlockHr()
|
||||||
{
|
{
|
||||||
_data[0] = 0;
|
_data[0] = 0;
|
||||||
|
@ -37,9 +39,9 @@ namespace RgbToHires {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::pair<BlockHr::eColorGroup, BlockHr::eColorGroup> BlockHr::getGroup(const BlockPixel& block) const
|
pair<BlockHr::eColorGroup, BlockHr::eColorGroup> BlockHr::getGroup(const BlockPixel& block) const
|
||||||
{
|
{
|
||||||
std::pair<eColorGroup, eColorGroup> groups{ GROUP_1, GROUP_1 };
|
pair<eColorGroup, eColorGroup> groups{ GROUP_1, GROUP_1 };
|
||||||
//1st block group, including the last semi-pixel
|
//1st block group, including the last semi-pixel
|
||||||
for (auto i = 0u; i < 4u; ++i) {
|
for (auto i = 0u; i < 4u; ++i) {
|
||||||
if (block[i] == GREEN || block[i] == VIOLET) {
|
if (block[i] == GREEN || block[i] == VIOLET) {
|
||||||
|
@ -86,25 +88,78 @@ namespace RgbToHires {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************* CLASS HiRes **********************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HiRes::HiRes(const ImageQuantized& source)
|
HiRes::HiRes(const ImageQuantized& source)
|
||||||
{
|
{
|
||||||
auto pixel_src = source.getConstPixels(0u, 0u, WIDTH, HEIGHT);
|
auto pixel_src = source.getConstPixels(0u, 0u, WIDTH, HEIGHT);
|
||||||
|
//Filling the storage with BlockHrs
|
||||||
for (auto& line : _blob) {
|
for (auto& line : _blob) {
|
||||||
for (auto& block : line) {
|
line.reserve(NB_BLOCK_PER_LINES);
|
||||||
|
//Useful data
|
||||||
|
for (auto blockNr = 0u; blockNr < NB_BLOCK_PER_LINES; ++blockNr ) {
|
||||||
BlockPixel blockPxRgb;
|
BlockPixel blockPxRgb;
|
||||||
for (auto& pxRgb : blockPxRgb) {
|
for (auto& pxRgb : blockPxRgb) {
|
||||||
pxRgb = *pixel_src++;
|
pxRgb = *pixel_src++;
|
||||||
}
|
}
|
||||||
block = BlockHr{ blockPxRgb };
|
line.emplace_back(BlockHr{ blockPxRgb });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//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];
|
||||||
|
_hrOrderedLines.insert(pair<const uint16_t, const LineHr*>(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<LineHr*>(line.second)->emplace_back(BlockHr{});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unique_ptr<array<uint8_t, HiRes::FRAME_SIZE>> HiRes::getBlob() const
|
||||||
|
{
|
||||||
|
auto blob = unique_ptr<array<uint8_t, FRAME_SIZE>>{ new array<uint8_t, FRAME_SIZE>};
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string HiRes::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
39
src/HiRes.h
39
src/HiRes.h
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
@ -18,14 +20,21 @@ namespace RgbToHires {
|
||||||
BlockHr();
|
BlockHr();
|
||||||
/// \brief Construction from 7 pixels
|
/// \brief Construction from 7 pixels
|
||||||
BlockHr(const BlockPixel& );
|
BlockHr(const BlockPixel& );
|
||||||
|
/// \brief returns the position of the first element
|
||||||
|
inline std::array<uint8_t, 2>::const_iterator begin() const {
|
||||||
|
return _data.begin();
|
||||||
|
}
|
||||||
|
/// \brief returns the position after the last element
|
||||||
|
inline std::array<uint8_t, 2>::const_iterator end() const {
|
||||||
|
return _data.end();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
/// \brief color group as defined in Apple's documentation
|
/// \brief color group as defined in Apple's documentation
|
||||||
enum eColorGroup {
|
enum eColorGroup {
|
||||||
GROUP_1,
|
GROUP_1,
|
||||||
GROUP_2
|
GROUP_2
|
||||||
};
|
};
|
||||||
/// \brief Returns the color group of these two pixel blocks
|
/// \brief Returns the color group of these two 3.5 pixel blocks
|
||||||
/// Works on double blocks instead of single blocks
|
|
||||||
std::pair<eColorGroup, eColorGroup> getGroup(const BlockPixel&) const;
|
std::pair<eColorGroup, eColorGroup> getGroup(const BlockPixel&) const;
|
||||||
/// \brief Returns the bit pait corresponding to the given color
|
/// \brief Returns the bit pait corresponding to the given color
|
||||||
uint8_t getDibit(const Magick::Color&) const;
|
uint8_t getDibit(const Magick::Color&) const;
|
||||||
|
@ -33,18 +42,38 @@ namespace RgbToHires {
|
||||||
std::array<uint8_t, 2> _data;
|
std::array<uint8_t, 2> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
using LineHr = std::array<BlockHr, 10>;
|
|
||||||
using Blob = std::array<LineHr, 192>;
|
static constexpr unsigned NB_BLOCK_PER_LINES = 20u;
|
||||||
|
static constexpr unsigned NB_LINES_PER_SCREEN = 192u;
|
||||||
|
using LineHr = std::vector<BlockHr>;
|
||||||
|
using Blob = std::array<LineHr, NB_LINES_PER_SCREEN>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class HiRes
|
class HiRes
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr unsigned FRAME_SIZE = 192 * 40 + 512; ///< Frame size in byte
|
||||||
|
|
||||||
HiRes(const ImageQuantized&);
|
HiRes(const ImageQuantized&);
|
||||||
~HiRes() = default;
|
~HiRes() = default;
|
||||||
|
|
||||||
|
/// \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;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Blob _blob; ///< A frame ordered buffer of hires data
|
Blob _blob; ///< A frame ordered buffer of hires data
|
||||||
|
static constexpr std::array<const uint16_t, 192 / 8> _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
|
||||||
|
};
|
||||||
|
static constexpr std::array<const uint16_t, 8> _lineOffsets = {
|
||||||
|
0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800, 0x1c00
|
||||||
|
};
|
||||||
|
std::map<const uint16_t, const LineHr*> _hrOrderedLines; ///< map<adress,line's data>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
23
src/Main.cpp
23
src/Main.cpp
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <Magick++.h>
|
#include <Magick++.h>
|
||||||
|
@ -19,16 +20,25 @@ inline bool exists(const std::string& path)
|
||||||
return (stat(path.c_str(), &buffer) == 0);
|
return (stat(path.c_str(), &buffer) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Program entry point
|
||||||
int main( int argc, char *argv[] )
|
int main( int argc, char *argv[] )
|
||||||
{
|
{
|
||||||
Magick::InitializeMagick(*argv);
|
Magick::InitializeMagick(*argv);
|
||||||
|
|
||||||
//Parsing command line
|
//Parsing command line
|
||||||
TCLAP::CmdLine cmd("rgbtohires", ' ', "0");
|
TCLAP::CmdLine cmd("rgbtohires", ' ', "0");
|
||||||
TCLAP::ValueArg<string> imagePath("i", "image", "Image path", true, "", "path_to_image");
|
TCLAP::ValueArg<string> imagePath("i", "image", "Source image path", true, "", "path_to_image");
|
||||||
|
TCLAP::ValueArg<string> outputPath("o", "output", "Output path", true, "", "path_to_output");
|
||||||
|
TCLAP::SwitchArg assembly("a", "asm", "Output asm format");
|
||||||
cmd.add(imagePath);
|
cmd.add(imagePath);
|
||||||
|
cmd.add(outputPath);
|
||||||
|
cmd.add(assembly);
|
||||||
cmd.parse(argc, argv);
|
cmd.parse(argc, argv);
|
||||||
|
|
||||||
|
if (imagePath.getValue().size() == 0 || outputPath.getValue().size() == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto filepath = imagePath.getValue();
|
const auto filepath = imagePath.getValue();
|
||||||
if (!exists(filepath)) {
|
if (!exists(filepath)) {
|
||||||
|
@ -36,7 +46,16 @@ int main( int argc, char *argv[] )
|
||||||
}
|
}
|
||||||
const auto imageRgb = Magick::Image{ filepath };
|
const auto imageRgb = Magick::Image{ filepath };
|
||||||
auto imageQuantized = ImageQuantized{ imageRgb };
|
auto imageQuantized = ImageQuantized{ imageRgb };
|
||||||
const auto imageHiRes = HiRes{ imageQuantized };
|
const auto imageHiRes = HiRes{ 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<const char*>(bytes.get()), bytes->size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fatal error
|
//Fatal error
|
||||||
|
|
Loading…
Reference in New Issue
Block a user