You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
6.4 KiB
257 lines
6.4 KiB
|
7 years ago
|
#include <algorithm>
|
||
|
|
#include <memory>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
5 years ago
|
#include "control.h"
|
||
|
7 years ago
|
#include "controls/menu_controls.h"
|
||
|
7 years ago
|
#include "DiabloUI/art_draw.h"
|
||
|
5 years ago
|
#include "DiabloUI/art.h"
|
||
|
|
#include "DiabloUI/credits_lines.h"
|
||
|
|
#include "DiabloUI/diabloui.h"
|
||
|
7 years ago
|
#include "DiabloUI/fonts.h"
|
||
|
5 years ago
|
#include "DiabloUI/support_lines.h"
|
||
|
5 years ago
|
#include "utils/display.h"
|
||
|
|
#include "utils/sdl_compat.h"
|
||
|
|
#include "utils/sdl_ptrs.h"
|
||
|
7 years ago
|
|
||
|
5 years ago
|
namespace devilution {
|
||
|
7 years ago
|
|
||
|
7 years ago
|
namespace {
|
||
|
|
|
||
|
6 years ago
|
const SDL_Rect VIEWPORT = { 0, 114, 640, 251 };
|
||
|
6 years ago
|
const int SHADOW_OFFSET_X = 2;
|
||
|
|
const int SHADOW_OFFSET_Y = 2;
|
||
|
|
const int LINE_H = 22;
|
||
|
7 years ago
|
|
||
|
5 years ago
|
char const *const *text;
|
||
|
|
std::size_t textLines;
|
||
|
|
|
||
|
6 years ago
|
// The maximum number of visible lines is the number of whole lines
|
||
|
|
// (VIEWPORT.h / LINE_H) rounded up, plus one extra line for when
|
||
|
|
// a line is leaving the screen while another one is entering.
|
||
|
|
#define MAX_VISIBLE_LINES ((VIEWPORT.h - 1) / LINE_H + 2)
|
||
|
|
|
||
|
6 years ago
|
struct CachedLine {
|
||
|
|
|
||
|
|
CachedLine()
|
||
|
7 years ago
|
{
|
||
|
6 years ago
|
m_index = 0;
|
||
|
|
palette_version = pal_surface_palette_version;
|
||
|
7 years ago
|
}
|
||
|
7 years ago
|
|
||
|
5 years ago
|
CachedLine(std::size_t index, SDLSurfaceUniquePtr surface)
|
||
|
7 years ago
|
{
|
||
|
6 years ago
|
m_index = index;
|
||
|
5 years ago
|
m_surface = std::move(surface);
|
||
|
6 years ago
|
palette_version = pal_surface_palette_version;
|
||
|
7 years ago
|
}
|
||
|
|
|
||
|
6 years ago
|
std::size_t m_index;
|
||
|
5 years ago
|
SDLSurfaceUniquePtr m_surface;
|
||
|
6 years ago
|
unsigned int palette_version;
|
||
|
7 years ago
|
};
|
||
|
|
|
||
|
6 years ago
|
SDL_Surface *RenderText(const char *text, SDL_Color color)
|
||
|
7 years ago
|
{
|
||
|
7 years ago
|
if (text[0] == '\0')
|
||
|
6 years ago
|
return NULL;
|
||
|
7 years ago
|
SDL_Surface *result = TTF_RenderUTF8_Solid(font, text, color);
|
||
|
6 years ago
|
if (result == NULL)
|
||
|
5 years ago
|
SDL_Log("%s", TTF_GetError());
|
||
|
6 years ago
|
return result;
|
||
|
7 years ago
|
}
|
||
|
|
|
||
|
7 years ago
|
CachedLine PrepareLine(std::size_t index)
|
||
|
7 years ago
|
{
|
||
|
5 years ago
|
const char *contents = text[index];
|
||
|
6 years ago
|
while (contents[0] == '\t')
|
||
|
7 years ago
|
++contents;
|
||
|
7 years ago
|
|
||
|
|
const SDL_Color shadow_color = { 0, 0, 0, 0 };
|
||
|
5 years ago
|
SDLSurfaceUniquePtr text { RenderText(contents, shadow_color) };
|
||
|
7 years ago
|
|
||
|
|
// Precompose shadow and text:
|
||
|
5 years ago
|
SDLSurfaceUniquePtr surface;
|
||
|
|
if (text != nullptr) {
|
||
|
7 years ago
|
// Set up the target surface to have 3 colors: mask, text, and shadow.
|
||
|
5 years ago
|
surface = SDLSurfaceUniquePtr { SDL_CreateRGBSurfaceWithFormat(0, text->w + SHADOW_OFFSET_X, text->h + SHADOW_OFFSET_Y, 8, SDL_PIXELFORMAT_INDEX8) };
|
||
|
6 years ago
|
const SDL_Color mask_color = { 0, 255, 0, 0 }; // Any color different from both shadow and text
|
||
|
7 years ago
|
const SDL_Color &text_color = palette->colors[224];
|
||
|
|
SDL_Color colors[3] = { mask_color, text_color, shadow_color };
|
||
|
5 years ago
|
if (SDLC_SetSurfaceColors(surface.get(), colors, 0, 3) <= -1)
|
||
|
5 years ago
|
SDL_Log("%s", SDL_GetError());
|
||
|
5 years ago
|
SDLC_SetColorKey(surface.get(), 0);
|
||
|
7 years ago
|
|
||
|
|
// Blit the shadow first:
|
||
|
|
SDL_Rect shadow_rect = { SHADOW_OFFSET_X, SHADOW_OFFSET_Y, 0, 0 };
|
||
|
5 years ago
|
if (SDL_BlitSurface(text.get(), NULL, surface.get(), &shadow_rect) <= -1)
|
||
|
7 years ago
|
ErrSdl();
|
||
|
7 years ago
|
|
||
|
|
// Change the text surface color and blit again:
|
||
|
|
SDL_Color text_colors[2] = { mask_color, text_color };
|
||
|
5 years ago
|
if (SDLC_SetSurfaceColors(text.get(), text_colors, 0, 2) <= -1)
|
||
|
7 years ago
|
ErrSdl();
|
||
|
5 years ago
|
SDLC_SetColorKey(text.get(), 0);
|
||
|
7 years ago
|
|
||
|
5 years ago
|
if (SDL_BlitSurface(text.get(), NULL, surface.get(), NULL) <= -1)
|
||
|
7 years ago
|
ErrSdl();
|
||
|
6 years ago
|
|
||
|
5 years ago
|
surface = ScaleSurfaceToOutput(std::move(surface));
|
||
|
7 years ago
|
}
|
||
|
5 years ago
|
return CachedLine(index, std::move(surface));
|
||
|
7 years ago
|
}
|
||
|
|
|
||
|
7 years ago
|
class CreditsRenderer {
|
||
|
|
|
||
|
|
public:
|
||
|
|
CreditsRenderer()
|
||
|
|
{
|
||
|
|
LoadTtfFont();
|
||
|
|
ticks_begin_ = SDL_GetTicks();
|
||
|
6 years ago
|
prev_offset_y_ = 0;
|
||
|
|
finished_ = false;
|
||
|
7 years ago
|
}
|
||
|
|
|
||
|
|
~CreditsRenderer()
|
||
|
|
{
|
||
|
5 years ago
|
ArtBackgroundWidescreen.Unload();
|
||
|
7 years ago
|
ArtBackground.Unload();
|
||
|
|
UnloadTtfFont();
|
||
|
5 years ago
|
lines_.clear();
|
||
|
7 years ago
|
}
|
||
|
|
|
||
|
|
void Render();
|
||
|
|
|
||
|
|
bool Finished() const
|
||
|
|
{
|
||
|
|
return finished_;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
6 years ago
|
std::vector<CachedLine> lines_;
|
||
|
7 years ago
|
bool finished_;
|
||
|
6 years ago
|
Uint32 ticks_begin_;
|
||
|
7 years ago
|
int prev_offset_y_;
|
||
|
|
};
|
||
|
|
|
||
|
|
void CreditsRenderer::Render()
|
||
|
7 years ago
|
{
|
||
|
6 years ago
|
const int offset_y = -VIEWPORT.h + (SDL_GetTicks() - ticks_begin_) / 40;
|
||
|
7 years ago
|
if (offset_y == prev_offset_y_)
|
||
|
|
return;
|
||
|
|
prev_offset_y_ = offset_y;
|
||
|
7 years ago
|
|
||
|
5 years ago
|
SDL_FillRect(DiabloUiSurface(), NULL, 0x000000);
|
||
|
5 years ago
|
DrawArt(PANEL_LEFT - 320, UI_OFFSET_Y, &ArtBackgroundWidescreen);
|
||
|
6 years ago
|
DrawArt(PANEL_LEFT, UI_OFFSET_Y, &ArtBackground);
|
||
|
6 years ago
|
if (font == NULL)
|
||
|
7 years ago
|
return;
|
||
|
|
|
||
|
|
const std::size_t lines_begin = std::max(offset_y / LINE_H, 0);
|
||
|
5 years ago
|
const std::size_t lines_end = std::min(lines_begin + MAX_VISIBLE_LINES, textLines);
|
||
|
7 years ago
|
|
||
|
|
if (lines_begin >= lines_end) {
|
||
|
5 years ago
|
if (lines_end == textLines)
|
||
|
7 years ago
|
finished_ = true;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
6 years ago
|
while (lines_end > lines_.size())
|
||
|
|
lines_.push_back(PrepareLine(lines_.size()));
|
||
|
7 years ago
|
|
||
|
6 years ago
|
SDL_Rect viewport = VIEWPORT;
|
||
|
6 years ago
|
viewport.x += PANEL_LEFT;
|
||
|
|
viewport.y += UI_OFFSET_Y;
|
||
|
6 years ago
|
ScaleOutputRect(&viewport);
|
||
|
5 years ago
|
SDL_SetClipRect(DiabloUiSurface(), &viewport);
|
||
|
6 years ago
|
|
||
|
|
// We use unscaled coordinates for calculation throughout.
|
||
|
6 years ago
|
Sint16 dest_y = UI_OFFSET_Y + VIEWPORT.y - (offset_y - lines_begin * LINE_H);
|
||
|
6 years ago
|
for (std::size_t i = lines_begin; i < lines_end; ++i, dest_y += LINE_H) {
|
||
|
6 years ago
|
CachedLine &line = lines_[i];
|
||
|
5 years ago
|
if (line.m_surface == nullptr)
|
||
|
7 years ago
|
continue;
|
||
|
|
|
||
|
|
// Still fading in: the cached line was drawn with a different fade level.
|
||
|
6 years ago
|
if (line.palette_version != pal_surface_palette_version) {
|
||
|
6 years ago
|
line = PrepareLine(line.m_index);
|
||
|
6 years ago
|
}
|
||
|
7 years ago
|
|
||
|
6 years ago
|
Sint16 dest_x = PANEL_LEFT + VIEWPORT.x + 31;
|
||
|
6 years ago
|
int j = 0;
|
||
|
5 years ago
|
while (text[line.m_index][j++] == '\t')
|
||
|
7 years ago
|
dest_x += 40;
|
||
|
|
|
||
|
6 years ago
|
SDL_Rect dst_rect = { dest_x, dest_y, 0, 0 };
|
||
|
|
ScaleOutputRect(&dst_rect);
|
||
|
6 years ago
|
dst_rect.w = line.m_surface->w;
|
||
|
|
dst_rect.h = line.m_surface->h;
|
||
|
5 years ago
|
if (SDL_BlitSurface(line.m_surface.get(), NULL, DiabloUiSurface(), &dst_rect) < 0)
|
||
|
6 years ago
|
ErrSdl();
|
||
|
7 years ago
|
}
|
||
|
5 years ago
|
SDL_SetClipRect(DiabloUiSurface(), NULL);
|
||
|
7 years ago
|
}
|
||
|
|
|
||
|
5 years ago
|
bool TextDialog()
|
||
|
7 years ago
|
{
|
||
|
|
CreditsRenderer credits_renderer;
|
||
|
7 years ago
|
bool endMenu = false;
|
||
|
|
|
||
|
|
SDL_Event event;
|
||
|
7 years ago
|
do {
|
||
|
|
credits_renderer.Render();
|
||
|
7 years ago
|
UiFadeIn();
|
||
|
|
while (SDL_PollEvent(&event)) {
|
||
|
|
switch (event.type) {
|
||
|
|
case SDL_KEYDOWN:
|
||
|
|
case SDL_MOUSEBUTTONDOWN:
|
||
|
|
endMenu = true;
|
||
|
|
break;
|
||
|
7 years ago
|
default:
|
||
|
|
switch (GetMenuAction(event)) {
|
||
|
6 years ago
|
case MenuAction_BACK:
|
||
|
|
case MenuAction_SELECT:
|
||
|
7 years ago
|
endMenu = true;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
7 years ago
|
}
|
||
|
6 years ago
|
UiHandleEvents(&event);
|
||
|
7 years ago
|
}
|
||
|
7 years ago
|
} while (!endMenu && !credits_renderer.Finished());
|
||
|
7 years ago
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
5 years ago
|
} // namespace
|
||
|
|
|
||
|
5 years ago
|
bool UiCreditsDialog()
|
||
|
5 years ago
|
{
|
||
|
|
text = CREDITS_LINES;
|
||
|
|
textLines = CREDITS_LINES_SIZE;
|
||
|
|
|
||
|
|
LoadArt("ui_art\\creditsw.pcx", &ArtBackgroundWidescreen);
|
||
|
|
LoadBackgroundArt("ui_art\\credits.pcx");
|
||
|
|
|
||
|
|
return TextDialog();
|
||
|
|
}
|
||
|
|
|
||
|
5 years ago
|
bool UiSupportDialog()
|
||
|
5 years ago
|
{
|
||
|
|
text = SUPPORT_LINES;
|
||
|
|
textLines = SUPPORT_LINES_SIZE;
|
||
|
|
|
||
|
|
if (gbIsHellfire) {
|
||
|
|
LoadArt("ui_art\\supportw.pcx", &ArtBackgroundWidescreen);
|
||
|
|
LoadBackgroundArt("ui_art\\support.pcx");
|
||
|
|
} else {
|
||
|
|
LoadArt("ui_art\\creditsw.pcx", &ArtBackgroundWidescreen);
|
||
|
|
LoadBackgroundArt("ui_art\\credits.pcx");
|
||
|
|
}
|
||
|
|
|
||
|
|
return TextDialog();
|
||
|
|
}
|
||
|
|
|
||
|
5 years ago
|
} // namespace devilution
|