Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 54dbf3419f
Fetching contributors…

Cannot retrieve contributors at this time

4038 lines (3670 sloc) 136.789 kB
/*
* Copyright (C) 2005-2012 Team XBMC
* http://www.xbmc.org
*
* This Program 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; either version 2, or (at your option)
* any later version.
*
* This Program 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 XBMC; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
/*
* Most Codeparts are taken from the TuxBox Teletext plugin which is based
* upon videotext-0.6.19991029 and written by Thomas Loewe (LazyT),
* Roland Meier and DBLuelle. See http://www.tuxtxt.net/ for more information.
* Many thanks to the TuxBox Teletext Team for this great work.
*/
#include "threads/SystemClock.h"
#include "Teletext.h"
#include "Application.h"
#include "utils/log.h"
#include "utils/TimeUtils.h"
#include "filesystem/SpecialProtocol.h"
#include "guilib/GraphicContext.h"
#ifdef HAS_SDL
#include <SDL/SDL_stdinc.h>
#else
#define SDL_memset4(dst, val, len) \
do { \
uint32_t _count = (len); \
uint32_t _n = (_count + 3) / 4; \
uint32_t *_p = static_cast<uint32_t *>(dst); \
uint32_t _val = (val); \
if (len == 0) break; \
switch (_count % 4) { \
case 0: do { *_p++ = _val; \
case 3: *_p++ = _val; \
case 2: *_p++ = _val; \
case 1: *_p++ = _val; \
} while ( --_n ); \
} \
} while(0)
#define SDL_memcpy4(dst, src, len) memcpy(dst, src, (len) << 2)
#endif
using namespace std;
static const char *TeletextFont = "special://xbmc/media/Fonts/teletext.ttf";
/* spacing attributes */
#define alpha_black 0x00
#define alpha_red 0x01
#define alpha_green 0x02
#define alpha_yellow 0x03
#define alpha_blue 0x04
#define alpha_magenta 0x05
#define alpha_cyan 0x06
#define alpha_white 0x07
#define flash 0x08
#define steady 0x09
#define end_box 0x0A
#define start_box 0x0B
#define normal_size 0x0C
#define double_height 0x0D
#define double_width 0x0E
#define double_size 0x0F
#define mosaic_black 0x10
#define mosaic_red 0x11
#define mosaic_green 0x12
#define mosaic_yellow 0x13
#define mosaic_blue 0x14
#define mosaic_magenta 0x15
#define mosaic_cyan 0x16
#define mosaic_white 0x17
#define conceal 0x18
#define contiguous_mosaic 0x19
#define separated_mosaic 0x1A
#define esc 0x1B
#define black_background 0x1C
#define new_background 0x1D
#define hold_mosaic 0x1E
#define release_mosaic 0x1F
#define RowAddress2Row(row) ((row == 40) ? 24 : (row - 40))
// G2 Set as defined in ETS 300 706
const unsigned short int G2table[5][6*16] =
{
// Latin G2 Supplementary Set
{ 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0023, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x0020, 0x0300, 0x0301, 0x02C6, 0x0303, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0020, 0x0020, 0x0020, 0x215B, 0x215C, 0x215D, 0x215E,
0x2126, 0x00C6, 0x00D0, 0x00AA, 0x0126, 0x0020, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x25A0},
// Cyrillic G2 Supplementary Set
{ 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0020, 0x00A7, 0x0020, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0141, 0x0142, 0x00DF, 0x215B, 0x215C, 0x215D, 0x215E,
0x0044, 0x0045, 0x0046, 0x0047, 0x0049, 0x004A, 0x004B, 0x004C, 0x004E, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x005A,
0x0064, 0x0065, 0x0066, 0x0067, 0x0069, 0x006A, 0x006B, 0x006C, 0x006E, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x007A},
// Greek G2 Supplementary Set
{ 0x0020, 0x0061, 0x0062, 0x00A3, 0x0065, 0x0068, 0x0069, 0x00A7, 0x003A, 0x2018, 0x201C, 0x006B, 0x2190, 0x2191, 0x2192, 0x2193,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x006D, 0x006E, 0x0070, 0x00F7, 0x2019, 0x201D, 0x0074, 0x00BC, 0x00BD, 0x00BE, 0x0078,
0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
0x003F, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x038A, 0x038E, 0x038F, 0x215B, 0x215C, 0x215D, 0x215E,
0x0043, 0x0044, 0x0046, 0x0047, 0x004A, 0x004C, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x0059, 0x005A, 0x0386, 0x0389,
0x0063, 0x0064, 0x0066, 0x0067, 0x006A, 0x006C, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x0079, 0x007A, 0x0388, 0x25A0},
// Arabic G2 Set
{ 0x0020, 0x0639, 0xFEC9, 0xFE83, 0xFE85, 0xFE87, 0xFE8B, 0xFE89, 0xFB7C, 0xFB7D, 0xFB7A, 0xFB58, 0xFB59, 0xFB56, 0xFB6D, 0xFB8E,
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFECE, 0xFECD, 0xFEFC, 0xFEEC, 0xFEEA, 0xFEE9,
0x00E0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00EB, 0x00EA, 0x00F9, 0x00EE, 0xFECA,
0x00E9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E2, 0x00F4, 0x00FB, 0x00E7, 0x25A0}
};
//const (avoid warnings :<)
TextPageAttr_t Text_AtrTable[] =
{
{ TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_WB */
{ TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_PassiveDefault */
{ TXT_ColorWhite , TXT_ColorRed , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L250 */
{ TXT_ColorBlack , TXT_ColorYellow, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L252 */
{ TXT_ColorBlack , TXT_ColorGreen , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L251 */
{ TXT_ColorWhite , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L253 */
{ TXT_ColorMagenta, TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU0 */
{ TXT_ColorGreen , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU1 */
{ TXT_ColorYellow , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU2 */
{ TXT_ColorCyan , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU3 */
{ TXT_ColorMenu2 , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG0 */
{ TXT_ColorYellow , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG1 */
{ TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG2 */
{ TXT_ColorWhite , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG3 */
{ TXT_ColorMenu2 , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM0 */
{ TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM1 */
{ TXT_ColorMenu2 , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM2 */
{ TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM3 */
{ TXT_ColorMenu1 , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL0 5a Z */
{ TXT_ColorWhite , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL1 58 X */
{ TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL2 9b õ */
{ TXT_ColorMenu2 , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU0 ab ´ */
{ TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU1 a4 § */
{ TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU2 9b õ */
{ TXT_ColorMenu2 , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU3 cb À */
{ TXT_ColorCyan , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU4 c7 « */
{ TXT_ColorWhite , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU5 c8 » */
{ TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU6 a8 ® */
{ TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_CATCHMENU0 a4 § */
{ TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f} /* ATR_CATCHMENU1 a8 ® */
};
/* shapes */
enum
{
S_END = 0,
S_FHL, /* full horizontal line: y-offset */
S_FVL, /* full vertical line: x-offset */
S_BOX, /* rectangle: x-offset, y-offset, width, height */
S_TRA, /* trapez: x0, y0, l0, x1, y1, l1 */
S_BTR, /* trapez in bgcolor: x0, y0, l0, x1, y1, l1 */
S_INV, /* invert */
S_LNK, /* call other shape: shapenumber */
S_CHR, /* Character from freetype hibyte, lowbyte */
S_ADT, /* Character 2F alternating raster */
S_FLH, /* flip horizontal */
S_FLV /* flip vertical */
};
/* shape coordinates */
enum
{
S_W13 = 5, /* width*1/3 */
S_W12, /* width*1/2 */
S_W23, /* width*2/3 */
S_W11, /* width */
S_WM3, /* width-3 */
S_H13, /* height*1/3 */
S_H12, /* height*1/2 */
S_H23, /* height*2/3 */
S_H11, /* height */
S_NrShCoord
};
/* G3 characters */
unsigned char aG3_20[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W12, S_END };
unsigned char aG3_21[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W11, S_END };
unsigned char aG3_22[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W12, S_END };
unsigned char aG3_23[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W11, S_END };
unsigned char aG3_24[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W12, S_END };
unsigned char aG3_25[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W11, S_END };
unsigned char aG3_26[] = { S_INV, S_LNK, 0x66, S_END };
unsigned char aG3_27[] = { S_INV, S_LNK, 0x67, S_END };
unsigned char aG3_28[] = { S_INV, S_LNK, 0x68, S_END };
unsigned char aG3_29[] = { S_INV, S_LNK, 0x69, S_END };
unsigned char aG3_2a[] = { S_INV, S_LNK, 0x6a, S_END };
unsigned char aG3_2b[] = { S_INV, S_LNK, 0x6b, S_END };
unsigned char aG3_2c[] = { S_INV, S_LNK, 0x6c, S_END };
unsigned char aG3_2d[] = { S_INV, S_LNK, 0x6d, S_END };
unsigned char aG3_2e[] = { S_BOX, 2, 0, 3, S_H11, S_END };
unsigned char aG3_2f[] = { S_ADT };
unsigned char aG3_30[] = { S_LNK, 0x20, S_FLH, S_END };
unsigned char aG3_31[] = { S_LNK, 0x21, S_FLH, S_END };
unsigned char aG3_32[] = { S_LNK, 0x22, S_FLH, S_END };
unsigned char aG3_33[] = { S_LNK, 0x23, S_FLH, S_END };
unsigned char aG3_34[] = { S_LNK, 0x24, S_FLH, S_END };
unsigned char aG3_35[] = { S_LNK, 0x25, S_FLH, S_END };
unsigned char aG3_36[] = { S_INV, S_LNK, 0x76, S_END };
unsigned char aG3_37[] = { S_INV, S_LNK, 0x77, S_END };
unsigned char aG3_38[] = { S_INV, S_LNK, 0x78, S_END };
unsigned char aG3_39[] = { S_INV, S_LNK, 0x79, S_END };
unsigned char aG3_3a[] = { S_INV, S_LNK, 0x7a, S_END };
unsigned char aG3_3b[] = { S_INV, S_LNK, 0x7b, S_END };
unsigned char aG3_3c[] = { S_INV, S_LNK, 0x7c, S_END };
unsigned char aG3_3d[] = { S_INV, S_LNK, 0x7d, S_END };
unsigned char aG3_3e[] = { S_LNK, 0x2e, S_FLH, S_END };
unsigned char aG3_3f[] = { S_BOX, 0, 0, S_W11, S_H11, S_END };
unsigned char aG3_40[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_END };
unsigned char aG3_41[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_FLV, S_END };
unsigned char aG3_42[] = { S_LNK, 0x50, S_BOX, S_W12, S_H13, S_W12, S_H13, S_END };
unsigned char aG3_43[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W12, S_H13, S_END };
unsigned char aG3_44[] = { S_LNK, 0x48, S_FLV, S_LNK, 0x48, S_END };
unsigned char aG3_45[] = { S_LNK, 0x44, S_FLH, S_END };
unsigned char aG3_46[] = { S_LNK, 0x47, S_FLV, S_END };
unsigned char aG3_47[] = { S_LNK, 0x48, S_FLH, S_LNK, 0x48, S_END };
unsigned char aG3_48[] = { S_TRA, 0, 0, S_W23, 0, S_H23, 0, S_BTR, 0, 0, S_W13, 0, S_H13, 0, S_END };
unsigned char aG3_49[] = { S_LNK, 0x48, S_FLH, S_END };
unsigned char aG3_4a[] = { S_LNK, 0x48, S_FLV, S_END };
unsigned char aG3_4b[] = { S_LNK, 0x48, S_FLH, S_FLV, S_END };
unsigned char aG3_4c[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W11, S_H13, S_END };
unsigned char aG3_4d[] = { S_CHR, 0x25, 0xE6 };
unsigned char aG3_4e[] = { S_CHR, 0x25, 0xCF };
unsigned char aG3_4f[] = { S_CHR, 0x25, 0xCB };
unsigned char aG3_50[] = { S_BOX, S_W12, 0, 2, S_H11, S_FLH, S_BOX, S_W12, 0, 2, S_H11,S_END };
unsigned char aG3_51[] = { S_BOX, 0, S_H12, S_W11, 2, S_FLV, S_BOX, 0, S_H12, S_W11, 2,S_END };
unsigned char aG3_52[] = { S_LNK, 0x55, S_FLH, S_FLV, S_END };
unsigned char aG3_53[] = { S_LNK, 0x55, S_FLV, S_END };
unsigned char aG3_54[] = { S_LNK, 0x55, S_FLH, S_END };
unsigned char aG3_55[] = { S_LNK, 0x7e, S_FLV, S_BOX, 0, S_H12, S_W12, 2, S_FLV, S_BOX, 0, S_H12, S_W12, 2, S_END };
unsigned char aG3_56[] = { S_LNK, 0x57, S_FLH, S_END};
unsigned char aG3_57[] = { S_LNK, 0x55, S_LNK, 0x50 , S_END};
unsigned char aG3_58[] = { S_LNK, 0x59, S_FLV, S_END};
unsigned char aG3_59[] = { S_LNK, 0x7e, S_LNK, 0x51 , S_END};
unsigned char aG3_5a[] = { S_LNK, 0x50, S_LNK, 0x51 , S_END};
unsigned char aG3_5b[] = { S_CHR, 0x21, 0x92};
unsigned char aG3_5c[] = { S_CHR, 0x21, 0x90};
unsigned char aG3_5d[] = { S_CHR, 0x21, 0x91};
unsigned char aG3_5e[] = { S_CHR, 0x21, 0x93};
unsigned char aG3_5f[] = { S_CHR, 0x00, 0x20};
unsigned char aG3_60[] = { S_INV, S_LNK, 0x20, S_END };
unsigned char aG3_61[] = { S_INV, S_LNK, 0x21, S_END };
unsigned char aG3_62[] = { S_INV, S_LNK, 0x22, S_END };
unsigned char aG3_63[] = { S_INV, S_LNK, 0x23, S_END };
unsigned char aG3_64[] = { S_INV, S_LNK, 0x24, S_END };
unsigned char aG3_65[] = { S_INV, S_LNK, 0x25, S_END };
unsigned char aG3_66[] = { S_LNK, 0x20, S_FLV, S_END };
unsigned char aG3_67[] = { S_LNK, 0x21, S_FLV, S_END };
unsigned char aG3_68[] = { S_LNK, 0x22, S_FLV, S_END };
unsigned char aG3_69[] = { S_LNK, 0x23, S_FLV, S_END };
unsigned char aG3_6a[] = { S_LNK, 0x24, S_FLV, S_END };
unsigned char aG3_6b[] = { S_BOX, 0, 0, S_W11, S_H13, S_TRA, 0, S_H13, S_W11, 0, S_H23, 1, S_END };
unsigned char aG3_6c[] = { S_TRA, 0, 0, 1, 0, S_H12, S_W12, S_FLV, S_TRA, 0, 0, 1, 0, S_H12, S_W12, S_BOX, 0, S_H12, S_W12,1, S_END };
unsigned char aG3_6d[] = { S_TRA, 0, 0, S_W12, S_W12, S_H12, 0, S_FLH, S_TRA, 0, 0, S_W12, S_W12, S_H12, 0, S_END };
unsigned char aG3_6e[] = { S_CHR, 0x00, 0x20};
unsigned char aG3_6f[] = { S_CHR, 0x00, 0x20};
unsigned char aG3_70[] = { S_INV, S_LNK, 0x30, S_END };
unsigned char aG3_71[] = { S_INV, S_LNK, 0x31, S_END };
unsigned char aG3_72[] = { S_INV, S_LNK, 0x32, S_END };
unsigned char aG3_73[] = { S_INV, S_LNK, 0x33, S_END };
unsigned char aG3_74[] = { S_INV, S_LNK, 0x34, S_END };
unsigned char aG3_75[] = { S_INV, S_LNK, 0x35, S_END };
unsigned char aG3_76[] = { S_LNK, 0x66, S_FLH, S_END };
unsigned char aG3_77[] = { S_LNK, 0x67, S_FLH, S_END };
unsigned char aG3_78[] = { S_LNK, 0x68, S_FLH, S_END };
unsigned char aG3_79[] = { S_LNK, 0x69, S_FLH, S_END };
unsigned char aG3_7a[] = { S_LNK, 0x6a, S_FLH, S_END };
unsigned char aG3_7b[] = { S_LNK, 0x6b, S_FLH, S_END };
unsigned char aG3_7c[] = { S_LNK, 0x6c, S_FLH, S_END };
unsigned char aG3_7d[] = { S_LNK, 0x6d, S_FLV, S_END };
unsigned char aG3_7e[] = { S_BOX, S_W12, 0, 2, S_H12, S_FLH, S_BOX, S_W12, 0, 2, S_H12, S_END };// help char, not printed directly (only by S_LNK)
unsigned char *aShapes[] =
{
aG3_20, aG3_21, aG3_22, aG3_23, aG3_24, aG3_25, aG3_26, aG3_27, aG3_28, aG3_29, aG3_2a, aG3_2b, aG3_2c, aG3_2d, aG3_2e, aG3_2f,
aG3_30, aG3_31, aG3_32, aG3_33, aG3_34, aG3_35, aG3_36, aG3_37, aG3_38, aG3_39, aG3_3a, aG3_3b, aG3_3c, aG3_3d, aG3_3e, aG3_3f,
aG3_40, aG3_41, aG3_42, aG3_43, aG3_44, aG3_45, aG3_46, aG3_47, aG3_48, aG3_49, aG3_4a, aG3_4b, aG3_4c, aG3_4d, aG3_4e, aG3_4f,
aG3_50, aG3_51, aG3_52, aG3_53, aG3_54, aG3_55, aG3_56, aG3_57, aG3_58, aG3_59, aG3_5a, aG3_5b, aG3_5c, aG3_5d, aG3_5e, aG3_5f,
aG3_60, aG3_61, aG3_62, aG3_63, aG3_64, aG3_65, aG3_66, aG3_67, aG3_68, aG3_69, aG3_6a, aG3_6b, aG3_6c, aG3_6d, aG3_6e, aG3_6f,
aG3_70, aG3_71, aG3_72, aG3_73, aG3_74, aG3_75, aG3_76, aG3_77, aG3_78, aG3_79, aG3_7a, aG3_7b, aG3_7c, aG3_7d, aG3_7e
};
// G0 Table as defined in ETS 300 706
// cyrillic G0 Charset (0 = Serbian/Croatian, 1 = Russian/Bulgarian, 2 = Ukrainian)
const unsigned short int G0table[6][6*16] =
{
// Cyrillic G0 Set - Option 1 - Serbian/Croatian
{ ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
0x0427, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0408, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
0x041F, 0x040C, 0x0420, 0x0421, 0x0422, 0x0423, 0x0412, 0x0403, 0x0409, 0x040A, 0x0417, 0x040B, 0x0416, 0x0402, 0x0428, 0x040F,
0x0447, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0458, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
0x043F, 0x045C, 0x0440, 0x0441, 0x0442, 0x0443, 0x0432, 0x0453, 0x0459, 0x045A, 0x0437, 0x045B, 0x0436, 0x0452, 0x0448, 0x25A0},
// Cyrillic G0 Set - Option 2 - Russian/Bulgarian
{ ' ', '!', '\"', '#', '$', '%', 0x044B, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042A, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042B,
0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044A, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x25A0},
// Cyrillic G0 Set - Option 3 - Ukrainian
{ ' ', '!', '\"', '#', '$', '%', 0x0457, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x0406, 0x0417, 0x0428, 0x0404, 0x0429, 0x0427, 0x0407,
0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x0456, 0x0437, 0x0448, 0x0454, 0x0449, 0x0447, 0x25A0},
// Greek G0 Set
{ ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', 0x00AB, '=', 0x00BB, '?',
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
0x03A0, 0x03A1, 0x0384, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x25A0},
// Hebrew G0 Set
{ ' ', '!', 0x05F2, 0x00A3, '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x2190, 0x00BD, 0x2192, 0x2191, '#',
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x20AA, 0x2551, 0x00BE, 0x00F7, 0x25A0},
// Arabic G0 Set - Thanks to Habib2006(fannansat)
{ ' ', '!', 0x05F2, 0x00A3, '$', 0x066A, 0xFEF0, 0xFEF2, 0xFD3F, 0xFD3E, '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', 0x061B, '>', '=', '<', 0x061F,
0xFE94, 0x0621, 0xFE92, 0x0628, 0xFE98, 0x062A, 0xFE8E, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
0x0630, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0xFE9C, 0xFEA0, 0xFEA4, 0xFEA8, 0x0023,
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFE99, 0xFE9D, 0xFEA1, 0xFEA5, 0xFEF4,
0xFEF0, 0xFECC, 0xFED0, 0xFED4, 0xFED1, 0xFED8, 0xFED5, 0xFED9, 0xFEE0, 0xFEDD, 0xFEE4, 0xFEE1, 0xFEE8, 0xFEE5, 0xFEFB, 0x25A0}
};
const unsigned short int nationaltable23[14][2] =
{
{ '#', 0x00A4 }, /* 0 */
{ '#', 0x016F }, /* 1 CS/SK */
{ 0x00A3, '$' }, /* 2 EN */
{ '#', 0x00F5 }, /* 3 ET */
{ 0x00E9, 0x0457 }, /* 4 FR */
{ '#', '$' }, /* 5 DE */
{ 0x00A3, '$' }, /* 6 IT */
{ '#', '$' }, /* 7 LV/LT */
{ '#', 0x0144 }, /* 8 PL */
{ 0x00E7, '$' }, /* 9 PT/ES */
{ '#', 0x00A4 }, /* A RO */
{ '#', 0x00CB }, /* B SR/HR/SL */
{ '#', 0x00A4 }, /* C SV/FI/HU */
{ 0x20A4, 0x011F }, /* D TR */
};
const unsigned short int nationaltable40[14] =
{
'@', /* 0 */
0x010D, /* 1 CS/SK */
'@', /* 2 EN */
0x0161, /* 3 ET */
0x00E0, /* 4 FR */
0x00A7, /* 5 DE */
0x00E9, /* 6 IT */
0x0161, /* 7 LV/LT */
0x0105, /* 8 PL */
0x00A1, /* 9 PT/ES */
0x0162, /* A RO */
0x010C, /* B SR/HR/SL */
0x00C9, /* C SV/FI/HU */
0x0130, /* D TR */
};
const unsigned short int nationaltable5b[14][6] =
{
{ '[', '\\', ']', '^', '_', '`' }, /* 0 */
{ 0x0165, 0x017E, 0x00FD, 0x00ED, 0x0159, 0x00E9 }, /* 1 CS/SK */
{ 0x2190, 0x00BD, 0x2192, 0x2191, '#', 0x00AD }, /* 2 EN */
{ 0x00C4, 0x00D6, 0x017D, 0x00DC, 0x00D5, 0x0161 }, /* 3 ET */
{ 0x0451, 0x00EA, 0x00F9, 0x00EE, '#', 0x00E8 }, /* 4 FR */
{ 0x00C4, 0x00D6, 0x00DC, '^', '_', 0x00B0 }, /* 5 DE */
{ 0x00B0, 0x00E7, 0x2192, 0x2191, '#', 0x00F9 }, /* 6 IT */
{ 0x0117, 0x0119, 0x017D, 0x010D, 0x016B, 0x0161 }, /* 7 LV/LT */
{ 0x017B, 0x015A, 0x0141, 0x0107, 0x00F3, 0x0119 }, /* 8 PL */
{ 0x00E1, 0x00E9, 0x00ED, 0x00F3, 0x00FA, 0x00BF }, /* 9 PT/ES */
{ 0x00C2, 0x015E, 0x01CD, 0x01CF, 0x0131, 0x0163 }, /* A RO */
{ 0x0106, 0x017D, 0x00D0, 0x0160, 0x0451, 0x010D }, /* B SR/HR/SL */
{ 0x00C4, 0x00D6, 0x00C5, 0x00DC, '_', 0x00E9 }, /* C SV/FI/HU */
{ 0x015E, 0x00D6, 0x00C7, 0x00DC, 0x011E, 0x0131 }, /* D TR */
};
const unsigned short int nationaltable7b[14][4] =
{
{ '{', '|', '}', '~' }, /* 0 */
{ 0x00E1, 0x011B, 0x00FA, 0x0161 }, /* 1 CS/SK */
{ 0x00BC, 0x2551, 0x00BE, 0x00F7 }, /* 2 EN */
{ 0x00E4, 0x00F6, 0x017E, 0x00FC }, /* 3 ET */
{ 0x00E2, 0x00F4, 0x00FB, 0x00E7 }, /* 4 FR */
{ 0x00E4, 0x00F6, 0x00FC, 0x00DF }, /* 5 DE */
{ 0x00E0, 0x00F3, 0x00E8, 0x00EC }, /* 6 IT */
{ 0x0105, 0x0173, 0x017E, 0x012F }, /* 7 LV/LT */
{ 0x017C, 0x015B, 0x0142, 0x017A }, /* 8 PL */
{ 0x00FC, 0x00F1, 0x00E8, 0x00E0 }, /* 9 PT/ES */
{ 0x00E2, 0x015F, 0x01CE, 0x00EE }, /* A RO */
{ 0x0107, 0x017E, 0x0111, 0x0161 }, /* B SR/HR/SL */
{ 0x00E4, 0x00F6, 0x00E5, 0x00FC }, /* C SV/FI/HU */
{ 0x015F, 0x00F6, 0x00E7, 0x00FC }, /* D TR */
};
const unsigned short int arrowtable[] =
{
8592, 8594, 8593, 8595, 'O', 'K', 8592, 8592
};
CTeletextDecoder::CTeletextDecoder()
{
memset(&m_RenderInfo, 0, sizeof(TextRenderInfo_t));
m_teletextFont = CSpecialProtocol::TranslatePath(TeletextFont);
m_TextureBuffer = NULL;
m_txtCache = NULL;
m_Manager = NULL;
m_Library = NULL;
m_RenderInfo.ShowFlof = true;
m_RenderInfo.Show39 = true;
m_RenderInfo.Showl25 = true;
m_RenderInfo.Prev_100 = 0x100;
m_RenderInfo.Prev_10 = 0x100;
m_RenderInfo.Next_100 = 0x100;
m_RenderInfo.Next_10 = 0x100;
m_RenderInfo.InputCounter = 2;
unsigned short rd0[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x00<<8, 0x00<<8, 0x00<<8, 0, 0 };
unsigned short gn0[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x20<<8, 0x10<<8, 0x20<<8, 0, 0 };
unsigned short bl0[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x40<<8, 0x20<<8, 0x40<<8, 0, 0 };
unsigned short tr0[] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
0x0000 , 0x0000 , 0x0A0A , 0xFFFF, 0x3030 };
memcpy(m_RenderInfo.rd0,rd0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
memcpy(m_RenderInfo.gn0,gn0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
memcpy(m_RenderInfo.bl0,bl0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
memcpy(m_RenderInfo.tr0,tr0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
m_LastPage = 0;
m_TempPage = 0;
m_Ascender = 0;
m_PCOldCol = 0;
m_PCOldRow = 0;
m_CatchedPage = 0;
m_CatchCol = 0;
m_CatchRow = 0;
prevTimeSec = 0;
prevHeaderPage = 0;
m_updateTexture = false;
m_YOffset = 0;
}
CTeletextDecoder::~CTeletextDecoder()
{
}
bool CTeletextDecoder::HandleAction(const CAction &action)
{
if (m_txtCache == NULL)
{
CLog::Log(LOGERROR, "CTeletextDecoder::HandleAction called without teletext cache");
return false;
}
if (action.GetID() == ACTION_MOVE_UP)
{
if (m_RenderInfo.PageCatching)
CatchNextPage(-1, -1);
else
GetNextPageOne(true);
return true;
}
else if (action.GetID() == ACTION_MOVE_DOWN)
{
if (m_RenderInfo.PageCatching)
CatchNextPage(1, 1);
else
GetNextPageOne(false);
return true;
}
else if (action.GetID() == ACTION_MOVE_RIGHT)
{
if (m_RenderInfo.PageCatching)
CatchNextPage(0, 1);
else if (m_RenderInfo.Boxed)
{
m_RenderInfo.SubtitleDelay++;
// display SubtitleDelay
m_RenderInfo.PosY = 0;
char ns[10];
SetPosX(1);
sprintf(ns,"+%d ", m_RenderInfo.SubtitleDelay);
RenderCharFB(ns[0], &Text_AtrTable[ATR_WB]);
RenderCharFB(ns[1], &Text_AtrTable[ATR_WB]);
RenderCharFB(ns[2], &Text_AtrTable[ATR_WB]);
RenderCharFB(ns[4], &Text_AtrTable[ATR_WB]);
}
else
{
GetNextSubPage(1);
}
return true;
}
else if (action.GetID() == ACTION_MOVE_LEFT)
{
if (m_RenderInfo.PageCatching)
CatchNextPage(0, -1);
else if (m_RenderInfo.Boxed)
{
m_RenderInfo.SubtitleDelay--;
// display subtitledelay
m_RenderInfo.PosY = 0;
char ns[10];
SetPosX(1);
sprintf(ns,"+%d ", m_RenderInfo.SubtitleDelay);
RenderCharFB(ns[0], &Text_AtrTable[ATR_WB]);
RenderCharFB(ns[1], &Text_AtrTable[ATR_WB]);
RenderCharFB(ns[2], &Text_AtrTable[ATR_WB]);
RenderCharFB(ns[4], &Text_AtrTable[ATR_WB]);
}
else
{
GetNextSubPage(-1);
}
return true;
}
else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
{
PageInput(action.GetID() - REMOTE_0);
return true;
}
else if (action.GetID() >= KEY_ASCII) // FIXME make it KEY_UNICODE
{ // input from the keyboard
if (action.GetUnicode() >= 48 && action.GetUnicode() < 58)
{
PageInput(action.GetUnicode() - 48);
return true;
}
return false;
}
else if (action.GetID() == ACTION_PAGE_UP)
{
SwitchZoomMode();
return true;
}
else if (action.GetID() == ACTION_PAGE_DOWN)
{
SwitchTranspMode();
return true;
}
else if (action.GetID() == ACTION_SELECT_ITEM)
{
if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xFF)
return false;
if (!m_RenderInfo.PageCatching)
StartPageCatching();
else
StopPageCatching();
return true;
}
if (m_RenderInfo.PageCatching)
{
m_txtCache->PageUpdate = true;
m_RenderInfo.PageCatching = 0;
return true;
}
if (action.GetID() == ACTION_SHOW_INFO)
{
SwitchHintMode();
return true;
}
else if (action.GetID() == ACTION_TELETEXT_RED)
{
ColorKey(m_RenderInfo.Prev_100);
return true;
}
else if (action.GetID() == ACTION_TELETEXT_GREEN)
{
ColorKey(m_RenderInfo.Prev_10);
return true;
}
else if (action.GetID() == ACTION_TELETEXT_YELLOW)
{
ColorKey(m_RenderInfo.Next_10);
return true;
}
else if (action.GetID() == ACTION_TELETEXT_BLUE)
{
ColorKey(m_RenderInfo.Next_100);
return true;
}
return false;
}
bool CTeletextDecoder::InitDecoder()
{
int error;
m_txtCache = g_application.m_pPlayer->GetTeletextCache();
if (m_txtCache == NULL)
{
CLog::Log(LOGERROR, "%s: called without teletext cache", __FUNCTION__);
return false;
}
/* init fontlibrary */
if ((error = FT_Init_FreeType(&m_Library)))
{
CLog::Log(LOGERROR, "%s: <FT_Init_FreeType: 0x%.2X>", __FUNCTION__, error);
m_Library = NULL;
return false;
}
if ((error = FTC_Manager_New(m_Library, 7, 2, 0, &MyFaceRequester, NULL, &m_Manager)))
{
FT_Done_FreeType(m_Library);
m_Library = NULL;
m_Manager = NULL;
CLog::Log(LOGERROR, "%s: <FTC_Manager_New: 0x%.2X>", __FUNCTION__, error);
return false;
}
if ((error = FTC_SBitCache_New(m_Manager, &m_Cache)))
{
FTC_Manager_Done(m_Manager);
FT_Done_FreeType(m_Library);
m_Manager = NULL;
m_Library = NULL;
CLog::Log(LOGERROR, "%s: <FTC_SBit_Cache_New: 0x%.2X>", __FUNCTION__, error);
return false;
}
/* calculate font dimensions */
m_RenderInfo.Width = (int)(g_graphicsContext.GetWidth()*g_graphicsContext.GetGUIScaleX());
m_RenderInfo.Height = (int)(g_graphicsContext.GetHeight()*g_graphicsContext.GetGUIScaleY());
m_RenderInfo.FontHeight = m_RenderInfo.Height / 25;
m_RenderInfo.FontWidth_Normal = m_RenderInfo.Width / (m_RenderInfo.Show39 ? 39 : 40);
SetFontWidth(m_RenderInfo.FontWidth_Normal);
for (int i = 0; i <= 10; i++)
m_RenderInfo.axdrcs[i+12+1] = (m_RenderInfo.FontHeight * i + 6) / 10;
/* center screen */
m_TypeTTF.face_id = (FTC_FaceID) m_teletextFont.c_str();
m_TypeTTF.height = (FT_UShort) m_RenderInfo.FontHeight;
m_TypeTTF.flags = FT_LOAD_MONOCHROME;
if (FTC_Manager_LookupFace(m_Manager, m_TypeTTF.face_id, &m_Face))
{
m_TypeTTF.face_id = (FTC_FaceID) m_teletextFont.c_str();
if ((error = FTC_Manager_LookupFace(m_Manager, m_TypeTTF.face_id, &m_Face)))
{
CLog::Log(LOGERROR, "%s: <FTC_Manager_Lookup_Face failed with Errorcode 0x%.2X>\n", __FUNCTION__, error);
FTC_Manager_Done(m_Manager);
FT_Done_FreeType(m_Library);
m_Manager = NULL;
m_Library = NULL;
return false;
}
}
m_Ascender = m_RenderInfo.FontHeight * m_Face->ascender / m_Face->units_per_EM;
/* set variable screeninfo for double buffering */
m_YOffset = 0;
m_TextureBuffer = new color_t [4*m_RenderInfo.Height*m_RenderInfo.Width];
ClearFB(GetColorRGB(TXT_ColorTransp));
ClearBB(GetColorRGB(TXT_ColorTransp)); /* initialize backbuffer */
/* set new colormap */
SetColors((unsigned short *)DefaultColors, 0, TXT_Color_SIZECOLTABLE);
for (int i = 0; i < 40 * 25; i++)
{
m_RenderInfo.PageChar[i] = ' ';
m_RenderInfo.PageAtrb[i].fg = TXT_ColorTransp;
m_RenderInfo.PageAtrb[i].bg = TXT_ColorTransp;
m_RenderInfo.PageAtrb[i].charset = C_G0P;
m_RenderInfo.PageAtrb[i].doubleh = 0;
m_RenderInfo.PageAtrb[i].doublew = 0;
m_RenderInfo.PageAtrb[i].IgnoreAtBlackBgSubst = 0;
}
m_RenderInfo.TranspMode = false;
m_LastPage = 0x100;
return true;
}
void CTeletextDecoder::EndDecoder()
{
/* clear SubtitleCache */
for (int i = 0; i < SUBTITLE_CACHESIZE; i++)
{
if (m_RenderInfo.SubtitleCache[i] != NULL)
{
delete m_RenderInfo.SubtitleCache[i];
m_RenderInfo.SubtitleCache[i] = NULL;
}
}
if (m_TextureBuffer)
{
delete[] m_TextureBuffer;
m_TextureBuffer = NULL;
}
/* close freetype */
if (m_Manager)
{
FTC_Manager_Done(m_Manager);
}
if (m_Library)
{
FT_Done_FreeType(m_Library);
}
m_Manager = NULL;
m_Library = NULL;
if (!m_txtCache)
{
CLog::Log(LOGNOTICE, "%s: called without cache", __FUNCTION__);
}
else
{
m_txtCache->PageUpdate = true;
CLog::Log(LOGDEBUG, "Teletext: Rendering ended");
}
return;
}
void CTeletextDecoder::PageInput(int Number)
{
m_updateTexture = true;
/* clear m_TempPage */
if (m_RenderInfo.InputCounter == 2)
m_TempPage = 0;
/* check for 0 & 9 on first position */
if (Number == 0 && m_RenderInfo.InputCounter == 2)
{
/* set page */
m_TempPage = m_LastPage; /* 0 toggles to last page as in program switching */
m_RenderInfo.InputCounter = -1;
}
else if (Number == 9 && m_RenderInfo.InputCounter == 2)
{
return;
}
/* show pageinput */
if (m_RenderInfo.ZoomMode == 2)
{
m_RenderInfo.ZoomMode = 1;
CopyBB2FB();
}
m_RenderInfo.PosY = 0;
switch (m_RenderInfo.InputCounter)
{
case 2:
SetPosX(1);
RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
RenderCharFB('-', &Text_AtrTable[ATR_WB]);
RenderCharFB('-', &Text_AtrTable[ATR_WB]);
break;
case 1:
SetPosX(2);
RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
break;
case 0:
SetPosX(3);
RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
break;
}
/* generate pagenumber */
m_TempPage |= Number << (m_RenderInfo.InputCounter*4);
m_RenderInfo.InputCounter--;
if (m_RenderInfo.InputCounter < 0)
{
/* disable SubPage zapping */
m_txtCache->ZapSubpageManual = false;
/* reset input */
m_RenderInfo.InputCounter = 2;
/* set new page */
m_LastPage = m_txtCache->Page;
m_txtCache->Page = m_TempPage;
m_RenderInfo.HintMode = false;
/* check cache */
int subp = m_txtCache->SubPageTable[m_txtCache->Page];
if (subp != 0xFF)
{
m_txtCache->SubPage = subp;
m_txtCache->PageUpdate = true;
}
else
{
m_txtCache->SubPage = 0;
// RenderMessage(PageNotFound);
}
}
}
void CTeletextDecoder::GetNextPageOne(bool up)
{
/* disable subpage zapping */
m_txtCache->ZapSubpageManual = false;
/* abort pageinput */
m_RenderInfo.InputCounter = 2;
/* find next cached page */
m_LastPage = m_txtCache->Page;
int subp;
do {
if (up)
CDVDTeletextTools::NextDec(&m_txtCache->Page);
else
CDVDTeletextTools::PrevDec(&m_txtCache->Page);
subp = m_txtCache->SubPageTable[m_txtCache->Page];
} while (subp == 0xFF && m_txtCache->Page != m_LastPage);
/* update Page */
if (m_txtCache->Page != m_LastPage)
{
if (m_RenderInfo.ZoomMode == 2)
m_RenderInfo.ZoomMode = 1;
m_txtCache->SubPage = subp;
m_RenderInfo.HintMode = false;
m_txtCache->PageUpdate = true;
}
}
void CTeletextDecoder::GetNextSubPage(int offset)
{
/* abort pageinput */
m_RenderInfo.InputCounter = 2;
for (int loop = m_txtCache->SubPage + offset; loop != m_txtCache->SubPage; loop += offset)
{
if (loop < 0)
loop = 0x79;
else if (loop > 0x79)
loop = 0;
if (loop == m_txtCache->SubPage)
break;
if (m_txtCache->astCachetable[m_txtCache->Page][loop])
{
/* enable manual SubPage zapping */
m_txtCache->ZapSubpageManual = true;
/* update page */
if (m_RenderInfo.ZoomMode == 2) /* if zoomed to lower half */
m_RenderInfo.ZoomMode = 1; /* activate upper half */
m_txtCache->SubPage = loop;
m_RenderInfo.HintMode = false;
m_txtCache->PageUpdate = true;
return;
}
}
}
void CTeletextDecoder::SwitchZoomMode()
{
if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
{
/* toggle mode */
m_RenderInfo.ZoomMode++;
if (m_RenderInfo.ZoomMode == 3)
m_RenderInfo.ZoomMode = 0;
/* update page */
m_txtCache->PageUpdate = true;
}
}
void CTeletextDecoder::SwitchTranspMode()
{
/* toggle mode */
if (!m_RenderInfo.TranspMode)
m_RenderInfo.TranspMode = true;
else
m_RenderInfo.TranspMode = false; /* backward to immediately switch to TV-screen */
/* set mode */
if (!m_RenderInfo.TranspMode) /* normal text-only */
{
ClearBB(m_txtCache->FullScrColor);
m_txtCache->PageUpdate = true;
}
else /* semi-transparent BG with FG text */
{
ClearBB(TXT_ColorTransp);
m_txtCache->PageUpdate = true;
}
}
void CTeletextDecoder::SwitchHintMode()
{
/* toggle mode */
m_RenderInfo.HintMode ^= true;
if (!m_RenderInfo.HintMode) /* toggle evaluation of level 2.5 information by explicitly switching off HintMode */
{
m_RenderInfo.Showl25 ^= true;
}
/* update page */
m_txtCache->PageUpdate = true;
}
void CTeletextDecoder::ColorKey(int target)
{
if (!target)
return;
if (m_RenderInfo.ZoomMode == 2)
m_RenderInfo.ZoomMode = 1;
m_LastPage = m_txtCache->Page;
m_txtCache->Page = target;
m_txtCache->SubPage = m_txtCache->SubPageTable[m_txtCache->Page];
m_RenderInfo.InputCounter = 2;
m_RenderInfo.HintMode = false;
m_txtCache->PageUpdate = true;
}
void CTeletextDecoder::StartPageCatching()
{
m_RenderInfo.PageCatching = true;
/* abort pageinput */
m_RenderInfo.InputCounter = 2;
/* show info line */
m_RenderInfo.ZoomMode = 0;
m_RenderInfo.PosX = 0;
m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
/* check for pagenumber(s) */
m_CatchRow = 1;
m_CatchCol = 0;
m_CatchedPage = 0;
m_PCOldRow = 0;
m_PCOldCol = 0; /* no inverted page number to restore yet */
CatchNextPage(0, 1);
if (!m_CatchedPage)
{
m_RenderInfo.PageCatching = false;
m_txtCache->PageUpdate = true;
return;
}
}
void CTeletextDecoder::StopPageCatching()
{
/* set new page */
if (m_RenderInfo.ZoomMode == 2)
m_RenderInfo.ZoomMode = 1;
m_LastPage = m_txtCache->Page;
m_txtCache->Page = m_CatchedPage;
m_RenderInfo.HintMode = false;
m_txtCache->PageUpdate = true;
m_RenderInfo.PageCatching = false;
int subp = m_txtCache->SubPageTable[m_txtCache->Page];
if (subp != 0xFF)
m_txtCache->SubPage = subp;
else
m_txtCache->SubPage = 0;
}
void CTeletextDecoder::CatchNextPage(int firstlineinc, int inc)
{
int tmp_page, allowwrap = 1; /* allow first wrap around */
/* catch next page */
for(;;)
{
unsigned char *p = &(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol]);
TextPageAttr_t a = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol];
if (!(a.charset == C_G1C || a.charset == C_G1S) && /* no mosaic */
(a.fg != a.bg) && /* not hidden */
(*p >= '1' && *p <= '8' && /* valid page number */
*(p+1) >= '0' && *(p+1) <= '9' &&
*(p+2) >= '0' && *(p+2) <= '9') &&
(m_CatchRow == 0 || (*(p-1) < '0' || *(p-1) > '9')) && /* non-numeric char before and behind */
(m_CatchRow == 37 || (*(p+3) < '0' || *(p+3) > '9')))
{
tmp_page = ((*p - '0')<<8) | ((*(p+1) - '0')<<4) | (*(p+2) - '0');
#if 0
if (tmp_page != m_CatchedPage) /* confusing to skip identical page numbers - I want to reach what I aim to */
#endif
{
m_CatchedPage = tmp_page;
RenderCatchedPage();
m_CatchCol += inc; /* FIXME: limit */
return;
}
}
if (firstlineinc > 0)
{
m_CatchRow++;
m_CatchCol = 0;
firstlineinc = 0;
}
else if (firstlineinc < 0)
{
m_CatchRow--;
m_CatchCol = 37;
firstlineinc = 0;
}
else
m_CatchCol += inc;
if (m_CatchCol > 37)
{
m_CatchRow++;
m_CatchCol = 0;
}
else if (m_CatchCol < 0)
{
m_CatchRow--;
m_CatchCol = 37;
}
if (m_CatchRow > 23)
{
if (allowwrap)
{
allowwrap = 0;
m_CatchRow = 1;
m_CatchCol = 0;
}
else
{
return;
}
}
else if (m_CatchRow < 1)
{
if (allowwrap)
{
allowwrap = 0;
m_CatchRow = 23;
m_CatchCol =37;
}
else
{
return;
}
}
}
}
void CTeletextDecoder::RenderCatchedPage()
{
int zoom = 0;
m_updateTexture = true;
/* handle zoom */
if (m_RenderInfo.ZoomMode)
zoom = 1<<10;
if (m_PCOldRow || m_PCOldCol) /* not at first call */
{
/* restore pagenumber */
SetPosX(m_PCOldCol);
if (m_RenderInfo.ZoomMode == 2)
m_RenderInfo.PosY = (m_PCOldRow-12)*m_RenderInfo.FontHeight*((zoom>>10)+1);
else
m_RenderInfo.PosY = m_PCOldRow*m_RenderInfo.FontHeight*((zoom>>10)+1);
RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol ], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol ]);
RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol + 1], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol + 1]);
RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol + 2], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol + 2]);
}
m_PCOldRow = m_CatchRow;
m_PCOldCol = m_CatchCol;
/* mark pagenumber */
if (m_RenderInfo.ZoomMode == 1 && m_CatchRow > 11)
{
m_RenderInfo.ZoomMode = 2;
CopyBB2FB();
}
else if (m_RenderInfo.ZoomMode == 2 && m_CatchRow < 12)
{
m_RenderInfo.ZoomMode = 1;
CopyBB2FB();
}
SetPosX(m_CatchCol);
if (m_RenderInfo.ZoomMode == 2)
m_RenderInfo.PosY = (m_CatchRow-12)*m_RenderInfo.FontHeight*((zoom>>10)+1);
else
m_RenderInfo.PosY = m_CatchRow*m_RenderInfo.FontHeight*((zoom>>10)+1);
TextPageAttr_t a0 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol ];
TextPageAttr_t a1 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol + 1];
TextPageAttr_t a2 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol + 2];
int t;
/* exchange colors */
t = a0.fg; a0.fg = a0.bg; a0.bg = t;
t = a1.fg; a1.fg = a1.bg; a1.bg = t;
t = a2.fg; a2.fg = a2.bg; a2.bg = t;
RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol ], &a0);
RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol + 1], &a1);
RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol + 2], &a2);
}
void CTeletextDecoder::RenderPage()
{
int StartRow = 0;
int national_subset_bak = m_txtCache->NationalSubset;
if (m_txtCache->PageUpdate)
m_updateTexture = true;
/* update page or timestring */
if (m_txtCache->PageUpdate && m_txtCache->PageReceiving != m_txtCache->Page && m_RenderInfo.InputCounter == 2)
{
/* reset update flag */
m_txtCache->PageUpdate = false;
if (m_RenderInfo.Boxed && m_RenderInfo.SubtitleDelay)
{
TextSubtitleCache_t* c = NULL;
int j = -1;
for (int i = 0; i < SUBTITLE_CACHESIZE; i++)
{
if (j == -1 && !m_RenderInfo.SubtitleCache[i])
j = i;
if (m_RenderInfo.SubtitleCache[i] && !m_RenderInfo.SubtitleCache[i]->Valid)
{
c = m_RenderInfo.SubtitleCache[i];
break;
}
}
if (c == NULL)
{
if (j == -1) // no more space in SubtitleCache
return;
c = new TextSubtitleCache_t;
if (c == NULL)
return;
memset(c, 0x00, sizeof(TextSubtitleCache_t));
m_RenderInfo.SubtitleCache[j] = c;
}
c->Valid = true;
c->Timestamp = XbmcThreads::SystemClockMillis()/1000;
if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
{
TextPageinfo_t * p = DecodePage(m_RenderInfo.Showl25, c->PageChar, c->PageAtrb, m_RenderInfo.HintMode, m_RenderInfo.ShowFlof);
if (p)
{
m_RenderInfo.Boxed = p->boxed;
}
}
m_RenderInfo.DelayStarted = true;
return;
}
m_RenderInfo.DelayStarted = false;
/* decode page */
if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
{
TextPageinfo_t * p = DecodePage(m_RenderInfo.Showl25, m_RenderInfo.PageChar, m_RenderInfo.PageAtrb, m_RenderInfo.HintMode, m_RenderInfo.ShowFlof);
if (p)
{
m_RenderInfo.PageInfo = p;
m_RenderInfo.Boxed = p->boxed;
}
if (m_RenderInfo.Boxed || m_RenderInfo.TranspMode)
FillBorder(GetColorRGB(TXT_ColorTransp));
else
FillBorder(GetColorRGB((enumTeletextColor)m_txtCache->FullScrColor));
if (m_txtCache->ColorTable) /* as late as possible to shorten the time the old page is displayed with the new colors */
SetColors(m_txtCache->ColorTable, 16, 16); /* set colors for CLUTs 2+3 */
}
else
StartRow = 1;
DoRenderPage(StartRow, national_subset_bak);
}
else
{
if (m_RenderInfo.DelayStarted)
{
long now = XbmcThreads::SystemClockMillis()/1000;
for (int i = 0; i < SUBTITLE_CACHESIZE ; i++)
{
if (m_RenderInfo.SubtitleCache[i] && m_RenderInfo.SubtitleCache[i]->Valid && now - m_RenderInfo.SubtitleCache[i]->Timestamp >= (long)m_RenderInfo.SubtitleDelay)
{
memcpy(m_RenderInfo.PageChar, m_RenderInfo.SubtitleCache[i]->PageChar, 40 * 25);
memcpy(m_RenderInfo.PageAtrb, m_RenderInfo.SubtitleCache[i]->PageAtrb, 40 * 25 * sizeof(TextPageAttr_t));
DoRenderPage(StartRow, national_subset_bak);
m_RenderInfo.SubtitleCache[i]->Valid = false;
return;
}
}
}
if (m_RenderInfo.ZoomMode != 2)
{
m_RenderInfo.PosY = 0;
if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xff)
{
m_RenderInfo.PageAtrb[32].fg = TXT_ColorYellow;
m_RenderInfo.PageAtrb[32].bg = TXT_ColorMenu1;
int showpage = m_txtCache->PageReceiving;
int showsubpage = m_txtCache->SubPageTable[showpage];
if (showsubpage!=0xff)
{
TextCachedPage_t *pCachedPage;
pCachedPage = m_txtCache->astCachetable[showpage][showsubpage];
if (pCachedPage && IsDec(showpage))
{
m_RenderInfo.PosX = 0;
if (m_RenderInfo.InputCounter == 2)
{
if (m_txtCache->BTTok && !m_txtCache->BasicTop[m_txtCache->Page]) /* page non-existent according to TOP (continue search anyway) */
{
m_RenderInfo.PageAtrb[0].fg = TXT_ColorWhite;
m_RenderInfo.PageAtrb[0].bg = TXT_ColorRed;
}
else
{
m_RenderInfo.PageAtrb[0].fg = TXT_ColorYellow;
m_RenderInfo.PageAtrb[0].bg = TXT_ColorMenu1;
}
CDVDTeletextTools::Hex2Str((char*)m_RenderInfo.PageChar+3, m_txtCache->Page);
int col;
for (col = m_RenderInfo.nofirst; col < 7; col++) // selected page
{
RenderCharFB(m_RenderInfo.PageChar[col], &m_RenderInfo.PageAtrb[0]);
}
RenderCharFB(m_RenderInfo.PageChar[col], &m_RenderInfo.PageAtrb[32]);
}
else
SetPosX(8);
memcpy(&m_RenderInfo.PageChar[8], pCachedPage->p0, 24); /* header line without timestring */
for (int i = 0; i < 24; i++)
{
RenderCharFB(pCachedPage->p0[i], &m_RenderInfo.PageAtrb[32]);
}
/* Update on every Header number change */
if (pCachedPage->p0[2] != prevHeaderPage)
{
prevHeaderPage = pCachedPage->p0[2];
m_updateTexture = true;
}
}
}
}
/* update timestring */
SetPosX(32);
for (int i = 0; i < 8; i++)
{
if (!m_RenderInfo.PageAtrb[32+i].flashing)
RenderCharFB(m_txtCache->TimeString[i], &m_RenderInfo.PageAtrb[32]);
else
{
SetPosX(33+i);
m_RenderInfo.PageChar[32+i] = m_RenderInfo.PageChar[32+i];
}
}
/* Update on every changed second */
if (m_txtCache->TimeString[7] != prevTimeSec)
{
prevTimeSec = m_txtCache->TimeString[7];
m_updateTexture = true;
}
}
DoFlashing(StartRow);
m_txtCache->NationalSubset = national_subset_bak;
}
}
void CTeletextDecoder::DoFlashing(int startrow)
{
/* get national subset */
if (m_txtCache->NationalSubset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */
m_RenderInfo.PageInfo && m_RenderInfo.PageInfo->nationalvalid) /* individual subset according to page header */
{
m_txtCache->NationalSubset = CountryConversionTable[m_RenderInfo.PageInfo->national];
}
/* Flashing */
TextPageAttr_t flashattr;
char flashchar;
long flashphase = XbmcThreads::SystemClockMillis() % 1000;
int srow = startrow;
int erow = 24;
int factor=1;
switch (m_RenderInfo.ZoomMode)
{
case 1: erow = 12; factor=2;break;
case 2: srow = 12; factor=2;break;
}
m_RenderInfo.PosY = startrow*m_RenderInfo.FontHeight*factor;
for (int row = srow; row < erow; row++)
{
int index = row * 40;
int dhset = 0;
int incflash = 3;
int decflash = 2;
m_RenderInfo.PosX = 0;
for (int col = m_RenderInfo.nofirst; col < 40; col++)
{
if (m_RenderInfo.PageAtrb[index + col].flashing && m_RenderInfo.PageChar[index + col] > 0x20 && m_RenderInfo.PageChar[index + col] != 0xff )
{
SetPosX(col);
flashchar = m_RenderInfo.PageChar[index + col];
bool doflash = false;
memcpy(&flashattr, &m_RenderInfo.PageAtrb[index + col], sizeof(TextPageAttr_t));
switch (flashattr.flashing &0x1c) // Flash Rate
{
case 0x00 : // 1 Hz
if (flashphase>500) doflash = true;
break;
case 0x04 : // 2 Hz Phase 1
if (flashphase<250) doflash = true;
break;
case 0x08 : // 2 Hz Phase 2
if (flashphase>=250 && flashphase<500) doflash = true;
break;
case 0x0c : // 2 Hz Phase 3
if (flashphase>=500 && flashphase<750) doflash = true;
break;
case 0x10 : // incremental flash
incflash++;
if (incflash>3) incflash = 1;
switch (incflash)
{
case 1: if (flashphase<250) doflash = true; break;
case 2: if (flashphase>=250 && flashphase<500) doflash = true;break;
case 3: if (flashphase>=500 && flashphase<750) doflash = true;
}
break;
case 0x14 : // decremental flash
decflash--;
if (decflash<1) decflash = 3;
switch (decflash)
{
case 1: if (flashphase<250) doflash = true; break;
case 2: if (flashphase>=250 && flashphase<500) doflash = true;break;
case 3: if (flashphase>=500 && flashphase<750) doflash = true;
}
break;
}
switch (flashattr.flashing &0x03) // Flash Mode
{
case 0x01 : // normal Flashing
if (doflash) flashattr.fg = flashattr.bg;
break;
case 0x02 : // inverted Flashing
doflash = !doflash;
if (doflash) flashattr.fg = flashattr.bg;
break;
case 0x03 : // color Flashing
if (doflash) flashattr.fg = flashattr.fg + (flashattr.fg > 7 ? (-8) : 8);
break;
}
RenderCharFB(flashchar, &flashattr);
if (flashattr.doublew) col++;
if (flashattr.doubleh) dhset = 1;
m_updateTexture = true;
}
}
if (dhset)
{
row++;
m_RenderInfo.PosY += m_RenderInfo.FontHeight*factor;
}
m_RenderInfo.PosY += m_RenderInfo.FontHeight*factor;
}
}
void CTeletextDecoder::DoRenderPage(int startrow, int national_subset_bak)
{
/* display first column? */
m_RenderInfo.nofirst = m_RenderInfo.Show39;
for (int row = 1; row < 24; row++)
{
int Byte = m_RenderInfo.PageChar[row*40];
if (Byte != ' ' && Byte != 0x00 && Byte != 0xFF && m_RenderInfo.PageAtrb[row*40].fg != m_RenderInfo.PageAtrb[row*40].bg)
{
m_RenderInfo.nofirst = 0;
break;
}
}
if (m_RenderInfo.TranspMode || m_RenderInfo.Boxed)
{
FillBorder(GetColorRGB(TXT_ColorTransp));//ClearBB(transp);
m_RenderInfo.ClearBBColor = TXT_ColorTransp;
}
/* get national subset */
if (m_txtCache->NationalSubset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */
m_RenderInfo.PageInfo && m_RenderInfo.PageInfo->nationalvalid) /* individual subset according to page header */
{
m_txtCache->NationalSubset = CountryConversionTable[m_RenderInfo.PageInfo->national];
}
/* render page */
if (m_RenderInfo.PageInfo && (m_RenderInfo.PageInfo->function == FUNC_GDRCS || m_RenderInfo.PageInfo->function == FUNC_DRCS)) /* character definitions */
{
#define DRCSROWS 8
#define DRCSCOLS (48/DRCSROWS)
#define DRCSZOOMX 3
#define DRCSZOOMY 5
#define DRCSXSPC (12*DRCSZOOMX + 2)
#define DRCSYSPC (10*DRCSZOOMY + 2)
unsigned char ax[] = { /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
DRCSZOOMX * 0,
DRCSZOOMX * 1,
DRCSZOOMX * 2,
DRCSZOOMX * 3,
DRCSZOOMX * 4,
DRCSZOOMX * 5,
DRCSZOOMX * 6,
DRCSZOOMX * 7,
DRCSZOOMX * 8,
DRCSZOOMX * 9,
DRCSZOOMX * 10,
DRCSZOOMX * 11,
DRCSZOOMX * 12,
DRCSZOOMY * 0,
DRCSZOOMY * 1,
DRCSZOOMY * 2,
DRCSZOOMY * 3,
DRCSZOOMY * 4,
DRCSZOOMY * 5,
DRCSZOOMY * 6,
DRCSZOOMY * 7,
DRCSZOOMY * 8,
DRCSZOOMY * 9,
DRCSZOOMY * 10
};
ClearBB(TXT_ColorBlack);
for (int col = 0; col < 24*40; col++)
m_RenderInfo.PageAtrb[col] = Text_AtrTable[ATR_WB];
for (int row = 0; row < DRCSROWS; row++)
{
for (int col = 0; col < DRCSCOLS; col++)
{
RenderDRCS(m_RenderInfo.Width,
m_RenderInfo.PageChar + 20 * (DRCSCOLS * row + col + 2),
m_TextureBuffer
+ (m_RenderInfo.FontHeight + DRCSYSPC * row + m_RenderInfo.Height) * m_RenderInfo.Width
+ DRCSXSPC * col,
ax, GetColorRGB(TXT_ColorWhite), GetColorRGB(TXT_ColorBlack));
}
}
memset(m_RenderInfo.PageChar + 40, 0xff, 24*40); /* don't render any char below row 0 */
}
m_RenderInfo.PosY = startrow*m_RenderInfo.FontHeight;
for (int row = startrow; row < 24; row++)
{
int index = row * 40;
m_RenderInfo.PosX = 0;
for (int col = m_RenderInfo.nofirst; col < 40; col++)
{
RenderCharBB(m_RenderInfo.PageChar[index + col], &m_RenderInfo.PageAtrb[index + col]);
if (m_RenderInfo.PageAtrb[index + col].doubleh && m_RenderInfo.PageChar[index + col] != 0xff) /* disable lower char in case of doubleh setting in l25 objects */
m_RenderInfo.PageChar[index + col + 40] = 0xff;
if (m_RenderInfo.PageAtrb[index + col].doublew) /* skip next column if double width */
{
col++;
if (m_RenderInfo.PageAtrb[index + col-1].doubleh && m_RenderInfo.PageChar[index + col] != 0xff) /* disable lower char in case of doubleh setting in l25 objects */
m_RenderInfo.PageChar[index + col + 40] = 0xff;
}
}
m_RenderInfo.PosY += m_RenderInfo.FontHeight;
}
DoFlashing(startrow);
/* update framebuffer */
CopyBB2FB();
m_txtCache->NationalSubset = national_subset_bak;
}
void CTeletextDecoder::Decode_BTT()
{
/* basic top table */
int current, b1, b2, b3, b4;
unsigned char btt[23*40];
if (m_txtCache->SubPageTable[0x1f0] == 0xff || 0 == m_txtCache->astCachetable[0x1f0][m_txtCache->SubPageTable[0x1f0]]) /* not yet received */
return;
g_application.m_pPlayer->LoadPage(0x1f0, m_txtCache->SubPageTable[0x1f0],btt);
if (btt[799] == ' ') /* not completely received or error */
return;
current = 0x100;
for (int i = 0; i < 800; i++)
{
b1 = btt[i];
if (b1 == ' ')
b1 = 0;
else
{
b1 = dehamming[b1];
if (b1 == 0xFF) /* hamming error in btt */
{
btt[799] = ' '; /* mark btt as not received */
return;
}
}
m_txtCache->BasicTop[current] = b1;
CDVDTeletextTools::NextDec(&current);
}
/* page linking table */
m_txtCache->ADIP_PgMax = -1; /* rebuild table of adip pages */
for (int i = 0; i < 10; i++)
{
b1 = dehamming[btt[800 + 8*i +0]];
if (b1 == 0xE)
continue; /* unused */
else if (b1 == 0xF)
break; /* end */
b4 = dehamming[btt[800 + 8*i +7]];
if (b4 != 2) /* only adip, ignore multipage (1) */
continue;
b2 = dehamming[btt[800 + 8*i +1]];
b3 = dehamming[btt[800 + 8*i +2]];
if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF)
{
CLog::Log(LOGERROR, "CTeletextDecoder::Decode_BTT <Biterror in btt/plt index %d>", i);
btt[799] = ' '; /* mark btt as not received */
return;
}
b1 = b1<<8 | b2<<4 | b3; /* page number */
m_txtCache->ADIP_Pg[++m_txtCache->ADIP_PgMax] = b1;
}
m_txtCache->BTTok = true;
}
void CTeletextDecoder::Decode_ADIP() /* additional information table */
{
int i, p, j, b1, b2, b3, charfound;
unsigned char padip[23*40];
for (i = 0; i <= m_txtCache->ADIP_PgMax; i++)
{
p = m_txtCache->ADIP_Pg[i];
if (!p || m_txtCache->SubPageTable[p] == 0xff || 0 == m_txtCache->astCachetable[p][m_txtCache->SubPageTable[p]]) /* not cached (avoid segfault) */
continue;
g_application.m_pPlayer->LoadPage(p,m_txtCache->SubPageTable[p],padip);
for (j = 0; j < 44; j++)
{
b1 = dehamming[padip[20*j+0]];
if (b1 == 0xE)
continue; /* unused */
if (b1 == 0xF)
break; /* end */
b2 = dehamming[padip[20*j+1]];
b3 = dehamming[padip[20*j+2]];
if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF)
{
CLog::Log(LOGERROR, "CTeletextDecoder::Decode_BTT <Biterror in ait %03x %d %02x %02x %02x %02x %02x %02x>", p, j,
padip[20*j+0],
padip[20*j+1],
padip[20*j+2],
b1, b2, b3
);
return;
}
if (b1>8 || b2>9 || b3>9) /* ignore extries with invalid or hex page numbers */
{
continue;
}
b1 = b1<<8 | b2<<4 | b3; /* page number */
charfound = 0; /* flag: no printable char found */
for (b2 = 11; b2 >= 0; b2--)
{
b3 = deparity[padip[20*j + 8 + b2]];
if (b3 < ' ')
b3 = ' ';
if (b3 == ' ' && !charfound)
m_txtCache->ADIPTable[b1][b2] = '\0';
else
{
m_txtCache->ADIPTable[b1][b2] = b3;
charfound = 1;
}
}
} /* next link j */
m_txtCache->ADIP_Pg[i] = 0; /* completely decoded: clear entry */
} /* next adip page i */
while ((m_txtCache->ADIP_PgMax >= 0) && !m_txtCache->ADIP_Pg[m_txtCache->ADIP_PgMax]) /* and shrink table */
m_txtCache->ADIP_PgMax--;
}
int CTeletextDecoder::TopText_GetNext(int startpage, int up, int findgroup)
{
int current, nextgrp, nextblk;
int stoppage = (IsDec(startpage) ? startpage : startpage & 0xF00); // avoid endless loop in hexmode
nextgrp = nextblk = 0;
current = startpage;
do {
if (up)
CDVDTeletextTools::NextDec(&current);
else
CDVDTeletextTools::PrevDec(&current);
if (!m_txtCache->BTTok || m_txtCache->BasicTop[current]) /* only if existent */
{
if (findgroup)
{
if (m_txtCache->BasicTop[current] >= 6 && m_txtCache->BasicTop[current] <= 7)
return current;
if (!nextgrp && (current&0x00F) == 0)
nextgrp = current;
}
if (m_txtCache->BasicTop[current] >= 2 && m_txtCache->BasicTop[current] <= 5) /* always find block */
return current;
if (!nextblk && (current&0x0FF) == 0)
nextblk = current;
}
} while (current != stoppage);
if (nextgrp)
return nextgrp;
else if (nextblk)
return nextblk;
else
return current;
}
void CTeletextDecoder::Showlink(int column, int linkpage)
{
unsigned char line[] = " >??? ";
int oldfontwidth = m_RenderInfo.FontWidth;
int yoffset;
if (m_YOffset)
yoffset = 0;
else
yoffset = m_RenderInfo.Height;
int abx = ((m_RenderInfo.Width)%(40-m_RenderInfo.nofirst) == 0 ? m_RenderInfo.Width+1 : (m_RenderInfo.Width)/(((m_RenderInfo.Width)%(40-m_RenderInfo.nofirst)))+1);// distance between 'inserted' pixels
int width = m_RenderInfo.Width /4;
m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
if (m_RenderInfo.Boxed)
{
m_RenderInfo.PosX = column*width;
FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY+yoffset, m_RenderInfo.Width, m_RenderInfo.FontHeight, GetColorRGB(TXT_ColorTransp));
return;
}
if (m_txtCache->ADIPTable[linkpage][0])
{
m_RenderInfo.PosX = column*width;
int l = strlen(m_txtCache->ADIPTable[linkpage]);
if (l > 9) /* smaller font, if no space for one half space at front and end */
SetFontWidth(oldfontwidth * 10 / (l+1));
FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY+yoffset, width+(m_RenderInfo.Width%4), m_RenderInfo.FontHeight, GetColorRGB((enumTeletextColor)Text_AtrTable[ATR_L250 + column].bg));
m_RenderInfo.PosX += ((width) - (l*m_RenderInfo.FontWidth+l*m_RenderInfo.FontWidth/abx))/2; /* center */
for (char *p = m_txtCache->ADIPTable[linkpage]; *p; p++)
RenderCharBB(*p, &Text_AtrTable[ATR_L250 + column]);
SetFontWidth(oldfontwidth);
}
else /* display number */
{
m_RenderInfo.PosX = column*width;
FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY+yoffset, m_RenderInfo.Width-m_RenderInfo.PosX, m_RenderInfo.FontHeight, GetColorRGB((enumTeletextColor)Text_AtrTable[ATR_L250 + column].bg));
if (linkpage < m_txtCache->Page)
{
line[6] = '<';
CDVDTeletextTools::Hex2Str((char*)line + 5, linkpage);
}
else
CDVDTeletextTools::Hex2Str((char*)line + 6, linkpage);
for (unsigned char *p = line; p < line+9; p++)
RenderCharBB(*p, &Text_AtrTable[ATR_L250 + column]);
}
}
void CTeletextDecoder::CreateLine25()
{
/* btt completely received and not yet decoded */
if (!m_txtCache->BTTok)
Decode_BTT();
if (m_txtCache->ADIP_PgMax >= 0)
Decode_ADIP();
if (!m_RenderInfo.ShowHex && m_RenderInfo.ShowFlof &&
(m_txtCache->FlofPages[m_txtCache->Page][0] || m_txtCache->FlofPages[m_txtCache->Page][1] || m_txtCache->FlofPages[m_txtCache->Page][2] || m_txtCache->FlofPages[m_txtCache->Page][3])) // FLOF-Navigation present
{
m_RenderInfo.Prev_100 = m_txtCache->FlofPages[m_txtCache->Page][0];
m_RenderInfo.Prev_10 = m_txtCache->FlofPages[m_txtCache->Page][1];
m_RenderInfo.Next_10 = m_txtCache->FlofPages[m_txtCache->Page][2];
m_RenderInfo.Next_100 = m_txtCache->FlofPages[m_txtCache->Page][3];
m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
m_RenderInfo.PosX = 0;
for (int i=m_RenderInfo.nofirst; i<40; i++)
RenderCharBB(m_RenderInfo.PageChar[24*40 + i], &m_RenderInfo.PageAtrb[24*40 + i]);
}
else
{
/* normal: blk-1, grp+1, grp+2, blk+1 */
/* hex: hex+1, blk-1, grp+1, blk+1 */
if (m_RenderInfo.ShowHex)
{
/* arguments: startpage, up, findgroup */
m_RenderInfo.Prev_100 = NextHex(m_txtCache->Page);
m_RenderInfo.Prev_10 = TopText_GetNext(m_txtCache->Page, 0, 0);
m_RenderInfo.Next_10 = TopText_GetNext(m_txtCache->Page, 1, 1);
}
else
{
m_RenderInfo.Prev_100 = TopText_GetNext(m_txtCache->Page, 0, 0);
m_RenderInfo.Prev_10 = TopText_GetNext(m_txtCache->Page, 1, 1);
m_RenderInfo.Next_10 = TopText_GetNext(m_RenderInfo.Prev_10, 1, 1);
}
m_RenderInfo.Next_100 = TopText_GetNext(m_RenderInfo.Next_10, 1, 0);
Showlink(0, m_RenderInfo.Prev_100);
Showlink(1, m_RenderInfo.Prev_10);
Showlink(2, m_RenderInfo.Next_10);
Showlink(3, m_RenderInfo.Next_100);
}
}
void CTeletextDecoder::RenderCharFB(int Char, TextPageAttr_t *Attribute)
{
RenderCharIntern(&m_RenderInfo, Char, Attribute, m_RenderInfo.ZoomMode, m_YOffset);
}
void CTeletextDecoder::RenderCharBB(int Char, TextPageAttr_t *Attribute)
{
RenderCharIntern(&m_RenderInfo, Char, Attribute, 0, m_RenderInfo.Height-m_YOffset);
}
void CTeletextDecoder::CopyBB2FB()
{
color_t *src, *dst, *topsrc;
int screenwidth;
color_t fillcolor;
/* line 25 */
if (!m_RenderInfo.PageCatching)
CreateLine25();
/* copy backbuffer to framebuffer */
if (!m_RenderInfo.ZoomMode)
{
if (m_YOffset)
m_YOffset = 0;
else
m_YOffset = m_RenderInfo.Height;
if (m_RenderInfo.ClearBBColor >= 0)
{
m_RenderInfo.ClearBBColor = -1;
}
return;
}
src = dst = topsrc = m_TextureBuffer + m_RenderInfo.Width;
if (m_YOffset)
{
dst += m_RenderInfo.Width * m_RenderInfo.Height;
}
else
{
src += m_RenderInfo.Width * m_RenderInfo.Height;
topsrc += m_RenderInfo.Width * m_RenderInfo.Height;
}
if (!m_RenderInfo.PageCatching)
SDL_memcpy4(dst+(24*m_RenderInfo.FontHeight)*m_RenderInfo.Width, src + (24*m_RenderInfo.FontHeight)*m_RenderInfo.Width, m_RenderInfo.Width*m_RenderInfo.FontHeight); /* copy line25 in normal height */
if (m_RenderInfo.TranspMode)
fillcolor = GetColorRGB(TXT_ColorTransp);
else
fillcolor = GetColorRGB((enumTeletextColor)m_txtCache->FullScrColor);
if (m_RenderInfo.ZoomMode == 2)
src += 12*m_RenderInfo.FontHeight*m_RenderInfo.Width;
screenwidth = m_RenderInfo.Width;
for (int i = 12*m_RenderInfo.FontHeight; i; i--)
{
SDL_memcpy4(dst, src, screenwidth);
dst += m_RenderInfo.Width;
SDL_memcpy4(dst, src, screenwidth);
dst += m_RenderInfo.Width;
src += m_RenderInfo.Width;
}
for (int i = m_RenderInfo.Height - 25*m_RenderInfo.FontHeight; i >= 0;i--)
{
SDL_memset4(dst + m_RenderInfo.Width*(m_RenderInfo.FontHeight+i), fillcolor, screenwidth);
}
}
FT_Error CTeletextDecoder::MyFaceRequester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface)
{
FT_Error result = FT_New_Face(library, (const char*)face_id, 0, aface);
if (!result)
CLog::Log(LOGNOTICE, "Teletext font %s loaded", (char*)face_id);
else
CLog::Log(LOGERROR, "Opening of Teletext font %s failed", (char*)face_id);
return result;
}
void CTeletextDecoder::SetFontWidth(int newWidth)
{
if (m_RenderInfo.FontWidth != newWidth)
{
m_RenderInfo.FontWidth = newWidth;
m_TypeTTF.width = (FT_UShort) m_RenderInfo.FontWidth;
for (int i = 0; i <= 12; i++)
m_RenderInfo.axdrcs[i] = (m_RenderInfo.FontWidth * i + 6) / 12;
}
}
int CTeletextDecoder::GetCurFontWidth()
{
int mx = (m_RenderInfo.Width)%(40-m_RenderInfo.nofirst); // # of unused pixels
int abx = (mx == 0 ? m_RenderInfo.Width+1 : (m_RenderInfo.Width)/(mx+1)); // distance between 'inserted' pixels
int nx = abx+1-(m_RenderInfo.PosX % (abx+1)); // # of pixels to next insert
return m_RenderInfo.FontWidth+(((m_RenderInfo.PosX+m_RenderInfo.FontWidth+1) <= m_RenderInfo.Width && nx <= m_RenderInfo.FontWidth+1) ? 1 : 0);
}
void CTeletextDecoder::SetPosX(int column)
{
m_RenderInfo.PosX = 0;
for (int i = 0; i < column-m_RenderInfo.nofirst; i++)
m_RenderInfo.PosX += GetCurFontWidth();
}
void CTeletextDecoder::ClearBB(color_t Color)
{
SDL_memset4(m_TextureBuffer + (m_RenderInfo.Height-m_YOffset)*m_RenderInfo.Width, Color, m_RenderInfo.Width*m_RenderInfo.Height);
}
void CTeletextDecoder::ClearFB(color_t Color)
{
SDL_memset4(m_TextureBuffer + m_RenderInfo.Width*m_YOffset, Color, m_RenderInfo.Width*m_RenderInfo.Height);
}
void CTeletextDecoder::FillBorder(color_t Color)
{
FillRect(m_TextureBuffer + (m_RenderInfo.Height-m_YOffset)*m_RenderInfo.Width, m_RenderInfo.Width, 0, 25*m_RenderInfo.FontHeight, m_RenderInfo.Width, m_RenderInfo.Height-(25*m_RenderInfo.FontHeight), Color);
FillRect(m_TextureBuffer + m_RenderInfo.Width*m_YOffset, m_RenderInfo.Width, 0, 25*m_RenderInfo.FontHeight, m_RenderInfo.Width, m_RenderInfo.Height-(25*m_RenderInfo.FontHeight), Color);
}
void CTeletextDecoder::FillRect(color_t *buffer, int xres, int x, int y, int w, int h, color_t Color)
{
if (!buffer) return;
color_t *p = buffer + x + y * xres;
if (w > 0)
{
for ( ; h > 0 ; h--)
{
SDL_memset4(p, Color, w);
p += xres;
}
}
}
void CTeletextDecoder::DrawVLine(color_t *lfb, int xres, int x, int y, int l, color_t color)
{
if (!lfb) return;
color_t *p = lfb + x + y * xres;
for ( ; l > 0 ; l--)
{
*p = color;
p += xres;
}
}
void CTeletextDecoder::DrawHLine(color_t *lfb, int xres,int x, int y, int l, color_t color)
{
if (!lfb) return;
if (l > 0)
SDL_memset4(lfb + x + y * xres, color, l);
}
void CTeletextDecoder::RenderDRCS(int xres,
unsigned char *s, /* pointer to char data, parity undecoded */
color_t *d, /* pointer to frame buffer of top left pixel */
unsigned char *ax, /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
color_t fgcolor, color_t bgcolor)
{
if (d == NULL) return;
unsigned char *ay = ax + 13; /* array[0..10] of y-offsets for each pixel */
for (int y = 0; y < 10; y++) /* 10*2 bytes a 6 pixels per char definition */
{
unsigned char c1 = deparity[*s++];
unsigned char c2 = deparity[*s++];
int h = ay[y+1] - ay[y];
if (!h)
continue;
if (((c1 == ' ') && (*(s-2) != ' ')) || ((c2 == ' ') && (*(s-1) != ' '))) /* parity error: stop decoding FIXME */
return;
for (int bit = 0x20, x = 0;
bit;
bit >>= 1, x++) /* bit mask (MSB left), column counter */
{
color_t f1 = (c1 & bit) ? fgcolor : bgcolor;
color_t f2 = (c2 & bit) ? fgcolor : bgcolor;
for (int i = 0; i < h; i++)
{
if (ax[x+1] > ax[x])
SDL_memset4(d + ax[x], f1, ax[x+1] - ax[x]);
if (ax[x+7] > ax[x+6])
SDL_memset4(d + ax[x+6], f2, ax[x+7] - ax[x+6]); /* 2nd byte 6 pixels to the right */
d += xres;
}
d -= h * xres;
}
d += h * xres;
}
}
void CTeletextDecoder::FillRectMosaicSeparated(color_t *lfb, int xres,int x, int y, int w, int h, color_t fgcolor, color_t bgcolor, int set)
{
if (!lfb) return;
FillRect(lfb,xres,x, y, w, h, bgcolor);
if (set)
{
FillRect(lfb,xres,x+1, y+1, w-2, h-2, fgcolor);
}
}
void CTeletextDecoder::FillTrapez(color_t *lfb, int xres,int x0, int y0, int l0, int xoffset1, int h, int l1, color_t color)
{
color_t *p = lfb + x0 + y0 * xres;
int xoffset, l;
for (int yoffset = 0; yoffset < h; yoffset++)
{
l = l0 + ((l1-l0) * yoffset + h/2) / h;
xoffset = (xoffset1 * yoffset + h/2) / h;
if (l > 0)
SDL_memset4(p + xoffset, color, l);
p += xres;
}
}
void CTeletextDecoder::FlipHorz(color_t *lfb, int xres,int x, int y, int w, int h)
{
color_t buf[2048];
color_t *p = lfb + x + y * xres;
int w1,h1;
for (h1 = 0 ; h1 < h ; h1++)
{
SDL_memcpy4(buf,p,w);
for (w1 = 0 ; w1 < w ; w1++)
{
*(p+w1) = buf[w-(w1+1)];
}
p += xres;
}
}
void CTeletextDecoder::FlipVert(color_t *lfb, int xres,int x, int y, int w, int h)
{
color_t buf[2048];
color_t *p = lfb + x + y * xres, *p1, *p2;
int h1;
for (h1 = 0 ; h1 < h/2 ; h1++)
{
p1 = (p+(h1*xres));
p2 = (p+(h-(h1+1))*xres);
SDL_memcpy4(buf, p1, w);
SDL_memcpy4(p1, p2, w);
SDL_memcpy4(p2, buf, w);
}
}
int CTeletextDecoder::ShapeCoord(int param, int curfontwidth, int curFontHeight)
{
switch (param)
{
case S_W13:
return curfontwidth/3;
case S_W12:
return curfontwidth/2;
case S_W23:
return curfontwidth*2/3;
case S_W11:
return curfontwidth;
case S_WM3:
return curfontwidth-3;
case S_H13:
return curFontHeight/3;
case S_H12:
return curFontHeight/2;
case S_H23:
return curFontHeight*2/3;
case S_H11:
return curFontHeight;
default:
return param;
}
}
void CTeletextDecoder::DrawShape(color_t *lfb, int xres, int x, int y, int shapenumber, int curfontwidth, int FontHeight, int curFontHeight, color_t fgcolor, color_t bgcolor, bool clear)
{
if (!lfb || shapenumber < 0x20 || shapenumber > 0x7e || (shapenumber == 0x7e && clear))
return;
unsigned char *p = aShapes[shapenumber - 0x20];
if (*p == S_INV)
{
int t = fgcolor;
fgcolor = bgcolor;
bgcolor = t;
p++;
}
if (clear)
FillRect(lfb, xres, x, y, curfontwidth, FontHeight, bgcolor);
while (*p != S_END)
{
switch (*p++)
{
case S_FHL:
{
int offset = ShapeCoord(*p++, curfontwidth, curFontHeight);
DrawHLine(lfb, xres, x, y + offset, curfontwidth, fgcolor);
break;
}
case S_FVL:
{
int offset = ShapeCoord(*p++, curfontwidth, curFontHeight);
DrawVLine(lfb,xres,x + offset, y, FontHeight, fgcolor);
break;
}
case S_FLH:
FlipHorz(lfb,xres,x,y,curfontwidth, FontHeight);
break;
case S_FLV:
FlipVert(lfb,xres,x,y,curfontwidth, FontHeight);
break;
case S_BOX:
{
int xo = ShapeCoord(*p++, curfontwidth, curFontHeight);
int yo = ShapeCoord(*p++, curfontwidth, curFontHeight);
int w = ShapeCoord(*p++, curfontwidth, curFontHeight);
int h = ShapeCoord(*p++, curfontwidth, curFontHeight);
FillRect(lfb,xres,x + xo, y + yo, w, h, fgcolor);
break;
}
case S_TRA:
{
int x0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int y0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int l0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int x1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int y1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int l1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
FillTrapez(lfb, xres,x + x0, y + y0, l0, x1-x0, y1-y0, l1, fgcolor);
break;
}
case S_BTR:
{
int x0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int y0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int l0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int x1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int y1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
int l1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
FillTrapez(lfb, xres, x + x0, y + y0, l0, x1-x0, y1-y0, l1, bgcolor);
break;
}
case S_LNK:
{
DrawShape(lfb,xres,x, y, ShapeCoord(*p, curfontwidth, curFontHeight), curfontwidth, FontHeight, curFontHeight, fgcolor, bgcolor, false);
break;
}
default:
break;
}
}
}
void CTeletextDecoder::RenderCharIntern(TextRenderInfo_t* RenderInfo, int Char, TextPageAttr_t *Attribute, int zoom, int yoffset)
{
int Row, Pitch;
int glyph;
color_t bgcolor, fgcolor;
int factor, xfactor;
unsigned char *sbitbuffer;
int national_subset_local = m_txtCache->NationalSubset;
int curfontwidth = GetCurFontWidth();
int t = curfontwidth;
m_RenderInfo.PosX += t;
int curfontwidth2 = GetCurFontWidth();
m_RenderInfo.PosX -= t;
int alphachar = RenderChar(m_TextureBuffer+(yoffset)*m_RenderInfo.Width, m_RenderInfo.Width, Char, &m_RenderInfo.PosX, m_RenderInfo.PosY, Attribute, zoom > 0, curfontwidth, curfontwidth2, m_RenderInfo.FontHeight, m_RenderInfo.TranspMode, m_RenderInfo.axdrcs, m_Ascender);
if (alphachar <= 0) return;
if (zoom && Attribute->doubleh)
factor = 4;
else if (zoom || Attribute->doubleh)
factor = 2;
else
factor = 1;
fgcolor = GetColorRGB((enumTeletextColor)Attribute->fg);
if (m_RenderInfo.TranspMode && m_RenderInfo.PosY < 24*m_RenderInfo.FontHeight)
{
bgcolor = GetColorRGB(TXT_ColorTransp);
}
else
{
bgcolor = GetColorRGB((enumTeletextColor)Attribute->bg);
}
if (Attribute->doublew)
{
curfontwidth += curfontwidth2;
xfactor = 2;
}
else
xfactor = 1;
if (!(glyph = FT_Get_Char_Index(m_Face, alphachar)))
{
CLog::Log(LOGERROR, "%s: <FT_Get_Char_Index for Char %x \"%c\" failed", __FUNCTION__, alphachar, alphachar);
FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, factor*m_RenderInfo.FontHeight, bgcolor);
m_RenderInfo.PosX += curfontwidth;
return;
}
if (FTC_SBitCache_Lookup(m_Cache, &m_TypeTTF, glyph, &m_sBit, NULL) != 0)
{
FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, m_RenderInfo.FontHeight, bgcolor);
m_RenderInfo.PosX += curfontwidth;
return;
}
/* render char */
sbitbuffer = m_sBit->buffer;
unsigned char localbuffer[1000]; // should be enough to store one character-bitmap...
// add diacritical marks
if (Attribute->diacrit)
{
FTC_SBit sbit_diacrit;
if ((national_subset_local == NAT_SC) || (national_subset_local == NAT_RB) || (national_subset_local == NAT_UA))
Char = G2table[1][0x20+ Attribute->diacrit];
else if (national_subset_local == NAT_GR)
Char = G2table[2][0x20+ Attribute->diacrit];
else if (national_subset_local == NAT_HB)
Char = G2table[3][0x20+ Attribute->diacrit];
else if (national_subset_local == NAT_AR)
Char = G2table[4][0x20+ Attribute->diacrit];
else
Char = G2table[0][0x20+ Attribute->diacrit];
if ((glyph = FT_Get_Char_Index(m_Face, Char)))
{
if (FTC_SBitCache_Lookup(m_Cache, &m_TypeTTF, glyph, &sbit_diacrit, NULL) == 0)
{
sbitbuffer = localbuffer;
memcpy(sbitbuffer,m_sBit->buffer,m_sBit->pitch*m_sBit->height);
for (Row = 0; Row < m_sBit->height; Row++)
{
for (Pitch = 0; Pitch < m_sBit->pitch; Pitch++)
{
if (sbit_diacrit->pitch > Pitch && sbit_diacrit->height > Row)
sbitbuffer[Row*m_sBit->pitch+Pitch] |= sbit_diacrit->buffer[Row*m_sBit->pitch+Pitch];
}
}
}
}
}
int backupTTFshiftY = m_RenderInfo.TTFShiftY;
if (national_subset_local == NAT_AR)
m_RenderInfo.TTFShiftY = backupTTFshiftY - 2; // for arabic TTF font should be shifted up slightly
color_t *p;
int f; /* running counter for zoom factor */
int he = m_sBit->height; // sbit->height should not be altered, I guess
Row = factor * (m_Ascender - m_sBit->top + m_RenderInfo.TTFShiftY);
if (Row < 0)
{
sbitbuffer -= m_sBit->pitch*Row;
he += Row;
Row = 0;
}
else
{
FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, Row, bgcolor); /* fill upper margin */
}
if (m_Ascender - m_sBit->top + m_RenderInfo.TTFShiftY + he > m_RenderInfo.FontHeight)
he = m_RenderInfo.FontHeight - m_Ascender + m_sBit->top - m_RenderInfo.TTFShiftY; /* limit char height to defined/calculated FontHeight */
if (he < 0) he = m_RenderInfo.FontHeight;
p = m_TextureBuffer + m_RenderInfo.PosX + (yoffset + m_RenderInfo.PosY + Row) * m_RenderInfo.Width; /* running pointer into framebuffer */
for (Row = he; Row; Row--) /* row counts up, but down may be a little faster :) */
{
int pixtodo = m_sBit->width;
color_t *pstart = p;
for (int Bit = xfactor * (m_sBit->left + m_RenderInfo.TTFShiftX); Bit > 0; Bit--) /* fill left margin */
{
for (f = factor-1; f >= 0; f--)
*(p + f*m_RenderInfo.Width) = bgcolor;
p++;
}
for (Pitch = m_sBit->pitch; Pitch; Pitch--)
{
for (int Bit = 0x80; Bit; Bit >>= 1)
{
color_t color;
if (--pixtodo < 0)
break;
if (*sbitbuffer & Bit) /* bit set -> foreground */
color = fgcolor;
else /* bit not set -> background */
color = bgcolor;
for (f = factor-1; f >= 0; f--)
*(p + f*m_RenderInfo.Width) = color;
p++;
if (xfactor > 1) /* double width */
{
for (f = factor-1; f >= 0; f--)
*(p + f*m_RenderInfo.Width) = color;
p++;
}
}
sbitbuffer++;
}
for (int Bit = (curfontwidth - xfactor*(m_sBit->width + m_sBit->left + m_RenderInfo.TTFShiftX));
Bit > 0; Bit--) /* fill rest of char width */
{
for (f = factor-1; f >= 0; f--)
*(p + f*m_RenderInfo.Width) = bgcolor;
p++;
}
p = pstart + factor*m_RenderInfo.Width;
}
Row = m_Ascender - m_sBit->top + he + m_RenderInfo.TTFShiftY;
FillRect(m_TextureBuffer,
m_RenderInfo.Width,
m_RenderInfo.PosX,
m_RenderInfo.PosY + yoffset + Row * factor,
curfontwidth,
(m_RenderInfo.FontHeight - Row) * factor,
bgcolor); /* fill lower margin */
if (Attribute->underline)
FillRect(m_TextureBuffer,
m_RenderInfo.Width,
m_RenderInfo.PosX,
m_RenderInfo.PosY + yoffset + (m_RenderInfo.FontHeight-2)* factor,
curfontwidth,
2*factor,
fgcolor); /* underline char */
m_RenderInfo.PosX += curfontwidth;
m_RenderInfo.TTFShiftY = backupTTFshiftY; // restore TTFShiftY
}
int CTeletextDecoder::RenderChar(color_t *buffer, // pointer to render buffer, min. FontHeight*2*xres
int xres, // length of 1 line in render buffer
int Char, // character to render
int *pPosX, // left border for rendering relative to *buffer, will be set to right border after rendering
int PosY, // vertical position of char in *buffer
TextPageAttr_t *Attribute,// Attributes of Char
bool zoom, // 1= character will be rendered in double height
int curfontwidth, // rendering width of character
int curfontwidth2, // rendering width of next character (needed for doublewidth)
int FontHeight, // height of character
bool transpmode, // 1= transparent display
unsigned char *axdrcs, // width and height of DRCS-chars
int Ascender) // Ascender of font
{
color_t bgcolor, fgcolor;
int factor, xfactor;
int national_subset_local = m_txtCache->NationalSubset;
int ymosaic[4];
ymosaic[0] = 0; /* y-offsets for 2*3 mosaic */
ymosaic[1] = (FontHeight + 1) / 3;
ymosaic[2] = (FontHeight * 2 + 1) / 3;
ymosaic[3] = FontHeight;
if (Attribute->setX26)
{
national_subset_local = 0; // no national subset
}
// G0+G2 set designation
if (Attribute->setG0G2 != 0x3f)
{
switch (Attribute->setG0G2)
{
case 0x20 :
national_subset_local = NAT_SC;
break;
case 0x24 :
national_subset_local = NAT_RB;
break;
case 0x25 :
national_subset_local = NAT_UA;
break;
case 0x37:
national_subset_local = NAT_GR;
break;
case 0x55:
national_subset_local = NAT_HB;
break;
case 0x47:
case 0x57:
national_subset_local = NAT_AR;
break;
default:
national_subset_local = CountryConversionTable[Attribute->setG0G2 & 0x07];
break;
}
}
if (Attribute->charset == C_G0S) // use secondary charset
national_subset_local = m_txtCache->NationalSubsetSecondary;
if (zoom && Attribute->doubleh)
factor = 4;
else if (zoom || Attribute->doubleh)
factor = 2;
else
factor = 1;
if (Attribute->doublew)
{
curfontwidth += curfontwidth2;
xfactor = 2;
}
else
xfactor = 1;
if (Char == 0xFF) /* skip doubleheight chars in lower line */
{
*pPosX += curfontwidth;
return -1;
}
/* get colors */
if (Attribute->inverted)
{
int t = Attribute->fg;
Attribute->fg = Attribute->bg;
Attribute->bg = t;
}
fgcolor = GetColorRGB((enumTeletextColor)Attribute->fg);
if (transpmode == true && PosY < 24*FontHeight)
{
bgcolor = GetColorRGB(TXT_ColorTransp);
}
else
{
bgcolor = GetColorRGB((enumTeletextColor)Attribute->bg);
}
/* handle mosaic */
if ((Attribute->charset == C_G1C || Attribute->charset == C_G1S) &&
((Char&0xA0) == 0x20))
{
int w1 = (curfontwidth / 2 ) *xfactor;
int w2 = (curfontwidth - w1) *xfactor;
Char = (Char & 0x1f) | ((Char & 0x40) >> 1);
if (Attribute->charset == C_G1S) /* separated mosaic */
{
for (int y = 0; y < 3; y++)
{
FillRectMosaicSeparated(buffer, xres,*pPosX, PosY + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x01);
FillRectMosaicSeparated(buffer, xres,*pPosX + w1, PosY + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x02);
Char >>= 2;
}
}
else
{
for (int y = 0; y < 3; y++)
{
FillRect(buffer, xres, *pPosX, PosY + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x01) ? fgcolor : bgcolor);
FillRect(buffer, xres, *pPosX + w1, PosY + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x02) ? fgcolor : bgcolor);
Char >>= 2;
}
}
*pPosX += curfontwidth;
return 0;;
}
if (Attribute->charset == C_G3)
{
if (Char < 0x20 || Char > 0x7d)
{
Char = 0x20;
}
else
{
if (*aShapes[Char - 0x20] == S_CHR)
{
unsigned char *p = aShapes[Char - 0x20];
Char = (*(p+1) <<8) + (*(p+2));
}
else if (*aShapes[Char - 0x20] == S_ADT)
{
if (buffer)
{
int x,y,f,c;
color_t* p = buffer + *pPosX + PosY* xres;
for (y=0; y<FontHeight;y++)
{
for (f=0; f<factor; f++)
{
for (x=0; x<curfontwidth*xfactor;x++)
{
c = (y&4 ? (x/3)&1 :((x+3)/3)&1);
*(p+x) = (c ? fgcolor : bgcolor);
}
p += xres;
}
}
}
*pPosX += curfontwidth;
return 0;
}
else
{
DrawShape(buffer, xres,*pPosX, PosY, Char, curfontwidth, FontHeight, factor*FontHeight, fgcolor, bgcolor, true);
*pPosX += curfontwidth;
return 0;
}
}
}
else if (Attribute->charset >= C_OFFSET_DRCS)
{
TextCachedPage_t *pcache = m_txtCache->astCachetable[(Attribute->charset & 0x10) ? m_txtCache->drcs : m_txtCache->gdrcs][Attribute->charset & 0x0f];
if (pcache)
{
unsigned char drcs_data[23*40];
g_application.m_pPlayer->LoadPage((Attribute->charset & 0x10) ? m_txtCache->drcs : m_txtCache->gdrcs, Attribute->charset & 0x0f, drcs_data);
unsigned char *p;
if (Char < 23*2)
p = drcs_data + 20*Char;
else if (pcache->pageinfo.p24)
p = pcache->pageinfo.p24 + 20*(Char - 23*2);
else
{
FillRect(buffer, xres,*pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
*pPosX += curfontwidth;
return 0;
}
axdrcs[12] = curfontwidth; /* adjust last x-offset according to position, FIXME: double width */
RenderDRCS(xres, p, buffer + *pPosX + PosY * xres, axdrcs, fgcolor, bgcolor);
}
else
{
FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
}
*pPosX += curfontwidth;
return 0;
}
else if (Attribute->charset == C_G2 && Char >= 0x20 && Char <= 0x7F)
{
if ((national_subset_local == NAT_SC) || (national_subset_local == NAT_RB) || (national_subset_local == NAT_UA))
Char = G2table[1][Char-0x20];
else if (national_subset_local == NAT_GR)
Char = G2table[2][Char-0x20];
else if (national_subset_local == NAT_AR)
Char = G2table[3][Char-0x20];
else
Char = G2table[0][Char-0x20];
//if (Char == 0x7F)
//{
// FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*Ascender, fgcolor);
// FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
// *pPosX += curfontwidth;
// return 0;
//}
}
else if (national_subset_local == NAT_SC && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for serbian/croatian */
Char = G0table[0][Char-0x20];
else if (national_subset_local == NAT_RB && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for russian/bulgarian */
Char = G0table[1][Char-0x20];
else if (national_subset_local == NAT_UA && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for ukrainian */
Char = G0table[2][Char-0x20];
else if (national_subset_local == NAT_GR && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for greek */
Char = G0table[3][Char-0x20];
else if (national_subset_local == NAT_HB && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for hebrew */
Char = G0table[4][Char-0x20];
else if (national_subset_local == NAT_AR && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for arabic */
Char = G0table[5][Char-0x20];
else
{
/* load char */
switch (Char)
{
case 0x00:
case 0x20:
FillRect(buffer, xres, *pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
*pPosX += curfontwidth;
return -3;
case 0x23:
case 0x24:
Char = nationaltable23[national_subset_local][Char-0x23];
break;
case 0x40:
Char = nationaltable40[national_subset_local];
break;
case 0x5B:
case 0x5C:
case 0x5D:
case 0x5E:
case 0x5F:
case 0x60:
Char = nationaltable5b[national_subset_local][Char-0x5B];
break;
case 0x7B:
case 0x7C:
case 0x7D:
case 0x7E:
Char = nationaltable7b[national_subset_local][Char-0x7B];
break;
case 0x7F:
FillRect(buffer,xres,*pPosX, PosY , curfontwidth, factor*Ascender, fgcolor);
FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE0: /* |- */
DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
DrawVLine(buffer,xres,*pPosX, PosY +1, FontHeight -1, fgcolor);
FillRect(buffer,xres,*pPosX +1, PosY +1, curfontwidth-1, FontHeight-1, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE1: /* - */
DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth, FontHeight-1, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE2: /* -| */
DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY +1, FontHeight -1, fgcolor);
FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth-1, FontHeight-1, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE3: /* | */
DrawVLine(buffer,xres,*pPosX, PosY, FontHeight, fgcolor);
FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth -1, FontHeight, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE4: /* | */
DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY, FontHeight, fgcolor);
FillRect(buffer,xres,*pPosX, PosY, curfontwidth -1, FontHeight, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE5: /* |_ */
DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
DrawVLine(buffer,xres,*pPosX, PosY, FontHeight -1, fgcolor);
FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth-1, FontHeight-1, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE6: /* _ */
DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
FillRect(buffer,xres,*pPosX, PosY, curfontwidth, FontHeight-1, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE7: /* _| */
DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY, FontHeight -1, fgcolor);
FillRect(buffer,xres,*pPosX, PosY, curfontwidth-1, FontHeight-1, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE8: /* Ii */
FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth -1, FontHeight, bgcolor);
for (int Row=0; Row < curfontwidth/2; Row++)
DrawVLine(buffer,xres,*pPosX + Row, PosY + Row, FontHeight - Row, fgcolor);
*pPosX += curfontwidth;
return 0;
case 0xE9: /* II */
FillRect(buffer,xres,*pPosX, PosY, curfontwidth/2, FontHeight, fgcolor);
FillRect(buffer,xres,*pPosX + curfontwidth/2, PosY, (curfontwidth+1)/2, FontHeight, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xEA: /* ∞ */
FillRect(buffer,xres,*pPosX, PosY, curfontwidth, FontHeight, bgcolor);
FillRect(buffer,xres,*pPosX, PosY, curfontwidth/2, curfontwidth/2, fgcolor);
*pPosX += curfontwidth;
return 0;
case 0xEB: /* ¨ */
FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth, FontHeight -1, bgcolor);
for (int Row=0; Row < curfontwidth/2; Row++)
DrawHLine(buffer,xres,*pPosX + Row, PosY + Row, curfontwidth - Row, fgcolor);
*pPosX += curfontwidth;
return 0;
case 0xEC: /* -- */
FillRect(buffer, xres,*pPosX, PosY, curfontwidth, curfontwidth/2, fgcolor);
FillRect(buffer, xres,*pPosX, PosY + curfontwidth/2, curfontwidth, FontHeight - curfontwidth/2, bgcolor);
*pPosX += curfontwidth;
return 0;
case 0xED:
case 0xEE:
case 0xEF:
case 0xF0:
case 0xF1:
case 0xF2:
case 0xF3:
case 0xF4:
case 0xF5:
case 0xF6:
Char = arrowtable[Char - 0xED];
break;
default:
break;
}
}
if (Char <= 0x20)
{
FillRect(buffer, xres, *pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
*pPosX += curfontwidth;
return -2;
}
return Char; // Char is an alphanumeric unicode character
}
TextPageinfo_t* CTeletextDecoder::DecodePage(bool showl25, // 1=decode Level2.5-graphics
unsigned char* PageChar, // page buffer, min. 25*40
TextPageAttr_t *PageAtrb, // attribut buffer, min 25*40
bool HintMode, // 1=show hidden information
bool showflof) // 1=decode FLOF-line
{
int col;
int hold, dhset;
int foreground, background, doubleheight, doublewidth, charset, previous_charset, mosaictype, IgnoreAtBlackBgSubst, concealed, flashmode, boxwin;
unsigned char held_mosaic, *p;
TextCachedPage_t *pCachedPage;
/* copy page to decode buffer */
if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xff) /* not cached: do nothing */
return NULL;
if (m_txtCache->ZapSubpageManual)
pCachedPage = m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage];
else
pCachedPage = m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPageTable[m_txtCache->Page]];
if (!pCachedPage) /* not cached: do nothing */
return NULL;
g_application.m_pPlayer->LoadPage(m_txtCache->Page, m_txtCache->SubPage, &PageChar[40]);
memcpy(&PageChar[8], pCachedPage->p0, 24); /* header line without TimeString */
TextPageinfo_t* PageInfo = &(pCachedPage->pageinfo);
if (PageInfo->p24)
memcpy(&PageChar[24*40], PageInfo->p24, 40); /* line 25 for FLOF */
/* copy TimeString */
memcpy(&PageChar[32], &m_txtCache->TimeString, 8);
bool boxed;
/* check for newsflash & subtitle */
if (PageInfo->boxed && IsDec(m_txtCache->Page))
boxed = true;
else
boxed = false;
/* modify header */
if (boxed)
{
memset(PageChar, ' ', 40);
}
else
{
memset(PageChar, ' ', 8);
CDVDTeletextTools::Hex2Str((char*)PageChar+3, m_txtCache->Page);
if (m_txtCache->SubPage)
{
*(PageChar+4) ='/';
*(PageChar+5) ='0';
CDVDTeletextTools::Hex2Str((char*)PageChar+6, m_txtCache->SubPage);
}
}
if (!IsDec(m_txtCache->Page))
{
TextPageAttr_t atr = { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f};
if (PageInfo->function == FUNC_MOT) /* magazine organization table */
{
for (col = 0; col < 24*40; col++)
PageAtrb[col] = atr;
for (col = 40; col < 24*40; col++)
PageChar[col] = number2char(PageChar[col]);
return PageInfo; /* don't interpret irregular pages */
}
else if (PageInfo->function == FUNC_GPOP || PageInfo->function == FUNC_POP) /* object definitions */
{
for (int col = 0; col < 24*40; col++)
PageAtrb[col] = atr;
p = PageChar + 40;
for (int row = 1; row < 12; row++)
{
*p++ = number2char(row); /* first column: number (0-9, A-..) */
for (int col = 1; col < 40; col += 3)
{
int d = CDVDTeletextTools::deh24(p);
if (d < 0)
{
memcpy(p, "???", 3);
p += 3;
}
else
{
*p++ = number2char((d >> 6) & 0x1f); /* mode */
*p++ = number2char(d & 0x3f); /* address */
*p++ = number2char((d >> 11) & 0x7f); /* data */
}
}
}
return PageInfo; /* don't interpret irregular pages */
}
else if (PageInfo->function == FUNC_GDRCS || PageInfo->function == FUNC_DRCS) /* character definitions */
{
return PageInfo; /* don't interpret irregular pages */
}
else
{
int h, parityerror = 0;
for (int i = 0; i < 8; i++)
PageAtrb[i] = atr;
/* decode parity/hamming */
for (unsigned int i = 40; i < sizeof(PageChar); i++)
{
PageAtrb[i] = atr;
p = PageChar + i;
h = dehamming[*p];
if (parityerror && h != 0xFF) /* if no regular page (after any parity error) */
CDVDTeletextTools::Hex2Str((char*)p, h); /* first try dehamming */
else
{
if (*p == ' ' || deparity[*p] != ' ') /* correct parity */
*p &= 127;
else
{
parityerror = 1;
if (h != 0xFF) /* first parity error: try dehamming */
CDVDTeletextTools::Hex2Str((char*)p, h);
else
*p = ' ';
}
}
}
if (parityerror)
{
return PageInfo; /* don't interpret irregular pages */
}
}
}
int mosaic_pending,esc_pending;
/* decode */
for (int row = 0; row < ((showflof && PageInfo->p24) ? 25 : 24); row++)
{
/* start-of-row default conditions */
foreground = TXT_ColorWhite;
background = TXT_ColorBlack;
doubleheight = 0;
doublewidth = 0;
charset = previous_charset = C_G0P; // remember charset for switching back after mosaic charset was used
mosaictype = 0;
concealed = 0;
flashmode = 0;
hold = 0;
boxwin = 0;
held_mosaic = ' ';
dhset = 0;
IgnoreAtBlackBgSubst = 0;
mosaic_pending = esc_pending = 0; // we need to render at least one mosaic char if 'esc' is received immediatly after mosac charset switch on
if (boxed && memchr(&PageChar[row*40], start_box, 40) == 0)
{
foreground = TXT_ColorTransp;
background = TXT_ColorTransp;
}
for (int col = 0; col < 40; col++)
{
int index = row*40 + col;
PageAtrb[index].fg = foreground;
PageAtrb[index].bg = background;
PageAtrb[index].charset = charset;
PageAtrb[index].doubleh = doubleheight;
PageAtrb[index].doublew = (col < 39 ? doublewidth : 0);
PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
PageAtrb[index].concealed = concealed;
PageAtrb[index].flashing = flashmode;
PageAtrb[index].boxwin = boxwin;
PageAtrb[index].inverted = 0; // only relevant for Level 2.5
PageAtrb[index].underline = 0; // only relevant for Level 2.5
PageAtrb[index].diacrit = 0; // only relevant for Level 2.5
PageAtrb[index].setX26 = 0; // only relevant for Level 2.5
PageAtrb[index].setG0G2 = 0x3f; // only relevant for Level 2.5
if (PageChar[index] < ' ')
{
if (esc_pending) { // mosaic char has been rendered and we can switch charsets
charset = previous_charset;
if (charset == C_G0P)
charset = previous_charset = C_G0S;
else if (charset == C_G0S)
charset = previous_charset = C_G0P;
esc_pending = 0;
}
switch (PageChar[index])
{
case alpha_black:
case alpha_red:
case alpha_green:
case alpha_yellow:
case alpha_blue:
case alpha_magenta:
case alpha_cyan:
case alpha_white:
concealed = 0;
foreground = PageChar[index] - alpha_black + TXT_ColorBlack;
if (col == 0 && PageChar[index] == alpha_white)
PageAtrb[index].fg = TXT_ColorBlack; // indicate level 1 color change on column 0; (hack)
if ((charset!=C_G0P) && (charset!=C_G0S)) // we need to change charset to state it was before mosaic
charset = previous_charset;
break;
case flash:
flashmode = 1;
break;
case steady:
flashmode = 0;
PageAtrb[index].flashing = 0;
break;
case end_box:
boxwin = 0;
IgnoreAtBlackBgSubst = 0;
break;
case start_box:
if (!boxwin)
boxwin = 1;
break;
case normal_size:
doubleheight = 0;
doublewidth = 0;
PageAtrb[index].doubleh = doubleheight;
PageAtrb[index].doublew = doublewidth;
break;
case double_height:
if (row < 23)
{
doubleheight = 1;
dhset = 1;
}
doublewidth = 0;
break;
case double_width:
if (col < 39)
doublewidth = 1;
doubleheight = 0;
break;
case double_size:
if (row < 23)
{
doubleheight = 1;
dhset = 1;
}
if (col < 39)
doublewidth = 1;
break;
case mosaic_black:
case mosaic_red:
case mosaic_green:
case mosaic_yellow:
case mosaic_blue:
case mosaic_magenta:
case mosaic_cyan:
case mosaic_white:
concealed = 0;
foreground = PageChar[index] - mosaic_black + TXT_ColorBlack;
if ((charset==C_G0P) || (charset==C_G0S))
previous_charset=charset;
charset = mosaictype ? C_G1S : C_G1C;
mosaic_pending = 1;
break;
case conceal:
PageAtrb[index].concealed = 1;
concealed = 1;
if (!HintMode)
{
foreground = background;
PageAtrb[index].fg = foreground;
}
break;
case contiguous_mosaic:
mosaictype = 0;
if (charset == C_G1S)
{
charset = C_G1C;
PageAtrb[index].charset = charset;
}
break;
case separated_mosaic:
mosaictype = 1;
if (charset == C_G1C)
{
charset = C_G1S;
PageAtrb[index].charset = charset;
}
break;
case esc:
if (!mosaic_pending) { // if mosaic is pending we need to wait before mosaic arrives
if ((charset != C_G0P) && (charset != C_G0S)) // we need to switch to charset which was active before mosaic
charset = previous_charset;
if (charset == C_G0P)
charset = previous_charset = C_G0S;
else if (charset == C_G0S)
charset = previous_charset = C_G0P;
} else esc_pending = 1;
break;
case black_background:
background = TXT_ColorBlack;
IgnoreAtBlackBgSubst = 0;
PageAtrb[index].bg = background;
PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
break;
case new_background:
background = foreground;
if (background == TXT_ColorBlack)
IgnoreAtBlackBgSubst = 1;
else
IgnoreAtBlackBgSubst = 0;
PageAtrb[index].bg = background;
PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
break;
case hold_mosaic:
hold = 1;
break;
case release_mosaic:
hold = 2;
break;
}
/* handle spacing attributes */
if (hold && (PageAtrb[index].charset == C_G1C || PageAtrb[index].charset == C_G1S))
PageChar[index] = held_mosaic;
else
PageChar[index] = ' ';
if (hold == 2)
hold = 0;
}
else /* char >= ' ' */
{
mosaic_pending = 0; // charset will be switched next if esc_pending
/* set new held-mosaic char */
if ((charset == C_G1C || charset == C_G1S) &&
((PageChar[index]&0xA0) == 0x20))
held_mosaic = PageChar[index];
if (PageAtrb[index].doubleh)
PageChar[index + 40] = 0xFF;
}
if (!(charset == C_G1C || charset == C_G1S))
held_mosaic = ' '; /* forget if outside mosaic */
} /* for col */
/* skip row if doubleheight */
if (row < 23 && dhset)
{
for (int col = 0; col < 40; col++)
{
int index = row*40 + col;
PageAtrb[index+40].bg = PageAtrb[index].bg;
PageAtrb[index+40].fg = TXT_ColorWhite;
if (!PageAtrb[index].doubleh)
PageChar[index+40] = ' ';
PageAtrb[index+40].flashing = 0;
PageAtrb[index+40].charset = C_G0P;
PageAtrb[index+40].doubleh = 0;
PageAtrb[index+40].doublew = 0;
PageAtrb[index+40].IgnoreAtBlackBgSubst = 0;
PageAtrb[index+40].concealed = 0;
PageAtrb[index+40].flashing = 0;
PageAtrb[index+40].boxwin = PageAtrb[index].boxwin;
}
row++;
}
} /* for row */
m_txtCache->FullScrColor = TXT_ColorBlack;
if (showl25)
Eval_l25(PageChar, PageAtrb, HintMode);
/* handle Black Background Color Substitution and transparency (CLUT1#0) */
{
int o = 0;
char bitmask ;
for (int r = 0; r < 25; r++)
{
for (int c = 0; c < 40; c++)
{
bitmask = (PageAtrb[o].bg == 0x08 ? 0x08 : 0x00) | (m_txtCache->FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (PageAtrb[o].boxwin <<1) | (int)boxed;
switch (bitmask)
{
case 0x08:
case 0x0b:
if (m_txtCache->FullRowColor[r] == 0x08)
PageAtrb[o].bg = m_txtCache->FullScrColor;
else
PageAtrb[o].bg = m_txtCache->FullRowColor[r];
break;
case 0x01:
case 0x05:
case 0x09:
case 0x0a:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
PageAtrb[o].bg = TXT_ColorTransp;
break;
}
bitmask = (PageAtrb[o].fg == 0x08 ? 0x08 : 0x00) | (m_txtCache->FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (PageAtrb[o].boxwin <<1) | (int)boxed;
switch (bitmask)
{
case 0x08:
case 0x0b:
if (m_txtCache->FullRowColor[r] == 0x08)
PageAtrb[o].fg = m_txtCache->FullScrColor;
else
PageAtrb[o].fg = m_txtCache->FullRowColor[r];
break;
case 0x01:
case 0x05:
case 0x09:
case 0x0a:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
PageAtrb[o].fg = TXT_ColorTransp;
break;
}
o++;
}
}
}
return PageInfo;
}
void CTeletextDecoder::Eval_l25(unsigned char* PageChar, TextPageAttr_t *PageAtrb, bool HintMode)
{
memset(m_txtCache->FullRowColor, 0, sizeof(m_txtCache->FullRowColor));
m_txtCache->FullScrColor = TXT_ColorBlack;
m_txtCache->ColorTable = NULL;
if (!m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage])
return;
/* normal page */
if (IsDec(m_txtCache->Page))
{
unsigned char APx0, APy0, APx, APy;
TextPageinfo_t *pi = &(m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage]->pageinfo);
TextCachedPage_t *pmot = m_txtCache->astCachetable[(m_txtCache->Page & 0xf00) | 0xfe][0];
int p26Received = 0;
int BlackBgSubst = 0;
int ColorTableRemapping = 0;
m_txtCache->pop = m_txtCache->gpop = m_txtCache->drcs = m_txtCache->gdrcs = 0;
if (pi->ext)
{
TextExtData_t *e = pi->ext;
if (e->p26[0])
p26Received = 1;
if (e->p27)
{
Textp27_t *p27 = e->p27;
if (p27[0].l25)
m_txtCache->gpop = p27[0].page;
if (p27[1].l25)
m_txtCache->pop = p27[1].page;
if (p27[2].l25)
m_txtCache->gdrcs = p27[2].page;
if (p27[3].l25)
m_txtCache->drcs = p27[3].page;
}
if (e->p28Received)
{
m_txtCache->ColorTable = e->bgr;
BlackBgSubst = e->BlackBgSubst;
ColorTableRemapping = e->ColorTableRemapping;
memset(m_txtCache->FullRowColor, e->DefRowColor, sizeof(m_txtCache->FullRowColor));
m_txtCache->FullScrColor = e->DefScreenColor;
m_txtCache->NationalSubset = SetNational(e->DefaultCharset);
m_txtCache->NationalSubsetSecondary = SetNational(e->SecondCharset);
} /* e->p28Received */
}
if (!m_txtCache->ColorTable && m_txtCache->astP29[m_txtCache->Page >> 8])
{
TextExtData_t *e = m_txtCache->astP29[m_txtCache->Page >> 8];
m_txtCache->ColorTable = e->bgr;
BlackBgSubst = e->BlackBgSubst;
ColorTableRemapping = e->ColorTableRemapping;
memset(m_txtCache->FullRowColor, e->DefRowColor, sizeof(m_txtCache->FullRowColor));
m_txtCache->FullScrColor = e->DefScreenColor;
m_txtCache->NationalSubset = SetNational(e->DefaultCharset);
m_txtCache->NationalSubsetSecondary = SetNational(e->SecondCharset);
}
if (ColorTableRemapping)
{
for (int i = 0; i < 25*40; i++)
{
PageAtrb[i].fg += MapTblFG[ColorTableRemapping - 1];
if (!BlackBgSubst || PageAtrb[i].bg != TXT_ColorBlack || PageAtrb[i].IgnoreAtBlackBgSubst)
PageAtrb[i].bg += MapTblBG[ColorTableRemapping - 1];
}
}
/* determine ?pop/?drcs from MOT */
if (pmot)
{
unsigned char pmot_data[23*40];
g_application.m_pPlayer->LoadPage((m_txtCache->Page & 0xf00) | 0xfe, 0, pmot_data);
unsigned char *p = pmot_data; /* start of link data */
int o = 2 * (((m_txtCache->Page & 0xf0) >> 4) * 10 + (m_txtCache->Page & 0x0f)); /* offset of links for current page */
int opop = p[o] & 0x07; /* index of POP link */
int odrcs = p[o+1] & 0x07; /* index of DRCS link */
unsigned char obj[3*4*4]; /* types* objects * (triplet,packet,subp,high) */
unsigned char type,ct, tstart = 4*4;
memset(obj,0,sizeof(obj));
if (p[o] & 0x08) /* GPOP data used */
{
if (!m_txtCache->gpop || !(p[18*40] & 0x08)) /* no p27 data or higher prio of MOT link */
{
m_txtCache->gpop = ((p[18*40] << 8) | (p[18*40+1] << 4) | p[18*40+2]) & 0x7ff;
if ((m_txtCache->gpop & 0xff) == 0xff)
m_txtCache->gpop = 0;
else
{
if (m_txtCache->gpop < 0x100)
m_txtCache->gpop += 0x800;
if (!p26Received)
{
ct = 2;
while (ct)
{
ct--;
type = (p[18*40+5] >> 2*ct) & 0x03;
if (type == 0) continue;
obj[(type-1)*(tstart)+ct*4 ] = 3 * ((p[18*40+7+ct*2] >> 1) & 0x03) + type; //triplet
obj[(type-1)*(tstart)+ct*4+1] = ((p[18*40+7+ct*2] & 0x08) >> 3) + 1 ; //packet
obj[(type-1)*(tstart)+ct*4+2] = p[18*40+6+ct*2] & 0x0f ; //subp
obj[(type-1)*(tstart)+ct*4+3] = p[18*40+7+ct*2] & 0x01 ; //high
}
}
}
}
}
if (opop) /* POP data used */
{
opop = 18*40 + 10*opop; /* offset to POP link */
if (!m_txtCache->pop || !(p[opop] & 0x08)) /* no p27 data or higher prio of MOT link */
{
m_txtCache->pop = ((p[opop] << 8) | (p[opop+1] << 4) | p[opop+2]) & 0x7ff;
if ((m_txtCache->pop & 0xff) == 0xff)
m_txtCache->pop = 0;
else
{
if (m_txtCache->pop < 0x100)
m_txtCache->pop += 0x800;
if (!p26Received)
{
ct = 2;
while (ct)
{
ct--;
type = (p[opop+5] >> 2*ct) & 0x03;
if (type == 0) continue;
obj[(type-1)*(tstart)+(ct+2)*4 ] = 3 * ((p[opop+7+ct*2] >> 1) & 0x03) + type; //triplet
obj[(type-1)*(tstart)+(ct+2)*4+1] = ((p[opop+7+ct*2] & 0x08) >> 3) + 1 ; //packet
obj[(type-1)*(tstart)+(ct+2)*4+2] = p[opop+6+ct*2] ; //subp
obj[(type-1)*(tstart)+(ct+2)*4+3] = p[opop+7+ct*2] & 0x01 ; //high
}
}
}
}
}
// eval default objects in correct order
for (int i = 0; i < 12; i++)
{
if (obj[i*4] != 0)
{
APx0 = APy0 = APx = APy = m_txtCache->tAPx = m_txtCache->tAPy = 0;
Eval_NumberedObject(i % 4 > 1 ? m_txtCache->pop : m_txtCache->gpop, obj[i*4+2], obj[i*4+1], obj[i*4], obj[i*4+3], &APx, &APy, &APx0, &APy0, PageChar, PageAtrb);
}
}
if (p[o+1] & 0x08) /* GDRCS data used */
{
if (!m_txtCache->gdrcs || !(p[20*40] & 0x08)) /* no p27 data or higher prio of MOT link */
{
m_txtCache->gdrcs = ((p[20*40] << 8) | (p[20*40+1] << 4) | p[20*40+2]) & 0x7ff;
if ((m_txtCache->gdrcs & 0xff) == 0xff)
m_txtCache->gdrcs = 0;
else if (m_txtCache->gdrcs < 0x100)
m_txtCache->gdrcs += 0x800;
}
}
if (odrcs) /* DRCS data used */
{
odrcs = 20*40 + 4*odrcs; /* offset to DRCS link */
if (!m_txtCache->drcs || !(p[odrcs] & 0x08)) /* no p27 data or higher prio of MOT link */
{
m_txtCache->drcs = ((p[odrcs] << 8) | (p[odrcs+1] << 4) | p[odrcs+2]) & 0x7ff;
if ((m_txtCache->drcs & 0xff) == 0xff)
m_txtCache->drcs = 0;
else if (m_txtCache->drcs < 0x100)
m_txtCache->drcs += 0x800;
}
}
if (m_txtCache->astCachetable[m_txtCache->gpop][0])
m_txtCache->astCachetable[m_txtCache->gpop][0]->pageinfo.function = FUNC_GPOP;
if (m_txtCache->astCachetable[m_txtCache->pop][0])
m_txtCache->astCachetable[m_txtCache->pop][0]->pageinfo.function = FUNC_POP;
if (m_txtCache->astCachetable[m_txtCache->gdrcs][0])
m_txtCache->astCachetable[m_txtCache->gdrcs][0]->pageinfo.function = FUNC_GDRCS;
if (m_txtCache->astCachetable[m_txtCache->drcs][0])
m_txtCache->astCachetable[m_txtCache->drcs][0]->pageinfo.function = FUNC_DRCS;
} /* if mot */
/* evaluate local extension data from p26 */
if (p26Received)
{
APx0 = APy0 = APx = APy = m_txtCache->tAPx = m_txtCache->tAPy = 0;
Eval_Object(13 * (23-2 + 2), m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage], &APx, &APy, &APx0, &APy0, OBJ_ACTIVE, &PageChar[40], PageChar, PageAtrb); /* 1st triplet p26/0 */
}
{
int o = 0;
for (int r = 0; r < 25; r++)
{
for (int c = 0; c < 40; c++)
{
if (BlackBgSubst && PageAtrb[o].bg == TXT_ColorBlack && !(PageAtrb[o].IgnoreAtBlackBgSubst))
{
if (m_txtCache->FullRowColor[r] == 0x08)
PageAtrb[o].bg = m_txtCache->FullScrColor;
else
PageAtrb[o].bg = m_txtCache->FullRowColor[r];
}
o++;
}
}
}
if (!HintMode)
{
for (int i = 0; i < 25*40; i++)
{
if (PageAtrb[i].concealed) PageAtrb[i].fg = PageAtrb[i].bg;
}
}
} /* is_dec(page) */
}
/* dump interpreted object data to stdout */
/* in: 18 bit object data */
/* out: termination info, >0 if end of object */
void CTeletextDecoder::Eval_Object(int iONr, TextCachedPage_t *pstCachedPage,
unsigned char *pAPx, unsigned char *pAPy,
unsigned char *pAPx0, unsigned char *pAPy0,
tObjType ObjType, unsigned char* pagedata, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
{
int iOData;
int iONr1 = iONr + 1; /* don't terminate after first triplet */
unsigned char drcssubp=0, gdrcssubp=0;
signed char endcol = -1; /* last column to which to extend attribute changes */
TextPageAttr_t attrPassive = { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}; /* current attribute for passive objects */
do
{
iOData = iTripletNumber2Data(iONr, pstCachedPage, pagedata); /* get triplet data, next triplet */
if (iOData < 0) /* invalid number, not cached, or hamming error: terminate */
break;
if (endcol < 0)
{
if (ObjType == OBJ_ACTIVE)
{
endcol = 40;
}
else if (ObjType == OBJ_ADAPTIVE) /* search end of line */
{
for (int i = iONr; i <= 506; i++)
{
int iTempOData = iTripletNumber2Data(i, pstCachedPage, pagedata); /* get triplet data, next triplet */
int iAddress = (iTempOData ) & 0x3f;
int iMode = (iTempOData >> 6) & 0x1f;
//int iData = (iTempOData >> 11) & 0x7f;
if (iTempOData < 0 || /* invalid number, not cached, or hamming error: terminate */
(iAddress >= 40 /* new row: row address and */
&& (iMode == 0x01 || /* Full Row Color or */
iMode == 0x04 || /* Set Active Position */
(iMode >= 0x15 && iMode <= 0x17) || /* Object Definition */
iMode == 0x17))) /* Object Termination */
break;
if (iAddress < 40 && iMode != 0x06)
endcol = iAddress;
}
}
}
iONr++;
}
while (0 == Eval_Triplet(iOData, pstCachedPage, pAPx, pAPy, pAPx0, pAPy0, &drcssubp, &gdrcssubp, &endcol, &attrPassive, pagedata, PageChar, PageAtrb) || iONr1 == iONr); /* repeat until termination reached */
}
void CTeletextDecoder::Eval_NumberedObject(int p, int s, int packet, int triplet, int high,
unsigned char *pAPx, unsigned char *pAPy,
unsigned char *pAPx0, unsigned char *pAPy0, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
{
if (!packet || 0 == m_txtCache->astCachetable[p][s])
return;
unsigned char pagedata[23*40];
g_application.m_pPlayer->LoadPage(p, s,pagedata);
int idata = CDVDTeletextTools::deh24(pagedata + 40*(packet-1) + 1 + 3*triplet);
int iONr;
if (idata < 0) /* hamming error: ignore triplet */
return;
if (high)
iONr = idata >> 9; /* triplet number of odd object data */
else
iONr = idata & 0x1ff; /* triplet number of even object data */
if (iONr <= 506)
{
Eval_Object(iONr, m_txtCache->astCachetable[p][s], pAPx, pAPy, pAPx0, pAPy0, (tObjType)(triplet % 3),pagedata, PageChar, PageAtrb);
}
}
int CTeletextDecoder::Eval_Triplet(int iOData, TextCachedPage_t *pstCachedPage,
unsigned char *pAPx, unsigned char *pAPy,
unsigned char *pAPx0, unsigned char *pAPy0,
unsigned char *drcssubp, unsigned char *gdrcssubp,
signed char *endcol, TextPageAttr_t *attrPassive, unsigned char* pagedata, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
{
int iAddress = (iOData ) & 0x3f;
int iMode = (iOData >> 6) & 0x1f;
int iData = (iOData >> 11) & 0x7f;
if (iAddress < 40) /* column addresses */
{
int offset; /* offset to PageChar and PageAtrb */
if (iMode != 0x06)
*pAPx = iAddress; /* new Active Column */
offset = (*pAPy0 + *pAPy) * 40 + *pAPx0 + *pAPx; /* offset to PageChar and PageAtrb */
switch (iMode)
{
case 0x00:
if (0 == (iData>>5))
{
int newcolor = iData & 0x1f;
if (*endcol < 0) /* passive object */
attrPassive->fg = newcolor;
else if (*endcol == 40) /* active object */
{
TextPageAttr_t *p = &PageAtrb[offset];
int oldcolor = (p)->fg; /* current color (set-after) */
int c = *pAPx0 + *pAPx; /* current column absolute */
do
{
p->fg = newcolor;
p++;
c++;
} while (c < 40 && p->fg == oldcolor); /* stop at change by level 1 page */
}
else /* adaptive object */
{
TextPageAttr_t *p = &PageAtrb[offset];
int c = *pAPx; /* current column relative to object origin */
do
{
p->fg = newcolor;
p++;
c++;
} while (c <= *endcol);
}
}
break;
case 0x01:
if (iData >= 0x20)
{
PageChar[offset] = iData;
if (*endcol < 0) /* passive object */
{
attrPassive->charset = C_G1C; /* FIXME: separated? */
PageAtrb[offset] = *attrPassive;
}
else if (PageAtrb[offset].charset != C_G1S)
PageAtrb[offset].charset = C_G1C; /* FIXME: separated? */
}
break;
case 0x02:
case 0x0b:
PageChar[offset] = iData;
if (*endcol < 0) /* passive object */
{
attrPassive->charset = C_G3;
PageAtrb[offset] = *attrPassive;
}
else
PageAtrb[offset].charset = C_G3;
break;
case 0x03:
if (0 == (iData>>5))
{
int newcolor = iData & 0x1f;
if (*endcol < 0) /* passive object */
attrPassive->bg = newcolor;
else if (*endcol == 40) /* active object */
{
TextPageAttr_t *p = &PageAtrb[offset];
int oldcolor = (p)->bg; /* current color (set-after) */
int c = *pAPx0 + *pAPx; /* current column absolute */
do
{
p->bg = newcolor;
if (newcolor == TXT_ColorBlack)
p->IgnoreAtBlackBgSubst = 1;
p++;
c++;
} while (c < 40 && p->bg == oldcolor); /* stop at change by level 1 page */
}
else /* adaptive object */
{
TextPageAttr_t *p = &PageAtrb[offset];
int c = *pAPx; /* current column relative to object origin */
do
{
p->bg = newcolor;
if (newcolor == TXT_ColorBlack)
p->IgnoreAtBlackBgSubst = 1;
p++;
c++;
} while (c <= *endcol);
}
}
break;
case 0x06:
/* ignore */
break;
case 0x07:
if ((iData & 0x60) != 0) break; // reserved data field
if (*endcol < 0) /* passive object */
{
attrPassive->flashing=iData & 0x1f;
PageAtrb[offset] = *attrPassive;
}
else
PageAtrb[offset].flashing=iData & 0x1f;
break;
case 0x08:
if (*endcol < 0) /* passive object */
{
attrPassive->setG0G2=iData & 0x3f;
PageAtrb[offset] = *attrPassive;
}
else
PageAtrb[offset].setG0G2=iData & 0x3f;
break;
case 0x09:
PageChar[offset] = iData;
if (*endcol < 0) /* passive object */
{
attrPassive->charset = C_G0P; /* FIXME: secondary? */
attrPassive->setX26 = 1;
PageAtrb[offset] = *attrPassive;
}
else
{
PageAtrb[offset].charset = C_G0P; /* FIXME: secondary? */
PageAtrb[offset].setX26 = 1;
}
break;
// case 0x0b: (see 0x02)
case 0x0c:
{
int conc = (iData & 0x04);
int inv = (iData & 0x10);
int dw = (iData & 0x40 ?1:0);
int dh = (iData & 0x01 ?1:0);
int sep = (iData & 0x20);
int bw = (iData & 0x02 ?1:0);
if (*endcol < 0) /* passive object */
{
if (conc)
{
attrPassive->concealed = 1;
attrPassive->fg = attrPassive->bg;
}
attrPassive->inverted = (inv ? 1- attrPassive->inverted : 0);
attrPassive->doubleh = dh;
attrPassive->doublew = dw;
attrPassive->boxwin = bw;
if (bw) attrPassive->IgnoreAtBlackBgSubst = 0;
if (sep)
{
if (attrPassive->charset == C_G1C)
attrPassive->charset = C_G1S;
else
attrPassive->underline = 1;
}
else
{
if (attrPassive->charset == C_G1S)
attrPassive->charset = C_G1C;
else
attrPassive->underline = 0;
}
}
else
{