BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
ce55115
Branches
Tags
master
Blinker
src
common
Game.cpp
base class for games
Stefan Schuermans
commited
ce55115
at 2019-06-10 10:11:49
Game.cpp
Blame
History
Raw
/* Blinker Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #include <string> #include <vector> #include <BlinkenLib/BlinkenFrame.h> #include "File.h" #include "Format.h" #include "FormatFile.h" #include "Game.h" #include "Mgrs.h" #include "Module.h" #include "OutStreamFile.h" namespace Blinker { /** * @brief constructor * @param[in] name module name * @param[in] mgrs managers * @param[in] dirBase base directory */ Game::Game(const std::string &name, Mgrs &mgrs, const Directory &dirBase): Module(name, mgrs, dirBase), m_fileFormat(dirBase.getFile("format")), m_fileBackgroundColor(dirBase.getFile("backgroundColor")), m_fileOutStream(dirBase.getFile("outstream"), mgrs.m_streamMgr), m_height(0), m_width(0), m_channels(0), m_imgBuf(), m_backgroundColor() { } /// virtual destructor Game::~Game() { // clean up deactivate(); } /// check for update of configuration void Game::updateConfig() { // format file was modified -> re-create canvas and redraw if (m_fileFormat.checkModified()) { createImgBuf(); } // color file was modified -> redraw image if (m_fileBackgroundColor.checkModified()) { redraw(); } // output stream name file was modified -> re-get output stream if (m_fileOutStream.checkModified()) { m_fileOutStream.update(); } } /// activate game: set up image buffer, call redraw() void Game::activate() { createImgBuf(); redraw(); } /// deactivate game: tear down image buffer, deactivate output void Game::deactivate() { destroyImgBuf(); sendFrame(); } /// set pixel in image buffer void Game::pixel(int y, int x, ColorData const &cd) { if (m_imgBuf.empty() || ! checkLimitInt(y, 0, m_height - 1) || ! checkLimitInt(x, 0, m_width - 1)) { return; } int pos = (y * m_width + x) * m_channels; std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos); } /// draw horizontal line to image buffer void Game::lineHor(int y, int x1, int x2, ColorData const &cd) { if (m_imgBuf.empty() || ! checkLimitInt(y, 0, m_height - 1) || ! checkIntRangeLimit(x1, x2, 0, m_width - 1)) { return; } int pos = (y * m_width + x1) * m_channels; int dx = m_channels; for (int x = x1; x <= x2; ++x) { std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos); pos += dx; } } /// draw vertical line to image buffer void Game::lineVert(int y1, int y2, int x, ColorData const &cd) { if (m_imgBuf.empty() || ! checkIntRangeLimit(y1, y2, 0, m_height - 1) || ! checkLimitInt(x, 0, m_width - 1)) { return; } int pos = (y1 * m_width + x) * m_channels; int dy = m_width * m_channels; for (int y = y1; y <= y2; ++y) { std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos); pos += dy; } } /// draw non-filled rectangle to image buffer void Game::rect(int y1, int y2, int x1, int x2, ColorData const &cd) { lineHor(y1, x1, x2, cd); lineHor(y2, x1, x2, cd); lineVert(y1, y2, x1, cd); lineVert(y1, y2, x2, cd); } /// draw filled rectangle to image buffer void Game::rectFill(int y1, int y2, int x1, int x2, ColorData const &cd) { if (m_imgBuf.empty() || ! checkIntRangeLimit(y1, y2, 0, m_height - 1) || ! checkIntRangeLimit(x1, x2, 0, m_width - 1)) { return; } int pos = (y1 * m_width + x1) * m_channels; int dx = m_channels; int dy = m_width - (x2 - x1 + 1) * m_channels; for (int y = y1; y <= y2; ++y) { for (int x = x1; x <= x2; ++x) { std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos); pos += dx; } pos += dy; } } /// convert color to raw color data void Game::color2data(Format const &format, Color const &color, ColorData &data) { data.resize(format.m_channels); if (format.m_channels == 1) { // single channel // convert to monochrome according to CIE XYZ double val = 0.2125 * color.m_red + 0.7154 * color.m_green + 0.0721 * color.m_blue; // adapt to maxval val = val * format.m_maxval / 255.0; // round data.at(0) = (unsigned char)(val + 0.5); } else if (format.m_channels == 2) { // two channels // adapt to maxval and round, ignore blue data.at(0) = (unsigned char)(color.m_red * format.m_maxval / 255.0 + 0.5); data.at(1) = (unsigned char)(color.m_green * format.m_maxval / 255.0 + 0.5); } else if (format.m_channels >= 3) { // three channels (more than three channels: further channels are dark) // adapt to maxval and round data.at(0) = (unsigned char)(color.m_red * format.m_maxval / 255.0 + 0.5); data.at(1) = (unsigned char)(color.m_green * format.m_maxval / 255.0 + 0.5); data.at(2) = (unsigned char)(color.m_blue * format.m_maxval / 255.0 + 0.5); } } /// send current image buffer as frame to output stream void Game::sendFrame() { // image buffer available -> send its contents as frame if (! m_imgBuf.empty()) { Format const &fmt = m_fileFormat.m_obj; stBlinkenFrame *pFrame = BlinkenFrameNew(fmt.m_height, fmt.m_width, fmt.m_channels, fmt.m_maxval, 1); BlinkenFrameSetPixelData(pFrame, 0, m_height, 0, m_width, 0, m_channels, m_imgBuf.data()); m_fileOutStream.setFrame(pFrame); BlinkenFrameFree(pFrame); } // no image buffer available -> send "no frame" information else { m_fileOutStream.setFrame(NULL); } } /// (re-)create image buffer void Game::createImgBuf() { // get rid of old image buffer destroyImgBuf(); // read format from format file m_fileFormat.update(); if (! m_fileFormat.m_valid) return; // read background color m_fileBackgroundColor.update(); if (! m_fileBackgroundColor.m_valid) return; // store parameters m_height = m_fileFormat.m_obj.m_height; m_width = m_fileFormat.m_obj.m_width; m_channels = m_fileFormat.m_obj.m_channels; // create image buffer m_imgBuf.resize(m_height * m_width * m_channels); // convert background color color2data(m_fileFormat.m_obj, m_fileBackgroundColor.m_obj, m_backgroundColor); // set image buffer to background color rectFill(0, m_height, 0, m_width, m_backgroundColor); } /// tear down image buffer void Game::destroyImgBuf() { m_imgBuf.clear(); m_backgroundColor.clear(); } } // namespace Blinker