[XBOX] Merged: Linuxport revisions
[xbmc:xbmc-antiquated.git] / guilib / GraphicContext.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "include.h"
23 #include "GraphicContext.h"
24 #include "GUIFontManager.h"
25 #include "GUIMessage.h"
26 #include "IMsgSenderCallback.h"
27 #include "Settings.h"
28 #include "GUISettings.h"
29 #include "XBVideoConfig.h"
30 #include "GUIAudioManager.h"
31 #ifdef HAS_XBOX_D3D
32  #include "xgraphics.h"
33  #define D3D_CLEAR_STENCIL D3DCLEAR_STENCIL
34 #else
35  #define D3D_CLEAR_STENCIL 0x0l
36 #endif
37 #include "SkinInfo.h"
38 #include "TextureManager.h"
39
40 using namespace std;
41
42 CGraphicContext g_graphicsContext;
43
44 /* quick access to a skin setting, fine unless we starts clearing video settings */
45 static CSettingInt* g_guiSkinzoom = NULL;
46
47 CGraphicContext::CGraphicContext(void)
48 {
49   m_iScreenWidth = 720;
50   m_iScreenHeight = 576;
51   m_pd3dDevice = NULL;
52   m_pd3dParams = NULL;
53   m_stateBlock = 0xffffffff;
54   m_maxTextureSize = 4096;
55   m_dwID = 0;
56   m_strMediaDir = "";
57   m_bCalibrating = false;
58   m_Resolution = INVALID;
59   m_pCallback = NULL;
60   m_guiScaleX = m_guiScaleY = 1.0f;
61   m_windowResolution = INVALID;
62 }
63
64 CGraphicContext::~CGraphicContext(void)
65 {
66   if (m_stateBlock != 0xffffffff)
67   {
68     Get3DDevice()->DeleteStateBlock(m_stateBlock);
69   }
70   while (m_viewStack.size())
71   {
72     D3DVIEWPORT8 *viewport = m_viewStack.top();
73     m_viewStack.pop();
74     if (viewport) delete viewport;
75   }
76 }
77
78
79 void CGraphicContext::SetD3DDevice(LPDIRECT3DDEVICE8 p3dDevice)
80 {
81   m_pd3dDevice = p3dDevice;
82 }
83
84 void CGraphicContext::SetD3DParameters(D3DPRESENT_PARAMETERS *p3dParams)
85 {
86   m_pd3dParams = p3dParams;
87 }
88
89 bool CGraphicContext::SendMessage(DWORD message, DWORD senderID, DWORD destID, DWORD param1, DWORD param2)
90 {
91   if (!m_pCallback) return false;
92   CGUIMessage msg(message, senderID, destID, param1, param2);
93   return m_pCallback->SendMessage(msg);
94 }
95
96 bool CGraphicContext::SendMessage(CGUIMessage& message)
97 {
98   if (!m_pCallback) return false;
99   return m_pCallback->SendMessage(message);
100 }
101
102 void CGraphicContext::setMessageSender(IMsgSenderCallback* pCallback)
103 {
104   m_pCallback = pCallback;
105 }
106
107 DWORD CGraphicContext::GetNewID()
108 {
109   m_dwID++;
110   return m_dwID;
111 }
112
113 void CGraphicContext::SetOrigin(float x, float y)
114 {
115   if (m_origins.size())
116     m_origins.push(CPoint(x,y) + m_origins.top());
117   else
118     m_origins.push(CPoint(x,y));
119   AddTransform(TransformMatrix::CreateTranslation(x, y));
120 }
121
122 void CGraphicContext::RestoreOrigin()
123 {
124   m_origins.pop();
125   RemoveTransform();
126 }
127
128 // add a new clip region, intersecting with the previous clip region.
129 bool CGraphicContext::SetClipRegion(float x, float y, float w, float h)
130 { // transform from our origin
131   CPoint origin;
132   if (m_origins.size())
133     origin = m_origins.top();
134   // ok, now intersect with our old clip region
135   CRect rect(x, y, x + w, y + h);
136   rect += origin;
137   if (m_clipRegions.size())
138   { // intersect with original clip region
139     rect.Intersect(m_clipRegions.top());
140   }
141   if (rect.IsEmpty())
142     return false;
143   m_clipRegions.push(rect);
144
145   // here we could set the hardware clipping, if applicable
146   return true;
147 }
148
149 void CGraphicContext::RestoreClipRegion()
150 {
151   if (m_clipRegions.size())
152     m_clipRegions.pop();
153
154   // here we could reset the hardware clipping, if applicable
155 }
156
157 void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2)
158 {
159   // this is the software clipping routine.  If the graphics hardware is set to do the clipping
160   // (eg via SetClipPlane in D3D for instance) then this routine is unneeded.
161   if (m_clipRegions.size())
162   {
163     // take a copy of the vertex rectangle and intersect
164     // it with our clip region (moved to the same coordinate system)
165     CRect clipRegion(m_clipRegions.top());
166     if (m_origins.size())
167       clipRegion -= m_origins.top();
168     CRect original(vertex);
169     vertex.Intersect(clipRegion);
170     // and use the original to compute the texture coordinates
171     if (original != vertex)
172     {
173       float scaleX = texture.Width() / original.Width();
174       float scaleY = texture.Height() / original.Height();
175       texture.x1 += (vertex.x1 - original.x1) * scaleX;
176       texture.y1 += (vertex.y1 - original.y1) * scaleY;
177       texture.x2 += (vertex.x2 - original.x2) * scaleX;
178       texture.y2 += (vertex.y2 - original.y2) * scaleY;
179       if (texture2)
180       {
181         scaleX = texture2->Width() / original.Width();
182         scaleY = texture2->Height() / original.Height();
183         texture2->x1 += (vertex.x1 - original.x1) * scaleX;
184         texture2->y1 += (vertex.y1 - original.y1) * scaleY;
185         texture2->x2 += (vertex.x2 - original.x2) * scaleX;
186         texture2->y2 += (vertex.y2 - original.y2) * scaleY;
187       }
188     }
189   }
190 }
191
192 bool CGraphicContext::SetViewPort(float fx, float fy , float fwidth, float fheight, bool intersectPrevious /* = false */)
193 {
194   D3DVIEWPORT8 newviewport;
195   D3DVIEWPORT8 *oldviewport = new D3DVIEWPORT8;
196   Get3DDevice()->GetViewport(oldviewport);
197   // transform coordinates - we may have a rotation which changes the positioning of the
198   // minimal and maximal viewport extents.  We currently go to the maximal extent.
199   float x[4], y[4];
200   x[0] = x[3] = fx;
201   x[1] = x[2] = fx + fwidth;
202   y[0] = y[1] = fy;
203   y[2] = y[3] = fy + fheight;
204   float minX = (float)m_iScreenWidth;
205   float maxX = 0;
206   float minY = (float)m_iScreenHeight;
207   float maxY = 0;
208   for (int i = 0; i < 4; i++)
209   {
210     float z = 0;
211     ScaleFinalCoords(x[i], y[i], z);
212     if (x[i] < minX) minX = x[i];
213     if (x[i] > maxX) maxX = x[i];
214     if (y[i] < minY) minY = y[i];
215     if (y[i] > maxY) maxY = y[i];
216   }
217
218   int newLeft = (int)(minX + 0.5f);
219   int newTop = (int)(minY + 0.5f);
220   int newRight = (int)(maxX + 0.5f);
221   int newBottom = (int)(maxY + 0.5f);
222   if (intersectPrevious)
223   {
224     // do the intersection
225     int oldLeft = (int)oldviewport->X;
226     int oldTop = (int)oldviewport->Y;
227     int oldRight = (int)oldviewport->X + oldviewport->Width;
228     int oldBottom = (int)oldviewport->Y + oldviewport->Height;
229     if (newLeft >= oldRight || newTop >= oldBottom || newRight <= oldLeft || newBottom <= oldTop)
230     { // empty intersection - return false to indicate no rendering should occur
231 #if defined(HAS_SDL_OPENGL)
232       delete [] oldviewport;
233 #else
234       delete oldviewport;
235 #endif
236       return false;
237     }
238     // ok, they intersect, do the intersection
239     if (newLeft < oldLeft) newLeft = oldLeft;
240     if (newTop < oldTop) newTop = oldTop;
241     if (newRight > oldRight) newRight = oldRight;
242     if (newBottom > oldBottom) newBottom = oldBottom;
243   }
244   // check range against screen size
245   if (newRight <= 0 || newBottom <= 0 ||
246       newTop >= m_iScreenHeight || newLeft >= m_iScreenWidth ||
247       newLeft >= newRight || newTop >= newBottom)
248   { // no intersection with the screen
249
250 #if defined(HAS_SDL_OPENGL)
251    delete [] oldviewport;
252 #else
253    delete oldviewport;
254 #endif
255     return false;
256   }
257   // intersection with the screen
258   if (newLeft < 0) newLeft = 0;
259   if (newTop < 0) newTop = 0;
260   if (newRight > m_iScreenWidth) newRight = m_iScreenWidth;
261   if (newBottom > m_iScreenHeight) newBottom = m_iScreenHeight;
262
263   ASSERT(newLeft < newRight);
264   ASSERT(newTop < newBottom);
265
266   newviewport.MinZ = 0.0f;
267   newviewport.MaxZ = 1.0f;
268   newviewport.X = newLeft;
269   newviewport.Y = newTop;
270   newviewport.Width = newRight - newLeft;
271   newviewport.Height = newBottom - newTop;
272   m_pd3dDevice->SetViewport(&newviewport);
273   m_viewStack.push(oldviewport);
274  
275   UpdateCameraPosition(m_cameras.top());
276   return true;
277 }
278
279 void CGraphicContext::RestoreViewPort()
280 {
281   if (!m_viewStack.size()) return;
282   D3DVIEWPORT8 *oldviewport = (D3DVIEWPORT8*)m_viewStack.top();
283   m_viewStack.pop();
284   Get3DDevice()->SetViewport(oldviewport);
285
286
287   if (oldviewport)
288   {
289 #if defined(HAS_SDL_OPENGL)
290     delete [] oldviewport;
291 #else
292     delete oldviewport;
293 #endif
294   }
295
296   UpdateCameraPosition(m_cameras.top());
297 }
298
299 const RECT& CGraphicContext::GetViewWindow() const
300 {
301   return m_videoRect;
302 }
303 void CGraphicContext::SetViewWindow(float left, float top, float right, float bottom)
304 {
305   if (m_bCalibrating)
306   {
307     SetFullScreenViewWindow(m_Resolution);
308   }
309   else
310   {
311     m_videoRect.left = (long)(ScaleFinalXCoord(left, top) + 0.5f);
312     m_videoRect.top = (long)(ScaleFinalYCoord(left, top) + 0.5f);
313     m_videoRect.right = (long)(ScaleFinalXCoord(right, bottom) + 0.5f);
314     m_videoRect.bottom = (long)(ScaleFinalYCoord(right, bottom) + 0.5f);
315   }
316 }
317
318 void CGraphicContext::ClipToViewWindow()
319 {
320   D3DRECT clip = { m_videoRect.left, m_videoRect.top, m_videoRect.right, m_videoRect.bottom };
321   if (m_videoRect.left < 0) clip.x1 = 0;
322   if (m_videoRect.top < 0) clip.y1 = 0;
323   if (m_videoRect.left > m_iScreenWidth - 1) clip.x1 = m_iScreenWidth - 1;
324   if (m_videoRect.top > m_iScreenHeight - 1) clip.y1 = m_iScreenHeight - 1;
325   if (m_videoRect.right > m_iScreenWidth) clip.x2 = m_iScreenWidth;
326   if (m_videoRect.bottom > m_iScreenHeight) clip.y2 = m_iScreenHeight;
327   if (clip.x2 < clip.x1) clip.x2 = clip.x1 + 1;
328   if (clip.y2 < clip.y1) clip.y2 = clip.y1 + 1;
329 #ifdef HAS_XBOX_D3D
330   m_pd3dDevice->SetScissors(1, FALSE, &clip);
331 #endif
332 }
333
334 void CGraphicContext::SetFullScreenViewWindow(RESOLUTION &res)
335 {
336   m_videoRect.left = g_settings.m_ResInfo[res].Overscan.left;
337   m_videoRect.top = g_settings.m_ResInfo[res].Overscan.top;
338   m_videoRect.right = g_settings.m_ResInfo[res].Overscan.right;
339   m_videoRect.bottom = g_settings.m_ResInfo[res].Overscan.bottom;
340 }
341
342 void CGraphicContext::SetFullScreenVideo(bool bOnOff)
343 {
344   Lock();
345   m_bFullScreenVideo = bOnOff;
346   SetFullScreenViewWindow(m_Resolution);
347   Unlock();
348 }
349
350 bool CGraphicContext::IsFullScreenVideo() const
351 {
352   return m_bFullScreenVideo;
353 }
354
355 bool CGraphicContext::IsCalibrating() const
356 {
357   return m_bCalibrating;
358 }
359
360 void CGraphicContext::SetCalibrating(bool bOnOff)
361 {
362   m_bCalibrating = bOnOff;
363 }
364
365 bool CGraphicContext::IsValidResolution(RESOLUTION res)
366 {
367   return g_videoConfig.IsValidResolution(res);
368 }
369
370 void CGraphicContext::GetAllowedResolutions(vector<RESOLUTION> &res, bool bAllowPAL60)
371 {
372   bool bCanDoWidescreen = g_videoConfig.HasWidescreen();
373   res.clear();  
374   if (g_videoConfig.HasPAL())
375   {
376     res.push_back(PAL_4x3);
377     if (bCanDoWidescreen) res.push_back(PAL_16x9);
378     if (bAllowPAL60 && g_videoConfig.HasPAL60())
379     {
380       res.push_back(PAL60_4x3);
381       if (bCanDoWidescreen) res.push_back(PAL60_16x9);
382     }
383   }
384   if (g_videoConfig.HasNTSC())
385   {
386     res.push_back(NTSC_4x3);
387     if (bCanDoWidescreen) res.push_back(NTSC_16x9);
388     if (g_videoConfig.Has480p())
389     {
390       res.push_back(HDTV_480p_4x3);
391       if (bCanDoWidescreen) res.push_back(HDTV_480p_16x9);
392     }
393     if (g_videoConfig.Has720p())
394       res.push_back(HDTV_720p);
395     if (g_videoConfig.Has1080i())
396       res.push_back(HDTV_1080i);
397   }
398 }
399
400 void CGraphicContext::SetVideoResolution(RESOLUTION &res, BOOL NeedZ, bool forceClear /* = false */)
401 {
402   if (res == AUTORES)
403   {
404     res = g_videoConfig.GetBestMode();
405   }
406   if (!IsValidResolution(res))
407   { // Choose a failsafe resolution that we can actually display
408     CLog::Log(LOGERROR, "The screen resolution requested is not valid, resetting to a valid mode");
409     res = g_videoConfig.GetSafeMode();
410   }
411   
412   if (!m_pd3dParams)
413   {
414     m_Resolution = res;
415     return ;
416   }
417   bool NeedReset = false;
418
419   UINT interval = D3DPRESENT_INTERVAL_ONE;  
420   //if( m_bFullScreenVideo )
421   //  interval = D3DPRESENT_INTERVAL_IMMEDIATE;
422
423 #ifdef PROFILE
424   interval = D3DPRESENT_INTERVAL_IMMEDIATE;
425 #endif
426
427 #ifndef HAS_XBOX_D3D
428   interval = 0;
429 #endif
430
431   if (interval != m_pd3dParams->FullScreen_PresentationInterval)
432   {
433     m_pd3dParams->FullScreen_PresentationInterval = interval;
434     NeedReset = true;
435   }
436
437
438   if (NeedZ != m_pd3dParams->EnableAutoDepthStencil)
439   {
440     m_pd3dParams->EnableAutoDepthStencil = NeedZ;
441     NeedReset = true;
442   }
443   if (m_Resolution != res)
444   {
445     NeedReset = true;
446     m_pd3dParams->BackBufferWidth = g_settings.m_ResInfo[res].iWidth;
447     m_pd3dParams->BackBufferHeight = g_settings.m_ResInfo[res].iHeight;
448     m_pd3dParams->Flags = g_settings.m_ResInfo[res].dwFlags;
449     m_pd3dParams->Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
450
451     if (res == HDTV_1080i || res == HDTV_720p || m_bFullScreenVideo)
452       m_pd3dParams->BackBufferCount = 1;
453     else
454       m_pd3dParams->BackBufferCount = 2;
455
456     if (res == PAL60_4x3 || res == PAL60_16x9)
457     {
458       if (m_pd3dParams->BackBufferWidth <= 720 && m_pd3dParams->BackBufferHeight <= 480)
459       {
460         m_pd3dParams->FullScreen_RefreshRateInHz = 60;
461       }
462       else
463       {
464         m_pd3dParams->FullScreen_RefreshRateInHz = 0;
465       }
466     }
467     else
468     {
469       m_pd3dParams->FullScreen_RefreshRateInHz = 0;
470     }
471   }
472   Lock();
473   if (m_pd3dDevice)
474   {
475     if (NeedReset)
476     {
477       CLog::Log(LOGDEBUG, "Setting resolution %i", res);
478       m_pd3dDevice->Reset(m_pd3dParams);
479     }
480
481     /* need to clear and preset, otherwise flicker filters won't take effect */
482     if (NeedReset || forceClear)
483     {
484       m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3D_CLEAR_STENCIL, 0x00010001, 1.0f, 0L );
485       m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
486     }
487
488     m_iScreenWidth = m_pd3dParams->BackBufferWidth;
489     m_iScreenHeight = m_pd3dParams->BackBufferHeight;
490     m_bWidescreen = (m_pd3dParams->Flags & D3DPRESENTFLAG_WIDESCREEN) != 0;
491   }
492   if ((g_settings.m_ResInfo[m_Resolution].iWidth != g_settings.m_ResInfo[res].iWidth) || (g_settings.m_ResInfo[m_Resolution].iHeight != g_settings.m_ResInfo[res].iHeight))
493   { // set the mouse resolution
494     g_Mouse.SetResolution(g_settings.m_ResInfo[res].iWidth, g_settings.m_ResInfo[res].iHeight, 1, 1);
495   }
496
497   SetFullScreenViewWindow(res);
498   SetScreenFilters(m_bFullScreenVideo);
499   
500   m_Resolution = res;
501   if (NeedReset)
502   {
503     CLog::Log(LOGDEBUG, "We set resolution %i", m_Resolution);
504     if (m_Resolution != INVALID)
505       g_fontManager.ReloadTTFFonts();
506   }
507
508   Unlock();  
509 }
510
511 RESOLUTION CGraphicContext::GetVideoResolution() const
512 {
513   return m_Resolution;
514 }
515
516 void CGraphicContext::SetScreenFilters(bool useFullScreenFilters)
517 {
518   Lock();
519   if (m_pd3dDevice)
520   {
521     // These are only valid here and nowhere else
522     // set soften on/off
523 #ifdef HAS_XBOX_D3D
524     m_pd3dDevice->SetSoftDisplayFilter(useFullScreenFilters ? g_guiSettings.GetBool("videoplayer.soften") : g_guiSettings.GetBool("videoscreen.soften"));
525     m_pd3dDevice->SetFlickerFilter(useFullScreenFilters ? g_guiSettings.GetInt("videoplayer.flicker") : g_guiSettings.GetInt("videoscreen.flickerfilter"));
526 #endif
527   }
528   Unlock();
529 }
530
531 void CGraphicContext::ResetOverscan(RESOLUTION res, OVERSCAN &overscan)
532 {
533   overscan.left = 0;
534   overscan.top = 0;
535   switch (res)
536   {
537   case HDTV_1080i:
538     overscan.right = 1920;
539     overscan.bottom = 1080;
540     break;
541   case HDTV_720p:
542     overscan.right = 1280;
543     overscan.bottom = 720;
544     break;
545   case HDTV_480p_16x9:
546   case HDTV_480p_4x3:
547   case NTSC_16x9:
548   case NTSC_4x3:
549   case PAL60_16x9:
550   case PAL60_4x3:
551     overscan.right = 720;
552     overscan.bottom = 480;
553     break;
554   case PAL_16x9:
555   case PAL_4x3:
556     overscan.right = 720;
557     overscan.bottom = 576;
558     break;
559   default:
560     break;
561   }
562 }
563
564 void CGraphicContext::ResetScreenParameters(RESOLUTION res)
565 {
566   ResetOverscan(res, g_settings.m_ResInfo[res].Overscan);
567   g_settings.m_ResInfo[res].fPixelRatio = GetPixelRatio(res);
568   // 1080i
569   switch (res)
570   {
571   case HDTV_1080i:
572     g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 1080);
573     g_settings.m_ResInfo[res].iWidth = 1920;
574     g_settings.m_ResInfo[res].iHeight = 1080;
575     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
576     g_settings.m_ResInfo[res].fPixelRatio = 1.0f;
577     strcpy(g_settings.m_ResInfo[res].strMode, "1080i 16:9");
578     break;
579   case HDTV_720p:
580     g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 720);
581     g_settings.m_ResInfo[res].iWidth = 1280;
582     g_settings.m_ResInfo[res].iHeight = 720;
583     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_PROGRESSIVE | D3DPRESENTFLAG_WIDESCREEN;
584     g_settings.m_ResInfo[res].fPixelRatio = 1.0f;
585     strcpy(g_settings.m_ResInfo[res].strMode, "720p 16:9");
586     break;
587   case HDTV_480p_4x3:
588     g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 480);
589     g_settings.m_ResInfo[res].iWidth = 720;
590     g_settings.m_ResInfo[res].iHeight = 480;
591     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
592     g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f;
593     strcpy(g_settings.m_ResInfo[res].strMode, "480p 4:3");
594     break;
595   case HDTV_480p_16x9:
596     g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 480);
597     g_settings.m_ResInfo[res].iWidth = 720;
598     g_settings.m_ResInfo[res].iHeight = 480;
599     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_PROGRESSIVE | D3DPRESENTFLAG_WIDESCREEN;
600     g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f*4.0f / 3.0f;
601     strcpy(g_settings.m_ResInfo[res].strMode, "480p 16:9");
602     break;
603   case NTSC_4x3:
604     g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 480);
605     g_settings.m_ResInfo[res].iWidth = 720;
606     g_settings.m_ResInfo[res].iHeight = 480;
607     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED;
608     g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f;
609     strcpy(g_settings.m_ResInfo[res].strMode, "NTSC 4:3");
610     break;
611   case NTSC_16x9:
612     g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 480);
613     g_settings.m_ResInfo[res].iWidth = 720;
614     g_settings.m_ResInfo[res].iHeight = 480;
615     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
616     g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f*4.0f / 3.0f;
617     strcpy(g_settings.m_ResInfo[res].strMode, "NTSC 16:9");
618     break;
619   case PAL_4x3:
620     g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 576);
621     g_settings.m_ResInfo[res].iWidth = 720;
622     g_settings.m_ResInfo[res].iHeight = 576;
623     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED;
624     g_settings.m_ResInfo[res].fPixelRatio = 128.0f / 117.0f;
625     strcpy(g_settings.m_ResInfo[res].strMode, "PAL 4:3");
626     break;
627   case PAL_16x9:
628     g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 576);
629     g_settings.m_ResInfo[res].iWidth = 720;
630     g_settings.m_ResInfo[res].iHeight = 576;
631     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
632     g_settings.m_ResInfo[res].fPixelRatio = 128.0f / 117.0f*4.0f / 3.0f;
633     strcpy(g_settings.m_ResInfo[res].strMode, "PAL 16:9");
634     break;
635   case PAL60_4x3:
636     g_settings.m_ResInfo[res].iSubtitles = (int)(0.9 * 480);
637     g_settings.m_ResInfo[res].iWidth = 720;
638     g_settings.m_ResInfo[res].iHeight = 480;
639     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED;
640     g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f;
641     strcpy(g_settings.m_ResInfo[res].strMode, "PAL60 4:3");
642     break;
643   case PAL60_16x9:
644     g_settings.m_ResInfo[res].iSubtitles = (int)(0.965 * 480);
645     g_settings.m_ResInfo[res].iWidth = 720;
646     g_settings.m_ResInfo[res].iHeight = 480;
647     g_settings.m_ResInfo[res].dwFlags = D3DPRESENTFLAG_INTERLACED | D3DPRESENTFLAG_WIDESCREEN;
648     g_settings.m_ResInfo[res].fPixelRatio = 4320.0f / 4739.0f*4.0f / 3.0f;
649     strcpy(g_settings.m_ResInfo[res].strMode, "PAL60 16:9");
650     break;
651   default:
652     break;
653   }
654 }
655
656 float CGraphicContext::GetPixelRatio(RESOLUTION iRes) const
657 {
658   return g_settings.m_ResInfo[iRes].fPixelRatio;
659 }
660
661 void CGraphicContext::Clear()
662 {
663   if (!m_pd3dDevice) return;
664   //Not trying to clear the zbuffer when there is none is 7 fps faster (pal resolution)
665   if ((!m_pd3dParams) || (m_pd3dParams->EnableAutoDepthStencil == TRUE))
666     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3D_CLEAR_STENCIL, 0x00010001, 1.0f, 0L );
667   else
668     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x00010001, 1.0f, 0L );
669 }
670
671 void CGraphicContext::CaptureStateBlock()
672 {
673   if (m_stateBlock != 0xffffffff)
674   {
675     Get3DDevice()->DeleteStateBlock(m_stateBlock);
676   }
677
678   if (D3D_OK != Get3DDevice()->CreateStateBlock(D3DSBT_PIXELSTATE, &m_stateBlock))
679   {
680     // Creation failure
681     m_stateBlock = 0xffffffff;
682   }
683 }
684
685 void CGraphicContext::ApplyStateBlock()
686 {
687   if (m_stateBlock != 0xffffffff)
688   {
689     Get3DDevice()->ApplyStateBlock(m_stateBlock);
690   }
691 }
692
693 void CGraphicContext::SetScalingResolution(RESOLUTION res, float posX, float posY, bool needsScaling)
694 {
695   m_windowResolution = res;
696   if (needsScaling)
697   {
698     // calculate necessary scalings    
699     float fFromWidth;
700     float fFromHeight;
701     float fToPosX;
702     float fToPosY;
703     float fToWidth;
704     float fToHeight;
705     
706     {
707       fFromWidth = (float)g_settings.m_ResInfo[res].iWidth;
708       fFromHeight = (float)g_settings.m_ResInfo[res].iHeight;
709       fToPosX = (float)g_settings.m_ResInfo[m_Resolution].Overscan.left;
710       fToPosY = (float)g_settings.m_ResInfo[m_Resolution].Overscan.top;
711       fToWidth = (float)g_settings.m_ResInfo[m_Resolution].Overscan.right - fToPosX;
712       fToHeight = (float)g_settings.m_ResInfo[m_Resolution].Overscan.bottom - fToPosY;      
713     }
714
715     // add additional zoom to compensate for any overskan built in skin
716     float fZoom = g_SkinInfo.GetSkinZoom();
717
718     if(!g_guiSkinzoom) // lookup gui setting if we didn't have it already
719       g_guiSkinzoom = (CSettingInt*)g_guiSettings.GetSetting("lookandfeel.skinzoom");
720
721     if(g_guiSkinzoom)
722       fZoom *= (100 + g_guiSkinzoom->GetData()) * 0.01f;
723
724     fZoom -= 1.0f;
725     fToPosX -= fToWidth * fZoom * 0.5f;
726     fToWidth *= fZoom + 1.0f;
727
728     // adjust for aspect ratio as zoom is given in the vertical direction and we don't 
729     // do aspect ratio corrections in the gui code 
730     fZoom = fZoom / g_settings.m_ResInfo[m_Resolution].fPixelRatio;
731     fToPosY -= fToHeight * fZoom * 0.5f;
732     fToHeight *= fZoom + 1.0f;
733     
734     m_guiScaleX = fFromWidth / fToWidth;
735     m_guiScaleY = fFromHeight / fToHeight;
736     TransformMatrix windowOffset = TransformMatrix::CreateTranslation(posX, posY);
737     TransformMatrix guiScaler = TransformMatrix::CreateScaler(fToWidth / fFromWidth, fToHeight / fFromHeight, fToHeight / fFromHeight);
738     TransformMatrix guiOffset = TransformMatrix::CreateTranslation(fToPosX, fToPosY);
739     m_guiTransform = guiOffset * guiScaler * windowOffset;
740   }
741   else
742   {
743     m_guiTransform = TransformMatrix::CreateTranslation(posX, posY);
744     m_guiScaleX = 1.0f;
745     m_guiScaleY = 1.0f;
746   }
747   // reset our origin and camera
748   while (m_origins.size())
749     m_origins.pop();
750   m_origins.push(CPoint(posX, posY));
751   while (m_cameras.size())
752     m_cameras.pop();
753   m_cameras.push(CPoint(0.5f*m_iScreenWidth, 0.5f*m_iScreenHeight));
754
755   // and reset the final transform
756   UpdateFinalTransform(m_guiTransform);
757 }
758
759 void CGraphicContext::SetRenderingResolution(RESOLUTION res, float posX, float posY, bool needsScaling)
760 {
761   Lock();
762   SetScalingResolution(res, posX, posY, needsScaling);
763   UpdateCameraPosition(m_cameras.top());
764   Unlock();
765 }
766
767 void CGraphicContext::UpdateFinalTransform(const TransformMatrix &matrix)
768 {
769   m_finalTransform = matrix;
770   // We could set the world transform here to GPU-ize the animation system.
771   // trouble is that we require the resulting x,y coords to be rounded to
772   // the nearest pixel (vertex shader perhaps?)
773 }
774
775 void CGraphicContext::InvertFinalCoords(float &x, float &y) const
776 {
777   m_finalTransform.InverseTransformPosition(x, y);
778 }
779
780 float CGraphicContext::GetScalingPixelRatio() const
781 {
782   if (m_Resolution == m_windowResolution)
783     return GetPixelRatio(m_windowResolution);
784
785   RESOLUTION checkRes = m_windowResolution;
786   if (checkRes == INVALID)
787     checkRes = m_Resolution;
788   // resolutions are different - we want to return the aspect ratio of the video resolution
789   // but only once it's been corrected for the skin -> screen coordinates scaling
790   float winWidth = (float)g_settings.m_ResInfo[checkRes].iWidth;
791   float winHeight = (float)g_settings.m_ResInfo[checkRes].iHeight;
792   float outWidth = (float)g_settings.m_ResInfo[m_Resolution].iWidth;
793   float outHeight = (float)g_settings.m_ResInfo[m_Resolution].iHeight;
794   float outPR = GetPixelRatio(m_Resolution);
795
796   return outPR * (outWidth / outHeight) / (winWidth / winHeight);
797 }
798
799 void CGraphicContext::SetCameraPosition(const CPoint &camera)
800 {
801   // offset the camera from our current location (this is in XML coordinates) and scale it up to
802   // the screen resolution
803   CPoint cam(camera);
804   if (m_origins.size())
805     cam += m_origins.top();
806
807   RESOLUTION windowRes = (m_windowResolution == INVALID) ? m_Resolution : m_windowResolution;
808   cam.x *= (float)m_iScreenWidth / g_settings.m_ResInfo[windowRes].iWidth;
809   cam.y *= (float)m_iScreenHeight / g_settings.m_ResInfo[windowRes].iHeight;
810
811   m_cameras.push(cam);
812   UpdateCameraPosition(m_cameras.top());
813 }
814
815 void CGraphicContext::RestoreCameraPosition()
816 { // remove the top camera from the stack
817   ASSERT(m_cameras.size());
818   m_cameras.pop();
819   UpdateCameraPosition(m_cameras.top());
820 }
821
822 void CGraphicContext::UpdateCameraPosition(const CPoint &camera)
823 {
824   // NOTE: This routine is currently called (twice) every time there is a <camera>
825   //       tag in the skin.  It actually only has to be called before we render
826   //       something, so another option is to just save the camera coordinates
827   //       and then have a routine called before every draw that checks whether
828   //       the camera has changed, and if so, changes it.  Similarly, it could set
829   //       the world transform at that point as well (or even combine world + view
830   //       to cut down on one setting)
831  
832   // and calculate the offset from the screen center
833   CPoint offset = camera - CPoint(m_iScreenWidth*0.5f, m_iScreenHeight*0.5f);
834
835   // grab the viewport dimensions and location
836   D3DVIEWPORT8 viewport;
837   m_pd3dDevice->GetViewport(&viewport);
838   float w = viewport.Width*0.5f;
839   float h = viewport.Height*0.5f;
840
841   // world view.  Until this is moved onto the GPU (via a vertex shader for instance), we set it to the identity
842   // here.
843   D3DXMATRIX mtxWorld;
844   D3DXMatrixIdentity(&mtxWorld);
845   m_pd3dDevice->SetTransform(D3DTS_WORLD, &mtxWorld);
846
847   // camera view.  Multiply the Y coord by -1 then translate so that everything is relative to the camera
848   // position.
849   D3DXMATRIX flipY, translate, mtxView;
850   D3DXMatrixScaling(&flipY, 1.0f, -1.0f, 1.0f);
851   D3DXMatrixTranslation(&translate, -(viewport.X + w + offset.x), -(viewport.Y + h + offset.y), 2*h);
852   D3DXMatrixMultiply(&mtxView, &translate, &flipY);
853   m_pd3dDevice->SetTransform(D3DTS_VIEW, &mtxView);
854
855   // projection onto screen space
856   D3DXMATRIX mtxProjection;
857   D3DXMatrixPerspectiveOffCenterLH(&mtxProjection, (-w - offset.x)*0.5f, (w - offset.x)*0.5f, (-h + offset.y)*0.5f, (h + offset.y)*0.5f, h, 100*h);
858   m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mtxProjection);
859 }
860
861 bool CGraphicContext::RectIsAngled(float x1, float y1, float x2, float y2) const
862 { // need only test 3 points, as they must be co-planer
863   if (m_finalTransform.TransformZCoord(x1, y1, 0)) return true;
864   if (m_finalTransform.TransformZCoord(x2, y2, 0)) return true;
865   if (m_finalTransform.TransformZCoord(x1, y2, 0)) return true;
866   return false;
867 }
868
869 int CGraphicContext::GetFPS() const
870 {
871   if (m_Resolution == PAL_4x3 || m_Resolution == PAL_16x9)
872     return 50;
873   else if (m_Resolution == HDTV_1080i)
874     return 30;
875   return 60;
876 }
877
878 void CGraphicContext::SetMediaDir(const CStdString &strMediaDir)
879 {
880   g_TextureManager.SetTexturePath(strMediaDir);
881   m_strMediaDir = strMediaDir;
882 }
883