• Main Page
  • Classes
  • Files
  • File List
  • File Members

code/source/main.cpp

Go to the documentation of this file.
00001 /*
00002  * TetriCycle
00003  * Copyright (C) 2009, 2010 Cale Scholl
00004  *
00005  * This file is part of TetriCycle.
00006  *
00007  * TetriCycle is free software: you can redistribute it and/or modify
00008  * it under the terms of the GNU Lesser General Public License as published
00009  * by the Free Software Foundation, either version 3 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * TetriCycle is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with TetriCycle.  If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00021 /** @file main.cpp
00022  * @brief TetriCycle for Wii.
00023  * @author Cale Scholl / calvinss4
00024  *
00025  * @mainpage TetriCycle
00026  *
00027  * @section Introduction
00028  * TetriCycle is Tetris projected onto a cylindrical surface. Rotate the 
00029  * cylinder left/right such that the descending piece falls into place.
00030  * TetriCycle is freeware, can be distributed freely and should never be charged for. \n
00031  * http://www.wiibrew.org/wiki/TetriCycle
00032  *
00033  * @section License
00034  * TetriCycle is distributed under the GNU Lesser General Public License.
00035  *
00036  * @section Contact
00037  * If you have any suggestions for documentation, or want to contribute, 
00038  * please visit the TetriCycle code website: \n
00039  * http://code.google.com/p/tetricycle/ \n
00040  * Please do not release mods; contribute to the source!
00041  *
00042  * @section Credits
00043  * Version 1.0 written by calvinss4.
00044  * @par
00045  *
00046  * - Thanks to Sonicdude41 for the idea of Tetris on a Cylindrical Surface: http://forum.wiibrew.org/read.php?26,41651
00047  * - Thanks to DesktopMan for sharing his source: http://www.wiibrew.org/wiki/Tetris_Wii
00048  * - Thanks to Tantric for his awesome Libwiigui library: http://www.wiibrew.org/wiki/Libwiigui
00049  * - Menu music is from 'tetricycle by dj dimz': http://www.youtube.com/watch?v=JGfJUM6-e10
00050  *
00051  * @section powerupsection Powerup Framework
00052  * For a list of all powerups, please see the @subpage poweruplistpage "Powerup List" page. \n
00053  * For information on adding new powerups, please see the @subpage powerupcreationpage "Powerup Creation" page.
00054  */
00055 
00056 #include <gcmodplay.h> // for MODPlay
00057 #include <fat.h>       // for fatInitDefault
00058 
00059 #include "main.h"       // for function prototypes
00060 #include "tcyc_input.h" // for input macros
00061 #include "tcyc_menu.h"  // for TCYC_MenuLoop
00062 #include "audio.h"      // for InitAudio
00063 #include "menu.h"       // for InitVideo
00064 #include "Options.h"    // for Options
00065 #include "Player.h"     // for Player
00066 
00067 // include generated headers
00068 #include "tetris_mod.h"
00069 #include "pieces_bin.h"
00070 
00071 extern TetrisPieceDesc g_pieceDesc[TETRISPIECE_ID_MAX][4]; ///< static description of every tetris piece for all 4 rotations
00072 extern ColorGradient g_cubeGradients[COLOR_ID_MAX]; ///< gradients for coloring the face of a tetris piece block
00073 extern Player *g_players;   ///< the player instances
00074 extern u32 *g_xfb[2];       ///< the external frame buffer
00075 extern GXRModeObj *g_vmode; ///< the video mode
00076 extern Mtx GXmodelView2D;   ///< 2D modelview matrix
00077 extern Mtx44 orthographic;  ///< 2D projection matrix
00078 extern Mtx g_view;          ///< the global view matrix
00079 extern Options *g_options;  ///< the global options
00080 extern MODPlay g_modPlay;   ///< used for playing the game music
00081 extern bool g_isEditMode;   ///< true when editing the playfield
00082 extern int g_tcycMenu;      ///< the current menu state
00083 
00084 extern GuiWindow *mainWindow;
00085 extern GuiTrigger *trigA;
00086 extern GuiSound *btnSoundOver;
00087 extern GuiSound *g_tetrisCheerSound;
00088 extern GuiImageData *btnData40x40Square;
00089 extern GuiImageData *btnData40x40SquareOver;
00090 extern GuiImageData *grabber[MAX_PLAYERS];
00091 extern GuiImageData *debug_grabber1;
00092 extern GuiImageData *debug_grabber2;
00093 extern GuiImageData *debug_grabber3;
00094 extern GuiImageData *debug_grabber4;
00095 extern GuiImageData *pointer[MAX_PLAYERS];
00096 
00097 static Mtx44 projection;
00098 
00099 // function prototypes
00100 static void TCYC_Update();
00101 static void TCYC_Draw();
00102 static void TCYC_DrawPlayfieldBoundary();
00103 static void TCYC_DrawTetriCycle();
00104 static void TCYC_DrawPowerups();
00105 static void TCYC_DrawPowerupBorders();
00106 static void TCYC_DrawPowerupTextures();
00107 static void TCYC_DrawPowerupTexture(int upperLeftX, int upperLeftY, GuiImageData *imgData, u8 alpha);
00108 static void TCYC_Render();
00109 
00110 static void TCYC_DrawEditMode();
00111 static void TCYC_DrawTetriCycleEditMode();
00112 static void TCYC_DrawEditPlayfieldMenu();
00113 
00114 // helper routines
00115 static void TCYC_InitPieceDescriptions();
00116 static void TCYC_GameInit();
00117 static void TCYC_GameOnExit();
00118 
00119 int main()
00120 {
00121   // VIDEO and GX initialization is handled by video#InitVideo.
00122   // PAD and WPAD initialization is handled by input#SetupPads
00123   // AUDIO and ASND init is handled by audio#InitAudio
00124   InitVideo(); // Initialize video
00125   SetupPads(); // Initialize input
00126   InitAudio(); // Initialize audio
00127   fatInitDefault(); // Initialize file system
00128   InitFreeType((u8*)font_ttf, font_ttf_size); // Initialize font system
00129   InitGUIThreads(); // Initialize GUI
00130 
00131   // Initialize the view matrix.
00132   // Setup the camera at the origin, looking down the -z axis with y up.
00133   guVector cam  = {0.0F, 0.0F, 0.0F};
00134   guVector up   = {0.0F, 1.0F, 0.0F};
00135   guVector look = {0.0F, 0.0F, -1.0F};
00136   guLookAt(g_view, &cam, &up, &look);
00137 
00138   // Initialize the projection matrix.
00139   // This creates a perspective matrix with a view angle of 90,
00140   // and aspect ratio based on the display resolution.
00141   f32 w = g_vmode->viWidth;
00142   f32 h = g_vmode->viHeight;
00143   guPerspective(projection, 45, (f32)w/h, 0.1F, 300.0F);
00144 
00145   // Initialize the main gui resources.
00146   mainWindow = new GuiWindow(screenwidth, screenheight);
00147   pointer[0] = new GuiImageData(player1_point_png);
00148   pointer[1] = new GuiImageData(player2_point_png);
00149   pointer[2] = new GuiImageData(player3_point_png);
00150   pointer[3] = new GuiImageData(player4_point_png);
00151 
00152   // Initialize TetriCycle settings.
00153   // Vertex data initialization is handled by video#ResetVideo_Menu.
00154   TCYC_InitPieceDescriptions();
00155   MODPlay_Init(&g_modPlay);
00156   MODPlay_SetMOD(&g_modPlay, tetris_mod);
00157   g_totalPowerups = PowerupUtils::GetTotalPowerups();
00158 
00159   // Options and Players must be initialized after setting g_totalPowerups!
00160   g_options = &Options::GetInstance(); // the global options
00161   g_players = new Player[MAX_PLAYERS];
00162   for (int i = 0; i < MAX_PLAYERS; ++i)
00163     g_players[i].id = i;
00164 
00165   // Enter the game state loop.
00166   TCYC_MenuLoop();
00167 }
00168 
00169 /// Runs the game loop.
00170 void TCYC_Game()
00171 {
00172   TCYC_GameInit();
00173 
00174   while (true)
00175   {
00176     TCYC_Update();
00177 
00178     // Do this here so the screen doesn't flicker when the game is quit.
00179     if (g_tcycMenu != TCYC_MENU_NONE)
00180       break;
00181 
00182     TCYC_Draw();
00183     TCYC_Render();
00184   }
00185 
00186   TCYC_GameOnExit();
00187 }
00188 
00189 /// Updates the game.
00190 void TCYC_Update()
00191 {
00192   ALL_ScanPads();
00193   TCYC_ProcessInput();
00194 
00195   for (int i = 0; i < g_options->players; ++i)
00196     g_players[i].Update();
00197 
00198   if (!g_tetrisCheerSound->IsPlaying())
00199     MODPlay_Pause(&g_modPlay, 0); // unpause music
00200 }
00201 
00202 /// Draws the game.
00203 void TCYC_Draw()
00204 {
00205   TCYC_SetUp2D();
00206   TCYC_DrawPlayfieldBoundary();
00207   TCYC_DrawText();
00208 
00209   TCYC_DrawTetriCycle();
00210 
00211   if (g_options->players > 1)
00212   {
00213     TCYC_SetUp2D();
00214     TCYC_DrawPowerups();
00215   }
00216 }
00217 
00218 /// Prepares for drawing 2D.
00219 void TCYC_SetUp2D()
00220 {
00221   // Prepare for drawing 2D.
00222   GX_SetZMode(GX_FALSE, GX_LEQUAL, GX_TRUE);
00223   GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
00224   GX_LoadProjectionMtx(orthographic, GX_ORTHOGRAPHIC);
00225 }
00226 
00227 /// Draws the playfield boundary for every player.
00228 void TCYC_DrawPlayfieldBoundary()
00229 {
00230   switch (g_options->players)
00231   {
00232     case 1:
00233       GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
00234         //--- 1P quad ---
00235         GX_Position3f32(0, 0, 0);     // top left
00236         GX_Color4u8(0, 0, 20, 255);
00237         GX_Position3f32(640, 0, 0);   // top right
00238         GX_Color4u8(88, 88, 108, 255);
00239         GX_Position3f32(640, 480, 0); // bottom right
00240         GX_Color4u8(195, 195, 215, 255);
00241         GX_Position3f32(0, 480, 0);   // bottom left
00242         GX_Color4u8(88, 88, 108, 255);
00243       GX_End();
00244     break;
00245 
00246     case 2:
00247       GX_Begin(GX_QUADS, GX_VTXFMT0, 8);
00248         //--- 1P quad ---
00249         GX_Position3f32(0, 0, 0);             // top left
00250         GX_Color4u8(0, 0, 20, 255);
00251         GX_Position3f32(P2_X_BORDER, 0, 0);   // top right
00252         GX_Color4u8(88, 88, 108, 255);
00253         GX_Position3f32(P2_X_BORDER, 480, 0); // bottom right
00254         GX_Color4u8(195, 195, 215, 255);
00255         GX_Position3f32(0, 480, 0);           // bottom left
00256         GX_Color4u8(88, 88, 108, 255);
00257 
00258         //--- 2P quad ---
00259         GX_Position3f32(P2_X_BORDER, 0, 0);   // top left
00260         GX_Color4u8(0, 0, 20, 255);
00261         GX_Position3f32(640, 0, 0);           // top right
00262         GX_Color4u8(88, 88, 108, 255);
00263         GX_Position3f32(640, 480, 0);         // bottom right
00264         GX_Color4u8(195, 195, 215, 255);
00265         GX_Position3f32(P2_X_BORDER, 480, 0); // bottom left
00266         GX_Color4u8(88, 88, 108, 255);
00267       GX_End();
00268     break;
00269 
00270     case 3:
00271       GX_Begin(GX_QUADS, GX_VTXFMT0, 12);
00272         //--- 1P quad ---
00273         GX_Position3f32(0, 0, 0);               // top left
00274         GX_Color4u8(0, 0, 20, 255);
00275         GX_Position3f32(P3_X_BORDER_1, 0, 0);   // top right
00276         GX_Color4u8(88, 88, 108, 255);
00277         GX_Position3f32(P3_X_BORDER_1, 480, 0); // bottom right
00278         GX_Color4u8(195, 195, 215, 255);
00279         GX_Position3f32(0, 480, 0);             // bottom left
00280         GX_Color4u8(88, 88, 108, 255);
00281 
00282         //--- 2P quad ---
00283         GX_Position3f32(P3_X_BORDER_1, 0, 0);   // top left
00284         GX_Color4u8(0, 0, 20, 255);
00285         GX_Position3f32(P3_X_BORDER_2, 0, 0);   // top right
00286         GX_Color4u8(88, 88, 108, 255);
00287         GX_Position3f32(P3_X_BORDER_2, 480, 0); // bottom right
00288         GX_Color4u8(195, 195, 215, 255);
00289         GX_Position3f32(P3_X_BORDER_1, 480, 0); // bottom left
00290         GX_Color4u8(88, 88, 108, 255);
00291 
00292         //--- 3P quad ---
00293         GX_Position3f32(P3_X_BORDER_2, 0, 0);   // top left
00294         GX_Color4u8(0, 0, 20, 255);
00295         GX_Position3f32(640, 0, 0);             // top right
00296         GX_Color4u8(88, 88, 108, 255);
00297         GX_Position3f32(640, 480, 0);           // bottom right
00298         GX_Color4u8(195, 195, 215, 255);
00299         GX_Position3f32(P3_X_BORDER_2, 480, 0); // bottom left
00300         GX_Color4u8(88, 88, 108, 255);
00301       GX_End();
00302     break;
00303 
00304     case 4:
00305       GX_Begin(GX_QUADS, GX_VTXFMT0, 16);
00306         //--- 1P quad ---
00307         GX_Position3f32(0, 0, 0);               // top left
00308         GX_Color4u8(0, 0, 20, 255);
00309         GX_Position3f32(P4_X_BORDER_1, 0, 0);   // top right
00310         GX_Color4u8(88, 88, 108, 255);
00311         GX_Position3f32(P4_X_BORDER_1, 480, 0); // bottom right
00312         GX_Color4u8(195, 195, 215, 255);
00313         GX_Position3f32(0, 480, 0);             // bottom left
00314         GX_Color4u8(88, 88, 108, 255);
00315 
00316         //--- 2P quad ---
00317         GX_Position3f32(P4_X_BORDER_1, 0, 0);   // top left
00318         GX_Color4u8(0, 0, 20, 255);
00319         GX_Position3f32(P4_X_BORDER_2, 0, 0);   // top right
00320         GX_Color4u8(88, 88, 108, 255);
00321         GX_Position3f32(P4_X_BORDER_2, 480, 0); // bottom right
00322         GX_Color4u8(195, 195, 215, 255);
00323         GX_Position3f32(P4_X_BORDER_1, 480, 0); // bottom left
00324         GX_Color4u8(88, 88, 108, 255);
00325 
00326         //--- 3P quad ---
00327         GX_Position3f32(P4_X_BORDER_2, 0, 0);   // top left
00328         GX_Color4u8(0, 0, 20, 255);
00329         GX_Position3f32(P4_X_BORDER_3, 0, 0);   // top right
00330         GX_Color4u8(88, 88, 108, 255);
00331         GX_Position3f32(P4_X_BORDER_3, 480, 0); // bottom right
00332         GX_Color4u8(195, 195, 215, 255);
00333         GX_Position3f32(P4_X_BORDER_2, 480, 0); // bottom left
00334         GX_Color4u8(88, 88, 108, 255);
00335 
00336         //--- 4P quad ---
00337         GX_Position3f32(P4_X_BORDER_3, 0, 0);   // top left
00338         GX_Color4u8(0, 0, 20, 255);
00339         GX_Position3f32(640, 0, 0);             // top right
00340         GX_Color4u8(88, 88, 108, 255);
00341         GX_Position3f32(640, 480, 0);           // bottom right
00342         GX_Color4u8(195, 195, 215, 255);
00343         GX_Position3f32(P4_X_BORDER_3, 480, 0); // bottom left
00344         GX_Color4u8(88, 88, 108, 255);
00345       GX_End();
00346     break;
00347   }
00348 }
00349 
00350 /// Draws in-game text such as lines, score, level.
00351 void TCYC_DrawText()
00352 {
00353   // Draw text. Add 2D effects such as lines, score, level.
00354   static const u8 a = 64; // alpha: 0 = transparent, 255 = opaque
00355   GXColor txtColor = !g_options->isPaused ? 
00356     (GXColor){255, 255, 255, a} : (GXColor){255, 255, 255, 255};
00357   GXColor deadColor = (GXColor){200, 0, 0, 255};
00358   
00359   GuiText txt(NULL, 28, txtColor); 
00360   txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
00361 
00362   char buf[5]; // allows for max value of 9999
00363   int player_x = 10, txt_dx = 100, y = 0, dy = 32;
00364   int player_dx = screenwidth / g_options->players; // assume: g_options->netplay == 0
00365 
00366   for (int i = 0; i < g_options->players; ++i, player_x += player_dx)
00367   {
00368     y = 0;
00369     txt.SetColor(!g_players[i].gameData.isDead ? txtColor : deadColor);
00370 
00371     // Draw lines, score, level.
00372     txt.SetText("lines:");
00373     txt.SetPosition(player_x, y += dy);
00374     txt.Draw();
00375     sprintf(buf, "%d", g_players[i].gameData.lines);
00376     txt.SetText(buf);
00377     txt.SetPosition(player_x + txt_dx, y);
00378     txt.Draw();
00379 
00380     txt.SetText("score:");
00381     txt.SetPosition(player_x, y += dy);
00382     txt.Draw();
00383     sprintf(buf, "%d", g_players[i].gameData.score);
00384     txt.SetText(buf);
00385     txt.SetPosition(player_x + txt_dx, y);
00386     txt.Draw();
00387 
00388     txt.SetText("level:");
00389     txt.SetPosition(player_x, y += dy);
00390     txt.Draw();
00391     sprintf(buf, "%d", g_players[i].gameData.level);
00392     txt.SetText(buf);
00393     txt.SetPosition(player_x + txt_dx, y);
00394     txt.Draw();
00395   }
00396 }
00397 
00398 /// Returns the player associated with the passed in x-coordinate.
00399 int TCYC_GetTargetPlayer(int x)
00400 {
00401   switch (g_options->players)
00402   {
00403     case 2: return x < P2_X_BORDER ? 0 : 1;
00404     case 3: return x < P3_X_BORDER_1 ? 0 : (x < P3_X_BORDER_2 ? 1 : 2);
00405     case 4: return x < P4_X_BORDER_1 ? 0 : (x < P4_X_BORDER_2 ? 1 : (x < P4_X_BORDER_3 ? 2 : 3));
00406   }
00407 
00408   TCYC_MenuError("Error in function TCYC_GetTargetPlayer.");
00409   return 0;
00410 }
00411 
00412 /// Returns the player's powerup slot associated with the passed in (x,y)-coordinate.
00413 /** Returns -1 if the cursor is outside the powerup zone. */
00414 int TCYC_GetTargetPowerupSlot(int player, int x, int y)
00415 {
00416   int borders[MAX_PLAYERS+1];
00417   borders[0] = 0;
00418   borders[g_options->players] = 640;
00419 
00420   switch (g_options->players)
00421   {
00422     case 2:
00423       borders[1] = P2_X_BORDER;
00424       break;
00425     case 3:
00426       borders[1] = P3_X_BORDER_1;
00427       borders[2] = P3_X_BORDER_2;
00428       break;
00429     case 4:
00430       borders[1] = P4_X_BORDER_1;
00431       borders[2] = P4_X_BORDER_2;
00432       borders[3] = P4_X_BORDER_3;
00433       break;
00434   }
00435 
00436   // Check if we are in the x-zone.
00437   if (x >= borders[player+1] - POWERUP_WIDTH - 2 * POWERUP_X_OFFSET && x <= borders[player+1])
00438   {
00439     // Determine what y-zone we are in.
00440     int py = POWERUP_Y_OFFSET + POWERUP_WIDTH;
00441     for (int i = 0; i < MAX_ACQUIRED_POWERUPS - 1; ++i, py += POWERUP_WIDTH)
00442     {
00443       if (y < py)
00444         return i;
00445     }
00446 
00447     if (y < py + POWERUP_Y_OFFSET)
00448       return MAX_ACQUIRED_POWERUPS - 1;
00449   }
00450 
00451   return -1;
00452 }
00453 
00454 /// Draws the black borders for the on-screen powerup queues.
00455 void TCYC_DrawPowerupBorders()
00456 {
00457   int borders[MAX_PLAYERS+1];
00458   borders[0] = 0;
00459   borders[g_options->players] = 640;
00460 
00461   switch (g_options->players)
00462   {
00463     case 2:
00464       borders[1] = P2_X_BORDER;
00465       break;
00466     case 3:
00467       borders[1] = P3_X_BORDER_1;
00468       borders[2] = P3_X_BORDER_2;
00469       break;
00470     case 4:
00471       borders[1] = P4_X_BORDER_1;
00472       borders[2] = P4_X_BORDER_2;
00473       borders[3] = P4_X_BORDER_3;
00474       break;
00475   }
00476 
00477   int x;
00478   int y;
00479 
00480   for (int i = 0; i < g_options->players; ++i)
00481   {
00482     x = 0;
00483     y = 0;
00484 
00485     // powerup queue
00486     GX_Begin(GX_LINESTRIP, GX_VTXFMT0, 2);
00487     GX_Position3f32(borders[i+1] - POWERUP_X_OFFSET - POWERUP_WIDTH, POWERUP_Y_OFFSET, 0); // top left
00488     GX_Color4u8(0, 0, 0, 255);
00489     GX_Position3f32(borders[i+1] - POWERUP_X_OFFSET, POWERUP_Y_OFFSET, 0); // top right
00490     GX_Color4u8(0, 0, 0, 255);
00491     GX_End();
00492   
00493     for (int j = 0; j < MAX_ACQUIRED_POWERUPS; ++j, y += POWERUP_WIDTH)
00494     {
00495       GX_Begin(GX_LINESTRIP, GX_VTXFMT0, 4);
00496       GX_Position3f32(borders[i+1] - POWERUP_X_OFFSET - POWERUP_WIDTH, y + POWERUP_Y_OFFSET, 0); // top left
00497       GX_Color4u8(0, 0, 0, 255);
00498       GX_Position3f32(borders[i+1] - POWERUP_X_OFFSET - POWERUP_WIDTH, y + POWERUP_Y_OFFSET + POWERUP_WIDTH, 0); // bottom left
00499       GX_Color4u8(0, 0, 0, 255);
00500       GX_Position3f32(borders[i+1] - POWERUP_X_OFFSET, y + POWERUP_Y_OFFSET + POWERUP_WIDTH, 0); // bottom right
00501       GX_Color4u8(0, 0, 0, 255);
00502       GX_Position3f32(borders[i+1] - POWERUP_X_OFFSET, y + POWERUP_Y_OFFSET, 0); // top right
00503       GX_Color4u8(0, 0, 0, 255);
00504       GX_End();
00505     }
00506 
00507     // effects queue
00508     GX_Begin(GX_LINESTRIP, GX_VTXFMT0, 2);
00509     GX_Position3f32(borders[i] + POWERUP_X_OFFSET, 480 - POWERUP_Y_OFFSET - POWERUP_WIDTH, 0); // top left
00510     GX_Color4u8(0, 0, 0, 255);
00511     GX_Position3f32(borders[i] + POWERUP_X_OFFSET, 480 - POWERUP_Y_OFFSET, 0); // bottom left
00512     GX_Color4u8(0, 0, 0, 255);
00513     GX_End();
00514 
00515     for (int j = 0; j < MAX_POWERUP_EFFECTS; ++j, x += POWERUP_WIDTH)
00516     {
00517       GX_Begin(GX_LINESTRIP, GX_VTXFMT0, 4);
00518       GX_Position3f32(borders[i] + POWERUP_X_OFFSET + x, 480 - POWERUP_Y_OFFSET - POWERUP_WIDTH, 0); // top left
00519       GX_Color4u8(0, 0, 0, 255);
00520       GX_Position3f32(borders[i] + POWERUP_X_OFFSET + POWERUP_WIDTH + x, 480 - POWERUP_Y_OFFSET - POWERUP_WIDTH, 0); // top right
00521       GX_Color4u8(0, 0, 0, 255);
00522       GX_Position3f32(borders[i] + POWERUP_X_OFFSET + POWERUP_WIDTH + x, 480 - POWERUP_Y_OFFSET, 0); // bottom right
00523       GX_Color4u8(0, 0, 0, 255);
00524       GX_Position3f32(borders[i] + POWERUP_X_OFFSET + x, 480 - POWERUP_Y_OFFSET, 0); // bottom left
00525       GX_Color4u8(0, 0, 0, 255);
00526       GX_End();
00527     }
00528   }
00529 }
00530 
00531 /// Draws a powerup texture.
00532 /** (x,y) corresponds to the upper left corner. */
00533 void TCYC_DrawPowerupTexture(int x, int y, GuiImageData *imgData, u8 alpha)
00534 {
00535   GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
00536   GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
00537 
00538   GXTexObj texObj;
00539   GX_InitTexObj(&texObj, imgData->GetImage(), imgData->GetWidth(), imgData->GetHeight(), GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
00540   GX_LoadTexObj(&texObj, GX_TEXMAP0);
00541   GX_InvalidateTexAll();
00542 
00543   GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
00544   GX_Position3f32(x, y, 0); // top left
00545   GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00546   GX_TexCoord2f32(0, 0);
00547   GX_Position3f32(x + POWERUP_WIDTH, y, 0); // top right
00548   GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00549   GX_TexCoord2f32(1, 0);
00550   GX_Position3f32(x + POWERUP_WIDTH, y + POWERUP_WIDTH, 0); // bottom right
00551   GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00552   GX_TexCoord2f32(1, 1);
00553   GX_Position3f32(x, y + POWERUP_WIDTH, 0); // bottom left
00554   GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00555   GX_TexCoord2f32(0, 1);
00556   GX_End();
00557 
00558   GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
00559   GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
00560 }
00561 
00562 /// Draws the textures for all the on-screen powerups.
00563 void TCYC_DrawPowerupTextures()
00564 {
00565   static const int yoffset = POWERUP_Y_OFFSET;
00566   static const int xoffset = POWERUP_X_OFFSET;
00567   static const int width = POWERUP_WIDTH;
00568 
00569   int x;
00570   int y;
00571   u8 alpha;
00572   Powerup *powerup;
00573   GuiImageData *imgData;
00574   GXTexObj texObj;
00575 
00576   int borders[MAX_PLAYERS+1];
00577   borders[0] = 0;
00578   borders[g_options->players] = 640;
00579 
00580   switch (g_options->players)
00581   {
00582     case 2:
00583       borders[1] = P2_X_BORDER;
00584       break;
00585     case 3:
00586       borders[1] = P3_X_BORDER_1;
00587       borders[2] = P3_X_BORDER_2;
00588       break;
00589     case 4:
00590       borders[1] = P4_X_BORDER_1;
00591       borders[2] = P4_X_BORDER_2;
00592       borders[3] = P4_X_BORDER_3;
00593       break;
00594   }
00595 
00596   GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
00597   GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
00598 
00599   for (int i = 0; i < g_options->players; ++i)
00600   {
00601     x = 0;
00602     y = 0;
00603     alpha = 128;
00604 
00605     // powerup queue
00606     for (int j = 0; j < MAX_ACQUIRED_POWERUPS; ++j, y += width)
00607     {
00608       powerup = g_players[i].gameData.powerupQueue[j];
00609       if (powerup)
00610       {
00611         imgData = powerup->GetImageData();
00612         GX_InitTexObj(&texObj, imgData->GetImage(), imgData->GetWidth(), imgData->GetHeight(), GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
00613         GX_LoadTexObj(&texObj, GX_TEXMAP0);
00614         GX_InvalidateTexAll();
00615 
00616         GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
00617         GX_Position3f32(borders[i+1] - xoffset - width, y + yoffset, 0); // top left
00618         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00619         GX_TexCoord2f32(0, 0);
00620         GX_Position3f32(borders[i+1] - xoffset, y + yoffset, 0); // top right
00621         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00622         GX_TexCoord2f32(1, 0);
00623         GX_Position3f32(borders[i+1] - xoffset, y + yoffset + width, 0); // bottom right
00624         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00625         GX_TexCoord2f32(1, 1);
00626         GX_Position3f32(borders[i+1] - xoffset - width, y + yoffset + width, 0); // bottom left
00627         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00628         GX_TexCoord2f32(0, 1);
00629         GX_End();
00630       }
00631     }
00632 
00633     alpha = 64;
00634 
00635     // effects queue
00636     for (int j = 0; j < MAX_POWERUP_EFFECTS; ++j, x += width)
00637     {
00638       powerup = g_players[i].gameData.powerupEffects[j];
00639       if (powerup)
00640       {
00641         imgData = powerup->GetImageData();
00642         GX_InitTexObj(&texObj, imgData->GetImage(), imgData->GetWidth(), imgData->GetHeight(), GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
00643         GX_LoadTexObj(&texObj, GX_TEXMAP0);
00644         GX_InvalidateTexAll();
00645 
00646         GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
00647         GX_Position3f32(borders[i] + xoffset + x, 480 - yoffset - width, 0); // top left
00648         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00649         GX_TexCoord2f32(0, 0);
00650         GX_Position3f32(borders[i] + xoffset + width + x, 480 - yoffset - width, 0); // top right
00651         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00652         GX_TexCoord2f32(1, 0);
00653         GX_Position3f32(borders[i] + xoffset + width + x, 480 - yoffset, 0); // bottom right
00654         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00655         GX_TexCoord2f32(1, 1);
00656         GX_Position3f32(borders[i] + xoffset + x, 480 - yoffset, 0); // bottom left
00657         GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00658         GX_TexCoord2f32(0, 1);
00659         GX_End();
00660       }
00661     }
00662   }
00663 
00664   GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
00665   GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
00666 }
00667 
00668 /// Draws the on-screen powerups.
00669 void TCYC_DrawPowerups()
00670 {
00671   TCYC_DrawPowerupBorders();
00672   TCYC_DrawPowerupTextures();
00673 
00674   for (int i = g_options->players - 1; i >= 0; --i) // so that player 1's cursor appears on top!
00675   {
00676     if (userInput[i].wpad->ir.valid)
00677     {
00678       int x = userInput[i].wpad->ir.x;
00679       int y = userInput[i].wpad->ir.y;
00680       u8 alpha = (TCYC_GetTargetPlayer(x) == i) ? 255 : 32;
00681       Powerup *powerup = g_players[i].gameData.grabbedPowerup;
00682 
00683       if (powerup)
00684         TCYC_DrawPowerupTexture(x - (POWERUP_WIDTH >> 1), y - (POWERUP_WIDTH >> 1), powerup->GetImageData(), alpha);
00685 
00686       GuiImageData *imgData = GRAB_HELD(i) ? grabber[i] : pointer[i];
00687       float scale = 1;
00688 
00689       if (g_players[i].gameData.powerupData.isBigHand)
00690       {
00691         scale = BIG_HAND_SCALE;
00692         alpha = 255;
00693       }
00694 
00695       // TODO Cale - There is a weird bug here. If I try to reference grabber[0] 
00696       // in 4-player mode then it crashes the game!
00697       /*if (g_options->players < MAX_PLAYERS || i != 0)
00698         Menu_DrawImg(x - 48, y - 48, 96, 96, imgData->GetImage(), userInput[i].wpad->ir.angle, scale, scale, alpha);
00699       else
00700         Menu_DrawImg(x - 48, y - 48, 96, 96, GRAB_HELD(i) ? debug_grabber1->GetImage() : imgData->GetImage(), userInput[i].wpad->ir.angle, scale, scale, alpha);*/
00701 
00702       // DEBUG FURTHER! The above code still causes the game to crash in 
00703       // strange ways, for example when switching from 4-player mode to 
00704       // 3-player mode.
00705       switch (i)
00706       {
00707         case 0:
00708           imgData = GRAB_HELD(i) ? debug_grabber1 : pointer[i];
00709           break;
00710         case 1:
00711           imgData = GRAB_HELD(i) ? debug_grabber2 : pointer[i];
00712           break;
00713         case 2:
00714           imgData = GRAB_HELD(i) ? debug_grabber3 : pointer[i];
00715           break;
00716         case 3:
00717           imgData = GRAB_HELD(i) ? debug_grabber4 : pointer[i];
00718           break;
00719       }
00720       Menu_DrawImg(x - 48, y - 48, 96, 96, imgData->GetImage(), userInput[i].wpad->ir.angle, scale, scale, alpha);
00721     }
00722 
00723     DoRumble(i);
00724   }
00725 }
00726 
00727 /// Draws the 3D TetriCycle for every player.
00728 void TCYC_DrawTetriCycle()
00729 {
00730   // Prepare for drawing TetriCycle
00731   GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
00732   GX_LoadProjectionMtx(projection, GX_PERSPECTIVE);
00733 
00734   for (int i = 0; i < g_options->players; ++i)
00735   {
00736     Player &player = g_players[i];
00737     player.DrawPlayfield();
00738     player.DrawNextPiece();
00739     player.DrawPiece();
00740     player.DrawPieceShadow();
00741     player.DrawBase();
00742   }
00743 }
00744 
00745 /// Renders the game.
00746 void TCYC_Render()
00747 {
00748   static int currFrame = 0;
00749   currFrame ^= 1; // flip framebuffer
00750 
00751   GX_CopyDisp(g_xfb[currFrame], GX_TRUE);
00752   GX_DrawDone();
00753 
00754   VIDEO_SetNextFramebuffer(g_xfb[currFrame]);
00755   VIDEO_Flush();   
00756   VIDEO_WaitVSync();
00757 
00758   for (int i = 0; i < g_options->players; ++i)
00759     g_players[i].gameData.frame++;
00760 }
00761 
00762 /// Draws a unit cube centered at the origin.
00763 void GX_Cube(int colorIdx, u8 alpha, GuiImageData *imgData)
00764 {
00765   ColorGradient &gradient = g_cubeGradients[colorIdx];
00766 
00767   u8 lightR = gradient.light.r;
00768   u8 lightG = gradient.light.g;
00769   u8 lightB = gradient.light.b;
00770 
00771   u8 mediumR = gradient.medium.r;
00772   u8 mediumG = gradient.medium.g;
00773   u8 mediumB = gradient.medium.b;
00774 
00775   u8 darkR = gradient.dark.r;
00776   u8 darkG = gradient.dark.g;
00777   u8 darkB = gradient.dark.b;
00778   
00779   static const float unit = 0.5;
00780 
00781   GX_Begin(GX_QUADS, GX_VTXFMT0, 8);
00782     //--- TOP quad ---
00783     GX_Position3f32(-unit, unit, -unit);  // top left
00784     GX_Color4u8(lightR, lightG, lightB, alpha);
00785     GX_Position3f32(unit, unit, -unit);   // top right
00786     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00787     GX_Position3f32(unit, unit, unit);    // bottom right
00788     GX_Color4u8(darkR, darkG, darkB, alpha);
00789     GX_Position3f32(-unit, unit, unit);   // bottom left
00790     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00791 
00792     //--- BOTTOM quad ---
00793     GX_Position3f32(-unit, -unit, unit);  // top left
00794     GX_Color4u8(lightR, lightG, lightB, alpha);
00795     GX_Position3f32(unit, -unit, unit);   // top right
00796     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00797     GX_Position3f32(unit, -unit, -unit);  // bottom right
00798     GX_Color4u8(darkR, darkG, darkB, alpha);
00799     GX_Position3f32(-unit, -unit, -unit); // bottom left
00800     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00801   GX_End();
00802 
00803   //--- FRONT quad ---
00804   if (!imgData)
00805   {
00806     GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
00807     GX_Position3f32(-unit, unit, unit);   // top left
00808     GX_Color4u8(lightR, lightG, lightB, alpha);
00809     GX_Position3f32(unit, unit, unit);    // top right
00810     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00811     GX_Position3f32(unit, -unit, unit);   // bottom right
00812     GX_Color4u8(darkR, darkG, darkB, alpha);
00813     GX_Position3f32(-unit, -unit, unit);  // bottom left
00814     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00815     GX_End();
00816   }
00817   else
00818   {
00819     GXTexObj texObj;
00820 
00821     int width  = imgData->GetWidth();
00822     int height = imgData->GetHeight();
00823     GX_InitTexObj(&texObj, imgData->GetImage(), width, height, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
00824     GX_LoadTexObj(&texObj, GX_TEXMAP0);
00825     GX_InvalidateTexAll();
00826 
00827     GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
00828     GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
00829 
00830     GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
00831     GX_Position3f32(-unit, unit, unit);   // top left
00832     GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00833     GX_TexCoord2f32(0, 0);
00834     GX_Position3f32(unit, unit, unit);    // top right
00835     GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00836     GX_TexCoord2f32(1, 0);
00837     GX_Position3f32(unit, -unit, unit);   // bottom right
00838     GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00839     GX_TexCoord2f32(1, 1);
00840     GX_Position3f32(-unit, -unit, unit);  // bottom left
00841     GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
00842     GX_TexCoord2f32(0, 1);
00843     GX_End();
00844 
00845     GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
00846     GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
00847   }
00848 
00849   GX_Begin(GX_QUADS, GX_VTXFMT0, 12);
00850     //--- BACK quad ---
00851     GX_Position3f32(unit, -unit, -unit);  // bottom left
00852     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00853     GX_Position3f32(-unit, -unit, -unit); // bottom right
00854     GX_Color4u8(darkR, darkG, darkB, alpha);
00855     GX_Position3f32(-unit, unit, -unit);  // top right
00856     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00857     GX_Position3f32(unit, unit, -unit);   // top left
00858     GX_Color4u8(lightR, lightG, lightB, alpha);
00859 
00860     //--- LEFT quad ---
00861     GX_Position3f32(-unit, unit, unit);   // top right
00862     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00863     GX_Position3f32(-unit, unit, -unit);  // top left
00864     GX_Color4u8(lightR, lightG, lightB, alpha);
00865     GX_Position3f32(-unit, -unit, -unit); // bottom left
00866     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00867     GX_Position3f32(-unit, -unit, unit);  // bottom right
00868     GX_Color4u8(darkR, darkG, darkB, alpha);
00869 
00870     //--- RIGHT quad ---
00871     GX_Position3f32(unit, unit, -unit);  // top right
00872     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00873     GX_Position3f32(unit, unit, unit);   // top left
00874     GX_Color4u8(lightR, lightG, lightB, alpha);
00875     GX_Position3f32(unit, -unit, unit);  // bottom left
00876     GX_Color4u8(mediumR, mediumG, mediumB, alpha);
00877     GX_Position3f32(unit, -unit, -unit); // bottom right
00878     GX_Color4u8(darkR, darkG, darkB, alpha);
00879   GX_End();
00880 }
00881 
00882 /// Runs the "edit playfield" loop.
00883 void TCYC_EditPlayfield()
00884 {
00885   GXColor white = (GXColor){255, 255, 255, 255};
00886   GXColor green = (GXColor){0, 255, 0, 255};
00887 
00888   char buf[7 + 5]; // allows for max value of 9999
00889   int player_x = 10, y = 0, dy = 32;
00890   int player_dx = screenwidth / g_options->players; // assume: g_options->netplay == 0
00891 
00892   GuiWindow window(screenwidth, screenheight);
00893 
00894   // CONFIRM BUTTON
00895   GuiButton confirmBtn(btnData40x40Square->GetWidth(), btnData40x40Square->GetHeight());
00896   GuiText confirmBtnTxt("OK", 22, (GXColor){0, 0, 255, 255});
00897   GuiImage confirmBtnImg(btnData40x40Square);
00898   GuiImage confirmBtnImgOver(btnData40x40SquareOver);
00899 
00900   confirmBtn.SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM);
00901   confirmBtn.SetPosition(-10, -20);
00902   confirmBtn.SetLabel(&confirmBtnTxt);
00903   confirmBtn.SetImage(&confirmBtnImg);
00904   confirmBtn.SetImageOver(&confirmBtnImgOver);
00905   confirmBtn.SetSoundOver(btnSoundOver);
00906   confirmBtn.SetTrigger(trigA);
00907   confirmBtn.SetEffectGrow();
00908 
00909   // CANCEL BUTTON
00910   GuiButton cancelBtn(btnData40x40Square->GetWidth(), btnData40x40Square->GetHeight());
00911   GuiText cancelBtnTxt("X", 22, (GXColor){255, 0, 0, 255});
00912   GuiImage cancelBtnImg(btnData40x40Square);
00913   GuiImage cancelBtnImgOver(btnData40x40SquareOver);
00914 
00915   cancelBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
00916   cancelBtn.SetPosition(10, -20);
00917   cancelBtn.SetLabel(&cancelBtnTxt);
00918   cancelBtn.SetImage(&cancelBtnImg);
00919   cancelBtn.SetImageOver(&cancelBtnImgOver);
00920   cancelBtn.SetSoundOver(btnSoundOver);
00921   cancelBtn.SetTrigger(trigA);
00922   cancelBtn.SetEffectGrow();
00923 
00924   // 1P Playfield Width Button
00925   GuiButton p1widthBtn((9 + 1) * 14, 28);
00926   GuiText p1widthTxt(NULL, 28, white);
00927   GuiText p1widthTxtOver(NULL, 28, green);
00928 
00929   // 2P Playfield Width Button
00930   GuiButton p2widthBtn((9 + 1) * 14, 28);
00931   GuiText p2widthTxt(NULL, 28, white);
00932   GuiText p2widthTxtOver(NULL, 28, green);
00933 
00934   // 3P Playfield Width Button
00935   GuiButton p3widthBtn((9 + 1) * 14, 28);
00936   GuiText p3widthTxt(NULL, 28, white);
00937   GuiText p3widthTxtOver(NULL, 28, green);
00938 
00939   // 4P Playfield Width Button
00940   GuiButton p4widthBtn((9 + 1) * 14, 28);
00941   GuiText p4widthTxt(NULL, 28, white);
00942   GuiText p4widthTxtOver(NULL, 28, green);
00943 
00944   // 1P Playfield Scale Button
00945   GuiButton p1scaleBtn((9 + 1) * 14, 28);
00946   GuiText p1scaleTxt(NULL, 28, white);
00947   GuiText p1scaleTxtOver(NULL, 28, green);
00948 
00949   // 2P Playfield Scale Button
00950   GuiButton p2scaleBtn((9 + 1) * 14, 28);
00951   GuiText p2scaleTxt(NULL, 28, white);
00952   GuiText p2scaleTxtOver(NULL, 28, green);
00953 
00954   // 3P Playfield Scale Button
00955   GuiButton p3scaleBtn((9 + 1) * 14, 28);
00956   GuiText p3scaleTxt(NULL, 28, white);
00957   GuiText p3scaleTxtOver(NULL, 28, green);
00958 
00959   // 4P Playfield Scale Button
00960   GuiButton p4scaleBtn((9 + 1) * 14, 28);
00961   GuiText p4scaleTxt(NULL, 28, white);
00962   GuiText p4scaleTxtOver(NULL, 28, green);
00963 
00964   // 1P Playfield Angle Button
00965   GuiButton p1angleBtn((9 + 1) * 14, 28);
00966   GuiText p1angleTxt(NULL, 28, white);
00967   GuiText p1angleTxtOver(NULL, 28, green);
00968 
00969   // 2P Playfield Angle Button
00970   GuiButton p2angleBtn((9 + 1) * 14, 28);
00971   GuiText p2angleTxt(NULL, 28, white);
00972   GuiText p2angleTxtOver(NULL, 28, green);
00973 
00974   // 3P Playfield Angle Button
00975   GuiButton p3angleBtn((9 + 1) * 14, 28);
00976   GuiText p3angleTxt(NULL, 28, white);
00977   GuiText p3angleTxtOver(NULL, 28, green);
00978 
00979   // 4P Playfield Angle Button
00980   GuiButton p4angleBtn((9 + 1) * 14, 28);
00981   GuiText p4angleTxt(NULL, 28, white);
00982   GuiText p4angleTxtOver(NULL, 28, green);
00983 
00984   // 1P Playfield DX Button
00985   GuiButton p1dxBtn((7 + 1) * 14, 28);
00986   GuiText p1dxTxt(NULL, 28, white);
00987   GuiText p1dxTxtOver(NULL, 28, green);
00988 
00989   // 2P Playfield DX Button
00990   GuiButton p2dxBtn((7 + 1) * 14, 28);
00991   GuiText p2dxTxt(NULL, 28, white);
00992   GuiText p2dxTxtOver(NULL, 28, green);
00993 
00994   // 3P Playfield DX Button
00995   GuiButton p3dxBtn((7 + 1) * 14, 28);
00996   GuiText p3dxTxt(NULL, 28, white);
00997   GuiText p3dxTxtOver(NULL, 28, green);
00998 
00999   // 4P Playfield DX Button
01000   GuiButton p4dxBtn((7 + 1) * 14, 28);
01001   GuiText p4dxTxt(NULL, 28, white);
01002   GuiText p4dxTxtOver(NULL, 28, green);
01003 
01004   // 1P Playfield DY Button
01005   GuiButton p1dyBtn((7 + 1) * 14, 28);
01006   GuiText p1dyTxt(NULL, 28, white);
01007   GuiText p1dyTxtOver(NULL, 28, green);
01008 
01009   // 2P Playfield DY Button
01010   GuiButton p2dyBtn((7 + 1) * 14, 28);
01011   GuiText p2dyTxt(NULL, 28, white);
01012   GuiText p2dyTxtOver(NULL, 28, green);
01013 
01014   // 3P Playfield DY Button
01015   GuiButton p3dyBtn((7 + 1) * 14, 28);
01016   GuiText p3dyTxt(NULL, 28, white);
01017   GuiText p3dyTxtOver(NULL, 28, green);
01018 
01019   // 4P Playfield DY Button
01020   GuiButton p4dyBtn((7 + 1) * 14, 28);
01021   GuiText p4dyTxt(NULL, 28, white);
01022   GuiText p4dyTxtOver(NULL, 28, green);
01023 
01024   // GuiElement Arrays
01025   GuiButton *widthButtons[MAX_PLAYERS] = {&p1widthBtn, &p2widthBtn, &p3widthBtn, &p4widthBtn};
01026   GuiText *widthTexts[MAX_PLAYERS]     = {&p1widthTxt, &p2widthTxt, &p3widthTxt, &p4widthTxt};
01027   GuiText *widthTextsOver[MAX_PLAYERS] = {&p1widthTxtOver, &p2widthTxtOver, &p3widthTxtOver, &p4widthTxtOver};
01028 
01029   GuiButton *scaleButtons[MAX_PLAYERS] = {&p1scaleBtn, &p2scaleBtn, &p3scaleBtn, &p4scaleBtn};
01030   GuiText *scaleTexts[MAX_PLAYERS]     = {&p1scaleTxt, &p2scaleTxt, &p3scaleTxt, &p4scaleTxt};
01031   GuiText *scaleTextsOver[MAX_PLAYERS] = {&p1scaleTxtOver, &p2scaleTxtOver, &p3scaleTxtOver, &p4scaleTxtOver};
01032 
01033   GuiButton *angleButtons[MAX_PLAYERS] = {&p1angleBtn, &p2angleBtn, &p3angleBtn, &p4angleBtn};
01034   GuiText *angleTexts[MAX_PLAYERS]     = {&p1angleTxt, &p2angleTxt, &p3angleTxt, &p4angleTxt};
01035   GuiText *angleTextsOver[MAX_PLAYERS] = {&p1angleTxtOver, &p2angleTxtOver, &p3angleTxtOver, &p4angleTxtOver};
01036 
01037   GuiButton *dxButtons[MAX_PLAYERS] = {&p1dxBtn, &p2dxBtn, &p3dxBtn, &p4dxBtn};
01038   GuiText *dxTexts[MAX_PLAYERS]     = {&p1dxTxt, &p2dxTxt, &p3dxTxt, &p4dxTxt};
01039   GuiText *dxTextsOver[MAX_PLAYERS] = {&p1dxTxtOver, &p2dxTxtOver, &p3dxTxtOver, &p4dxTxtOver};
01040 
01041   GuiButton *dyButtons[MAX_PLAYERS] = {&p1dyBtn, &p2dyBtn, &p3dyBtn, &p4dyBtn};
01042   GuiText *dyTexts[MAX_PLAYERS]     = {&p1dyTxt, &p2dyTxt, &p3dyTxt, &p4dyTxt};
01043   GuiText *dyTextsOver[MAX_PLAYERS] = {&p1dyTxtOver, &p2dyTxtOver, &p3dyTxtOver, &p4dyTxtOver};
01044 
01045   // previous values
01046   u8 prevWidth[MAX_PLAYERS];
01047   u8 prevScale[MAX_PLAYERS];
01048   float prevAngle[MAX_PLAYERS];
01049   s16 prevDX[MAX_PLAYERS];
01050   s16 prevDY[MAX_PLAYERS];
01051 
01052   for (int i = 0; i < g_options->players; ++i, player_x += player_dx)
01053   {
01054     y = 0;
01055 
01056     widthButtons[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
01057     widthButtons[i]->SetPosition(player_x, y += dy);
01058     widthButtons[i]->SetLabel(widthTexts[i]);
01059     widthButtons[i]->SetLabelOver(widthTextsOver[i]);
01060     widthButtons[i]->SetEffectGrow();     
01061     sprintf(buf, "width: %d", g_players[i].playfieldWidth);
01062     widthTexts[i]->SetText(buf);
01063     widthTextsOver[i]->SetText(buf);
01064 
01065     scaleButtons[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
01066     scaleButtons[i]->SetPosition(player_x, y += dy);
01067     scaleButtons[i]->SetLabel(scaleTexts[i]);
01068     scaleButtons[i]->SetLabelOver(scaleTextsOver[i]);
01069     scaleButtons[i]->SetEffectGrow();     
01070     sprintf(buf, "scale: %d", g_players[i].playfieldScale);
01071     scaleTexts[i]->SetText(buf);
01072     scaleTextsOver[i]->SetText(buf);
01073 
01074     angleButtons[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
01075     angleButtons[i]->SetPosition(player_x, y += dy);
01076     angleButtons[i]->SetLabel(angleTexts[i]);
01077     angleButtons[i]->SetLabelOver(angleTextsOver[i]);
01078     angleButtons[i]->SetEffectGrow();     
01079     sprintf(buf, "angle: %d", (int)g_players[i].cubeAngle);
01080     angleTexts[i]->SetText(buf);
01081     angleTextsOver[i]->SetText(buf);
01082 
01083     dxButtons[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
01084     dxButtons[i]->SetPosition(player_x, y += dy);
01085     dxButtons[i]->SetLabel(dxTexts[i]);
01086     dxButtons[i]->SetLabelOver(dxTextsOver[i]);
01087     dxButtons[i]->SetEffectGrow();     
01088     sprintf(buf, "dx: %d", g_players[i].playfieldDX);
01089     dxTexts[i]->SetText(buf);
01090     dxTextsOver[i]->SetText(buf);
01091 
01092     dyButtons[i]->SetAlignment(ALIGN_LEFT, ALIGN_TOP);
01093     dyButtons[i]->SetPosition(player_x, y += dy);
01094     dyButtons[i]->SetLabel(dyTexts[i]);
01095     dyButtons[i]->SetLabelOver(dyTextsOver[i]);
01096     dyButtons[i]->SetEffectGrow();     
01097     sprintf(buf, "dy: %d", g_players[i].playfieldDY);
01098     dyTexts[i]->SetText(buf);
01099     dyTextsOver[i]->SetText(buf);
01100 
01101     window.Append(widthButtons[i]);
01102     window.Append(scaleButtons[i]);
01103     window.Append(angleButtons[i]);
01104     window.Append(dxButtons[i]);
01105     window.Append(dyButtons[i]);
01106 
01107     prevWidth[i] = g_players[i].playfieldWidth;
01108     prevScale[i] = g_players[i].playfieldScale;
01109     prevAngle[i] = g_players[i].cubeAngle;
01110     prevDX[i] = g_players[i].playfieldDX;
01111     prevDY[i] = g_players[i].playfieldDY;
01112   }
01113 
01114   window.Append(&confirmBtn);
01115   window.Append(&cancelBtn);
01116   mainWindow->Append(&window);
01117 
01118   g_tcycMenu = TCYC_MENU_NONE;
01119 
01120   while (g_tcycMenu == TCYC_MENU_NONE)
01121   {
01122     ALL_ScanPads();
01123     TCYC_ProcessEditModeInput();
01124     TCYC_DrawEditMode();
01125     TCYC_Render();
01126 
01127     if (confirmBtn.GetState() == STATE_CLICKED)
01128     {
01129       g_tcycMenu = TCYC_MENU_MAIN;
01130       break;
01131     }
01132     else if (cancelBtn.GetState() == STATE_CLICKED)
01133     {
01134       for (int i = 0; i < g_options->players; ++i)
01135       {
01136         g_players[i].playfieldWidth = prevWidth[i];
01137         g_players[i].playfieldScale = prevScale[i];
01138         g_players[i].cubeAngle = prevAngle[i];
01139         g_players[i].playfieldDX = prevDX[i];
01140         g_players[i].playfieldDY = prevDY[i];
01141       }
01142 
01143       g_tcycMenu = TCYC_MENU_MAIN;
01144       break;
01145     }
01146 
01147     for (int i = 0; i < g_options->players; ++i)
01148     {
01149       if (widthButtons[i]->GetState() == STATE_SELECTED)
01150       {
01151         int incr = 0;
01152 
01153         if (A_PRESSED(i))
01154           incr = 2;
01155         else if (B_PRESSED(i))
01156           incr = -2;
01157 
01158         if (incr)
01159         {
01160           g_players[i].playfieldWidth += incr;
01161 
01162           if (g_players[i].playfieldWidth > MAX_PLAYFIELD_WIDTH)
01163             g_players[i].playfieldWidth = MAX_PLAYFIELD_WIDTH;
01164           else if (g_players[i].playfieldWidth < MIN_PLAYFIELD_WIDTH)
01165             g_players[i].playfieldWidth = MIN_PLAYFIELD_WIDTH;
01166 
01167           sprintf(buf, "width: %d", g_players[i].playfieldWidth);
01168           widthTexts[i]->SetText(buf);
01169           widthTextsOver[i]->SetText(buf);
01170 
01171           float maxAngle = 360 / (float)g_players[i].playfieldWidth;
01172           if (g_players[i].cubeAngle > maxAngle)
01173           {
01174             g_players[i].cubeAngle = maxAngle;
01175             sprintf(buf, "angle: %d", (int)g_players[i].cubeAngle);
01176             angleTexts[i]->SetText(buf);
01177             angleTextsOver[i]->SetText(buf);
01178           }
01179         }
01180       }
01181       else if (scaleButtons[i]->GetState() == STATE_SELECTED)
01182       {
01183         int incr = 0;
01184 
01185         if (A_PRESSED(i))
01186           incr = 1;
01187         else if (B_PRESSED(i))
01188           incr = -1;
01189 
01190         if (incr)
01191         {
01192           g_players[i].playfieldScale += incr;
01193 
01194           if (g_players[i].playfieldScale > MAX_PLAYFIELD_SCALE)
01195             g_players[i].playfieldScale = MAX_PLAYFIELD_SCALE;
01196           else if (g_players[i].playfieldScale < MIN_PLAYFIELD_SCALE)
01197             g_players[i].playfieldScale = MIN_PLAYFIELD_SCALE;
01198 
01199           sprintf(buf, "scale: %d", g_players[i].playfieldScale);
01200           scaleTexts[i]->SetText(buf);
01201           scaleTextsOver[i]->SetText(buf);
01202         }
01203       }
01204       else if (angleButtons[i]->GetState() == STATE_SELECTED)
01205       {
01206         int incr = 0;
01207 
01208         if (A_PRESSED(i))
01209           incr = 1;
01210         else if (B_PRESSED(i))
01211           incr = -1;
01212 
01213         if (incr)
01214         {
01215           g_players[i].cubeAngle += incr;
01216 
01217           float maxAngle = 360 / (float)g_players[i].playfieldWidth;
01218           if (g_players[i].cubeAngle > maxAngle)
01219           {
01220             g_players[i].cubeAngle = maxAngle;
01221           }
01222           else if (g_players[i].cubeAngle < MIN_CUBE_ANGLE)
01223           {
01224             g_players[i].cubeAngle = MIN_CUBE_ANGLE;
01225           }
01226           else
01227           {
01228             g_players[i].cubeAngle = (int)g_players[i].cubeAngle;
01229           }
01230 
01231           sprintf(buf, "angle: %d", (int)g_players[i].cubeAngle);
01232           angleTexts[i]->SetText(buf);
01233           angleTextsOver[i]->SetText(buf);
01234         }
01235       }
01236       else if (dxButtons[i]->GetState() == STATE_SELECTED)
01237       {
01238         int incr = 0;
01239 
01240         if (A_PRESSED(i))
01241           incr = 5;
01242         else if (B_PRESSED(i))
01243           incr = -5;
01244 
01245         if (incr)
01246         {
01247           g_players[i].playfieldDX += incr;
01248 
01249           if (g_players[i].playfieldDX > MAX_PLAYFIELD_DELTA)
01250             g_players[i].playfieldDX = MAX_PLAYFIELD_DELTA;
01251           else if (g_players[i].playfieldDX < -MAX_PLAYFIELD_DELTA)
01252             g_players[i].playfieldDX = -MAX_PLAYFIELD_DELTA;
01253 
01254           sprintf(buf, "dx: %d", g_players[i].playfieldDX);
01255           dxTexts[i]->SetText(buf);
01256           dxTextsOver[i]->SetText(buf);
01257         }
01258       }
01259       else if (dyButtons[i]->GetState() == STATE_SELECTED)
01260       {
01261         int incr = 0;
01262 
01263         if (A_PRESSED(i))
01264           incr = 5;
01265         else if (B_PRESSED(i))
01266           incr = -5;
01267 
01268         if (incr)
01269         {
01270           g_players[i].playfieldDY += incr;
01271 
01272           if (g_players[i].playfieldDY > MAX_PLAYFIELD_DELTA)
01273             g_players[i].playfieldDY = MAX_PLAYFIELD_DELTA;
01274           else if (g_players[i].playfieldDY < -MAX_PLAYFIELD_DELTA)
01275             g_players[i].playfieldDY = -MAX_PLAYFIELD_DELTA;
01276 
01277           sprintf(buf, "dy: %d", g_players[i].playfieldDY);
01278           dyTexts[i]->SetText(buf);
01279           dyTextsOver[i]->SetText(buf);
01280         }
01281       }
01282     }
01283   }
01284 
01285   mainWindow->Remove(&window);
01286 }
01287 
01288 /// Draws the "edit playfield" mode.
01289 void TCYC_DrawEditMode()
01290 {
01291   TCYC_SetUp2D();
01292   TCYC_DrawPlayfieldBoundary();
01293   
01294   TCYC_DrawTetriCycleEditMode();
01295 
01296   TCYC_SetUp2D();
01297   TCYC_DrawEditPlayfieldMenu();
01298 }
01299 
01300 /// Draws the 3D TetriCycle for every player in "edit playfield" mode.
01301 void TCYC_DrawTetriCycleEditMode()
01302 {
01303   // Prepare for drawing TetriCycle
01304   GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
01305   GX_LoadProjectionMtx(projection, GX_PERSPECTIVE);
01306 
01307   int width;
01308   int height;
01309   int ci;
01310   int top;
01311 
01312   for (int i = 0; i < g_options->players; ++i)
01313   {
01314     Player &player = g_players[i];
01315 
01316     width = player.playfieldWidth;
01317     ci    = player.gameData.cycleIdx;
01318     top   = 0;
01319 
01320     for (int x = 0; x < width; ++x)
01321     {
01322       height = player.playfieldHeight;
01323 
01324       for (int y = height - 1; y >= top; --y)
01325       {
01326         int offset = (x - ci >= 0) ? x - ci : width - (ci - x);
01327         player.DrawBlockAsCube(offset, y, COLOR_ID_RED);
01328       }
01329 
01330       if (top < height - 1)
01331         ++top;
01332     }
01333 
01334     player.DrawBase();
01335   }
01336 }
01337 
01338 /// Draws the gui in "edit playfield" mode.
01339 void TCYC_DrawEditPlayfieldMenu()
01340 {
01341   mainWindow->Draw();
01342 
01343   for (int i = MAX_PLAYERS - 1; i >= 0; --i) // so that player 1's cursor appears on top!
01344   {
01345     if (userInput[i].wpad->ir.valid)
01346     {
01347             Menu_DrawImg(userInput[i].wpad->ir.x - 48, userInput[i].wpad->ir.y - 48,
01348                                96, 96, pointer[i]->GetImage(), userInput[i].wpad->ir.angle, 
01349                    1, 1, 255);
01350     }
01351 
01352     DoRumble(i);
01353   }
01354 
01355   for (int i = 0; i < MAX_PLAYERS; ++i)
01356     mainWindow->Update(&userInput[i]);
01357 }
01358 
01359 /// Initializes the game state.
01360 void TCYC_GameInit()
01361 {
01362   MODPlay_Start(&g_modPlay);
01363   sgenrand(time(NULL));
01364   g_tcycMenu = TCYC_MENU_NONE;
01365   
01366   for (int i = 0; i < g_options->players; ++i)
01367     g_players[i].Reset();
01368 }
01369 
01370 /// Called when the game is reset/quit.
01371 void TCYC_GameOnExit()
01372 {
01373   MODPlay_Stop(&g_modPlay);
01374 
01375   // We have to delete any powerups from a previous game before 
01376   // memset'ing the PlayerGameData.
01377   PowerupUtils::DeleteAllPowerups();
01378 }
01379 
01380 /// Initialize the static description for every tetris piece.
01381 void TCYC_InitPieceDescriptions()
01382 {
01383         // Fill in data for every piece
01384         for (int i = 0; i < TETRISPIECE_ID_RAND_MAX; ++i)
01385         {
01386                 // Every rotation
01387                 for (int rot = 0; rot < 4; ++rot)
01388                 {
01389                         TetrisPieceDesc &desc = g_pieceDesc[i][rot];
01390 
01391                         // Every square
01392                         for (int y = 0; y < 4; ++y)
01393                         {
01394                                 for (int x = 0; x < 4; ++x)
01395                                 {
01396                                         // Get square from data file
01397                                         desc.map[x][y] = pieces_bin[i * 4 * 4 * 4 + rot * 4 * 4 + y * 4 + x];
01398                                 }
01399                         }
01400                 }
01401         }
01402 
01403   // Init special pieces
01404   TetrisPieceDesc &desc = g_pieceDesc[TETRISPIECE_ID_JUNK][0];
01405   desc.map[1][1] = desc.map[2][1] = desc.map[3][1] = 
01406   desc.map[1][2] =                  desc.map[3][2] = 
01407   desc.map[1][3] = desc.map[2][3] = desc.map[3][3] = 1;
01408 
01409   for (int rot = 1; rot < 4; ++rot)
01410     memcpy(&g_pieceDesc[TETRISPIECE_ID_JUNK][rot], &desc, sizeof(TetrisPieceDesc));
01411 }

Generated on Wed Oct 20 2010 17:06:58 for TetriCycle by  doxygen 1.7.1