Handout
This commit is contained in:
317
kernel/graphics/framebuffer.h
Normal file
317
kernel/graphics/framebuffer.h
Normal file
@@ -0,0 +1,317 @@
|
||||
/*! \file
|
||||
* \brief \ref Framebuffer implementing primitive graphic operations
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../types.h"
|
||||
#include "../utils/string.h"
|
||||
#include "primitives.h"
|
||||
|
||||
/*! \brief Implementation of primitive operations on a memory area used as
|
||||
* framebuffer.
|
||||
* \ingroup gfx
|
||||
*
|
||||
* The implementation as template class allows the compiler to heavily optimize
|
||||
* the bit operations depending on the video mode.
|
||||
*
|
||||
* \tparam COLORDEPTH color depth of video mode
|
||||
* \tparam OFFSET_RED Bit position of red color mask in video mode
|
||||
* \tparam OFFSET_GREEN Bit position of green color mask in video mode
|
||||
* \tparam OFFSET_BLUE Bit position of blue color mask in video mode
|
||||
* \tparam BITS_RED Size of red color mask in video mode
|
||||
* \tparam BITS_GREEN Size of green color mask in video mode
|
||||
* \tparam BITS_BLUE Size of blue color mask in video mode
|
||||
*/
|
||||
template <unsigned char COLORDEPTH, unsigned char OFFSET_RED,
|
||||
unsigned char OFFSET_GREEN, unsigned char OFFSET_BLUE,
|
||||
unsigned char BITS_RED, unsigned char BITS_GREEN,
|
||||
unsigned char BITS_BLUE>
|
||||
class Framebuffer {
|
||||
/*! \brief Start address of the linear framebuffer
|
||||
*/
|
||||
uintptr_t framebuffer;
|
||||
|
||||
/*! \brief Internal width of the screen
|
||||
*
|
||||
* At least the visible width of the screen, depends on the hardware but
|
||||
* required for calculating the rows
|
||||
*/
|
||||
unsigned pitch;
|
||||
|
||||
protected:
|
||||
/*! \brief Visible width of the screen
|
||||
*/
|
||||
unsigned screen_width;
|
||||
|
||||
/*! \brief Visible height of the screen
|
||||
*/
|
||||
unsigned screen_height;
|
||||
|
||||
/*! \brief Initialize screen dimensions
|
||||
*
|
||||
* \param width visible width of graphics screen
|
||||
* \param height visible height of graphics screen
|
||||
* \param pitch width of graphics screen (including invisible part, has to
|
||||
* be at least `width`)
|
||||
*/
|
||||
void init(const unsigned width, const unsigned height,
|
||||
const unsigned pitch) {
|
||||
this->screen_width = width;
|
||||
this->screen_height = height;
|
||||
this->pitch = pitch;
|
||||
}
|
||||
|
||||
/*! \brief Set the video memory address
|
||||
*
|
||||
* \param lfb pointer to the linear framebuffer (lfb)
|
||||
*/
|
||||
void buffer(void *lfb) { framebuffer = reinterpret_cast<uintptr_t>(lfb); }
|
||||
|
||||
/*! \brief Clear all pixel of the current back buffer
|
||||
* (set full screen to black)
|
||||
*/
|
||||
void clear() {
|
||||
memset(reinterpret_cast<void *>(framebuffer), 0, screen_height * pitch);
|
||||
}
|
||||
|
||||
/*! \brief Pixel component
|
||||
*
|
||||
* \tparam OFFSET Bit position of mask
|
||||
* \tparam BITS Size of mask
|
||||
*/
|
||||
template <unsigned OFFSET, unsigned SIZE>
|
||||
class PixelComponent {
|
||||
unsigned : OFFSET; ///< Reserved space for offset
|
||||
unsigned value : SIZE; ///< Value
|
||||
|
||||
public:
|
||||
/*! \brief Constructor
|
||||
*
|
||||
* \param value Initial component value
|
||||
*/
|
||||
explicit PixelComponent(unsigned value) : value(value) {}
|
||||
|
||||
/*! \brief Assign component value
|
||||
* (from a \ref SpritePixelComponent with different bit mask size)
|
||||
*
|
||||
* \tparam BITS Size of bit mask
|
||||
* \param other new component value
|
||||
*/
|
||||
template <unsigned BITS>
|
||||
void set(const struct SpritePixelComponent<BITS> &other) {
|
||||
value = BITS > SIZE ? (other.value >> (BITS - SIZE))
|
||||
: (other.value << (SIZE - BITS));
|
||||
}
|
||||
|
||||
/*! \brief Assign component value
|
||||
* (from a \ref SpritePixelComponent with same bit mask size)
|
||||
*
|
||||
* \param other new component value
|
||||
*/
|
||||
void set(const struct SpritePixelComponent<SIZE> &other) {
|
||||
value = other.value;
|
||||
}
|
||||
|
||||
/*! \brief Assign component value
|
||||
* (from an integer)
|
||||
*
|
||||
* \param value new component value
|
||||
*/
|
||||
void set(unsigned value) {
|
||||
value = 8 > SIZE ? (value >> (8 - SIZE)) : (value << (SIZE - 8));
|
||||
}
|
||||
|
||||
/*! \brief Alpha blend component value
|
||||
* (from a \ref SpritePixelComponent with different bit mask size)
|
||||
*
|
||||
* \tparam BITS Size of bit mask
|
||||
* \param other component value to blend
|
||||
* \param alpha transparency used for blending
|
||||
*/
|
||||
template <unsigned BITS>
|
||||
void blend(const struct SpritePixelComponent<BITS> &other,
|
||||
const struct SpritePixelComponent<BITS> &alpha) {
|
||||
int other_value = BITS > SIZE ? (other.value >> (BITS - SIZE))
|
||||
: (other.value << (SIZE - BITS));
|
||||
int other_alpha = BITS > SIZE ? (alpha.value >> (BITS - SIZE))
|
||||
: (alpha.value << (SIZE - BITS));
|
||||
value +=
|
||||
((other_value - static_cast<int>(value)) * other_alpha) >> SIZE;
|
||||
}
|
||||
|
||||
/*! \brief Alpha blend component value
|
||||
* (from a \ref SpritePixelComponent with same bit mask size)
|
||||
*
|
||||
* \param other component value to blend
|
||||
* \param alpha transparency used for blending
|
||||
*/
|
||||
void blend(const struct SpritePixelComponent<SIZE> &other,
|
||||
const struct SpritePixelComponent<SIZE> &alpha) {
|
||||
value +=
|
||||
((static_cast<int>(other.value) - static_cast<int>(value)) *
|
||||
alpha.value) >>
|
||||
SIZE;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
/*! \brief Pixel (colored)
|
||||
*/
|
||||
union Pixel {
|
||||
/*! \brief Bits per pixel
|
||||
*/
|
||||
struct {
|
||||
unsigned data : COLORDEPTH; ///< RGB value
|
||||
} __attribute__((packed));
|
||||
|
||||
PixelComponent<OFFSET_RED, BITS_RED> red; ///< Red color component
|
||||
PixelComponent<OFFSET_GREEN, BITS_GREEN>
|
||||
green; ///< Green color component
|
||||
PixelComponent<OFFSET_BLUE, BITS_BLUE> blue; ///< Blue color component
|
||||
|
||||
/*! \brief Constructor (using RGB value)
|
||||
*
|
||||
* \param data RGB value
|
||||
*/
|
||||
explicit Pixel(const unsigned data) : data(data) {}
|
||||
|
||||
/*! \brief Constructor (using explicit RGB components)
|
||||
*
|
||||
* Unused bits are zeroed.
|
||||
*
|
||||
* \param r Red color component
|
||||
* \param g Green color component
|
||||
* \param b Blue color component
|
||||
*/
|
||||
Pixel(const unsigned r, const unsigned g, const unsigned b) : data(0) {
|
||||
red.set(r);
|
||||
green.set(g);
|
||||
blue.set(b);
|
||||
}
|
||||
|
||||
/*! \brief Constructor (using \ref SpritePixel)
|
||||
*
|
||||
* \tparam ALPHA `true` if alpha channel
|
||||
* \tparam BITS Size of mask
|
||||
* \param other other
|
||||
*/
|
||||
template <bool ALPHA, unsigned BITS>
|
||||
explicit Pixel(const struct SpritePixel<RGB, ALPHA, BITS> &other) {
|
||||
red.set(other.red);
|
||||
green.set(other.green);
|
||||
blue.set(other.blue);
|
||||
}
|
||||
|
||||
/*! \brief Get color of pixel
|
||||
*
|
||||
* \return color of pixel
|
||||
*/
|
||||
Color getColor() const { return Color(red, green, blue); }
|
||||
|
||||
/*! \brief Assign pixel (with colored \ref SpritePixel)
|
||||
*
|
||||
* \tparam BITS Size of other pixels mask
|
||||
* \param other other pixel
|
||||
*/
|
||||
template <unsigned BITS>
|
||||
Pixel &operator=(const struct SpritePixel<RGB, false, BITS> &other) {
|
||||
red.set(other.red);
|
||||
green.set(other.green);
|
||||
blue.set(other.blue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Assign pixel (with greyscale \ref SpritePixel)
|
||||
*
|
||||
* \tparam BITS Size of other pixels mask
|
||||
* \param other other pixel
|
||||
*/
|
||||
template <unsigned BITS>
|
||||
Pixel &operator=(
|
||||
const struct SpritePixel<GREYSCALE, false, BITS> &other) {
|
||||
red.set(other.luminance);
|
||||
green.set(other.luminance);
|
||||
blue.set(other.luminance);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Assign pixel (with greyscale \ref SpritePixel supporting
|
||||
* transparency)
|
||||
*
|
||||
* \tparam BITS Size of other pixels mask
|
||||
* \param other other pixel
|
||||
*/
|
||||
template <unsigned BITS>
|
||||
Pixel &operator=(const struct SpritePixel<RGB, true, BITS> &other) {
|
||||
red.blend(other.red, other.alpha);
|
||||
green.blend(other.green, other.alpha);
|
||||
blue.blend(other.blue, other.alpha);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Assign pixel (with greyscale \ref SpritePixel supporting
|
||||
* transparency)
|
||||
*
|
||||
* \tparam BITS Size of other pixels mask
|
||||
* \param other other pixel
|
||||
*/
|
||||
template <unsigned BITS>
|
||||
Pixel &operator=(
|
||||
const struct SpritePixel<GREYSCALE, true, BITS> &other) {
|
||||
red.blend(other.luminance, other.alpha);
|
||||
green.blend(other.luminance, other.alpha);
|
||||
blue.blend(other.luminance, other.alpha);
|
||||
return *this;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
static_assert(OFFSET_RED + BITS_RED <= COLORDEPTH &&
|
||||
OFFSET_GREEN + BITS_GREEN <= COLORDEPTH &&
|
||||
OFFSET_BLUE + BITS_BLUE <= COLORDEPTH,
|
||||
"color settings invalid!");
|
||||
|
||||
/*! \brief Get pixel at position
|
||||
*
|
||||
* \param x X position
|
||||
* \param y Y position
|
||||
* \return Pointer to pixel
|
||||
*/
|
||||
Pixel *get(const unsigned x, const unsigned y) const {
|
||||
return reinterpret_cast<Pixel *>(framebuffer + y * pitch) + x;
|
||||
}
|
||||
|
||||
/*! \brief Get pixel at position
|
||||
*
|
||||
* \param p Coordinate of position
|
||||
* \return Pointer to pixel
|
||||
*/
|
||||
Pixel *get(const Point &p) const { return get(p.x, p.y); }
|
||||
|
||||
/*! \brief Assign color to a pixel at a given position
|
||||
*
|
||||
* \tparam COLOR color or greyscale?
|
||||
* \tparam ALPHA with transparency?
|
||||
* \tparam BITS Size of mask
|
||||
* \param x X position
|
||||
* \param y Y position
|
||||
* \param color color to assign
|
||||
*/
|
||||
template <enum SpriteColorMode COLOR, bool ALPHA, unsigned BITS>
|
||||
void set(const unsigned x, const unsigned y,
|
||||
const SpritePixel<COLOR, ALPHA, BITS> &color) {
|
||||
Pixel *pos = get(x, y);
|
||||
*pos = color;
|
||||
}
|
||||
|
||||
/*! \brief Assign color to a pixel at a given position
|
||||
*
|
||||
* \tparam COLOR color or greyscale?
|
||||
* \tparam ALPHA with transparency?
|
||||
* \tparam BITS Size of mask
|
||||
* \param p Coordinate of position
|
||||
* \param color color to assign
|
||||
*/
|
||||
template <enum SpriteColorMode COLOR, bool ALPHA, unsigned BITS>
|
||||
void set(const Point &p, const SpritePixel<COLOR, ALPHA, BITS> &color) {
|
||||
set(p.x, p.y, color);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user