summaryrefslogtreecommitdiff
path: root/txtrender.c
diff options
context:
space:
mode:
authorTobias Grimm <tobias@e-tobi.loc>2008-12-02 21:00:33 +0100
committerTobias Grimm <tobias@e-tobi.loc>2008-12-02 21:00:33 +0100
commitb451fdb5a36c0f749d63d53165cdf4e84a8f476a (patch)
treeaa3b6548ea52ef133028098c8fbaebbe47ed8a5d /txtrender.c
downloadvdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.gz
vdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.bz2
Initial commit of version 0.5.1v0.5.1release/v0.5.1
Diffstat (limited to 'txtrender.c')
-rw-r--r--txtrender.c543
1 files changed, 543 insertions, 0 deletions
diff --git a/txtrender.c b/txtrender.c
new file mode 100644
index 0000000..f4b27e6
--- /dev/null
+++ b/txtrender.c
@@ -0,0 +1,543 @@
+/***************************************************************************
+ * *
+ * txtrender.c - Teletext display abstraction and teletext code *
+ * renderer *
+ * *
+ * 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 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#include <strings.h>
+#include "txtrender.h"
+
+
+// Font tables
+
+// teletext uses 7-bit numbers to identify a font set.
+// There are three font sets involved:
+// Primary G0, Secondary G0, and G2 font set.
+
+// Font tables are organized in blocks of 8 fonts:
+
+enumCharsets FontBlockG0_0000[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0_PT_ES,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_LATIN_G0
+};
+
+enumCharsets FontBlockG2Latin[8]={
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2
+};
+
+enumCharsets FontBlockG0_0001[8] = {
+ CHARSET_LATIN_G0_PL,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_LATIN_G0
+};
+
+enumCharsets FontBlockG0_0010[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0_PT_ES,
+ CHARSET_LATIN_G0_TR,
+ CHARSET_LATIN_G0
+};
+
+
+enumCharsets FontBlockG0_0011[8] = {
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_SR_HR_SL,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_RO
+};
+
+enumCharsets FontBlockG0_0100[8] = {
+ CHARSET_CYRILLIC_G0_SR_HR,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_EE,
+ CHARSET_LATIN_G0_LV_LT,
+ CHARSET_CYRILLIC_G0_RU_BG,
+ CHARSET_CYRILLIC_G0_UK,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_INVALID
+};
+
+enumCharsets FontBlockG2_0100[8] = {
+ CHARSET_CYRILLIC_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_CYRILLIC_G2,
+ CHARSET_CYRILLIC_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_INVALID
+};
+
+enumCharsets FontBlockG0_0110[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G0_TR,
+ CHARSET_GREEK_G0
+};
+
+enumCharsets FontBlockG2_0110[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G2,
+ CHARSET_GREEK_G2
+};
+
+enumCharsets FontBlockG0_1000[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G0
+};
+
+enumCharsets FontBlockG2_1000[8] = {
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2
+};
+
+enumCharsets FontBlockG0_1010[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_HEBREW_G0,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G0,
+};
+
+enumCharsets FontBlockG2_1010[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+};
+
+enumCharsets FontBlockInvalid[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID
+};
+
+
+
+// The actual font table definition:
+// Split the 7-bit number into upper 4 and lower 3 bits,
+// use upper 4 bits for outer array,
+// use lower 3 bits for inner array
+
+struct structFontBlock {
+ enumCharsets *G0Block;
+ enumCharsets *G2Block;
+};
+
+structFontBlock FontTable[16] = {
+ { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block
+ { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block
+ { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block
+ { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block
+ { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block
+ { FontBlockInvalid, FontBlockInvalid }, // 0101 block
+ { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block
+ { FontBlockInvalid, FontBlockInvalid }, // 0111 block
+ { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1001 block
+ { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1011 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1100 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1101 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1110 block
+ { FontBlockInvalid, FontBlockInvalid } // 1111 block
+};
+
+inline enumCharsets GetG0Charset(int codepage) {
+ return FontTable[codepage>>3].G0Block[codepage&7];
+}
+inline enumCharsets GetG2Charset(int codepage) {
+ return FontTable[codepage>>3].G2Block[codepage&7];
+}
+
+
+cRenderPage::cRenderPage() {
+ Dirty=false;
+ DirtyAll=false;
+
+ // Todo: make this configurable
+ FirstG0CodePage=0;
+ SecondG0CodePage=0;
+}
+
+enum enumSizeMode {
+ // Possible size modifications of characters
+ sizeNormal,
+ sizeDoubleWidth,
+ sizeDoubleHeight,
+ sizeDoubleSize
+};
+
+/*
+// Debug only: List of teletext spacing code short names
+const char *(names[0x20])={
+ "AlBk","AlRd","AlGr","AlYl","AlBl","AlMg","AlCy","AlWh",
+ "Flsh","Stdy","EnBx","StBx","SzNo","SzDh","SzDw","SzDs",
+ "MoBk","MoRd","MoGr","MoYl","MoBl","MoMg","MoCy","MoWh",
+ "Conc","GrCn","GrSp","ESC", "BkBl","StBk","HoMo","ReMo"};
+*/
+
+void cRenderPage::ReadTeletextHeader(unsigned char *Header) {
+ // Format of buffer:
+ // 0 String "VTXV4"
+ // 5 always 0x01
+ // 6 magazine number
+ // 7 page number
+ // 8 flags
+ // 9 lang
+ // 10 always 0x00
+ // 11 always 0x00
+ // 12 teletext data, 40x24 bytes
+ // Format of flags:
+ // 0x80 C4 - Erase page
+ // 0x40 C5 - News flash
+ // 0x20 C6 - Subtitle
+ // 0x10 C7 - Suppress Header
+ // 0x08 C8 - Update
+ // 0x04 C9 - Interrupt Sequence
+ // 0x02 C9 (Bug?)
+ // 0x01 C11 - Magazine Serial mode
+
+ Flags=Header[8];
+ Lang=Header[9];
+}
+
+
+void cRenderPage::RenderTeletextCode(unsigned char *PageCode) {
+ int x,y;
+ bool EmptyNextLine=false;
+ // Skip one line, in case double height chars were/will be used
+
+ // Get code pages:
+ int LocalG0CodePage=(FirstG0CodePage & 0x78)
+ | ((Lang & 0x04)>>2) | (Lang & 0x02) | ((Lang & 0x01)<<2);
+
+ enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);
+ enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);
+ // Reserved for later use:
+ // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);
+
+ for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {
+ // Start of line: Set start of line defaults
+
+ // Hold Mosaics mode: Remember last mosaic char/charset
+ // for next spacing code
+ bool HoldMosaics=false;
+ unsigned char HoldMosaicChar=' ';
+ enumCharsets HoldMosaicCharset=FirstG0;
+
+ enumSizeMode Size=sizeNormal;
+ // Font size modification
+ bool SecondCharset=false;
+ // Use primary or secondary G0 charset
+ bool GraphicCharset=false;
+ // Graphics charset used?
+ bool SeparateGraphics=false;
+ // Use separated vs. contiguous graphics charset
+ bool NoNextChar=false;
+ // Skip display of next char, for double-width
+ EmptyNextLine=false;
+ // Skip next line, for double-height
+
+ cTeletextChar c;
+ // auto.initialized to everything off
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(FirstG0);
+
+ if (y==0 && (Flags&0x10)) {
+ c.SetBoxedOut(true);
+ }
+ if (Flags&0x60) {
+ c.SetBoxedOut(true);
+ }
+
+ // Pre-scan for double-height and double-size codes
+ for (x=0;x<40;x++) {
+ if (y==0 && x<8) x=8;
+ if ((PageCode[x+40*y] & 0x7f)==0x0D || (PageCode[x+40*y] & 0x7f)==0x0F)
+ EmptyNextLine=true;
+ }
+
+ // Move through line
+ for (x=0;x<40;x++) {
+ unsigned char ttc=PageCode[x+40*y] & 0x7f;
+ // skip parity check
+
+ if (y==0 && x<8) continue;
+ // no displayable data here...
+
+/* // Debug only: Output line data and spacing codes
+ if (y==6) {
+ if (ttc<0x20)
+ printf("%s ",names[ttc]);
+ else
+ printf("%02x ",ttc);
+ if (x==39) printf("\n");
+ }
+*/
+
+ // Handle all 'Set-At' spacing codes
+ switch (ttc) {
+ case 0x09: // Steady
+ c.SetBlink(false);
+ break;
+ case 0x0C: // Normal Size
+ if (Size!=sizeNormal) {
+ Size=sizeNormal;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x18: // Conceal
+ c.SetConceal(true);
+ break;
+ case 0x19: // Contiguous Mosaic Graphics
+ SeparateGraphics=false;
+ if (GraphicCharset)
+ c.SetCharset(CHARSET_GRAPHICS_G1);
+ break;
+ case 0x1A: // Separated Mosaic Graphics
+ SeparateGraphics=true;
+ if (GraphicCharset)
+ c.SetCharset(CHARSET_GRAPHICS_G1_SEP);
+ break;
+ case 0x1C: // Black Background
+ c.SetBGColor(ttcBlack);
+ break;
+ case 0x1D: // New Background
+ c.SetBGColor(c.GetFGColor());
+ break;
+ case 0x1E: // Hold Mosaic
+ HoldMosaics=true;
+ break;
+ }
+
+ // temporary copy of character data:
+ cTeletextChar c2=c;
+ // c2 will be text character or space character or hold mosaic
+ // c2 may also have temporary flags or charsets
+
+ if (ttc<0x20) {
+ // Spacing code, display space or hold mosaic
+ if (HoldMosaics) {
+ c2.SetChar(HoldMosaicChar);
+ c2.SetCharset(HoldMosaicCharset);
+ } else {
+ c2.SetChar(' ');
+ }
+ } else {
+ // Character code
+ c2.SetChar(ttc);
+ if (GraphicCharset) {
+ if (ttc&0x20) {
+ // real graphics code, remember for HoldMosaics
+ HoldMosaicChar=ttc;
+ HoldMosaicCharset=c.GetCharset();
+ } else {
+ // invalid code, pass-through to G0
+ c2.SetCharset(SecondCharset?SecondG0:FirstG0);
+ }
+ }
+ }
+
+ // Handle double-height and double-width extremes
+ if (y>=23) {
+ if (Size==sizeDoubleHeight) Size=sizeNormal;
+ if (Size==sizeDoubleSize) Size=sizeDoubleWidth;
+ }
+ if (x>=38) {
+ if (Size==sizeDoubleWidth) Size=sizeNormal;
+ if (Size==sizeDoubleSize) Size=sizeDoubleHeight;
+ }
+
+ // Now set character code
+
+ if (NoNextChar) {
+ // Suppress this char due to double width last char
+ NoNextChar=false;
+ } else {
+ switch (Size) {
+ case sizeNormal:
+ // Normal sized
+ SetChar(x,y,c2);
+ if (EmptyNextLine && y<23) {
+ // Clean up next line
+ SetChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ }
+ break;
+ case sizeDoubleWidth:
+ // Double width
+ SetChar(x,y,c2.ToDblWidth(dblw_Left));
+ SetChar(x+1,y,c2.ToDblWidth(dblw_Right));
+ if (EmptyNextLine && y<23) {
+ // Clean up next line
+ SetChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ SetChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ }
+ NoNextChar=true;
+ break;
+ case sizeDoubleHeight:
+ // Double height
+ SetChar(x,y,c2.ToDblHeight(dblh_Top));
+ SetChar(x,y+1,c2.ToDblHeight(dblh_Bottom));
+ break;
+ case sizeDoubleSize:
+ // Double Size
+ SetChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left ));
+ SetChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right));
+ SetChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));
+ SetChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));
+ NoNextChar=true;
+ break;
+ }
+ }
+
+ // Handle all 'Set-After' spacing codes
+ switch (ttc) {
+ case 0x00 ... 0x07: // Set FG color
+ if (GraphicCharset) {
+ // Actual switch from graphics charset
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ c.SetFGColor((enumTeletextColor)ttc);
+ c.SetCharset(SecondCharset?SecondG0:FirstG0);
+ GraphicCharset=false;
+ c.SetConceal(false);
+ break;
+ case 0x08: // Flash
+ c.SetBlink(true);
+ break;
+ case 0x0A: // End Box
+ c.SetBoxedOut(true);
+ break;
+ case 0x0B: // Start Box
+ c.SetBoxedOut(false);
+ break;
+ case 0x0D: // Double Height
+ if (Size!=sizeDoubleHeight) {
+ Size=sizeDoubleHeight;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x0E: // Double Width
+ if (Size!=sizeDoubleWidth) {
+ Size=sizeDoubleWidth;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x0F: // Double Size
+ if (Size!=sizeDoubleSize) {
+ Size=sizeDoubleSize;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x10 ... 0x17: // Mosaic FG Color
+ if (!GraphicCharset) {
+ // Actual switch to graphics charset
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ c.SetFGColor((enumTeletextColor)(ttc-0x10));
+ c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);
+ GraphicCharset=true;
+ c.SetConceal(false);
+ break;
+ case 0x1B: // ESC Switch
+ SecondCharset=!SecondCharset;
+ if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);
+ break;
+ case 0x1F: // Release Mosaic
+ HoldMosaics=false;
+ break;
+ }
+ } // end for x
+ } // end for y
+
+ for (x=0;x<40;x++) {
+ // Clean out last line
+ cTeletextChar c;
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(FirstG0);
+ c.SetChar(' ');
+ if (Flags&0x60) {
+ c.SetBoxedOut(true);
+ }
+ SetChar(x,24,c);
+ }
+}
+
+