diff options
Diffstat (limited to 'src/koopatlas/hud.cpp')
-rw-r--r-- | src/koopatlas/hud.cpp | 323 |
1 files changed, 299 insertions, 24 deletions
diff --git a/src/koopatlas/hud.cpp b/src/koopatlas/hud.cpp index c9124d2..2401a04 100644 --- a/src/koopatlas/hud.cpp +++ b/src/koopatlas/hud.cpp @@ -1,5 +1,146 @@ #include "koopatlas/hud.h" + +dTexMapColouriser_c::dTexMapColouriser_c() { + texmap = 0; + original = 0; + mine = 0; +} + +void *EGG__Heap__alloc(unsigned long size, int unk, void *heap); +void EGG__Heap__free(void *ptr, void *heap); + +dTexMapColouriser_c::~dTexMapColouriser_c() { + resetAndClear(); +} + +void dTexMapColouriser_c::resetAndClear() { + texmap = 0; + if (mine) { + EGG__Heap__free(mine, 0); + mine = 0; + } +} + +void dTexMapColouriser_c::setTexMap(nw4r::lyt::TexMap *tm) { + OSReport("Colourising TexMap: %p (w:%d h:%d)\n", tm, tm->width, tm->height); + if (texmap) + resetAndClear(); + + if (tm->mBits.textureFormat != GX_TF_IA8) { + OSReport("Warning: Trying to colourise image whose format is %d not GX_TF_IA8\n", tm->mBits.textureFormat); + } + + texmap = tm; + original = (u16*)tm->image; + mine = (u16*)EGG__Heap__alloc(tm->width * tm->height * 4, 0x20, mHeap::gameHeaps[2]); + tm->image = mine; + tm->mBits.textureFormat = GX_TF_RGBA8; +} + +void dTexMapColouriser_c::applyAlso(nw4r::lyt::TexMap *tm) { + if (!texmap) { + setTexMap(tm); + } else { + tm->image = mine; + tm->mBits.textureFormat = GX_TF_RGBA8; + } +} + +inline static float hslValue(float n1, float n2, float hue) { + if (hue > 6.0f) + hue -= 6.0f; + else if (hue < 0.0f) + hue += 6.0f; + + if (hue < 1.0f) + return n1 + (n1 - n1) * hue; + else if (hue < 3.0f) + return n2; + else if (hue < 4.0f) + return n1 + (n2 - n1) * (4.0f - hue); + else + return n1; +} + +void dTexMapColouriser_c::colourise(int h, int s, int l) { + if (!mine) + return; + + int width = texmap->width, height = texmap->height; + int texelW = width / 4, texelH = height / 4; + + u16 *source = original, *dest = mine; + + float hueParam = h / 360.0f; + float satParam = s / 100.0f; + float lumParam = l / 100.0f; + + for (int texelY = 0; texelY < texelH; texelY++) { + for (int texelX = 0; texelX < texelW; texelX++) { + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + u8 intensity = *source & 0xFF; + u8 alpha = *source >> 8; + + u8 r, g, b; + + // This is a hack + if (alpha < 250) { + r = g = b = intensity; + } else { + // converting from GIMP's colourise code... + // h and s are always the same + // l is the only thing we need to touch: + // we get the luminance from the source pixel + // (which, conveniently, is the intensity) + // manipulate it using the passed l and then + // convert the whole thing to RGB + + float lum = intensity / 255.0f; + + // manipulate it + if (l > 0) { + lum = lum * (1.0f - lumParam); + lum += (1.0f - (1.0f - lumParam)); + } else if (l < 0) { + lum = lum * (lumParam + 1.0f); + } + + // make it RGB + + if (s == 0) { + r = g = b = lum*255.0f; + } else { + float m1, m2; + if (lum <= 0.5f) + m2 = lum * (1.0f + satParam); + else + m2 = lum + satParam - lum * satParam; + + m1 = 2.0f * lum - m2; + + r = hslValue(m1, m2, hueParam * 6.0f + 2.0) * 255.0f; + g = hslValue(m1, m2, hueParam * 6.0f) * 255.0f; + b = hslValue(m1, m2, hueParam * 6.0f - 2.0) * 255.0f; + } + } + + // now write it + dest[0] = (alpha<<8)|r; + dest[16] = (g<<8)|b; + + source++; + dest++; + } + } + + dest += 16; + } + } +} + + dWMHud_c *dWMHud_c::instance = 0; dWMHud_c *dWMHud_c::build() { @@ -15,6 +156,7 @@ dWMHud_c *dWMHud_c::build() { dWMHud_c::dWMHud_c() { layoutLoaded = false; displayedControllerType = -1; + isFooterVisible = false; } enum WMHudAnimation { @@ -50,7 +192,7 @@ int dWMHud_c::onCreate() { layout.disableAllAnimations(); layout.enableNonLoopAnim(SHOW_LIVES); - layout.enableNonLoopAnim(SHOW_FOOTER); + layout.resetAnim(SHOW_FOOTER); layout.resetAnim(SHOW_HEADER); static const char *tbNames[2] = {"MenuButtonInfo", "ItemsButtonInfo"}; @@ -63,13 +205,14 @@ int dWMHud_c::onCreate() { layout.getPanes(paneNames, &N_IconPosXP_00[0], 4); static const char *pictureNames[] = { - "Header_Centre", "Header_Right", + "Header_Centre", "Header_Right", "Footer", "NormalExitFlag", "SecretExitFlag", + "StarCoinOff0", "StarCoinOff1", "StarCoinOff2", "StarCoinOn0", "StarCoinOn1", "StarCoinOn2", "P_marioFace_00", "P_luigiFace_00", "P_BkinoFace_00", "P_YkinoFace_00" }; - layout.getPictures(pictureNames, &Header_Centre, 11); + layout.getPictures(pictureNames, &Header_Centre, 15); static const char *textBoxNames[] = { "LevelName", "LevelNameS", @@ -81,9 +224,20 @@ int dWMHud_c::onCreate() { }; layout.getTextBoxes(textBoxNames, &LevelName, 11); + headerCol.setTexMap(Header_Right->material->texMaps); + headerCol.applyAlso(Header_Centre->material->texMaps); + footerCol.setTexMap(Footer->material->texMaps); + layoutLoaded = true; + layout.drawOrder = 0; + willShowHeader = false; + willShowFooter = false; + + loadFooterInfo(); + SaveBlock *save = GetSaveFile()->GetBlock(-1); + willShowFooter = (save->newerWorldName[0] != 0); if (!dScKoopatlas_c::instance->pathManager.isMoving) enteredNode(); @@ -96,6 +250,8 @@ int dWMHud_c::onCreate() { int dWMHud_c::onDelete() { + dWMHud_c::instance = 0; + if (!layoutLoaded) return true; @@ -110,11 +266,22 @@ int dWMHud_c::onExecute() { if (willShowHeader && (!(layout.isAnimOn(SHOW_HEADER)))) { willShowHeader = false; loadHeaderInfo(); - playShowHeaderAnim(); + playShowAnim(SHOW_HEADER); + } + + if (willShowFooter && (!(layout.isAnimOn(SHOW_FOOTER)))) { + willShowFooter = false; + isFooterVisible = true; + loadFooterInfo(); + playShowAnim(SHOW_FOOTER); } + setupLives(); // FUCK IT updatePressableButtonThingies(); + int scCount = getStarCoinCount(); + WriteNumberToTextBox(&scCount, StarCoinCounter, false); + layout.execAnimations(); layout.update(); @@ -134,26 +301,28 @@ int dWMHud_c::onDraw() { -void dWMHud_c::playShowHeaderAnim() { +void dWMHud_c::playShowAnim(int id) { if (!this || !this->layoutLoaded) return; - layout.enableNonLoopAnim(SHOW_HEADER); + layout.enableNonLoopAnim(id); } -void dWMHud_c::playHideHeaderAnim() { +void dWMHud_c::playHideAnim(int id) { if (!this || !this->layoutLoaded) return; - if (!layout.isAnimOn(SHOW_HEADER)) { - layout.enableNonLoopAnim(SHOW_HEADER, true); + if (!layout.isAnimOn(id)) { + layout.enableNonLoopAnim(id, true); } - layout.grpHandlers[SHOW_HEADER].frameCtrl.flags = 3; // NO_LOOP | REVERSE + layout.grpHandlers[id].frameCtrl.flags = 3; // NO_LOOP | REVERSE + if (id == SHOW_FOOTER) + isFooterVisible = false; } void dWMHud_c::loadHeaderInfo() { dLevelInfo_c *levelInfo = &dScKoopatlas_c::instance->levelInfo; - dLevelInfo_c::entry_s *infEntry = levelInfo->search( + dLevelInfo_c::entry_s *infEntry = levelInfo->searchBySlot( nodeForHeader->levelNumber[0]-1, nodeForHeader->levelNumber[1]-1); if (infEntry == 0) { @@ -177,32 +346,102 @@ void dWMHud_c::loadHeaderInfo() { LevelName->SetString(convertedLevelName); LevelNameS->SetString(convertedLevelName); + // a hack because I don't feel like editing the rlyt + LevelName->size.x = LevelNameS->size.x = 400.0f; + // LEVEL NUMBER - wchar_t levelNumber[6]; - levelNumber[0] = '0' + nodeForHeader->levelNumber[0]; + static const wchar_t *numberKinds[] = { + // 0-19 are handled by code + // To insert a picturefont character: + // \x0B\x01YY\xZZZZ + // YY is the character code, ZZZZ is ignored + L"A", // 20, alternate + L"\x0B\x012F\xBEEF", // 21, tower + L"\x0B\x012F\xBEEF" L"2", // 22, tower 2 + L"\x0B\x012E\xBEEF", // 23, castle + L"\x0B\x012F\xBEEF", // 24, fortress + L"\x0B\x013D\xBEEF", // 25, final castle + L"Train", // 26, train + L"\x0B\x0132\xBEEF", // 27, airship + L"Palace", // 28, switch palace + L"House", // 29, yoshi's house + L"Key1", // 30, key 1 + L"Key2", // 31, key 2 + L"Key3", // 32, key 3 + L"Key4", // 33, key 4 + L"Key5", // 34, key 5 + L"Key6", // 35, key 6 + }; + + int origWN = infEntry->displayWorld; + int origWL = infEntry->displayLevel; + + wchar_t levelNumber[16]; + levelNumber[0] = (origWN >= 10) ? (origWN-10+'A') : (origWN+'0'); levelNumber[1] = '-'; - if (nodeForHeader->levelNumber[1] >= 10) { - levelNumber[2] = '0' + (nodeForHeader->levelNumber[1] / 10); - levelNumber[3] = '0' + (nodeForHeader->levelNumber[1] % 10); + if (origWL > 20) { + wcscpy(&levelNumber[2], numberKinds[origWL-20]); + } else if (origWL >= 10) { + levelNumber[2] = '1'; + levelNumber[3] = ('0' - 10) + origWL; levelNumber[4] = 0; } else { - levelNumber[2] = '0' + nodeForHeader->levelNumber[1]; + levelNumber[2] = '0' + origWL; levelNumber[3] = 0; } LevelNumber->SetString(levelNumber); + + // make the picture shadowy + int sidx = 0; + while (levelNumber[sidx]) { + if (levelNumber[sidx] == 11) { + levelNumber[sidx+1] = 0x200 | (levelNumber[sidx+1]&0xFF); + sidx += 2; + } + sidx++; + } LevelNumberS->SetString(levelNumber); + nw4r::ut::TextWriter tw2; + tw2.font = LevelNumber->font; + tw2.SetFontSize(LevelNumber->fontSizeX, LevelNumber->fontSizeY); + tw2.lineSpace = LevelNumber->lineSpace; + tw2.charSpace = LevelNumber->charSpace; + if (LevelNumber->tagProc != 0) + tw2.tagProcessor = LevelNumber->tagProc; + + float currentPos = tw2.CalcStringWidth(levelNumber, wcslen(levelNumber)); + currentPos += LevelNumber->trans.x + 12.0f; + // INFO int w = nodeForHeader->levelNumber[0] - 1; int l = nodeForHeader->levelNumber[1] - 1; u32 conds = GetSaveFile()->GetBlock(-1)->GetLevelCondition(w, l); + + NormalExitFlag->trans.x = currentPos; NormalExitFlag->SetVisible(conds & COND_NORMAL); + if (conds & COND_NORMAL) + currentPos += NormalExitFlag->size.x; + + SecretExitFlag->trans.x = currentPos; SecretExitFlag->SetVisible(conds & COND_SECRET); - StarCoinOn[0]->SetVisible(conds & COND_COIN1); - StarCoinOn[1]->SetVisible(conds & COND_COIN2); - StarCoinOn[2]->SetVisible(conds & COND_COIN3); + if (conds & COND_SECRET) + currentPos += SecretExitFlag->size.x; + + // are star coins enabled or not? + bool haveSC = (infEntry->flags & 2); + + for (int i = 0; i < 3; i++) { + bool flag = (conds & (COND_COIN1 << i)); + StarCoinOn[i]->SetVisible(flag); + StarCoinOff[i]->SetVisible(haveSC); + if (haveSC) { + StarCoinOff[i]->trans.x = currentPos; + currentPos += StarCoinOff[i]->size.x + 4.0f; + } + } // SIZE THING nw4r::ut::TextWriter tw; @@ -215,10 +454,35 @@ void dWMHud_c::loadHeaderInfo() { float width = tw.CalcStringWidth(convertedLevelName, charCount); float totalWidth = width + LevelName->trans.x - 20.0f; - if (totalWidth < 270.0f) - totalWidth = 270.0f; + if (totalWidth < currentPos) + totalWidth = currentPos; Header_Centre->size.x = totalWidth; Header_Right->trans.x = totalWidth; + + SaveBlock *save = GetSaveFile()->GetBlock(-1); + headerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL); +} + + +void dWMHud_c::loadFooterInfo() { + SaveBlock *save = GetSaveFile()->GetBlock(-1); + + wchar_t convertedWorldName[36]; + int i; + for (i = 0; i < 36; i++) { + convertedWorldName[i] = save->newerWorldName[i]; + if (convertedWorldName[i] == 0) + break; + } + convertedWorldName[35] = 0; + + WorldName->SetString(convertedWorldName); + WorldNameS->SetString(convertedWorldName); + + WorldName->colour1 = save->hudTextColours[0]; + WorldName->colour2 = save->hudTextColours[1]; + + footerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL); } @@ -237,15 +501,26 @@ void dWMHud_c::leftNode() { if (layout.grpHandlers[SHOW_HEADER].frameCtrl.currentFrame > 0.1f) { // not hidden - if ((layout.isAnimOn(SHOW_HEADER) && (layout.grpHandlers[SHOW_HEADER].frameCtrl.flags & 2)) + if ((layout.isAnimOn(SHOW_HEADER) && !(layout.grpHandlers[SHOW_HEADER].frameCtrl.flags & 2)) || (!layout.isAnimOn(SHOW_HEADER))) { // currently being shown, OR fully shown already - playHideHeaderAnim(); + playHideAnim(SHOW_HEADER); } } } +void dWMHud_c::hideFooter() { + if (isFooterVisible) + playHideAnim(SHOW_FOOTER); +} + +void dWMHud_c::showFooter() { + willShowFooter = true; + if (isFooterVisible) + playHideAnim(SHOW_FOOTER); +} + void dWMHud_c::setupLives() { static const int LogicalPlayerIDs[] = {0,1,3,2}; |