diff --git a/Makefile b/Makefile index f1e95c66..b485cf7f 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ include $(DEVKITPPC)/wii_rules TARGET := boot BUILD := build SOURCES := source \ + source/banner \ source/cheats \ source/config \ source/data \ @@ -45,6 +46,7 @@ DATA := data \ data/help INCLUDES := source \ + source/banner \ source/cheats \ source/config \ source/devicemounter \ diff --git a/source/banner/AnimatedBanner.cpp b/source/banner/AnimatedBanner.cpp new file mode 100644 index 00000000..75d6eb61 --- /dev/null +++ b/source/banner/AnimatedBanner.cpp @@ -0,0 +1,174 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include +#include "U8Archive.h" +#include "LanguageCode.h" +#include "AnimatedBanner.h" +#include "text.hpp" +#include "lz77.h" +#include "ash.h" + +AnimatedBanner::AnimatedBanner(u8 *font1, u8 *font2) +{ + first = true; + layout_banner = NULL; + newBanner = NULL; + sysFont1 = font1; + sysFont2 = font2; +} + +void AnimatedBanner::Clear() +{ + if(first) + return; + if(layout_banner) + { + delete layout_banner; + layout_banner = NULL; + } + if(newBanner) + { + delete newBanner; + newBanner = NULL; + } +} + +bool AnimatedBanner::LoadBanner(Banner *banner) +{ + first = false; + Clear(); + + u32 banner_bin_size; + const u8 *banner_bin = banner->GetFile((char*)"banner.bin", &banner_bin_size); + if(banner_bin == NULL) + return false; + + layout_banner = LoadLayout(banner_bin, banner_bin_size, "banner", CONF_GetLanguageString()); + return (layout_banner != NULL); +} + +Layout* AnimatedBanner::LoadLayout(const u8 *bnr, u32 bnr_size, const std::string& lyt_name, const std::string &language) +{ + u32 brlyt_size = 0; + newBanner = DecompressCopy(bnr, bnr_size, &bnr_size); + + const u8 *brlyt = u8_get_file(newBanner, (char*)fmt("%s.brlyt", lyt_name.c_str()), &brlyt_size); + if(!brlyt) + return NULL; + + Layout *layout = new Layout(sysFont1, sysFont2); + layout->Load(brlyt); + + u32 length_start = 0, length_loop = 0; + + u32 brlan_start_size = 0; + const u8 *brlan_start = u8_get_file(newBanner, (char*)fmt("%s_Start.brlan", lyt_name.c_str()), &brlan_start_size); + const u8 *brlan_loop = 0; + + // try the alternative file + if(!brlan_start) + brlan_start = u8_get_file(newBanner, (char*)fmt("%s_In.brlan", lyt_name.c_str()), &brlan_start_size); + + if(brlan_start) + length_start = Animator::LoadAnimators((const RLAN_Header *)brlan_start, *layout, 0); + + u32 brlan_loop_size = 0; + brlan_loop = u8_get_file(newBanner, (char*)fmt("%s.brlan", lyt_name.c_str()), &brlan_loop_size); + if(!brlan_loop) + brlan_loop = u8_get_file(newBanner, (char*)fmt("%s_Loop.brlan", lyt_name.c_str()), &brlan_loop_size); + if(!brlan_loop) + brlan_loop = u8_get_file(newBanner, (char*)fmt("%s_Rso0.brlan", lyt_name.c_str()), &brlan_loop_size); // added for "artstyle" wiiware + + if(brlan_loop) + length_loop = Animator::LoadAnimators((const RLAN_Header *)brlan_loop, *layout, 1); + + // load textures after loading the animations so we get the list of tpl filenames from the brlans + layout->LoadTextures(newBanner); + layout->LoadFonts(newBanner); + layout->SetLanguage(language); + layout->SetLoopStart(length_start); + layout->SetLoopEnd(length_start + length_loop); + layout->SetFrame(0); + + return layout; +} + +u8 *AnimatedBanner::DecompressCopy( const u8 * stuff, u32 len, u32 *size ) +{ + // check for IMD5 header and skip it + if( len > 0x40 && *(u32*)stuff == 0x494d4435 )// IMD5 + { + stuff += 0x20; + len -= 0x20; + } + + u8* ret = NULL; + // determine if it needs to be decompressed + if( IsAshCompressed( stuff, len ) ) + { + //u32 len2 = len; + // ASH0 + ret = DecompressAsh( stuff, len ); + if( !ret ) + { + gprintf( "out of memory\n" ); + return NULL; + } + } + else if( isLZ77compressed( (u8*)stuff ) ) + { + // LZ77 with no magic word + if( decompressLZ77content( (u8*)stuff, len, &ret, &len ) ) + { + return NULL; + } + } + else if( *(u32*)( stuff ) == 0x4C5A3737 )// LZ77 + { + // LZ77 with a magic word + if( decompressLZ77content( (u8*)stuff + 4, len - 4, &ret, &len ) ) + { + return NULL; + } + } + else + { + // just copy the data out of the archive + ret = (u8*)memalign( 32, len ); + if( !ret ) + { + gprintf( "out of memory\n" ); + return NULL; + } + memcpy( ret, stuff, len ); + } + if( size ) + { + *size = len; + } + + // flush the cache so if there are any textures in this data, it will be ready for the GX + DCFlushRange( ret, len ); + return ret; +} diff --git a/source/banner/AnimatedBanner.h b/source/banner/AnimatedBanner.h new file mode 100644 index 00000000..9ad1ef98 --- /dev/null +++ b/source/banner/AnimatedBanner.h @@ -0,0 +1,51 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef _ANIMATEDBANNER_H_ +#define _ANIMATEDBANNER_H_ + +#include "Layout.h" +#include "disc.h" +#include "channel/banner.h" + +class AnimatedBanner +{ +public: + AnimatedBanner(u8 *font1, u8 *font2); + void Clear(); + + bool LoadBanner(Banner *banner); + Layout *getBanner() const { return layout_banner; } + +protected: + Layout* LoadLayout(const u8 *bnr, u32 bnr_size, const std::string& lyt_name, const std::string &language); + u8 *DecompressCopy( const u8 * stuff, u32 len, u32 *size ); + Layout *layout_banner; + u8 *newBanner; + u8 *sysFont1; + u8 *sysFont2; + bool first; +}; + +#endif diff --git a/source/banner/Animator.cpp b/source/banner/Animator.cpp new file mode 100644 index 00000000..573f5f3b --- /dev/null +++ b/source/banner/Animator.cpp @@ -0,0 +1,260 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include "Animator.h" +#include "Layout.h" + +// load keyframes from a brlan file +u32 Animator::LoadAnimators(const RLAN_Header *header, Layout& layout, u8 key_set) +{ + u32 frame_count = 0; + + if (!header || header->magic != MAGIC_ANIMATION || header->endian != 0xFEFF || header->version != 0x0008) + return 0; // bad header + + // first section + const u8 *position = ((const u8 *) header) + header->offset; + + for(u32 i = 0; i < header->section_count; ++i) + { + section_t *section = (section_t *) position; + position += section->size; + + if (section->magic == MAGIC_PANE_ANIMATION_INFO) + { + const PAI1_Header *pai = (const PAI1_Header *) section; + u16 animator_count = pai->animator_count; + frame_count += pai->frame_count; + + // read animation file names + const u32 *nameOffsets = (const u32 *)(pai + 1); + for(u32 i = 0; i < pai->file_count; i++) + { + const char* name = (((const char *) nameOffsets) + nameOffsets[i]); + layout.AddPalette(name, key_set); + } + + const u32 *offsets = (const u32 *) (((const u8 *)section) + pai->entry_offset); + // read each animator + for(u32 n = 0; n < animator_count; n++) + { + const AnimatorHeader *animHdr = (const AnimatorHeader *) (((const u8 *)section) + offsets[n]); + std::string anim_name(animHdr->name, 0, 20); + + Animator* animator = animHdr->is_material ? + (Animator*) layout.FindMaterial(anim_name) : + (Animator*) layout.FindPane(anim_name); + + if (animator) + animator->LoadKeyFrames((const u8 *) animHdr, animHdr->tag_count, sizeof(AnimatorHeader), key_set); + } + } + else + { + gprintf("Unknown: %c%c%c%c\n", position[0], position[1], position[2], position[3]); + } + } + + return frame_count; +} + +void Animator::LoadKeyFrames(const u8 *file, u8 tag_count, u32 offset, u8 key_set) +{ + const u32 *tag_offsets = (const u32 *) (file + offset); + + for(u32 tag = 0; tag < tag_count; tag++) + { + const Anim_Header *animHdr = (const Anim_Header *) (file + tag_offsets[tag]); + + u32 animation_type = animHdr->animation_type; + u8 frame_count = animHdr->frame_count; + + const u32 *frame_offsets = (const u32 *) (animHdr + 1); + + for(u32 frame = 0; frame < frame_count; frame++) + { + const KeyFrame_Header *keyFrame = (const KeyFrame_Header *)(((const u8 *) animHdr) + frame_offsets[frame]); + const KeyType frame_type(static_cast(animation_type), keyFrame->index, keyFrame->target); + + switch (keyFrame->data_type) + { + // step key frame + case 0x01: + keys[key_set].step_keys[frame_type].Load((const u8 *) (keyFrame+1), keyFrame->key_count); + break; + + // hermite key frame + case 0x02: + keys[key_set].hermite_keys[frame_type].Load((const u8 *) (keyFrame+1), keyFrame->key_count); + break; + + default: + break; + } + } + } +} + +void Animator::SetFrame(FrameNumber frame_number, u8 key_set) +{ + std::map::iterator itr; + for(itr = keys[key_set].hermite_keys.begin(); itr != keys[key_set].hermite_keys.end(); itr++) + { + const KeyType& frame_type = itr->first; + const float frame_value = itr->second.GetFrame(frame_number); + + ProcessHermiteKey(frame_type, frame_value); + } + + std::map::iterator itr2; + for(itr2 = keys[key_set].step_keys.begin(); itr2 != keys[key_set].step_keys.end(); itr2++) + { + const KeyType& frame_type = itr2->first; + StepKeyHandler::KeyData const frame_data = itr2->second.GetFrame(frame_number); + + ProcessStepKey(frame_type, frame_data); + } +} + +void StepKeyHandler::Load(const u8 *file, u16 count) +{ + while (count--) + { + FrameNumber frame; + frame = *((FrameNumber *) file); + file += 4; + + KeyData& data = keys[frame]; + data.data1 = *file; + file++; + data.data2 = *file; + file++; + + file += 2; + } +} + +void HermiteKeyHandler::Load(const u8 *file, u16 count) +{ + while (count--) + { + std::pair pair; + + // read the frame number, value and slope + pair.first = *((FrameNumber *) file); + file += 4; + pair.second.value = *((float *) file); + file += 4; + pair.second.slope = *((float *) file); + file += 4; + + keys.insert(pair); + + //std::cout << "\t\t\t" "frame: " << frame << ' ' << keys[frame] << '\n'; + } +} + +StepKeyHandler::KeyData StepKeyHandler::GetFrame(FrameNumber frame_number) const +{ + // assuming not empty, a safe assumption currently + + // find the current frame, or the one after it + std::map::const_iterator frame_it = keys.lower_bound(frame_number); + + // current frame is higher than any keyframe, use the last keyframe + if (keys.end() == frame_it) + --frame_it; + + // if this is after the current frame and not the first keyframe, use the previous one + if (frame_number < frame_it->first && keys.begin() != frame_it) + --frame_it; + + return frame_it->second; +} + +float HermiteKeyHandler::GetFrame(FrameNumber frame_number) const +{ + // assuming not empty, a safe assumption currently + + // find the current keyframe, or the one after it + std::multimap::const_iterator next = keys.lower_bound(frame_number); + + // current frame is higher than any keyframe, use the last keyframe + if (keys.end() == next) + --next; + + std::multimap::const_iterator prev = next; + + // if this is after the current frame and not the first keyframe, use the previous one + if (frame_number < prev->first && keys.begin() != prev) + --prev; + + const float nf = next->first - prev->first; + if (fabs(nf) < 0.01) + { + // same frame numbers, just return the first's value + return prev->second.value; + } + else + { + // different frames, blend them together + // this is a "Cubic Hermite spline" apparently + + frame_number = (frame_number < prev->first) ? prev->first : + ((frame_number > next->first) ? next->first : frame_number); + + const float t = (frame_number - prev->first) / nf; + + // old curve-less code + //return prev->second.value + (next->second.value - prev->second.value) * t; + + // curvy code from marcan, :p + return + prev->second.slope * nf * (t + powf(t, 3) - 2 * powf(t, 2)) + + next->second.slope * nf * (powf(t, 3) - powf(t, 2)) + + prev->second.value * (1 + (2 * powf(t, 3) - 3 * powf(t, 2))) + + next->second.value * (-2 * powf(t, 3) + 3 * powf(t, 2)); + } +} + +void Animator::ProcessHermiteKey(const KeyType& type, float value) +{ +// std::cout << "unhandled key (" << GetName() << "): type: " << FourCC(type.type) +// << " index: " << (int)type.index +// << " target: " << (int)type.target +// << " value: " << value +// << '\n'; + gprintf("Animator::ProcessHermiteKey\n"); +} + +void Animator::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ +// std::cout << "unhandled key (" << GetName() << "): type: " << FourCC(type.type) +// << " index: " << (int)type.index +// << " target: " << (int)type.target +// << " data:" << (int)data.data1 << " " << (int)data.data2 +// << '\n'; + gprintf("Animator::ProcessStepKey\n"); +} diff --git a/source/banner/Animator.h b/source/banner/Animator.h new file mode 100644 index 00000000..962d8186 --- /dev/null +++ b/source/banner/Animator.h @@ -0,0 +1,169 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_ANIMATOR_H_ +#define WII_BNR_ANIMATOR_H_ + +#include +#include +#include +#include "BannerTools.h" + +typedef float FrameNumber; + +enum AnimationType +{ + ANIMATION_TYPE_PANE = MAKE_FOURCC('R', 'L', 'P', 'A'), + ANIMATION_TYPE_TEXTURE_SRT = MAKE_FOURCC('R', 'L', 'T', 'S'), + ANIMATION_TYPE_VISIBILITY = MAKE_FOURCC('R', 'L', 'V', 'I'), + ANIMATION_TYPE_VERTEX_COLOR = MAKE_FOURCC('R', 'L', 'V', 'C'), + ANIMATION_TYPE_MATERIAL_COLOR = MAKE_FOURCC('R', 'L', 'M', 'C'), + ANIMATION_TYPE_TEXTURE_PALETTE = MAKE_FOURCC('R', 'L', 'T', 'P'), + ANIMATION_TYPE_IND_MATERIAL = MAKE_FOURCC('R', 'L', 'I', 'M'), +}; + +struct RLAN_Header +{ + u32 magic; + u16 endian; + u16 version; + u32 file_size; + u16 offset; + u16 section_count; +} __attribute__((packed)); + +struct PAI1_Header +{ + u32 magic; + u32 section_size; + u16 frame_count; + u8 loop; + u8 pad; + u16 file_count; + u16 animator_count; + u32 entry_offset; +} __attribute__((packed)); + +struct AnimatorHeader +{ + char name[20]; + u8 tag_count; + u8 is_material; + u16 apad; +} __attribute__((packed)); + +struct Anim_Header +{ + u32 animation_type; + u8 frame_count; + u8 pad[3]; +} __attribute__((packed)); + +struct KeyFrame_Header +{ + u8 index; + u8 target; + u8 data_type; + u8 pad; + u16 key_count; + u16 pad1; + u32 offset; +} __attribute__((packed)); + +struct KeyType +{ + KeyType(AnimationType _type, u8 _index, u8 _target) + : type(_type) + , index(_index) + , target(_target) + {} + + bool operator<(const KeyType& rhs) const + { + return memcmp(this, &rhs, sizeof(*this)) < 0; + } + + const AnimationType type; + const u8 index, target; +}; + +class StepKeyHandler +{ +public: + void Load(const u8* file, u16 count); + + struct KeyData + { + u8 data1, data2; + }; + + KeyData GetFrame(FrameNumber frame_number) const; + +private: + std::map keys; +}; + +class HermiteKeyHandler +{ +public: + void Load(const u8* file, u16 count); + + struct KeyData + { + float value, slope; + }; + + float GetFrame(FrameNumber frame_number) const; + +private: + std::multimap keys; +}; + +class Layout; +class Animator +{ +public: + static const u32 MAGIC_ANIMATION = MAKE_FOURCC('R', 'L', 'A', 'N'); + static const u32 MAGIC_PANE_ANIMATION_INFO = MAKE_FOURCC('p', 'a', 'i', '1'); + + static u32 LoadAnimators(const RLAN_Header *header, Layout& layout, u8 key_set); + + void LoadKeyFrames(const u8 *file, u8 tag_count, u32 offset, u8 key_set); + virtual void SetFrame(FrameNumber frame, u8 key_set); + +protected: + Animator() {} + + virtual void ProcessHermiteKey(const KeyType& type, float value); + virtual void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); +private: + + struct + { + std::map step_keys; + std::map hermite_keys; + } keys[2]; +}; + +#endif diff --git a/source/banner/BannerTexture.cpp b/source/banner/BannerTexture.cpp new file mode 100644 index 00000000..60f67082 --- /dev/null +++ b/source/banner/BannerTexture.cpp @@ -0,0 +1,148 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok +Copyright (c) 2012 - giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include +#include +#include "BannerTexture.hpp" + +Texture::~Texture() +{ + if(texture_data) + free(texture_data); +} + +void Texture::Load(const u8 *file ) +{ + if(!file) + return; + + header = (Texture::Header *) file; + + if (header->magic != MAGIC) { + header = NULL; + return; // bad header + } + + u32 texture_count = header->num_textures; + // only support a single texture + if (texture_count > 1) + { + // Never saw it happen + texture_count = 1; + gprintf("texture count > 1\n"); + } + + // read textures + const TPL_Texture *tpl_list = (const TPL_Texture *) (file + header->header_size); + + for(u32 i = 0; i < texture_count; i++) + { + // seek to texture header + const TPL_Texture_Header *texture = (const TPL_Texture_Header *) (file + tpl_list[i].texture_offset); + + u8 mipmap = 0; + u8 bias_clamp = 0; + + if(texture->max_lod > 0) + mipmap = GX_TRUE; + if(texture->lod_bias > 0.0f) + bias_clamp = GX_ENABLE; + + // texture data + u8 *texture_data = (u8 *) (file + texture->offset); + + // seek to/read palette header + if (tpl_list[i].palette_offset != 0) + { + palette = (TPL_Palette_Header *) (file + tpl_list[i].palette_offset); + + // load the texture + GX_InitTexObjCI(&texobj, texture_data, texture->width, texture->height, texture->format, + texture->wrap_s, texture->wrap_t, mipmap, 0); + } + else + { + // load the texture + GX_InitTexObj(&texobj, texture_data, texture->width, texture->height, texture->format, + texture->wrap_s, texture->wrap_t, mipmap); + } + + // filter mode + if(mipmap) + { + GX_InitTexObjLOD(&texobj, texture->min, texture->mag, texture->min_lod, texture->max_lod, + texture->lod_bias, bias_clamp, bias_clamp, texture->edge_lod); + } + } +} + +//! This function is to load custom texture data and replace the original one. +void Texture::LoadTextureData(const u8 *data, u16 width, u16 height, u8 fmt) +{ + if(texture_data) + free(texture_data); + + int tex_size = GX_GetTexBufferSize(width, height, fmt, GX_FALSE, 0); + texture_data = (u8*) memalign(32, tex_size); + if(!texture_data) + return; + + memcpy(texture_data, data, tex_size); + DCFlushRange(texture_data, tex_size); + + GX_InitTexObj(&texobj, texture_data, width, height, fmt, 0, 0, GX_FALSE); +} + +void Texture::Apply(u8 &tlutName, u8 map_id, u8 wrap_s, u8 wrap_t) const +{ + if(!header) + return; + + if(tlutName >= 20 || map_id >= 8) + return; + + // create a temporary texture object to not modify the original with the wrap_s and wrap_t parameters + GXTexObj tmpTexObj; + for(int i = 0; i < 8; ++i) + tmpTexObj.val[i] = texobj.val[i]; + + // assume that if there is a palette header, then this format is a CIx one + if(palette) + { + // seek to/read palette data + u8 *tlut_data = (u8 *) (((u8 *) header) + palette->offset); + + // load tlut + GXTlutObj tlutobj; + GX_InitTlutObj(&tlutobj, tlut_data, palette->format, palette->num_items ); + GX_LoadTlut(&tlutobj, tlutName); + GX_InitTexObjTlut((GXTexObj *) &tmpTexObj, tlutName); + tlutName++; + } + + GX_InitTexObjWrapMode((GXTexObj *) &tmpTexObj, wrap_s, wrap_t); + GX_LoadTexObj((GXTexObj *) &tmpTexObj, map_id); +} diff --git a/source/banner/BannerTexture.hpp b/source/banner/BannerTexture.hpp new file mode 100644 index 00000000..de6cfa72 --- /dev/null +++ b/source/banner/BannerTexture.hpp @@ -0,0 +1,102 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok +Copyright (c) 2012 - giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef TEXTURE_H_ +#define TEXTURE_H_ + +#include +#include +#include +#include "BannerTools.h" + +class Texture +{ +public: + static const u32 MAGIC = MAKE_FOURCC(0x00, ' ', 0xAF, 0x30); + + Texture() : header(NULL), palette(NULL), texture_data(NULL) {} + virtual ~Texture(); + + void Load(const u8 *texture); + const std::string &getName() const { return name; } + void setName(const std::string& _name) { name = _name; } + + // load custom data into the texture object + void LoadTextureData(const u8 *data, u16 width, u16 height, u8 fmt); + + void Apply(u8 &tlutName, u8 map_id, u8 wrap_s, u8 wrap_t) const; +private: + struct Header + { + u32 magic; + u32 num_textures; + u32 header_size; + } __attribute__((packed)) ; + + struct TPL_Texture + { + u32 texture_offset; + u32 palette_offset; + } __attribute__((packed)) ; + + struct TPL_Texture_Header + { + u16 height; + u16 width; + u32 format; + u32 offset; + u32 wrap_s; + u32 wrap_t; + u32 min; + u32 mag; + f32 lod_bias; + u8 edge_lod; + u8 min_lod; + u8 max_lod; + u8 unpacked; + } __attribute__((packed)); + + struct TPL_Palette_Header + { + u16 num_items; + u8 unpacked; + u8 pad; + u32 format; + u32 offset; + } __attribute__((packed)); + + Texture::Header *header; + TPL_Palette_Header *palette; + u8 *texture_data; + GXTexObj texobj; + std::string name; +}; + +class TextureList : public std::vector +{ + public: + static const u32 MAGIC = MAKE_FOURCC('t', 'x', 'l', '1'); +}; + +#endif diff --git a/source/banner/BannerTools.h b/source/banner/BannerTools.h new file mode 100644 index 00000000..60a15768 --- /dev/null +++ b/source/banner/BannerTools.h @@ -0,0 +1,61 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef BANNER_TOOLS_H_ +#define BANNER_TOOLS_H_ + +#include +#include "gecko.h" + +#define MAKE_FOURCC(a, b, c, d) ((a) * (1 << 24) + (b) * (1 << 16) + (c) * (1 << 8) + (d) * (1 << 0)) + +typedef struct +{ + u32 magic; + u32 size; +} section_t; + +typedef struct +{ + float x, y; +} Vec2f; + +typedef struct +{ + float x, y, z; +} Vec3f; + +#define ALIGN32(x) (((x) + 31) & ~31) +#define LIMIT(x, min, max) \ + ({ \ + typeof( x ) _x = x; \ + typeof( min ) _min = min; \ + typeof( max ) _max = max; \ + ( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \ + }) + +#define MultiplyAlpha(a1, a2) ((u16) (a1) * (u16) (a2) / 0xFF) +#define FLOAT_2_U8(x) ((u8)((x) > 255.0f ? 255.0f : ((x) < 0.0f ? 0.0f : (x) + 0.5f))) +#define FLOAT_2_S16(x) ((s16)((x) > 32767.0f ? 32767.0f : ((x) < -32768.0f ? 32768.0f : (x) + 0.5f))) + +#endif diff --git a/source/banner/BannerWindow.cpp b/source/banner/BannerWindow.cpp new file mode 100644 index 00000000..05bf8b98 --- /dev/null +++ b/source/banner/BannerWindow.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include "BannerWindow.hpp" +#include "menu.hpp" +#include "utils.h" +#include "gx_addons.h" +#include "gecko.h" + +void BannerWindow::LoadBanner(Banner *banner, CVideo *vid, u8 *font1, u8 *font2) +{ + MaxAnimSteps = 30; + returnVal = -1; + reducedVol = false; + ScreenProps.x = 620; //620 + ScreenProps.y = 400; //400 + sysFont1 = font1; + sysFont2 = font2; + + video = vid; + guMtxIdentity(modelview); + guMtxTransApply(modelview, modelview, (!video->wide() || video->vid_50hz()) ? 0.0f : 2.0f, video->vid_50hz() ? -1.0f : 0.0f, 0.0F); + + AnimPosX = 0.5f * (ScreenProps.x - fIconWidth); + AnimPosY = 0.5f * (ScreenProps.y - fIconHeight); + AnimZoomIn = false; + AnimZoomOut = false; + AnimationRunning = false; + BannerAlpha = 255.f; + ChangeGame(banner); + gameSelected = 1; +} + +void BannerWindow::DeleteBanner() +{ + gameSelected = 0; + gameBanner->Clear(); +} + +BannerWindow::BannerWindow() +{ + AnimStep = 20; + gameSelected = 0; + firstRun = true; +} + +void BannerWindow::ChangeGame(Banner *banner) +{ + gameSelected = 0; + if(firstRun) + { + gameBanner = new AnimatedBanner(sysFont1, sysFont2); + firstRun = false; + } + gameBanner->LoadBanner(banner); +} + +void BannerWindow::ZoomIn(void) +{ + AnimZoomIn = true; + AnimZoomOut = false; + if(AnimStep <= 20) + AnimStep++; +} + +void BannerWindow::PauseZoom(void) +{ + AnimZoomIn = false; + AnimZoomOut = false; +} + +void BannerWindow::ZoomOut(void) +{ + AnimZoomIn = false; + AnimZoomOut = true; + if(AnimStep >= MaxAnimSteps) + AnimStep--; +} + +void BannerWindow::Animate(void) +{ + // animation is on going + if(AnimStep < MaxAnimSteps) + { + AnimationRunning = true; + if(AnimZoomIn && AnimStep < MaxAnimSteps) + AnimStep++; + else if(AnimZoomOut && AnimStep > 20) + AnimStep--; + + /* + // zoom in animation + if(AnimZoomIn) { + BGAlpha = std::min(255.f * AnimStep * 2.f / MaxAnimSteps, 255.f); + //if(AnimStep < 0.4f * MaxAnimSteps) + //BannerAlpha = 0; + //else + //BannerAlpha = std::min(255.f * (AnimStep - 0.4f * MaxAnimSteps) / (0.6f * MaxAnimSteps), 255.f); + } + // zoom out animation + else { + BGAlpha = std::min(255.f * (MaxAnimSteps-AnimStep) * 2.f / MaxAnimSteps, 255.f); + //if((MaxAnimSteps - AnimStep) < 0.4f * MaxAnimSteps) + //BannerAlpha = 0; + //else + //BannerAlpha = std::min(255.f * ((MaxAnimSteps - AnimStep) - 0.4f * MaxAnimSteps) / (0.6f * MaxAnimSteps), 255.f); + } + */ + + float curAnimStep = ((float)(MaxAnimSteps - AnimStep)/(float)MaxAnimSteps); + + float stepx1 = -AnimPosX; + float stepy1 = -AnimPosY; + float stepx2 = (640 - 1) - (AnimPosX + fIconWidth); + float stepy2 = (480 - 1) - (AnimPosY + fIconHeight); + + float top = AnimPosY + stepy1 * curAnimStep; + float bottom = AnimPosY + fIconHeight + stepy2 * curAnimStep; + float left = AnimPosX + stepx1 * curAnimStep; + float right = AnimPosX + fIconWidth + stepx2 * curAnimStep; + + // set main projection of all GUI stuff if we are using the banner browser + //if(dynamic_cast(browserMenu->GetGameBrowser()) != NULL) + // guOrtho(FSProjection2D, top, bottom, left, right, 0, 10000); + + float xDiff = 0.5f * (video->wide() ? (video->vid_50hz() ? 616 : 620.0f) : 608.0f); + float yDiff = 0.5f * (video->vid_50hz() ? 448.0f : 470.0f); + + // this just looks better for banner/icon ratio + float iconWidth = fIconWidth - 20; + float iconHeight = fIconHeight - 20; + + f32 ratioX = xDiff * 2.f / iconWidth; + f32 ratioY = yDiff * 2.f / iconHeight; + stepx1 = ((ScreenProps.x * 0.1f - xDiff) - (AnimPosX + 0.1f * fIconWidth - 0.1f * iconWidth)) * ratioX; + stepx2 = ((ScreenProps.x * 0.1f + xDiff) - (AnimPosX + 0.1f * fIconWidth + 0.1f * iconWidth)) * ratioX; + stepy1 = ((ScreenProps.y * 0.7f - yDiff) - (AnimPosY + 0.7f * fIconHeight - 0.7f * iconHeight)) * ratioY; + stepy2 = ((ScreenProps.y * 0.7f + yDiff) - (AnimPosY + 0.7f * fIconHeight + 0.7f * iconHeight)) * ratioY; + + //! This works good for banners + top = (ScreenProps.y * 0.5f - yDiff) + stepy1 * curAnimStep; + bottom = (ScreenProps.y * 0.5f + yDiff) + stepy2 * curAnimStep; + left = (ScreenProps.x * 0.5f - xDiff) + stepx1 * curAnimStep; + right = (ScreenProps.x * 0.5f + xDiff) + stepx2 * curAnimStep; + + // set banner projection + guOrtho(projection,top, bottom, left, right,-100,10000); + } + // last animation step + else if(AnimationRunning) + { + // set back original projection and stop animation/render of the browser (save some CPU ;P) + //memcpy(&video->projMtx, &originalProjection, sizeof(Mtx44)); + AnimationRunning = false; + } +} + +void BannerWindow::Draw(void) +{ + // draw a black background image first + //DrawRectangle(0.0f, 0.0f, ScreenProps.x, ScreenProps.y, (GXColor) {0, 0, 0, BGAlpha}, true); + + // Run window animation + Animate(); + + // no banner alpha means its the start of the animation + if(BannerAlpha == 0) + return; + + // cut the unneeded crap + Mtx mv1, mv2, mv3; + guMtxIdentity(mv2); + guMtxIdentity(mv3); + guMtxScaleApply(modelview,mv1, 1.f, -1.f, 1.f); + guMtxTransApply(mv1,mv1, 0.5f * ScreenProps.x, 0.5f * ScreenProps.y, 0.f); + guMtxTransApply(mv2,mv2, -0.5f * fBannerWidth, 0.5f * fBannerHeight, 0.f); + guMtxTransApply(mv3,mv3, 0.5f * fBannerWidth, -0.5f * fBannerHeight, 0.f); + guMtxConcat(mv1, mv2, mv2); + guMtxConcat(mv1, mv3, mv3); + + f32 viewportv[6]; + f32 projectionv[7]; + + GX_GetViewportv(viewportv, video->vid_mode()); + GX_GetProjectionv(projectionv, projection, GX_ORTHOGRAPHIC); + + guVector vecTL; + guVector vecBR; + GX_Project(0.0f, 0.0f, 0.0f, mv2, projectionv, viewportv, &vecTL.x, &vecTL.y, &vecTL.z); + GX_Project(0.0f, 0.0f, 0.0f, mv3, projectionv, viewportv, &vecBR.x, &vecBR.y, &vecBR.z); + + // round up scissor box offset and round down the size + u32 scissorX = (u32)(0.5f + std::max(vecTL.x, 0.0f)); + u32 scissorY = (u32)(0.5f + std::max(vecTL.y, 0.0f)); + u32 scissorW = (u32)std::max(vecBR.x - vecTL.x, 0.0f); + u32 scissorH = (u32)std::max(vecBR.y - vecTL.y, 0.0f); + + GX_SetScissor(scissorX, scissorY, scissorW, scissorH); + + // load projection matrix + GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC); + + if(gameBanner->getBanner()) + { + gameBanner->getBanner()->Render(modelview, ScreenProps, video->wide(), BannerAlpha); + gameBanner->getBanner()->AdvanceFrame(); + } + + //if(AnimationRunning) + GX_SetScissor(0, 0, video->width(), video->height()); + + // Clear and back to previous projection + video->setup2DProjection(); + GX_InvVtxCache(); + GX_InvalidateTexAll(); +} + +void BannerWindow::DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color, u8 filled) +{ + 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); + + u8 fmt; + long n; + 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 } }; + + if (!filled) + { + fmt = GX_LINESTRIP; + n = 5; + } + else + { + fmt = GX_TRIANGLEFAN; + n = 4; + } + + GX_Begin(fmt, GX_VTXFMT0, n); + for (i = 0; i < n; 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); +} diff --git a/source/banner/BannerWindow.hpp b/source/banner/BannerWindow.hpp new file mode 100644 index 00000000..b02c6f66 --- /dev/null +++ b/source/banner/BannerWindow.hpp @@ -0,0 +1,82 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef BANNERWINDOW_HPP_ +#define BANNERWINDOW_HPP_ + +#include + +#include "disc.h" +#include "AnimatedBanner.h" +#include "gui_sound.h" +#include "video.hpp" +#include "channel/banner.h" + +#define FAVORITE_STARS 5 + +class BannerWindow +{ + public: + BannerWindow(); + void DeleteBanner(); + void LoadBanner(Banner *banner, CVideo *vid, u8 *font1, u8 *font2); + int GetSelectedGame() { return gameSelected; } + void Draw(void); + void ZoomIn(void); + void PauseZoom(void); + void ZoomOut(void); + protected: + int MainLoop(); + void Animate(void); + void ChangeGame(Banner *banner); + void DrawRectangle(f32 x, f32 y, f32 width, f32 height, GXColor color, u8 filled); + + static const float fBannerWidth = 608.f; + static const float fBannerHeight = 448.f; + static const float fIconWidth = 128.f; + static const float fIconHeight = 96.f; + + CVideo *video; + bool reducedVol; + int returnVal; + int gameSelected; + dir_discHdr dvdheader; + + int MaxAnimSteps; + + int AnimStep; + float AnimPosX, AnimPosY; + float fAnimScale; + bool AnimZoomIn; + bool AnimZoomOut; + bool AnimationRunning; + bool oldAnimationRunning; + bool firstRun; + + u8 BGAlpha; + u8 BannerAlpha; + + Mtx modelview; + Mtx44 projection; + Mtx44 originalProjection; + Vec2f ScreenProps; + + AnimatedBanner *gameBanner; + u8 *sysFont1; + u8 *sysFont2; +}; + +#endif diff --git a/source/banner/LanguageCode.c b/source/banner/LanguageCode.c new file mode 100644 index 00000000..415f60f4 --- /dev/null +++ b/source/banner/LanguageCode.c @@ -0,0 +1,26 @@ +#include + +const char* CONF_GetLanguageString(void) +{ + static int confLang = 0xdead; + + if(confLang == 0xdead) + confLang = CONF_GetLanguage(); + + const char*lang; + switch( confLang ) + { + case CONF_LANG_JAPANESE: lang = "JPN"; break; + default: + case CONF_LANG_ENGLISH: lang = "ENG"; break; + case CONF_LANG_GERMAN: lang = "GER"; break; + case CONF_LANG_FRENCH: lang = "FRA"; break; + case CONF_LANG_SPANISH: lang = "SPA"; break; + case CONF_LANG_ITALIAN: lang = "ITA"; break; + case CONF_LANG_DUTCH: lang = "NED"; break; + case CONF_LANG_SIMP_CHINESE: + case CONF_LANG_TRAD_CHINESE: lang = "CHN"; break; + case CONF_LANG_KOREAN: lang = "KOR"; break; + } + return lang; +} diff --git a/source/banner/LanguageCode.h b/source/banner/LanguageCode.h new file mode 100644 index 00000000..c80008b9 --- /dev/null +++ b/source/banner/LanguageCode.h @@ -0,0 +1,14 @@ +#ifndef __LANGUAGE_CODE_H_ +#define __LANGUAGE_CODE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +const char* CONF_GetLanguageString(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/banner/Layout.cpp b/source/banner/Layout.cpp new file mode 100644 index 00000000..629c26f8 --- /dev/null +++ b/source/banner/Layout.cpp @@ -0,0 +1,392 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "Layout.h" +#include "WiiFont.h" +#include "U8Archive.h" + +Layout::Layout(u8 *font1, u8 *font2) + : header(0) +{ + Wbf1Font = font1; + Wbf2Font = font2; +} + +Layout::~Layout() +{ + for(u32 i = 0; i < panes.size(); ++i) + delete panes[i]; + + for(u32 i = 0; i < resources.materials.size(); ++i) + delete resources.materials[i]; + + for(u32 i = 0; i < resources.textures.size(); ++i) + delete resources.textures[i]; + + for(u32 i = 0; i < resources.fonts.size(); ++i) + delete resources.fonts[i]; +} + +bool Layout::Load(const u8 *brlyt) +{ + if(!brlyt) + return false; + + const BRLYT_Header *brlytFile = (const BRLYT_Header *) brlyt; + + if(brlytFile->magic != BRLYT_MAGIC || brlytFile->version != BRLYT_VERSION) + return false; + + Group* last_group = NULL; + std::stack*> group_stack; + group_stack.push(&groups); + + Pane* last_pane = NULL; + std::stack*> pane_stack; + pane_stack.push(&panes); + + const u8 *position = brlyt + brlytFile->header_len; + + for(u32 i = 0; i < brlytFile->section_count; ++i) + { + section_t *section = (section_t *) position; + position += section->size; + + if(section->magic == Layout::MAGIC) + { + header = (Layout::Header *) (section + 1); + } + else if (section->magic == TextureList::MAGIC) + { + const LytItemList *txl1 = (const LytItemList *) (section+1); + const char *nameoffset = ((const char *)(txl1+1)); + const LytStringTable *stringTable = (const LytStringTable *) (((const u8 *)(txl1+1))+txl1->offset_to_first); + + for(u32 i = 0; i < txl1->num_items; ++i) + { + const char *name = nameoffset+stringTable[i].offset_filename; + + Texture *texture = new Texture; + texture->setName(name); + resources.textures.push_back(texture); + } + } + else if (section->magic == MaterialList::MAGIC) + { + const LytItemList *mat1 = (const LytItemList *) (section+1); + const u32 *mat_offsets = (const u32 *) (((const u8 *)(mat1+1))+mat1->offset_to_first); + + for(u32 i = 0; i < mat1->num_items; ++i) + { + Material *material = new Material; + material->Load((Material::Header *) (((const u8 *) section)+mat_offsets[i])); + resources.materials.push_back(material); + } + } + else if (section->magic == FontList::MAGIC) + { + // load font list + const LytItemList *fnl1 = (const LytItemList *) (section+1); + const char *nameoffset = ((const char *)(fnl1+1)); + const LytStringTable *stringTable = (const LytStringTable *) (((const u8 *)(fnl1+1))+fnl1->offset_to_first); + + for(u32 i = 0; i < fnl1->num_items; i++) + { + const char *name = nameoffset+stringTable[i].offset_filename; + + WiiFont *font; + + if(strcmp(name, "wbf1.brfna") == 0 || strcmp(name, "RevoIpl_RodinNTLGPro_DB_32_I4.brfnt") == 0) { + //! 1st system font or alias for it + font = new WiiFont; + font->SetName("wbf1.brfna"); + font->Load(Wbf1Font); + if(!font) continue; + } + else if(strcmp(name, "wbf2.brfna") == 0) { + //! 2nd system font + font = new WiiFont; + font->SetName("wbf2.brfna"); + font->Load(Wbf2Font); + if(!font) continue; + } + else { + //! font from banner + font = new WiiFont; + font->SetName(name); + } + resources.fonts.push_back(font); + } + } + else if (section->magic == Pane::MAGIC) + { + Pane* pane = new Pane; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Bounding::MAGIC) + { + Bounding* pane = new Bounding; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Picture::MAGIC) + { + Picture* pane = new Picture; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Window::MAGIC) + { + Window* pane = new Window; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Textbox::MAGIC) + { + Textbox* pane = new Textbox; + pane->Load((Pane::Header *) section); + pane_stack.top()->push_back(last_pane = pane); + } + else if (section->magic == Layout::MAGIC_PANE_PUSH) + { + if (last_pane) + pane_stack.push(&last_pane->panes); + } + else if (section->magic == Layout::MAGIC_PANE_POP) + { + if (pane_stack.size() > 1) + pane_stack.pop(); + } + else if (section->magic == Group::MAGIC) + { + const char *grp = (const char *) (section + 1); + std::string group_name(grp, 0, Layout::Group::NAME_LENGTH); + Group& group_ref = (*group_stack.top())[group_name]; + grp += Layout::Group::NAME_LENGTH; + + u16 sub_count = *(u16 *) grp; + grp += 4; // 2 bytes reserved + + while (sub_count--) + { + std::string pane_name(grp, 0, Layout::Group::NAME_LENGTH); + group_ref.panes.push_back(pane_name); + grp += Layout::Group::NAME_LENGTH; + } + + last_group = &group_ref; + } + else if (section->magic == Layout::MAGIC_GROUP_PUSH) + { + if (last_group) + group_stack.push(&last_group->groups); + } + else if (section->magic == Layout::MAGIC_GROUP_POP) + { + if (group_stack.size() > 1) + group_stack.pop(); + } + else { + gprintf("Uknown layout section: %08X\n", section->magic); + } + } + return true; +} + +bool Layout::LoadTextures(const u8 *banner_file) +{ + bool success = false; + + for(u32 i = 0; i < resources.textures.size(); ++i) + { + u32 filesize; + const u8 *file = u8_get_file(banner_file, resources.textures[i]->getName().c_str(), &filesize); + if (file) + resources.textures[i]->Load(file); + else + success = false; + } + + return success; +} + +bool Layout::LoadFonts(const u8 *banner_file) +{ + bool success = false; + + for(u32 i = 0; i < resources.fonts.size(); ++i) + { + if(resources.fonts[i]->IsLoaded()) + continue; + u32 filesize; + const u8 *file = u8_get_file(banner_file, resources.fonts[i]->getName().c_str(), &filesize); + if (file) + resources.fonts[i]->Load(file); + else + success = false; + } + + return success; +} + +void Layout::Render(Mtx &modelview, const Vec2f &ScreenProps, bool widescreen, u8 render_alpha) const +{ + if(!header) + return; + + Mtx mv; + // we draw inverse + guMtxScaleApply(modelview, mv, 1.0f, -1.0f, 1.0f); + + // centered draw + if(header->centered) + guMtxTransApply(mv, mv, ScreenProps.x * 0.5f, ScreenProps.y * 0.5f, 0.f); + + // render all panes + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->Render(resources, render_alpha, mv, widescreen); +} + +void Layout::SetFrame(FrameNumber frame_number) +{ + frame_current = frame_number; + + const u8 key_set = (frame_current >= frame_loop_start); + if (key_set) + frame_number -= frame_loop_start; + + resources.cur_set = key_set; + + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->SetFrame(frame_number, key_set); + + for(u32 i = 0; i < resources.materials.size(); ++i) + resources.materials[i]->SetFrame(frame_number, key_set); +} + +void Layout::AdvanceFrame() +{ + ++frame_current; + + if (frame_current >= frame_loop_end) + frame_current = frame_loop_start; + + SetFrame(frame_current); +} + +void Layout::SetLanguage(const std::string& language) +{ + if(!header) + return; + + // check if that language is found + bool lang_found = false; + + // hide panes of non-matching languages + std::map::iterator itr; + for(itr = groups["RootGroup"].groups.begin(); itr != groups["RootGroup"].groups.end(); itr++) + { + // check if that language exists + if(!lang_found && itr->first == language) + lang_found = true; + + // some hax, there are some odd "Rso0" "Rso1" groups that shouldn't be hidden + // only the 3 character language groups should be + if (itr->first != language && itr->first.length() == 3) + { + std::list::iterator itr2; + for(itr2 = itr->second.panes.begin(); itr2 != itr->second.panes.end(); itr2++) + { + Pane* const found = FindPane(*itr2); + if (found) + found->SetHide(true); + } + } + } + + // show english if langauge is not found + if(!lang_found && language != "ENG") + { + SetLanguage("ENG"); + return; + } + + // unhide panes of matching language, some banners list language specific panes in multiple language groups + std::list::iterator itr2; + for(itr2 = groups["RootGroup"].groups[language].panes.begin(); itr2 != groups["RootGroup"].groups[language].panes.end(); itr2++) + { + Pane* const found = FindPane(*itr2); + if (found) + { + found->SetHide(false); + found->SetVisible(true); // all games with languages start as visible + } + } +} + +void Layout::AddPalette(const std::string &name, u8 key_set) +{ + resources.palettes[key_set].push_back(name); + + if(FindTexture(name) != 0) + return; + + Texture *texture = new Texture; + texture->setName(name); + resources.textures.push_back(texture); +} + +Pane* Layout::FindPane(const std::string& find_name) +{ + for(u32 i = 0; i < panes.size(); ++i) + { + Pane* found = panes[i]->FindPane(find_name); + if(found) + return found; + } + + return NULL; +} + +Material* Layout::FindMaterial(const std::string& find_name) +{ + for(u32 i = 0; i < resources.materials.size(); ++i) + { + if (find_name.compare(0, 20, resources.materials[i]->getName()) == 0) + return resources.materials[i]; + } + + return NULL; +} + +Texture* Layout::FindTexture(const std::string& find_name) +{ + for(u32 i = 0; i < resources.textures.size(); ++i) + { + if (find_name == resources.textures[i]->getName()) + return resources.textures[i]; + } + + return NULL; +} diff --git a/source/banner/Layout.h b/source/banner/Layout.h new file mode 100644 index 00000000..2095dbe3 --- /dev/null +++ b/source/banner/Layout.h @@ -0,0 +1,145 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef LAYOUT_H_ +#define LAYOUT_H_ + +#include +#include +#include +#include +#include + +#include "BannerTexture.hpp" +#include "Material.h" +#include "Pane.h" +#include "Picture.h" +#include "Window.h" +#include "WiiFont.h" +#include "Textbox.h" + +typedef std::vector PaletteList; + +struct BannerResources +{ + MaterialList materials; + TextureList textures; + FontList fonts; + PaletteList palettes[2]; + u8 cur_set; +}; + +class Layout +{ +public: + Layout(u8 *font1, u8* font2); + virtual ~Layout(); + + static const u32 BRLYT_MAGIC = MAKE_FOURCC('R', 'L', 'Y', 'T'); + static const u32 BRLYT_VERSION = 0xFEFF0008; + static const u32 MAGIC = MAKE_FOURCC('l', 'y', 't', '1'); + static const u32 MAGIC_PANE_PUSH = MAKE_FOURCC('p', 'a', 's', '1'); + static const u32 MAGIC_PANE_POP = MAKE_FOURCC('p', 'a', 'e', '1'); + static const u32 MAGIC_GROUP_PUSH = MAKE_FOURCC('g', 'r', 's', '1'); + static const u32 MAGIC_GROUP_POP = MAKE_FOURCC('g', 'r', 'e', '1'); + + bool Load(const u8 *brlyt); + bool LoadTextures(const u8 *banner_file); + bool LoadFonts(const u8 *banner_file); + + void Render(Mtx &modelview, const Vec2f &ScreenProps, bool widescreen, u8 render_alpha = 0xFF) const; + + FrameNumber GetFrame() const { return frame_current; } + void SetFrame(FrameNumber frame_number); + void AdvanceFrame(); + + void SetLoopStart(FrameNumber loop_start) { frame_loop_start = loop_start; } + void SetLoopEnd(FrameNumber loop_end) { frame_loop_end = loop_end; } + + float GetWidth() const { return header->width; } + void SetWidth(float _width) { header->width = _width; } + + float GetHeight() const { return header->height; } + void SetHeight(float _height) { header->height = _height; } + + bool isCentered() const { return header->centered; } + + void SetLanguage(const std::string& language); + + Pane* FindPane(const std::string& name); + Material* FindMaterial(const std::string& name); + Texture *FindTexture(const std::string &name); + + void AddPalette(const std::string &name, u8 key_set); +protected: + struct BRLYT_Header + { + u32 magic; + u32 version; + u32 filesize; + u16 header_len; + u16 section_count; + } __attribute__((packed)); + + struct Header + { + u8 centered; + u8 pad[3]; + float width; + float height; + } __attribute__((packed)); + + struct LytItemList + { + u16 num_items; + u16 offset_to_first; + } __attribute__((packed)); + + struct LytStringTable + { + u32 offset_filename; + u32 pad; + } __attribute__((packed)); + + struct Group + { + static const u32 MAGIC = MAKE_FOURCC('g', 'r', 'p', '1'); + static const u32 NAME_LENGTH = 0x10; + + std::map groups; + std::list panes; + }; + + Layout::Header *header; + u8 *Wbf1Font; + u8 *Wbf2Font; + + BannerResources resources; + PaneList panes; + + FrameNumber frame_current, frame_loop_start, frame_loop_end; + + std::map groups; +}; + +#endif diff --git a/source/banner/Material.cpp b/source/banner/Material.cpp new file mode 100644 index 00000000..e1143226 --- /dev/null +++ b/source/banner/Material.cpp @@ -0,0 +1,591 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok and giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include +#include "Layout.h" +#include "Material.h" + +Material::Material() + : flags(0) + , texture_maps(0) + , texture_srts(0) + , texture_coord_gens(0) + , chan_control(0) + , mat_color(0) + , tev_swap_table(0) + , ind_srt(0) + , ind_stage(0) + , tev_stages(0) + , alpha_compare(0) + , blend_mode(0) + , header(0) +{ + for( int i = 0; i < 8; i++ ) + palette_texture[i] = DEFAULT_PALETTE; +} + +void Material::Load(Material::Header *file) +{ + header = file; + + // Flags + flags = (MatFlags *) &header->flags; + + flags->texture_map = std::min((int)MAX_TEX_MAP, (int)flags->texture_map); + flags->texture_srt = std::min((int)MAX_TEX_SRT, (int)flags->texture_srt); + flags->texture_coord_gen = std::min((int)MAX_TEX_GEN, (int)flags->texture_coord_gen); + flags->ind_srt = flags->ind_srt; + flags->ind_stage = std::min((int)MAX_IND_STAGES, (int)flags->ind_stage); + flags->tev_stages = std::min((int)MAX_TEV_STAGES, (int)flags->tev_stages); + + u8 *buf_offset = (u8 *) (header+1); + + // texture map + if(flags->texture_map) + { + texture_maps = (TextureMap *) buf_offset; + buf_offset += sizeof(TextureMap) * flags->texture_map; + } + + // texture srt + if(flags->texture_srt) + { + texture_srts = (TextureSrt *) buf_offset; + buf_offset += sizeof(TextureSrt) * flags->texture_srt; + } + + // texture coord gen + if(flags->texture_coord_gen) + { + texture_coord_gens = (TextureCoordGen *) buf_offset; + buf_offset += sizeof(TextureCoordGen) * flags->texture_coord_gen; + } + + // channel control + if (flags->channel_control) + { + chan_control = (ChannelControl *) buf_offset; + buf_offset += sizeof(ChannelControl); + } + + // material color + if (flags->material_color) + { + mat_color = (GXColor *) buf_offset; + buf_offset += sizeof(GXColor); + } + //else Default to 0xFFFFFFFF + + // tev swap table + if (flags->tev_swap_table) + { + tev_swap_table = (TevSwap *) buf_offset; + buf_offset += sizeof(TevSwap) * 4; + } + + // ind srt + if(flags->ind_srt) + { + ind_srt = (IndSrt *) buf_offset; + buf_offset += sizeof(IndSrt) * flags->ind_srt; + } + + // ind stage + if(flags->ind_stage) + { + ind_stage = (IndStage *) buf_offset; + buf_offset += sizeof(IndStage) * flags->ind_stage; + } + + // tev stage + if(flags->tev_stages) + { + tev_stages = (TevStage *) buf_offset; + buf_offset += sizeof(TevStage) * flags->tev_stages; + } + + // alpha compare + if (flags->alpha_compare) + { + alpha_compare = (AlphaCompareModes *) buf_offset; + buf_offset += sizeof(AlphaCompareModes); + } + + // blend mode + if (flags->blend_mode) + { + blend_mode = (BlendModes *) buf_offset; + buf_offset += sizeof(BlendModes); + } +} + +inline void Material::ApplyChannelControl(u8 render_alpha, bool &modulate_colors) const +{ + if(flags->channel_control) + { + GX_SetChanCtrl(0, 0, 0, chan_control->color_matsrc, 0, 0, 2 ); + GX_SetChanCtrl(2, 0, 0, chan_control->alpha_matsrc, 0, 0, 2 ); + + if(chan_control->alpha_matsrc != 1 && chan_control->color_matsrc != 1) + modulate_colors = false; + + if(!chan_control->alpha_matsrc || !chan_control->color_matsrc) + { + GXColor matColor = (GXColor){0xff, 0xff, 0xff, MultiplyAlpha(0xff, render_alpha) }; + + if(flags->material_color) + matColor = (GXColor){ mat_color->r, mat_color->g, mat_color->b, + MultiplyAlpha(mat_color->a, render_alpha) }; + + GX_SetChanMatColor(4, matColor); + + if((*(u32 *)&matColor) == 0xFFFFFFFF) + modulate_colors = true; + } + } + else + { + GX_SetChanCtrl(4, 0, 0, 1, 0, 0, 2); + } + + GX_SetNumChans(1); +} + +inline void Material::ApplyTexCoordGens(void) const +{ + // texture coord gen + for(u32 i = 0; i != flags->texture_coord_gen; ++i) + { + const TextureCoordGen &tcg = texture_coord_gens[i]; + GX_SetTexCoordGen(GX_TEXCOORD0 + i, tcg.tgen_typ, tcg.tgen_src, tcg.mtxsrc); + + const u8 mtrx = (tcg.mtxsrc - GX_TEXMTX0) / 3; + + if (tcg.tgen_typ == 1 && tcg.mtxsrc != GX_IDENTITY && mtrx < flags->texture_srt) + { + const TextureSrt& srt = texture_srts[mtrx]; + + const float rotate_rad = DegToRad(srt.rotate); + const float cosF = cosf(rotate_rad); + const float sinF = sinf(rotate_rad); + + // setup texture matrix + Mtx m; + m[0][0] = srt.scale_x * cosF; + m[0][1] = srt.scale_y * -sinF; + m[0][2] = 0.0f; + m[0][3] = -0.5f * (m[0][0] + m[0][1]) + srt.translate_x + 0.5f; + m[1][0] = srt.scale_x * sinF; + m[1][1] = srt.scale_y * cosF; + m[1][2] = 0.0f; + m[1][3] = -0.5f * (m[1][0] + m[1][1]) + srt.translate_y + 0.5f; + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f; + m[2][3] = 0.0f; + + GX_LoadTexMtxImm(m, tcg.mtxsrc, GX_MTX3x4); + } + } + + GX_SetNumTexGens(flags->texture_coord_gen); +} + +inline void Material::ApplyTevSwapTable(void) const +{ + if (flags->tev_swap_table) + { + for(int i = 0; i < 4; i++) + GX_SetTevSwapModeTable(GX_TEV_SWAP0 + i, + tev_swap_table[i].r, tev_swap_table[i].g, + tev_swap_table[i].b, tev_swap_table[i].a); + } + else + { + GX_SetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); + } +} + +inline void Material::ApplyTevStages(bool modulate_colors) const +{ + u32 tev_stages_cnt = 0; + + if(flags->tev_stages) + { + // tev stages + for(u32 i = 0; i < flags->tev_stages; ++i) + { + const TevStage &ts = tev_stages[i]; + + GX_SetTevOrder(i, ts.texcoord, ts.tex_map | (ts.lowBit << 8), ts.color ); + GX_SetTevSwapMode(i, ts.ras_sel, ts.tex_sel); + + GX_SetTevColorIn(i, ts.color_in.a, ts.color_in.b, ts.color_in.c, ts.color_in.d); + GX_SetTevColorOp(i, ts.color_in.tevop, ts.color_in.tevbias, ts.color_in.tevscale, ts.color_in.clamp, ts.color_in.tevregid ); + GX_SetTevKColorSel(i, ts.color_in.sel ); + + GX_SetTevAlphaIn(i, ts.alpha_in.a, ts.alpha_in.b, ts.alpha_in.c, ts.alpha_in.d); + GX_SetTevAlphaOp(i, ts.alpha_in.tevop, ts.alpha_in.tevbias, ts.alpha_in.tevscale, ts.alpha_in.clamp, ts.alpha_in.tevregid ); + GX_SetTevKAlphaSel(i, ts.alpha_in.sel ); + + GX_SetTevIndirect(i, ts.ind.indtexid, ts.ind.format, ts.ind.bias, ts.ind.mtxid, + ts.ind.wrap_s, ts.ind.wrap_t, ts.ind.addprev, ts.ind.utclod, ts.ind.a); + + tev_stages_cnt++; + } + } + else + { + if(flags->texture_map == 0) + { + // 1st stage + GX_SetTevOrder(GX_TEVSTAGE0, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0, 0xF, 4, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0, 0x7, 2, 0x5, 0x7); + tev_stages_cnt++; + } + else if(flags->texture_map == 1) + { + // 1st stage + GX_SetTevOrder(GX_TEVSTAGE0, 0, 0, 0xFF); + GX_SetTevColorIn(GX_TEVSTAGE0, 2, 4, 8, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0, 1, 2, 4, 7); + tev_stages_cnt++; + + // 2nd stage + if(modulate_colors) + { + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 0xF, 0, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 7, 0, 5, 7); + tev_stages_cnt++; + } + } + else if(flags->texture_map == 2) + { + // 1st stage + GX_SetTevOrder(GX_TEVSTAGE0, 0, 0, 0xFF); + GX_SetTevColorIn(GX_TEVSTAGE0, 0xF, 0xF, 0xF, 8); + GX_SetTevAlphaIn(GX_TEVSTAGE0, 7, 7, 7, 4); + tev_stages_cnt++; + + // 2nd stage + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 1, 1, 0xFF); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 8, 0, 0xE, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 4, 0, 6, 7); + GX_SetTevKColorSel(GX_TEVSTAGE0 + tev_stages_cnt, 0x1f); + GX_SetTevKAlphaSel(GX_TEVSTAGE0 + tev_stages_cnt, 0x1f); + tev_stages_cnt++; + + // 3rd stage + if(modulate_colors) + { + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 0xF, 0, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 7, 0, 5, 7); + tev_stages_cnt++; + } + } + else + { + u32 TevKDefault[] = { 0x1F, 0x1B, 0x17, 0x13, 0x1E, 0x1A, 0x16, 0x12 }; + + for(int i = 0; i < flags->texture_map; i++) + { + GX_SetTevOrder(i, i, i, 0xff ); + + GX_SetTevColorIn(i, 0xf, 8, 0xe, i ? 0xf : 0 ); + GX_SetTevAlphaIn(i, 7, 4, 6, i ? 7 : 0 ); + GX_SetTevKColorSel(i, TevKDefault[i] ); + GX_SetTevKAlphaSel(i, TevKDefault[i] ); + tev_stages_cnt++; + } + + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xff, 0xff, 0xff ); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 2, 4, 0, 0xf ); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 1, 2, 0, 7 ); + tev_stages_cnt++; + + if(modulate_colors) + { + GX_SetTevOrder(GX_TEVSTAGE0 + tev_stages_cnt, 0xFF, 0xFF, 4); + GX_SetTevColorIn(GX_TEVSTAGE0 + tev_stages_cnt, 0xF, 0, 0xA, 0xF); + GX_SetTevAlphaIn(GX_TEVSTAGE0 + tev_stages_cnt, 7, 0, 5, 7); + tev_stages_cnt++; + } + } + + for(u32 i = 0; i < tev_stages_cnt; i++) + { + GX_SetTevColorOp(GX_TEVSTAGE0 + i, 0, 0, 0, 1, 0); + GX_SetTevAlphaOp(GX_TEVSTAGE0 + i, 0, 0, 0, 1, 0); + GX_SetTevDirect(GX_TEVSTAGE0 + i); + GX_SetTevSwapMode(GX_TEVSTAGE0 + i, 0, 0); + } + } + + // enable correct number of tev stages + GX_SetNumTevStages(tev_stages_cnt); +} + +inline void Material::ApplyIndStages(void) const +{ + for( int i = 0; i < flags->ind_srt; i++ ) + { + const IndSrt &ind = ind_srt[i]; + + const float rotate_rad = DegToRad(ind.rotate); + // maybe add a look up table + float cosF = cosf(rotate_rad); + float sinF = sinf(rotate_rad); + + int scale_exp = 0; + f32 mtx23[2][3]; + f32 mtxabs23[2][3]; + + mtx23[0][0] = ind.scale_x * cosF; + mtx23[0][1] = ind.scale_y * -sinF; + mtx23[0][2] = ind.translate_x; + + mtx23[1][0] = ind.scale_x * sinF; + mtx23[1][1] = ind.scale_y * cosF; + mtx23[1][2] = ind.translate_y; + + // create matrix with abs values + // compiler will optimize the loops + for(int n = 0; n < 2; n++) + for(int m = 0; m < 3; m++) + mtxabs23[n][m] = fabs(mtx23[n][m]); + + // hardcore clamping going on here + if( (mtxabs23[0][0] >= 1.0f) + || (mtxabs23[0][1] >= 1.0f) + || (mtxabs23[0][2] >= 1.0f) + || (mtxabs23[1][0] >= 1.0f) + || (mtxabs23[1][1] >= 1.0f) + || (mtxabs23[1][2] >= 1.0f)) + { + while( scale_exp < 0x2E + && ((mtxabs23[0][0] >= 1.0f) + || (mtxabs23[0][1] >= 1.0f) + || (mtxabs23[0][2] >= 1.0f) + || (mtxabs23[1][0] >= 1.0f) + || (mtxabs23[1][1] >= 1.0f) + || (mtxabs23[1][2] >= 1.0f))) + { + for(int n = 0; n < 2; n++) + { + for(int m = 0; m < 3; m++) + { + mtx23[n][m] *= 0.5f; + mtxabs23[n][m] *= 0.5f; + } + } + + scale_exp++; + } + } + else if( (mtxabs23[0][0] < 0.5f) + && (mtxabs23[0][1] < 0.5f) + && (mtxabs23[0][2] < 0.5f) + && (mtxabs23[1][0] < 0.5f) + && (mtxabs23[1][1] < 0.5f) + && (mtxabs23[1][2] < 0.5f)) + { + while( scale_exp > -0x11 + && (mtxabs23[0][0] < 0.5f) + && (mtxabs23[0][1] < 0.5f) + && (mtxabs23[0][2] < 0.5f) + && (mtxabs23[1][0] < 0.5f) + && (mtxabs23[1][1] < 0.5f) + && (mtxabs23[1][2] < 0.5f)) + { + for(int n = 0; n < 2; n++) + { + for(int m = 0; m < 3; m++) + { + mtx23[n][m] *= 2.0f; + mtxabs23[n][m] *= 2.0f; + } + } + + scale_exp--; + } + } + + GX_SetIndTexMatrix(GX_ITM_0 + i, mtx23, scale_exp); + } + + for( int i = 0; i < flags->ind_stage; i++ ) + { + const IndStage &stage = ind_stage[i]; + GX_SetIndTexOrder(i, stage.texcoord, stage.tex_map); + GX_SetIndTexCoordScale(i, stage.scale_s, stage.scale_t); + } + + GX_SetNumIndStages(flags->ind_stage); +} + +inline void Material::ApplyTextures(const BannerResources& resources) const +{ + u8 tlut_name = 0; + + for(u32 i = 0; i < flags->texture_map; ++i) + { + const TextureMap &tr = texture_maps[i]; + + if(palette_texture[i] == DEFAULT_PALETTE) + { + if (tr.tex_index < resources.textures.size()) + resources.textures[tr.tex_index]->Apply(tlut_name, i, tr.wrap_s, tr.wrap_t); + } + else + { + // find texture from palette + if(palette_texture[i] >= resources.palettes[resources.cur_set].size()) + { + gprintf( "palette index is out of range %i\n", palette_texture[i]); + return; + } + for(u32 n = 0; n < resources.textures.size(); n++) + { + if(resources.textures[n]->getName() == resources.palettes[resources.cur_set][palette_texture[i]]) + { + resources.textures[n]->Apply(tlut_name, i, tr.wrap_s, tr.wrap_t); + break; + } + } + } + } + + // invalidate texture cache + GX_InvalidateTexAll(); +} + +void Material::Apply(const BannerResources& resources, u8 render_alpha, bool modulate_colors) const +{ + // channel control and material color + ApplyChannelControl(render_alpha, modulate_colors); + + // texture coordinates gen + ApplyTexCoordGens(); + + // bind textures + ApplyTextures(resources); + + for (u32 i = 0; i < 4; ++i) + { + // tev reg colors + if(i < 3) + GX_SetTevColorS10(GX_TEVREG0 + i, header->color_regs[i]); + + // tev k colors + GX_SetTevKColor(GX_KCOLOR0 + i, header->color_constants[i]); + } + + // tev swap colors + ApplyTevSwapTable(); + + // tev stages + ApplyTevStages(modulate_colors); + + // ind stages + ApplyIndStages(); + + // alpha compare + if(flags->alpha_compare) + GX_SetAlphaCompare(alpha_compare->compare & 0xf, alpha_compare->ref0, + alpha_compare->op, alpha_compare->compare >> 4, alpha_compare->ref1); + else + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + + // blend mode + if (flags->blend_mode) + GX_SetBlendMode(blend_mode->type, blend_mode->src_factor, blend_mode->dst_factor, blend_mode->logical_op); + else + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET); +} + +void Material::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_TEXTURE_SRT) // texture scale/rotate/translate + { + if (type.target < 5 && type.index < flags->texture_srt) + { + (&texture_srts[type.index].translate_x)[type.target] = value; + return; + } + // TODO: Something is still here: target 0-4 and index 1-9 while texture_srt is 1, value is always 0 or 1 + return; // TODO remove this + } + else if (type.type == ANIMATION_TYPE_IND_MATERIAL) // ind texture crap + { + if (type.target < 5 && type.index < flags->ind_srt) + { + (&ind_srt[type.index].translate_x)[type.target] = value; + return; + } + return; // TODO remove this + } + else if (type.type == ANIMATION_TYPE_MATERIAL_COLOR) // material color + { + if (type.target < 4) + { + // mat_color + if(flags->material_color) + (&mat_color->r)[type.target] = FLOAT_2_U8(value); + return; + } + else if (type.target < 0x10) + { + (&header->color_regs->r)[type.target - 4] = FLOAT_2_S16(value); + return; + } + else if (type.target < 0x20) + { + (&header->color_constants->r)[type.target - 0x10] = FLOAT_2_U8(value); + return; + } + } + + Base::ProcessHermiteKey(type, value); +} + +void Material::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ + if (type.type == ANIMATION_TYPE_TEXTURE_PALETTE) // tpl palette + { + if(type.index < MAX_TEX_MAP) + { + palette_texture[type.index] = data.data2; + return; + } + } + + Base::ProcessStepKey(type, data); +} diff --git a/source/banner/Material.h b/source/banner/Material.h new file mode 100644 index 00000000..fa7f3487 --- /dev/null +++ b/source/banner/Material.h @@ -0,0 +1,253 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok and giantpune + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_MATERIAL_H_ +#define WII_BNR_MATERIAL_H_ + +#include "Animator.h" +#include "BannerTexture.hpp" + +struct BannerResources; + +class Material : public Animator +{ +public: + typedef Animator Base; + + struct Header + { + char name[20]; + GXColorS10 color_regs[3]; + GXColor color_constants[4]; + u32 flags; + } __attribute__((packed)); + + Material(); + + void Load(Material::Header *mat); + void Apply(const BannerResources& resources, u8 render_alpha, bool modulate) const; + const char *getName() const { return header->name; } + + const Material::Header *GetHeader() const { return header; } +protected: + void ProcessHermiteKey(const KeyType& type, float value); + void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); + +private: + void ApplyChannelControl(u8 render_alpha, bool &modulate_colors) const; + void ApplyTevSwapTable(void) const; + void ApplyTexCoordGens(void) const; + void ApplyTevStages(bool modulate_colors) const; + void ApplyIndStages(void) const; + void ApplyTextures(const BannerResources& resources) const; + + enum + { + MAX_TEX_MAP = 8, + MAX_TEX_SRT = 10, + MAX_TEX_GEN = 8, + MAX_IND_STAGES = 4, + MAX_TEV_STAGES = 16, + DEFAULT_PALETTE = 0xFF, + }; + + struct MatFlags + { + u32 pad2 : 4; + u32 material_color : 1; + u32 pad : 1; + u32 channel_control : 1; + u32 blend_mode : 1; + u32 alpha_compare : 1; + u32 tev_stages : 5; + u32 ind_stage : 3; + u32 ind_srt : 2; + u32 tev_swap_table : 1; + u32 texture_coord_gen : 4; + u32 texture_srt : 4; + u32 texture_map : 4; + } __attribute__((packed)); + + struct TextureMap + { + u16 tex_index; + u8 wrap_s; + u8 wrap_t; + } __attribute__((packed)); + + struct TextureSrt + { + f32 translate_x; + f32 translate_y; + f32 rotate; + f32 scale_x; + f32 scale_y; + } __attribute__((packed)); + + struct TextureCoordGen + { + u8 tgen_typ; + u8 tgen_src; + u8 mtxsrc; + u8 pad; + } __attribute__((packed)); + + struct ChannelControl + { + u8 color_matsrc; + u8 alpha_matsrc; + u16 pad; + } __attribute__((packed)); + + struct IndSrt + { + f32 translate_x; + f32 translate_y; + f32 rotate; + f32 scale_x; + f32 scale_y; + } __attribute__((packed)); + + struct IndStage + { + u8 texcoord; + u8 tex_map; + u8 scale_s; + u8 scale_t; + } __attribute__((packed)); + + struct BlendModes + { + u8 type, src_factor, dst_factor, logical_op; + + } __attribute__((packed)); + + struct AlphaCompareModes + { + u8 compare, op, ref0, ref1; + + } __attribute__((packed)); + + struct TevSwap + { + u32 a : 2; + u32 b : 2; + u32 g : 2; + u32 r : 2; + } __attribute__((packed)); + + struct TevStage + { + u32 texcoord : 8; + u32 color : 8; + u32 tex_map : 8; + + u32 unk : 3; + u32 tex_sel : 2; + u32 ras_sel : 2; + u32 lowBit : 1; + + struct + { + u32 b : 4; + u32 a : 4; + + u32 d : 4; + u32 c : 4; + + u32 tevscale : 2; + u32 tevbias : 2; + u32 tevop : 4; + + u32 sel : 5; + u32 tevregid : 2; + u32 clamp : 1; + + } __attribute__((packed)) color_in, __attribute__((packed)) alpha_in; + + struct + { + u32 unk1 : 6; + u32 indtexid : 2; + + u32 unk2 : 1; + u32 mtxid : 4; + u32 bias : 3; + + u32 unk3 : 2; + u32 wrap_t : 3; + u32 wrap_s : 3; + + u32 unk4 : 2; + u32 a : 2; + u32 utclod : 1; + u32 addprev : 1; + u32 format : 2; + + } __attribute__((packed)) ind; + } __attribute__((packed)); + + // Material flags + MatFlags *flags; + + // Texture + TextureMap *texture_maps; + TextureSrt *texture_srts; + TextureCoordGen *texture_coord_gens; + + // Color channels + ChannelControl *chan_control; + + // Material colors + GXColor *mat_color; + + // Tev color swap + TevSwap *tev_swap_table; + + // Indirect textures + IndSrt *ind_srt; + IndStage *ind_stage; + + // Texture environment + TevStage *tev_stages; + + // Blending and alpha compare + AlphaCompareModes *alpha_compare; + BlendModes *blend_mode; + + // palette animation + u8 palette_texture[MAX_TEX_MAP]; + + //! Material header + Material::Header *header; +}; + +class MaterialList : public std::vector +{ +public: + static const u32 MAGIC = MAKE_FOURCC('m', 'a', 't', '1'); +}; + + +#endif diff --git a/source/banner/Pane.cpp b/source/banner/Pane.cpp new file mode 100644 index 00000000..84139607 --- /dev/null +++ b/source/banner/Pane.cpp @@ -0,0 +1,165 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "Pane.h" +#include "Layout.h" + +void Pane::Load(Pane::Header *pan) +{ + if(!pan) + return; + + header = pan; + hide = false; + RootPane = !strcmp( header->name, "RootPane" ); + AlignHor = header->origin % 3; + AlignVer = 2 - header->origin / 3; +} + +Pane::~Pane() +{ + // delete children + for(u32 i = 0; i < panes.size(); ++i) + delete panes[i]; +} + +void Pane::SetFrame(FrameNumber frame, u8 key_set) +{ + // setframe on self + Animator::SetFrame(frame, key_set); + + // setframe on children + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->SetFrame(frame, key_set); +} + +void Pane::Render(const BannerResources& resources, u8 parent_alpha, Mtx &modelview, + bool widescreen, bool modify_alpha) const +{ + if (!header || !GetVisible() || GetHide()) + return; + + u8 render_alpha = header->alpha; + + if(RootPane && parent_alpha != 0xFF) + { + modify_alpha = true; + render_alpha = MultiplyAlpha(header->alpha, parent_alpha); + } + if(!RootPane && modify_alpha) + { + render_alpha = MultiplyAlpha(header->alpha, parent_alpha); + } + else if(GetInfluencedAlpha() && header->alpha != 0xff) + { + modify_alpha = true; + parent_alpha = MultiplyAlpha(header->alpha, parent_alpha); + } + + float ws_scale = 1.0f; + + if(widescreen && GetWidescren()) + { + ws_scale *= 0.82f; // should actually be 0.75? + widescreen = false; + } + + Mtx m1,m2,m3,m4, mv; + guMtxIdentity (m1); + + // Scale + guMtxScaleApply(m1,m1, header->scale.x * ws_scale, header->scale.y, 1.f); + + // Rotate + guMtxRotDeg ( m2, 'x', header->rotate.x ); + guMtxRotDeg ( m3, 'y', header->rotate.y ); + guMtxRotDeg ( m4, 'z', header->rotate.z ); + guMtxConcat(m2, m3, m2); + guMtxConcat(m2, m4, m2); + guMtxConcat(m1, m2, m1); + + // Translate + guMtxTransApply(m1,m1, header->translate.x, header->translate.y, header->translate.z); + + guMtxConcat (modelview, m1, mv); + + // render self + Draw(resources, render_alpha, ws_scale, mv); + + // render children + for(u32 i = 0; i < panes.size(); ++i) + panes[i]->Render(resources, render_alpha, mv, widescreen, modify_alpha); +} + +Pane* Pane::FindPane(const std::string& find_name) +{ + if(!header) + return NULL; + + if (find_name.compare(0, 0x10, getName()) == 0) + return this; + + for(u32 i = 0; i < panes.size(); ++i) + { + Pane *found = panes[i]->FindPane(find_name); + if (found) + return found; + } + + return NULL; +} + +void Pane::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_VERTEX_COLOR) // vertex color + { + // only alpha is supported for Panes afaict + if (0x10 == type.target) + { + header->alpha = FLOAT_2_U8(value); + return; + } + } + else if (type.type == ANIMATION_TYPE_PANE) // pane animation + { + if (type.target < 10) + { + (&header->translate.x)[type.target] = value; + return; + } + } + + Base::ProcessHermiteKey(type, value); +} + +void Pane::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ + if (type.type == ANIMATION_TYPE_VISIBILITY) // visibility + { + SetVisible(!!data.data2); + return; + } + + Base::ProcessStepKey(type, data); +} diff --git a/source/banner/Pane.h b/source/banner/Pane.h new file mode 100644 index 00000000..b0374bfe --- /dev/null +++ b/source/banner/Pane.h @@ -0,0 +1,143 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_PANE_H_ +#define WII_BNR_PANE_H_ + +#include +#include + +#include "Animator.h" + +struct BannerResources; + +class Pane; +typedef std::vector PaneList; + +class Pane : public Animator +{ +public: + typedef Animator Base; + + static const u32 MAGIC = MAKE_FOURCC('p', 'a', 'n', '1'); + + struct Header + { + u32 magic; + u32 size_section; + u8 flags; + u8 origin; + u8 alpha; + u8 padding; + char name [0x10]; + char user_data [0x08]; + Vec3f translate; + Vec3f rotate; + Vec2f scale; + float width; + float height; + } __attribute__((packed)); + + Pane() : header(NULL) {} + virtual ~Pane(); + + void Load(Pane::Header *file); + + const char *getName() const { if(!header) return ""; return header->name; } + + void Render(const BannerResources& resources, u8 parent_alpha, Mtx &modelview, + bool widescreen, bool modify_alpha = false) const; + + void SetFrame(FrameNumber frame, u8 key_set); + + void SetScale(float scale) { if(header) header->scale.x = header->scale.y = scale; } + + bool GetHide() const { return hide; } + void SetHide(bool _hide) { hide = _hide; } + + bool GetVisible() const { if(!header) return false; return ((header->flags & (1 << FLAG_VISIBLE)) != 0); } + void SetVisible(bool visible) + { + if(!header) + return; + + if(visible) + header->flags |= (1 << FLAG_VISIBLE); + else + header->flags &= ~(1 << FLAG_VISIBLE); + } + + u8 GetOriginX() const { return AlignHor; } + u8 GetOriginY() const { return AlignVer; } + + float GetWidth() const { if(!header) return 0.f; return header->width; } + float GetHeight() const { if(!header) return 0.f; return header->height; } + + bool GetInfluencedAlpha() const { if(!header) return false; return ((header->flags & (1 << FLAG_INFLUENCED_ALPHA)) != 0); } + void SetInfluencedAlpha(bool influenced) + { + if(!header) + return; + + if(influenced) + header->flags |= (1 << FLAG_INFLUENCED_ALPHA); + else + header->flags &= ~(1 << FLAG_INFLUENCED_ALPHA); + } + + bool GetWidescren() const { return ((header->flags & (1 << FLAG_WIDESCREEN)) != 0); } + + Pane* FindPane(const std::string& name); // recursive + + PaneList panes; + +protected: + void ProcessHermiteKey(const KeyType& type, float value); + void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); + +private: + virtual void Draw(const BannerResources&, u8, const float, Mtx&) const {} + + enum + { + FLAG_VISIBLE = 0x00, + FLAG_INFLUENCED_ALPHA = 0x01, + FLAG_WIDESCREEN = 0x02 + }; + + Pane::Header *header; + bool hide; // used by the groups + bool RootPane; + u8 AlignVer; + u8 AlignHor; +}; + +// apparently Bounding is just a regular pane +class Bounding : public Pane +{ +public: + static const u32 MAGIC = MAKE_FOURCC('b', 'n', 'd', '1'); +}; + +#endif diff --git a/source/banner/Picture.cpp b/source/banner/Picture.cpp new file mode 100644 index 00000000..1583899b --- /dev/null +++ b/source/banner/Picture.cpp @@ -0,0 +1,34 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "Picture.h" + +void Picture::Load(Pane::Header * file) +{ + if(!file) + return; + + Pane::Load(file); + QuadPane::Load((QuadPane::Header *) (file+1)); +} diff --git a/source/banner/Picture.h b/source/banner/Picture.h new file mode 100644 index 00000000..9c957c2b --- /dev/null +++ b/source/banner/Picture.h @@ -0,0 +1,40 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_PICTURE_H_ +#define WII_BNR_PICTURE_H_ + +#include "QuadPane.h" + +class Picture : public QuadPane +{ +public: + typedef QuadPane Base; + + static const u32 MAGIC = MAKE_FOURCC('p', 'i', 'c', '1'); + + void Load(Pane::Header *hdr); +}; + +#endif diff --git a/source/banner/QuadPane.cpp b/source/banner/QuadPane.cpp new file mode 100644 index 00000000..c8890994 --- /dev/null +++ b/source/banner/QuadPane.cpp @@ -0,0 +1,126 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "QuadPane.h" +#include "Layout.h" + +void QuadPane::Load(QuadPane::Header* file) +{ + if(!file) + return; + + header = file; + tex_coords = (const TexCoords *) (header+1); +} + +inline void QuadPane::SetVertex(int ind, float x, float y, u8 render_alpha) const +{ + // position + GX_Position3f32(x, y, 0.f); + + const GXColor &vertex_color = header->vertex_colors[ind]; + // color + GX_Color4u8(vertex_color.r, vertex_color.g, vertex_color.b, + MultiplyAlpha(vertex_color.a, render_alpha)); + + // texture coord + for(u32 i = 0; i < header->tex_coord_count; i++) + GX_TexCoord2f32(tex_coords[i].coords[ind].s, tex_coords[i].coords[ind].t); +} + +static inline bool IsModulateColor(GXColor *colors, u8 render_alpha) +{ + if(render_alpha != 0xFF) + return true; + + u32 *colorPtr = (u32 *) colors; + + for(int i = 0; i < 4; ++i) + { + if(colorPtr[i] != 0xFFFFFFFF) + return true; + } + + return false; +} + +void QuadPane::Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &modelview, u16 material_index, u8 texture_flip) const +{ + if(!header) + return; + + if (material_index < resources.materials.size()) + { + bool modulate_color = IsModulateColor(header->vertex_colors, render_alpha); + resources.materials[material_index]->Apply(resources, render_alpha, modulate_color); + } + + Mtx m, mv; + guMtxIdentity (m); + + guMtxTransApply(m,m, -0.5f * GetOriginX(), -0.5f * GetOriginY(), 0.f); + guMtxScaleApply(m,m, GetWidth(), GetHeight(), 1.f); + + guMtxConcat (modelview, m, mv); + + GX_LoadPosMtxImm (mv, GX_PNMTX0); + + GX_ClearVtxDesc(); + GX_InvVtxCache(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + for(u32 i = 0; i < header->tex_coord_count; i++) + GX_SetVtxDesc(GX_VA_TEX0+i, GX_DIRECT); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + if(texture_flip) + { + SetVertex(0, 0.f, 0.f, render_alpha); + SetVertex(1, 1.f, 0.f, render_alpha); + SetVertex(3, 1.f, 1.f, render_alpha); + SetVertex(2, 0.f, 1.f, render_alpha); + } + else + { + SetVertex(2, 0.f, 0.f, render_alpha); + SetVertex(3, 1.f, 0.f, render_alpha); + SetVertex(1, 1.f, 1.f, render_alpha); + SetVertex(0, 0.f, 1.f, render_alpha); + } + GX_End(); +} + +void QuadPane::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_VERTEX_COLOR) // vertex color + { + if (type.target < 0x10) + { + // vertex colors + (&header->vertex_colors->r)[type.target] = FLOAT_2_U8(value); + return; + } + } + + Base::ProcessHermiteKey(type, value); +} diff --git a/source/banner/QuadPane.h b/source/banner/QuadPane.h new file mode 100644 index 00000000..c0302449 --- /dev/null +++ b/source/banner/QuadPane.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef _QUAD_PANE_H_ +#define _QUAD_PANE_H_ + +#include "Pane.h" + +// used by Picture and Window +class QuadPane : public Pane +{ +public: + typedef Pane Base; + + struct Header + { + GXColor vertex_colors[4]; + u16 material_index; + u8 tex_coord_count; + u8 pad; + } __attribute__((packed)); + + QuadPane() : header(NULL) {} + void Load(QuadPane::Header *file); + +protected: + void ProcessHermiteKey(const KeyType& type, float value); + //! overload + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view, + u16 material_index, u8 texture_flip) const; + //! main virtual draw function + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const { + Draw(resources, render_alpha, ws_scale, view, header->material_index, 0); + } + +private: + void SetVertex(int ind, float x, float y, u8 render_alpha) const; + + struct TexCoords + { + struct TexCoord + { + float s; + float t; + + } coords[4]; + }; + + QuadPane::Header *header; + const TexCoords *tex_coords; +}; + +#endif diff --git a/source/banner/Textbox.cpp b/source/banner/Textbox.cpp new file mode 100644 index 00000000..2202cc6c --- /dev/null +++ b/source/banner/Textbox.cpp @@ -0,0 +1,280 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "Textbox.h" +#include "Layout.h" + +void Textbox::Load(Pane::Header *file) +{ + if(!file) + return; + + Pane::Load(file); + header = (Textbox::Header *) (file + 1); + text = (const u16 *) (header + 1); + + textAlignVer = (header->text_alignment / 3); + textAlignHor = (header->text_alignment % 3); +} + +void Textbox::SetTextWidth(WiiFont *font) +{ + lineWidths.clear(); + frameWidth = 0.f; + frameHeight = header->font_size; + float currentLine = 0.f; + float scale = header->font_size /(float)font->CharacterHeight(); + + for(const u16 *txtString = text; *txtString != 0; txtString++) + { + if(*txtString == '\n') + { + currentLine *= scale; + lineWidths.push_back(currentLine); + frameWidth = MAX(frameWidth, currentLine); + frameHeight += header->font_size + header->space_line; + currentLine = 0.f; + continue; + } + + const WiiFont::CharInfo *charInfo = font->GetCharInfo(*txtString); + if(!charInfo) + continue; + + if(charInfo->unk) + currentLine += (float) charInfo->advanceKerning; + + currentLine += (float) charInfo->advanceGlyphX; + } + + currentLine *= scale; + lineWidths.push_back(currentLine); + frameWidth = MAX(frameWidth, currentLine); +} + +void Textbox::SetupGX(const BannerResources& resources) const +{ + GX_ClearVtxDesc(); + GX_InvVtxCache(); + + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + // channel control + GX_SetNumChans(1); + GX_SetChanCtrl(GX_COLOR0A0,GX_DISABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHTNULL,GX_DF_NONE,GX_AF_NONE); + + // texture gen. + GX_SetNumTexGens(1); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + // texture environment + GX_SetNumTevStages(1); + GX_SetNumIndStages(0); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); + GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_1_4); + GX_SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_1); + GX_SetTevDirect(GX_TEVSTAGE0); + // swap table + GX_SetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); + GX_SetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); + // alpha compare and blend mode + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET); + + if(header->material_index < resources.materials.size()) + { + const Material::Header *matHead = resources.materials[header->material_index]->GetHeader(); + if(!matHead) + return; + + //GX_SetFog(0, 0.0f, 0.0f, 0.0f, 0.0f, (GXColor){0xff, 0xff, 0xff, 0xff}); + GX_SetTevSwapModeTable(0, 0, 1, 2, 3); + //GX_SetZTexture(0, 0x11, 0); + GX_SetNumChans(1 ); + GX_SetChanCtrl(4, 0, 0, 1, 0, 0, 2); + GX_SetChanCtrl(5, 0, 0, 0, 0, 0, 2); + GX_SetNumTexGens(1); + GX_SetTexCoordGen2(0, 1, 4, 0x3c, 0, 0x7D); + GX_SetNumIndStages(0); + GX_SetBlendMode(1, 4, 5, 0xf); + GX_SetNumTevStages(2); + GX_SetTevDirect(0); + GX_SetTevDirect(1); + GX_SetTevSwapMode(0, 0, 0); + GX_SetTevSwapMode(1, 0, 0); + GX_SetTevOrder(0, 0, 0, 0xff); + + for( int i = 0; i < 2; i++ ) + { + GX_SetTevColor(i + 1, (GXColor){ LIMIT(matHead->color_regs[i].r, 0, 0xFF), + LIMIT(matHead->color_regs[i].g, 0, 0xFF), + LIMIT(matHead->color_regs[i].b, 0, 0xFF), + LIMIT(matHead->color_regs[i].a, 0, 0xFF) }); + } + + GX_SetTevColorIn(0, 2, 4, 8, 0xf); + GX_SetTevAlphaIn(0, 1, 2, 4, 7); + GX_SetTevColorOp(0, 0, 0, 0, 1, 0); + GX_SetTevAlphaOp(0, 0, 0, 0, 1, 0); + GX_SetTevOrder(1, 0xff, 0xff, 4); + GX_SetTevColorIn(1, 0xf, 0, 0xa, 0xf); + GX_SetTevAlphaIn(1, 7, 0, 5, 7); + GX_SetTevColorOp(1, 0, 0, 0, 1, 0); + GX_SetTevAlphaOp(1, 0, 0, 0, 1, 0); + } +} + +void Textbox::Draw(const BannerResources& resources, u8 parent_alpha, const float ws_scale, Mtx &modelview) const +{ + if(!text) + return; + + if(header->font_index >= resources.fonts.size()) + return; + + WiiFont *font = resources.fonts[header->font_index]; + if(!font->IsLoaded()) + return; + + // Ugly...but doing it by going through all panes is more ugly + // TODO: move it to somewhere else + if(lineWidths.empty()) + ((Textbox *) this)->SetTextWidth(font); + + if(lineWidths.empty()) + return; + + SetupGX(resources); + + GX_LoadPosMtxImm(modelview, GX_PNMTX0); + + // Setup text color + GXColor color0 = { header->color[0].r, + header->color[0].g, + header->color[0].b, + MultiplyAlpha(header->color[0].a, parent_alpha) }; + + GXColor color1 = { header->color[1].r, + header->color[1].g, + header->color[1].b, + MultiplyAlpha(header->color[1].a, parent_alpha) }; + + u32 lastSheetIdx = 0xffff; + float scale = header->font_size /(float)font->CharacterHeight(); + + // use complete text width if not aligned to middle + float textWidth = (GetAlignHor() == 1) ? lineWidths[0] : frameWidth; + + // position offset calculation for first line...why the hell is it that complex? + float xPos = -0.5f * ( GetOriginX() * GetWidth() * ws_scale + + GetAlignHor() * (-GetWidth() * ws_scale + textWidth) ); + float yPos = -0.5f * ( GetAlignVer() * -frameHeight + + GetHeight() * (GetAlignVer() - (2 - GetOriginY())) ) + - header->font_size; + + // store the character width here for later use, it's constant over the text + float charWidth = scale * (float)font->CharacterWidth(); + int lineNumber = 0; + + for(const u16 *txtString = text; *txtString != 0; txtString++) + { + if(*txtString == '\n') + { + lineNumber++; + // use complete text width if not aligned to middle + textWidth = (GetAlignHor() == 1) ? lineWidths[lineNumber] : frameWidth; + // calculate text position depending on line width + xPos = -0.5f * (GetOriginX() * GetWidth() * ws_scale + + GetAlignHor() * (-GetWidth() * ws_scale + textWidth)); + // go one line down + yPos -= (header->font_size + header->space_line); + continue; + } + + const WiiFont::CharInfo *charInfo = font->GetCharInfo(*txtString); + if(!charInfo) + continue; + + if(charInfo->sheetIdx != lastSheetIdx) + { + lastSheetIdx = charInfo->sheetIdx; + + if(!font->Apply(charInfo->sheetIdx)) + continue; + } + + if(charInfo->unk) + xPos += scale * (float)charInfo->advanceKerning; + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + + GX_Position3f32(xPos, yPos, 0.f); + GX_Color4u8(color1.r, color1.g, color1.b, color1.a); + GX_TexCoord2f32(charInfo->s1, charInfo->t2); + + GX_Position3f32(xPos + charWidth, yPos, 0.f); + GX_Color4u8(color1.r, color1.g, color1.b, color1.a); + GX_TexCoord2f32(charInfo->s2, charInfo->t2); + + GX_Position3f32(xPos + charWidth, yPos + header->font_size, 0.f); + GX_Color4u8(color0.r, color0.g, color0.b, color0.a); + GX_TexCoord2f32(charInfo->s2, charInfo->t1); + + GX_Position3f32(xPos, yPos + header->font_size, 0.f); + GX_Color4u8(color0.r, color0.g, color0.b, color0.a); + GX_TexCoord2f32(charInfo->s1, charInfo->t1); + + GX_End(); + + xPos += scale * (float)charInfo->advanceGlyphX; + } +} + +void Textbox::ProcessHermiteKey(const KeyType& type, float value) +{ + if (type.type == ANIMATION_TYPE_VERTEX_COLOR) // vertex color + { + if(type.target < 4) + { + (&header->color[0].r)[type.target] = FLOAT_2_U8(value); + return; + } + else if(type.target >= 8 && type.target < 12) + { + (&header->color[1].r)[type.target - 8] = FLOAT_2_U8(value); + return; + } + } + Base::ProcessHermiteKey(type, value); +} + +void Textbox::ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data) +{ + Base::ProcessStepKey(type, data); +} diff --git a/source/banner/Textbox.h b/source/banner/Textbox.h new file mode 100644 index 00000000..96c815f8 --- /dev/null +++ b/source/banner/Textbox.h @@ -0,0 +1,85 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef WII_BNR_TEXTBOX_H_ +#define WII_BNR_TEXTBOX_H_ + +#include "Pane.h" + +class WiiFont; + +class Textbox : public Pane +{ +public: + typedef Pane Base; + + Textbox() : header(NULL), text(NULL), frameWidth(0.f), frameHeight(0.f) + { } + + static const u32 MAGIC = MAKE_FOURCC('t', 'x', 't', '1'); + + void Load(Pane::Header *file); + + u8 GetAlignHor() const { return textAlignHor; } + u8 GetAlignVer() const { return textAlignVer; } + + void SetText(const u16 *t) { text = t; lineWidths.clear(); } + +protected: + void ProcessHermiteKey(const KeyType& type, float value); + void ProcessStepKey(const KeyType& type, StepKeyHandler::KeyData data); + +private: + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const; + void SetupGX(const BannerResources& resources) const; + void SetTextWidth(WiiFont *font); + + struct Header + { + u16 text_buf_bytes; + u16 text_str_bytes; + u16 material_index; + u16 font_index; + u8 text_alignment; + u8 pad1; // ? + u8 pad2[2]; + u32 text_str_offset; + GXColor color[2]; + float font_size; + float height; // seems to work better for offset calculation + float space_char; + float space_line; + } __attribute__((packed)); + + Textbox::Header *header; + const u16 *text; + float frameWidth; + float frameHeight; + u8 textAlignVer; + u8 textAlignHor; + std::vector lineWidths; +}; + +#endif diff --git a/source/banner/WiiFont.cpp b/source/banner/WiiFont.cpp new file mode 100644 index 00000000..c9b4bf6d --- /dev/null +++ b/source/banner/WiiFont.cpp @@ -0,0 +1,387 @@ +/* +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include "WiiFont.h" + +WiiFont::WiiFont() + : header(NULL) + , finf(NULL) + , tglp(NULL) + , cwdh(NULL) + , font_loaded(false) +{ +} + +WiiFont::~WiiFont() +{ + std::map::iterator itr; + + for (itr = textureMap.begin(); itr != textureMap.end(); itr++) + { + if(itr->second.allocated && itr->second.texture_data) + free(itr->second.texture_data); + } +} + +bool WiiFont::Load(const u8 *file) +{ + if(!file) + return false; + + header = (WiiFont::Header *) file; + + if((header->magic != MAGIC_FONT && header->magic != MAGIC_FONT_ARCHIVE) + || header->version != MAGIC_VERSION) + { + header = NULL; + return false; + } + + const u8 *position = ((const u8 *)header) + header->header_len; + + for(u32 i = 0; i < header->section_count; ++i) + { + section_t *section = (section_t *) position; + position += section->size; + + switch( section->magic ) + { + case MAGIC_GLYPH_GROUP: + glgr = (GlgrHeader *) section; + break; + case MAGIC_FONT_INFORMATION: + finf = (FinfHeader *) section; + break; + case MAGIC_TEXTURE_GLYPH: + tglp = (TglpHeader *) section; + break; + case MAGIC_CHARACTER_WIDTH: + cwdh = (CwdhHeader *) section; + break; + case MAGIC_CHARACTER_CODE_MAP: + ParseCmap((CmapEntry *) (section + 1)); + break; + default: + // ignore + gprintf("Uknown section %.4s\n", (char *) §ion->magic); + break; + } + } + + // Some sanity checks + if(!finf || !tglp || !cwdh) + return false; + + if(finf->tglpOffset > header->filesize || finf->cwdhOffset > header->filesize + || finf->cmapOffset > header->filesize) + return false; + + font_loaded = true; + + return true; +} + +inline bool WiiFont::CheckCmap(u16 charCode, u16 mapValue) +{ + std::map::iterator it = cmap.find(charCode); + if(it != cmap.end()) + { + if((*it).second != mapValue) + { + gprintf("Duplicate characters\n"); + return false; + } + } + return true; +} + +bool WiiFont::ParseCmap(CmapEntry *cmapEntry) +{ + if(!cmapEntry) + return false; + + while(true) + { + switch(cmapEntry->type) + { + case 0: + { + for(u16 i = cmapEntry->charCode, j = cmapEntry->start; j < cmapEntry->end; j++, i++) + { + if(!CheckCmap(j, i)) + return false; + cmap[j] = i; + } + break; + } + case 1: + { + u16 idx = 0; + u16 *idxPointer = &cmapEntry->charCode; + for(u32 i = cmapEntry->start; i < cmapEntry->end; i++) + { + u16 m_idx = idxPointer[idx++]; + if(m_idx == 0xffff) + continue; + + if(!CheckCmap(i, m_idx)) + return false; + + cmap[i] = m_idx; + } + break; + } + case 2: + { + u16 ind, character; + u16 *charData = (u16 *) (cmapEntry + 1); + for(u32 i = 0; i < cmapEntry->charCode; i++) + { + character = charData[0]; + ind = charData[1]; + charData += 2; + + if(!CheckCmap(character, ind)) + return false; + + cmap[character] = ind; + } + break; + } + default: + gprintf( "unknown cmap type\n" ); + return false; + } + + if(cmapEntry->pos == 0) + return true; + + cmapEntry = (CmapEntry *)(((u8 *)header) + cmapEntry->pos); + } +} + +const WiiFont::CharInfo *WiiFont::GetCharInfo(u16 charCode) +{ + if(!finf || !tglp || !cwdh) + return NULL; + + // see if the character already exists in our cache + std::map::iterator itr = charInfoMap.find(charCode); + if(itr != charInfoMap.end()) + return &itr->second; + + u16 idx = CharToIdx(charCode); + if(idx > cwdh->endIdx) + { + gprintf( "idx > cwdh->endIdx" ); + return NULL; + } + + Cwdh *cwdh2 = (Cwdh*) (((u8 *)header) + finf->cwdhOffset + 8); + + u32 chars_per_texture = (tglp->charColumns * tglp->charRows); + u32 tex_idx = idx / chars_per_texture; + u32 row = (idx - chars_per_texture * tex_idx) / tglp->charColumns; + u32 col = (idx - chars_per_texture * tex_idx) - ( tglp->charColumns * row ); + + f32 _s1 = ((tglp->cellWidth + 1) * col) / (f32)tglp->width; + f32 _s2 = _s1 + CharacterWidth() / (f32)tglp->width; + + // this is good vertically but horizontal without it it looks clearer + f32 _t1 = ((tglp->cellHeight + 1) * row + 0.5f * (CharacterHeight() - (tglp->cellHeight + 1))) / (f32)tglp->height; + f32 _t2 = _t1 + CharacterHeight() / (f32)tglp->height; + + CharInfo charInfo; + charInfo.sheetIdx = tex_idx; + charInfo.s1 = _s1; + charInfo.s2 = _s2; + charInfo.t1 = _t1; + charInfo.t2 = _t2; + charInfo.advanceGlyphX = cwdh2[idx].advanceGlyphX; + charInfo.unk = cwdh2[idx].unk; + charInfo.advanceKerning = cwdh2[idx].advanceKerning; + + charInfoMap[charCode] = charInfo; + return &charInfoMap[charCode]; +} + +GXTexObj *WiiFont::LoadTextureObj(u16 tex_idx) +{ + if(!font_loaded || tex_idx >= tglp->texCnt) + return NULL; + + // init texture and add it to the list + TextureCache chacheStruct; + + if(header->magic == MAGIC_FONT_ARCHIVE) + { + chacheStruct.texture_data = GetUnpackedTexture(tex_idx); + chacheStruct.allocated = true; + } + else + { + chacheStruct.texture_data = ((u8 *) header) + tglp->dataOffset + tex_idx * tglp->texSize; + chacheStruct.allocated = false; + } + + if(!chacheStruct.texture_data) + return NULL; + + GX_InitTexObj( &chacheStruct.texObj, chacheStruct.texture_data, tglp->width, tglp->height, 0, 0, 0, true ); + GX_InitTexObjLOD( &chacheStruct.texObj, GX_LINEAR,GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_DISABLE, GX_FALSE, GX_ANISO_1 ); + + textureMap[tex_idx] = chacheStruct; + return &textureMap[tex_idx].texObj; +} + +bool WiiFont::Apply(u16 tex_indx) +{ + if(!font_loaded) + return false; + + if(tex_indx >= tglp->texCnt) + return false; + + GXTexObj *tex_obj; + + // Load character texture from cache if available otherwise create cache + std::map::iterator itr = textureMap.find(tex_indx); + if(itr != textureMap.end()) + tex_obj = &itr->second.texObj; + else + tex_obj = LoadTextureObj(tex_indx); + + // no texture for this character found + if(!tex_obj) + return false; + + GX_LoadTexObj(tex_obj, GX_TEXMAP0); + GX_InvalidateTexAll(); + return true; +} + +// giantpunes little magic function +bool WiiFont::Decompress_0x28( unsigned char *outBuf, u32 outLen, const unsigned char *inBuf, u32 inLen ) +{ + if( outLen & 3 )// this copies 32 bits at a time, so it probably needs to be aligned + { + gprintf( "length not aligned to 32 bits\n" ); + return false; + } + const u32 root_offset = 5; + u32 symbol = 0; + u32 counter = 0; + u32 inIdx = 0; + u32 outIdx = 0; + u32 *in32 = (u32*)( ( inBuf + 6 ) + ( ( inBuf[ 4 ] << 1 ) ) ); + u32 *out32 = (u32*)outBuf; + u8 *p = (u8*)inBuf + root_offset; + + outLen >>= 2; //we are copying 4 bytes at a time + while( outLen ) + { + for( u32 i = 0, leaf = p[ 0 ], bits = __builtin_bswap32( in32[ inIdx ] ) + ; i < 0x20 && outLen + ; i++, leaf = p[ 0 ], bits <<= 1 ) + { + u32 topBit = bits >> 31; + u8 d = 2 - ((u64)p & 1); + p += topBit + ( ( leaf << 1 ) & 0x7e ) + d; + + if( !( p > (u8*)inBuf ) && ( p < (u8*)inBuf + inLen ) ) + { + gprintf( "out of range 1\n" ); + return false; + } + + if( ( ( leaf << ( topBit ) ) & ( 1 << 7 ) ) ) // p->isLeaf + { + symbol = ( ( p[ 0 ] << 0x18 ) | ( symbol >> 8 ) ); + p = (u8*)inBuf + root_offset; // p = root + if( counter++ > 2 ) + { + out32[ outIdx++ ] = __builtin_bswap32( symbol );// buf[bufcur++] = p->symbol + counter = 0; // reset counter + outLen--; // decrease amount to copy + } + } + } + if( inIdx++ >= ( inLen >> 2 ) ) + { + gprintf( "out of range 2\n" ); + return false; + } + } + return true; +} + +u8 *WiiFont::GetUnpackedTexture(u16 sheetNo) +{ + u8 *data = (u8 *) header; + u32 compressedSize; + u32 off = 0; + + // skip over all the sheets till we get the one we want + for( u32 i = 0; i < sheetNo; i++ ) + { + compressedSize = *(u32*)( data + tglp->dataOffset + off ); + off += compressedSize + 4; + } + + compressedSize = *(u32*)( data + tglp->dataOffset + off ); + + u32 uncompressedSize = *(u32*)( data + tglp->dataOffset + off + 4 ); + if( (uncompressedSize & 0xff000000) != 0x28000000 )// looks like all the sheets in wbf1 and wbf2.brfna are 0x28 + { + gprintf( "Brfna::LoadSheets(): unknown data type\n" ); + return NULL; + } + uncompressedSize = ( __builtin_bswap32( uncompressedSize ) >> 8 ); + if( !uncompressedSize )// is this right? it looks like it is. but it SHOULD only happen for files over 0xffffff bytes + { + uncompressedSize = __builtin_bswap32(*(u32*)( data + tglp->dataOffset + off + 8 )); + } + if( uncompressedSize != glgr->sheet_size ) + { + gprintf( "uncompressedSize != glgr->sheet_size %08x\n", uncompressedSize ); + return NULL; + } + + // decompress + u8* sheetData = (u8*)memalign( 32, uncompressedSize );// buffer needs to be 32bit aligned + if( !sheetData ) + return NULL; + + if( !Decompress_0x28( sheetData, uncompressedSize, ( data + tglp->dataOffset + off + 4 ), compressedSize ) ) + { + free( sheetData ); + return NULL; + } + + // Flush cache + DCFlushRange(sheetData, uncompressedSize); + + return sheetData; +} diff --git a/source/banner/WiiFont.h b/source/banner/WiiFont.h new file mode 100644 index 00000000..3861c08f --- /dev/null +++ b/source/banner/WiiFont.h @@ -0,0 +1,226 @@ +/* +Copyright (c) 2012 - giantpune +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef __WII_FONT_H_ +#define __WII_FONT_H_ + +#include +#include + +#include "Pane.h" + +class WiiFont +{ +public: + static const u32 MAGIC_FONT = MAKE_FOURCC('R', 'F', 'N', 'T'); + static const u32 MAGIC_FONT_ARCHIVE = MAKE_FOURCC('R', 'F', 'N', 'A'); + static const u32 MAGIC_VERSION = 0xFEFF0104; + static const u32 MAGIC_GLYPH_GROUP = MAKE_FOURCC('G', 'L', 'G', 'R'); + static const u32 MAGIC_FONT_INFORMATION = MAKE_FOURCC('F', 'I', 'N', 'F'); + static const u32 MAGIC_TEXTURE_GLYPH = MAKE_FOURCC('T', 'G', 'L', 'P'); + static const u32 MAGIC_CHARACTER_CODE_MAP = MAKE_FOURCC('C', 'M', 'A', 'P'); + static const u32 MAGIC_CHARACTER_WIDTH = MAKE_FOURCC('C', 'W', 'D', 'H'); + + WiiFont(); + ~WiiFont(); + + // load the file + bool Load(const u8 *file); + + // apply texture, non-const because we load texture on demand + bool Apply(u16 tex_idx); + + // struct to hold info for a character to keep from searching and calculating it all every frame + struct CharInfo + { + u32 sheetIdx; + f32 s1; + f32 t1; + f32 s2; + f32 t2; + s8 advanceKerning; + u8 unk; + s8 advanceGlyphX; + }; + + // get the character information + const CharInfo *GetCharInfo(u16 charCode); + + // check if the font was loaded correctly + bool IsLoaded() const { return font_loaded; } + + // get some parameters from the FINF header + u8 CharacterWidth() const { return finf ? finf->charWidth : 0; } + u8 CharacterHeight() const { return finf ? finf->height : 0; } + + const std::string& getName() const { return name; } + void SetName(const std::string& _name) { name = _name; } + +private: + struct Header + { + u32 magic; + u32 version; + u32 filesize; + u16 header_len; + u16 section_count; + } __attribute__((packed)); + + struct GlgrHeader + { + u32 magic; + u32 sectionSize; + u32 sheet_size; + u16 glyphs_per_sheet; + u16 set_count; + u16 sheet_count; + u16 cwdh_count; + u16 cmap_count; + }__attribute__(( packed )); + + struct FinfHeader + { + u32 magic; + u32 headerSize; // finf size + u8 unk8_1; // font type? + u8 leading; // + u16 defaultChar; + u8 leftMargin; + u8 charWidth; + u8 fullWidth; + u8 encoding; + u32 tglpOffset; // TLGP offset + u32 cwdhOffset; // CWDH offset + u32 cmapOffset; // CMAP offset + u8 height; + u8 width; + u8 ascent; + u8 unk8_10; + } __attribute__(( packed )); + + struct TglpHeader + { + u32 magic; + u32 tglpSize; // TGLP size + + u8 cellWidth; // font width - 1 + u8 cellHeight; // font heigh - 1 + u8 baselinePos; + u8 maxCharWidth; + + u32 texSize; // length of 1 image + + u16 texCnt; // number of images + u16 texType; // + u16 charColumns; // character per row + u16 charRows; // characters per column + u16 width; // width of image + u16 height; // height of image + u32 dataOffset; // data offset + } __attribute__(( packed )); + + struct CwdhHeader + { + u32 magic; + u32 length; // section length? + u16 startIdx; // + u16 endIdx; // + u32 next; // + + } __attribute__(( packed )); + + struct CmapEntry + { + u16 start; + u16 end; + u16 type; + u16 pad; + u32 pos; + u16 charCode; + } __attribute__(( packed )); + + struct Cwdh + { + s8 advanceKerning; + u8 unk; + s8 advanceGlyphX; + } __attribute__(( packed )); + + // font texture decompress functions + static bool Decompress_0x28( unsigned char *outBuf, u32 outLen, const unsigned char *inBuf, u32 inLen ); + u8 *GetUnpackedTexture(u16 sheetNo); + + // load a GX texture from index + GXTexObj *LoadTextureObj(u16 texture_idx); + + // cmap parser + bool ParseCmap(CmapEntry *cmapEntry); + + // just a duplicate check + bool CheckCmap(u16 charCode, u16 mapValue); + + // get index of a character + u16 CharToIdx(u16 charCode) + { + std::map::iterator itr = cmap.find(charCode); + if(itr != cmap.end()) + return itr->second; + + return finf->defaultChar; + } + + WiiFont::Header *header; + + // pointers to each sections + FinfHeader *finf; + TglpHeader *tglp; + CwdhHeader *cwdh; + GlgrHeader *glgr; + + // struct to contain a decompressed texture caches + struct TextureCache + { + u8* texture_data; + bool allocated; + GXTexObj texObj; + }; + std::map textureMap; + + // character info cache map + std::map charInfoMap; + + // holds all the character codes and their index within the font + std::map cmap; + + std::string name; + bool font_loaded; +}; + +class FontList : public std::vector +{ +public: + static const u32 MAGIC = MAKE_FOURCC('f', 'n', 'l', '1'); +}; + +#endif diff --git a/source/banner/Window.cpp b/source/banner/Window.cpp new file mode 100644 index 00000000..d3a89e1e --- /dev/null +++ b/source/banner/Window.cpp @@ -0,0 +1,51 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#include "Window.h" + +void Window::Load(Pane::Header *file) +{ + if(!file) + return; + + const u8 *section_start = (const u8 *)file; + + Pane::Load(file); + header = (Window::Header *) (file+1); + + // read content + QuadPane::Load((QuadPane::Header *)(section_start + header->content_offset)); + + // read frames + const u32 *frame_offsets = (const u32 *) (section_start + header->frame_table_offset); + for(u32 i = 0; i < header->frame_count; i++) + frames.push_back((Frame *) (section_start + frame_offsets[i])); +} + +void Window::Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const +{ + // TODO: handle "inflation" + // TODO: handle "frames" and "texture_flip" + + QuadPane::Draw(resources, render_alpha, ws_scale, view); +} diff --git a/source/banner/Window.h b/source/banner/Window.h new file mode 100644 index 00000000..97880818 --- /dev/null +++ b/source/banner/Window.h @@ -0,0 +1,65 @@ +/* +Copyright (c) 2010 - Wii Banner Player Project +Copyright (c) 2012 - Dimok + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +#ifndef WII_BNR_WINDOW_H_ +#define WII_BNR_WINDOW_H_ + +#include "QuadPane.h" + +class Window : public QuadPane +{ +public: + typedef QuadPane Base; + + static const u32 MAGIC = MAKE_FOURCC('w', 'n', 'd', '1'); + + void Load(Pane::Header *file); + +private: + void Draw(const BannerResources& resources, u8 render_alpha, const float ws_scale, Mtx &view) const; + + struct inflation + { + float l, r, t, b; + }; + + struct Header + { + inflation infl; + u8 frame_count; + u8 pad[3]; + u32 content_offset; + u32 frame_table_offset; + } __attribute__((packed)); + + struct Frame + { + u16 material_index; + u8 texture_flip; + } __attribute__((packed)); + + Header *header; + std::vector frames; +}; + +#endif diff --git a/source/banner/ash.cpp b/source/banner/ash.cpp new file mode 100644 index 00000000..53f099b6 --- /dev/null +++ b/source/banner/ash.cpp @@ -0,0 +1,455 @@ +/**************************************************************************** + * Copyright (C) 2012 giantpune + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include "ash.h" +#include "gecko.h" + +#include +#include +//#include +#include +#include + + + +bool IsAshCompressed( const u8 *stuff, u32 len ) +{ + return ( len > 0x10 && + ((*(u32*)( stuff )) & 0xFFFFFF00 ) == 0x41534800 ); +} + +u8* DecompressAsh( const u8 *stuff, u32 &len ) +{ + if( !IsAshCompressed( stuff, len ) ) + { + return NULL; + } + + unsigned int r[32]; + unsigned int count = 0; + unsigned int t; + + r[4] = (u32)stuff; //in + + r[5] = 0x415348; + r[6] = 0x415348; + + r[5] = s32(*(unsigned int *)(r[4]+4)); + r[5] = r[5] & 0x00FFFFFF; + + u32 size = r[5]; + //gprintf("Decompressed size: %d\n", size); + u8* buf1 = (u8*)memalign( 32, size ); + if( !buf1 ) + { + gprintf( "ASH: no memory\n" ); + return NULL; + } + r[3] = (u32)buf1; //out + memset( (void*)buf1, 0, size ); + //printf("r[3] :%08X\n", r[3]); + + //printf("\n\n"); + + r[24] = 0x10; + r[28] = s32(*(unsigned int *)(r[4]+8)); + r[25] = 0; + r[29] = 0; + r[26] = s32(*(unsigned int *)(r[4]+0xC)); + r[30] = s32(*(unsigned int *)(r[4]+r[28])); + r[28] = r[28] + 4; + //r[8] = 0x8108<<16; + //HACK, pointer to RAM + u8* workingBuffer = (u8*)memalign( 32, 0x100000 ); + if( !workingBuffer ) + { + gprintf( "ASH: no memory 2\n" ); + free( buf1 ); + return NULL; + } + r[8] = (u32)workingBuffer; + memset( (void*)workingBuffer, 0, 0x100000 ); + //printf("r[8] :%08X\n", r[8]); + + r[8] = r[8]; + r[9] = r[8] + 0x07FE; + r[10] = r[9] + 0x07FE; + r[11] = r[10] + 0x1FFE; + r[31] = r[11] + 0x1FFE; + r[23] = 0x200; + r[22] = 0x200; + r[27] = 0; + +loc_81332124: + + if( r[25] != 0x1F ) + goto loc_81332140; + + r[0] = r[26] >> 31; + r[26]= s32(*(unsigned int *)(r[4] + r[24])); + r[25]= 0; + r[24]= r[24] + 4; + goto loc_8133214C; + +loc_81332140: + + r[0] = r[26] >> 31; + r[25]= r[25] + 1; + r[26]= r[26] << 1; + +loc_8133214C: + + if( r[0] == 0 ) + goto loc_81332174; + + r[0] = r[23] | 0x8000; + *(unsigned short *)(r[31]) = s16(r[0]); + r[0] = r[23] | 0x4000; + *(unsigned short *)(r[31]+2) = s16(r[0]); + + r[31] = r[31] + 4; + r[27] = r[27] + 2; + r[23] = r[23] + 1; + r[22] = r[22] + 1; + + goto loc_81332124; + +loc_81332174: + + r[12] = 9; + r[21] = r[25] + r[12]; + t = r[21]; + if( r[21] > 0x20 ) + goto loc_813321AC; + + r[21] = (~(r[12] - 0x20))+1; + r[6] = r[26] >> r[21]; + if( t == 0x20 ) + goto loc_8133219C; + + r[26] = r[26] << r[12]; + r[25] = r[25] + r[12]; + goto loc_813321D0; + +loc_8133219C: + + r[26]= s32(*(unsigned int *)(r[4] + r[24])); + r[25]= 0; + r[24]= r[24] + 4; + goto loc_813321D0; + +loc_813321AC: + + r[0] = (~(r[12] - 0x20))+1; + r[6] = r[26] >> r[0]; + r[26]= s32(*(unsigned int *)(r[4] + r[24])); + r[0] = (~(r[21] - 0x40))+1; + r[24]= r[24] + 4; + r[0] = r[26] >> r[0]; + r[6] = r[6] | r[0]; + r[25] = r[21] - 0x20; + r[26] = r[26] << r[25]; + +loc_813321D0: + + r[12]= s16(*(unsigned short *)(r[31] - 2)); + r[31] -= 2; + r[27]= r[27] - 1; + r[0] = r[12] & 0x8000; + r[12]= (r[12] & 0x1FFF) << 1; + if( r[0] == 0 ) + goto loc_813321F8; + + *(unsigned short *)(r[9]+r[12]) = s16(r[6]); + r[6] = (r[12] & 0x3FFF)>>1; // extrwi %r6, %r12, 14,17 + if( r[27] != 0 ) + goto loc_813321D0; + + goto loc_81332204; + +loc_813321F8: + + *(unsigned short *)(r[8]+r[12]) = s16(r[6]); + r[23] = r[22]; + goto loc_81332124; + +loc_81332204: + + r[23] = 0x800; + r[22] = 0x800; + +loc_8133220C: + + if( r[29] != 0x1F ) + goto loc_81332228; + + r[0] = r[30] >> 31; + r[30]= s32(*(unsigned int *)(r[4] + r[28])); + r[29]= 0; + r[28]= r[28] + 4; + goto loc_81332234; + +loc_81332228: + + r[0] = r[30] >> 31; + r[29]= r[29] + 1; + r[30]= r[30] << 1; + +loc_81332234: + + if( r[0] == 0 ) + goto loc_8133225C; + + r[0] = r[23] | 0x8000; + *(unsigned short *)(r[31]) = s16(r[0]); + r[0] = r[23] | 0x4000; + *(unsigned short *)(r[31]+2) = s16(r[0]); + + r[31] = r[31] + 4; + r[27] = r[27] + 2; + r[23] = r[23] + 1; + r[22] = r[22] + 1; + + goto loc_8133220C; + +loc_8133225C: + + r[12] = 0xB; + r[21] = r[29] + r[12]; + t = r[21]; + if( r[21] > 0x20 ) + goto loc_81332294; + + r[21] = (~(r[12] - 0x20))+1; + r[7] = r[30] >> r[21]; + if( t == 0x20 ) + goto loc_81332284; + + r[30] = r[30] << r[12]; + r[29] = r[29] + r[12]; + goto loc_813322B8; + +loc_81332284: + + r[30]= s32(*(unsigned int *)(r[4] + r[28])); + r[29]= 0; + r[28]= r[28] + 4; + goto loc_813322B8; + +loc_81332294: + + r[0] = (~(r[12] - 0x20))+1; + r[7] = r[30] >> r[0]; + r[30]= s32(*(unsigned int *)(r[4] + r[28])); + r[0] = (~(r[21] - 0x40))+1; + r[28]= r[28] + 4; + r[0] = r[30] >> r[0]; + r[7] = r[7] | r[0]; + r[29]= r[21] - 0x20; + r[30]= r[30] << r[29]; + +loc_813322B8: + + r[12]= s16(*(unsigned short *)(r[31] - 2)); + r[31] -= 2; + r[27]= r[27] - 1; + r[0] = r[12] & 0x8000; + r[12]= (r[12] & 0x1FFF) << 1; + if( r[0] == 0 ) + goto loc_813322E0; + + *(unsigned short *)(r[11]+r[12]) = s16(r[7]); + r[7] = (r[12] & 0x3FFF)>>1; // extrwi %r7, %r12, 14,17 + if( r[27] != 0 ) + goto loc_813322B8; + + goto loc_813322EC; + +loc_813322E0: + + *(unsigned short *)(r[10]+r[12]) = s16(r[7]); + r[23] = r[22]; + goto loc_8133220C; + +loc_813322EC: + + r[0] = r[5]; + +loc_813322F0: + + r[12]= r[6]; + +loc_813322F4: + + if( r[12] < 0x200 ) + goto loc_8133233C; + + if( r[25] != 0x1F ) + goto loc_81332318; + + r[31] = r[26] >> 31; + r[26] = s32(*(unsigned int *)(r[4] + r[24])); + r[24] = r[24] + 4; + r[25] = 0; + goto loc_81332324; + +loc_81332318: + + r[31] = r[26] >> 31; + r[25] = r[25] + 1; + r[26] = r[26] << 1; + +loc_81332324: + + r[27] = r[12] << 1; + if( r[31] != 0 ) + goto loc_81332334; + + r[12] = s16(*(unsigned short *)(r[8] + r[27])); + goto loc_813322F4; + +loc_81332334: + + r[12] = s16(*(unsigned short *)(r[9] + r[27])); + goto loc_813322F4; + +loc_8133233C: + + if( r[12] >= 0x100 ) + goto loc_8133235C; + + *(unsigned char *)(r[3]) = r[12]; + r[3] = r[3] + 1; + r[5] = r[5] - 1; + if( r[5] != 0 ) + goto loc_813322F0; + + goto loc_81332434; + +loc_8133235C: + + r[23] = r[7]; + +loc_81332360: + + if( r[23] < 0x800 ) + goto loc_813323A8; + + if( r[29] != 0x1F ) + goto loc_81332384; + + r[31] = r[30] >> 31; + r[30] = s32(*(unsigned int *)(r[4] + r[28])); + r[28] = r[28] + 4; + r[29] = 0; + goto loc_81332390; + +loc_81332384: + + r[31] = r[30] >> 31; + r[29] = r[29] + 1; + r[30] = r[30] << 1; + +loc_81332390: + + r[27] = r[23] << 1; + if( r[31] != 0 ) + goto loc_813323A0; + + r[23] = s16(*(unsigned short *)(r[10] + r[27])); + goto loc_81332360; + +loc_813323A0: + + r[23] = s16(*(unsigned short *)(r[11] + r[27])); + goto loc_81332360; + +loc_813323A8: + + r[12] = r[12] - 0xFD; + r[23] = ~r[23] + r[3] + 1; + r[5] = ~r[12] + r[5] + 1; + r[31] = r[12] >> 3; + + if( r[31] == 0 ) + goto loc_81332414; + + count = r[31]; + +loc_813323C0: + + r[31] = *(unsigned char *)(r[23] - 1); + *(unsigned char *)(r[3]) = r[31]; + + r[31] = *(unsigned char *)(r[23]); + *(unsigned char *)(r[3]+1) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 1); + *(unsigned char *)(r[3]+2) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 2); + *(unsigned char *)(r[3]+3) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 3); + *(unsigned char *)(r[3]+4) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 4); + *(unsigned char *)(r[3]+5) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 5); + *(unsigned char *)(r[3]+6) = r[31]; + + r[31] = *(unsigned char *)(r[23] + 6); + *(unsigned char *)(r[3]+7) = r[31]; + + r[23] = r[23] + 8; + r[3] = r[3] + 8; + + if( --count ) + goto loc_813323C0; + + r[12] = r[12] & 7; + if( r[12] == 0 ) + goto loc_8133242C; + +loc_81332414: + + count = r[12]; + +loc_81332418: + + r[31] = *(unsigned char *)(r[23] - 1); + r[23] = r[23] + 1; + *(unsigned char *)(r[3]) = r[31]; + r[3] = r[3] + 1; + + if( --count ) + goto loc_81332418; + +loc_8133242C: + + if( r[5] != 0 ) + goto loc_813322F0; + +loc_81332434: + + r[3] = r[0]; + len = r[3]; + + //gprintf("Decompressed %d bytes\n", r[3]); + free( workingBuffer ); + return buf1; +} diff --git a/source/banner/ash.h b/source/banner/ash.h new file mode 100644 index 00000000..43614c64 --- /dev/null +++ b/source/banner/ash.h @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (C) 2012 giantpune + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef ASH_H +#define ASH_H + +#include + +// check if data is ash compressed +bool IsAshCompressed( const u8 *stuff, u32 len ); + +// decompress ash compressed data +//! len is the size of the compressed data, and is set to the size of the decompressed data +//! this allocates memory with memalign, free it when you are done with it + +u8* DecompressAsh( const u8 *stuff, u32 &len ); +#endif // ASH_H diff --git a/source/banner/gx_addons.c b/source/banner/gx_addons.c new file mode 100644 index 00000000..ce7402ae --- /dev/null +++ b/source/banner/gx_addons.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include + +void GX_Project(f32 mx, f32 my, f32 mz, Mtx mv, const f32 *projection, + const f32 *viewport, f32 *sx, f32 *sy, f32 *sz) +{ + float x, y, z, w; + + guVector vec = (guVector) { mx, my, mz }; + guVector vecRes; + guVecMultiply(mv, &vec, &vecRes); + + if(projection[0] == GX_PERSPECTIVE) + { + x = (vecRes.x * projection[1]) + (vecRes.z * projection[2]); + y = (vecRes.y * projection[3]) + (vecRes.z * projection[4]); + z = (vecRes.z * projection[5]) + projection[6]; + w = -1.0f / vecRes.z; + } + else + { + x = (vecRes.x * projection[1]) + projection[2]; + y = (vecRes.y * projection[3]) + projection[4]; + z = (vecRes.z * projection[5]) + projection[6]; + w = 1.0f; + } + + *sx = viewport[0] + (w * x * viewport[2] + viewport[2]) * 0.5f; + *sy = viewport[1] - (w * y * viewport[3] - viewport[3]) * 0.5f; + *sz = viewport[5] + (w * z * (viewport[5] - viewport[4])); +} + +void GX_GetProjectionv( f32* ptr, Mtx44 p, u8 type) +{ + ptr[0] = (f32)type; + ptr[1] = p[0][0]; + ptr[3] = p[1][1]; + ptr[5] = p[2][2]; + ptr[6] = p[2][3]; + + if(type == GX_PERSPECTIVE) + { + ptr[2] = p[0][2]; + ptr[4] = p[1][2]; + } + else + { + ptr[2] = p[0][3]; + ptr[4] = p[1][3]; + } +} + +void GX_GetViewportv( f32* ptr, GXRModeObj *vmode ) +{ + ptr[0] = 0.0f; + ptr[1] = 0.0f; + ptr[2] = vmode->fbWidth; + ptr[3] = vmode->efbHeight; + ptr[4] = 0.0f; + ptr[5] = 1.0f; +} diff --git a/source/banner/gx_addons.h b/source/banner/gx_addons.h new file mode 100644 index 00000000..89afbf3a --- /dev/null +++ b/source/banner/gx_addons.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * Copyright (C) 2012 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef GX_ADDONS_H_ +#define GX_ADDONS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void GX_Project(f32 mx, f32 my, f32 mz, Mtx mv, const f32 *projection, + const f32 *viewport, f32 *sx, f32 *sy, f32 *sz); +void GX_GetProjectionv( f32* ptr, Mtx44 p, u8 type); +void GX_GetViewportv( f32* ptr, GXRModeObj *vmode ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/channel/lz77.c b/source/channel/lz77.c index d477480e..457b86eb 100644 --- a/source/channel/lz77.c +++ b/source/channel/lz77.c @@ -45,7 +45,7 @@ s32 __decompressLZ77_11(u8 *in, u32 inputLen, u8 **output, u32 *outputLen) compressedPos += 0x4; } - printf("Decompressed size : %i\n", decompressedSize); + //printf("Decompressed size : %i\n", decompressedSize); out = MEM2_alloc(ALIGN32(decompressedSize)); if (out == NULL) @@ -132,7 +132,7 @@ s32 __decompressLZ77_10(u8 *in, u8 **output, u32 *outputLen) //int compressionType = (packBytes(in[0], in[1], in[2], in[3]) >> 4) & 0xF; - printf("Decompressed size : %i\n", decompressedSize); + //printf("Decompressed size : %i\n", decompressedSize); out = MEM2_alloc(ALIGN32(decompressedSize)); if (out == NULL) @@ -200,15 +200,15 @@ int decompressLZ77content(u8 *buffer, u32 length, u8 **output, u32 *outputLen) switch (buffer[0]) { case LZ77_0x10_FLAG: - printf("LZ77 variant 0x10 compressed content...unpacking may take a while...\n"); + //printf("LZ77 variant 0x10 compressed content...unpacking may take a while...\n"); ret = __decompressLZ77_10(buffer, output, outputLen); break; case LZ77_0x11_FLAG: - printf("LZ77 variant 0x11 compressed content...unpacking may take a while...\n"); + //printf("LZ77 variant 0x11 compressed content...unpacking may take a while...\n"); ret = __decompressLZ77_11(buffer, length, output, outputLen); break; default: - printf("Not compressed ...\n"); + //printf("Not compressed ...\n"); ret = -1; break; } diff --git a/source/fonts.h b/source/fonts.h index b712d90a..ffaad867 100644 --- a/source/fonts.h +++ b/source/fonts.h @@ -5,6 +5,7 @@ #define WIIFONT_NAME_KOR "Wii-kr_Round Gothic B.ttf" const u8 WIIFONT_HASH[] = {0x32, 0xb3, 0x39, 0xcb, 0xbb, 0x50, 0x7d, 0x50, 0x27, 0x79, 0x25, 0x9a, 0x78, 0x66, 0x99, 0x5d, 0x03, 0x0b, 0x1d, 0x88}; const u8 WIIFONT_HASH_KOR[] = {0xb7, 0x15, 0x6d, 0xf0, 0xf4, 0xae, 0x07, 0x8f, 0xd1, 0x53, 0x58, 0x3e, 0x93, 0x6e, 0x07, 0xc0, 0x98, 0x77, 0x49, 0x0e}; +const u8 WFB_HASH[] = { 0x4f, 0xad, 0x97, 0xfd, 0x4a, 0x28, 0x8c, 0x47, 0xe0, 0x58, 0x7f, 0x3b, 0xbd, 0x29, 0x23, 0x79, 0xf8, 0x70, 0x9e, 0xb9 }; #define FONT_BOLD 36u #define FONT_NOBOLD 8u diff --git a/source/gui/video.cpp b/source/gui/video.cpp index c1cd35f5..aba49656 100644 --- a/source/gui/video.cpp +++ b/source/gui/video.cpp @@ -169,6 +169,10 @@ void CVideo::init(void) 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); _clearScreen(); VIDEO_SetBlack(FALSE); VIDEO_Flush(); diff --git a/source/gui/video.hpp b/source/gui/video.hpp index 74d547ce..c1b560f1 100644 --- a/source/gui/video.hpp +++ b/source/gui/video.hpp @@ -58,6 +58,7 @@ public: void setup2DProjection(bool setViewPort = true, bool noScale = false); u32 width(void) const { return m_rmode->fbWidth; } u32 height(void) const { return m_rmode->efbHeight; } + GXRModeObj *vid_mode(void) const { return m_rmode; } u32 width2D(void) { return m_width2D; } u32 height2D(void) { return m_height2D; } bool wide(void) const { return m_wide; } diff --git a/source/menu/menu.cpp b/source/menu/menu.cpp index 3e2f1ac2..4a808d82 100644 --- a/source/menu/menu.cpp +++ b/source/menu/menu.cpp @@ -25,6 +25,7 @@ #include "gc/fileOps.h" #include "Gekko.h" #include "GameTDB.hpp" +#include "BannerWindow.hpp" // Sounds extern const u8 click_wav[]; @@ -109,6 +110,10 @@ extern const u8 butzhcnoffs_png[]; extern const u8 checkbox_png[]; extern const u8 checkboxs_png[]; +SmartBuf m_wbf1_font; +SmartBuf m_wbf2_font; +BannerWindow m_banner; + CMenu::CMenu(CVideo &vid) : m_vid(vid) { @@ -472,7 +477,7 @@ void CMenu::cleanup(bool ios_reload) m_cf.stopCoverLoader(); m_cf.clear(); ClearGameSoundThreadStack(); - + m_banner.DeleteBanner(); m_plugin.Cleanup(); _stopSounds(); @@ -1758,11 +1763,12 @@ void CMenu::_mainLoopCommon(bool withCF, bool blockReboot, bool adjusting) } m_fa.draw(); + if(m_banner.GetSelectedGame()) + m_banner.Draw(); m_btnMgr.draw(); ScanInput(); - m_vid.setup2DProjection(); m_vid.render(); if(!blockReboot) { @@ -2324,12 +2330,10 @@ retry: u8 *u8_font_archive = ISFS_GetFile((u8 *) u8_font_filename, &size, 0); //gprintf("Opened fontfile: %s: %d bytes\n", u8_font_filename, size); - if (u8_font_archive != NULL) + if(u8_font_archive != NULL) { const u8 *font_file = u8_get_file_by_index(u8_font_archive, 1, &size); // There is only one file in that app - //gprintf("Extracted font: %d\n", size); - m_base_font = smartMem2Alloc(size); memcpy(m_base_font.get(), font_file, size); if(!!m_base_font) @@ -2338,6 +2342,26 @@ retry: } break; } + else if(memcmp(cm[i].sha1, WFB_HASH, 20) == 0) + { + // Name found, load it and unpack it + char font_filename[32] ATTRIBUTE_ALIGN(32); + strcpy(font_filename, "/shared1/XXXXXXXX.app"); // Faster than sprintf + memcpy(font_filename+9, cm[i].filename, 8); + u8 *u8_font_archive = ISFS_GetFile((u8 *)font_filename, &size, 0); + if(u8_font_archive != NULL) + { + const u8 *font_file1 = u8_get_file(u8_font_archive, "wbf1.brfna", &size); + m_wbf1_font = smartMem2Alloc(size); + memcpy(m_wbf1_font.get(), font_file1, size); + + const u8 *font_file2 = u8_get_file(u8_font_archive, "wbf2.brfna", &size); + m_wbf2_font = smartMem2Alloc(size); + memcpy(m_wbf2_font.get(), font_file2, size); + + MEM2_free(u8_font_archive); + } + } } if (!retry) @@ -2353,6 +2377,9 @@ void CMenu::_cleanupDefaultFont() { m_base_font.release(); m_base_font_size = 0; + + m_wbf1_font.release(); + m_wbf2_font.release(); } const char *CMenu::_domainFromView() diff --git a/source/menu/menu.hpp b/source/menu/menu.hpp index 30ed1384..caa6bd8f 100644 --- a/source/menu/menu.hpp +++ b/source/menu/menu.hpp @@ -73,7 +73,6 @@ private: Config m_titles; Config m_version; Plugin m_plugin; - Channels m_channels; vector m_homebrewArgs; SmartBuf m_base_font; u32 m_base_font_size; @@ -147,10 +146,6 @@ private: STexture m_gameBgLQ; STexture m_mainBgLQ; STexture m_categoryBg; - // - u32 m_errorLblMessage; - u32 m_errorLblIcon; - u32 m_errorLblUser[4]; //Main Coverflow u32 m_mainBtnConfig; u32 m_mainBtnInfo; @@ -677,7 +672,7 @@ private: lwp_t m_gameSoundThread; bool m_gamesound_changed; u8 m_bnrSndVol; - + bool m_video_playing; private: diff --git a/source/menu/menu_config4.cpp b/source/menu/menu_config4.cpp index cf96e102..5f3fcf05 100644 --- a/source/menu/menu_config4.cpp +++ b/source/menu/menu_config4.cpp @@ -16,6 +16,8 @@ static inline int loopNum(int i, int s) int currentChannelIndex = -1; int amountOfChannels = -1; +Channels m_channels; + const CMenu::SOption CMenu::_exitTo[6] = { { "def", L"Default" }, { "menu", L"System Menu" }, diff --git a/source/menu/menu_error.cpp b/source/menu/menu_error.cpp index 09ff35b8..6934f352 100644 --- a/source/menu/menu_error.cpp +++ b/source/menu/menu_error.cpp @@ -3,6 +3,9 @@ #include "gecko.h" extern const u8 error_png[]; +u32 m_errorLblMessage; +u32 m_errorLblIcon; +u32 m_errorLblUser[4]; void CMenu::error(const wstringEx &msg) { diff --git a/source/menu/menu_game.cpp b/source/menu/menu_game.cpp index ddc28e86..6ea17409 100644 --- a/source/menu/menu_game.cpp +++ b/source/menu/menu_game.cpp @@ -17,6 +17,7 @@ #include "wip.h" #include "channel_launcher.h" #include "devicemounter/sdhc.h" +#include "BannerWindow.hpp" #include #include @@ -57,6 +58,8 @@ extern u32 sector_size; extern int mainIOS; static u64 sm_title_id[8] ATTRIBUTE_ALIGN(32); +bool m_zoom_banner; + const string CMenu::_translations[23] = { "Default", "Arab", @@ -359,17 +362,19 @@ void CMenu::_game(bool launch) m_gameSelected = true; } + extern BannerWindow m_banner; + string id(m_cf.getId()); s8 startGameSound = 1; while(true) { if(startGameSound < 1) startGameSound++; - string id(m_cf.getId()); u64 chantitle = m_cf.getChanTitle(); if(startGameSound == -5) { + id = m_cf.getId(); _playGameSound(); _showGame(); } @@ -392,6 +397,7 @@ void CMenu::_game(bool launch) m_gameSound.FreeMemory(); CheckGameSoundThread(); ClearGameSoundThreadStack(); + m_banner.DeleteBanner(); break; } else if(BTN_PLUS_PRESSED && m_GameTDBLoaded && (m_cf.getHdr()->type == TYPE_WII_GAME || m_cf.getHdr()->type == TYPE_GC_GAME || m_cf.getHdr()->type == TYPE_CHANNEL)) @@ -466,9 +472,19 @@ void CMenu::_game(bool launch) m_gcfg1.setBool("ADULTONLY", id, !m_gcfg1.getBool("ADULTONLY", id, false)); else if(m_btnMgr.selected(m_gameBtnBack)) { - m_gameSound.Stop(); - CheckGameSoundThread(); - break; + //m_gameSound.Stop(); + //CheckGameSoundThread(); + //break; + if(m_zoom_banner) + { + m_banner.ZoomOut(); + m_zoom_banner = false; + } + else + { + m_banner.ZoomIn(); + m_zoom_banner = true; + } } else if(m_btnMgr.selected(m_gameBtnSettings)) { @@ -1425,6 +1441,8 @@ void CMenu::_initGameMenu(CMenu::SThemeData &theme) _setHideAnim(m_gameBtnDelete, "GAME/DELETE_BTN", 0, 0, -1.5f, -1.5f); _hideGame(true); _textGame(); + + m_zoom_banner = false; } void CMenu::_textGame(void) @@ -1476,7 +1494,12 @@ void CMenu::_gameSoundThread(CMenu *m) } _extractBannerTitle(banner, GetLanguage(m->m_loc.getString(m->m_curLanguage, "gametdb_code", "EN").c_str())); + extern SmartBuf m_wbf1_font; + extern SmartBuf m_wbf2_font; + extern BannerWindow m_banner; + const u8 *soundBin = banner->GetFile((char *) "sound.bin", &sndSize); + m_banner.LoadBanner(banner, &m->m_vid, m_wbf1_font.get(), m_wbf2_font.get()); delete banner; if (soundBin == NULL || (((IMD5Header *)soundBin)->fcc != 'IMD5' && ((IMD5Header *)soundBin)->fcc != 'RIFF')) diff --git a/source/music/gui_sound.cpp b/source/music/gui_sound.cpp index 2b6c0db1..034d206e 100644 --- a/source/music/gui_sound.cpp +++ b/source/music/gui_sound.cpp @@ -480,7 +480,7 @@ void GuiSound::UncompressSoundbin(const u8 * snd, u32 len, bool isallocated) if(isallocated) { void *p = (void *)snd; - MEM1_free(p); + free(p); } allocated = true;