DirectX7 SetPalette всегда терпел неудачу

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

#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 может создавать только 2-битные, 4-битные, 8-битные палитры. Может ли 32-битный режим отображения быть совместимым с 8-битной палитрой? В чем проблема?

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

2 ответа

Решение

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

Чтобы ваш пример работал как есть, измените SCREEN_BPP 8. Проблема в том, что в современных версиях Windows вы можете обнаружить, что ваша палитра не прилипает и возвращается к системной палитре. Здесь можно найти несколько обходных путей: "Эксклюзивная" палитра DirectDraw на самом деле не является эксклюзивной.

Если вы хотите использовать 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;

@Retired Ninja, который прав, и я реализовал свой код на основе его / ее комментариев, как в приведенном ниже рабочем коде, чтобы сначала инициализировать видео, чтобы использовать соотношение сторон 16:9, которое даст вам полноэкранный режим в DirectX 7.0, - это то, что я тестировал это на:

Это правда, что вам не нужна палитра при использовании файла bmp 32 бит на пиксель (BPP).

void Video :: Initialize (void) {

      TRACE("Video::Initialize invoked\n");


try
{
    hrRetVal = DirectDrawCreateEx(NULL, (void**)&pDDraw, IID_IDirectDraw7, NULL);
    if (DD_OK == hrRetVal)
    {
        hrRetVal = pDDraw->SetCooperativeLevel(hwnd,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
        

        if (DD_OK == hrRetVal)
        {
            // Lets see if the video is supported 
            hrRetVal = QueryVideoCapability();
            if (DD_OK != hrRetVal)
            {
                Check(hrRetVal);
            }
                            
            hrRetVal = pDDraw->SetDisplayMode(1600, 900, 32, 60, 0);
            if (DD_OK != hrRetVal)
               throw (VIDEO_EXCEPTION);
            
        }
        else
           throw (VIDEO_EXCEPTION);
    }
    else
        throw (VIDEO_EXCEPTION);
}

catch(int exception)
....

.....

Вот рабочий код для чтения в BMP-файле 32BPP.

void Bitmap :: BMP32 ::Read(BMP32& a_bmp32, const char* file_name) // новое чтение, которое будет отображать фон 32BPP {

      TRACE("Bitmap::BMP32::Read invoked on file_name = %s", file_name);

FILE* fp;
//IMAGE an_image;
//SURFACE a_surface;


if ((fp = fopen(file_name, "rb")) != NULL)
{

    if (fp != NULL)
    {
        TRACE("Reading the first Block of data from %s The File Type Data\n", file_name);
        /*
            uint16_t FileType{ 0x424D };
            uint32_t FileSize{ 0 };
            uint16_t Reserved1{ 0 };
            uint16_t Reserved2{ 0 };
            uint32_t PixelDataOffset{ 0 };
        */

        fread(&a_bmp32.HeaderSection.FileType, sizeof(a_bmp32.HeaderSection.FileType), 1, fp);
        fread(&a_bmp32.HeaderSection.FileSize, sizeof(a_bmp32.HeaderSection.FileSize), 1, fp);
        fread(&a_bmp32.HeaderSection.Reserved1, sizeof(a_bmp32.HeaderSection.Reserved1), 1, fp);
        fread(&a_bmp32.HeaderSection.Reserved2, sizeof(a_bmp32.HeaderSection.Reserved2), 1, fp);
        fread(&a_bmp32.HeaderSection.PixelDataOffset, sizeof(a_bmp32.HeaderSection.PixelDataOffset), 1, fp);

        TRACE("Reading in the Second Block of data from %s The Image Info Data\n", file_name);
        /*
        uint32_t HeaderSize{ 0x28 }; // the size of this structure
        uint32_t ImageWidth{ 0 };
        uint32_t ImageHeight{ 0 };
        uint16_t Planes{ 0 };
        uint16_t BitsPerPixel{ 0 };
        uint32_t Compression{ 0 };
        uint32_t ImageSize{ 0 };
        uint32_t XPixelsPerMeter{ 0 };
        uint32_t YPixelsPerMeter{ 0 };
        uint32_t TotalColors{ 0 };
        uint32_t ImportantColors{ 0 };*/



        fread(&a_bmp32.InfoSection.HeaderSize, sizeof(a_bmp32.InfoSection.HeaderSize), 1, fp);
        fread(&a_bmp32.InfoSection.ImageWidth, sizeof(a_bmp32.InfoSection.ImageWidth), 1, fp);  // if ImageWidth % 4 = Zero then we need to take into consideration row padding
        fread(&a_bmp32.InfoSection.ImageHeight, sizeof(a_bmp32.InfoSection.ImageHeight), 1, fp);
        fread(&a_bmp32.InfoSection.Planes, sizeof(a_bmp32.InfoSection.Planes), 1, fp);
        fread(&a_bmp32.InfoSection.BitsPerPixel, sizeof(a_bmp32.InfoSection.BitsPerPixel), 1, fp);
        fread(&a_bmp32.InfoSection.Compression, sizeof(a_bmp32.InfoSection.Compression), 1, fp);
        fread(&a_bmp32.InfoSection.ImageSize, sizeof(a_bmp32.InfoSection.ImageSize), 1, fp);
        fread(&a_bmp32.InfoSection.XPixelsPerMeter, sizeof(a_bmp32.InfoSection.XPixelsPerMeter), 1, fp);
        fread(&a_bmp32.InfoSection.YPixelsPerMeter, sizeof(a_bmp32.InfoSection.YPixelsPerMeter), 1, fp);
        fread(&a_bmp32.InfoSection.TotalColors, sizeof(a_bmp32.InfoSection.TotalColors), 1, fp);
        fread(&a_bmp32.InfoSection.ImportantColors, sizeof(a_bmp32.InfoSection.ImportantColors), 1, fp);


        TRACE("Reading in the Third Block of data from %s The Color Palette Data\n", file_name);

        /*
        uint8_t RedIntensity{ 0 };
        uint8_t GreenIntensity{ 0 };
        uint8_t BlueIntensity{ 0 };
        uint8_t Reserved{ 0 };
        */

        // note I have only tested this algorithm on 32BPP BMP images
        // in theory the ColorTableSection is skipped on 1,2,4,8 and 16BPP BMP files
        // here I skip that section only for 32BPP or 24BPP


        if (a_bmp32.InfoSection.BitsPerPixel < 24) {

            fread(&a_bmp32.ColorTableSection.RedIntensity, sizeof(a_bmp32.ColorTableSection.RedIntensity), 1, fp);
            fread(&a_bmp32.ColorTableSection.GreenIntensity, sizeof(a_bmp32.ColorTableSection.GreenIntensity), 1, fp);
            fread(&a_bmp32.ColorTableSection.BlueIntensity, sizeof(a_bmp32.ColorTableSection.BlueIntensity), 1, fp);
            fread(&a_bmp32.ColorTableSection.Reserved, sizeof(a_bmp32.ColorTableSection.Reserved), 1, fp);

        }
        else
        {
            TRACE("Reading in the Fourth Block of data from %s The Raw Pixel Data\n", file_name);

            // what are the dimensions of the surface that was read in
        
            
            // a_surface.surfrect.left = 0;
            // a_surface.surfrect.top = 0;
            // a_surface.surfrect.right = a_bmp32.InfoSection.ImageWidth;
            //a_surface.surfrect.bottom = a_bmp32.InfoSection.ImageHeight;

            // an_image.width = a_bmp32.InfoSection.ImageWidth;
            // an_image.height = a_bmp32.InfoSection.ImageHeight;
            // an_image.size = a_bmp32.InfoSection.ImageSize;

            // an_image.buffer = new BYTE[an_image.size];
            
            // fread(an_image.buffer, sizeof(BYTE), an_image.size, fp);
        
            a_bmp32.buffer = new BYTE[a_bmp32.InfoSection.ImageSize];
            fread(a_bmp32.buffer, sizeof(BYTE), a_bmp32.InfoSection.ImageSize, fp);
             

        }



    }



    if (fp != NULL)
    {
        fclose(fp);
    }

}
else
{
    TRACE("Bitmap::Read %s not found\n", file_name);

    char message[60];
    strcpy(message, "BMP Graphics file not found. ");
    strcat(message, file_name);
    strcat(message, "\nApplication will now terminate.");

    FatalMessageBox(message);
}

}

Другие вопросы по тегам