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);
}
}