Adding the memory holes

This commit is contained in:
Christophe Meneboeuf 2016-12-02 00:32:53 +01:00
parent 6b68e7bc84
commit d7cd5f8cef
5 changed files with 121 additions and 24 deletions

5
.gitignore vendored
View File

@ -1,4 +1,9 @@
./x64
./x86
./RgbToHiRes.vcxproj.user
*.sln
*.bin
*.asm
**/.vs
**/Debug
**/Release

View File

@ -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>

View File

@ -9,6 +9,8 @@ using namespace std;
namespace RgbToHires {
/************************* CLASS BlockHr **********************/
BlockHr::BlockHr()
{
_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
for (auto i = 0u; i < 4u; ++i) {
if (block[i] == GREEN || block[i] == VIOLET) {
@ -86,25 +88,78 @@ namespace RgbToHires {
}
/************************* CLASS HiRes **********************/
HiRes::HiRes(const ImageQuantized& source)
{
auto pixel_src = source.getConstPixels(0u, 0u, WIDTH, HEIGHT);
//Filling the storage with BlockHrs
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;
for (auto& pxRgb : blockPxRgb) {
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;
}
}

View File

@ -3,6 +3,8 @@
#include <cstdint>
#include <array>
#include <vector>
#include <string>
#include "Common.h"
@ -18,14 +20,21 @@ namespace RgbToHires {
BlockHr();
/// \brief Construction from 7 pixels
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:
/// \brief color group as defined in Apple's documentation
enum eColorGroup {
GROUP_1,
GROUP_2
};
/// \brief Returns the color group of these two pixel blocks
/// Works on double blocks instead of single blocks
/// \brief Returns the color group of these two 3.5 pixel blocks
std::pair<eColorGroup, eColorGroup> getGroup(const BlockPixel&) const;
/// \brief Returns the bit pait corresponding to the given color
uint8_t getDibit(const Magick::Color&) const;
@ -33,18 +42,38 @@ namespace RgbToHires {
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
{
public:
static constexpr unsigned FRAME_SIZE = 192 * 40 + 512; ///< Frame size in byte
HiRes(const ImageQuantized&);
~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:
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>
};

View File

@ -1,6 +1,7 @@
#include <exception>
#include <iostream>
#include <fstream>
#include <string>
#include <Magick++.h>
@ -19,16 +20,25 @@ inline bool exists(const std::string& path)
return (stat(path.c_str(), &buffer) == 0);
}
/// \brief Program entry point
int main( int argc, char *argv[] )
{
Magick::InitializeMagick(*argv);
//Parsing command line
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(outputPath);
cmd.add(assembly);
cmd.parse(argc, argv);
if (imagePath.getValue().size() == 0 || outputPath.getValue().size() == 0) {
return -1;
}
try {
const auto filepath = imagePath.getValue();
if (!exists(filepath)) {
@ -36,7 +46,16 @@ int main( int argc, char *argv[] )
}
const auto imageRgb = Magick::Image{ filepath };
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