Merge pull request #4314 from MartijnKaijser/beta1
[vuplus_xbmc] / xbmc / cores / VideoRenderers / OverlayRenderer.cpp
1 /*
2  *      Initial code sponsored by: Voddler Inc (voddler.com)
3  *      Copyright (C) 2005-2013 Team XBMC
4  *      http://xbmc.org
5  *
6  *  This Program 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, or (at your option)
9  *  any later version.
10  *
11  *  This Program 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 XBMC; see the file COPYING.  If not, see
18  *  <http://www.gnu.org/licenses/>.
19  *
20  */
21
22 #include "system.h"
23 #include "OverlayRenderer.h"
24 #include "cores/dvdplayer/DVDCodecs/Overlay/DVDOverlay.h"
25 #include "cores/dvdplayer/DVDCodecs/Overlay/DVDOverlayImage.h"
26 #include "cores/dvdplayer/DVDCodecs/Overlay/DVDOverlaySpu.h"
27 #include "cores/dvdplayer/DVDCodecs/Overlay/DVDOverlaySSA.h"
28 #include "cores/VideoRenderers/RenderManager.h"
29 #include "guilib/GraphicContext.h"
30 #include "Application.h"
31 #include "guilib/GraphicContext.h"
32 #include "windowing/WindowingFactory.h"
33 #include "settings/DisplaySettings.h"
34 #include "settings/Settings.h"
35 #include "settings/DisplaySettings.h"
36 #include "threads/SingleLock.h"
37 #include "utils/MathUtils.h"
38 #include "OverlayRendererUtil.h"
39 #include "OverlayRendererGUI.h"
40 #if defined(HAS_GL) || defined(HAS_GLES)
41 #include "OverlayRendererGL.h"
42 #elif defined(HAS_DX)
43 #include "OverlayRendererDX.h"
44 #endif
45
46 using namespace OVERLAY;
47
48
49 COverlay::COverlay()
50 {
51   m_x      = 0.0f;
52   m_y      = 0.0f;
53   m_width  = 0.0;
54   m_height = 0.0;
55   m_type   = TYPE_NONE;
56   m_align  = ALIGN_SCREEN;
57   m_pos    = POSITION_RELATIVE;
58   m_references = 1;
59 }
60
61 COverlay::~COverlay()
62 {
63 }
64
65 COverlay* COverlay::Acquire()
66 {
67   AtomicIncrement(&m_references);
68   return this;
69 }
70
71 long COverlay::Release()
72 {
73   long count = AtomicDecrement(&m_references);
74   if (count == 0)
75     delete this;
76
77   return count;
78 }
79
80 long COverlayMainThread::Release()
81 {
82   long count = AtomicDecrement(&m_references);
83   if (count == 0)
84   {
85     if (g_application.IsCurrentThread())
86       delete this;
87     else
88       g_renderManager.AddCleanup(this);
89   }
90   return count;
91 }
92
93
94 CRenderer::CRenderer()
95 {
96 }
97
98 CRenderer::~CRenderer()
99 {
100   for(int i = 0; i < NUM_BUFFERS; i++)
101     Release(m_buffers[i]);
102 }
103
104 void CRenderer::AddOverlay(CDVDOverlay* o, double pts, int index)
105 {
106   CSingleLock lock(m_section);
107
108   SElement   e;
109   e.pts = pts;
110   e.overlay_dvd = o->Acquire();
111   m_buffers[index].push_back(e);
112 }
113
114 void CRenderer::AddOverlay(COverlay* o, double pts, int index)
115 {
116   CSingleLock lock(m_section);
117
118   SElement   e;
119   e.pts = pts;
120   e.overlay = o->Acquire();
121   m_buffers[index].push_back(e);
122 }
123
124 void CRenderer::AddCleanup(COverlay* o)
125 {
126   CSingleLock lock(m_section);
127   m_cleanup.push_back(o->Acquire());
128 }
129
130 void CRenderer::Release(SElementV& list)
131 {
132   SElementV l = list;
133   list.clear();
134
135   for(SElementV::iterator it = l.begin(); it != l.end(); ++it)
136   {
137     if(it->overlay)
138       it->overlay->Release();
139     if(it->overlay_dvd)
140       it->overlay_dvd->Release();
141   }
142 }
143
144 void CRenderer::Release(COverlayV& list)
145 {
146   COverlayV l = list;
147   list.clear();
148
149   for(COverlayV::iterator it = l.begin(); it != l.end(); ++it)
150     (*it)->Release();
151 }
152
153 void CRenderer::Flush()
154 {
155   CSingleLock lock(m_section);
156
157   for(int i = 0; i < NUM_BUFFERS; i++)
158     Release(m_buffers[i]);
159
160   Release(m_cleanup);
161 }
162
163 void CRenderer::Release(int idx)
164 {
165   CSingleLock lock(m_section);
166   Release(m_buffers[idx]);
167 }
168
169 void CRenderer::Render(int idx)
170 {
171   CSingleLock lock(m_section);
172
173   Release(m_cleanup);
174
175   SElementV& list = m_buffers[idx];
176   for(SElementV::iterator it = list.begin(); it != list.end(); ++it)
177   {
178     COverlay* o = NULL;
179
180     if(it->overlay)
181       o = it->overlay->Acquire();
182     else if(it->overlay_dvd)
183       o = Convert(it->overlay_dvd, it->pts);
184
185     if(!o)
186       continue;
187
188     Render(o);
189
190     o->Release();
191   }
192 }
193
194 void CRenderer::Render(COverlay* o)
195 {
196   CRect rs, rd, rv;
197   RESOLUTION_INFO res;
198   g_renderManager.GetVideoRect(rs, rd);
199   rv  = g_graphicsContext.GetViewWindow();
200   res = g_graphicsContext.GetResInfo(g_renderManager.GetResolution());
201
202   SRenderState state;
203   state.x       = o->m_x;
204   state.y       = o->m_y;
205   state.width   = o->m_width;
206   state.height  = o->m_height;
207
208   COverlay::EPosition pos   = o->m_pos;
209   COverlay::EAlign    align = o->m_align;
210
211   if(pos == COverlay::POSITION_RELATIVE)
212   {
213     float scale_x = 1.0;
214     float scale_y = 1.0;
215
216     if(align == COverlay::ALIGN_SCREEN
217     || align == COverlay::ALIGN_SUBTITLE)
218     {
219       scale_x = (float)res.iWidth;
220       scale_y = (float)res.iHeight;
221     }
222
223     if(align == COverlay::ALIGN_VIDEO)
224     {
225       scale_x = rs.Width();
226       scale_y = rs.Height();
227     }
228
229     state.x      *= scale_x;
230     state.y      *= scale_y;
231     state.width  *= scale_x;
232     state.height *= scale_y;
233
234     pos = COverlay::POSITION_ABSOLUTE;
235   }
236
237   if(pos == COverlay::POSITION_ABSOLUTE)
238   {
239     if(align == COverlay::ALIGN_SCREEN
240     || align == COverlay::ALIGN_SUBTITLE)
241     {
242       float scale_x = rv.Width() / res.iWidth;
243       float scale_y = rv.Height()  / res.iHeight;
244
245       state.x      *= scale_x;
246       state.y      *= scale_y;
247       state.width  *= scale_x;
248       state.height *= scale_y;
249
250       if(align == COverlay::ALIGN_SUBTITLE)
251       {
252         state.x += rv.x1 + rv.Width() * 0.5f;
253         state.y += rv.y1  + (res.iSubtitles - res.Overscan.top) * scale_y;
254       }
255       else
256       {
257         state.x += rv.x1;
258         state.y += rv.y1;
259       }
260     }
261
262     if(align == COverlay::ALIGN_VIDEO)
263     {
264       float scale_x = rd.Width() / rs.Width();
265       float scale_y = rd.Height() / rs.Height();
266
267       state.x      *= scale_x;
268       state.y      *= scale_y;
269       state.width  *= scale_x;
270       state.height *= scale_y;
271
272       state.x      += rd.x1;
273       state.y      += rd.y1;
274     }
275
276   }
277
278   state.x += GetStereoscopicDepth();
279
280   o->Render(state);
281 }
282
283 COverlay* CRenderer::Convert(CDVDOverlaySSA* o, double pts)
284 {
285   CRect src, dst;
286   g_renderManager.GetVideoRect(src, dst);
287
288   int width  = MathUtils::round_int(dst.Width());
289   int height = MathUtils::round_int(dst.Height());
290
291   int changes = 0;
292   ASS_Image* images = o->m_libass->RenderImage(width, height, pts, &changes);
293
294   if(o->m_overlay)
295   {
296     if(changes == 0)
297       return o->m_overlay->Acquire();
298   }
299
300 #if defined(HAS_GL) || defined(HAS_GLES)
301   return new COverlayGlyphGL(images, width, height);
302 #elif defined(HAS_DX)
303   return new COverlayQuadsDX(images, width, height);
304 #endif
305   return NULL;
306 }
307
308
309 COverlay* CRenderer::Convert(CDVDOverlay* o, double pts)
310 {
311   COverlay* r = NULL;
312
313   if(o->IsOverlayType(DVDOVERLAY_TYPE_SSA))
314     r = Convert((CDVDOverlaySSA*)o, pts);
315   else if(o->m_overlay)
316     r = o->m_overlay->Acquire();
317
318   if(r)
319   {
320     if(o->m_overlay)
321       o->m_overlay->Release();
322     o->m_overlay = r->Acquire();
323     return r;
324   }
325
326 #if defined(HAS_GL) || defined(HAS_GLES)
327   if     (o->IsOverlayType(DVDOVERLAY_TYPE_IMAGE))
328     r = new COverlayTextureGL((CDVDOverlayImage*)o);
329   else if(o->IsOverlayType(DVDOVERLAY_TYPE_SPU))
330     r = new COverlayTextureGL((CDVDOverlaySpu*)o);
331 #elif defined(HAS_DX)
332   if     (o->IsOverlayType(DVDOVERLAY_TYPE_IMAGE))
333     r = new COverlayImageDX((CDVDOverlayImage*)o);
334   else if(o->IsOverlayType(DVDOVERLAY_TYPE_SPU))
335     r = new COverlayImageDX((CDVDOverlaySpu*)o);
336 #endif
337
338   if(!r && o->IsOverlayType(DVDOVERLAY_TYPE_TEXT))
339     r = new COverlayText((CDVDOverlayText*)o);
340
341   if(r)
342     o->m_overlay = r->Acquire();
343   return r;
344 }
345