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