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