]> git.vomp.tv Git - vompclient.git/blob - osdwin.cc
A win bug fix
[vompclient.git] / osdwin.cc
1 /*\r
2     Copyright 2004-2005 Chris Tallon\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 */\r
20 \r
21 \r
22 #include "osdwin.h"\r
23 #include "mtd.h"\r
24 #include "videowin.h"\r
25 #include "surfacewin.h"\r
26 \r
27 #include "dsallocator.h"\r
28 \r
29 \r
30 //This is stuff for rendering the OSD\r
31 \r
32 \r
33 OsdWin::OsdWin()\r
34 {\r
35   d3d=NULL;\r
36   d3ddevice=NULL;\r
37   d3dvb=NULL;\r
38   d3drtsurf=NULL;\r
39   external_driving=false;\r
40   dsallocator=NULL;\r
41   filter_type=D3DTEXF_NONE;\r
42   lastrendertime=timeGetTime();\r
43   event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);\r
44   d3dmutex = CreateMutex(NULL,FALSE,NULL);\r
45   \r
46 }\r
47 \r
48 OsdWin::~OsdWin()\r
49 {\r
50   if (initted) shutdown();\r
51   CloseHandle(event);\r
52   CloseHandle(d3dmutex);\r
53 }\r
54 \r
55 int OsdWin::getFD()\r
56 {\r
57   if (!initted) return 0;\r
58   return fdOsd;\r
59 }\r
60 \r
61 int OsdWin::init(void* device)\r
62 {\r
63   if (initted) return 0;\r
64    Video* video = Video::getInstance();\r
65   //First Create Direct 3D Object\r
66   d3d=Direct3DCreate9(D3D_SDK_VERSION);\r
67   if (!d3d) \r
68   {\r
69     Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");\r
70     return 0;\r
71   }\r
72   // then create the Device\r
73   D3DPRESENT_PARAMETERS d3dparas;\r
74   ZeroMemory(&d3dparas,sizeof(d3dparas));\r
75   d3dparas.BackBufferWidth=video->getScreenWidth();\r
76   d3dparas.BackBufferHeight=video->getScreenHeight();\r
77   d3dparas.Windowed=TRUE;\r
78   d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
79   if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device),\r
80           D3DCREATE_SOFTWARE_VERTEXPROCESSING |D3DCREATE_MULTITHREADED,&d3dparas,&d3ddevice)!=D3D_OK) {\r
81            Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");\r
82        return 0;\r
83   }\r
84   d3ddevice->GetRenderTarget(0,&d3drtsurf);\r
85 \r
86   if (!InitVertexBuffer()) {\r
87            Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");\r
88                   return 0;\r
89   }\r
90   /* We have to determine which kind of filtering is supported*/\r
91   D3DCAPS9 caps;\r
92   d3ddevice->GetDeviceCaps(&caps);\r
93   filter_type=D3DTEXF_NONE;\r
94   if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0)\r
95           && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT)!=0)) {\r
96                   filter_type=D3DTEXF_POINT;\r
97    }\r
98    if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)!=0)\r
99           && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0)) {\r
100                   filter_type=D3DTEXF_LINEAR;\r
101    }\r
102 \r
103   //Now we will create the Screen\r
104   screen = new SurfaceWin(Surface::SCREEN);\r
105   SetEvent(event);//Now all devices are ready\r
106   screen->create(video->getScreenWidth(), video->getScreenHeight());\r
107   screen->display();\r
108   initted = 1; // must set this here or create surface won't work\r
109   \r
110   return 1;\r
111 }\r
112 \r
113 \r
114 int OsdWin::InitVertexBuffer() {\r
115   Video* video = Video::getInstance();\r
116   FLOAT texx=((float)video->getScreenWidth())/1024.f;\r
117   FLOAT texy=((float)video->getScreenHeight())/1024.f;\r
118   D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255);\r
119   osdvertices[0].c=osdcolor;\r
120   osdvertices[0].x=0.f-0.5f;\r
121   osdvertices[0].y=0.f-0.5f;\r
122   osdvertices[0].z=0.5f;\r
123   osdvertices[0].rhw=1.f;\r
124   osdvertices[0].u=0.f;\r
125   osdvertices[0].v=0.f;\r
126   osdvertices[1].c=osdcolor;\r
127   osdvertices[1].x=((float)video->getScreenWidth())-0.5f;-0.5f;\r
128   osdvertices[1].y=0.f-0.5f;\r
129   osdvertices[1].z=0.5f;\r
130   osdvertices[1].u=texx;\r
131   osdvertices[1].v=0.f;\r
132   osdvertices[1].rhw=1.f;\r
133   osdvertices[2].c=osdcolor;\r
134   osdvertices[2].x=((float)video->getScreenWidth())-0.5f;\r
135   osdvertices[2].y=((float)video->getScreenHeight())-0.5f;\r
136   osdvertices[2].z=0.5f;\r
137   osdvertices[2].rhw=1.f;\r
138   osdvertices[2].u=texx;\r
139   osdvertices[2].v=texy;\r
140   osdvertices[3].c=osdcolor;\r
141   osdvertices[3].x=0.f-0.5f;\r
142   osdvertices[3].y=((float)video->getScreenHeight())-0.5f;\r
143   osdvertices[3].z=0;\r
144   osdvertices[3].rhw=1.f;\r
145   osdvertices[3].u=0.f;\r
146   osdvertices[3].v=texy;\r
147   if (d3dvb) {\r
148           d3dvb->Release();\r
149           d3dvb=NULL;\r
150   }\r
151   if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED,\r
152           &d3dvb,NULL)!=D3D_OK) {\r
153           return 0;\r
154   }\r
155   void *pvertex=NULL;\r
156   if (d3dvb->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) {\r
157           return 0;\r
158   }\r
159   memcpy(pvertex,osdvertices,sizeof(osdvertices));\r
160   d3dvb->Unlock();\r
161   return 1;\r
162 }\r
163 \r
164 int OsdWin::shutdown()\r
165 {\r
166   if (!initted) return 0;\r
167   initted = 0;\r
168   d3drtsurf->Release();\r
169   d3ddevice->Release();\r
170   d3d->Release();\r
171 \r
172   return 1;\r
173 }\r
174 \r
175 void OsdWin::screenShot(char* fileName)\r
176 {\r
177   screen->screenShot(fileName);\r
178 }\r
179 \r
180 // This function is called from the WinMain function in order to get Screen updates\r
181 void OsdWin::Render()\r
182 {\r
183         if (!initted) return ;\r
184         if (external_driving) {\r
185                 Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads\r
186         } else {\r
187                 DWORD time1=timeGetTime();\r
188                 if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing\r
189                         InternalRendering(NULL);\r
190                         lastrendertime=timeGetTime();\r
191                 } else {\r
192                         Sleep(5);\r
193                 \r
194                 }\r
195                 \r
196         }\r
197 }\r
198 \r
199 void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){\r
200         if (!initted) return;\r
201         if (external_driving) {\r
202                 InternalRendering(present);\r
203         }\r
204 }\r
205 \r
206 \r
207 void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){\r
208         WaitForSingleObject(event,INFINITE);\r
209         WaitForSingleObject(d3dmutex,INFINITE);\r
210         BeginPainting();\r
211         if (external_driving) {\r
212                 //Copy video to Backbuffer\r
213                 if (present!=NULL) {\r
214                         VideoWin* video =(VideoWin*) Video::getInstance();\r
215                         /*calculating destination rect */\r
216                         RECT destrect={0,0,video->getScreenWidth(),video->getScreenHeight()};\r
217                         UCHAR mode=video->getMode();\r
218                         switch (mode) {\r
219                         case Video::EIGHTH:\r
220                         destrect.right=destrect.right/2;\r
221                         destrect.bottom=destrect.bottom/2;\r
222                         case Video::QUARTER:\r
223                         destrect.right=destrect.right/2+video->getPosx()*2;\r
224                         destrect.bottom=destrect.bottom/2+video->getPosy()*2;\r
225                         destrect.left=video->getPosx()*2;\r
226                         destrect.top=video->getPosy()*2;\r
227                         d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
228                         break;\r
229                         };\r
230                         D3DSURFACE_DESC surf_desc;\r
231                         present->GetDesc(&surf_desc);//for chop sides\r
232                         RECT sourcerect= {0,0,surf_desc.Width,surf_desc.Height};\r
233                         if (video->getPseudoTVsize()==Video::ASPECT4X3 \r
234                                 && video->getMode()==Video::NORMAL \r
235                                 && video->getAspectRatio()==Video::ASPECT16X9) {\r
236                                         unsigned int correction=((double) (surf_desc.Width))*4.*9./3./16.;\r
237                                         sourcerect.left=(surf_desc.Width-correction)/2;\r
238                                         sourcerect.right=sourcerect.left+correction;\r
239                         }\r
240                         d3ddevice->StretchRect(present,&sourcerect,d3drtsurf  ,&destrect,filter_type);\r
241                 }\r
242         } else {\r
243                 VideoWin* video =(VideoWin*) Video::getInstance();\r
244                 //Clear Background\r
245                 if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
246         }\r
247         //Drawing the OSD\r
248         if (d3ddevice->BeginScene()==D3D_OK) {\r
249                 d3ddevice->SetStreamSource(0,d3dvb,0,sizeof(OSDVERTEX));\r
250                 d3ddevice->SetFVF(D3DFVF_OSDVERTEX);\r
251                 d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture());\r
252                 //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);\r
253                 d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP,D3DTOP_MODULATE);\r
254                 d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);\r
255                 d3ddevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);\r
256                 d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);\r
257                 d3ddevice->SetRenderState(D3DRS_LIGHTING,FALSE);\r
258 \r
259 \r
260                 d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);\r
261                 d3ddevice->EndScene();\r
262                 //Show it to the user!\r
263                 if (d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){\r
264                         EndPainting();\r
265                         DoLost();\r
266                 }\r
267                 EndPainting();\r
268         }\r
269         ReleaseMutex(d3dmutex);\r
270         if (!external_driving) {\r
271                 Sleep(4);//The User can wait for 4 milliseconds to see his changes\r
272         }\r
273 }\r
274 \r
275 void OsdWin::DoLost(){\r
276         Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");\r
277         ResetEvent(event);\r
278         if (external_driving && dsallocator!=NULL) {\r
279                 dsallocator->LostDevice(); //Propagate the information through DS\r
280         }\r
281         //First we free up all resources\r
282         Video* video = Video::getInstance();\r
283         ((SurfaceWin*)screen)->ReleaseSurface();\r
284         d3drtsurf->Release();\r
285         d3dvb->Release();\r
286         d3dvb=NULL;\r
287         D3DPRESENT_PARAMETERS d3dparas;\r
288         ZeroMemory(&d3dparas,sizeof(d3dparas));\r
289         d3dparas.BackBufferWidth=video->getScreenWidth();\r
290         d3dparas.BackBufferHeight=video->getScreenHeight();\r
291         d3dparas.Windowed=TRUE;\r
292         d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;\r
293         if (d3ddevice->Reset(&d3dparas)!=D3D_OK){\r
294                 return;\r
295         }\r
296         screen->create(video->getScreenWidth(), video->getScreenHeight());\r
297         screen->display();\r
298         d3ddevice->GetRenderTarget(0,&d3drtsurf);\r
299         InitVertexBuffer();\r
300         //Redraw Views, Chris could you add a member function to viewman, so that\r
301         // I can cause it to completely redraw the Views?\r
302         // Otherwise the OSD would be distorted after Device Lost\r
303         \r
304         SetEvent(event);\r
305 \r
306 }\r
307 LPDIRECT3DDEVICE9 OsdWin::getD3dDev() {\r
308         WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
309         return d3ddevice;\r
310 }\r
311 \r
312 LPDIRECT3D9 OsdWin::getD3d() {\r
313         WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
314         return d3d;\r
315 }\r
316 \r
317 void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads\r
318         WaitForSingleObject(d3dmutex,INFINITE);\r
319 }\r
320 \r
321 void OsdWin::EndPainting() {\r
322         ReleaseMutex(d3dmutex);\r
323 }\r
324 \r
325 void OsdWin::setExternalDriving(DsAllocator* dsall) {\r
326         if (dsall==NULL) {\r
327                 external_driving=false;\r
328                 dsallocator=NULL;\r
329                 return;\r
330         }\r
331         WaitForSingleObject(event,INFINITE);//We will only return if we are initted\r
332         dsallocator=dsall;\r
333         external_driving=true;\r
334 }\r
335 \r
336 void OsdWin::Blank() {\r
337         WaitForSingleObject(event,INFINITE);\r
338         BeginPainting();\r
339         d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);\r
340         EndPainting();\r
341 }\r
342 \r