爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      游戏编程之十五 DirectDraw 的基本知识

      首页 知识中心 云计算 文章详情页

      游戏编程之十五 DirectDraw 的基本知识

      2023-02-20 10:22:15 阅读次数:489

      游戏,计算机

       

      DirectDraw 游戏编程基础(2)



      游戏使计算机的发展超越了晶体管时代
             
          


      例程1(DDEX1):DirectDraw 的基本知识
      在使用 DirextDraw时,需要首先创建一个对象DirectDraw 的实体,该对象实体代表了微机显示适配器。然后,使用接口所提供的方法来操作该对象实体,使之完成有关命令和任务。接着,你还需要创建一个或多个 DirectDraw-surface对象的实体,以便能在图形表面(Surface)上展示你的游戏画面。
      下面,在例程 DDEX1 中展示如何使用Directx 3 SDK来 DirectDraw对象实体,如何创建一个带有后台缓冲区的基本表面(Surface),以及如何弹出表面(Surface)。


      注意:所有的例程都是用C++写成的,如果你的编辑器是C,你需要在文件中作出某些改动(至少,你要加入 Vtable 和指向各种接口方法的 this 指针)。
      DirectDraw 初始化:
           DirectDraw 初始化代码写在例程 DDEX1 的 doInit 函数中。


              /*
               * Create the main DirectDraw object.
               */
           ddrval = DirectDrawCreate(NULL,&lpDD,NULL);
           if(ddrval==DD_OK)
             {
               //Get exclusive mode.
               Ddrval=lpdd->SetCooperativeLevel(hwnd,
                                    DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
               if(ddrval==DD_OK)
                 {
                   //Create the primary surface with 1 back buffer.
                   Ddsd.dwSize = sizeof(ddsd);
                   ddsd.dwFlags = DDSD_CAPS \ DSD_BACKBUFFERCOUNT;
                   ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | 
                                             DDSCAPS_FLIP |
                                             DDSCAPS_COMPLEX;
                   ddsd.dwBackBufferCount = 1;
                   ddrval = lpDD->CreateSurfae(&ddsd, &lpDDSPrimary,
                 NULL);
                   if(ddrval == DD_OK)
                    {
                     //Cet a pointer to the back buffer.
                     Ddscaps.dwCaps = DDSCAPS_BACKBUFFER; 
                     ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps,
                                                              &lpDDSBack);
                     if( ddrval == DD_OK)
                     { // Draw some text.
                     If(lpDDSPrimary->GetDC(&hdc) == DD_OK)
                     { 
                       SetBkColor(hdc, RGB(0,0,255));
                       SetTextColor( hdc,RGB(255,255,0 ) );
                       TextOut( hdc, 0, 0, sxFrontMsg, lstrlen(szFrontMsg ));
                       lpDDSPrimary->ReleaseDC(hdc);
                       }
                       if(lpDDSBack->GetDC(&hdc) == DD_OK)
                       {
                         SetBkColor( hdc, RGB(0, 0, 255 ) );
                         SetTextColor( hdc, RGB( 255,255, 0 ) ):
                         TexOut( hdc, 0, 0, szBackMsg, lstrlen( szBackMsg ) );
                         lpDDSBack->ReleaseDC(hdc);
                         }
                       // Create a timer to flop the pages.
                       If(SetTimer( hwnd, TIMER_ID, TIMER_RATE, NULL))
                         {
                          return TRUE;
                          }
                       }
                    }
                  }
                }
              }
              wsprintf(buf,"Direct Draw Init Failed (%08lx)\n",ddrval);
                .
                .
                .


      以下针对初始化 DirectDraw 对象和准备表面(Surface)集的各个步骤分别进行讨论:


      创建一个 DirectDraw 对象
          为了创建一个 DirecDraw 对象实体,你应该在程序中使用DirectDrawCreate API 函数(注意:这里我所说的是应该,而不是必须), 这是因为使用 OLE 中的 CoCreatelnstance 函数也能创建一个 DirectDraw 对象实体,但这不在我们的讨论范围之中)。DirectDrawCreate 采用全球统一的标准,它代表显示设备,这些显示设备在大多数情况下被定为 NULL (即:系统使用缺省的显示设备)。 当DirectDraw对象实体创建好后,就会有一个指针指向该对象实体。而且,在调色板中有三分之一的指针指向 NULL (这样做的目的是为了今后的扩展)。
      接下来的例子说明如何创建一个DirectDraw 对象,并判别该对象是否创建成功:
          ddrval = directDrawCreat( NULL, &lpDD, NULL );
          if( ddrval == DD_OK )
          {
            //lpDD is a valid DirectDraw object.
            }
            else
            {
              //DirectDraw object could not be created.
              }


      使用 IDirectDraw2 和 IDirectDrawSurface2 接口


      在你读本文的其他部分时,你会注意到所有的例程都使用的是 IDirectDraw和 IDirectDrawSurface 的老版本接口。这是因为 DirectX 3 SDK 所给出的例程还没有来及使用 IDirectDraw 和 IDirectDrawSurface 更新后的接口。你可以通过调用 IDirectDraw::QueryInterface 方法来得到 IDirectDraw2 和IDirectDrawSurface2 接口。
          下面的代码给出如何得到 IDirectDraw2 接口:


             // Create an IDirectDraw2 interface.
             LPDIRECTDRAW lpDD;


             ddrval = DirectDrawCreate( NULL, &lpDD, NULL);
             if(ddrval != DD_OK)
                 return;
             ddrval = lpDD->SetCooperativeLevel(hwnd, DDSCL_NORMAL);
             if(ddrval != DD_OK)
                 return;
             ddrval = lpDD->QueryInterfave(IID_IDirectDraw2, (lPVOID *)&lpDD2);
             if(ddrval !=DD_OK)
                 return;


      下面的代码给出如何得到 IDirectDrawSurface2 接口:
             LPDIRECTDRAWSURFACE lpSurf;
             LPDIRECTDRAWSURFACE lpSurf2;


             // Create surfaces.
             Memset( &ddsd, 0, sizeof(ddsd ));
             ddsd.dwSize = sizeof(ddsd);
             ddsd.dwFlags = DDSD_CAPS |DDSD_WIDTH |DDSD_HEIGHT;
             ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | 
                                DDSCAPS_SYSTEMMEMORY;
             ddsd.dwWidth = 10;
             ddsd.dwHeight = 10;


             ddrval = lpDD2->CreateSurface( &ddsd, &lpSurf, NULL);
             if(ddrval != DD_OK)
                    return;


             ddrval = lpSurf->QueryInterface( 
                    IID_IDirectDrawSurface2, ( LPVOID *(&lpSurf2);


             if(ddrval !=DD_OK)
                    return;
      设置显示模式
      安装DirectDraw 的下一步是设置显示模式。在DirectDraw应用程序中设置显示模式关键有两个步骤:第一,调用Idirectdraw::SetCooperativelevel方法设置底层参数。设置好底层参数后,再调用 IDirectDraw::SetdisplayMode方法来设置显示方式。


      确定应用程序的运行特征:
      如果你想改变你的显示方式 ,  你必须先在调色板的 dwFlags 中设置    DDSCL_ EXCLUSIVE  和 DDSCL_FULLSCREEN 标志。其中,调色板的dwFlags包含在IDirectDraw::SetCooperativelLevel 方法中。这样一来,你的应用程序就可以单独占用显示设备,而使其它进程不能共享显示设备。 另外 , 标志DDSCL_FULLSCREEN 把显示设备置为全屏幕方式。正如在运行DDWX1时见到的那样,当同时按下ALT键和TAB键后,最初的表面(Surface)(尽管仍然有效)会被你的表面(Surface)所覆盖,且只有你的表面(Surface)能够进行写屏操作。
      下面的例子说明如何使用 IDirectDraw::SetCooperativeLevel:
               HRESULT    ddrval;
               LPDIRECTDRAW  lpDD;  // already created by DirectDrawCreate


               ddrval = lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE |
                               DDSCL_FULLSCREEN);
               if(ddrval == DD_OK)
               {
                 // exclusive mode was successful
               }
               else
               {
                 // not successful
                 // however, the application can still run
                 }


      如果 IDirectDraw::SetCooperativeLevel 不返回 DD_OK,你的应用程序仍能继续执行,但是我不主张这样做。因为这样会使你的程序无法工作在全屏幕模式下,而且可能不按照你预先的要求工作。如果你确实想使你的应用程序继续运行下去,你应该显示一个错误信息,以便使终端用户知道 IDirectDraw ::SetCooperativeLevel 没有返回DD_OK,然后由用户自己去决定是否继续执行该程序。
      使用IDirectDraw::SetCooperativeLevel 时,有一个要求:给每一个窗口赋一个句柄。这样当你的应用程序被异常中止时,Windows 能够知道。例如:
          当发生GP错误时,GDI被推入缓冲区,终端用户就再也不能返回到Windows界面。为防止这种情况的发生,DirectDraw 能够在关键时刻执行一个后台过程向前台弹出一定的信息,利用这些信息可以确定应用程序是何时被中止的。这就给应用程序强加了一个限制。首先,你必须给每个窗口赋一个特殊的句柄。通过这些句柄,可以知道应用程序的运行信息。也就是说,要创建一个窗口,你必须设置一个处于活动状态的句柄。否则,无法很好执行许多功能。诸如:
          当你的程序被终止时,可能会导致GDI的混乱,也可能会使组合键ALT+TAB不能正常工作。


      改变显示模式
      确定好应用程序的运行特征后,你就可以使用IDiredctDraw::SetDisplay方法来改变显示模式了。下面的例子展示出如何把显示模式设置为 640’480’8 bpp:
               HRESULT ddrval;
               LPDIRECTDRAW  lpDD; // already created


               ddrval = lpDD->SetDisplayMode(640, 480, 8);
               if( ddrval == DD_OK)
               {
                 // mode changed
                 }
                else
                {
                  // mode cannot be changed
                  //mode is either not supported
                 //or someone else has exclusive mode
                }


      在设置显示模式时,你应该判别一下终端用户的硬件设备是否支持高级显示模式。如果不支持,则你应把显示模式设为标准模式,以便能支持更多的适配器。例如,如果你想设计能在所有系统下运行的应用程序,则应把显示模式设为:640 480 8。如果适配器不支持你要设置的显示模式,则IDirectDraw::SetDisplayMode  会返回一个DDERR_INVALIDMODE错误值。因此,在设置显示模式之前,你应使用IDirectDraw::EnumDisplayMode方法来判别一下终端用户适配器所支持的显示类型。
          创建一个可弹出式表面(Surface)集
      当你已经设置好上面的显示模式后,你就可以创建一个表面(Surface)系统,且可以在它上面开发各种应用。尽管我们在DDEX1例程中把显示模式设为全屏幕模式,你仍能够创建一系列的表面(Surface),并在这些表面(Surface)之间进行自由切换。  如果,我们调用方法DirectDraw::SetCooperativeLevel把显示模式设置为 DDSCL_NORMAL的话, 则只能创建一个位拷贝表面(Surface)集。
      设置表面(Surface)的各项参数
      创建可切换式表面(Surface)集的第一步是:在DDSURFACEDESC结构中设定表面(Surface)的各     项参数。下面的例子显示了要创建一个可切换式表面(Surface)集需用到的各项定义和标志:
               // Create the primary surface with 1 back buffer.
               Ddsd.dwSize = sizeof( ddsd );
               ddsd.dwFlags = DDSD_CAPS \ DDSD_BACKBUFFERCOUNT;
               ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
                       DDSCAPS_FLIP | DDSCAPS_COMPLEX;
               ddsd,dwBackBufferCount = 1;
      在上面的例子中,DDSURFACEDESC结构的大小被赋给dwSize成员。这样做的      目的是:防止你在调用DirectDraw的方法时返回一个无效值(且更关键的是:这样做便于今后DDSURFACEDESC结构的扩展)。
      成员dwFlags用于标明DDSURFACEDESC结构中哪些区域填入的信息有效,哪      些区域的信息无效。正如例程DDEX1,我们用dwFlags表明了你要使用结构DDSCAPS      (DDSC_CAPS),以及你要创建一个后台缓冲区(DDSD_BACKBUFFERCOUNT)。
      例程中成员dwCaps包含了一些用在DDSCAPS结构中的标志。这样一来,成员      dwCaps就定义了一个主表面(Surface)(DDSCAPS_PRIMARYSURFACE),一个弹出式表面(Surface)(DDS-CPAS_PRIMARYSURFACE),和一个复表面(Surface)(DDSCAPS_COMPLEX)。所谓复表面(Surface)是指,该表面(Surface)是由若干子表面(Surface)组成的。最后,上面的例程定义了一个后台缓冲区。这个后台缓冲区是背景和前景真正被写入的内存区。写好背景和前景后,再把它们从后台缓冲区弹到主表面(Surface)上。在例程DDEX1中,后台缓冲区的个数被设为1。
      你可以在显示存储器空间允许的前提下,设置任意多的后台缓冲区。有关创建多个后台缓冲区的详细内容参见后面的“三重缓冲技术”(Triple Buffering)一节。表面(Surface)所占用的存储单元可以是显示存储器,也可以是系统内存。如果应用程序所需的存储空间超出了系统内存,则DirectDraw会自动使用显示存储器(例如,你的适配器只有 1 兆 RAM,而你同时定义了多个后台缓冲区)。当然,你也可以指定只使用系统内存或只使用显示存储器。如果把DDSCAPS结构中的dwCaps设为DDSCAPS_SYSTEMMEMORY,DirectDraw就只使用系统内存。如果把结构DDSCAPS中的dwCaps设为DDSCAPS_VIDEOMEMORY,则DirectDraw就只使用显示存储器。(如果,你设定只使用显存,但显存的大小又不够用来创建一个表面(Surface),这时,IDirectDraw::CreateDurface就会返回一个DDERR_OUTOFVIDEOMEMORY的错误信息。)


      创建表面(Surface)集
      定义完DDSURFACEDESC结构中的各项参数后,你就可以使用这个结构和指针       IpDD  来调用IDirectDraw::CreatSurface方法了。其中,指针IpDD指向由函数       DirectDrawCreate所生成的对象DirectDraw。上述的具体过程见下例:
                 ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary,NULL);
                 if( ddrval == DD_OK )
                 {
                   // lppDDSPrimary points to new surface
                   }
                   else
                   {
                    // surface was not created
                    return FALSE;
                    }
      调用IDirectDraw::CreateSurface成功后,调色板IpDDSPrimary将指向主表面(Surface)。
        完成上述过程后,你就可以通过调用IDirectDrawSurface::GetAttached-Surface方法得到一个指向后台缓冲区的指针。如下例所示:
                 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
                 ddrval = lpDDSPrimary->GetAttachedSurface( &ddcaps, &lpDDSBack );
                 if( ddrval == DD_OK)
                 {
                   // lpDDSBack points to the back buffer
                   }
                   else
                   {
                     return FALSE;
                     }
      通过提供主表面(Surface)的地址和设定DDSCAPS_BACKBUFFER标志,调用方法:         IdirectDrawSurface::GetAttackedSrface成功后,调色板lpDDSBack就指向后台缓冲区。
      对表面(Surface)进行写操作
          创建好主表面(Surface)和后台缓冲区后,例程DDEX1调用Windows GDI标准函数,        对主表面(Surface)和后台缓冲区进行写文本操作。如下例所示:
      if ( lpDDSPrimary->GetDC( &hdc) == DD_OK)
                   {
                    SetBkColor( hdc, RGB(0, 0, 255 ) );
                    SetTextColor( hdc, RGB(255, 255, 0) );
                    TextOut(hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );
                    lpDDSPrimary->ReleaseDC(hdc);
                    }
                    if (lpDDSBack->GetDc(&hdc) == DD_OK)
                    {
                     SetBkColor(hdc,RGB(0,0,255));
                     SetTextColor(hdc, RGB(255,255,0));
                     TextOut(hdc,0,0,szBackMsg,lstrlen(szBackMsg));
                     lpDDSBack->ReleaseDC(hdc);
                     }
      上例中调用了方法IDirectDrawSrface::GetDC来用一个句柄给表面(Surface)加         锁。使用Windows标准函数需要一个指向deviceContext的句柄。如果你不习惯这样做,你可以不调用Windows标准函数,而调用IDirectDrawSurface::Lock方法和IDirectDrawSurface::UnLock方法来给后台缓冲区加锁和解锁。
      给表面(Surface)加锁(可以是整个表面(Surface),也可以是表面(Surface)的一部分),能确保应用程序和位拷贝进程不能覆盖表面(Surface)所占存储空间。这样可以避免应用程序对表面(Surface)进行写操作时发生错误。另外,只有当表面(Surface)存储单元处于开锁状态时,你的应用程序才能把表面(Surface)一页一页地由后台弹至前台。
      在表面(Surface)加锁状态下,上例调用Windows GDI标准函数SetBkColor来设定背景颜色,用SetTextColor来设定前景文本的颜色,还调用了TextOut函数把背景和前景显示到表面(Surface)上。
      当把文本写到缓冲区后,例程调用了IDirectDrawSurface::ReleaseDC方法解锁表面(Surface),并释放句柄。无论何时,只要你停止对缓冲区进行写操作,你就必须调用IDirectDrawSurface::ReleaseDC  或者IDirectDrawSurface::Unlock来解锁表面(Surface),释放句柄。至于具体调用上述两种方法的哪一个,要视具体情况而定。重申一遍,只有表面(Surface)处于开锁状态,应用程序才能把它们由后台弹至前台。
      你可能还有点疑惑,为什么这里只对主表面(Surface)进行写操作?通常,在你写一个表面(Surface)时,只有那些写到主表面(Surface)后台缓冲区的内容才能显示出来。在本例DDEX1中,程序完成第一次弹出表面(Surface)操作时,会有一个明显的延时,所以DDEX1的初始化函数中只对主表面(Surface)缓冲区进行写操作是为了防止程序刚开始时显示不连贯。正如后面所看到的,例程DDEX1在WM_TIMER期间只对后台缓冲区进行写操作。初始化函数和标题页只能放在主表面(Surface)缓冲区中。
      注意:调用IDirectDrawSurface::Unlock对表面(Surface)解锁后,指向表面(Surface)存储单元的指针就失效。要想重新获得该指针,就必须调用IDirectDrawSurface::Lock方法。
      对表面(Surface)集进行写和弹出操作
      初始化结束后,DDEX1应用程序进入消息环。就是在这个循环中,后台缓冲区被锁定,新的内容被写入,当后台缓冲区未被锁定时,表面(Surface)就被弹出。WM TIMER包括了用以写入和弹出表面(Surface)大部分代码。
      写入表面(Surface)
      WM TIMER信息的前半部分是用来写入到后台缓冲区的。在这里使用到的大部分     技术,在"对表面(Surface)进行布置操作"部分中,就已经被讨论过了。但是我将再次简要地讨论一下。以下就是在DDEX1中WM TIMERde的内容:
          case WM TIMER:
               // Flip surface.
               If(bActive)
               {
                  if (LpDDSBack->GetDC(&hdc)_== DD_OK)
                  {
                      SetBKColor( hdc, RGB(0, 0, 255 ) );
                      SetTextColor( hdc, RGB( 255,255, 0 ) );
                      if( phase )
                      {
                        TextOut( hdc, 0, 0, szFrontMsg, Lstrlen(szFrontMsg));
                        phase = 0;
                      }
                      else
                      {
                        TextOut(hdc, 0, 0, szBackMsg, Lstrlen(szBackMsg) );
                        phase = 1;
                      }
                      LpDDSBack_>ReleaseDC(hdc);
                   }


      在准备写入之前,GetDC行将锁定后台缓冲区。SetBKColor和SetTextColor函数设     置背景和文本的颜色。
          下一步,变量"phase"决定应该写入主缓冲区信息还是写入后台缓冲区信息。如果"phase"等于1, 主表面(Surface)信息便被写入, 并且将"phase"置为0。 如果"phase" 等于0,后台缓冲区信息便被写入, 并且将"phase"置为1。 但是, 你应当注意,在这两种情况下, 这些信息都要被写入到后台缓冲区中。一旦信息被写入到后台缓冲区中,那末通过使用IDrectDrawSurface::ReleaseDC方法, 后台缓冲区就被解锁。
      弹出表面(Surface)
      一旦表面(Surface)内存被打开, 你就可以使用IDirectDrawSurface::Flip方法将后台缓冲区弹出到主表面(Surface)中了。 下面的例程表示了在DDEX1中如何做到这一点:
         while( 1 )
           {
              HRESULT ddrval;
              ddral = LpDDSPriprimary->Flip( NULL, 0 );
              if( ddral == DD_OK )
              {
                  break;
              }
              if( ddral == DDERR_SURFACELOST )
              {
                  ddral = LpDDSPrimary->Restore();
                  if( ddral != DD_OK )
                  {
                      break;
                  }
               }
               if( ddral != DDERR_WASSTILLDRAWING )
               {
                   break;
               }
           }
      在这个例程中,IPDDSPrimary指针指明了主表面(Surface)和与之相关联的后台缓冲区。当IDirectDrawSurface:Flip被调用时, 前表面(Surface)和后表面(Surface)被交换(注意:只是表面(Surface)的指针被交换, 并无数据移动)。 如果弹出是成功的, 并且返回到DD_ok,那末,应用程序就从当前循环中断。
      在弹出的同时,返回一个DDERR_SURFACELOST值,则调用IDirectdrawSurface::Restore即可恢复该表面(Surface)。 如果恢复成功,应用程序就循环返回到IDirectDrawSurface::Flip的调用,并且再运行一次。 如果表面(Surface)恢复不成功, 那末,应用程序便从当前循环中断,并且返回一个错误信息。一件很重要的事情就是:即使在你已经调用IDirectDrawSurface::Flip之后,交换也不会立即完成。 此时,系统中的原表面(Surface)将缩小为一个条形图标,这样一来,就为下一次点击该图标弹出原表面(Surface)作好了准备。例如,如果以前的弹出操作还没有发生,那末方法IDirectDrawSurface::Flip就会返回参数DDERR_WASSTILLDRAWING的值。在这个例程中,方法IDirectDrawSurface::Flip调用将会继续循环,直到调用返回DD_OK值为止。
      Deallocating the DirectDraw Objects
           当你按下F12时,在退出应用程序之前,DDEX1应用程序处理WM DESTROY信息。该信息调用finiObjects函数,该函数包括了所有的Iunknown Release调用,如下所示:
           static void finiObjects( void )
           {
              if( LpDD != NULL )
              {
                  if( LpDDSPrimary !+Null )
                  {
                      LpDDSPrimary->Release();
                      LpDDSprimary = NULL;
                  }
                  LpDD->Release();
                  LpDD = NULL;
               }
             }/* finiObjects */
      该程序是相当直观的。该应用程序检查DirectDraw和DirectDrawSurface对象的指针是否为空,当然,这些指针非空。然后DDEX1调用IDirectDrawSurface::Release方法,将IdirectDrawSurface对象的参考值减1。如果当参考值等于0时,IDirectDrawSurface对象所占的内存就将被释放。然后通过设置IDirectDrawSurface的值为空,DirectDrawSurface的指针就被释放了。应用程序然后调用IDirectDraw::relese,并将DirectDraw对象的关联值减少到0,释放 DirectDraw对象的操作是通过设置DirectDraw对象的值为空完成的,此时DirectDraw对象的指针也就被释放了。
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.51cto.com/teayear/3186821,作者:跟张哥学编程,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:用zookeeper实现分布式session

      下一篇:js:偏函数Partial和柯里化Currying

      相关文章

      2025-05-13 09:53:13

      计算机初级选手的成长历程——扫雷详解

      计算机初级选手的成长历程——扫雷详解

      2025-05-13 09:53:13
      坐标 , 游戏
      2025-05-07 09:08:54

      【Windows】远程桌面配置不求人!`mstsc` 命令全面教程

      远程桌面(Remote Desktop)是 Windows 系统自带的功能之一,允许用户通过网络远程控制另一台计算机。使用 mstsc 命令可以快速启动远程桌面连接,为日常工作和 IT 管理提供了极大的便利。

      2025-05-07 09:08:54
      计算机 , 远程 , 连接
      2025-04-22 09:24:51

      怎么只用语言实现扫雷?

      怎么只用语言实现扫雷?

      2025-04-22 09:24:51
      代码 , 实现 , 数组 , 游戏
      2025-04-09 09:15:47

      《Java游戏编程原理与实践教程》读书笔记(第4章——Java游戏程序的基本框架)

      《Java游戏编程原理与实践教程》读书笔记(第4章——Java游戏程序的基本框架)

      2025-04-09 09:15:47
      动画 , 图像 , 屏幕 , 方法 , 游戏 , 绘制
      2025-04-09 09:14:12

      前端案例:像素鸟小游戏(js+dom操作,完整代码,附案例素材)

      前端案例:像素鸟小游戏(js+dom操作,完整代码,附案例素材)

      2025-04-09 09:14:12
      png , 位置 , 案例 , 游戏 , 管道
      2025-03-21 09:33:42

      【Python】超简单的华容道小游戏制作+保姆级讲解(附源码)

      【Python】超简单的华容道小游戏制作+保姆级讲解(附源码)

      2025-03-21 09:33:42
      array , index , 函数 , 游戏
      2025-03-21 07:03:12

      【C++图论 并集查找】1319. 连通网络的操作次数|1633

      【C++图论 并集查找】1319. 连通网络的操作次数|1633

      2025-03-21 07:03:12
      C++ , 计算机 , 连通
      2025-03-10 09:53:07

      手把手教你使用JavaScript打造一款扫雷游戏

      手把手教你使用JavaScript打造一款扫雷游戏

      2025-03-10 09:53:07
      div , 标记 , 游戏 , 点击 , 页面
      2025-03-06 09:16:45

      C语言零基础项目:打地鼠,详细思路+源码分享

      C语言零基础项目:打地鼠,详细思路+源码分享

      2025-03-06 09:16:45
      游戏
      2025-03-06 09:16:45

      【实战项目】用C语言+easyX编写游戏:找方块

      【实战项目】用C语言+easyX编写游戏:找方块

      2025-03-06 09:16:45
      游戏 , 编写 , 项目
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5247150

      查看更多

      最新文章

      计算机初级选手的成长历程——扫雷详解

      2025-05-13 09:53:13

      【Windows】远程桌面配置不求人!`mstsc` 命令全面教程

      2025-05-07 09:08:54

      【C++图论 并集查找】1319. 连通网络的操作次数|1633

      2025-03-21 07:03:12

      初识Python

      2025-03-04 09:00:58

      定义损失、进行优化

      2025-02-21 08:57:46

      【C深度解剖】计算机数据下载和删除原理

      2025-02-12 09:28:40

      查看更多

      热门文章

      计算机角度的加减法

      2023-05-08 10:00:39

      计算机操作系统学习笔记

      2023-05-31 08:33:58

      计算机网络协议简称汇总

      2023-05-31 08:27:21

      计算机概述和特点

      2023-06-19 06:59:15

      软考中级(软件设计)----计算机体系结构分类与指令系统

      2023-05-31 08:32:43

      计算机网络实验二---静态路由配置

      2023-06-19 06:59:01

      查看更多

      热门标签

      系统 测试 用户 分布式 Java java 计算机 docker 代码 数据 服务器 数据库 源码 管理 python
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      应用层【计算机网络】

      计算机组成原理知识点

      计算机专业和规划的联系与区别

      计算机相关专业还值得选择吗?

      在普通计算机上安装VMware ESX 3.5 Update2注意事项

      AD域批量运维管理脚本

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号