2 Copyright 2012 Marten Richter
4 This file is part of VOMP.
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.
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.
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/>.
24 #include "staticartwork.h"
25 #include "surfacevector.h"
27 const static char* TAG = "SurfaceVector";
29 SurfaceVector::SurfaceVector(OsdVector* vosd)
31 logger = LogNT::getInstance();
33 commands.reserve(2048);
36 SurfaceVector::~SurfaceVector()
39 osd->removeSurface(this);
41 for (SVGCommand& command : commands)
43 osd->decrementDrawStyleHandleRefCount(command.getHandle()); // We remove the Style reference, so that osd can free stuff // FIXME BUG BUG BUG
45 VectorHandleImage handle = command.getImageHandle();
46 if (handle) osd->removeImageRef(handle);
48 LoadingIndex li = command.getLoadingIndex();
49 if (li) osd->removeLoadingIndexRef(li);
53 int SurfaceVector::getFontHeight()
55 return (int)osd->getFontHeight();
58 float SurfaceVector::getCharWidth(wchar_t c)
60 return osd->getCharWidth(c);
64 * By current design it's not permitted to have a surface without the first drawing being to
65 * fill with a background colour. The fillblt calls removeCommands which deletes all the old
66 * commands before the background colour becomes the new first command, then all the rest are
67 * redrawn on top. If you want to change this in future then do this as the first thing in
70 * and have this function in here:
71 * void SurfaceVector::clear()
73 * removeCommands(0, 0, swidth, sheight);
75 * Or preferably a simpler one that doesn't do all the comparison work.
78 int SurfaceVector::drawText(const char* text, int x, int y, const DrawStyle& c)
80 return drawText(text, x, y, 0, c);
83 int SurfaceVector::drawText(const char* text, int x, int y, int width, const DrawStyle& c)
86 const char* run = text;
87 size_t length = strlen(text);
93 float* charwidtharray = osd->getCharWidthArray();
94 int commands_size = commands.size();
96 commands.resize(commands_size + strlen(text));
100 size_t num_bytes = 1;
101 memset((void*)&state, 0, sizeof(state));
102 num_bytes = mbrtowc(&tempo, run, length, &state);
104 while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
106 ref = osd->getDrawStyleHandle(c); // Need to call this each time to have OSD get the ref count right. Maybe expose incRefCount sometime
107 SVGCommand::PaintGlyph(commands[commands_size + chars], x + shift, y, tempo, ref);
110 float cur_shift = charwidtharray[tempo & 0xFF];
112 if (tempo && 0xFFFFFF00) cur_shift = osd->getCharWidth(tempo);
118 if (shift > width && width > 0)
120 command_mutex.unlock();
124 num_bytes = mbrtowc(&tempo, run, length, &state);
128 wchar_t* temptext = new wchar_t[length + 1];
129 int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
130 temptext, length + 1) - 1;
132 for (int i = 0; i < real_length; i++)
134 ref = osd->getDrawStyleHandle(c); // Need to call this each time to have OSD get the ref count right. Maybe expose incRefCount sometime
135 SVGCommand::PaintGlyph(commands[commands_size + chars], x + shift, y, temptext[i], ref);
138 float cur_shift = charwidtharray[temptext[i] & 0xFF];
140 if (temptext[i] && 0xFFFFFF00) cur_shift = osd->getCharWidth(temptext[i]);
148 commands.resize(commands_size + chars);
149 command_mutex.unlock();
153 int SurfaceVector::drawTextRJ(const char* text, int x, int y, const DrawStyle& c)
156 const char* run = text;
157 size_t length = strlen(text);
162 size_t num_bytes = 1;
163 memset((void*)&state, 0, sizeof(state));
164 num_bytes = mbrtowc(tempo, run, length, &state);
166 while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
168 shift += osd->getCharWidth(*tempo);
171 num_bytes = mbrtowc(tempo, run, length, &state);
175 wchar_t* temptext = new wchar_t[length + 1];
176 int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
177 temptext, length + 1) - 1;
179 for (int i = 0; i < real_length; i++)
181 shift += osd->getCharWidth(temptext[i]);
186 return drawText(text, (int)(x - shift), y, c);
189 int SurfaceVector::drawTextCentre(const char* text, int x, int y, const DrawStyle& c)
192 const char* run = text;
193 size_t length = strlen(text);
198 size_t num_bytes = 1;
199 memset((void*)&state, 0, sizeof(state));
200 num_bytes = mbrtowc(tempo, run, length, &state);
202 while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
204 shift += osd->getCharWidth(*tempo);
207 num_bytes = mbrtowc(tempo, run, length, &state);
211 wchar_t* temptext = new wchar_t[length + 1];
212 int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
213 temptext, length + 1) - 1;
215 for (int i = 0; i < real_length; i++)
217 shift += osd->getCharWidth(temptext[i]);
223 return drawText(text, (int)(x - shift / 2.), y, c);
226 void SurfaceVector::drawJpeg(const char* fileName, int x, int y, int* width, int* height)
228 StaticArtwork index = sa_MAX; // This is for compatibility only
230 if (strcmp(fileName, "/vdr.jpg") == 0)
233 *height = 100; // this is faked so that the system does use the old coordinate system
234 *width = (int)ceil(190.f * osd->getPixelAspect());
236 else if (strcmp(fileName, "/wallpaperPAL.jpg") == 0)
238 index = sa_wallpaper;
239 *width = 720; // this is faked so that the system does use the old coordinate system
246 info.setStaticArtwork(index);
247 drawTVMedia(info, x, y, *width, *height, TopLeft);
252 void SurfaceVector::drawJpeg(const char *fileName,int x, int y,int *width, int *height)
254 command_mutex.lock();
255 VectorHandleImage handle=osd->getJpegRef(fileName,width,height);
256 commands.push_back(SVGCommand::PaintImage(x,y,*width,*height,handle,0));
257 command_mutex.unlock();
261 void SurfaceVector::drawTVMedia(TVMediaInfo& tvmedia, float x, float y, float width, float height, Corner corner)
263 command_mutex.lock();
264 VectorHandleImage handle = 0;
265 LoadingIndex load_index = osd->getTVMediaRef(tvmedia, handle); // This is where you can get a cache hit
268 if (width != 0 && height != 0)
270 removeCommands(x, y, width, height);
275 logger->trace(TAG, "drawTVMedia: i=true, Add instr PaintImage load_index={} handle={}", load_index, handle);
276 commands.push_back(SVGCommand::PaintImage(x, y, width, height, handle, 0, corner));
280 logger->trace(TAG, "drawTVMedia: i=false, Add instr PaintImageLoading {} {}", load_index, handle);
281 commands.push_back(SVGCommand::PaintImageLoading(load_index, x, y, width, height, corner));
284 command_mutex.unlock();
287 void SurfaceVector::drawClippingRectangle(float x, float y, float w, float h)
289 command_mutex.lock();
290 commands.push_back(SVGCommand::PaintClipping((float)x, (float)y, (float)w, (float)h));
291 command_mutex.unlock();
294 int SurfaceVector::create(UINT width, UINT height)
300 void SurfaceVector::display()
302 //nothing this is really mvp specific // FIXME remove?
305 int SurfaceVector::fillblt(int x, int y, int width, int height, const DrawStyle& c)
307 command_mutex.lock();
308 removeCommands(x, y, width, height); // remove commands below the box
309 VectorHandle ref = osd->getDrawStyleHandle(c);
310 commands.push_back(SVGCommand::PaintPath(x, y, width, height, PIRectangle, ref));
311 command_mutex.unlock();
315 void SurfaceVector::drawHorzLine(int x1, int x2, int y, const DrawStyle& c)
317 command_mutex.lock();
318 VectorHandle ref = osd->getDrawStyleHandle(c);
319 commands.push_back(SVGCommand::PaintPath(x1, y, x2 - x1, 1, PIHorzLine, ref));
320 command_mutex.unlock();
323 void SurfaceVector::drawVertLine(int x, int y1, int y2, const DrawStyle& c)
325 command_mutex.lock();
326 VectorHandle ref = osd->getDrawStyleHandle(c);
327 commands.push_back(SVGCommand::PaintPath(x, y1, 1, y2 - y1, PIVertLine, ref));
328 command_mutex.unlock();
331 void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm, const DisplayRegion& region)
333 //this is complicated
334 command_mutex.lock();
336 unsigned int * data=(unsigned int*)malloc(sizeof(unsigned int)*bm.getWidth()*bm.getHeight());
337 for (UINT j = 0; j < bm.getHeight(); ++j){
338 for (UINT i = 0; i < bm.getWidth(); ++i)
340 data[i+j*bm.getHeight()]=bm.getColour(i,j);
343 VectorHandleImage handle = osd->getImagePalette(bm.getWidth(), bm.getHeight(), &(bm.rawData()[0]),
344 (const unsigned int*)&bm.palette.getColourVector()[0]); // data is freed by the OSD
346 float tx = x + region.windowx;
347 float ty = y + region.windowy;
348 float th = bm.getHeight();
349 float tw = bm.getWidth();
351 float scalex = 720.f / ((float) (region.framewidth + 1));
352 float scaley = 576.f / ((float) (region.frameheight + 1));
357 SVGCommand temp = SVGCommand::PaintImage(tx, ty, tw, th, handle, 0);
358 removeCommands(tx, ty, tw, th);
359 commands.push_back(temp);
360 command_mutex.unlock();
363 void SurfaceVector::drawPoint(int x, int y, const DrawStyle& c, bool fastdraw)
365 if (!fastdraw) command_mutex.lock();
367 VectorHandle ref = osd->getDrawStyleHandle(c);
368 commands.push_back(SVGCommand::PaintPath(x, y, 1, 1, PIPoint, ref));
370 if (!fastdraw) command_mutex.unlock();
373 void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height, unsigned int width, const DrawStyle& nextColour)
375 command_mutex.lock();
376 VectorHandleImage handle = osd->getMonoBitmapRef(base, width, height);
377 VectorHandle ref = osd->getDrawStyleHandle(nextColour);
378 removeCommands(dx, dy, width, height);
379 commands.push_back(SVGCommand::PaintImage(dx, dy, height, width, handle, ref)); // FIXME BUG height and width wrong way around?
380 command_mutex.unlock();
383 int SurfaceVector::removeCommands(float x, float y, float width, float height)
385 // we iterate through all old commands in order to remove commands hidden by this rectangle
386 std::vector<SVGCommand>::iterator itty = commands.begin();
387 std::vector<SVGCommand>::iterator remstart;
389 float cx, cy, cw, ch;
393 bool clipping_erases = false;
395 while (itty != commands.end())
397 if ((clipping_erases // test if clipping helps
398 || (*itty).Test(x, y, width, height) )
399 && (*itty).instr != DrawClipping)
401 //Log::getInstance()->log("OSD", Log::DEBUG, "Remove command %d %g %g %g %g %d %d",(*itty).instr,
402 //(*itty).x,(*itty).y,(*itty).w,(*itty).h,(*itty).handle,(*itty).target.image);
403 osd->decrementDrawStyleHandleRefCount((*itty).getHandle()); // We remove the Style reference, so that osd can free stuff // FIXME BUG BUG BUG
404 VectorHandleImage handle = (*itty).getImageHandle();
406 if (handle) osd->removeImageRef(handle);
408 LoadingIndex li = (*itty).getLoadingIndex();
410 if (li) osd->removeLoadingIndexRef(li);
420 if ((*itty).instr == DrawClipping)
422 if ((*itty).w == 0.f && (*itty).h == 0.f)
437 clipping_erases = (cx >= x) && (cy >= y) && ((cx + cw) <= (x + width)) && ((cy + ch) <= (y + height));
442 itty = commands.erase(remstart, itty);
452 itty = commands.erase(remstart, itty);
459 int SurfaceVector::updateToScreen(int sx, int sy, int w, int h, int dx, int dy)
461 // ok this method really works in a pixel oriented way
462 command_mutex.lock();
463 osd->updateOrAddSurface(this, dx - sx, dy - sy, swidth, sheight, commands);
464 command_mutex.unlock();
469 /* This is for systems which need a locking of the drawing surface to speed up drawing */
470 void SurfaceVector::startFastDraw()
472 command_mutex.lock();
474 void SurfaceVector::endFastDraw()
476 command_mutex.unlock();
480 void SurfaceVector::drawTTChar(int ox, int oy, int x, int y, cTeletextChar c)
482 command_mutex.lock();
483 std::vector<SVGCommand>::iterator itty = commands.begin();
485 while (itty != commands.end())
487 if ((*itty).TTTest(ox, oy, x, y) )
489 itty = commands.erase(itty);
498 commands.push_back(SVGCommand::PaintTTchar(ox, oy, x, y, c.getInternal()));
499 command_mutex.unlock();