tron@2186: /* $Id$ */ tron@2186: rubidium@9111: /** @file texteff.cpp Handling of text effects. */ belugas@6422: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" maedhros@6453: #include "landscape.h" rubidium@8225: #include "gfx_func.h" tron@2153: #include "variables.h" truelight@6998: #include "texteff.hpp" rubidium@9898: #include "core/bitmath_func.hpp" belugas@7849: #include "transparency.h" rubidium@8114: #include "strings_func.h" rubidium@8130: #include "core/alloc_func.hpp" rubidium@8131: #include "functions.h" rubidium@8225: #include "viewport_func.h" rubidium@8270: #include "settings_type.h" truelight@0: rubidium@5428: enum { rubidium@9898: INIT_NUM_TEXT_EFFECTS = 20, rubidium@5428: }; rubidium@5428: rubidium@6248: struct TextEffect { truelight@0: StringID string_id; tron@849: int32 x; tron@849: int32 y; tron@849: int32 right; tron@849: int32 bottom; truelight@0: uint16 duration; rubidium@7006: uint64 params_1; rubidium@7006: uint64 params_2; truelight@6998: TextEffectMode mode; rubidium@6248: }; truelight@0: rubidium@7454: /* used for text effects */ truelight@6998: static TextEffect *_text_effect_list = NULL; rubidium@9898: static uint16 _num_text_effects = INIT_NUM_TEXT_EFFECTS; truelight@543: rubidium@7545: /* Text Effects */ rubidium@7545: /** rubidium@7545: * Mark the area of the text effect as dirty. rubidium@7545: * rubidium@7545: * This function marks the area of a text effect as dirty for repaint. rubidium@7545: * rubidium@7545: * @param te The TextEffect to mark the area dirty rubidium@7545: * @ingroup dirty rubidium@7545: */ truelight@0: static void MarkTextEffectAreaDirty(TextEffect *te) truelight@0: { rubidium@7535: /* Width and height of the text effect are doubled, so they are correct in both zoom out levels 1x and 2x. */ truelight@0: MarkAllViewportsDirty( truelight@0: te->x, truelight@0: te->y - 1, truelight@0: (te->right - te->x)*2 + te->x + 1, truelight@0: (te->bottom - (te->y - 1)) * 2 + (te->y - 1) + 1 truelight@0: ); truelight@0: } truelight@0: truelight@6998: TextEffectID AddTextEffect(StringID msg, int x, int y, uint16 duration, TextEffectMode mode) truelight@0: { truelight@0: TextEffect *te; truelight@0: int w; truelight@0: char buffer[100]; truelight@6998: TextEffectID i; truelight@0: truelight@6998: if (_game_mode == GM_MENU) return INVALID_TE_ID; truelight@193: truelight@6998: /* Look for a free spot in the text effect array */ truelight@6998: for (i = 0; i < _num_text_effects; i++) { truelight@6998: if (_text_effect_list[i].string_id == INVALID_STRING_ID) break; truelight@0: } truelight@0: truelight@6998: /* If there is none found, we grow the array */ truelight@6998: if (i == _num_text_effects) { truelight@6998: _num_text_effects += 25; rubidium@8037: _text_effect_list = ReallocT(_text_effect_list, _num_text_effects); truelight@6998: for (; i < _num_text_effects; i++) _text_effect_list[i].string_id = INVALID_STRING_ID; truelight@6998: i = _num_text_effects - 1; truelight@6998: } truelight@6998: truelight@6998: te = &_text_effect_list[i]; truelight@6998: truelight@6998: /* Start defining this object */ truelight@0: te->string_id = msg; truelight@0: te->duration = duration; truelight@0: te->y = y - 5; truelight@0: te->bottom = y + 5; tron@534: te->params_1 = GetDParam(0); tron@534: te->params_2 = GetDParam(4); truelight@6998: te->mode = mode; truelight@0: Darkvater@4912: GetString(buffer, msg, lastof(buffer)); Darkvater@4609: w = GetStringBoundingBox(buffer).width; truelight@0: truelight@0: te->x = x - (w >> 1); truelight@0: te->right = x + (w >> 1) - 1; truelight@0: MarkTextEffectAreaDirty(te); truelight@6998: truelight@6998: return i; truelight@6998: } truelight@6998: truelight@6998: void UpdateTextEffect(TextEffectID te_id, StringID msg) truelight@6998: { truelight@6998: assert(te_id < _num_text_effects); truelight@6998: TextEffect *te; truelight@6998: truelight@6998: /* Update details */ truelight@6998: te = &_text_effect_list[te_id]; truelight@6998: te->string_id = msg; truelight@6998: te->params_1 = GetDParam(0); truelight@6998: te->params_2 = GetDParam(4); truelight@6998: rubidium@7535: /* Update width of text effect */ rubidium@7535: char buffer[100]; rubidium@7535: GetString(buffer, msg, lastof(buffer)); rubidium@7535: int w = GetStringBoundingBox(buffer).width; rubidium@7535: rubidium@7535: /* Only allow to make it broader, so it completely covers the old text. That avoids remnants of the old text. */ rubidium@7535: int right_new = te->x + w; rubidium@7535: if (te->right < right_new) te->right = right_new; rubidium@7535: truelight@6998: MarkTextEffectAreaDirty(te); truelight@6998: } truelight@6998: truelight@6998: void RemoveTextEffect(TextEffectID te_id) truelight@6998: { truelight@6998: assert(te_id < _num_text_effects); truelight@6998: TextEffect *te; truelight@6998: truelight@6998: te = &_text_effect_list[te_id]; truelight@6998: MarkTextEffectAreaDirty(te); truelight@6998: te->string_id = INVALID_STRING_ID; truelight@0: } truelight@0: truelight@0: static void MoveTextEffect(TextEffect *te) truelight@0: { truelight@6998: /* Never expire for duration of 0xFFFF */ truelight@6998: if (te->duration == 0xFFFF) return; truelight@0: if (te->duration < 8) { tron@2470: te->string_id = INVALID_STRING_ID; truelight@0: } else { tron@2549: te->duration -= 8; truelight@0: te->y--; truelight@0: te->bottom--; truelight@0: } truelight@0: MarkTextEffectAreaDirty(te); truelight@0: } truelight@0: rubidium@6247: void MoveAllTextEffects() truelight@0: { truelight@6998: for (TextEffectID i = 0; i < _num_text_effects; i++) { truelight@6998: TextEffect *te = &_text_effect_list[i]; truelight@6998: if (te->string_id != INVALID_STRING_ID && te->mode == TE_RISING) MoveTextEffect(te); truelight@0: } truelight@0: } truelight@0: rubidium@6247: void InitTextEffects() truelight@0: { truelight@6998: if (_text_effect_list == NULL) _text_effect_list = MallocT(_num_text_effects); truelight@0: truelight@6998: for (TextEffectID i = 0; i < _num_text_effects; i++) _text_effect_list[i].string_id = INVALID_STRING_ID; truelight@0: } truelight@0: truelight@0: void DrawTextEffects(DrawPixelInfo *dpi) truelight@0: { tron@4469: switch (dpi->zoom) { truelight@6624: case ZOOM_LVL_NORMAL: truelight@6998: for (TextEffectID i = 0; i < _num_text_effects; i++) { truelight@6998: TextEffect *te = &_text_effect_list[i]; tron@4469: if (te->string_id != INVALID_STRING_ID && tron@4469: dpi->left <= te->right && tron@4469: dpi->top <= te->bottom && tron@4469: dpi->left + dpi->width > te->x && tron@4469: dpi->top + dpi->height > te->y) { rubidium@9413: if (te->mode == TE_RISING || (_settings_client.gui.loading_indicators && !IsTransparencySet(TO_LOADING))) { truelight@6998: AddStringToDraw(te->x, te->y, te->string_id, te->params_1, te->params_2); truelight@6998: } tron@4469: } tron@4469: } tron@4469: break; truelight@0: truelight@6624: case ZOOM_LVL_OUT_2X: truelight@6998: for (TextEffectID i = 0; i < _num_text_effects; i++) { truelight@6998: TextEffect *te = &_text_effect_list[i]; tron@4469: if (te->string_id != INVALID_STRING_ID && tron@4469: dpi->left <= te->right * 2 - te->x && tron@4469: dpi->top <= te->bottom * 2 - te->y && tron@4469: dpi->left + dpi->width > te->x && tron@4469: dpi->top + dpi->height > te->y) { rubidium@9413: if (te->mode == TE_RISING || (_settings_client.gui.loading_indicators && !IsTransparencySet(TO_LOADING))) { truelight@6998: AddStringToDraw(te->x, te->y, (StringID)(te->string_id - 1), te->params_1, te->params_2); truelight@6998: } tron@4469: } tron@4469: } tron@4469: break; truelight@6624: truelight@6626: case ZOOM_LVL_OUT_4X: truelight@6653: case ZOOM_LVL_OUT_8X: truelight@6624: break; truelight@6626: truelight@6626: default: NOT_REACHED(); truelight@0: } truelight@0: }