mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-08-27 16:39:09 +00:00
Compare commits
1 Commits
1.4.0-beta
...
1.4.0-beta
Author | SHA1 | Date | |
---|---|---|---|
|
dd7fffc27e |
@@ -1,16 +1,3 @@
|
||||
1.4.0-beta3 (2014-01-21)
|
||||
------------------------------------------------------------------------
|
||||
- Feature: Several small performance improvements with the SSE blitters (r26260, r26259, r26256, r26255, r26254)
|
||||
- Feature: [NewGRF] Add StringCodes 9A 1B, 9A 1C and 9A 1D to display amounts of cargo (r26244)
|
||||
- Fix: Do not run into infinite recursion when getting next stopping station [FS#5865] (r26267, r26263)
|
||||
- Fix: Update smallmap overlay if player joins different company and make sure company masks are valid [FS#5860] (r26266)
|
||||
- Fix: Do not rebuild the link graph overlay cache twice in a row (r26265)
|
||||
- Fix: Custom currency was reset on game start (r26262)
|
||||
- Fix: Possible out of bounds reads with the sse blitters [FS#5854, FS#5855] (r26247)
|
||||
- Fix: Do not overreserve after autorefit, but do reserve mail for aircraft (r26236)
|
||||
- Fix: Decimal and digit separators were swapped for Korean language (r26235)
|
||||
|
||||
|
||||
1.4.0-beta2 (2014-01-07)
|
||||
------------------------------------------------------------------------
|
||||
- Feature: Blitter autoselection is now based on full animation state, so a non-animated specialised blitter will generally be chosen when animation is turned off (r26217)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
OpenTTD's known bugs
|
||||
Last updated: 2014-01-21
|
||||
Release version: 1.4.0-beta3
|
||||
Last updated: 2014-01-07
|
||||
Release version: 1.4.0-beta2
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@@ -1,16 +1,10 @@
|
||||
openttd (1.4.0~beta3-0) unstable; urgency=low
|
||||
|
||||
* New upstream release 1.4.0-beta3
|
||||
|
||||
-- OpenTTD <info@openttd.org> Tue, 21 Jan 2014 21:00:00 +0100
|
||||
|
||||
openttd (1.4.0~beta2-0) unstable; urgency=low
|
||||
openttd (1.4.0~beta2) unstable; urgency=low
|
||||
|
||||
* New upstream release 1.4.0-beta2
|
||||
|
||||
-- OpenTTD <info@openttd.org> Tue, 07 Jan 2014 21:00:00 +0100
|
||||
|
||||
openttd (1.4.0~beta1-0) unstable; urgency=low
|
||||
openttd (1.4.0~beta1) unstable; urgency=low
|
||||
|
||||
* New upstream release 1.4.0-beta1
|
||||
|
||||
|
@@ -2,8 +2,8 @@
|
||||
!define APPV_MAJOR 1
|
||||
!define APPV_MINOR 4
|
||||
!define APPV_MAINT 0
|
||||
!define APPV_BUILD 2
|
||||
!define APPV_EXTRA "-beta3"
|
||||
!define APPV_BUILD 1
|
||||
!define APPV_EXTRA "-beta2"
|
||||
|
||||
!define APPNAME "OpenTTD" ; Define application name
|
||||
!define APPVERSION "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}${APPV_EXTRA}" ; Define application version
|
||||
|
@@ -1123,8 +1123,6 @@
|
||||
<ClInclude Include="..\src\blitter\32bpp_optimized.hpp" />
|
||||
<ClCompile Include="..\src\blitter\32bpp_simple.cpp" />
|
||||
<ClInclude Include="..\src\blitter\32bpp_simple.hpp" />
|
||||
<ClInclude Include="..\src\blitter\32bpp_sse_func.hpp" />
|
||||
<ClInclude Include="..\src\blitter\32bpp_sse_type.h" />
|
||||
<ClCompile Include="..\src\blitter\32bpp_sse2.cpp" />
|
||||
<ClInclude Include="..\src\blitter\32bpp_sse2.hpp" />
|
||||
<ClCompile Include="..\src\blitter\32bpp_sse4.cpp" />
|
||||
|
@@ -2598,12 +2598,6 @@
|
||||
<ClInclude Include="..\src\blitter\32bpp_simple.hpp">
|
||||
<Filter>Blitters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\blitter\32bpp_sse_func.hpp">
|
||||
<Filter>Blitters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\blitter\32bpp_sse_type.h">
|
||||
<Filter>Blitters</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\src\blitter\32bpp_sse2.cpp">
|
||||
<Filter>Blitters</Filter>
|
||||
</ClCompile>
|
||||
|
@@ -3834,14 +3834,6 @@
|
||||
RelativePath=".\..\src\blitter\32bpp_simple.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\blitter\32bpp_sse_func.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\blitter\32bpp_sse_type.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\blitter\32bpp_sse2.cpp"
|
||||
>
|
||||
|
@@ -3831,14 +3831,6 @@
|
||||
RelativePath=".\..\src\blitter\32bpp_simple.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\blitter\32bpp_sse_func.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\blitter\32bpp_sse_type.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\blitter\32bpp_sse2.cpp"
|
||||
>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
Last updated: 2014-01-21
|
||||
Release version: 1.4.0-beta3
|
||||
Last updated: 2014-01-07
|
||||
Release version: 1.4.0-beta2
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@@ -912,8 +912,6 @@ blitter/32bpp_optimized.hpp
|
||||
blitter/32bpp_simple.cpp
|
||||
blitter/32bpp_simple.hpp
|
||||
#if SSE
|
||||
blitter/32bpp_sse_func.hpp
|
||||
blitter/32bpp_sse_type.h
|
||||
blitter/32bpp_sse2.cpp
|
||||
blitter/32bpp_sse2.hpp
|
||||
blitter/32bpp_sse4.cpp
|
||||
|
@@ -15,7 +15,6 @@
|
||||
#include "../video/video_driver.hpp"
|
||||
#include "../table/sprites.h"
|
||||
#include "32bpp_anim_sse4.hpp"
|
||||
#include "32bpp_sse_func.hpp"
|
||||
|
||||
/** Instantiation of the SSE4 32bpp blitter factory. */
|
||||
static FBlitter_32bppSSE4_Anim iFBlitter_32bppSSE4_Anim;
|
||||
@@ -28,15 +27,15 @@ static FBlitter_32bppSSE4_Anim iFBlitter_32bppSSE4_Anim;
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last, bool translucent, bool animated>
|
||||
template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last>
|
||||
inline void Blitter_32bppSSE4_Anim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
{
|
||||
const byte * const remap = bp->remap;
|
||||
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
|
||||
uint16 *anim_line = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left;
|
||||
int effective_width = bp->width;
|
||||
|
||||
/* Find where to start reading in the source sprite. */
|
||||
const byte * const remap = bp->remap;
|
||||
const Blitter_32bppSSE_Base::SpriteData * const sd = (const Blitter_32bppSSE_Base::SpriteData *) bp->sprite;
|
||||
const SpriteInfo * const si = &sd->infos[zoom];
|
||||
const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
|
||||
@@ -46,277 +45,309 @@ inline void Blitter_32bppSSE4_Anim::Draw(const Blitter::BlitterParams *bp, ZoomL
|
||||
src_rgba_line += bp->skip_left;
|
||||
src_mv_line += bp->skip_left;
|
||||
}
|
||||
const MapValue *src_mv = src_mv_line;
|
||||
|
||||
/* Load these variables into register before loop. */
|
||||
const __m128i a_cm = ALPHA_CONTROL_MASK;
|
||||
const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK;
|
||||
const __m128i briAB_cm = BRIGHTNESS_LOW_CONTROL_MASK;
|
||||
const __m128i div_cleaner = BRIGHTNESS_DIV_CLEANER;
|
||||
const __m128i ob_check = OVERBRIGHT_PRESENCE_MASK;
|
||||
const __m128i ob_mask = OVERBRIGHT_VALUE_MASK;
|
||||
const __m128i ob_cm = OVERBRIGHT_CONTROL_MASK;
|
||||
const __m128i tr_nom_base = TRANSPARENT_NOM_BASE;
|
||||
|
||||
for (int y = bp->height; y != 0; y--) {
|
||||
Colour *dst = dst_line;
|
||||
const Colour *src = src_rgba_line + META_LENGTH;
|
||||
if (mode != BM_TRANSPARENT) src_mv = src_mv_line;
|
||||
const MapValue *src_mv = src_mv_line;
|
||||
uint16 *anim = anim_line;
|
||||
|
||||
if (read_mode == RM_WITH_MARGIN) {
|
||||
assert(bt_last == BT_NONE); // or you must ensure block type is preserved
|
||||
anim += src_rgba_line[0].data;
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
if (mode != BM_TRANSPARENT) src_mv += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int new_width = effective_width - delta_diff;
|
||||
effective_width = delta_diff > 0 ? new_width : effective_width;
|
||||
if (effective_width <= 0) goto next_line;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
if (!translucent) {
|
||||
for (uint x = (uint) effective_width; x > 0; x--) {
|
||||
if (src->a) {
|
||||
if (animated) {
|
||||
*anim = *(const uint16*) src_mv;
|
||||
*dst = (src_mv->m >= PALETTE_ANIM_START) ? AdjustBrightneSSE(this->LookupColourInPalette(src_mv->m), src_mv->v) : src->data;
|
||||
default: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
src_mv += src_rgba_line[0].data;
|
||||
anim += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int new_width = effective_width - (delta_diff & ~1);
|
||||
effective_width = delta_diff > 0 ? new_width : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
uint32 mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
for (uint x = (uint) effective_width/2; x != 0; x--) {
|
||||
/* Remap colours. */
|
||||
const byte m0 = mvX2;
|
||||
if (m0 >= PALETTE_ANIM_START) {
|
||||
const Colour c0 = (this->LookupColourInPalette(m0).data & 0x00FFFFFF) | (src[0].data & 0xFF000000);
|
||||
INSR32(AdjustBrightness(c0, (byte) (mvX2 >> 8)).data, srcABCD, 0);
|
||||
}
|
||||
const byte m1 = mvX2 >> 16;
|
||||
if (m1 >= PALETTE_ANIM_START) {
|
||||
const Colour c1 = (this->LookupColourInPalette(m1).data & 0x00FFFFFF) | (src[1].data & 0xFF000000);
|
||||
INSR32(AdjustBrightness(c1, (byte) (mvX2 >> 24)).data, srcABCD, 1);
|
||||
}
|
||||
|
||||
/* Update anim buffer. */
|
||||
const byte a0 = src[0].a;
|
||||
const byte a1 = src[1].a;
|
||||
uint32 anim01 = 0;
|
||||
if (a0 == 255) {
|
||||
if (a1 == 255) {
|
||||
*(uint32*) anim = mvX2;
|
||||
goto bmno_full_opacity;
|
||||
}
|
||||
anim01 = (uint16) mvX2;
|
||||
} else if (a0 == 0) {
|
||||
if (a1 == 0) {
|
||||
goto bmno_full_transparency;
|
||||
} else {
|
||||
if (a1 == 255) anim[1] = (uint16) (mvX2 >> 16);
|
||||
goto bmno_alpha_blend;
|
||||
}
|
||||
}
|
||||
if (a1 > 0) {
|
||||
if (a1 == 255) anim01 |= mvX2 & 0xFFFF0000;
|
||||
*(uint32*) anim = anim01;
|
||||
} else {
|
||||
anim[0] = (uint16) anim01;
|
||||
}
|
||||
|
||||
/* Blend colours. */
|
||||
bmno_alpha_blend:
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
bmno_full_opacity:
|
||||
srcABCD = _mm_blend_epi16(srcABCD, dstABCD, 0xF0);
|
||||
|
||||
src_mv += 2;
|
||||
mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
src += 2;
|
||||
anim += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) (dst+2));
|
||||
_mm_storeu_si128((__m128i *) dst, srcABCD);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
dst += 2;
|
||||
continue;
|
||||
|
||||
bmno_full_transparency:
|
||||
src_mv += 2;
|
||||
mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
dst += 2;
|
||||
src += 2;
|
||||
anim += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
|
||||
if (bt_last == BT_ODD) {
|
||||
if (src->a == 0) {
|
||||
} else if (src->a == 255) {
|
||||
*anim = (uint16) mvX2;
|
||||
*dst = ((byte) mvX2 >= PALETTE_ANIM_START) ? AdjustBrightness(LookupColourInPalette((byte) mvX2), (byte) (mvX2 >> 8)) : *src;
|
||||
} else {
|
||||
*anim = 0;
|
||||
*dst = *src;
|
||||
}
|
||||
}
|
||||
if (animated) src_mv++;
|
||||
anim++;
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint x = (uint) effective_width/2; x != 0; x--) {
|
||||
uint32 mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
__m128i srcABCD = _mm_loadl_epi64((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
|
||||
|
||||
if (animated) {
|
||||
/* Remap colours. */
|
||||
const byte m0 = mvX2;
|
||||
if (m0 >= PALETTE_ANIM_START) {
|
||||
const Colour c0 = (this->LookupColourInPalette(m0).data & 0x00FFFFFF) | (src[0].data & 0xFF000000);
|
||||
InsertFirstUint32(AdjustBrightneSSE(c0, (byte) (mvX2 >> 8)).data, srcABCD);
|
||||
}
|
||||
const byte m1 = mvX2 >> 16;
|
||||
if (m1 >= PALETTE_ANIM_START) {
|
||||
const Colour c1 = (this->LookupColourInPalette(m1).data & 0x00FFFFFF) | (src[1].data & 0xFF000000);
|
||||
InsertSecondUint32(AdjustBrightneSSE(c1, (byte) (mvX2 >> 24)).data, srcABCD);
|
||||
}
|
||||
|
||||
/* Update anim buffer. */
|
||||
const byte a0 = src[0].a;
|
||||
const byte a1 = src[1].a;
|
||||
uint32 anim01 = 0;
|
||||
if (a0 == 255) {
|
||||
if (a1 == 255) {
|
||||
*(uint32*) anim = mvX2;
|
||||
goto bmno_full_opacity;
|
||||
}
|
||||
anim01 = (uint16) mvX2;
|
||||
} else if (a0 == 0) {
|
||||
if (a1 == 0) {
|
||||
goto bmno_full_transparency;
|
||||
} else {
|
||||
if (a1 == 255) anim[1] = (uint16) (mvX2 >> 16);
|
||||
goto bmno_alpha_blend;
|
||||
}
|
||||
}
|
||||
if (a1 > 0) {
|
||||
if (a1 == 255) anim01 |= mvX2 & 0xFFFF0000;
|
||||
*(uint32*) anim = anim01;
|
||||
} else {
|
||||
anim[0] = (uint16) anim01;
|
||||
}
|
||||
} else {
|
||||
if (src[0].a) anim[0] = 0;
|
||||
if (src[1].a) anim[1] = 0;
|
||||
}
|
||||
|
||||
/* Blend colours. */
|
||||
bmno_alpha_blend:
|
||||
srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm);
|
||||
bmno_full_opacity:
|
||||
_mm_storel_epi64((__m128i *) dst, srcABCD);
|
||||
bmno_full_transparency:
|
||||
src_mv += 2;
|
||||
src += 2;
|
||||
anim += 2;
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
if (src->a == 0) {
|
||||
} else if (src->a == 255) {
|
||||
*anim = *(const uint16*) src_mv;
|
||||
*dst = (src_mv->m >= PALETTE_ANIM_START) ? AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v) : *src;
|
||||
} else {
|
||||
*anim = 0;
|
||||
__m128i srcABCD;
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
if (src_mv->m >= PALETTE_ANIM_START) {
|
||||
Colour colour = AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v);
|
||||
colour.a = src->a;
|
||||
srcABCD = _mm_cvtsi32_si128(colour.data);
|
||||
} else {
|
||||
srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
}
|
||||
dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BM_COLOUR_REMAP:
|
||||
for (uint x = (uint) effective_width / 2; x != 0; x--) {
|
||||
uint32 mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
__m128i srcABCD = _mm_loadl_epi64((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
|
||||
|
||||
/* Remap colours. */
|
||||
const uint m0 = (byte) mvX2;
|
||||
const uint r0 = remap[m0];
|
||||
const uint m1 = (byte) (mvX2 >> 16);
|
||||
const uint r1 = remap[m1];
|
||||
if (mvX2 & 0x00FF00FF) {
|
||||
#define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \
|
||||
/* Written so the compiler uses CMOV. */ \
|
||||
Colour m_colour = m_colour_init; \
|
||||
{ \
|
||||
const Colour srcm = (Colour) (m_src); \
|
||||
const uint m = (byte) (m_m); \
|
||||
const uint r = remap[m]; \
|
||||
const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \
|
||||
m_colour = r == 0 ? m_colour : cmap; \
|
||||
m_colour = m != 0 ? m_colour : srcm; \
|
||||
}
|
||||
#ifdef _SQ64
|
||||
uint64 srcs = _mm_cvtsi128_si64(srcABCD);
|
||||
uint64 dsts;
|
||||
if (animated) dsts = _mm_cvtsi128_si64(dstABCD);
|
||||
uint64 remapped_src = 0;
|
||||
CMOV_REMAP(c0, animated ? dsts : 0, srcs, mvX2);
|
||||
remapped_src = c0.data;
|
||||
CMOV_REMAP(c1, animated ? dsts >> 32 : 0, srcs >> 32, mvX2 >> 16);
|
||||
remapped_src |= (uint64) c1.data << 32;
|
||||
srcABCD = _mm_cvtsi64_si128(remapped_src);
|
||||
#else
|
||||
Colour remapped_src[2];
|
||||
CMOV_REMAP(c0, animated ? _mm_cvtsi128_si32(dstABCD) : 0, _mm_cvtsi128_si32(srcABCD), mvX2);
|
||||
remapped_src[0] = c0.data;
|
||||
CMOV_REMAP(c1, animated ? dst[1] : 0, src[1], mvX2 >> 16);
|
||||
remapped_src[1] = c1.data;
|
||||
srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src);
|
||||
#endif
|
||||
|
||||
if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2);
|
||||
}
|
||||
|
||||
/* Update anim buffer. */
|
||||
if (animated) {
|
||||
const byte a0 = src[0].a;
|
||||
const byte a1 = src[1].a;
|
||||
uint32 anim01 = mvX2 & 0xFF00FF00;
|
||||
if (a0 == 255) {
|
||||
anim01 |= r0;
|
||||
if (a1 == 255) {
|
||||
*(uint32*) anim = anim01 | (r1 << 16);
|
||||
goto bmcr_full_opacity;
|
||||
}
|
||||
} else if (a0 == 0) {
|
||||
if (a1 == 0) {
|
||||
goto bmcr_full_transparency;
|
||||
} else {
|
||||
if (a1 == 255) {
|
||||
anim[1] = r1 | (anim01 >> 16);
|
||||
if ((byte) mvX2 >= PALETTE_ANIM_START) {
|
||||
ALIGN(16) Colour colour = AdjustBrightness(LookupColourInPalette((byte) mvX2), (byte) (mvX2 >> 8));
|
||||
colour.a = src->a;
|
||||
srcABCD = _mm_load_si128((__m128i*) &colour);
|
||||
}
|
||||
goto bmcr_alpha_blend;
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
(*dst).data = EXTR32(srcABCD, 0);
|
||||
}
|
||||
}
|
||||
if (a1 > 0) {
|
||||
if (a1 == 255) anim01 |= r1 << 16;
|
||||
*(uint32*) anim = anim01;
|
||||
} else {
|
||||
anim[0] = (uint16) anim01;
|
||||
}
|
||||
} else {
|
||||
if (src[0].a) anim[0] = 0;
|
||||
if (src[1].a) anim[1] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Blend colours. */
|
||||
bmcr_alpha_blend:
|
||||
srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm);
|
||||
bmcr_full_opacity:
|
||||
_mm_storel_epi64((__m128i *) dst, srcABCD);
|
||||
bmcr_full_transparency:
|
||||
src_mv += 2;
|
||||
dst += 2;
|
||||
src += 2;
|
||||
anim += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way. */
|
||||
__m128i srcABCD;
|
||||
if (src->a == 0) break;
|
||||
if (src_mv->m) {
|
||||
const uint r = remap[src_mv->m];
|
||||
*anim = (animated && src->a == 255) ? r | ((uint16) src_mv->v << 8 ) : 0;
|
||||
if (r != 0) {
|
||||
Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v);
|
||||
if (src->a == 255) {
|
||||
*dst = remapped_colour;
|
||||
} else {
|
||||
remapped_colour.a = src->a;
|
||||
srcABCD = _mm_cvtsi32_si128(remapped_colour.data);
|
||||
goto bmcr_alpha_blend_single;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*anim = 0;
|
||||
srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
if (src->a < 255) {
|
||||
bmcr_alpha_blend_single:
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm);
|
||||
}
|
||||
dst->data = _mm_cvtsi128_si32(srcABCD);
|
||||
}
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BM_TRANSPARENT:
|
||||
case BM_COLOUR_REMAP: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
src_mv += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
anim += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int nd = effective_width - delta_diff;
|
||||
effective_width = delta_diff > 0 ? nd : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
uint32 mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
|
||||
for (uint x = (uint) effective_width / 2; x != 0; x--) {
|
||||
/* Remap colours. */
|
||||
const uint m0 = (byte) mvX2;
|
||||
const uint r0 = remap[m0];
|
||||
const uint m1 = (byte) (mvX2 >> 16);
|
||||
const uint r1 = remap[m1];
|
||||
if (mvX2 & 0x00FF00FF) {
|
||||
/* Written so the compiler uses CMOV. */
|
||||
const Colour src0 = src[0];
|
||||
const Colour c0map = (this->LookupColourInPalette(r0).data & 0x00FFFFFF) | (src0.data & 0xFF000000);
|
||||
Colour c0 = dst[0];
|
||||
c0 = r0 == 0 ? c0 : c0map;
|
||||
c0 = m0 != 0 ? c0 : src0;
|
||||
INSR32(c0.data, srcABCD, 0);
|
||||
|
||||
const Colour src1 = src[1];
|
||||
const Colour c1map = (this->LookupColourInPalette(r1).data & 0x00FFFFFF) | (src1.data & 0xFF000000);
|
||||
Colour c1 = dst[1];
|
||||
c1 = r1 == 0 ? c1 : c1map;
|
||||
c1 = m1 != 0 ? c1 : src1;
|
||||
INSR32(c1.data, srcABCD, 1);
|
||||
|
||||
if ((mvX2 & 0xFF00FF00) != 0x80008000) {
|
||||
ADJUST_BRIGHTNESS_2(srcABCD, mvX2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update anim buffer. */
|
||||
const byte a0 = src[0].a;
|
||||
const byte a1 = src[1].a;
|
||||
uint32 anim01 = mvX2 & 0xFF00FF00;
|
||||
if (a0 == 255) {
|
||||
anim01 |= r0;
|
||||
if (a1 == 255) {
|
||||
*(uint32*) anim = anim01 | (r1 << 16);
|
||||
goto bmcr_full_opacity;
|
||||
}
|
||||
} else if (a0 == 0) {
|
||||
if (a1 == 0) {
|
||||
goto bmcr_full_transparency;
|
||||
} else {
|
||||
if (a1 == 255) {
|
||||
anim[1] = r1 | (anim01 >> 16);
|
||||
}
|
||||
goto bmcr_alpha_blend;
|
||||
}
|
||||
}
|
||||
if (a1 > 0) {
|
||||
if (a1 == 255) anim01 |= r1 << 16;
|
||||
*(uint32*) anim = anim01;
|
||||
} else {
|
||||
anim[0] = (uint16) anim01;
|
||||
}
|
||||
|
||||
/* Blend colours. */
|
||||
bmcr_alpha_blend:
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
bmcr_full_opacity:
|
||||
srcABCD = _mm_blend_epi16(srcABCD, dstABCD, 0xF0);
|
||||
|
||||
src += 2;
|
||||
src_mv += 2;
|
||||
anim += 2;
|
||||
mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
dstABCD = _mm_loadu_si128((__m128i*) (dst+2));
|
||||
_mm_storeu_si128((__m128i *) dst, srcABCD);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
dst += 2;
|
||||
continue;
|
||||
|
||||
bmcr_full_transparency:
|
||||
src_mv += 2;
|
||||
mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
dst += 2;
|
||||
src += 2;
|
||||
anim += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
|
||||
if (effective_width & 1) {
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way. */
|
||||
if (src->a == 0) {
|
||||
} else if ((byte) mvX2 != 0) {
|
||||
const uint r = remap[(byte) mvX2];
|
||||
*anim = (src->a == 255) ? (r | ((uint16) mvX2 & 0xFF00)) : 0;
|
||||
if (r != 0) {
|
||||
Colour remapped_colour = AdjustBrightness(LookupColourInPalette(r), (byte) (mvX2 >> 8));
|
||||
if (src->a == 255) {
|
||||
*dst = remapped_colour;
|
||||
} else {
|
||||
remapped_colour.a = src->a;
|
||||
INSR32(remapped_colour.data, srcABCD, 0);
|
||||
goto bmcr_alpha_blend_single;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*anim = 0;
|
||||
if (src->a == 255) {
|
||||
*dst = *src;
|
||||
} else {
|
||||
bmcr_alpha_blend_single:
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
(*dst).data = EXTR32(srcABCD, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BM_TRANSPARENT: {
|
||||
/* Make the current colour a bit more black, so it looks like this image is transparent. */
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
for (uint x = (uint) bp->width / 2; x > 0; x--) {
|
||||
__m128i srcABCD = _mm_loadl_epi64((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
|
||||
_mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base));
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i dstCD = _mm_unpackhi_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shuffle_epi8(srcAB, a_cm);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits.
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstCD);
|
||||
Colour *old_dst = dst;
|
||||
src += 2;
|
||||
dst += 2;
|
||||
anim += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, dstAB);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
if (src[-2].a) anim[-2] = 0;
|
||||
if (src[-1].a) anim[-1] = 0;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) {
|
||||
__m128i srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base));
|
||||
if (bp->width & 1) {
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shuffle_epi8(srcAB, a_cm);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2);
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstAB);
|
||||
(*dst).data = EXTR32(dstAB, 0);
|
||||
if (src[0].a) anim[0] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
next_line:
|
||||
if (mode != BM_TRANSPARENT) src_mv_line += si->sprite_width;
|
||||
src_mv_line += si->sprite_width;
|
||||
src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size);
|
||||
dst_line += bp->pitch;
|
||||
anim_line += this->anim_buf_width;
|
||||
@@ -333,47 +364,42 @@ IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
*/
|
||||
void Blitter_32bppSSE4_Anim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
|
||||
{
|
||||
const Blitter_32bppSSE_Base::SpriteFlags sprite_flags = ((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags;
|
||||
switch (mode) {
|
||||
default: {
|
||||
bm_normal:
|
||||
case BM_NORMAL: {
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) {
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
if (bt_last == BT_EVEN) {
|
||||
if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN, true, false>(bp, zoom);
|
||||
else Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN, true, true>(bp, zoom);
|
||||
} else {
|
||||
if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD, true, false>(bp, zoom);
|
||||
else Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD, true, true>(bp, zoom);
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
} else {
|
||||
#ifdef _SQ64
|
||||
if (sprite_flags & SF_TRANSLUCENT) {
|
||||
if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
|
||||
} else {
|
||||
if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, false, false>(bp, zoom);
|
||||
else Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, false, true>(bp, zoom);
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
#else
|
||||
if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BM_COLOUR_REMAP:
|
||||
if (sprite_flags & SF_NO_REMAP) goto bm_normal;
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) {
|
||||
if (sprite_flags & SF_NO_ANIM) Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE, true, true>(bp, zoom);
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE>(bp, zoom); return;
|
||||
} else {
|
||||
if (sprite_flags & SF_NO_ANIM) Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE>(bp, zoom); return;
|
||||
}
|
||||
break;
|
||||
case BM_TRANSPARENT: Draw<BM_TRANSPARENT, RM_NONE, BT_NONE, true, true>(bp, zoom); return;
|
||||
case BM_TRANSPARENT: Draw<BM_TRANSPARENT, RM_NONE, BT_NONE>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/** Same code as seen in 32bpp_sse2.cpp but some macros are not the same. */
|
||||
inline Colour Blitter_32bppSSE4_Anim::AdjustBrightness(Colour colour, uint8 brightness)
|
||||
{
|
||||
/* Shortcut for normal brightness. */
|
||||
if (brightness == DEFAULT_BRIGHTNESS) return colour;
|
||||
|
||||
return Blitter_32bppSSE4::ReallyAdjustBrightness(colour, brightness);
|
||||
}
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -14,14 +14,6 @@
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
#ifndef SSE_VERSION
|
||||
#define SSE_VERSION 4
|
||||
#endif
|
||||
|
||||
#ifndef FULL_ANIMATION
|
||||
#define FULL_ANIMATION 1
|
||||
#endif
|
||||
|
||||
#include "32bpp_anim.hpp"
|
||||
#include "32bpp_sse4.hpp"
|
||||
|
||||
@@ -33,12 +25,14 @@ class Blitter_32bppSSE4_Anim FINAL : public Blitter_32bppAnim, public Blitter_32
|
||||
private:
|
||||
|
||||
public:
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent, bool animated>
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last>
|
||||
/* virtual */ void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
/* virtual */ Colour AdjustBrightness(Colour colour, uint8 brightness);
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) {
|
||||
return Blitter_32bppSSE_Base::Encode(sprite, allocator);
|
||||
}
|
||||
|
||||
/* virtual */ const char *GetName() { return "32bpp-sse4-anim"; }
|
||||
};
|
||||
|
||||
|
@@ -15,14 +15,223 @@
|
||||
#include "../zoom_func.h"
|
||||
#include "../settings_type.h"
|
||||
#include "32bpp_sse2.hpp"
|
||||
#include "32bpp_sse_func.hpp"
|
||||
|
||||
/** Instantiation of the SSE2 32bpp blitter factory. */
|
||||
static FBlitter_32bppSSE2 iFBlitter_32bppSSE2;
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. It is templated to allow faster operation.
|
||||
*
|
||||
* @tparam mode blitter mode
|
||||
* @param bp further blitting parameters
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last>
|
||||
inline void Blitter_32bppSSE2::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
{
|
||||
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
|
||||
int effective_width = bp->width;
|
||||
|
||||
/* Find where to start reading in the source sprite */
|
||||
const SpriteData * const sd = (const SpriteData *) bp->sprite;
|
||||
const SpriteInfo * const si = &sd->infos[zoom];
|
||||
const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
|
||||
const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
|
||||
|
||||
if (read_mode != RM_WITH_MARGIN) {
|
||||
src_rgba_line += bp->skip_left;
|
||||
src_mv_line += bp->skip_left;
|
||||
}
|
||||
|
||||
/* Load these variables into register before loop. */
|
||||
const __m128i clear_hi = CLEAR_HIGH_BYTE_MASK;
|
||||
const __m128i tr_nom_base = TRANSPARENT_NOM_BASE;
|
||||
|
||||
for (int y = bp->height; y != 0; y--) {
|
||||
Colour *dst = dst_line;
|
||||
const Colour *src = src_rgba_line + META_LENGTH;
|
||||
const MapValue *src_mv = src_mv_line;
|
||||
|
||||
switch (mode) {
|
||||
default: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int new_width = effective_width - (delta_diff & ~1);
|
||||
effective_width = delta_diff > 0 ? new_width : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
for (uint x = (uint) effective_width / 2; x > 0; x--) {
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
ALPHA_BLEND_2();
|
||||
*(uint64*) dst = EXTR64(srcABCD, 0);
|
||||
src += 2;
|
||||
dst += 2;
|
||||
}
|
||||
if (bt_last == BT_ODD) {
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
ALPHA_BLEND_2();
|
||||
(*dst).data = EXTR32(srcABCD, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BM_COLOUR_REMAP: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
src_mv += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int nd = effective_width - delta_diff;
|
||||
effective_width = delta_diff > 0 ? nd : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
const byte *remap = bp->remap;
|
||||
for (uint x = (uint) effective_width; x != 0; x--) {
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (src_mv->m == 0) {
|
||||
if (src->a < 255) {
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
ALPHA_BLEND_2();
|
||||
(*dst).data = EXTR32(srcABCD, 0);
|
||||
} else {
|
||||
*dst = src->data;
|
||||
}
|
||||
} else {
|
||||
const uint r = remap[src_mv->m];
|
||||
if (r != 0) {
|
||||
Colour remapped_colour = AdjustBrightness(this->LookupColourInPalette(r), src_mv->v);
|
||||
if (src->a < 255) {
|
||||
__m128i srcABCD;
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
remapped_colour.a = src->a;
|
||||
INSR32(remapped_colour.data, srcABCD, 0);
|
||||
ALPHA_BLEND_2();
|
||||
(*dst).data = EXTR32(srcABCD, 0);
|
||||
} else
|
||||
*dst = remapped_colour;
|
||||
}
|
||||
}
|
||||
src_mv++;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
src_mv_line += si->sprite_width;
|
||||
break;
|
||||
}
|
||||
case BM_TRANSPARENT: {
|
||||
/* Make the current colour a bit more black, so it looks like this image is transparent.
|
||||
* rgb = rgb * ((256/4) * 4 - (alpha/4)) / ((256/4) * 4)
|
||||
*/
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
for (uint x = (uint) bp->width / 2; x > 0; x--) {
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i dstCD = _mm_unpackhi_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shufflelo_epi16(srcAB, 0x3F);
|
||||
alphaAB = _mm_shufflehi_epi16(alphaAB, 0x3F);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits.
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstCD);
|
||||
Colour *old_dst = dst;
|
||||
src += 2;
|
||||
dst += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, dstAB);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
if (bp->width & 1) {
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shufflelo_epi16(srcAB, 0x3F);
|
||||
alphaAB = _mm_shufflehi_epi16(alphaAB, 0x3F);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2);
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstAB);
|
||||
(*dst).data = EXTR32(dstAB, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size);
|
||||
dst_line += bp->pitch;
|
||||
}
|
||||
}
|
||||
IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. Calls adequate templated function.
|
||||
*
|
||||
* @param bp further blitting parameters
|
||||
* @param mode blitter mode
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
void Blitter_32bppSSE2::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
|
||||
{
|
||||
switch (mode) {
|
||||
case BM_NORMAL: {
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) {
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
} else {
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BM_COLOUR_REMAP:
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE>(bp, zoom); return;
|
||||
} else {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE>(bp, zoom); return;
|
||||
}
|
||||
case BM_TRANSPARENT: Draw<BM_TRANSPARENT, RM_NONE, BT_NONE>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator)
|
||||
{
|
||||
/* First uint32 of a line = the number of transparent pixels from the left.
|
||||
/* First uint32 of a line = ~1 & the number of transparent pixels from the left.
|
||||
* Second uint32 of a line = the number of transparent pixels from the right.
|
||||
* Then all RGBA then all MV.
|
||||
*/
|
||||
@@ -57,10 +266,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, Alloca
|
||||
dst_sprite->y_offs = sprite->y_offs;
|
||||
memcpy(dst_sprite->data, &sd, sizeof(SpriteData));
|
||||
|
||||
/* Copy colours and determine flags. */
|
||||
bool has_remap = false;
|
||||
bool has_anim = false;
|
||||
bool has_translucency = false;
|
||||
/* Copy colours. */
|
||||
for (ZoomLevel z = zoom_min; z <= zoom_max; z++) {
|
||||
const SpriteLoader::Sprite *src_sprite = &sprite[z];
|
||||
const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *) src_sprite->data;
|
||||
@@ -71,19 +277,14 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, Alloca
|
||||
for (uint x = src_sprite->width; x != 0; x--) {
|
||||
if (src->a != 0) {
|
||||
dst_rgba->a = src->a;
|
||||
if (src->a != 0 && src->a != 255) has_translucency = true;
|
||||
dst_mv->m = src->m;
|
||||
if (src->m != 0) {
|
||||
/* Do some accounting for flags. */
|
||||
has_remap = true;
|
||||
if (src->m >= PALETTE_ANIM_START) has_anim = true;
|
||||
|
||||
/* Get brightest value (or default brightness if it's a black pixel). */
|
||||
const uint8 rgb_max = max(src->r, max(src->g, src->b));
|
||||
dst_mv->v = (rgb_max == 0) ? Blitter_32bppBase::DEFAULT_BRIGHTNESS : rgb_max;
|
||||
|
||||
/* Pre-convert the mapping channel to a RGB value. */
|
||||
const Colour colour = AdjustBrightneSSE(Blitter_32bppBase::LookupColourInPalette(src->m), dst_mv->v);
|
||||
const Colour colour = AdjustBrightness(Blitter_32bppBase::LookupColourInPalette(src->m), dst_mv->v);
|
||||
dst_rgba->r = colour.r;
|
||||
dst_rgba->g = colour.g;
|
||||
dst_rgba->b = colour.b;
|
||||
@@ -110,7 +311,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, Alloca
|
||||
else break;
|
||||
dst_rgba++;
|
||||
}
|
||||
(*dst_rgba_line).data = nb_pix_transp;
|
||||
(*dst_rgba_line).data = nb_pix_transp & ~1; // "& ~1" to preserve the last block type
|
||||
|
||||
Colour *nb_right = dst_rgba_line + 1;
|
||||
dst_rgba_line = (Colour*) ((byte*) dst_rgba_line + sd.infos[z].sprite_line_size);
|
||||
@@ -123,18 +324,56 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, Alloca
|
||||
else break;
|
||||
dst_rgba--;
|
||||
}
|
||||
(*nb_right).data = nb_pix_transp;
|
||||
(*nb_right).data = nb_pix_transp; // no "& ~1" here, must be done when we know bp->width
|
||||
}
|
||||
}
|
||||
|
||||
/* Store sprite flags. */
|
||||
sd.flags = SF_NONE;
|
||||
if (has_translucency) sd.flags |= SF_TRANSLUCENT;
|
||||
if (!has_remap) sd.flags |= SF_NO_REMAP;
|
||||
if (!has_anim) sd.flags |= SF_NO_ANIM;
|
||||
memcpy(dst_sprite->data, &sd, sizeof(SpriteData));
|
||||
|
||||
return dst_sprite;
|
||||
}
|
||||
|
||||
/** ReallyAdjustBrightness() is not called that often.
|
||||
* Inlining this function implies a far jump, which has a huge latency.
|
||||
*/
|
||||
inline Colour Blitter_32bppSSE2::AdjustBrightness(Colour colour, uint8 brightness)
|
||||
{
|
||||
/* Shortcut for normal brightness. */
|
||||
if (brightness == DEFAULT_BRIGHTNESS) return colour;
|
||||
|
||||
return Blitter_32bppSSE2::ReallyAdjustBrightness(colour, brightness);
|
||||
}
|
||||
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
/* static */ Colour Blitter_32bppSSE2::ReallyAdjustBrightness(Colour colour, uint8 brightness)
|
||||
{
|
||||
ALIGN(16) uint64 c16 = colour.b | (uint64) colour.g << 16 | (uint64) colour.r << 32;
|
||||
c16 *= brightness;
|
||||
uint64 c16_ob = c16; // Helps out of order execution.
|
||||
c16 /= DEFAULT_BRIGHTNESS;
|
||||
c16 &= 0x01FF01FF01FF;
|
||||
|
||||
/* Sum overbright (maximum for each rgb is 508, 9 bits, -255 is changed in -256 so we just have to take the 8 lower bits into account). */
|
||||
c16_ob = (((c16_ob >> (8 + 7)) & 0x0100010001) * 0xFF) & c16;
|
||||
uint64 ob = (uint16) c16_ob + (uint16) (c16_ob >> 16) + (uint16) (c16_ob >> 32);
|
||||
|
||||
const uint32 alpha32 = colour.data & 0xFF000000;
|
||||
__m128i ret;
|
||||
INSR64(c16, ret, 0);
|
||||
if (ob != 0) {
|
||||
/* Reduce overbright strength. */
|
||||
ob /= 2;
|
||||
__m128i ob128;
|
||||
INSR64(ob | ob << 16 | ob << 32, ob128, 0);
|
||||
__m128i white = OVERBRIGHT_VALUE_MASK;
|
||||
__m128i c128 = ret;
|
||||
ret = _mm_subs_epu16(white, c128); /* PSUBUSW, (255 - rgb) */
|
||||
ret = _mm_mullo_epi16(ret, ob128); /* PMULLW, ob*(255 - rgb) */
|
||||
ret = _mm_srli_epi16(ret, 8); /* PSRLW, ob*(255 - rgb)/256 */
|
||||
ret = _mm_add_epi16(ret, c128); /* PADDW, ob*(255 - rgb)/256 + rgb */
|
||||
}
|
||||
|
||||
ret = _mm_packus_epi16(ret, ret); /* PACKUSWB, saturate and pack. */
|
||||
return alpha32 | EXTR32(ret, 0);
|
||||
}
|
||||
IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -14,15 +14,64 @@
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
#ifndef SSE_VERSION
|
||||
#define SSE_VERSION 2
|
||||
#include "32bpp_simple.hpp"
|
||||
#include "emmintrin.h"
|
||||
|
||||
#define META_LENGTH 2 ///< Number of uint32 inserted before each line of pixels in a sprite.
|
||||
#define MARGIN_NORMAL_THRESHOLD (zoom == ZOOM_LVL_OUT_32X ? 8 : 4) ///< Minimum width to use margins with BM_NORMAL.
|
||||
#define MARGIN_REMAP_THRESHOLD 4 ///< Minimum width to use margins with BM_COLOUR_REMAP.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ALIGN(n) __declspec(align(n))
|
||||
#else
|
||||
#define ALIGN(n) __attribute__ ((aligned (n)))
|
||||
#endif
|
||||
|
||||
#ifndef FULL_ANIMATION
|
||||
#define FULL_ANIMATION 0
|
||||
#endif
|
||||
typedef union ALIGN(16) um128i {
|
||||
__m128i m128i;
|
||||
uint8 m128i_u8[16];
|
||||
uint16 m128i_u16[8];
|
||||
uint32 m128i_u32[4];
|
||||
uint64 m128i_u64[2];
|
||||
} um128i;
|
||||
|
||||
#include "32bpp_sse_type.h"
|
||||
#define CLEAR_HIGH_BYTE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0)
|
||||
#define ALPHA_CONTROL_MASK _mm_setr_epi8( 6, 7, 6, 7, 6, 7, -1, -1, 14, 15, 14, 15, 14, 15, -1, -1)
|
||||
#define PACK_LOW_CONTROL_MASK _mm_setr_epi8( 0, 2, 4, -1, 8, 10, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1)
|
||||
#define PACK_HIGH_CONTROL_MASK _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 0, 2, 4, -1, 8, 10, 12, -1)
|
||||
#define BRIGHTNESS_LOW_CONTROL_MASK _mm_setr_epi8( 1, 2, 1, 2, 1, 2, 0, 2, 3, 2, 3, 2, 3, 2, 0, 2)
|
||||
#define BRIGHTNESS_DIV_CLEANER _mm_setr_epi8(-1, 1, -1, 1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, -1, 0)
|
||||
#define OVERBRIGHT_PRESENCE_MASK _mm_setr_epi8( 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0)
|
||||
#define OVERBRIGHT_VALUE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0)
|
||||
#define OVERBRIGHT_CONTROL_MASK _mm_setr_epi8( 0, 1, 0, 1, 0, 1, 7, 7, 2, 3, 2, 3, 2, 3, 7, 7)
|
||||
#define TRANSPARENT_NOM_BASE _mm_setr_epi16(256, 256, 256, 256, 256, 256, 256, 256)
|
||||
|
||||
#define EXTR32(from, rank) (*(um128i*) &from).m128i_u32[rank]
|
||||
#define EXTR64(from, rank) (*(um128i*) &from).m128i_u64[rank]
|
||||
#define INSR32(val, into, rank) { \
|
||||
(*(um128i*) &into).m128i = _mm_insert_epi16((*(um128i*) &into).m128i, val, (rank)*2); \
|
||||
(*(um128i*) &into).m128i = _mm_insert_epi16((*(um128i*) &into).m128i, (val) >> 16, (rank)*2 + 1); \
|
||||
}
|
||||
#define INSR64(val, into, rank) (*(um128i*) &into).m128i_u64[rank] = (val)
|
||||
|
||||
/* Alpha blend 2 pixels. */
|
||||
#define ALPHA_BLEND_2() { \
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128()); /* PUNPCKLBW, expand each uint8 into uint16 */ \
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128()); \
|
||||
\
|
||||
__m128i alphaAB = _mm_cmpgt_epi16(srcAB, _mm_setzero_si128()); /* PCMPGTW, if (alpha > 0) a++; */ \
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 15); \
|
||||
alphaAB = _mm_add_epi16(alphaAB, srcAB); \
|
||||
alphaAB = _mm_shufflelo_epi16(alphaAB, 0x3F); /* PSHUFLW, put alpha1 in front of each rgb1 */ \
|
||||
alphaAB = _mm_shufflehi_epi16(alphaAB, 0x3F); /* PSHUFHW, put alpha2 in front of each rgb2 */ \
|
||||
\
|
||||
srcAB = _mm_sub_epi16(srcAB, dstAB); /* PSUBW, (r - Cr) */ \
|
||||
srcAB = _mm_mullo_epi16(srcAB, alphaAB); /* PMULLW, a*(r - Cr) */ \
|
||||
srcAB = _mm_srli_epi16(srcAB, 8); /* PSRLW, a*(r - Cr)/256 */ \
|
||||
srcAB = _mm_add_epi16(srcAB, dstAB); /* PADDW, a*(r - Cr)/256 + Cr */ \
|
||||
srcAB = _mm_and_si128(srcAB, clear_hi); /* PAND, wipe high bytes to keep low bytes when packing */ \
|
||||
srcABCD = _mm_packus_epi16(srcAB, srcAB); /* PACKUSWB, pack 2 colours (with saturation) */ \
|
||||
}
|
||||
|
||||
/** Base methods for 32bpp SSE blitters. */
|
||||
class Blitter_32bppSSE_Base {
|
||||
@@ -49,18 +98,6 @@ public:
|
||||
BT_NONE, ///< No specialisation for either case.
|
||||
};
|
||||
|
||||
/** Helper for using specialised functions designed to prevent whenever it's possible things like:
|
||||
* - IO (reading video buffer),
|
||||
* - calculations (alpha blending),
|
||||
* - heavy branching (remap lookups and animation buffer handling).
|
||||
*/
|
||||
enum SpriteFlags {
|
||||
SF_NONE = 0,
|
||||
SF_TRANSLUCENT = 1 << 1, ///< The sprite has at least 1 translucent pixel.
|
||||
SF_NO_REMAP = 1 << 2, ///< The sprite has no remappable colour pixel.
|
||||
SF_NO_ANIM = 1 << 3, ///< The sprite has no palette animated pixel.
|
||||
};
|
||||
|
||||
/** Data stored about a (single) sprite. */
|
||||
struct SpriteInfo {
|
||||
uint32 sprite_offset; ///< The offset to the sprite data.
|
||||
@@ -69,21 +106,21 @@ public:
|
||||
uint16 sprite_width; ///< The width of the sprite.
|
||||
};
|
||||
struct SpriteData {
|
||||
SpriteFlags flags;
|
||||
SpriteInfo infos[ZOOM_LVL_COUNT];
|
||||
byte data[]; ///< Data, all zoomlevels.
|
||||
};
|
||||
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
|
||||
virtual Colour AdjustBrightness(Colour colour, uint8 brightness) = 0;
|
||||
};
|
||||
|
||||
DECLARE_ENUM_AS_BIT_SET(Blitter_32bppSSE_Base::SpriteFlags);
|
||||
|
||||
/** The SSE2 32 bpp blitter (without palette animation). */
|
||||
class Blitter_32bppSSE2 : public Blitter_32bppSimple, public Blitter_32bppSSE_Base {
|
||||
public:
|
||||
virtual Colour AdjustBrightness(Colour colour, uint8 brightness);
|
||||
static Colour ReallyAdjustBrightness(Colour colour, uint8 brightness);
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) {
|
||||
|
@@ -15,9 +15,310 @@
|
||||
#include "../zoom_func.h"
|
||||
#include "../settings_type.h"
|
||||
#include "32bpp_sse4.hpp"
|
||||
#include "32bpp_sse_func.hpp"
|
||||
|
||||
/** Instantiation of the SSE4 32bpp blitter factory. */
|
||||
static FBlitter_32bppSSE4 iFBlitter_32bppSSE4;
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. It is templated to allow faster operation.
|
||||
*
|
||||
* @tparam mode blitter mode
|
||||
* @param bp further blitting parameters
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last>
|
||||
inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
{
|
||||
const byte * const remap = bp->remap;
|
||||
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
|
||||
int effective_width = bp->width;
|
||||
|
||||
/* Find where to start reading in the source sprite. */
|
||||
const SpriteData * const sd = (const SpriteData *) bp->sprite;
|
||||
const SpriteInfo * const si = &sd->infos[zoom];
|
||||
const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
|
||||
const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
|
||||
|
||||
if (read_mode != RM_WITH_MARGIN) {
|
||||
src_rgba_line += bp->skip_left;
|
||||
src_mv_line += bp->skip_left;
|
||||
}
|
||||
|
||||
/* Load these variables into register before loop. */
|
||||
const __m128i a_cm = ALPHA_CONTROL_MASK;
|
||||
const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK;
|
||||
const __m128i briAB_cm = BRIGHTNESS_LOW_CONTROL_MASK;
|
||||
const __m128i div_cleaner = BRIGHTNESS_DIV_CLEANER;
|
||||
const __m128i ob_check = OVERBRIGHT_PRESENCE_MASK;
|
||||
const __m128i ob_mask = OVERBRIGHT_VALUE_MASK;
|
||||
const __m128i ob_cm = OVERBRIGHT_CONTROL_MASK;
|
||||
const __m128i tr_nom_base = TRANSPARENT_NOM_BASE;
|
||||
|
||||
for (int y = bp->height; y != 0; y--) {
|
||||
const Colour *src = src_rgba_line + META_LENGTH;
|
||||
Colour *dst = dst_line;
|
||||
const MapValue *src_mv = src_mv_line;
|
||||
|
||||
switch (mode) {
|
||||
default: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int new_width = effective_width - (delta_diff & ~1);
|
||||
effective_width = delta_diff > 0 ? new_width : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
for (uint x = (uint) effective_width / 2; x > 0; x--) {
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
srcABCD = _mm_blend_epi16(srcABCD, dstABCD, 0xF0);
|
||||
Colour *old_dst = dst;
|
||||
src += 2;
|
||||
dst += 2;
|
||||
/* It is VERY important to read next data before it gets invalidated in cpu cache.
|
||||
* And PEXTR latency is a real problem here.
|
||||
*/
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, srcABCD);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
if (bt_last == BT_ODD) {
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
*dst = (Colour) EXTR32(srcABCD, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BM_COLOUR_REMAP: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
src_mv += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int nd = effective_width - delta_diff;
|
||||
effective_width = delta_diff > 0 ? nd : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
uint32 mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
|
||||
for (uint x = (uint) effective_width / 2; x > 0; x--) {
|
||||
/* Remap colours. */
|
||||
if (mvX2 & 0x00FF00FF) {
|
||||
/* Written so the compiler uses CMOV. */
|
||||
const Colour src0 = src[0];
|
||||
const uint m0 = (byte) mvX2;
|
||||
const uint r0 = remap[m0];
|
||||
const Colour c0map = (this->LookupColourInPalette(r0).data & 0x00FFFFFF) | (src0.data & 0xFF000000);
|
||||
Colour c0 = 0; // Use alpha of 0 to keep dst as is.
|
||||
c0 = r0 == 0 ? c0 : c0map;
|
||||
c0 = m0 != 0 ? c0 : src0;
|
||||
INSR32(c0.data, srcABCD, 0);
|
||||
|
||||
const Colour src1 = src[1];
|
||||
const uint m1 = (byte) (mvX2 >> 16);
|
||||
const uint r1 = remap[m1];
|
||||
const Colour c1map = (this->LookupColourInPalette(r1).data & 0x00FFFFFF) | (src1.data & 0xFF000000);
|
||||
Colour c1 = 0;
|
||||
c1 = r1 == 0 ? c1 : c1map;
|
||||
c1 = m1 != 0 ? c1 : src1;
|
||||
INSR32(c1.data, srcABCD, 1);
|
||||
|
||||
if ((mvX2 & 0xFF00FF00) != 0x80008000) {
|
||||
ADJUST_BRIGHTNESS_2(srcABCD, mvX2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Blend colours. */
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
srcABCD = _mm_blend_epi16(srcABCD, dstABCD, 0xF0);
|
||||
Colour *old_dst = dst;
|
||||
dst += 2;
|
||||
src += 2;
|
||||
src_mv += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, srcABCD);
|
||||
mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
|
||||
if (effective_width & 1) {
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way. */
|
||||
if ((byte) mvX2 == 0) {
|
||||
if (src->a < 255) {
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
(*dst).data = EXTR32(srcABCD, 0);
|
||||
} else
|
||||
*dst = *src;
|
||||
} else {
|
||||
const uint r = remap[(byte) mvX2];
|
||||
if (r != 0) {
|
||||
Colour remapped_colour = AdjustBrightness(this->LookupColourInPalette(r), (byte) (mvX2 >> 8));
|
||||
if (src->a == 255) {
|
||||
*dst = remapped_colour;
|
||||
} else {
|
||||
remapped_colour.a = src->a;
|
||||
INSR32(remapped_colour.data, srcABCD, 0);
|
||||
ALPHA_BLEND_2(pack_low_cm);
|
||||
(*dst).data = EXTR32(srcABCD, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
src_mv_line += si->sprite_width;
|
||||
break;
|
||||
}
|
||||
|
||||
case BM_TRANSPARENT: {
|
||||
/* Make the current colour a bit more black, so it looks like this image is transparent.
|
||||
* rgb = rgb * ((256/4) * 4 - (alpha/4)) / ((256/4) * 4)
|
||||
*/
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
for (uint x = (uint) bp->width / 2; x > 0; x--) {
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i dstCD = _mm_unpackhi_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shuffle_epi8(srcAB, a_cm);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits.
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstCD);
|
||||
Colour *old_dst = dst;
|
||||
src += 2;
|
||||
dst += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, dstAB);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
if (bp->width & 1) {
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shuffle_epi8(srcAB, a_cm);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2);
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstAB);
|
||||
(*dst).data = EXTR32(dstAB, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size);
|
||||
dst_line += bp->pitch;
|
||||
}
|
||||
}
|
||||
IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. Calls adequate templated function.
|
||||
*
|
||||
* @param bp further blitting parameters
|
||||
* @param mode blitter mode
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
void Blitter_32bppSSE4::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
|
||||
{
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
switch (mode) {
|
||||
case BM_NORMAL: {
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) {
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
} else {
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BM_COLOUR_REMAP:
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE>(bp, zoom); return;
|
||||
} else {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE>(bp, zoom); return;
|
||||
}
|
||||
case BM_TRANSPARENT: Draw<BM_TRANSPARENT, RM_NONE, BT_NONE>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/** Same code as seen in 32bpp_sse2.cpp but some macros are not the same. */
|
||||
inline Colour Blitter_32bppSSE4::AdjustBrightness(Colour colour, uint8 brightness)
|
||||
{
|
||||
/* Shortcut for normal brightness. */
|
||||
if (brightness == DEFAULT_BRIGHTNESS) return colour;
|
||||
|
||||
return Blitter_32bppSSE4::ReallyAdjustBrightness(colour, brightness);
|
||||
}
|
||||
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
/* static */ Colour Blitter_32bppSSE4::ReallyAdjustBrightness(Colour colour, uint8 brightness)
|
||||
{
|
||||
ALIGN(16) uint64 c16 = colour.b | (uint64) colour.g << 16 | (uint64) colour.r << 32;
|
||||
c16 *= brightness;
|
||||
uint64 c16_ob = c16; // Helps out of order execution.
|
||||
c16 /= DEFAULT_BRIGHTNESS;
|
||||
c16 &= 0x01FF01FF01FF;
|
||||
|
||||
/* Sum overbright (maximum for each rgb is 508, 9 bits, -255 is changed in -256 so we just have to take the 8 lower bits into account). */
|
||||
c16_ob = (((c16_ob >> (8 + 7)) & 0x0100010001) * 0xFF) & c16;
|
||||
uint64 ob = (uint16) c16_ob + (uint16) (c16_ob >> 16) + (uint16) (c16_ob >> 32);
|
||||
|
||||
const uint32 alpha32 = colour.data & 0xFF000000;
|
||||
__m128i ret;
|
||||
INSR64(c16, ret, 0);
|
||||
if (ob != 0) {
|
||||
/* Reduce overbright strength. */
|
||||
ob /= 2;
|
||||
__m128i ob128;
|
||||
INSR64(ob | ob << 16 | ob << 32, ob128, 0);
|
||||
__m128i white = OVERBRIGHT_VALUE_MASK;
|
||||
__m128i c128 = ret;
|
||||
ret = _mm_subs_epu16(white, c128); /* PSUBUSW, (255 - rgb) */
|
||||
ret = _mm_mullo_epi16(ret, ob128); /* PMULLW, ob*(255 - rgb) */
|
||||
ret = _mm_srli_epi16(ret, 8); /* PSRLW, ob*(255 - rgb)/256 */
|
||||
ret = _mm_add_epi16(ret, c128); /* PADDW, ob*(255 - rgb)/256 + rgb */
|
||||
}
|
||||
|
||||
ret = _mm_packus_epi16(ret, ret); /* PACKUSWB, saturate and pack. */
|
||||
return alpha32 | EXTR32(ret, 0);
|
||||
}
|
||||
IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -14,21 +14,38 @@
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
#ifndef SSE_VERSION
|
||||
#define SSE_VERSION 4
|
||||
#endif
|
||||
|
||||
#ifndef FULL_ANIMATION
|
||||
#define FULL_ANIMATION 0
|
||||
#endif
|
||||
|
||||
#include "32bpp_ssse3.hpp"
|
||||
#include "smmintrin.h"
|
||||
|
||||
#undef EXTR32
|
||||
#define EXTR32(from, rank) _mm_extract_epi32((*(um128i*) &from).m128i, rank)
|
||||
#undef INSR32
|
||||
#define INSR32(val, into, rank) (*(um128i*) &into).m128i = _mm_insert_epi32((*(um128i*) &into).m128i, val, rank)
|
||||
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
#ifdef _SQ64
|
||||
#undef INSR64
|
||||
#define INSR64(val, into, rank) (*(um128i*) &into).m128i = _mm_insert_epi64((*(um128i*) &into).m128i, val, rank)
|
||||
#else
|
||||
typedef union { uint64 u64; struct _u32 { uint32 low, high; } u32; } u6432;
|
||||
#undef INSR64
|
||||
#define INSR64(val, into, rank) { \
|
||||
u6432 v; \
|
||||
v.u64 = val; \
|
||||
(*(um128i*) &into).m128i = _mm_insert_epi32((*(um128i*) &into).m128i, v.u32.low, (rank)*2); \
|
||||
(*(um128i*) &into).m128i = _mm_insert_epi32((*(um128i*) &into).m128i, v.u32.high, (rank)*2 + 1); \
|
||||
}
|
||||
#endif
|
||||
IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
|
||||
/** The SSE4 32 bpp blitter (without palette animation). */
|
||||
class Blitter_32bppSSE4 : public Blitter_32bppSSSE3 {
|
||||
public:
|
||||
Colour AdjustBrightness(Colour colour, uint8 brightness);
|
||||
static Colour ReallyAdjustBrightness(Colour colour, uint8 brightness);
|
||||
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
/* virtual */ const char *GetName() { return "32bpp-sse4"; }
|
||||
};
|
||||
|
@@ -1,437 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file 32bpp_sse_func.hpp Functions related to SSE 32 bpp blitter. */
|
||||
|
||||
#ifndef BLITTER_32BPP_SSE_FUNC_HPP
|
||||
#define BLITTER_32BPP_SSE_FUNC_HPP
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
static inline void InsertFirstUint32(const uint32 value, __m128i &into)
|
||||
{
|
||||
#if (SSE_VERSION >= 4)
|
||||
into = _mm_insert_epi32(into, value, 0);
|
||||
#else
|
||||
into = _mm_insert_epi16(into, value, 0);
|
||||
into = _mm_insert_epi16(into, value >> 16, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void InsertSecondUint32(const uint32 value, __m128i &into)
|
||||
{
|
||||
#if (SSE_VERSION >= 4)
|
||||
into = _mm_insert_epi32(into, value, 1);
|
||||
#else
|
||||
into = _mm_insert_epi16(into, value, 2);
|
||||
into = _mm_insert_epi16(into, value >> 16, 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void LoadUint64(const uint64 value, __m128i &into)
|
||||
{
|
||||
#ifdef _SQ64
|
||||
into = _mm_cvtsi64_si128(value);
|
||||
#else
|
||||
#if (SSE_VERSION >= 4)
|
||||
into = _mm_cvtsi32_si128(value);
|
||||
InsertSecondUint32(value >> 32, into);
|
||||
#else
|
||||
(*(um128i*) &into).m128i_u64[0] = value;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i PackUnsaturated(__m128i from, const __m128i &mask)
|
||||
{
|
||||
#if (SSE_VERSION == 2)
|
||||
from = _mm_and_si128(from, mask); // PAND, wipe high bytes to keep low bytes when packing
|
||||
return _mm_packus_epi16(from, from); // PACKUSWB, pack 2 colours (with saturation)
|
||||
#else
|
||||
return _mm_shuffle_epi8(from, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i DistributeAlpha(const __m128i from, const __m128i &mask)
|
||||
{
|
||||
#if (SSE_VERSION == 2)
|
||||
__m128i alphaAB = _mm_shufflelo_epi16(from, 0x3F); // PSHUFLW, put alpha1 in front of each rgb1
|
||||
return _mm_shufflehi_epi16(alphaAB, 0x3F); // PSHUFHW, put alpha2 in front of each rgb2
|
||||
#else
|
||||
return _mm_shuffle_epi8(from, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i AlphaBlendTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &pack_mask)
|
||||
{
|
||||
__m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128()); // PUNPCKLBW, expand each uint8 into uint16
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128());
|
||||
|
||||
__m128i alphaAB = _mm_cmpgt_epi16(srcAB, _mm_setzero_si128()); // PCMPGTW, if (alpha > 0) a++;
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 15);
|
||||
alphaAB = _mm_add_epi16(alphaAB, srcAB);
|
||||
alphaAB = DistributeAlpha(alphaAB, distribution_mask);
|
||||
|
||||
srcAB = _mm_sub_epi16(srcAB, dstAB); // PSUBW, (r - Cr)
|
||||
srcAB = _mm_mullo_epi16(srcAB, alphaAB); // PMULLW, a*(r - Cr)
|
||||
srcAB = _mm_srli_epi16(srcAB, 8); // PSRLW, a*(r - Cr)/256
|
||||
srcAB = _mm_add_epi16(srcAB, dstAB); // PADDW, a*(r - Cr)/256 + Cr
|
||||
return PackUnsaturated(srcAB, pack_mask);
|
||||
}
|
||||
|
||||
/* Darken 2 pixels.
|
||||
* rgb = rgb * ((256/4) * 4 - (alpha/4)) / ((256/4) * 4)
|
||||
*/
|
||||
static inline __m128i DarkenTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &tr_nom_base)
|
||||
{
|
||||
__m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128());
|
||||
__m128i alphaAB = DistributeAlpha(srcAB, distribution_mask);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits.
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
return _mm_packus_epi16(dstAB, dstAB);
|
||||
}
|
||||
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
static Colour ReallyAdjustBrightness(Colour colour, uint8 brightness)
|
||||
{
|
||||
uint64 c16 = colour.b | (uint64) colour.g << 16 | (uint64) colour.r << 32;
|
||||
c16 *= brightness;
|
||||
uint64 c16_ob = c16; // Helps out of order execution.
|
||||
c16 /= Blitter_32bppBase::DEFAULT_BRIGHTNESS;
|
||||
c16 &= 0x01FF01FF01FF;
|
||||
|
||||
/* Sum overbright (maximum for each rgb is 508, 9 bits, -255 is changed in -256 so we just have to take the 8 lower bits into account). */
|
||||
c16_ob = (((c16_ob >> (8 + 7)) & 0x0100010001) * 0xFF) & c16;
|
||||
const uint ob = ((uint16) c16_ob + (uint16) (c16_ob >> 16) + (uint16) (c16_ob >> 32)) / 2;
|
||||
|
||||
const uint32 alpha32 = colour.data & 0xFF000000;
|
||||
__m128i ret;
|
||||
LoadUint64(c16, ret);
|
||||
if (ob != 0) {
|
||||
__m128i ob128 = _mm_cvtsi32_si128(ob);
|
||||
ob128 = _mm_shufflelo_epi16(ob128, 0xC0);
|
||||
__m128i white = OVERBRIGHT_VALUE_MASK;
|
||||
__m128i c128 = ret;
|
||||
ret = _mm_subs_epu16(white, c128); // PSUBUSW, (255 - rgb)
|
||||
ret = _mm_mullo_epi16(ret, ob128); // PMULLW, ob*(255 - rgb)
|
||||
ret = _mm_srli_epi16(ret, 8); // PSRLW, ob*(255 - rgb)/256
|
||||
ret = _mm_add_epi16(ret, c128); // PADDW, ob*(255 - rgb)/256 + rgb
|
||||
}
|
||||
|
||||
ret = _mm_packus_epi16(ret, ret); // PACKUSWB, saturate and pack.
|
||||
return alpha32 | _mm_cvtsi128_si32(ret);
|
||||
}
|
||||
IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
|
||||
/** ReallyAdjustBrightness() is not called that often.
|
||||
* Inlining this function implies a far jump, which has a huge latency.
|
||||
*/
|
||||
static inline Colour AdjustBrightneSSE(Colour colour, uint8 brightness)
|
||||
{
|
||||
/* Shortcut for normal brightness. */
|
||||
if (brightness == Blitter_32bppBase::DEFAULT_BRIGHTNESS) return colour;
|
||||
|
||||
return ReallyAdjustBrightness(colour, brightness);
|
||||
}
|
||||
|
||||
static inline __m128i AdjustBrightnessOfTwoPixels(__m128i from, uint32 brightness)
|
||||
{
|
||||
#if (SSE_VERSION < 3)
|
||||
NOT_REACHED();
|
||||
#else
|
||||
/* The following dataflow differs from the one of AdjustBrightness() only for alpha.
|
||||
* In order to keep alpha in colAB, insert a 1 in a unused brightness byte (a*1->a).
|
||||
* OK, not a 1 but DEFAULT_BRIGHTNESS to compensate the div.
|
||||
*/
|
||||
brightness &= 0xFF00FF00;
|
||||
brightness += Blitter_32bppBase::DEFAULT_BRIGHTNESS;
|
||||
|
||||
__m128i colAB = _mm_unpacklo_epi8(from, _mm_setzero_si128());
|
||||
__m128i briAB = _mm_cvtsi32_si128(brightness);
|
||||
briAB = _mm_shuffle_epi8(briAB, BRIGHTNESS_LOW_CONTROL_MASK); // DEFAULT_BRIGHTNESS in 0, 0x00 in 2.
|
||||
colAB = _mm_mullo_epi16(colAB, briAB);
|
||||
__m128i colAB_ob = _mm_srli_epi16(colAB, 8+7);
|
||||
colAB = _mm_srli_epi16(colAB, 7);
|
||||
|
||||
/* Sum overbright.
|
||||
* Maximum for each rgb is 508 => 9 bits. The highest bit tells if there is overbright.
|
||||
* -255 is changed in -256 so we just have to take the 8 lower bits into account.
|
||||
*/
|
||||
colAB = _mm_and_si128(colAB, BRIGHTNESS_DIV_CLEANER);
|
||||
colAB_ob = _mm_and_si128(colAB_ob, OVERBRIGHT_PRESENCE_MASK);
|
||||
colAB_ob = _mm_mullo_epi16(colAB_ob, OVERBRIGHT_VALUE_MASK);
|
||||
colAB_ob = _mm_and_si128(colAB_ob, colAB);
|
||||
__m128i obAB = _mm_hadd_epi16(_mm_hadd_epi16(colAB_ob, _mm_setzero_si128()), _mm_setzero_si128());
|
||||
|
||||
obAB = _mm_srli_epi16(obAB, 1); // Reduce overbright strength.
|
||||
obAB = _mm_shuffle_epi8(obAB, OVERBRIGHT_CONTROL_MASK);
|
||||
__m128i retAB = OVERBRIGHT_VALUE_MASK; // ob_mask is equal to white.
|
||||
retAB = _mm_subs_epu16(retAB, colAB); // (255 - rgb)
|
||||
retAB = _mm_mullo_epi16(retAB, obAB); // ob*(255 - rgb)
|
||||
retAB = _mm_srli_epi16(retAB, 8); // ob*(255 - rgb)/256
|
||||
retAB = _mm_add_epi16(retAB, colAB); // ob*(255 - rgb)/256 + rgb
|
||||
|
||||
return _mm_packus_epi16(retAB, retAB);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FULL_ANIMATION == 0
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. It is templated to allow faster operation.
|
||||
*
|
||||
* @tparam mode blitter mode
|
||||
* @param bp further blitting parameters
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
IGNORE_UNINITIALIZED_WARNING_START
|
||||
template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last, bool translucent>
|
||||
#if (SSE_VERSION == 2)
|
||||
inline void Blitter_32bppSSE2::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
#elif (SSE_VERSION == 3)
|
||||
inline void Blitter_32bppSSSE3::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
#elif (SSE_VERSION == 4)
|
||||
inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
#endif
|
||||
{
|
||||
const byte * const remap = bp->remap;
|
||||
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
|
||||
int effective_width = bp->width;
|
||||
|
||||
/* Find where to start reading in the source sprite. */
|
||||
const SpriteData * const sd = (const SpriteData *) bp->sprite;
|
||||
const SpriteInfo * const si = &sd->infos[zoom];
|
||||
const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
|
||||
const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
|
||||
|
||||
if (read_mode != RM_WITH_MARGIN) {
|
||||
src_rgba_line += bp->skip_left;
|
||||
src_mv_line += bp->skip_left;
|
||||
}
|
||||
const MapValue *src_mv = src_mv_line;
|
||||
|
||||
/* Load these variables into register before loop. */
|
||||
#if (SSE_VERSION == 2)
|
||||
const __m128i clear_hi = CLEAR_HIGH_BYTE_MASK;
|
||||
#define ALPHA_BLEND_PARAM_1 clear_hi
|
||||
#define ALPHA_BLEND_PARAM_2 clear_hi
|
||||
#define DARKEN_PARAM_1 tr_nom_base
|
||||
#define DARKEN_PARAM_2 tr_nom_base
|
||||
#else
|
||||
const __m128i a_cm = ALPHA_CONTROL_MASK;
|
||||
const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK;
|
||||
#define ALPHA_BLEND_PARAM_1 a_cm
|
||||
#define ALPHA_BLEND_PARAM_2 pack_low_cm
|
||||
#define DARKEN_PARAM_1 a_cm
|
||||
#define DARKEN_PARAM_2 tr_nom_base
|
||||
#endif
|
||||
const __m128i tr_nom_base = TRANSPARENT_NOM_BASE;
|
||||
|
||||
for (int y = bp->height; y != 0; y--) {
|
||||
Colour *dst = dst_line;
|
||||
const Colour *src = src_rgba_line + META_LENGTH;
|
||||
if (mode == BM_COLOUR_REMAP) src_mv = src_mv_line;
|
||||
|
||||
if (read_mode == RM_WITH_MARGIN) {
|
||||
assert(bt_last == BT_NONE); // or you must ensure block type is preserved
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
if (mode == BM_COLOUR_REMAP) src_mv += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int new_width = effective_width - delta_diff;
|
||||
effective_width = delta_diff > 0 ? new_width : effective_width;
|
||||
if (effective_width <= 0) goto next_line;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
if (!translucent) {
|
||||
for (uint x = (uint) effective_width; x > 0; x--) {
|
||||
if (src->a) *dst = *src;
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint x = (uint) effective_width / 2; x > 0; x--) {
|
||||
__m128i srcABCD = _mm_loadl_epi64((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
|
||||
_mm_storel_epi64((__m128i*) dst, AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2));
|
||||
src += 2;
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
__m128i srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2));
|
||||
}
|
||||
break;
|
||||
|
||||
case BM_COLOUR_REMAP:
|
||||
#if (SSE_VERSION >= 3)
|
||||
for (uint x = (uint) effective_width / 2; x > 0; x--) {
|
||||
__m128i srcABCD = _mm_loadl_epi64((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
|
||||
uint32 mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
|
||||
/* Remap colours. */
|
||||
if (mvX2 & 0x00FF00FF) {
|
||||
#define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \
|
||||
/* Written so the compiler uses CMOV. */ \
|
||||
Colour m_colour = m_colour_init; \
|
||||
{ \
|
||||
const Colour srcm = (Colour) (m_src); \
|
||||
const uint m = (byte) (m_m); \
|
||||
const uint r = remap[m]; \
|
||||
const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \
|
||||
m_colour = r == 0 ? m_colour : cmap; \
|
||||
m_colour = m != 0 ? m_colour : srcm; \
|
||||
}
|
||||
#ifdef _SQ64
|
||||
uint64 srcs = _mm_cvtsi128_si64(srcABCD);
|
||||
uint64 remapped_src = 0;
|
||||
CMOV_REMAP(c0, 0, srcs, mvX2);
|
||||
remapped_src = c0.data;
|
||||
CMOV_REMAP(c1, 0, srcs >> 32, mvX2 >> 16);
|
||||
remapped_src |= (uint64) c1.data << 32;
|
||||
srcABCD = _mm_cvtsi64_si128(remapped_src);
|
||||
#else
|
||||
Colour remapped_src[2];
|
||||
CMOV_REMAP(c0, 0, _mm_cvtsi128_si32(srcABCD), mvX2);
|
||||
remapped_src[0] = c0.data;
|
||||
CMOV_REMAP(c1, 0, src[1], mvX2 >> 16);
|
||||
remapped_src[1] = c1.data;
|
||||
srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src);
|
||||
#endif
|
||||
|
||||
if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2);
|
||||
}
|
||||
|
||||
/* Blend colours. */
|
||||
_mm_storel_epi64((__m128i *) dst, AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2));
|
||||
dst += 2;
|
||||
src += 2;
|
||||
src_mv += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
#else
|
||||
for (uint x = (uint) effective_width; x > 0; x--) {
|
||||
#endif
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way. */
|
||||
__m128i srcABCD;
|
||||
if (src_mv->m) {
|
||||
const uint r = remap[src_mv->m];
|
||||
if (r != 0) {
|
||||
Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v);
|
||||
if (src->a == 255) {
|
||||
*dst = remapped_colour;
|
||||
} else {
|
||||
remapped_colour.a = src->a;
|
||||
srcABCD = _mm_cvtsi32_si128(remapped_colour.data);
|
||||
goto bmcr_alpha_blend_single;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
if (src->a < 255) {
|
||||
bmcr_alpha_blend_single:
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2);
|
||||
}
|
||||
dst->data = _mm_cvtsi128_si32(srcABCD);
|
||||
}
|
||||
#if (SSE_VERSION == 2)
|
||||
src_mv++;
|
||||
dst++;
|
||||
src++;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case BM_TRANSPARENT:
|
||||
/* Make the current colour a bit more black, so it looks like this image is transparent. */
|
||||
for (uint x = (uint) bp->width / 2; x > 0; x--) {
|
||||
__m128i srcABCD = _mm_loadl_epi64((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
|
||||
_mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, DARKEN_PARAM_1, DARKEN_PARAM_2));
|
||||
src += 2;
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) {
|
||||
__m128i srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, DARKEN_PARAM_1, DARKEN_PARAM_2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
next_line:
|
||||
if (mode == BM_COLOUR_REMAP) src_mv_line += si->sprite_width;
|
||||
src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size);
|
||||
dst_line += bp->pitch;
|
||||
}
|
||||
}
|
||||
IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. Calls adequate templated function.
|
||||
*
|
||||
* @param bp further blitting parameters
|
||||
* @param mode blitter mode
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
#if (SSE_VERSION == 2)
|
||||
void Blitter_32bppSSE2::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
|
||||
#elif (SSE_VERSION == 3)
|
||||
void Blitter_32bppSSSE3::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
|
||||
#elif (SSE_VERSION == 4)
|
||||
void Blitter_32bppSSE4::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
|
||||
#endif
|
||||
{
|
||||
switch (mode) {
|
||||
default: {
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) {
|
||||
bm_normal:
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
switch (bt_last) {
|
||||
default: Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN, true>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD, true>(bp, zoom); return;
|
||||
}
|
||||
} else {
|
||||
if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags & SF_TRANSLUCENT) {
|
||||
Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true>(bp, zoom);
|
||||
} else {
|
||||
Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, false>(bp, zoom);
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BM_COLOUR_REMAP:
|
||||
if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags & SF_NO_REMAP) goto bm_normal;
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE, true>(bp, zoom); return;
|
||||
} else {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE, true>(bp, zoom); return;
|
||||
}
|
||||
case BM_TRANSPARENT: Draw<BM_TRANSPARENT, RM_NONE, BT_NONE, true>(bp, zoom); return;
|
||||
}
|
||||
}
|
||||
#endif /* FULL_ANIMATION */
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
#endif /* BLITTER_32BPP_SSE_FUNC_HPP */
|
@@ -1,56 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD 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, version 2.
|
||||
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file 32bpp_sse_type.hpp Types related to SSE 32 bpp blitter. */
|
||||
|
||||
#ifndef BLITTER_32BPP_SSE_TYPE_HPP
|
||||
#define BLITTER_32BPP_SSE_TYPE_HPP
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
#include "32bpp_simple.hpp"
|
||||
#if (SSE_VERSION == 2)
|
||||
#include <emmintrin.h>
|
||||
#elif (SSE_VERSION == 3)
|
||||
#include <tmmintrin.h>
|
||||
#elif (SSE_VERSION == 4)
|
||||
#include <smmintrin.h>
|
||||
#endif
|
||||
|
||||
#define META_LENGTH 2 ///< Number of uint32 inserted before each line of pixels in a sprite.
|
||||
#define MARGIN_NORMAL_THRESHOLD (zoom == ZOOM_LVL_OUT_32X ? 8 : 4) ///< Minimum width to use margins with BM_NORMAL.
|
||||
#define MARGIN_REMAP_THRESHOLD 4 ///< Minimum width to use margins with BM_COLOUR_REMAP.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ALIGN(n) __declspec(align(n))
|
||||
#else
|
||||
#define ALIGN(n) __attribute__ ((aligned (n)))
|
||||
#endif
|
||||
|
||||
typedef union ALIGN(16) um128i {
|
||||
__m128i m128i;
|
||||
uint8 m128i_u8[16];
|
||||
uint16 m128i_u16[8];
|
||||
uint32 m128i_u32[4];
|
||||
uint64 m128i_u64[2];
|
||||
} um128i;
|
||||
|
||||
#define CLEAR_HIGH_BYTE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0)
|
||||
#define ALPHA_CONTROL_MASK _mm_setr_epi8( 6, 7, 6, 7, 6, 7, -1, -1, 14, 15, 14, 15, 14, 15, -1, -1)
|
||||
#define PACK_LOW_CONTROL_MASK _mm_setr_epi8( 0, 2, 4, -1, 8, 10, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1)
|
||||
#define PACK_HIGH_CONTROL_MASK _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 0, 2, 4, -1, 8, 10, 12, -1)
|
||||
#define BRIGHTNESS_LOW_CONTROL_MASK _mm_setr_epi8( 1, 2, 1, 2, 1, 2, 0, 2, 3, 2, 3, 2, 3, 2, 0, 2)
|
||||
#define BRIGHTNESS_DIV_CLEANER _mm_setr_epi8(-1, 1, -1, 1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, -1, 0)
|
||||
#define OVERBRIGHT_PRESENCE_MASK _mm_setr_epi8( 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0)
|
||||
#define OVERBRIGHT_VALUE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0)
|
||||
#define OVERBRIGHT_CONTROL_MASK _mm_setr_epi8( 0, 1, 0, 1, 0, 1, 7, 7, 2, 3, 2, 3, 2, 3, 7, 7)
|
||||
#define TRANSPARENT_NOM_BASE _mm_setr_epi16(256, 256, 256, 256, 256, 256, 256, 256)
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
#endif /* BLITTER_32BPP_SSE_TYPE_HPP */
|
@@ -15,9 +15,273 @@
|
||||
#include "../zoom_func.h"
|
||||
#include "../settings_type.h"
|
||||
#include "32bpp_ssse3.hpp"
|
||||
#include "32bpp_sse_func.hpp"
|
||||
|
||||
/** Instantiation of the SSSE3 32bpp blitter factory. */
|
||||
static FBlitter_32bppSSSE3 iFBlitter_32bppSSSE3;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. It is templated to allow faster operation.
|
||||
*
|
||||
* @tparam mode blitter mode
|
||||
* @param bp further blitting parameters
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last>
|
||||
inline void Blitter_32bppSSSE3::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
{
|
||||
const byte * const remap = bp->remap;
|
||||
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
|
||||
int effective_width = bp->width;
|
||||
|
||||
/* Find where to start reading in the source sprite */
|
||||
const SpriteData * const sd = (const SpriteData *) bp->sprite;
|
||||
const SpriteInfo * const si = &sd->infos[zoom];
|
||||
const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
|
||||
const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
|
||||
|
||||
if (read_mode != RM_WITH_MARGIN) {
|
||||
src_rgba_line += bp->skip_left;
|
||||
src_mv_line += bp->skip_left;
|
||||
}
|
||||
|
||||
/* Load these variables into register before loop. */
|
||||
const __m128i a_cm = ALPHA_CONTROL_MASK;
|
||||
const __m128i pack_hi_cm = PACK_HIGH_CONTROL_MASK;
|
||||
const __m128i briAB_cm = BRIGHTNESS_LOW_CONTROL_MASK;
|
||||
const __m128i div_cleaner = BRIGHTNESS_DIV_CLEANER;
|
||||
const __m128i ob_check = OVERBRIGHT_PRESENCE_MASK;
|
||||
const __m128i ob_mask = OVERBRIGHT_VALUE_MASK;
|
||||
const __m128i ob_cm = OVERBRIGHT_CONTROL_MASK;
|
||||
const __m128i tr_nom_base = TRANSPARENT_NOM_BASE;
|
||||
|
||||
for (int y = bp->height; y != 0; y--) {
|
||||
Colour *dst = dst_line;
|
||||
const Colour *src = src_rgba_line + META_LENGTH;
|
||||
const MapValue *src_mv = src_mv_line;
|
||||
|
||||
switch (mode) {
|
||||
default: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int new_width = effective_width - (delta_diff & ~1);
|
||||
effective_width = delta_diff > 0 ? new_width : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
for (uint x = (uint) effective_width / 2; x > 0; x--) {
|
||||
ALPHA_BLEND_2(pack_hi_cm);
|
||||
/* With high repack, srcABCD have its 2 blended pixels like: [S0 S1 S2 S3] -> [-- -- BS0 BS1]
|
||||
* dstABCD shuffled: [D0 D1 D2 D3] -> [D2 D3 D0 D0]
|
||||
* PALIGNR takes what's in (): [-- -- (BS0 BS1] [D2 D3) D0 D0]
|
||||
*/
|
||||
dstABCD = _mm_shuffle_epi32(dstABCD, 0x0E);
|
||||
srcABCD = _mm_alignr_epi8(dstABCD, srcABCD, 8);
|
||||
Colour *old_dst = dst;
|
||||
src += 2;
|
||||
dst += 2;
|
||||
/* It is VERY important to read next data before it gets invalidated in cpu cache. */
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, srcABCD);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
if (bt_last == BT_ODD) {
|
||||
ALPHA_BLEND_2(pack_hi_cm);
|
||||
(*dst).data = EXTR32(srcABCD, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BM_COLOUR_REMAP: {
|
||||
switch (read_mode) {
|
||||
case RM_WITH_MARGIN: {
|
||||
src += src_rgba_line[0].data;
|
||||
src_mv += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
const int width_diff = si->sprite_width - bp->width;
|
||||
effective_width = bp->width - (int) src_rgba_line[0].data;
|
||||
const int delta_diff = (int) src_rgba_line[1].data - width_diff;
|
||||
const int nd = effective_width - delta_diff;
|
||||
effective_width = delta_diff > 0 ? nd : effective_width;
|
||||
if (effective_width <= 0) break;
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case RM_WITH_SKIP: {
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
uint32 mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
|
||||
for (uint x = (uint) effective_width / 2; x > 0; x--) {
|
||||
/* Remap colours. */
|
||||
if (mvX2 & 0x00FF00FF) {
|
||||
/* Written so the compiler uses CMOV. */
|
||||
const Colour src0 = src[0];
|
||||
const uint m0 = (byte) mvX2;
|
||||
const uint r0 = remap[m0];
|
||||
const Colour c0map = (this->LookupColourInPalette(r0).data & 0x00FFFFFF) | (src0.data & 0xFF000000);
|
||||
Colour c0 = 0; // Use alpha of 0 to keep dst as is.
|
||||
c0 = r0 == 0 ? c0 : c0map;
|
||||
c0 = m0 != 0 ? c0 : src0;
|
||||
INSR32(c0.data, srcABCD, 0);
|
||||
|
||||
const Colour src1 = src[1];
|
||||
const uint m1 = (byte) (mvX2 >> 16);
|
||||
const uint r1 = remap[m1];
|
||||
const Colour c1map = (this->LookupColourInPalette(r1).data & 0x00FFFFFF) | (src1.data & 0xFF000000);
|
||||
Colour c1 = 0;
|
||||
c1 = r1 == 0 ? c1 : c1map;
|
||||
c1 = m1 != 0 ? c1 : src1;
|
||||
INSR32(c1.data, srcABCD, 1);
|
||||
|
||||
if ((mvX2 & 0xFF00FF00) != 0x80008000) {
|
||||
ADJUST_BRIGHTNESS_2(srcABCD, mvX2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Blend colours. */
|
||||
ALPHA_BLEND_2(pack_hi_cm);
|
||||
dstABCD = _mm_shuffle_epi32(dstABCD, 0x0E);
|
||||
srcABCD = _mm_alignr_epi8(dstABCD, srcABCD, 8);
|
||||
Colour *old_dst = dst;
|
||||
dst += 2;
|
||||
src += 2;
|
||||
src_mv += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, srcABCD);
|
||||
mvX2 = *((uint32 *) const_cast<MapValue *>(src_mv));
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
|
||||
if (effective_width & 1) {
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (src_mv->m == 0) {
|
||||
if (src->a < 255) {
|
||||
ALPHA_BLEND_2(pack_hi_cm);
|
||||
(*dst).data = EXTR32(srcABCD, 2);
|
||||
} else {
|
||||
*dst = src->data;
|
||||
}
|
||||
} else {
|
||||
const uint r = remap[src_mv->m];
|
||||
if (r != 0) {
|
||||
Colour remapped_colour = AdjustBrightness(this->LookupColourInPalette(r), src_mv->v);
|
||||
if (src->a < 255) {
|
||||
remapped_colour.a = src->a;
|
||||
INSR32(remapped_colour.data, srcABCD, 0);
|
||||
ALPHA_BLEND_2(pack_hi_cm);
|
||||
(*dst).data = EXTR32(srcABCD, 2);
|
||||
} else
|
||||
*dst = remapped_colour;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
src_mv_line += si->sprite_width;
|
||||
break;
|
||||
}
|
||||
case BM_TRANSPARENT: {
|
||||
/* Make the current colour a bit more black, so it looks like this image is transparent.
|
||||
* rgb = rgb * ((256/4) * 4 - (alpha/4)) / ((256/4) * 4)
|
||||
*/
|
||||
__m128i srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
__m128i dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
for (uint x = (uint) bp->width / 2; x > 0; x--) {
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i dstCD = _mm_unpackhi_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shuffle_epi8(srcAB, a_cm);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits.
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstCD);
|
||||
Colour *old_dst = dst;
|
||||
src += 2;
|
||||
dst += 2;
|
||||
dstABCD = _mm_loadu_si128((__m128i*) dst);
|
||||
_mm_storeu_si128((__m128i *) old_dst, dstAB);
|
||||
srcABCD = _mm_loadu_si128((const __m128i*) src);
|
||||
}
|
||||
if (bp->width & 1) {
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128());
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128());
|
||||
__m128i alphaAB = _mm_shuffle_epi8(srcAB, a_cm);
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 2);
|
||||
__m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
|
||||
dstAB = _mm_mullo_epi16(dstAB, nom);
|
||||
dstAB = _mm_srli_epi16(dstAB, 8);
|
||||
dstAB = _mm_packus_epi16(dstAB, dstAB);
|
||||
(*dst).data = EXTR32(dstAB, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size);
|
||||
dst_line += bp->pitch;
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. Calls adequate templated function.
|
||||
*
|
||||
* @param bp further blitting parameters
|
||||
* @param mode blitter mode
|
||||
* @param zoom zoom level at which we are drawing
|
||||
*/
|
||||
void Blitter_32bppSSSE3::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
|
||||
{
|
||||
switch (mode) {
|
||||
case BM_NORMAL: {
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) {
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
} else {
|
||||
switch (bt_last) {
|
||||
case BT_EVEN: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_EVEN>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BM_NORMAL, RM_WITH_MARGIN, BT_ODD>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BM_COLOUR_REMAP:
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE>(bp, zoom); return;
|
||||
} else {
|
||||
Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE>(bp, zoom); return;
|
||||
}
|
||||
case BM_TRANSPARENT: Draw<BM_TRANSPARENT, RM_NONE, BT_NONE>(bp, zoom); return;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -14,21 +14,71 @@
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
#ifndef SSE_VERSION
|
||||
#define SSE_VERSION 3
|
||||
#endif
|
||||
|
||||
#ifndef FULL_ANIMATION
|
||||
#define FULL_ANIMATION 0
|
||||
#endif
|
||||
|
||||
#include "32bpp_sse2.hpp"
|
||||
#include "tmmintrin.h"
|
||||
|
||||
/* Alpha blend 2 pixels. */
|
||||
#undef ALPHA_BLEND_2
|
||||
#define ALPHA_BLEND_2(m_pack_mask) { \
|
||||
__m128i srcAB = _mm_unpacklo_epi8(srcABCD, _mm_setzero_si128()); /* PUNPCKLBW, expand each uint8 into uint16 */ \
|
||||
__m128i dstAB = _mm_unpacklo_epi8(dstABCD, _mm_setzero_si128()); \
|
||||
\
|
||||
__m128i alphaAB = _mm_cmpgt_epi16(srcAB, _mm_setzero_si128()); /* PCMPGTW, if (alpha > 0) a++; */ \
|
||||
alphaAB = _mm_srli_epi16(alphaAB, 15); \
|
||||
alphaAB = _mm_add_epi16(alphaAB, srcAB); \
|
||||
alphaAB = _mm_shuffle_epi8(alphaAB, a_cm); /* PSHUFB, put alpha in front of each rgb */ \
|
||||
\
|
||||
srcAB = _mm_sub_epi16(srcAB, dstAB); /* PSUBW, (r - Cr) */ \
|
||||
srcAB = _mm_mullo_epi16(srcAB, alphaAB); /* PMULLW, a*(r - Cr) */ \
|
||||
srcAB = _mm_srli_epi16(srcAB, 8); /* PSRLW, a*(r - Cr)/256 */ \
|
||||
srcAB = _mm_add_epi16(srcAB, dstAB); /* PADDW, a*(r - Cr)/256 + Cr */ \
|
||||
srcABCD = _mm_shuffle_epi8(srcAB, m_pack_mask); /* PSHUFB, pack 2 Colour (without saturation) */ \
|
||||
}
|
||||
|
||||
/* Adjust brightness of 2 pixels. */
|
||||
#define ADJUST_BRIGHTNESS_2(colourX2, brightnessX2) \
|
||||
/* The following dataflow differs from the one of AdjustBrightness() only for alpha.
|
||||
* In order to keep alpha in colAB, insert a 1 in a unused brightness byte (a*1->a).
|
||||
* OK, not a 1 but DEFAULT_BRIGHTNESS to compensate the div.
|
||||
*/ \
|
||||
brightnessX2 &= 0xFF00FF00; \
|
||||
brightnessX2 += DEFAULT_BRIGHTNESS; \
|
||||
\
|
||||
__m128i zero = _mm_setzero_si128(); \
|
||||
__m128i colAB = _mm_unpacklo_epi8(colourX2, zero); \
|
||||
\
|
||||
__m128i briAB; \
|
||||
INSR64(brightnessX2, briAB, 0); \
|
||||
briAB = _mm_shuffle_epi8(briAB, briAB_cm); /* DEFAULT_BRIGHTNESS in 0, 0x00 in 2. */ \
|
||||
colAB = _mm_mullo_epi16(colAB, briAB); \
|
||||
__m128i colAB_ob = _mm_srli_epi16(colAB, 8+7); \
|
||||
colAB = _mm_srli_epi16(colAB, 7); \
|
||||
\
|
||||
/* Sum overbright.
|
||||
* Maximum for each rgb is 508 => 9 bits. The highest bit tells if there is overbright.
|
||||
* -255 is changed in -256 so we just have to take the 8 lower bits into account.
|
||||
*/ \
|
||||
colAB = _mm_and_si128(colAB, div_cleaner); \
|
||||
colAB_ob = _mm_and_si128(colAB_ob, ob_check); \
|
||||
colAB_ob = _mm_mullo_epi16(colAB_ob, ob_mask); \
|
||||
colAB_ob = _mm_and_si128(colAB_ob, colAB); \
|
||||
__m128i obAB = _mm_hadd_epi16(_mm_hadd_epi16(colAB_ob, zero), zero); \
|
||||
\
|
||||
obAB = _mm_srli_epi16(obAB, 1); /* Reduce overbright strength. */ \
|
||||
obAB = _mm_shuffle_epi8(obAB, ob_cm); \
|
||||
__m128i retAB = ob_mask; /* ob_mask is equal to white. */ \
|
||||
retAB = _mm_subs_epu16(retAB, colAB); /* (255 - rgb) */ \
|
||||
retAB = _mm_mullo_epi16(retAB, obAB); /* ob*(255 - rgb) */ \
|
||||
retAB = _mm_srli_epi16(retAB, 8); /* ob*(255 - rgb)/256 */ \
|
||||
retAB = _mm_add_epi16(retAB, colAB); /* ob*(255 - rgb)/256 + rgb */ \
|
||||
\
|
||||
colourX2 = _mm_packus_epi16(retAB, retAB);
|
||||
|
||||
/** The SSSE3 32 bpp blitter (without palette animation). */
|
||||
class Blitter_32bppSSSE3 : public Blitter_32bppSSE2 {
|
||||
public:
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
/* virtual */ const char *GetName() { return "32bpp-ssse3"; }
|
||||
};
|
||||
|
@@ -772,14 +772,13 @@ static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
|
||||
{
|
||||
uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL);
|
||||
if (callback == CALLBACK_FAILED || callback == 0x400) return y;
|
||||
const GRFFile *grffile = Engine::Get(engine)->GetGRF();
|
||||
if (callback > 0x400) {
|
||||
ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback);
|
||||
ErrorUnknownCallbackResult(Engine::Get(engine)->GetGRFID(), CBID_VEHICLE_ADDITIONAL_TEXT, callback);
|
||||
return y;
|
||||
}
|
||||
|
||||
StartTextRefStackUsage(grffile, 6);
|
||||
uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK);
|
||||
StartTextRefStackUsage(6);
|
||||
uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(Engine::Get(engine)->GetGRFID(), 0xD000 + callback), TC_BLACK);
|
||||
StopTextRefStackUsage();
|
||||
return result;
|
||||
}
|
||||
|
@@ -571,7 +571,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
|
||||
/* Only show the error when it's for us. */
|
||||
StringID error_part1 = GB(cmd, 16, 16);
|
||||
if (estimate_only || (IsLocalCompany() && error_part1 != 0 && my_cmd)) {
|
||||
ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack());
|
||||
ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackSize(), res.GetTextRefStack());
|
||||
}
|
||||
} else if (estimate_only) {
|
||||
ShowEstimatedCostOrIncome(res.GetCost(), x, y);
|
||||
@@ -779,15 +779,13 @@ uint32 CommandCost::textref_stack[16];
|
||||
|
||||
/**
|
||||
* Activate usage of the NewGRF #TextRefStack for the error message.
|
||||
* @param grffile NewGRF that provides the #TextRefStack
|
||||
* @param num_registers number of entries to copy from the temporary NewGRF registers
|
||||
* @param number of entries to copy from the temporary NewGRF registers
|
||||
*/
|
||||
void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers)
|
||||
void CommandCost::UseTextRefStack(uint num_registers)
|
||||
{
|
||||
extern TemporaryStorageArray<int32, 0x110> _temp_store;
|
||||
|
||||
assert(num_registers < lengthof(textref_stack));
|
||||
this->textref_stack_grffile = grffile;
|
||||
this->textref_stack_size = num_registers;
|
||||
for (uint i = 0; i < num_registers; i++) {
|
||||
textref_stack[i] = _temp_store.GetValue(0x100 + i);
|
||||
|
@@ -16,8 +16,6 @@
|
||||
#include "strings_type.h"
|
||||
#include "tile_type.h"
|
||||
|
||||
struct GRFFile;
|
||||
|
||||
/**
|
||||
* Common return value for all commands. Wraps the cost and
|
||||
* a possible error message/state together.
|
||||
@@ -27,7 +25,6 @@ class CommandCost {
|
||||
Money cost; ///< The cost of this action
|
||||
StringID message; ///< Warning message for when success is unset
|
||||
bool success; ///< Whether the comment went fine up to this moment
|
||||
const GRFFile *textref_stack_grffile; ///< NewGRF providing the #TextRefStack content.
|
||||
uint textref_stack_size; ///< Number of uint32 values to put on the #TextRefStack for the error message.
|
||||
|
||||
static uint32 textref_stack[16];
|
||||
@@ -36,25 +33,25 @@ public:
|
||||
/**
|
||||
* Creates a command cost return with no cost and no error
|
||||
*/
|
||||
CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {}
|
||||
CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_size(0) {}
|
||||
|
||||
/**
|
||||
* Creates a command return value the is failed with the given message
|
||||
*/
|
||||
explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_grffile(NULL), textref_stack_size(0) {}
|
||||
explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_size(0) {}
|
||||
|
||||
/**
|
||||
* Creates a command cost with given expense type and start cost of 0
|
||||
* @param ex_t the expense type
|
||||
*/
|
||||
explicit CommandCost(ExpensesType ex_t) : expense_type(ex_t), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {}
|
||||
explicit CommandCost(ExpensesType ex_t) : expense_type(ex_t), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_size(0) {}
|
||||
|
||||
/**
|
||||
* Creates a command return value with the given start cost and expense type
|
||||
* @param ex_t the expense type
|
||||
* @param cst the initial cost of this command
|
||||
*/
|
||||
CommandCost(ExpensesType ex_t, const Money &cst) : expense_type(ex_t), cost(cst), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {}
|
||||
CommandCost(ExpensesType ex_t, const Money &cst) : expense_type(ex_t), cost(cst), message(INVALID_STRING_ID), success(true), textref_stack_size(0) {}
|
||||
|
||||
|
||||
/**
|
||||
@@ -106,16 +103,7 @@ public:
|
||||
this->message = message;
|
||||
}
|
||||
|
||||
void UseTextRefStack(const GRFFile *grffile, uint num_registers);
|
||||
|
||||
/**
|
||||
* Returns the NewGRF providing the #TextRefStack of the error message.
|
||||
* @return the NewGRF.
|
||||
*/
|
||||
const GRFFile *GetTextRefStackGRF() const
|
||||
{
|
||||
return this->textref_stack_grffile;
|
||||
}
|
||||
void UseTextRefStack(uint num_registers);
|
||||
|
||||
/**
|
||||
* Returns the number of uint32 values for the #TextRefStack of the error message.
|
||||
|
@@ -144,14 +144,14 @@ void CheckSwitchToEuro()
|
||||
* Will fill _currency_specs array with
|
||||
* default values from origin_currency_specs
|
||||
* Called only from newgrf.cpp and settings.cpp.
|
||||
* @param preserve_custom will not reset custom currency
|
||||
* @param preserve_custom will not reset custom currency (the latest one on the list)
|
||||
* if ever it is flagged to true. In which case, the total size of the memory to move
|
||||
* will be one currency spec less, thus preserving the custom currency from been
|
||||
* overwritten.
|
||||
*/
|
||||
void ResetCurrencies(bool preserve_custom)
|
||||
{
|
||||
for (uint i = 0; i < CURRENCY_END; i++) {
|
||||
if (preserve_custom && i == CURRENCY_CUSTOM) continue;
|
||||
_currency_specs[i] = origin_currency_specs[i];
|
||||
}
|
||||
memcpy(&_currency_specs, &origin_currency_specs, sizeof(origin_currency_specs) - (preserve_custom ? sizeof(_custom_currency) : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1427,14 +1427,12 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
|
||||
/* Add new capacity to consist capacity and reserve cargo */
|
||||
w = v_start;
|
||||
do {
|
||||
st->goods[w->cargo_type].cargo.Reserve(w->cargo_cap - w->cargo.RemainingCount(), &w->cargo, st->xy, next_station);
|
||||
st->goods[w->cargo_type].cargo.Reserve(w->cargo_cap, &w->cargo, st->xy, next_station);
|
||||
consist_capleft[w->cargo_type] += w->cargo_cap - w->cargo.RemainingCount();
|
||||
w = w->HasArticulatedPart() ? w->GetNextArticulatedPart() : NULL;
|
||||
} while (w != NULL);
|
||||
if (is_normal_aircraft) {
|
||||
w = v->Next();
|
||||
st->goods[w->cargo_type].cargo.Reserve(w->cargo_cap - w->cargo.RemainingCount(), &w->cargo, st->xy, next_station);
|
||||
consist_capleft[w->cargo_type] += w->cargo_cap - w->cargo.RemainingCount();
|
||||
consist_capleft[v->Next()->cargo_type] += v->Next()->cargo_cap - v->Next()->cargo.RemainingCount();
|
||||
}
|
||||
|
||||
cur_company.Restore();
|
||||
|
@@ -16,8 +16,6 @@
|
||||
#include "company_type.h"
|
||||
#include "core/geometry_type.hpp"
|
||||
|
||||
struct GRFFile;
|
||||
|
||||
/** Message severity/type */
|
||||
enum WarningLevel {
|
||||
WL_INFO, ///< Used for DoCommand-like (and some non-fatal AI GUI) errors/information
|
||||
@@ -32,7 +30,6 @@ protected:
|
||||
uint duration; ///< Length of display of the message. 0 means forever,
|
||||
uint64 decode_params[20]; ///< Parameters of the message strings.
|
||||
const char *strings[20]; ///< Copies of raw strings that were used.
|
||||
const GRFFile *textref_stack_grffile; ///< NewGRF that filled the #TextRefStack for the error message.
|
||||
uint textref_stack_size; ///< Number of uint32 values to put on the #TextRefStack for the error message.
|
||||
uint32 textref_stack[16]; ///< Values to put on the #TextRefStack for the error message.
|
||||
StringID summary_msg; ///< General error message showed in first line. Must be valid.
|
||||
@@ -43,7 +40,7 @@ protected:
|
||||
public:
|
||||
ErrorMessageData(const ErrorMessageData &data);
|
||||
~ErrorMessageData();
|
||||
ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration = 0, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = NULL, uint textref_stack_size = 0, const uint32 *textref_stack = NULL);
|
||||
ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration = 0, int x = 0, int y = 0, uint textref_stack_size = 0, const uint32 *textref_stack = NULL);
|
||||
|
||||
/** Check whether error window shall display a company manager face */
|
||||
bool HasFace() const { return face != INVALID_COMPANY; }
|
||||
@@ -56,7 +53,7 @@ public:
|
||||
|
||||
void ScheduleErrorMessage(const ErrorMessageData &data);
|
||||
|
||||
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = NULL, uint textref_stack_size = 0, const uint32 *textref_stack = NULL);
|
||||
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, uint textref_stack_size = 0, const uint32 *textref_stack = NULL);
|
||||
void ClearErrorMessages();
|
||||
void ShowFirstError();
|
||||
void UnshowCriticalError();
|
||||
|
@@ -94,13 +94,11 @@ ErrorMessageData::~ErrorMessageData()
|
||||
* @param duration The amount of time to show this error message.
|
||||
* @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
|
||||
* @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
|
||||
* @param textref_stack_grffile NewGRF that provides the #TextRefStack for the error message.
|
||||
* @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used.
|
||||
* @param textref_stack Values to put on the #TextRefStack.
|
||||
*/
|
||||
ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) :
|
||||
ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, uint textref_stack_size, const uint32 *textref_stack) :
|
||||
duration(duration),
|
||||
textref_stack_grffile(textref_stack_grffile),
|
||||
textref_stack_size(textref_stack_size),
|
||||
summary_msg(summary_msg),
|
||||
detailed_msg(detailed_msg),
|
||||
@@ -128,7 +126,7 @@ void ErrorMessageData::CopyOutDParams()
|
||||
memset(this->strings, 0, sizeof(this->strings));
|
||||
|
||||
/* Get parameters using type information */
|
||||
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack);
|
||||
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_size, this->textref_stack);
|
||||
CopyOutDParam(this->decode_params, this->strings, this->detailed_msg == INVALID_STRING_ID ? this->summary_msg : this->detailed_msg, lengthof(this->decode_params));
|
||||
if (this->textref_stack_size > 0) StopTextRefStackUsage();
|
||||
|
||||
@@ -183,7 +181,7 @@ public:
|
||||
if (widget != WID_EM_MESSAGE) return;
|
||||
|
||||
CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
|
||||
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack);
|
||||
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_size, this->textref_stack);
|
||||
|
||||
int text_width = max(0, (int)size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT);
|
||||
this->height_summary = GetStringHeight(this->summary_msg, text_width);
|
||||
@@ -255,7 +253,7 @@ public:
|
||||
|
||||
case WID_EM_MESSAGE:
|
||||
CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
|
||||
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack);
|
||||
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_size, this->textref_stack);
|
||||
|
||||
if (this->detailed_msg == INVALID_STRING_ID) {
|
||||
DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM,
|
||||
@@ -360,20 +358,19 @@ void UnshowCriticalError()
|
||||
* @param wl Message severity.
|
||||
* @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
|
||||
* @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
|
||||
* @param textref_stack_grffile NewGRF providing the #TextRefStack for the error message.
|
||||
* @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used.
|
||||
* @param textref_stack Values to put on the #TextRefStack.
|
||||
*/
|
||||
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack)
|
||||
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, uint textref_stack_size, const uint32 *textref_stack)
|
||||
{
|
||||
assert(textref_stack_size == 0 || (textref_stack_grffile != NULL && textref_stack != NULL));
|
||||
assert(textref_stack_size == 0 || textref_stack != NULL);
|
||||
if (summary_msg == STR_NULL) summary_msg = STR_EMPTY;
|
||||
|
||||
if (wl != WL_INFO) {
|
||||
/* Print message to console */
|
||||
char buf[DRAW_STRING_BUFFER];
|
||||
|
||||
if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_grffile, textref_stack_size, textref_stack);
|
||||
if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_size, textref_stack);
|
||||
|
||||
char *b = GetString(buf, summary_msg, lastof(buf));
|
||||
if (detailed_msg != INVALID_STRING_ID) {
|
||||
@@ -393,7 +390,7 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel
|
||||
|
||||
if (_settings_client.gui.errmsg_duration == 0 && !no_timeout) return;
|
||||
|
||||
ErrorMessageData data(summary_msg, detailed_msg, no_timeout ? 0 : _settings_client.gui.errmsg_duration, x, y, textref_stack_grffile, textref_stack_size, textref_stack);
|
||||
ErrorMessageData data(summary_msg, detailed_msg, no_timeout ? 0 : _settings_client.gui.errmsg_duration, x, y, textref_stack_size, textref_stack);
|
||||
data.CopyOutDParams();
|
||||
|
||||
ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0);
|
||||
|
@@ -79,7 +79,7 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
|
||||
if (callback > 0x400) {
|
||||
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_CARGO_SUFFIX, callback);
|
||||
} else if (indspec->grf_prop.grffile->grf_version >= 8 || GB(callback, 0, 8) != 0xFF) {
|
||||
StartTextRefStackUsage(indspec->grf_prop.grffile, 6);
|
||||
StartTextRefStackUsage(6);
|
||||
GetString(suffix, GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback), suffix_last);
|
||||
StopTextRefStackUsage();
|
||||
}
|
||||
@@ -471,7 +471,7 @@ public:
|
||||
} else {
|
||||
str = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string
|
||||
if (str != STR_UNDEFINED) {
|
||||
StartTextRefStackUsage(indsp->grf_prop.grffile, 6);
|
||||
StartTextRefStackUsage(6);
|
||||
DrawStringMultiLine(left, right, y, bottom, str, TC_YELLOW);
|
||||
StopTextRefStackUsage();
|
||||
}
|
||||
@@ -800,7 +800,7 @@ public:
|
||||
if (message != STR_NULL && message != STR_UNDEFINED) {
|
||||
y += WD_PAR_VSEP_WIDE;
|
||||
|
||||
StartTextRefStackUsage(ind->grf_prop.grffile, 6);
|
||||
StartTextRefStackUsage(6);
|
||||
/* Use all the available space left from where we stand up to the
|
||||
* end of the window. We ALSO enlarge the window if needed, so we
|
||||
* can 'go' wild with the bottom of the window. */
|
||||
|
@@ -201,28 +201,21 @@ STR_UNITS_POWER_IMPERIAL :{COMMA} к.с.
|
||||
STR_UNITS_POWER_METRIC :{COMMA} к.с.
|
||||
STR_UNITS_POWER_SI :{COMMA} kW
|
||||
|
||||
STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}т
|
||||
STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA} т.
|
||||
STR_UNITS_WEIGHT_SHORT_SI :{COMMA} кг.
|
||||
|
||||
STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} тон{P "" а}
|
||||
STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} тон{P "" а}
|
||||
STR_UNITS_WEIGHT_LONG_SI :{COMMA} кг
|
||||
|
||||
STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}гал
|
||||
STR_UNITS_VOLUME_SHORT_METRIC :{COMMA} л.
|
||||
STR_UNITS_VOLUME_SHORT_SI :{COMMA} м³
|
||||
|
||||
STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} галон{P "" и}
|
||||
STR_UNITS_VOLUME_LONG_METRIC :{COMMA} лит{P ър ри}
|
||||
STR_UNITS_VOLUME_LONG_SI :{COMMA} куб. м.
|
||||
|
||||
STR_UNITS_FORCE_IMPERIAL :{COMMA} lbf
|
||||
STR_UNITS_FORCE_METRIC :{COMMA} kgf
|
||||
STR_UNITS_FORCE_SI :{COMMA} kN
|
||||
|
||||
STR_UNITS_HEIGHT_IMPERIAL :{COMMA} фут
|
||||
STR_UNITS_HEIGHT_METRIC :{COMMA} м
|
||||
STR_UNITS_HEIGHT_SI :{COMMA} м
|
||||
|
||||
# Common window strings
|
||||
@@ -241,7 +234,7 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Затв
|
||||
STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Заглавие на прозорец - преместване на прозореца с мишката
|
||||
STR_TOOLTIP_SHADE :{BLACK}Прибиране на прозореца - показва само заглавната лента
|
||||
STR_TOOLTIP_DEBUG :{BLACK}Покажи debug информация за новите графики (NewGRF)
|
||||
STR_TOOLTIP_STICKY :{BLACK}Маркиране прозореца като незатворяем от клавиша 'Затваряне всички прозороци'
|
||||
STR_TOOLTIP_STICKY :{BLACK}Маркиране прозореца за незатваряне от клавиша 'Затваряне всички прозороци'
|
||||
STR_TOOLTIP_RESIZE :{BLACK}Преместете за оразмеряване прозореца
|
||||
STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Активирай голям/малък размер на прозореца
|
||||
STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Лента за позициониране - превърта списъка нагоре/надолу
|
||||
@@ -285,8 +278,6 @@ STR_SORT_BY_LENGTH :Дължина
|
||||
STR_SORT_BY_LIFE_TIME :Оставащо време за експлоатация
|
||||
STR_SORT_BY_TIMETABLE_DELAY :Закъснение
|
||||
STR_SORT_BY_FACILITY :Вид на гарата
|
||||
STR_SORT_BY_WAITING_TOTAL :Целия чакащ товар
|
||||
STR_SORT_BY_WAITING_AVAILABLE :Наличен чакащ товар
|
||||
STR_SORT_BY_RATING_MAX :Най-голяма оценка на товари
|
||||
STR_SORT_BY_RATING_MIN :Най-ниска оценка на товари
|
||||
STR_SORT_BY_ENGINE_ID :Двигател № (класическо сортиране)
|
||||
@@ -299,7 +290,6 @@ STR_SORT_BY_POWER_VS_RUNNING_COST :Мощност/
|
||||
STR_SORT_BY_CARGO_CAPACITY :Товарен капацитет
|
||||
STR_SORT_BY_RANGE :Обхват
|
||||
STR_SORT_BY_POPULATION :Население
|
||||
STR_SORT_BY_RATING :Рейтинг
|
||||
|
||||
# Tooltips for the main toolbar
|
||||
STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Пауза
|
||||
@@ -312,7 +302,6 @@ STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Пока
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Списък със станциите на компанията
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Показване на финансова информация за компанията
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Покажи обща информация за компанията
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Покази списък с целите
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Покажи графиките
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Покажи класирането на компаниите
|
||||
STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Инвестирай в нова индустрия
|
||||
@@ -887,8 +876,6 @@ STR_GAME_OPTIONS_CURRENCY_LTL :Литовск
|
||||
STR_GAME_OPTIONS_CURRENCY_KRW :Южнокорейски Вон (KRW)
|
||||
STR_GAME_OPTIONS_CURRENCY_ZAR :Южноафрикански Ранд (ZAR)
|
||||
STR_GAME_OPTIONS_CURRENCY_CUSTOM :друга...
|
||||
STR_GAME_OPTIONS_CURRENCY_GEL :Грузинско лари (ГЕЛ)
|
||||
STR_GAME_OPTIONS_CURRENCY_IRR :Ирански Риал (ИРР)
|
||||
############ end of currency region
|
||||
|
||||
|
||||
@@ -1117,9 +1104,9 @@ STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Задава к
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Цени на конструкции: {STRING}
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Задава ниво то на конструиране и цени за закупуване
|
||||
STR_CONFIG_SETTING_RECESSIONS :Рецесии: {STRING}
|
||||
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Ако е разрешено, рецесии могат да се появяват на всеки няколко години. По време на рецесия цялото производство е значително намалено (връща се на предишно ниво след края на рецесията)
|
||||
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Ако е разрешено рецесии могат да се появяват на всеки няколко години. По време на рецесия цялото производство е значително намалено (връща се на предишно ниво след края на рецесията)
|
||||
STR_CONFIG_SETTING_TRAIN_REVERSING :Забрани обръщане на посоката на влакове в гарите: {STRING}
|
||||
STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Ако е избрано, влаковете няма да обръщат на не-терминални гари, ако има по-кратък път до целта им при обръщане.
|
||||
STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Ако е избрано влаковете няма да обръщат на не-терминални гари, ако има по-кратък път до целта им при обръщане.
|
||||
STR_CONFIG_SETTING_DISASTERS :Бедствия: {STRING}
|
||||
STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Включване/Изключване на бедствия които могат от време на време да блокират или разрушат превозни средства или инфраструктура
|
||||
STR_CONFIG_SETTING_CITY_APPROVAL :Отношението на градския съвет към реструктурирането на района: {STRING}
|
||||
@@ -1339,7 +1326,6 @@ STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31
|
||||
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE :Палитра по подразбиране за NewGRF, които не са задали палитра: {STRING}
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_HELPTEXT :Палитра по подразбиране за NewGRF, за които е зададена от коя се нуждаят
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_WIN :Legacy (W) palette
|
||||
|
||||
STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Игрите започват в пауза: {STRING}
|
||||
STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Ако тази опция бъде активирана, играта автоматично ще бъде паузирана, когато започнете нова игра, това ще ви позволи да изучите по-подробно картата
|
||||
@@ -1376,7 +1362,7 @@ STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Звуков с
|
||||
STR_CONFIG_SETTING_SOUND_NEWS :Вестник: {STRING}
|
||||
STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Звуков сигнал при показването на новини
|
||||
STR_CONFIG_SETTING_SOUND_NEW_YEAR :Край на година: {STRING}
|
||||
STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Звуков сигнал при проказване на баланса в края на годината сравнен с края на предишната година
|
||||
STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Звуков сигнал при проказване на баланса в края на годината
|
||||
STR_CONFIG_SETTING_SOUND_CONFIRM :Конструкция: {STRING}
|
||||
STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Изпълнявай звуков ефект при успешно конструиране или други действия
|
||||
STR_CONFIG_SETTING_SOUND_CLICK :Вутона натиска: {STRING}
|
||||
@@ -1566,44 +1552,13 @@ STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD :Премахв
|
||||
STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD_HELPTEXT :Премахва краищата на пътища при финансиране на ремонт на пътя
|
||||
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Единици за скорост: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Всеки път при показване на скорости, да бъдат изписвани в избраните мерни единици
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metric (km/h)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Единици на мощност на превозното средство: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Всеки път при показване на мощност, да бъде изписвана в избраните мерни единици
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperial (hp)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metric (hp)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Единици за тежина: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Всеки път при показване на тежести, да бъдат изписвани в избраните мерни единици
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperial (short t/ton)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metric (t/tonne)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Мерни единици на обем: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Всеки път при показване на обеми, да се изписват в избраните мерни единици
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperial (gal)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metric (l)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Мерни единици на теглителната сила: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Всеки път при показване на теглителна сила, да бъде изписване в избраните мерни единици
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperial (lbf)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metric (kgf)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Височинна мерна единица: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Всеки път при показване на височините, да се изписват в избраните мерни единици
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperial (ft)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metric (m)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m)
|
||||
|
||||
STR_CONFIG_SETTING_GUI :{ORANGE}Интерфейс
|
||||
STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Позициониране
|
||||
STR_CONFIG_SETTING_CONSTRUCTION :{ORANGE}Строене
|
||||
STR_CONFIG_SETTING_VEHICLES :{ORANGE}Автомобили
|
||||
STR_CONFIG_SETTING_STATIONS :{ORANGE}Станции
|
||||
@@ -1655,7 +1610,6 @@ STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... save
|
||||
STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... пропуска набора от основната графика '{STRING}': не е открит
|
||||
STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... пропуска набора от основни звуци '{STRING}': не е открит
|
||||
STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... пропруска набора от основни песни '{STRING}': не е открит
|
||||
STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Отвъд паметта
|
||||
|
||||
# Intro window
|
||||
STR_INTRO_CAPTION :{WHITE}OpenTTD {REV}
|
||||
@@ -1832,10 +1786,6 @@ STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cмен
|
||||
|
||||
# Network server list
|
||||
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Онлайн играчи
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Рекламирана
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Избери игра измежду рекламирана през интернет или нерекламирана през Локален интернет хост или ЛАН
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Не
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Да
|
||||
STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Име на играч:
|
||||
STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Чрез това име другите играчи ще ви идентифицират
|
||||
|
||||
@@ -1894,7 +1844,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Имет
|
||||
STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Поставяне на парола
|
||||
STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Защитаване на вашата игра с парола за да не е публично достъпна
|
||||
|
||||
STR_NETWORK_START_SERVER_UNADVERTISED :Не
|
||||
STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} клиент{P "" s}
|
||||
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Макс. брой играчи:
|
||||
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Избор на максималния брой клиенти. Не всички слотове трябва да се попълнят
|
||||
@@ -2015,7 +1964,6 @@ STR_NETWORK_CLIENT :Клиент
|
||||
STR_NETWORK_SPECTATORS :Наблюдатели
|
||||
|
||||
STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Въведете количеството пари, което искате да дадете
|
||||
STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Зрител
|
||||
|
||||
# Network set password
|
||||
STR_COMPANY_PASSWORD_CANCEL :{BLACK}Незапазвай паролата
|
||||
@@ -2856,7 +2804,6 @@ STR_NEWGRF_INVALID_ENGINE :<невалид
|
||||
STR_NEWGRF_INVALID_INDUSTRYTYPE :<невалдна индустрия>
|
||||
|
||||
# Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script).
|
||||
STR_INVALID_VEHICLE :<невалидно превозно средство>
|
||||
|
||||
# NewGRF scanning window
|
||||
STR_NEWGRF_SCAN_CAPTION :{WHITE}Търси NewGRF-и
|
||||
@@ -2939,11 +2886,9 @@ STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Пок
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW} Подкупването на местната власт за да увеличи рейтинга носи огромен риск ако бъдете хванати.{} Цена: {CURRENCY_LONG}
|
||||
|
||||
# Goal window
|
||||
STR_GOALS_SPECTATOR_CAPTION :{WHITE}Глобални цели
|
||||
STR_GOALS_GLOBAL_TITLE :{BLACK}Основни цели:
|
||||
STR_GOALS_TEXT :{ORANGE}{STRING}
|
||||
STR_GOALS_NONE :{ORANGE}- Никакви -
|
||||
STR_GOALS_SPECTATOR_NONE :{ORANGE}- Неприложимо-
|
||||
STR_GOALS_COMPANY_TITLE :{BLACK}Цели на компанията:
|
||||
STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Кликни на задачата за да центрирате камерата на фабрика/град/плочка. Ctrl+Click отваря нов прозорец центриран на фабрика/град/плочка
|
||||
|
||||
@@ -2983,7 +2928,6 @@ STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING
|
||||
STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Натисни върху услугата за да се фокусира върху индустрията/града. Ctrl отваря нов изглед към индустрията/града
|
||||
|
||||
# Story book window
|
||||
STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Невалидна цел
|
||||
|
||||
# Station list window
|
||||
STR_STATION_LIST_TOOLTIP :{BLACK}Имена на станции - натиснете върху името, за да фиксирате главния прозорец върху станцията
|
||||
@@ -3014,7 +2958,6 @@ STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Рейт
|
||||
STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Покажи нивото на обслужване
|
||||
|
||||
|
||||
STR_STATION_VIEW_GROUP_D_V_S :Посока-през-Източника
|
||||
|
||||
############ range for rating starts
|
||||
STR_CARGO_RATING_APPALLING :Плачевно
|
||||
@@ -3157,7 +3100,6 @@ STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Прои
|
||||
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% превозено)
|
||||
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Фокусиране на основният изглед върху индустрията. Ctrl+Click отваря прозорец на нов изглед върху индустрията.
|
||||
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Ниво на производство: {YELLOW}{COMMA}%
|
||||
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Индустрията обяви незабавна ликвидация!
|
||||
|
||||
############ range for requires starts
|
||||
STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Нуждае се от: {YELLOW}{STRING}{STRING}
|
||||
@@ -3874,8 +3816,6 @@ STR_AI_SETTINGS_START_DELAY :Броят дн
|
||||
STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {STRING}
|
||||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} Дневник на промените на {STRING}
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} лиценз на {STRING}
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}Реорганизирай текста
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Реорганизирай текста така, че изцяло да се помести в прозореца
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}Отвори readme
|
||||
STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Дневник на промените
|
||||
STR_TEXTFILE_VIEW_LICENCE :{BLACK}Лиценз
|
||||
@@ -4253,10 +4193,6 @@ STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Инте
|
||||
|
||||
STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... машината е унищожена
|
||||
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Никакви превозни средства няма да бъдат налични
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Промени своята NewGRF конфигурация
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Няма налични превозни средства все още
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Започни нова игра след {DATE_SHORT} или използвай NewGRF , който показва ранни превозни средства
|
||||
|
||||
# Specific vehicle errors
|
||||
STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Влака не може да пропусне сигнала при опасност...
|
||||
@@ -4758,7 +4694,6 @@ STR_JUST_DATE_ISO :{DATE_ISO}
|
||||
STR_JUST_STRING :{STRING}
|
||||
STR_JUST_STRING_STRING :{STRING}{STRING}
|
||||
STR_JUST_RAW_STRING :{STRING}
|
||||
STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING}
|
||||
|
||||
# Slightly 'raw' stringcodes with colour or size
|
||||
STR_BLACK_COMMA :{BLACK}{COMMA}
|
||||
|
@@ -199,28 +199,21 @@ STR_UNITS_POWER_IMPERIAL :{COMMA}hk
|
||||
STR_UNITS_POWER_METRIC :{COMMA}hk
|
||||
STR_UNITS_POWER_SI :{COMMA}kW
|
||||
|
||||
STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}t
|
||||
STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t
|
||||
STR_UNITS_WEIGHT_SHORT_SI :{COMMA}kg
|
||||
|
||||
STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton{P "" s}
|
||||
STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} ton{P "" s}
|
||||
STR_UNITS_WEIGHT_LONG_SI :{COMMA} kg
|
||||
|
||||
STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal
|
||||
STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}l
|
||||
STR_UNITS_VOLUME_SHORT_SI :{COMMA}m³
|
||||
|
||||
STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} gallon
|
||||
STR_UNITS_VOLUME_LONG_METRIC :{COMMA} liter
|
||||
STR_UNITS_VOLUME_LONG_SI :{COMMA} m³
|
||||
|
||||
STR_UNITS_FORCE_IMPERIAL :{COMMA} lbf
|
||||
STR_UNITS_FORCE_METRIC :{COMMA} kp
|
||||
STR_UNITS_FORCE_SI :{COMMA} kN
|
||||
|
||||
STR_UNITS_HEIGHT_IMPERIAL :{COMMA} fod
|
||||
STR_UNITS_HEIGHT_METRIC :{COMMA} m
|
||||
STR_UNITS_HEIGHT_SI :{COMMA} m
|
||||
|
||||
# Common window strings
|
||||
@@ -228,7 +221,6 @@ STR_LIST_FILTER_TITLE :{BLACK}Filtrer
|
||||
STR_LIST_FILTER_OSKTITLE :{BLACK}Indtast filter-udtryk
|
||||
STR_LIST_FILTER_TOOLTIP :{BLACK}Indtast nøgleord til at filtrere listen efter
|
||||
|
||||
STR_TOOLTIP_GROUP_ORDER :{BLACK}Vælg grupperingssortering
|
||||
STR_TOOLTIP_SORT_ORDER :{BLACK}Vælg sorteringsorden (faldende/stigende)
|
||||
STR_TOOLTIP_SORT_CRITERIA :{BLACK}Vælg sorteringskriterie
|
||||
STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Vælg filtreringskriterier
|
||||
@@ -240,7 +232,6 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Luk vind
|
||||
STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Vinduestitel - træk her for at flytte vinduet
|
||||
STR_TOOLTIP_SHADE :{BLACK}Oprul vindue - vis kun titellinien
|
||||
STR_TOOLTIP_DEBUG :{BLACK}Vis information om NewGRF fejl
|
||||
STR_TOOLTIP_DEFSIZE :{BLACK}Gendan vinduets standardstørrelse. Ctrl+Klik for at gemme nuværende størrelse som standard
|
||||
STR_TOOLTIP_STICKY :{BLACK}Marker dette vindue som ulukkeligt af 'Luk ALLE vinduer' tasten. Ctrl+Klik for også at gemme tilstand som standart
|
||||
STR_TOOLTIP_RESIZE :{BLACK}Klik og træk for at ændre vinduets størrelse
|
||||
STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Skift mellem stort/lille vindue
|
||||
@@ -285,8 +276,6 @@ STR_SORT_BY_LENGTH :Længde
|
||||
STR_SORT_BY_LIFE_TIME :Resterende levetid
|
||||
STR_SORT_BY_TIMETABLE_DELAY :Køreplans forsinkelse
|
||||
STR_SORT_BY_FACILITY :Stationstype
|
||||
STR_SORT_BY_WAITING_TOTAL :Total ventende fragt
|
||||
STR_SORT_BY_WAITING_AVAILABLE :Tilgængelig ventende fragt
|
||||
STR_SORT_BY_RATING_MAX :Højeste værdi af last
|
||||
STR_SORT_BY_RATING_MIN :Laveste værdi af last
|
||||
STR_SORT_BY_ENGINE_ID :Lokomotiv ID (klassisk)
|
||||
@@ -312,8 +301,6 @@ STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Vis tils
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Vis liste over selskabets stationer
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Vis selskabets finansinformation
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Vis generel selskabsinformation
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Vis historiebog
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Vis målliste
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Vis grafer
|
||||
STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Vis selskabsoversigten
|
||||
STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Finansiér opførelse af ny industri
|
||||
@@ -355,7 +342,7 @@ STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Hent scenarie
|
||||
STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Gem højdekort
|
||||
STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Hent højdekort
|
||||
STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Forlad scenarieeditor
|
||||
STR_SCENEDIT_FILE_MENU_SEPARATOR :STR_SCENEDIT_FILE_MENU_SEPARATOR
|
||||
STR_SCENEDIT_FILE_MENU_SEPARATOR :
|
||||
STR_SCENEDIT_FILE_MENU_QUIT :Afslut
|
||||
############ range for SE file menu starts
|
||||
|
||||
@@ -387,7 +374,6 @@ STR_FILE_MENU_EXIT :Afslut
|
||||
# map menu
|
||||
STR_MAP_MENU_MAP_OF_WORLD :Kort over verden
|
||||
STR_MAP_MENU_EXTRA_VIEW_PORT :Nyt lokalitetsvindue
|
||||
STR_MAP_MENU_LINGRAPH_LEGEND :Laststrømforklaring
|
||||
STR_MAP_MENU_SIGN_LIST :Liste over skilte
|
||||
|
||||
############ range for town menu starts
|
||||
@@ -518,7 +504,7 @@ STR_MONTH_ABBREV_OCT :okt
|
||||
STR_MONTH_ABBREV_NOV :nov
|
||||
STR_MONTH_ABBREV_DEC :dec
|
||||
|
||||
STR_MONTH_JAN :Januar
|
||||
STR_MONTH_JAN :januar
|
||||
STR_MONTH_FEB :februar
|
||||
STR_MONTH_MAR :marts
|
||||
STR_MONTH_APR :april
|
||||
@@ -674,20 +660,17 @@ STR_SMALLMAP_CAPTION :{WHITE}Kort - {
|
||||
STR_SMALLMAP_TYPE_CONTOURS :Konturer
|
||||
STR_SMALLMAP_TYPE_VEHICLES :Køretøjer
|
||||
STR_SMALLMAP_TYPE_INDUSTRIES :Industrier
|
||||
STR_SMALLMAP_TYPE_ROUTEMAP :Laststrøm
|
||||
STR_SMALLMAP_TYPE_ROUTES :Ruter
|
||||
STR_SMALLMAP_TYPE_VEGETATION :Vegetation
|
||||
STR_SMALLMAP_TYPE_OWNERS :Ejere
|
||||
STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Vis landskabskonturer på kortet
|
||||
STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Vis køretøjer på kortet
|
||||
STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Vis industrier på kortet
|
||||
STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Vis laststrøm på kortet
|
||||
STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Vis transportruter på kortet
|
||||
STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Vis vegetation på kortet
|
||||
STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Vis landejere på kortet
|
||||
STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Klik på en industritype for at vise den.
|
||||
STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Kik på et selskab for at se dens ejendomme. Ctrl+klik deaktiverer alle selskaber undtagen det valgte. Ctrl+klik igen for atter at aktivere
|
||||
STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Klik på en last for at skifte visning af dens egenskab. Ctrl+Klik slår alle laster undtagen den valgte fra. Ctrl+Klik på den igen for at slå alle laster til
|
||||
|
||||
STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Veje
|
||||
STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Jernbaner
|
||||
@@ -721,7 +704,6 @@ STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLA
|
||||
STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Vis/skjul bynavne på kort
|
||||
STR_SMALLMAP_CENTER :{BLACK}Centrer det lille kort ved den nuværende position
|
||||
STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM})
|
||||
STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING}
|
||||
STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY}
|
||||
STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN}
|
||||
STR_SMALLMAP_DISABLE_ALL :{BLACK}Slå alle fra
|
||||
@@ -1339,8 +1321,6 @@ STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31
|
||||
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE :Standard palette NewGRFer uden valgt palette: {STRING}
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_HELPTEXT :Standardpalet til brug af NewGRFs der ikke angiver hvilken en de har brug for
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_DOS :Standard (D) palet
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_WIN :Legacy (W) palette
|
||||
|
||||
STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Sæt automatisk på pause når nyt spil startes: {STRING}
|
||||
STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Når aktiveret, vil spillet automatisk pause når du starter et nyt spil, det giver mulighed for at studerer kortet nærmere
|
||||
@@ -1566,73 +1546,18 @@ STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Gennemsnitlig s
|
||||
STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD :Fjern absurde vejelementer under opførelse af vej: {STRING}
|
||||
STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD_HELPTEXT :Fjern døde vej-ender i løbet af finansierede vej-rekostruktioner
|
||||
|
||||
STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Opdatér distributionsgraf hver {STRING} dag{P 0:2 "" e}
|
||||
STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Tid mellem efterfølgende genberegninger af forbindelsesgrafen. Hver genberegning beregner planerne for et komponent af grafen. Det betyder, at en værdi X for denne indstilling ikke betyder at hele grafen vil blive opdateret hver X dage. Kun nogle komponenter vil. Jo kortere du sætter indstillingen, jo mere CPU-tid vil være nødvendig for at beregne forbindelsesgrafen. Jo længere du sætter indstillingen, jo længere vil det tage før lastdistribution starter på nye ruter.
|
||||
STR_CONFIG_SETTING_LINKGRAPH_TIME :Tag {STRING} dag{P 0:2 "" e} for genberegning af distributionsgraf
|
||||
STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Tid taget for hver genberegning af et forbindelsesgrafkomponent. Når en genberegning startes, skabes en tråd som er tilladt at køre dette antal dage. Jo kortere du sætter denne indstilling, jo mere sandsynligt er det at tråden ikke er færdig når det er meningen. Så stopper spillet indtil den er ("lag"). Jo længere du sætter denne indstilling, jo længere tager det for distributionen at blive opdateret når ruter ændres.
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manuel
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asymmetrisk
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetrisk
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_PAX :Distributionsmodel for passagerer: {STRING}
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"symmetrisk" betyder at omtrent det samme antal passagerer vil rejse fra en station A til en station B som fra B til A. "asymmetrisk" betyder at vilkårlige antal passagerer kan rejse i hver retning. "manuel" betyder at ingen automatisk distribution vil finde sted for passagerer.
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Distributionsmodel for post: {STRING}
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"symmetrisk" betyder at omtrent den samme mængde post vil blive sendt fra en station A til en station B som fra B til A. "asymmetrisk" betyder at vilkårlige mængder post kan blive sendt i hver retning. "manuel" betyder at ingen automatisk distribution vil finde sted for post.
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Distributionsmodel for PANSRET lastklasse: {STRING}
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :PANSRET lastklassen indeholder værdigenstande i det tempererede klima, diamanter i det subtropiske klima, eller guld i det subarktiske klima. NewGRF kan ændre dette. "symmetrisk" betyder at omtrent den samme mængde af denne last vil blive sendt fra en station A til en station B som fra B til A. "asymmetrisk" betyder at vilkårlige mængder af denne last kan blive sendt i hver retning. "manuel" betyder at ingen automatisk distribution vil finde sted for denne last. Det anbefales at sætte denne indstilling til assymetrisk eller manuel når der spilles subarktisk, da banker ikke sender guld tilbage til guldminer. For tempereret og subtropisk kan du også vælge symmetrisk, da banker vil sende værdigenstande tilbage til oprindelsesbanken for et læs værdigenstande.
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Distributionsmodel for andre lastklasser: {STRING}
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"symmetrisk" betyder at omtrent den samme mængde last vil blive sendt fra en station A til en station B som fra B til A. "asymmetrisk" betyder at vilkårlige mængder last kan blive sendt i hver retning. "manuel" betyder at ingen automatisk distribution vil finde sted for disse laster. Du vil nok ønske at sætte dette til "asymmetrisk" eller manuel.
|
||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Distributionsnøjagtighed: {STRING}
|
||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Jo højere du sætter denne indstilling, jo mere CPU-tid vil beregningen af forbindelsesgrafen tage. Hvis den tager for længe, kan du opleve lag. Hvis du derimod sætter indstillingen til en lav værdi, vil distributionen være unøjagtig, og du kan opleve last ikke blive sendt til de steder, du forventer.
|
||||
STR_CONFIG_SETTING_DEMAND_DISTANCE :Effekt af afstand på efterspørgsel: {STRING}
|
||||
STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Hvis du sætter denne indstilling til en værdi større end 0, vil afstanden mellem oprindelsesstation A for noget last og en mulig destination B have en effekt på mængden af last sendt fra A til B. Jo længere væk B er fra A, jo mindre last vil blive sendt. Jo højere du sætter denne indstilling, jo mindre last vil blive sendt til fjerne stationer, og jo mere last vil blive sendt til nærliggende stationer.
|
||||
STR_CONFIG_SETTING_DEMAND_SIZE :Mængde returnerende last for symmetrisk model: {STRING}
|
||||
STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Ved at sætte denne indstilling til mindre end 100%, opfører den symmetriske distribution sig mere som den asymmetriske. Mindre last vil blive tvunget sendt tilbage hvis en bestemt mængde er blevet sendt til en station. Hvis du sætter denne indstilling til 0%, vil den symmetriske distribution opfører sig ligesom den asymmetriske.
|
||||
STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Mætning af korte veje før brug af veje med høj kapacitet: {STRING}
|
||||
STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Der er ofte flere veje mellem to givne stationer. Cargodist vil mætte den korteste vej først, så bruge den næstkorteste vej indtil den er mættet, osv.. Mætning bestemmes af en vurdering af kapacitet og planlagt brug. Når den har mættet alle veje, og hvis der stadig er efterspørgsel tilbage, vil den overbelaste alle veje, og foretrække vejene med høj kapacitet. Det meste af tiden vil algoritmen dog ikke vurdere kapaciteten nøjagtigt. Denne indstilling giver dig mulighed for at bestemme op til hvilken procentdel en kortere vej skal være mættet i første omgang før den næste, længere vej vælges. Sæt denne indstilling til mindre end 100% for at undgå overfyldte stationer i tilfælde af overvurderet kapacitet.
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Hastighedsenheder: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Når en hastighed er vist i brugergrænsefladen, så vis dem i de valgte enheder
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperisk (mph)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metrisk (km/t)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Køretøjskraftenheder: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Når et køretøjs kraft er vist i brugergrænsefladen, så vis dem i de valgte enheder
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperisk (hk)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metrisk (hk)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Vægtenheder: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Når vægte er vist i brugergrænsefladen, så vis dem i de valgte enheder
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperisk (short t/ton)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metrisk (t/ton)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Rumfangsenheder: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Når rumfang er vist i brugergrænsefladen, så vis dem i de valgte enheder
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperisk (gal)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metrisk (l)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Trækevneenheder: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Når trækevne, også kendt som trækkraft, er vist i brugergrænsefladen, så vis det i de valgte enheder
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperisk (lbf)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metrisk (kp)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Højdeenheder: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Når højder er vist i brugergrænsefladen, så vis dem i de valgte enheder
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperisk (fod)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metrisk (m)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m)
|
||||
|
||||
STR_CONFIG_SETTING_GUI :{ORANGE}Brugerflade
|
||||
STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Lokalisering
|
||||
STR_CONFIG_SETTING_CONSTRUCTION :{ORANGE}Konstruktion
|
||||
STR_CONFIG_SETTING_VEHICLES :{ORANGE}Køretøjer
|
||||
STR_CONFIG_SETTING_STATIONS :{ORANGE}Stationer
|
||||
STR_CONFIG_SETTING_ECONOMY :{ORANGE}Økonomi
|
||||
STR_CONFIG_SETTING_LINKGRAPH :{ORANGE}Fragtdistribution
|
||||
STR_CONFIG_SETTING_AI :{ORANGE}Modstandere
|
||||
STR_CONFIG_SETTING_DISPLAY_OPTIONS :{ORANGE}Visningsindstillinger
|
||||
STR_CONFIG_SETTING_INTERACTION :{ORANGE}Brugerflade
|
||||
@@ -1858,10 +1783,7 @@ STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Ændre s
|
||||
|
||||
# Network server list
|
||||
STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Netværksspil
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Advertised / Offentlig server
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Vælg mellem en Offentlig server (internet) og en ikke Offentlig server (Lokal Network, LAN) spil-server
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Nej
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Ja
|
||||
STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spiller navn:
|
||||
STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Dette er det navn, som andre spillere vil kende dig ved
|
||||
|
||||
@@ -1920,8 +1842,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Navnet v
|
||||
STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Sæt kodeord
|
||||
STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beskyt dit spil med et kodeord hvis du ikke vil have fremmede med
|
||||
|
||||
STR_NETWORK_START_SERVER_UNADVERTISED :Nej
|
||||
STR_NETWORK_START_SERVER_ADVERTISED :Ja
|
||||
STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" er}
|
||||
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimalt antal tilladte klienter:
|
||||
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Vælg det maksimale antal klienter. Det er ikke nødvendigt at fylde dem alle
|
||||
@@ -2042,7 +1962,6 @@ STR_NETWORK_CLIENT :Klient
|
||||
STR_NETWORK_SPECTATORS :Tilskuere
|
||||
|
||||
STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Skriv beløbet du vil give
|
||||
STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Tilskuer
|
||||
|
||||
# Network set password
|
||||
STR_COMPANY_PASSWORD_CANCEL :{BLACK}Gem ikke den indtastede adgangskode
|
||||
@@ -2235,15 +2154,8 @@ STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Slå gen
|
||||
STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Gør objekter usynlige i stedet for gennemsigtige
|
||||
|
||||
# Linkgraph legend window
|
||||
STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Laststrømforklaring
|
||||
STR_LINKGRAPH_LEGEND_ALL :{BLACK}Alle
|
||||
STR_LINKGRAPH_LEGEND_NONE :{BLACK}Ingen
|
||||
STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Vælg firmaer at vise
|
||||
|
||||
# Linkgraph legend window and linkgraph legend in smallmap
|
||||
STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}ubrugt
|
||||
STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}mættet
|
||||
STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}overbelastet
|
||||
|
||||
# Base for station construction window(s)
|
||||
STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Vis dækningsområde
|
||||
@@ -2974,14 +2886,9 @@ STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Køb et
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Bestik de lokale myndigheder til at hæve din bedømmelse, med risiko for en stor straf hvis det bliver opdaget.{}Pris: {CURRENCY_LONG}
|
||||
|
||||
# Goal window
|
||||
STR_GOALS_CAPTION :{WHITE}{COMPANY} Mål
|
||||
STR_GOALS_SPECTATOR_CAPTION :{WHITE}Globale Mål
|
||||
STR_GOALS_GLOBAL_TITLE :{BLACK}Globale mål:
|
||||
STR_GOALS_GLOBAL_TITLE :{BLACK}Globale mål
|
||||
STR_GOALS_TEXT :{ORANGE}{STRING}
|
||||
STR_GOALS_NONE :{ORANGE}- Ingen -
|
||||
STR_GOALS_SPECTATOR_NONE :{ORANGE}- Ikke anvendelig -
|
||||
STR_GOALS_PROGRESS :{ORANGE}{STRING}
|
||||
STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING}
|
||||
STR_GOALS_COMPANY_TITLE :{BLACK}Selskabsmål:
|
||||
STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klik på mål for at centrere hovedvinduet over industri/by/felt Ctrl+klik åbner et nyt vindue over industri/by/felt lokation
|
||||
|
||||
@@ -3021,16 +2928,6 @@ STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING
|
||||
STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klik på servicen for at centrere skærmen over industrien/byen. Ctrl+Klik åbner et nyt vindue ved industriens/byens lokalitet.
|
||||
|
||||
# Story book window
|
||||
STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Historiebog
|
||||
STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Global Historiebog
|
||||
STR_STORY_BOOK_TITLE :{YELLOW}{STRING}
|
||||
STR_STORY_BOOK_GENERIC_PAGE_ITEM :Side {NUM}
|
||||
STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Gå til en bestemt side ved at vælge den i denne rulleliste.
|
||||
STR_STORY_BOOK_PREV_PAGE :{BLACK}Forrige
|
||||
STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Gå til forrige side
|
||||
STR_STORY_BOOK_NEXT_PAGE :{BLACK}Næste
|
||||
STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Gå til næste side
|
||||
STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Ugyldig målreference
|
||||
|
||||
# Station list window
|
||||
STR_STATION_LIST_TOOLTIP :{BLACK}Stationsnavne - klik på et navn for at centrere skærmen over stationen. Ctrl+Klik åbner et nyt vindue ved stationens lokalitet
|
||||
@@ -3059,31 +2956,8 @@ STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW} {COMPA
|
||||
|
||||
STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Bedømmelse
|
||||
STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Vis stationens bedømmelse
|
||||
STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Månedligt udbud og lokal bedømmelse
|
||||
STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%)
|
||||
|
||||
STR_STATION_VIEW_GROUP :{BLACK}Gruppér på
|
||||
STR_STATION_VIEW_WAITING_STATION :Station: Ventende
|
||||
STR_STATION_VIEW_WAITING_AMOUNT :Mængde: Ventende
|
||||
STR_STATION_VIEW_PLANNED_STATION :Station: Planlagt
|
||||
STR_STATION_VIEW_PLANNED_AMOUNT :Mængde: Planlagt
|
||||
STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} fra {STATION}
|
||||
STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} via {STATION}
|
||||
STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} til {STATION}
|
||||
STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} fra ukendt station
|
||||
STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} til enhver station
|
||||
STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} via enhver station
|
||||
STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} fra denne station
|
||||
STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} stopper ved denne station
|
||||
STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} til denne station
|
||||
STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} uden stop
|
||||
|
||||
STR_STATION_VIEW_GROUP_S_V_D :Kilde-Via-Destination
|
||||
STR_STATION_VIEW_GROUP_S_D_V :Kilde-Destination-Via
|
||||
STR_STATION_VIEW_GROUP_V_S_D :Via-Kilde-Destination
|
||||
STR_STATION_VIEW_GROUP_V_D_S :Via-Destination-Kilde
|
||||
STR_STATION_VIEW_GROUP_D_S_V :Destination-Kilde-Via
|
||||
STR_STATION_VIEW_GROUP_D_V_S :Destination-Via-Kilde
|
||||
|
||||
############ range for rating starts
|
||||
STR_CARGO_RATING_APPALLING :Rædselsfuld
|
||||
@@ -3226,7 +3100,6 @@ STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Produkti
|
||||
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% transporteret)
|
||||
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centrer skærmen over industriens lokalitet. Ctrl+Klik åbner et nyt vindue ved industriens lokalitet.
|
||||
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Produktions niveauet: {YELLOW}{COMMA}%
|
||||
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Industrien har rapporteret øjeblikkelig nedlukning!
|
||||
|
||||
############ range for requires starts
|
||||
STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Kræver: {YELLOW}{STRING}{STRING}
|
||||
@@ -3475,7 +3348,7 @@ STR_REPLACE_VEHICLES_STOP :{BLACK}Stop uds
|
||||
STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Tryk for at stoppe udskiftningen at den køretøjstype, som du har valgt til venstre
|
||||
|
||||
STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Udskifter: {ORANGE}{STRING}
|
||||
STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Skift imellem lokomotiv- og vogn- udskiftningsvindue
|
||||
STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Skift imellem lokomotiv- og vogn-udskiftningsvindue
|
||||
STR_REPLACE_ENGINES :Lokomotiver
|
||||
STR_REPLACE_WAGONS :Vogne
|
||||
|
||||
@@ -3830,7 +3703,6 @@ STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}Denne ti
|
||||
STR_TIMETABLE_STATUS_START_AT :{BLACK}Denne tidsplan vil starte på {STRING}
|
||||
|
||||
STR_TIMETABLE_STARTING_DATE :{BLACK}Startdato
|
||||
STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Vælg en dato som starttidspunkt for denne køreplan. Ctrl+Klik sætter starttidspunkt for denne køreplan, og distribuerer alle køretøjer der deler denne ordre ligeligt baseret på deres relative rækkefølge, hvis ordren er fuldstændigt tidsplanlagt
|
||||
|
||||
STR_TIMETABLE_CHANGE_TIME :{BLACK}Ændre tid
|
||||
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Ændre hvor lang tid den markerede ordre skal tage
|
||||
@@ -3944,8 +3816,6 @@ STR_AI_SETTINGS_START_DELAY :Antal dage denn
|
||||
STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme for {STRING}
|
||||
STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} ændringslog for {STRING}
|
||||
STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licens for {STRING}
|
||||
STR_TEXTFILE_WRAP_TEXT :{WHITE}Ombryd tekst
|
||||
STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Ombryd teksten i vinduet, så det hele passer uden at skulle rulle
|
||||
STR_TEXTFILE_VIEW_README :{BLACK}Se readme
|
||||
STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Ændringslog
|
||||
STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licens
|
||||
@@ -4323,10 +4193,6 @@ STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Kan ikke
|
||||
|
||||
STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... fartøjet er ødelagt
|
||||
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Ingen køretøjer vil være tilgængelige overhovedet
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Skift din NewGRF-konfiguration
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Ingen køretøjer er tilgængelige endnu
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start et nyt spil efter {DATE_SHORT} eller brug en NewGRF der giver tidlige køretøjer
|
||||
|
||||
# Specific vehicle errors
|
||||
STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan ikke få toget til at passere signalet...
|
||||
@@ -4828,7 +4694,6 @@ STR_JUST_DATE_ISO :{DATE_ISO}
|
||||
STR_JUST_STRING :{STRING}
|
||||
STR_JUST_STRING_STRING :{STRING}{STRING}
|
||||
STR_JUST_RAW_STRING :{STRING}
|
||||
STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING}
|
||||
|
||||
# Slightly 'raw' stringcodes with colour or size
|
||||
STR_BLACK_COMMA :{BLACK}{COMMA}
|
||||
|
@@ -3,9 +3,9 @@
|
||||
##isocode ko_KR
|
||||
##plural 11
|
||||
##textdir ltr
|
||||
##digitsep ,
|
||||
##digitsepcur ,
|
||||
##decimalsep .
|
||||
##digitsep .
|
||||
##digitsepcur .
|
||||
##decimalsep ,
|
||||
##winlangid 0x0412
|
||||
##grflangid 0x3a
|
||||
##gender m f
|
||||
@@ -2965,14 +2965,14 @@ STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :새 건물에
|
||||
STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :수송 권한 독점권 구입
|
||||
STR_LOCAL_AUTHORITY_ACTION_BRIBE :지역 당국에게 뇌물 주기
|
||||
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}더 많은 승객과 화물을 유치하기 위해 소규모의 광고 캠페인을 시작합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}더 많은 승객과 화물을 유치하기 위해 중간 규모의 광고 캠페인을 시작합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}더 많은 승객과 화물을 유치하기 위해 대규모의 광고 캠페인을 시작합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW} 더 많은 승객과 화물을 유치하기 위해 소규모의 광고 캠페인을 시작합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW} 더 많은 승객과 화물을 유치하기 위해 중간 규모의 광고 캠페인을 시작합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW} 더 많은 승객과 화물을 유치하기 위해 대규모의 광고 캠페인을 시작합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}도시 도로망 보수공사를 시행합니다. 앞으로 6개월간 극심한 도로 혼잡을 일으킵니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}당신의 회사를 대표하는 '명예의 동상'을 건설합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}도시 상업 건물의 건설에 투자합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}1년간의 수송 권한 독점권을 구입합니다. 도시 당국은 오직 당신 회사의 역에만 승객과 화물을 허용할 것입니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}성취도를 올리기 위해 처벌을 감수하고 지역 당국에 뇌물을 줍니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW} 도시 상업 건물의 건설에 투자합니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW} 1년간의 수송 권한 독점권을 구입합니다. 도시 당국은 오직 당신 회사의 역에만 승객과 화물을 허용할 것입니다.{}가격: {CURRENCY_LONG}
|
||||
STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW} 성취도를 올리기 위해 처벌을 감수하고 지역 당국에 뇌물을 줍니다.{}가격: {CURRENCY_LONG}
|
||||
|
||||
# Goal window
|
||||
STR_GOALS_CAPTION :{WHITE}{COMPANY} 목표
|
||||
|
@@ -1143,10 +1143,7 @@ STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Togakselerasjon
|
||||
STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Vel fysikkmodell for akselerasjonen til tog. Med den opphavlege modellen vert alle toga påverka like mykje av bakkar. Med den realistiske modellen vert toga påverka ut i frå eigenskapar som lengd og trekkraft
|
||||
STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Køyretøyers akselerasjonstype: {STRING}
|
||||
STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Vel fysikkmodell for akselerasjonen til køyretøy på vegar. Med den opphavlege modellen vert alle køyretøya påverka like mykje av bakkar. Med den realistiske modellen vert køyretøya påverka ut i frå eigenskapar som lengd og trekkraft
|
||||
STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Hellingskurve for tog: {STRING}
|
||||
STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Bratthet for en rute med helling, for tog. Høgare verdi gjer det vanskelegare å klatra opp hallinga
|
||||
STR_CONFIG_SETTING_PERCENTAGE :{COMMA}%
|
||||
STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Hellingskurve for veg-køyretøy: {STRING}
|
||||
STR_CONFIG_SETTING_FORBID_90_DEG :Forby tog og skip å gjere 90-graderssvingar: {STRING}
|
||||
STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Tillet samanbygging av ikkje direkte tilstøtande stasjonar: {STRING}
|
||||
STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Tillat å bygge stasjonar som ikkje heng saman. (Ctrl+klikk for å bygge åtskilte delar av stasjonen )
|
||||
@@ -1184,28 +1181,19 @@ STR_CONFIG_SETTING_ROAD_VEHICLE_QUEUEING :Køyretøykøar
|
||||
STR_CONFIG_SETTING_ROAD_VEHICLE_QUEUEING_HELPTEXT :Gjer at køyretøy stoppar foran vegsperringar til dei vert fjerna. Alternativet er at dei snur for å finne ein annan veg
|
||||
STR_CONFIG_SETTING_AUTOSCROLL :Flytt på vindauget dersom pila er nær ytterkantane på skjermen: {STRING}
|
||||
STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Deaktivert
|
||||
STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Alle tilleggsvindauge
|
||||
STR_CONFIG_SETTING_BRIBE :Tillet bestikkelse av bystyret: {STRING}
|
||||
STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Tillet kjøp av eksklusive transportretter: {STRING}
|
||||
STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Tillat sponsing av bygningar: {STRING}
|
||||
STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Tillat at firma kan gi pengar til byar for finansiering av nye bygningar
|
||||
STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Tillat finansiering av lokal ombyggjing av vegnettet: {STRING}
|
||||
STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Tillet å sende pengar til andre firma: {STRING}
|
||||
STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Tillat overføring mellom firma i fleirspelar-modus
|
||||
STR_CONFIG_SETTING_FREIGHT_TRAINS :Vektmultiplikator for frakt til å simulere tunge tog: {STRING}
|
||||
STR_CONFIG_SETTING_PLANE_SPEED :Flyhastighet-faktor: {STRING}
|
||||
STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA}
|
||||
STR_CONFIG_SETTING_PLANE_CRASHES :Antal flystyrtar: {STRING}
|
||||
STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Sett sannsynlighet for at flykrasj skjer
|
||||
STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ingen
|
||||
STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Redusert
|
||||
STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normalt
|
||||
STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Tillet stoppestadar med gjennomkøyring på by-eigde vegar: {STRING}
|
||||
STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Tillat bygging av stoppestadar med gjennomkøyring på vegar eigd av byen
|
||||
STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Tillet stoppestadar med gjennomkøyring på konkurent-eigde vegar: {STRING}
|
||||
STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Tillatt bygging av stopp med gjennomkøyring på vegar eigd av andre firma
|
||||
STR_CONFIG_SETTING_ADJACENT_STATIONS :Tillet å byggje stasjonar inntil andre: {STRING}
|
||||
STR_CONFIG_SETTING_ADJACENT_STATIONS_HELPTEXT :Tillat forskjellige stasjonar å berøra kvarandre
|
||||
STR_CONFIG_SETTING_DYNAMIC_ENGINES :Aktiver fleire NewGRF-kjernesett: {STRING}
|
||||
STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Endring av denne instillinga er ikkje mogleg når det finst køyretøy
|
||||
STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Vedlikehald av infrastruktur: {STRING}
|
||||
@@ -1220,24 +1208,13 @@ STR_CONFIG_SETTING_ORDER_REVIEW_ON :Alle køyretøy
|
||||
STR_CONFIG_SETTING_WARN_INCOME_LESS :Åtvar dersom eit køyretøy har negativ inntekt: {STRING}
|
||||
STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Køyretøy utgår aldri: {STRING}
|
||||
STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Autoforny køyretøy når det vert gamalt: {STRING}
|
||||
STR_CONFIG_SETTING_AUTORENEW_MONTHS :Automatisk fornying når køyretøy er {STRING} maks alder
|
||||
STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relativ alder for når eit køyretøy skal vurderast for automatisk fornying
|
||||
STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} månad{P 0 "" s} før
|
||||
STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} månad{P 0 "" s} etter
|
||||
STR_CONFIG_SETTING_AUTORENEW_MONEY :Minimum formue for autofornying av køyretøy: {STRING}
|
||||
STR_CONFIG_SETTING_ERRMSG_DURATION :Varighet for feilmelding: {STRING}
|
||||
STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} sekund{P 0 "" s}
|
||||
STR_CONFIG_SETTING_HOVER_DELAY :Syn verktøytips: {STRING}
|
||||
STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Hold over i {COMMA} sekund{P 0 "" s}
|
||||
STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Høgreklikk
|
||||
STR_CONFIG_SETTING_POPULATION_IN_LABEL :Syne innbyggjartalet til byane i tittel: {STRING}
|
||||
STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Syn befolkningstal for byar saman med stadnamn på kartet
|
||||
STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Bredde på linjer i grafar: {STRING}
|
||||
|
||||
STR_CONFIG_SETTING_LAND_GENERATOR :Landskapsgenerator: {STRING}
|
||||
STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original
|
||||
STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis
|
||||
STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maksimal avstand frå kartkanten for Oljeraffineri: {STRING}
|
||||
STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Snøgrense: {STRING}
|
||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Kor ulendt skal terrenget vere (kun TerraGenesis): {STRING}
|
||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Særs jamnt
|
||||
@@ -1253,16 +1230,12 @@ STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Mot klokka
|
||||
STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Med klokka
|
||||
STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :Høgdenivå eit flatt scenariokart får: {STRING}
|
||||
STR_CONFIG_SETTING_ENABLE_FREEFORM_EDGES :Tillat endring av landskapsruter på kanten av kartet: {STRING}
|
||||
STR_CONFIG_SETTING_ENABLE_FREEFORM_EDGES_HELPTEXT :Om deaktivert, vil kartkantene alltid være hav
|
||||
STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}Ei eller fleire ruter på nordkanten er ikkje tomme
|
||||
STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}Ei eller fleire ruter på ein av kantane inneheld ikkje vatn
|
||||
|
||||
STR_CONFIG_SETTING_STATION_SPREAD :Maksimal utspreiing av stasjonar: {STRING}
|
||||
STR_CONFIG_SETTING_SERVICEATHELIPAD :Automatisk vedlikehald ved helikopterplass: {STRING}
|
||||
STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Service på helikopter etter kvar landing, sjølv om det ikkje er depot på landingsplassen.
|
||||
STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Koble landskapsverktøylinja til bygningsverktøylinjane: {STRING}
|
||||
STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Landfarge nytta på oversiktskartet: {STRING}
|
||||
STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Farge på terrenget i oversiktskartet
|
||||
STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Grøn
|
||||
STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Mørkegrøn
|
||||
STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Fiolett
|
||||
@@ -1461,7 +1434,6 @@ STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Storleiken til
|
||||
STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD :Fjern absurde vegelement under vegkonstruksjon: {STRING}
|
||||
STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD_HELPTEXT :Fjern blindvegar under finansiering av vegutbygging
|
||||
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"symmetrisk" betyr at omlag same mengd post blir sendt frå stasjon A til stasjon B og omvendt (frå B til A). "asymmetrisk" betyr at vilkårlege mengder post kan bli sendt i begge retningar. "manuelt" betyr at ingen automatisk distribusjon vil forekomma for post.
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Eining for fart: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Bruk vald eining for å vise fart
|
||||
@@ -1553,7 +1525,6 @@ STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... lagr
|
||||
STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... utelèt grafikksettet "{STRING}": ikkje funne
|
||||
STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... utelèt lydsettet "{STRING}": ikkje funne
|
||||
STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... utelèt musikksettet "{STRING}": ikkje funne
|
||||
STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Ikkje meir minne
|
||||
|
||||
# Intro window
|
||||
STR_INTRO_CAPTION :{WHITE}OpenTTD {REV}
|
||||
@@ -2033,8 +2004,6 @@ STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Vel oppd
|
||||
STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Merk alt innhald som er ei oppgradering av eksisterande, og skal lastast ned
|
||||
STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Vel bort alle
|
||||
STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Merk alt innhald som ikkje skal lastast ned
|
||||
STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Søk på eksterne nettstader
|
||||
STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Du forlet OpenTTD.
|
||||
STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Vilkåra for nedlasting av innhald frå eksterne nettsider varierar.{}Du må oppsøke dei eksterne nettsidane for å finne instruksjonar om korleis du innstalerar innhaldet i OpenTTD.{}Vil du fortsette?
|
||||
STR_CONTENT_FILTER_TITLE :{BLACK}Merke/Namnefilter:
|
||||
STR_CONTENT_OPEN_URL :{BLACK}Vitje nettsida
|
||||
@@ -3335,7 +3304,6 @@ STR_REPLACE_VEHICLES_WHEN_OLD :Berre forny gam
|
||||
STR_REPLACE_HELP_START_BUTTON :{BLACK}Klikk denne knappen dersom du vil byte ut det valde lokomotivet på venstresida med det valde lokomotivet på høgresida
|
||||
STR_REPLACE_NOT_REPLACING :{BLACK}Erstatter ikkje
|
||||
STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Ingen køyretøy vald
|
||||
STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} når gamal
|
||||
STR_REPLACE_VEHICLES_STOP :{BLACK}Stopp utskiftinga av køyretøy
|
||||
STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Klikk denne knappen for å avbryte utskiftinga av lokomotivet du har vald på venstresida
|
||||
|
||||
|
@@ -1586,7 +1586,7 @@ STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Precisão de di
|
||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Quanto mais alto o definir, mais tempo o CPU demorará a calcular o gráfico de ligações. Se demorar muito poderá notar-se algum lag. Se no entanto for definido um valor reduzido a distribuição será imprecisa, e poderá verificar cargas não serem entregues onde seriam esperadas.
|
||||
STR_CONFIG_SETTING_DEMAND_DISTANCE :Efeito de distância nos pedidos: {STRING}
|
||||
STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Se definir para um valor maior que 0, a distância entre a estação de origem A para alguma carga e um possível destino B terá um efeito na quantidade de carga transportada de A para B. Quanto maior a distância de B para A, menos carga será enviada. Quanto maior o valor definido, menos carga será transportada para estações distantes, e mais carga será levada para estações próximas.
|
||||
STR_CONFIG_SETTING_DEMAND_SIZE :Quantidade de carga a regressar para o modo simétrico: {STRING}
|
||||
STR_CONFIG_SETTING_DEMAND_SIZE :Quantidade de carga a regressar para o modo assimétrico: {STRING}
|
||||
STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Definir isto para menos de 100% torna a distribuição simétrica reagir mais como a assimétrica. Menos carga será forçada a ser devolvida se uma determinada quantidade for enviada para uma estação. Se for definido para 0% a distribuição simétrica irá reagir como a assimétrica.
|
||||
STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Saturação de percursos curtos antes de usar percursos de grande capacidade: {STRING}
|
||||
STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Frequentemente existem múltiplos trajectos entre duas estações. Cargodist irá saturar o trajecto mais curto primeiro, depois usar o segundo trajecto mais curto até o saturar, e assim por diante. A saturação é determinada pelo estimativa da capacidade do uso planeado. Ao saturar todos os caminhos, se ainda existir procura, irá sobrecarregar todos os trajectos, com preferência pelos de maior capacidade. No entanto, grande parte das vezes o algoritmo não irá estimar correctamente a capacidade. Esta configuração permite definir até que percentagem um trajecto mais curto deverá ser saturado na primeira passagem antes do algoritmo proceder ao próximo. Defina-o para menos de 100% para evitar estações sobrecarregadas no caso de capacidade super-estimada.
|
||||
|
@@ -1079,7 +1079,7 @@ STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Inställningar
|
||||
STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Inställningar med annat värde än dina inställningar för nytt spel
|
||||
|
||||
STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Begränsar listan till vissa typer av inställningar
|
||||
STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :Alla typer av inställningar
|
||||
STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :Alla inställningar
|
||||
STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Klientinställningar (sparas ej i spel-filer och påverkar alla spel)
|
||||
STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Spelinställningar (sparas i spel-fil och påverkar enbart nya spel)
|
||||
STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Spelinställningar (sparas i spel-fil och påverkar enbart nuvarande spel)
|
||||
@@ -1340,7 +1340,6 @@ STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE :Standardpalett för NewGRF när ingen annan palett är angiven: {STRING}
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_HELPTEXT :Standardpalett att använda med NewGRFer som inte anger vilken palett de behöver
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_DOS :Standardpalett (D)
|
||||
STR_CONFIG_SETTING_NEWGRF_DEFAULT_PALETTE_WIN :Tidigare versions (W) palett
|
||||
|
||||
STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Pausa automatiskt vid start av nytt spel: {STRING}
|
||||
STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Om det är aktiverat kommer OpenTTD automatiskt att pausa vid start av ett nytt spel, så att kartan kan studeras noggrannare
|
||||
@@ -1566,8 +1565,6 @@ STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Storstäders ge
|
||||
STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD :Ta bort absurda väg-element under vägkonstruktion: {STRING}
|
||||
STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD_HELPTEXT :Ta bort återvändsgränder vid bekostad vägombyggnad
|
||||
|
||||
STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Uppdatera distributionsgrafen var {STRING}:e dag{P 0:2 "" s}
|
||||
STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Tid mellan efterföljande omräkningar av länkgrafen. Varje omräkning beräknar planer för en komponent i grafen. Det medför att ett värde X för den här inställningen inte innebär att hela grafen uppdateras var X:e dag, bara vissa komponenter. Ju lägre värde du ställer in desto mer processorkraft kommer att behövas för beräkningarna. Ju högre värde du ställer in desto längre tid kommer det att ta innan distributionen av last börjar använda nya rutter.
|
||||
STR_CONFIG_SETTING_LINKGRAPH_TIME :Avsätt {STRING} dag{P 0:2 "" ar} för omberäkning av distributionsgraf
|
||||
STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Den tid varje omberäkning av en länkgrafkomponent tillåts ta. När en omberäkning startas skapas en tråd som tillåts löpa detta antal dagar. Ju kortare du sätter denna, desto mer troligt är det att tråden inte är hinner bli färdig i tid. Då kommer spelet att stanna tills den är klar (vilket gör att det laggar). Ju längre du sätter denna, desto längre tid tar det för distributionen att uppdateras när rutter ändras.
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manuellt
|
||||
@@ -1587,7 +1584,7 @@ STR_CONFIG_SETTING_DEMAND_DISTANCE :Avståndets på
|
||||
STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Om du sätter denna till ett värde högre än 0 kommer avståndet mellan ursprungsstationen A för en viss last och en möjlig destination B påverka mängden last som skickas från A till B. Ju längre B är ifrån A, desto mindre last kommer att skickas. Ju högre du sätter den, desto mindre last kommer att skickas till avlägsna stationer och desto mer last kommer att skickas till närbelägna stationer.
|
||||
STR_CONFIG_SETTING_DEMAND_SIZE :Mängd återsänd last i symmetriskt läge: {STRING}
|
||||
STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Genom att sätta denna till mindre än 100% får man den symmetriska distributionen att bete sig mer som den asymmetriska. En mindre andel än vanligt av den last som skickas till en station kommer att skickas tillbaka. Sätter du den till 0% beter sig den symmetriska distributionen precis som den asymmetriska.
|
||||
STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Belastning av korta rutter innan rutter med hög kapacitet används: {STRING}
|
||||
STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Belastning av korta ruter innan längre rutter används: {STRING}
|
||||
STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Ofta finns det flera rutter mellan två givna stationer. Godsdistributionen kommer att fylla upp den första rutten först och därefter den näst kortaste tills den är mättad osv. Mättnadsgraden bestäms utifrån en uppskattning av kapaciteten och planerad användning. När godsdristributionen har belastat samtliga rutter, och om det finns kvarvarande behov, då kommer samtliga rutter att överbelastas med preferens för rutterna med högst kapacitet. Uppskattningen av kapaciteten kommer oftast inte ske med hög noggrannhet. Denna inställning tillåter dig att ställa in hur många procent som en kort rutt ska belastas innan algoritmen ska välja nästa längre rutt. Sätt värdet till under 100 % om du vill undvika överfulla stationer i händelse av överskattad kapacitet.
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Hastighetsenhet: {STRING}
|
||||
@@ -1614,8 +1611,6 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Brittisk (gal)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metrisk (l)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³)
|
||||
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Dragkraftsenheter: {STRING}
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :När dragkraft visas i användargränssnittet, visa den i de valda enheterna
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Brittisk (lbf)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metrisk (kgf)
|
||||
STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN)
|
||||
|
@@ -2571,7 +2571,6 @@ STR_NEWGRF_INVALID_ENGINE :«مدل وسی
|
||||
STR_NEWGRF_INVALID_INDUSTRYTYPE :«صنایع نامعتبر»
|
||||
|
||||
# Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script).
|
||||
STR_INVALID_VEHICLE :وسیله نقلیه نامعتبر
|
||||
|
||||
# NewGRF scanning window
|
||||
STR_NEWGRF_SCAN_CAPTION :{WHITE}چک کردن برای فایل های NewGRF
|
||||
|
@@ -51,7 +51,8 @@ public:
|
||||
* @param company_mask Bitmask of companies to be shown.
|
||||
* @param scale Desired thickness of lines and size of station dots.
|
||||
*/
|
||||
LinkGraphOverlay(const Window *w, uint wid, uint32 cargo_mask, uint32 company_mask, uint scale) :
|
||||
LinkGraphOverlay(const Window *w, uint wid, uint32 cargo_mask = 0xFFFFFFFF,
|
||||
uint32 company_mask = 1 << _local_company, uint scale = 1) :
|
||||
window(w), widget_id(wid), cargo_mask(cargo_mask), company_mask(company_mask), scale(scale)
|
||||
{}
|
||||
|
||||
|
174
src/newgrf.cpp
174
src/newgrf.cpp
@@ -450,94 +450,9 @@ static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = NUL
|
||||
return config->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information for mapping static StringIDs.
|
||||
*/
|
||||
struct StringIDMapping {
|
||||
uint32 grfid; ///< Source NewGRF.
|
||||
StringID source; ///< Source StringID (GRF local).
|
||||
StringID *target; ///< Destination for mapping result.
|
||||
};
|
||||
typedef SmallVector<StringIDMapping, 16> StringIDMappingVector;
|
||||
static StringIDMappingVector _string_to_grf_mapping;
|
||||
|
||||
/**
|
||||
* Record a static StringID for getting translated later.
|
||||
* @param source Source StringID (GRF local).
|
||||
* @param target Destination for the mapping result.
|
||||
*/
|
||||
static void AddStringForMapping(StringID source, StringID *target)
|
||||
{
|
||||
*target = STR_UNDEFINED;
|
||||
StringIDMapping *item = _string_to_grf_mapping.Append();
|
||||
item->grfid = _cur.grffile->grfid;
|
||||
item->source = source;
|
||||
item->target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a mapping from TTDPatch's string IDs to OpenTTD's
|
||||
* string IDs, but only for the ones we are aware off; the rest
|
||||
* like likely unused and will show a warning.
|
||||
* @param str the string ID to convert
|
||||
* @return the converted string ID
|
||||
*/
|
||||
static StringID TTDPStringIDToOTTDStringIDMapping(StringID str)
|
||||
{
|
||||
/* StringID table for TextIDs 0x4E->0x6D */
|
||||
static const StringID units_volume[] = {
|
||||
STR_ITEMS, STR_PASSENGERS, STR_TONS, STR_BAGS,
|
||||
STR_LITERS, STR_ITEMS, STR_CRATES, STR_TONS,
|
||||
STR_TONS, STR_TONS, STR_TONS, STR_BAGS,
|
||||
STR_TONS, STR_TONS, STR_TONS, STR_BAGS,
|
||||
STR_TONS, STR_TONS, STR_BAGS, STR_LITERS,
|
||||
STR_TONS, STR_LITERS, STR_TONS, STR_ITEMS,
|
||||
STR_BAGS, STR_LITERS, STR_TONS, STR_ITEMS,
|
||||
STR_TONS, STR_ITEMS, STR_LITERS, STR_ITEMS
|
||||
};
|
||||
|
||||
/* A string straight from a NewGRF; this was already translated by MapGRFStringID(). */
|
||||
assert(!IsInsideMM(str, 0xD000, 0xD7FF));
|
||||
|
||||
#define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \
|
||||
assert_compile(stringend - stringid == end - begin); \
|
||||
if (str >= begin && str <= end) return str + (stringid - begin)
|
||||
|
||||
/* We have some changes in our cargo strings, resulting in some missing. */
|
||||
TEXTID_TO_STRINGID(0x000E, 0x002D, STR_CARGO_PLURAL_NOTHING, STR_CARGO_PLURAL_FIZZY_DRINKS);
|
||||
TEXTID_TO_STRINGID(0x002E, 0x004D, STR_CARGO_SINGULAR_NOTHING, STR_CARGO_SINGULAR_FIZZY_DRINK);
|
||||
if (str >= 0x004E && str <= 0x006D) return units_volume[str - 0x004E];
|
||||
TEXTID_TO_STRINGID(0x006E, 0x008D, STR_QUANTITY_NOTHING, STR_QUANTITY_FIZZY_DRINKS);
|
||||
TEXTID_TO_STRINGID(0x008E, 0x00AD, STR_ABBREV_NOTHING, STR_ABBREV_FIZZY_DRINKS);
|
||||
TEXTID_TO_STRINGID(0x00D1, 0x00E0, STR_COLOUR_DARK_BLUE, STR_COLOUR_WHITE);
|
||||
|
||||
/* Map building names according to our lang file changes. There are several
|
||||
* ranges of house ids, all of which need to be remapped to allow newgrfs
|
||||
* to use original house names. */
|
||||
TEXTID_TO_STRINGID(0x200F, 0x201F, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1);
|
||||
TEXTID_TO_STRINGID(0x2036, 0x2041, STR_TOWN_BUILDING_NAME_COTTAGES_1, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1);
|
||||
TEXTID_TO_STRINGID(0x2059, 0x205C, STR_TOWN_BUILDING_NAME_IGLOO_1, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1);
|
||||
|
||||
/* Same thing for industries */
|
||||
TEXTID_TO_STRINGID(0x4802, 0x4826, STR_INDUSTRY_NAME_COAL_MINE, STR_INDUSTRY_NAME_SUGAR_MINE);
|
||||
TEXTID_TO_STRINGID(0x482D, 0x482E, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_PLANTED);
|
||||
TEXTID_TO_STRINGID(0x4832, 0x4834, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES);
|
||||
TEXTID_TO_STRINGID(0x4835, 0x4838, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM);
|
||||
TEXTID_TO_STRINGID(0x4839, 0x483A, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM);
|
||||
|
||||
switch (str) {
|
||||
case 0x4830: return STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY;
|
||||
case 0x4831: return STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED;
|
||||
case 0x483B: return STR_ERROR_CAN_ONLY_BE_POSITIONED;
|
||||
}
|
||||
#undef TEXTID_TO_STRINGID
|
||||
|
||||
if (str == STR_NULL) return STR_EMPTY;
|
||||
|
||||
DEBUG(grf, 0, "Unknown StringID 0x%04X remapped to STR_EMPTY. Please open a Feature Request if you need it", str);
|
||||
|
||||
return STR_EMPTY;
|
||||
}
|
||||
typedef std::map<StringID *, uint32> StringIDToGRFIDMapping;
|
||||
static StringIDToGRFIDMapping _string_to_grf_mapping;
|
||||
|
||||
/**
|
||||
* Used when setting an object's property to map to the GRF's strings
|
||||
@@ -2417,7 +2332,8 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt
|
||||
break;
|
||||
|
||||
case 0x12: // Building name ID
|
||||
AddStringForMapping(buf->ReadWord(), &housespec->building_name);
|
||||
housespec->building_name = buf->ReadWord();
|
||||
_string_to_grf_mapping[&housespec->building_name] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x13: // Building availability mask
|
||||
@@ -2883,11 +2799,13 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea
|
||||
break;
|
||||
|
||||
case 0x09: // String ID for cargo type name
|
||||
AddStringForMapping(buf->ReadWord(), &cs->name);
|
||||
cs->name = buf->ReadWord();
|
||||
_string_to_grf_mapping[&cs->name] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0A: // String for 1 unit of cargo
|
||||
AddStringForMapping(buf->ReadWord(), &cs->name_single);
|
||||
cs->name_single = buf->ReadWord();
|
||||
_string_to_grf_mapping[&cs->name_single] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0B: // String for singular quantity of cargo (e.g. 1 tonne of coal)
|
||||
@@ -2895,7 +2813,8 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea
|
||||
/* String for units of cargo. This is different in OpenTTD
|
||||
* (e.g. tonnes) to TTDPatch (e.g. {COMMA} tonne of coal).
|
||||
* Property 1B is used to set OpenTTD's behaviour. */
|
||||
AddStringForMapping(buf->ReadWord(), &cs->units_volume);
|
||||
cs->units_volume = buf->ReadWord();
|
||||
_string_to_grf_mapping[&cs->units_volume] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0C: // String for plural quantity of cargo (e.g. 10 tonnes of coal)
|
||||
@@ -2903,11 +2822,13 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea
|
||||
/* Strings for an amount of cargo. This is different in OpenTTD
|
||||
* (e.g. {WEIGHT} of coal) to TTDPatch (e.g. {COMMA} tonnes of coal).
|
||||
* Property 1C is used to set OpenTTD's behaviour. */
|
||||
AddStringForMapping(buf->ReadWord(), &cs->quantifier);
|
||||
cs->quantifier = buf->ReadWord();
|
||||
_string_to_grf_mapping[&cs->quantifier] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0D: // String for two letter cargo abbreviation
|
||||
AddStringForMapping(buf->ReadWord(), &cs->abbrev);
|
||||
cs->abbrev = buf->ReadWord();
|
||||
_string_to_grf_mapping[&cs->abbrev] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0E: // Sprite ID for cargo icon
|
||||
@@ -3506,15 +3427,18 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop,
|
||||
break;
|
||||
|
||||
case 0x0C: // Industry closure message
|
||||
AddStringForMapping(buf->ReadWord(), &indsp->closure_text);
|
||||
indsp->closure_text = buf->ReadWord();
|
||||
_string_to_grf_mapping[&indsp->closure_text] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0D: // Production increase message
|
||||
AddStringForMapping(buf->ReadWord(), &indsp->production_up_text);
|
||||
indsp->production_up_text = buf->ReadWord();
|
||||
_string_to_grf_mapping[&indsp->production_up_text] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0E: // Production decrease message
|
||||
AddStringForMapping(buf->ReadWord(), &indsp->production_down_text);
|
||||
indsp->production_down_text = buf->ReadWord();
|
||||
_string_to_grf_mapping[&indsp->production_down_text] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0F: // Fund cost multiplier
|
||||
@@ -3585,7 +3509,8 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop,
|
||||
break;
|
||||
|
||||
case 0x1B: // New industry text ID
|
||||
AddStringForMapping(buf->ReadWord(), &indsp->new_industry_text);
|
||||
indsp->new_industry_text = buf->ReadWord();
|
||||
_string_to_grf_mapping[&indsp->new_industry_text] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x1C: // Input cargo multipliers for the three input cargo types
|
||||
@@ -3598,7 +3523,8 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop,
|
||||
}
|
||||
|
||||
case 0x1F: // Industry name
|
||||
AddStringForMapping(buf->ReadWord(), &indsp->name);
|
||||
indsp->name = buf->ReadWord();
|
||||
_string_to_grf_mapping[&indsp->name] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x20: // Prospecting success chance
|
||||
@@ -3616,15 +3542,10 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop,
|
||||
indsp->removal_cost_multiplier = buf->ReadDWord();
|
||||
break;
|
||||
|
||||
case 0x24: { // name for nearby station
|
||||
uint16 str = buf->ReadWord();
|
||||
if (str == 0) {
|
||||
indsp->station_name = STR_NULL;
|
||||
} else {
|
||||
AddStringForMapping(str, &indsp->station_name);
|
||||
}
|
||||
case 0x24: // name for nearby station
|
||||
indsp->station_name = buf->ReadWord();
|
||||
if (indsp->station_name != STR_NULL) _string_to_grf_mapping[&indsp->station_name] = _cur.grffile->grfid;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = CIR_UNKNOWN;
|
||||
@@ -3817,7 +3738,8 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
AddStringForMapping(buf->ReadWord(), &as->name);
|
||||
as->name = buf->ReadWord();
|
||||
_string_to_grf_mapping[&as->name] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x11: // Maintenance cost factor
|
||||
@@ -3927,13 +3849,16 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea
|
||||
}
|
||||
|
||||
case 0x09: { // Class name
|
||||
StringID class_name = buf->ReadWord();
|
||||
ObjectClass *objclass = ObjectClass::Get(spec->cls_id);
|
||||
AddStringForMapping(buf->ReadWord(), &objclass->name);
|
||||
objclass->name = class_name;
|
||||
_string_to_grf_mapping[&objclass->name] = _cur.grffile->grfid;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0A: // Object name
|
||||
AddStringForMapping(buf->ReadWord(), &spec->name);
|
||||
spec->name = buf->ReadWord();
|
||||
_string_to_grf_mapping[&spec->name] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0B: // Climate mask
|
||||
@@ -4039,29 +3964,33 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR
|
||||
buf->ReadDWord();
|
||||
break;
|
||||
|
||||
case 0x09: { // Toolbar caption of railtype (sets name as well for backwards compatibility for grf ver < 8)
|
||||
uint16 str = buf->ReadWord();
|
||||
AddStringForMapping(str, &rti->strings.toolbar_caption);
|
||||
case 0x09: // Toolbar caption of railtype (sets name as well for backwards compatibility for grf ver < 8)
|
||||
rti->strings.toolbar_caption = buf->ReadWord();
|
||||
_string_to_grf_mapping[&rti->strings.toolbar_caption] = _cur.grffile->grfid;
|
||||
if (_cur.grffile->grf_version < 8) {
|
||||
AddStringForMapping(str, &rti->strings.name);
|
||||
rti->strings.name = rti->strings.toolbar_caption;
|
||||
_string_to_grf_mapping[&rti->strings.name] = _cur.grffile->grfid;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0A: // Menu text of railtype
|
||||
AddStringForMapping(buf->ReadWord(), &rti->strings.menu_text);
|
||||
rti->strings.menu_text = buf->ReadWord();
|
||||
_string_to_grf_mapping[&rti->strings.menu_text] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0B: // Build window caption
|
||||
AddStringForMapping(buf->ReadWord(), &rti->strings.build_caption);
|
||||
rti->strings.build_caption = buf->ReadWord();
|
||||
_string_to_grf_mapping[&rti->strings.build_caption] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0C: // Autoreplace text
|
||||
AddStringForMapping(buf->ReadWord(), &rti->strings.replace_text);
|
||||
rti->strings.replace_text = buf->ReadWord();
|
||||
_string_to_grf_mapping[&rti->strings.replace_text] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0D: // New locomotive text
|
||||
AddStringForMapping(buf->ReadWord(), &rti->strings.new_loco);
|
||||
rti->strings.new_loco = buf->ReadWord();
|
||||
_string_to_grf_mapping[&rti->strings.new_loco] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x0E: // Compatible railtype list
|
||||
@@ -4125,7 +4054,8 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR
|
||||
break;
|
||||
|
||||
case 0x1B: // Name of railtype (overridden by prop 09 for grf ver < 8)
|
||||
AddStringForMapping(buf->ReadWord(), &rti->strings.name);
|
||||
rti->strings.name = buf->ReadWord();
|
||||
_string_to_grf_mapping[&rti->strings.name] = _cur.grffile->grfid;
|
||||
break;
|
||||
|
||||
case 0x1C: // Maintenance cost factor
|
||||
@@ -9096,10 +9026,10 @@ extern void InitGRFTownGeneratorNames();
|
||||
/** Finish loading NewGRFs and execute needed post-processing */
|
||||
static void AfterLoadGRFs()
|
||||
{
|
||||
for (StringIDMapping *it = _string_to_grf_mapping.Begin(); it != _string_to_grf_mapping.End(); it++) {
|
||||
*it->target = MapGRFStringID(it->grfid, it->source);
|
||||
for (StringIDToGRFIDMapping::iterator it = _string_to_grf_mapping.begin(); it != _string_to_grf_mapping.end(); it++) {
|
||||
*((*it).first) = MapGRFStringID((*it).second, *((*it).first));
|
||||
}
|
||||
_string_to_grf_mapping.Clear();
|
||||
_string_to_grf_mapping.clear();
|
||||
|
||||
/* Free the action 6 override sprites. */
|
||||
for (GRFLineToSpriteOverride::iterator it = _grf_line_to_action6_sprite_override.begin(); it != _grf_line_to_action6_sprite_override.end(); it++) {
|
||||
|
@@ -473,16 +473,16 @@ uint32 GetCompanyInfo(CompanyID owner, const Livery *l)
|
||||
/**
|
||||
* Get the error message from a shape/location/slope check callback result.
|
||||
* @param cb_res Callback result to translate. If bit 10 is set this is a standard error message, otherwise a NewGRF provided string.
|
||||
* @param grffile NewGRF to use to resolve a custom error message.
|
||||
* @param grfid grfID to use to resolve a custom error message.
|
||||
* @param default_error Error message to use for the generic error.
|
||||
* @return CommandCost indicating success or the error message.
|
||||
*/
|
||||
CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, const GRFFile *grffile, StringID default_error)
|
||||
CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, uint32 grfid, StringID default_error)
|
||||
{
|
||||
CommandCost res;
|
||||
|
||||
if (cb_res < 0x400) {
|
||||
res = CommandCost(GetGRFStringID(grffile->grfid, 0xD000 + cb_res));
|
||||
res = CommandCost(GetGRFStringID(grfid, 0xD000 + cb_res));
|
||||
} else {
|
||||
switch (cb_res) {
|
||||
case 0x400: return res; // No error.
|
||||
@@ -501,7 +501,7 @@ CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, const GRFFi
|
||||
}
|
||||
|
||||
/* Copy some parameters from the registers to the error message text ref. stack */
|
||||
res.UseTextRefStack(grffile, 4);
|
||||
res.UseTextRefStack(4);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@@ -297,7 +297,7 @@ uint32 GetTerrainType(TileIndex tile, TileContext context = TCX_NORMAL);
|
||||
TileIndex GetNearbyTile(byte parameter, TileIndex tile, bool signed_offsets = true, Axis axis = INVALID_AXIS);
|
||||
uint32 GetNearbyTileInformation(TileIndex tile, bool grf_version8);
|
||||
uint32 GetCompanyInfo(CompanyID owner, const struct Livery *l = NULL);
|
||||
CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, const GRFFile *grffile, StringID default_error);
|
||||
CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, uint32 grfid, StringID default_error);
|
||||
|
||||
void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res);
|
||||
bool ConvertBooleanCallback(const struct GRFFile *grffile, uint16 cbid, uint16 cb_res);
|
||||
|
@@ -531,7 +531,7 @@ CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uin
|
||||
uint16 result = group->GetCallbackResult();
|
||||
if (result == CALLBACK_FAILED) return CommandCost();
|
||||
|
||||
return GetErrorMessageFromLocationCallbackResult(result, indspec->grf_prop.grffile, STR_ERROR_SITE_UNSUITABLE);
|
||||
return GetErrorMessageFromLocationCallbackResult(result, indspec->grf_prop.grffile->grfid, STR_ERROR_SITE_UNSUITABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -256,7 +256,7 @@ CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind
|
||||
return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
|
||||
}
|
||||
|
||||
return GetErrorMessageFromLocationCallbackResult(callback_res, its->grf_prop.grffile, STR_ERROR_SITE_UNSUITABLE);
|
||||
return GetErrorMessageFromLocationCallbackResult(callback_res, its->grf_prop.grffile->grfid, STR_ERROR_SITE_UNSUITABLE);
|
||||
}
|
||||
|
||||
/* Simple wrapper for GetHouseCallback to keep the animation unified. */
|
||||
|
@@ -680,7 +680,7 @@ CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_til
|
||||
|
||||
/* The meaning of bit 10 is inverted for a grf version < 8. */
|
||||
if (statspec->grf_prop.grffile->grf_version < 8) ToggleBit(cb_res, 10);
|
||||
return GetErrorMessageFromLocationCallbackResult(cb_res, statspec->grf_prop.grffile, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||
return GetErrorMessageFromLocationCallbackResult(cb_res, statspec->grf_prop.grffile->grfid, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#include "strings_func.h"
|
||||
#include "newgrf_storage.h"
|
||||
#include "newgrf_text.h"
|
||||
#include "newgrf_cargo.h"
|
||||
#include "string_func.h"
|
||||
#include "date_type.h"
|
||||
#include "debug.h"
|
||||
@@ -36,6 +35,70 @@
|
||||
#define GRFTAB 28
|
||||
#define TABSIZE 11
|
||||
|
||||
/**
|
||||
* Perform a mapping from TTDPatch's string IDs to OpenTTD's
|
||||
* string IDs, but only for the ones we are aware off; the rest
|
||||
* like likely unused and will show a warning.
|
||||
* @param str the string ID to convert
|
||||
* @return the converted string ID
|
||||
*/
|
||||
StringID TTDPStringIDToOTTDStringIDMapping(StringID str)
|
||||
{
|
||||
/* StringID table for TextIDs 0x4E->0x6D */
|
||||
static const StringID units_volume[] = {
|
||||
STR_ITEMS, STR_PASSENGERS, STR_TONS, STR_BAGS,
|
||||
STR_LITERS, STR_ITEMS, STR_CRATES, STR_TONS,
|
||||
STR_TONS, STR_TONS, STR_TONS, STR_BAGS,
|
||||
STR_TONS, STR_TONS, STR_TONS, STR_BAGS,
|
||||
STR_TONS, STR_TONS, STR_BAGS, STR_LITERS,
|
||||
STR_TONS, STR_LITERS, STR_TONS, STR_ITEMS,
|
||||
STR_BAGS, STR_LITERS, STR_TONS, STR_ITEMS,
|
||||
STR_TONS, STR_ITEMS, STR_LITERS, STR_ITEMS
|
||||
};
|
||||
|
||||
/* A string straight from a NewGRF; no need to remap this as it's already mapped. */
|
||||
if (IsInsideMM(str, 0xD000, 0xD7FF)) return str;
|
||||
|
||||
#define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \
|
||||
assert_compile(stringend - stringid == end - begin); \
|
||||
if (str >= begin && str <= end) return str + (stringid - begin)
|
||||
|
||||
/* We have some changes in our cargo strings, resulting in some missing. */
|
||||
TEXTID_TO_STRINGID(0x000E, 0x002D, STR_CARGO_PLURAL_NOTHING, STR_CARGO_PLURAL_FIZZY_DRINKS);
|
||||
TEXTID_TO_STRINGID(0x002E, 0x004D, STR_CARGO_SINGULAR_NOTHING, STR_CARGO_SINGULAR_FIZZY_DRINK);
|
||||
if (str >= 0x004E && str <= 0x006D) return units_volume[str - 0x004E];
|
||||
TEXTID_TO_STRINGID(0x006E, 0x008D, STR_QUANTITY_NOTHING, STR_QUANTITY_FIZZY_DRINKS);
|
||||
TEXTID_TO_STRINGID(0x008E, 0x00AD, STR_ABBREV_NOTHING, STR_ABBREV_FIZZY_DRINKS);
|
||||
TEXTID_TO_STRINGID(0x00D1, 0x00E0, STR_COLOUR_DARK_BLUE, STR_COLOUR_WHITE);
|
||||
|
||||
/* Map building names according to our lang file changes. There are several
|
||||
* ranges of house ids, all of which need to be remapped to allow newgrfs
|
||||
* to use original house names. */
|
||||
TEXTID_TO_STRINGID(0x200F, 0x201F, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1);
|
||||
TEXTID_TO_STRINGID(0x2036, 0x2041, STR_TOWN_BUILDING_NAME_COTTAGES_1, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1);
|
||||
TEXTID_TO_STRINGID(0x2059, 0x205C, STR_TOWN_BUILDING_NAME_IGLOO_1, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1);
|
||||
|
||||
/* Same thing for industries */
|
||||
TEXTID_TO_STRINGID(0x4802, 0x4826, STR_INDUSTRY_NAME_COAL_MINE, STR_INDUSTRY_NAME_SUGAR_MINE);
|
||||
TEXTID_TO_STRINGID(0x482D, 0x482E, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_PLANTED);
|
||||
TEXTID_TO_STRINGID(0x4832, 0x4834, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES);
|
||||
TEXTID_TO_STRINGID(0x4835, 0x4838, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM);
|
||||
TEXTID_TO_STRINGID(0x4839, 0x483A, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM);
|
||||
|
||||
switch (str) {
|
||||
case 0x4830: return STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY;
|
||||
case 0x4831: return STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED;
|
||||
case 0x483B: return STR_ERROR_CAN_ONLY_BE_POSITIONED;
|
||||
}
|
||||
#undef TEXTID_TO_STRINGID
|
||||
|
||||
if (str == STR_NULL) return STR_EMPTY;
|
||||
|
||||
DEBUG(grf, 0, "Unknown StringID 0x%04X remapped to STR_EMPTY. Please open a Feature Request if you need it", str);
|
||||
|
||||
return STR_EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explains the newgrf shift bit positioning.
|
||||
* the grf base will not be used in order to find the string, but rather for
|
||||
@@ -521,12 +584,7 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16);
|
||||
break;
|
||||
case 0x1A: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16); break;
|
||||
|
||||
default:
|
||||
grfmsg(1, "missing handler for extended format code");
|
||||
@@ -696,12 +754,20 @@ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool ne
|
||||
return (GRFTAB << TABSIZE) + id;
|
||||
}
|
||||
|
||||
/* Used to remember the grfid that the last retrieved string came from */
|
||||
static uint32 _last_grfid = 0;
|
||||
|
||||
/**
|
||||
* Returns the index for this stringid associated with its grfID
|
||||
*/
|
||||
StringID GetGRFStringID(uint32 grfid, uint16 stringid)
|
||||
{
|
||||
for (uint id = 0; id < _num_grf_texts; id++) {
|
||||
uint id;
|
||||
|
||||
/* grfid is zero when we're being called via an include */
|
||||
if (grfid == 0) grfid = _last_grfid;
|
||||
|
||||
for (id = 0; id < _num_grf_texts; id++) {
|
||||
if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
|
||||
return (GRFTAB << TABSIZE) + id;
|
||||
}
|
||||
@@ -743,6 +809,9 @@ const char *GetGRFStringPtr(uint16 stringid)
|
||||
{
|
||||
assert(_grf_text[stringid].grfid != 0);
|
||||
|
||||
/* Remember this grfid in case the string has included text */
|
||||
_last_grfid = _grf_text[stringid].grfid;
|
||||
|
||||
const char *str = GetGRFStringFromGRFText(_grf_text[stringid].textholder);
|
||||
if (str != NULL) return str;
|
||||
|
||||
@@ -811,14 +880,12 @@ void CleanUpStrings()
|
||||
struct TextRefStack {
|
||||
byte stack[0x30];
|
||||
byte position;
|
||||
const GRFFile *grffile;
|
||||
bool used;
|
||||
|
||||
TextRefStack() : position(0), grffile(NULL), used(false) {}
|
||||
TextRefStack() : position(0), used(false) {}
|
||||
|
||||
TextRefStack(const TextRefStack &stack) :
|
||||
position(stack.position),
|
||||
grffile(stack.grffile),
|
||||
used(stack.used)
|
||||
{
|
||||
memcpy(this->stack, stack.stack, sizeof(this->stack));
|
||||
@@ -870,14 +937,7 @@ struct TextRefStack {
|
||||
this->stack[this->position + 1] = GB(word, 8, 8);
|
||||
}
|
||||
|
||||
void ResetStack(const GRFFile *grffile)
|
||||
{
|
||||
assert(grffile != NULL);
|
||||
this->position = 0;
|
||||
this->grffile = grffile;
|
||||
this->used = true;
|
||||
}
|
||||
|
||||
void ResetStack() { this->position = 0; this->used = true; }
|
||||
void RewindStack() { this->position = 0; }
|
||||
};
|
||||
|
||||
@@ -926,15 +986,14 @@ void RestoreTextRefStackBackup(struct TextRefStack *backup)
|
||||
* by calling #StopTextRefStackUsage(), so NewGRF string codes operate on the
|
||||
* normal string parameters again.
|
||||
*
|
||||
* @param grffile the NewGRF providing the stack data
|
||||
* @param numEntries number of entries to copy from the registers
|
||||
* @param values values to copy onto the stack; if NULL the temporary NewGRF registers will be used instead
|
||||
*/
|
||||
void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values)
|
||||
void StartTextRefStackUsage(byte numEntries, const uint32 *values)
|
||||
{
|
||||
extern TemporaryStorageArray<int32, 0x110> _temp_store;
|
||||
|
||||
_newgrf_textrefstack.ResetStack(grffile);
|
||||
_newgrf_textrefstack.ResetStack();
|
||||
|
||||
byte *p = _newgrf_textrefstack.stack;
|
||||
for (uint i = 0; i < numEntries; i++) {
|
||||
@@ -963,53 +1022,11 @@ void RewindTextRefStack()
|
||||
* @param buff the buffer we're writing to
|
||||
* @param str the string that we need to write
|
||||
* @param argv the OpenTTD stack of values
|
||||
* @param argv_size space on the stack \a argv
|
||||
* @param modify_argv When true, modify the OpenTTD stack.
|
||||
* @return the string control code to "execute" now
|
||||
*/
|
||||
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv)
|
||||
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, bool modify_argv)
|
||||
{
|
||||
switch (scc) {
|
||||
default: break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_DWORD_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_WORD_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_BYTE_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_WORD_UNSIGNED:
|
||||
case SCC_NEWGRF_PRINT_BYTE_HEX:
|
||||
case SCC_NEWGRF_PRINT_WORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_DWORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_QWORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
|
||||
case SCC_NEWGRF_PRINT_QWORD_CURRENCY:
|
||||
case SCC_NEWGRF_PRINT_WORD_STRING_ID:
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_SPEED:
|
||||
case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_POWER:
|
||||
case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
|
||||
if (argv_size < 1) {
|
||||
DEBUG(misc, 0, "Too many NewGRF string parameters.");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
|
||||
if (argv_size < 2) {
|
||||
DEBUG(misc, 0, "Too many NewGRF string parameters.");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (_newgrf_textrefstack.used && modify_argv) {
|
||||
switch (scc) {
|
||||
default: NOT_REACHED();
|
||||
@@ -1047,15 +1064,8 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const
|
||||
case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break;
|
||||
case SCC_NEWGRF_UNPRINT: *buff = max(*buff - Utf8Consume(str), buf_start); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
|
||||
argv[0] = GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
|
||||
argv[1] = _newgrf_textrefstack.PopUnsignedWord();
|
||||
break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_STRING_ID:
|
||||
*argv = MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord());
|
||||
*argv = TTDPStringIDToOTTDStringIDMapping(_newgrf_textrefstack.PopUnsignedWord());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1107,15 +1117,6 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const
|
||||
case SCC_NEWGRF_PRINT_WORD_POWER:
|
||||
return SCC_POWER;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
|
||||
return SCC_CARGO_LONG;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
|
||||
return SCC_CARGO_SHORT;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
|
||||
return SCC_CARGO_TINY;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
|
||||
return SCC_STATION_NAME;
|
||||
|
||||
|
@@ -35,13 +35,15 @@ void CleanUpGRFText(struct GRFText *grftext);
|
||||
|
||||
bool CheckGrfLangID(byte lang_id, byte grf_version);
|
||||
|
||||
void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values = NULL);
|
||||
void StartTextRefStackUsage(byte numEntries, const uint32 *values = NULL);
|
||||
void StopTextRefStackUsage();
|
||||
void RewindTextRefStack();
|
||||
bool UsingNewGRFTextStack();
|
||||
struct TextRefStack *CreateTextRefStackBackup();
|
||||
void RestoreTextRefStackBackup(struct TextRefStack *backup);
|
||||
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv);
|
||||
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, bool modify_argv);
|
||||
|
||||
StringID TTDPStringIDToOTTDStringIDMapping(StringID string);
|
||||
|
||||
/** Mapping of language data between a NewGRF and OpenTTD. */
|
||||
struct LanguageMap {
|
||||
|
@@ -270,7 +270,7 @@ CommandCost CmdBuildObject(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
} else {
|
||||
/* The meaning of bit 10 is inverted for a grf version < 8. */
|
||||
if (spec->grf_prop.grffile->grf_version < 8) ToggleBit(callback, 10);
|
||||
CommandCost ret = GetErrorMessageFromLocationCallbackResult(callback, spec->grf_prop.grffile, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||
CommandCost ret = GetErrorMessageFromLocationCallbackResult(callback, spec->grf_prop.grffile->grfid, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
}
|
||||
|
@@ -286,7 +286,7 @@ public:
|
||||
} else {
|
||||
StringID message = GetGRFStringID(spec->grf_prop.grffile->grfid, 0xD000 + callback_res);
|
||||
if (message != STR_NULL && message != STR_UNDEFINED) {
|
||||
StartTextRefStackUsage(spec->grf_prop.grffile, 6);
|
||||
StartTextRefStackUsage(6);
|
||||
/* Use all the available space left from where we stand up to the
|
||||
* end of the window. We ALSO enlarge the window if needed, so we
|
||||
* can 'go' wild with the bottom of the window. */
|
||||
|
@@ -263,7 +263,7 @@ public:
|
||||
*/
|
||||
inline VehicleOrderID GetNumManualOrders() const { return this->num_manual_orders; }
|
||||
|
||||
StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first = NULL, uint hops = 0) const;
|
||||
StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first = NULL) const;
|
||||
const Order *GetNextDecisionNode(const Order *next, uint hops) const;
|
||||
|
||||
void InsertOrderAt(Order *new_order, int index);
|
||||
|
@@ -391,12 +391,11 @@ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
|
||||
* Recursively determine the next deterministic station to stop at.
|
||||
* @param v The vehicle we're looking at.
|
||||
* @param first Order to start searching at or NULL to start at cur_implicit_order_index + 1.
|
||||
* @param hops Number of orders we have already looked at.
|
||||
* @return Next stoppping station or INVALID_STATION.
|
||||
* @pre The vehicle is currently loading and v->last_station_visited is meaningful.
|
||||
* @note This function may draw a random number. Don't use it from the GUI.
|
||||
*/
|
||||
StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
|
||||
StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first) const
|
||||
{
|
||||
|
||||
const Order *next = first;
|
||||
@@ -414,27 +413,42 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *
|
||||
}
|
||||
}
|
||||
|
||||
uint hops = 0;
|
||||
do {
|
||||
next = this->GetNextDecisionNode(next, ++hops);
|
||||
|
||||
/* Resolve possibly nested conditionals by estimation. */
|
||||
while (next != NULL && next->IsType(OT_CONDITIONAL)) {
|
||||
/* We return both options of conditional orders. */
|
||||
const Order *skip_to = this->GetNextDecisionNode(
|
||||
this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
|
||||
const Order *advance = this->GetNextDecisionNode(
|
||||
this->GetNext(next), hops);
|
||||
if (advance == NULL || advance == first || skip_to == advance) {
|
||||
next = (skip_to == first) ? NULL : skip_to;
|
||||
} else if (skip_to == NULL || skip_to == first) {
|
||||
next = (advance == first) ? NULL : advance;
|
||||
} else {
|
||||
StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
|
||||
StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
|
||||
while (!st2.IsEmpty()) st1.Push(st2.Pop());
|
||||
return st1;
|
||||
}
|
||||
++hops;
|
||||
if (next->GetConditionVariable() == OCV_LOAD_PERCENTAGE) {
|
||||
/* If the condition is based on load percentage we can't
|
||||
* tell what it will do. So we choose randomly. */
|
||||
const Order *skip_to = this->GetNextDecisionNode(
|
||||
this->GetOrderAt(next->GetConditionSkipToOrder()),
|
||||
hops);
|
||||
const Order *advance = this->GetNextDecisionNode(
|
||||
this->GetNext(next), hops);
|
||||
if (advance == NULL) {
|
||||
next = skip_to;
|
||||
} else if (skip_to == NULL) {
|
||||
next = advance;
|
||||
} else {
|
||||
StationIDStack st1 = this->GetNextStoppingStation(v, skip_to);
|
||||
StationIDStack st2 = this->GetNextStoppingStation(v, advance);
|
||||
while (!st2.IsEmpty()) st1.Push(st2.Pop());
|
||||
return st1;
|
||||
}
|
||||
} else {
|
||||
/* Otherwise we're optimistic and expect that the
|
||||
* condition value won't change until it's evaluated. */
|
||||
VehicleOrderID skip_to = ProcessConditionalOrder(next, v);
|
||||
if (skip_to != INVALID_VEH_ORDER_ID) {
|
||||
next = this->GetNextDecisionNode(this->GetOrderAt(skip_to),
|
||||
hops);
|
||||
} else {
|
||||
next = this->GetNextDecisionNode(this->GetNext(next), hops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't return a next stop if the vehicle has to unload everything. */
|
||||
|
@@ -298,10 +298,7 @@
|
||||
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
|
||||
}
|
||||
uint32 townnameparts;
|
||||
if (!GenerateTownName(&townnameparts)) {
|
||||
ScriptObject::SetLastError(ScriptError::ERR_NAME_IS_NOT_UNIQUE);
|
||||
return false;
|
||||
}
|
||||
GenerateTownName(&townnameparts);
|
||||
|
||||
return ScriptObject::DoCommand(tile, size | (city ? 1 << 2 : 0) | layout << 3, townnameparts, CMD_FOUND_TOWN, text);
|
||||
}
|
||||
|
@@ -1049,7 +1049,7 @@ void SmallMapWindow::SetupWidgetData()
|
||||
SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc), refresh(FORCE_REFRESH_PERIOD)
|
||||
{
|
||||
_smallmap_industry_highlight = INVALID_INDUSTRYTYPE;
|
||||
this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1);
|
||||
this->overlay = new LinkGraphOverlay(this, WID_SM_MAP);
|
||||
this->InitNested(window_number);
|
||||
this->LowerWidget(this->map_type + WID_SM_CONTOUR);
|
||||
|
||||
@@ -1309,6 +1309,7 @@ void SmallMapWindow::SetOverlayCargoMask()
|
||||
if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type);
|
||||
}
|
||||
this->overlay->SetCargoMask(cargo_mask);
|
||||
this->overlay->RebuildCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1530,14 +1531,7 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
|
||||
/* Update the window every now and then */
|
||||
if (--this->refresh != 0) return;
|
||||
|
||||
if (this->map_type == SMT_LINKSTATS) {
|
||||
uint32 company_mask = this->GetOverlayCompanyMask();
|
||||
if (this->overlay->GetCompanyMask() != company_mask) {
|
||||
this->overlay->SetCompanyMask(company_mask);
|
||||
} else {
|
||||
this->overlay->RebuildCache();
|
||||
}
|
||||
}
|
||||
if (this->map_type == SMT_LINKSTATS) this->overlay->RebuildCache();
|
||||
_smallmap_industry_highlight_state = !_smallmap_industry_highlight_state;
|
||||
|
||||
this->refresh = _smallmap_industry_highlight != INVALID_INDUSTRYTYPE ? BLINK_PERIOD : FORCE_REFRESH_PERIOD;
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#define SMALLMAP_GUI_H
|
||||
|
||||
#include "industry_type.h"
|
||||
#include "company_base.h"
|
||||
#include "window_gui.h"
|
||||
#include "strings_func.h"
|
||||
#include "blitter/factory.hpp"
|
||||
@@ -136,16 +135,6 @@ protected:
|
||||
this->GetNumberRowsLegend(num_columns) * FONT_HEIGHT_SMALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bitmask for company links to be displayed. Usually this will be
|
||||
* the _local_company. Spectators get to see all companies' links.
|
||||
* @return Company mask.
|
||||
*/
|
||||
inline uint32 GetOverlayCompanyMask() const
|
||||
{
|
||||
return Company::IsValidID(_local_company) ? 1U << _local_company : 0xffffffff;
|
||||
}
|
||||
|
||||
uint GetNumberRowsLegend(uint columns) const;
|
||||
void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0);
|
||||
void SwitchMapType(SmallMapType map_type);
|
||||
|
@@ -192,8 +192,8 @@ const char *GetStringPtr(StringID string)
|
||||
{
|
||||
switch (GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)) {
|
||||
case GAME_TEXT_TAB: return GetGameStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
|
||||
/* 0xD0xx and 0xD4xx IDs have been converted earlier. */
|
||||
case 26: NOT_REACHED();
|
||||
/* GetGRFStringPtr doesn't handle 0xD4xx ids, we need to convert those to 0xD0xx. */
|
||||
case 26: return GetStringPtr(GetGRFStringID(0, 0xD000 + GB(string, TAB_SIZE_OFFSET, 10)));
|
||||
case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
|
||||
case 29: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x0800);
|
||||
case 30: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x1000);
|
||||
@@ -242,7 +242,12 @@ char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, co
|
||||
return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
|
||||
|
||||
case 26:
|
||||
NOT_REACHED();
|
||||
/* Include string within newgrf text (format code 81) */
|
||||
if (HasBit(index, 10)) {
|
||||
StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
|
||||
return GetStringWithArgs(buffr, string, args, last, case_index);
|
||||
}
|
||||
break;
|
||||
|
||||
case 28:
|
||||
return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index);
|
||||
@@ -272,6 +277,14 @@ char *GetString(char *buffr, StringID string, const char *last)
|
||||
}
|
||||
|
||||
|
||||
char *InlineString(char *buf, StringID string)
|
||||
{
|
||||
buf += Utf8Encode(buf, SCC_STRING_ID);
|
||||
buf += Utf8Encode(buf, string);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is used to "bind" a C string to a OpenTTD dparam slot.
|
||||
* @param n slot of the string
|
||||
@@ -804,7 +817,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg
|
||||
if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
|
||||
/* We need to pass some stuff as it might be modified; oh boy. */
|
||||
//todo: should argve be passed here too?
|
||||
b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), args->GetDataLeft(), dry_run);
|
||||
b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), dry_run);
|
||||
if (b == 0) continue;
|
||||
}
|
||||
|
||||
@@ -1004,6 +1017,11 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg
|
||||
buff = strecpy(buff, _openttd_revision, last);
|
||||
break;
|
||||
|
||||
case SCC_STRING_ID: // {STRINL}
|
||||
if (game_script) break;
|
||||
buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
|
||||
break;
|
||||
|
||||
case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
|
||||
if (game_script) break;
|
||||
const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
|
||||
@@ -1017,7 +1035,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg
|
||||
/* WARNING. It's prohibited for the included string to consume any arguments.
|
||||
* For included strings that consume argument, you should use STRING1, STRING2 etc.
|
||||
* To debug stuff you can set argv to NULL and it will tell you */
|
||||
StringParameters tmp_params(args->GetDataPointer(), args->GetDataLeft(), NULL);
|
||||
StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
|
||||
buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
|
||||
next_substr_case_index = 0;
|
||||
break;
|
||||
@@ -1034,7 +1052,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg
|
||||
StringID str = args->GetInt32(b);
|
||||
if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
|
||||
uint size = b - SCC_STRING1 + 1;
|
||||
if (game_script && size > args->GetDataLeft()) {
|
||||
if (game_script && size > args->num_param - args->offset) {
|
||||
buff = strecat(buff, "(too many parameters)", last);
|
||||
} else {
|
||||
StringParameters sub_args(*args, size);
|
||||
|
@@ -56,7 +56,7 @@ public:
|
||||
offset(0),
|
||||
num_param(size)
|
||||
{
|
||||
assert(size <= parent.GetDataLeft());
|
||||
assert(size <= parent.num_param - parent.offset);
|
||||
if (parent.type == NULL) {
|
||||
this->type = NULL;
|
||||
} else {
|
||||
@@ -89,12 +89,6 @@ public:
|
||||
return &this->data[this->offset];
|
||||
}
|
||||
|
||||
/** Return the amount of elements which can still be read. */
|
||||
uint GetDataLeft() const
|
||||
{
|
||||
return this->num_param - this->offset;
|
||||
}
|
||||
|
||||
/** Get a pointer to a specific element in the data array. */
|
||||
uint64 *GetPointerToOffset(uint offset) const
|
||||
{
|
||||
@@ -130,6 +124,7 @@ public:
|
||||
};
|
||||
extern StringParameters _global_string_params;
|
||||
|
||||
char *InlineString(char *buf, StringID string);
|
||||
char *GetString(char *buffr, StringID string, const char *last);
|
||||
char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false);
|
||||
const char *GetStringPtr(StringID string);
|
||||
|
@@ -85,6 +85,7 @@ enum StringControlCode {
|
||||
SCC_HEX,
|
||||
SCC_BYTES,
|
||||
|
||||
SCC_STRING_ID,
|
||||
SCC_RAW_STRING_POINTER,
|
||||
SCC_PLURAL_LIST,
|
||||
SCC_GENDER_LIST,
|
||||
@@ -140,9 +141,6 @@ enum StringControlCode {
|
||||
SCC_NEWGRF_PRINT_WORD_POWER, ///< Read 2 bytes from the stack as unsigned power
|
||||
SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT, ///< Read 2 bytes from the stack as short signed volume
|
||||
SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT, ///< Read 2 bytes from the stack as short unsigned weight
|
||||
SCC_NEWGRF_PRINT_WORD_CARGO_LONG, ///< Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount
|
||||
SCC_NEWGRF_PRINT_WORD_CARGO_SHORT, ///< Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount
|
||||
SCC_NEWGRF_PRINT_WORD_CARGO_TINY, ///< Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount
|
||||
SCC_NEWGRF_PUSH_WORD, ///< Pushes 2 bytes onto the stack
|
||||
SCC_NEWGRF_UNPRINT, ///< "Unprints" the given number of bytes from the string
|
||||
SCC_NEWGRF_DISCARD_WORD, ///< Discard the next two bytes
|
||||
|
@@ -1077,7 +1077,7 @@ static bool AllocateDibSection(int w, int h, bool force)
|
||||
bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
|
||||
bi->bmiHeader.biWidth = _wnd.width = w;
|
||||
bi->bmiHeader.biHeight = -(_wnd.height = h);
|
||||
bi->bmiHeader.biHeight = -(_wnd.height = h+1); // Allocate extra room to prevent out-of-bounds when SSE reads a 16B block at the end of the buffer.
|
||||
|
||||
bi->bmiHeader.biPlanes = 1;
|
||||
bi->bmiHeader.biBitCount = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
||||
|
Reference in New Issue
Block a user