]> git.vomp.tv Git - vompclient.git/blob - surfacevector.cc
Replace TVMedia & OsdVector refcounting with new Image system
[vompclient.git] / surfacevector.cc
1 /*
2     Copyright 2012 Marten Richter
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <wchar.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include "bitmap.h"
24 #include "staticartwork.h"
25 #include "imageloader.h"
26
27 #include "surfacevector.h"
28
29 const static char* TAG = "SurfaceVector";
30
31 SurfaceVector::SurfaceVector(OsdVector* vosd)
32 {
33   logger = LogNT::getInstance();
34   osd = vosd;
35   imageLoader = ImageLoader::getInstance();
36   commands.reserve(2048);
37 }
38
39 SurfaceVector::~SurfaceVector()
40 {
41   osd->removeSurface(this);
42
43   for (SVGCommand& command : commands)
44   {
45     osd->decrementDrawStyleHandleRefCount(command.getHandle()); // We remove the Style reference, so that osd can free stuff // FIXME BUG BUG BUG
46
47     VectorHandleImage handle = command.getImageHandle();
48     if (handle) osd->removeImageRef(handle);
49   }
50 }
51
52 int SurfaceVector::getFontHeight()
53 {
54   return (int)osd->getFontHeight();
55 }
56
57 float SurfaceVector::getCharWidth(wchar_t c)
58 {
59   return osd->getCharWidth(c);
60 }
61
62 /*
63  * By current design it's not permitted to have a surface without the first drawing being to
64  * fill with a background colour. The fillblt calls removeCommands which deletes all the old
65  * commands before the background colour becomes the new first command, then all the rest are
66  * redrawn on top. If you want to change this in future then do this as the first thing in
67  * Boxx::draw():
68  *   surface->clear();
69  * and have this function in here:
70  *   void SurfaceVector::clear()
71  *   {
72  *     removeCommands(0, 0, swidth, sheight);
73  *   }
74  * Or preferably a simpler one that doesn't do all the comparison work.
75 */
76
77 int SurfaceVector::drawText(const char* text, int x, int y, const DrawStyle& c)
78 {
79   return drawText(text, x, y, 0, c);
80 }
81
82 int SurfaceVector::drawText(const char* text, int x, int y, int width, const DrawStyle& c)
83 {
84   float shift = 0.;
85   const char* run = text;
86   size_t length = strlen(text);
87
88
89   command_mutex.lock();
90
91   VectorHandle ref;
92   float* charwidtharray = osd->getCharWidthArray();
93   int commands_size = commands.size();
94   int chars = 0;
95   commands.resize(commands_size + strlen(text));
96 #ifndef WIN32
97   mbstate_t state;
98   wchar_t tempo;
99   size_t num_bytes = 1;
100   memset((void*)&state, 0, sizeof(state));
101   num_bytes = mbrtowc(&tempo, run, length, &state);
102
103   while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
104   {
105     ref = osd->getDrawStyleHandle(c); // Need to call this each time to have OSD get the ref count right. Maybe expose incRefCount sometime
106     SVGCommand::PaintGlyph(commands[commands_size + chars], x + shift, y, tempo, ref);
107     chars++;
108
109     float cur_shift = charwidtharray[tempo & 0xFF];
110
111     if (tempo && 0xFFFFFF00) cur_shift = osd->getCharWidth(tempo);
112
113     shift += cur_shift;
114     length -= num_bytes;
115     run += num_bytes;
116
117     if (shift > width && width > 0)
118     {
119       command_mutex.unlock();
120       return 1;
121     }
122
123     num_bytes = mbrtowc(&tempo, run, length, &state);
124   }
125
126 #else
127   wchar_t* temptext = new wchar_t[length + 1];
128   int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
129                                         temptext, length + 1) - 1;
130
131   for (int i = 0; i < real_length; i++)
132   {
133     ref = osd->getDrawStyleHandle(c); // Need to call this each time to have OSD get the ref count right. Maybe expose incRefCount sometime
134     SVGCommand::PaintGlyph(commands[commands_size + chars], x + shift, y, temptext[i], ref);
135     chars++;
136
137     float cur_shift = charwidtharray[temptext[i] & 0xFF];
138
139     if (temptext[i] && 0xFFFFFF00) cur_shift = osd->getCharWidth(temptext[i]);
140
141     shift += cur_shift;
142   }
143
144   delete[] temptext;
145 #endif
146
147   commands.resize(commands_size + chars);
148   command_mutex.unlock();
149   return 1;
150
151 }
152 int SurfaceVector::drawTextRJ(const char* text, int x, int y, const DrawStyle& c)
153 {
154   float shift = 0.;
155   const char* run = text;
156   size_t length = strlen(text);
157
158 #ifndef WIN32
159   mbstate_t state;
160   wchar_t tempo[1];
161   size_t num_bytes = 1;
162   memset((void*)&state, 0, sizeof(state));
163   num_bytes = mbrtowc(tempo, run, length, &state);
164
165   while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
166   {
167     shift += osd->getCharWidth(*tempo);
168     length -= num_bytes;
169     run += num_bytes;
170     num_bytes = mbrtowc(tempo, run, length, &state);
171   }
172
173 #else
174   wchar_t* temptext = new wchar_t[length + 1];
175   int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
176                                         temptext, length + 1) - 1;
177
178   for (int i = 0; i < real_length; i++)
179   {
180     shift += osd->getCharWidth(temptext[i]);
181   }
182
183   delete[] temptext;
184 #endif
185   return drawText(text, (int)(x - shift), y, c);
186 }
187
188 int SurfaceVector::drawTextCentre(const char* text, int x, int y, const DrawStyle& c)
189 {
190   float shift = 0;
191   const char* run = text;
192   size_t length = strlen(text);
193
194 #ifndef WIN32
195   mbstate_t state;
196   wchar_t tempo[1];
197   size_t num_bytes = 1;
198   memset((void*)&state, 0, sizeof(state));
199   num_bytes = mbrtowc(tempo, run, length, &state);
200
201   while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
202   {
203     shift += osd->getCharWidth(*tempo);
204     length -= num_bytes;
205     run += num_bytes;
206     num_bytes = mbrtowc(tempo, run, length, &state);
207   }
208
209 #else
210   wchar_t* temptext = new wchar_t[length + 1];
211   int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
212                                         temptext, length + 1) - 1;
213
214   for (int i = 0; i < real_length; i++)
215   {
216     shift += osd->getCharWidth(temptext[i]);
217   }
218
219   delete[] temptext;
220 #endif
221
222   return drawText(text, (int)(x - shift / 2.),  y, c);
223 }
224
225 void SurfaceVector::drawJpeg(const char* fileName, int x, int y, int* width, int* height)
226 {
227   StaticArtwork index = sa_MAX; // This is for compatibility only
228
229   if (strcmp(fileName, "/vdr.jpg") == 0)
230   {
231     index = sa_vdrlogo;
232     *height = 100; // this is faked so that the system does use the old coordinate system
233     *width = (int)ceil(190.f * osd->getPixelAspect());
234   }
235   else if (strcmp(fileName, "/wallpaperPAL.jpg") == 0)
236   {
237     index = sa_wallpaper;
238     *width = 720; // this is faked so that the system does use the old coordinate system
239     *height = 576;
240   }
241
242   if (index != sa_MAX)
243   {
244     ImageStatic image = imageLoader->createStatic(index);
245     Image toDraw = image;
246     drawImage(toDraw, x, y, *width, *height, TopLeft);
247   }
248 }
249
250 /*
251 void SurfaceVector::drawJpeg(const char *fileName,int x, int y,int *width, int *height)
252 {
253         command_mutex.lock();
254         VectorHandleImage handle=osd->getJpegRef(fileName,width,height);
255         commands.push_back(SVGCommand::PaintImage(x,y,*width,*height,image));
256         command_mutex.unlock();
257 }
258 */
259
260 void SurfaceVector::drawImage(Image& image, float x, float y, float  width, float height, Corner corner)
261 {
262   command_mutex.lock();
263
264   if (width != 0 && height != 0)
265   {
266     removeCommands(x, y, width, height);
267   }
268
269   if (image->isReady())
270   {
271     logger->trace(TAG, "drawImage: READY, Add instr PaintImage for {}", static_cast<void*>(image.get()));
272     commands.push_back(SVGCommand::PaintImage(x, y, width, height, image, corner));
273   }
274   else
275   {
276     logger->trace(TAG, "drawImage: NOT_READY, Add instr PaintImageLoading {} LI {}", static_cast<void*>(image.get()), reinterpret_cast<void*>(image.get()));
277     commands.push_back(SVGCommand::PaintImageLoading(image, x, y, width, height, corner));
278   }
279
280   command_mutex.unlock();
281 }
282
283 void SurfaceVector::drawClippingRectangle(float x, float y, float w, float h)
284 {
285   command_mutex.lock();
286   commands.push_back(SVGCommand::PaintClipping((float)x, (float)y, (float)w, (float)h));
287   command_mutex.unlock();
288 }
289
290 int SurfaceVector::create(UINT width, UINT height)
291 {
292   sheight = height;
293   swidth = width;
294   return 1;
295 }
296 void SurfaceVector::display()
297 {
298   //nothing this is really mvp specific  // FIXME remove? -- yes, only surfacedirectfb has some commented out code in display()
299 }
300
301 int SurfaceVector::fillblt(int x, int y, int width, int height, const DrawStyle& c)
302 {
303   command_mutex.lock();
304   removeCommands(x, y, width, height); // remove commands below the box
305   VectorHandle ref = osd->getDrawStyleHandle(c);
306   commands.push_back(SVGCommand::PaintPath(x, y, width, height, PIRectangle, ref));
307   command_mutex.unlock();
308   return 1;
309
310 }
311 void SurfaceVector::drawHorzLine(int x1, int x2, int y, const DrawStyle& c)
312 {
313   command_mutex.lock();
314   VectorHandle ref = osd->getDrawStyleHandle(c);
315   commands.push_back(SVGCommand::PaintPath(x1, y, x2 - x1, 1, PIHorzLine, ref));
316   command_mutex.unlock();
317 }
318
319 void SurfaceVector::drawVertLine(int x, int y1, int y2, const DrawStyle& c)
320 {
321   command_mutex.lock();
322   VectorHandle ref = osd->getDrawStyleHandle(c);
323   commands.push_back(SVGCommand::PaintPath(x, y1, 1, y2 - y1, PIVertLine, ref));
324   command_mutex.unlock();
325 }
326
327 void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm, const DisplayRegion& region)
328 {
329   //this is complicated
330   command_mutex.lock();
331   /*
332         unsigned int * data=(unsigned int*)malloc(sizeof(unsigned int)*bm.getWidth()*bm.getHeight());
333         for (UINT j = 0; j < bm.getHeight(); ++j){
334            for (UINT i = 0; i < bm.getWidth(); ++i)
335            {
336                    data[i+j*bm.getHeight()]=bm.getColour(i,j);
337            }
338       }*/
339   VectorHandleImage handle = osd->getImagePalette(bm.getWidth(), bm.getHeight(), &(bm.rawData()[0]),
340                                           (const unsigned int*)&bm.palette.getColourVector()[0]); // data is freed by the OSD
341   //free(data);
342   float tx = x + region.windowx;
343   float ty = y + region.windowy;
344   float th = bm.getHeight();
345   float tw = bm.getWidth();
346
347   float scalex = 720.f / ((float) (region.framewidth + 1));
348   float scaley = 576.f / ((float) (region.frameheight + 1));
349   tx *= scalex;
350   ty *= scaley;
351   tw *= scalex;
352   th *= scaley;
353   SVGCommand temp = SVGCommand::PaintBitmap(tx, ty, tw, th, handle, 0);
354   removeCommands(tx, ty, tw, th);
355   commands.push_back(temp);
356   command_mutex.unlock();
357 }
358
359 void SurfaceVector::drawPoint(int x, int y, const DrawStyle& c, bool fastdraw)
360 {
361   if (!fastdraw) command_mutex.lock();
362
363   VectorHandle ref = osd->getDrawStyleHandle(c);
364   commands.push_back(SVGCommand::PaintPath(x, y, 1, 1, PIPoint, ref));
365
366   if (!fastdraw)  command_mutex.unlock();
367 }
368
369 void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height, unsigned int width, const DrawStyle& nextColour)
370 {
371   command_mutex.lock();
372   VectorHandleImage handle = osd->getMonoBitmapRef(base, width, height);
373   VectorHandle ref = osd->getDrawStyleHandle(nextColour);
374   removeCommands(dx, dy, width, height);
375   commands.push_back(SVGCommand::PaintBitmap(dx, dy, height, width, handle, ref)); // FIXME BUG height and width wrong way around?
376   command_mutex.unlock();
377 }
378
379 int SurfaceVector::removeCommands(float x, float y, float width, float height)
380 {
381   // we iterate through all old commands in order to remove commands hidden by this rectangle
382   std::vector<SVGCommand>::iterator itty = commands.begin();
383   std::vector<SVGCommand>::iterator remstart;
384   bool remove = false;
385   float cx, cy, cw, ch;
386   cx = cy = 0.f;
387   cw = swidth;
388   ch = sheight;
389   bool clipping_erases = false;
390
391   while (itty != commands.end())
392   {
393     if ((clipping_erases // test if clipping helps
394          || (*itty).Test(x, y, width, height)  )
395         && (*itty).instr != DrawClipping)
396     {
397       //Log::getInstance()->log("OSD", Log::DEBUG, "Remove command %d %g %g %g %g %d %d",(*itty).instr,
398       //(*itty).x,(*itty).y,(*itty).w,(*itty).h,(*itty).handle,(*itty).target.image);
399       osd->decrementDrawStyleHandleRefCount((*itty).getHandle()); // We remove the Style reference, so that osd can free stuff // FIXME BUG BUG BUG
400
401       VectorHandleImage handle = (*itty).getImageHandle();
402       if (handle) osd->removeImageRef(handle);
403
404       if (!remove)
405       {
406         remstart = itty;
407         remove = true;
408       }
409     }
410     else
411     {
412       if ((*itty).instr == DrawClipping)
413       {
414         if ((*itty).w == 0.f && (*itty).h == 0.f)
415         {
416           cx = cy = 0.f;
417           cw = swidth;
418           ch = sheight;
419
420         }
421         else
422         {
423           cx = (*itty).x;
424           cy = (*itty).y;
425           cw = (*itty).w;
426           ch = (*itty).h;
427         }
428
429         clipping_erases = (cx >= x) && (cy >= y) && ((cx + cw) <= (x + width)) && ((cy + ch) <= (y + height));
430       }
431
432       if (remove)
433       {
434         itty = commands.erase(remstart, itty);
435         remove = false;
436       }
437     }
438
439     itty++;
440   }
441
442   if (remove)
443   {
444     itty = commands.erase(remstart, itty);
445   }
446
447   return 1;
448
449 }
450
451 int SurfaceVector::updateToScreen(int sx, int sy, int w, int h, int dx, int dy)
452 {
453   // ok this method really works in a pixel oriented way
454   command_mutex.lock();
455   osd->updateOrAddSurface(this, dx - sx, dy - sy, swidth, sheight, commands);
456   command_mutex.unlock();
457   return 1;
458 }
459
460
461 /* This is for systems which need a locking of the drawing surface to speed up drawing */
462 void SurfaceVector::startFastDraw()
463 {
464   command_mutex.lock();
465 }
466 void SurfaceVector::endFastDraw()
467 {
468   command_mutex.unlock();
469 }
470
471
472 void SurfaceVector::drawTTChar(int ox, int oy, int x, int y, cTeletextChar c)
473 {
474   command_mutex.lock();
475   std::vector<SVGCommand>::iterator itty = commands.begin();
476
477   while (itty != commands.end())
478   {
479     if ((*itty).TTTest(ox, oy, x, y) )
480     {
481       itty = commands.erase(itty);
482       break;
483     }
484     else
485     {
486       itty++;
487     }
488   }
489
490   commands.push_back(SVGCommand::PaintTTchar(ox, oy, x, y, c.getInternal()));
491   command_mutex.unlock();
492 }