AGS: Configurable font init mode, for backward compatibility

From upstream 9a11a1d4334aef99b8b516a13d5a5bcc0284fde7
This commit is contained in:
Paul Gilbert 2022-03-23 19:50:16 -07:00
parent 7f3ea3074f
commit ca4c91031b
5 changed files with 43 additions and 36 deletions

View File

@ -258,10 +258,10 @@ HError InitAndRegisterGameEntities() {
return HError::None(); return HError::None();
} }
void LoadFonts(GameDataVersion data_ver) { void LoadFonts(GameSetupStruct &game, GameDataVersion data_ver) {
for (int i = 0; i < _GP(game).numfonts; ++i) { for (int i = 0; i < _GP(game).numfonts; ++i) {
FontInfo &finfo = _GP(game).fonts[i]; FontInfo &finfo = _GP(game).fonts[i];
if (!wloadfont_size(i, finfo)) if (!load_font_size(i, finfo, game.options[OPT_FONTLOADLOGIC]))
quitprintf("Unable to load font %d, no renderer could load a matching file", i); quitprintf("Unable to load font %d, no renderer could load a matching file", i);
const bool is_wfn = is_bitmap_font(i); const bool is_wfn = is_bitmap_font(i);
@ -299,14 +299,12 @@ void LoadFonts(GameDataVersion data_ver) {
if (finfo.LineSpacing == 0) { if (finfo.LineSpacing == 0) {
set_font_linespacing(i, height + 2 * finfo.AutoOutlineThickness); set_font_linespacing(i, height + 2 * finfo.AutoOutlineThickness);
// WORKAROUND: For qfg2vga at least, fInfo.SizePt == 0, which causes below // Backward compatibility: if the real font's height != formal height
// to screw up line spacing. Since by the current upstream HEAD this has all // and there's no custom linespacing, then set linespacing = formal height.
// been replaced anyway, for now I'm adding an explicit 0 check if ((game.options[OPT_FONTLOADLOGIC] & FONT_LOAD_REPORTREALHEIGHT) == 0) {
if (finfo.SizePt != 0) {
// Backward compatibility: if the real font's height != formal height
// and there's no custom linespacing, then set linespacing = formal height.
const int compat_height = finfo.SizePt * finfo.SizeMultiplier; const int compat_height = finfo.SizePt * finfo.SizeMultiplier;
if (height != compat_height) { // WORKAROUND: Don't replace if no height
if (compat_height != 0 && height != compat_height) {
set_font_linespacing(i, compat_height + 2 * finfo.AutoOutlineThickness); set_font_linespacing(i, compat_height + 2 * finfo.AutoOutlineThickness);
} }
} }
@ -355,8 +353,9 @@ void AllocScriptModules() {
} }
HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion data_ver) { HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion data_ver) {
const ScriptAPIVersion base_api = (ScriptAPIVersion)_GP(game).options[OPT_BASESCRIPTAPI]; GameSetupStruct &game = ents.Game;
const ScriptAPIVersion compat_api = (ScriptAPIVersion)_GP(game).options[OPT_SCRIPTCOMPATLEV]; const ScriptAPIVersion base_api = (ScriptAPIVersion)game.options[OPT_BASESCRIPTAPI];
const ScriptAPIVersion compat_api = (ScriptAPIVersion)game.options[OPT_SCRIPTCOMPATLEV];
if (data_ver >= kGameVersion_341) { if (data_ver >= kGameVersion_341) {
const char *base_api_name = GetScriptAPIName(base_api); const char *base_api_name = GetScriptAPIName(base_api);
const char *compat_api_name = GetScriptAPIName(compat_api); const char *compat_api_name = GetScriptAPIName(compat_api);
@ -366,42 +365,43 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
} }
// If the game was compiled using unsupported version of the script API, // If the game was compiled using unsupported version of the script API,
// we warn about potential incompatibilities but proceed further. // we warn about potential incompatibilities but proceed further.
if (_GP(game).options[OPT_BASESCRIPTAPI] > kScriptAPI_Current) if (game.options[OPT_BASESCRIPTAPI] > kScriptAPI_Current)
_G(platform)->DisplayAlert("Warning: this game requests a higher version of AGS script API, it may not run correctly or run at all."); _G(platform)->DisplayAlert("Warning: this game requests a higher version of AGS script API, it may not run correctly or run at all.");
// //
// 1. Check that the loaded data is valid and compatible with the current // 1. Check that the loaded data is valid and compatible with the current
// engine capabilities. // engine capabilities.
// //
if (_GP(game).numfonts == 0) if (game.numfonts == 0)
return new GameInitError(kGameInitErr_NoFonts); return new GameInitError(kGameInitErr_NoFonts);
if (_GP(game).audioClipTypes.size() > MAX_AUDIO_TYPES) if (game.audioClipTypes.size() > MAX_AUDIO_TYPES)
return new GameInitError(kGameInitErr_TooManyAudioTypes, return new GameInitError(kGameInitErr_TooManyAudioTypes,
String::FromFormat("Required: %zu, max: %zu", _GP(game).audioClipTypes.size(), MAX_AUDIO_TYPES)); String::FromFormat("Required: %zu, max: %zu", game.audioClipTypes.size(), MAX_AUDIO_TYPES));
// //
// 3. Allocate and init game objects // 3. Allocate and init game objects
// //
_G(charextra) = (CharacterExtras *)calloc(_GP(game).numcharacters, sizeof(CharacterExtras)); _G(charextra) = (CharacterExtras *)calloc(game.numcharacters, sizeof(CharacterExtras));
_G(charcache) = (CharacterCache *)calloc(1, sizeof(CharacterCache) * _GP(game).numcharacters + 5); _G(charcache) = (CharacterCache *)calloc(1, sizeof(CharacterCache) * game.numcharacters + 5);
_G(mls) = (MoveList *)calloc(_GP(game).numcharacters + MAX_ROOM_OBJECTS + 1, sizeof(MoveList)); _G(mls) = (MoveList *)calloc(game.numcharacters + MAX_ROOM_OBJECTS + 1, sizeof(MoveList));
init_game_drawdata(); init_game_drawdata();
_GP(views) = std::move(ents.Views); _GP(views) = std::move(ents.Views);
_GP(play).charProps.resize(_GP(game).numcharacters); _GP(play).charProps.resize(game.numcharacters);
_G(old_dialog_scripts) = ents.OldDialogScripts; _G(old_dialog_scripts) = ents.OldDialogScripts;
_G(old_speech_lines) = ents.OldSpeechLines; _G(old_speech_lines) = ents.OldSpeechLines;
// Set number of game channels corresponding to the loaded game version // Set number of game channels corresponding to the loaded game version
if (_G(loaded_game_file_version) < kGameVersion_360) if (_G(loaded_game_file_version) < kGameVersion_360)
_GP(game).numGameChannels = MAX_GAME_CHANNELS_v320; game.numGameChannels = MAX_GAME_CHANNELS_v320;
else else
_GP(game).numGameChannels = MAX_GAME_CHANNELS; game.numGameChannels = MAX_GAME_CHANNELS;
HError err = InitAndRegisterGameEntities(); HError err = InitAndRegisterGameEntities();
if (!err) if (!err)
return new GameInitError(kGameInitErr_EntityInitFail, err); return new GameInitError(kGameInitErr_EntityInitFail, err);
LoadFonts(data_ver); LoadFonts(game, data_ver);
LoadLipsyncData();
// //
// 4. Initialize certain runtime variables // 4. Initialize certain runtime variables
@ -410,12 +410,12 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
_G(ifacepopped) = -1; _G(ifacepopped) = -1;
String svg_suffix; String svg_suffix;
if (_GP(game).saveGameFileExtension[0] != 0) if (game.saveGameFileExtension[0] != 0)
svg_suffix.Format(".%s", _GP(game).saveGameFileExtension); svg_suffix.Format(".%s", game.saveGameFileExtension);
set_save_game_suffix(svg_suffix); set_save_game_suffix(svg_suffix);
_GP(play).score_sound = _GP(game).scoreClipID; _GP(play).score_sound = game.scoreClipID;
_GP(play).fade_effect = _GP(game).options[OPT_FADETYPE]; _GP(play).fade_effect = game.options[OPT_FADETYPE];
// //
// 5. Initialize runtime state of certain game objects // 5. Initialize runtime state of certain game objects
@ -424,7 +424,7 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
// labels are not clickable by default // labels are not clickable by default
_GP(guilabels)[i].SetClickable(false); _GP(guilabels)[i].SetClickable(false);
} }
_GP(play).gui_draw_order = (int32_t *)calloc(_GP(game).numgui * sizeof(int), 1); _GP(play).gui_draw_order = (int32_t *)calloc(game.numgui * sizeof(int), 1);
update_gui_zorder(); update_gui_zorder();
calculate_reserved_channel_count(); calculate_reserved_channel_count();

View File

@ -744,7 +744,7 @@ void IAGSEngine::BreakIntoDebugger() {
} }
IAGSFontRenderer *IAGSEngine::ReplaceFontRenderer(int fontNumber, IAGSFontRenderer *newRenderer) { IAGSFontRenderer *IAGSEngine::ReplaceFontRenderer(int fontNumber, IAGSFontRenderer *newRenderer) {
auto *old_render = font_replace_renderer(fontNumber, newRenderer); auto *old_render = font_replace_renderer(fontNumber, newRenderer, _GP(game).options[OPT_FONTLOADLOGIC]);
GUI::MarkForFontUpdate(fontNumber); GUI::MarkForFontUpdate(fontNumber);
return old_render; return old_render;
} }

View File

@ -85,6 +85,7 @@ namespace AGS3 {
#define OPT_RENDERATSCREENRES 45 // scale sprites at the (final) screen resolution #define OPT_RENDERATSCREENRES 45 // scale sprites at the (final) screen resolution
#define OPT_RELATIVEASSETRES 46 // relative asset resolution mode (where sprites are resized to match game type) #define OPT_RELATIVEASSETRES 46 // relative asset resolution mode (where sprites are resized to match game type)
#define OPT_WALKSPEEDABSOLUTE 47 // if movement speeds are independent of walkable mask resolution #define OPT_WALKSPEEDABSOLUTE 47 // if movement speeds are independent of walkable mask resolution
#define OPT_FONTLOADLOGIC 48 // fonts load/init logic, see FONT_LOAD_xxx flags
#define OPT_HIGHESTOPTION OPT_WALKSPEEDABSOLUTE #define OPT_HIGHESTOPTION OPT_WALKSPEEDABSOLUTE
#define OPT_NOMODMUSIC 98 #define OPT_NOMODMUSIC 98
#define OPT_LIPSYNCTEXT 99 #define OPT_LIPSYNCTEXT 99

View File

@ -73,7 +73,7 @@ bool is_font_loaded(size_t fontNumber) {
} }
// Finish font's initialization // Finish font's initialization
static void post_init_font(size_t fontNumber) { static void post_init_font(size_t fontNumber, int load_mode) {
Font &font = _GP(fonts)[fontNumber]; Font &font = _GP(fonts)[fontNumber];
if (font.Metrics.Height == 0) { if (font.Metrics.Height == 0) {
// There is no explicit method for getting maximal possible height of any // There is no explicit method for getting maximal possible height of any
@ -85,19 +85,20 @@ static void post_init_font(size_t fontNumber) {
font.Metrics.Height = height; font.Metrics.Height = height;
font.Metrics.RealHeight = height; font.Metrics.RealHeight = height;
} }
font.Metrics.CompatHeight = font.Metrics.Height; font.Metrics.CompatHeight = (load_mode & FONT_LOAD_REPORTREALHEIGHT) == 0 ?
font.Metrics.Height : font.Metrics.RealHeight;
if (font.Info.Outline != FONT_OUTLINE_AUTO) { if (font.Info.Outline != FONT_OUTLINE_AUTO) {
font.Info.AutoOutlineThickness = 0; font.Info.AutoOutlineThickness = 0;
} }
} }
IAGSFontRenderer *font_replace_renderer(size_t fontNumber, IAGSFontRenderer *renderer) { IAGSFontRenderer *font_replace_renderer(size_t fontNumber, IAGSFontRenderer *renderer, int load_mode) {
if (fontNumber >= _GP(fonts).size()) if (fontNumber >= _GP(fonts).size())
return nullptr; return nullptr;
IAGSFontRenderer *oldRender = _GP(fonts)[fontNumber].Renderer; IAGSFontRenderer *oldRender = _GP(fonts)[fontNumber].Renderer;
_GP(fonts)[fontNumber].Renderer = renderer; _GP(fonts)[fontNumber].Renderer = renderer;
_GP(fonts)[fontNumber].Renderer2 = nullptr; _GP(fonts)[fontNumber].Renderer2 = nullptr;
post_init_font(fontNumber); post_init_font(fontNumber, load_mode);
return oldRender; return oldRender;
} }
@ -350,7 +351,7 @@ FontInfo get_fontinfo(size_t font_number) {
} }
// Loads a font from disk // Loads a font from disk
bool wloadfont_size(size_t fontNumber, const FontInfo &font_info) { bool load_font_size(size_t fontNumber, const FontInfo &font_info, int load_mode) {
if (_GP(fonts).size() <= fontNumber) if (_GP(fonts).size() <= fontNumber)
_GP(fonts).resize(fontNumber + 1); _GP(fonts).resize(fontNumber + 1);
else else
@ -372,7 +373,7 @@ bool wloadfont_size(size_t fontNumber, const FontInfo &font_info) {
_GP(fonts)[fontNumber].Info = font_info; _GP(fonts)[fontNumber].Info = font_info;
_GP(fonts)[fontNumber].Metrics = metrics; _GP(fonts)[fontNumber].Metrics = metrics;
post_init_font(fontNumber); post_init_font(fontNumber, load_mode);
return true; return true;
} }

View File

@ -31,6 +31,11 @@
namespace AGS3 { namespace AGS3 {
// Font load flags, primarily for backward compatibility
// REPORTREALHEIGHT: get_font_height should return real font's height,
// otherwise returns formal height, equal to "font size" parameter
#define FONT_LOAD_REPORTREALHEIGHT 0x01
class IAGSFontRenderer; class IAGSFontRenderer;
class IAGSFontRenderer2; class IAGSFontRenderer2;
struct FontInfo; struct FontInfo;
@ -66,7 +71,7 @@ struct FontRenderParams;
void init_font_renderer(); void init_font_renderer();
void shutdown_font_renderer(); void shutdown_font_renderer();
void adjust_y_coordinate_for_text(int *ypos, size_t fontnum); void adjust_y_coordinate_for_text(int *ypos, size_t fontnum);
IAGSFontRenderer *font_replace_renderer(size_t fontNumber, IAGSFontRenderer *renderer); IAGSFontRenderer *font_replace_renderer(size_t fontNumber, IAGSFontRenderer *renderer, int load_mode);
bool font_first_renderer_loaded(); bool font_first_renderer_loaded();
bool is_font_loaded(size_t fontNumber); bool is_font_loaded(size_t fontNumber);
bool is_bitmap_font(size_t fontNumber); bool is_bitmap_font(size_t fontNumber);
@ -115,7 +120,7 @@ void set_fontinfo(size_t fontNumber, const FontInfo &finfo);
// Gets full information about the font // Gets full information about the font
FontInfo get_fontinfo(size_t font_number); FontInfo get_fontinfo(size_t font_number);
// Loads a font from disk // Loads a font from disk
bool wloadfont_size(size_t fontNumber, const FontInfo &font_info); bool load_font_size(size_t fontNumber, const FontInfo &font_info, int load_mode);
void wgtprintf(Shared::Bitmap *ds, int xxx, int yyy, size_t fontNumber, color_t text_color, char *fmt, ...); void wgtprintf(Shared::Bitmap *ds, int xxx, int yyy, size_t fontNumber, color_t text_color, char *fmt, ...);
// Allocates two outline stencil buffers, or returns previously creates ones; // Allocates two outline stencil buffers, or returns previously creates ones;
// these buffers are owned by the font, they should not be deleted by the caller. // these buffers are owned by the font, they should not be deleted by the caller.