3

UEFI开发探索96 – 温度计小游戏

 3 years ago
source link: http://yiiyee.cn/blog/2021/08/20/uefi%e5%bc%80%e5%8f%91%e6%8e%a2%e7%b4%a296-%e6%b8%a9%e5%ba%a6%e8%ae%a1%e5%b0%8f%e6%b8%b8%e6%88%8f/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

syslibforuefi中,还有几个小程序。从我的角度来看,最值得学习的是他将图像变为HII资源的方式,其他图形图像的知识,在很久以前的博客中,已经研究了很多了。

早上打开CSDN,让我吃了一惊:

图1 CSDN的评价

悄没声息地跑到了游戏领域内容榜的第2名了!

上次我就说过,我这是UEFI开发的博客啊,又不是介绍游戏开发的。这奇怪的评价,让我都不知道从哪里吐槽了。

我是不是转行去开发游戏比较好?

算了,今天把syslibforuefi中的温度计小游戏移植下,看看效果。这是syslibforuefi的最后一篇了,代码也读得差不多了。

1 程序设计

温度计程序是syslibforuefi的ImageStack工程,其主要功能如下:
1) 显示温度计图像;
2) 当用户按上下键时,温度计的水银部分随之升高或降低。

也就是说,需要动态处理的部分,只是水银部分,其他当做背景图案处理就可以了。

用来实现图像拉伸和收缩的函数为StrethcImage(),而显示函数为DisplayImageStack()。DisplayImageStack()与前两篇的同名函数不同,其实现经过了改造,具体实现可以在我新建的工程中查看(见文末的地址)。

2 移植和编写代码

原来的代码中,仍旧使用了HII资源的方式,这部分需要修改。为了方便移植,所有代码都在一个源文件中了,没有根据功能进行拆分。基本的移植步骤如下:

1)重新实现图像的加载方法

需要加载的图像有三个:bg.bmp、front.bmp和mid.bmp。加载的目标是将图像拷贝到EFI_GRAPHICS_OUTPUT_BLT_PIXEL型指针所指向的内存中。因此,可以使用上一篇的LoadFile()和LoadBitmapFile()。

将原来工程中的SetUpImages()改为如下内容:

EFI_STATUS 
SetUpImages (  
  IN CONST CHAR8    *BgLogoFilePath,
  IN CONST CHAR8    *MidLogoFilePath,
  IN CONST CHAR8    *FrontLogoFilePath)
{
  // Initialize the graphics support.
  if (!InitGop()) {
    return EFI_UNSUPPORTED;
  }

  // Load the background bitmap.
  if (!LoadBitmapFile(BgLogoFilePath, &mBgBlt, &mBgHeight, &mBgWidth)) {
    return EFI_UNSUPPORTED;
  }

  
  if (!LoadBitmapFile(MidLogoFilePath, &mMidBlt, &mMidHeight, &mMidWidth)) {
    return EFI_UNSUPPORTED;
  }
  MaxHeight = mMidHeight;
 
  if (!LoadBitmapFile(FrontLogoFilePath, &mFrontBlt, &mFrontHeight, &mFrontWidth)) {
    return EFI_UNSUPPORTED;
  }

  return EFI_SUCCESS;
}

2)图像显示函数

由于图像会变动,因此增加了一个处理函数CopyBitmapToBitmap(),用来处理水银部分的变动。

EFI_STATUS CopyBitmapToBitmap (
             IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Dest, 
             IN UINTN DestWidth, 
             IN UINTN DestHeight, 
             IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Src, 
             IN UINTN SrcWidth,
             IN UINTN SrcHeight,
             IN UINTN OffsetX,
             IN UINTN OffsetY
             ) 
{
  UINTN CurrentX;
  UINTN CurrentY;
  UINTN SourceX;
  UINTN SourceY;

  EFI_GRAPHICS_OUTPUT_BLT_PIXEL Current;
  Current.Red = 0;
  Current.Green = 0;
  Current.Blue = 0;

  SourceX = 0;
  SourceY = 0;
  CurrentX = OffsetX;
  CurrentY = OffsetY;

  if (CurrentX > DestWidth || CurrentY > DestHeight) {
    return EFI_INVALID_PARAMETER;
  }

  //copy image
  //if source would go over edge of destination buffer, then clip edges

  while (SourceY < SrcHeight && CurrentY < DestHeight) {
    
    while (SourceX < SrcWidth && CurrentX < DestWidth) {
      Current = Src[(SourceY * SrcWidth) + SourceX];

      if (! (Current.Red == 0 && Current.Green == 0 && Current.Blue == 0)) {
        Dest[(CurrentY * DestWidth) + CurrentX] = Src[(SourceY * SrcWidth) + SourceX];
      }
        SourceX++;
        CurrentX++;
    }
    SourceX = 0;
    CurrentX = OffsetX;

    SourceY++;
    CurrentY++;

  }

  return EFI_SUCCESS;

}

而图像显示函数DisplayImageStack()则调用CopyBitmapToBitmap(),进行实际的显示处理。

EFI_STATUS DisplayImageStack ()   
{
  UINTN CoordinateX;
  UINTN CoordinateY;
    
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
  
  Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) malloc(mBgWidth * mBgHeight * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
  memset (Blt, 0, mBgWidth * mBgHeight * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

  CopyBitmapToBitmap (Blt, mBgWidth, mBgHeight, mBgBlt, mBgWidth, mBgHeight, 0, 0);

  CoordinateX = (mBgWidth - mMidWidth) / 2;
  CoordinateY = 15 + (MaxHeight - mMidHeight);
  CopyBitmapToBitmap (Blt, mBgWidth, mBgHeight, mMidBlt, mMidWidth, mMidHeight, CoordinateX, CoordinateY);

  CoordinateX = (mBgWidth - mFrontWidth) / 2;
  CoordinateY = 15;
  CopyBitmapToBitmap (Blt, mBgWidth, mBgHeight, mFrontBlt, mFrontWidth, mFrontHeight, CoordinateX, CoordinateY);

  CoordinateX = (mGraphicsOutput->Mode->Info->HorizontalResolution / 2) - (mBgWidth / 2);
  CoordinateY = (mGraphicsOutput->Mode->Info->VerticalResolution / 2) - (mBgHeight / 2);

  mGraphicsOutput->Blt (
                    mGraphicsOutput,
                    Blt,
                    EfiBltBufferToVideo,
                    0,
                    0,
                    CoordinateX,
                    CoordinateY,
                    mBgWidth,
                    mBgHeight,
                    mBgWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
                    );
               
  return EFI_SUCCESS;

}

3)用户操作处理

主函数main()中调用StretchImage(),处理用户输入的上下方向键,控制水银的上升和下降。实现如下:

EFI_STATUS StretchImage () 
{
  EFI_INPUT_KEY Key;
  UINTN index;
  
  //clear screen
  gST->ConOut->Reset (gST->ConOut, FALSE);

  DisplayImageStack();
  
  //input loop
  do {
    gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &index);
    gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);

    if (Key.ScanCode != SCAN_NULL) {
      if (Key.ScanCode == SCAN_UP) {
        // Print(L"UP");
        RotateUp ();
      } else if (Key.ScanCode == SCAN_DOWN) {
        // Print(L"Down");
        RotateDown();
      }
    }

    DisplayImageStack();

  } while (Key.ScanCode != SCAN_END);

  //clear screen after app exits
  gST->ConOut->Reset (gST->ConOut, FALSE); 

  return EFI_SUCCESS;
}

水银下降上升的处理函数为RotateDown()和RotateUp(),它对水银部分的长度进行更改,通过DisplayImageStack()显示处理。

3 测试温度计小游戏

使用如下命令编译:

C:\vUDK2018\edk2>build -p RobinPkg\RobinPkg.dsc -m RobinPkg\Applications\ImageStack\ImageStack.inf -a IA32

把编译好的程序ImageStack.efi以及项目文件夹下的:bg.bmp、front.bmp和mid.bmp拷贝到模拟器所在文件夹,运行ImageStack.efi即可看到效果。

在Tianocore模拟器中,运行效果如图2所示。

图2 温度计小游戏

实际写完后,感觉功能有点简单,和之前移植过的GuiLite的某个程序很像。如果用博客中之前写好的图形库,也能很容易的构建出来。

后面对syslibforuefi的代码就不再探索了,有兴趣的网友可以自己下载读读看。

Gitee地址:https://gitee.com/luobing4365/uefi-explorer
项目代码位于:/ FF RobinPkg/RobinPkg/Applications/ImageStack下

65 total views, 7 views today


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK