285 lines
9.2 KiB
C++
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);
|
|
}
|
|
};
|