A9VG电玩部落论坛

 找回密码
 注册
搜索
查看: 27027|回复: 64

[教程]wii homebrew 程序编程入门指南

[复制链接]

精华
2
帖子
4942
威望
7 点
积分
6124 点
种子
0 点
注册时间
2007-4-8
最后登录
2024-3-12
 楼主| 发表于 2008-8-10 22:01  ·  北京 | 显示全部楼层 |阅读模式
wii homebrew 程序编程入门指南


请尊重原作者的劳动成果,转载请注明出自A9VG和原作者Silenceburn!
本人水平有限,难免错漏,欢迎各路高手拍砖指正,非常感谢!


[BB***C]Chapter 1: wii 自制程序简介


由于TP漏洞的存在,wii使用自制程序的大门被完全的打开了。这也吸引了大量的编程高手在这个全新的平台上一展身手。

时至今日,wii上的自制程序的种类和数量都是相当丰富的,以下简单列举几类,
完整的主流自制程序列表请查看  homebrew apps

LOADER类:
程序名称程序作者
Homebrew ChannelTeam Twiizers
WiiloadTeam Twiizers
All-in-1 EmuloaderEke-eke
Front SD ELF Loadersvpe
Gecko Region FreeNuke
geckoloaderdhewg
TCP Loadersvpe
Wii Homebrew LauncherHell Hibou
WiiTCPLoadBart?omiej Burdukiewicz


模拟器类:
程序名称程序作者
AtaWiiNoNameNo
FCE Ultra WiiAskot+others
FUSEbg
Genesis PlusEke-eke
Hugo-wiiEke-eke
Mike Tyson's Jungle BeatSpindleyQ + FCEU Team
Neopop WiiAskot
RIN Wiimirakichi
ScummVMdhewg
SDL MAMENuvalo
SMSPlusEke-eke
Snes9X WiiAskot+dsbomb
Trojan WiiJon Conrad
Visual Boy Advanceemu_kidid
Wii64tehpola
Yabause WiiYabause team


工具类:
程序名称程序作者
Duplicate Channel RemoverWaninkoko
ftpiijoedj
Gamecube Saverdasda
Homebrew Browserteknecal
Mii ExtractorWaninkoko
Mii InstallerWaninkoko
RebooterSquidMan
Save ExtractorWaninkoko
Savegame InstallerWaninkoko
SD Explorermiom
Title Listerbushing
WAD ManagerWaninkoko
WiiBServerJay
Wiihttpdteknecal
WiiMUSquidMan
Wii Web ServerCboomf + Felix123 + Others
WiiWhiteboardBg
xyzzybushing


仔细看看上述列表的话,会发现很多我们耳熟能详的程序名称,我们在享受这些程序、工具带给我们的快乐和方便的同时,请不要忘记这些程序的开发者在幕后的艰辛工作,再次向他们表示敬意和感谢!

我作为一名程序员,个人一直笃信中国的程序员的聪明才智不落后于世界上任何一个国家的程序员群体。而wii独特的体感操作方式,大量简单快乐的休闲游戏,一定的健身和运动效果,都非常适合高脑力强度高压力工作的程序员(IT工作者)群体用于放松身心,所以我相信入手wii的程序员(IT工作者)也不会少^_^。那么何不在自己心爱的wii上写一点小程序自娱自乐,或者小工具方便大家呢?

例如我的两个demo恶搞作品:
漂浮的A9 logo
支持wiiRemote的mini小游戏

我个人能力和精力都很有限,没法写出更多更好的作品来给大家使用,因此想通过这篇文章,介绍一下wii 自制程序编程的一些基础和入门知识,好让更多的高手们少走一些弯路,尽快投入到真正的应用研发中去^_^

值得注意的是,本文假设本文读者具备一定的 linux / linux 环境编程 / C语言 知识,否则您的阅读可能会很辛苦


[BB***C]Chapter 2: 准备软硬环境


硬件方面
   
   -- wii本体
   -- PC主机
   -- SD卡  (或者通过无线路由器使用wii TCPLoader )

软件方面      
   -- devkitProUpdate-1.4.7 devkitPro开发包安装程序


Cygwin  MinGW  Msys 的选择
   
   由于大多数人没有安装双系统,为了方便起见,这里只介绍在WINDOWS上如何搭建编程环境。
  
  为了编译程序,我们需要一套windows下面的linux编译环境仿真程序,而这种仿真程序,主流的有三种,Cygwin、MinGW和Msys 。Cygwin 功能强大使用广泛,可支持的安装包也非常多,但是安装时需要做大量的手工选择,对于编译环境不熟悉的人很有可能漏选一些重要的包。MinGW的情况和Cygwin差不多,功能强大,但是其实我们使用不到那么多的功能。最后,我个人的选择是MSys,而且使用的是 devkitPro 开发包中自带的Msys,已经特别为我们所要做的工作进行了定制,强烈推荐大家直接使用这个自带的MSys来编译程序。

[BB***C]Chapter 3: 安装DevkitPPC开发包


   devkitPro是一款非常非常强大的开发包集合,目前几乎所有工作在windows平台下的NDS/PSP/WII的自制程序开发者都是使用这套集成开发包来进行开发的。

  官方网站:www.devkitpro.org

  devkitPro的安装也非常简单,因为有一个独立的安装/更新工具存在。有了这个工具,我们确定自己的需求后,该工具会自动选择下载并安装我们需要的开发包。而且通过改工具,我们还可以随时在线更新这套开发包。该安装/更新工具的最新版本是 devkitProUpdate-1.4.7 ,我在上一章中已经提供了该最新版本工具的纳米盘下载。

  启动该工具后,就可看到如下的安装向导界面


  点击next后,选择是仅下载还是下载并安装,我们当然是选择下载并安装了:


  继续next后,选择是否保留下载文件,建议大家选择保留:


  再次NEXT后,就到重点部分了,在这里我们需要选择要安装的开发包:

  点击“select the type of install ”,然后选择 devkitPPC,这是wii/ngc程序的开发包,
如果选择 devkitARM 就是安装NDS开发包,选择 devkitPSP 的话顾名思义了。如果选择full自然就是全部安装,选择custom可以手动调整要安装的开发包。
  
  选择devkitPPC后的情况如下:


  再次next,接下来是选择安装路径,这一步没什么好说的:  


  再次next,接下来本工具开始自动下载安装包,根据网速情况这一步可能后花很长时间,请耐心等待:


  耐心等待全部下载完毕后,进入解压安装界面:


  至此,devkitPPC 安装完成。

注意:由于安装时是从国外站点下载,可能会非常慢,因此我把所有安装时需要的包单独打包了一份,上传到了纳米盘供大家使用。
  
  devkitPPC打包下载

把我打包的这份安装包里面的内容解压到devkitProUpdate的相同路径下,像这样:

  然后运行Update,就可以跳过下载步骤,直接进入解压安装部分。但是我上传的这份仅是我使用的开发包,可能不是最新版本,如果有条件的话,还是尽量直接使用update工具自动下载安装。



[BB***C]Chapter 4:  HELLO WORLD !


  OK,万事具备了,现在我们就可以开始编写wii上的homebrew程序了。
  我也不能免俗,带大家从hello world开始写起吧哈哈~
  
● Step 1: 确认环境变量

  首先需要确认环境变量是否设置好了,从开始菜单下执行Msys进行仿真环境:


  执行Msys后进入仿真环境命令行,echo 或者 env 检查环境变量 DEVKITPPC 是否存在:


  如果不存在就要 我的电脑 - 属性 - 高级 - 环境变量 - 系统变量 里面做如下配置:

  
  这里一定要注意路径的写法,我把devkitpro安装在D:\devkitpro下面,路径就要写为/d/devkitpro

● Step 2: 认识 devkitpro 文件夹结构  

  进入devkitpro的安装目录,会发现很多文件夹:


  我们从最上边开始介绍
  -- devkitPPC      devkitPPC库函数和头文件,一般不用动
  -- emulators      NGC模拟器,主要用于调试程序
  -- examples      NGC和wii自制程序例子,等会我们会使用到其中的例子
  -- libogc          libogc LIB库,一般不用动
  -- msys           msys仿真环境,其子目录home文件夹是进入msys以后的缺省工作目录
  -- Programmers Notepad  编译调试工具

  一般来说,我们建议把工作文件都放到home下进行编译开发工作,当然你放到其它地方也可以。

● Step 3: 编译 hello world! 程序  

首先打开Msys,进入随devkitPro附送的例子程序的文件夹:(请注意我安装在了d:\devkitpro 下面,请根据自己安装的路径做相应修改)   


  然后执行make即可:


  我们可以看到 .dol .elf 两个wii用的自制程序已经编译完成了。
OK,到了这一步接下来需要干什么就不用我说了吧,心急的同学可以把我们刚刚编译出来的.dol或者.elf拿到wii上运行一下看看了。

我们刚才make的时候真正编译的是 source 目录下面的 template.c 文件:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <gccore.h>
  4. #include <wiiuse/wpad.h>
  5. static void *xfb = NULL;
  6. static GXRModeObj *rmode = NULL;
  7. //---------------------------------------------------------------------------------
  8. int main(int argc, char **argv) {
  9. //---------------------------------------------------------------------------------
  10.      // Initialise the video system
  11.      VIDEO_Init();
  12.      
  13.      // This function initialises the attached controllers
  14.      WPAD_Init();
  15.      
  16.      // Obtain the preferred video mode from the system
  17.      // This will correspond to the settings in the Wii menu
  18.      rmode = VIDEO_GetPreferredMode(NULL);
  19.      // Allocate memory for the display in the uncached region
  20.      xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
  21.      
  22.      // Initialise the console, required for printf
  23.      console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ);
  24.      
  25.      // Set up the video registers with the chosen mode
  26.      VIDEO_Configure(rmode);
  27.      
  28.      // Tell the video hardware where our display memory is
  29.      VIDEO_SetNextFramebuffer(xfb);
  30.      
  31.      // Make the display visible
  32.      VIDEO_SetBlack(FALSE);
  33.      // Flush the video register changes to the hardware
  34.      VIDEO_Flush();
  35.      // Wait for Video setup to complete
  36.      VIDEO_WaitVSync();
  37.      if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
  38.      // The console understands VT terminal escape codes
  39.      // This positions the cursor on row 2, column 0
  40.      // we can use variables for this with format codes too
  41.      // e.g. printf ("\x1b[%d;%dH", row, column );
  42.      printf("\x1b[2;0H");
  43.      
  44.      printf("Hello World!");
  45.      while(1) {
  46.           // Call WPAD_ScanPads each loop, this reads the latest controller states
  47.           WPAD_ScanPads();
  48.           // WPAD_ButtonsDown tells us which buttons were pressed in this loop
  49.           // this is a "one shot" state which will not fire again until the button has been released
  50.           u32 pressed = WPAD_ButtonsDown(0);
  51.           // We return to the launcher application via exit
  52.           if ( pressed & WPAD_BUTTON_HOME ) exit(0);
  53.           // Wait for the next frame
  54.           VIDEO_WaitVSync();
  55.      }
  56.      return 0;
  57. }
复制代码

我们在下一章会讲解这个程序,心急的同学可以先把 “printf("Hello World!");”这句里面的hello world 改成任意其它内容,然后再次执行make,然后把新生成的 .dol 和 .elf 文件拿到wii上运行一下,看看自己修改输出的成果.

精华
2
帖子
4942
威望
7 点
积分
6124 点
种子
0 点
注册时间
2007-4-8
最后登录
2024-3-12
 楼主| 发表于 2008-8-10 22:02  ·  北京 | 显示全部楼层
[BB***C]Chapter 5: hello world 程序分析


我将上一章中使用的hello world 的代码进行了中文注释:


#include
#include
#include  // OGCLIB核心库头文件
#include  // 双节棍手柄支持库头文件

static void *xfb = NULL;
static GXRModeObj *rmode = NULL;

//---------------------------------------------------------------------------------
int main(int argc, char **argv) {
//---------------------------------------------------------------------------------

     // 初始化视频输出
     VIDEO_Init();
     
     // 初始化wii手柄连接
     WPAD_Init();
     
     // 获得最优显示模式
     rmode = VIDEO_GetPreferredMode(NULL);

     // 为显示分配内存
     xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
     
     // 初始化控制台终端, 用于printf输出
     console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ);
     
     // 根据获得的最优显示模式,配置视频输出
     VIDEO_Configure(rmode);
     
     // 配置视频缓冲内存大小
     VIDEO_SetNextFramebuffer(xfb);
     
     // 打开视频输出
     VIDEO_SetBlack(FALSE);

     // 应用视频设置
     VIDEO_Flush();

     // 等待视频输出设置完毕
     VIDEO_WaitVSync();
     if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();


     // 输出终端支持VT100控制码
     printf("x1b[2;0H");
     

     printf("Hello World!");


     while(1) {

          // 获得wii手柄动作
          WPAD_ScanPads();

          // 获得wii手柄上按下的键
          u32 pressed = WPAD_ButtonsDown(0);

          // 如果按下的是 HOME 键,则退出
          if ( pressed & WPAD_BUTTON_HOME ) exit(0);

          // 等待输出下一帧
          VIDEO_WaitVSync();
     }



     return 0;
}



从上面的代码中我们可以看出一般的wii自制程序的大致流程
1.初始化和设置视频输出选项
2.初始化wii手柄连接
3.进入1个死循环
4.在这个死循环中,通过对wii手柄的响应,每个循环输出1帧或完成1个逻辑功能
5.返回

其中1,2,3,5是上述代码中的绿色字体部分,而4是上述代码中的红色字体部分,
从中我们可以分析出,对于大多数情况下的wii自制程序的编程,我们是不需要修改
1,2,3,5中的内容中的,只需要对于4的循环体内的代码进行编辑。

绝大多数的wii自制程序的大部分逻辑功能都是在4的循环体内的代码中完成的,
这就是一般的wii自制程序的基本架构。

为了再说明的具体点,我再写一段伪码,比如我们要编程实现这样的功能,
显示一条从屏幕上方向屏幕下方移动的横线,该怎么写呢?
首先,从上面的分析中,我们可以得知1,2,3,5是不用动的(其实还是要稍微动动的,后面会提到),只需要改4就可以了。

然后继续分析,假设我们把wii的输出设置为640*480,画线函数的坐标原点在左上角,
采用XY坐标系,那么问题就转化为了这样:
1.    从X,Y(0,0)到X,Y(640,0) 画一条线
2.    从X,Y(0,1)到X,Y(640,1) 画一条线,同时把上次的线抹去
3.    从X,Y(0,2)到X,Y(640,2) 画一条线,同时把上次的线抹去
...........
480. 从X,Y(0,480)到X,Y(640,480) 画一条线,同时把上次的线抹去

假设把这480步很快的连续起来执行(可以想象一下动画片的原理),
那么最终的显示效果就变成了一条线从屏幕上面往屏幕下面移动!

那么代码就很好写了:
   
    int Ypoint = 0 ; 定义变量存储Y轴位置  
    while(1) {

          // 如果按下的是 HOME 键,则退出
          if ( pressed & WPAD_BUTTON_HOME ) exit(0);
          (这段代码建议在任何程序中都保留,用于退出自制程序的执行死循环)

          //在指定坐标上画一条线
       //DrawLine(线起点X坐标,线起点Y坐标,线终点X坐标,线终点Y坐标,线的颜色)
       DrawLine(0,i,640,i,BLACK);
          i++;// Y轴位置增加1
          if (i == 481) break; //画完退出
          // 等待输出下一帧
          VIDEO_WaitVSync();
     }

就是这样了,简单吧?
这里面我们注意到一点,就是我们是把每一帧的绘画都放在了每一次循环的执行中去调用,循环共执行了480次,完成了整个绘制动作。而不是一次在一个for里面把480帧都绘画完。为什么这样呢?是因为每次VIDEO_WaitVSync()后画面才会变化一帧,如果在一次循环的执行中把480个变化都绘制完,其结果就是你只能看到最后一根线,根本看不到画面的变化。

精华
2
帖子
4942
威望
7 点
积分
6124 点
种子
0 点
注册时间
2007-4-8
最后登录
2024-3-12
 楼主| 发表于 2008-8-10 22:03  ·  北京 | 显示全部楼层
[BB***C]Chapter 7: wiiuse和光标移动控制


wii最大的亮点之一就是带来无限可能的双节棍手柄了,如果自制程序无法使用wii手柄,那无疑是一个极大的损失。感谢wiiuse开发库,让我们的自制程序可以完全的使用wii手柄的各种功能。

wiiuse是目前最强的wii手柄支持库,没有之一。
Wiiuse是一个C语言写的库,支持多种wii手柄的连接和使用。
支持动作响应,光标跟踪( IR tracking ),鸡腿,经典手柄,甚至吉他英雄3的专用控制器!
拥有单线程和非阻塞的清晰易用、轻量级的API。

Wiiuse被集成到了Libogc里面并扩展为WPAD库.
WPAD库进一步进行了一些封装,使得wiiuse库更加的简单易用。

wiibrew wiki: http://www.wiibrew.org/wiki/Wiiuse

OK,下面我们来演示一下wiiuse提供的 IR tracking 光标移动控制的使用。
我们想实现这样的功能,在上一章的程序的基础上,再实现用wiiremote控制一个火炬形状的光标移动。

[BB***C]step 1: 准备图片文件

和上一章中一样,首先我们要准备好图片文件。
我截取修正过的20*80的火炬光标文件如下:
http://www.namipan.com/d/logo.pn ... 27aa287294eac090000

使用GRRLIB Converter转换生成的.h头文件如下:
http://www.namipan.com/d/bjologo ... 5ca732a131f3a3d0000

[BB***C]step 2: 编码


首先当然还是把头文件放置到 gfx 文件夹下面
然后添加头文件引用
#include "gfx/bjologo.h"

读取材质
u8 *tex_bjologo=GRRLIB_LoadTexture(bjologo);

定义IR信息结构体(注意了,这个可是上一章中没有的呦~)
struct ir_t ir;//定义IR信息结构体     
//我们用它来保存获取到的IR信息

初始化WPAD配置(写在 WPAD_Init() 之后)
   WPAD_SetVRes(WPAD_CHAN_ALL,640,480);
//定义WPAD返回光标位置时使用的分辨率,定义为640*480
   WPAD_SetDataFormat(0,WPAD_FMT_BTNS_ACC_IR);
//定义WPAD返回数据的格式, WPAD_FMT_BTNS_ACC_IR表示需要返回加速度信息和IR位置信息

在循环体中获取IR信息(写在while(1)一进去的WPAD_ScanPads()之后 )
  WPAD_IR(0, &ir);
// 获取0号手柄的IR位置信息(最多4个手柄,0,1,2,3编号)

绘制图标(写在绘制完***之后)
GRRLIB_DrawImg(ir.x, ir.y , 20 , 80 , tex_bjologo , 0 , 1, 1, 255 );
//从上一步获取的IR结构体中获得X,Y坐标的位置,在该位置绘制图标
//由于每次绘制帧的时候IR的X,Y都会变化,连续起来看就好像是光标在移动一样


完整的代码:
  1. /*===========================================
  2.       GRRLIB (GX version) 3.0 alpha
  3.       Code    : NoNameNo
  4.       GX hints : RedShade
  5.       Template Code (Minimum Requirement)
  6. ============================================*/
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include
  15. #include
  16. #include "GRRLIB/GRRLIB.h"
  17. #include "gfx/bjos.h"
  18. #include "gfx/bjologo.h"
  19. Mtx GXmodelView2D;
  20. int main(){
  21.      
  22.    u8 *tex_bjos=GRRLIB_LoadTexture(bjos);
  23.    u8 *tex_bjologo=GRRLIB_LoadTexture(bjologo);     
  24.    struct ir_t ir;//定义IR信息结构体      
  25.      
  26.    VIDEO_Init();
  27.    WPAD_Init();
  28.    WPAD_SetVRes(WPAD_CHAN_ALL,640,480);
  29.    WPAD_SetDataFormat(0,WPAD_FMT_BTNS_ACC_IR);
  30.    GRRLIB_InitVideo();
  31.    GRRLIB_Start();
  32.    while(1){
  33.       WPAD_ScanPads();
  34.       WPAD_IR(0, &ir);
  35.       u32 wpaddown = WPAD_ButtonsDown(0);
  36.      if (wpaddown & WPAD_BUTTON_A) exit(0);
  37.       
  38.       GRRLIB_FillScreen(0xFFFFFFFF);
  39.       
  40.       GRRLIB_DrawImg(210, 90 , 220 , 300 , tex_bjos , 0 , 1, 1, 255 );
  41.       
  42.       GRRLIB_DrawImg(ir.x, ir.y , 20 , 80 , tex_bjologo , 0 , 1, 1, 255 );
  43.       GRRLIB_Render();
  44.       
  45.    }
  46.    return 0;
  47. }
复制代码

[BB***C]step 3: 编译执行


编写完代码不要忘记了保存^_^
然后make即可,把编译完的.dol或.elf拿到wii上看看效果吧~

这里我们注意到,根本没有wiiRemote的连接过程中,原因是新版的wiiuse已经支持自动连接了。

精华
2
帖子
4942
威望
7 点
积分
6124 点
种子
0 点
注册时间
2007-4-8
最后登录
2024-3-12
 楼主| 发表于 2008-8-10 22:04  ·  北京 | 显示全部楼层
[BB***C]END: 结语


慢慢来~

悟道者

公元2008年7月9日,登记了

精华
2
帖子
32678
威望
14 点
积分
36269 点
种子
5 点
注册时间
2007-8-15
最后登录
2016-6-19
发表于 2008-8-10 22:06  ·  上海 | 显示全部楼层
6楼。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

版主

☆LEGO is everthing☆

精华
24
帖子
8617
威望
56 点
积分
15200 点
种子
7 点
注册时间
2006-6-18
最后登录
2022-2-20
发表于 2008-8-10 22:06  ·  北京 | 显示全部楼层
攻占首页...........支持燃烧君...............
该用户已被禁言

精华
0
帖子
176
威望
0 点
积分
201 点
种子
5 点
注册时间
2007-10-10
最后登录
2019-12-14
发表于 2008-8-10 22:08  ·  北京 | 显示全部楼层
7楼。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

精华
0
帖子
203
威望
0 点
积分
305 点
种子
0 点
注册时间
2008-8-8
最后登录
2009-2-13
发表于 2008-8-10 22:09  ·  北京 | 显示全部楼层
........................完全的看不懂......樓主太强大了

悟道者

公元2008年7月9日,登记了

精华
2
帖子
32678
威望
14 点
积分
36269 点
种子
5 点
注册时间
2007-8-15
最后登录
2016-6-19
发表于 2008-8-10 22:19  ·  上海 | 显示全部楼层
好强的C++~~~~~~~~~~~~~

退伍者

☆◎King of the Pop◎☆

精华
13
帖子
30119
威望
29 点
积分
33358 点
种子
876 点
注册时间
2005-8-21
最后登录
2024-5-2
发表于 2008-8-10 22:39  ·  云南 | 显示全部楼层

Re:[]wii homebrew

Support!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|A9VG电玩部落 川公网安备 51019002005286号

GMT+8, 2024-5-3 08:20 , Processed in 0.227926 second(s), 17 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

返回顶部