From b451fdb5a36c0f749d63d53165cdf4e84a8f476a Mon Sep 17 00:00:00 2001 From: Tobias Grimm Date: Tue, 2 Dec 2008 21:00:33 +0100 Subject: Initial commit of version 0.5.1 --- COPYING | 340 ++++++ HISTORY | 207 ++++ Makefile | 86 ++ README | 98 ++ README.DE | 86 ++ display.c | 240 ++++ display.h | 131 +++ displaybase.c | 507 +++++++++ displaybase.h | 287 +++++ i18n.c | 445 ++++++++ i18n.h | 16 + menu.c | 681 ++++++++++++ menu.h | 82 ++ osdteletext.c | 481 ++++++++ setup.h | 65 ++ tables.h | 112 ++ txtfont.c | 3371 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ txtfont.h | 14 + txtrecv.c | 884 +++++++++++++++ txtrecv.h | 204 ++++ txtrender.c | 543 ++++++++++ txtrender.h | 311 ++++++ 22 files changed, 9191 insertions(+) create mode 100644 COPYING create mode 100644 HISTORY create mode 100644 Makefile create mode 100644 README create mode 100644 README.DE create mode 100644 display.c create mode 100644 display.h create mode 100644 displaybase.c create mode 100644 displaybase.h create mode 100644 i18n.c create mode 100644 i18n.h create mode 100644 menu.c create mode 100644 menu.h create mode 100644 osdteletext.c create mode 100644 setup.h create mode 100644 tables.h create mode 100644 txtfont.c create mode 100644 txtfont.h create mode 100644 txtrecv.c create mode 100644 txtrecv.h create mode 100644 txtrender.c create mode 100644 txtrender.h diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..295c5c1 --- /dev/null +++ b/HISTORY @@ -0,0 +1,207 @@ +VDR Plugin 'teletextosd' Revision History +----------------------------------------- + +2005-08-16: version 0.5.1 + +- show page if it was initially not found + but is received later + (suggested by Luca Olivetti) +- added timeout for user inactivity after + which the plugin is closed. Without timeout the plugin would + prevent VDR's auto-shutdown mechanism if it remains open. + The value is the same as VDR's min user inactivity + setup option. + (suggested by Peter Bieringer) +- fixed gcc4 warnings + (thanks to Ville Skyttä) +- updated Finnish translation + (thanks to Rolf Ahrenberg) +- added command line parameter documentation + to READMEs +- added /var/cache/vdr/osdteletext to the list of recommended + cache directories + (suggested by Ville Skyttä) + +2005-04-21: version 0.5 + + Udo Richter: +- font subsystem now supports Teletext level 1. + Fonts are provided for English, German, French, + Italian, Spanish, Portuguese, Swedish and Finnish. + The correct font is chosen automatically. +- support for "boxed mode" (newstickers, subtitles): + in 4Bpp mode the area not covered by the box + will be completely transparent +- OSD can now be aligned on screen: + - in horizontal alignment mode, 0 means on the left, + 50 in the center and 100 on the right + - in vertical alignment mode, 0 means at the top, + 50 in the center and 100 at the bottom + - default is central alignment +- changed palette system, no longer depending on + order of indexing +- fixed compilation failure with gcc 2.95 +- changed OSD minimum size from 480x324 to 320x250 +- some bugfixes and comments in txtrecv.c + Marcel Wiesweg: +- avoid crash and improve behavior when an + invalid channel number is entered + +2005-03-30: version 0.5-pre1 + + Udo Richter: +- extensive rewrite of display code +- removed display.*, txtbitmap.*, colormapping.h +- added txtrender.*, displaybase.*, display.* +- menu.c adapted to new display engine +- speed improvements by incremental drawing +- strict adherence to standard + +2005-03-21: version 0.4.9-inofficial + +- rewrite of scaling and drawing code, better scaling + algorithm, removed inefficient double painting. + Increases speed by a factor of 4. (Udo Richter) +- minor fixes for pagenumber, channel number and clock + fields to minimize overdrawing (Rolf Ahrenberg) +- fix for graphical errors if normal characters are + introduced after double high ones (Rolf Ahrenberg) +- fix in receiving code to make osdteletext work + with some Swedish channels (thanks to Magnus Andersson) +- pseudo target in Makefile allows a simple "make". + Previously, this would fail and you needed "make all" + +2005-03-03: version 0.4.2 + +- fixes for double-high characters, scaling and localization + (thanks to Rolf Ahrenberg for his patch edition) +- adapted to VDR API >= 1.3.18, reentrancy fixes +- added Spanish and Catalan translation + (thanks to Luca Olivetti) +- create stored files with 644 permissions + (suggested by Andreas Brachold) + +2004-09-21: version 0.4.1 + +- fixed problem with undefined file permissions + of created files (thanks to whoever created the patch) +- fixed hexadecimal/decimal misinterpretation for "Jump to" + key bindings (thanks to Peter Bieringer for pointing this out) +- cosmetic change: key Left when entering channel number + now resets the cursor by one position, other keys stop + entering of page number + +2004-06-18: version 0.4 + +- ported to VDR 1.3/1.4 series (>=1.3.8 now required) + This mostly involved changes in the OSD graphics code, +- now supports OSDs with color depth of 3 + (thanks to Sascha Volkenandt) +- rewrote the storage system: + - cache directory is now configurable (option -d) + Default value is still /vtx to allow seamless migration, + but /tmp/vtx is recommended (conforms to LSB etc.) + - changed the default file format: Now more than one + page is stored in one file. On filesystems that depend + on a blocksize the increases storage efficiency. + For tmpfs the improvement factor is approx. 4. + - The old system is still available via a + command line option (though it now uses a slightly + different naming) + - when no more space is available on disk + or a specified number of harddisk space is exceeded + (option -n) the folder least recently modified + will be deleted. + On exit, all files will be deleted, i.e. + (!) on exit, all files with suffix .vtx + below the storage directory will be deleted + - the option -r is now obsolete (will be ignored) + option -R/--no-receive is deprecated +- code cleanups, removed broken or unused code +- fixed quite a few bugs +- Added Russian translation (thanks to Vyacheslav Dikonov) + +2003-12-2: version 0.3.2 + +- receiver now uses a ring buffer and a thread to reduce + time spent in Receive() function, thus delaying VDR's + receiver thread (several people reported problems + with bitstreamout - thanks to Christian Jacobsen + and Dr. Werner Fink) +- fixed and improved the newly introduced receiver thread + (thanks to Dr. Werner Fink) +- fixed a bug that if there is a double high title on a page, + the last line on that page will be missing + (fixed by Rolf Ahrenberg) +- fixed Finnish translation (thanks to Rolf Ahrenberg) +- added Italian translation (thanks to "kikko77") +- fixed bug that you could not enter 0 when switching + channel (thanks to Dietmar Hilbrich) + +2003-04-28: version 0.3.1 + +- added support for DXR3 systems. Patches contributed by Kai Moeller + and Sascha Volkenandt, thanks to them. +- the "0" if pressed as first digit now switches between current + and last page (as VDR does it with channels) +- fixed autosuspend thread + +2003-04-03: version 0.3 + +- fixed two serious memory leaks, thanks to Martin Pley +- added feature to automatically update the page if it changed. +- moved color definitions to colormapping.h +- made width and height configurable, independent from, but with the same + mechanism as VDR +- made setup menu items dynamic, i.e. the "Page Number" entries are hidden + when "Jump to..." is not selected +- Experimental: added option to suspend the receiving automatically + for 5min after 30s. This may enable you to use your TV set's + teletext decoder if you like to. (patch to VDR needed) +- Experimental: added an action to immediately suspend receiving, + respectively reenable it +- added an action to switch the background color between the value + you configured in the setup and black +- improved color handling when foreground and background + color are the same, thanks to Martin Pley +- fixed small bug in ChangePageRelative, thanks to Martin Pley +- improvements in page switching, thanks to Martin Pley +- rewrote parts of the README +- added a German README.DE +- several fixes and code clean-ups + + + +2003-02-26: version 0.2.1 + +- fixed two compiling problems with gcc versions other than 3.2 + (asprintf, ) +- included Finnish translations, thanks to Lauri Tischler +- improved Makefile, now uses install instead of mkdir/cp + +2003-02-15: version 0.2 + +- Copied code to receive and save teletext data from original teletext plugin. + (appreciating Peter Seyringer's great work) +- added command line option to enable the receiving code +- added setup options to make key bindings fully configurable. + For each key you can choose between the three actions "Zoom", "Half page" or + "Switch channel" or use it to jump to a page +- added setup option to make background transparency configurable + (0...255, VDR's default value being 127) +- included Emil Naepflein's patch to improve changing pages relatively +- added feature to view saved pages of other channels than the current + ("Switch Channel"). Last pages are remembered over channel switching. +- fixed bug when the upper half of a page was not automatically shown + when using the number keys +- page and channel numbers now persist when returning to VDR +- added clock which can regularly be updated. + (the clock shows the system time, which may definitely be different + from the time broadcast via teletext) +- added setup option to enable clock +- now copies README to ../../man, as Reinhard Walter Buchner suggested + + +2003-02-05: Version 0.1 + +- Initial revision. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1e0a0ac --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id$ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = osdteletext + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: + +OPTLEVEL ?= 2 +CXXFLAGS = -O$(OPTLEVEL) -g -Wall -Woverloaded-virtual -fPIC -DPIC + +### The directory environment: + +DVBDIR = ../../../../DVB +VDRDIR = ../../.. +LIBDIR = ../../lib +TMPDIR = /tmp + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR (taken from VDR's "config.h"): + +VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -D_GNU_SOURCE + +### The object files (add further files here): + +OBJS = $(PLUGIN).o menu.o txtfont.o i18n.o txtrecv.o txtrender.o displaybase.o display.o + +### Implicit rules: + +all-redirect: all + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +all: libvdr-$(PLUGIN).so + @install -d ../../man + @install README ../../man/$(PLUGIN).man + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ + @cp $@ $(LIBDIR)/$@.$(VDRVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ diff --git a/README b/README new file mode 100644 index 0000000..865dc52 --- /dev/null +++ b/README @@ -0,0 +1,98 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Marcel Wiesweg + +Project's homepage: http://www.wiesweg-online.de/linux/vdr + +Latest version available at: http://www.wiesweg-online.de/linux/vdr + +See the file COPYING for license information. + +Description: + +Osd-Teletext displays the teletext directly on the OSD. +Both sound and video are played in the background. + + +Keys: + 1,...,9: insert page number + Up: page+ + Down: page- + Right: sub page+ + Left: sub page- + Back: close teletext plugin + + All other user interaction ("Actions") is configurably assigned to the other + available keys. + You can e.g. configure that you jump to page 100 when you press Red. + In this example, the Action "Jump to 100" is assigned to key "Red". + Have a look at the plugin's setup page to learn the current assignment + and adapt it to your needs. + + Available Keys: Blue, Red, Yellow, Green, Play, Stop, FastFwd, FastRwd + Actions: "Zoom", "Half page", "Switch channel", "Switch background", + "Jump to..." a specific page. + + Description of the actions: + Zoom: Zoom to upper half/lower half/back to full page + Half Page: Reduce OSD window to the lower half of the screen and display upper half/lower half/back to full size + Switch channel:Show pages of a channel different from the one currently tuned to. + This does _not_ include any tuning or channel switching with vdr's core. + You must have tuned to the channel chosen some time before so that the pages have been stored on disk. + When you press the key associated with that action, you are asked for the channel number. + Press OK after you entered it with the number keys. + Jump to...: Jumps to the page you configure. + Switch background: Changes the in the setup configurable background color immediately + to black and back to your degree of transparency. + + How to configure the key bindings: + In the plugins setup menu, you can assign one of actions to each key. + You can choose freely which actions you need, you are not forced to assign + an action to a key at all if you do not need it. + If you select "Jump to...", specify the page number in the line immediately below. + + +Other Setup options: + Background transparency: + number between 0 (transparent) and 255 (black). Default is 127 (also used by VDR) + Show Clock: Toggles whether an additional clock is drawn approximately every second. + The clock shows the current system time, not any time broadcast via teletext. + Let VDR set the system time from a transponder to have the exact time. + Auto-update pages: + Continuously checks whether a page has changed and updates it if yes. + OSD width, OSD height: + Adjusts the width and height of the OSD independent from VDR's settings. + The valid range is 40 to 56 for the width and 12 to 21 for the height. + Minimum user inactivity: + Sets a timeout (in minutes) for user inactivity. When this timespan has elapsed + and the user did not press any keys, the plugin will be closed. Set to 0 to disable this. + Note that disabling timeout will also effectively disable VDR's auto-shutdown feature + as long as the plugin is active. + Key bindings: See above. + +Command line options: + A few settings are given on the command line rather than in the setup menu. + Available options: + + -d --directory=DIR The directory where the temporary + files will be stored. + (standard value: /vtx, recommended: /tmp/vtx + or /var/cache/vdr/osdteletext.) + Ensure that the directory exists and is writable. + -n --max-cache=NUM Maximum size in megabytes of cache used + to store the pages on the harddisk. + (standard value: a calculated value below 50 MB) + -s --cache-system=SYS Set the cache system to be used. + Choose "legacy" for the traditional + one-file-per-page system. + Default is "packed" for the + one-file-for-a-few-pages system. + +Colors: + On all sorts of output devices which are not limited as to color depth + the original teletext colors will be displayed. (Only difference: Cyan is used instead of + white to make reading easier). + On the classic full-featured DVB card and other limited devices, the colors will be reduced to four. + The mapping is currently optimized for German ARD, ZDF and RTL. If you are for some reason + really and definitely not satisfied with my choices, edit colormapping.h and recompile. + diff --git a/README.DE b/README.DE new file mode 100644 index 0000000..2384e81 --- /dev/null +++ b/README.DE @@ -0,0 +1,86 @@ +Beschreibung: + +OSD-Teletext zeigt Videotext direkt auf dem OSD an. +Im Hintergrund gibt es weiterhin Bild und Ton. + + +Tasten: + 1,...,9: Seitenzahl eingeben + Hoch: Seite weiter + Herunter:Seite zurück + Rechts: Unterseite weiter + Links: Unterseite zurück + Zurück: Videotext-Plugin schließen + + Die restliche Bedienung ("Aktionen") durch die anderen Tasten ist frei konfigurierbar. + Man kann z.B. einstellen, das die man mit der Taste Rot auf die Seite 100 springt. + Bei dieser Einstellung wäre die Aktion "Springe zu 100" der Taste Rot zugeordnet. + + Verfügbare Tasten: Blau, Rot, Gelb, Grün, Play, Stop, Schneller Vorlauf, Schn. Rücklauf + Aktionen: "Vergrößern", "Halbe Seite", "Kanal wechseln", + "Hintergrund wechseln", "Springe zu..." einer bestimmten Seite + + Beschreibung der Aktionen: + Vergrößern: Obere / untere Hälfte vergrößern / zurück zur ganzen Seite + Halbe Seite: OSD-Fenster nur noch in unterer Hälfte des Bildschirms zeigen + und obere / untere Hälfte anzeigen bzw. zurück + Kanal wechseln:Seiten eines anderen Senders als des gerade eingestellten anzeigen. + Dabei wird keine Frequenz gewechselt oder mit VDR ein anderer Kanal eingestellt. + Damit Seiten verfügbar sind, muss irgendwann vorher der gewählte + Kanal eingestellt gewesen sein. Bei Aufruf der Aktion wird nach der Kanalnummer + gefragt. Die Nummer mit den Zifferntasten eingeben und OK drücken. + Springe zu...: Springt zu der entsprechenden Seite + Hintergrund wechseln: Ändert die im Setup einstellbare Hintergrundfarbe sofort zu Schwarz + und nach erneutem Aufruf wieder zurück. + + Wie man Tasten Aktionen zuordnet: + Im Einstellungsmenü des Plugins kann jeder Taste eine Aktion zugeordnet werden. + Dabei ist nichts vorgeschrieben - keine Aktion muss irgendeiner Taste zugewiesen werden, + wenn sie nicht benötigt wird. + Bei Auswahl von "Springe zu..." wird die Seitennummer in der Zeile direkt darunter + angegeben. + +Andere Optionen: + Hintergrund-Transparenz: Zahl zwischen 0 (transparent) und 255 (schwarz). Vorgegeben ist 127 (wie auch von VDR) + Zeige Uhr: Diese Option bestimmt, ob etwa im Sekundenabstand zusätzlich eine Uhr angezeigt wird. + Die Uhr zeigt die aktuelle Systemzeit, nicht die mit dem Videotext ausgestrahlte Zeit. + Um genaue Werte zu haben, kann VDR die Systemzeit von einem Transponder einstellen. + Automatisch aktualisieren: + Überprüft ständig, ob sich die Seite geändert hat und aktualisiert sie wenn nötig + OSD-Breite, OSD-Höhe: + Hier kann die Breite des OSD unabhängig von den Einstellungen für VDR + bestimmt werden. Für die Breite liegt die Zahl zwischen 40 und 56, + für die Höhe zwischen 12 und 21. + Mindest Benutzer-Inaktivität: + Bestimmt die Zeit (in Minuten), nach der das Plugin automatisch geschlossen wird, wenn + der Benutzer solange keine Taste betätigt hat. Das kann durch setzen des Wertes auf 0 + verhindert werden. Dann wird jedoch auch das automatische Abschalten von VDR effektiv + außer Kraft gesetzt, solange das Plugin geöffnet ist. + Tasten einrichten: siehe oben + +Kommandozeilen-Optionen: + Einige Einstellungen werden über die Kommandozeile anstatt über das Menü gesetzt. + Verfügbare Optionen: + + -d --directory=DIR Das Verzeichnis für die temporären Dateien. + (Voreinstellung: /vtx, empfohlen: /tmp/vtx + oder /var/cache/vdr/osdteletext.) + Stellen Sie sicher, dass das Verzeichnis existiert + und beschreibbar ist. + -n --max-cache=NUM Maximale Größe des Zwischenspeichers für Seiten + auf der Festplatte. + (Voreinstellung: ein berechneter Wert unter 50 MB) + -s --cache-system=SYS Das zu benutzende Zwischenspeichersystem. + Wählen Sie "legacy" für das althergebrachte + System "Eine Datei - eine Seite". + Voreinstellung ist "packed" für ein System, das + in eine Datei mehrere Seiten speichert. + +Farben: + Auf allen Ausgabegeräten, die nicht in der Farbtiefe des OSD beschränkt sind, + werden die unveränderten Farben des Videotexts dargestellt (einzig Weiß wurde zum Zwecke der besseren + Lesbarkeit durch Cyan ersetzt). + Für die klassische DVB-Karte mit Hardware-Dekoder und anderen so beschränkten Geräten werden nur vier Farben dargestellt. Die Zuordnung ist auf ARD, ZDF und RTL optimiert. Sollten Sie aus irgendeinem Grund absolut nicht + meiner Meinung sein, passen Sie die Datei colormapping.h an und kompilieren Sie neu. + + \ No newline at end of file diff --git a/display.c b/display.c new file mode 100644 index 0000000..c9ac59f --- /dev/null +++ b/display.c @@ -0,0 +1,240 @@ +/*************************************************************************** + * * + * display.c - Actual implementation of OSD display variants and * + * Display:: namespace that encapsulates a single cDisplay. * + * * + * 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 +#include +#include "setup.h" +#include "display.h" +#include "txtfont.h" + +// Static variables of Display:: namespace +Display::Mode Display::mode=Display::Full; +cDisplay *Display::display=NULL; + + +void Display::SetMode(Display::Mode NewMode) { + // (re-)set display mode. + + if (display!=NULL && NewMode==mode) return; + // No change, nothing to do + + // OSD origin, centered on VDR OSD + int x0=Setup.OSDLeft+(Setup.OSDWidth-ttSetup.OSDwidth)*ttSetup.OSDHAlign/100; + int y0=Setup.OSDTop +(Setup.OSDHeight-ttSetup.OSDheight)*ttSetup.OSDVAlign/100; + + switch (NewMode) { + case Display::Full: + // Need to re-initialize *display: + Delete(); + // Try 4BPP display first: + display=new cDisplay4BPP(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight); + if (!display->Valid()) { + // Failed, possibly out of memory + delete display; + // Try 2BPP display + display=new cDisplay2BPP(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight); + } + break; + case Display::HalfUpper: + // Shortcut to switch from HalfUpper to HalfLower: + if (mode==Display::HalfLower) { + // keep instance. + ((cDisplay4BPPHalf*)display)->SetUpper(true); + break; + } + // Need to re-initialize *display: + Delete(); + display=new cDisplay4BPPHalf(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight,true); + break; + case Display::HalfLower: + // Shortcut to switch from HalfUpper to HalfLower: + if (mode==Display::HalfUpper) { + // keep instance. + ((cDisplay4BPPHalf*)display)->SetUpper(false); + break; + } + // Need to re-initialize *display: + Delete(); + display=new cDisplay4BPPHalf(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight,false); + break; + } + mode=NewMode; + // If display is invalid, clean up immediately: + if (!display->Valid()) Delete(); + // Pass through OSD black transparency + SetBackgroundColor((tColor)ttSetup.configuredClrBackground); +} + +void Display::ShowUpperHalf() { + // Enforce upper half of screen to be visible + if (GetZoom()==cDisplay::Zoom_Lower) + SetZoom(cDisplay::Zoom_Upper); + if (mode==HalfLower) + SetMode(HalfUpper); +} + + + + + + +cDisplay2BPP::cDisplay2BPP(int x0, int y0, int width, int height) + : cDisplay(width,height) { + // 2BPP display with color mapping + + osd = cOsdProvider::NewOsd(x0, y0); + if (!osd) return; + + width=(width+3)&~3; + // Width has to end on byte boundary, so round up + + tArea Areas[] = { { 0, 0, width - 1, height - 1, 2 } }; + if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) { + delete osd; + osd=NULL; + return; + } + osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea)); + + InitPalette(); + + InitScaler(); + + CleanDisplay(); +} + +tColor cDisplay2BPP::GetColorRGB(enumTeletextColor ttc, int Area) { + switch (ttc) { + case ttcBlack: return Background; + case ttcRed: return clrRed; + case ttcGreen: return clrYellow; + case ttcYellow: return clrYellow; + case ttcBlue: return Background; + case ttcMagenta: return clrRed; + case ttcCyan: return clrCyan; + case ttcWhite: return clrCyan; + case ttcTransparent: return Background; + default: return Background; + } +} + +tColor cDisplay2BPP::GetColorRGBAlternate(enumTeletextColor ttc, int Area) { + switch (ttc) { + case ttcBlack: return clrCyan; + case ttcRed: return clrYellow; + case ttcGreen: return clrRed; + case ttcYellow: return clrRed; + case ttcBlue: return clrCyan; + case ttcMagenta: return clrYellow; + case ttcCyan: return Background; + case ttcWhite: return Background; + case ttcTransparent: return clrCyan; + default: return Background; + } +} + + + + + +cDisplay4BPP::cDisplay4BPP(int x0, int y0, int width, int height) + : cDisplay(width,height) { + // 4BPP display for memory-modded DVB cards and other OSD providers + + osd = cOsdProvider::NewOsd(x0, y0); + if (!osd) return; + + width=(width+1)&~1; + // Width has to end on byte boundary, so round up + + tArea Areas[] = { { 0, 0, width - 1, height - 1, 4 } }; + if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) { + delete osd; + osd=NULL; + return; + } + osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea)); + + InitPalette(); + + InitScaler(); + + CleanDisplay(); +} + + +cDisplay4BPPHalf::cDisplay4BPPHalf(int x0, int y0, int width, int height, bool upper) + : cDisplay(width,height) { + + OsdX0=x0; + OsdY0=y0; + Upper=upper; + osd=NULL; + + // Redirect all real init work to method + InitOSD(); +} + +void cDisplay4BPPHalf::InitOSD() { + if (osd) delete osd; + osd = cOsdProvider::NewOsd(OsdX0, OsdY0); + if (!osd) return; + + int width=(Width+1)&~1; + // Width has to end on byte boundary, so round up + + tArea Areas[] = { { 0, 0, width - 1, Height - 1, 4 } }; + // Try full-size area first + + while (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) { + // Out of memory, so shrink + if (Upper) { + // Move up lower border + Areas[0].y2=Areas[0].y2-1; + } else { + // Move down upper border + Areas[0].y1=Areas[0].y1+1; + } + if (Areas[0].y1>Areas[0].y2) { + // Area is empty, fail miserably + delete osd; + osd=NULL; + return; + } + } + // Add some backup + // CanHandleAreas is not accurate enough + if (Upper) { + Areas[0].y2=Areas[0].y2-10; + } else { + Areas[0].y1=Areas[0].y1+10; + } + + osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea)); + + InitPalette(); + + InitScaler(); + + CleanDisplay(); + + // In case we switched on the fly, do a full redraw + Dirty=true; + DirtyAll=true; + Flush(); +} + + + diff --git a/display.h b/display.h new file mode 100644 index 0000000..37c76c2 --- /dev/null +++ b/display.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * * + * display.h - Actual implementation of OSD display variants and * + * Display:: namespace that encapsulates a single cDisplay. * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef OSDTELETEXT_DISPLAY_H_ +#define OSDTELETEXT_DISPLAY_H_ + +#include "displaybase.h" +#include + +namespace Display { + // The Display:: namespace mainly encapsulates a cDisplay *display variable + // and allows NULL-safe access to display members. + // Additionally, selects via mode the actually used instance for *display. + + enum Mode { Full, HalfUpper, HalfLower }; + // Full mode: 2BPP or 4BPP full screen display, depending on memory constrains + // HalfUpper: 4BPP display of upper half, drop lower half if out of memory + // HalfLower: 4BPP display of lower half, drop upper half if out of memory + + extern Mode mode; + extern cDisplay *display; + + // Access to display mode: + void SetMode(Display::Mode mode); + inline void Delete() + { if (display) { delete display; display=NULL; } } + + void ShowUpperHalf(); + // Make sure the upper half of screen is visible + // eg. for entering numbers etc. + + + // Wrapper calls for various *display members: + inline bool GetBlink() + { if (display) return display->GetBlink(); else return false; } + inline bool SetBlink(bool blink) + { if (display) display->SetBlink(blink); else return false; } + inline bool GetConceal() + { if (display) return display->GetConceal(); else return false; } + inline bool SetConceal(bool conceal) + { if (display) display->SetConceal(conceal); else return false; } + inline cDisplay::enumZoom GetZoom() + { if (display) return display->GetZoom(); else return cDisplay::Zoom_Off; } + inline void SetZoom(cDisplay::enumZoom zoom) + { if (display) display->SetZoom(zoom); } + + inline void SetBackgroundColor(tColor c) + { if (display) display->SetBackgroundColor(c); } + + inline tColor GetBackgroundColor() + { if (display) return display->GetBackgroundColor(); else return 0; } + + inline void HoldFlush() + { if (display) display->HoldFlush(); } + inline void ReleaseFlush() + { if (display) display->ReleaseFlush(); } + + inline void RenderTeletextCode(unsigned char *PageCode) + { if (display) display->RenderTeletextCode(PageCode); } + + inline void DrawClock() + { if (display) display->DrawClock(); } + inline void DrawPageId(const char *text) + { if (display) display->DrawPageId(text); } + inline void DrawMessage(const char *txt) + { if (display) display->DrawMessage(txt); } + inline void ClearMessage() + { if (display) display->ClearMessage(); } +} + + + + +class cDisplay2BPP : public cDisplay { + // 2BPP (4 color) OSD display + // Use static color mapping to limit color depth + +public: + cDisplay2BPP(int x0, int y0, int width, int height); + + virtual tColor GetColorRGB(enumTeletextColor ttc, int Area); + virtual tColor GetColorRGBAlternate(enumTeletextColor ttc, int Area); +}; + + + +class cDisplay4BPP : public cDisplay { + // 4BPP (16 color) OSD display + // No need for color mapping +public: + cDisplay4BPP(int x0, int y0, int width, int height); +}; + + + + +class cDisplay4BPPHalf : public cDisplay { + // 4BPP (16 color) OSD display with auto size reduction on memory constrains + // Automatically tries to make visible area as big as possible + // No need for color mapping + bool Upper; + // Prefer to show upper half or lower half? + + int OsdX0,OsdY0; + // Needed to re-initialize osd + +public: + cDisplay4BPPHalf(int x0, int y0, int width, int height, bool upper); + bool GetUpper() { return Upper; } + void SetUpper(bool upper) + { if (Upper!=upper) { Upper=upper; InitOSD(); } } +protected: + void InitOSD(); +}; + + + + +#endif diff --git a/displaybase.c b/displaybase.c new file mode 100644 index 0000000..b46fa25 --- /dev/null +++ b/displaybase.c @@ -0,0 +1,507 @@ +/*************************************************************************** + * * + * displaybase.c - Base class for rendering a teletext cRenderPage to * + * an actual VDR OSD. * + * * + * 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 +#include +#include "displaybase.h" +#include "txtfont.h" + + +cDisplay::cDisplay(int width, int height) { + Concealed=false; + Blinked=false; + FlushLock=0; + Zoom=Zoom_Off; + osd=NULL; + ScaleX=1; + ScaleY=1; + OffsetX=0; + OffsetY=0; + Width=width; + Height=height; + Background=clrGray50; + Boxed=false; + + MessageX=0; + MessageY=0; + MessageW=0; + MessageH=0; + MessageFont=cFont::GetFont(fontSml); +} + +cDisplay::~cDisplay() { + if (osd) delete osd; + osd=NULL; +} + +void cDisplay::InitScaler() { + // Set up the scaling factors. Also do zoom mode by + // scaling differently. + + if (!osd) return; + + int height=Height-6; + int width=Width-6; + OffsetX=3; + OffsetY=3; + + switch (Zoom) { + case Zoom_Upper: + height=height*2; + break; + case Zoom_Lower: + OffsetY=OffsetY-height; + height=height*2; + break; + default:; + } + + ScaleX=(480<<16)/width; + ScaleY=(250<<16)/height; +} + +void cDisplay::InitPalette() { + cBitmap *bm; + if (!osd) return; + + int Area=0; + while ((bm=osd->GetBitmap(Area))) { + enumTeletextColor c; + + bm->Reset(); + // reset palette + + for (c=ttcFirst;c<=ttcLast;c++) bm->Index(GetColorRGB(c,Area)); + // Announce all palette colors in defined order + + int x1,y1,x2,y2; + if (!bm->Dirty(x1,y1,x2,y2)) { + // force bitmap dirty to update palette + bm->SetIndex(bm->X0(),bm->Y0(),*bm->Data(bm->X0(),bm->Y0())); + // otherwise palette change wont be displayed on flush + } + + Area++; + } +} + +bool cDisplay::SetBlink(bool blink) { + int x,y; + bool Change=false; + + if (blink==Blinked) return false; + + // touch all blinking chars + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + if (Page[x][y].GetBlink()) { + Page[x][y].SetDirty(true); + Change=true; + } + } + } + Blinked=blink; + if (Change) Dirty=true; + + Flush(); + + return Change; +} + +bool cDisplay::SetConceal(bool conceal) { + int x,y; + bool Change=false; + + if (conceal==Concealed) return false; + + // touch all concealed chars + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + if (Page[x][y].GetConceal()) { + Page[x][y].SetDirty(true); + Change=true; + } + } + } + Concealed=conceal; + if (Change) Dirty=true; + + Flush(); + + return Change; +} + +void cDisplay::SetZoom(enumZoom zoom) { + + if (!osd) return; + if (Zoom==zoom) return; + Zoom=zoom; + + // Re-initialize scaler to let zoom take effect + InitScaler(); + + // Clear screen - mainly clear border + CleanDisplay(); + + Flush(); +} + +void cDisplay::SetBackgroundColor(tColor c) { + Background=c; + InitPalette(); + CleanDisplay(); + Flush(); +} + +void cDisplay::CleanDisplay() { + cBitmap *bm; + enumTeletextColor bgc=(Boxed)?(ttcTransparent):(ttcBlack); + int Area=0; + while ((bm=osd->GetBitmap(Area))) { + // Draw rect in two steps to avoid zapping palette + bm->DrawRectangle(bm->X0(), bm->Y0() , bm->X0()+bm->Width()-1, bm->Y0() , bm->Color(GetColorIndex(bgc,Area))); + bm->DrawRectangle(bm->X0(), bm->Y0()+1, bm->X0()+bm->Width()-1, bm->Y0()+bm->Height()-1, bm->Color(GetColorIndex(bgc,Area))); + // Yes, this *is* stupid. + // Otherwise, ttcTransparent would shift into 0 index of palette, + // causing palette re-organization and flicker on page change + Area++; + } + + // repaint all + Dirty=true; + DirtyAll=true; +} + + +tColor cDisplay::GetColorRGB(enumTeletextColor ttc, int Area) { + switch (ttc) { + case ttcBlack: return Background; + case ttcRed: return clrRed; + case ttcGreen: return clrGreen; + case ttcYellow: return clrYellow; + case ttcBlue: return clrBlue; + case ttcMagenta: return clrMagenta; + case ttcCyan: return clrCyan; + case ttcWhite: return clrWhite; + case ttcTransparent: return clrTransparent; + default: return Background; + } +} + +tColor cDisplay::GetColorRGBAlternate(enumTeletextColor ttc, int Area) { + return GetColorRGB(ttc,Area); +} + +void cDisplay::RenderTeletextCode(unsigned char *PageCode) { + // Interprete teletext code referenced by PageCode + // and draw the whole page content into OSD. + // PageCode must be a 40*24+12 bytes buffer + + #ifdef timingdebug + cTime t; + t.Start(); + #endif + + HoldFlush(); + + cRenderPage::ReadTeletextHeader(PageCode); + + if (!Boxed && (Flags&0x60)!=0) { + Boxed=true; + CleanDisplay(); + } else if (Boxed && (Flags&0x60)==0) { + Boxed=false; + CleanDisplay(); + } + + cRenderPage::RenderTeletextCode(PageCode+12); + + #ifdef timingdebug + t.Stop("Render Teletext"); + #endif + + ReleaseFlush(); +} + + + +void cDisplay::DrawDisplay() { + int x,y; + int cnt=0; + + if (!IsDirty()) return; + // nothing to do + + #ifdef timingdebug + cTime t; + t.Start(); + #endif + + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + if (IsDirty(x,y)) { + // Need to draw char to osd + cnt++; + cTeletextChar c=Page[x][y]; + c.SetDirty(false); + if ((Blinked && c.GetBlink()) || (Concealed && c.GetConceal())) { + c.SetChar(0x20); + c.SetCharset(CHARSET_LATIN_G0_DE); + } + DrawChar(x,y,c); + Page[x][y]=c; + } + } + } + #ifdef timingdebug + t.Stop("Draw Display"); + #endif + + Dirty=false; + DirtyAll=false; +} + + +inline bool IsPureChar(unsigned int *bitmap) { + // Check if character is pure foreground or + // pure background color + int i; + if (bitmap[0]==0x0000) { + for (i=1;i<10;i++) { + if (bitmap[i]!=0x0000) return false; + } + } else if (bitmap[0]==0xfff0) { + for (i=1;i<10;i++) { + if (bitmap[i]!=0xfff0) return false; + } + } else { + return false; + } + return true; +} + + + +void cDisplay::DrawChar(int x, int y, cTeletextChar c) { + unsigned int buffer[10]; + unsigned int *charmap; + cBitmap *bm; + + // Get character face: + charmap=GetFontChar(c,buffer); + if (!charmap) { + // invalid - clear buffer + bzero(&buffer,sizeof buffer); + charmap=buffer; + } + + // Get colors + enumTeletextColor ttfg=c.GetFGColor(); + enumTeletextColor ttbg=c.GetBGColor(); + + if (c.GetBoxedOut()) { + ttbg=ttcTransparent; + ttfg=ttcTransparent; + } + + // Virtual box area of the character + cBox box; + box.SetToCharacter(x,y); + + // OSD top left pixel of char + cVirtualCoordinate TopLeft; + TopLeft.VirtualToPixel(this,box.XMin,box.YMin); + // This pixel overlaps the box, but may be almost outside. + + // Move in OSD pixel units until we are inside the box + while (TopLeft.VirtXGetBitmap(Area))) { + cVirtualCoordinate BMTopLeft=TopLeft; + + // Correct for bitmap offset + BMTopLeft.OsdX-=bm->X0(); + BMTopLeft.OsdY-=bm->Y0(); + + // Map color to local + int fg=GetColorIndex(ttfg,Area); + int bg=GetColorIndex(ttbg,Area); + if (ttfg!=ttbg && fg==bg && !IsPureChar(charmap)) { + // Color collision + bg=GetColorIndexAlternate(ttbg,Area); + } + + // Now draw the character. Start at the top left corner, and walk + // through all pixels on OSD. To speed up, keep one pointer to OSD pixel + // and one to virtual box coordinates, and move them together. + + cVirtualCoordinate p=BMTopLeft; + while (p.VirtY<=box.YMax) { + // run through OSD lines + + // OSD line in this bitmap? + if (0<=p.OsdY && p.OsdYHeight()) { + // bits for this line + int bitline; + bitline=charmap[(p.VirtY-box.YMin)>>16]; + + p.OsdX=BMTopLeft.OsdX; + p.VirtX=BMTopLeft.VirtX; + while (p.VirtX<=box.XMax) { + // run through line pixels + + // pixel insied this bitmap? + if (0<=p.OsdX && p.OsdXWidth()) { + // pixel offset in bitline: + int bit=(p.VirtX-box.XMin)>>16; + + if (bitline&(0x8000>>bit)) { + bm->SetIndex(p.OsdX,p.OsdY,fg); + } else { + bm->SetIndex(p.OsdX,p.OsdY,bg); + } + } + p.IncPixelX(this); + } + } + p.IncPixelY(this); + } + Area++; + } +} + +void cDisplay::DrawText(int x, int y, const char *text, int len) { + // Copy text to teletext page + + cTeletextChar c; + c.SetFGColor(ttcWhite); + c.SetBGColor(ttcBlack); + c.SetCharset(CHARSET_LATIN_G0); + + // Copy chars up to len or null char + while (len>0 && *text!=0x00) { + c.SetChar(*text); + SetChar(x,y,c); + text++; + x++; + len--; + } + + // Fill remaining chars with spaces + c.SetChar(' '); + while (len>0) { + SetChar(x,y,c); + x++; + len--; + } + // .. and display + Flush(); +} + +void cDisplay::DrawClock() { + char text[9]; + time_t t=time(0); + struct tm loct; + + localtime_r(&t, &loct); + sprintf(text, "%02d:%02d:%02d", loct.tm_hour, loct.tm_min, loct.tm_sec); + + DrawText(32,0,text,8); +} + +void cDisplay::DrawMessage(const char *txt) { + const int border=5; + cBitmap *bm; + + if (!osd) return; + + HoldFlush(); + // Hold flush until done + + ClearMessage(); + // Make sure old message is gone + + if (IsDirty()) DrawDisplay(); + // Make sure all characters are out, so we can draw on top + + int w=MessageFont->Width(txt)+4*border; + int h=MessageFont->Height(txt)+4*border; + int x=(Width-w)/2; + int y=(Height-h)/2; + + int Area=0; + while ((bm=osd->GetBitmap(Area))) { + // Walk through all OSD areas + + // Get local color mapping + tColor fg=bm->Color(GetColorIndex(ttcWhite,Area)); + tColor bg=bm->Color(GetColorIndex(ttcBlack,Area)); + if (fg==bg) bg=bm->Color(GetColorIndexAlternate(ttcBlack,Area)); + + // Draw framed box + osd->DrawRectangle(x ,y ,x+w-1 ,y+border-1 ,fg); + osd->DrawRectangle(x ,y+h-border,x+w-1 ,y+h-1 ,fg); + osd->DrawRectangle(x ,y ,x+border-1 ,y+h-1 ,fg); + osd->DrawRectangle(x+w-border,y ,x+w-1 ,y+h-1 ,fg); + osd->DrawRectangle(x+border ,y+border ,x+w-border-1,y+h-border-1,bg); + + // Draw text + osd->DrawText(x+2*border,y+2*border,txt, fg, bg, MessageFont); + + Area++; + } + + // Remember box + MessageW=w; + MessageH=h; + MessageX=x; + MessageY=y; + + // And flush all changes + ReleaseFlush(); +} + +void cDisplay::ClearMessage() { + if (!osd) return; + if (MessageW==0 || MessageH==0) return; + + // map OSD pixel to virtual coordinate, use center of pixel + int x0=(MessageX-OffsetX)*ScaleX+ScaleX/2; + int y0=(MessageY-OffsetY)*ScaleY+ScaleY/2; + int x1=(MessageX+MessageW-1-OffsetX)*ScaleX+ScaleX/2; + int y1=(MessageY+MessageH-1-OffsetY)*ScaleY+ScaleY/2; + + // map to character + x0=x0/(12<<16); + y0=y0/(10<<16); + x1=(x1+(12<<16)-1)/(12<<16); + y1=(y1+(10<<16)-1)/(10<<16); + + for (int x=x0;x<=x1;x++) { + for (int y=y0;y<=y1;y++) { + MakeDirty(x,y); + } + } + + MessageW=0; + MessageH=0; + + Flush(); +} + + diff --git a/displaybase.h b/displaybase.h new file mode 100644 index 0000000..708689f --- /dev/null +++ b/displaybase.h @@ -0,0 +1,287 @@ +/*************************************************************************** + * * + * displaybase.h - Base class for rendering a teletext cRenderPage to * + * an actual VDR OSD. * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef OSDTELETEXT_DISPLAYBASE_H_ +#define OSDTELETEXT_DISPLAYBASE_H_ + +#include "txtrender.h" +#include + +//#define timingdebug +// Enables some time measure debugging code + +#ifdef timingdebug + #include + + class cTime { + // Debugging: Simple class to measure time + timeb start; + public: + void Start() { + ftime(&start); + } + void Stop(char *txt) { + timeb t; + ftime(&t); + int s=t.time-start.time; + int ms=t.millitm-start.millitm; + if (ms<0) { + s--; + ms+=1000; + } + printf("%s: %i.%03i\n",txt,s,ms); + } + }; +#endif + + +class cDisplay : public cRenderPage { + // Class that extends the virtual cRenderPage with the capability + // to render its contents to an OSD of variable size. + // Renders incrementally - just changes + // plus adds some more display features like message display. + +public: + enum enumZoom { + // Zoom up upper/lower half of page + Zoom_Off, + Zoom_Upper, + Zoom_Lower + } Zoom; + +protected: + bool Concealed; + // Hidden text internal state + + bool Blinked; + // Blinking text internal state + + int FlushLock; + // Lock counter for bundeling OSD flushes + + bool Boxed; + // Page is 'boxed mode' transparent + + int Width; + int Height; + // OSD pixel dimension + + tColor Background; + // Color to be used for black background + // - allow transparency + + cOsd *osd; + // The osd object. If creation fails, may be NULL + + int ScaleX,ScaleY; + int OffsetX,OffsetY; + // Virtual coordinate system, see InitScaler + + const cFont *MessageFont; + int MessageX,MessageY,MessageW,MessageH; + // Message overlay window, position and font + + class cBox { + // helper class. Represents a character's box in virtual coordinates + public: + int XMin,YMin,XMax,YMax; + inline void SetToCharacter(int x, int y); + }; + friend class cBox; + + class cVirtualCoordinate { + // helper class. Represents a coordinate in virtual display space + // and in OSD pixel coordinates. + public: + int OsdX,OsdY; + int VirtX,VirtY; + inline void VirtualToPixel(cDisplay *Display, int x, int y); + inline void IncPixelX(cDisplay *Display); + inline void IncPixelY(cDisplay *Display); + }; + friend class cVirtualCoordinate; + +public: + cDisplay(int width, int height); + virtual ~cDisplay(); + bool Valid() { return (osd!=NULL); } + // After creation, check for Valid(). Destroy, if not valid. + +protected: + void InitScaler(); + // Initialize transformation for OSD->Virtual coordinates + // Some words about scaling: + + // OSD display is variable width x height, with 3 pixels border + // on all sides. There is a virtual coordinate system projected + // on this, with (3,3) mapped to (0,0) and (width-3,height-3) + // mapped to (480<<16,250<<16). + // The idea is, that each font pixel uses a virtual rectangle + // of (1<<16,1<<16) size. + + // ScaleX,ScaleY represent the (virtual) width and height of a + // physical OSD pixel. + // OffsetX,OffsetY default to 3,3 to represent the border offset, + // but may be used differently. + +public: + bool GetBlink() { return Blinked; } + bool SetBlink(bool blink); + // Switch blink frequently to get blinking chars + // Returns true if there are blinking characters. + + bool GetConceal() { return Concealed; } + bool SetConceal(bool conceal); + // Hidden text. Set to true to see hidden text. + // Returns true if there are concealed characters. + + enumZoom GetZoom() { return Zoom; } + void SetZoom(enumZoom zoom); + // Zoom to upper/lower half of page + + void SetBackgroundColor(tColor c); + tColor GetBackgroundColor() { return Background; } + // Set the background color for black. Allows transparent black. + + // Color mapping interface. + virtual tColor GetColorRGB(enumTeletextColor ttc, int Area); + // Map a teletext color to an OSD color in #Area. + + virtual tColor GetColorRGBAlternate(enumTeletextColor ttc, int Area); + // For color collision: + // Map this teletext color to an OSD color in #Area, but dont + // return same as GetColorRGB(). Used to solve conflicts if + // foreground and background are mapped to same color. + // Defaults to 1:1 identity. Not needed if all colors actually + // supported by OSD. + + int GetColorIndex(enumTeletextColor ttc, int Area) { + // Map this teletext color to an OSD color index in #Area. + if (!osd) return 0; + cBitmap *bm=osd->GetBitmap(Area); + if (!bm) return 0; + return bm->Index(GetColorRGB(ttc,Area)); + } + + int GetColorIndexAlternate(enumTeletextColor ttc, int Area) { + // Map this teletext color to an OSD color index in #Area. + if (!osd) return 0; + cBitmap *bm=osd->GetBitmap(Area); + if (!bm) return 0; + return bm->Index(GetColorRGBAlternate(ttc,Area)); + } + + + +protected: + void InitPalette(); + // Initialize palette(s) for OSD + + void DrawDisplay(); + // Draw all dirty characters from cRenderPage buffer to OSD + + void CleanDisplay(); + // Clean OSD completely + + virtual void DrawChar(int x, int y, cTeletextChar c); + // Draw a single character to OSD + + +public: + void HoldFlush() { FlushLock++; } + // Hold all OSD flush updates to bundle operations. + + void ReleaseFlush() { FlushLock--; Flush(); } + // Release hold of flush updates. After last release, + // the flush will be done + +protected: + void Flush() { + // Commit all changes from OSD internal bitmaps to device + // All draw operations inside cDisplay should call it, + // no one outside should need to call it. + + if (FlushLock>0) return; + if (!osd) return; + if (IsDirty()) DrawDisplay(); + + #ifdef timingdebug + cTime t; + t.Start(); + #endif + + osd->Flush(); + + #ifdef timingdebug + t.Stop("osd Flush"); + #endif + } + +public: + void RenderTeletextCode(unsigned char *PageCode); + // Interprete teletext code referenced by PageCode + // and draw the whole page content into OSD. + // PageCode must be a 40*24+12 bytes buffer + + void DrawText(int x, int y, const char *text, int len); + // Draw some characters in teletext page. + // Max len chars, fill up with spaces + + void DrawClock(); + // Draw current time to OSD + + void DrawPageId(const char *text) + { DrawText(0,0,text,8); } + // Draw Page ID string to OSD + + void DrawMessage(const char *txt); + // Draw a framed, centered message box to OSD + + void ClearMessage(); + // Remove message box and redraw hidden content +}; + + + +inline void cDisplay::cBox::SetToCharacter(int x, int y) { + // Virtual box area of a character + XMin=(x*12)<<16; + YMin=(y*10)<<16; + XMax=XMin+(12<<16)-1; + YMax=YMin+(10<<16)-1; +} + +inline void cDisplay::cVirtualCoordinate::VirtualToPixel(cDisplay *Display, int x, int y) { + // Map virtual coordinate to OSD pixel + OsdX=x/Display->ScaleX+Display->OffsetX; + OsdY=y/Display->ScaleY+Display->OffsetY; + + // map OSD pixel back to virtual coordinate, use center of pixel + VirtX=(OsdX-Display->OffsetX)*Display->ScaleX+Display->ScaleX/2; + VirtY=(OsdY-Display->OffsetY)*Display->ScaleY+Display->ScaleY/2; +} + +inline void cDisplay::cVirtualCoordinate::IncPixelX(cDisplay *Display) { + // Move one OSD pixel + OsdX++; + VirtX+=Display->ScaleX; +} +inline void cDisplay::cVirtualCoordinate::IncPixelY(cDisplay *Display) { + // Move one OSD pixel + OsdY++; + VirtY+=Display->ScaleY; +} + +#endif diff --git a/i18n.c b/i18n.c new file mode 100644 index 0000000..1d64b59 --- /dev/null +++ b/i18n.c @@ -0,0 +1,445 @@ +/* + * i18n.c: Internationalization + * + * See the README file for copyright information and how to reach the author. + * + * $Id: i18n.c 1.3 2002/06/23 13:05:59 kls Exp $ + */ + +#include "i18n.h" + +const tI18nPhrase Phrases[] = { + { "Page", //English + "Seite", //German + "", //Slovenian + "Pagina", //Italian + "", //Dutch + "", //Portuguese + "Page", //French + "", //Norwegian + "Sivua", //Finnish + "", //Polish + "Página", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Pàgina", //Catalan + "ÁâàÐÝØæÐ", //Russian + }, + { "not found", //English + "nicht gefunden", //German + "", //Slovenian + "non trovata", //Italian + "", //Dutch + "", //Portuguese + "pas trouvé", //French + "", //Norwegian + "ei löydy", //Finnish + "", //Polish + "no encontrada", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "no trobada", //Catalan + "ÝÕ ÝÐÙÔÕÝÐ", //Russian + }, + { "Teletext (OSD)", //English + "Videotext (OSD)", //German + "", //Slovenian + "Teletext (OSD)", //Italian + "", //Dutch + "", //Portuguese + "Teletext (OSD)", //French + "", //Norwegian + "Teksti-TV", //Finnish + "", //Polish + "Teletexto (OSD)",//Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Teletext (OSD)", //Catalan + "ÂÕÛÕâÕÚáâ", //Russian + }, + { "Zoom", //English + "Vergrößern", //German + "", //Slovenian + "Zoom", //Italian + "", //Dutch + "", //Portuguese + "Zoom", //French + "", //Norwegian + "Suurenna", //Finnish + "", //Polish + "Zoom", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Zoom", //Catalan + "ãÒÕÛØçØâì", //Russian + }, + { "Half page", //English + "Halbe Seite", //German + "", //Slovenian + "Mezza pagina", //Italian + "", //Dutch + "", //Portuguese + "Demi-Page", //French + "", //Norwegian + "Puolikas sivu", //Finnish + "", //Polish + "Media página", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Mitja pàgina", //Catalan + "ßÞÛ-áâàÐÝØæë", //Russian + }, + { "Change channel", //English + "Kanal wechseln", //German + "", //Slovenian + "Cambio canale", //Italian + "", //Dutch + "", //Portuguese + "Changer la chaîne", //French + "", //Norwegian + "Vaihda kanavaa", //Finnish + "", //Polish + "Cambio cadena", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Canvi cadena", //Catalan + "ßÕàÕÚÛîçØâì ÚÐÝÐÛ", //Russian + }, + { "Jump to...", //English + "Springe zu...", //German + "", //Slovenian + "Salta a...", //Italian + "", //Dutch + "", //Portuguese + "Aller à...", //French + "", //Norwegian + "Siirry sivulle...", //Finnish + "", //Polish + "Salta a...", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Salta a...", //Catalan + "ßÕàÕÙâØ Ú...", //Russian + }, + { "Background transparency", //English + "Hintergrund-Transparenz", //German + "", //Slovenian + "Trasparenza dello sfondo", //Italian + "", //Dutch + "", //Portuguese + "Fond transparent", //French + "", //Norwegian + "Taustan läpinäkyvyys", //Finnish + "", //Polish + "Transparencia del fondo", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Transparència del fons", //Catalan + "ÁâÕßÕÝì ßàÞ×àÐçÝÞáâØ äÞÝÐ", //Russian + }, + { "Red key", //English + "Rote Taste", //German + "", //Slovenian + "Tasto Rosso", //Italian + "", //Dutch + "", //Portuguese + "Touche rouge", //French + "", //Norwegian + "Punainen näppäin", //Finnish + "", //Polish + "Tecla roja", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Tecla vermella", //Catalan + "ºàÐáÝÐï ÚÝÞßÚÐ", //Russian + }, + { " Page number", //English + " Seitenzahl", //German + "", //Slovenian + " Numero di pagina", //Italian + "", //Dutch + "", //Portuguese + " Nombre de pages", //French + "", //Norwegian + " Sivunumero", //Finnish + "", //Polish + " Número de página", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + " Nombre de pàgina", //Catalan + " ½ÞÜÕà áâàÐÝØæë", //Russian + }, + { "Green key", //English + "Grüne Taste", //German + "", //Slovenian + "Tasto Verde", //Italian + "", //Dutch + "", //Portuguese + "Touche verte", //French + "", //Norwegian + "Vihreä näppäin", //Finnish + "", //Polish + "Tecla verde", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Tecla verda", //Catalan + "·ÕÛñÝÐï ÚÝÞßÚÐ", //Russian + }, + { "Yellow key", //English + "Gelbe Taste", //German + "", //Slovenian + "Tasto Giallo", //Italian + "", //Dutch + "", //Portuguese + "Touche jaune", //French + "", //Norwegian + "Keltainen näppäin", //Finnish + "", //Polish + "Tecla amarilla", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Tecla groga", //Catalan + "¶ñÛâÐï ÚÝÞßÚÐ", //Russian + }, + { "Blue key", //English + "Blaue Taste", //German + "", //Slovenian + "Tasto Blu", //Italian + "", //Dutch + "", //Portuguese + "Touche bleue", //French + "", //Norwegian + "Sininen näppäin", //Finnish + "", //Polish + "Tecla azul", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Tecla blava", //Catalan + "ÁØÝïï ÚÝÞßÚÐ", //Russian + }, + { "Channel (press OK): ", //English + "Sender (OK drücken): ", //German + "", //Slovenian + "Canale (premere OK)", //Italian + "", //Dutch + "", //Portuguese + "Chaine (Appuyer sur OK): ", //French + "", //Norwegian + "Kanava (paina OK):", //Finnish + "", //Polish + "Canal (pulse OK):", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Canal (premi OK):", //Catalan + "ºÐÝÐÛ (½ÐÖÜØâÕ ¾º)", //Russian + }, + { "Show clock", //English + "Uhr anzeigen", //German + "", //Slovenian + "Visualizza la hora", //Italian + "", //Dutch + "", //Portuguese + "Afficher l'heure", //French + "", //Norwegian + "Näytä kello", //Finnish + "", //Polish + "Visualiza el reloj", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Visualitza l'hora", //Catalan + "¿ÞÚÐ×ëÒÐâì çÐáë", //Russian + }, + { "Setup$Suspend receiving", //English + "Empfang unterbrechen", //German + "", //Slovenian + "Sospendi ricezione", //Italian + "", //Dutch + "", //Portuguese + "Suspension de la réception", //French + "", //Norwegian + "Keskeytä vastaanottaminen", //Finnish + "", //Polish + "Suspende la recepción", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Suspèn la recepció", //Catalan + "¿àØÞáâÐÝÞÒØâì ßàØñÜ", //Russian + }, + { "Suspend receiving", //English + "Empfang unterbrechen", //German + "", //Slovenian + "Sospendi ricezione", //Italian + "", //Dutch + "", //Portuguese + "Suspension de la réception", //French + "", //Norwegian + "Keskeytä vastaanottaminen", //Finnish + "", //Polish + "Suspende la recepción", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Suspèn la recepció", //Catalan + "ßàØÞáâÐÝÞÒØâì ßàØñÜ", //Russian + }, + { "Switch background", //English + "Hintergrund ändern", //German + "", //Slovenian + "Cambia sfondo", //Italian + "", //Dutch + "", //Portuguese + "Change le fond d'écran", //French + "", //Norwegian + "Vaihda tausta", //Finnish + "", //Polish + "Cambia el fondo", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Canvia el fons", //Catalan + "ÝÕßàÞ×àÐçÝëÙ äÞÝ", //Russian + }, + { "Auto-update pages", //English + "Seiten aktualisieren", //German + "", //Slovenian + "Aggiornamento pagina automatico", //Italian + "", //Dutch + "", //Portuguese + "Mise a jour des pages", //French + "", //Norwegian + "Automaattinen sivupäivitys", //Finnish + "Actualización páginas automática", //Polish + "", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Actualització pàgines automàtica", //Catalan + "°ÒâÞÞÑÝÞÒÛÕÝØÕ áâàÐÝØæ", //Russian + }, + { "OSD height", //English + "OSD-Höhe", //German + "", //Slovenian + "Altezza OSD", //Italian + "", //Dutch + "", //Portuguese + "OSD Hauteur", //French + "", //Norwegian + "Korkeus", //Finnish + "", //Polish + "Altura OSD", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Altura OSD", //Catalan + "²ëáÞâÐ ÜÕÝî", //Russian + }, + { "OSD width", //English + "OSD-Breite", //German + "", //Slovenian + "Larghezza OSD", //Italian + "", //Dutch + "", //Portuguese + "OSD Largeur", //French + "", //Norwegian + "Leveys", //Finnish + "", //Polish + "Anchura OSD", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Amplària OSD", //Catalan + "ÈØàØÝÐ ÜÕÝî", //Russian + }, + { "OSD horizontal align", //English + "OSD horizontale Anordnung", //German + "", //Slovenian + "", //Italian + "", //Dutch + "", //Portuguese + "", //French + "", //Norwegian + "Pystykeskitys", //Finnish + "", //Polish + "", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "", //Catalan + "", //Russian + }, + { "OSD vertical align", //English + "OSD vertikale Anordnung", //German + "", //Slovenian + "", //Italian + "", //Dutch + "", //Portuguese + "", //French + "", //Norwegian + "Vaakakeskitys", //Finnish + "", //Polish + "", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "", //Catalan + "", //Russian + }, + { "Displays teletext on the OSD", //English + "Zeigt den Videotext auf dem OSD an", //German + "", //Slovenian + "", //Italian + "", //Dutch + "", //Portuguese + "", //French + "", //Norwegian + "Teksti-TV (OSD)", //Finnish + "", //Polish + "Visualiza el teletexto en el OSD", //Spanish + "", //Greek + "", //Swedish + "", //Romanian + "", //Hugarian + "Visualitza el teletext en l'OSD", //Catalan + "¿ÞÚÐ× âÕÛÕâÕÚáâÐ Ò ÜÕÝî", //Russian + }, + { NULL } + }; diff --git a/i18n.h b/i18n.h new file mode 100644 index 0000000..577628a --- /dev/null +++ b/i18n.h @@ -0,0 +1,16 @@ +/* + * i18n.h: Internationalization + * + * See the README file for copyright information and how to reach the author. + * + * $Id: i18n.h 1.2 2002/05/11 14:48:16 kls Exp $ + */ + +#ifndef _I18N__H +#define _I18N__H + +#include + +extern const tI18nPhrase Phrases[]; + +#endif //_I18N__H diff --git a/menu.c b/menu.c new file mode 100644 index 0000000..cfefff7 --- /dev/null +++ b/menu.c @@ -0,0 +1,681 @@ +/*************************************************************************** + * Copyright (c) 2003,2004 by Marcel Wiesweg * + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "menu.h" +#include "display.h" +#include "setup.h" +#include "txtrecv.h" + + +#define TXTROOT "/vtx" + +#define GET_HUNDREDS(x) ( ( (x) - ((x)%256) ) /256 ) +#define GET_TENS(x) ( (( (x) - ((x)%16) )%256 ) /16 ) +#define GET_ONES(x) ( (x)%16 ) + +#define GET_HUNDREDS_DECIMAL(x) ( ( (x) - ((x)%100) ) /100 ) +#define GET_TENS_DECIMAL(x) ( (( (x) - ((x)%10) )%100 ) /10 ) +#define GET_ONES_DECIMAL(x) ( (x)%10 ) + +#define PSEUDO_HEX_TO_DECIMAL(x) ( (GET_HUNDREDS_DECIMAL(x))*256 + (GET_TENS_DECIMAL(x))*16 + (GET_ONES_DECIMAL(x)) ) + +using namespace std; + +int Stretch = true; +typedef map IntMap; +IntMap channelPageMap; + +//static variables +int TeletextBrowser::currentPage=0x100; //Believe it or not, the teletext numbers are somehow hexadecimal +int TeletextBrowser::currentSubPage=0; +tChannelID TeletextBrowser::channel; +int TeletextBrowser::currentChannelNumber=0; +TeletextBrowser* TeletextBrowser::self=0; + + +TeletextBrowser::TeletextBrowser(cTxtStatus *txtSt) { + cursorPos=0; + pageFound=true; + selectingChannel=false; + needClearMessage=false; + selectingChannelNumber=-1; + self=this; + txtStatus=txtSt; + //if (txtStatus) + // txtStatus->ForceReceiving(true); + suspendedReceiving=false; + previousPage=currentPage; + previousSubPage=currentSubPage; + pageBeforeNumberInput=currentPage; + lastActivity=time(NULL); + inactivityTimeout=-1; +} + + +TeletextBrowser::~TeletextBrowser() { + Display::Delete(); + + self=0; + /*if (txtStatus) { + if (suspendedReceiving) + txtStatus->ForceSuspending(false); + txtStatus->ForceReceiving(false); + }*/ +} + +void TeletextBrowser::Show(void) { + Display::SetMode(Display::mode); + ShowPage(); +} + +bool TeletextBrowser::CheckIsValidChannel(int number) { + return (Channels.GetByNumber(number) != 0); +} + +void TeletextBrowser::ChannelSwitched(int ChannelNumber) { + cChannel *chan=Channels.GetByNumber(ChannelNumber); + + if (!chan) + return; + + tChannelID chid=chan->GetChannelID(); + if (chid==channel || chid==tChannelID::InvalidID) + return; + + channel=chid; + + //store page number of current channel + IntMap::iterator it; + channelPageMap[currentChannelNumber] = currentPage; + currentChannelNumber=ChannelNumber; + + currentPage=0x100; + currentSubPage=0; + + //see if last page number on this channel was stored + it=channelPageMap.find(ChannelNumber); + if (it != channelPageMap.end()) { //found + currentPage=(*it).second; + } + + //on the one hand this must work in background mode, when the plugin is not active. + //on the other hand, if active, the page should be shown. + //so this self-Pointer. + if (self) { + self->ShowPage(); + } +} + + +eOSState TeletextBrowser::ProcessKey(eKeys Key) { + if (Key != kNone) + lastActivity = time(NULL); + + switch (Key) { + case k1: SetNumber(1);break; + case k2: SetNumber(2);break; + case k3: SetNumber(3);break; + case k4: SetNumber(4);break; + case k5: SetNumber(5);break; + case k6: SetNumber(6);break; + case k7: SetNumber(7);break; + case k8: SetNumber(8);break; + case k9: SetNumber(9);break; + case k0: + //same behavior for 0 as VDR does it with channels + if ((cursorPos==0) && (!selectingChannel)) { + //swap variables + int tempPage=currentPage; + int tempSubPage=currentSubPage; + currentPage=previousPage; + currentSubPage=previousSubPage; + previousPage=tempPage; + previousSubPage=tempSubPage; + ShowPage(); + } else + SetNumber(0); + break; + case kOk: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + if (selectingChannelNumber>0) { + if (CheckIsValidChannel(selectingChannelNumber)) + ChannelSwitched(selectingChannelNumber); + else { + needClearMessage=true; + //string tranlated in VDR's i18n.c + Display::DrawMessage(tr("*** Invalid Channel ***")); + } + } else { + ShowPage(); + } + } + break; + case kBack: return osEnd; + case kNone: //approx. every second + //checking if page changed + if ( pageFound && ttSetup.autoUpdatePage && cursorPos==0 && !selectingChannel && (PageCheckSum() != checkSum) ) { + ShowPage(); + //check if page was previously not found and is available now + } else if (!pageFound && CheckFirstSubPage(0)) { + ShowPage(); + } else { + if (needClearMessage) { + needClearMessage=false; + Display::ClearMessage(); + } + //updating clock + UpdateClock(); + } + //check for activity timeout + if (ttSetup.inactivityTimeout && (time(NULL) - lastActivity > ttSetup.inactivityTimeout*60)) + return osEnd; + break; + case kUp: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + + if (cursorPos != 0) { + //fully revert cursor + SetNumber(-3); + } + ChangePageRelative(DirectionForward); + Display::ShowUpperHalf(); + ShowPage(); + break; + case kDown: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + if (cursorPos != 0) { + //fully reset + SetNumber(-3); + } + ChangePageRelative(DirectionBackward); + Display::ShowUpperHalf(); + ShowPage(); + break; + case kRight: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + if (cursorPos != 0) { + //fully reset + SetNumber(-3); + } + ChangeSubPageRelative(DirectionForward); + Display::ShowUpperHalf(); + ShowPage(); + break; + case kLeft: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + if (cursorPos != 0) { + //revert cursor + SetNumber(-1); + break; + } + ChangeSubPageRelative(DirectionBackward); + Display::ShowUpperHalf(); + ShowPage(); + break; + + + case kRed: + case kGreen: + case kBlue: + case kYellow: + //case kUser1:case kUser2:case kUser3:case kUser4:case kUser5: + //case kUser6:case kUser7:case kUser8:case kUser9: + case kPlay:case kPause:case kStop: case kRecord:case kFastFwd:case kFastRew: + if (cursorPos != 0) { + //fully reset + SetNumber(-3); + } + ExecuteAction(TranslateKey(Key)); + break; + default: break; + } + return osContinue; +} + +void TeletextBrowser::ExecuteAction(eTeletextAction e) { + switch (e) { + case Zoom: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + + switch (Display::GetZoom()) { + case cDisplay::Zoom_Off: + Display::SetZoom(cDisplay::Zoom_Upper); + break; + case cDisplay::Zoom_Upper: + Display::SetZoom(cDisplay::Zoom_Lower); + break; + case cDisplay::Zoom_Lower: + Display::SetZoom(cDisplay::Zoom_Off); + break; + } + + break; + case HalfPage: + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + + switch (Display::mode) { + case Display::HalfUpper: + Display::SetMode(Display::HalfLower); + break; + case Display::HalfLower: + Display::SetMode(Display::Full); + break; + case Display::Full: + Display::SetMode(Display::HalfUpper); + break; + } + ShowPage(); + break; + case SwitchChannel: + selectingChannelNumber=0; + selectingChannel=true; + ShowAskForChannel(); + break; + /*case SuspendReceiving: + if (!txtStatus) + break; + //if (suspendedReceiving) + // txtStatus->ForceSuspending(false); + //else + // txtStatus->ForceSuspending(true); + //suspendedReceiving=(!suspendedReceiving); + break;*/ + case DarkScreen: + if (Display::GetBackgroundColor() == clrBlack) + Display::SetBackgroundColor((tColor)ttSetup.configuredClrBackground); + else + Display::SetBackgroundColor(clrBlack); + break; + default: + //In osdteletext.c, numbers are thought to be decimal, the setup page + //entries will display them in this way. It is a lot easier to do the + //conversion to hexadecimal here. + //This means, we convert the number to what it would be if the string + //had been parsed with hexadecimal base. + int pageNr=PSEUDO_HEX_TO_DECIMAL((int)e); + if (0x100<=pageNr<=0x899) { + if (selectingChannel) { + selectingChannel=false; + Display::ClearMessage(); + } + SetPreviousPage(currentPage, currentSubPage, pageNr); + currentPage=pageNr; + cursorPos=0; + currentSubPage=0; + + Display::ShowUpperHalf(); + ShowPage(); + } + break; + } +} + +eTeletextAction TeletextBrowser::TranslateKey(eKeys Key) { + switch(Key) { + case kRed: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyRed]; + case kGreen: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyGreen]; + case kYellow: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyYellow]; + case kBlue: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyBlue]; + case kPlay: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyPlay]; + //case kPause: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyPause]; + case kStop: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyStop]; + //case kRecord: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyRecord]; + case kFastFwd: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyFastFwd]; + case kFastRew: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyFastRew]; + default: return (eTeletextAction)100; //just to keep gcc quiet + } +} + + +void TeletextBrowser::SetNumber(int i) { + //cursorPos means insertion after, 0<=cursorPos<=2 + if (selectingChannel) { + selectingChannelNumber = selectingChannelNumber*10+i; + ShowAskForChannel(); + return; + } + + //i<0 means revert cursor position + if (i<0) { + for (;i<0;i++) { + switch (cursorPos) { + case 0: + return; + case 1: + currentPage = currentPage-256*GET_HUNDREDS(currentPage)+256*GET_HUNDREDS(pageBeforeNumberInput); + break; + case 2: + currentPage = currentPage-16*GET_TENS(currentPage)+16*GET_TENS(pageBeforeNumberInput); + break; + } + cursorPos--; + } + ShowPageNumber(); + return; + } + + + static int tempPage; + switch (cursorPos) { + case 0: + if (i<1) i=1; + //accept no 9 when cursorPos==0 + if (i>8) i=8; + tempPage= currentPage; + pageBeforeNumberInput = currentPage; + currentPage = currentPage-256*GET_HUNDREDS(currentPage)+256*i; + break; + case 1: + if (i<0) i=0; + if (i>9) i=9; + currentPage = currentPage-16*GET_TENS(currentPage)+16*i; + break; + case 2: + if (i<0) i=0; + if (i>9) i=9; + currentPage = currentPage-GET_ONES(currentPage)+i; + pageBeforeNumberInput = currentPage; + SetPreviousPage(tempPage, currentSubPage, currentPage); + break; + } + pageFound=true; //so that "page ... not found" is not displayed, but e.g. 1**-00 + if (++cursorPos>2) { + cursorPos=0; + CheckFirstSubPage(0); + Display::ShowUpperHalf(); + ShowPage(); + } else { + ShowPageNumber(); + } +} + +//returns whether x, when written in hexadecimal form, +//will only contain the digits 0...9 and not A...F +//in the first three digits. +static inline bool onlyDecimalDigits(int x) { + return (( x & 0xE) < 0xA) && + (( (x>>4) & 0xE) < 0xA) && + (( (x>>8) & 0xE) < 0xA); +} + +//after 199 comes 1A0, but if these pages exist, they contain no useful data, so filter them out +int TeletextBrowser::nextValidPageNumber(int start, Direction direction) { + do { + switch (direction) { + case DirectionForward: + start++; + break; + case DirectionBackward: + start--; + break; + } + } while (!onlyDecimalDigits(start)); + return start; +} + +void TeletextBrowser::ChangePageRelative(Direction direction) +{ + int oldpage = currentPage; + int oldSubPage = currentSubPage; + + do { + /*if (back) + currentPage--; + else + currentPage++;*/ + currentPage=nextValidPageNumber(currentPage, direction); + if (currentPage>0x899) currentPage=0x100; + if (currentPage<0x100) currentPage=0x899; + // sub page is always 0 if you change the page + if (CheckFirstSubPage(0)) { + SetPreviousPage(oldpage, oldSubPage, currentPage); + return; + } + } while (currentPage != oldpage); + + return; +} + +void TeletextBrowser::ChangeSubPageRelative(Direction direction) +{ + int oldsubpage = currentSubPage; + + do { + /*if (back) + currentSubPage--; + else + currentSubPage++;*/ + currentSubPage=nextValidPageNumber(currentSubPage, direction); + if (currentSubPage > 0x99) currentSubPage=0; + if (currentSubPage < 0) currentSubPage=0x99; + + if (CheckPage()) + return; + } while (currentSubPage != oldsubpage); + + return; +} + +bool TeletextBrowser::CheckFirstSubPage(int startWith) { + int oldsubpage = currentSubPage; + + do { + if (CheckPage()) + return true; + //currentSubPage++; + currentSubPage=nextValidPageNumber(currentSubPage, DirectionForward); + + if (currentSubPage > 0x99) currentSubPage=0; + if (currentSubPage < 0) currentSubPage=0x99; + + } while (currentSubPage != oldsubpage); + + return false; +} + +bool TeletextBrowser::CheckPage() +{ + StorageHandle fd; + + Storage *s=Storage::instance(); + if (!(fd=s->openForReading(PageID(channel, currentPage, currentSubPage), false)) ) + return false; + + s->close(fd); + return true; +} + +//sets the previousPage variables if and only if new page is different from old page +void TeletextBrowser::SetPreviousPage(int oldPage, int oldSubPage, int newPage) { + if (oldPage != newPage) { + previousPage=oldPage; + previousSubPage=oldSubPage; + } +} + + + + +void TeletextBrowser::ShowPage() { + if ((pageFound=DecodePage())) { + if (ttSetup.autoUpdatePage) + checkSum=PageCheckSum(); + } +} + +void TeletextBrowser::ShowPageNumber() { + char str[8]; + sprintf(str, "%3x-%02x", currentPage, currentSubPage); + if (cursorPos>0) { + str[2]='*'; + if (cursorPos==1) + str[1]='*'; + } + Display::DrawPageId(str); +} + +void TeletextBrowser::ShowAskForChannel() { + if (selectingChannel) { + char *str; + if (selectingChannelNumber>0) + asprintf(&str,"%s%d", tr("Channel (press OK): "), selectingChannelNumber); + else + asprintf(&str,"%s", tr("Channel (press OK): ") ); + Display::DrawMessage(str); + free(str); + } +} + +//this is taken and adapted from the teletext plugin since it uses its data +bool TeletextBrowser::DecodePage() { + // Load the page and decodes it + #ifdef timingdebug + cTime t; + t.Start(); + #endif + + unsigned char cache[40*24+12]; + StorageHandle fd; + // Take a look if there is a xxx-00 page + Storage *s=Storage::instance(); + if (currentSubPage==0) { + if ( !(fd=s->openForReading(PageID(channel, currentPage,currentSubPage), false)) ) { + // There is no subpage 0 so look if there is subpage 1 + currentSubPage++; + // Generate file string + } else { + // yes file exists + s->close(fd); + } + } + + if ( (fd=s->openForReading(PageID(channel, currentPage, currentSubPage), true)) ) + { + s->read(cache,sizeof cache,fd); // Read full page data + s->close(fd); + + Display::HoldFlush(); + Display::ClearMessage(); + Display::RenderTeletextCode(cache); + ShowPageNumber(); + UpdateClock(); + Display::ReleaseFlush(); + + #ifdef timingdebug + t.Stop("Full Page Update"); + #endif + } else { + // page doesn't exist + currentSubPage--; + + Display::HoldFlush(); + ShowPageNumber(); + char str[80]; + snprintf(str,80, "%s %3x-%02x %s",tr("Page"),currentPage, currentSubPage,tr("not found")); + Display::DrawMessage(str); + Display::ReleaseFlush(); + + return false; + } + return true; +} + + + +int TeletextBrowser::PageCheckSum() { + int retSum=0; + StorageHandle fd; + + CheckFirstSubPage(currentSubPage); + + Storage *s=Storage::instance(); + if ((fd=s->openForReading(PageID(channel, currentPage, currentSubPage), false)) ) { + uchar cache[960]; + s->read(cache, 12, fd); //skip + s->read(cache, sizeof(cache), fd); + s->close(fd); + memset(cache+12, 0, 8); //it seems that there the clock is transmitted, ignore changes + for (uint i=0;iIsPrimaryDevice() && ChannelNumber>0) + TeletextBrowser::ChannelSwitched(ChannelNumber); +} + +TeletextSetup ttSetup; + +TeletextSetup::TeletextSetup() { + //Set default values for setup options + + configuredClrBackground=clrGray50; + + //init key bindings + for (int i=0;i<10;i++) + mapKeyToAction[0]=(eTeletextAction)0; + mapKeyToAction[3]=Zoom; + mapKeyToAction[2]=HalfPage; + mapKeyToAction[0]=SwitchChannel; + + showClock=true; + suspendReceiving=false; + autoUpdatePage=true; + //OSDHeight+width default values given in Start() + OSDHAlign=50; + OSDVAlign=50; + + //use the value set for VDR's min user inactivity. + //Initially this value could be changed via the plugin's setup, but I removed that + //because there is no advantage, but a possible problem when VDR's value is change + //after the plugin has stored its own value. + inactivityTimeout=Setup.MinUserInactivity; +} + diff --git a/menu.h b/menu.h new file mode 100644 index 0000000..0aaf3d1 --- /dev/null +++ b/menu.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (c) 2003,2004 by Marcel Wiesweg * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef OSDTELETEXT_MENU__H +#define OSDTELETEXT_MENU__H + +#include + +#include +#include +#include + +#include "txtrecv.h" +#include "setup.h" + +extern int Stretch; + +class ChannelStatus : public cStatus { +public: + ChannelStatus(); +protected: + virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); +}; + + +class TeletextBrowser : public cOsdObject { +public: + TeletextBrowser(cTxtStatus *txtSt); + ~TeletextBrowser(); + void Show(void); + static void ChannelSwitched(int ChannelNumber); + virtual eOSState ProcessKey(eKeys Key); +protected: + enum Direction { DirectionForward, DirectionBackward }; + void SetNumber(int i); + void ShowPage(); + void UpdateClock(); + bool DecodePage(); + void ChangePageRelative(Direction direction); + void ChangeSubPageRelative(Direction direction); + bool CheckPage(); + void ShowAskForChannel(); + bool CheckFirstSubPage(int startWith); + void SetPreviousPage(int oldPage, int oldSubPage, int newPage); + bool CheckIsValidChannel(int number); + int PageCheckSum(); + void ShowPageNumber(); + void ExecuteAction(eTeletextAction e); + int nextValidPageNumber(int start, Direction direction); + char fileName[PATH_MAX]; + char page[40][24]; + int cursorPos; + eTeletextAction TranslateKey(eKeys Key); + bool pageFound; + bool selectingChannel; + bool needClearMessage; + int selectingChannelNumber; + int checkSum; + cTxtStatus *txtStatus; + bool suspendedReceiving; + int previousPage; + int previousSubPage; + int pageBeforeNumberInput; + time_t lastActivity; + int inactivityTimeout; + static int currentPage; + static int currentSubPage; + static tChannelID channel; + static int currentChannelNumber; + static TeletextBrowser* self; +}; + + +#endif + diff --git a/osdteletext.c b/osdteletext.c new file mode 100644 index 0000000..a7dfbcd --- /dev/null +++ b/osdteletext.c @@ -0,0 +1,481 @@ +/*************************************************************************** + * Copyright (c) 2003,2004 by Marcel Wiesweg * + * (autogenerated code (c) Klaus Schmidinger) + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include + +using namespace std; + +#include "menu.h" +#include "i18n.h" +#include "txtrecv.h" +#include "setup.h" + +static const char *VERSION = "0.5.1"; +static const char *DESCRIPTION = "Displays teletext on the OSD"; +static const char *MAINMENUENTRY = "Teletext (OSD)"; + +class cPluginTeletextosd : public cPlugin { +private: + // Add any member variables or functions you may need here. + cTxtStatus *txtStatus; + ChannelStatus *channelStatus; + bool startReceiver; + void initTexts(); +public: + cPluginTeletextosd(void); + virtual ~cPluginTeletextosd(); + virtual const char *Version(void) { return VERSION; } + virtual const char *Description(void) { return tr(DESCRIPTION); } + virtual const char *CommandLineHelp(void); + virtual bool ProcessArgs(int argc, char *argv[]); + virtual bool Start(void); + virtual void Housekeeping(void); + virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); } + virtual cOsdObject *MainMenuAction(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); +}; + +class cTeletextSetupPage; +class ActionEdit { + public: + void Init(cTeletextSetupPage*, int, cMenuEditIntItem *, cMenuEditStraItem *); + cMenuEditStraItem *action; + cMenuEditIntItem *number; + bool visible; + }; + +struct ActionKeyName { + const char *internalName; + const char *userName; +}; + +class cTeletextSetupPage : public cMenuSetupPage { +friend class ActionEdit; +private: + TeletextSetup temp; + int tempPageNumber[LastActionKey]; + int tempConfiguredClrBackground; //must be a signed int +protected: + virtual void Store(void); + ActionEdit ActionEdits[LastActionKey]; + virtual eOSState ProcessKey(eKeys Key); +public: + cTeletextSetupPage(void); + static const ActionKeyName *actionKeyNames; + static const char **modes; + //~cTeletextSetupPage(void); + //void SetItemVisible(cOsdItem *Item, bool visible, bool callDisplay=false); +}; + +const ActionKeyName *cTeletextSetupPage::actionKeyNames = 0; +const char **cTeletextSetupPage::modes = 0; + +/*class MenuEditActionItem : public cMenuEditStraItem { +public: + MenuEditActionItem(cTeletextSetupPage *parentMenu, cMenuEditIntItem *pageNumberMenuItem, + const char *Name, int *Value, int NumStrings, const char * const *Strings); +protected: + virtual eOSState ProcessKey(eKeys Key); + cTeletextSetupPage *parent; + cMenuEditIntItem *pageNumberItem; +};*/ + + + +cPluginTeletextosd::cPluginTeletextosd(void) +{ + // Initialize any member variables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! + txtStatus=0; + channelStatus=0; + startReceiver=true; +} + +cPluginTeletextosd::~cPluginTeletextosd() +{ + // Clean up after yourself! + if (txtStatus) + delete txtStatus; + if (channelStatus) + delete channelStatus; + Storage::instance()->cleanUp(); +} + +const char *cPluginTeletextosd::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return " -d --directory=DIR The directory where the temporary\n" + " files will be stored.\n" + " (default: /vtx, recommended: /tmp/vtx\n" + " or /var/cache/vdr/osdteletext.)\n" + " Ensure that the directory exists and is writable.\n" + " -n --max-cache=NUM Maximum size in megabytes of cache used\n" + " to store the pages on the harddisk.\n" + " (default: a calculated value below 50 MB)\n" + " -s --cache-system=SYS Set the cache system to be used.\n" + " Choose \"legacy\" for the traditional\n" + " one-file-per-page system.\n" + " Default is \"packed\" for the \n" + " one-file-for-a-few-pages system.\n" + " -R, --no-receive Do not receive and store teletext\n" + " (deprecated - plugin will be useless).\n" + " -r, --receive (obsolete)\n"; +} + +bool cPluginTeletextosd::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + static struct option long_options[] = { + { "directory", required_argument, NULL, 'd' }, + { "max-cache", required_argument, NULL, 'n' }, + { "cache-system", required_argument, NULL, 's' }, + { "no-receiver", no_argument, NULL, 'R' }, + { "receive", no_argument, NULL, 'r' }, + { NULL } + }; + + int c; + int maxStorage=-1; + while ((c = getopt_long(argc, argv, "s:d:n:Rr", long_options, NULL)) != -1) { + switch (c) { + case 's': + if (!optarg) + break; + if (strcasecmp(optarg, "legacy")==0) + Storage::setSystem(Storage::StorageSystemLegacy); + else if (strcasecmp(optarg, "packed")==0) + Storage::setSystem(Storage::StorageSystemPacked); + break; + case 'd': Storage::setRootDir(optarg); + break; + case 'n': if (isnumber(optarg)) { + int n = atoi(optarg); + maxStorage=n; + } + break; + case 'R': startReceiver=false; + break; + case 'r': startReceiver=true; + break; + } + } + //do this here because the option -s to change the storage system might be given + // after -n, and then -s would have no effect + if (maxStorage>=0) + Storage::instance()->setMaxStorage(maxStorage); + return true; +} + +bool cPluginTeletextosd::Start(void) +{ + // Start any background activities the plugin shall perform. + //Clean any files which might be remaining from the last session, + //perhaps due to a crash they have not been deleted. + Storage::instance()->init(); + initTexts(); + if (startReceiver) + txtStatus=new cTxtStatus(); + channelStatus=new ChannelStatus(); + if (ttSetup.OSDheight<=100) ttSetup.OSDheight=Setup.OSDHeight; + if (ttSetup.OSDwidth<=100) ttSetup.OSDwidth=Setup.OSDWidth; + + return true; +} + +void cPluginTeletextosd::initTexts() { + if (cTeletextSetupPage::actionKeyNames) + return; + RegisterI18n(Phrases); + //TODO: rewrite this in the xy[0].cd="fg"; form + static const ActionKeyName st_actionKeyNames[] = + { + { "Action_kRed", tr("Red key") }, + { "Action_kGreen", tr("Green key") }, + { "Action_kYellow", tr("Yellow key") }, + { "Action_kBlue", tr("Blue key") }, + { "Action_kPlay", tr(cKey::ToString( kPlay)) }, + //{ "Action_kPause", tr(cKey::ToString( kPause)) }, + { "Action_kStop", tr(cKey::ToString( kStop)) }, + //{ "Action_kRecord", tr(cKey::ToString( kRecord)) }, + { "Action_kFastFwd", tr(cKey::ToString( kFastFwd)) }, + { "Action_kFastRew", tr(cKey::ToString( kFastRew)) } + }; + + cTeletextSetupPage::actionKeyNames = st_actionKeyNames; + + static const char *st_modes[] = + { + tr("Zoom"), + tr("Half page"), + tr("Change channel"), + tr("Switch background"), + //tr("Suspend receiving"), + tr("Jump to...") + }; + + cTeletextSetupPage::modes = st_modes; +} + +void cPluginTeletextosd::Housekeeping(void) +{ + // Perform any cleanup or other regular tasks. +} + +cOsdObject *cPluginTeletextosd::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. + return new TeletextBrowser(txtStatus); +} + +cMenuSetupPage *cPluginTeletextosd::SetupMenu(void) +{ + // Return a setup menu in case the plugin supports one. + return new cTeletextSetupPage; +} + + + +bool cPluginTeletextosd::SetupParse(const char *Name, const char *Value) +{ + initTexts(); + // Parse your own setup parameters and store their values. + //Stretch=true; + if (!strcasecmp(Name, "configuredClrBackground")) ttSetup.configuredClrBackground=( ((unsigned int)atoi(Value)) << 24); + /*else if (!strcasecmp(Name, "Action_kRed")) ttSetup.mapKeyToAction[0]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kGreen")) ttSetup.mapKeyToAction[1]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kYellow")) ttSetup.mapKeyToAction[2]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kBlue")) ttSetup.mapKeyToAction[3]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kPlay")) ttSetup.mapKeyToAction[4]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kPause")) ttSetup.mapKeyToAction[5]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kStop")) ttSetup.mapKeyToAction[6]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kRecord")) ttSetup.mapKeyToAction[7]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kFastFwd")) ttSetup.mapKeyToAction[8]=(eTeletextAction)atoi(Value); + else if (!strcasecmp(Name, "Action_kFastRew")) ttSetup.mapKeyToAction[9]=(eTeletextAction)atoi(Value);*/ + else if (!strcasecmp(Name, "showClock")) ttSetup.showClock=atoi(Value); + //currently not used + else if (!strcasecmp(Name, "suspendReceiving")) ttSetup.suspendReceiving=atoi(Value); + else if (!strcasecmp(Name, "autoUpdatePage")) ttSetup.autoUpdatePage=atoi(Value); + else if (!strcasecmp(Name, "OSDheight")) ttSetup.OSDheight=atoi(Value); + else if (!strcasecmp(Name, "OSDwidth")) ttSetup.OSDwidth=atoi(Value); + else if (!strcasecmp(Name, "OSDHAlign")) ttSetup.OSDHAlign=atoi(Value); + else if (!strcasecmp(Name, "OSDVAlign")) ttSetup.OSDVAlign=atoi(Value); + else if (!strcasecmp(Name, "inactivityTimeout")) /*ttSetup.inactivityTimeout=atoi(Value)*/; + else { + for (int i=0;i=LastAction) + ttSetup.mapKeyToAction[i]=LastAction-1; + + return true; + } + } + + //for migration to 0.4 + char act[7]; + strncpy(act, Name, 7); + if (!strcasecmp(act, "Action_")) + return true; + + return false; + } + return true; +} + +void cTeletextSetupPage::Store(void) { + //copy table + for (int i=0;i= LastAction) //jump to page selected + ttSetup.mapKeyToAction[i]=(eTeletextAction)tempPageNumber[i]; + else //one of the other modes selected + ttSetup.mapKeyToAction[i]=temp.mapKeyToAction[i]; + } + ttSetup.configuredClrBackground=( ((unsigned int)tempConfiguredClrBackground) << 24); + ttSetup.showClock=temp.showClock; + ttSetup.suspendReceiving=temp.suspendReceiving; + ttSetup.autoUpdatePage=temp.autoUpdatePage; + ttSetup.OSDheight=temp.OSDheight; + ttSetup.OSDwidth=temp.OSDwidth; + ttSetup.OSDHAlign=temp.OSDHAlign; + ttSetup.OSDVAlign=temp.OSDVAlign; + //ttSetup.inactivityTimeout=temp.inactivityTimeout; + + for (int i=0;i> 24)); + SetupStore("showClock", ttSetup.showClock); + //currently not used + //SetupStore("suspendReceiving", ttSetup.suspendReceiving); + SetupStore("autoUpdatePage", ttSetup.autoUpdatePage); + SetupStore("OSDheight", ttSetup.OSDheight); + SetupStore("OSDwidth", ttSetup.OSDwidth); + SetupStore("OSDHAlign", ttSetup.OSDHAlign); + SetupStore("OSDVAlign", ttSetup.OSDVAlign); + //SetupStore("inactivityTimeout", ttSetup.inactivityTimeout); +} + + +cTeletextSetupPage::cTeletextSetupPage(void) { + //init tables + for (int i=0;i= LastAction) {//jump to page selected + temp.mapKeyToAction[i]=LastAction; //to display the last string + tempPageNumber[i]=ttSetup.mapKeyToAction[i]; + } else { //one of the other modes selected + temp.mapKeyToAction[i]=ttSetup.mapKeyToAction[i]; + tempPageNumber[i]=100; + } + } + tempConfiguredClrBackground=(ttSetup.configuredClrBackground >> 24); + temp.showClock=ttSetup.showClock; + temp.suspendReceiving=ttSetup.suspendReceiving; + temp.autoUpdatePage=ttSetup.autoUpdatePage; + temp.OSDheight=ttSetup.OSDheight; + temp.OSDwidth=ttSetup.OSDwidth; + temp.OSDHAlign=ttSetup.OSDHAlign; + temp.OSDVAlign=ttSetup.OSDVAlign; + //temp.inactivityTimeout=ttSetup.inactivityTimeout; + + Add(new cMenuEditIntItem(tr("Background transparency"), &tempConfiguredClrBackground, 0, 255)); + + Add(new cMenuEditBoolItem(tr("Show clock"), &temp.showClock )); + + //Add(new cMenuEditBoolItem(tr("Setup$Suspend receiving"), &temp.suspendReceiving )); + + Add(new cMenuEditBoolItem(tr("Auto-update pages"), &temp.autoUpdatePage )); + + Add(new cMenuEditIntItem(tr("OSD height"), &temp.OSDheight, 250, MAXOSDHEIGHT)); + Add(new cMenuEditIntItem(tr("OSD width"), &temp.OSDwidth, 320, MAXOSDWIDTH)); + + Add(new cMenuEditIntItem(tr("OSD horizontal align"), &temp.OSDHAlign, 0, 100)); + Add(new cMenuEditIntItem(tr("OSD vertical align"), &temp.OSDVAlign, 0, 100)); + + //Using same string as VDR's setup menu + //Add(new cMenuEditIntItem(tr("Setup.Miscellaneous$Min. user inactivity (min)"), &temp.inactivityTimeout)); + + for (int i=0;iProcessKey(Key); + //if (state != osUnknown) { //really should not return osUnknown I think + if (temp.mapKeyToAction[i] == LastAction && !ActionEdits[i].visible) { + //need to make it visible + if (i+1::Del(ActionEdits[i].number, false); + ActionEdits[i].visible=false; + Display(); + } + break; + //return state; + //} + } + } + + return state; + //return cMenuSetupPage::ProcessKey(Key); +} + + +void ActionEdit::Init(cTeletextSetupPage* s, int num, cMenuEditIntItem *p, cMenuEditStraItem * a) { + action=a; + number=p; + s->Add(action); + if (s->temp.mapKeyToAction[num] == LastAction) { + s->Add(number); + visible=true; + } else + visible=false; +} + + + + +VDRPLUGINCREATOR(cPluginTeletextosd); // Don't touch this! diff --git a/setup.h b/setup.h new file mode 100644 index 0000000..f04488f --- /dev/null +++ b/setup.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#ifndef __SETUP_H +#define __SETUP_H + + +//There are two places to be kept in sync with these enums: +//TeletextBrowser::TranslateKey and +//the constants in cPluginTeletextosd::initTexts +enum eTeletextAction { Zoom, HalfPage, SwitchChannel, + DarkScreen, /*SuspendReceiving,*/ LastAction }; //and 100-899 => jump to page + +enum ActionKeys { +ActionKeyRed, +ActionKeyGreen, +ActionKeyYellow, +ActionKeyBlue, +ActionKeyPlay, +//ActionKeyPause, +ActionKeyStop, +//ActionKeyRecord, +ActionKeyFastFwd, +ActionKeyFastRew, + +LastActionKey +}; + +/* +kRed +kGreen +kYellow +kBlue +kPlay +kPause +kStop +kRecord +kFastFwd*/ + +//Default values are set in menu.c, setup menu, parsing and storing can be found in osdteletext.c +class TeletextSetup { +public: + TeletextSetup(); + int mapKeyToAction[10]; //4 color keys + kPlay, kPause etc. + unsigned int configuredClrBackground; + int showClock; + int suspendReceiving; + int autoUpdatePage; + int OSDheight; + int OSDwidth; + int OSDHAlign; + int OSDVAlign; + int inactivityTimeout; +}; + +extern TeletextSetup ttSetup; + +#endif diff --git a/tables.h b/tables.h new file mode 100644 index 0000000..08fe344 --- /dev/null +++ b/tables.h @@ -0,0 +1,112 @@ +/* This file is copied from Ralph Metzler's vbidecode package. */ + +/* + tables.h - some data conversion tables for vbidecode +*/ + +#ifndef _TABLES_H +#define _TABLES_H + +unsigned char invtab[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +unsigned char unhamtab[256] = { + 0x01, 0xff, 0x81, 0x01, 0xff, 0x00, 0x01, 0xff, + 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07, + 0xff, 0x00, 0x01, 0xff, 0x00, 0x80, 0xff, 0x00, + 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff, + 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07, + 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x87, + 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff, + 0x86, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07, + 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09, + 0x02, 0x82, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff, + 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff, + 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x83, 0x03, + 0x04, 0xff, 0xff, 0x05, 0x84, 0x04, 0x04, 0xff, + 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07, + 0xff, 0x05, 0x05, 0x85, 0x04, 0xff, 0xff, 0x05, + 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff, + 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09, + 0x0a, 0xff, 0xff, 0x0b, 0x8a, 0x0a, 0x0a, 0xff, + 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff, + 0xff, 0x0b, 0x0b, 0x8b, 0x0a, 0xff, 0xff, 0x0b, + 0x0c, 0x8c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff, + 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07, + 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x8d, 0x0d, + 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff, + 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x89, + 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09, + 0x88, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09, + 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff, + 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09, + 0x0f, 0xff, 0x8f, 0x0f, 0xff, 0x0e, 0x0f, 0xff, + 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff, + 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x8e, 0xff, 0x0e, +}; + +unsigned char cct2vtx_table[] = + { 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, + + 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0xef, + + 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, + + 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, + + 0x60, 0x61, 0x62, 0x63, + 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, + 0x6c, 0x6d, 0x6e, 0x6f, + + 0x70, 0x71, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, + 0x7c, 0x7d, 0x7e, 0x7f + }; + +#endif diff --git a/txtfont.c b/txtfont.c new file mode 100644 index 0000000..438ff7d --- /dev/null +++ b/txtfont.c @@ -0,0 +1,3371 @@ +#include "txtfont.h" + +unsigned int TXT_Mask[11]= { + 0x0000, // ************ **** + 0x39C0, // **###**###** **** + 0x39C0, // **###**###** **** + 0x0000, // ************ **** + 0x39C0, // **###**###** **** + 0x39C0, // **###**###** **** + 0x0000, // ************ **** + 0x39C0, // **###**###** **** + 0x39C0, // **###**###** **** + 0x0000 // ************ **** + }; + +unsigned int TXT_Font[][11]= { + { // 0x20 = Leerzeichen + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x21 = ! + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x22 = " + 0x0000, // ************ **** + 0x39C0, // **###**###** **** + 0x18C0, // ***##***##** **** + 0x3180, // **##***##*** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x23 = # = NC + 0x0000, // ************ **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x0000 // ************ **** + }, + { // 0x24 = $ = NC + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x6660, // *##**##**##* **** + 0x6600, // *##**##***** **** + 0x3FC0, // **########** **** + 0x0660, // *****##**##* **** + 0x6660, // *##**##**##* **** + 0x3FC0, // **########** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + }, + { // 0x25 = % + 0x0000, // ************ **** + 0x70C0, // *###****##** **** + 0xD980, // ##*##**##*** **** + 0x7300, // *###**##**** **** + 0x0600, // *****##***** **** + 0x0CE0, // ****##**###* **** + 0x19B0, // ***##**##*## **** + 0x30E0, // **##****###* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x26 = & + 0x0000, // ************ **** + 0x1E00, // ***####***** **** + 0x3300, // **##**##**** **** + 0x3300, // **##**##**** **** + 0x1E00, // ***####***** **** + 0x3330, // **##**##**## **** + 0x61C0, // *##****###** **** + 0x3F30, // **######**## **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x27 = ' + 0x0000, // ************ **** + 0x0700, // *****###**** **** + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x28 = ( + 0x0000, // ************ **** + 0x0700, // *****###**** **** + 0x0C00, // ****##****** **** + 0x1800, // ***##******* **** + 0x1800, // ***##******* **** + 0x1800, // ***##******* **** + 0x0C00, // ****##****** **** + 0x0700, // *****###**** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x29 = ) + 0x0000, // ************ **** + 0x0E00, // ****###***** **** + 0x0300, // ******##**** **** + 0x0180, // *******##*** **** + 0x0180, // *******##*** **** + 0x0180, // *******##*** **** + 0x0300, // ******##**** **** + 0x0E00, // ****###***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x2A = * + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x6660, // *##**##**##* **** + 0x36C0, // **##*##*##** **** + 0x0F00, // ****####**** **** + 0x36C0, // **##*##*##** **** + 0x6660, // *##**##**##* **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x2B = + + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x2C = , + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x3800, // **###******* **** + 0x1800, // ***##******* **** + 0x3000, // **##******** **** + }, + { // 0x2D = - + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x2E = . + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x1800, // ***##******* **** + 0x1800, // ***##******* **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x2F = / + 0x0000, // ************ **** + 0x00C0, // ********##** **** + 0x0180, // *******##*** **** + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0C00, // ****##****** **** + 0x1800, // ***##******* **** + 0x3000, // **##******** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + + { // 0x30 = 0 + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x38E0, // **###***###* **** + 0x38E0, // **###***###* **** + 0x38E0, // **###***###* **** + 0x38E0, // **###***###* **** + 0x38E0, // **###***###* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x31 = 1 + 0x0000, // ************ **** + 0x0700, // *****###**** **** + 0x1F00, // ***#####**** **** + 0x0700, // *****###**** **** + 0x0700, // *****###**** **** + 0x0700, // *****###**** **** + 0x0700, // *****###**** **** + 0x0700, // *****###**** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x32 = 2 + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x30E0, // **##****###* **** + 0x00E0, // ********###* **** + 0x01C0, // *******###** **** + 0x0780, // *****####*** **** + 0x1E00, // ***####***** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x33 = 3 + 0x0000, // ************ **** + 0x3FE0, // **#########* **** + 0x00C0, // ********##** **** + 0x0080, // *******##*** **** + 0x07E0, // *****######* **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x34 = 4 + 0x0000, // ************ **** + 0x00E0, // ********###* **** + 0x03C0, // ******####** **** + 0x0700, // *****###**** **** + 0x1C00, // ***###****** **** + 0x38E0, // **###***###* **** + 0x3FE0, // **#########* **** + 0x00E0, // ********###* **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x35 = 5 + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3FC0, // **########** **** + 0x00E0, // ********###* **** + 0x30E0, // **##****###* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x36 = 6 + 0x0000, // ************ **** + 0x0700, // *****###**** **** + 0x0E00, // ****###***** **** + 0x1C00, // ***###****** **** + 0x3FC0, // **########** **** + 0x3860, // **###****##* **** + 0x3860, // **###****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x37 = 7 + 0x0000, // ************ **** + 0x7FE0, // *##########* **** + 0x01C0, // *******###** **** + 0x0380, // ******###*** **** + 0x0700, // *****###**** **** + 0x0E00, // ****###***** **** + 0x1C00, // ***###****** **** + 0x3800, // **###******* **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x38 = 8 + 0x0000, // ************ **** + 0x0F80, // ****#####*** **** + 0x38E0, // **###***###* **** + 0x38E0, // **###***###* **** + 0x0F80, // ****#####*** **** + 0x38E0, // **###***###* **** + 0x38E0, // **###***###* **** + 0x0F80, // ****#####*** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x39 = 9 + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x30E0, // **##****###* **** + 0x30E0, // **##****###* **** + 0x1FC0, // ***#######** **** + 0x0380, // ******###*** **** + 0x0700, // *****###**** **** + 0x0E00, // ****###***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x3A = : + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x0000, // ************ **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x3B = ; + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x1800, // ***##******* **** + }, + { // 0x3C = < + 0x0000, // ************ **** + 0x00E0, // ********###* **** + 0x0380, // ******###*** **** + 0x0E00, // ****###***** **** + 0x3800, // **###******* **** + 0x0E00, // ****###***** **** + 0x0380, // ******###*** **** + 0x00E0, // ********###* **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x3D = = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x3E = > + 0x0000, // ************ **** + 0x7000, // *###******** **** + 0x1C00, // ***###****** **** + 0x0700, // *****###**** **** + 0x01C0, // *******###** **** + 0x0700, // *****###**** **** + 0x1C00, // ***###****** **** + 0x7000, // *###******** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + { // 0x3F = ? + 0x0000, // ************ **** + 0x1F80, // ***######*** **** + 0x30C0, // **##****##** **** + 0x30C0, // **##****##** **** + 0x0180, // *******##*** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + }, + + { // 0x40 = § = NC + 0x0000, // ************ **** + 0x1F80, // ***######*** **** + 0x30C0, // **##****##** **** + 0x3000, // **##******** **** + 0x1F80, // ***######*** **** + 0x30C0, // **##****##** **** + 0x1F80, // ***######*** **** + 0x00C0, // ********##** **** + 0x30C0, // **##****##** **** + 0x1F80 // ***######*** **** + }, + { // 0x41 = A + 0x0000, // ************ **** + 0x0F00, // ****####**** **** + 0x1980, // ***##**##*** **** + 0x30C0, // **##****##** **** + 0x6060, // *##******##* **** + 0x7FE0, // *##########* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x42 = B + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FC0, // **########** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x43 = C + 0x0000, // ************ **** + 0x0FC0, // ****######** **** + 0x1860, // ***##****##* **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x1860, // ***##****##* **** + 0x0FC0, // ****######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x44 = D + 0x0000, // ************ **** + 0x3F80, // **#######*** **** + 0x30C0, // **##****##** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30C0, // **##****##** **** + 0x3F80, // **#######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x45 = E + 0x0000, // ************ **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3F80, // **#######*** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x46 = F + 0x0000, // ************ **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3F80, // **#######*** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x47 = G + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x33E0, // **##**#####* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x48 = H + 0x0000, // ************ **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x7FE0, // *##########* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x49 = I + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x4A = J + 0x0000, // ************ **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x4B = K + 0x0000, // ************ **** + 0x30E0, // **##****###* **** + 0x3180, // **##***##*** **** + 0x3700, // **##*###**** **** + 0x3C00, // **####****** **** + 0x3700, // **##*###**** **** + 0x3180, // **##***##*** **** + 0x30E0, // **##****###* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x4C = L + 0x0000, // ************ **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x4D = M + 0x0000, // ************ **** + 0x70E0, // *###****###* **** + 0x79E0, // *####**####* **** + 0x6F60, // *##*####*##* **** + 0x6660, // *##**##**##* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x4E = N + 0x0000, // ************ **** + 0x7060, // *###*****##* **** + 0x7860, // *####****##* **** + 0x6C60, // *##*##***##* **** + 0x6660, // *##**##**##* **** + 0x6360, // *##***##*##* **** + 0x61E0, // *##****####* **** + 0x60E0, // *##*****###* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x4F = O + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + + { // 0x50 = P + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FC0, // **########** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x51 = Q + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3360, // **##**##*##* **** + 0x1FC0, // ***#######** **** + 0x0180, // *******##*** **** + 0x00E0 // ********###* **** + }, + { // 0x52 = R + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FC0, // **########** **** + 0x3300, // **##**##**** **** + 0x31C0, // **##***###** **** + 0x30E0, // **##****###* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x53 = S + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x54 = T + 0x0000, // ************ **** + 0x7FE0, // *##########* **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x55 = U + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x56 = V + 0x0000, // ************ **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x30C0, // **##****##** **** + 0x30C0, // **##****##** **** + 0x1980, // ***##**##*** **** + 0x0F00, // ****####**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x57 = W + 0x0000, // ************ **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x6660, // *##**##**##* **** + 0x6660, // *##**##**##* **** + 0x6F60, // *##*####*##* **** + 0x39C0, // **###**###** **** + 0x30C0, // **##****##** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x58 = X + 0x0000, // ************ **** + 0x30C0, // **##****##** **** + 0x1980, // ***##**##*** **** + 0x0F00, // ****####**** **** + 0x0600, // *****##***** **** + 0x0F00, // ****####**** **** + 0x1980, // ***##**##*** **** + 0x30C0, // **##****##** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x59 = Y + 0x0000, // ************ **** + 0x6060, // *##******##* **** + 0x30C0, // **##****##** **** + 0x1980, // ***##**##*** **** + 0x0F00, // ****####**** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x5A = Z + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x0180, // *******##*** **** + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0C00, // ****##****** **** + 0x1800, // ***##******* **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x5B = Ä = NC + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x5C = Ö = NC + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x5D = Ü = NC + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x5E = ^ = NC + 0x0600, // *****##***** **** + 0x0F00, // ****####**** **** + 0x1980, // ***##**##*** **** + 0x30C0, // **##****##** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x5F = _ = NC + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x7FE0 // *##########* **** + }, + + { // 0x60 = ° = NC + 0x0000, // ************ **** + 0x0000, // *****####*** **** + 0x0000, // ****##**##** **** + 0x0000, // *****####*** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x61 = a + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x62 = b + 0x0000, // ************ **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x37C0, // **##*#####** **** + 0x3860, // **###****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x63 = c + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0FE0, // ****#######* **** + 0x1800, // ***##******* **** + 0x3000, // **##******** **** + 0x1800, // ***##******* **** + 0x0FE0, // ****#######* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x64 = d + 0x0000, // ************ **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x1F60, // ***#####*##* **** + 0x30E0, // **##****###* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FE0, // ***########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x65 = e + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x66 = f + 0x0000, // ************ **** + 0x07E0, // *****######* **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x3F80, // **#######*** **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x67 = g + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x1F60, // ***#####*##* **** + 0x30E0, // **##****###* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0060, // *********##* **** + 0x1FC0 // ***#######** **** + }, + { // 0x68 = h + 0x0000, // ************ **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x37C0, // **##*#####** **** + 0x3860, // **###****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x69 = i + 0x0000, // ************ **** + 0x0E00, // ****###***** **** + 0x0000, // ************ **** + 0x0E00, // ****###***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x1F80, // ***######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x6A = j + 0x0000, // ************ **** + 0x00E0, // ********###* **** + 0x0000, // ************ **** + 0x01E0, // *******####* **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x0060, // *********##* **** + 0x3060, // **##*****##* **** + 0x1FC0 // ***#######** **** + }, + { // 0x6B = k + 0x0000, // ************ **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x30E0, // **##****###* **** + 0x3180, // **##***##*** **** + 0x3E00, // **#####***** **** + 0x3180, // **##***##*** **** + 0x30E0, // **##****###* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x6C = l + 0x0000, // ************ **** + 0x1E00, // ***####***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x6D = m + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x6DC0, // *##*##*###** **** + 0x6660, // *##**##**##* **** + 0x6660, // *##**##**##* **** + 0x6660, // *##**##**##* **** + 0x6660, // *##**##**##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x6E = n + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x37C0, // **##*#####** **** + 0x3860, // **###****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x6F = o + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + + { // 0x70 = p + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x37C0, // **##*#####** **** + 0x3860, // **###****##* **** + 0x3060, // **##*****##* **** + 0x3860, // **###****##* **** + 0x37C0, // **##*#####** **** + 0x3000, // **##******** **** + 0x3000 // **##******** **** + }, + { // 0x71 = q + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x1EC0, // ***####*##** **** + 0x31C0, // **##***###** **** + 0x30C0, // **##****##** **** + 0x31C0, // **##***###** **** + 0x1EC0, // ***####*##** **** + 0x00C0, // ********##** **** + 0x01E0 // *******####* **** + }, + { // 0x72 = r + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x33E0, // **##**#####* **** + 0x3C00, // **####****** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x73 = s + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0060, // *********##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x74 = t + 0x0000, // ************ **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x3F80, // **#######*** **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x0C00, // ****##****** **** + 0x07E0, // *****######* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x75 = u + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x76 = v + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x6060, // *##******##* **** + 0x30C0, // **##****##** **** + 0x1980, // ***##**##*** **** + 0x0F00, // ****####**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x77 = w + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x6060, // *##******##* **** + 0x6660, // *##**##**##* **** + 0x6660, // *##**##**##* **** + 0x36C0, // **##*##*##** **** + 0x2980, // ***##**##*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x78 = x + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x70E0, // *###****###* **** + 0x1980, // ***##**##*** **** + 0x0F00, // ****####**** **** + 0x1980, // ***##**##*** **** + 0x70E0, // *###****###* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x79 = y + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x18C0, // ***##***##** **** + 0x0D80, // ****##*##*** **** + 0x0700, // *****###**** **** + 0x0600, // *****##***** **** + 0x0C00, // ****##****** **** + 0x3800 // **###******* **** + }, + { // 0x7A = z + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x3FE0, // **#########* **** + 0x0180, // *******##*** **** + 0x0700, // *****###**** **** + 0x0C00, // ****##****** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x7B = ä = NC + 0x0000, // ************ **** + 0x3180, // **##***##*** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x7C = ö = NC + 0x0000, // ************ **** + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x7D = ü = NC + 0x0000, // ************ **** + 0x10C0, // ***##***##** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x7E = ß = NC + 0x0000, // ************ **** + 0x0F80, // ****#####*** **** + 0x18C0, // ***##***##** **** + 0x30C0, // **##****##** **** + 0x3380, // **##**###*** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x33C0, // **##**####** **** + 0x3000, // **##******** **** + 0x3000 // **##******** **** + }, + { // 0x7F = Block + 0x0000, // ************ **** + 0x7FE0, // *##########* **** + 0x7FE0, // *##########* **** + 0x7FE0, // *##########* **** + 0x7FE0, // *##########* **** + 0x7FE0, // *##########* **** + 0x7FE0, // *##########* **** + 0x7FE0, // *##########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + + { // 0x80 = + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x63E0, // *##***#####* **** + 0x6660, // *##**##**##* **** + 0x6660, // *##**##**##* **** + 0x63E0, // *##***#####* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000 // ************ **** + }, + { // 0x81 = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x82 = + 0x0000, // ************ **** + 0x3000, // **##******** **** + 0x7000, // *###******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3180, // **##***##*** **** + 0x0300, // ******##**** **** + 0x0660, // *****##**##* **** + 0x07E0, // *****######* **** + 0x0060 // *********##* **** + }, + { // 0x83 = + 0x0000, // ************ **** + 0x0FC0, // ****######** **** + 0x1860, // ***##****##* **** + 0x0C00, // ****##****** **** + 0x3F00, // **######**** **** + 0x0C00, // ****##****** **** + 0x3E60, // **#####**##* **** + 0x33C0, // **##**####** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x84 = + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x6660, // *##**##**##* **** + 0x6600, // *##**##***** **** + 0x3FC0, // **########** **** + 0x0660, // *****##**##* **** + 0x6660, // *##**##**##* **** + 0x3FC0, // **########** **** + 0x0600, // *****##***** **** + 0x0000 // ************ **** + }, + { // 0x85 = + 0x07F0, // *****####### **** + 0x0C00, // ****##****** **** + 0x19F0, // ***##**##### **** + 0x1800, // ***##******* **** + 0x19F0, // ***##**##### **** + 0x1800, // ***##******* **** + 0x19F0, // ***##**##### **** + 0x0C00, // ****##****** **** + 0x07F0, // *****####### **** + 0x0000 // ************ **** + }, + { // 0x86 = + 0xFFC0, // ##########** **** + 0x1C60, // ***###***##* **** + 0x0830, // ****#*****## **** + 0x7F30, // *#######**## **** + 0x4130, // *#*****#**## **** + 0x7F30, // *#######**## **** + 0x0830, // ****#*****## **** + 0x1C60, // ***###***##* **** + 0xFFC0, // ##########** **** + 0x0000 // ************ **** + }, + { // 0x87 = + 0xFFC0, // ##########** **** + 0x0060, // *********##* **** + 0x3E30, // **#####***## **** + 0x6330, // *##***##**## **** + 0x0E30, // ****###***## **** + 0x1830, // ***##*****## **** + 0x1830, // ***##*****## **** + 0x0060, // *********##* **** + 0xFFC0, // ##########** **** + 0x0000 // ************ **** + }, + { // 0x88 = + 0x0000, // ************ **** + 0x3980, // ***##**##*** **** + 0x3980, // ***##**##*** **** + 0x3980, // ***##**##*** **** + 0x3980, // ***##**##*** **** + 0x3980, // ***##**##*** **** + 0x3980, // ***##**##*** **** + 0x3980, // ***##**##*** **** + 0x3980, // ***##**##*** **** + 0x0000 // ************ **** + }, + { // 0x89 = + 0x0000, // ************ **** + 0x7C00, // *#####****** **** + 0x0C00, // ****##****** **** + 0x3800, // **###******* **** + 0x0C00, // ****##****** **** + 0x7980, // *####**##*** **** + 0x0300, // ******##**** **** + 0x0660, // *****##**##* **** + 0x07E0, // *****######* **** + 0x0060 // *********##* **** + }, + { // 0x8A = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x8B = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x1C00, // ***###****** **** + 0x7FF0, // *########### **** + 0x1C00, // ***###****** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x8C = + 0x0000, // ************ **** + 0x3000, // **##******** **** + 0x7000, // *###******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x33C0, // **##**####** **** + 0x0660, // *****##**##* **** + 0x00C0, // ********##** **** + 0x0300, // ******##**** **** + 0x07E0 // *****######* **** + }, + { // 0x8D = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0380, // ******###*** **** + 0xFFE0, // ###########* **** + 0x0380, // ******###*** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x8E = + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0F00, // ****####**** **** + 0x1F80, // ***######*** **** + 0x36C0, // **##*##*##** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600 // *****##***** **** + }, + { // 0x8F = + 0x0000, // ************ **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x0000 // ************ **** + }, + + { // 0x90 = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x3000, // **##******** **** + 0x3F80, // **#######*** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x91 = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x92 = + 0x0000, // ************ **** + 0x3180, // **##***##*** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x93 = + 0x0000, // ************ **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x0000 // ************ **** + }, + { // 0x94 = + 0x0000, // ************ **** + 0x6060, // *##******##* **** + 0x30C0, // **##****##** **** + 0x1F80, // ***######*** **** + 0x30C0, // **##****##** **** + 0x30C0, // **##****##** **** + 0x1F80, // ***######*** **** + 0x30C0, // **##****##** **** + 0x6060, // *##******##* **** + 0x0000 // ************ **** + }, + { // 0x95 = + 0xFFC0, // ##########** **** + 0x0060, // *********##* **** + 0xFF30, // ########**## **** + 0x0030, // **********## **** + 0xFF30, // ########**## **** + 0x0030, // **********## **** + 0xFF30, // ########**## **** + 0x0060, // *********##* **** + 0xFFC0, // ##########** **** + 0x0000 // ************ **** + }, + { // 0x96 = + 0xFFC0, // ##########** **** + 0x0060, // *********##* **** + 0x3E30, // **#####***## **** + 0x4730, // *#***###**## **** + 0x4730, // *#***###**## **** + 0x7F30, // *#######**## **** + 0x3E30, // **#####***## **** + 0x0060, // *********##* **** + 0xFFC0, // ##########** **** + 0x0000 // ************ **** + }, + { // 0x97 = + 0xFFC0, // ##########** **** + 0x0860, // ****#****##* **** + 0x1C30, // ***###****## **** + 0x0030, // **********## **** + 0x7F30, // *#######**## **** + 0x0030, // **********## **** + 0x1C30, // ***###****## **** + 0x0860, // ****#****##* **** + 0xFFC0, // ##########** **** + 0x0000 // ************ **** + }, + { // 0x98 = + 0x0000, // ************ **** + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x99 = + 0x0E00, // ****###***** **** + 0x1B00, // ***##*##**** **** + 0x0E00, // ****###***** **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x9A = + 0x0000, // ************ **** + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x9B = + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x9C = + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x9D = + 0x0700, // *****###**** **** + 0x0700, // *****###**** **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x9E = + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0x9F = _ + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x7FE0 // *##########* **** + }, + + + { // 0xA0 = 0x20a + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA1 = 0x21a + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA2 = 0x22a + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA3 = 0x23a + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA4 = 0x24a + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA5 = 0x25a + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA6 = 0x26a + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA7 = 0x27a + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA8 = 0x28a + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xA9 = 0x29a + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xAA = 0x2Aa + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xAB = 0x2Ba + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xAC = 0x2Ca + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xAD = 0x2Da + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xAE = 0x2Ea + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xAF = 0x2Fa + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + + { // 0xB0 = 0x30a + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB1 = 0x31a + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB2 = 0x32a + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB3 = 0x33a + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB4 = 0x34a + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB5 = 0x35a + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB6 = 0x36a + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB7 = 0x37a + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB8 = 0x38a + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xB9 = 0x39a + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xBA = 0x3Aa + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xBB = 0x3Ba + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xBC = 0x3Ca + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xBD = 0x3Da + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xBE = 0x3Ea + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + { // 0xBF = 0x3Fa + 0xFFFF, // ############ **** + 0xFFFF, // ############ **** + 0xFFFF, // ############ **** + 0xFFFF, // ############ **** + 0xFFFF, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00 // ######****** **** + }, + + { // 0xC0 = + 0x0600, // *****##***** **** + 0x0C00, // ****##****** **** + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x6060, // *##******##* **** + 0x7FE0, // *##########* **** + 0x6000, // *##********* **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xC1 = + 0x0600, // *****##***** **** + 0x0300, // ******##**** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000 // ************ **** + }, + { // 0xC2 = + 0x0C00, // ****##****** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xC3 = + 0x0000, // ************ **** + 0x0FC0, // ****######** **** + 0x1860, // ***##****##* **** + 0x0C00, // ****##****** **** + 0x3F00, // **######**** **** + 0x0C00, // ****##****** **** + 0x3E60, // **#####**##* **** + 0x33C0, // **##**####** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xC4 = + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x6660, // *##**##**##* **** + 0x6600, // *##**##***** **** + 0x3FC0, // **########** **** + 0x0660, // *****##**##* **** + 0x6660, // *##**##**##* **** + 0x3F60, // **########** **** + 0x06C0, // *****##***** **** + 0x0000 // ************ **** + }, + { // 0xC5 = + 0x3CC0, // **####**##** **** + 0x6780, // *##**####*** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xC6 = + 0x3C60, // **####***##* **** + 0x67C0, // *##**#####** **** + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xC7 = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xC8 = + 0x0600, // *****##***** **** + 0x0300, // ******##**** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xC9 = + 0x0600, // *****##***** **** + 0x0300, // ******##**** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xCA = + 0x0C00, // ****##****** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0E00, // ****###***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x1F80, // ***######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xCB = + 0x0000, // ************ **** + 0x0780, // *****####*** **** + 0x0CC0, // ****##**##** **** + 0x0780, // *****####*** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xCC = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0FE0, // ****#######* **** + 0x1800, // ***##******* **** + 0x3000, // **##******** **** + 0x1800, // ***##******* **** + 0x0FE0, // ****#######* **** + 0x0300, // ******##**** **** + 0x0E00 // ****###***** **** + }, + { // 0xCD = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0310, // ******###*** **** + 0xFFE0, // ###########* **** + 0x0310, // ******###*** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xCE = + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0F00, // ****####**** **** + 0x1F80, // ***######*** **** + 0x36C0, // **##*##*##** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600 // *****##***** **** + }, + { // 0xCF = + 0x0000, // ************ **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x0000 // ************ **** + }, + + { // 0xD0 = + 0x0C00, // ****##****** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD1 = + 0x0600, // *****##***** **** + 0x0300, // ******##**** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD2 = + 0x0E00, // ****###***** **** + 0x1B00, // ***##*##**** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD3 = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD4 = + 0x0000, // ************ **** + 0x1980, // ***##**##*** **** + 0x0000, // ************ **** + 0x0E00, // ****###***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x1F80, // ***######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD5 = + 0x1E60, // ***####**##* **** + 0x33C0, // **##**####** **** + 0x1F80, // ***######*** **** + 0x30C0, // **##****##** **** + 0x6060, // *##******##* **** + 0x7FE0, // *##########* **** + 0x6060, // *##******##* **** + 0x6060, // *##******##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD6 = + 0x1E60, // ***####**##* **** + 0x33C0, // **##**####** **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD7 = + 0x0000, // ************ **** + 0x0FC0, // ****######** **** + 0x1860, // ***##****##* **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x1860, // ***##****##* **** + 0x0FC0, // ****######** **** + 0x0300, // ******##**** **** + 0x0E00 // ****###***** **** + }, + { // 0xD8 = + 0x0700, // *****###**** **** + 0x0D80, // ****##*##*** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xD9 = + 0x0700, // *****###**** **** + 0x0D80, // ****##*##*** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xDA = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0FE0, // ****#######* **** + 0x1800, // ***##******* **** + 0x3000, // **##******** **** + 0x1800, // ***##******* **** + 0x0FE0, // ****#######* **** + 0x0300, // ******##**** **** + 0x0E00 // ****###***** **** + }, + { // 0xDB = + 0x0000, // ************ **** + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xDC = + 0x0700, // *****###**** **** + 0x0D80, // ****##*##*** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xDD = + 0x0600, // *****##***** **** + 0x0300, // ******##**** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xDE = + 0x0F00, // ****####**** **** + 0x1980, // ***##**##*** **** + 0x0000, // ************ **** + 0x0E00, // ****###***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x1F80, // ***######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xDF = + 0x0000, // ************ **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x7FE0, // *##########* **** + 0x1980, // ***##**##*** **** + 0x1980, // ***##**##*** **** + 0x0000 // ************ **** + }, + + { // 0xE0 = + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xE1 = + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0600, // *****##***** **** + 0x1800, // ***##******* **** + 0x30C0, // **##****##** **** + 0x30C0, // **##****##** **** + 0x1F00, // ***######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xE2 = + 0x0000, // ************ **** + 0x18C0, // ***##***##** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xE3 = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0FE0, // ****#######* **** + 0x1800, // ***##******* **** + 0x3000, // **##******** **** + 0x1800, // ***##******* **** + 0x0FE0, // ****#######* **** + 0x0300, // ******##**** **** + 0x0E00 // ****###***** **** + }, + { // 0xE4 = + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x6660, // *##**##**##* **** + 0x6600, // *##**##***** **** + 0x3FC0, // **########** **** + 0x0660, // *****##**##* **** + 0x6660, // *##**##**##* **** + 0x3FC0, // **########** **** + 0x0600, // *****##***** **** + 0x0000 // ************ **** + }, + { // 0xE5 = + 0x0000, // ************ **** + 0x3F80, // **#######*** **** + 0x6180, // *##****##*** **** + 0x6180, // *##****##*** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x7FE0, // *##########* **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xE6 = + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xE7 = + 0x1E60, // ***####**##* **** + 0x33C0, // **##**####** **** + 0x3860, // **###****##* **** + 0x3C60, // **####***##* **** + 0x3660, // **##*##**##* **** + 0x3360, // **##**##*##* **** + 0x31E0, // **##***####* **** + 0x30E0, // **##****###* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xE8 = + 0x1E60, // ***####**##* **** + 0x33C0, // **##**####** **** + 0x0000, // ************ **** + 0x37C0, // **##*#####** **** + 0x3860, // **###****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xE9 = + 0x0600, // *****##***** **** + 0x0300, // ******##**** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xEA = + 0x0C00, // ****##****** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xEB = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x7F80, // *########*** **** + 0x00C0, // ********##** **** + 0x3FC0, // **########** **** + 0x60C0, // *##*****##** **** + 0x3FE0, // **#########* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xEC = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3000, // **##******** **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xED = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x0E00, // ****###***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x1F80, // ***######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xEE = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xEF = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x0000, // ************ **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x30E0, // **##****###* **** + 0x1F60, // ***#####*##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + + { // 0xF0 = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF1 = + 0x0C00, // ****##****** **** + 0x0600, // *****##***** **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3FE0, // **#########* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF2 = + 0x0C00, // ****##****** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x3000, // **##******** **** + 0x3F00, // **######**** **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF3 = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF4 = + 0x19C0, // ***##**##*** **** + 0x0000, // ************ **** + 0x3FC0, // **########** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x0600, // *****##***** **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF5 = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF6 = + 0x0600, // *****##***** **** + 0x0300, // ******##**** **** + 0x1FC0, // ***#######** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF7 = + 0x0300, // ******##**** **** + 0x0600, // *****##***** **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x3060, // **##*****##* **** + 0x1FC0, // ***#######** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF8 = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x3DC0, // **####*###** **** + 0x0660, // *****##**##* **** + 0x3FE0, // **#########* **** + 0x6600, // *##**##***** **** + 0x3FC0, // **########** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xF9 = + 0x0000, // ************ **** + 0x0FE0, // ****#######* **** + 0x1B00, // ***##*##**** **** + 0x3300, // **##**##**** **** + 0x7FC0, // *#########** **** + 0x6300, // *##***##**** **** + 0x6300, // *##***##**** **** + 0x63E0, // *##***#####* **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xFA = + 0x0000, // ************ **** + 0x0300, // ******##**** **** + 0x0FC0, // ****######** **** + 0x0180, // *******##*** **** + 0x1FC0, // ***#######** **** + 0x30C0, // **##****##** **** + 0x30C0, // **##****##** **** + 0x1F80, // ***######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xFB = + 0x0000, // ************ **** + 0x3F80, // **#######*** **** + 0x30C0, // **##****##** **** + 0x3060, // **##*****##* **** + 0x7C60, // *#####***##* **** + 0x3060, // **##*****##* **** + 0x30C0, // **##****##** **** + 0x3F80, // **#######*** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + { // 0xFC = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0180, // *******##*** **** + 0x3FC0, // **########** **** + 0x6360, // *##***##*##* **** + 0x6660, // *##**##**##* **** + 0x6C60, // *##*##***##* **** + 0x3FC0, // **########** **** + 0x1800, // ***##******* **** + 0x0000 // ************ **** + }, + { // 0xFD = + 0x0060, // *********##* **** + 0x3FC0, // **########** **** + 0x61E0, // *##****####* **** + 0x6360, // *##***##*##* **** + 0x6660, // *##**##**##* **** + 0x6C60, // *##*##***##* **** + 0x7860, // *####****##* **** + 0x3FC0, // **########** **** + 0x6000, // *##********* **** + 0x0000 // ************ **** + }, + { // 0xFE = + 0x0000, // ************ **** + 0x3000, // **##******** **** + 0x3000, // **##******** **** + 0x3F80, // **#######*** **** + 0x30C0, // **##****##** **** + 0x30C0, // **##****##** **** + 0x30C0, // **##****##** **** + 0x3F80, // **#######*** **** + 0x3000, // **##******** **** + 0x3000 // **##******** **** + }, + { // 0xFF = + 0x3C00, // **####****** **** + 0x1800, // ***##******* **** + 0x1F80, // ***######*** **** + 0x18C0, // ***##***##** **** + 0x18C0, // ***##***##** **** + 0x1F80, // ***######*** **** + 0x1800, // ***##******* **** + 0x3C00, // **####****** **** + 0x0000, // ************ **** + 0x0000 // ************ **** + }, + + { // 0x60a = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x61a = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x62a = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x63a = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x64a = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x65a = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x66a = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x67a = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x68a = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x69a = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x6Aa = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x6Ba = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x6Ca = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x6Da = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x6Ea = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + { // 0x6Fa = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0 // ******###### **** + }, + + { // 0x70a = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x71a = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x72a = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x73a = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x74a = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x75a = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x76a = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x77a = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x78a = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x79a = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x7Aa = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x7Ba = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x7Ca = + 0x0000, // ************ **** + 0x0000, // ************ **** + 0x0000, // ************ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x7Da = + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFC00, // ######****** **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x7Ea = + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0x03F0, // ******###### **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0 // ############ **** + }, + { // 0x7Fa = + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + 0xFFF0, // ############ **** + } +}; + + + +int NationalOptionSubsetG0Default[13]= + {0x23,0x94,0x80,0 ,0 ,0 ,0x5e,0x5f,0 ,0 ,0 ,0 ,0 }; + +int NationalOptionSubsetCZ_SK[13]= + {0x23,0 ,0 ,0 ,0 ,0 ,0xed,0 ,0xec,0xeb,0 ,0xef,0 }; +int NationalOptionSubsetEN[13]= + {0x83,0x24,0x80,0x8b,0x8c,0x8d,0x8e,0x23,0x81,0x82,0x88,0x89,0x8a}; +int NationalOptionSubsetEE[13]= + {0x23,0xc6,0 ,0x5b,0x5c,0 ,0x5d,0xd6,0 ,0x7b,0x7c,0 ,0x7d}; +int NationalOptionSubsetFR[13]= + {0xd3,0xd4,0xd0,0xdb,0xdc,0xc1,0xde,0x23,0xd1,0xd2,0xd8,0xd9,0xcc}; +int NationalOptionSubsetDE[13]= + {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e}; +int NationalOptionSubsetIT[13]= + {0x83,0x24,0xd3,0x60,0xcc,0x8d,0x8e,0x23,0xdd,0xc1,0xc8,0xc9,0xca}; +int NationalOptionSubsetLV_LT[13]= + {0x23,0x24,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; +int NationalOptionSubsetPL[13]= + {0x23,0 ,0 ,0 ,0 ,0 ,0 ,0xee,0 ,0 ,0 ,0 ,0 }; +int NationalOptionSubsetPT_ES[13]= + {0xcc,0x24,0xe0,0xeb,0xec,0xed,0xee,0xef,0xe1,0x7d,0xe8,0xc9,0xc2}; +int NationalOptionSubsetRO[13]= + {0x23,0x94,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0xd2,0 ,0 ,0xde}; +int NationalOptionSubsetSR_HR_SL[13]= + {0x23,0 ,0 ,0 ,0 ,0xfb,0 ,0xdb,0 ,0 ,0 ,0 ,0 }; +int NationalOptionSubsetSV_FI[13]= + {0x23,0x94,0x90,0x5b,0x5c,0x9d,0x5d,0x5f,0x91,0x7b,0x7c,0x99,0x7d}; +int NationalOptionSubsetTR[13]= + {0 ,0 ,0 ,0 ,0x5c,0xd7,0x5d,0 ,0 ,0 ,0x7c,0xcc,0x7d}; + + + +inline int NationalOptionSubset(int chr) { + switch (chr) { + case 0x23: return 0; + case 0x24: return 1; + case 0x40: return 2; + case 0x5b: return 3; + case 0x5c: return 4; + case 0x5d: return 5; + case 0x5e: return 6; + case 0x5f: return 7; + case 0x60: return 8; + case 0x7b: return 9; + case 0x7c: return 10; + case 0x7d: return 11; + case 0x7e: return 12; + } + return -1; +} + +inline unsigned int LeftBits(unsigned int bits) { + // Scale bit positions 0xfc00 to 0xfff0 positions + unsigned int res=0; + if (bits&0x8000) res|=0xC000; + if (bits&0x4000) res|=0x3000; + if (bits&0x2000) res|=0x0C00; + if (bits&0x1000) res|=0x0300; + if (bits&0x0800) res|=0x00C0; + if (bits&0x0400) res|=0x0030; + return res; +} +inline unsigned int RightBits(unsigned int bits) { + // Scale bit positions 0x03f0 to 0xfff0 positions + unsigned int res=0; + if (bits&0x0200) res|=0xC000; + if (bits&0x0100) res|=0x3000; + if (bits&0x0080) res|=0x0C00; + if (bits&0x0040) res|=0x0300; + if (bits&0x0020) res|=0x00C0; + if (bits&0x0010) res|=0x0030; + return res; +} + + + +unsigned int* GetFontChar(cTeletextChar c, unsigned int *buffer) { + // Get character bitmap for character/charset + + enumCharsets font=c.GetCharset(); + int chr=c.GetChar(); + unsigned int *bitmap=NULL; + int i; + int NationalOption=NationalOptionSubset(chr); + + switch (font) { + case CHARSET_LATIN_G0: + if (NationalOption>=0) { + if (NationalOptionSubsetG0Default[NationalOption]>0) + bitmap=TXT_Font[NationalOptionSubsetG0Default[NationalOption]-0x20]; + } else { + if (chr>=0x20 && chr<0x80) { + bitmap=TXT_Font[chr-0x20]; + } + } + break; + case CHARSET_LATIN_G0_EN: + if (NationalOption>=0) { + if (NationalOptionSubsetEN[NationalOption]>0) + bitmap=TXT_Font[NationalOptionSubsetEN[NationalOption]-0x20]; + } else { + if (chr>=0x20 && chr<0x80) { + bitmap=TXT_Font[chr-0x20]; + } + } + break; + case CHARSET_LATIN_G0_FR: + if (NationalOption>=0) { + if (NationalOptionSubsetFR[NationalOption]>0) + bitmap=TXT_Font[NationalOptionSubsetFR[NationalOption]-0x20]; + } else { + if (chr>=0x20 && chr<0x80) { + bitmap=TXT_Font[chr-0x20]; + } + } + break; + case CHARSET_LATIN_G0_IT: + if (NationalOption>=0) { + if (NationalOptionSubsetIT[NationalOption]>0) + bitmap=TXT_Font[NationalOptionSubsetIT[NationalOption]-0x20]; + } else { + if (chr>=0x20 && chr<0x80) { + bitmap=TXT_Font[chr-0x20]; + } + } + break; + case CHARSET_LATIN_G0_PT_ES: + if (NationalOption>=0) { + if (NationalOptionSubsetPT_ES[NationalOption]>0) + bitmap=TXT_Font[NationalOptionSubsetPT_ES[NationalOption]-0x20]; + } else { + if (chr>=0x20 && chr<0x80) { + bitmap=TXT_Font[chr-0x20]; + } + } + break; + case CHARSET_LATIN_G0_SV_FI: + if (NationalOption>=0) { + if (NationalOptionSubsetSV_FI[NationalOption]>0) + bitmap=TXT_Font[NationalOptionSubsetSV_FI[NationalOption]-0x20]; + } else { + if (chr>=0x20 && chr<0x80) { + bitmap=TXT_Font[chr-0x20]; + } + } + break; + case CHARSET_LATIN_G0_DE: + if (chr>=0x20 && chr<0x80) { + bitmap=TXT_Font[chr-0x20]; + } + break; + case CHARSET_LATIN_G0_CZ_SK: + case CHARSET_LATIN_G0_EE: + case CHARSET_LATIN_G0_LV_LT: + case CHARSET_LATIN_G0_PL: + case CHARSET_LATIN_G0_RO: + case CHARSET_LATIN_G0_SR_HR_SL: + case CHARSET_LATIN_G0_TR: + // Partially supported latin charsets + if (chr>=0x20 && chr<0x80 && NationalOption<0) { + bitmap=TXT_Font[chr-0x20]; + } + break; + + case CHARSET_LATIN_G2: + case CHARSET_CYRILLIC_G0_SR_HR: + case CHARSET_CYRILLIC_G0_RU_BG: + case CHARSET_CYRILLIC_G0_UK: + case CHARSET_CYRILLIC_G2: + case CHARSET_GREEK_G0: + case CHARSET_GREEK_G2: + case CHARSET_ARABIC_G0: + case CHARSET_ARABIC_G2: + case CHARSET_HEBREW_G0: + // totally unsupported + break; + + case CHARSET_GRAPHICS_G1: + if (chr>=0x20 && chr<0x40) { + bitmap=TXT_Font[chr-0x20+0x80]; + } else if (chr>=0x60 && chr<0x80) { + bitmap=TXT_Font[chr-0x60+0xE0]; + } + break; + case CHARSET_GRAPHICS_G1_SEP: + if (chr>=0x20 && chr<0x40) { + bitmap=TXT_Font[chr-0x20+0x80]; + } else if (chr>=0x60 && chr<0x80) { + bitmap=TXT_Font[chr-0x60+0xE0]; + } + if (bitmap) { + for (i=0;i<10;i++) buffer[i]=bitmap[i]&TXT_Mask[i]; + bitmap=buffer; + } + break; + + case CHARSET_GRAPHICS_G3: + case CHARSET_INVALID: + // Totally unsupported + break; + } + + + + if (!buffer) { + printf("Warning: Undefined char: %x %x\n",font,chr); + return NULL; + } + + switch (c.GetDblHeight()) { + case dblh_Top: + // Scale top 5 lines to full height + buffer[8]=buffer[9]=bitmap[4]; + buffer[6]=buffer[7]=bitmap[3]; + buffer[4]=buffer[5]=bitmap[2]; + buffer[2]=buffer[3]=bitmap[1]; + buffer[1]=buffer[0]=bitmap[0]; + bitmap=buffer; + break; + case dblh_Bottom: + // Scale bottom 5 lines to full height + buffer[0]=buffer[1]=bitmap[5]; + buffer[2]=buffer[3]=bitmap[6]; + buffer[4]=buffer[5]=bitmap[7]; + buffer[6]=buffer[7]=bitmap[8]; + buffer[8]=buffer[9]=bitmap[9]; + bitmap=buffer; + default:; + } + + switch (c.GetDblWidth()) { + case dblw_Left: + // Scale 6 left columns to full width + buffer[0]=LeftBits(bitmap[0]); + buffer[1]=LeftBits(bitmap[1]); + buffer[2]=LeftBits(bitmap[2]); + buffer[3]=LeftBits(bitmap[3]); + buffer[4]=LeftBits(bitmap[4]); + buffer[5]=LeftBits(bitmap[5]); + buffer[6]=LeftBits(bitmap[6]); + buffer[7]=LeftBits(bitmap[7]); + buffer[8]=LeftBits(bitmap[8]); + buffer[9]=LeftBits(bitmap[9]); + bitmap=buffer; + break; + case dblw_Right: + // Scale 6 right columns to full width + buffer[0]=RightBits(bitmap[0]); + buffer[1]=RightBits(bitmap[1]); + buffer[2]=RightBits(bitmap[2]); + buffer[3]=RightBits(bitmap[3]); + buffer[4]=RightBits(bitmap[4]); + buffer[5]=RightBits(bitmap[5]); + buffer[6]=RightBits(bitmap[6]); + buffer[7]=RightBits(bitmap[7]); + buffer[8]=RightBits(bitmap[8]); + buffer[9]=RightBits(bitmap[9]); + bitmap=buffer; + default:; + } + + return bitmap; +} diff --git a/txtfont.h b/txtfont.h new file mode 100644 index 0000000..c2b73f4 --- /dev/null +++ b/txtfont.h @@ -0,0 +1,14 @@ +#ifndef __TXTFONT_H +#define __TXTFONT_H + +#include "txtrender.h" + +unsigned int* GetFontChar(cTeletextChar c, unsigned int *buffer); +// Get a character bitmap for character/charset +// Also handle double width/height partial characters +// buffer must be an unsigned int[10] buffer, that *may* be used +// to store the character - a different pointer may be returned too. +// returns NULL if undefined character + + +#endif diff --git a/txtrecv.c b/txtrecv.c new file mode 100644 index 0000000..af76a3a --- /dev/null +++ b/txtrecv.c @@ -0,0 +1,884 @@ +/*************************************************************************** + * Copyright (c) 2003,2004 by Marcel Wiesweg * + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include "txtrecv.h" +#include "tables.h" +#include "setup.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +const char *RootDir::root = "/vtx"; + +void RootDir::setRootDir(const char *newRoot) { + root=newRoot; +} + +const char *RootDir::getRootDir() { + return root; +} + +int Storage::doCleanUp() { + DIR *top=opendir(root); + int pagesDeleted=0; + if (top) { + struct dirent *chandir, path; + struct stat chandirstat; + char fullPath[PATH_MAX]; + while ( (!readdir_r(top, &path, &chandir) && chandir != NULL) ) { + if (strcmp(chandir->d_name, "..")==0 || strcmp(chandir->d_name, ".")==0) + continue; + snprintf(fullPath, PATH_MAX, "%s/%s", root, chandir->d_name); + if (stat(fullPath, &chandirstat)==0) { + if (S_ISDIR(chandirstat.st_mode)) { + pagesDeleted+=cleanSubDir(fullPath); + } + } + } + closedir(top); + } else { + esyslog("Error opening teletext storage directory \"%s\": %s", root, strerror(errno)); + } + return pagesDeleted; +} + +int Storage::cleanSubDir(const char *dir) { + static bool reportedError=false; //avoid filling up syslog + DIR *d=opendir(dir); + bool hadError=false; + int bytesDeleted=0, filesize; + if (d) { + struct dirent *txtfile, path; + struct stat txtfilestat; + char fullPath[PATH_MAX]; + while ( (!readdir_r(d, &path, &txtfile) && txtfile != NULL) ) { + int len=strlen(txtfile->d_name); + //check that the file end with .vtx to avoid accidents and disasters + if (strcmp(txtfile->d_name+len-4, ".vtx")==0) { + snprintf(fullPath, PATH_MAX, "%s/%s", dir, txtfile->d_name); + stat(fullPath, &txtfilestat); + filesize=actualFileSize(txtfilestat.st_size); + int ret=unlink(fullPath); + if (ret==0) + bytesDeleted+=filesize; + else + hadError=ret; + } + } + closedir(d); + rmdir(dir); + } else { + if (!reportedError) { + esyslog("OSD-Teletext: Error opening teletext storage subdirectory \"%s\": %s", dir, strerror(errno)); + reportedError=true; + } + } + + if (hadError && !reportedError) { + esyslog("OSD-Teletext: Error removing teletext storage subdirectory \"%s\": %s", dir, strerror(hadError)); + reportedError=true; + } + return bytesDeleted; +} + +Storage *Storage::s_self = 0; +Storage::StorageSystem Storage::system = Storage::StorageSystemPacked; + +Storage::Storage() { + s_self=this; + byteCount=0; + currentDir=0; + storageOption=-1; + failedFreeSpace=false; +} + +Storage::~Storage() { +} + +void Storage::setSystem(StorageSystem s) { + system=s; +} + +Storage *Storage::instance() { + if (!s_self) { + switch (system) { + case StorageSystemLegacy: + s_self=new LegacyStorage(); + break; + case StorageSystemPacked: + default: + s_self=new PackedStorage(); + break; + } + } + return s_self; +} + +void Storage::setMaxStorage(int maxMB) { + storageOption=maxMB; +} + +void Storage::init() { + cleanUp(); + initMaxStorage(storageOption); +} + +void Storage::freeSpace() { + //there might be a situation where only the current directory is left and + //occupies the whole space. We cannot delete anything. Don't waste time scanning. + if (failedFreeSpace) + return; + + //printf("freeSpace()\n"); + time_t min=time(0); + char minDir[PATH_MAX]; + char fullPath[PATH_MAX]; + int haveDir=0; + DIR *top=opendir(getRootDir()); + if (top) { + struct dirent *chandir, path; + struct stat chandirstat; + while ( (!readdir_r(top, &path, &chandir) && chandir != NULL) ) { + if (strcmp(chandir->d_name, "..")==0 || strcmp(chandir->d_name, ".")==0) + continue; + snprintf(fullPath, PATH_MAX, "%s/%s", getRootDir(), chandir->d_name); + if (stat(fullPath, &chandirstat)==0) { + if (S_ISDIR(chandirstat.st_mode)) { + if (chandirstat.st_ctime < min && strcmp(fullPath, currentDir)) { + min=chandirstat.st_ctime; + strcpy(minDir, fullPath); + haveDir++; + } + } + } + } + closedir(top); + + //if haveDir, only current directory present, which must not be deleted + if (haveDir>=2) + byteCount-=cleanSubDir(minDir); + else + failedFreeSpace=true; + } +} + +bool Storage::exists(const char* file) { + struct stat s; + return (stat(file, &s)==0); +} + +void Storage::getFilename(char *buffer, int bufLength, PageID page) { + snprintf(buffer, bufLength, "%s/%s/%03x_%02x.vtx", getRootDir(), +#if VDRVERSNUM >= 10318 + *page.channel.ToString(), +#else + page.channel.ToString(), +#endif + page.page, page.subPage); +} + +void Storage::prepareDirectory(tChannelID chan) { + free(currentDir); + asprintf(¤tDir, "%s/%s", root, +#if VDRVERSNUM >= 10318 + *chan.ToString() +#else + chan.ToString() +#endif + ); + MakeDirs(currentDir, 1); + failedFreeSpace=false; +} + +#define TELETEXT_PAGESIZE 972 + +LegacyStorage::LegacyStorage() { + maxBytes=0; + fsBlockSize=1; + pageBytes=TELETEXT_PAGESIZE; +} + +LegacyStorage::~LegacyStorage() { +} + +/* +static inline int FilesForMegabytes(double MB, int blocksize) { + double pageBytes; + if (TELETEXT_PAGESIZE<=blocksize) + pageBytes=blocksize; + else + pageBytes=((TELETEXT_PAGESIZE/blocksize)+1)*blocksize; + //reserve 10% for directories + return (int)( (1024.0 * 1024.0 * (MB-MB*0.1)) / pageBytes ); +}*/ + +int LegacyStorage::actualFileSize(int netFileSize) { + if (netFileSize<=0) + return 0; + if (netFileSize<=fsBlockSize) + return fsBlockSize; + else + return ((netFileSize/fsBlockSize)+1)*fsBlockSize; +} + +//max==0 means unlimited, max==-1 means a reasonable default value shall be calculated +void LegacyStorage::initMaxStorage(int maxMB) { + + struct statfs fs; + if (statfs(getRootDir(), &fs)!=0) { + esyslog("OSD-Teletext: Error statfs'ing root directory \"%s\": %s, cache size uncontrolled", getRootDir(), strerror(errno)); + return; + } + fsBlockSize=fs.f_bsize; + + pageBytes=actualFileSize(TELETEXT_PAGESIZE); + + if (maxMB>=0) { + if (maxMB<3) { + esyslog("OSD-Teletext: Request to use at most %d MB for caching. This is not enough, using 3 MB", maxMB); + maxMB=3; + } + maxBytes=MEGABYTE(maxMB); + } else if (maxMB==-1) { + //calculate a default value + double blocksPerMeg = 1024.0 * 1024.0 / fs.f_bsize; + double capacityMB=fs.f_blocks / blocksPerMeg; + double freeMB=(fs.f_bavail / blocksPerMeg); + if (capacityMB<=50 || freeMB<50) { + //small (<=50MB) filesystems as root dir are assumed to be dedicated for use as a teletext cache + //for others, the maximum default size is set to 50 MB + maxBytes=MEGABYTE((int)freeMB); + //maxPages= FilesForMegabytes(freeMB, fs.f_bsize); + if (freeMB<3.0) { + esyslog("OSD-Teletext: Less than %.1f MB free on filesystem of root directory \"%s\"!", freeMB, getRootDir()); + maxBytes=MEGABYTE(3); + } + } else { + //the maximum default size is set to 50 MB + maxBytes=MEGABYTE(50); + } + //printf("Set maxBytes to %ld, %.2f %.2f\n", maxBytes, capacityMB, freeMB); + } +} + +void LegacyStorage::cleanUp() { + byteCount -= Storage::doCleanUp(); +} + +void LegacyStorage::registerFile(PageID page) { + //pageBytes is already effective size + if ( maxBytes && (byteCount+=pageBytes)>maxBytes ) + freeSpace(); +} + +StorageHandle LegacyStorage::openForReading(PageID page, bool countAsAccess) { + //the countAsAccess argument was intended for use in a LRU cache, currently unused + char filename[PATH_MAX]; + getFilename(filename, sizeof(filename), page); + StorageHandle ret=(StorageHandle)open(filename, O_RDONLY); + return ret; +} + +StorageHandle LegacyStorage::openForWriting(PageID page) { + static bool wroteError=false; + char filename[PATH_MAX]; + getFilename(filename, sizeof(filename), page); + bool existed=exists(filename); + //first try + StorageHandle fd=(StorageHandle)open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd) { + if (!existed) + registerFile(page); + return fd; + } + //no space on disk? make some space available + if (errno == ENOSPC) + freeSpace(); + //second try + fd=(StorageHandle)open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (!fd && !wroteError) { + //report error to syslog - once! + wroteError=true; + esyslog("OSD-Teletext: Error opening teletext file %s: %s", filename, strerror(errno)); + } + //make sure newly created files are counted + if (fd && !existed) + registerFile(page); + return fd; +} + +ssize_t LegacyStorage::write(const void *ptr, size_t size, StorageHandle stream) { + ssize_t written; + if (!(written=::write((int)stream, ptr, size)) ) { + switch (errno) { + case ENOSPC: + freeSpace(); + return ::write((int)stream, ptr, size); + case EINTR: + esyslog("OSD-Teletext: EINTR while writing. Please contact the author and tell him this happened."); + break; + default: + break; + } + } + return written; +} + + + +PackedStorage::PackedStorage() { +} +#define TOC_SIZE 8 +//The file structure is simple: +// TOC_SIZE*PageAddress contains the numbers of the following pages +// TOC_SIZE*TELETEXT_PAGESIZE contains the page data +//and the same again. +bool PackedStorage::seekTo(PageID page, int desc, bool create) { + lseek(desc, 0, SEEK_SET); + PageAddress addr[TOC_SIZE]; + + while (::read(desc, addr, sizeof(addr)) == sizeof(addr)) { + lseek(desc, 0, SEEK_CUR); + for (int index=0; index= 10318 + *page.channel.ToString(), +#else + page.channel.ToString(), +#endif + (page.page & 0xFF0)); +} + +StorageHandle PackedStorage::openForWriting(PageID page) { + static bool wroteError=false; + char filename[PATH_MAX]; + getFilename(filename, sizeof(filename), page); + //first try + int desc=open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (desc != -1) { + if (!seekTo(page, desc, true)) { + ::close(desc); + return StorageHandle(); + } + if ( maxBytes && byteCount>maxBytes ) + freeSpace(); + return (StorageHandle)desc; + } + //no space on disk? make some space available + if (errno == ENOSPC) + freeSpace(); + //second try + desc=open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (desc==-1 && !wroteError) { + //report error to syslog - once! + wroteError=true; + esyslog("OSD-Teletext: Error opening teletext file %s: %s", filename, strerror(errno)); + } + + if (desc==-1) + return StorageHandle(); + else if (!seekTo(page, desc, true)) { + ::close(desc); + return StorageHandle(); + } + + if ( maxBytes && byteCount>maxBytes ) + freeSpace(); + return (StorageHandle)desc; +} + +StorageHandle PackedStorage::openForReading(PageID page, bool countAsAccess) { + int desc; + if ( (desc=(int)LegacyStorage::openForReading(page, false))!= -1 ) { + if (!seekTo(page, desc, false)) { + //this is not an error condition here, may and shall happen! + ::close(desc); + } else { + return (StorageHandle)desc; + } + } + return StorageHandle(); +} + + + + +cTelePage::cTelePage(PageID t_page, uchar t_flags, uchar t_lang,int t_mag) + : mag(t_mag), flags(t_flags), lang(t_lang), page(t_page) +{ + memset(pagebuf,' ',26*40); +} + +cTelePage::~cTelePage() { +} + +void cTelePage::SetLine(int line, uchar *myptr) +{ + memcpy(pagebuf+40*line,myptr,40); +} + +void cTelePage::save() +{ + Storage *s=Storage::instance(); + unsigned char buf; + StorageHandle fd; + if ( (fd=s->openForWriting(page)) ) { + s->write("VTXV4",5,fd); + buf=0x01; s->write(&buf,1,fd); + buf=mag; s->write(&buf,1,fd); + buf=page.page; s->write(&buf,1,fd); + buf=flags; s->write(&buf,1,fd); + buf=lang; s->write(&buf,1,fd); + buf=0x00; s->write(&buf,1,fd); + buf=0x00; s->write(&buf,1,fd); + s->write(pagebuf,24*40,fd); + s->close(fd); + } +} + + +cTxtStatus::cTxtStatus(void) +{ + receiver = NULL; + + //running=false; + TPid=0; + /*doNotSuspend=false; + doNotReceive=false;*/ + //suspended=false; +} + +cTxtStatus::~cTxtStatus() +{ + /*if (running) + Cancel(3);*/ + if (receiver) + delete receiver; +} + +void cTxtStatus::ChannelSwitch(const cDevice *Device, int ChannelNumber) +{ + if (Device->IsPrimaryDevice()) { + +/*#ifdef OSDTELETEXT_REINSERTION_PATCH + if (ttSetup.suspendReceiving) { + if (!running) + Start(); + } else if (running) { //setup option changed, apply + running=false; + Cancel(3); + } +#endif*/ + + CheckDeleteReceiver(); + + if (ChannelNumber) { + cChannel *channel = Channels.GetByNumber(ChannelNumber); + if (channel && channel->Tpid()) { +/*#ifdef OSDTELETEXT_REINSERTION_PATCH + cMutexLock MutexLock(&mutex); + count=0; //reset 20 second intervall + condVar.Broadcast(); + //other thread is locked on the mutex until the end of this function! +#endif */ + TPid=channel->Tpid(); + chan=channel->GetChannelID(); + CheckCreateReceiver(); + } + } + } +} + +void cTxtStatus::CheckCreateReceiver() { + if (!receiver && TPid ) { + cChannel *channel = Channels.GetByChannelID(chan); + if (!channel) + return; + //primary device a full-featured card + if (cDevice::PrimaryDevice()->ProvidesChannel(channel, Setup.PrimaryLimit)) { + receiver = new cTxtReceiver(TPid, chan); + cDevice::PrimaryDevice()->AttachReceiver(receiver); + //dsyslog("OSDTeletext: Created teletext receiver for channel %d, PID %d on primary device", ChNum, TPid); + //primary device a DXR3 or similar + } else { + int devNum = cDevice::NumDevices(); + bool bFound = false; + cDevice* pDevice = 0; + for (int i = 0; i < devNum && !bFound; ++i) { + pDevice = cDevice::GetDevice(i); + if (pDevice && pDevice->ProvidesChannel(channel, Setup.PrimaryLimit) && pDevice->Receiving(true)) { + bFound = true; + receiver = new cTxtReceiver(TPid, chan); + pDevice->AttachReceiver(receiver); + //dsyslog("OSDTeletext: Created teletext receiver for channel %d, PID %d on device %d", ChNum, TPid, i); + } + } + if (!bFound) //can this happen? + esyslog("OSDTeletext: Did not find appropriate device for teletext receiver for channel %s, PID %d", channel->Name(), TPid); + } + } +} + +void cTxtStatus::CheckDeleteReceiver() { + if (receiver) { + //dsyslog("OSDTeletext: Deleted teletext receiver"); + delete receiver; +/*#ifdef OSDTELETEXT_REINSERTION_PATCH + //the patch only makes sense if primary device is a DVB card, so no handling for DXR3 + cDevice::PrimaryDevice()->ReinsertTeletextPid(TPid); +#endif*/ + receiver = NULL; + } +} + +/* +//only used for suspending the receiver, if selected by user in setup +void cTxtStatus::Action() { +#ifdef OSDTELETEXT_REINSERTION_PATCH + running=true; + + dsyslog("OSDTeletext waiting thread started with pid %d", getpid()); + + count=0; + + + while (running) { + cMutexLock MutexLock(&mutex); + + if (doNotSuspend) { + CheckCreateReceiver(); + count=0; + } else if (doNotReceive) { + CheckDeleteReceiver(); + count=0; + } else { + count++; + if (count <= 20) + CheckCreateReceiver(); + else if (count < 20+5*60) + CheckDeleteReceiver(); + else + count=0; //if count=20+5*60 + } + + condVar.TimedWait(mutex, 1000); //one second + + } + + running=false; + dsyslog("OSDTeletext waiting thread ended"); + +#endif +} + +//only has an effect when suspending is enabled: +//prevents receiving from suspension when argument is true +//reenables suspension when argument is false, +// but does not necessarily suspend immediately, that is the task of ForceSuspending, +// in contrast to which it does not make any sense if suspending is +// not enabled. +//In clear words: When the plugin is in use, it calls the function +//with onOrOff=true so that data is received continously during the +//TeletextBrowser object's lifetime. When it is destroyed, it releases +//this constraint by calling onOrOff=false. +void cTxtStatus::ForceReceiving(bool onOrOff) { +#ifdef OSDTELETEXT_REINSERTION_PATCH + if (!running) + return; + if (onOrOff && !doNotSuspend) { + cMutexLock MutexLock(&mutex); + doNotSuspend=true; + condVar.Broadcast(); + } else if (!onOrOff && doNotSuspend) { + cMutexLock MutexLock(&mutex); + doNotSuspend=false; + condVar.Broadcast(); + } +#endif +} + +//opposite as above: +//allows to switch off receiving +void cTxtStatus::ForceSuspending(bool onOrOff) { +#ifdef OSDTELETEXT_REINSERTION_PATCH + if (!running) { //thread is not running, suspend anyway + if (onOrOff) { + CheckDeleteReceiver(); + } else { + CheckCreateReceiver(); + } + } else { + doNotSuspend=false; //ForceReceive may have been called before + if (onOrOff && !doNotReceive) { + cMutexLock MutexLock(&mutex); + doNotReceive=true; + condVar.Broadcast(); + } else if (!onOrOff && doNotReceive) { + cMutexLock MutexLock(&mutex); + doNotReceive=false; + condVar.Broadcast(); + } + } +#endif +} +*/ + +cTxtReceiver::cTxtReceiver(int TPid, tChannelID chan) +#if VDRVERSNUM >= 10319 + : cReceiver(0, -1, TPid), +#else + : cReceiver(0, -1, 1, TPid), +#endif + chan(chan), TxtPage(0), buffer((188+60)*75), running(false) +{ + Storage::instance()->prepareDirectory(chan); + // 10 ms timeout on getting TS frames + buffer.SetTimeouts(0, 10); +} + + +cTxtReceiver::~cTxtReceiver() +{ + Detach(); + if (running) { + running=false; + buffer.Signal(); + Cancel(2); + } + buffer.Clear(); + delete TxtPage; +} + +void cTxtReceiver::Activate(bool On) +{ + if (On) { + if (!running) { + running=true; + Start(); + } + } + else if (running) { + running = false; + buffer.Signal(); + Cancel(2); + } +} + +void cTxtReceiver::Receive(uchar *Data, int Length) +{ + int len = Length+60; + + if (!buffer.Check(len)) { + // Buffer overrun + buffer.Signal(); + return; + } + cFrame *frame=new cFrame(Data, len); + if (frame && !buffer.Put(frame)) { + // Buffer overrun + delete frame; + buffer.Signal(); + } +} + +void cTxtReceiver::Action() { + + while (running) { + cFrame *frame=buffer.Get(); + if (frame) { + uchar *Datai=frame->Data(); + + for (int i=0; i < 4; i++) { + if (Datai[4+i*46]==2 || Datai[4+i*46]==3) { + for (int j=(8+i*46);j<(50+i*46);j++) + Datai[j]=invtab[Datai[j]]; + DecodeTXT(&Datai[i*46]); + } + } + + buffer.Drop(frame); + } else + buffer.Wait(); + } + + buffer.Clear(); + running=false; +} + +uchar cTxtReceiver::unham16 (uchar *p) +{ + unsigned short c1,c2; + c1=unhamtab[p[0]]; + c2=unhamtab[p[1]]; + return (c1 & 0x0F) | (c2 & 0x0F) *16; +} + +void cTxtReceiver::DecodeTXT(uchar* TXT_buf) +{ + // Format of buffer: + // 0x00-0x04 ? + // 0x05-0x06 Clock Run-In? + // 0x07 Framing Code? + // 0x08 Magazine number (100-digit of page number) + // 0x09 Line number + // 0x0A..0x31 Line data + // Line 0 only: + // 0x0A 10-digit of page number + // 0x0B 1-digit of page number + // 0x0C Sub-Code bits 0..3 + // 0x0D Sub-Code bits 4..6 + C4 flag + // 0x0E Sub-Code bits 8..11 + // 0x0F Sub-Code bits 12..13 + C5,C6 flag + // 0x10 C7-C10 flags + // 0x11 C11-C14 flags + // + // Flags: + // C4 - Erase last page, new page transmitted + // C5 - News flash, boxed display + // C6 - Subtitle, boxed display + // C7 - Suppress Header, dont show line 0 + // C8 - Update, page has changed + // C9 - Interrupt Sequence, page number is out of order + // C10 - Inhibit Display + // C11 - Magazine Serial mode + // C12-C14 - Language selection, lower 3 bits + + + int hdr,mag,mag8,line; + uchar *ptr; + uchar flags,lang; + + hdr = unham16 (&TXT_buf[0x8]); + mag = hdr & 0x07; + mag8 = mag ?: 8; + line = (hdr>>3) & 0x1f; + ptr = &TXT_buf[10]; + + switch (line) { + case 0: + { + unsigned char b1, b2, b3, b4; + int pgno, subno; + b1 = unham16 (ptr); + // Page no, 10- and 1-digit + + if (b1 == 0xff) break; + if (TxtPage) { + TxtPage->save(); + delete TxtPage; + TxtPage=NULL; + } + + b2 = unham16 (ptr+2); // Sub-code 0..6 + C4 + b3 = unham16 (ptr+4); // Sub-code 8..13 + C5,C6 + b4 = unham16 (ptr+6); // C7..C14 + + // 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=b2 & 0x80; + flags|=(b3&0x40)|((b3>>2)&0x20); //?????? + flags|=((b4<<4)&0x10)|((b4<<2)&0x08)|(b4&0x04)|((b4>>1)&0x02)|((b4>>4)&0x01); + lang=((b4>>5) & 0x07); + + pgno = mag8 * 256 + b1; + subno = (b2 + b3 * 256) & 0x3f7f; // Sub Page Number + + TxtPage = new cTelePage(PageID(chan, pgno, subno), flags, lang, mag); + TxtPage->SetLine((int)line,(uchar *)ptr); + break; + } + case 1 ... 25: + { + if (TxtPage) TxtPage->SetLine((int)line,(uchar *)ptr); + break; + } + /*case 23: + { + if (TxtPage) { + TxtPage->save(); + delete TxtPage; + TxtPage=NULL; + } + break; + }*/ + default: + break; + } +} + + diff --git a/txtrecv.h b/txtrecv.h new file mode 100644 index 0000000..cafb1dd --- /dev/null +++ b/txtrecv.h @@ -0,0 +1,204 @@ +/*************************************************************************** + * Copyright (c) 2003,2004 by Marcel Wiesweg * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __TXTRECV_H +#define __TXTRECV_H + +#include +#include +#include +#include + +#include +#include + +struct PageID { + PageID() { page=subPage=0; } + PageID(tChannelID id, int p, int s) { set(id, p, s); } + void set(tChannelID id, int p, int s) + { channel=id; page=p; subPage=s; } + tChannelID channel; + int page; + int subPage; +}; + +struct StorageHandle { +public: + StorageHandle() { handle=-1; } + StorageHandle(const StorageHandle &s) { handle=s.handle; } + StorageHandle(int h) { handle=h; } + StorageHandle &operator=(int h) { handle=h; return *this; } + StorageHandle &operator=(const StorageHandle &s) { handle=s.handle; return *this; } + operator bool() const { return handle!=-1; } + operator int() const { return handle; } +private: + int handle; +}; + +class RootDir { +public: + static void setRootDir(const char *); + static const char *getRootDir(); +protected: + static const char *root; +}; + +class Storage : public RootDir { +public: + virtual ~Storage(); + enum StorageSystem { StorageSystemLegacy, StorageSystemPacked }; + //must be called before the first call to instance() + static void setSystem(StorageSystem system); + void setMaxStorage(int maxMB=-1); + + static Storage *instance(); + + //must be called before operation starts. Set all options (RootDir, maxStorage) before. + void init(); + virtual void cleanUp() = 0; + + virtual void getFilename(char *buffer, int bufLength, PageID page); + void prepareDirectory(tChannelID chan); + + virtual StorageHandle openForWriting(PageID page) = 0; + virtual StorageHandle openForReading(PageID page, bool countAsAccess) = 0; + virtual ssize_t write(const void *ptr, size_t size, StorageHandle stream) = 0; + virtual ssize_t read(void *ptr, size_t size, StorageHandle stream) = 0; + virtual void close(StorageHandle stream) = 0; +protected: + virtual void initMaxStorage(int maxMB=-1) = 0; + + Storage(); + int cleanSubDir(const char *dir); + int doCleanUp(); + virtual int actualFileSize(int netFileSize) { return netFileSize; } + static Storage *s_self; + void freeSpace(); + bool exists(const char* file); + + long byteCount; + char *currentDir; +private: + static StorageSystem system; + int storageOption; + bool failedFreeSpace; +}; + +class LegacyStorage : public Storage { +public: + LegacyStorage(); + virtual ~LegacyStorage(); + virtual void cleanUp(); + + virtual StorageHandle openForWriting(PageID page); + virtual StorageHandle openForReading(PageID page, bool countAsAccess); + virtual ssize_t write(const void *ptr, size_t size, StorageHandle stream); + virtual ssize_t read(void *ptr, size_t size, StorageHandle stream) + { return ::read((int)stream, ptr, size); } + virtual void close(StorageHandle stream) + { ::close((int)stream); } +protected: + virtual void initMaxStorage(int maxMB=-1); + void registerFile(PageID page); + virtual int actualFileSize(int netFileSize); + //int maxPages; + long maxBytes; + int fsBlockSize; + int pageBytes; +}; + +class PackedStorage : public LegacyStorage { +public: + PackedStorage(); + //virtual void setMaxStorage(int maxMB=-1); + //virtual void cleanUp(); + + virtual void getFilename(char *buffer, int bufLength, PageID page); + virtual StorageHandle openForWriting(PageID page); + virtual StorageHandle openForReading(PageID page, bool countAsAccess); +protected: + struct PageAddress { + bool operator==(const PageID &id) const + { return page==id.page && subPage==id.subPage; } + void operator=(const PageID &id) + { page=id.page; subPage=id.subPage; } + int page; + int subPage; + }; + bool seekTo(PageID page, int fd, bool create); + void registerFile(PageID page); +}; + +class cTelePage { + private: + int mag; + unsigned char flags; + unsigned char lang; + PageID page; + unsigned char pagebuf[27*40]; + char Directory [255]; + public: + cTelePage(PageID page, uchar flags, uchar lang, int mag); + ~cTelePage(); + void SetLine(int, uchar*); + void save(); + }; + +class cRingTxtFrames : public cRingBufferFrame { + public: + cRingTxtFrames(int Size) : cRingBufferFrame(Size, true) {}; + ~cRingTxtFrames() { Clear(); }; + void Wait(void) { WaitForGet(); }; + void Signal(void) { EnableGet(); }; + bool Check(int Size) { return (Free() >= Size); }; +}; + +class cTxtReceiver : public cReceiver, public cThread { +private: + void DecodeTXT(uchar*); + uchar unham16 (uchar*); + tChannelID chan; + cTelePage *TxtPage; +protected: + virtual void Activate(bool On); + virtual void Receive(uchar *Data, int Length); + void Action(); + cRingTxtFrames buffer; + bool running; +public: + cTxtReceiver(int TPid, tChannelID chan); + virtual ~cTxtReceiver(); +}; + +class cTxtStatus : public cStatus/*, public cThread*/ { +private: + cTxtReceiver *receiver; + //bool running; + //cCondVar condVar; + //cMutex mutex; + //int count; +protected: + int TPid; + tChannelID chan; + //bool doNotSuspend; + //bool doNotReceive; + virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); + //virtual void Action(); + void CheckCreateReceiver(); + void CheckDeleteReceiver(); +public: + cTxtStatus(void); + ~cTxtStatus(); + //void ForceReceiving(bool onOrOff); + //void ForceSuspending(bool onOrOff); +}; + + +#endif 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 +#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); + } +} + + diff --git a/txtrender.h b/txtrender.h new file mode 100644 index 0000000..e7da20d --- /dev/null +++ b/txtrender.h @@ -0,0 +1,311 @@ +/*************************************************************************** + * * + * txtrender.h - 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 * + * * + ***************************************************************************/ + +#ifndef OSDTELETEXT_TXTRENDER_H_ +#define OSDTELETEXT_TXTRENDER_H_ + +#include + + +// Teletext character sets +enum enumCharsets { + CHARSET_LATIN_G0 = 0x0000, // native latin (partially todo) + CHARSET_LATIN_G0_CZ_SK = 0x0100, // Czech/Slovak (todo) + CHARSET_LATIN_G0_EN = 0x0200, // English + CHARSET_LATIN_G0_EE = 0x0300, // Estonian (todo) + CHARSET_LATIN_G0_FR = 0x0400, // French + CHARSET_LATIN_G0_DE = 0x0500, // German + CHARSET_LATIN_G0_IT = 0x0600, // Italian + CHARSET_LATIN_G0_LV_LT = 0x0700, // Lettish/Lithuanian (todo) + CHARSET_LATIN_G0_PL = 0x0800, // Polish (todo) + CHARSET_LATIN_G0_PT_ES = 0x0900, // Portugese/Spanish + CHARSET_LATIN_G0_RO = 0x0A00, // Romanian (todo) + CHARSET_LATIN_G0_SR_HR_SL = 0x0B00, // Serbian/Croatian/Slovenian (todo) + CHARSET_LATIN_G0_SV_FI = 0x0C00, // Swedish/Finnish + CHARSET_LATIN_G0_TR = 0x0D00, // Turkish (todo) + CHARSET_LATIN_G2 = 0x0E00, // Latin G2 supplementary set (todo) + CHARSET_CYRILLIC_G0_SR_HR = 0x0F00, // Serbian/Croatian (todo) + CHARSET_CYRILLIC_G0_RU_BG = 0x1000, // Russian/Bulgarian (todo) + CHARSET_CYRILLIC_G0_UK = 0x1100, // Ukrainian (todo) + CHARSET_CYRILLIC_G2 = 0x1200, // Cyrillic G2 Supplementary (todo) + CHARSET_GREEK_G0 = 0x1300, // Greek G0 (todo) + CHARSET_GREEK_G2 = 0x1400, // Greeek G2 (todo) + CHARSET_ARABIC_G0 = 0x1500, // Arabic G0 (todo) + CHARSET_ARABIC_G2 = 0x1600, // Arabic G2 (todo) + CHARSET_HEBREW_G0 = 0x1700, // Hebrew G0 (todo) + CHARSET_GRAPHICS_G1 = 0x1800, // G1 graphics set + CHARSET_GRAPHICS_G1_SEP = 0x1900, // G1 graphics set, separated + CHARSET_GRAPHICS_G3 = 0x1A00, // G3 graphics set (todo) + CHARSET_INVALID = 0x1F00 // no charset defined +}; + +// Macro to get the lowest non-0 bit position from a bit mask +// Should evaluate to const on a const mask +#define LowestSet2Bit(mask) ((mask)&0x0001?0:1) +#define LowestSet4Bit(mask) ((mask)&0x0003?LowestSet2Bit(mask):LowestSet2Bit((mask)>>2)+2) +#define LowestSet8Bit(mask) ((mask)&0x000f?LowestSet4Bit(mask):LowestSet4Bit((mask)>>4)+4) +#define LowestSet16Bit(mask) ((mask)&0x00ff?LowestSet8Bit(mask):LowestSet8Bit((mask)>>8)+8) +#define LowestSet32Bit(mask) ((mask)&0xffff?LowestSet16Bit(mask):LowestSet16Bit((mask)>>16)+16) + + +// Character modifcation double height: +enum enumDblHeight { + dblh_Normal=0x00000000, // normal height + dblh_Top =0x04000000, // upper half character + dblh_Bottom=0x08000000 // lower half character +}; +// Character modifcation double width: +enum enumDblWidth { + dblw_Normal=0x00000000, // normal width + dblw_Left =0x10000000, // left half character + dblw_Right =0x20000000 // right half character +}; + +// Teletext colors +enum enumTeletextColor { + // level 1: + ttcBlack=0, + ttcRed=1, + ttcGreen=2, + ttcYellow=3, + ttcBlue=4, + ttcMagenta=5, + ttcCyan=6, + ttcWhite=7, + // level 2.5: + ttcTransparent=8, + ttcHalfRed=9, + ttcHalfGreen=10, + ttcHalfYellow=11, + ttcHalfBlue=12, + ttcHalfMagenta=13, + ttcHalfCyan=14, + ttcGrey=15, + // unnamed, level 2.5: + ttcColor16=16, ttcColor17=17, ttcColor18=18, ttcColor19=19, + ttcColor20=20, ttcColor21=21, ttcColor22=22, ttcColor23=23, + ttcColor24=24, ttcColor25=25, ttcColor26=26, ttcColor27=27, + ttcColor28=28, ttcColor29=29, ttcColor30=30, ttcColor31=31, + + ttcFirst=0, ttcLast=31 +}; +inline enumTeletextColor& operator++(enumTeletextColor& c) { return c=enumTeletextColor(int(c)+1); } +inline enumTeletextColor operator++(enumTeletextColor& c, int) { enumTeletextColor tmp(c); ++c; return tmp; } + +class cTeletextChar { + // Wrapper class that represents a teletext character, + // including colors and effects. Should optimize back + // to 4 byte unsigned int on compile. + +protected: + unsigned int c; + + static const unsigned int CHAR = 0x000000FF; + // character code + static const unsigned int CHARSET = 0x00001F00; + // character set code, see below + static const unsigned int BOXOUT = 0x00004000; + // 'boxed' mode hidden area + static const unsigned int DIRTY = 0x00008000; + // 'dirty' bit - internal marker only + static const unsigned int FGCOLOR = 0x001F0000; + // 5-bit foreground color code, 3 bit used for now + static const unsigned int BGCOLOR = 0x03E00000; + // 5-bit background color code, 3 bit used for now + static const unsigned int DBLHEIGHT = 0x0C000000; + // show double height + static const unsigned int DBLWIDTH = 0x30000000; + // show double width (todo) + static const unsigned int CONCEAL = 0x40000000; + // character concealed + static const unsigned int BLINK = 0x80000000; + // blinking character + + cTeletextChar(unsigned int cc) { c=cc; } + +public: + cTeletextChar() { c=0; } + + // inline helper functions: + // For each parameter encoded into the 32-bit int, there is + // a Get...() to read, a Set...() to write, and a To...() to + // return a modified copy + + inline unsigned char GetChar() + { return c&CHAR; } + inline void SetChar(unsigned char chr) + { c=(c&~CHAR)|chr; } + inline cTeletextChar ToChar(unsigned char chr) + { return cTeletextChar((c&~CHAR)|chr); } + + inline enumCharsets GetCharset() + { return (enumCharsets)(c&CHARSET); } + inline void SetCharset(enumCharsets charset) + { c=(c&~CHARSET)|charset; } + inline cTeletextChar ToCharset(enumCharsets charset) + { return cTeletextChar((c&~CHARSET)|charset); } + + inline enumTeletextColor GetFGColor() + { return (enumTeletextColor)((c&FGCOLOR) >> LowestSet32Bit(FGCOLOR)); } + inline void SetFGColor(enumTeletextColor fgc) + { c=(c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR)); } + inline cTeletextChar ToFGColor(enumTeletextColor fgc) + { return cTeletextChar((c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR))); } + + inline enumTeletextColor GetBGColor() + { return (enumTeletextColor)((c&BGCOLOR) >> LowestSet32Bit(BGCOLOR)); } + inline void SetBGColor(enumTeletextColor bgc) + { c=(c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR)); } + inline cTeletextChar ToBGColor(enumTeletextColor bgc) + { return cTeletextChar((c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR))); } + + inline bool GetBoxedOut() + { return c&BOXOUT; } + inline void SetBoxedOut(bool BoxedOut) + { c=(BoxedOut)?(c|BOXOUT):(c&~BOXOUT); } + inline cTeletextChar ToBoxedOut(bool BoxedOut) + { return cTeletextChar((BoxedOut)?(c|BOXOUT):(c&~BOXOUT)); } + + inline bool GetDirty() + { return c&DIRTY; } + inline void SetDirty(bool Dirty) + { c=(Dirty)?(c|DIRTY):(c&~DIRTY); } + inline cTeletextChar ToDirty(bool Dirty) + { return cTeletextChar((Dirty)?(c|DIRTY):(c&~DIRTY)); } + + inline enumDblHeight GetDblHeight() + { return (enumDblHeight)(c&DBLHEIGHT); } + inline void SetDblHeight(enumDblHeight dh) + { c=(c&~(DBLHEIGHT)) | dh; } + inline cTeletextChar ToDblHeight(enumDblHeight dh) + { return cTeletextChar((c&~(DBLHEIGHT)) | dh); } + + inline enumDblWidth GetDblWidth() + { return (enumDblWidth)(c&DBLWIDTH); } + inline void SetDblWidth(enumDblWidth dw) + { c=(c&~(DBLWIDTH)) | dw; } + inline cTeletextChar ToDblWidth(enumDblWidth dw) + { return cTeletextChar((c&~(DBLWIDTH)) | dw); } + + inline bool GetConceal() + { return c&CONCEAL; } + inline void SetConceal(bool Conceal) + { c=(Conceal)?(c|CONCEAL):(c&~CONCEAL); } + inline cTeletextChar ToConceal(bool Conceal) + { return cTeletextChar((Conceal)?(c|CONCEAL):(c&~CONCEAL)); } + + inline bool GetBlink() + { return c&BLINK; } + inline void SetBlink(bool Blink) + { c=(Blink)?(c|BLINK):(c&~BLINK); } + inline cTeletextChar ToBlink(bool Blink) + { return cTeletextChar((Blink)?(c|BLINK):(c&~BLINK)); } + + bool operator==(cTeletextChar &chr) { return c==chr.c; } + bool operator!=(cTeletextChar &chr) { return c!=chr.c; } +}; + + +class cRenderPage { + // Abstraction of a 40x25 teletext character page + // with all special attributes and colors + // Additionally tracks changes by maintaining a + // 'dirty' flag on each character + +protected: + cTeletextChar Page[40][25]; + + int Flags; + // 0x80 C4 - Erase page + // 0x40 C5 - News flash + // 0x20 C6 - Subtitle + // 0x10 C7 - Suppress Header + // 0x08 C8 - Update + // 0x04 C9 - Interrupt Sequence + // 0x02 C10 - Inhibit Display + // 0x01 C11 - Magazine Serial mode + + int Lang; + // 3-bit language number from header + + bool Dirty; // At least one character is dirty + bool DirtyAll; // Consider all characters dirty, regardless of flag + + // Font Code pages + int FirstG0CodePage; // 7-bit number, lower 3 bits ignored + int SecondG0CodePage; // 7-bit number + +public: + cRenderPage(); + + cTeletextChar GetChar(int x, int y) { + // Read character content from page + if (x<0 || x>=40 || y<0 || y>=25) { + printf("Warning: out of bounds read access to teletext page\n"); + return cTeletextChar(); + } + return Page[x][y].ToDirty(false); + } + + bool IsDirty() { + // global dirty status + return Dirty; + } + + bool IsDirty(int x, int y) { + // local dirty status + if (x<0 || x>=40 || y<0 || y>=25) { + printf("Warning: out of bounds read access to teletext page\n"); + return false; + } + return Page[x][y].GetDirty() | DirtyAll; + } + + void MakeDirty(int x, int y) { + // force one character dirty + if (x<0 || x>=40 || y<0 || y>=25) { + printf("Warning: out of bounds write access to teletext page\n"); + return; + } + Page[x][y].SetDirty(true); + Dirty=true; + } + + void SetChar(int x, int y, cTeletextChar c) { + // Set character at given location + + if (x<0 || x>=40 || y<0 || y>=25) { + printf("Warning: out of bounds write access to teletext page\n"); + return; + } + if (GetChar(x,y) != c) { + Page[x][y]=c.ToDirty(true); + Dirty=true; + } + } + + void ReadTeletextHeader(unsigned char *Header); + // Read header from teletext page + // Header must be a 12 bytes buffer + + void RenderTeletextCode(unsigned char *PageCode); + // Interprete teletext code referenced by PageCode + // and draw the whole page content into this object + // PageCode must be a 40*24 bytes buffer +}; + + + +#endif -- cgit v1.2.3