From WiiBrew
Jump to navigation Jump to search

3D Library

GX API for my own reference:

Perhaps a 3D Class library is in order? GX and TEV look really complex, though it does bear some similarities to OpenGL. Something that takes a lot of the linear algebra out of the equation and lets the user work simply with 3D model files and height fields, utilize prewritten effects (and generate custom ones too), and integrate seamlessly with 2D libraries like GRRLIB and Libwiisprite would be awesome and would really help the learning curve out a lot. These are just ideas of course.

I volunteer to work on this in my spare time if nobody else has chosen to undertake a task of this magnitude, but don't expect anything really impressive really soon. I'll probably work on class abstractions for GX stuff as I learn it, but a really sophisticated library will probably be a rewrite once I get good at low-level Wii programming.

Bernerbrau 12:51, 20 July 2009 (UTC)

Cursor Library

This is just something I hacked together over one weekend to clean up some stray globals and pull all the wiimote management code into its own place.

The following C++ library can be used to easily display up to 4 cursors on the screen using the wiimotes. It allows for semi-loose coupling with the rest of the app. Further work, especially callbacks for button presses, controller extensions, accelerometer goodness etc., are needed to utilize all the Wiimote capabilities. I may look into boost bindings which would allow for more flexible callbacks.

It links to HomeMenu and libwiisprite. It also requires some images be defined (as unsigned char arrays, from png files). I used the ones available in the wiimote cursor package (Wii Homebrew Cursors).

Some setup in the main function is required, as well as third-party dependencies that must be installed (Development Tools).

The header utilizes the compiler firewall for quick compilation of files it is included in. The implementation uses reference counting to minimize the amount of heavy-duty memory copies during call-by-value operations. This could be further reduced by grouping all the privates into a pimpl class.


#pragma once

#include <gccore.h>

namespace wsp {
	class Sprite;
	class Image;

class _wpad_data;
typedef _wpad_data WPADData;

class Cursor {
	static void init(int max_pads);
	static void update();
	static void drawAll();

	Cursor(Cursor const &);
	Cursor& operator=(Cursor const &);

	void destruct();

	s32 chan;
	wsp::Image* pointerImg;
	wsp::Sprite* pointer;
	wsp::Sprite* shadow;
	static void readEvent(s32 channel, const WPADData * data);

	int* copies;

	void readEvent(const WPADData * data);

	int cursorx, cursory, cursora;
	bool drawCursor;
	Cursor(s32 channel);


<source lang="cpp">

  1. include "cursor.h"
  2. include "images.h"
  1. include <wiiuse/wpad.h>
  2. include <wiiuse/wiiuse.h>
  1. include <map>

using std::map;

  1. include <wiisprite.h>

using namespace wsp;

extern "C" { bool HomeMenu_Show(); } extern GameWindow window;

static const u16 FRAMES_PER_SECOND = 60; static unsigned long long framecount; static int showHome = 0;

static map<s32,Cursor> cursors;

static LayerManager mgr(8); static Image shadowImg;

void Cursor::init(int max_pads) { shadowImg.LoadImage(shadow_point_data);

WPAD_Init(); for(int i = 0; i < max_pads; i++) { WPAD_SetVRes(i,window.GetWidth()+400,window.GetHeight()+400); WPAD_SetDataFormat(i, WPAD_FMT_BTNS_ACC_IR); Cursor& c = cursors[i]; c = Cursor(i); mgr.Append(c.pointer); mgr.Append(c.shadow); } }

void Cursor::update() { framecount++; WPAD_ReadPending(WPAD_CHAN_ALL, Cursor::readEvent); }

void Cursor::readEvent(s32 channel, const WPADData * data) { if(cursors.size() > static_cast<u32>(channel)) { cursors[channel].readEvent(data); } }

void Cursor::readEvent(const WPADData * data) { drawCursor = data->ir.smooth_valid; if(drawCursor) { cursorx = data->; cursory = data->; cursora = data->orient.roll;

shadow->SetPosition(cursorx-34,cursory-32); shadow->SetRotation(cursora/2); pointer->SetPosition(cursorx-36,cursory-36); pointer->SetRotation(cursora/2); } else { shadow->SetPosition(-1000,-1000); pointer->SetPosition(-1000,-1000); }

if(framecount % (FRAMES_PER_SECOND*4) < (FRAMES_PER_SECOND / 8)) { WPAD_Rumble(chan,1); } else { WPAD_Rumble(chan,0); }

// We return to the launcher application via exit() u32 up = data->btns_u; if ( up & WPAD_BUTTON_HOME && showHome == 0 ) { showHome = 1; } else if ( !(up & WPAD_BUTTON_HOME) && showHome < 0 ) { showHome ++; } }

void Cursor::drawAll() { if(showHome == 1) { WPAD_Rumble(WPAD_CHAN_ALL,0); HomeMenu_Show(); showHome = -20; } else { mgr.Draw(0,-50); } }

Cursor::Cursor() : pointerImg(new Image), pointer(new Sprite), shadow(new Sprite), copies(new int(1)) { pointerImg->LoadImage(generic_point_data);

pointer->SetImage(pointerImg); shadow->SetImage(&shadowImg); pointer->SetZoom(0.75); shadow->SetZoom(0.75); shadow->SetPosition(-1000,-1000); pointer->SetPosition(-1000,-1000); }

Cursor::Cursor(s32 channel) : chan(channel), pointerImg(new Image), pointer(new Sprite), shadow(new Sprite), copies(new int(1)), cursorx(0), cursory(0), cursora(0), drawCursor(false) { switch(channel) { case 0: pointerImg->LoadImage(player1_point_data); break; case 1: pointerImg->LoadImage(player2_point_data); break; case 2: pointerImg->LoadImage(player3_point_data); break; case 3: pointerImg->LoadImage(player4_point_data); break; }

pointer->SetImage(pointerImg); shadow->SetImage(&shadowImg); shadow->SetZoom(0.75); pointer->SetZoom(0.75); shadow->SetPosition(-1000,-1000); pointer->SetPosition(-1000,-1000); }

Cursor& Cursor::operator=(Cursor const & other) { destruct();

chan = other.chan; pointerImg = other.pointerImg; pointer = other.pointer; shadow = other.shadow; copies = other.copies; cursorx = other.cursorx; cursory = other.cursory; cursora = other.cursora; drawCursor = other.drawCursor;


return *this; }

Cursor::Cursor(Cursor const & other) : chan(other.chan), pointerImg(other.pointerImg), pointer(other.pointer), shadow(other.shadow), copies(other.copies), cursorx(other.cursorx), cursory(other.cursory), cursora(other.cursora), drawCursor(other.drawCursor) { (*copies)++; }

Cursor::~Cursor() { destruct(); }

void Cursor::destruct() { (*copies)--; if(*copies == 0) { delete shadow; delete pointer; delete pointerImg; delete copies; } }