FIRST 3D Application

After MAGIC101 enter beta, we found developers more care about to make a 3D applications for mobile devices. This paper will introducing basic ideas about to build up your first 3D application on mobile device. In this article, I assume you have experience on 3D application developing and already looked at MAGIC101 2D samples.

First of all, you must ensure which type of '3D' you shuold use. Typically, there is two types of '3D' applications: 2.5D and Real 3D.

As it's name, 2.5D games not realy a 3D game, but they looks like 3D games. DOOM, DUKE3D, Steel Warrior are all good samples of 2.5D games. They use sprits and other technique to speed up the game. For example there are no declining walls in DOOM, and you can't look up or down.

Real 3D game, which is most common in popular PC or Console games today. They use triangle-meshes build-up the whole game world, Camera can place to every where and in any direction. Quake, Zelda64, Need of Speed 5 are all real 3D games.

Real 3D games often needs much more device power. For 9210(<50Mhz ARM9), I think 2.5D games are more suitable. But on iPAQ(206Mhz StrongARM) a real 3D game can run smoothly. For 7650? I don't know, it seems 7650's chip still can't compare with iPAQ. But it has a realy small and cute screen(which can save much cycle for raster).

MAGIC101 supports both 2.5D and Real 3D games. KXRacer is based on 2.5D technique and Mobile Pool is a real 3D game, they may looks ugly cause our artist haven't join these projects.

In 3D games developing you'll meet more math theories. Most of them are float-number based. Unfortunately mobile devices's cpus are very week at that. To speed up, MAGIC101 use Fixed-Point-Number instead of Float-Point-Number. There are a lot of articles discuss on Fixed-Point math, so I'll skip that.

In MAGIC101 Fixed-Point-Number type is MAGFIXED, which is a signed-32bit-integer decleared in MAGFixed.h. you can use FixMul(), FixDiv(), and other functions to operate at fixed point number. Many useful functions also can be found in MAGFixed3DTypes.h.

Fixed number's arrange is very limited, if you're not very good at fixed-math, I suggest you keep your scens in -100.0~+100.0 and not excat to much( for exmaple, 0.00001), 0.01 shuold be fine.

There is a Engine-Class MAGFXRaster take charges of most 3D functions. MAGFXRaster's reference can be found in MGAIC101 SDK Help later. Now let's build up our first 3D application step by step.

 

Step1:

Open MS-VC 6 and use MAGIC101 AppWizard to create a new MAGIC101 project for 9210. I assume your MAGIC101 SDK is installed to D:\MAGIC101 and your project located at D:\MAGIC101\Samples\First3D and name is First3D, app-symbol is F3D.

Step2: Setup 3D environment

  1. Open F3DPlayUI.h, add two include lines:
    #include "MAGFXRaster.h"
    #include "MAGFXTexManager.h"

  2. Add some member varibales to F3DPlayUI class:
    MAGFXRaster* lpRaster; //The Raster object
    int iViewportW; //Width of Viewport
    int iViewportH; //Height of Viewport
    MAGFIXED fViewLong; //Distance from camera to origin.
    MAGFIXED fViewAngle; //View angle, how wide is your camera
    MAGFIXED fModelXAngle; //Camera direction, in X-Axis.
    MAGFIXED fModelZAngle; //Camera direction in Z-Axis
    MAGFXVECTOR vViewAt; //Where your camera look at?
    MAGFXMesh* lpMesh; //a trianle mesh that will be render.
    MAGFxTexManager* lpTexMan; //resource manager of textures.

  3. Open F3DPlayUI.cpp, in F3DPlayUI::F3DPlayUI() function, initalize new variables:
    iViewportW=320;
    iViewportH=200;
    fViewLong=REALTOFIX(3.0f);
    fViewAngle=REALTOFIX(0.70f);
    fModelXAngle=REALTOFIX(0.5f);
    fModelZAngle=REALTOFIX(3.1415926f);
    vViewAt=0; //this will set all x,y,z elements of vViewAt to 0
    lpRaster=NULL;
    lpMesh=NULL;
    lpTexMan=NULL;

  4. in F3DPlayUI::Free() add resource-release logic:
    SAFERELEASE(lpMesh);
    SAFERELEASE(lpTexMan);
    Note that lpRaster should not be released.

  5. In F3DPlayUI::InitApp(), add resource set-up codes:

    1. First create a MAGBlendTable8 object for engine.

    2. Get raster object from engine and setup it

    3. Setup Camera info

    4. Create texture manager and load textures.

    5. Create mesh object and load content form file.
      List-1 F3DPlayUI::InitApp()

      MAGFXMATRIX vtm,ptm;
      MAGBlendTable8* lptable;

      lpFather=lpf;
      lpCanvas=lpengine->GetCanvas();
      ClientRect.left=0;
      ClientRect.top=0;
      ClientRect.right=ClientRect.left+639;
      ClientRect.bottom=ClientRect.top+199;
      LoadPalette(GAMEPATH(FILE_GAME_PAL));

      //Load Fonts!
      lpFonts[0]=MAGSimpleFont::Create();
      lpFonts[0]->LoadFromFile(GAMEPATH(FILE_GAME_FONT1));
      lpFonts[1]=MAGSimpleFont::Create();
      lpFonts[1]->LoadFromFile(GAMEPATH(FILE_GAME_FONT2));

      lptable=MAGBlendTable8::Create();
      lptable->LoadFromFile(GAMEPATH(FILE_GAME_LIGHTTABLE));
      lpRaster=lpengine->GetRaster();
      lpRaster->SetRastTarget(lpCanvas);
      lpRaster->SetLightPal(lptable);
      lpRaster->Reset(8);
      lpRaster->SetViewport(120,0,320,200,0,REALTOFIX(1.0f));
      lptable->Release();

      vtm=magEasyViewMatrix(MAGFXVECTOR(REALTOFIX(0.0f),fViewLong,REALTOFIX(2.0f)), MAGFXVECTOR(REALTOFIX(0.0f),REALTOFIX(0.0f),REALTOFIX(0.0f)), MAGFXVECTOR(0,0,REALTOFIX(1.0f)));
      lpRaster->SetMatrix(MAGTMTYPE_VIEW,vtm);
      ptm=magProjectMatrix(fViewAngle,REALTOFIX(1.0f*iViewportW/iViewportH), REALTOFIX(0.1f),REALTOFIX(15.0f));
      lpRaster->SetMatrix(MAGTMTYPE_PROJECT,ptm);

      lpRaster->SetRasterState(MAGRS_ZENABLE,0); //Do not use ZBuffer
      lpRaster->SetRasterState(MAGRS_ZSORT,1);
      lpRaster->SetRasterState(MAGRS_CULLMODE,MAGCULL_CCW); lpRaster->SetRasterState(MAGRS_SHADEMODE,MAGSHADE_FLAT);

      lpTexMan=MAGFxTexManager::Create();
      lpTexMan->LoadFromFile(GAMEPATH(FILE_GAME_TEXTURE));

      lpMesh=MAGFXMesh::Create();
      lpMesh->LoadFromFile(GAMEPATH(FILE_MESH_PLANE));

      //Init Controls:
      MAGTextBtn* tmp; tmp=MAGTextBtn::Create(NULL,lpCanvas,F3DPLAYUI_BUTTON1,MAGPoint(510,10),MAGSTR("Demo1"),lpFonts[1],lpFonts[0]);
      tmp->SetSize(MAGPoint(120,40));
      tmp->SetBtnKey(MAGAPP_KEY_F1);
      tmp->AddObserver(this);
      tmp->SetAlignType(MAGALIGN_RIGHT|MAGALIGN_VMIDDLE);
      lpCtrls=tmp;

      tmp=MAGTextBtn::Create(lpCtrls,lpCanvas,F3DPLAYUI_BUTTON2,MAGPoint(0,50),MAGSTR("Demo2"),lpFonts[1],lpFonts[0]);
      tmp->SetSize(MAGPoint(120,40));
      tmp->SetBtnKey(MAGAPP_KEY_F2);
      tmp->AddObserver(this);
      tmp->SetAlignType(MAGALIGN_RIGHT|MAGALIGN_VMIDDLE);
      lpCtrls->AddChild(tmp);
      tmp=MAGTextBtn::Create(lpCtrls,lpCanvas,F3DPLAYUI_BUTTON3,MAGPoint(0,100),MAGSTR("Demo3"),lpFonts[1],lpFonts[0]);
      tmp->SetSize(MAGPoint(120,40));
      tmp->SetBtnKey(MAGAPP_KEY_F3);
      tmp->AddObserver(this);
      tmp->SetAlignType(MAGALIGN_RIGHT|MAGALIGN_VMIDDLE);
      lpCtrls->AddChild(tmp);
      tmp=MAGTextBtn::Create(lpCtrls,lpCanvas,F3DPLAYUI_BUTTON4,MAGPoint(0,150),MAGSTR("QUIT"),lpFonts[1],lpFonts[0]);
      tmp->SetSize(MAGPoint(120,40));
      tmp->SetBtnKey(MAGAPP_KEY_F4);
      tmp->AddObserver(this);
      tmp->SetAlignType(MAGALIGN_RIGHT|MAGALIGN_VMIDDLE);
      lpCtrls->AddChild(tmp);
      StartFade(FADE_IN,1000);
      iState=F3DPLAYUI_FADEIN;

      return 0;

      Italic Fonts means auto generated by MAGIC101 AppWizard

  6. Add scene rendering codes in RenderScene()
    1. First start rendering by call raster's BeginRast();
    2. Clear the render area by call raster's Clear function.
    3. Set the mesh's space position and directions by set raster's world transform matrix.
    4. Get a texture object pointer from
    5. Set mesh's texture
    6. Render the mesh
    7. Exit rendering by call raster's EndRaster() function.
      List - 2 New F3DPlayUI::RenderScen()
      MAGFXMATRIX tm;
      RenderFade();
      lpRaster->BeginRast();
      lpRaster->Clear(0,0,MAGCLEAR_TARGET|MAGCLEAR_ZBUFFER);
      tm=magIdentityMatrix();
      lpRaster->SetMatrix(MAGTMTYPE_WORLD,tm);
      lpRaster->SetTexture(NULL);
      lpMesh->Render(lpRaster);
      lpRaster->EndRast();
      if(lpCtrls)
          lpCtrls->Draw();
      return ;
       

  7. Add scene animation codes to UpdateScene();