User:Mucki.at

From WiiBrew
Jump to navigation Jump to search

Hi fellow homebrew users and devs. Since I don't have much conclusive to say atm, so I'll just put up some random notes here on stuff that comes up during my work.

Third Party Libs

libogc is nice, but of course one needs a lot of other things to make a successful project. Since I am cosing c++ I need boost as a basis for utilities. Secondly, resource loading and management.

Boost

Don't even start a project without it ;-)

I used the instructions from User:AerialX/Coding_Sandbox/Boost.Regex to get me started. So far I was unable to actually build boost::regex as he did. The header-only libs work perfectly though. I am missing boost::filesystem a bit, and boost:serialization would have been handy aswell. Of course it would be nice to have boost::asio, but I am afraid with the limited networking this is currently out of the question.

Resources

Resources are a very importat part of any game-like project. Besides the problem of actually loading and rendering them, they also pose a lot of other problems:

  • How to create them
  • How to manage them reasonably
  • How does your game find them, how do resources reference other resources ?
  • How to store them efficiently

To start out, I decided to use plain image files for textures and an open format with blender support for meshes. The usual image formats (png, ...) are not the best suited for storing textures, but they are easy to come by and edit. They can be automatically converted into something more suitable later.

FreeImage

I found a prebuilt binary of the FreeImage library and also a patch that can be used to roll ones own (FreeImage Wii-Port). The library is quite big size-wise but loads images perfectly.

Collada

Collada is quite complex, but having the data in XML makes it easier to debug it all, and it has the big advantage of providing meshes, skeletal animation, skinning, physics and materials all in one package. I am currently trying to build a wii version, see the talk page for updates until i have a final version ready.

UPDATE: the build of collada seems to work well. I am able to import scenes from blender with animations. Cleaned up building instructions will follow soon

Bullet

I decided to try bullet for collision detection and physics. It integrates in collada, blender has support for it, and it is used in wii games, so at least in theory it works on the wii.

Development

Logging

Since neither a debugger, nor a convenient console are available, I decided to implement network logging. I am queueing up log messages on the wii, and then send it one message per frame so as not to block the application. I wrote a quick Qt app to show them, but netcat would do as well. Drop me a note if you are interested in some sample code.

Graphics

The GX part of libogc is excellent, but documentation is a bit sketchy. I had to find out most of the stuff by trial and error, so I am collecting the info i found here:

Vertex Arrays

They should be faster than direct mode, but so far i haven't gotten them to work. If i enable them, then some indices seem to get lost. My triangles reference wrong vertices and generally everything breaks down.

Lighting

  • Use GX_InitLightXYZ to setup your GXLightObj. You only need to do this once
  • Use GC_LoadLightObj to load the previously initialized light into one of the predefined light IDs. You can have 8 lights loaded at the same time, if your scene has more, then you need some mechanism to decide which to use. I don't know how expensive this call is, but its probably best not to overabuse it.
  • The tricky part: Setup color channels to calculate the lighting
  • Use GX_SetNumChans to set the number of color channels. max is two (GX_COLOR0A0, GX_COLOR1A1).
  • Use SetChanCtrl to actually enable lighting for a channel:
   GX_SetChanCtrl(		// set channel params
       GX_COLOR0A0,	// for color and alpha 0
       TRUE,			// enable it (ie: enable lighting)
       GX_SRC_REG,		// take ambient color from register (ie: material), other choice: VTX
       GX_SRC_REG,		// take diffuse color from register (ie: material), other choice: VTX
       GX_LIGHT0,		// apply the params of light 0
       GX_DF_CLAMP,		// none, signed, clamp,	??
       GX_AF_SPOT		// none, spot, specular	??
   );
  • If you use GX_SRC_REG, then use GX_SetChanXXXColor to define the color of the material, if you use GX_SRC_VTX then use vertex colors (GX_ColorXXX family of calls)
  • It might be possible to use something like GX_LIGHT0 | GXLIGHT2 to use both lights 0 and 2 for a channel.

Textures

  • Use the following code to setup simple texturing with one diffuse texture that is modulated (ie: made brighter and darker) by the lighting and material color:
   GX_SetNumTexGens(1);
   GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
   GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
   GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
  • You must send texture coordinates (GX_TexCoord2f32 and the like) to define which part of the texture goes where on your model.
  • Initialize the texture as follows (use GX_TF_RGBA8 for 32bit textures with alpha channel). It might look weird, but the data is actually filled after the init call. The final DCFlushRange makes sure the data is stored in memory correctly before it is used:
   data=memalign(32,width*height*4);
   GX_InitTexObj(&texObj, data, width, height, format, GX_CLAMP, GX_CLAMP, GX_FALSE);
   // copy colors to data
   DCFlushRange(data, width*height*4);

Texture Layout in memory

The memory layout of textures is a bit complicated. Usually images are stored line by line, with the components packed. The following two lines would be a 4x2 pixel argb image:

   ARGBARGBARGBARGB
   ARGBARGBARGBARGB

The wii however, stores textures in 4x4 pixel blocks of data. The memory contains the blocks in row major order, that is: first come the first row of blocks, followed by the second, and so on. The following sample shows the block layout for a texture of size 12x8:

   (Block at 0,0)(Block at 4,0)(Block at 8,0)(Block at 0,4)(Block at 4,4)(Block at 8,4)

Within each block, the data is stored in fields of 32 bytes. Since each block has 16 pixels, that means that 16 bit textures (ex. RGB565) need exactly 1 field (16 pixels * 2 bytes per pixel) and 32 bit (RGBA8) needs 2 fields. The pixels are stored in row major order in each field, with the components packed, just like an ordinary image. However, since each field only stores 2 bytes per pixel, 32bit formats are split as follows:

  • the first field contains alpha and red values in the order AR
  • the second field contains green and blue values in the order GB

in memory a single block of 32bit data looks like this:

   ARARARAR
   ARARARAR
   ARARARAR
   ARARARAR
   GBGBGBGB
   GBGBGBGB
   GBGBGBGB
   GBGBGBGB

You can use the following code to transform an image in memory that is in RGBA color order (like the ones from FreeImage) to the internal format:

   u8* block=(u8*)data;
   u8* line[4];
   for (u32 y=0; y<height; y+=4)
   {
       // fetch the next 4 scanlines
       line[0]=(u8*)FreeImage_GetScanLine(src,height-y-1);
       line[1]=(u8*)FreeImage_GetScanLine(src,height-y-2);
       line[2]=(u8*)FreeImage_GetScanLine(src,height-y-3);
       line[3]=(u8*)FreeImage_GetScanLine(src,height-y-4);
       
       for (u32 x=0; x<width; x+=4)
       {
           for (int l=0; l<4; ++l)
           {
               // copy AR pairs
               block[ 0]=line[l][ 3];	block[ 1]=line[l][ 0];
               block[ 2]=line[l][ 7];	block[ 3]=line[l][ 4];
               block[ 4]=line[l][11];	block[ 5]=line[l][ 8];
               block[ 6]=line[l][15];	block[ 7]=line[l][12];
               
               // copy GB pairs
               block[32]=line[l][ 1];	block[33]=line[l][ 2];
               block[34]=line[l][ 5];	block[35]=line[l][ 6];
               block[36]=line[l][ 9];	block[37]=line[l][10];
               block[38]=line[l][13];	block[39]=line[l][14];
               
               block+=8;
               line[l]+=16;
           }
           block+=32;
       }
   }

Limitations

Usually not all combinations of features that can be enabled on a graphics hardware work. I have found the following limitations so far:

  • Using vertex colors and texture coordinates at the same time does not seem to work. If i send both texture coordinates and colors for a vertex, become screwed up. Basically texture coordinates are all messed up, and colors just become random.