1

我正在学习 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只能创建2Bit、4Bit、8Bit调色板。32 位显示模式可以兼容 8 位调色板吗?哪里有问题?

如果有人能给我一些建议,我将不胜感激。谢谢。

4

2 回答 2

1

任何大于 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;
于 2013-09-04T20:17:19.013 回答
0

@Retired Ninja 是正确的,我根据他/她的评论实现了我的代码,如下面的工作代码中所示,首先初始化他的视频以使用 16:9 的纵横比,这将使你在 directx 7.0 中获得全屏是我测试的这在:

确实,在使用每像素 32 位 (BPP) bmp 文件时不需要调色板

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)
    ....
.....

这里也是读取 32BPP BMP 文件的工作代码。

void Bitmap::BMP32::Read(BMP32& a_bmp32, const char* file_name) // the new read that will dispaly 32BPP background
{

    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);
    }
}
于 2021-04-07T12:00:11.123 回答