Step 2
This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
message(STATUS " Configuring Graphics")
|
||||
message(STATUS "··Configuring Graphics")
|
||||
|
||||
add_library(Graphics
|
||||
add_library(DisplayGraphics
|
||||
Framebuffer.cpp
|
||||
Renderer.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(Graphics
|
||||
PRIVATE Model Helpers UI
|
||||
add_library(Display::Graphics ALIAS DisplayGraphics)
|
||||
|
||||
target_link_libraries(DisplayGraphics
|
||||
PRIVATE
|
||||
Model::All
|
||||
Helpers::All
|
||||
Display::UI::Text
|
||||
Display::UI::HostBlock
|
||||
)
|
||||
|
||||
target_include_directories(Graphics
|
||||
target_include_directories(DisplayGraphics
|
||||
PUBLIC
|
||||
${INCLUDE_BASE_DIR}
|
||||
)
|
||||
|
||||
@@ -9,95 +9,129 @@
|
||||
|
||||
namespace Display::Graphics
|
||||
{
|
||||
Framebuffer::Framebuffer(const char *device)
|
||||
Framebuffer::Framebuffer(const char *device, FramebufferRotation rotation) : rotation(rotation)
|
||||
{
|
||||
fd_ = open(device, O_RDWR);
|
||||
if (fd_ < 0)
|
||||
throw std::runtime_error("Cannot open framebuffer");
|
||||
fd = open(device, O_RDWR);
|
||||
if (fd < 0)
|
||||
throw std::runtime_error("Failed to open framebuffer");
|
||||
|
||||
fb_var_screeninfo vinfo;
|
||||
fb_fix_screeninfo finfo;
|
||||
fb_var_screeninfo vinfo{};
|
||||
fb_fix_screeninfo finfo{};
|
||||
ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
|
||||
ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
|
||||
physical.width = vinfo.xres;
|
||||
physical.height = vinfo.yres;
|
||||
line_length = finfo.line_length;
|
||||
size = finfo.smem_len;
|
||||
|
||||
ioctl(fd_, FBIOGET_VSCREENINFO, &vinfo);
|
||||
ioctl(fd_, FBIOGET_FSCREENINFO, &finfo);
|
||||
if (rotation == FramebufferRotation::R90 || rotation == FramebufferRotation::R270)
|
||||
{
|
||||
logical.width = physical.height;
|
||||
logical.height = physical.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
logical.width = physical.width;
|
||||
logical.height = physical.height;
|
||||
}
|
||||
|
||||
width_ = vinfo.xres;
|
||||
height_ = vinfo.yres;
|
||||
line_len_ = finfo.line_length;
|
||||
size_ = finfo.smem_len;
|
||||
buffer.resize(physical.width * physical.height, 0);
|
||||
|
||||
fb_ = static_cast<uint8_t *>(mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0));
|
||||
if (fb_ == MAP_FAILED)
|
||||
throw std::runtime_error("mmap failed");
|
||||
fb = static_cast<uint8_t *>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
if (fb == MAP_FAILED)
|
||||
throw std::runtime_error("Failed to mmap framebuffer");
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer()
|
||||
{
|
||||
munmap(fb_, size_);
|
||||
close(fd_);
|
||||
munmap(fb, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void Framebuffer::clear(uint16_t color)
|
||||
{
|
||||
for (int y = 0; y < height_; ++y)
|
||||
for (int y = 0; y < logical.height; ++y)
|
||||
{
|
||||
uint16_t *row = reinterpret_cast<uint16_t *>(fb_ + y * line_len_);
|
||||
for (int x = 0; x < width_; ++x)
|
||||
uint16_t *row = reinterpret_cast<uint16_t *>(fb + y * line_length);
|
||||
for (int x = 0; x < logical.width; ++x)
|
||||
row[x] = color;
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::fillRect(int x, int y, int w, int h, uint16_t color)
|
||||
void Framebuffer::present()
|
||||
{
|
||||
for (int j = 0; j < h; ++j)
|
||||
for (int y = 0; y < logical.height; ++y)
|
||||
{
|
||||
int py = y + j;
|
||||
if (py < 0 || py >= height_)
|
||||
continue;
|
||||
|
||||
uint16_t *row = reinterpret_cast<uint16_t *>(fb_ + py * line_len_);
|
||||
for (int i = 0; i < w; ++i)
|
||||
for (int x = 0; x < logical.width; ++x)
|
||||
{
|
||||
int px = x + i;
|
||||
if (px < 0 || px >= width_)
|
||||
continue;
|
||||
int fx = 0;
|
||||
int fy = 0;
|
||||
|
||||
row[px] = color;
|
||||
switch (rotation)
|
||||
{
|
||||
case FramebufferRotation::R0:
|
||||
fx = x;
|
||||
fy = y;
|
||||
break;
|
||||
|
||||
case FramebufferRotation::R90:
|
||||
fx = physical.width - 1 - y;
|
||||
fy = x;
|
||||
break;
|
||||
|
||||
case FramebufferRotation::R180:
|
||||
fx = physical.width - 1 - x;
|
||||
fy = physical.height - 1 - y;
|
||||
break;
|
||||
|
||||
case FramebufferRotation::R270:
|
||||
fx = y;
|
||||
fy = physical.height - 1 - x;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t *row =
|
||||
reinterpret_cast<uint16_t *>(fb + fy * line_length);
|
||||
row[fx] = buffer[y * logical.width + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::drawRect(int x, int y, int w, int h, const Color &c)
|
||||
void Framebuffer::fillRect(int x, int y, int w, int h, const Color &color)
|
||||
{
|
||||
// верх
|
||||
fillRect(x, y, w, 1, c);
|
||||
// низ
|
||||
fillRect(x, y + h - 1, w, 1, c);
|
||||
// лево
|
||||
fillRect(x, y, 1, h, c);
|
||||
// право
|
||||
fillRect(x + w - 1, y, 1, h, c);
|
||||
for (int j = 0; j < h; ++j)
|
||||
for (int i = 0; i < w; ++i)
|
||||
setPixel(x + i, y + j, color);
|
||||
}
|
||||
|
||||
void Framebuffer::setPixel(int x, int y, const Color &c)
|
||||
void Framebuffer::drawRect(int x, int y, int w, int h, const Color &color)
|
||||
{
|
||||
if (x < 0 || x >= width_ || y < 0 || y >= height_)
|
||||
return;
|
||||
// верх
|
||||
fillRect(x, y, w, 1, color);
|
||||
// низ
|
||||
fillRect(x, y + h - 1, w, 1, color);
|
||||
// лево
|
||||
fillRect(x, y, 1, h, color);
|
||||
// право
|
||||
fillRect(x + w - 1, y, 1, h, color);
|
||||
}
|
||||
|
||||
uint16_t *p = reinterpret_cast<uint16_t *>(fb_ + y * line_len_) + x;
|
||||
*p = ((c.r & 0xF8) << 8) | ((c.g & 0xFC) << 3) | (c.b >> 3);
|
||||
void Framebuffer::setPixel(int x, int y, const Color &color)
|
||||
{
|
||||
if (x < 0 || x >= logical.width || y < 0 || y >= logical.height)
|
||||
return;
|
||||
buffer[y * logical.width + x] = rgb565(color);
|
||||
}
|
||||
|
||||
Color Framebuffer::getPixel(int x, int y) const
|
||||
{
|
||||
if (x < 0 || x >= width_ || y < 0 || y >= height_)
|
||||
if (x < 0 || x >= logical.width || y < 0 || y >= logical.height)
|
||||
return {0, 0, 0, 255};
|
||||
|
||||
uint16_t p = *(reinterpret_cast<uint16_t *>(fb_ + y * line_len_) + x);
|
||||
uint16_t p = buffer[y * logical.width + x];
|
||||
Color c;
|
||||
c.r = (p >> 8) & 0xF8;
|
||||
c.g = (p >> 3) & 0xFC;
|
||||
c.b = (p << 3) & 0xF8;
|
||||
c.r = ((p >> 11) & 0x1F) << 3;
|
||||
c.g = ((p >> 5) & 0x3F) << 2;
|
||||
c.b = (p & 0x1F) << 3;
|
||||
c.a = 255;
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,43 @@
|
||||
#pragma once
|
||||
#include "Display/Graphics/Color.h"
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include "Display/Graphics/Color.h"
|
||||
#include "Display/Graphics/FramebufferRotation.h"
|
||||
|
||||
namespace Display::Graphics
|
||||
{
|
||||
class Framebuffer
|
||||
{
|
||||
public:
|
||||
Framebuffer(const char *device);
|
||||
Framebuffer(const char *device, FramebufferRotation rotation);
|
||||
~Framebuffer();
|
||||
|
||||
void clear(uint16_t color);
|
||||
void fillRect(int x, int y, int w, int h, uint16_t color);
|
||||
void drawRect(int x, int y, int w, int h, const Color &c);
|
||||
void setPixel(int x, int y, const Color &c);
|
||||
void present();
|
||||
void fillRect(int x, int y, int w, int h, const Color &color);
|
||||
void drawRect(int x, int y, int w, int h, const Color &color);
|
||||
void setPixel(int x, int y, const Color &color);
|
||||
Color getPixel(int x, int y) const;
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
int getWidth() const { return logical.width; }
|
||||
int getHeight() const { return logical.height; }
|
||||
FramebufferRotation getRotation() const { return rotation; }
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
uint8_t *fb_;
|
||||
size_t size_;
|
||||
int width_;
|
||||
int height_;
|
||||
int line_len_;
|
||||
struct Dimensions
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
FramebufferRotation rotation = FramebufferRotation::R0;
|
||||
std::vector<uint16_t> buffer;
|
||||
|
||||
Dimensions physical;
|
||||
Dimensions logical;
|
||||
int fd;
|
||||
uint8_t *fb;
|
||||
size_t size;
|
||||
int line_length;
|
||||
};
|
||||
} // namespace Display::Graphics
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace Display::Graphics
|
||||
{
|
||||
enum class FramebufferRotation
|
||||
{
|
||||
R0,
|
||||
R90,
|
||||
R180,
|
||||
R270
|
||||
};
|
||||
} // namespace Display::Graphics
|
||||
@@ -4,38 +4,40 @@ namespace Display::Graphics
|
||||
{
|
||||
Renderer::Renderer(Framebuffer &framebuffer, Model::HostRegistry ®istry)
|
||||
: framebuffer(framebuffer),
|
||||
registry(registry),
|
||||
barMem(200, 10)
|
||||
registry(registry)
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::render()
|
||||
{
|
||||
// очистка экрана
|
||||
framebuffer.clear(Color{0, 0, 0});
|
||||
|
||||
int y = 10; // начальная вертикальная позиция
|
||||
int lineHeight = 24; // высота строки (подбираем под шрифт)
|
||||
int blocksPerRow =
|
||||
(SCREEN_WIDTH + BLOCK_GAP) / (Display::UI::HostBlock::BLOCK_WIDTH + BLOCK_GAP);
|
||||
if (blocksPerRow < 1)
|
||||
blocksPerRow = 1;
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (auto &[host, m] : registry.snapshot())
|
||||
{
|
||||
// рисуем фон строки
|
||||
framebuffer.fillRect(10, y - 18, 300, lineHeight, Color{0, 64, 0});
|
||||
int col = index % blocksPerRow;
|
||||
int row = index / blocksPerRow;
|
||||
|
||||
// формируем строку
|
||||
std::string line = host + " " + std::to_string(int(m.cpu.loads.at(0))) +
|
||||
"% " + std::to_string(int(m.memory.used / 1024 / 1024)) +
|
||||
"/" + std::to_string(int(m.memory.total / 1024 / 1024)) +
|
||||
" " + std::to_string(int(m.disks.at(0).used / 1024 / 1024)) +
|
||||
"/" + std::to_string(int(m.disks.at(0).total / 1024 / 1024));
|
||||
int x = START_X + col * (Display::UI::HostBlock::BLOCK_WIDTH + BLOCK_GAP);
|
||||
int y = START_Y + row * (Display::UI::HostBlock::BLOCK_HEIGHT + BLOCK_GAP);
|
||||
|
||||
// выводим текст на экран
|
||||
textRenderer.drawText(framebuffer, 12, y, line, Color{255, 255, 255});
|
||||
hostblock.draw(
|
||||
framebuffer,
|
||||
textRenderer,
|
||||
x,
|
||||
y,
|
||||
host,
|
||||
m);
|
||||
|
||||
float mem = (float)m.memory.used / (float)m.memory.total;
|
||||
barMem.draw(framebuffer, 10, y + 35, mem);
|
||||
|
||||
y += lineHeight; // переход на следующую строку
|
||||
++index;
|
||||
}
|
||||
|
||||
framebuffer.present();
|
||||
}
|
||||
} // namespace Display::Graphics
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
#include "Display/Graphics/Framebuffer.h"
|
||||
#include "Model/HostRegistry.h"
|
||||
#include "Display/UI/Text/Renderer.h"
|
||||
#include "Display/UI/Bar/Bar.h"
|
||||
#include "Display/UI/HostBlock/HostBlock.h"
|
||||
#include "Display/Graphics/Color.h"
|
||||
#include <string>
|
||||
|
||||
namespace Display::Graphics
|
||||
{
|
||||
static constexpr int START_X = 0;
|
||||
static constexpr int START_Y = 10;
|
||||
static constexpr int BLOCK_GAP = 4;
|
||||
|
||||
static constexpr int SCREEN_WIDTH = 240;
|
||||
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
@@ -22,6 +28,6 @@ namespace Display::Graphics
|
||||
Framebuffer &framebuffer;
|
||||
Model::HostRegistry ®istry;
|
||||
Display::UI::Text::Renderer textRenderer;
|
||||
Display::UI::Bar::Bar barMem;
|
||||
Display::UI::HostBlock::HostBlock hostblock;
|
||||
};
|
||||
} // namespace Display::Graphics
|
||||
|
||||
Reference in New Issue
Block a user