OpenGL and Brew

来源:互联网 发布:淘宝联盟收入怎么提现 编辑:程序博客网 时间:2024/06/15 07:16
 艾伦坎普

ADVERTISEMENT 广告 <A HREF="http://www.gamedev.net/banman/a.aspx?Task=Click&ZoneID=26&CampaignID=585&AdvertiserID=119&BannerID=653&SiteID=1&RandomNumber=2089700122&Keywords=" TARGET="_top"><IMG SRC="http://members.gamedev.net/dave/ads/NewHavok-static_300x250.jpg" WIDTH="300" HEIGHT="250" BORDER="0"></A>

Introduction导言

It was only a matter of time until someone decided to put a 3d graphics API onto a phone handset.这只是一个时间问题,直到有人决定把一个三维图形API到手机。 OpenGL has long been a graphics industry standard for 3d, and now OpenGL ES is fast becoming the standard for 3d on limited devices. OpenGL的长久以来一直是行业标准的图形的三维,现在OpenGL的胚胎干正迅速成为标准的三维有限的设备。 Limited devices is an apt description though, even a high end phone might only have a 50Mhz ARM processor and 1MB of memory.设备有限公司是一个恰当的描述不过,即使是高端手机可能只有一个50MHz的ARM处理器和1MB的记忆。 But don't be put off, even with these limitations you can still create some very impressive games.但是,不要被推迟,即使有这些限制,你仍然可以创造一些令人印象深刻的游戏。

Writing games for mobile phones is unlike writing for the PC.写作游戏手机不同于书面的PC 。 With the design more limited by the platform restrictions you don't need a huge team with multiple programmers and an army of artists, its well within reason for a single person to turn out a quality title from the comfort of their bedroom.由于设计较为有限的平台限制,你不需要一个巨大的团队与多个程序员和军队的艺术家,其内部原因以及为一个人打开了一个质量标题从舒适的卧室。

This article will go from installing and setting up a BREW development environment and emulator, through to getting an Open GL ES system up and running and displaying a single triangle.本文将从安装和设置的BREW开发环境和模拟器,通过获得美国公开赛吉尔胚胎干系统启动和运行并显示一个三角形。 From there existing OpenGL resources can take you further into the process of developing your 3d application.从现有的OpenGL的资源,就可以进一步的发展过程中的三维应用程序。

Installing the BREW SDK安装了BREW SDK的

You really need to use Internet Explorer for this process.你确实需要使用Internet Explorer这一进程。 The BREW SDK is installed by an ActiveX control which only seems to work in Internet Explorer 6 or better.在BREW SDK是安装一个ActiveX控件,只有工作似乎在Internet Explorer 6或更高。 During this article I am going to assume you create ac:/BREW directory, and then install the BREW SDK into c:/BREW/BREW 3.0.1.在这条我要假设你建立C : /的BREW目录,然后安装了BREW SDK的至C : /的BREW /的BREW 3.0.1 。 If you want to install it somewhere else (like the default c:/program files/BREW 3.0.1), then just adapt the paths I mention as you proceed.如果你想安装在其他地方(如默认ç : /程序文件/的BREW 3.0.1 ) ,然后刚刚适应的道路我提到你着手。

First, go here and register for a free BREW developer account, then install the BREW 3.0.1 SDK from here .首先,到这里注册一个免费的BREW开发商的帐户,然后安装了BREW 3.0.1 SDK的来自这里。 Its a web based installer, just start it going, give it a directory to install to and wait.它是一种基于网络的安装,只要启动它去,给它一个目录来安装和等待。 At around 20MB it won't take too long to install, even on a 56k modem.在它周围容量约为20MB不会太长,无法安装,即使是56K调制解调器。 Towards the end it will ask if you want it to set a BREWDIR environment variable.接近年底时它会询问您是否要设定一个BREWDIR环境变量。 Say yes or various things won't work correctly.说是或各种事情将无法正常工作。

From this page , install the Visual C++ addon, and download the BREW SDK Extension for OpenGL ES. 这个网页上,安装Visual C + +的插件,并下载的BREW SDK的延期为OpenGL ES 。 Extract the OpenGL ES zip file, and:提取的OpenGL ES zip档案,并且:

  • Move all files from inc into c:/BREW/BREW 3.0.1/sdk/inc将所有文件从公司至 C : /的BREW /的BREW 3.0.1 / SDK的/公司
  • Move all files from src into c:/BREW//BREW 3.0.1/sdk/src将所有文件从源至 C : /的BREW / /的BREW 3.0.1 / SDK的/源
  • Move the dll from BREW 3.x into c:/BREW/BREW 3.0.1/sdk/bin/modules移动从该dll 的BREW 3.x版至 C : /的BREW /的BREW 3.0.1 / SDK的/斌/模块
  • Move all files from devices into c:/BREW/BREW 3.0.1/sdk/devices将所有文件从设备至 C : /的BREW /的BREW 3.0.1 / SDK的/设备

Directory structure目录结构

BREW is a bit tricky sometimes when it comes to where it expects to find various files, and tends to give the same cryptic error message for pretty much any case of missing or misplaced files. BREW是有点棘手有时时候的地方希望能够找到各种文件,并往往使同样的隐蔽错误讯息相当任何情况下丢失或错误的文件。 Below is how I have my machine setup.以下是如何我有我的机器安装。 For this article I am assuming you have the same setup, again if you install BREW somewhere else just substitute your paths as appropriate.本文我假设你有相同的设置,再次如果您安装的BREW别的地方只是代替你的路径是适当的。

c:/BREW/ ç : /的BREW / My BREW root directory我国的BREW根目录
c:/BREW/BREW 3.0.1/ ç : /的BREW /的BREW 3.0.1 / The 3.0.1 SDK.在3.0.1 SDK的。 You can have several SDKs installed at once and chose between them by setting an environment variable您可以有几种软件开发工具包安装在一次和它们之间的选择设定一个环境变量
c:/BREW/project1/ ç : /的BREW /专案/ A project directory项目目录
c:/BREW/project1.mif ç : /的BREW / project1.mif The MIF file for project 1 (note that its here and not inside the project1 directory, very important)多国临时部队档案项目1 (请注意,它在这里,而不是在专案目录中,非常重要)

Create new project创建新项目

  • Select the Brew App Wizard (under Visual c++ projects)选择啤酒,应用程序向导(在Visual C + +项目)
  • Set the "location" to c:/BREW设置“位置”到C : /的BREW
  • Enter a project name.输入一个项目名称。 Make it lower case with no spaces or special symbols, lets choose "test_project1" (this is what I'll refer to through out the article as the project name)作出小写它没有空格或特殊符号,可以选择“ test_project1 ” (这就是我要提到通过了条项目名称)
  • Hit OK, and then Finish without making any changes on the Wizard dialog or running the MIF editor点击确定,然后完成而不做任何变更的向导对话框或运行的多国临时部队编辑
  • It will probably say that the project has been modified outside Visual C++, so say OK to reload它可能会说,该项目已被修改以外的Visual C + + ,所以说,确定以重新载入

MIF editor多国临时部队编辑

  • Run the MIF editor.多国临时部队执行编辑。 On the Visual C++ BREW toolbar (which should be on by default, if not right click in the toolbar are and enable it) its third button在Visual C + +中的BREW工具栏(这应该是默认情况下,如果不正确请在工具栏上的,使它)第三届按钮
  • Click the new button (NOT File -> New)按一下新的按钮(不是文件-> “新建)
  • Assuming your not a licensed BREW developer you will need to generate a class id locally.假设你不是一个持牌BREW开发商您需要将生成一个类ID当地。 Select that option.选择该选项。
  • Make up a class id, I started at A0000001 and went up as I created more projects.弥补一类标识,我开始在A0000001 ,走到我创造了更多的项目。 Pick anything, but if you create more projects they must have unique class id's挑选东西,但是如果你创造更多的项目,他们必须拥有自己独特的类ID的
  • Enter your project name as the class name, so in our case "test_project1"输入您的项目名称作为类的名称,因此,在我们的案例“ test_project1 ”
  • Click OK, and you will be prompted to save.单击确定,系统将提示您保存。 Save into the project directory, so c:/BREW/test_project1/test_project1.bid保存到项目目录,让ç : /的BREW / test_project1 / test_project1.bid
  • File->save, save into the PARENT of the project directory, so c:/BREW/test_project1.mif文件>保存“ ,保存到上级项目目录,让ç : /的BREW / test_project1.mif
  • Now compile the MIF by choosing Build -> compile MIF script.现在编译通过选择多国临时部队建设-> “编辑多国临时部队的脚本。 Click OK a couple of times and you're done.单击确定了几次即可大功告成。

Setting up to run and debug through Visual Studio建立运行和调试通过的Visual Studio

  • Right click on the project in solution explorer to get up project properties右击该项目在解决方案资源管理器起床项目属性
  • Configuration properties -> Debugging -> Command, Select BREW_Simulator.exe in your BREW SDK bin directory (in my case, C:/BREW/BREW 3.0.1/sdk/bin/BREW_Simulator.exe)配置属性-> “调试- >”命令,选择BR EW_Simulator.exe在您的B R EWSD K的b i n目录(在我的情况下为C : /的B R EW/的B R EW3. 0.1/S D K的/斌/ B R EW_Simulator.exe)
  • Configuration properties -> Linker -> Debugging, Change "Generate debug info" to "Yes (/DEBUG)"配置属性-> “连接- >”调试,更改“生成调试信息”到“是( /调试)”

Compile and run the project.编译并运行该项目。 It should compile with no errors and start the emulator.它应该没有编译错误,并启动模拟器。 If you get compile errors you probably didn't set your class name in the MIF editor to exactly the same as the project name.如果你编译错误你可能没有设置您的类别名称中的多国临时部队的编辑完全一样的项目名称。

Now if you set a break point in your code it will get triggered correctly when the emulator is running your dll.现在,如果您设置了一个破发点中的代码将获得正确触发时模拟器运行您的DLL 。

The emulator模拟器

Select Blackcap16 as your emulator profile.选择Blackcap16模拟器作为您的个人资料。 From File -> Load Device browse to the devices directory of the SDK and select Blackcap16.qsc.从档案-> “浏览装置负荷的设备目录的S DK和选择B lackcap16.qsc。 It remembers which device you are using, so you will only have to do this the first time you run the emulator.它会记住哪些设备正在使用,所以你只有做到这一点你第一次运行模拟器。

In the emulator, File -> Change applet directory.在模拟器,文件-> “更改程序的目录。 Set it to the directory that contains your .mif file and your project directory, for me thats c:/BREW.它设定的目录,其中包含您的。多国临时部队的档案和你的项目目录,对我来说多数民众赞成ç : /的BREW 。

You should now see the emulator with two icons, your projects and Settings.您现在应该可以看到模拟器有两个图标,您的项目和设置。 Use the arrow keys to select which application you want to run, and enter to start it.使用箭头键选择哪个应用程序要运行,并输入启动。 When you run your project it looks like nothing happens!当您运行您的项目看起来没有任何反应! Thats because the app wizard only generates boiler plate start up code for you.多数民众赞成,因为只有应用程序向导生成锅炉钢板启动代码为你。 You should see in the output window of Visual C++ a message saying that your dll was loaded, assuming it does and you get no errors, success!您应该看到在输出窗口中的Visual C + +的讯息说,您的DLL被加载,假设它和你没有任何错误,取得圆满成功!

If you get a message saying "This app was disabled to save space. Would you like to restore it now?", that's the cryptic message I mentioned earlier.如果您收到一条消息说: “这程序被停用,以节省空间。是否要恢复它现在? ” ,这是隐蔽的信息我前面提到的。 It almost always means you have your files in the wrong places (probably the .dll in the wrong place.) Assuming you used the app wizard to generate your initial code, check you saved the .mif file into the right place.它几乎总是意味着你的档案在错误的地方(可能的。 dll放错了地方。 )假设您使用的应用程序向导生成您的初始代码,检查你救了。多国临时部队档案到正确的位置。

The best laid plans...最好的计划...

Coding for limited devices like mobile phones can be a nightmare, especially if you come from a PC background and are used to luxuries like having more than a few hundred kb of heap, and more than a few hundred bytes of stack space.有限的编码设备,如手机可以是一个恶梦,特别是如果你来自一个电脑的背景和使用的奢侈品一样拥有超过几百KB的堆积,超过几百个字节的栈空间。

Although it must be a Design Patterns advocates wildest fantasy, there is no static or global data on BREW.虽然它必须是一个设计模式的倡导者异想天开,没有任何静态或全球性的BREW数据。 Also, BREW is completly event driven.此外, BREW是completly事件驱动。 Unlike "normal" programming where you typically have a while(..) loop to do your stuff, with BREW you can only respond to events like key presses or timers going off.与“正常”的节目,您一般都则( .. )环做你的东西,与BREW你只能应付这样的活动主要塑机或兼职去了。 There's also no floating point math, GL ES expected its values in 16.16 fixed point format.还有没有浮点运算,吉尔胚胎干预计值16.16固定点格式。 I'll address each of these in turn.我会解决所有这些反过来。

Storage space存储空间

So with no global or static data, where do we store our variables?因此,没有全球性的或静态数据,而我们商店的变数? BREW will store a single struct for us, which must first contain an AEEAplet structure, but can then contain any other data we want.商店的BREW将一个单一的结构对我们来说,它首先必须包含一个AEEAplet结构,但可以包含任何其他数据,我们想要的。 Check out the main .c file the app wizard created for you.检查的主要。 ç文件的应用程序向导为您创建。 Right at the top is a structure named after your application, and in the AEEClsCreateInstance function is a call to AEEApplet_New which allocates heap space for it.正确的上方是一个结构的名字命名您的应用程序,并在AEEClsCreateInstance功能是打电话给AEEApplet_New这堆空间分配给它。 BREW will look after a pointer to this data for us, and will pass it to us as a parameter to most things.的BREW将在指针这一数据对我们来说,将它传给我们作为一个参数,以最事情。 I am going to refer to this as "the global BREW structure".我要提到这是“全球的BREW结构” 。

Some people like to just put all their data straight into that structure.有些人喜欢只把所有的数据直接进入该结构。 However I prefer a slightly more oo approach.但是我更喜欢稍微面向对象的方法。

Assuming you are going to write more than one BREW application you want to structure your startup/shutdown/event handling code into a shell so you dont have to rewrite it for every single application you create.假设你要写入一个以上的BREW应用要结构启动/关机/事件处理代码到壳所以你不要有重写它的每一个应用程序创建。 First, change your main .c file to a .cpp file so it compiles as C++ (else you will get errors using classes).首先,改变您的主。 ç档案。 cpp文件,以便汇编为C + + (否则你将得到错误使用班) 。 Create a class called Game with functions boolean Create() , void Destroy() and void Tick(int timeElapsed) .创建一类所谓的博弈与职能布尔建立( ) ,无效的破坏( )和无效的蜱(整数timeElapsed ) 。 Add an instance of Game into your global BREW data structure, right after AEEApplet, and remove the other data from the struct.新增的一个实例游戏到您的全球的BREW数据结构,后AEEApplet权,并删除其他数据结构。 I have also added int mOldTime which will will use later to track the elapsed time between frames.我还补充说整数mOldTime将稍后将使用跟踪过去了帧之间的时间。

 // From test_project1.cpp / /从test_project1.cpp  struct test_project1结构test_project1  {    AEEApplet  a;         // The compulsory applet structure AEEApplet 1 ; / /强制程序结构    Game       mGame;     // Our game class游戏mGame ; / /我们的游戏类    int        mOldTime;  // used to track the speed we are running at整数mOldTime ; / /用来跟踪的速度,我们运行  }; ) ; 
 // From Game.h / /从Game.h  class Game一流的博弈  {  private:私人:    IShell *       mShell; IShell * mShell ;    IDisplay *     mDisplay; IDisplay * mDisplay ;    AEEDeviceInfo  mDeviceInfo; AEEDeviceInfo mDeviceInfo ;  public:市民:    boolean Create(IShell * shell, IDisplay * display);布尔创建( IShell *壳, IDisplay *显示) ;    void Destroy();无效的破坏( ) ;    void Tick(int timeElapsed);无效蜱(整数timeElapsed ) ;    IShell * GetShell()      { return mShell;    } IShell * GetShell ( ) (返回mShell ; )    IDisplay * GetDisplay()  { return mDisplay;    } IDisplay * GetDisplay ( ) (返回mDisplay ; )    int GetWidth()           { return mDeviceInfo.cxScreen;  }整数GetWidth ( ) (返回mDeviceInfo.cxScreen ; )    int GetHeight()          { return mDeviceInfo.cyScreen;  }整数GetHeight ( ) (返回mDeviceInfo.cyScreen ; )  }; ) ; 

The AEEDeviceinfo structure contains various information about the current phone and operating environment, most importantly for now it contains the width and height of the screen.该AEEDeviceinfo结构包含各种信息对目前的电话和作业环境,最重要的现在它包含的宽度和高度的画面。 Given that virtually all phones have different sized screens you should try and adapt to the screen size at run time.鉴于几乎所有的手机有不同大小的屏幕你应该尝试和适应屏幕大小在运行时。 That way your program will have a chance to work on several phones without recompiling.这样,您的计划将有机会在工作的几款手机没有重新编译。

 // From Game.cpp / /从Game.cpp  boolean Game::Create(IShell * shell, IDisplay * display)布尔游戏: :创建( IShell *壳, IDisplay *显示)  {    mShell = shell; mShell =壳;    mDisplay = display; mDisplay =显示;    mDeviceInfo.wStructSize = sizeof(mDeviceInfo); mDeviceInfo.wStructSize =大小( mDeviceInfo ) ;    ISHELL_GetDeviceInfo(mShell, &mDeviceInfo); ISHELL_GetDeviceInfo ( mShell , & mDeviceInfo ) ;    DBGPRINTF(" *** Width %d, Height %d", GetWidth(), GetHeight()); DBGPRINTF ( “ *** % d个宽度,高度% d个” , GetWidth ( ) , GetHeight ( ) ) ;    return TRUE;返回真;  }  void Game::Destroy()无效游戏: :破坏( )  {  }  void Game::Tick(int timeElapsed)无效游戏: :蜱(整数timeElapsed )  {    // Uncomment this if you want proof the timer callback is working / /取消如果您想证明计时器回调工作    //DBGPRINTF("TICK! %d", timeElapsed); / / DBGPRINTF ( “剔! % d个” , timeElapsed ) ;  } 

The DBGPRINTF function to output text, either to the Visual C++ output pane if you are running in the debugger, or to a window within the emulator.该DBGPRINTF功能,输出的文字,无论是在Visual C + +的输出窗格如果您正在运行中的调试器,或一个窗口内的模拟器。 To get access to it you need to include AEEStdLib.h.为了获得它需要包括AEEStdLib.h 。 For now Destroy() doesn't do anything, as you add more functionality you can use it to clean up any resources you allocate.现在破坏( )没有做任何事,因为你添加更多的功能,您可以使用它来清理你的任何资源分配。

Now to wire these up.现在电汇这些行动。 Replace the contents of test_project1_InitAppData with a call to Game::Create, and make a call to Game::Destroy in test_project1_FreeAppData.替换的内容与test_project1_InitAppData打电话给游戏: :创建,并打电话到游戏: :在test_project1_FreeAppData破坏。 Both of these functions are passed a pointer to the global BREW data structure, so you have easy access to the instance of your Game class.这两项职能是通过一个指针到全球的BREW数据结构,所以你可以很方便地到达该实例的游戏类。 The other parameters you need are available through the AEEApplet stored within the global BREW structure.其他参数你需要可通过AEEApplet储存在全球的BREW结构。

Timers定时器

Every thing in BREW is event based.一切都在BREW是基于事件的。 If you were to try and remain in the startup function forever with a while loop after a few seconds the phone would reboot.如果你试图留在启动功能永远与while循环后,几秒钟后手机将重新启动。 BREW detects applications that have stopped responding (in its opinion) and forces a full reboot to try and clear the problem.检测的BREW应用程序已经停止响应(其认为)和部队全面启动尝试和明确的问题。

To get an application to run in a style resembling a real time game we use a timer to repetedly execute our game loop.要获得应用运行在一个风格类似的实时游戏,我们使用的计时器,以repetedly执行我们的游戏循环。 BREW makes it really easy to set up a timer to callback a function of our choice with ISHELL_SetTimer.的BREW使它真的很容易建立一个计时器回调函数的选择ISHELL_SetTimer 。 ISHELL_SetTimer takes four parameters, a pointer to the applications IShell (which is now contained in our Game class), the number of miliseconds in the future you want the function called, a pointer to a function to call, and finally a void * to some data you want passed to the callback. ISHELL_SetTimer需要四个参数,一个指针的应用IShell (这是现在已包含在我们的游戏类)的人数miliseconds在未来您想要的功能要求,指向一个函数调用,最后一个空白*一些您想要的数据传递给回调。

The callback function needs to take a void pointer as a parameter and return void.回调函数需要一个空白指标作为参数和返回无效。 I usually cast the address of global BREW structure to a void * and use that as my user data, that way in the callback function I can call Game::Tick(int timeElapsed) .我通常演员的地址全球的BREW结构的一个空白*和使用,作为我的用户数据,这种方式在回调函数中我可以调用游戏: :蜱(整数timeElapsed ) 。 One thing to note is that timer callback functions are one shot wonders.有一件事,值得注意的是定时器回调函数是一杆之奇观。 If you want the callback to happen again you need to set the timer again.如果你想回调再次发生您需要设置的计时器了。

 // From test_project1.cpp / /从test_project1.cpp  void SetTimer(test_project1 * data);无效SetTimer ( test_project1 *数据) ;  void timer_tick(void * data)无效timer_tick (无效*数据)  {    test_project1 * tp1 = static_cast < test_project1 * > (data); test_project1 * tp1 = static_cast “ test_project1 * ” (数据) ;    int TimeElapsed = GETUPTIMEMS() - tp1->mOldTime;整数TimeElapsed = GETUPTIMEMS ( ) -t p1, “ m OldTime;    tp1->mOldTime = GETUPTIMEMS(); tp1 , “ mOldTime = GETUPTIMEMS ( ) ;    tp1->mGame.Tick(TimeElapsed); tp1 , “ mGame.Tick ( TimeElapsed ) ;    SetTimer(tp1); SetTimer ( tp1 ) ;  }  void SetTimer(test_project1 * data)无效SetTimer ( test_project1 *数据)  {    int result = ISHELL_SetTimer(data->mGame.GetShell(), TickTime,整数结果= ISHELL_SetTimer (数据“ mGame.GetShell ( ) , TickTime ,                                 timer_tick, static_cast < void * > (data)); timer_tick , static_cast “无效* ” (数据) ) ;    if (result != SUCCESS)如果(结果! =成功)    {      DBGPRINTF(" *** SetTimer failed"); DBGPRINTF ( “ *** SetTimer失败” ) ;    }  } 

GETUPTIMEMS() returns the number of miliseconds the phone has been on. TickTime is a constant that specifies how often (again in miliseconds) to call the main loop. GETUPTIMEMS ( )返回的人数miliseconds的电话一直在。 TickTime是一个常数,指定多久(再次miliseconds )打电话给主回路。 Its calculated based on the FPS you want, like this:其计算的FPS游戏你想,象这样:

 // From test_project1.cpp / /从test_project1.cpp  const int WantedFPS = 20;常量整数WantedFPS = 20 ;  const int TickTime = 1000 / WantedFPS;常量整数TickTime = 1000 / WantedFPS ; 

The only thing that remains is to set the timer going for the first time.唯一要做的是设定计时器会首次。 Do this from the event handler funtion in test_project1.cpp.这样做的事件处理功能在test_project1.cpp 。 The function is called test_project1_HandleEvent.该功能被称为test_project1_HandleEvent 。 Add a call to SetTimer(pMe); to the EVT_APP_START case.新增电话SetTimer (中小企业) ;的EVT_APP_START案件。 This will get called by BREW when (if) your create function has successfully completed.这将所获得的BREW要求时, (如果)你创造功能已成功完成。

Fixed Point Math不动点数学

The ARM chips that power most BREW phones have no floating point units. ARM的芯片,功率最大的BREW手机已经没有浮点单位。 Instead they use a format called 16.16 fixed point.相反,他们使用的格式要求的不动点16.16 。 The 16.16 refers to taking a 32 bit variable, using the first 16 bits for the whole part of a number, and the last 16 bits for the fractional part.在16.16是指采取了32位变量,第一次使用16位的整个的一部分了一些,最后16位的小数部分。

To convert an int to 16.16 format, simply shift it left 16 places.要转换一个int ,以16.16的格式,只要改变它留下16个名额。 To convert it back, shift the other way.要转换回来,转向其他途径。 A full fixed point tutorial is outside the scope of this article, but there are plenty of resources on the internet.全部定点以外的教程是本文讨论的范围,但有丰富的资源在互联网上。 All you need for this article is a macro to convert numbers to fixed point.所有您需要本文是一个宏观数字转换为固定点。

 // From Game.h / /从Game.h  #define ITOFP(x) ((x)<<16) #定义ITOFP (十) ( (十) “ ” 16 ) 

Input输入

We recieve an event to our event handler function when a key is pressed, and another when it is released.我们收到一个事件对我们的事件处理功能时,关键是压力,另一个当它被释放。 Its up to us to track which keys are down at any given time.它由我们来追踪钥匙下跌在任何特定时间。

To make things slightly more intresting the key codes used dont start at 0.为了让事情稍微intresting关键代码开始使用不要在0 。 They start at a constant called AVK_FIRST, and end at AVK_END.他们开始不断地呼吁AVK_FIRST ,并结束在AVK_END 。 AVK is the prefix for the key codes too, so the 3 key would be AVK_3, the direction keys are AVK_UP, AVK_DOWN, etc. Check out aeevcodes.h for a complete list. AVK是前缀编码的关键,所以3个关键将是AVK_3 ,方向键AVK_UP , AVK_DOWN等aeevcodes.h退房的完整名单。

Lets add an array to our Game class to track the state of keys, and two functions to be called when we recieve key press and release events.允许添加一个阵列我们游戏类跟踪的状态键,两个功能被称为当我们收到关键的记者和释放的事件。

 // From game.h / /从game.h  class Game一流的博弈  {  ...    boolean mKeysDown[AVK_LAST - AVK_FIRST];布尔mKeysDown [ AVK_LAST -A VK_FIRST] ;  ...    void KeyPressed(int keyCode);无效KeyPressed (整数键码) ;    void KeyReleased(int keyCode);无效KeyReleased (整数键码) ;  ... 

In Game::Create loop through and set all the mKeysDown[..] to false so we start with a blank slate.在游戏: :建立循环并设置所有mKeysDown [ .. ]假,所以我们开始一个空白石板。 The implementation of KeyPressed and KeyReleased is simple enough, just remember to take into consideration the key codes starting at AVK_FIRST not 0.实施KeyPressed和KeyReleased非常简单,只记得考虑到关键代码开始AVK_FIRST而不是0 。

In your startup file, in your event handler function test_project1_HandleEvent, in the switch statement replace the whole case EVT_KEY with the following to route key events into the Game class.在您的启动文件,你在事件处理函数test_project1_HandleEvent ,在switch语句代替整个案件EVT_KEY下列路线进入关键事件类的游戏。

 // From test_project1.cpp / /从test_project1.cpp  ...    case EVT_KEY_PRESS:案件EVT_KEY_PRESS :      pMe->mGame.KeyPressed(wParam);中小企业, “ mGame.KeyPressed ( wParam ) ;      return TRUE;返回真;    case EVT_KEY_RELEASE:案件EVT_KEY_RELEASE :      pMe->mGame.KeyReleased(wParam);中小企业, “ mGame.KeyReleased ( wParam ) ;      return TRUE;返回真;  ... 

Now in game code you can test if (mKeysDown[AVK_UP - AVK_FIRST] == TRUE) .现在,在游戏代码,您可以测试是否( mKeysDown [ AVK_UP -A VK_FIRST] = =属实) 。 Again, don't forget to take into account the offset of AVK_FIRST.再次,不要忘记考虑到偏移AVK_FIRST 。 It would probably be best to write a wrapper function to do the test which handles the offset internally.这可能是最好写一个包装功能做测试处理抵消国内。

If you compile and run now you should see the code from Game::Create printing out the width and height of the screen to the Visual C++ output pane.如果你编译和运行现在您应该看到代码游戏: :创建打印出的宽度和高度的屏幕的Visual C + +的输出窗格。

OpenGL ES 1.0 OpenGL的胚胎干1.0

At last we come to the actual topic of this article, OpenGL ES.最后我们来到的实际问题本文中, OpenGL的胚胎干。 It taken a while to get here mainly because for a lot of people this will be their first non-PC programming target.它采取了同时获得这主要是因为这里的很多人来说,这将是他们第一次非PC编程的目标。

If you have any experience with writing Open GL code you will find your knowledge translates nearly directly to GL ES.如果您有任何经验的书面公开赛吉尔代码你会发现你的知识直接转化为近吉尔胚胎干。 There are however a few differences.但是,一些分歧。 The startup and shutdown sequence is different from PC based Open GL.在开机和关机顺序是不同的基于PC的开放式吉尔。 Given that there are no floating point functions things have slightly different names.由于没有浮点运算功能的事情略有不同的名字。 Most of the names simply replace the trailing f (for float), with an x (for fixed).大多数简单的名称取代落后函数f (浮法) ,与× (固定) 。 The most significant difference is GL ES does away with the immediate mode glVertexf interface.最重要的区别是吉尔胚胎干不取消直接模式glVertexf接口。 All renderering is done through the batched glDrawElements interface for improved efficiency.所有renderering是通过批处理glDrawElements接口提高效率。

To get access to the GL ES functions and data types you need to include IGL.h in your code.要获得胚胎干的吉尔功能和数据类型你需要包括IGL.h在您的代码。 You will also need to add the file GL.c, which came with the GL ES SDK to your project.您还需要添加的文件GL.c ,其中与胚胎干SDK的吉尔对您的项目。 Its located at c:/BREW/BREW 3.0.1/sdk/src/GL.c.它位于C : /的BREW /的BREW 3.0.1 / SDK的/源/ GL.c.

There's another header called AEEGL.h which is intended for (the few) people who'd prefer to use OpenGL ES in the same way other BREW features are used: through an interface.还有一个标题所谓AEEGL.h其目的是为(少数)人谁想要使用OpenGL胚胎干以同样的方式其他的BREW功能的使用:通过一个接口。 So instead of calling因此,而不是要求

glPushMatrix() glPushMatrix ( )

, you'd call ,你会要求

IGL_glPushMatrix(pIGL) IGL_glPushMatrix ( pIGL )

where pIGL is a pointer to an IGL interface.pIGL是一个指针的IGL接口。

This article sticks to the standard way of using OpenGL.本文坚持标准的方式使用OpenGL 。

The Renderer class一流的转译器

Keeping with the oo theme, all the setup and shutdown code is gathered into a class called Renderer.按照面向对象的主题,所有的设置和关机代码是聚集到了一类所谓的转译器。 Take a look at the class definition.看看类的定义。

 // From Renderer.h / /从Renderer.h  class Renderer一流的转译器  {  private:私人:    IGL *       mIGL; IGL * mIGL ;    IEGL *      mIEGL; IEGL * mIEGL ;    EGLDisplay  mDisplay; EGLDisplay mDisplay ;    EGLConfig   mConfig; EGLConfig mConfig ;    EGLSurface  mSurface; EGLSurface mSurface ;    EGLContext  mContext; EGLContext mContext ;  public:市民:    boolean Create(IShell * shell, IDisplay * display);布尔创建( IShell *壳, IDisplay *显示) ;    void Destroy();无效的破坏( ) ;    void FlipToScreen();无效FlipToScreen ( ) ;  }; ) ; 

IGL is an Interface to GL, while IEGL is a platform specific layer to sit between IGL and the underlying architecture. IGL是一个接口吉尔,而IEGL是一个平台,具体层之间坐在IGL和基本架构。

The other parameters are just as their names suggest. EGLDisplay is the graphics display, EGLConfig is the video mode (there is normally only one mode available, as opposed to a PC graphics card which might have several to choose from). EGLSurface is the actual surface rendering operations write to. EGLContext represents the current state of the GL environment that will be used when you execute commands.其他参数也同样显示他们的名字。 EGLDisplay是图形显示, EGLConfig是视频模式(通常是只有一个模式可用,而不是个人电脑的图形卡可能有几种选择) 。 EGLSurface是实际表面绘制业务写入。 EGLContext代表了目前的状况吉尔的环境,将被用来当你执行命令。

Renderer::Create(..)转译器: :创建( .. )

Throughout this function its very important to check every function call for errors, and to completely clean up if anything goes wrong.在此功能非常重要,检查每一个函数调用的错误,并完全清理,如果任何事情都会发生错误的。 On a PC its maybe a bit annoying if a program spews garbage and you have to reboot, but I have heard several stories of phones locking up and having to be sent for repair after particularly nasty code errors.在个人电脑上的也许有点厌烦如果一个程序排放垃圾,你必须重新启动,但我已经听到几个故事,手机锁定,不得不被送到修理后,特别讨厌的代码错误。

   // From Renderer.cpp / /从Renderer.cpp    if (ISHELL_CreateInstance(shell, AEECLSID_GL, (void **)&mIGL) != SUCCESS)如果( ISHELL_CreateInstance (壳, AEECLSID_GL , (无效** ) & mIGL ) ! =成功)    {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    }    if (ISHELL_CreateInstance(shell, AEECLSID_EGL, (void **)&mIEGL) != SUCCESS)如果( ISHELL_CreateInstance (壳, AEECLSID_EGL , (无效** ) & mIEGL ) ! =成功)    {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    }    IGL_Init(mIGL); IGL_Init ( mIGL ) ;    IEGL_Init(mIEGL); IEGL_Init ( mIEGL ) ; 

Using the ISHELL interface we get BREW to create IGL and IEGL objects for us.使用ISHELL界面我们得到的BREW创造IGL和IEGL物体我们。 The IGL_Init() and IEGL_Init() functions are part of a wrapper system that stores pointers to the IGL and IEGL so we can just call the more usual glClear(..) rather than IGL_glClear(mIGL, ...) .该IGL_Init ( )和IEGL_Init ( )函数的一部分,包装系统,商店的三分球IGL和IEGL ,所以我们只能呼吁更常见glClear ( .. ) ,而不是IGL_glClear ( mIGL , ... ) 。

   // From Renderer.cpp / /从Renderer.cpp    mDisplay = eglGetDisplay(display); mDisplay = eglGetDisplay (显示) ;    if (mDisplay == EGL_NO_DISPLAY)如果( mDisplay == EGL_NO_DISPLAY )     {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    } 

Get the GL display, based on the current BREW display.获取吉尔显示,根据目前的BREW显示。

   // From Renderer.cpp / /从Renderer.cpp    EGLint major = 0; EGLint主要= 0 ;    EGLint minor = 0; EGLint未成年人= 0 ;    if (eglInitialize(mDisplay, &major, &minor) == FALSE)如果( eglInitialize ( mDisplay ,和主要的,与未成年人) == FALSE的)    {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    }    DBGPRINTF(" *** ES version %d.%d", major, minor); DBGPRINTF ( “ ***第ES版本% d. % d个”重大,未成年人) ; 

Initialize GL ES, which also sets major and minor to the major and minor version numbers of the current GL ES implementation.初始化吉尔胚胎干,这也套主要和次要的主要和次要版本号码当前的吉尔胚胎干的实施。 At the moment that is going to always say 1.0, but version 1.1 is coming soon.目前,这将总是说1.0 ,但1.1版即将推出。 In the future it will be worth checking this the same way you check for various extensions in GL to be able to use more advanced features if they are available.它将来会是值得勾选此相同的方式,检查各种扩展吉尔可以使用更先进的功能,如果它们是可用。 If you really don't care, you can pass NULL for the last two parameters to not retrieve the version information.如果你真的不在乎,您可以通过空的最后两个参数不检索版本信息。

   // From Renderer.cpp / /从Renderer.cpp    EGLint numConfigs = 1; EGLint numConfigs = 1 ;    if (eglGetConfigs(mDisplay, &mConfig, 1, &numConfigs) == FALSE)如果( eglGetConfigs ( mDisplay , & mConfig , 1 , & numConfigs ) == FALSE的)    {      Destroy();销毁( ) ;      return false;返回虚假的;    } 

Retrieve a valid configuration based on the display.检索有效配置的基础上显示。

   // From Renderer.cpp / /从Renderer.cpp    IBitmap *  DeviceBitmap = NULL; IBitmap * DeviceBitmap =空;     IDIB *    DIB = NULL; IDIB *零钱=空;    if (IDISPLAY_GetDeviceBitmap(display, &DeviceBitmap) != SUCCESS)如果( IDISPLAY_GetDeviceBitmap (显示,与DeviceBitmap ) ! =成功)     {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    }    if (IBITMAP_QueryInterface(DeviceBitmap, AEECLSID_DIB, (void**)&DIB) != SUCCESS)如果( IBITMAP_QueryInterface ( DeviceBitmap , AEECLSID_DIB , (无效** ) &零钱) ! =成功)     {      IBITMAP_Release(DeviceBitmap); IBITMAP_Release ( DeviceBitmap ) ;      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    } 

Using the BREW IDISPLAY interface, get the current device bitmap.使用BREW IDISPLAY介面,让目前的装置图。 From this, use the IBITMAP interface to query for a device dependant bitmap (a bitmap in the native phone format).从这一点出发,利用IBITMAP界面查询设备依赖位图(位图中的本地电话格式) 。 This will be our front buffer.这将是我们前面的缓冲区。

   // From Renderer.cpp / /从Renderer.cpp    mSurface = eglCreateWindowSurface(mDisplay, mConfig, DIB, NULL); mSurface = eglCreateWindowSurface ( mDisplay , mConfig ,零钱,空) ;    IDIB_Release(DIB); IDIB_Release (零钱) ;    IBITMAP_Release(DeviceBitmap); IBITMAP_Release ( DeviceBitmap ) ;    if (mSurface == EGL_NO_SURFACE)如果( mSurface == EGL_NO_SURFACE )     {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    } 

Create the surface we will be rendering to.创建的表面,我们将渲染到。 This is our back buffer which when we issue an eglSwapBuffers will be copied to the font buffer.这是我们这回缓冲区当我们发出eglSwapBuffers将复制到字体的缓冲区。 We can release the bitmaps we acquired earlier, they have served their purpose.我们可以释放点阵图我们收购前,他们已达到其目的。

   // From Renderer.cpp / /从Renderer.cpp    mContext = eglCreateContext(mDisplay, mConfig, NULL, NULL); mContext = eglCreateContext ( mDisplay , mConfig ,空,空) ;     if (mContext == EGL_NO_CONTEXT)如果( mContext == EGL_NO_CONTEXT )    {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    }    if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == FALSE)如果( eglMakeCurrent ( mDisplay , mSurface , mSurface , mContext ) == FALSE的)    {      Destroy();销毁( ) ;      return FALSE;返回FALSE ;    } 

Create a context, and then lastly make our display, surface and context current so they are the target of any rendering we do.创建一个背景,然后最后使我们的显示屏,表面和背景目前,所以他们的目标,任何渲染,我们这样做。

Assuming we got this far with no errors, the basic GL ES system is up and ready to be used.假设我们得到这远远没有错误,基本吉尔胚胎干系统,并准备使用。

Renderer::Destroy转译器: :破坏

I have mentioned the importance of cleaning up correctly several times, so lets take a look at the Destroy function that takes care of shutting everything down.我刚才提到的重要性,正确地清理好几次,所以可以看看消灭函式照顾关闭一切下降。

   // From Renderer.cpp / /从Renderer.cpp    eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglMakeCurrent ( EGL_NO_DISPLAY , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;    if (mContext)如果( mContext )    {      eglDestroyContext(mDisplay, mContext); eglDestroyContext ( mDisplay , mContext ) ;      mContext = NULL; mContext =空;    }    if (mSurface)如果( mSurface )    {      eglDestroySurface(mDisplay, mSurface); eglDestroySurface ( mDisplay , mSurface ) ;      mSurface = NULL; mSurface =空;    }    if (mDisplay)如果( mDisplay )    {      eglTerminate(mDisplay); eglTerminate ( mDisplay ) ;      mDisplay = NULL; mDisplay =空;    }    if (mIEGL)如果( mIEGL )    {      IEGL_Release(mIEGL); IEGL_Release ( mIEGL ) ;      mIEGL = NULL; mIEGL =空;    }    if (mIGL)如果( mIGL )    {      IGL_Release(mIGL); IGL_Release ( mIGL ) ;      mIGL = NULL; mIGL =空;    } 

First we deactivate our display, surface and context, then take each in turn and destroy or release them depending on how they were created.首先,我们停用我们的显示屏,表面和背景,然后每个又和销毁或者释放他们视他们如何建立。

Renderer::FlipToScreen转译器: : FlipToScreen

We are nearly finished with the Renderer class now, lets take a look at the final function FlipToScreen , and then move onto actually getting something on screen.我们正在接近完成的转译器类现在,可以看看最后的功能FlipToScreen ,然后走上真正得到的东西在屏幕上。

 // From Renderer.cpp / /从Renderer.cpp  void Renderer::FlipToScreen()无效的转译器: : FlipToScreen ( )  {    eglSwapBuffers(mDisplay, mSurface); eglSwapBuffers ( mDisplay , mSurface ) ;  } 

That is the entire function, it just calls eglSwapBuffers to copy our backbuffer to the screen.这是整个功能,它只是要求eglSwapBuffers复制我们backbuffer到屏幕上。

A Spinning Triangle纺纱三角

Add an instance of Renderer to the Game class.新增的一个实例渲染游戏类。 Also add an int called mRotateAngle to record the current rotation of the triangle.又新增一个int所谓mRotateAngle记录当前轮换的三角形。 In Game::Create , at the end, we have this:游戏: :创建结束时,我们这一点:

   mRenderer.Create(mShell, mDisplay); mRenderer.Create ( mShell , mDisplay ) ;    // Enable the zbuffer / /启用zbuffer    glEnable(GL_DEPTH_TEST); glEnable ( GL_DEPTH_TEST ) ;    // Set the view port size to the window size / /设置认为港口规模的窗口大小    glViewport(0, 0, GetWidth(), GetHeight()); glViewport ( 0 , 0 , GetWidth ( ) , GetHeight ( ) ) ;    // Setup the projection matrix / /设置投影矩阵    glMatrixMode(GL_PROJECTION); glMatrixMode ( GL_PROJECTION ) ;    glLoadIdentity(); glLoadIdentity ( ) ;    // Diable lighting and alpha blending / /迪亚布勒照明和alpha混合    glDisable(GL_LIGHTING); glDisable ( GL_LIGHTING ) ;    glDisable(GL_BLEND); glDisable ( GL_BLEND ) ;    // Set the fustrum clipping planes / /设置fustrum裁剪机    glFrustumx(ITOFP(-5), ITOFP(5), ITOFP(-5), ITOFP(5), ITOFP(10),  ITOFP(100)); glFrustumx ( ITOFP ( -5 ) , ITOFP ( 5 ) , ITOFP ( -5 ) , ITOFP ( 5 ) , ITOFP ( 10 ) , ITOFP ( 100 ) ) ;    // Set the model view to identity / /设置模式,以身份证    glMatrixMode(GL_MODELVIEW ); glMatrixMode ( GL_MODELVIEW ) ;    glLoadIdentity(); glLoadIdentity ( ) ;    // Enable the arrays we want used when we glDrawElements(..) / /启用阵列我们希望当我们使用glDrawElements ( .. )    glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState ( GL_VERTEX_ARRAY ) ;    glEnableClientState(GL_COLOR_ARRAY); glEnableClientState ( GL_COLOR_ARRAY ) ;    mRotateAngle = 0; mRotateAngle = 0 ; 

This initializes our renderer with our stored ISHELL and IDISPLAY.这初始化我们的渲染与我们的存储ISHELL和IDISPLAY 。 It sets various initial GL states.这两套不同的初始吉尔国家。 Note the use of the ITOFP macro to convert values into 16.16 fixed point.注意:使用ITOFP宏观转换价值变为16.16固定点。 Start the triangle with no rotation, facing the camera.开始的三角形,没有轮换,面临的摄像头。 Don't forget to add a matching call to Renderer::Destroy to Game::Destroy to clean up when the program exits.不要忘记添加一个符合要求转译器: :破坏游戏: :摧毁清理程序时退出。

   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;    glPushMatrix(); glPushMatrix ( ) ;    glLoadIdentity(); glLoadIdentity ( ) ;    glTranslatex(0,  0, ITOFP(-15)); glTranslatex ( 0 , 0 , ITOFP ( -15 ) ) ;    if (mKeysDown[AVK_LEFT - AVK_FIRST] == TRUE)如果( mKeysDown [ AVK_LEFT -A VK_FIRST] = =真)    {      mRotateAngle -= 3; mRotateAngle -= 3 ;    }    if (mKeysDown[AVK_RIGHT - AVK_FIRST] == TRUE)如果( mKeysDown [ AVK_RIGHT -A VK_FIRST] = =真)    {      mRotateAngle += 3; mRotateAngle + = 3 ;    }      if (mRotateAngle < 0) mRotateAngle += 360;如果( mRotateAngle “ 0 ) mRotateAngle + = 360 ;    if (mRotateAngle > 360) mRotateAngle -= 360;如果( mRotateAngle “ 360的) mRotateAngle -= 360 ;    glRotatex(ITOFP(mRotateAngle), ITOFP(0), ITOFP(1), ITOFP(0)); glRotatex ( ITOFP ( mRotateAngle ) , ITOFP ( 0 ) , ITOFP ( 1 ) , ITOFP ( 0 ) ) ;    int FaceData[9] =整数FaceData [ 9 ] =    {      -ITOFP(2), -ITOFP(2), ITOFP(0),    // First vertex position - ITOFP ( 2 ) , - ITOFP ( 2 ) , ITOFP ( 0 ) , / /第一顶点位置      ITOFP(2),  -ITOFP(2), ITOFP(0),    // Second vertex position ITOFP ( 2 ) , - ITOFP ( 2 ) , ITOFP ( 0 ) , / /第二个顶点位置      -ITOFP(0),  ITOFP(2), ITOFP(0)    // Third vertex position - ITOFP ( 0 ) , ITOFP ( 2 ) , ITOFP ( 0 ) / /第三个顶点位置    }; ) ;    int ColorData[12] =整数ColorData [ 12 ] =    {      ITOFP(1), ITOFP(0), ITOFP(0), ITOFP(0),  // First vertex color ITOFP ( 1 ) , ITOFP ( 0 ) , ITOFP ( 0 ) , ITOFP ( 0 ) , / /第一个顶点的颜色      ITOFP(0), ITOFP(1), ITOFP(0), ITOFP(0),  // Second vertex color ITOFP ( 0 ) , ITOFP ( 1 ) , ITOFP ( 0 ) , ITOFP ( 0 ) , / /第二个顶点的颜色      ITOFP(0), ITOFP(0), ITOFP(1), ITOFP(0)  // Third vertex color ITOFP ( 0 ) , ITOFP ( 0 ) , ITOFP ( 1 ) , ITOFP ( 0 ) / /第三个顶点的颜色    }; ) ;    uint8 IndexData[3] = {0, 1, 2}; uint8 IndexData [ 3 ] = ( 0 , 1 , 2 ) ;    glVertexPointer(3, GL_FIXED, 0, FaceData);  // Set the vertex (position) data source glVertexPointer ( 3 , GL_FIXED , 0 , FaceData ) ; / /设置顶点(位置)的数据源    glColorPointer(4, GL_FIXED, 0, ColorData);  // Set the color data source glColorPointer ( 4 , GL_FIXED , 0 , ColorData ) ; / /设置的颜色数据源    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, IndexData);  // Draw the triangle glDrawElements ( GL_TRIANGLES , 3 , GL_UNSIGNED_BYTE , IndexData ) ; / /绘制三角形    glPopMatrix(); glPopMatrix ( ) ;    mRenderer.FlipToScreen(); mRenderer.FlipToScreen ( ) ; 

As I said earlier if you have any existing OpenGL knowledge this should look very familiar to you.正如我前面所说,如果您有任何现有的OpenGL知识这个看起来应该非常熟悉你。 Note again the use of the ITOFP macro to convert values to 16.16 fixed point, and the introduction of the new data type GL_FIXED as a parameter to various functions.注意:再次使用ITOFP宏观转换值16.16固定点,并采用新的数据类型GL_FIXED作为参数的各种功能。

Adding Text添加文字

We can use the BREW functions to draw text to screen, as long as we do it after ending GL rendering for the frame.我们可以利用的BREW功能提请文字,画面,只要我们做到这一点结束吉尔绘制的框架。 At the end of Game::Tick , after calling mRenderer.EndFrame() , add this:在结束游戏: :蜱后,要求mRenderer.EndFrame ( ) ,补充一点:

   AECHAR buffer[16]; AECHAR缓冲区[ 16 ] ;    WSPRINTF(buffer, 16, L"FPS: %d", 1000 / timeElapsed); WSPRINTF (缓冲, 16日,升“指纹图谱: % d个” , 1000 / timeElapsed ) ;    IDISPLAY_DrawText(mDisplay, AEE_FONT_BOLD, buffer, -1, 5, 5, NULL, 0); IDISPLAY_DrawText ( mDisplay , AEE_FONT_BOLD ,缓冲区, -1 , 5 , 5 ,空, 0 ) ;    IDISPLAY_Update(mDisplay); IDISPLAY_Update ( mDisplay ) ; 

The last call, IDISPLAY_Update only needs to be called once at the very end for however much text or other data you want to put on screen.最后呼吁, IDISPLAY_Update只需要再次呼吁在最后的无论文字或其他数据要放在屏幕上。 BREW is entirely UNICODE (except for filenames), so we need to use the wide version of sprintf. BREW是完全的UNICODE (除文件名) ,所以我们需要使用全版的sprintf 。 To declare a string constant as a wide string simply precede it with an L.声明一个字符串常量作为一个广泛的字符串之前,它只是一个研究

Run!跑!

If you compile and run you should have a triangle with three different colored corners.如果你编译和运行你应该有一个三角形的三个不同颜色的弯道。 The FPS should be in the top left corner, and pressing the left and right arrows (either use the keyboard, or click the emulator buttons) should rotate the triangle.该新鲜粮食店应在左上角,而紧迫的左,右箭头(或者使用键盘,或按一下按钮模拟器)应旋转的三角形。 Congratulations, you just wrote your first Open GL ES program!恭喜你,你刚才写你的第一个开放吉尔胚胎干计划!

Conclusion结论

Hopefully if you have been following along you have managed to install the BREW SDK, set up the emulator and have built your first OpenGL ES program.如果你希望一直沿着你已成功地安装了BREW SDK的,成立了模拟器和建立你的第一个OpenGL的胚胎干计划。

Once you have OpenGL ES up and running you can use nearly any existing OpenGL books or websites for information.一旦你的OpenGL胚胎干和运行您可以使用几乎任何现有的OpenGL的书籍或网站信息。 Just bear in mind the restrictions of the hardware, and don't forget to convert all your values to 16.16 fixed point!只要牢记限制的硬件,同时不要忘记把您所有的转换值16.16固定点!

Source来源

The source code, including a Visual C++ 2003 project file, that accompanies this article is available here (10k).源代码,其中包括Visual C + +的2003年项目文件,即伴随着这一条在这里( 1万) 。

Where now?现在在哪里?

I hope you are aware of the great contest Gamedev.net and Qualcomm are running.我希望大家都知道伟大的竞赛Gamedev.net和高通正在运行。 This article provides enough information to get you started writing the contest winner, and next cult classic 3d game for mobile phones.本文提供足够的信息,让您一开始写作竞赛冠军,明年邪教的经典3D游戏

原创粉丝点击