forked from scottyallen/flaschen-taschen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
terminal-flaschen-taschen.cc
84 lines (74 loc) · 3.33 KB
/
terminal-flaschen-taschen.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; -*-
//
// 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 version 2.
//
// 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://gnu.org/licenses/gpl-2.0.txt>
#include "led-flaschen-taschen.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define SCREEN_CLEAR "\033c"
#define SCREEN_PREFIX "\033[48;2;0;0;0m" // set black background
#define SCREEN_POSTFIX "\033[0m\n" // reset terminal settings
#define SCREEN_CURSOR_UP_FORMAT "\033[%dA" // Move cursor up given lines.
#define CURSOR_OFF "\033[?25l"
#define CURSOR_ON "\033[?25h"
// Idea is that we have all colors same width for fast in-place updates.
// so each pixel needs to be fixed width. Thus we do %03 (which luckily is
// not interpreted as octal by the terminal)
// Setting this Unicode character seems to confuse at least konsole. Also,
// it is pretty dark.
//#define PIXEL_FORMAT "\033[38;2;%03d;%03d;%03dm●" // Sent per pixel.
// This is a little dark.
//#define PIXEL_FORMAT "\033[38;2;%03d;%03d;%03dm*" // Sent per pixel.
// So, let's just send two spaces. First space here, rest separate below.
#define PIXEL_FORMAT "\033[48;2;%03d;%03d;%03dm " // Sent per pixel.
TerminalFlaschenTaschen::TerminalFlaschenTaschen(int fd, int width, int height)
: terminal_fd_(fd), width_(width), height_(height), is_first_(true) {
buffer_.append(SCREEN_PREFIX);
initial_offset_ = buffer_.size();
char scratch[64];
snprintf(scratch, sizeof(scratch), PIXEL_FORMAT, 0, 0, 0); // black.
pixel_offset_ = strlen(scratch) + 1; // one extra space.
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
buffer_.append(scratch);
buffer_.append(" "); // Need to add space here.
}
buffer_.append("\n");
}
buffer_.append(SCREEN_POSTFIX);
snprintf(scratch, sizeof(scratch), SCREEN_CURSOR_UP_FORMAT, height + 1);
buffer_.append(scratch);
}
TerminalFlaschenTaschen::~TerminalFlaschenTaschen() {
if (!is_first_) {
write(terminal_fd_, SCREEN_CLEAR, strlen(SCREEN_CLEAR));
write(terminal_fd_, CURSOR_ON, strlen(CURSOR_ON));
}
}
void TerminalFlaschenTaschen::SetPixel(int x, int y, const Color &col) {
if (x < 0 || x >= width_ || y < 0 || y >= height_) return;
const int pos = initial_offset_
+ (width_ * y + x) * pixel_offset_
+ y; // <- one newline per y
char *buf = const_cast<char*>(buffer_.data()) + pos; // Living on the edge
snprintf(buf, pixel_offset_, PIXEL_FORMAT, col.r, col.g, col.b);
buf[pixel_offset_-1] = ' '; // overwrite \0-byte with space again.
}
void TerminalFlaschenTaschen::Send() {
if (is_first_) {
write(terminal_fd_, SCREEN_CLEAR, strlen(SCREEN_CLEAR));
write(terminal_fd_, CURSOR_OFF, strlen(CURSOR_OFF));
is_first_ = false;
}
write(terminal_fd_, buffer_.data(), buffer_.size());
}