2013-09-04 2 views
1

Я изучаю DirectX, я хочу привязать палитру к PrimarySurface, но процесс всегда терпел неудачу. Я даю свой код ниже:DirectX7 SetPalette всегда сбой

#define SCREEN_WIDTH 640 
#define SCREEN_HEIGHT 480 
#define SCREEN_BPP 32 
#define MAX_COLORS_PALETTE 256 

#define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct, 0, sizeof(ddstruct)); ddstruct.dwSize = sizeof(ddstruct); } 

LPDIRECTDRAW7 lpdd = NULL; 
LPDIRECTDRAWSURFACE7 lpddPrimarySurface = NULL; 
LPDIRECTDRAWPALETTE lpddPalette = NULL; 
PALETTEENTRY palette[256]; 

// Omit the unneccessary content 

int GameInit() 
{ 
    if (FAILED(DirectDrawCreateEx(NULL, (void**)&lpdd, IID_IDirectDraw7, NULL))) 
     return 0; 
    if (FAILED(lpdd->SetCooperativeLevel(g_GameHwnd, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT))) 
     return 0; 
    if (FAILED(lpdd->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0, 0))) 
     return 0; 

    DDRAW_INIT_STRUCT(ddsd); 
    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; 
    ddsd.dwBackBufferCount = 1; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; 

    if (FAILED(lpdd->CreateSurface(&ddsd, &lpddPrimarySurface, NULL))) 
     return 0; 

    ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; 
    if (FAILED(lpddPrimarySurface->GetAttachedSurface(&ddsd.ddsCaps, &lpddBackSurface))) 
     return 0; 

    memset(palette, 0, MAX_COLORS_PALETTE * sizeof(PALETTEENTRY)); 

    for (int index = 0; index < MAX_COLORS_PALETTE; index++) 
    { 
     if (index < 64) 
      palette[index].peRed = index * 4; 
     else if (index >= 64 && index < 128) 
      palette[index].peGreen = (index - 64) * 4; 
     else if (index >= 128 && index < 192) 
      palette[index].peBlue = (index - 128) * 4; 
     else if (index >= 192 && index < 256) 
      palette[index].peRed = palette[index].peGreen = palette[index].peBlue = (index - 192) * 4; 

     palette[index].peFlags = PC_NOCOLLAPSE; 
    } 

    if (FAILED(lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, palette, &lpddPalette, NULL))) 
     return 0; 

    **// I always failed to set palette to primary surface here....** 
    if (FAILED(lpddPrimarySurface->SetPalette(lpddPalette))) 
    { 
     MessageBox(NULL, "Failed", NULL, MB_OK); 
     return 0; 
    } 

    DDRAW_INIT_STRUCT(ddsd); 

    if (FAILED(lpddBackSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))) 
     return 0; 

    UINT *videoBuffer = (UINT*)ddsd.lpSurface; 

    for (int y = 0; y < SCREEN_HEIGHT; y++) 
    { 
     memset((void*)videoBuffer, y % 256, SCREEN_WIDTH * sizeof(UINT)); 
     videoBuffer += ddsd.lPitch >> 2; 
    } 

    if (FAILED(lpddBackSurface->Unlock(NULL))) 
     return 0; 


    return 1; 
} 

Я не знаю, почему я всегда не получал SetPalette на основной поверхности. Я установил DisplayMode на 640 * 480 * 32, моя палитра только 256-цветная, это причина? Но я консультирую MSDN, CreatePalette может создавать только 2Bit, 4Bit, 8Bit палитры. Может ли 32-битный режим отображения быть совместимым с палитрой 8Bit? В чем проблема?

Буду признателен, если кто-нибудь может дать мне совет. Благодарю.

+1

Священный крест ..! Подождите. Это DirectDraw? Поддерживается ли она? Я имею в виду, можете ли вы запустить его в своей операционной системе? Во всяком случае, проверьте правильность ошибок, чтобы понять, почему это происходит. Вы можете преобразовать код ошибки «HRESULT» (который возвращается практически всеми функциями DirectX) в читаемую строку. В древние времена для этого была библиотека-помощник «dxerr». И ... может быть, вам лучше получить DirectX 11 и/или Direct2D? =) – Drop

+0

Вероятно, [это] (http://stackoverflow.com/questions/18613229/loading-textures-in-directx/18622954#18622954) макрос будет делать трюк. Используйте его, чтобы получить описание ошибок. – Drop

+0

@Drop: Может быть, ему будет лучше с OpenGL, поэтому он не застрянет с Microsoft. – SigTerm

ответ

1

Все, что отличается от 8-битного режима (16, 24, 32), являются прямыми цветовыми режимами, а данные в буфере кадра являются фактическим цветом, поэтому нет палитры, как в 8-битном индексированном цвете Режим.

Чтобы ваш пример работал так, как это, измените SCREEN_BPP на 8. Проблема с этим в современных версиях Windows, вы можете обнаружить, что ваша палитра не вставлена, и она возвращается к системной палитре. Ниже приведены некоторые обходные пути, которые вы можете попробовать: "Exclusive" DirectDraw palette isn't actually exclusive

Если вы хотите использовать 32-битный режим, тогда нет палитры, и вы должны установить цвет напрямую, а не использовать индекс в палитре. Вы можете сделать что-то подобное, чтобы скопировать цвет палитры в буфер рамки в вашем примере:

if (FAILED(lpddBackSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))) 
    return 0; 

UINT *videoBuffer = (UINT*)ddsd.lpSurface; 

for (int y = 0; y < SCREEN_HEIGHT; y++) 
{ 
    const PALETTEENTRY& p = palette[y%256]; 
    UINT color = (p.peRed << 16) | (p.peGreen << 8) | p.peBlue; 
    for(int x = 0; x < SCREEN_WIDTH; ++x) 
    { 
     videoBuffer[x] = color; 
    } 
    videoBuffer += ddsd.lPitch/sizeof(UINT); 
} 

if (FAILED(lpddBackSurface->Unlock(NULL))) 
    return 0; 
+0

Большое спасибо ~ Я поймаю это. –