d3cb8b37233edf0e03d6976fa561ee841e51576c
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

1) /* Blinker
2)    Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
3)    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4)    a blinkenarea.org project */
5) 
6) #include <string>
7) #include <vector>
8) 
9) #include <BlinkenLib/BlinkenFrame.h>
10) 
11) #include "File.h"
12) #include "Format.h"
13) #include "FormatFile.h"
14) #include "Game.h"
15) #include "Mgrs.h"
16) #include "Module.h"
17) #include "OutStreamFile.h"
18) 
19) namespace Blinker {
20) 
21) /**
22)  * @brief constructor
23)  * @param[in] name module name
24)  * @param[in] mgrs managers
25)  * @param[in] dirBase base directory
26)  */
27) Game::Game(const std::string &name, Mgrs &mgrs, const Directory &dirBase):
28)   Module(name, mgrs, dirBase),
29)   m_fileFormat(dirBase.getFile("format")),
30)   m_fileBackgroundColor(dirBase.getFile("backgroundColor")),
31)   m_fileOutStream(dirBase.getFile("outstream"), mgrs.m_streamMgr),
32)   m_height(0), m_width(0), m_channels(0), m_imgBuf(), m_backgroundColor()
33) {
34) }
35) 
36) /// virtual destructor
37) Game::~Game()
38) {
39)   // clean up
40)   deactivate();
41) }
42) 
43) /// check for update of configuration
44) void Game::updateConfig()
45) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

46)   bool doReinit = false;
47)   bool doRedraw = false;
48) 
49)   // format file was modified -> re-create canvas and schedule redraw
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

50)   if (m_fileFormat.checkModified()) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

51)     m_fileFormat.update();
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

52)     createImgBuf();
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

53)     doReinit = true;
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

54)   }
55) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

56)   // color file was modified -> convert color, schedule redraw
57)   if (colorUpdate(m_fileBackgroundColor, m_backgroundColor)) {
58)     doRedraw = true;
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

59)   }
60) 
61)   // output stream name file was modified -> re-get output stream
62)   if (m_fileOutStream.checkModified()) {
63)     m_fileOutStream.update();
64)   }
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

65) 
66)   // check config update of derived game
67)   if (updateConfigGame()) {
68)     doRedraw = true;
69)   }
70) 
71)   // re-initialize / redraw
72)   if (doReinit) {
73)     reinitialize();
74)     doRedraw = true;
75)   }
76)   if (doRedraw) {
77)     redraw();
78)   }
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

79) }
80) 
81) /// activate game: set up image buffer, call redraw()
82) void Game::activate()
83) {
84)   createImgBuf();
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

85)   reinitialize();
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

86)   redraw();
87) }
88) 
89) /// deactivate game: tear down image buffer, deactivate output
90) void Game::deactivate()
91) {
92)   destroyImgBuf();
93)   sendFrame();
94) }
95) 
96) /// set pixel in image buffer
97) void Game::pixel(int y, int x, ColorData const &cd)
98) {
99)   if (m_imgBuf.empty() ||
100)       ! checkLimitInt(y, 0, m_height - 1) ||
101)       ! checkLimitInt(x, 0, m_width - 1)) {
102)     return;
103)   }
104)   int pos = (y * m_width + x) * m_channels;
105)   std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
106) }
107) 
108) /// draw horizontal line to image buffer
109) void Game::lineHor(int y, int x1, int x2, ColorData const &cd)
110) {
111)   if (m_imgBuf.empty() ||
112)       ! checkLimitInt(y, 0, m_height - 1) ||
113)       ! checkIntRangeLimit(x1, x2, 0, m_width - 1)) {
114)     return;
115)   }
116)   int pos = (y * m_width + x1) * m_channels;
117)   int dx = m_channels;
118)   for (int x = x1; x <= x2; ++x) {
119)     std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
120)     pos += dx;
121)   }
122) }
123) 
124) /// draw vertical line to image buffer
125) void Game::lineVert(int y1, int y2, int x, ColorData const &cd)
126) {
127)   if (m_imgBuf.empty() ||
128)       ! checkIntRangeLimit(y1, y2, 0, m_height - 1) ||
129)       ! checkLimitInt(x, 0, m_width - 1)) {
130)     return;
131)   }
132)   int pos = (y1 * m_width + x) * m_channels;
133)   int dy = m_width * m_channels;
134)   for (int y = y1; y <= y2; ++y) {
135)     std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
136)     pos += dy;
137)   }
138) }
139) 
140) /// draw non-filled rectangle to image buffer
141) void Game::rect(int y1, int y2, int x1, int x2, ColorData const &cd)
142) {
143)   lineHor(y1, x1, x2, cd);
144)   lineHor(y2, x1, x2, cd);
145)   lineVert(y1, y2, x1, cd);
146)   lineVert(y1, y2, x2, cd);
147) }
148) 
149) /// draw filled rectangle to image buffer
150) void Game::rectFill(int y1, int y2, int x1, int x2, ColorData const &cd)
151) {
152)   if (m_imgBuf.empty() ||
153)       ! checkIntRangeLimit(y1, y2, 0, m_height - 1) ||
154)       ! checkIntRangeLimit(x1, x2, 0, m_width - 1)) {
155)     return;
156)   }
157)   int pos = (y1 * m_width + x1) * m_channels;
158)   int dx = m_channels;
159)   int dy = m_width - (x2 - x1 + 1) * m_channels;
160)   for (int y = y1; y <= y2; ++y) {
161)     for (int x = x1; x <= x2; ++x) {
162)       std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
163)       pos += dx;
164)     }
165)     pos += dy;
166)   }
167) }
168) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

169) /// process update of color file, return true on update
170) bool Game::colorUpdate(ColorFile &colorFile, ColorData &data) const
171) {
172)   if (colorFile.checkModified()) {
173)     colorFile.update();
174)     color2data(colorFile, data);
175)     return true;
176)   } else {
177)     return false;
178)   }
179) }
180) 
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

181) /// convert color to raw color data
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

182) void Game::color2data(ColorFile const &colorFile, ColorData &data) const
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

183) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

184)   if (! m_fileFormat.m_valid) {
185)     data.clear();
186)   } else {
187)     unsigned int channels = m_fileFormat.m_obj.m_channels;
188)     unsigned int maxval = m_fileFormat.m_obj.m_maxval;
189)     data.resize(m_fileFormat.m_obj.m_channels);
190)     Color const &color = colorFile.m_obj;
191)     if (channels == 1) {
192)       // single channel
193)       // convert to monochrome according to CIE XYZ
194)       double val = 0.2125 * color.m_red + 0.7154 * color.m_green
195)                                         + 0.0721 * color.m_blue;
196)       // adapt to maxval and round
197)       data.at(0) = (unsigned char)(val * maxval / 255.0 + 0.5);
198)     } else if (channels == 2) {
199)       // two channels
200)       // adapt to maxval and round, ignore blue
201)       data.at(0) = (unsigned char)(color.m_red * maxval / 255.0 + 0.5);
202)       data.at(1) = (unsigned char)(color.m_green * maxval / 255.0 + 0.5);
203)     } else if (channels >= 3) {
204)       // three channels (more than three channels: further channels are dark)
205)       // adapt to maxval and round
206)       data.at(0) = (unsigned char)(color.m_red * maxval / 255.0 + 0.5);
207)       data.at(1) = (unsigned char)(color.m_green * maxval / 255.0 + 0.5);
208)       data.at(2) = (unsigned char)(color.m_blue * maxval / 255.0 + 0.5);
209)     }
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

210)   }
211) }
212) 
213) /// send current image buffer as frame to output stream
214) void Game::sendFrame()
215) {
216)   // image buffer available -> send its contents as frame
217)   if (! m_imgBuf.empty()) {
218)     Format const &fmt = m_fileFormat.m_obj;
219)     stBlinkenFrame *pFrame = BlinkenFrameNew(fmt.m_height, fmt.m_width,
220)                                              fmt.m_channels, fmt.m_maxval, 1);
221)     BlinkenFrameSetPixelData(pFrame, 0, m_height, 0, m_width, 0, m_channels,
222)                              m_imgBuf.data());
223)     m_fileOutStream.setFrame(pFrame);
224)     BlinkenFrameFree(pFrame);
225)   }
226)   // no image buffer available -> send "no frame" information
227)   else {
228)     m_fileOutStream.setFrame(NULL);
229)   }
230) }
231) 
232) /// (re-)create image buffer
233) void Game::createImgBuf()
234) {
235)   // get rid of old image buffer
236)   destroyImgBuf();
237) 
238)   // read format from format file
239)   m_fileFormat.update();
240)   if (! m_fileFormat.m_valid)
241)     return;
242) 
243)   // read background color
244)   m_fileBackgroundColor.update();
245)   if (! m_fileBackgroundColor.m_valid)
246)     return;
247) 
248)   // store parameters
249)   m_height = m_fileFormat.m_obj.m_height;
250)   m_width = m_fileFormat.m_obj.m_width;
251)   m_channels = m_fileFormat.m_obj.m_channels;
252) 
253)   // create image buffer
254)   m_imgBuf.resize(m_height * m_width * m_channels);
255) 
256)   // convert background color
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

257)   color2data(m_fileBackgroundColor, m_backgroundColor);