In memory of Ben “bushing” Byer, who passed away on Monday, February 8th, 2016.

User:Michelinux/3DGlasses

From WiiBrew
< User:Michelinux
Jump to navigation Jump to search
3DGlasses
General
Author(s)Michelinux
TypeLibrary

Description

3DGlasses is a C++ library to develop applications that can be seen wearing 3D glasses.

This is not a full featured 3D library: it's your responsability to draw objects in correct z-order.

Development status

  • Reading/writing configuration file works
  • Geometry init works
  • Simple shapes are drawn correctly

Supported glasses

Different kind of 3D glasses exists, this library supports the old ones with each lens of a different color; these glasses are called anaglyphs. Most common anaglyphs have a red lens for left eye, and a cyan lens for the right one, also exists glasses with green - magenta and very rare ones with yellow - blue lenses; 3DGlasses library supports all of them.

Geometry

Origin of the axis is set at the center of the screen, with x incresing towards right, y increasing towards botton and z increasing towards "internal" of screen. For negative values of z the object appears outside the tv, inside the screen for positive values.

For z = 0, x goes from -320 to 320; perspective makes the range narrower for z < 0 and wider for z > 0. Y scale may change because the library tryes to keep 1:1 aspect ratio between axis.

Configuration file

The configuration file 3DGlasses.cfg, inside the main directory of your SD, is shared among all applications using this library. This file contains geometry info about your screen and the kind of anaglyphs you wear.

Probably this file is created the first time you run an application using 3DGlasses. If you change tv or glasses just delete this file (it will be recreated) or edit it by hand (instructions are inside the file itself).

Use of colors

Since the two eyes see different colors of the image you must avoid pure colors in your applications: if you draw a monochromatic red object it will be seen only by left eye with no 3D effect at all.

Classes

3DGlasses library defines its own namespace: l3dg with the following classes

l3dg::Glasses

It's the main class of the library; you need to instanziate one (probably no more than one) object of this class.

This class incapsulates a GRRLIB_texImg where the drawing of the 3D scene happens. startDrawing() method clears internal image while doneDrawing() puts it on the screen.

You can provide a callback function to the constructor of this class; if configuration file is not found, che callback is called to ask user some parameters. If configuration file is found, callback is not called.

That's the public part of the class:

class Glasses {
public:
 Glasses(void callback(glassesTypes& , unsigned int&, bool&, float&, unsigned int&)=NULL);
 Glasses(const Glasses &g);
 ~Glasses();
 u32 getLeftColor() const;
 u32 getRightColor() const;
 void splitColor(u32 color, u32 &left, u32 &right) const;
 qualities getQuality() const;
 void setQuality(qualities quality);
 visibility getPerspectives(const Vector3D &point, Vector2D &left, Vector2D &right) const;
 float getMinX(float z, bool overscanSafe) const;
 float getMaxX(float z, bool overscanSafe) const;
 float getMinY(float z, bool overscanSafe) const;
 float getMaxY(float z, bool overscanSafe) const;
 float getMinZ(float x, float y, bool overscanSafe) const;
 void startDrawing();
 void doneDrawing() const;
 void drawDot(int x, int y, eyes eye, u32 color);
 void drawDot(int x, int y, eyes eye, u32 color, u32 opaqueness, u32 transparency);
 void drawDot(int x, int y, eyes eye, u32 color, u32 textureColor);
 void dualDotDraw(int x, int y, u32 color, u32 leftTextureColor, u32 rightTextureColor);
};

Sample code

The user can select parameter using up/down buttons of wiimote, adjust values with left/right buttons. A rectangle is shown to adjust xYRatioCorrection: make it a square to set proper value. Press button A when finished.

#include <wiiuse/wpad.h>
#include <3DGlasses.h>
#include "BMfont4.h"

#define GRAY 0x808080FF
#define WHITE 0xFFFFFFFF

GRRLIB_texImg *tex_BMfont4;

void callback(l3dg::glassesTypes &glassesType, unsigned int &screenSize, bool &isWidescreen, float &xYRatioCorrection, unsigned int &distanceEyesScreen) {
 guVector v[5];
 v[0].x= 280; v[0].y= 320; v[0].z= 0;
 v[1].x= 370; v[1].y= 320; v[1].z= 0;
 v[2].x= 370; v[2].y= 320 + 100 * xYRatioCorrection; v[2].z= 0;
 v[3].x= 280; v[3].y= v[2].y; v[3].z= 0;
 v[4].x= 280; v[4].y= 320; v[4].z= 0;
 u32 textColors[4];
 u32 quadColors[5];
 u32 pressed;
 int type= glassesType;
 int i;
 int hilighted= 0;
 do {
   for (i= 0; i < 4; i++) {
     if (i == hilighted) {
       textColors[i]= WHITE;
     } else {
       textColors[i]= GRAY;
     }
   }
   for (i= 0; i < 5; i++) {
     if (hilighted == 4) {
       quadColors[i]= WHITE;
     } else {
       quadColors[i]= GRAY;
     }
   }
   WPAD_ScanPads();
   pressed= WPAD_ButtonsDown(0);
   switch (hilighted) {
     case 0:
       if (pressed & WPAD_BUTTON_RIGHT) type++;
       else if (pressed & WPAD_BUTTON_LEFT) type--;
       if (type < 0) type= l3dg::glassesTypesNumber - 1;
       else if (type >= l3dg::glassesTypesNumber) type= 0;
     break;
     case 1:
       if (pressed & WPAD_BUTTON_RIGHT) screenSize++;
       else if (pressed & WPAD_BUTTON_LEFT) screenSize--;
     break;
     case 2:
       if (pressed & (WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT)) isWidescreen= !isWidescreen;
     break;
     case 3:
       if (pressed & WPAD_BUTTON_RIGHT) distanceEyesScreen++;
       else if (pressed & WPAD_BUTTON_LEFT) distanceEyesScreen--;
     break;
     case 4:
       if (pressed & WPAD_BUTTON_RIGHT) xYRatioCorrection+= 0.05;
       else if (pressed & WPAD_BUTTON_LEFT) xYRatioCorrection-= 0.05;
       v[2].y= 320 + 100 * xYRatioCorrection;
       v[3].y= v[2].y;
     break;
   }
   if (pressed & (WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT)) {
   }
   if (pressed &  WPAD_BUTTON_DOWN) {
     hilighted++;
     if (hilighted > 4) hilighted= 0;
   }
   if (pressed &  WPAD_BUTTON_UP) {
     hilighted--;
     if (hilighted < 0) hilighted= 4;
   }
   GRRLIB_FillScreen(0x00000000);
   GRRLIB_Printf(64, 64, tex_BMfont4, textColors[0], 1, "GLASSES TYPE: %s", l3dg::glassesTypesStrings[type]);
   GRRLIB_Printf(64, 128, tex_BMfont4, textColors[1], 1, "SCREEN SIZE: %d\"", screenSize);
   if (isWidescreen) {
     GRRLIB_Printf(64, 192, tex_BMfont4, textColors[2], 1, "16:9 WIDESCREEN");
   } else {
     GRRLIB_Printf(64, 192, tex_BMfont4, textColors[2], 1, "4:3");
   }
   GRRLIB_Printf(64, 256, tex_BMfont4, textColors[3], 1, "DISTANCE EYES-SCREEN: %d CM", distanceEyesScreen);
   GRRLIB_NGone(v, quadColors, 5);
   GRRLIB_Render();
 } while (!(pressed & WPAD_BUTTON_A));
 glassesType= (l3dg::glassesTypes) type;
}

int main(int argc, char *argv[]) {
 GRRLIB_Init();
 tex_BMfont4= GRRLIB_LoadTexture(BMfont4);
 GRRLIB_InitTileSet(tex_BMfont4, 16, 16, 32);
 WPAD_Init();
 l3dg::Glasses glasses= l3dg::Glasses(callback);
 u32 pressed= WPAD_ButtonsDown(0);
 while (!(pressed & WPAD_BUTTON_HOME)) {
   GRRLIB_FillScreen(0x00000000);
   // draw your own 2D background here using GRRLIB
   glasses.startDrawing();
   // draw 3D scene here using 3DGlasses library
   glasses.doneDrawing();
   // draw your own 2D foreground here using GRRLIB
   GRRLIB_Render();
   WPAD_ScanPads();
   pressed= WPAD_ButtonsDown(0);
 }
 GRRLIB_Exit();
}

l3dg::DrawableObject

This abstract class is the ancestor of all the objects you can draw with 3DGlasses library.

The constructor needs a reference to a Glasses type object to learn about geometry.

Every object has its own visible attribute: visibility is an enum wich can be NOT_VISIBLE, PERHAPS_VISIBLE or VISIBLE. PERHAPS_VISIBLE is used when the object is near the border of the screen (overscan unsafe area) or when its visibility is hard to compute.

class DrawableObject {
public:
 DrawableObject(Glasses &glasses, const Vector3D &position, u32 color);
 DrawableObject(const DrawableObject &d);
 virtual void setPosition(const Vector3D &position);
 const Vector3D &getPosition() const;
 void setColor(u32 color);
 u32 getColor() const;
 visibility getVisibility() const;
 virtual void draw() const =0;
protected:
 Glasses *glasses;
 Vector3D position;
 u32 color;
 visibility visible;
};

l3dg::Point

A Point is the simplest object you can draw: it is projected to two screen points of different color, each one seen by only one eye.

class Point : public DrawableObject {
public:
 Point(Glasses &glasses, const Vector3D &position, u32 color);
 Point(const Point &p);
 void setPosition(const Vector3D &position);
 void draw() const;
private:
 Vector2D left;
 Vector2D right;
};

Sample code

Draw a single point, half way between screen and observer.

l3dg::Glasses glasses= l3dg::Glasses(callback);
l3dg::Vector3D position= l3dg::Vector3D(0, 0, glasses.getMinZ(0, 0, true) / 2);
l3dg::Point point= l3dg::Point(glasses, position, WHITE);
GRRLIB_FillScreen(0x00000000);
glasses.startDrawing();
point.draw();
glasses.doneDrawing();
GRRLIB_Render();

Contacts

michelinux AT gmail DOT com