8432360ab9252a32f98608fe63775fc9aafb7f11
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) 
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

96) /// check if game is active
97) bool Game::isActive() const
98) {
99)   return ! m_imgBuf.empty(); // game is active if there is an image buffer
100) }
101) 
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

175) /// process update of color file, return true on update
176) bool Game::colorUpdate(ColorFile &colorFile, ColorData &data) const
177) {
178)   if (colorFile.checkModified()) {
179)     colorFile.update();
180)     color2data(colorFile, data);
181)     return true;
182)   } else {
183)     return false;
184)   }
185) }
186) 
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

189) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

263)   color2data(m_fileBackgroundColor, m_backgroundColor);