first version of canvas module (not yet completely happy with it)
Stefan Schuermans

Stefan Schuermans commited on 2011-11-19 13:35:10
Showing 5 changed files, with 686 additions and 0 deletions.

... ...
@@ -0,0 +1,232 @@
1
+/* Blinker
2
+   Copyright 2011 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 <list>
7
+#include <string>
8
+
9
+#include <BlinkenLib/BlinkenFrame.h>
10
+
11
+#include "CallMgr.h"
12
+#include "Canvas.h"
13
+#include "CanvasInput.h"
14
+#include "Directory.h"
15
+#include "File.h"
16
+#include "Format.h"
17
+#include "Module.h"
18
+#include "SettingFile.h"
19
+#include "StreamMgr.h"
20
+#include "StreamRecv.h"
21
+
22
+namespace Blinker {
23
+
24
+/**
25
+ * @brief constructor
26
+ * @param[in] callMgr callback manager
27
+ * @param[in] streamMgr stream manager
28
+ * @param[in] dirBase base directory
29
+ */
30
+Canvas::Canvas(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase):
31
+  Module(callMgr, streamMgr, dirBase),
32
+  m_fileFormat(dirBase.getFile("format")),
33
+  m_dirInputs(dirBase.getSubdir("inputs")),
34
+  m_fileOutStream(dirBase.getFile("outstream")),
35
+  m_pCanvas(NULL),
36
+  m_canvasHasFrame(false),
37
+  m_pOutStream(NULL)
38
+{
39
+  // set up
40
+  createCanvas();
41
+  updateInListFull();
42
+  getOutStream();
43
+}
44
+
45
+/// virtual destructor
46
+Canvas::~Canvas()
47
+{
48
+  // clean up
49
+  releaseOutStream();
50
+  while (!m_inList.empty()) {
51
+    delete m_inList.back().m_pInput;
52
+    m_inList.pop_back();
53
+  }
54
+  destroyCanvas();
55
+}
56
+
57
+/// check for update of configuration
58
+void Canvas::updateConfig()
59
+{
60
+  // format file was modified -> re-create canvas
61
+  if (m_fileFormat.checkModified()) {
62
+    createCanvas();
63
+  }
64
+
65
+  // input list update (directory modified -> full, otherwise -> light)
66
+  if (m_dirInputs.checkModified())
67
+    updateInListFull();
68
+  else
69
+    updateInListLight();
70
+
71
+  // output stream name file was modified -> re-get output stream
72
+  if (m_fileOutStream.checkModified()) {
73
+    releaseOutStream();
74
+    getOutStream();
75
+  }
76
+}
77
+
78
+/// (re-)create canvas
79
+void Canvas::createCanvas()
80
+{
81
+  std::string strFormat;
82
+
83
+  // get rid of old canvas
84
+  destroyCanvas();
85
+
86
+  // read format from format file
87
+  if (!m_fileFormat.getStr(strFormat) || !m_format.fromStr(strFormat))
88
+    return;
89
+
90
+  // create frame
91
+  m_pCanvas = BlinkenFrameNew(m_format.m_height, m_format.m_width,
92
+                              m_format.m_channels, m_format.m_maxval, 1);
93
+  m_canvasHasFrame = 0;
94
+}
95
+
96
+/// tear down canvas
97
+void Canvas::destroyCanvas()
98
+{
99
+  if (m_pCanvas) {
100
+    BlinkenFrameFree(m_pCanvas);
101
+    m_pCanvas = NULL;
102
+    m_canvasHasFrame = 0;
103
+  }
104
+}
105
+
106
+/// light update of input list, i.e. check all entries in current input list
107
+void Canvas::updateInListLight()
108
+{
109
+  // walk through all inputs in input list and check for modification
110
+  InList::iterator itIn;
111
+  for (itIn = m_inList.begin(); itIn != m_inList.end(); ++itIn)
112
+    itIn->m_pInput->updateConfig();
113
+}
114
+
115
+/// full update of input list, i.e. scan subdirs in input list directory
116
+void Canvas::updateInListFull()
117
+{
118
+  // get list of subdirs in input directory
119
+  typedef std::list<std::string> Subdirlist;
120
+  Subdirlist curSubdirs;
121
+  m_dirInputs.getEntries(Directory::TypeSubdir, curSubdirs);
122
+
123
+  // walk through current input list and subdir list simultaneously
124
+  Subdirlist::const_iterator itSubdir = curSubdirs.begin();
125
+  InList::iterator           itIn     = m_inList.begin();
126
+  while (itSubdir != curSubdirs.end() || itIn != m_inList.end()) {
127
+
128
+    // new input inserted
129
+    if (itIn == m_inList.end() ||
130
+        (itSubdir != curSubdirs.end() && *itSubdir < itIn->m_name)) {
131
+      // create input object
132
+      InEntry inEntry(*itSubdir);
133
+      inEntry.m_pInput = new Input(*this, m_dirInputs.getSubdir(*itSubdir));
134
+      if (inEntry.m_pInput)
135
+        // insert input list entry
136
+        m_inList.insert(itIn, inEntry);
137
+      // advance to next subdir
138
+      ++itSubdir;
139
+    }
140
+
141
+    // input removed
142
+    else if (itSubdir == curSubdirs.end() || *itSubdir > itIn->m_name) {
143
+      // remove input
144
+      delete itIn->m_pInput;
145
+      itIn = m_inList.erase(itIn);
146
+      // do not advance to next subdir
147
+    }
148
+
149
+    // input stayed in input list
150
+    else {
151
+      // check for update
152
+      itIn->m_pInput->updateConfig();
153
+      // advance to next file and next entry
154
+      ++itSubdir;
155
+      ++itIn;
156
+    }
157
+
158
+  } // while itFile itIn
159
+}
160
+
161
+/// get output stream
162
+void Canvas::getOutStream()
163
+{
164
+  // get name of output stream
165
+  m_fileOutStream.getStr(m_nameOutStream);
166
+
167
+  // get output stream
168
+  m_pOutStream = &m_streamMgr.refStream(m_nameOutStream);
169
+
170
+  // send current frame to stream
171
+  sendFrame();
172
+}
173
+
174
+/// release output stream
175
+void Canvas::releaseOutStream()
176
+{
177
+  // send no frame information
178
+  if (m_pOutStream)
179
+    m_pOutStream->setNoFrame();
180
+
181
+  // unreference output stream
182
+  m_pOutStream = NULL;
183
+  m_streamMgr.unrefStream(m_nameOutStream);
184
+}
185
+
186
+/// notfication to redraw (called by inputs)
187
+void Canvas::redraw()
188
+{
189
+  // do nothing if there is no canvas
190
+  if (!m_pCanvas)
191
+    return;
192
+
193
+  // black background
194
+  BlinkenFrameClear(m_pCanvas);
195
+  m_canvasHasFrame = false; // no frame on canvas yet
196
+
197
+  // tell all inputs to draw on canvas
198
+  InList::iterator itIn;
199
+  for (itIn = m_inList.begin(); itIn != m_inList.end(); ++itIn)
200
+    if (itIn->m_pInput->draw())
201
+      m_canvasHasFrame = true; // drawing successful -> there is a frame now
202
+
203
+  // send current frame to stream
204
+  sendFrame();
205
+}
206
+
207
+/// send current frame to output stream
208
+void Canvas::sendFrame()
209
+{
210
+  if (m_pOutStream) {
211
+    // frame avalable -> send it
212
+    if (m_canvasHasFrame)
213
+      m_pOutStream->setFrame(m_pCanvas);
214
+    // no frame available -> send this information
215
+    else
216
+      m_pOutStream->setNoFrame();
217
+  }
218
+}
219
+
220
+/* ###################
221
+   # Canvas::InEntry #
222
+   ################### */
223
+
224
+/// constructor
225
+Canvas::InEntry::InEntry(const std::string &name):
226
+  m_name(name),
227
+  m_pInput(NULL)
228
+{
229
+}
230
+
231
+} // namespace Blinker
232
+
... ...
@@ -0,0 +1,104 @@
1
+/* Blinker
2
+   Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#ifndef CANVAS_H
7
+#define CANVAS_H
8
+
9
+#include <list>
10
+#include <string>
11
+
12
+#include <BlinkenLib/BlinkenFrame.h>
13
+
14
+#include "CallMgr.h"
15
+#include "Directory.h"
16
+#include "File.h"
17
+#include "Format.h"
18
+#include "Module.h"
19
+#include "SettingFile.h"
20
+#include "StreamMgr.h"
21
+
22
+namespace Blinker {
23
+
24
+/// a canvas to merge and split streams
25
+class Canvas: public Module
26
+{
27
+protected:
28
+  /// input to canvas
29
+  class Input;
30
+
31
+  /// input list entry
32
+  struct InEntry {
33
+    std::string m_name;    ///< name of input list entry
34
+    Input       *m_pInput; ///< input object
35
+    InEntry(const std::string &name); ///< constructor
36
+  };
37
+
38
+  /// input list
39
+  typedef std::list<InEntry> InList;
40
+
41
+public:
42
+  /**
43
+   * @brief constructor
44
+   * @param[in] callMgr callback manager
45
+   * @param[in] streamMgr stream manager
46
+   * @param[in] dirBase base directory
47
+   */
48
+  Canvas(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase);
49
+
50
+  /// virtual destructor
51
+  virtual ~Canvas();
52
+
53
+private:
54
+  /// copy constructor disabled
55
+  Canvas(const Canvas &that);
56
+
57
+  /// assignment operator disabled
58
+  const Canvas & operator=(const Canvas &that);
59
+
60
+public:
61
+  /// check for update of configuration
62
+  virtual void updateConfig();
63
+
64
+protected:
65
+  /// (re-)create canvas
66
+  void createCanvas();
67
+
68
+  /// tear down canvas
69
+  void destroyCanvas();
70
+
71
+  /// light update of input list, i.e. check all entries in current input list
72
+  void updateInListLight();
73
+
74
+  /// full update of input list, i.e. scan subdirs in input list directory
75
+  void updateInListFull();
76
+
77
+  /// get output stream
78
+  void getOutStream();
79
+
80
+  /// release output stream
81
+  void releaseOutStream();
82
+
83
+  /// notfication to redraw (called by inputs)
84
+  void redraw();
85
+
86
+  /// send current frame to output stream
87
+  void sendFrame();
88
+
89
+protected:
90
+  SettingFile    m_fileFormat;     ///< canvas format file
91
+  Directory      m_dirInputs;      ///< input stream directory
92
+  SettingFile    m_fileOutStream;  ///< output stream name file
93
+  Format         m_format;         ///< canvas format
94
+  stBlinkenFrame *m_pCanvas;       ///< canvas to put streams on
95
+  bool           m_canvasHasFrame; ///< if there is at >= 1 frame on canvas
96
+  InList         m_inList;         ///< current input list
97
+  std::string    m_nameOutStream;  ///< name of output stream
98
+  Stream         *m_pOutStream;    ///< output stream
99
+}; // class Canvas
100
+
101
+} // namespace Blinker
102
+
103
+#endif // #ifndef CANVAS_H
104
+
... ...
@@ -0,0 +1,236 @@
1
+/* Blinker
2
+   Copyright 2011 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
+
8
+#include <BlinkenLib/BlinkenFrame.h>
9
+
10
+#include "Canvas.h"
11
+#include "CanvasInput.h"
12
+#include "Directory.h"
13
+#include "File.h"
14
+#include "Position.h"
15
+#include "SettingFile.h"
16
+#include "Size.h"
17
+#include "StreamMgr.h"
18
+#include "StreamRecv.h"
19
+
20
+namespace Blinker {
21
+
22
+/**
23
+ * @brief constructor
24
+ * @param[in] canvas owning canvas
25
+ * @param[in] dirBase base directory
26
+ */
27
+Canvas::Input::Input(Canvas &canvas, const Directory &dirBase):
28
+  m_canvas(canvas),
29
+  m_fileInStream(dirBase.getFile("instream")),
30
+  m_filePosition(dirBase.getFile("position")),
31
+  m_fileSize(dirBase.getFile("size")),
32
+  m_havePosition(false),
33
+  m_haveSize(false),
34
+  m_pInStream(NULL),
35
+  m_ownFrame(false),
36
+  m_pFrame(NULL)
37
+{
38
+  // get setting and attach to input stream
39
+  getPosition();
40
+  getSize();
41
+  getInStream();
42
+}
43
+
44
+/// virtual destructor
45
+Canvas::Input::~Input()
46
+{
47
+  // detach from input stream and release it
48
+  releaseInStream();
49
+}
50
+
51
+/// check for update of configuration
52
+void Canvas::Input::updateConfig()
53
+{
54
+  // input stream name file was modified -> re-get input stream
55
+  if (m_fileInStream.checkModified()) {
56
+    releaseInStream();
57
+    getInStream();
58
+  }
59
+
60
+  // position file was modified -> re-get position
61
+  if (m_filePosition.checkModified()) {
62
+    getPosition();
63
+  }
64
+
65
+  // size file was modified -> re-get size
66
+  if (m_fileSize.checkModified()) {
67
+    getSize();
68
+  }
69
+}
70
+
71
+/**
72
+ * @brief set current frame
73
+ * @param[in] stream stream name
74
+ * @param[in] pFrame current frame
75
+ */
76
+void Canvas::Input::setFrame(const std::string &stream, stBlinkenFrame *pFrame)
77
+{
78
+  // prepare frame
79
+  prepareFrame(pFrame);
80
+
81
+  // notify canvas to redraw
82
+  m_canvas.redraw();
83
+
84
+  (void)stream; // unused
85
+}
86
+
87
+/**
88
+ * @brief set current frame to none
89
+ * @param[in] stream stream name
90
+ */
91
+void Canvas::Input::setNoFrame(const std::string &stream)
92
+{
93
+  // throw away prepared frame
94
+  unprepareFrame();
95
+
96
+  // notify canvas to redraw
97
+  m_canvas.redraw();
98
+
99
+  (void)stream; // unused
100
+}
101
+
102
+/**
103
+ * @brief draw current frame to canvas
104
+ * @return if a frame was available and it was drawn
105
+ */
106
+bool Canvas::Input::draw()
107
+{
108
+  // no position, no frame or no canvas -> leave
109
+  if (!m_havePosition || !m_pFrame || !m_canvas.m_pCanvas)
110
+    return false;
111
+
112
+  // draw frame to canvas
113
+  BlinkenFrameCopyRect(m_canvas.m_pCanvas, m_position.m_y, m_position.m_x,
114
+                       m_pFrame, 0, 0,
115
+                       BlinkenFrameGetHeight(m_pFrame),
116
+                       BlinkenFrameGetWidth(m_pFrame));
117
+
118
+  return true;
119
+}
120
+
121
+/// get input stream and attach to it
122
+void Canvas::Input::getInStream()
123
+{
124
+  // get input stream
125
+  m_fileInStream.getStr(m_nameInStream);
126
+  m_pInStream = &m_canvas.m_streamMgr.refStream(m_nameInStream);
127
+
128
+  // attach to input stream
129
+  if (m_pInStream)
130
+    m_pInStream->attach(this);
131
+
132
+  // redrawing canvas will happen automaticall because stream will set frame
133
+}
134
+
135
+/// detach from input stream and release it
136
+void Canvas::Input::releaseInStream()
137
+{
138
+  // get rid of prepared frame
139
+  unprepareFrame();
140
+
141
+  // detach from input stream
142
+  if (m_pInStream)
143
+    m_pInStream->detach(this);
144
+
145
+  // unreference stream
146
+  m_pInStream = NULL;
147
+  m_canvas.m_streamMgr.unrefStream(m_nameInStream);
148
+
149
+  // notify canvas to redraw
150
+  m_canvas.redraw();
151
+}
152
+
153
+/// (re-)get position of stream on canvas
154
+void Canvas::Input::getPosition()
155
+{
156
+  std::string strPos;
157
+
158
+  // read position from position file
159
+  m_havePosition = m_filePosition.getStr(strPos) && m_position.fromStr(strPos);
160
+
161
+  // notify canvas to redraw
162
+  m_canvas.redraw();
163
+}
164
+
165
+/// (re-)get size of stream on canvas
166
+void Canvas::Input::getSize()
167
+{
168
+  std::string strSize;
169
+
170
+  // read size from size file
171
+  m_haveSize = m_fileSize.getStr(strSize) && m_size.fromStr(strSize);
172
+
173
+  // update prepared frame
174
+  updateFrame();
175
+
176
+  // notify canvas to redraw
177
+  m_canvas.redraw();
178
+}
179
+
180
+/// (un-)prepare frame based on current frame of stream
181
+void Canvas::Input::updateFrame()
182
+{
183
+  stBlinkenFrame *pFrame;
184
+
185
+  // get current frame from stream
186
+  if (m_pInStream && m_pInStream->getCurFrame(pFrame)) {
187
+    // got a frame -> prepare it
188
+    prepareFrame(pFrame);
189
+  } else {
190
+    // no frame -> throw away prepared frame
191
+    unprepareFrame();
192
+  }
193
+}
194
+
195
+/**
196
+ * @brief prepare frame (scale it if needed)
197
+ * @param[in] pFrame frame to prepare
198
+ */
199
+void Canvas::Input::prepareFrame(stBlinkenFrame *pFrame)
200
+{
201
+  // throw away old frame
202
+  unprepareFrame();
203
+
204
+  // no scaling needed
205
+  if (!m_haveSize ||
206
+      ((unsigned int)BlinkenFrameGetWidth(pFrame) == m_size.m_width &&
207
+       (unsigned int)BlinkenFrameGetHeight(pFrame) == m_size.m_height)) {
208
+    // just remember pointer
209
+    m_pFrame = pFrame;
210
+  }
211
+  // scaling needed
212
+  else {
213
+    // clone frame and scale it
214
+    m_pFrame = BlinkenFrameClone(pFrame);
215
+    if (m_pFrame) {
216
+      BlinkenFrameScale(m_pFrame, m_size.m_height, m_size.m_width);
217
+      m_ownFrame = true; // frame allocated ourself -> free it later
218
+    }
219
+  }
220
+}
221
+
222
+/// throw away prepared frame
223
+void Canvas::Input::unprepareFrame()
224
+{
225
+  // free frame if it was allocated ourself
226
+  if (m_ownFrame) {
227
+    BlinkenFrameFree(m_pFrame);
228
+    m_ownFrame = false;
229
+  }
230
+
231
+  // no frame any more
232
+  m_pFrame = NULL;
233
+}
234
+
235
+} // namespace Blinker
236
+
... ...
@@ -0,0 +1,111 @@
1
+/* Blinker
2
+   Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#ifndef CANVASINPUT_H
7
+#define CANVASINPUT_H
8
+
9
+#include <string>
10
+
11
+#include <BlinkenLib/BlinkenFrame.h>
12
+
13
+#include "Canvas.h"
14
+#include "Directory.h"
15
+#include "File.h"
16
+#include "Position.h"
17
+#include "SettingFile.h"
18
+#include "Size.h"
19
+#include "StreamMgr.h"
20
+#include "StreamRecv.h"
21
+
22
+namespace Blinker {
23
+
24
+/// input to canvas
25
+class Canvas::Input: public StreamRecv
26
+{
27
+public:
28
+  /**
29
+   * @brief constructor
30
+   * @param[in] canvas owning canvas
31
+   * @param[in] dirBase base directory
32
+   */
33
+  Input(Canvas &canvas, const Directory &dirBase);
34
+
35
+  /// virtual destructor
36
+  virtual ~Input();
37
+
38
+private:
39
+  /// copy constructor disabled
40
+  Input(const Input &that);
41
+
42
+  /// assignment operator disabled
43
+  const Input & operator=(const Input &that);
44
+
45
+public:
46
+  /// check for update of configuration
47
+  void updateConfig();
48
+
49
+  /**
50
+   * @brief set current frame
51
+   * @param[in] stream stream name
52
+   * @param[in] pFrame current frame
53
+   */
54
+  virtual void setFrame(const std::string &stream, stBlinkenFrame *pFrame);
55
+
56
+  /**
57
+   * @brief set current frame to none
58
+   * @param[in] stream stream name
59
+   */
60
+  virtual void setNoFrame(const std::string &stream);
61
+
62
+  /**
63
+   * @brief draw current frame to canvas
64
+   * @return if a frame was available and it was drawn
65
+   */
66
+  bool draw();
67
+
68
+protected:
69
+  /// get input stream and attach to it
70
+  void getInStream();
71
+
72
+  /// detach from input stream and release it
73
+  void releaseInStream();
74
+
75
+  /// (re-)get position of stream on canvas
76
+  void getPosition();
77
+
78
+  /// (re-)get size of stream on canvas
79
+  void getSize();
80
+
81
+  /// (un-)prepare frame based on current frame of stream
82
+  void updateFrame();
83
+
84
+  /**
85
+   * @brief prepare frame (scale it if needed)
86
+   * @param[in] pFrame frame to prepare
87
+   */
88
+  void prepareFrame(stBlinkenFrame *pFrame);
89
+
90
+  /// throw away prepared frame
91
+  void unprepareFrame();
92
+
93
+protected:
94
+  Canvas         &m_canvas;      ///< owning canvas
95
+  SettingFile    m_fileInStream; ///< input stream name file
96
+  SettingFile    m_filePosition; ///< position file
97
+  SettingFile    m_fileSize;     ///< size file
98
+  std::string    m_nameInStream; ///< name of input stream
99
+  bool           m_havePosition; ///< if position of stream on canvas is defined
100
+  Position       m_position;     ///< position of stream on canvas
101
+  bool           m_haveSize;     ///< if size of stream on canvas is defined
102
+  Size           m_size;         ///< size of stream on canvas
103
+  Stream         *m_pInStream;   ///< input stream
104
+  bool           m_ownFrame;     ///< if the frame was allocated ourself
105
+  stBlinkenFrame *m_pFrame;      ///< frame to draw (already scaled to size)
106
+}; // class Canvas::Input
107
+
108
+} // namespace Blinker
109
+
110
+#endif // #ifndef CANVASINPUT_H
111
+
... ...
@@ -2,6 +2,7 @@
2 2
 #include <string>
3 3
 
4 4
 #include "CallMgr.h"
5
+#include "Canvas.h"
5 6
 #include "Directory.h"
6 7
 #include "ModuleMgr.h"
7 8
 #include "Player.h"
... ...
@@ -18,6 +19,8 @@ void run(const std::string &dirConfig)
18 19
   CallMgr callMgr;
19 20
   StreamMgr streamMgr;
20 21
 
22
+  ModuleMgr<Canvas> canvasMgr(callMgr, streamMgr,
23
+                              dirCfg.getSubdir("canvases"));
21 24
   ModuleMgr<Player> playerMgr(callMgr, streamMgr,
22 25
                               dirCfg.getSubdir("players"));
23 26
   ModuleMgr<Printer> printerMgr(callMgr, streamMgr,
24 27