Skip to content

Commit

Permalink
Episode background images
Browse files Browse the repository at this point in the history
  • Loading branch information
deathkiller committed Dec 10, 2023
1 parent e0c76d4 commit d25cede
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 28 deletions.
41 changes: 30 additions & 11 deletions Sources/Jazz2/Compatibility/JJ2Episode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ using namespace Death::IO;
namespace Jazz2::Compatibility
{
JJ2Episode::JJ2Episode()
: Position(0), TitleWidth(0), TitleHeight(0)
: Position(0), ImageWidth(0), ImageHeight(0), TitleWidth(0), TitleHeight(0)
{
}

JJ2Episode::JJ2Episode(const String& name, const String& displayName, const String& firstLevel, int32_t position)
: Name(name), DisplayName(displayName), FirstLevel(firstLevel), Position(position), TitleWidth(0), TitleHeight(0)
: Name(name), DisplayName(displayName), FirstLevel(firstLevel), Position(position), ImageWidth(0), ImageHeight(0), TitleWidth(0), TitleHeight(0)
{
}

Expand Down Expand Up @@ -79,8 +79,8 @@ namespace Jazz2::Compatibility
FirstLevel = String(tmpBuffer, length);
lowercaseInPlace(FirstLevel);

/*int32_t width =*/ s->ReadValue<int32_t>();
/*int32_t height =*/ s->ReadValue<int32_t>();
ImageWidth = s->ReadValue<int32_t>();
ImageHeight = s->ReadValue<int32_t>();
/*int32_t unknown2 =*/ s->ReadValue<int32_t>();
/*int32_t unknown3 =*/ s->ReadValue<int32_t>();

Expand All @@ -89,15 +89,16 @@ namespace Jazz2::Compatibility
/*int32_t unknown4 =*/ s->ReadValue<int32_t>();
/*int32_t unknown5 =*/ s->ReadValue<int32_t>();

// Background image
{
int32_t imagePackedSize = s->ReadValue<int32_t>();
//int imageUnpackedSize = width * height;
//JJ2Block imageBlock(s, imagePackedSize, imageUnpackedSize);
//episode.image = ConvertIndicesToRgbaBitmap(width, height, imageBlock, false);

// Skip it for now
s->Seek(imagePackedSize, SeekOrigin::Current);
int imageUnpackedSize = ImageWidth * ImageHeight;
JJ2Block imageBlock(s, imagePackedSize, imageUnpackedSize);
ImageData = std::make_unique<uint8_t[]>(imageUnpackedSize);
imageBlock.ReadRawBytes(ImageData.get(), imageUnpackedSize);
}

// Title image
{
int32_t titleLightPackedSize = s->ReadValue<int32_t>();
int32_t titleLightUnpackedSize = TitleWidth * TitleHeight;
Expand Down Expand Up @@ -176,7 +177,7 @@ namespace Jazz2::Compatibility
so->WriteValue<uint8_t>(0);
}

// Write episode logo
// Write episode title image
so->WriteValue<uint16_t>((uint16_t)TitleWidth);
so->WriteValue<uint16_t>((uint16_t)TitleHeight);

Expand All @@ -198,5 +199,23 @@ namespace Jazz2::Compatibility
}

JJ2Anims::WriteImageToFileInternal(so, titlePixels.get(), TitleWidth, TitleHeight, 4);

// Write episode background image
so->WriteValue<uint16_t>((uint16_t)ImageWidth);
so->WriteValue<uint16_t>((uint16_t)ImageHeight);

uint32_t imagePixelsCount = ImageWidth * ImageHeight;
std::unique_ptr<uint8_t[]> imagePixels = std::make_unique<uint8_t[]>(imagePixelsCount * 4);
for (uint32_t i = 0; i < imagePixelsCount; i++) {
uint8_t colorIdx = ImageData[i];

const Color& src = MenuPalette[colorIdx];
imagePixels[i * 4] = src.R;
imagePixels[i * 4 + 1] = src.G;
imagePixels[i * 4 + 2] = src.B;
imagePixels[i * 4 + 3] = src.A;
}

JJ2Anims::WriteImageToFileInternal(so, imagePixels.get(), ImageWidth, ImageHeight, 4);
}
}
5 changes: 5 additions & 0 deletions Sources/Jazz2/Compatibility/JJ2Episode.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ namespace Jazz2::Compatibility
String FirstLevel;
String PreviousEpisode;
String NextEpisode;

int32_t ImageWidth;
int32_t ImageHeight;
std::unique_ptr<uint8_t[]> ImageData;

int32_t TitleWidth;
int32_t TitleHeight;
std::unique_ptr<uint8_t[]> TitleData;
Expand Down
28 changes: 20 additions & 8 deletions Sources/Jazz2/ContentResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,16 +1229,16 @@ namespace Jazz2
}
}

std::optional<Episode> ContentResolver::GetEpisode(const StringView& name, bool withLogo)
std::optional<Episode> ContentResolver::GetEpisode(const StringView& name, bool withImages)
{
String fullPath = fs::CombinePath({ GetContentPath(), "Episodes"_s, name + ".j2e"_s });
if (!fs::IsReadableFile(fullPath)) {
fullPath = fs::CombinePath({ GetCachePath(), "Episodes"_s, name + ".j2e"_s });
}
return GetEpisodeByPath(fullPath);
return GetEpisodeByPath(fullPath, withImages);
}

std::optional<Episode> ContentResolver::GetEpisodeByPath(const StringView& path, bool withLogo)
std::optional<Episode> ContentResolver::GetEpisodeByPath(const StringView& path, bool withImages)
{
auto s = fs::Open(path, FileAccessMode::Read);
if (s->GetSize() < 16) {
Expand Down Expand Up @@ -1274,17 +1274,29 @@ namespace Jazz2
episode.NextEpisode = String(NoInit, nameLength);
s->Read(episode.NextEpisode.data(), nameLength);

if (withLogo && !_isHeadless) {
if (withImages && !_isHeadless) {
std::uint16_t titleWidth = s->ReadValue<std::uint16_t>();
std::uint16_t titleHeight = s->ReadValue<std::uint16_t>();
if (titleWidth > 0 && titleHeight > 0) {
std::unique_ptr<std::uint32_t[]> pixels = std::make_unique<std::uint32_t[]>(titleWidth * titleHeight);
ReadImageFromFile(s, (std::uint8_t*)pixels.get(), titleWidth, titleHeight, 4);

episode.TitleLogo = std::make_unique<Texture>(path.data(), Texture::Format::RGBA8, titleWidth, titleHeight);
episode.TitleLogo->loadFromTexels((unsigned char*)pixels.get(), 0, 0, titleWidth, titleHeight);
episode.TitleLogo->setMinFiltering(SamplerFilter::Nearest);
episode.TitleLogo->setMagFiltering(SamplerFilter::Nearest);
episode.TitleImage = std::make_unique<Texture>(path.data(), Texture::Format::RGBA8, titleWidth, titleHeight);
episode.TitleImage->loadFromTexels((unsigned char*)pixels.get(), 0, 0, titleWidth, titleHeight);
episode.TitleImage->setMinFiltering(SamplerFilter::Nearest);
episode.TitleImage->setMagFiltering(SamplerFilter::Nearest);
}

std::uint16_t backgroundWidth = s->ReadValue<std::uint16_t>();
std::uint16_t backgroundHeight = s->ReadValue<std::uint16_t>();
if (backgroundWidth > 0 && backgroundHeight > 0) {
std::unique_ptr<std::uint32_t[]> pixels = std::make_unique<std::uint32_t[]>(backgroundWidth * backgroundHeight);
ReadImageFromFile(s, (std::uint8_t*)pixels.get(), backgroundWidth, backgroundHeight, 4);

episode.BackgroundImage = std::make_unique<Texture>(path.data(), Texture::Format::RGBA8, backgroundWidth, backgroundHeight);
episode.BackgroundImage->loadFromTexels((unsigned char*)pixels.get(), 0, 0, backgroundWidth, backgroundHeight);
episode.BackgroundImage->setMinFiltering(SamplerFilter::Nearest);
episode.BackgroundImage->setMagFiltering(SamplerFilter::Nearest);
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/Jazz2/ContentResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ namespace Jazz2
bool TryLoadLevel(const StringView& path, GameDifficulty difficulty, LevelDescriptor& descriptor);
void ApplyDefaultPalette();

std::optional<Episode> GetEpisode(const StringView& name, bool withLogo = false);
std::optional<Episode> GetEpisodeByPath(const StringView& path, bool withLogo = false);
std::optional<Episode> GetEpisode(const StringView& name, bool withImages = false);
std::optional<Episode> GetEpisodeByPath(const StringView& path, bool withImages = false);
std::unique_ptr<AudioStreamPlayer> GetMusic(const StringView& path);
UI::Font* GetFont(FontType fontType);
Shader* GetShader(PrecompiledShader shader);
Expand Down
3 changes: 2 additions & 1 deletion Sources/Jazz2/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ namespace Jazz2
String PreviousEpisode;
String NextEpisode;
std::uint16_t Position;
std::unique_ptr<Texture> TitleLogo;
std::unique_ptr<Texture> TitleImage;
std::unique_ptr<Texture> BackgroundImage;

Episode() noexcept;
};
Expand Down
2 changes: 1 addition & 1 deletion Sources/Jazz2/Scripting/ScriptLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ namespace Jazz2::Scripting
if (!currentNamespace.empty()) {
currentNamespace += "::"_s;
}
currentClass = currentNamespace.slice(pos, pos + len);
currentNamespace += scriptContent.slice(pos, pos + len);

// Search until first { is encountered
while (pos < scriptSize) {
Expand Down
45 changes: 40 additions & 5 deletions Sources/Jazz2/UI/Menu/EpisodeSelectSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ namespace Jazz2::UI::Menu
float expandedAnimation2 = std::min(_expandedAnimation * 6.0f, 1.0f);
float expandedAnimation3 = (expandedAnimation2 * expandedAnimation2 * (3.0f - 2.0f * expandedAnimation2));

if (item.Item.Description.TitleLogo != nullptr) {
Vector2i titleSize = item.Item.Description.TitleLogo->size() / 2;
_root->DrawTexture(*item.Item.Description.TitleLogo, centerX, item.Y + 2.2f, IMenuContainer::FontLayer + 9, Alignment::Center, Vector2f(titleSize.X, titleSize.Y) * size * (1.0f - expandedAnimation3 * 0.2f) * 1.02f, Colorf(0.0f, 0.0f, 0.0f, 0.26f - expandedAnimation3 * 0.1f));
_root->DrawTexture(*item.Item.Description.TitleLogo, centerX, item.Y, IMenuContainer::FontLayer + 10, Alignment::Center, Vector2f(titleSize.X, titleSize.Y) * size * (1.0f - expandedAnimation3 * 0.2f), Colorf(1.0f, 1.0f, 1.0f, 1.0f - expandedAnimation3 * 0.4f));
if (item.Item.Description.TitleImage != nullptr) {
Vector2i titleSize = item.Item.Description.TitleImage->size() / 2;
_root->DrawTexture(*item.Item.Description.TitleImage, centerX, item.Y + 2.2f, IMenuContainer::FontLayer + 8, Alignment::Center, Vector2f(titleSize.X, titleSize.Y) * size * (1.0f - expandedAnimation3 * 0.2f) * 1.02f, Colorf(0.0f, 0.0f, 0.0f, 0.26f - expandedAnimation3 * 0.1f));
float alpha = 1.0f - expandedAnimation3 * 0.4f;
_root->DrawTexture(*item.Item.Description.TitleImage, centerX, item.Y, IMenuContainer::FontLayer + 10, Alignment::Center, Vector2f(titleSize.X, titleSize.Y) * size * (1.0f - expandedAnimation3 * 0.2f), Colorf(alpha, alpha, alpha, 1.0f));
} else {
_root->DrawElement(MenuGlow, 0, centerX, item.Y, IMenuContainer::MainLayer, Alignment::Center, Colorf(1.0f, 1.0f, 1.0f, 0.4f * size), (Utf8::GetLength(item.Item.Description.DisplayName) + 3) * 0.5f * size, 4.0f * size, true);

Expand Down Expand Up @@ -216,12 +217,46 @@ namespace Jazz2::UI::Menu

if ((item.Item.Flags & (EpisodeDataFlags::IsCompleted | EpisodeDataFlags::IsAvailable)) == (EpisodeDataFlags::IsCompleted | EpisodeDataFlags::IsAvailable)) {
float size = (isSelected ? 0.5f + IMenuContainer::EaseOutElastic(_animation) * 0.6f : 0.7f);
float expandX = centerX - (item.Item.Description.DisplayName.size() + 3) * 4.0f * (isSelected ? size : 1.1f) + 10.0f;
float textWidth = item.Item.Description.DisplayName.size() + 3;
if (isSelected) {
if (item.Item.Description.Name == "prince"_s || item.Item.Description.Name == "share"_s) {
// "Formerly a Prince" & "Shareware Demo" title image is too narrow, so try to adjust it a bit
textWidth *= 0.8f;
} else if (item.Item.Description.Name == "flash"_s) {
// "Flashback" title image is too wide, so try to adjust it a bit
textWidth *= 1.5f;
}
}
float expandedAnimation2 = std::min(_expandedAnimation * 6.0f, 1.0f);
float expandX = centerX - textWidth * 4.0f * (isSelected ? (size - (expandedAnimation2 * 0.12f)) : 1.1f) + 10.0f;
_root->DrawElement(EpisodeComplete, 0, expandX, item.Y - 2.0f, IMenuContainer::MainLayer + (isSelected ? 20 : 10), Alignment::Right,
((item.Item.Flags & EpisodeDataFlags::CheatsUsed) == EpisodeDataFlags::CheatsUsed ? Colorf::Black : Colorf::White), size, size);
}
}

void EpisodeSelectSection::OnDrawClipped(Canvas* canvas)
{
if (!_items.empty()) {
auto& item = _items[_selectedIndex];
if (item.Item.Description.BackgroundImage != nullptr) {
Vector2f center = Vector2f(canvas->ViewSize.X * 0.5f, canvas->ViewSize.Y * 0.7f);
Vector2i backgroundSize = item.Item.Description.BackgroundImage->size();

float expandedAnimation2 = std::min(_expandedAnimation * 6.0f, 1.0f);
float expandedAnimation3 = (expandedAnimation2 * expandedAnimation2 * (3.0f - 2.0f * expandedAnimation2));
if (expandedAnimation3 > 0.0f) {
backgroundSize += expandedAnimation3 * 100;
}

_root->DrawSolid(center.X, center.Y, IMenuContainer::BackgroundLayer - 10, Alignment::Center, Vector2f(backgroundSize.X + 2.0f, backgroundSize.Y + 2.0f), Colorf(1.0f, 1.0f, 1.0f, 0.26f));
float alpha = 0.4f - expandedAnimation3 * 0.1f;
_root->DrawTexture(*item.Item.Description.BackgroundImage, center.X, center.Y, IMenuContainer::BackgroundLayer, Alignment::Center, Vector2f(backgroundSize.X, backgroundSize.Y), Colorf(alpha, alpha, alpha, 1.0f));
}
}

ScrollableMenuSection::OnDrawClipped(canvas);
}

void EpisodeSelectSection::OnDrawOverlay(Canvas* canvas)
{
if (_shouldStart) {
Expand Down
1 change: 1 addition & 0 deletions Sources/Jazz2/UI/Menu/EpisodeSelectSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Jazz2::UI::Menu

void OnUpdate(float timeMult) override;
void OnDraw(Canvas* canvas) override;
void OnDrawClipped(Canvas* canvas) override;
void OnDrawOverlay(Canvas* canvas) override;
void OnTouchEvent(const TouchEvent& event, const Vector2i& viewSize) override;

Expand Down

0 comments on commit d25cede

Please sign in to comment.