diff --git a/data/images/splash.jpg b/data/images/splash.jpg new file mode 100644 index 00000000..45bd5a82 Binary files /dev/null and b/data/images/splash.jpg differ diff --git a/out/boot.dol b/out/boot.dol index bd76c20a..8ffc3f51 100644 Binary files a/out/boot.dol and b/out/boot.dol differ diff --git a/source/devicemounter/DeviceHandler.cpp b/source/devicemounter/DeviceHandler.cpp index 1bc1dc45..663bc7c5 100644 --- a/source/devicemounter/DeviceHandler.cpp +++ b/source/devicemounter/DeviceHandler.cpp @@ -42,9 +42,10 @@ DeviceHandler DeviceHandle; void DeviceHandler::Init() { + /* PartitionHandle inits */ sd.Init(); usb.Init(); - OGC_Device.Init(); + OGC_Device.Init();// used for Devolution gamecube iso launcher } void DeviceHandler::MountAll() diff --git a/source/gui/coverflow.cpp b/source/gui/coverflow.cpp index 73ca7b07..0d35537b 100644 --- a/source/gui/coverflow.cpp +++ b/source/gui/coverflow.cpp @@ -356,9 +356,16 @@ void CCoverFlow::setRange(u32 rows, u32 columns) if (m_covers != NULL) { stopCoverLoader(); + MEM2_free(m_covers); CCover *tmpCovers = (CCover*)MEM2_alloc(sizeof(CCover) * range); for(size_t i = 0; i < range; ++i) - tmpCovers[i] = *(new(tmpCovers+i) CCover); + { + // does not allocate memory -- calls: operator new (sizeof(CCover), tmpCovers+i) + // only constructs an object at tmpCovers+i + // delete is not needed + // this is the same as CCover tmpCovers[range] except the objects memory address is specified and won't go out of scope + tmpCovers[i] = *(new (tmpCovers+i) CCover); + } if (rows >= 3) for (u32 x = 0; x < columns; ++x) for (u32 y = 1; y < rows - 1; ++y) @@ -369,7 +376,6 @@ void CCoverFlow::setRange(u32 rows, u32 columns) m_rows = rows; m_columns = columns; m_range = range; - MEM2_free(m_covers); m_covers = tmpCovers; _loadAllCovers(m_covers[m_range / 2].index); _updateAllTargets(); @@ -1903,7 +1909,7 @@ bool CCoverFlow::start(const string &m_imgsDir) m_covers = NULL; if(m_range > 0) { - m_covers = (CCover*)MEM2_alloc(sizeof(struct CCover) * m_range); + m_covers = (CCover*)MEM2_alloc(sizeof(CCover) * m_range); for(size_t i = 0; i < m_range; ++i) m_covers[i] = *(new(m_covers+i) CCover); } diff --git a/source/gui/gui.cpp b/source/gui/gui.cpp index 94273928..e359f5be 100644 --- a/source/gui/gui.cpp +++ b/source/gui/gui.cpp @@ -748,6 +748,8 @@ void CButtonsMgr::_drawBtn(CButtonsMgr::SButton &b, bool selected, bool click) if (!b.font.font) return; b.font.font->reset(); //CColor txtColor(b.textColor.r, b.textColor.g, b.textColor.b, (u8)((int)b.textColor.a * (int)alpha / 0xFF)); + if(m_vid.wide()) + scaleX *= 0.8f; b.font.font->setXScale(scaleX); b.font.font->setYScale(scaleY); //b.font.font->drawText(0, 0, b.text.c_str(), txtColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE); @@ -795,6 +797,8 @@ void CButtonsMgr::_drawLbl(CButtonsMgr::SLabel &b) b.font.font->reset(); b.text.setColor(CColor(b.textColor.r, b.textColor.g, b.textColor.b, (u8)((int)b.textColor.a * (int)alpha / 0xFF))); + if(m_vid.wide()) + scaleX *= 0.8f; b.font.font->setXScale(scaleX); b.font.font->setYScale(scaleY); float posX = b.pos.x; diff --git a/source/gui/video.cpp b/source/gui/video.cpp index 36258b99..513d058e 100644 --- a/source/gui/video.cpp +++ b/source/gui/video.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "memory/mem2.hpp" #include "video.hpp" #include "pngu.h" @@ -17,25 +18,6 @@ #define DEFAULT_FIFO_SIZE (256 * 1024) -extern const u8 wait_01_jpg[]; -extern const u32 wait_01_jpg_size; -extern const u8 wait_02_jpg[]; -extern const u32 wait_02_jpg_size; -extern const u8 wait_03_jpg[]; -extern const u32 wait_03_jpg_size; -extern const u8 wait_04_jpg[]; -extern const u32 wait_04_jpg_size; -extern const u8 wait_05_jpg[]; -extern const u32 wait_05_jpg_size; -extern const u8 wait_06_jpg[]; -extern const u32 wait_06_jpg_size; -extern const u8 wait_07_jpg[]; -extern const u32 wait_07_jpg_size; -extern const u8 wait_08_jpg[]; -extern const u32 wait_08_jpg_size; - -vector m_defaultWaitMessages; - const float CVideo::_jitter2[2][2] = { { 0.246490f, 0.249999f }, { -0.246490f, -0.249999f } @@ -115,20 +97,10 @@ GXRModeObj TVPal574IntDfScale = } }; -struct movieP normalMoviePos = { 410, 31, 610, 181 }; -struct movieP zoomedMoviePos = { 0, 0, 640, 480 }; -struct movieP currentMoviePos = zoomedMoviePos; - -const int CVideo::_stencilWidth = 128; -const int CVideo::_stencilHeight = 128; - -static lwp_t waitThread = LWP_THREAD_NULL; +vector m_defaultWaitMessages; CVideo m_vid; -u8 CVideo::waitMessageStack[2048] ATTRIBUTE_ALIGN(32); -const u32 CVideo::waitMessageStackSize = 2048; - CVideo::CVideo(void) : m_rmode(NULL), m_frameBuf(), m_curFB(0), m_fifo(NULL), m_yScale(0.0f), m_xfbHeight(0), m_wide(false), @@ -139,35 +111,6 @@ CVideo::CVideo(void) : memset(m_frameBuf, 0, sizeof m_frameBuf); } -void CColor::blend(const CColor &src) -{ - if (src.a == 0) return; - r = (u8)(((int)src.r * (int)src.a + (int)r * (0xFF - (int)src.a)) / 0xFF); - g = (u8)(((int)src.g * (int)src.a + (int)g * (0xFF - (int)src.a)) / 0xFF); - b = (u8)(((int)src.b * (int)src.a + (int)b * (0xFF - (int)src.a)) / 0xFF); -} - -CColor CColor::interpolate(const CColor &c1, const CColor &c2, u8 n) -{ - CColor c; - c.r = (u8)(((int)c2.r * (int)n + (int)c1.r * (0xFF - (int)n)) / 0xFF); - c.g = (u8)(((int)c2.g * (int)n + (int)c1.g * (0xFF - (int)n)) / 0xFF); - c.b = (u8)(((int)c2.b * (int)n + (int)c1.b * (0xFF - (int)n)) / 0xFF); - c.a = (u8)(((int)c2.a * (int)n + (int)c1.a * (0xFF - (int)n)) / 0xFF); - return c; -} - -void CVideo::setAA(u8 aa, bool alpha, int width, int height) -{ - if (aa <= 8 && aa != 7 && width <= m_rmode->fbWidth && height <= m_rmode->efbHeight && ((width | height) & 3) == 0) - { - m_aa = aa; - m_aaAlpha = alpha; - m_aaWidth = width; - m_aaHeight = height; - } -} - void CVideo::init(void) { /* General Video Init */ @@ -212,11 +155,15 @@ void CVideo::init(void) m_frameBuf[0] = MEM_K0_TO_K1(MEM1_memalign(32, VIDEO_GetFrameBufferSize(m_rmode))); m_frameBuf[1] = MEM_K0_TO_K1(MEM1_memalign(32, VIDEO_GetFrameBufferSize(m_rmode))); m_curFB = 0; + m_fifo = MEM1_memalign(32, DEFAULT_FIFO_SIZE); memset(m_fifo, 0, DEFAULT_FIFO_SIZE); + GX_Init(m_fifo, DEFAULT_FIFO_SIZE); GX_SetCopyClear(CColor(0), 0x00FFFFFF); + _setViewPort(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); + m_yScale = GX_GetYScaleFactor(m_rmode->efbHeight, m_rmode->xfbHeight); m_xfbHeight = GX_SetDispCopyYScale(m_yScale); GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); @@ -237,11 +184,14 @@ void CVideo::init(void) GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0); GX_SetNumChans(0); GX_SetZCompLoc(GX_ENABLE); + setup2DProjection(); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); for(u32 i = 0; i < 8; i++) GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0+i, GX_TEX_ST, GX_F32, 0); + m_stencil = MEM1_memalign(32, CVideo::_stencilWidth * CVideo::_stencilHeight); memset(m_stencil, 0, CVideo::_stencilWidth * CVideo::_stencilHeight); @@ -255,65 +205,6 @@ void CVideo::init(void) VIDEO_WaitVSync(); } -void CVideo::_clearScreen() -{ - VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[0], COLOR_BLACK); - VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[1], COLOR_BLACK); - render(); - render(); -} - -void CVideo::set2DViewport(u32 w, u32 h, int x, int y) -{ - m_width2D = std::min(std::max(512ul, w), 800ul); - m_height2D = std::min(std::max(384ul, h), 600ul); - m_x2D = std::min(std::max(-50, x), 50); - m_y2D = std::min(std::max(-50, y), 50); -} - -void CVideo::setup2DProjection(bool setViewPort, bool noScale) -{ - Mtx44 projMtx; - float width2D = noScale ? 640.f : (float)m_width2D; - float height2D = noScale ? 480.f : (float)m_height2D; - float x = noScale ? 0.f : (float)(640 - width2D) * 0.5f + (float)m_x2D; - float y = noScale ? 0.f : (float)(480 - height2D) * 0.5f + (float)m_y2D; - - if (setViewPort) - _setViewPort(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); - guOrtho(projMtx, y, height2D + y, x, width2D + x, 0.f, 1000.0f); - GX_LoadProjectionMtx(projMtx, GX_ORTHOGRAPHIC); -} - -void CVideo::renderToTexture(TexData &tex, bool clear) -{ - if(tex.data == NULL) - { - tex.dataSize = GX_GetTexBufferSize(tex.width, tex.height, tex.format, GX_FALSE, 0); - tex.data = (u8*)MEM2_alloc(tex.dataSize); - if(tex.data == NULL) - return; - } - GX_DrawDone(); - GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); - GX_SetTexCopySrc(0, 0, tex.width, tex.height); - GX_SetTexCopyDst(tex.width, tex.height, tex.format, GX_FALSE); - GX_CopyTex(tex.data, clear ? GX_TRUE : GX_FALSE); - GX_PixModeSync(); - GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter); - DCFlushRange(tex.data, tex.dataSize); - GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); -} - -void CVideo::prepare(void) -{ - GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); - _setViewPort(0.f, 0.f, (float)m_rmode->fbWidth, (float)m_rmode->efbHeight); - GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); - GX_InvVtxCache(); - GX_InvalidateTexAll(); -} - void CVideo::cleanup(void) { //gprintf("Cleaning up video...\n"); @@ -350,6 +241,79 @@ void CVideo::cleanup(void) m_fifo = NULL; } +void CVideo::_clearScreen() +{ + VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[0], COLOR_BLACK); + VIDEO_ClearFrameBuffer(m_rmode, m_frameBuf[1], COLOR_BLACK); + render(); + render(); +} + +void CVideo::prepare(void) +{ + GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); + _setViewPort(0.f, 0.f, (float)m_rmode->fbWidth, (float)m_rmode->efbHeight); + GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); + GX_InvVtxCache(); + GX_InvalidateTexAll(); +} + +void CVideo::setup2DProjection(bool setViewPort, bool noScale) +{ + Mtx44 projMtx; + float width2D = noScale ? 640.f : (float)m_width2D; + float height2D = noScale ? 480.f : (float)m_height2D; + float x = noScale ? 0.f : (float)(640 - width2D) * 0.5f + (float)m_x2D; + float y = noScale ? 0.f : (float)(480 - height2D) * 0.5f + (float)m_y2D; + + if (setViewPort) + _setViewPort(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); + guOrtho(projMtx, y, height2D + y, x, width2D + x, 0.f, 1000.0f); + GX_LoadProjectionMtx(projMtx, GX_ORTHOGRAPHIC); +} + +void CVideo::_setViewPort(float x, float y, float w, float h) +{ + m_vpX = x; + m_vpY = y; + m_vpW = w; + m_vpH = h; + GX_SetViewport(x, y, w, h, 0.f, 1.f); +} + +void CVideo::shiftViewPort(float x, float y) +{ + GX_SetViewport(m_vpX + x, m_vpY + y, m_vpW, m_vpH, 0.f, 1.f); +} + +void CVideo::set2DViewport(u32 w, u32 h, int x, int y) +{ + m_width2D = std::min(std::max(512ul, w), 800ul); + m_height2D = std::min(std::max(384ul, h), 600ul); + m_x2D = std::min(std::max(-50, x), 50); + m_y2D = std::min(std::max(-50, y), 50); +} + +void CVideo::renderToTexture(TexData &tex, bool clear) +{ + if(tex.data == NULL) + { + tex.dataSize = GX_GetTexBufferSize(tex.width, tex.height, tex.format, GX_FALSE, 0); + tex.data = (u8*)MEM2_alloc(tex.dataSize); + if(tex.data == NULL) + return; + } + GX_DrawDone(); + GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); + GX_SetTexCopySrc(0, 0, tex.width, tex.height); + GX_SetTexCopyDst(tex.width, tex.height, tex.format, GX_FALSE); + GX_CopyTex(tex.data, clear ? GX_TRUE : GX_FALSE); + GX_PixModeSync(); + GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter); + DCFlushRange(tex.data, tex.dataSize); + GX_SetScissor(0, 0, m_rmode->fbWidth, m_rmode->efbHeight); +} + void CVideo::prepareAAPass(int aaStep) { float x = 0.f; @@ -390,31 +354,6 @@ void CVideo::prepareAAPass(int aaStep) GX_InvalidateTexAll(); } -void CVideo::renderAAPass(int aaStep) -{ - u8 texFmt = GX_TF_RGBA8; - u32 w = m_aaWidth <= 0 ? m_rmode->fbWidth : (u32)m_aaWidth; - u32 h = m_aaHeight <= 0 ? m_rmode->efbHeight: (u32)m_aaHeight; - u32 bufLen = GX_GetTexBufferSize(w, h, texFmt, GX_FALSE, 0); - - if (!m_aaBuffer[aaStep] || m_aaBufferSize[aaStep] < bufLen) - { - m_aaBuffer[aaStep] = (u8*)MEM2_alloc(bufLen); - if (m_aaBuffer[aaStep] != NULL) - m_aaBufferSize[aaStep] = bufLen; - } - if (!m_aaBuffer[aaStep] || m_aaBufferSize[aaStep] < bufLen) - return; - GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE); - GX_DrawDone(); - GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); - GX_SetTexCopySrc(0, 0, w, h); - GX_SetTexCopyDst(w, h, texFmt, GX_FALSE); - GX_CopyTex(m_aaBuffer[aaStep], GX_TRUE); - GX_PixModeSync(); - GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter); -} - void CVideo::drawAAScene(bool fs) { GXTexObj texObj[8]; @@ -488,57 +427,28 @@ void CVideo::drawAAScene(bool fs) GX_SetNumTevStages(1); } -void CVideo::_setViewPort(float x, float y, float w, float h) +void CVideo::renderAAPass(int aaStep) { - m_vpX = x; - m_vpY = y; - m_vpW = w; - m_vpH = h; - GX_SetViewport(x, y, w, h, 0.f, 1.f); -} + u8 texFmt = GX_TF_RGBA8; + u32 w = m_aaWidth <= 0 ? m_rmode->fbWidth : (u32)m_aaWidth; + u32 h = m_aaHeight <= 0 ? m_rmode->efbHeight: (u32)m_aaHeight; + u32 bufLen = GX_GetTexBufferSize(w, h, texFmt, GX_FALSE, 0); -void CVideo::shiftViewPort(float x, float y) -{ - GX_SetViewport(m_vpX + x, m_vpY + y, m_vpW, m_vpH, 0.f, 1.f); -} - -static inline u32 coordsI8(u32 x, u32 y, u32 w) -{ - return (((y >> 2) * (w >> 3) + (x >> 3)) << 5) + ((y & 3) << 3) + (x & 7); -} - -int CVideo::stencilVal(int x, int y) -{ - if ((u32)x >= m_rmode->fbWidth || (u32)y >= m_rmode->efbHeight) - return 0; - x = x * CVideo::_stencilWidth / 640; - y = y * CVideo::_stencilHeight / 480; - u32 i = coordsI8(x, y, (u32)CVideo::_stencilWidth); - if (i >= (u32)(CVideo::_stencilWidth * CVideo::_stencilHeight)) - return 0; - return ((u8*)m_stencil)[i]; -} - -void CVideo::prepareStencil(void) -{ - GX_SetPixelFmt(GX_PF_Y8, GX_ZC_LINEAR); - _setViewPort(0.f, 0.f, (float)CVideo::_stencilWidth, (float)CVideo::_stencilHeight); - GX_SetScissor(0, 0, CVideo::_stencilWidth, CVideo::_stencilHeight); - GX_InvVtxCache(); - GX_InvalidateTexAll(); -} - -void CVideo::renderStencil(void) -{ - GX_DrawDone(); + if (!m_aaBuffer[aaStep] || m_aaBufferSize[aaStep] < bufLen) + { + m_aaBuffer[aaStep] = (u8*)MEM2_alloc(bufLen); + if (m_aaBuffer[aaStep] != NULL) + m_aaBufferSize[aaStep] = bufLen; + } + if (!m_aaBuffer[aaStep] || m_aaBufferSize[aaStep] < bufLen) + return; GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE); - GX_SetColorUpdate(GX_TRUE); + GX_DrawDone(); GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); - GX_SetTexCopySrc(0, 0, CVideo::_stencilWidth, CVideo::_stencilHeight); - GX_SetTexCopyDst(CVideo::_stencilWidth, CVideo::_stencilHeight, GX_CTF_R8, GX_FALSE); - GX_CopyTex(m_stencil, GX_TRUE); + GX_SetTexCopySrc(0, 0, w, h); + GX_SetTexCopyDst(w, h, texFmt, GX_FALSE); + GX_CopyTex(m_aaBuffer[aaStep], GX_TRUE); GX_PixModeSync(); - DCFlushRange(m_stencil, CVideo::_stencilWidth * CVideo::_stencilHeight); GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter); } @@ -556,12 +466,38 @@ void CVideo::render(void) GX_InvalidateTexAll(); } +/* wait animation control */ + +extern const u8 splash_jpg[]; +extern const u32 splash_jpg_size; + +extern const u8 wait_01_jpg[]; +extern const u32 wait_01_jpg_size; +extern const u8 wait_02_jpg[]; +extern const u32 wait_02_jpg_size; +extern const u8 wait_03_jpg[]; +extern const u32 wait_03_jpg_size; +extern const u8 wait_04_jpg[]; +extern const u32 wait_04_jpg_size; +extern const u8 wait_05_jpg[]; +extern const u32 wait_05_jpg_size; +extern const u8 wait_06_jpg[]; +extern const u32 wait_06_jpg_size; +extern const u8 wait_07_jpg[]; +extern const u32 wait_07_jpg_size; +extern const u8 wait_08_jpg[]; +extern const u32 wait_08_jpg_size; + +static lwp_t waitThread = LWP_THREAD_NULL; +u8 CVideo::waitMessageStack[2048] ATTRIBUTE_ALIGN(32); +const u32 CVideo::waitMessageStackSize = 2048; + bool custom = false; bool waitLoop = false; static vector waitImgs; + static void GrabWaitFiles(char *FullPath) { - //Just push back waitImgs.push_back(FullPath); } @@ -573,13 +509,14 @@ void CVideo::setCustomWaitImgs(const char *path, bool wait_loop) GetFiles(path, stringToVector(".png|.jpg", '|'), GrabWaitFiles, false, 1); if(waitImgs.size() > 0) { + sort(waitImgs.begin(), waitImgs.end()); custom = true; waitLoop = wait_loop; } } } -void CVideo::waitMessage(float delay)// called from main.cpp to show wait animation on wf boot +void CVideo::waitMessage(float delay)// set wait images from custom or internal { if(m_defaultWaitMessages.size() == 0) { @@ -613,7 +550,7 @@ void CVideo::waitMessage(float delay)// called from main.cpp to show wait animat waitMessage(m_defaultWaitMessages, delay); } -void CVideo::waitMessage(const vector &tex, float delay)// start wait images and wii slot light threads or draw +void CVideo::waitMessage(const vector &tex, float delay)// start wait images and wii slot light threads { hideWaitMessage(); @@ -698,7 +635,7 @@ void * CVideo::_showWaitMessages(void *obj)// wait images thread return NULL; } -void CVideo::hideWaitMessage()// stop wait images and wii disc slot light threads +void CVideo::hideWaitMessage()// stop wait images thread and wii disc slot light thread { m_showWaitMessage = false; if(waitThread != LWP_THREAD_NULL) @@ -716,7 +653,9 @@ void CVideo::hideWaitMessage()// stop wait images and wii disc slot light thread waitThread = LWP_THREAD_NULL; } -void CVideo::waitMessage(const TexData &tex)//draw frame image +/* draws wait animation image centered on screen */ +/* can be used to draw any texture centered on screen */ +void CVideo::waitMessage(const TexData &tex) { Mtx modelViewMtx; GXTexObj texObj; @@ -743,7 +682,7 @@ void CVideo::waitMessage(const TexData &tex)//draw frame image GX_LoadTexObj(&texObj, GX_TEXMAP0); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); u32 texWidth = m_wide ? tex.width * .75 : tex.width; - GX_Position3f32((float)((640 - texWidth) / 2), (float)((480 - tex.height) / 2), 0.f);// widescreen = tex.width * .80 + GX_Position3f32((float)((640 - texWidth) / 2), (float)((480 - tex.height) / 2), 0.f); GX_TexCoord2f32(0.f, 0.f); GX_Position3f32((float)((640 + texWidth) / 2), (float)((480 - tex.height) / 2), 0.f); GX_TexCoord2f32(1.f, 0.f); @@ -754,6 +693,17 @@ void CVideo::waitMessage(const TexData &tex)//draw frame image GX_End(); } +/* draw and render startup splash screen */ +void CVideo::startImage(void) +{ + TexData splashTex; + TexHandle.fromJPG(splashTex, splash_jpg, splash_jpg_size); + waitMessage(splashTex); + render(); + TexHandle.Cleanup(splashTex); +} + +/* save screenshot */ s32 CVideo::TakeScreenshot(const char *path) { IMGCTX ctx = PNGU_SelectImageFromDevice(path); @@ -762,7 +712,9 @@ s32 CVideo::TakeScreenshot(const char *path) return ret; } -void DrawTexture(TexData * &tex)// used by coverflow to draw cover texture. use in mainloopcommon() in menu.cpp +/* used by coverflow to draw cover texture. used in mainloopcommon() in menu.cpp */ +/* this draws a texture in the upper left at 0,0 */ +void DrawTexture(TexData * &tex) { if(tex == NULL) return; @@ -805,35 +757,14 @@ void DrawTexture(TexData * &tex)// used by coverflow to draw cover texture. use GX_End(); } -void DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color)// used by banner window and screen saver below -{ - Mtx modelViewMtx; - guMtxIdentity(modelViewMtx); - GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0); +/* draws movie frame texture when playing movie in menu_game.cpp */ +struct movieP normalMoviePos = { 410, 31, 610, 181 }; +struct movieP zoomedMoviePos = { 0, 0, 640, 480 }; +struct movieP currentMoviePos = zoomedMoviePos; - GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); - GX_ClearVtxDesc(); - GX_InvVtxCache(); - GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); - GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); - GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); - - int i; - f32 x2 = x + width; - f32 y2 = y + height; - guVector v[] = { { x, y, 0.0f }, { x2, y, 0.0f }, { x2, y2, 0.0f }, { x, y2, 0.0f }, { x, y, 0.0f } }; - - GX_Begin(GX_TRIANGLEFAN, GX_VTXFMT0, 4); - for(i = 0; i < 4; i++) - { - GX_Position3f32(v[i].x, v[i].y, v[i].z); - GX_Color4u8(color.r, color.g, color.b, color.a); - } - GX_End(); - GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); -} - -void DrawTexturePos(const TexData *tex)// draws movie frame texture when playing movie in menu_game.cpp +/* draws a texture/image at a position and width and height specified by struct movieP currentMoviePos */ +/* set currentMoviePos before calling this. example - {x, y, x+w, y+h} */ +void DrawTexturePos(const TexData *tex) { Mtx modelViewMtx; GXTexObj texObj; @@ -868,17 +799,122 @@ void DrawTexturePos(const TexData *tex)// draws movie frame texture when playing GX_End(); } +/* screen saver and full banner frame */ +void DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color) +{ + Mtx modelViewMtx; + guMtxIdentity(modelViewMtx); + GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0); + + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); + + int i; + f32 x2 = x + width; + f32 y2 = y + height; + guVector v[] = { { x, y, 0.0f }, { x2, y, 0.0f }, { x2, y2, 0.0f }, { x, y2, 0.0f }, { x, y, 0.0f } }; + + GX_Begin(GX_TRIANGLEFAN, GX_VTXFMT0, 4); + for(i = 0; i < 4; i++) + { + GX_Position3f32(v[i].x, v[i].y, v[i].z); + GX_Color4u8(color.r, color.g, color.b, color.a); + } + GX_End(); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); +} + void CVideo::screensaver(u32 no_input, u32 max_no_input) { - if(no_input == 0) + if(no_input == 0)// no idle time so reset alpha to 0 for next time and don't draw the rectangle on this pass { m_screensaver_alpha = 0; return; } - if(no_input > max_no_input) + if(no_input > max_no_input)// if idle time > max idle draw rectangle full screen increasing alpha each time { DrawRectangle(0, 0, 640, 480, (GXColor){0,0,0,m_screensaver_alpha}); if(m_screensaver_alpha < 150) m_screensaver_alpha+=2; } } + +/* misc settings */ + +void CColor::blend(const CColor &src) +{ + if (src.a == 0) return; + r = (u8)(((int)src.r * (int)src.a + (int)r * (0xFF - (int)src.a)) / 0xFF); + g = (u8)(((int)src.g * (int)src.a + (int)g * (0xFF - (int)src.a)) / 0xFF); + b = (u8)(((int)src.b * (int)src.a + (int)b * (0xFF - (int)src.a)) / 0xFF); +} + +CColor CColor::interpolate(const CColor &c1, const CColor &c2, u8 n) +{ + CColor c; + c.r = (u8)(((int)c2.r * (int)n + (int)c1.r * (0xFF - (int)n)) / 0xFF); + c.g = (u8)(((int)c2.g * (int)n + (int)c1.g * (0xFF - (int)n)) / 0xFF); + c.b = (u8)(((int)c2.b * (int)n + (int)c1.b * (0xFF - (int)n)) / 0xFF); + c.a = (u8)(((int)c2.a * (int)n + (int)c1.a * (0xFF - (int)n)) / 0xFF); + return c; +} + +void CVideo::setAA(u8 aa, bool alpha, int width, int height) +{ + if (aa <= 8 && aa != 7 && width <= m_rmode->fbWidth && height <= m_rmode->efbHeight && ((width | height) & 3) == 0) + { + m_aa = aa; + m_aaAlpha = alpha; + m_aaWidth = width; + m_aaHeight = height; + } +} + +/* stencil used by coverflow */ + +const int CVideo::_stencilWidth = 128; +const int CVideo::_stencilHeight = 128; + +static inline u32 coordsI8(u32 x, u32 y, u32 w)// used by stencilval below +{ + return (((y >> 2) * (w >> 3) + (x >> 3)) << 5) + ((y & 3) << 3) + (x & 7); +} + +int CVideo::stencilVal(int x, int y) +{ + if ((u32)x >= m_rmode->fbWidth || (u32)y >= m_rmode->efbHeight) + return 0; + x = x * CVideo::_stencilWidth / 640; + y = y * CVideo::_stencilHeight / 480; + u32 i = coordsI8(x, y, (u32)CVideo::_stencilWidth); + if (i >= (u32)(CVideo::_stencilWidth * CVideo::_stencilHeight)) + return 0; + return ((u8*)m_stencil)[i]; +} + +void CVideo::prepareStencil(void) +{ + GX_SetPixelFmt(GX_PF_Y8, GX_ZC_LINEAR); + _setViewPort(0.f, 0.f, (float)CVideo::_stencilWidth, (float)CVideo::_stencilHeight); + GX_SetScissor(0, 0, CVideo::_stencilWidth, CVideo::_stencilHeight); + GX_InvVtxCache(); + GX_InvalidateTexAll(); +} + +void CVideo::renderStencil(void) +{ + GX_DrawDone(); + GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE); + GX_SetColorUpdate(GX_TRUE); + GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); + GX_SetTexCopySrc(0, 0, CVideo::_stencilWidth, CVideo::_stencilHeight); + GX_SetTexCopyDst(CVideo::_stencilWidth, CVideo::_stencilHeight, GX_CTF_R8, GX_FALSE); + GX_CopyTex(m_stencil, GX_TRUE); + GX_PixModeSync(); + DCFlushRange(m_stencil, CVideo::_stencilWidth * CVideo::_stencilHeight); + GX_SetCopyFilter(m_rmode->aa, m_rmode->sample_pattern, GX_TRUE, m_rmode->vfilter); +} diff --git a/source/gui/video.hpp b/source/gui/video.hpp index 28aec42e..1791a5a9 100644 --- a/source/gui/video.hpp +++ b/source/gui/video.hpp @@ -70,6 +70,7 @@ public: int stencilVal(int x, int y); void setCustomWaitImgs(const char *path, bool loop); void hideWaitMessage(); + void startImage(void); void waitMessage(float delay); void waitMessage(const vector &tex, float delay); void waitMessage(const TexData &tex); diff --git a/source/main.cpp b/source/main.cpp index 9d75d63f..ebb36f1f 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -33,16 +33,14 @@ int main(int argc, char **argv) Gecko_Init(); //USB Gecko and SD/WiFi buffer gprintf(" \nWelcome to %s!\nThis is the debug output.\n", VERSION_STRING.c_str()); - m_vid.init(); // Init video - DeviceHandle.Init(); - NandHandle.Init(); - - char *gameid = NULL; bool iosOK = true; + char *gameid = NULL; + bool showFlashImg = true; + bool sd_only = false; bool wait_loop = false; char wait_dir[256]; memset(&wait_dir, 0, sizeof(wait_dir)); - + for(u8 i = 0; i < argc; i++) { if(argv[i] != NULL && strcasestr(argv[i], "ios=") != NULL && strlen(argv[i]) > 4) @@ -52,6 +50,17 @@ int main(int argc, char **argv) if(atoi(argv[i]) < 254 && atoi(argv[i]) > 0) mainIOS = atoi(argv[i]); } + else if(strcasestr(argv[i], "waitdir=") != NULL) + { + char *ptr = strcasestr(argv[i], "waitdir="); + strncpy(wait_dir, ptr+strlen("waitdir="), sizeof(wait_dir)); + } + else if(strcasestr(argv[i], "Waitloop") != NULL) + wait_loop = true; + else if(strcasestr(argv[i], "noflash") != NULL) + showFlashImg = false; + else if(strcasestr(argv[i], "sdonly") != NULL) + sd_only = true; else if(strlen(argv[i]) == 6) { gameid = argv[i]; @@ -60,41 +69,52 @@ int main(int argc, char **argv) if(!isalnum(gameid[i])) gameid = NULL; } - } - else if(strcasestr(argv[i], "waitdir=") != NULL) - { - char *ptr = strcasestr(argv[i], "waitdir="); - strncpy(wait_dir, ptr+strlen("waitdir="), sizeof(wait_dir)); - } - else if(strcasestr(argv[i], "Waitloop") != NULL) - { - wait_loop = true; - } + } } + /* Init video */ + m_vid.init(); + if(showFlashImg) + m_vid.startImage(); + + /* Init device partition handlers */ + DeviceHandle.Init(); + + /* Init NAND handlers */ + NandHandle.Init(); check_neek2o(); - /* Init ISFS */ if(neek2o() || Sys_DolphinMode()) NandHandle.Init_ISFS(); else NandHandle.LoadDefaultIOS(); /* safe reload to preferred IOS */ - /* Maybe new IOS and Port settings */ + + /* load and check wiiflow save for possible new IOS and Port settings */ if(InternalSave.CheckSave()) InternalSave.LoadSettings(); + /* Handle (c)IOS Loading */ if(neek2o() || Sys_DolphinMode()) /* wont reload anythin */ iosOK = loadIOS(IOS_GetVersion(), false); else if(useMainIOS && CustomIOS(IOS_GetType(mainIOS))) /* Requested */ iosOK = loadIOS(mainIOS, false) && CustomIOS(CurrentIOS.Type); - // Init + + /* set reset and power button callbacks and exitTo option */ Sys_Init(); Sys_ExitTo(EXIT_TO_HBC); - DeviceHandle.MountAll(); + /* mount Devices */ + DeviceHandle.MountSD(); + if(!sd_only && !Sys_DolphinMode()) + DeviceHandle.MountAllUSB(); + + /* init wait images and show wait animation */ m_vid.setCustomWaitImgs(wait_dir, wait_loop); m_vid.waitMessage(0.15f); + /* init controllers for input */ Open_Inputs(); + + /* init configs, folders, coverflow, gui and more */ if(mainMenu.init()) { if(CurrentIOS.Version != mainIOS && !neek2o() && !Sys_DolphinMode()) @@ -114,14 +134,13 @@ int main(int argc, char **argv) mainMenu.terror("errboot2", L"Could not find a device to save configuration files on!"); else if(WDVD_Init() < 0) mainMenu.terror("errboot3", L"Could not initialize the DIP module!"); - else + else // alls good lets start wiiflow { - writeStub(); - if(gameid != NULL && strlen(gameid) == 6) + writeStub();// copy return stub to memory + if(gameid != NULL && strlen(gameid) == 6)// if argv game ID then launch it mainMenu.directlaunch(gameid); else - mainMenu.main(); - //if mainMenu.init set exit=true then mainMenu.main while loop does nothing and returns to here to exit wiiflow + mainMenu.main();// start wiiflow with main menu displayed } //Exit WiiFlow, no game booted... mainMenu.cleanup();// removes all sounds, fonts, images, coverflow, plugin stuff, source menu and clear memory diff --git a/source/menu/menu.cpp b/source/menu/menu.cpp index a546f68a..1e8a4b55 100644 --- a/source/menu/menu.cpp +++ b/source/menu/menu.cpp @@ -138,7 +138,6 @@ bool CMenu::init() if(drive == check) // Should not happen { /* Could not find a device to save configuration files on! */ - //m_exit = true; return false; } @@ -166,7 +165,17 @@ bool CMenu::init() bool onUSB = m_cfg.getBool("GENERAL", "data_on_usb", strncmp(drive, "usb", 3) == 0); drive = check; //reset the drive variable for the check //check for wiiflow data directory on USB or SD based on data_on_usb - if(onUSB) + if(!onUSB) + { + if(DeviceHandle.IsInserted(SD))// no need to find sd:/wiiflow, it will be made if not exist + drive = DeviceName[SD]; + else + { + onUSB = true; + m_cfg.setBool("GENERAL", "data_on_usb", true); + } + } + else // onUSB = true { for(u8 i = USB1; i <= USB8; i++) //Look for first partition with a wiiflow folder in root { @@ -176,12 +185,7 @@ bool CMenu::init() break; } } - } - if(!onUSB && DeviceHandle.IsInserted(SD) && stat(fmt("%s:/%s", DeviceName[SD], APP_DATA_DIR), &dummy) == 0) - drive = DeviceName[SD]; - if(drive == check)//if wiiflow data directory not found then check just for a USB partition or SD card - { - if(onUSB) + if(drive == check)// if wiiflow data directory not found just find a valid USB partition { for(u8 i = USB1; i <= USB8; i++) { @@ -191,21 +195,16 @@ bool CMenu::init() break; } } - if(drive == check && DeviceHandle.IsInserted(SD))//if no available USB partition then force SD - drive = DeviceName[SD]; - else if(drive == check) - { - /* No available usb partitions for data and no SD inserted! */ - //m_exit = true; - return false; - } } - else - { - if(DeviceHandle.IsInserted(SD)) - drive = DeviceName[SD]; - else - drive = DeviceName[USB1];//if no SD insterted then force USB. may set this to the wf boot.dol partition + if(drive == check && DeviceHandle.IsInserted(SD))//if no valid USB partition then force SD if inserted + { + drive = DeviceName[SD]; + // show error msg later after building menus + } + if(drive == check)// should not happen + { + /* No available usb partitions for data and no SD inserted! */ + return false; } } m_dataDir = fmt("%s:/%s", drive, APP_DATA_DIR); @@ -427,7 +426,10 @@ bool CMenu::init() /* Init Button Manager and build the menus */ _buildMenus(); if(drive == DeviceName[SD] && onUSB) + { error(_fmt("errboot5", L"data_on_usb=yes and No available usb partitions for data!\nUsing SD.")); + m_cfg.setBool("GENERAL", "data_on_usb", false); + } /* Check if locked, set return to, set exit to, and init multi threading */ m_locked = m_cfg.getString("GENERAL", "parent_code", "").size() >= 4; @@ -1662,12 +1664,17 @@ void CMenu::_mainLoopCommon(bool withCF, bool adjusting) m_vid.render(); return; }*/ + + /* ticks - for moving and scaling covers and gui buttons and text */ if(withCF) CoverFlow.tick(); m_btnMgr.tick(); + /* video setup */ m_vid.prepare(); m_vid.setup2DProjection(false, true); + + /* background and coverflow drawing */ _updateBg(); if(CoverFlow.getRenderTex()) CoverFlow.RenderTex(); @@ -1704,6 +1711,8 @@ void CMenu::_mainLoopCommon(bool withCF, bool adjusting) CoverFlow.drawText(adjusting); } } + + /* game video or banner drawing */ if(m_gameSelected) { if(m_video_playing) @@ -1717,18 +1726,24 @@ void CMenu::_mainLoopCommon(bool withCF, bool adjusting) else if(m_banner.GetSelectedGame() && (!m_banner.GetInGameSettings() || (m_banner.GetInGameSettings() && m_bnr_settings))) m_banner.Draw(); } + + /* gui buttons and text drawing */ m_btnMgr.draw(); + + /* reading controller inputs and drawing cursor pointers*/ ScanInput(); - // check if we need to start screensaver - if(!m_vid.showingWaitMessage()) - { - if(!m_cfg.getBool("GENERAL", "screensaver_disabled", true)) - m_vid.screensaver(NoInputTime(), m_cfg.getInt("GENERAL", "screensaver_idle_seconds", 60)); - m_vid.render(); - } + + /* check if we want screensaver and if its idle long enuff, if so draw full screen black square with mild alpha */ + if(!m_cfg.getBool("GENERAL", "screensaver_disabled", true)) + m_vid.screensaver(NoInputTime(), m_cfg.getInt("GENERAL", "screensaver_idle_seconds", 60)); + + /* render everything on screen */ + m_vid.render(); + // check if power button is pressed and exit wiiflow if(Sys_Exiting()) exitHandler(BUTTON_CALLBACK); + // check if we need to start playing the game/banner sound // m_gameSelected means we are on the game selected menu // m_gamesound_changed means a new game sound is loaded and ready to play @@ -1743,15 +1758,16 @@ void CMenu::_mainLoopCommon(bool withCF, bool adjusting) // stop game/banner sound from playing if we exited game selected menu or if we move to new game else if((withCF && m_gameSelected && m_gamesound_changed && m_gameSound.IsPlaying()) || (!m_gameSelected && m_gameSound.IsPlaying())) m_gameSound.Stop(); + /* decrease music volume to zero if any of these are true: - trailer video playing or - game/banner sound is being loaded because we are switching to a new game or - game/banner sound is loaded and ready to play or + trailer video playing or|| + game/banner sound is being loaded because we are switching to a new game or|| + game/banner sound is loaded and ready to play or|| gamesound hasn't finished - when finishes music volume back to normal - some gamesounds don't loop continuously also this switches to next song if current song is done */ MusicPlayer.Tick((withCF && (m_video_playing || (m_gameSelected && m_soundThrdBusy) || - (m_gameSelected && m_gamesound_changed))) || - m_gameSound.IsPlaying()); + (m_gameSelected && m_gamesound_changed))) || m_gameSound.IsPlaying()); + // set song title and display it if music info is allowed if(MusicPlayer.SongChanged() && m_music_info) { diff --git a/source/menu/menu.hpp b/source/menu/menu.hpp index 8e8ebf94..f17703a6 100644 --- a/source/menu/menu.hpp +++ b/source/menu/menu.hpp @@ -81,7 +81,7 @@ private: Config m_titles; Config m_version; - vector m_homebrewArgs; + //vector m_homebrewArgs; u8 *m_base_font; u32 m_base_font_size; u8 *m_wbf1_font; @@ -1088,6 +1088,7 @@ private: void _launchGame(dir_discHdr *hdr, bool dvd, bool disc_cfg = false); void _launchChannel(dir_discHdr *hdr); void _launchHomebrew(const char *filepath, vector arguments); + vector _getMetaXML(const char *bootpath); void _launchGC(dir_discHdr *hdr, bool disc); void _launchShutdown(); void _setCurrentItem(const dir_discHdr *hdr); diff --git a/source/menu/menu_cftheme.cpp b/source/menu/menu_cftheme.cpp index da9289f4..e0ad8070 100644 --- a/source/menu/menu_cftheme.cpp +++ b/source/menu/menu_cftheme.cpp @@ -218,6 +218,7 @@ void CMenu::_showCFTheme(u32 curParam, int version, bool wide) } break; case CMenu::SCFParamDesc::PDT_FLOAT: + // should we use wstringEx(sfmt()) m_btnMgr.setText(m_cfThemeLblVal[k], sfmt("%.2f", m_coverflow.getFloat(domain, key))); for (int j = 1; j < 4; ++j) { diff --git a/source/menu/menu_explorer.cpp b/source/menu/menu_explorer.cpp index 5a8d4454..0202f79c 100644 --- a/source/menu/menu_explorer.cpp +++ b/source/menu/menu_explorer.cpp @@ -244,7 +244,8 @@ void CMenu::_Explorer(void) else if(strcasestr(file, ".dol") != NULL || strcasestr(file, ".elf") != NULL) { _hideExplorer(); - _launchHomebrew(file, m_homebrewArgs); + vector arguments = _getMetaXML(file); + _launchHomebrew(file, arguments); _showExplorer(); } else if(strcasestr(file, ".txt") != NULL || strcasestr(file, ".nfo") != NULL diff --git a/source/menu/menu_game.cpp b/source/menu/menu_game.cpp index fe9b1a05..80851a03 100644 --- a/source/menu/menu_game.cpp +++ b/source/menu/menu_game.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "menu.hpp" #include "types.h" @@ -1065,21 +1068,136 @@ void CMenu::_launch(const dir_discHdr *hdr) } else if(launchHdr.type == TYPE_HOMEBREW) { - const char *gamepath = fmt("%s/boot.dol", launchHdr.path); - if(!fsop_FileExist(gamepath)) - gamepath = fmt("%s/boot.elf", launchHdr.path); - if(fsop_FileExist(gamepath)) + const char *bootpath = fmt("%s/boot.dol", launchHdr.path); + if(!fsop_FileExist(bootpath)) + bootpath = fmt("%s/boot.elf", launchHdr.path); + if(fsop_FileExist(bootpath)) { m_cfg.setString(HOMEBREW_DOMAIN, "current_item", strrchr(launchHdr.path, '/') + 1); - _launchHomebrew(gamepath, m_homebrewArgs); - /*m_homebrewArgs is basically an empty vector string not needed for homebrew - but used by plugins when _launchHomebrew is called */ + vector arguments = _getMetaXML(bootpath); + _launchHomebrew(bootpath, arguments); } } ShutdownBeforeExit(); Sys_Exit(); } +void CMenu::_launchHomebrew(const char *filepath, vector arguments) +{ + /* clear coverflow, start wiiflow wait animation, set exit handler */ + _launchShutdown(); + m_gcfg1.save(true); + m_gcfg2.save(true); + m_cat.save(true); + m_cfg.save(true); + + Playlog_Delete(); + + bool ret = (LoadHomebrew(filepath) && LoadAppBooter(fmt("%s/app_booter.bin", m_binsDir.c_str()))); + if(ret == false) + { + error(_t("errgame14", L"app_booter.bin not found!")); + _exitWiiflow(); + } + /* no more error msgs - remove btns and sounds */ + cleanup(); + + AddBootArgument(filepath); + for(u32 i = 0; i < arguments.size(); ++i) + { + gprintf("Argument: %s\n", arguments[i].c_str()); + AddBootArgument(arguments[i].c_str()); + } + + ShutdownBeforeExit();// wifi and sd gecko doesnt work anymore after + loadIOS(58, false); + BootHomebrew(); + Sys_Exit(); +} + +vector CMenu::_getMetaXML(const char *bootpath) +{ + char *meta_buf = NULL; + vector args; + char meta_path[200]; + char *p; + char *e, *end; + struct stat st; + + /* load meta.xml */ + + p = strrchr(bootpath, '/'); + snprintf(meta_path, sizeof(meta_path), "%.*smeta.xml", p ? p-bootpath+1 : 0, bootpath); + + if (stat(meta_path, &st) != 0) + return args; + if (st.st_size > 64*1024) + return args; + + meta_buf = (char *) calloc(st.st_size + 1, 1);// +1 so that the buf is 0 terminated + if (!meta_buf) + return args; + + int fd = open(meta_path, O_RDONLY); + if (fd < 0) + { + free(meta_buf); + meta_buf = NULL; + return args; + } + read(fd, meta_buf, st.st_size); + close(fd); + + /* strip comments */ + + p = meta_buf; + int len; + while (p && *p) + { + p = strstr(p, ""); + if (!e) + { + *p = 0; // terminate + break; + } + e += 3; + len = strlen(e); + memmove(p, e, len + 1); // +1 for 0 termination + } + + /* parse meta */ + + if (strstr(meta_buf, "") && strstr(meta_buf, "") && strstr(meta_buf, "")) + { + p = strstr(meta_buf, ""); + end = strstr(meta_buf, ""); + + do + { + p = strstr(p, ""); + if (!p) + break; + + p += 5; //strlen(""); + e = strstr(p, ""); + if (!e) + break; + + string arg(p, e-p); + args.push_back(arg); + p = e + 6; + } + while (p < end); + } + + free(meta_buf); + meta_buf = NULL; + return args; +} + void CMenu::_launchGC(dir_discHdr *hdr, bool disc) { /* note for a disc boot hdr->id is set to the disc id before _launchGC is called */ @@ -1343,39 +1461,6 @@ void CMenu::_launchGC(dir_discHdr *hdr, bool disc) Sys_Exit(); } -void CMenu::_launchHomebrew(const char *filepath, vector arguments) -{ - /* clear coverflow, start wiiflow wait animation, set exit handler */ - _launchShutdown(); - m_gcfg1.save(true); - m_gcfg2.save(true); - m_cat.save(true); - m_cfg.save(true); - - Playlog_Delete(); - - bool ret = (LoadHomebrew(filepath) && LoadAppBooter(fmt("%s/app_booter.bin", m_binsDir.c_str()))); - if(ret == false) - { - error(_t("errgame14", L"app_booter.bin not found!")); - _exitWiiflow(); - } - /* no more error msgs - remove btns and sounds */ - cleanup(); - - AddBootArgument(filepath); - for(u32 i = 0; i < arguments.size(); ++i) - { - gprintf("Argument: %s\n", arguments[i].c_str()); - AddBootArgument(arguments[i].c_str()); - } - - ShutdownBeforeExit();// wifi and sd gecko doesnt work anymore after - loadIOS(58, false); - BootHomebrew(); - Sys_Exit(); -} - /* dont confuse loadIOS with _loadIOS */ int CMenu::_loadIOS(u8 gameIOS, int userIOS, string id, bool RealNAND_Channels) { diff --git a/source/menu/menu_main.cpp b/source/menu/menu_main.cpp index 352e46cf..0fe2b39f 100644 --- a/source/menu/menu_main.cpp +++ b/source/menu/menu_main.cpp @@ -754,7 +754,8 @@ int CMenu::main(void) CoverFlow.clear(); _showWaitMessage(); exitHandler(PRIILOADER_DEF); //Making wiiflow ready to boot something - _launchHomebrew(fmt("%s/boot.dol", m_appDir.c_str()), m_homebrewArgs); + vector arguments = _getMetaXML(fmt("%s/boot.dol", m_appDir.c_str())); + _launchHomebrew(fmt("%s/boot.dol", m_appDir.c_str()), arguments); return 0; } else if(Sys_GetExitTo() == EXIT_TO_SMNK2O || Sys_GetExitTo() == EXIT_TO_WFNK2O) diff --git a/source/music/MusicPlayer.cpp b/source/music/MusicPlayer.cpp index af569d03..096e97f9 100644 --- a/source/music/MusicPlayer.cpp +++ b/source/music/MusicPlayer.cpp @@ -150,7 +150,7 @@ void Musicplayer::LoadFile(const char *name, bool display_change) } else if(FileNames.size() == 1 && strcmp(name, PLUGIN_DOMAIN) == 0) { - MusicFile.FreeMemory(); + MusicFile.FreeMemory();// GuiSound is MusicFile in gui_sound.cpp MusicStopped = true; return; } diff --git a/wii/wiiflow/Languages/spanish.ini b/wii/wiiflow/Languages/spanish.ini index 03b025fa..2a5e520a 100644 --- a/wii/wiiflow/Languages/spanish.ini +++ b/wii/wiiflow/Languages/spanish.ini @@ -1,6 +1,6 @@  [SPANISH] -about1=Loader original por:\n%s +about1=Cargador original por:\n%s about2=Interfaz original por:\n%s about4=Gracias a:\n%s about6=Desarrolladores actuales:\n%s @@ -8,32 +8,33 @@ about7=Desarrolladores anteriores:\n%s about8=Parte del código obtenido desde:\n%s about9=Sitios que apoyan el proyecto:\n%s about10=Guía de ayuda -alphabetically=Alfabéticamente +alphabetically=alfabéticamente appname=%s v%s aspect169=Forzar 16:9 aspect43=Forzar 4:3 -aspectDef=Por Defecto +aspectDef=Por defecto bootmii=BootMii -bycontrollers=Núm. de mandos -byesrb=Clasificación ESRB -bygameid=ID del juego -bylastplayed=Últimos jugados -byplaycount=Más jugados -byplayers=Núm. jugadores -bywifiplayers=Núm. jugadores WiFi -cat1=Seleccionar Categorías -cat2=Borrar -cd1=Atrás +bycontrollers=Por controles +byesrb=Por ESRB +bygameid=Por ID del juego +bylastplayed=Por última jugada +byplaycount=Por veces jugado +byplayers=Por jugadores +bywifiplayers=Por jugadores Wifi +cat1=Elegir categorías +cat2=Limpiar +cd1=Volver cd2=Eliminar -cd3=Bloqueo de edad +cd3=Bloqueo por edad cfg1=Configuración -cfg10=Atrás -cfg11=Emulación de partidas en USB -cfg12=Emulación NAND -cfg13=Configuración de emulación NAND -cfg14=Establecer -cfg15=Extras +cfg10=Volver +cfg11=Emulación de archivos en USB +cfg12=Emulación de NAND +cfg13=Ajustes de emulación de NAND +cfg14=Ajustar +cfg15=Complementos cfg16=Elegir +cfg17=Particiones del juego cfg3=Descargar carátulas y títulos cfg4=Descargar cfg5=Control parental @@ -44,86 +45,109 @@ cfga3=Instalar cfga6=Idioma cfga7=Tema cfgb1=Ocarina -cfgb3=Modo de video -cfgb2=Cargador de GC predefinido -cfgb4=Idioma del juego -cfgb5=DML Modo de video -cfgb6=DML Idioma del juego +cfgb2=Cargador de GC por defecto +cfgb3=Modo de video por defecto +cfgb4=Idioma del juego por defecto +cfgb5=Modo de video GC por defecto +cfgb6=Idioma del juego GC por defecto +cfgb7=Tipo de canales +cfgb8=Ajustes de GameCube +cfgb9=Ajustes de GameCube por defecto cfgbnr1=Descargar carátula cfgbnr2=Borrar carátula -cfgbnr3=Descargar Banner personalizado -cfgbnr4=Borrar Banner +cfgbnr3=Descargar banner personalizado +cfgbnr4=Borrar banner cfgbnr5=Descargar cfgbnr6=Borrar -cfgbt1=Configuración de inicio +cfgbt1=Ajustes de inicio cfgbt2=Forzar carga de cIOS cfgbt3=Forzar revisión de cIOS cfgbt4=Puerto USB cfgbt5=Mostrar menú de fuentes al iniciar -cfgbt6=Activar funciones de varias fuentes +cfgbt6=Activar funciones multifuente cfgbt7=Iniciar servidor FTP al inicio cfgc1=Salir a -cfgc2=Ajustar ancho -cfgc3=Ajustar altura +cfgc2=Ajustar ancho TV +cfgc3=Ajustar altura TV cfgc4=Ajustar Coverflow cfgc5=Ajustar cfgc6=Ajuste horizontal cfgc7=Ajuste vertical cfgc8=Configuración de inicio -cfgc9=Manejar idiomas -cfgd4=Manejador de parches +cfgc9=Idiomas de WiiFlow +cfgd4=Gestor de ubicación cfgd5=Guardar el modo favorito cfgd7=Mostrar categorías al iniciar -cfgg1=Configuración +cfgg1=Ajustes cfgg10=IOS -cfgg12=Descargar carátula -cfgg13=Descargar -cfgg14=Parchar video -cfgg15=Trucos +cfgg11= +cfgg12= +cfgg13= +cfgg14=Parchar modos de video +cfgg15=Códigos de trampa cfgg16=Elegir -cfgg17=Elegir categorías -cfgg18=Tipo de enganche +cfgg17=Categorías +cfgg18=Tipo de gancho +cfgg19= cfgg2=Modo de video +cfgg20= cfgg21=Volver al canal cfgg22=Depurador -cfgg23=Descargando trucos.... -cfgg24=Emulación NAND +cfgg23=Descargando archivo de trampas.... +cfgg24=Emulación de NAND cfgg25=Contraseña incorrecta -cfgg26=Desactivar bloque de recarga de IOS +cfgg26= cfgg27=Relación de aspecto -cfgg28=NMM -cfgg29=No parche DVD +cfgg28= +cfgg29= cfgg3=Idioma cfgg30=Extraer partida de NAND cfgg31=Extraer cfgg32=Copiar partida a NAND cfgg33=Copiar -cfgg34=Emulador de memoria de Devolution +cfgg34= cfgg35=Cargador de GameCube cfgg36=Parche pantalla ancha -cfgg37=Cargar Apploader +cfgg37=Apploader de inicio cfgg38=LED de actividad -cfgg39=Captura de pantalla DM -cfgg40=Manejar Carátula y Banner -cfgg41=Manejar -cfgg4=Parchar frases de país +cfgg39= +cfgg40=Gestionar carátula y banner +cfgg41=Gestionar +cfgg42=Control USB-HID +cfgg43=Control nativo +cfgg44=Antiparpadeo de video +cfgg45=Servidor privado +cfgg46=Pantalla ancha en WiiU +cfgg47=Memoria emulada +cfgg48=Modo arcade Triforce +cfgg50=¡No hay partida a extraer! +cfgg51=¡No hay partida a meter en la NAND! +cfgg52=Vibración de GC en Wiimote +cfgg53=Saltar BIOS IPL +cfgg54=Ancho del video +cfgg55=Posición del video +cfgg56=Parchar PAL50 +cfgg57=¡No permitido para discos! +cfgg4=Parchar cadenas de país cfgg5=Ocarina +cfgg6= cfgg7=Vipatch cfgg8=Volver -cfglng1=Manejar idiomas +cfgg9= +cfglng1=Gestionar idiomas cfglng2=Obtener idiomas -cfglng3=Seleccionar archivo -cfglng4=Descargar archivo seleccionado +cfglng3=Elegir archivo +cfglng4=Descargar archivo elegido cfgne1=Emulación de NAND cfgne2=Extraer partidas cfgne3=Todas cfgne4=Faltantes cfgne5=Extraer NAND cfgne6=Empezar -cfgne7=Atrás +cfgne7=Volver cfgne8=¡No se encontró partición FAT válida para emulación de NAND! cfgne9=Archivo actual: %s -cfgne10=Opciones para emulación de NAND +cfgne10=Ajustes de emulación de NAND cfgne11=Progreso total: cfgne12=Extractor de NAND cfgne13=Extractor de partidas @@ -132,70 +156,76 @@ cfgne15=Extraídos: %d archivos / %d carpetas cfgne16=Tamaño total: %uMB (%d bloques) cfgne17=Tamaño total: %uKB (%d bloques) cfgne18=Listando partidas a extraer... -cfgne19=¡La extracción termino! -cfgne20=¡La extracción falló! -cfgne22=Desactivar emulación de NAND -cfgne23=Bienvenido a WiiFlow. No encontré una NAND válida para emulación de NAND. Pulse Extraer para extraer su NAND, o pulse desactivar para desactivar la emulación de NAND. -cfgne24=Extraer partida guardada +cfgne19=¡Extracción terminada! +cfgne20=¡Extracción fallida! +cfgne21= +cfgne22= +cfgne23= +cfgne24=Extraer partida cfgne25=Crear nueva partida -cfgne26=Una nueva partida se ha creado para este juego en la NAND real. ¿Extraer partida guardada existente de la NAND real o crear un nuevo archivo para emulación de NAND? -cfgne27=Calculando espacio necesario para extracción... -cfgne28=Importar partida guardada -cfgne29=Importados: %d partidas / %d archivos / %d directorios -cfgne30=¡Importación de archivos finalizada! -cfgne31=Seleccionar partición -cfgne32=Cambiar Nand -cfgne32=Cambiar Nand de guardado +cfgne26=Un archivo de guardado fue creado para este juego en la NAND real. ¿Extraer partida existente en la NAND real o crear una nueva para la emulación de NAND? +cfgne27=Calculando espacio necesario para la extracción... +cfgne28=Grabador de partidas +cfgne29=Grabados: %d partidas / %d archivos / %d directorios +cfgne30=¡Grabado de partidas finalizado! +cfgne31= +cfgne32=Elegir NAND de partidas +cfgne32=Emulación de NAND de partidas cfgne34=Ajustar -cfgne35=Atrás +cfgne35=Volver cfgne36=Ubicación = -cfgne37=Escoger NAND predefinida +cfgne37=Elegir NAND por defecto cfgne38=Vacío -cfgp1=Partición de juegos +cfgp1=Partición de NAND de partidas cfgp2=Carátulas planas -cfgp3=Conectar a la red al inicio +cfgp3=Conectar red al inicio cfgp4=Caché de banners cfgp5=Juegos de Wii cfgp6=Juegos de GC cfgp7=Música cfgp8=Carátulas de cajas cfgp9=Banners personalizados -cfgpl1=Seleccionar extras +cfgpl1=Elegir complementos cfgs1=Volumen de la música cfgs2=Volumen de la interfaz -cfgs3=Volumen de Coverflow +cfgs3=Volumen del coverflow cfgs4=Volumen del juego cfgsm1=Ajustes del menú de fuentes -cfgsm2=Activar B para menú de fuentes cfgsm3=Activar Sourceflow cfgsm4=Cajas chicas para Sourceflow cfgsm5=Limpiar caché de Sourceflow -cfgsm6=B en modo para fuente -cfgsm7=Manejar menú de fuentes +cfghb1=Ajustes de Homebrew +cfghb2=Cajas chicas para Coverflow +cfghb3=Partición de Homebrew +cfghb4=Modo de caja +cfghb5=Descargar carátulas +ChanReal=NAND real +ChanEmu=NAND emulada +ChanBoth=Ambas cheat1=Volver cheat2=Aplicar -cheat3=Archivo de trucos para el juego no encontrado +cheat3=Archivo de trampas para el juego no encontrado. cheat4=Descarga no encontrada. commodore=Commodore 64 custom=Personalizado -def=Por Defecto +def=Por defecto disabled=Desactivado dl1=Cancelar dl10=Por favor dona\na GameTDB.com dl12=GameTDB dl13=Orden de descarga -dl14=Elija regiones donde buscar carátulas: +dl14=Elige las regiones para buscar carátulas: dl15=Configuración de descarga -dl16=Establecer +dl16=Ajustar dl17=Configuración de descarga -dl18=Atrás +dl18=Volver dl19=Solo original -dl2=Atrás +dl2=Volver dl20=Original/Original -dl21=Original/Personal -dl22=Personal/Original -dl23=Personal/Personal -dl24=Solo personal +dl21=Original/Personalizada +dl22=Personalizada/Original +dl23=Personalizada/Personalizada +dl24=Solo personalizada dl25=Todas dl3=Todas dl4=Faltantes @@ -211,9 +241,9 @@ dlmsg14=Terminado. dlmsg15=¡Falló el guardando! dlmsg16=No se pudo leer el archivo dlmsg17=¡No hay actualizaciones! -dlmsg18=boot.dol no encontrado en la carpeta predeterminada +dlmsg18=boot.dol no encontrado en la ubicación predeterminada dlmsg19=¡Actualización disponible! -dlmsg2=No se pudo inicializar la red +dlmsg2=No se pudo conectar a la red dlmsg20=No se ha encontrado información sobre la versión dlmsg21=WiiFlow se cerrará para que los cambios tengan efecto. dlmsg22=Actualizando directorio de la aplicación... @@ -221,7 +251,7 @@ dlmsg23=Actualizando directorio de datos dlmsg24=Extrayendo... dlmsg25=¡La extracción ha fallado! Renombrando la copia de seguridad a boot.dol dlmsg26=Actualizando caché... -dlmsg27=¡Falta memoria! +dlmsg27=¡No hay suficiente memoria! dlmsg28=Ejecutando servidor FTP en %s:%u dlmsg29=El servidor FTP se encuentra detenido. dlmsg3=Descargando desde %s @@ -238,10 +268,10 @@ DMLpal=PAL 576i DMLpal60=PAL 480i DMLprog=NTSC 480p DMLprogP=PAL 480p -errboot1=¡No se encontró cIOS!\ncIOS d2x 249 base 56 y 250 base 57 son suficientes para todos sus juegos. +errboot1=¡No se encontró cIOS!\ncIOS d2x 249 base 56 y 250 base 57 son suficientes para todos tus juegos. errboot2=¡No se encontró un dispositivo donde guardar los archivos de configuración! errboot3=¡No se pudo iniciar el módulo DIP! -errboot4=¡No se encontraron particiones disponibles! +errboot4=¡No se encontró el directorio apps/wiiflow! errboot5=data_on_usb=yes, ¡pero no hay particiones USB disponibles para datos!\nUsando SD. errboot6=¡No hay particiones USB disponibles para datos ni tarjeta SD insertada!\nSaliendo. errgame1=No se encontró un juego con el ID: %s @@ -250,17 +280,26 @@ errgame4=No se pudo cargar el IOS %i errgame5=¡Falló la activación del emu! errgame6=¡Falló la activación del emu luego de recargar! errgame7=¡Falló WDVDGetCoverStatus! -errgame8=Por favor, inserte un dico de juego. +errgame8=Por favor, inserta un dico de juego. errgame9=Esto no es un disco de Wii o GC -errgame10=Falló ajuste de USB: %d -errneek1=No se pudo iniciar neek2o. Verifique sus ajustes de neek2o +errgame11=¡Cargador de GameCube no encontrado! No se puede lanzar el juego. +errgame12=¡Nintendont no encontrado! No se puede lanzar el disco de GC. +errgame13=¡EmuNAND para la partida no encontrado! Usando NAND real. +errgame14=¡app_booter.bin no encontrado! +errgame15=¡WiiFlow bloqueado! Desbloquea WiiFlow para usar esta función. +errgame16=¡No disponible para juegos de complementos! +errgame17=¡No se pueden eliminar canales de la NAND real! +errgame18=¡No hay info del juego! +errneek1=No se pudo iniciar neek2o. Verifica tu instalación de neek2o +errsource1=¡Homebrew bloqueado! +errsource2=¡Homebrew y multifuente no permitidos! exit_to=Salir a ftp1=Iniciar ftp2=Detener gameinfo1=Desarrollador: %s gameinfo2=Distribuidor: %s gameinfo3=Región: %s -gameinfo4=Fecha de lanzamiento: %i.%i.%i +gameinfo4=Lanzamiento: %i.%i.%i gameinfo5=Género: %s gameinfo6=Sin información del juego gametdb_code=ES @@ -270,7 +309,7 @@ GC_Devo=Devolution GC_Auto=Auto genesis=Sega Genesis gm1=Jugar -gm2=Atrás +gm2=Volver hbc=HBC homebrew=Homebrew home1=Ajustes @@ -304,43 +343,51 @@ lngspa=Español lngsys=Sistema lngtch=Chino T. main1=Instalar Juego -main2=Bienvenido a WiiFlow. No encontré ningún juego. Pulse Instalar para instalar un juego o Seleccionar partición para seleccionar su tipo de partición. -main3=Seleccionar partición -main4=Bienvenido a WiiFlow. No encontré ningún juego Pulse Seleccionar partición para elegir su tipo de partición. -main5=Bienvenido a WiiFlow. No encontré ningún complemento. Pulse Seleccionar partición para elegir su tipo de partición. +main2=No se encontraron juegos en +main3=No se encontraron títulos en +main4=No se encontraron apps en +main5=No se encontraron roms/elementos. +main6=No hay complementos elegidos. +main7=Total de juegos: %u mastersystem=Sega Master System menu=Menú del sistema NANDfull=Completa -NANDoff=Desactivado +NANDoff=Desactivada NANDpart=Parcial neek1=Lanzar título con neek2o neek2o=neek2o neogeo=Neo-Geo nes=Nintendo nintendo64=Nintendo64 +NMMdebug=Depurar NMMDef=Por defecto NMMOff=Desactivado NMMon=Activado -NMMdebug=Depurar NoDVDDef=Por defecto NoDVDOff=Desactivado NoDVDon=Activado off=Desactivado on=Activado -players=Jugadores +part1=Partición de Wii +part2=Partición de GameCube +part3=Partición de Emu NANDs +part4=Partición de complementos +part5=Ajustes de particiones +players= jugadores prii=Priiloader real=Nand real SaveDef=Por defecto SaveFull=Completa SaveFullG=Completa -SaveOff=Desactivado -SaveOffG=Desactivado +SaveOff=Desactivada +SaveOffG=Desactivada SavePart=Partida guardada SavePartG=Partida guardada SaveReg=Cambio de región SaveRegG=Cambio de región +savedtheme=¡Configuración del tema guardada! snes=Super Nintendo -stup1=Seleccione fuente +stup1=Elegir fuente stup2=** DESACTIVADO ** sys1=Actualizar WiiFlow sys2=Versión de WiiFlow: @@ -363,46 +410,49 @@ vmpmore=Más vmpnone=Ninguno vmpnormal=Normal wad1=Instalar WAD -wad2=Comenzar -wad3=Seleccionado %s, después de la instalación usted regresará al explorador. -wad4=Instalando WAD, por favor espere... +wad2=Empezar +wad3= +wad4=Instalando WAD, por favor espera... wad5=Error de instalación %i! wad6=Instalación finalizada con %i errores de hash. -wbfsadddlg=Por favor inserte el disco que quiera copiar, y pulse Ir. -wbfscpydlg=Si quiere copiar este juego a la tarjeta SD, pulse Ir -wbfsop1=Instalar Juego +wad7=Listo para instalar %s\nElige emuNAND y aprieta en Empezar. +wbfsadddlg=Por favor, inserta el disco que quieres copiar, y aprieta Empezar. +wbfscpydlg=Si quieres copiar este juego a la tarjeta SD, aprieta Empezar +wbfsop1=Instalar juego wbfsop10=Copiando [%s] %s... wbfsop11=Copiar juego -wbfsop12=Error en DVD(%d) +wbfsop12=DVDError(%d) wbfsop13=Juego instalado, pero el disco tiene errores (%d) -wbfsop14=Juego copiado, pulse volver para iniciar el juego. +wbfsop14=Juego copiado, presiona Volver para iniciar el juego. wbfsop15=Calculando espacio necesario para %s wbfsop16=Instalando %s wbfsop17=Instalando %s disco %d/2 wbfsop18=¡Esto es un juego de Wii! -wbfsop19=¡Esto no es un juego de Gamecube! +wbfsop19=¡Esto no es un juego de GameCube! wbfsop2=Borrar juego -wbfsop20=¡Ha insertado otra vez el disco %d! +wbfsop20=¡Has insertado otra vez el disco %d! wbfsop21=¡¡Este es un disco de otro juego!! -wbfsop22=Instalando %s...\n Por favor, inserte el disco 2 para continuar -wbfsop23=Calculando espacio necesario para %s...\n Por favor, inserte el disco %d para continuar -wbfsop24=No hay espacio suficiente: %d bloques necesarios, %d disponible -wbfsop25=¡Error leyendo disco! Pruebe limpiar el disco -wbfsop26=¡¡Disco extraído!! Por favor, inserte el disco -wbfsop4=Atrás -wbfsop5=Ir +wbfsop22=Instalando %s...\n Por favor, inserta el disco 2 para continuar +wbfsop23=Calculando espacio necesario para %s...\n Por favor, inserta el disco %d para continuar +wbfsop24=No hay espacio suficiente: %d bloques necesarios, %d disponibles +wbfsop25=¡Error leyendo el disco! Prueba a limpiar el disco +wbfsop26=¡¡Disco extraído!! Por favor, inserta el disco +wbfsop4=Volver +wbfsop5=Empezar wbfsop6=Instalando [%s] %s... -wbfsop7=Juego eliminado +wbfsop7=Juego borrado wbfsop8=Juego instalado, presiona B para salir. wbfsop9=Ha ocurrido un error wbfsoperr1=Disc_Wait falló wbfsoperr2=Disc_Open falló wbfsoperr3=¡Esto no es un disco de Wii! -wbfsoperr4=El juego ya esta instalado -wbfsoperr5=¡No se permite eliminar este canal! +wbfsoperr4=El juego ya está instalado +wbfsoperr5=¡Eliminar este canal no está permitido! +wbfsoperr6=El instalador de juegos de Wii esta malo, por favor usa cleanrip. wbfsprogress=%i%% -wbfsremdlg=Para eliminar el juego permanentemente : %s, presione Ir. +wbfsremdlg=Para eliminar permanentemente el juego: %s, presiona Empezar. wifiplayers= jugadores WiFi wii=Wii -wiichannels=Canales de Wii +wiichannels=Canales de Wii oficiales wiiware=WiiWare +wiiu=Menú de Wii U \ No newline at end of file