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:
parent
a43cf5cf8a
commit
e68748a158
5 changed files with 230 additions and 39 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue