游戏开发论坛

 找回密码
 立即注册
搜索
查看: 4588|回复: 4

解析到主显示表面的8位BMP位图失真颜色暗淡

[复制链接]

3

主题

6

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2009-2-15 20:53:00 | 显示全部楼层 |阅读模式
rt,是按照 《游戏编程大师技巧》里面的知识写的,个人觉得跟例子代码差不多,但是书里面的代码可以正常显示8位的bmp位图,而我的显示暗淡。但是形状基本没有变,就像没有光照的样子,小弟初学游戏编程,刚走了没有几步,就有问题啦,哪位大哥帮忙看看啊,万分感谢。


代码如下:

// Game7.cpp : Defines the entry point for the application.
//



#include "stdafx.h"
#include "resource.h"
#include "ddraw.h"
#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"

#define MAX_LOADSTRING 100
#define KEYDOWN(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000)?1:0)
#define SCREEN_WIDTH   640
#define SCREEN_HEIGHT  480
#define SCREEN_BPP      8

// Global Variables:
HINSTANCE hInst;                                                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                                                                // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];                                                                // The title bar text
LPDIRECTDRAW7   lpdd7;
LPDIRECTDRAWPALETTE lpddpal;
LPDIRECTDRAWSURFACE7 lpddprimarysurface;
LPDIRECTDRAWSURFACE7 lpddbacksurface;

HWND  g_hWnd;
PALETTEENTRY  g_palette[256];
DDSURFACEDESC2  g_ddsur;
DDSURFACEDESC2  ddsd;
DDSCAPS2        ddsCaps;




// Foward declarations of functions included in this code module:
ATOM                                MyRegisterClass(HINSTANCE hInstance);
BOOL                                InitInstance(HINSTANCE, int);
LRESULT CALLBACK        WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK        About(HWND, UINT, WPARAM, LPARAM);



typedef  struct   BITMAP_FILE_TAG
{
        BITMAPFILEHEADER  bitmapfileheader;
        BITMAPINFOHEADER  bitmapinfoheader;
        PALETTEENTRY      palette[256];
        UCHAR  *          Buffer;

}BITMAP_FILE;


BITMAP_FILE   bitmap;

//位图数据翻转函数
void  Flip_Bitmap(UCHAR *buffer,int size_per_line,int lines)
{
        UCHAR * temp_buffer=(UCHAR *)malloc(size_per_line *lines);
    memcpy(temp_buffer,buffer,size_per_line*lines);

        for (int i=0;i<lines;i++)
        {
                memcpy(&buffer[(lines-i-1)*size_per_line],&temp_buffer[i*size_per_line],size_per_line);
        }

        free(temp_buffer);

}

//这个函数从盘上读取BMP文件信息,放入到BITMAP_FILE这个结构中
int   Load_Bitmap_File(BITMAP_FILE *bitmap,char *filename)
{
        FILE *pfile;
        pfile=fopen(filename,"r");
        if (pfile==NULL)
        {
                MessageBox(g_hWnd,"打开BMP文件失败","提示",NULL);
                return 0;
        }

        fread(&(bitmap->bitmapfileheader),1,sizeof(BITMAPFILEHEADER),pfile);

        if (bitmap->bitmapfileheader.bfType !=0x4D42)
        {
                fclose(pfile);
                MessageBox(g_hWnd,"不是BMP文件,不能解析","提示",NULL);
                return 0;
        }

        fread(&(bitmap->bitmapinfoheader),1,sizeof(BITMAPINFOHEADER),pfile);
        if (bitmap->bitmapinfoheader.biBitCount==8)//如果是8位读入调色板信息
        {
                fread(&(bitmap->palette),1,sizeof(PALETTEENTRY)*256,pfile);
                for (int i=0;i<256;i++)//颠倒颜色顺序
                {
                        int temp_color=bitmap->palette.peRed;
                        bitmap->palette.peRed=bitmap->palette.peBlue;
                        bitmap->palette.peBlue=temp_color;
                        bitmap->palette.peFlags=PC_NOCOLLAPSE;
                }
        }

        fseek(pfile,(bitmap->bitmapinfoheader.biSizeImage)*(-1),SEEK_END);//定位文件指针到真正的位图数据块

        //下面拷贝真正的位图数据
        if (bitmap->bitmapinfoheader.biBitCount==8 ||bitmap->bitmapinfoheader.biBitCount==16 ||bitmap->bitmapinfoheader.biBitCount==24)
        {
                if (bitmap->Buffer)//如果有数据,释放
                {
                        free(bitmap->Buffer);
                }

                //申请内存空间
                bitmap->Buffer=(UCHAR *)malloc (bitmap->bitmapinfoheader.biSizeImage);
                if (bitmap->Buffer==NULL)
                {
                fclose(pfile);
                MessageBox(g_hWnd,"文件数据内存分配失败","提示",NULL);
                return 0;
                }

                fread(bitmap->Buffer,1,bitmap->bitmapinfoheader.biSizeImage,pfile);
        }

        else
        {
                MessageBox(g_hWnd,"颜色深度不对","提示",NULL);
                return 0;

        }

        //关闭文件指针
        fclose(pfile);

        //下面翻转位图数据
        if (bitmap->bitmapinfoheader.biHeight>0)
        {
                //MessageBox(g_hWnd,"翻转位图","提示",NULL);
                Flip_Bitmap(bitmap->Buffer,(bitmap->bitmapinfoheader.biWidth)*(bitmap->bitmapinfoheader.biBitCount)/8,bitmap->bitmapinfoheader.biHeight);
        }

    return   1;
}


int  Unload_Bitmap_File(BITMAP_FILE * bitmap)
{
        if (bitmap->Buffer)
        {
                free(bitmap->Buffer);
        }

    bitmap->Buffer=NULL;
        return 1;
}


int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)
{
        DDBLTFX ddbltfx;

        ddbltfx.dwSize=sizeof(DDBLTFX);
        ddbltfx.dwFillColor = color;
        lpdds->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&ddbltfx);  

        return(1);
}




int Game_Init(void *parms=NULL, int num_parms=0)
{
        //获得DirectDraw7接口
        if (FAILED(DirectDrawCreateEx(NULL,(void **)&lpdd7,IID_IDirectDraw7,NULL)))
        {
                MessageBox(g_hWnd,"DirectDraw7获取失败","提示",NULL);
                return  0;
        }
   
        //设置与windows协作
        if(FAILED(lpdd7->SetCooperativeLevel(g_hWnd,DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX |DDSCL_EXCLUSIVE |DDSCL_ALLOWREBOOT)))
        {
                MessageBox(g_hWnd,"与windows协作失败","提示",NULL);
                return  0;
        }
       
        //设置视频模式
        if(FAILED(lpdd7->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,0,0)))
        {
                MessageBox(g_hWnd,"设置视频模式失败","提示",NULL);
                return  0;
        }

        //创建调色板
        for (int i=1;i<255;i++)
        {
                g_palette.peRed=rand()%256;
                g_palette.peGreen=rand()%256;
                g_palette.peBlue=rand()%256;
                g_palette.peFlags=PC_NOCOLLAPSE;

        }
        g_palette[0].peRed=0;
        g_palette[0].peGreen=0;
        g_palette[0].peBlue=0;
        g_palette[0].peFlags=PC_NOCOLLAPSE;

        g_palette[255].peRed=255;
        g_palette[255].peGreen=255;
        g_palette[255].peBlue=255;
        g_palette[255].peFlags=PC_NOCOLLAPSE;

        if(FAILED(lpdd7->CreatePalette(DDPCAPS_8BIT |DDPCAPS_ALLOW256 |DDPCAPS_INITIALIZE,g_palette,&lpddpal,NULL)))
        {       
                MessageBox(g_hWnd,"创建调色板失败","提示",NULL);
                return  0;
        }

        //创建主显示表面
        g_ddsur.dwSize=sizeof(DDSURFACEDESC2);
        g_ddsur.dwFlags=DDSD_CAPS;
        g_ddsur.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;

   if(FAILED(lpdd7->CreateSurface(&g_ddsur,&lpddprimarysurface,NULL)))
   {
           MessageBox(g_hWnd,"创建主显示表面失败","提示",NULL);
           return  0;
   }





   //关联主显示表面和调色板
   if ( FAILED(lpddprimarysurface->SetPalette(lpddpal)))
   {
           MessageBox(g_hWnd,"主表面关联调色板失败","提示",NULL);
           return  0;
   }
      
   if(Load_Bitmap_File(&bitmap,"bitmap8.bmp")==0)
   {
           MessageBox(g_hWnd,"读取位图失败","提示",NULL);
           return  0;
   }

  //改变调色板
   if (FAILED(lpddpal->SetEntries(0,0,256,bitmap.palette)))
   {
           MessageBox(g_hWnd,"调入位图调色板失败","提示",NULL);
           return  0;
   }

   // clean the surface
//DDraw_Fill_Surface(lpddprimarysurface,0);

        return 1;
}





int Game_ShutDown(void *parms=NULL, int num_parms=0)
{

        if (lpddprimarysurface)
        {
                lpddprimarysurface->Release();
                lpddprimarysurface=NULL;
        }

        if (lpddpal)
        {
                lpddpal->Release();
                lpddpal=NULL;
        }

        if (lpdd7)
        {
                lpdd7->Release();
                lpdd7=NULL;
        }

        Unload_Bitmap_File(&bitmap);

        return 1;
}

int Game_Main(void *parms=NULL, int num_parms=0)
{

        if (KEYDOWN(VK_ESCAPE))
        {
                SendMessage(g_hWnd,WM_CLOSE,0,0);
        }


        //锁定主显示表面
        ddsd.dwSize=sizeof(DDSURFACEDESC2);
        if (FAILED( lpddprimarysurface->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL)))
        {
                MessageBox(g_hWnd,"锁定主显示表面失败","提示",NULL);
                return  0;
        }

        UCHAR *primary_buffer=(UCHAR *)ddsd.lpSurface;

        if (ddsd.lPitch == SCREEN_WIDTH)
        {
                memcpy((void *)primary_buffer, (void *)bitmap.Buffer, SCREEN_WIDTH*SCREEN_HEIGHT);
        }
        else
        {
                UCHAR *dest_ptr = primary_buffer;
                UCHAR *src_ptr  = bitmap.Buffer;
               

                for (int y=0; y < SCREEN_HEIGHT; y++)
                {
               
                        memcpy((void *)dest_ptr, (void *)src_ptr, SCREEN_WIDTH);
                       

                        dest_ptr+=ddsd.lPitch;
                        src_ptr +=SCREEN_WIDTH;
                }        
        }

       
       

        // now unlock the primary surface
        if (FAILED(lpddprimarysurface->Unlock(NULL)))
                return(0);

        return 1;

}



int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
        // TODO: Place code here.
        MSG msg;
        HACCEL hAccelTable;
        int  start_tick;

        // Initialize global strings
        LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadString(hInstance, IDC_GAME7, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);

        // Perform application initialization:
        if (!InitInstance (hInstance, nCmdShow))
        {
                return FALSE;
        }

        hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_GAME7);

        // Main message loop:

        Game_Init();

        while (1)
        {
                start_tick=GetTickCount();
                if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
                {
                        if (msg.message==WM_QUIT)
                        {
                                break;
                        }
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                }
               
                Game_Main();
                while (GetTickCount()-start_tick<33);       
        }
        Game_ShutDown();
        return msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage is only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
        WNDCLASSEX wcex;

        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style                        = CS_DBLCLKS |CS_HREDRAW | CS_VREDRAW| CS_OWNDC;
        wcex.lpfnWndProc        = (WNDPROC)WndProc;
        wcex.cbClsExtra                = 0;
        wcex.cbWndExtra                = 0;
        wcex.hInstance                = hInstance;
        wcex.hIcon                        = LoadIcon(hInstance, (LPCTSTR)IDI_GAME7);
        wcex.hCursor                = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground        = (HBRUSH)GetStockObject(WHITE_BRUSH);
        //wcex.lpszMenuName        = (LPCSTR)IDC_GAME3;
        wcex.lpszMenuName=NULL;
        wcex.lpszClassName        = szWindowClass;
        wcex.hIconSm                = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

        return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_POPUP | WS_VISIBLE,
      0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);

   g_hWnd=hWnd;
   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND        - process the application menu
//  WM_PAINT        - Paint the main window
//  WM_DESTROY        - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        int wmId, wmEvent;
        PAINTSTRUCT ps;
        HDC hdc;
        TCHAR szHello[MAX_LOADSTRING];
        LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

        switch (message)
        {
                case WM_COMMAND:
                        wmId    = LOWORD(wParam);
                        wmEvent = HIWORD(wParam);
                        // Parse the menu selections:
                        switch (wmId)
                        {
                                case IDM_ABOUT:
                                   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
                                   break;
                                case IDM_EXIT:
                                   DestroyWindow(hWnd);
                                   break;
                                default:
                                   return DefWindowProc(hWnd, message, wParam, lParam);
                        }
                        break;
                case WM_PAINT:
                        hdc = BeginPaint(hWnd, &ps);
                        // TODO: Add any drawing code here...
                        RECT rt;
                        GetClientRect(hWnd, &rt);
                        DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
                        EndPaint(hWnd, &ps);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
        switch (message)
        {
                case WM_INITDIALOG:
                                return TRUE;

                case WM_COMMAND:
                        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
                        {
                                EndDialog(hDlg, LOWORD(wParam));
                                return TRUE;
                        }
                        break;
        }
    return FALSE;
}



19

主题

638

帖子

638

积分

高级会员

Rank: 4

积分
638
发表于 2009-2-15 21:35:00 | 显示全部楼层

Re:解析到主显示表面的8位BMP位图失真颜色暗淡

DDraw在两年前就obsolete了,不要再在上面浪费时间了,直接学D3D9或者DX11的Direct2D吧

3

主题

6

帖子

13

积分

新手上路

Rank: 1

积分
13
 楼主| 发表于 2009-2-16 09:51:00 | 显示全部楼层

Re:解析到主显示表面的8位BMP位图失真颜色暗淡

我的这本书就是讲DDraw的啊,先学2D再学3D啊。请教。。。高手,师兄们。。。,好心人

19

主题

638

帖子

638

积分

高级会员

Rank: 4

积分
638
发表于 2009-2-16 20:01:00 | 显示全部楼层

Re: Re:解析到主显示表面的8位BMP位图失真颜色暗淡

tangaowen: Re:解析到主显示表面的8位BMP位图失真颜色暗淡

我的这本书就是讲DDraw的啊,先学2D再学3D啊。请教。。。高手,师兄们。。。,好心人


DirectX只是个底层API,各个组件是独立的,没什么先后顺序。你学了DDraw,对其他的东西也一点用也没有。从API上讲,DDraw其实比D3D9还不好用。DDraw是十年前显卡的功能的接口,而新的显卡核心是D3D10架构,DDraw的功能都是用D3D10模拟的,当然现在主流还是D3D9。

3

主题

6

帖子

13

积分

新手上路

Rank: 1

积分
13
 楼主| 发表于 2009-2-18 12:52:00 | 显示全部楼层

Re:解析到主显示表面的8位BMP位图失真颜色暗淡

不管怎么说,我的意思是我在做这个东东,就要弄个明白,知道怎么回事而已,跟这个已经是否过时没有关系。也许我是死脑筋,你叫我看了一半的一本经典书放下,那是不可能的,OK?DDraw我在学,同样D3D我也会学,只是我现在在学DDraw,难道你要我放下这个去学D3D,这些东西都是触类旁通的,学会了DDraw,再去学D3D就会很快了是吧。不会就别在这里打消我的积极性,OK?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-20 07:42

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表