Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / firmware / drivers / lcd-1bit-vert.c
blob75d1e660c4df8c83c89f85a7bed2df6c1ae3f9db
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Alan Korr
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "config.h"
24 #include "lcd.h"
25 #include "kernel.h"
26 #include "thread.h"
27 #include <string.h>
28 #include <stdlib.h>
29 #include "file.h"
30 #include "debug.h"
31 #include "system.h"
32 #include "font.h"
33 #include "rbunicode.h"
34 #include "bidi.h"
35 #include "scroll_engine.h"
37 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
38 #define LCDFN(fn) lcd_ ## fn
39 #define FBFN(fn) fb_ ## fn
40 #define LCDM(ma) LCD_ ## ma
41 #define LCDNAME "lcd_"
42 #define MAIN_LCD
43 #endif
45 /*** globals ***/
47 FBFN(data) LCDFN(framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)]
48 #if CONFIG_CPU != SH7034
49 IBSS_ATTR
50 #endif
53 static struct viewport default_vp =
55 .x = 0,
56 .y = 0,
57 .width = LCDM(WIDTH),
58 .height = LCDM(HEIGHT),
59 .font = FONT_SYSFIXED,
60 .drawmode = DRMODE_SOLID,
63 static struct viewport* current_vp = &default_vp;
65 /*** Viewports ***/
67 void LCDFN(set_viewport)(struct viewport* vp)
69 if (vp == NULL)
70 current_vp = &default_vp;
71 else
72 current_vp = vp;
75 void LCDFN(update_viewport)(void)
77 LCDFN(update_rect)(current_vp->x, current_vp->y,
78 current_vp->width, current_vp->height);
81 void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
83 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
86 /* LCD init */
87 void LCDFN(init)(void)
89 LCDFN(clear_display)();
90 #ifndef SIMULATOR
91 LCDFN(init_device)();
92 #endif
93 #ifdef MAIN_LCD
94 scroll_init();
95 #endif
98 /*** parameter handling ***/
100 void LCDFN(set_drawmode)(int mode)
102 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
105 int LCDFN(get_drawmode)(void)
107 return current_vp->drawmode;
110 int LCDFN(getwidth)(void)
112 return current_vp->width;
115 int LCDFN(getheight)(void)
117 return current_vp->height;
120 void LCDFN(setfont)(int newfont)
122 current_vp->font = newfont;
125 int LCDFN(getfont)(void)
127 return current_vp->font;
130 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
132 return font_getstringsize(str, w, h, current_vp->font);
135 /*** low-level drawing functions ***/
137 static void setpixel(int x, int y)
139 LCDFN(framebuffer)[y>>3][x] |= 1 << (y & 7);
142 static void clearpixel(int x, int y)
144 LCDFN(framebuffer)[y>>3][x] &= ~(1 << (y & 7));
147 static void flippixel(int x, int y)
149 LCDFN(framebuffer)[y>>3][x] ^= 1 << (y & 7);
152 static void nopixel(int x, int y)
154 (void)x;
155 (void)y;
158 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs)[8] = {
159 flippixel, nopixel, setpixel, setpixel,
160 nopixel, clearpixel, nopixel, clearpixel
163 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
164 unsigned bits)
166 *address ^= bits & mask;
169 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
170 unsigned bits)
172 *address &= bits | ~mask;
175 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
176 unsigned bits)
178 *address |= bits & mask;
181 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
182 unsigned bits)
184 unsigned data = *(char*)address;
186 bits ^= data;
187 *address = data ^ (bits & mask);
190 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
191 unsigned bits)
193 *address ^= ~bits & mask;
196 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
197 unsigned bits)
199 *address &= ~(bits & mask);
202 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
203 unsigned bits)
205 *address |= ~bits & mask;
208 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
209 unsigned bits)
211 unsigned data = *(char *)address;
213 bits = ~bits ^ data;
214 *address = data ^ (bits & mask);
217 LCDFN(blockfunc_type)* const LCDFN(blockfuncs)[8] = {
218 flipblock, bgblock, fgblock, solidblock,
219 flipinvblock, bginvblock, fginvblock, solidinvblock
222 /*** drawing functions ***/
224 /* Clear the whole display */
225 void LCDFN(clear_display)(void)
227 unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
229 memset(LCDFN(framebuffer), bits, sizeof LCDFN(framebuffer));
230 LCDFN(scroll_info).lines = 0;
233 /* Clear the current viewport */
234 void LCDFN(clear_viewport)(void)
236 int oldmode;
238 if (current_vp == &default_vp)
240 LCDFN(clear_display)();
242 else
244 oldmode = current_vp->drawmode;
246 /* Invert the INVERSEVID bit and set basic mode to SOLID */
247 current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
248 DRMODE_SOLID;
250 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
252 current_vp->drawmode = oldmode;
254 LCDFN(scroll_stop)(current_vp);
258 /* Set a single pixel */
259 void LCDFN(drawpixel)(int x, int y)
261 if (((unsigned)x < (unsigned)current_vp->width) &&
262 ((unsigned)y < (unsigned)current_vp->height))
263 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
266 /* Draw a line */
267 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
269 int numpixels;
270 int i;
271 int deltax, deltay;
272 int d, dinc1, dinc2;
273 int x, xinc1, xinc2;
274 int y, yinc1, yinc2;
275 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
277 deltax = abs(x2 - x1);
278 if (deltax == 0)
280 DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n");
281 LCDFN(vline)(x1, y1, y2);
282 return;
284 deltay = abs(y2 - y1);
285 if (deltay == 0)
287 DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n");
288 LCDFN(hline)(x1, x2, y1);
289 return;
291 xinc2 = 1;
292 yinc2 = 1;
294 if (deltax >= deltay)
296 numpixels = deltax;
297 d = 2 * deltay - deltax;
298 dinc1 = deltay * 2;
299 dinc2 = (deltay - deltax) * 2;
300 xinc1 = 1;
301 yinc1 = 0;
303 else
305 numpixels = deltay;
306 d = 2 * deltax - deltay;
307 dinc1 = deltax * 2;
308 dinc2 = (deltax - deltay) * 2;
309 xinc1 = 0;
310 yinc1 = 1;
312 numpixels++; /* include endpoints */
314 if (x1 > x2)
316 xinc1 = -xinc1;
317 xinc2 = -xinc2;
320 if (y1 > y2)
322 yinc1 = -yinc1;
323 yinc2 = -yinc2;
326 x = x1;
327 y = y1;
329 for (i = 0; i < numpixels; i++)
331 if (((unsigned)x < (unsigned)current_vp->width)
332 && ((unsigned)y < (unsigned)current_vp->height))
333 pfunc(current_vp->x + x, current_vp->y + y);
335 if (d < 0)
337 d += dinc1;
338 x += xinc1;
339 y += yinc1;
341 else
343 d += dinc2;
344 x += xinc2;
345 y += yinc2;
350 /* Draw a horizontal line (optimised) */
351 void LCDFN(hline)(int x1, int x2, int y)
353 int x, width;
354 unsigned char *dst, *dst_end;
355 unsigned mask;
356 LCDFN(blockfunc_type) *bfunc;
358 /* direction flip */
359 if (x2 < x1)
361 x = x1;
362 x1 = x2;
363 x2 = x;
366 /* nothing to draw? */
367 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
368 || (x2 < 0))
369 return;
371 /* clipping */
372 if (x1 < 0)
373 x1 = 0;
374 if (x2 >= current_vp->width)
375 x2 = current_vp->width-1;
377 width = x2 - x1 + 1;
379 /* adjust to viewport */
380 x1 += current_vp->x;
381 y += current_vp->y;
383 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
384 dst = &LCDFN(framebuffer)[y>>3][x1];
385 mask = 1 << (y & 7);
387 dst_end = dst + width;
389 bfunc(dst++, mask, 0xFFu);
390 while (dst < dst_end);
393 /* Draw a vertical line (optimised) */
394 void LCDFN(vline)(int x, int y1, int y2)
396 int ny;
397 FBFN(data) *dst;
398 unsigned mask, mask_bottom;
399 LCDFN(blockfunc_type) *bfunc;
401 /* direction flip */
402 if (y2 < y1)
404 ny = y1;
405 y1 = y2;
406 y2 = ny;
409 /* nothing to draw? */
410 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
411 || (y2 < 0))
412 return;
414 /* clipping */
415 if (y1 < 0)
416 y1 = 0;
417 if (y2 >= current_vp->height)
418 y2 = current_vp->height-1;
420 /* adjust for viewport */
421 y1 += current_vp->y;
422 y2 += current_vp->y;
423 x += current_vp->x;
425 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
426 dst = &LCDFN(framebuffer)[y1>>3][x];
427 ny = y2 - (y1 & ~7);
428 mask = 0xFFu << (y1 & 7);
429 mask_bottom = 0xFFu >> (~ny & 7);
431 for (; ny >= 8; ny -= 8)
433 bfunc(dst, mask, 0xFFu);
434 dst += LCDM(WIDTH);
435 mask = 0xFFu;
437 mask &= mask_bottom;
438 bfunc(dst, mask, 0xFFu);
441 /* Draw a rectangular box */
442 void LCDFN(drawrect)(int x, int y, int width, int height)
444 if ((width <= 0) || (height <= 0))
445 return;
447 int x2 = x + width - 1;
448 int y2 = y + height - 1;
450 LCDFN(vline)(x, y, y2);
451 LCDFN(vline)(x2, y, y2);
452 LCDFN(hline)(x, x2, y);
453 LCDFN(hline)(x, x2, y2);
456 /* Fill a rectangular area */
457 void LCDFN(fillrect)(int x, int y, int width, int height)
459 int ny;
460 FBFN(data) *dst, *dst_end;
461 unsigned mask, mask_bottom;
462 unsigned bits = 0;
463 LCDFN(blockfunc_type) *bfunc;
464 bool fillopt = false;
466 /* nothing to draw? */
467 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
468 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
469 return;
471 /* clipping */
472 if (x < 0)
474 width += x;
475 x = 0;
477 if (y < 0)
479 height += y;
480 y = 0;
482 if (x + width > current_vp->width)
483 width = current_vp->width - x;
484 if (y + height > current_vp->height)
485 height = current_vp->height - y;
487 /* adjust for viewport */
488 x += current_vp->x;
489 y += current_vp->y;
491 if (current_vp->drawmode & DRMODE_INVERSEVID)
493 if (current_vp->drawmode & DRMODE_BG)
495 fillopt = true;
498 else
500 if (current_vp->drawmode & DRMODE_FG)
502 fillopt = true;
503 bits = 0xFFu;
506 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
507 dst = &LCDFN(framebuffer)[y>>3][x];
508 ny = height - 1 + (y & 7);
509 mask = 0xFFu << (y & 7);
510 mask_bottom = 0xFFu >> (~ny & 7);
512 for (; ny >= 8; ny -= 8)
514 if (fillopt && (mask == 0xFFu))
515 memset(dst, bits, width);
516 else
518 FBFN(data) *dst_row = dst;
520 dst_end = dst_row + width;
522 bfunc(dst_row++, mask, 0xFFu);
523 while (dst_row < dst_end);
526 dst += LCDM(WIDTH);
527 mask = 0xFFu;
529 mask &= mask_bottom;
531 if (fillopt && (mask == 0xFFu))
532 memset(dst, bits, width);
533 else
535 dst_end = dst + width;
537 bfunc(dst++, mask, 0xFFu);
538 while (dst < dst_end);
542 /* About Rockbox' internal bitmap format:
544 * A bitmap contains one bit for every pixel that defines if that pixel is
545 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
546 * at top.
547 * The bytes are stored in row-major order, with byte 0 being top left,
548 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
549 * 0..7, the second row defines pixel row 8..15 etc.
551 * This is the same as the internal lcd hw format. */
553 /* Draw a partial bitmap */
554 void ICODE_ATTR LCDFN(bitmap_part)(const unsigned char *src, int src_x,
555 int src_y, int stride, int x, int y,
556 int width, int height)
558 int shift, ny;
559 FBFN(data) *dst, *dst_end;
560 unsigned mask, mask_bottom;
561 LCDFN(blockfunc_type) *bfunc;
563 /* nothing to draw? */
564 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
565 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
566 return;
568 /* clipping */
569 if (x < 0)
571 width += x;
572 src_x -= x;
573 x = 0;
575 if (y < 0)
577 height += y;
578 src_y -= y;
579 y = 0;
581 if (x + width > current_vp->width)
582 width = current_vp->width - x;
583 if (y + height > current_vp->height)
584 height = current_vp->height - y;
586 /* adjust for viewport */
587 x += current_vp->x;
588 y += current_vp->y;
590 src += stride * (src_y >> 3) + src_x; /* move starting point */
591 src_y &= 7;
592 y -= src_y;
593 dst = &LCDFN(framebuffer)[y>>3][x];
594 shift = y & 7;
595 ny = height - 1 + shift + src_y;
597 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
598 mask = 0xFFu << (shift + src_y);
599 mask_bottom = 0xFFu >> (~ny & 7);
601 if (shift == 0)
603 bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
605 for (; ny >= 8; ny -= 8)
607 if (copyopt && (mask == 0xFFu))
608 memcpy(dst, src, width);
609 else
611 const unsigned char *src_row = src;
612 FBFN(data) *dst_row = dst;
614 dst_end = dst_row + width;
616 bfunc(dst_row++, mask, *src_row++);
617 while (dst_row < dst_end);
620 src += stride;
621 dst += LCDM(WIDTH);
622 mask = 0xFFu;
624 mask &= mask_bottom;
626 if (copyopt && (mask == 0xFFu))
627 memcpy(dst, src, width);
628 else
630 dst_end = dst + width;
632 bfunc(dst++, mask, *src++);
633 while (dst < dst_end);
636 else
638 dst_end = dst + width;
641 const unsigned char *src_col = src++;
642 FBFN(data) *dst_col = dst++;
643 unsigned mask_col = mask;
644 unsigned data = 0;
646 for (y = ny; y >= 8; y -= 8)
648 data |= *src_col << shift;
650 if (mask_col & 0xFFu)
652 bfunc(dst_col, mask_col, data);
653 mask_col = 0xFFu;
655 else
656 mask_col >>= 8;
658 src_col += stride;
659 dst_col += LCDM(WIDTH);
660 data >>= 8;
662 data |= *src_col << shift;
663 bfunc(dst_col, mask_col & mask_bottom, data);
665 while (dst < dst_end);
669 /* Draw a full bitmap */
670 void LCDFN(bitmap)(const unsigned char *src, int x, int y, int width,
671 int height)
673 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
676 /* put a string at a given pixel position, skipping first ofs pixel columns */
677 static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
679 unsigned short ch;
680 unsigned short *ucs;
681 struct font* pf = font_get(current_vp->font);
683 ucs = bidi_l2v(str, 1);
685 while ((ch = *ucs++) != 0 && x < current_vp->width)
687 int width;
688 const unsigned char *bits;
690 /* get proportional width and glyph bits */
691 width = font_get_width(pf, ch);
693 if (ofs > width)
695 ofs -= width;
696 continue;
699 bits = font_get_bits(pf, ch);
701 LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs,
702 pf->height);
704 x += width - ofs;
705 ofs = 0;
708 /* put a string at a given pixel position */
709 void LCDFN(putsxy)(int x, int y, const unsigned char *str)
711 LCDFN(putsxyofs)(x, y, 0, str);
714 /*** Line oriented text output ***/
716 /* put a string at a given char position */
717 void LCDFN(puts)(int x, int y, const unsigned char *str)
719 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, 0);
722 void LCDFN(puts_style)(int x, int y, const unsigned char *str, int style)
724 LCDFN(puts_style_offset)(x, y, str, style, 0);
727 void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset)
729 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, offset);
732 /* put a string at a given char position, style, and pixel position,
733 * skipping first offset pixel columns */
734 void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str,
735 int style, int offset)
737 int xpos,ypos,w,h,xrect;
738 int lastmode = current_vp->drawmode;
740 /* make sure scrolling is turned off on the line we are updating */
741 LCDFN(scroll_stop_line)(current_vp, y);
743 if(!str || !str[0])
744 return;
746 LCDFN(getstringsize)(str, &w, &h);
747 xpos = x*w / utf8length(str);
748 ypos = y*h;
749 current_vp->drawmode = (style & STYLE_INVERT) ?
750 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
751 LCDFN(putsxyofs)(xpos, ypos, offset, str);
752 current_vp->drawmode ^= DRMODE_INVERSEVID;
753 xrect = xpos + MAX(w - offset, 0);
754 LCDFN(fillrect)(xrect, ypos, current_vp->width - xrect, h);
755 current_vp->drawmode = lastmode;
758 /*** scrolling ***/
760 void LCDFN(puts_scroll)(int x, int y, const unsigned char *string)
762 LCDFN(puts_scroll_style)(x, y, string, STYLE_DEFAULT);
765 void LCDFN(puts_scroll_style)(int x, int y, const unsigned char *string,
766 int style)
768 LCDFN(puts_scroll_style_offset)(x, y, string, style, 0);
771 void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string,
772 int offset)
774 LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset);
777 void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string,
778 int style, int offset)
780 struct scrollinfo* s;
781 int w, h;
783 if ((unsigned)y >= (unsigned)current_vp->height)
784 return;
786 /* remove any previously scrolling line at the same location */
787 LCDFN(scroll_stop_line)(current_vp, y);
789 if (LCDFN(scroll_info.lines) >= LCDM(SCROLLABLE_LINES)) return;
791 s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines];
793 s->start_tick = current_tick + LCDFN(scroll_info).delay;
794 s->style = style;
795 if (style & STYLE_INVERT) {
796 LCDFN(puts_style_offset)(x,y,string,STYLE_INVERT,offset);
798 else
799 LCDFN(puts_offset)(x,y,string,offset);
801 LCDFN(getstringsize)(string, &w, &h);
803 if (current_vp->width - x * 8 < w) {
804 /* prepare scroll line */
805 char *end;
807 memset(s->line, 0, sizeof s->line);
808 strcpy(s->line, string);
810 /* get width */
811 s->width = LCDFN(getstringsize)(s->line, &w, &h);
813 /* scroll bidirectional or forward only depending on the string
814 width */
815 if ( LCDFN(scroll_info).bidir_limit ) {
816 s->bidir = s->width < (current_vp->width) *
817 (100 + LCDFN(scroll_info).bidir_limit) / 100;
819 else
820 s->bidir = false;
822 if (!s->bidir) { /* add spaces if scrolling in the round */
823 strcat(s->line, " ");
824 /* get new width incl. spaces */
825 s->width = LCDFN(getstringsize)(s->line, &w, &h);
828 end = strchr(s->line, '\0');
829 strncpy(end, string, current_vp->width/2);
831 s->vp = current_vp;
832 s->y = y;
833 s->len = utf8length(string);
834 s->offset = offset;
835 s->startx = x * s->width / s->len;;
836 s->backward = false;
838 LCDFN(scroll_info).lines++;
842 void LCDFN(scroll_fn)(void)
844 struct font* pf;
845 struct scrollinfo* s;
846 int index;
847 int xpos, ypos;
848 int lastmode;
849 struct viewport* old_vp = current_vp;
851 for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) {
852 s = &LCDFN(scroll_info).scroll[index];
854 /* check pause */
855 if (TIME_BEFORE(current_tick, s->start_tick))
856 continue;
858 LCDFN(set_viewport)(s->vp);
860 if (s->backward)
861 s->offset -= LCDFN(scroll_info).step;
862 else
863 s->offset += LCDFN(scroll_info).step;
865 pf = font_get(current_vp->font);
866 xpos = s->startx;
867 ypos = s->y * pf->height;
869 if (s->bidir) { /* scroll bidirectional */
870 if (s->offset <= 0) {
871 /* at beginning of line */
872 s->offset = 0;
873 s->backward = false;
874 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
876 if (s->offset >= s->width - (current_vp->width - xpos)) {
877 /* at end of line */
878 s->offset = s->width - (current_vp->width - xpos);
879 s->backward = true;
880 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
883 else {
884 /* scroll forward the whole time */
885 if (s->offset >= s->width)
886 s->offset %= s->width;
889 lastmode = current_vp->drawmode;
890 current_vp->drawmode = (s->style&STYLE_INVERT) ?
891 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
892 LCDFN(putsxyofs)(xpos, ypos, s->offset, s->line);
893 current_vp->drawmode = lastmode;
894 LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width - xpos, pf->height);
897 LCDFN(set_viewport)(old_vp);