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