|
| DirectDraw i vinduer Fra : Klaus Petersen |
Dato : 04-02-03 22:10 |
|
Hej NG.
Jeg er lidt i tvivl om hvordan man skal bruge directdraw i vinduer.
Når det er fullscreen, flipper man jo bare mellem sin primære surface og sin
sekundære - men det kan man vist ikke, når det ikke er fullscreen.
Så hvordan opnår jeg f.eks. 60 fps i et vindue?
Kan nogen give mig nogle hints?
Klaus.
| |
Morten F. Hansen (04-02-2003)
| Kommentar Fra : Morten F. Hansen |
Dato : 04-02-03 22:32 |
|
> Jeg er lidt i tvivl om hvordan man skal bruge directdraw i vinduer.
> Når det er fullscreen, flipper man jo bare mellem sin primære surface og sin
> sekundære - men det kan man vist ikke, når det ikke er fullscreen.
Regner med at du bruger DirectX 7.
Du skal først lave en primary surface (med DDSCAPS_PRIMARYSURFACE i dine surface-caps).
Denne surface er den synlige skærm. Når du laver denne surface skal du egentligt kun
fortælle at det er en surface med DDSCAPS_PRIMARYSURFACE, og ikke ting som f.eks. width,
height eller pixelformat, da dette er givet på forhånd af desktop-opløsningen.
Så skal du lave en back-buffer (med DDSCAPS_OFFSCREENPLAIN i dine surface-caps), som du
tegner din grafik på. Her skal du give den width og height som dit vindue, men stadig
ikke pixelformat (så passer det nemlig til desktop-pixelformatet).
Når du så skal have grafikken fra din back-buffer til skærmen laver du noget ala
følgende:
if FAILED(lpPrimary->Blt(&dest_rect, lpBackBuffer, NULL, DDBLT_WAIT))
HandleError();
hvor lpPrimary er din primary surface, lpBackBuffer er din back-buffer og dest_rect
er position og størrelse på vinduet (altså hvor på skærmen der skal blittes til).
Hvis du har hjælpefilen til DirectX 7, kan du kigge på den tutorial som hedder
"Rendering a Simple Triangle". Her forklares det hvordan man gør ovenstående i
detajler (selv om det er en Direct3D sample, gælder back-buffer og Blt()-teknikken
for DirectDraw også).
| |
Morten F. Hansen (04-02-2003)
| Kommentar Fra : Morten F. Hansen |
Dato : 04-02-03 22:36 |
|
> if FAILED(lpPrimary->Blt(&dest_rect, lpBackBuffer, NULL, DDBLT_WAIT))
> HandleError();
Oops.. Der skal lige byttes om på NULL og DDBLT_WAIT kan jeg se.. :)
| |
Klaus Petersen (04-02-2003)
| Kommentar Fra : Klaus Petersen |
Dato : 04-02-03 22:55 |
|
Mange tak for dit meget anvendelig svar.
Nu blitter du jo din offscreen til primary surface med en DDBLT_WAIT - men
hvis jeg ikke husker helt forkert, får det kun den til at vente på at
blitteren er klar.
Så hvad med vertial sync? Uanset hvad er jeg på rette vej til at forstå hvad
der skal til
| |
Morten F. Hansen (04-02-2003)
| Kommentar Fra : Morten F. Hansen |
Dato : 04-02-03 23:11 |
|
> Mange tak for dit meget anvendelig svar.
Selv tak
> Nu blitter du jo din offscreen til primary surface med en DDBLT_WAIT - men
> hvis jeg ikke husker helt forkert, får det kun den til at vente på at
> blitteren er klar.
DDBLT_WAIT får Blt()-funktionen til at vente på at blitteren er klar, *OG* laver
derefter overførslen af pixels. Hvis man ikke giver den en DDBLT_WAIT vil Blt()
returnere en DDERR_WASSTILLDRAWING-fejl uden at overføre pixels, i tilfælde af
at blitteren har travlt.
> Så hvad med vertial sync? Uanset hvad er jeg på rette vej til at forstå hvad
> der skal til
Jeg kender ikke til nogen metode til at synkronisere sine Blt()-kald med vsync i
DirectX 7, men derfor kan der selvfølgelig godt findes en metode alligevel
I DirectX 8 findes et flag til det, men jeg tror bare flag-konstanten findes uden
at være implementeret.
| |
Klaus Petersen (05-02-2003)
| Kommentar Fra : Klaus Petersen |
Dato : 05-02-03 03:01 |
|
> Jeg kender ikke til nogen metode til at synkronisere sine Blt()-kald med
vsync i
> DirectX 7, men derfor kan der selvfølgelig godt findes en metode alligevel
Måske. Jeg kan se at DirectDraw interfacet har en WaitForVerticalSync
(...) - men det får min computer til at gå helt amok og programmet crasher i
den helt store stil.
Men det kan der jo være så mange årsager til :o}
| |
Morten F. Hansen (05-02-2003)
| Kommentar Fra : Morten F. Hansen |
Dato : 05-02-03 09:43 |
|
> Jeg kan se at DirectDraw interfacet har en WaitForVerticalSync (...) - men det
> får min computer til at gå helt amok og programmet crasher i den helt store stil.
Den funktion kendte jeg ikke, men den ser jo fin ud. Underligt din computer går
ned, når du bruger den. Hvordan laver du funktions-kaldet?
Følgende ser ud til at virke fint på min maskine:
bool dd7_EndFrame()
{
if FAILED(lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL))
return false;
if FAILED(lpPrimary->Blt(&dest_rect, lpBackBuffer, NULL, DDBLT_WAIT, NULL))
return false;
return true;
}
| |
Rasmus Christian Kaa~ (05-02-2003)
| Kommentar Fra : Rasmus Christian Kaa~ |
Dato : 05-02-03 08:40 |
|
> Så skal du lave en back-buffer (med DDSCAPS_OFFSCREENPLAIN i dine
surface-caps), som du
> tegner din grafik på. Her skal du give den width og height som dit vindue,
men stadig
> ikke pixelformat (så passer det nemlig til desktop-pixelformatet).
Hmm, så skal man formentlig tage højde for forskelle i pixel-dybder, det
skal man i hvert fald når man gør noget tilsvarende i GDI.
| |
Gonex (04-02-2003)
| Kommentar Fra : Gonex |
Dato : 04-02-03 22:43 |
|
Følgende kode er skrevet i C# og bruger et VB library fra DX7. Det er
sikkert ikke ligefrem det du leder efter, efter som dette er en C(++)
gruppe. Men til gengæld har jeg næsten lige lavet det og kunne hurtig poste
det. Ellers hvis du ved hvordan man laver fullscreen kan det jo være dette
her er nok til at få dig videre.
Nedenfor er to metoder. En der viser initialisering af et DirectDraw vindue
og en til at foretage tegne operationen i hver game-loop. Håber det er
fejlfri, jeg har skåret noget kode fra for at gøre det mere overskuelig
håber ikke nogle vitale dele er røget med.
class DirectDrawExample
{
private DirectX7 m_directX = new DirectX7();
private DirectDraw7 m_directDraw;
private DirectDrawSurface7 m_primarySurface;
private DDSURFACEDESC2 m_primarySurfaceDescription;
private RECT m_primarySurfaceRect;
private DirectDrawClipper m_directDrawClipper;
private DirectDrawSurface7 m_backBufferSurface;
private DDSURFACEDESC2 m_backBufferSurfaceDescription;
private RECT m_backBufferRect;
private Panel m_panelDirectDrawArea;
protected void InitDirectDrawWindow(bool UseVideoMem)
{
//Setting form proporties
this.Text = "F7S GUI Using DirectDraw.";
this.Width = 806;
this.Height = 644;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
//Creating main menu items and setting menu handlers
MainMenu menu = new MainMenu();
MenuItem item = menu.MenuItems.Add("&File");
item.MenuItems.Add("E&xit", new EventHandler(MenuExit));
item.MenuItems.Add("&Disconnect", new EventHandler(MenuDisconnect));
this.Menu = menu;
//Creating a panel which will represent the DirectDraw window
m_panelDirectDrawArea = new Panel();
m_panelDirectDrawArea.BorderStyle = BorderStyle.Fixed3D;
m_panelDirectDrawArea.Left = 0;
m_panelDirectDrawArea.Top = 0;
m_panelDirectDrawArea.Width = this.Width - 6;
m_panelDirectDrawArea.Height = this.Height - 44;
m_panelDirectDrawArea.BackColor = System.Drawing.Color.White;
this.Controls.Add(m_panelDirectDrawArea);
//Creating DirectDraw
m_directDraw = m_directX.DirectDrawCreate("");
m_directDraw.SetCooperativeLevel(m_panelDirectDrawArea.Handle.ToInt32(),
CONST_DDSCLFLAGS.DDSCL_NORMAL);
//Creating primary surface (frontbuffer)
m_primarySurfaceDescription.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS;
m_primarySurfaceDescription.ddsCaps.lCaps =
CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE;
m_primarySurface = m_directDraw.CreateSurface(ref
m_primarySurfaceDescription);
//Creating clipper object
m_directDrawClipper = m_directDraw.CreateClipper(0);
m_directDrawClipper.SetHWnd(m_panelDirectDrawArea.Handle.ToInt32());
m_primarySurface.SetClipper(m_directDrawClipper);
//Creating backbuffer
m_backBufferSurfaceDescription.lFlags =
CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH |
CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT;
m_backBufferSurfaceDescription.ddsCaps.lCaps =
CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN;
if (UseVideoMem)
m_backBufferSurfaceDescription.ddsCaps.lCaps |=
CONST_DDSURFACECAPSFLAGS.DDSCAPS_VIDEOMEMORY;
else
m_backBufferSurfaceDescription.ddsCaps.lCaps |=
CONST_DDSURFACECAPSFLAGS.DDSCAPS_SYSTEMMEMORY;
m_backBufferSurfaceDescription.lWidth = m_panelDirectDrawArea.Width;
m_backBufferSurfaceDescription.lHeight = m_panelDirectDrawArea.Height;
m_backBufferSurface = m_directDraw.CreateSurface(ref
m_backBufferSurfaceDescription);
//Setting backbuffer ractangel description
m_backBufferRect.Top = 0;
m_backBufferRect.Left = 0;
m_backBufferRect.Bottom = m_backBufferSurfaceDescription.lHeight;
m_backBufferRect.Right = m_backBufferSurfaceDescription.lWidth;
}
protected void DrawScene()
{
//Clearing the backbuffer
m_backBufferSurface.BltColorFill(ref m_backBufferRect, 0);
/********************************************
Draw operations on the back buffer goes here.
*********************************************/
m_directX.GetWindowRect(m_panelDirectDrawArea.Handle.ToInt32(), ref
m_primarySurfaceRect);
m_primarySurface.Blt(ref m_primarySurfaceRect, m_backBufferSurface, ref
m_backBufferRect, CONST_DDBLTFLAGS.DDBLT_WAIT);
}
}
Mvh. Mikael
| |
Michael Rasmussen (05-02-2003)
| Kommentar Fra : Michael Rasmussen |
Dato : 05-02-03 09:39 |
|
"Klaus Petersen" <ng@spectual.ra.bnaa.dk> wrote in message
news:b1pa6a$4du$1@sunsite.dk...
> Hej NG.
>
> Jeg er lidt i tvivl om hvordan man skal bruge directdraw i vinduer.
udover det, der allerede er nævnt kan du kigge på
http://www.gaffer.org/tinyptc/TinyPTC-Windows-0.8.zip for at få lidt
"inspiration".
>
> Når det er fullscreen, flipper man jo bare mellem sin primære surface og
sin
> sekundære - men det kan man vist ikke, når det ikke er fullscreen.
Nej, du skal Blt()'e, og huske at sætte en clipper op for dit vindue.
>
> Så hvordan opnår jeg f.eks. 60 fps i et vindue?
ved at lave dine ting hurtigt nok :)
du kan nemlig ikke vente på vertical sync i window mode.
- Michael
| |
|
|