add display support for osmio4k+

use --enable-lcd as configure option
This commit is contained in:
TangoCash
2022-11-07 21:22:46 +01:00
committed by Thilo Graf
parent e39f9d8b23
commit bf4e032a3b
14 changed files with 2976 additions and 0 deletions

View File

@@ -18,6 +18,11 @@ SUBDIRS += \
libupnpclient
endif
if ENABLE_LCD
SUBDIRS += \
liblcddisplay
endif
if BOXTYPE_CST
SUBDIRS += \
hardware/coolstream

View File

@@ -0,0 +1,19 @@
AM_CPPFLAGS = \
-I$(top_builddir) \
-I$(top_srcdir) \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/system \
-I$(top_srcdir)/src/zapit/include \
-I$(top_srcdir)/lib/connection \
-I$(top_srcdir)/lib/libconfigfile \
-I$(top_srcdir)/lib/libeventserver
AM_CPPFLAGS += -fno-rtti -fno-exceptions
noinst_LIBRARIES = liblcddisplay.a
liblcddisplay_a_SOURCES = lcddisplay.cpp fontrenderer.cpp
AM_CXXFLAGS = \
@FREETYPE_CFLAGS@

View File

@@ -0,0 +1,371 @@
/*
$Header$
LCD-Daemon - DBoxII-Project
Copyright (C) 2001 Steffen Hehn 'McClean'
Copyright (C) 2003 thegoodguy
baseroutines by tmbinc
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include "fontrenderer.h"
#include <stdio.h>
#include <string.h>
#include <system/debug.h>
#include <ft2build.h>
#include FT_FREETYPE_H
/* tested with freetype 2.3.9, and 2.1.4 */
#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 3
#define FT_NEW_CACHE_API
#endif
// fribidi
#if 0// defined (ENABLE_FRIBIDI)
#include <fribidi/fribidi.h>
#endif
FT_Error LcdFontRenderClass::myFTC_Face_Requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface)
{
return ((LcdFontRenderClass *)request_data)->FTC_Face_Requester(face_id, aface);
}
LcdFontRenderClass::LcdFontRenderClass(CLCDDisplay *fb)
{
framebuffer = fb;
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::LcdFontRenderClass: initializing core...\n");
fflush(stdout);
if (FT_Init_FreeType(&library))
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::LcdFontRenderClass: failed.\n");
return;
}
dprintf(DEBUG_NORMAL, "\n");
font = 0;
pthread_mutex_init(&render_mutex, NULL);
}
LcdFontRenderClass::~LcdFontRenderClass()
{
FTC_Manager_Done(cacheManager);
FT_Done_FreeType(library);
}
void LcdFontRenderClass::InitFontCache()
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::InitFontCache: Intializing font cache...\n");
fflush(stdout);
if (FTC_Manager_New(library, 3, 0, 0, myFTC_Face_Requester, this, &cacheManager))
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::InitFontCache: manager failed!\n");
return;
}
if (!cacheManager)
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::InitFontCache: error.\n");
return;
}
if (FTC_SBitCache_New(cacheManager, &sbitsCache))
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::InitFontCache: sbit failed!\n");
return;
}
if (FTC_ImageCache_New(cacheManager, &imageCache))
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::InitFontCache: imagecache failed!\n");
}
printf("\n");
}
FT_Error LcdFontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, FT_Face *aface)
{
fontListEntry *font = (fontListEntry *)face_id;
if (!font)
return -1;
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::FTC_Face_Requester: FTC_Face_Requester (%s/%s)\n", font->family, font->style);
int error;
if ((error = FT_New_Face(library, font->filename, 0, aface)))
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::FTC_Face_Requester: failed: %i\n", error);
return error;
}
return 0;
}
FTC_FaceID LcdFontRenderClass::getFaceID(const char *family, const char *style)
{
for (fontListEntry *f = font; f; f = f->next)
{
if ((!strcmp(f->family, family)) && (!strcmp(f->style, style)))
return (FTC_FaceID)f;
}
for (fontListEntry *f = font; f; f = f->next)
{
if (!strcmp(f->family, family))
return (FTC_FaceID)f;
}
return 0;
}
#ifdef FT_NEW_CACHE_API
FT_Error LcdFontRenderClass::getGlyphBitmap(FTC_ImageType font, FT_ULong glyph_index, FTC_SBit *sbit)
{
return FTC_SBitCache_Lookup(sbitsCache, font, glyph_index, sbit, NULL);
}
#else
FT_Error LcdFontRenderClass::getGlyphBitmap(FTC_Image_Desc *font, FT_ULong glyph_index, FTC_SBit *sbit)
{
return FTC_SBit_Cache_Lookup(sbitsCache, font, glyph_index, sbit);
}
#endif
const char *LcdFontRenderClass::AddFont(const char *const filename)
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::AddFont: adding font %s...\n", filename);
fflush(stdout);
int error;
fontListEntry *n;
FT_Face face;
if ((error = FT_New_Face(library, filename, 0, &face)))
{
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::AddFont: failed: %i\n", error);
return NULL;
}
n = new fontListEntry;
n->filename = strdup(filename);
n->family = strdup(face->family_name);
n->style = strdup(face->style_name);
FT_Done_Face(face);
n->next = font;
dprintf(DEBUG_NORMAL, "LcdFontRenderClass::AddFont: OK (%s/%s)\n", n->family, n->style);
font = n;
return n->style;
}
LcdFontRenderClass::fontListEntry::~fontListEntry()
{
free(filename);
free(family);
free(style);
}
LcdFont *LcdFontRenderClass::getFont(const char *family, const char *style, int size)
{
FTC_FaceID id = getFaceID(family, style);
if (!id)
return 0;
return new LcdFont(framebuffer, this, id, size);
}
LcdFont::LcdFont(CLCDDisplay *fb, LcdFontRenderClass *render, FTC_FaceID faceid, int isize)
{
framebuffer = fb;
renderer = render;
#ifdef FT_NEW_CACHE_API
font.face_id = faceid;
font.width = isize;
font.height = isize;
font.flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_MONOCHROME;
#else
font.font.face_id = faceid;
font.font.pix_width = isize;
font.font.pix_height = isize;
font.image_type = ftc_image_mono;
font.image_type |= ftc_image_flag_autohinted;
#endif
}
FT_Error LcdFont::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit)
{
return renderer->getGlyphBitmap(&font, glyph_index, sbit);
}
extern int UTF8ToUnicode(const char *&text, const bool utf8_encoded); //defined in src/driver/fontrenderer.cpp
#if 0 //defined (ENABLE_FRIBIDI)
std::string fribidiShapeChar(const char *text, const bool utf8_encoded);
#endif
void LcdFont::RenderString(int x, int y, const int width, const char *text, const int color, const int selected, const bool utf8_encoded)
{
int err;
pthread_mutex_lock(&renderer->render_mutex);
// fribidi
#if 0// defined (ENABLE_FRIBIDI)
std::string Text = fribidiShapeChar(text, utf8_encoded);
text = Text.c_str();
#endif
#ifdef FT_NEW_CACHE_API
FTC_ScalerRec scaler;
scaler.face_id = font.face_id;
scaler.width = font.width;
scaler.height = font.height;
scaler.pixel = true;
if ((err = FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size)) != 0)
#else
if ((err = FTC_Manager_Lookup_Size(renderer->cacheManager, &font.font, &face, &size)) != 0)
#endif
{
dprintf(DEBUG_NORMAL, "LcdFont::RenderString: FTC_Manager_Lookup_Size failed! (%d)\n", err);
pthread_mutex_unlock(&renderer->render_mutex);
return;
}
int left = x, step_y = (size->metrics.height >> 6) * 3 / 4 + 4;
int pos = 0;
for (; *text; text++)
{
pos++;
FTC_SBit glyph;
//if ((x + size->metrics.x_ppem > (left+width)) || (*text=='\n'))
if (x + size->metrics.x_ppem > (left + width))
{
//width clip
break;
}
if (*text == '\n')
{
x = left;
y += step_y;
}
int unicode_value = UTF8ToUnicode(text, utf8_encoded);
if (unicode_value == -1)
break;
#ifdef FT_NEW_CACHE_API
int index = FT_Get_Char_Index(size->face, unicode_value);
#else
int index = FT_Get_Char_Index(face, unicode_value);
#endif
if (!index)
continue;
if (getGlyphBitmap(index, &glyph))
{
dprintf(DEBUG_NORMAL, "LcdFont::RenderString: failed to get glyph bitmap.\n");
continue;
}
int rx = x + glyph->left;
int ry = y - glyph->top;
if (pos == selected)
{
framebuffer->draw_fill_rect(x - 2, y - glyph->height - 2, x + glyph->width + 2, y + 2, CLCDDisplay::PIXEL_INV);
}
for (int ay = 0; ay < glyph->height; ay++)
{
int ax = 0;
int w = glyph->width;
int xpos = rx;
for (; ax < w; ax++)
{
unsigned char c = glyph->buffer[ay * abs(glyph->pitch) + (ax >> 3)];
if ((c >> (7 - (ax & 7))) & 1)
framebuffer->draw_point(xpos, ry, color);
xpos ++;
}
ry++;
}
x += glyph->xadvance + 1;
}
pthread_mutex_unlock(&renderer->render_mutex);
}
int LcdFont::getRenderWidth(const char *text, const bool utf8_encoded)
{
pthread_mutex_lock(&renderer->render_mutex);
// fribidi
#if 0// defined (ENABLE_FRIBIDI)
std::string Text = fribidiShapeChar(text, utf8_encoded);
text = Text.c_str();
#endif
FT_Error err;
#ifdef FT_NEW_CACHE_API
FTC_ScalerRec scaler;
scaler.face_id = font.face_id;
scaler.width = font.width;
scaler.height = font.height;
scaler.pixel = true;
err = FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size);
#else
err = FTC_Manager_Lookup_Size(renderer->cacheManager, &font.font, &face, &size);
#endif
if (err != 0)
{
dprintf(DEBUG_NORMAL, "LcdFont::getRenderWidth: FTC_Manager_Lookup_Size failed! (0x%x)\n", err);
pthread_mutex_unlock(&renderer->render_mutex);
return -1;
}
int x = 0;
for (; *text; text++)
{
FTC_SBit glyph;
int unicode_value = UTF8ToUnicode(text, utf8_encoded);
if (unicode_value == -1)
break;
#ifdef FT_NEW_CACHE_API
int index = FT_Get_Char_Index(size->face, unicode_value);
#else
int index = FT_Get_Char_Index(face, unicode_value);
#endif
if (!index)
continue;
if (getGlyphBitmap(index, &glyph))
{
dprintf(DEBUG_NORMAL, "LcdFont::getRenderWidth: failed to get glyph bitmap.\n");
continue;
}
x += glyph->xadvance + 1;
}
pthread_mutex_unlock(&renderer->render_mutex);
return x;
}

View File

@@ -0,0 +1,106 @@
/*
$Header$
LCD-Daemon - DBoxII-Project
Copyright (C) 2001 Steffen Hehn 'McClean'
baseroutines by tmbinc
Homepage: http://dbox.cyberphoria.org/
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __LCDFONTRENDERER__
#define __LCDFONTRENDERER__
#include "lcddisplay.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_CACHE_H
#include FT_CACHE_IMAGE_H
#include FT_CACHE_SMALL_BITMAPS_H
#include <asm/types.h>
class LcdFontRenderClass;
class LcdFont
{
CLCDDisplay *framebuffer;
#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 3
FTC_ImageTypeRec font;
#else
FTC_Image_Desc font;
FT_Face face;
#endif
LcdFontRenderClass *renderer;
FT_Size size;
FT_Error getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit);
public:
void RenderString(int x, int y, int width, const char *text, int color, int selected = 0, const bool utf8_encoded = false);
int getRenderWidth(const char *text, const bool utf8_encoded = false);
LcdFont(CLCDDisplay *fb, LcdFontRenderClass *render, FTC_FaceID faceid, int isize);
~LcdFont() {}
};
class LcdFontRenderClass
{
CLCDDisplay *framebuffer;
struct fontListEntry
{
char *filename, *style, *family;
fontListEntry *next;
~fontListEntry();
} *font;
FT_Library library;
FTC_Manager cacheManager; /* the cache manager */
FTC_ImageCache imageCache; /* the glyph image cache */
FTC_SBitCache sbitsCache; /* the glyph small bitmaps cache */
FTC_FaceID getFaceID(const char *family, const char *style);
#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 3
FT_Error getGlyphBitmap(FTC_ImageType font, FT_ULong glyph_index, FTC_SBit *sbit);
#else
FT_Error getGlyphBitmap(FTC_Image_Desc *font, FT_ULong glyph_index, FTC_SBit *sbit);
#endif
public:
pthread_mutex_t render_mutex;
const char *AddFont(const char *const filename);
void InitFontCache();
FT_Error FTC_Face_Requester(FTC_FaceID face_id, FT_Face *aface);
static FT_Error myFTC_Face_Requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface);
//FT_Face getFace(const char *family, const char *style);
LcdFont *getFont(const char *family, const char *style, int size);
LcdFontRenderClass(CLCDDisplay *fb);
~LcdFontRenderClass();
friend class LcdFont;
};
#endif /* __LCDFONTRENDERER__ */

View File

@@ -0,0 +1,950 @@
/*
LCD-Daemon - DBoxII-Project
Copyright (C) 2001 Steffen Hehn 'McClean'
baseroutines by Shadow_
Homepage: http://dbox.cyberphoria.org/
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include "lcddisplay.h"
#include <png.h>
#include <stdint.h> /* uint8_t */
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <byteswap.h>
#include <string.h>
#ifndef BYTE_ORDER
#error "no BYTE_ORDER defined!"
#endif
#ifndef max
#define max(a,b)(((a)<(b)) ? (b) : (a))
#endif
#ifndef min
#define min(a,b)(((a)<(b)) ? (a) : (b))
#endif
void CLCDDisplay::setSize(int w, int h, int b)
{
xres = w;
yres = h;
bpp = 8;
bypp = 1;
surface_bpp = b;
real_offset = 0;
real_yres = yres;
if (yres == 32)
real_offset = 16;
if (yres < 64)
yres = 48;
switch (surface_bpp)
{
case 8:
surface_bypp = 1;
break;
case 15:
case 16:
surface_bypp = 2;
break;
case 24: // never use 24bit mode
case 32:
surface_bypp = 4;
break;
default:
surface_bypp = (bpp + 7) / 8;
}
surface_stride = xres * surface_bypp;
surface_buffer_size = xres * yres * surface_bypp;
surface_data = new unsigned char[surface_buffer_size];
memset(surface_data, 0, surface_buffer_size);
printf("[CLCDDisplay] %s surface buffer %p %d bytes, stride %d\n", __FUNCTION__, surface_data, surface_buffer_size, surface_stride);
_stride = xres * bypp;
raw_buffer_size = xres * yres * bypp;
_buffer = new unsigned char[raw_buffer_size];
memset(_buffer, 0, raw_buffer_size);
printf("[CLCDDisplay] %s lcd buffer %p %d bytes, stride %d, type %d\n", __FUNCTION__, _buffer, raw_buffer_size, _stride, is_oled);
}
CLCDDisplay::CLCDDisplay()
{
paused = 0;
available = false;
raw_buffer_size = 0;
xres = 132;
yres = 32;
bpp = 8;
flipped = false;
inverted = 0;
is_oled = 0;
last_brightness = 0;
//open device
fd = open("/dev/dbox/oled0", O_RDWR);
if (fd < 0)
{
xres = 128;
if (!access("/proc/stb/lcd/oled_brightness", W_OK) || !access("/proc/stb/fp/oled_brightness", W_OK))
is_oled = 2;
fd = open(LCD_DEVICE, O_RDWR);
}
else
{
printf("found OLED display!\n");
is_oled = 1;
}
if (fd < 0)
{
printf("couldn't open LCD - load lcd.ko!\n");
return;
}
else
{
int i = LCD_MODE_BIN;
ioctl(fd, LCD_IOCTL_ASC_MODE, &i);
FILE *f = fopen("/proc/stb/lcd/xres", "r");
if (f)
{
int tmp;
if (fscanf(f, "%x", &tmp) == 1)
xres = tmp;
fclose(f);
f = fopen("/proc/stb/lcd/yres", "r");
if (f)
{
if (fscanf(f, "%x", &tmp) == 1)
yres = tmp;
fclose(f);
f = fopen("/proc/stb/lcd/bpp", "r");
if (f)
{
if (fscanf(f, "%x", &tmp) == 1)
bpp = tmp;
fclose(f);
}
}
is_oled = 3;
}
}
setSize(xres, yres, bpp);
available = true;
iconBasePath = "";
}
//e2
void CLCDDisplay::setInverted(unsigned char inv)
{
inverted = inv;
update();
}
void CLCDDisplay::setFlipped(bool onoff)
{
flipped = onoff;
update();
}
int CLCDDisplay::setLCDContrast(int contrast)
{
return(0);
int fp;
fp = open("/dev/dbox/fp0", O_RDWR);
if (fp < 0)
fp = open("/dev/dbox/lcd0", O_RDWR);
if (fp < 0)
{
printf("[LCD] can't open /dev/dbox/fp0(%m)\n");
return (-1);
}
if (ioctl(fd, LCD_IOCTL_SRV, &contrast) < 0)
{
printf("[LCD] can't set lcd contrast(%m)\n");
}
close(fp);
return (0);
}
int CLCDDisplay::setLCDBrightness(int brightness)
{
printf("setLCDBrightness %d\n", brightness);
FILE *f = fopen("/proc/stb/lcd/oled_brightness", "w");
if (!f)
f = fopen("/proc/stb/fp/oled_brightness", "w");
if (f)
{
if (fprintf(f, "%d", brightness) == 0)
printf("write /proc/stb/lcd/oled_brightness failed!! (%m)\n");
fclose(f);
}
else
{
int fp;
if ((fp = open("/dev/dbox/fp0", O_RDWR)) < 0)
{
printf("[LCD] can't open /dev/dbox/fp0\n");
return (-1);
}
if (ioctl(fp, FP_IOCTL_LCD_DIMM, &brightness) < 0)
printf("[LCD] can't set lcd brightness (%m)\n");
close(fp);
}
if (brightness == 0)
{
memset(_buffer, inverted, raw_buffer_size);
update();
}
last_brightness = brightness;
return (0);
}
bool CLCDDisplay::isAvailable()
{
return available;
}
CLCDDisplay::~CLCDDisplay()
{
delete [] _buffer;
if (fd >= 0)
{
close(fd);
fd = -1;
}
}
void CLCDDisplay::pause()
{
paused = 1;
}
void CLCDDisplay::resume()
{
//clear the display
if (ioctl(fd, LCD_IOCTL_CLEAR) < 0)
printf("[lcddisplay] LCD_IOCTL_CLEAR failed (%m)\n");
//graphic (binary) mode
int i = LCD_MODE_BIN;
if (ioctl(fd, LCD_IOCTL_ASC_MODE, &i) < 0)
printf("[lcddisplay] LCD_IOCTL_ASC_MODE failed (%m)\n");
//
paused = 0;
}
void CLCDDisplay::convert_data()
{
#ifndef PLATFORM_GENERIC
unsigned int x, y, z;
char tmp;
#if 0
unsigned int height = yres;
unsigned int width = xres;
for (x = 0; x < width; x++)
{
for (y = 0; y < (height / 8); y++)
{
tmp = 0;
for (z = 0; z < 8; z++)
if (_buffer[(y * 8 + z) * width + x] == LCD_PIXEL_ON)
tmp |= (1 << z);
lcd[y][x] = tmp;
}
}
#endif
#endif
}
void CLCDDisplay::update()
{
#ifndef PLATFORM_GENERIC
if ((fd >= 0) && (last_brightness > 0))
{
for (unsigned int y = 0; y < yres; y++)
{
for (unsigned int x = 0; x < xres; x++)
{
surface_fill_rect(x, y, x + 1, y + 1, _buffer[y * xres + x]);
}
}
if (is_oled == 0 || is_oled == 2)
{
unsigned int height = yres;
unsigned int width = xres;
unsigned char raw[132 * 8];
int x, y, yy;
memset(raw, 0x00, 132 * 8);
for (y = 0; y < 8; y++)
{
// display has only 128 but buffer must be 132
for (x = 0; x < 128; x++)
{
int pix = 0;
for (yy = 0; yy < 8; yy++)
{
pix |= (surface_data[(y * 8 + yy) * width + x] >= 108) << yy;
}
if (flipped)
{
/* 8 pixels per byte, swap bits */
#define BIT_SWAP(a) ((((a << 7)&0x80) + ((a << 5)&0x40) + ((a << 3)&0x20) + ((a << 1)&0x10) + ((a >> 1)&0x08) + ((a >> 3)&0x04) + ((a >> 5)&0x02) + ((a >> 7)&0x01))&0xff)
raw[(7 - y) * 132 + (132 - 1 - x - 2)] = BIT_SWAP(pix ^ inverted);
}
else
{
raw[y * 132 + x + 2] = pix ^ inverted;
}
}
}
write(fd, raw, 132 * 8);
}
else if (is_oled == 3)
{
/* for now, only support flipping / inverting for 8bpp displays */
if ((flipped || inverted) && surface_stride == xres)
{
unsigned int height = yres;
unsigned int width = xres;
unsigned char raw[surface_stride * height];
for (unsigned int y = 0; y < height; y++)
{
for (unsigned int x = 0; x < width; x++)
{
if (flipped)
{
/* 8bpp, no bit swapping */
raw[(height - 1 - y) * width + (width - 1 - x)] = surface_data[y * width + x] ^ inverted;
}
else
{
raw[y * width + x] = surface_data[y * width + x] ^ inverted;
}
}
}
write(fd, raw, surface_stride * height);
}
else
{
//write(fd, surface_data, surface_stride * yres);
//
#ifdef PLATFORM_GIGABLUE
unsigned char gb_buffer[surface_stride * yres];
for (int offset = 0; offset < surface_stride * yres; offset += 2)
{
gb_buffer[offset] = (surface_data[offset] & 0x1F) | ((surface_data[offset + 1] << 3) & 0xE0);
gb_buffer[offset + 1] = ((surface_data[offset + 1] >> 5) & 0x03) | ((surface_data[offset] >> 3) & 0x1C) | ((_buffer[offset + 1] << 5) & 0x60);
}
write(fd, gb_buffer, surface_stride * yres);
#else
write(fd, surface_data + surface_stride * real_offset, surface_stride * real_yres);
#endif
//
}
}
else /* is_oled == 1 */
{
unsigned char raw[64 * 64];
int x, y;
memset(raw, 0, 64 * 64);
for (y = 0; y < 64; y++)
{
int pix = 0;
for (x = 0; x < 128 / 2; x++)
{
pix = (surface_data[y * 132 + x * 2 + 2] & 0xF0) | (surface_data[y * 132 + x * 2 + 1 + 2] >> 4);
if (inverted)
pix = 0xFF - pix;
if (flipped)
{
/* device seems to be 4bpp, swap nibbles */
unsigned char byte;
byte = (pix >> 4) & 0x0f;
byte |= (pix << 4) & 0xf0;
raw[(63 - y) * 64 + (63 - x)] = byte;
}
else
{
raw[y * 64 + x] = pix;
}
}
}
write(fd, raw, 64 * 64);
}
}
#endif
}
void CLCDDisplay::surface_fill_rect(int area_left, int area_top, int area_right, int area_bottom, int color)
{
int area_width = area_right - area_left;
int area_height = area_bottom - area_top;
if (surface_bpp == 8)
{
for (int y = area_top; y < area_bottom; y++)
memset(((uint8_t *)surface_data) + y * surface_stride + area_left, color, area_width);
}
else if (surface_bpp == 16)
{
uint32_t icol;
#if 0
if (surface_clut.data && color < surface_clut.colors)
icol = (surface_clut.data[color].a << 24) | (surface_clut.data[color].r << 16) | (surface_clut.data[color].g << 8) | (surface_clut.data[color].b);
else
#endif
icol = 0x10101 * color;
#if BYTE_ORDER == LITTLE_ENDIAN
uint16_t col = bswap_16(((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19);
#else
uint16_t col = ((icol & 0xFF) >> 3) << 11 | ((icol & 0xFF00) >> 10) << 5 | (icol & 0xFF0000) >> 19;
#endif
for (int y = area_top; y < area_bottom; y++)
{
uint16_t *dst = (uint16_t *)(((uint8_t *)surface_data) + y * surface_stride + area_left * surface_bypp);
int x = area_width;
while (x--)
*dst++ = col;
}
}
else if (surface_bpp == 32)
{
uint32_t col;
#if 0
if (surface_clut.data && color < surface_clut.colors)
col = (surface_clut.data[color].a << 24) | (surface_clut.data[color].r << 16) | (surface_clut.data[color].g << 8) | (surface_clut.data[color].b);
else
#endif
col = 0x10101 * color;
col ^= 0xFF000000;
#if 0
if (surface_data_phys && gAccel::getInstance())
if (!gAccel::getInstance()->fill(surface, area, col))
continue;
#endif
for (int y = area_top; y < area_bottom; y++)
{
uint32_t *dst = (uint32_t *)(((uint8_t *)surface_data) + y * surface_stride + area_left * surface_bypp);
int x = area_width;
while (x--)
*dst++ = col;
}
}
}
void CLCDDisplay::draw_point(const int x, const int y, const int state)
{
if ((x < 0) || (x >= xres) || (y < 0) || (y >= yres))
return;
if (state == LCD_PIXEL_INV)
_buffer[y * xres + x] ^= 1;
else
_buffer[y * xres + x] = state;
}
/*
* draw_line
*
* args:
* x1 StartCol
* y1 StartRow
* x2 EndCol
* y1 EndRow
* state LCD_PIXEL_OFF/LCD_PIXEL_ON/LCD_PIXEL_INV
*
*/
void CLCDDisplay::draw_line(const int x1, const int y1, const int x2, const int y2, const int state)
{
int dx = abs(x1 - x2);
int dy = abs(y1 - y2);
int x;
int y;
int End;
int step;
if (dx > dy)
{
int p = 2 * dy - dx;
int twoDy = 2 * dy;
int twoDyDx = 2 * (dy - dx);
if (x1 > x2)
{
x = x2;
y = y2;
End = x1;
step = y1 < y2 ? -1 : 1;
}
else
{
x = x1;
y = y1;
End = x2;
step = y2 < y1 ? -1 : 1;
}
draw_point(x, y, state);
while (x < End)
{
x++;
if (p < 0)
p += twoDy;
else
{
y += step;
p += twoDyDx;
}
draw_point(x, y, state);
}
}
else
{
int p = 2 * dx - dy;
int twoDx = 2 * dx;
int twoDxDy = 2 * (dx - dy);
if (y1 > y2)
{
x = x2;
y = y2;
End = y1;
step = x1 < x2 ? -1 : 1;
}
else
{
x = x1;
y = y1;
End = y2;
step = x2 < x1 ? -1 : 1;
}
draw_point(x, y, state);
while (y < End)
{
y++;
if (p < 0)
p += twoDx;
else
{
x += step;
p += twoDxDy;
}
draw_point(x, y, state);
}
}
}
void CLCDDisplay::draw_fill_rect(int left, int top, int right, int bottom, int state)
{
int x, y;
for (x = left + 1; x < right; x++)
{
for (y = top + 1; y < bottom; y++)
{
draw_point(x, y, state);
}
}
}
void CLCDDisplay::draw_rectangle(int left, int top, int right, int bottom, int linestate, int fillstate)
{
// coordinate checking in draw_pixel (-> you can draw lines only
// partly on screen)
draw_line(left, top, right, top, linestate);
draw_line(left, top, left, bottom, linestate);
draw_line(right, top, right, bottom, linestate);
draw_line(left, bottom, right, bottom, linestate);
draw_fill_rect(left, top, right, bottom, fillstate);
}
void CLCDDisplay::draw_polygon(int num_vertices, int *vertices, int state)
{
// coordinate checking in draw_pixel (-> you can draw polygons only
// partly on screen)
int i;
for (i = 0; i < num_vertices - 1; i++)
{
draw_line(vertices[(i << 1) + 0],
vertices[(i << 1) + 1],
vertices[(i << 1) + 2],
vertices[(i << 1) + 3],
state);
}
draw_line(vertices[0],
vertices[1],
vertices[(num_vertices << 1) - 2],
vertices[(num_vertices << 1) - 1],
state);
}
struct rawHeader
{
uint8_t width_lo;
uint8_t width_hi;
uint8_t height_lo;
uint8_t height_hi;
uint8_t transp;
} __attribute__((packed));
bool CLCDDisplay::paintIcon(std::string filename, int x, int y, bool invert)
{
struct rawHeader header;
uint16_t stride;
uint16_t height;
unsigned char *pixpos;
int _fd;
filename = iconBasePath + filename;
_fd = open(filename.c_str(), O_RDONLY);
if (_fd == -1)
{
printf("\nerror while loading icon: %s\n\n", filename.c_str());
return false;
}
read(_fd, &header, sizeof(struct rawHeader));
stride = ((header.width_hi << 8) | header.width_lo) >> 1;
height = (header.height_hi << 8) | header.height_lo;
unsigned char pixbuf[200];
while (height-- > 0)
{
read(fd, &pixbuf, stride);
pixpos = (unsigned char *) &pixbuf;
for (int count2 = 0; count2 < stride; count2++)
{
unsigned char compressed = *pixpos;
draw_point(x + (count2 << 1), y, ((((compressed & 0xf0) >> 4) != header.transp) ^ invert) ? PIXEL_ON : PIXEL_OFF);
draw_point(x + (count2 << 1) + 1, y, (((compressed & 0x0f) != header.transp) ^ invert) ? PIXEL_ON : PIXEL_OFF);
pixpos++;
}
y++;
}
close(_fd);
return true;
}
void CLCDDisplay::clear_screen()
{
memset(_buffer, 0, raw_buffer_size);
}
void CLCDDisplay::dump_screen(raw_display_t *screen)
{
memmove(*screen, _buffer, raw_buffer_size);
}
void CLCDDisplay::load_screen_element(const raw_lcd_element_t *element, int left, int top)
{
unsigned int i;
//if (element->buffer)
// for (i = 0; i < element->header.height; i++)
// memmove(_buffer+((top+i) * xres)+left, element->buffer+(i * element->header.width), element->header.width);
//
if ((element->buffer) && (element->header.height <= yres - top))
for (i = 0; i < min(element->header.height, yres - top); i++)
memmove(_buffer + ((top + i) * xres) + left, element->buffer + (i * element->header.width), min(element->header.width, xres - left));
//
}
void CLCDDisplay::load_screen(const raw_display_t *const screen)
{
raw_lcd_element_t element;
element.buffer_size = raw_buffer_size;
element.buffer = *screen;
element.header.width = xres;
element.header.height = yres;
load_screen_element(&element, 0, 0);
}
bool CLCDDisplay::load_png_element(const char *const filename, raw_lcd_element_t *element)
{
png_structp png_ptr;
png_infop info_ptr;
unsigned int i;
unsigned int pass;
unsigned int number_passes;
int bit_depth;
int color_type;
int interlace_type;
png_uint_32 width;
png_uint_32 height;
png_byte *fbptr;
FILE *fh;
bool ret_value = false;
if ((fh = fopen(filename, "rb")))
{
if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
{
if (!(info_ptr = png_create_info_struct(png_ptr)))
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
else
{
#if (PNG_LIBPNG_VER < 10500)
if (!(setjmp(png_ptr->jmpbuf)))
#else
if (!setjmp(png_jmpbuf(png_ptr)))
#endif
{
unsigned int lcd_height = yres;
unsigned int lcd_width = xres;
png_init_io(png_ptr, fh);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
if (
((color_type == PNG_COLOR_TYPE_PALETTE) ||
((color_type & PNG_COLOR_MASK_COLOR) == PNG_COLOR_TYPE_GRAY)) &&
(bit_depth <= 8) &&
(width <= lcd_width) &&
(height <= lcd_height)
)
{
printf("[CLCDDisplay] %s %s %dx%dx%d, type %d\n", __FUNCTION__, filename, width, height, bit_depth, color_type);
element->header.width = width;
element->header.height = height;
element->header.bpp = bit_depth;
if (!element->buffer)
{
element->buffer_size = width * height;
element->buffer = new unsigned char[element->buffer_size];
lcd_width = width;
lcd_height = height;
}
memset(element->buffer, 0, element->buffer_size);
png_set_packing(png_ptr); /* expand to 1 byte blocks */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(png_ptr);
if (color_type & PNG_COLOR_MASK_COLOR)
#if (PNG_LIBPNG_VER < 10200)
png_set_rgb_to_gray(png_ptr);
#else
png_set_rgb_to_gray(png_ptr, 1, NULL, NULL);
#endif
number_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
if (width == png_get_rowbytes(png_ptr, info_ptr))
{
ret_value = true;
for (pass = 0; pass < number_passes; pass++)
{
fbptr = (png_byte *)element->buffer;
for (i = 0; i < element->header.height; i++)
{
//fbptr = row_pointers[i];
//png_read_rows(png_ptr, &fbptr, NULL, 1);
png_read_row(png_ptr, fbptr, NULL);
/* if the PNG is smaller, than the display width... */
if (width < lcd_width) /* clear the area right of the PNG */
memset(fbptr + width, 0, lcd_width - width);
fbptr += lcd_width;
}
}
png_read_end(png_ptr, info_ptr);
}
}
}
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
}
}
fclose(fh);
}
return ret_value;
}
bool CLCDDisplay::load_png(const char *const filename)
{
raw_lcd_element_t element;
element.buffer_size = raw_buffer_size;
element.buffer = _buffer;
return load_png_element(filename, &element);
}
bool CLCDDisplay::dump_png_element(const char *const filename, raw_lcd_element_t *element)
{
png_structp png_ptr;
png_infop info_ptr;
unsigned int i;
png_byte *fbptr;
FILE *fp;
bool ret_value = false;
/* create file */
fp = fopen(filename, "wb");
if (!fp)
printf("[CLCDDisplay] File %s could not be opened for writing\n", filename);
else
{
/* initialize stuff */
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
printf("[CLCDDisplay] png_create_write_struct failed\n");
else
{
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
printf("[CLCDDisplay] png_create_info_struct failed\n");
else
{
if (setjmp(png_jmpbuf(png_ptr)))
printf("[CLCDDisplay] Error during init_io\n");
else
{
unsigned int lcd_height = yres;
unsigned int lcd_width = xres;
png_init_io(png_ptr, fp);
/* write header */
if (setjmp(png_jmpbuf(png_ptr)))
printf("[CLCDDisplay] Error during writing header\n");
png_set_IHDR(png_ptr, info_ptr, element->header.width, element->header.height,
element->header.bpp, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info(png_ptr, info_ptr);
/* write bytes */
if (setjmp(png_jmpbuf(png_ptr)))
{
printf("[CLCDDisplay] Error during writing bytes\n");
return ret_value;
}
ret_value = true;
fbptr = (png_byte *)element->buffer;
for (i = 0; i < element->header.height; i++)
{
png_write_row(png_ptr, fbptr);
fbptr += lcd_width;
}
/* end write */
if (setjmp(png_jmpbuf(png_ptr)))
{
printf("[CLCDDisplay] Error during end of write\n");
return ret_value;
}
png_write_end(png_ptr, NULL);
}
}
}
fclose(fp);
}
return ret_value;
}
bool CLCDDisplay::dump_png(const char *const filename)
{
raw_lcd_element_t element;
element.buffer_size = raw_buffer_size;
element.buffer = _buffer;
element.header.width = xres;
element.header.height = yres;
element.header.bpp = 8;
return dump_png_element(filename, &element);
}

View File

@@ -0,0 +1,148 @@
/*
LCD-Daemon - DBoxII-Project
Copyright (C) 2001 Steffen Hehn 'McClean'
baseroutines by Shadow_
Homepage: http://dbox.cyberphoria.org/
License: GPL
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __lcddisplay__
#define __lcddisplay__
#include <string>
#include <stdint.h> /* uint8_t */
#define LCD_DEVICE "/dev/dbox/lcd0"
#define LCD_PIXEL_OFF 0x00
#define LCD_PIXEL_ON 0xff
#define LCD_PIXEL_INV 0x1000000
// ioctls
#define LCD_IOCTL_CLEAR (26)
#define FP_IOCTL_LCD_DIMM 3
#ifndef LCD_IOCTL_ASC_MODE
#define LCDSET 0x1000
#define LCD_IOCTL_ASC_MODE (21|LCDSET)
#define LCD_MODE_ASC 0
#define LCD_MODE_BIN 1
#endif
#ifndef LCD_IOCTL_SRV
#define LCDSET 0x1000
#define LCD_IOCTL_SRV (10|LCDSET)
#endif
typedef unsigned char *raw_display_t;
struct raw_lcd_element_header_t
{
uint16_t width;
uint16_t height;
uint8_t bpp;
} __attribute__((packed));
struct raw_lcd_element_t
{
raw_lcd_element_header_t header;
int buffer_size;
raw_display_t buffer;
};
class CLCDDisplay
{
private:
int fd, paused;
std::string iconBasePath;
bool available;
unsigned char inverted;
bool flipped;
int is_oled; //1=oled, 2=lcd, 3=???
int last_brightness;
raw_display_t _buffer;
int _stride;
raw_display_t surface_data;
int surface_stride;
int surface_bpp, surface_bypp;
int surface_buffer_size;
int real_offset;
int real_yres;
public:
enum
{
PIXEL_ON = LCD_PIXEL_ON,
PIXEL_OFF = LCD_PIXEL_OFF,
PIXEL_INV = LCD_PIXEL_INV
};
CLCDDisplay();
~CLCDDisplay();
void pause();
void resume();
void convert_data();
void setIconBasePath(std::string bp)
{
iconBasePath = bp;
};
bool isAvailable();
void update();
void surface_fill_rect(int area_left, int area_top, int area_right, int area_bottom, int color);
void draw_point(const int x, const int y, const int state);
void draw_line(const int x1, const int y1, const int x2, const int y2, const int state);
void draw_fill_rect(int left, int top, int right, int bottom, int state);
void draw_rectangle(int left, int top, int right, int bottom, int linestate, int fillstate);
void draw_polygon(int num_vertices, int *vertices, int state);
bool paintIcon(std::string filename, int x, int y, bool invert);
void clear_screen();
void dump_screen(raw_display_t *screen);
void load_screen_element(const raw_lcd_element_t *element, int left, int top);
void load_screen(const raw_display_t *const screen);
bool dump_png_element(const char *const filename, raw_lcd_element_t *element);
bool dump_png(const char *const filename);
bool load_png_element(const char *const filename, raw_lcd_element_t *element);
bool load_png(const char *const filename);
void setSize(int w, int h, int b);
int setLCDContrast(int contrast);
int setLCDBrightness(int brightness);
void setInverted(unsigned char);
void setFlipped(bool);
bool isOled() const
{
return !!is_oled;
}
int raw_buffer_size;
int xres, yres, bpp;
int bypp;
};
#endif