。。真不容易啊,被个素材搞到我吐血,本来是8位的显示模式,可是那效果太TMD的烂了,改了N小时,。。做了很多无用功
才改成32位模式。。那素材我纠结啊,1帧2帧扫描正常,3.4帧死活不能正常素描~,若有人知道是怎么回事,麻烦告知一下。

 

就是这玩意,第一行 1 。2帧都扫描正常。之后的全部不正常


键盘方向键控制最下面的角色,由于只扫描了2帧动画。看起来怪怪的- -。。我擦

 

 
  
  1. // INCLUDES ///  
  2.  
  3. #define WIN32_LEAN_AND_MEAN  // just say no to MFC  
  4.  
  5. #define INITGUID  
  6.  
  7. #include <windows.h>   // include important windows stuff  
  8. #include <windowsx.h>   
  9. #include <mmsystem.h>  
  10. #include <iostream> // include important C/C++ stuff  
  11. #include <conio.h>  
  12. #include <stdlib.h>  
  13. #include <malloc.h>  
  14. #include <memory.h>  
  15. #include <string.h>  
  16. #include <stdarg.h>  
  17. #include <stdio.h>   
  18. #include <math.h>  
  19. #include <io.h>  
  20. #include <fcntl.h>  
  21.  
  22. #include <ddraw.h> // include directdraw  
  23.  
  24.  
  25. // DEFINES   
  26.  
  27. // defines for windows   
  28. #define WINDOW_CLASS_NAME TEXT("WINCLASS1")  
  29.  
  30. // default screen size  
  31. #define SCREEN_WIDTH    640  // size of screen  
  32. #define SCREEN_HEIGHT   480  
  33. #define SCREEN_BPP      32 // bits per pixel  
  34.  
  35. #define BITMAP_ID            0x4D42 // universal id for a bitmap  
  36. #define MAX_COLORS_PALETTE   256  
  37. #define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))  
  38.  
  39. // TYPES //  
  40.  
  41. // basic unsigned types  
  42. typedef unsigned short USHORT;  
  43. typedef unsigned short WORD;  
  44. typedef unsigned char  UCHAR;  
  45. typedef unsigned char  BYTE;  
  46.  
  47. //BMP 位图容器 结构  
  48. typedef struct BITMAP_FILE_TAG  
  49. {  
  50.         BITMAPFILEHEADER bitmapfileheader;  // 包含位图文件头  
  51.         BITMAPINFOHEADER bitmapinfoheader;  // 位图信息段,包含调色板(如果有的话)  
  52.         PALETTEENTRY     palette[256];      // 调色板我们将存储在这里  
  53.         UCHAR            *buffer;           // 数据指针  
  54.  
  55. } BITMAP_FILE, *BITMAP_FILE_PTR;  
  56. typedef struct ALIEN_OBJ_TYP  
  57. {  
  58.         LPDIRECTDRAWSURFACE7 frames[2]; // 三帧的动画完整步行周期  
  59.         int x,y;                        //外星人的位置  
  60.         int velocity;                   //X坐标的速度  
  61.         int current_frame;              // 当前帧的动画  
  62.         int counter;                    // 动画的使用时间  
  63.  
  64. } ALIEN_OBJ, *ALIEN_OBJ_PTR;  
  65. // PROTOTYPES  //  
  66. //翻转位图  
  67. int Flip_Bitmap(UCHAR *p_w_picpath, int bytes_per_line, int height);  
  68. //读取位图  
  69. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);  
  70. //释放内存  
  71. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap);  
  72. //生成离屏表面  
  73. LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width,int height,int mem_flags);  
  74. //生成剪辑器  
  75. LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,int num_rects,LPRECT clip_list);  
  76. //填充表面  
  77. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color);  
  78. //扫描位图  
  79. int Scan_Image_Bitmap(BITMAP_FILE_PTR bitmap,LPDIRECTDRAWSURFACE7 lpdds,int cx, int cy);      
  80. // MACROS /  
  81.  
  82.  
  83. #define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)  
  84. #define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)  
  85.  
  86.  
  87. #define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }  
  88.  
  89. // GLOBALS   
  90.  
  91. HWND      main_window_handle = NULL;   
  92. int       window_closed      = 0;      
  93. HINSTANCE hinstance_app      = NULL;   
  94.  
  95. // directdraw stuff  
  96.  
  97. LPDIRECTDRAW7         lpdd         = NULL;   // 申请接口对象  
  98. LPDIRECTDRAWSURFACE7  lpddsprimary = NULL;   //主表面  
  99. LPDIRECTDRAWSURFACE7  lpddsback    = NULL;   //背面  
  100. LPDIRECTDRAWPALETTE   lpddpal      = NULL;   //调色板指针  
  101. LPDIRECTDRAWCLIPPER   lpddclipper  = NULL;   //剪切器  
  102. PALETTEENTRY          palette[256];          // 调色板  
  103. PALETTEENTRY          save_palette[256];     // 用于保存调色板  
  104. DDSURFACEDESC2        ddsd;                  // 直接绘制表面的描述结构  
  105. DDBLTFX               ddbltfx;               // 用来填充  
  106. DDSCAPS2              ddscaps;               //直接绘制表面的功能结构  
  107. HRESULT               ddrval;                // result back from dd calls  
  108. DWORD                 start_clock_count = 0; //用于定时  
  109.  
  110. BITMAP_FILE           bitmap;                // holds the bitmap  
  111.  
  112. ALIEN_OBJ             aliens[3];             //3个外星人  
  113.  
  114. LPDIRECTDRAWSURFACE7  lpddsbackground=NULL;        //这将保留背景图片  
  115. char buffer[80];                             // general printing buffer  
  116. int gwidth  = -1;  
  117. int gheight = -1;  
  118.  
  119.  
  120.  
  121. // FUNCTIONS   
  122.  
  123.  
  124.  
  125.  
  126.  
  127. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)  
  128. {  
  129.         //此函数打开一个位图文件,并加载数据导入位图  
  130.  
  131.         int file_handle,  // 文件句柄   
  132.                 index;        // 循环用的变量  
  133.  
  134.         UCHAR   *temp_buffer = NULL; //用于把24位转换成16位的图像  
  135.         OFSTRUCT file_data;          // 文件的数据信息  
  136.  
  137.         //打开文件,如果存在的话  
  138.         if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)  
  139.                 return(0);  
  140.  
  141.         // 现在载入位图文件头  
  142.         _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));  
  143.  
  144.         // 测试,如果这是一个位图文件  
  145.         if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)  
  146.         {  
  147.                 // 关闭文件  
  148.                 _lclose(file_handle);  
  149.  
  150.                 // 返回 error  
  151.                 return(0);  
  152.         } // end if  
  153.  
  154.         //现在我们知道这是一个位图,所以在读取所有部分之前,  
  155.  
  156.         // 首先是读取位图的 infoheader  
  157.  
  158.         //现在载人位图文件头  
  159.         _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));  
  160.  
  161.  
  162.  
  163.         // 最后,读取图像数据本身  
  164.         _llseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);  
  165.  
  166.         //现在读的图像,如果图像是8位或16位则仅仅是读取它,  
  167.         //但如果是24位,就读入一个临时区域,然后将其转换为16位的图像  
  168.  
  169.         if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16 ||   
  170.                 bitmap->bitmapinfoheader.biBitCount==24||bitmap->bitmapinfoheader.biBitCount==32)  
  171.         {  
  172.                 // 删除最后的图像,如果有的话  
  173.                 if (bitmap->buffer)  
  174.                         free(bitmap->buffer);  
  175.  
  176.                 // 为图像分配内存  
  177.                 if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))  
  178.                 {  
  179.                         //分配失败,关闭文件  
  180.                         _lclose(file_handle);  
  181.  
  182.                         // 返回 error  
  183.                         return(0);  
  184.                 } // end if  
  185.  
  186.                 // 现在读取它  
  187.                 _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);  
  188.  
  189.         } // end if  
  190.         else 
  191.         {  
  192.                 // 出现严重问题  
  193.                 return(0);  
  194.  
  195.         } // end else  
  196.  
  197. #if 0  
  198.         // 写出来的文件信息  
  199.         printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",  
  200.                 filename,  
  201.                 bitmap->bitmapinfoheader.biSizeImage,  
  202.                 bitmap->bitmapinfoheader.biWidth,  
  203.                 bitmap->bitmapinfoheader.biHeight,  
  204.                 bitmap->bitmapinfoheader.biBitCount,  
  205.                 bitmap->bitmapinfoheader.biClrUsed,  
  206.                 bitmap->bitmapinfoheader.biClrImportant);  
  207. #endif  
  208.  
  209.         // 关闭文件  
  210.         _lclose(file_handle);  
  211.  
  212.         // 翻转位图  
  213.         Flip_Bitmap(bitmap->buffer,   
  214.                 bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),   
  215.                 bitmap->bitmapinfoheader.biHeight);  
  216.  
  217.  
  218.         return(1);  
  219.  
  220. // end Load_Bitmap_File  
  221.  
  222. ///  
  223.  
  224. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)  
  225. {  
  226.         // 这个函数释放与“位图“相关联的所有内存  
  227.         if (bitmap->buffer)  
  228.         {  
  229.                 // 释放内存  
  230.                 free(bitmap->buffer);  
  231.  
  232.                 //指针置空  
  233.                 bitmap->buffer = NULL;  
  234.  
  235.         } // end if  
  236.  
  237.         // return success  
  238.         return(1);  
  239.  
  240. // end Unload_Bitmap_File  
  241.  
  242. ///  
  243.  
  244. int Flip_Bitmap(UCHAR *p_w_picpath, int bytes_per_line, int height)  
  245. {  
  246.         //此函数是用来翻转自下而上的BMP图像  
  247.  
  248.         UCHAR *buffer; //用来进行图像处理  
  249.         int index;     //循环用的变量  
  250.  
  251.         //分配临时缓冲区  
  252.         if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))  
  253.                 return(0);  
  254.  
  255.         // 将图像复制到工作区  
  256.         memcpy(buffer,p_w_picpath,bytes_per_line*height);  
  257.  
  258.         // 垂直翻转  
  259.         for (index=0; index < height; index++)  
  260.                 memcpy(&p_w_picpath[((height-1) - index)*bytes_per_line],  
  261.                 &buffer[index*bytes_per_line], bytes_per_line);  
  262.  
  263.         //释放内存  
  264.         free(buffer);  
  265.  
  266.         // return success  
  267.         return(1);  
  268.  
  269. // end Flip_Bitmap  
  270.  
  271. LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width,int height,  
  272.                                               int mem_flags)  
  273. {  
  274.                 //        这个函数创建一个简单的离屏表面  
  275.         DDSURFACEDESC2 ddsd;  
  276.         LPDIRECTDRAWSURFACE7 lpdds;//临时用的表面  
  277.  
  278.         //清空并设置size值  
  279.         DDRAW_INIT_STRUCT(ddsd);  
  280.         //设置宽,高,CAPS成员有效  
  281.         ddsd.dwFlags=DDSD_CAPS | DDSD_WIDTH|DDSD_HEIGHT;  
  282.         //设置离屏表面的尺寸  
  283.         ddsd.dwWidth=width;  
  284.         ddsd.dwHeight=height;  
  285.  
  286.         ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN |mem_flags;  
  287.  
  288.         //生成表面  
  289.         if (FAILED(lpdd->CreateSurface(&ddsd,&lpdds,NULL)))  
  290.         {  
  291.                 return 0;  
  292.         }  
  293.         //设置色彩键  
  294.         DDCOLORKEY color_key;  
  295.         color_key.dwColorSpaceLowValue=0;  
  296.         color_key.dwColorSpaceHighValue=0;  
  297.  
  298.         //设置绑定  
  299.         lpdds->SetColorKey(DDCKEY_SRCBLT,&color_key);  
  300.         return lpdds;  
  301. }  
  302.           
  303.  
  304. LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,  
  305.         int num_rects,  
  306.         LPRECT clip_list)  
  307.  
  308. {  
  309.         //这个函数创建一个从发送剪辑列表Clipper和其附加到发送的表面  
  310.  
  311.         int index;                         // 循环变量  
  312.         LPDIRECTDRAWCLIPPER lpddclipper;   // 创建一个指向剪切器的指针  
  313.         LPRGNDATA region_data;             // 数据指针  
  314.         // the header and clip list  
  315.  
  316.         // 创建剪切器  
  317.         if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))  
  318.                 return(NULL);  
  319.  
  320.         //现在创建剪辑列表发送的数据  
  321.  
  322.         //第一个区域的数据存储器分配  
  323.         region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));  
  324.  
  325.         // 现在复制到该矩形的区域的数据  
  326.         memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);  
  327.  
  328.         // set up fields of header  
  329.         region_data->rdh.dwSize          = sizeof(RGNDATAHEADER);  
  330.         region_data->rdh.iType           = RDH_RECTANGLES;  
  331.         region_data->rdh.nCount          = num_rects;  
  332.         region_data->rdh.nRgnSize        = num_rects*sizeof(RECT);  
  333.  
  334.         region_data->rdh.rcBound.left    =  64000;  
  335.         region_data->rdh.rcBound.top     =  64000;  
  336.         region_data->rdh.rcBound.right   = -64000;  
  337.         region_data->rdh.rcBound.bottom  = -64000;  
  338.  
  339.         // find bounds of all clipping regions  
  340.         for (index=0; index<num_rects; index++)  
  341.         {  
  342.                 // test if the next rectangle unioned with the current bound is larger  
  343.                 if (clip_list[index].left < region_data->rdh.rcBound.left)  
  344.                         region_data->rdh.rcBound.left = clip_list[index].left;  
  345.  
  346.                 if (clip_list[index].right > region_data->rdh.rcBound.right)  
  347.                         region_data->rdh.rcBound.right = clip_list[index].right;  
  348.  
  349.                 if (clip_list[index].top < region_data->rdh.rcBound.top)  
  350.                         region_data->rdh.rcBound.top = clip_list[index].top;  
  351.  
  352.                 if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)  
  353.                         region_data->rdh.rcBound.bottom = clip_list[index].bottom;  
  354.  
  355.         } // end for index  
  356.  
  357.         // now we have computed the bounding rectangle region and set up the data  
  358.         // now let's set the clipping list  
  359.  
  360.         if (FAILED(lpddclipper->SetClipList(region_data, 0)))  
  361.         {  
  362.                 // release memory and return error  
  363.                 free(region_data);  
  364.                 return(NULL);  
  365.         } // end if  
  366.  
  367.         // now attach the clipper to the surface  
  368.         if (FAILED(lpdds->SetClipper(lpddclipper)))  
  369.         {  
  370.                 // release memory and return error  
  371.                 free(region_data);  
  372.                 return(NULL);  
  373.         } // end if  
  374.  
  375.         // all is well, so release memory and send back the pointer to the new clipper  
  376.         free(region_data);  
  377.         return(lpddclipper);  
  378.  
  379. // end DDraw_Attach_Clipper  
  380.  
  381. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)  
  382. {  
  383.         DDBLTFX ddbltfx;   
  384.  
  385.         // 清空并设置size字段  
  386.         DDRAW_INIT_STRUCT(ddbltfx);  
  387.  
  388.         // 设置填充颜色  
  389.         ddbltfx.dwFillColor = color;   
  390.  
  391.         // 准备blt到表面  
  392.         lpdds->Blt(NULL,       // ptr to dest rectangle  
  393.                 NULL,       // ptr to source surface, NA              
  394.                 NULL,       // ptr to source rectangle, NA  
  395.                 DDBLT_COLORFILL | DDBLT_WAIT,   // fill and wait                     
  396.                 &ddbltfx);  // ptr to DDBLTFX structure  
  397.  
  398.         // return success  
  399.         return(1);  
  400. // end DDraw_Fill_Surface  
  401.  
  402. ///  
  403.  
  404. int DDraw_Draw_Surface(LPDIRECTDRAWSURFACE7 source, // 要画的源表面  
  405.         int x, int y,                 // 要绘制的位置  
  406.         int width, int height,        // 源表面的尺寸  
  407.         LPDIRECTDRAWSURFACE7 dest,    // 要画的目标表面  
  408.         int transparent = 1)          //透明颜色标志  
  409. {  
  410.         // draw a bob at the x,y defined in the BOB  
  411.         // on the destination surface defined in dest  
  412.  
  413.         RECT dest_rect,   //目标矩形  
  414.                 source_rect; // 源矩形                               
  415.  
  416.         //设置目标矩形的数据  
  417.         dest_rect.left   = x;  
  418.         dest_rect.top    = y;  
  419.         dest_rect.right  = x+width-1;  
  420.         dest_rect.bottom = y+height-1;  
  421.  
  422.         //设置源矩形的数据  
  423.         source_rect.left    = 0;  
  424.         source_rect.top     = 0;  
  425.         source_rect.right   = width-1;  
  426.         source_rect.bottom  = height-1;  
  427.  
  428.         // 透明度标志测试  
  429.  
  430.         if (transparent)  
  431.         {  
  432.                 //启用色彩键  
  433.                   if (FAILED(dest->Blt(&dest_rect, source,  
  434.                         &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),  
  435.                         NULL)))  
  436.                         return(0);  
  437.  
  438.         } // end if  
  439.         else 
  440.         {  
  441.                 //不启用色彩键  
  442.                 if (FAILED(dest->Blt(&dest_rect, source,  
  443.                         &source_rect,(DDBLT_WAIT),  
  444.                         NULL)))  
  445.                         return(0);  
  446.  
  447.         } // end if  
  448.  
  449.         // return success  
  450.         return(1);  
  451.  
  452. // end DDraw_Draw_Surface  
  453.  
  454. int Scan_Image_Bitmap(BITMAP_FILE_PTR bitmap,     // 存放要扫描的位图文件的数据  
  455.         LPDIRECTDRAWSURFACE7 lpdds, // 在表面存储数据  
  456.         int cx, int cy)             // 扫描图像的单元  
  457. {  
  458.         //此函数从位图文件中提取数据  
  459.  
  460.         UCHAR *source_ptr;   // working pointers  
  461.         DWORD        *dest_ptr;  
  462.  
  463.         DDSURFACEDESC2 ddsd;  //  直接绘制表面的描述  
  464.  
  465.         //获取到目标表面的内存地址  
  466.    //设置结构的大小  
  467.         ddsd.dwSize = sizeof(ddsd);  
  468.  
  469.         // 锁定表面  
  470.         lpdds->Lock(NULL,  
  471.                 &ddsd,  
  472.                 DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,  
  473.                 NULL);  
  474.         int ccx,ccy;  
  475.         // 计算开始扫描的位置  
  476.         cx = cx*(ddsd.dwWidth) ;  
  477.         cy = cy*(ddsd.dwHeight) ;  
  478.  
  479.         gwidth  = ddsd.dwWidth;  
  480.         gheight = ddsd.dwHeight;  
  481.  
  482.  
  483.  
  484.  
  485.         // extract bitmap data  
  486.         source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;  
  487.  
  488.         // assign a pointer to the memory surface for manipulation  
  489.         dest_ptr = (DWORD *)ddsd.lpSurface;  
  490.  
  491.         // iterate thru each scanline and copy bitmap  
  492.         for (int index_y = 0; index_y < 80; index_y++)  
  493.         {  
  494.                 for (int index_x = cx; index_x <cx+gwidth; index_x++)  
  495.                 {  
  496.                         // get BGR values  
  497.                         UCHAR blue  = (bitmap->buffer[index_y*640*4 + index_x*4 + 0]),  
  498.                                   green = (bitmap->buffer[index_y*640*4 + index_x*4 + 1]),  
  499.                                   red   = (bitmap->buffer[index_y*640*4 + index_x*4 + 2]);  
  500.  
  501.                         // this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode)  
  502.                         DWORD pixel = _RGB32BIT(0,red,green,blue);  
  503.  
  504.                         // write the pixel  
  505.                         dest_ptr[index_x + (index_y*ddsd.lPitch >> 2)] = pixel;  
  506.  
  507.                 } // end for index_x  
  508.  
  509.         } // end for index_y  
  510.  
  511.         // unlock the surface   
  512.         lpdds->Unlock(NULL);  
  513.  
  514.         // return success  
  515.         return(1);  
  516.  
  517. // end Scan_Image_Bitmap  
  518.  

还有后面一部分,放在第二个文章里