Files
bsb2/kernel/device/graphics.h
Niklas Gollenstede 174fe17e89 Handout
2025-10-31 22:37:36 +01:00

285 lines
9.2 KiB
C++

/*! \file
* \brief The \ref Graphics device is an interface for the \ref Framebuffer
*/
#pragma once
/*! \defgroup gfx Graphics
*
* Graphical VESA video modes.
*/
#include "../graphics/primitives.h"
#include "../graphics/printer.h"
/*! \brief Driver managing the video mode and synchronizing its buffer with the
* \ref AbstractGraphicsPrinter "graphics printer"
* \ingroup gfx
*
* This device detects the current video mode set by the \ref Multiboot
* compliant boot loader and initializes a suitable \ref GraphicsPrinter.
*
* With the methods \ref Graphics::switchBuffers() (to exchange front- and
* backbuffer) and \ref Graphics::scanoutFrontbuffer() (copying the contents of
* the frontbuffer into the video memory) it provides some kind of manually
* [triple
* buffering](https://en.wikipedia.org/wiki/Multiple_buffering#Triple_buffering).
*
* A typical usage is to fully prepare the back buffer before switching it with
* the front buffer
* \code{.cpp}
* graphics.init();
* while(true) {
* // Draw on back buffer
* // using the primitives provided by the driver
*
* graphics.switchBuffers();
* }
* \endcode
*
* The method \ref Graphics::scanoutFrontbuffer() has to be executed either
* inside the loop (right after \ref Graphics::switchBuffers() in the example
* above) or at a predefined interval by employing the \ref LAPIC::Timer.
*
* \note The driver requires \ref Multiboot to initialize a video mode, which
* can be configured using the flags in `boot/multiboot/config.inc`.
*/
class Graphics {
/*! \brief Pointer to a \ref GraphicsPrinter supporting the current video
* mode
*/
AbstractGraphicsPrinter* printer;
/*! \brief Pointer to the physical address of the video memory (linear frame
* buffer)
*/
void* address;
/*! \brief Video memory size required for a full screen picture
*/
unsigned size;
/*! \brief Size of the front (or back) buffer (which has to be at least \ref
* size)
*/
unsigned buffer_size;
/*! \brief Pointer to the two buffers
* (used alternately as front and back buffers)
*/
void* const buffer[2];
/*! \brief Index of the current front buffer
*/
int scanout_buffer;
/*! \brief Has the current front buffer already been drawn?
*/
bool refresh;
public:
/// MULTIBOOT_VIDEO_WIDTH * MULTIBOOT_VIDEO_HEIGHT *
/// MULTIBOOT_VIDEO_BITDEPTH (in bits)
static constexpr size_t SCREEN_BUF_SIZE =
1920UL * 1080UL * 32UL / sizeof(char);
/*! \brief Constructor
*/
Graphics();
/*! \brief Initialize \ref GraphicsPrinter according to the current video
* mode
*
* \param force Do not check video attributes for the linear frame buffer
* (required on our test systems due to some strange VBE
* behaviour)
* \return 'true' if a suitable \ref GraphicsPrinter was found for the video
* mode
*/
bool init(bool force = false);
/*! \brief Switch front and back buffer
* (only if front buffer was already copied to video memory)
*
* \return `true` if buffers have been switched, `false` if previous front
* buffer wasn't yet fully copied to video memory.
*/
bool switchBuffers();
/*! \brief Copy current front buffer to the video memory
*/
void scanoutFrontbuffer();
/*! \brief Clear all pixel of the current back buffer
* (set full screen to black)
*/
void clear() { printer->clear(); }
/*! \brief Check if a \ref Point can be displayed at the current resolution
*
* \param p Coordinates to check
* \return 'true' if can be displayed
*/
bool valid(const Point& p) { return printer->valid(p); }
/*! \brief Number of vertical pixels in current resolution
*
* \return Height of the screen in current video mode
*/
unsigned height() { return printer->height(); }
/*! \brief Number of horizontal pixels in current resolution
*
* \return Width of the screen in current video mode
*/
unsigned width() { return printer->width(); }
/*! \brief Draw a pixel on the current back buffer
*
* \param p Coordinates of the pixel
* \param color Color of the pixel
*/
void pixel(const Point& p, const Color& color) { printer->pixel(p, color); }
/// \copydoc pixel
void pixel(const Point& p, const ColorAlpha& color) {
printer->pixel(p, color);
}
/*! \brief Draw a line on the current back buffer
*
* \param start Coordinates of the begin of the line
* \param end Coordinates of the end of the line
* \param color Color of the line
*/
void line(const Point& start, const Point& end, const Color& color) {
printer->line(start, end, color);
}
/// \copydoc line
void line(const Point& start, const Point& end, const ColorAlpha& color) {
printer->line(start, end, color);
}
/*! \brief Draw a rectangle on the current back buffer
*
* \param start Coordinate of the rectangles upper left corner
* \param end Coordinate of the rectangles lower right corner
* \param color Color of the rectangle
* \param filled If set, the rectangle will be filled with the same color.
* (otherwise only borders will be drawn)
*/
void rectangle(const Point& start, const Point& end, const Color& color,
bool filled = true) {
printer->rectangle(start, end, color, filled);
}
/// \copydoc rectangle
void rectangle(const Point& start, const Point& end,
const ColorAlpha& color, bool filled = true) {
printer->rectangle(start, end, color, filled);
}
/*! \brief Change the current font for text output in video mode
*
* \param new_font Font to be used on subsequent calls to \ref text (without
* explicit font parameter)
*/
void font(const Font& new_font) { printer->font(new_font); }
/*! \brief Print text (without automatic word wrap) on the current back
* buffer
*
* \param p Upper left start position of the text
* \param string Pointer to char array containing the text to be displayed
* \param len Number of characters to be displayed
* \param color Color for the text characters
* \param font Explicit font -- or `nullptr` to use default font (set by
* \ref font method)
*/
void text(const Point& p, const char* string, unsigned len,
const Color& color, const Font* font = nullptr) {
printer->text(p, string, len, color, font);
}
/// \copydoc text
void text(const Point& p, const char* string, unsigned len,
const ColorAlpha& color, const Font* font = nullptr) {
printer->text(p, string, len, color, font);
}
/*! \brief Draw a \ref PNG image [detail] on the current back buffer.
*
* The image can has to be in a supported \ref PNG format.
* Alpha blending (transparency) is supported.
*
* \param p Coordinate of the images upper left corner
* \param image Source image to display
* \param width Width of the image detail (full image width of the source
* image if zero/default value)
* \param height Height of the image detail (full image height of the source
* if zero/default value)
* \param offset_x Right offset of the source image
* \param offset_y Top offset of the source image
*/
void image(const Point& p, PNG& image, unsigned width = 0,
unsigned height = 0, unsigned offset_x = 0,
unsigned offset_y = 0) {
printer->image(p, image, width, height, offset_x, offset_y);
}
/*! \brief Draw a GIMP image [detail] on the current back buffer.
*
* The image has to be exported as C-source (without `Glib` types!) in
* [GIMP](https://www.gimp.org/), alpha blending (transparency) is
* supported.
*
* \param p Coordinate of the images upper left corner
* \param image Source image to display
* \param width Width of the image detail (full image width of the source
* image if zero/default value)
* \param height Height of the image detail (full image height of the source
* if zero/default value)
* \param offset_x Right offset of the source image
* \param offset_y Top offset of the source image
*/
void image(const Point& p, const GIMP& image, unsigned width = 0,
unsigned height = 0, unsigned offset_x = 0,
unsigned offset_y = 0) {
printer->image(p, image, width, height, offset_x, offset_y);
}
/*! \brief Draw a sprite on the current back buffer.
*
* Each element in the source array will be displayed as a single pixel.
*
* \param p Coordinate of the sprites upper left corner
* \param image Source sprite to display
* \param width Width of the sprite detail
* \param height Height of the sprite detail
* \param offset_x Right offset of the source sprite
* \param offset_y Top offset of the source sprite
*/
void image(const Point& p, const Color* image, unsigned width,
unsigned height, unsigned offset_x = 0, unsigned offset_y = 0) {
printer->image(p, image, width, height, offset_x, offset_y);
}
/*! \brief Draw a sprite with alpha blending (transparency) on the current
* back buffer.
*
* Each element in the source array will be displayed as a single pixel.
*
* \param p Coordinate of the sprites upper left corner
* \param image Source sprite to display
* \param width Width of the sprite detail
* \param height Height of the sprite detail
* \param offset_x Right offset of the source sprite
* \param offset_y Top offset of the source sprite
*/
void image(const Point& p, const ColorAlpha* image, unsigned width,
unsigned height, unsigned offset_x = 0, unsigned offset_y = 0) {
printer->image(p, image, width, height, offset_x, offset_y);
}
};