游戏开发论坛

 找回密码
 立即注册
搜索
查看: 4210|回复: 5

请教:我的图片的宽度如果不是 4 的倍数,就不能正常显

[复制链接]

37

主题

67

帖子

73

积分

注册会员

Rank: 2

积分
73
发表于 2007-2-7 17:22:00 | 显示全部楼层 |阅读模式
请教:
我的图片的宽度如果不是 4 的倍数,就不能正常显示,这是什么原因啊?

请教:

#include <ddraw.h>

//BMP图形结构
typedef struct BMPPIC_TAG
        {
        BITMAPFILEHEADER bitmapfileheader;  //文件头
        BITMAPINFOHEADER bitmapinfoheader;  //头信息
        UCHAR            *buffer;      
        } BMPPIC, *BMP_FILE;

//定义屏幕设置
#define SCREEN_WIDTH    800  //屏宽
#define SCREEN_HEIGHT   600  //屏高
#define SCREEN_BPP      16   //位数
//16位5.6.5格式
#define _RGB16BIT565(r,g,b) ((b%32) + ((g%64) << 6) + ((r%32) << 11))

#define BITMAP_ID            0x4D42 //BMP的句柄
#define MAX_COLORS_PALETTE   256


//Directdraw 变量
extern LPDIRECTDRAW7         lpDDraw7;      //Directdraw对象
extern LPDIRECTDRAWSURFACE7  lpDDprimary;   //Directdraw主表面
extern LPDIRECTDRAWSURFACE7  lpDDback ;     //Directdraw后备画面
extern LPDIRECTDRAWSURFACE7  lpDDbpic ;      //Directdraw备用画面
extern LPDIRECTDRAWSURFACE7  lpDDbpic2 ;     //Directdraw备用画面
extern DDSURFACEDESC2        ddsd;          //Directdraw表面描述界面
extern DDBLTFX               ddbltfx;       //Directdraw图形变换变量
extern LPDIRECTDRAWCLIPPER   lpDDclip;      //Directdraw剪切板
extern LPDIRECTDRAWCLIPPER   lpDDclip2;      //Directdraw剪切板
extern BMPPIC           bitmap;        //BMP变量

//DirectDraw函数
int MyDirectDrawInit(void); //DirectDraw初始化
int MyDirectDrawShut(void); //DirectDraw结束

//Directdraw剪切板
LPDIRECTDRAWCLIPPER CreatDDClipper(LPDIRECTDRAWSURFACE7 lpDDraw,
                                         int Clipnumber,
                                         LPRECT clipsqe);
//读取的BMP函数
int FlipBMPFile(UCHAR *image, int bytes_per_line, int height);
int LoadBMPFile(BMP_FILE bitmap, char *filename);
int UnloadBMPFile(BMP_FILE bitmap);

//创建BMP画面
LPDIRECTDRAWSURFACE7 CreatePicSurface(char *filename ,
                                                                          int mem_flags , int colorkey);
//画面数据交换
int SurfaceToBack(LPDIRECTDRAWSURFACE7 sourcesurface , int x1 , int y1,
                                   int x2 , int y2,
                                   LPDIRECTDRAWSURFACE7 destsurface , int x3 , int y3,
                                   int x4 , int y4);




#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>

#include <ddraw.h>

#include"../H/MyDirectDraw.h"

extern HWND main_window_handle; //外部定义的主窗口变量
extern HINSTANCE main_instance; //外部定义的主句柄
//extern char buffer[80];         //外部定义的临时数组


//Directdraw 变量
LPDIRECTDRAW7         lpDDraw7    = NULL;      //Directdraw对象
LPDIRECTDRAWSURFACE7  lpDDprimary = NULL;      //Directdraw主画面
LPDIRECTDRAWSURFACE7  lpDDback    = NULL;      //Directdraw后备画面
LPDIRECTDRAWSURFACE7  lpDDbpic    = NULL;      //Directdraw备用画面
LPDIRECTDRAWSURFACE7  lpDDbpic2    = NULL;      //Directdraw备用画面
DDSURFACEDESC2        ddsd;                    //Directdraw表面描述界面
DDBLTFX ddbltfx;                               //Directdraw图形变换变量
LPDIRECTDRAWCLIPPER   lpDDclip    = NULL;      //Directdraw剪切板
LPDIRECTDRAWCLIPPER   lpDDclip2    = NULL;      //Directdraw剪切板
BMPPIC                bitmap;                  //BMP图


/////////////////////////////////////////////
//DirectDraw初始化
/////////////////////////////////////////////
int MyDirectDrawInit(void)
{
        LPDIRECTDRAW lpDDraw_temp; //Directdraw对象

        //创建Directdraw界面
        if (FAILED(DirectDrawCreate(NULL, &lpDDraw_temp, NULL)))
        {
                MessageBox(NULL,TEXT("Direct Draw Create error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //查询Directdraw界面
        if (FAILED(lpDDraw_temp->QueryInterface(IID_IDirectDraw7,
                (LPVOID *)&lpDDraw7)))
        {
                MessageBox(NULL,TEXT("DirectDraw QueryInterface error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //设置协作等级
        if (FAILED(lpDDraw7->SetCooperativeLevel(main_window_handle,
                DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX |
                DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))
        {
                MessageBox(NULL,TEXT("DirectDraw SetCooperativeLevel error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //设置显示模式
        if (FAILED(lpDDraw7->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,0,0)))
        {
                MessageBox(NULL,TEXT("DirectDraw SetDisplayMode error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //创建主画面及后备画面
        memset(&ddsd,0,sizeof(ddsd));
        ddsd.dwSize=sizeof(ddsd);
       
        //设置dwFlags
        ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

        //定义设置一个后备画面
        ddsd.dwBackBufferCount = 2;

        //定义ddsCaps.dwCaps
        ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;

        //创建主画面
        if (FAILED(lpDDraw7->CreateSurface(&ddsd, &lpDDprimary, NULL)))
        {
                MessageBox(NULL,TEXT("DirectDraw Create primary Surface error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //设置ddsCaps.dwCaps
        ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;

        //连接主画面及后备画面
        if (FAILED(lpDDprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpDDback)))
        {
                MessageBox(NULL,TEXT("DirectDraw Create back Surface error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }
       
        return(1);
}



/////////////////////////////////////////////
//DirectDraw结束
/////////////////////////////////////////////
int MyDirectDrawShut(void)
{
        //释放备用画面指针
        if (lpDDbpic2)
        {
                lpDDbpic2->Release();
                lpDDbpic2 = NULL;
        }       

        //释放备用画面指针
        if (lpDDbpic)
        {
                lpDDbpic->Release();
                lpDDbpic = NULL;
        }       
       
        //释放后备画面指针
        if (lpDDback)
        {
                lpDDback->Release();
                lpDDback = NULL;
        }

        //释放主画面指针
        if (lpDDprimary)
        {
                lpDDprimary->Release();
                lpDDprimary = NULL;
        }

        //释放DirectDraw7界面
        if (lpDDraw7)
        {
                lpDDraw7->Release();
                lpDDraw7 = NULL;
        }

        return(1);
}

/////////////////////////////////////////////
//DirectDraw剪切板
/////////////////////////////////////////////
LPDIRECTDRAWCLIPPER CreatDDClipper(LPDIRECTDRAWSURFACE7 lpDDraw,
                                         int Clipnumber,
                                         LPRECT clipsqe)
{
        int index;
        LPDIRECTDRAWCLIPPER lpDDtempclip; //Directdraw剪切板
        LPRGNDATA clipregion;            //剪切区域序列
                                   
        //创建剪切板
        if (FAILED(lpDDraw7->CreateClipper(0,&lpDDtempclip,NULL)))
        {
                MessageBox(NULL,TEXT("DirectDraw Create clipper error!"),
                        TEXT("Wrong!"),MB_OK);
                return(NULL);
        }
       
        //定义剪切区
        clipregion = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+Clipnumber*sizeof(RECT));
        memcpy(clipregion->Buffer, clipsqe, sizeof(RECT)*Clipnumber);

        clipregion->rdh.dwSize          = sizeof(RGNDATAHEADER);
        clipregion->rdh.iType           = RDH_RECTANGLES;
        clipregion->rdh.nCount          = Clipnumber;
        clipregion->rdh.nRgnSize        = Clipnumber*sizeof(RECT);
        clipregion->rdh.rcBound.left    =  80000;
        clipregion->rdh.rcBound.top     =  80000;
        clipregion->rdh.rcBound.right   = -80000;
        clipregion->rdh.rcBound.bottom  = -80000;


        for (index=0; index<Clipnumber; index++)
    {
                if (clipsqe[index].left < clipregion->rdh.rcBound.left)
                        clipregion->rdh.rcBound.left = clipsqe[index].left;

                if (clipsqe[index].right > clipregion->rdh.rcBound.right)
                        clipregion->rdh.rcBound.right = clipsqe[index].right;

                if (clipsqe[index].top < clipregion->rdh.rcBound.top)
                        clipregion->rdh.rcBound.top = clipsqe[index].top;

                if (clipsqe[index].bottom > clipregion->rdh.rcBound.bottom)
                        clipregion->rdh.rcBound.bottom = clipsqe[index].bottom;
    }
       
        if (FAILED(lpDDtempclip->SetClipList(clipregion, 0)))
        {
                free(clipregion);
                return(NULL);
        }

        if (FAILED(lpDDraw->SetClipper(lpDDtempclip)))
        {
                free(clipregion);
                return(NULL);
        }

        free(clipregion);
        return(lpDDtempclip);
}


/////////////////////////////////////////////
//读取BMP文件
/////////////////////////////////////////////
int LoadBMPFile(BMP_FILE bitmap, char *filename)
{
        int file_handle;  //文件句柄
        UCHAR   *temp_buffer = NULL;
        OFSTRUCT file_data;         

        //打开文件
        if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
        {
                MessageBox(NULL,TEXT("Open bmp File error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //读取文件头
        _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));

        //是否BMP图形格式
        if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
        {
                //关闭文件
                _lclose(file_handle);
                   MessageBox(NULL,TEXT("bmp File ID error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }
       
        //读取文件头
        _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));

        //读数据
        _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);

        //将24位转为16位
        if (bitmap->bitmapinfoheader.biBitCount==16 || bitmap->bitmapinfoheader.biBitCount==24)
        {
                //删除已有信息
                if (bitmap->buffer)
                        free(bitmap->buffer);

                //分配空间
                if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
                {
                        //关闭文件
                        _lclose(file_handle);                       
                        MessageBox(NULL,TEXT("bmp File buffer error!"),
                                TEXT("Wrong!"),MB_OK);
                        return(0);
                }

                //读取
                _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
        }
        else
        {
                //出错
                MessageBox(NULL,TEXT("bmp File read error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);       
        }

        //关闭文件
        _lclose(file_handle);

        //翻转图形
        FlipBMPFile(bitmap->buffer,
                bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),
                bitmap->bitmapinfoheader.biHeight);

        return(1);
}

/////////////////////////////////////////////
//释放BMP文件
/////////////////////////////////////////////
int UnloadBMPFile(BMP_FILE bitmap)
{
        if (bitmap->buffer)
        {
               
                free(bitmap->buffer);
                bitmap->buffer = NULL;

        }

        return(1);
}

/////////////////////////////////////////////
//翻转BMP文件
/////////////////////////////////////////////
int FlipBMPFile(UCHAR *image, int bytes_per_line, int height)
{
        UCHAR *buffer;
        int index;

        // 分配空间
        if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
        {
                MessageBox(NULL,TEXT("flip bmp File buffer error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //翻转
        memcpy(buffer,image,bytes_per_line*height);
        for (index=0; index < height; index++)
                memcpy(&image[((height-1) - index)*bytes_per_line],
                &buffer[index*bytes_per_line], bytes_per_line);

        free(buffer);
        return(1);

}

/////////////////////////////////////////////
//创建BMP画面
/////////////////////////////////////////////
LPDIRECTDRAWSURFACE7 CreatePicSurface(char *filename , int mem_flags , int colorkey)
{
        DDSURFACEDESC2 ddsd;
        LPDIRECTDRAWSURFACE7 picsurface = NULL;

        //读取BMP文件
        if (!LoadBMPFile(&bitmap , filename))
        {
                MessageBox(NULL,TEXT("Load Bitmap File error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

        //创建画面
        memset(&ddsd,0,sizeof(ddsd));
        ddsd.dwSize=sizeof(ddsd);

        ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
        ddsd.dwWidth = bitmap.bitmapinfoheader.biWidth;
        ddsd.dwHeight= bitmap.bitmapinfoheader.biHeight;
        ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = _RGB16BIT565(0,0,0);
        ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = _RGB16BIT565(0,0,0);

        if(mem_flags == 0)
                ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |DDSCAPS_VIDEOMEMORY;
        else
                ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |DDSCAPS_SYSTEMMEMORY;

        if(FAILED(lpDDraw7->CreateSurface(&ddsd,&picsurface,NULL)))
        {
                MessageBox(NULL,TEXT("DirectDraw Create Pic Surface error!"),
                        TEXT("Wrong!"),MB_OK);
                return(NULL);
        }

         //设置色彩关键色
        DDCOLORKEY color_key;
        color_key.dwColorSpaceLowValue  = _RGB16BIT565(0,0,255);
        color_key.dwColorSpaceHighValue = _RGB16BIT565(0,0,255);  
        if(FAILED(picsurface->SetColorKey(DDCKEY_SRCBLT , &color_key)))
        {
                MessageBox(NULL,TEXT("DirectDraw SetColorKey error!"),
                        TEXT("Wrong!"),MB_OK);
                return(NULL);
        }


        //写入BMP数据
        if (FAILED(picsurface->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL)))
        {
                MessageBox(NULL,TEXT("DirectDraw picsurface lock error!"),
                        TEXT("Wrong!"),MB_OK);
                return(NULL);
        }

        //得到指针
        USHORT *pic_buffer = (USHORT *)ddsd.lpSurface;      

        //将位图写入画面
        for (int index_y = 0; index_y < bitmap.bitmapinfoheader.biHeight; index_y++)
    {
                for (int index_x = 0; index_x < bitmap.bitmapinfoheader.biWidth; index_x++)
        {
                        //读取色彩
                        UCHAR blue  = (bitmap.buffer[index_y*bitmap.bitmapinfoheader.biWidth*3 + index_x*3]) >> 3,
                                green = (bitmap.buffer[index_y*bitmap.bitmapinfoheader.biWidth*3 + index_x*3 + 1]) >> 3,
                                red   = (bitmap.buffer[index_y*bitmap.bitmapinfoheader.biWidth*3 + index_x*3 + 2]) >> 3;

                        pic_buffer[index_x + (index_y*ddsd.lPitch >> 1)] = _RGB16BIT565(red,green,blue);
        }
    }

        if (FAILED(picsurface->Unlock(NULL)))
        {
                MessageBox(NULL,TEXT("DirectDraw picsurface Unlock error!"),
                        TEXT("Wrong!"),MB_OK);
                return(NULL);
        }

        //释放BMP
        UnloadBMPFile(&bitmap);

        return (picsurface);
}

/////////////////////////////////////////////
//画面数据交换
/////////////////////////////////////////////
int SurfaceToBack(LPDIRECTDRAWSURFACE7 sourcesurface , int x1 , int y1,
                                   int x2 , int y2,
                                   LPDIRECTDRAWSURFACE7 destsurface , int x3 , int y3,
                                   int x4 , int y4)
{
        RECT dest_rect,   // the destination rectangle
     source_rect; // the source rectangle
       
        dest_rect.left   = x3;
        dest_rect.top    = y3;
        dest_rect.right  = x4;
        dest_rect.bottom = y4;
        source_rect.left    = x1;
        source_rect.top     = y1;
        source_rect.right   = x2;
        source_rect.bottom  = y2;
        if (FAILED(destsurface->Blt(&dest_rect, sourcesurface,
                &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
                NULL)))
        {
                MessageBox(NULL,TEXT("DirectDraw backsurface blt error!"),
                        TEXT("Wrong!"),MB_OK);
                return(1);
        }       
        return (0);
}




//////////////////////////////////
//游戏初始化
//////////////////////////////////
int GameInit(void)
{
       
        //DirectDraw初始化
        MyDirectDrawInit();

        //剪切序列
        RECT rect_list[1] = {{0,0,799,599}};
   // RECT rect_list1[1] = {{0,0,500,500}};
        //建立剪切区
        if (FAILED(lpDDclip = CreatDDClipper(lpDDback,1,rect_list)))
        {
                MessageBox(NULL,TEXT("primary surface Blt error!"),
                        TEXT("Wrong!"),MB_OK);
                return(0);
        }

       
                //建立剪切区
//        if (FAILED(lpDDclip2 = CreatDDClipper(lpDDback,1,rect_list1)))
//        {
//                MessageBox(NULL,TEXT("primary surface Blt error!"),
//                        TEXT("Wrong!"),MB_OK);
//                return(0);
//        }

        if(!(lpDDbpic  = CreatePicSurface(&quotic/BackGround1.bmp" , 0 , 0)))
        {
                MessageBox(NULL,TEXT("Create Pic Background Surface error!"),
                        TEXT("Wrong!"),MB_OK);
                return(1);
        }


        if(!(lpDDbpic2 = CreatePicSurface("Pic/per5.bmp" , 0 , 0)))
        {
                MessageBox(NULL,TEXT("Create Pic Background Surface error!"),
                        TEXT("Wrong!"),MB_OK);
                return(1);
        }


        //DirectInput初始化
        MyDirectInputInit();

        //隐藏鼠标
        ShowCursor(FALSE);

        GameStart();

        return 0;
}



在  int GameInit(void)  

if(!(lpDDbpic2 = CreatePicSurface("Pic/per5.bmp" , 0 , 0)))
        {
                MessageBox(NULL,TEXT("Create Pic Background Surface error!"),
                        TEXT("Wrong!"),MB_OK);
                return(1);
        }

如果我的 per5.bmp 宽度不为 4  的倍数的话,就有错!


大哥,我要改哪里,才可以使它是任何宽度都可以呢?


还有

//16位5.6.5格式
#define _RGB16BIT565(r,g,b) ((b%32) + ((g%64) << 6) + ((r%32) << 11))

是什么意思?
是不是  16位5.6.5格式 只能显示 16 位的位图,为什么 我 24 位的也可以显示呢?
还有,是不是 565 太低了


谢谢!
[em3] [em13] [em24] [em3]

2万

主题

2万

帖子

6万

积分

论坛元老

Rank: 8Rank: 8

积分
66489
QQ
发表于 2007-2-7 18:01:00 | 显示全部楼层

Re:请教:我的图片的宽度如果不是 4 的倍数,就不能正常

BMP是按32位对齐的,一行象素数据的总字节长度必须能被4整除,不足的随便补什么。

6

主题

307

帖子

309

积分

中级会员

Rank: 3Rank: 3

积分
309
发表于 2007-2-7 18:02:00 | 显示全部楼层

Re:请教:我的图片的宽度如果不是 4 的倍数,就不能正常

D3D装载的纹理都必须是2的N次方大小,不是的会自动放大到符合

放大的方法,根据你是否设了过滤器,会留空白或拉伸

0

主题

275

帖子

676

积分

高级会员

Rank: 4

积分
676
发表于 2007-2-7 22:54:00 | 显示全部楼层

Re:请教:我的图片的宽度如果不是 4 的倍数,就不能正常

?在????都是??R32bit所以要?正
?正公式 加 3 AND 3的?? 就是
int pWidth=(width+3)&~3;

37

主题

67

帖子

73

积分

注册会员

Rank: 2

积分
73
 楼主| 发表于 2007-2-8 08:01:00 | 显示全部楼层

Re:请教:我的图片的宽度如果不是 4 的倍数,就不能正常

真是太感谢各位大哥了!

2万

主题

2万

帖子

6万

积分

论坛元老

Rank: 8Rank: 8

积分
66489
QQ
发表于 2007-2-8 11:20:00 | 显示全部楼层

Re: Re:请教:我的图片的宽度如果不是 4 的倍数,就不能正

Aming: Re:请教:我的图片的宽度如果不是 4 的倍数,就不能正常显示,这是什么原因啊?

?在????都是??R32bit所以要?正
?正公式 加 3 AND 3的?? 就是
int pWidth=(width+3)&~3;


这个和记忆体没有任何关系,只是BMP设计的是这样。
你拿一台286跑windows 3.0,它BMP也是32位对齐。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2026-1-26 10:40

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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