Allow to control of high resolution graphics.

Horizontal resolution: x1 x2 x3 4 x5 x6 x7.
Vertical: x1 x2 x4.

Use Alt-arrows to change.


Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
This commit is contained in:
Andrea Odetti 2017-06-24 19:01:08 +01:00
parent a43cf5cf8a
commit e68748a158
5 changed files with 230 additions and 39 deletions

View file

@ -3,14 +3,14 @@
#include <cfloat>
#include <memory>
ASCIIArt::Unicode::Unicode(const char * aC, std::vector<int> aValues)
ASCIIArt::Unicode::Unicode(const char * aC, Blocks aValues)
: c(aC), values(aValues)
{
}
const int ASCIIArt::PPQ = 8 * (2 * 7) / 4;
ASCIIArt::ASCIIArt()
ASCIIArt::ASCIIArt() : myRows(0), myColumns(0)
{
myGlyphs.push_back(Unicode("\u2580", {PPQ, PPQ, 0, 0})); // top half
myGlyphs.push_back(Unicode("\u258C", {PPQ, 0, PPQ, 0})); // left half
@ -19,43 +19,145 @@ ASCIIArt::ASCIIArt()
myGlyphs.push_back(Unicode("\u2598", {PPQ, 0, 0, 0})); // top left
myGlyphs.push_back(Unicode("\u259A", {PPQ, 0, 0, PPQ})); // diagonal
myGlyphs.push_back(Unicode("\u259D", { 0, PPQ, 0, 0})); // top right
myBlocks.resize(128);
init(1, 1); // normal size
}
const ASCIIArt::Character & ASCIIArt::getCharacter(const unsigned char * address)
void ASCIIArt::init(const int rows, const int columns)
{
std::vector<int> values(4, 0);
if (myRows != rows || myColumns != columns)
{
if (myColumns != columns)
{
myColumns = columns;
for (size_t i = 0; i < myBlocks.size(); ++i)
{
myBlocks[i] = decodeByte(i);
}
}
myRows = rows;
myValues.resize(boost::extents[myRows][myColumns]);
myChars.resize(boost::extents[rows][columns]);
}
}
void ASCIIArt::changeColumns(const int x)
{
int newColumns = myColumns + x;
newColumns = std::max(1, std::min(7, newColumns));
init(myRows, newColumns);
}
void ASCIIArt::changeRows(const int x)
{
int newRows = x > 0 ? myRows * 2 : myRows / 2;
newRows = std::max(1, std::min(4, newRows));
init(newRows, myColumns);
}
const ASCIIArt::array_char_t & ASCIIArt::getCharacters(const unsigned char * address)
{
const array_val_t & values = getQuadrantValues(address);
return getCharacters(values);
}
const ASCIIArt::array_val_t & ASCIIArt::getQuadrantValues(const unsigned char * address) const
{
std::fill(myValues.origin(), myValues.origin() + myValues.num_elements(), 0);
const int linesPerRow = 8 / myRows;
const int linesPerQuadrant = linesPerRow / 2;
// 8 lines per text character
for (size_t i = 0; i < 8; ++i)
{
const int offset = 0x0400 * i;
const unsigned char value = *(address + offset);
// group color bit is ignored
const unsigned char value = (*(address + offset)) & 0x7f;
const int base = (i / 4) * 2;
const int row = i / linesPerRow;
const int lineInRow = i % linesPerRow;
const int quadrant = lineInRow / linesPerQuadrant;
const int base = quadrant * 2;
// 76543210
values[base] += __builtin_popcount(value & 0b00000111) * 2;
values[base + 1] += __builtin_popcount(value & 0b01110000) * 2;
const std::vector<Blocks> & decoded = myBlocks[value];
// allocate the middle pixels to each quadrant (with half the weight)
if (value & 0b00001000)
for (size_t col = 0; col < myColumns; ++col)
{
++values[base];
++values[base + 1];
Blocks & blocks = myValues[row][col];
blocks.add(base + 0, decoded[col][0] * myRows);
blocks.add(base + 1, decoded[col][1] * myRows);
}
}
return getCharacter(values);
return myValues;
}
const ASCIIArt::Character & ASCIIArt::getCharacter(const std::vector<int> & values)
std::vector<Blocks> ASCIIArt::decodeByte(const unsigned char value) const
{
int zip = 0;
for (const int v: values)
const int each = myColumns * 4 * PPQ / (8 * 7);
int available = 7;
int col = 0;
int pos = 0; // left right
std::vector<Blocks> decoded(myColumns);
for (size_t j = 0; j < 7; ++j)
{
zip = (zip << 4) + v;
int to_allocate = each;
do
{
const int here = std::min(available, to_allocate);
if (value & (1 << j))
{
decoded[col].add(pos, here);
}
to_allocate -= here;
available -= here;
if (available == 0)
{
// new quadrant
available = 7;
++pos;
if (pos == 2)
{
pos = 0;
++col;
}
}
}
while (to_allocate > 0);
}
return decoded;
}
const ASCIIArt::array_char_t & ASCIIArt::getCharacters(const array_val_t & values)
{
const int rows = values.shape()[0];
const int columns = values.shape()[1];
for (size_t i = 0; i < rows; ++i)
{
for (size_t j = 0; j < columns; ++j)
{
myChars[i][j] = getCharacter(values[i][j]);
}
}
return myChars;
}
const ASCIIArt::Character & ASCIIArt::getCharacter(const Blocks & values)
{
const int zip = values.value;
const std::unordered_map<int, Character>::const_iterator it = myAsciiPixels.find(zip);
if (it == myAsciiPixels.end())
{
@ -86,7 +188,7 @@ const ASCIIArt::Character & ASCIIArt::getCharacter(const std::vector<int> & valu
}
void ASCIIArt::fit(const std::vector<int> & art, const Unicode & glyph,
void ASCIIArt::fit(const Blocks & art, const Unicode & glyph,
double & foreground, double & background, double & error)
{
int num_fg = 0;

View file

@ -2,6 +2,49 @@
#include <unordered_map>
#include <vector>
#include <initializer_list>
#include <boost/multi_array.hpp>
struct Blocks
{
Blocks() : value(0) { }
Blocks(std::initializer_list<int> q)
{
value = 0;
for (auto it = rbegin(q); it != rend(q); ++it)
{
value <<= 5;
value += *it;
}
}
void add(int i, int val)
{
value += val << (i * 5);
}
int operator[](int i) const
{
const int val = (value >> (i * 5)) & 0b11111;
return val;
}
Blocks & operator=(const int val)
{
value = val;
return *this;
}
size_t size() const
{
return 4;
}
int value;
};
class ASCIIArt
{
@ -16,8 +59,18 @@ public:
double error;
};
const Character & getCharacter(const unsigned char * address);
const Character & getCharacter(const std::vector<int> & values);
typedef boost::multi_array<Character, 2> array_char_t;
typedef boost::multi_array<Blocks, 2> array_val_t;
void init(const int rows, const int columns);
void changeColumns(const int x);
void changeRows(const int x);
const array_char_t & getCharacters(const unsigned char * address);
const array_char_t & getCharacters(const array_val_t & values);
const array_val_t & getQuadrantValues(const unsigned char * address) const;
std::vector<Blocks> decodeByte(const unsigned char value) const;
private:
static const int PPQ; // Pixels per Quadrant
@ -26,15 +79,24 @@ private:
struct Unicode
{
Unicode(const char * aC, std::vector<int> aValues);
Unicode(const char * aC, Blocks aValues);
const char * c;
std::vector<int> values; // foreground: top left - top right - bottom left - bottom right
Blocks values; // foreground: top left - top right - bottom left - bottom right
};
int myRows;
int myColumns;
std::vector<Unicode> myGlyphs;
static void fit(const std::vector<int> & art, const Unicode & glyph,
std::vector<std::vector<Blocks>> myBlocks;
mutable array_val_t myValues; // workspace
array_char_t myChars; // workspace
const Character & getCharacter(const Blocks & values);
static void fit(const Blocks & art, const Unicode & glyph,
double & foreground, double & background, double & error);
};

View file

@ -1,8 +1,8 @@
#include "frontends/ncurses/nframe.h"
Frame::Frame() : myColumns(-1)
Frame::Frame() : myColumns(-1), myRows(-1)
{
init(40);
init(24, 40);
const int rows = 28;
const int cols = 30;
@ -19,11 +19,11 @@ Frame::Frame() : myColumns(-1)
wrefresh(myBorders.get());
}
void Frame::init(int columns)
void Frame::init(int rows, int columns)
{
if (myColumns != columns)
if (myRows != rows || myColumns != columns)
{
if (columns < myColumns)
if (columns < myColumns || rows < myRows)
{
werase(myStatus.get());
wrefresh(myStatus.get());
@ -31,18 +31,19 @@ void Frame::init(int columns)
wrefresh(myFrame.get());
}
myRows = rows;
myColumns = columns;
const int width = 1 + myColumns + 1;
const int left = (COLS - width) / 2;
myFrame.reset(newwin(1 + 24 + 1, width, 0, left), delwin);
myFrame.reset(newwin(1 + myRows + 1, width, 0, left), delwin);
box(myFrame.get(), 0 , 0);
wtimeout(myFrame.get(), 0);
keypad(myFrame.get(), true);
wrefresh(myFrame.get());
myStatus.reset(newwin(4, width, 1 + 24 + 1, left), delwin);
myStatus.reset(newwin(4, width, 1 + myRows + 1, left), delwin);
box(myStatus.get(), 0 , 0);
wrefresh(myStatus.get());
}

View file

@ -13,11 +13,12 @@ class Frame
WINDOW * getBuffer();
WINDOW * getStatus();
void init(int columns);
void init(int rows, int columns);
int getColumns() const;
private:
int myRows;
int myColumns;
std::shared_ptr<WINDOW> myFrame;

View file

@ -165,7 +165,8 @@ void output(const char *fmt, ...)
bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset)
{
frame->init(40);
frame->init(24, 40);
asciiArt->init(1, 1);
BYTE ch = *(g_pTextBank0+offset);
@ -179,7 +180,8 @@ bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset)
bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset)
{
frame->init(80);
frame->init(24, 80);
asciiArt->init(1, 2);
BYTE ch1 = *(g_pTextBank1+offset);
BYTE ch2 = *(g_pTextBank0+offset);
@ -226,14 +228,25 @@ bool UpdateHiResCell (int x, int y, int xpixel, int ypixel, int offset)
{
const BYTE * base = g_pHiresBank0 + offset;
const ASCIIArt::array_char_t & chs = asciiArt->getCharacters(base);
const auto shape = chs.shape();
const size_t rows = shape[0];
const size_t cols = shape[1];
frame->init(24 * rows, 40 * cols);
WINDOW * win = frame->getWindow();
const ASCIIArt::Character & ch = asciiArt->getCharacter(base);
for (size_t i = 0; i < rows; ++i)
{
for (size_t j = 0; j < cols; ++j)
{
const int pair = colors->getGrey(chs[i][j].foreground, chs[i][j].background);
const int pair = colors->getGrey(ch.foreground, ch.background);
wcolor_set(win, pair, NULL);
mvwaddstr(win, 1 + y, 1 + x, ch.c);
wcolor_set(win, pair, NULL);
mvwaddstr(win, 1 + rows * y + i, 1 + cols * x + j, chs[i][j].c);
}
}
wcolor_set(win, 0, NULL);
return true;
@ -461,6 +474,18 @@ int ProcessKeyboard()
case 0x14a: // DEL
ch = 0x7f;
break;
case 0x221: // ALT - LEFT
asciiArt->changeColumns(-1);
break;
case 0x230: // ALT - RIGHT
asciiArt->changeColumns(+1);
break;
case 0x236:
asciiArt->changeRows(-1);
break;
case 0x20D:
asciiArt->changeRows(+1);
break;
default:
if (inch < 0x80)
{