DirectDraw - DDERR_SURFACEBUSY

Odpowiedz Nowy wątek
Taito
2013-09-07 07:58
Taito
0

Witam!
Zacząłem ostatnio bawić się nieco DD i wyszystko bylo ok, dopóki nie spróbowałem wczytac bitmapy do IDirectDrawSurface4. Niby bitmapa laduje się do pamięci, potem przepisuje się do obiektu IDirectDrawSurface4, ale jak próbuje narysować tą powierzchnie na buforze to ciągle mam DDERR_SURFACEBUSY. Wszytsko robie tak jak jest w kursie (tyle że przerabiam kod z C). Jeśli ktoś wie co moge robić źle niech poratuje!
hError przechwytuje błędy DD. Kod obslugi błędów wywaliłem, żeby nie zaśmiecać.

procedure LoadBmpToDDS(const BMPFileName : PAnsiChar; out lpDDS : IDIRECTDRAWSURFACE4);
var
  ddsd : TDDSURFACEDESC2;
  bitmapa : HBITMAP;
  bmpS : BITMAP;
  pomoc : HDC;
  hdcc : HDC;
begin
  lpDDS := nil;
  bitmapa := LoadImage(0, BMPFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

  pomoc := CreateCompatibleDC(0);
  SelectObject(pomoc, bitmapa);
  ZeroMemory(@ddsd, SizeOf(ddsd));
  ddsd.dwSize := SizeOf(ddsd);
  ddsd.dwFlags := DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT;
  ddsd.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN or DDSCAPS_SYSTEMMEMORY;

  GetObject(bitmapa, SizeOf(bmpS), @bmpS);
  ddsd.dwWidth := bmpS.bmWidth;
  ddsd.dwHeight := bmpS.bmHeight;

  hError := lpDD4.CreateSurface(ddsd, lpDDS, nil);

  hError := lpDDS.GetDC(hdcc);
  BitBlt(hdcc, 0, 0, bmpS.bmWidth, bmpS.bmHeight, pomoc, 0, 0, SRCCOPY);

  hError := lpDDS.ReleaseDC(hdcc);

 DeleteDC(pomoc);
 DeleteDC(hdcc);
 DeleteObject(bitmapa);
end;

I rysowanie na buforze

lpDDSBufor.Blt(0, 0, lpDDSbmp, nil, DDBLTFAST_WAIT);

Pozostało 580 znaków

2013-09-07 08:57

Rejestracja: 16 lat temu

Ostatnio: 2 minuty temu

0
  1. DDBLTFAST_WAIT jest do BltFast. Użyj DDBL_WAIT (pewnie i tak mają tę samą wartość, ale chodzi o zasadę).
  2. DirectDraw samo w sobie jest deprecated, ale jak już, to czemu nie użyjesz ostatniej wersji, DD7? Samo to może ci rozwiązać problem... (do DD7 trzeba użyć DirectDrawCreateEx).
  3. I rysowanie na buforze
    Nie podałeś co to za bufor, jak powstaje, a to może wyjaśnić dlaczego jest busy.

edytowany 1x, ostatnio: Azarien, 2013-09-07 09:04

Pozostało 580 znaków

Taito
2013-09-07 16:27
Taito
0

Sorki tam mała literowka. Używam BltFast.

  dds_hdc                 : HDC;                // HDC(kontekst) buforu
  hdcmem                  : HDC;                // kolejny kontekst ;)
  lpDDSEkran, lpDDSBufor  : IDIRECTDRAWSURFACE4;
  lpDD                    : IDirectDraw;        // obiekt DirectDraw
  lpDD4                   : IDirectDraw4;       // obiekt DirectDraw 4

Funkcja tworzenia DD:

function InitDirectDraw( h_Wnd : HWND ) : boolean;
var
  ddsd : TDDSURFACEDESC2;
begin
  Result := true;
  DirectDrawCreate(nil, lpDD, nil) <> DD_OK;
  lpDD.QueryInterface(IID_IDirectDraw4,lpDD4);

  lpDD4.SetCooperativeLevel(h_Wnd, DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN or DDSCL_ALLOWREBOOT);
  lpDD4.SetDisplayMode(DD_Width, DD_Height, DD_bDepth, 0, 0);

  ZeroMemory(@ddsd,sizeof(ddsd));
  ddsd.dwSize := sizeof(ddsd);
  ddsd.dwFlags := DDSD_CAPS or DDSD_BACKBUFFERCOUNT;
  ddsd.ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE
                        or DDSCAPS_FLIP or DDSCAPS_COMPLEX;
  ddsd.dwBackBufferCount := 1;
  lpDD4.CreateSurface(ddsd,lpDDSEkran, nil);
  ddsd.ddsCaps.dwCaps := DDSCAPS_BACKBUFFER;
  lpDDSEkran.GetAttachedSurface(ddsd.ddsCaps, lpDDSBufor);
  hdcmem := CreateCompatibleDC(0);
end;

A narazie korzystam z DD4 bo jak pisałem robie na podstawie kursu a tam jest na DD4. Ale jeśli DD7 może rozwiązać problem to się przerzuce.

daj cały kod, żeby dał się skompilować. - Azarien 2013-09-07 19:32

Pozostało 580 znaków

Taito
2013-09-08 07:01
Taito
0

Już rozgryzłem. Sam sobie blokowałem surface funkcja lpDDS.GetDC... Ale teraz z kolei nie moge dojść jak ustawić kolor np czyszczenia ekranu czy ColorKey dla powierzchni. Próbowałem

$FF00FF, $00FF00FF, RGB(255, 0, 255)

ale kolor jaki z tego wychodzi jest zupełnie inny... Jakieś pomysły?

Pozostało 580 znaków

2013-09-08 16:32

Rejestracja: 16 lat temu

Ostatnio: 2 minuty temu

0

A jaką masz głębię kolorów ekranu? Bo DD_bDepth nic nie mówi.

Dla 24 bitów to będzie albo RGB albo BGR.
Dla 32 bitów masz możliwości: 0RGB, RGB0, 0BGR, BGR0.

Nie ma wiele możliwości, kilka prób i będziesz wiedział.

Najlepiej znajdź gdzie jest czerwony: $FF000000, $00FF0000, $0000FF00 czy $000000FF.

$FF00FF, $00FF00FF
Te dwie liczby są sobie oczywiście równe.

PS. do wczytywania obrazów polecam zapoznać się z biblioteką WIC (Windows Imaging Component). Obsługuje wiele formatów (jpg, png, ...), jest bardziej zrozumiała w użyciu od HBITMAP i ferajny, i działa na interfejsach podobnie jak DirectX.
Nie wiem jednak jak jest z dostępnością unitu do WIC pod Delphi.

edytowany 4x, ostatnio: Azarien, 2013-09-08 16:39

Pozostało 580 znaków

Taito
2013-09-12 08:18
Taito
0

Chyba z tym WIC pod delphi bedzie problem... Co do glebi 24 bity to program mi tego "nie uznaje". Co prawda uruchamia sie ale w rozdzielczosci ekranu (a ma sie uruchomic w 800x600) i jak klikne myszka to sie wysypuje. Przy 8, 16 i 32 jest wszystko ok. Poza tym ciezko mi idzie z debugowaniem bo nie bardzo wiem jak uruchomic program w oknie, a na fullscreen nie moge sie przelaczyc na delphi przy breakpoincie.

Pozostało 580 znaków

2013-09-12 10:05

Rejestracja: 16 lat temu

Ostatnio: 2 minuty temu

0

Chyba z tym WIC pod delphi bedzie problem...
Kwestia napisania unitu importującego interfejsy. Pewnie ktoś już to zrobił, pogóglaj.

bo nie bardzo wiem jak uruchomic program w oknie

SetCooperativeLevel(DDSCL_NORMAL).
Nie robisz SetDisplayMode, przy tworzeniu powierzchni ekranu nie podajesz DDSD_BACKBUFFERCOUNT, DDSCAPS_FLIP ani DDSCAPS_COMPLEX.
Nie robisz GetAttachedSurface, tylko tworzysz drugą powierzchnię o rozmiarze okna (GetClientRect).
Tworzysz clippera (CreateClipper, SetHWnd, SetClipper) do głównej powierzchni.
Pamiętaj że główna powierzchnia nadal wskazuje CAŁY ekran, z całą jego rozdzielczością i głębią kolorów.
Rysujesz na drugiej powierzchni, ale nie robisz Flip tylko Blt do powierzchni podstawowej (ale na pozycję okna, nie na współrzędne 0,0 - patrz zdanie wyżej).

edytowany 1x, ostatnio: Azarien, 2013-09-12 10:06

Pozostało 580 znaków

Taito
2013-09-13 07:48
Taito
0

Dziala jak rzekles. Tylko nadal mnie zastanawia co jest nie tak z ta glebia 24bity... I jeszcze taka rzecz - jak narysowac polprzezroczysta powierzchnie? Bo nie wiem za bardzo jak to ugryzc a w zadnym tutku ktory znalazlem tego nie ma. Z gory dzieki :)

Pozostało 580 znaków

2013-09-13 10:34

Rejestracja: 16 lat temu

Ostatnio: 2 minuty temu

0

Karta graficzna może ci po prostu nie obsługiwać 24-bitowego koloru.

Jeśli przez półprzezroczystość masz na myśli wzajemne przenikanie obiektów, to DD nie ma takiego mechanizmu wbudowanego. Wszystko da się oczywiście zasymulować...

Pozostało 580 znaków

Taito
2013-09-13 12:05
Taito
0

A jak to + - zrobic w DD? Cos ala polprzezroczystosc w vcl w TBitmap? Czy jakos inaczej sie da?

Ale to by troche dziwne bylo ze nie ma 24bitow a 32 sa...

mieszasz dwie bitmapy w ten sposób, że kolor docelowy piksela to średnia arytmetyczna (ważona lub nie) pikseli z dwóch bitmap źródłowych - Azarien 2013-09-13 12:09

Pozostało 580 znaków

Taito
2013-09-18 10:11
Taito
0

Kurcze, ze nie ma zadnego dobrego kursu o DD...
Znowu pojawil sie problem ktorego wczesniej nie zauwazylem...
Na poczatku chcialem zwalniac wszystkie obiekty DD w WM_QUIT ale jakos sie nie zwalnialy (zrobilem log i nie wpisalo ze rozpoczeto zwalnianie obiektow DD), wiec wrzucilem ten kod za petle komunikatow. No i tu jest szkopul: zwalniam wszystko w odwrotnej kolejnosci niz jest tworzone a ciagle mi wyrzuca Runtime error 216... Probowalem komentowac na wszystkie chyba sposoby i nic... ograniczylem sie tylko do inicjalizacji DD i tez nic... ciagle error 216. Czy to mozliwe, ze DD samoistnie zwalnia wszystkie obiekty po wyjsciu z programu?
Zwalniajac najpierw sprawdzam czy np lpDD7 <> nil.

bez kodu chyba nic nie poradzimy... - Azarien 2013-09-18 10:20

Pozostało 580 znaków

Odpowiedz

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0