netsurf/atari/plot/plotter_vdi.c

1506 lines
42 KiB
C
Executable File

/*
* Copyright 2010 Ole Loots <ole@monochrom.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf 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; version 2 of the License.
*
* NetSurf 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <windom.h>
#include <Hermes/Hermes.h>
#include "atari/plot/eddi.h"
#include "atari/plot/plotter.h"
#include "atari/plot/plotter_vdi.h"
/* assign vdi line style to dst ( netsurf type ) */
#define NSLT2VDI(dst, src) \
dst = 0;\
switch( src->stroke_type ) {\
case PLOT_OP_TYPE_DOT: \
dst = (0xAAAA00 | 7);\
break;\
case PLOT_OP_TYPE_DASH:\
dst = 3; \
break;\
case PLOT_OP_TYPE_SOLID:\
case PLOT_OP_TYPE_NONE:\
default:\
dst = 1;\
break;\
}\
static int dtor( GEM_PLOTTER self );
static int resize( GEM_PLOTTER self, int w, int h );
static int move( GEM_PLOTTER self, short x, short y );
static int lock( GEM_PLOTTER self );
static int unlock( GEM_PLOTTER self );
static int put_pixel(GEM_PLOTTER self, int x, int y, int color );
static int copy_rect( GEM_PLOTTER self, GRECT src, GRECT dst );
static int set_clip(GEM_PLOTTER self, const struct rect * clip);
static int get_clip( GEM_PLOTTER self, struct rect * out );
static int arc(GEM_PLOTTER self,int x, int y, int radius, int angle1, int angle2, const plot_style_t * pstyle);
static int disc(GEM_PLOTTER self,int x, int y, int radius, const plot_style_t * pstyle);
static int line(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle);
static int rectangle(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle);
static int polygon(GEM_PLOTTER self,const int *p, unsigned int n, const plot_style_t * pstyle);
static int path(GEM_PLOTTER self,const float *p, unsigned int n, int fill, float width, int c, const float transform[6]);
static int bitmap_resize( GEM_PLOTTER self, struct bitmap * img, int nw, int nh );
static int bitmap_convert( GEM_PLOTTER self, struct bitmap * img, int x, int y,
GRECT * clip,uint32_t bg,uint32_t flags, MFDB *out );
static int bitmap_convert_8( GEM_PLOTTER self, struct bitmap * img,int x, int y,
GRECT * clip,uint32_t bg,uint32_t flags, MFDB *out );
static int bitmap( GEM_PLOTTER self, struct bitmap * bmp, int x, int y,
unsigned long bg, unsigned long flags );
static int plot_mfdb( GEM_PLOTTER self, GRECT * where, MFDB * mfdb, unsigned char fgcolor, uint32_t flags);
static int text(GEM_PLOTTER self, int x, int y, const char *text,size_t length, const plot_font_style_t *fstyle);
static inline void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val );
static inline unsigned char get_stdpx(MFDB * dst, int wdplanesz, int x, int y );
/*
Set clipping for current framebuffer
*/
static int plotter_std_clip(GEM_PLOTTER self, const struct rect * clip);
extern struct s_vdi_sysinfo vdi_sysinfo;
static HermesHandle hermes_pal_h; /* hermes palette handle */
static HermesHandle hermes_cnv_h; /* hermes converter instance handle */
static HermesHandle hermes_res_h;
static short prev_vdi_clip[4];
#ifdef WITH_8BPP_SUPPORT
static unsigned short sys_pal[256][3]; /*RGB*/
static unsigned short pal[256][3]; /*RGB*/
static char rgb_lookup[256][4];
extern unsigned short vdi_web_pal[216][3];
#endif
static inline void vsl_rgbcolor( short vdih, uint32_t cin )
{
if( vdi_sysinfo.scr_bpp > 8 ) {
unsigned short c[4];
rgb_to_vdi1000( (unsigned char*)&cin, (unsigned short*)&c );
vs_color( vdih, OFFSET_CUSTOM_COLOR, (unsigned short*)&c[0] );
vsl_color( vdih, OFFSET_CUSTOM_COLOR );
} else {
if( vdi_sysinfo.scr_bpp >= 4 ){
vsl_color( vdih, RGB_TO_VDI(cin) );
}
else
vsl_color( vdih, BLACK );
}
}
static inline void vsf_rgbcolor( short vdih, uint32_t cin )
{
if( vdi_sysinfo.scr_bpp > 8 ) {
unsigned short c[4];
rgb_to_vdi1000( (unsigned char*)&cin, (unsigned short*)&c );
vs_color( vdih, OFFSET_CUSTOM_COLOR, &c[0] );
vsf_color( vdih, OFFSET_CUSTOM_COLOR );
} else {
if( vdi_sysinfo.scr_bpp >= 4 ){
vsf_color( vdih, RGB_TO_VDI(cin) );
}
else
vsf_color( vdih, WHITE );
}
}
static int set_clip(GEM_PLOTTER self, const struct rect * clip)
{
VIEW( self ).clipping.x0 = clip->x0;
VIEW( self ).clipping.y0 = clip->y0;
VIEW( self ).clipping.x1 = clip->x1;
VIEW( self ).clipping.y1 = clip->y1;
return ( 1 );
}
static int get_clip( GEM_PLOTTER self, struct rect * out )
{
out->x0 = VIEW( self ).clipping.x0;
out->y0 = VIEW( self ).clipping.y0;
out->x1 = VIEW( self ).clipping.x1;
out->y1 = VIEW( self ).clipping.y1;
return( 1 );
}
/*
Get current visible coords
*/
static inline void plotter_get_visible_grect( GEM_PLOTTER self, GRECT * out )
{
/*todo: !!! */
out->g_x = VIEW( self ).clipping.x0;
out->g_y = VIEW( self ).clipping.y0;
out->g_w = VIEW( self ).clipping.x1 - VIEW( self ).clipping.x0;
out->g_h = VIEW( self ).clipping.y1 - VIEW( self ).clipping.y0;
}
/*
1. calculate visible area of framebuffer in coords relative to framebuffer position
result:
this function should calc offsets into x,y coords of the framebuffer which
can be drawn. If the framebuffer coords do not fall within the screen region,
all values of visible region are set to zero.
*/
static inline void update_visible_rect( GEM_PLOTTER p )
{
GRECT screen;
GRECT common;
GRECT frame;
screen.g_x = 0;
screen.g_y = 0;
screen.g_w = vdi_sysinfo.scr_w;
screen.g_h = vdi_sysinfo.scr_h;
common.g_x = frame.g_x = VIEW(p).x;
common.g_y = frame.g_y = VIEW(p).y;
common.g_w = frame.g_w = VIEW(p).w;
common.g_h = frame.g_h = VIEW(p).h;
if( rc_intersect( &screen, &common ) ) {
VIEW(p).vis_w = common.g_w;
VIEW(p).vis_h = common.g_h;
if( VIEW(p).x < screen.g_x )
VIEW(p).vis_x = frame.g_w - common.g_w;
else
VIEW(p).vis_x = 0;
if( VIEW(p).y <screen.g_y )
VIEW(p).vis_y = frame.g_h - common.g_h;
else
VIEW(p).vis_y = 0;
} else {
VIEW(p).vis_w = VIEW(p).vis_h = 0;
VIEW(p).vis_x = VIEW(p).vis_y = 0;
}
}
/*
Returns the visible parts of the box (relative coords within framebuffer),
relative to screen coords (normally starting at 0,0 )
*/
static inline bool fbrect_to_screen( GEM_PLOTTER self, GRECT box, GRECT * ret )
{
GRECT out, vis, screen;
screen.g_x = 0;
screen.g_y = 0;
screen.g_w = vdi_sysinfo.scr_w;
screen.g_h = vdi_sysinfo.scr_h;
/* get visible region: */
vis.g_x = VIEW(self).x;
vis.g_y = VIEW(self).y;
vis.g_w = VIEW(self).w;
vis.g_h = VIEW(self).h;
if ( !rc_intersect( &screen, &vis ) ) {
return( false );
}
vis.g_x = VIEW(self).w - vis.g_w;
vis.g_y = VIEW(self).h - vis.g_h;
/* clip box to visible region: */
if( !rc_intersect(&vis, &box) ) {
return( false );
}
out.g_x = box.g_x + VIEW(self).x;
out.g_y = box.g_y + VIEW(self).y;
out.g_w = box.g_w;
out.g_h = box.g_h;
*ret = out;
return ( true );
}
/*
convert framebuffer clipping to vdi clipping and activates it
*/
static inline void plotter_vdi_clip( GEM_PLOTTER self, bool set)
{
return;
if( set == true ) {
struct rect c;
short vdiflags[58];
short newclip[4];
self->get_clip( self, &c );
vq_extnd( self->vdi_handle, 1, (short*)&vdiflags);
prev_vdi_clip[0] = vdiflags[45];
prev_vdi_clip[1] = vdiflags[46];
prev_vdi_clip[2] = vdiflags[47];
prev_vdi_clip[3] = vdiflags[48];
newclip[0] = VIEW(self).x + MAX(c.x0, 0);
newclip[1] = VIEW(self).y + MAX(c.y0, 0);
newclip[2] = MIN(VIEW(self).x+VIEW(self).w, newclip[0] + (c.x1 - c.x0) )-1;
newclip[3] = MIN(VIEW(self).y+VIEW(self).h, newclip[1] + (c.y1 - c.y0) )-1;
vs_clip( self->vdi_handle, 1, (short*)&newclip );
} else {
vs_clip( self->vdi_handle, 1, (short *)&prev_vdi_clip );
}
}
int ctor_plotter_vdi( GEM_PLOTTER self , GRECT * loc_size )
{
int retval = 0;
int i;
struct rect clip;
self->dtor = dtor;
self->resize= resize;
self->move = move;
self->lock = lock;
self->unlock = unlock;
self->put_pixel = put_pixel;
self->copy_rect = copy_rect;
self->set_clip = set_clip;
self->get_clip = get_clip;
self->arc = arc;
self->disc = disc;
self->line = line;
self->rectangle = rectangle;
self->polygon = polygon;
self->path = path;
self->bitmap = bitmap;
self->bitmap_resize = bitmap_resize;
/* override virtual bpp - must be in sync with screen for this driver: */
self->bpp_virt = app.nplanes;
#ifdef WITH_8BPP_SUPPORT
self->bitmap_convert =(app.nplanes > 8) ? bitmap_convert : bitmap_convert_8;
#else
self->bitmap_convert = bitmap_convert;
#endif
self->plot_mfdb = plot_mfdb;
self->text = text;
LOG(("Screen: x: %d, y: %d\n", vdi_sysinfo.scr_w, vdi_sysinfo.scr_h));
self->priv_data = malloc( sizeof(struct s_vdi_priv_data) );
if( self->priv_data == NULL )
return( 0-ERR_NO_MEM );
memset( self->priv_data, 0, sizeof(struct s_vdi_priv_data) );
memset( &VIEW(self), 0, sizeof( struct s_view) );
VIEW( self ).x = loc_size->g_x;
VIEW( self ).y = loc_size->g_y;
VIEW( self ).w = loc_size->g_w;
VIEW( self ).h = loc_size->g_h;
DUMMY_PRIV(self)->bufops = 0;
DUMMY_PRIV(self)->size_buf_packed = 0;
DUMMY_PRIV(self)->size_buf_planar = 0;
DUMMY_PRIV(self)->buf_packed = NULL;
DUMMY_PRIV(self)->buf_planar = NULL;
if( vdi_sysinfo.vdiformat == VDI_FORMAT_PACK ) {
self->bpp_virt = vdi_sysinfo.scr_bpp;
} else {
DUMMY_PRIV(self)->bufops = C2P;
self->bpp_virt = 8;
}
VIEW(self).mem = NULL;
update_visible_rect( self );
clip.x0 = 0;
clip.y0 = 0;
clip.x1 = VIEW(self).w;
clip.y1 = VIEW(self).h;
self->set_clip( self, &clip );
assert( Hermes_Init() );
/* store system palette & setup the new (web) palette: */
#ifdef WITH_8BPP_SUPPORT
i = 0;
unsigned char * col;
unsigned char rgbcol[4];
unsigned char graytone=0;
if( app.nplanes <= 8 ){
for( i=0; i<=255; i++ ) {
// get the current color and save it for restore:
vq_color(self->vdi_handle, i, 1, (unsigned short*)&sys_pal[i][0] );
if( i<OFFSET_WEB_PAL ) {
pal[i][0] = sys_pal[i][0];
pal[i][1] = sys_pal[i][1];
pal[i][2] = sys_pal[i][2];
} else if( app.nplanes >= 8 ) {
if ( i < OFFSET_CUST_PAL ){
pal[i][0] = vdi_web_pal[i-OFFSET_WEB_PAL][0];
pal[i][1] = vdi_web_pal[i-OFFSET_WEB_PAL][1];
pal[i][2] = vdi_web_pal[i-OFFSET_WEB_PAL][2];
//set the new palette color to websafe value:
vs_color( self->vdi_handle, i, &pal[i][0] );
}
if( i >= OFFSET_CUST_PAL && i<OFFSET_CUST_PAL+16 ) {
/* here we define 20 additional gray colors... */
rgbcol[1] = rgbcol[2] = rgbcol[3] = ((graytone&0x0F) << 4);
rgb_to_vdi1000( &rgbcol[0], &pal[i][0] );
vs_color( self->vdi_handle, i, &pal[i][0] );
graytone++;
}
}
vdi1000_to_rgb( &pal[i][0], &rgb_lookup[i][0] );
}
} else {
/* no need to change the palette - its application specific */
}
#endif
unsigned long flags = ( self->flags & PLOT_FLAG_DITHER ) ? HERMES_CONVERT_DITHER : 0;
hermes_cnv_h = Hermes_ConverterInstance( flags );
assert( hermes_cnv_h );
hermes_res_h = Hermes_ConverterInstance( flags );
assert( hermes_res_h );
/* set up the src & dst format: */
/* netsurf uses RGBA ... */
DUMMY_PRIV(self)->nsfmt.a = 0xFFUL;
DUMMY_PRIV(self)->nsfmt.b = 0x0FF00UL;
DUMMY_PRIV(self)->nsfmt.g = 0x0FF0000UL;
DUMMY_PRIV(self)->nsfmt.r = 0x0FF000000UL;
DUMMY_PRIV(self)->nsfmt.bits = 32;
DUMMY_PRIV(self)->nsfmt.indexed = false;
DUMMY_PRIV(self)->nsfmt.has_colorkey = false;
DUMMY_PRIV(self)->vfmt.r = vdi_sysinfo.mask_r;
DUMMY_PRIV(self)->vfmt.g = vdi_sysinfo.mask_g;
DUMMY_PRIV(self)->vfmt.b = vdi_sysinfo.mask_b;
DUMMY_PRIV(self)->vfmt.a = vdi_sysinfo.mask_a;
DUMMY_PRIV(self)->vfmt.bits = self->bpp_virt;
DUMMY_PRIV(self)->vfmt.indexed = ( app.nplanes <= 8 ) ? 1 : 0;
DUMMY_PRIV(self)->vfmt.has_colorkey = 0;
return( 1 );
}
static int dtor( GEM_PLOTTER self )
{
int i=0;
LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__));
if( VIEW(self).mem )
free( VIEW(self).mem );
#ifdef WITH_8BPP_SUPPORT
for( i=OFFSET_WEB_PAL; i<OFFSET_CUST_PAL+16; i++){
vs_color( self->vdi_handle, i, &sys_pal[i][0] );
}
#endif
/* close Hermes stuff: */
Hermes_ConverterReturn( hermes_cnv_h );
Hermes_Done();
if( self->priv_data != NULL ){
if( DUMMY_PRIV(self)->buf_packed )
free( DUMMY_PRIV(self)->buf_packed );
if( DUMMY_PRIV(self)->buf_planar )
free( DUMMY_PRIV(self)->buf_planar );
free( self->priv_data );
}
snapshot_destroy( self );
return( 1 );
}
static int resize( GEM_PLOTTER self, int w, int h )
{
if( w == VIEW(self).w && h == VIEW(self).h )
return( 1 );
VIEW(self).w = w;
VIEW(self).h = h;
update_visible_rect( self );
LOG(("%s: %s\n", (char*)__FILE__, (char*)__FUNCTION__));
return( 1 );
}
static int move( GEM_PLOTTER self,short x, short y )
{
bool upd;
if(x == VIEW(self).x && y == VIEW(self).y ){
return 1;
}
LOG(("%s: x: %d, y: %d\n",(char*)__FUNCTION__, x, y));
VIEW(self).x = x;
VIEW(self).y = y;
update_visible_rect( self );
return( 1 );
}
static int lock( GEM_PLOTTER self )
{
LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__));
if( (self->flags & PLOT_FLAG_LOCKED) != 0 )
return(1);
self->flags |= PLOT_FLAG_LOCKED;
if( !wind_update(BEG_UPDATE|0x100) )
return(0);
if( !wind_update(BEG_MCTRL|0x100) ){
wind_update(END_UPDATE);
return(0);
}
graf_mouse(M_OFF, NULL);
return( 1 );
}
static int unlock( GEM_PLOTTER self )
{
LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__));
if( (self->flags & PLOT_FLAG_LOCKED) == 0 )
return(1);
self->flags &= ~PLOT_FLAG_LOCKED;
wind_update(END_MCTRL);
wind_update(END_UPDATE);
graf_mouse(M_ON, NULL);
return( 1 );
}
static int put_pixel(GEM_PLOTTER self, int x, int y, int color )
{
LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__));
return( 1 );
}
/* copy an rectangle from the plot buffer to screen */
/* because this is an on-screen plotter, this is an screen to screen copy. */
static int copy_rect( GEM_PLOTTER self, GRECT src, GRECT dst )
{
MFDB devmf;
MFDB scrmf;
short pxy[8];
GRECT vis;
/* clip to visible rect, only needed for onscreen renderer: */
plotter_get_visible_grect( self, &vis );
if( !rc_intersect(&vis, &src) )
return 1;
if( !rc_intersect(&vis, &dst) )
return 1;
src.g_x = VIEW(self).x + src.g_x;
src.g_y = VIEW(self).y + src.g_y;
dst.g_x = VIEW(self).x + dst.g_x;
dst.g_y = VIEW(self).y + dst.g_y;
devmf.fd_addr = NULL;
devmf.fd_w = src.g_w;
devmf.fd_h = src.g_h;
devmf.fd_wdwidth = 0;
devmf.fd_stand = 0;
devmf.fd_nplanes = 0;
devmf.fd_r1 = devmf.fd_r2 = devmf.fd_r3 = 0;
scrmf.fd_addr = NULL;
scrmf.fd_w = dst.g_w;
scrmf.fd_h = dst.g_h;
scrmf.fd_wdwidth = 0 ;
scrmf.fd_stand = 0;
scrmf.fd_nplanes = 0;
scrmf.fd_r1 = scrmf.fd_r2 = scrmf.fd_r3 = 0;
pxy[0] = src.g_x;
pxy[1] = src.g_y;
pxy[2] = pxy[0] + src.g_w-1;
pxy[3] = pxy[1] + src.g_h-1;
pxy[4] = dst.g_x;
pxy[5] = dst.g_y;
pxy[6] = pxy[4] + dst.g_w-1;
pxy[7] = pxy[5] + dst.g_h-1;
self->lock( self );
vro_cpyfm( self->vdi_handle, S_ONLY, (short*)&pxy, &devmf, &scrmf);
self->unlock( self );
return( 1 );
}
static int arc(GEM_PLOTTER self,int x, int y, int radius, int angle1, int angle2, const plot_style_t * pstyle)
{
//plotter_vdi_clip( self, 1);
vswr_mode( self->vdi_handle, MD_REPLACE );
if( pstyle->fill_type == PLOT_OP_TYPE_NONE )
return 1;
if( pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour);
vsf_perimeter( self->vdi_handle, 1);
vsf_interior( self->vdi_handle, 1 );
v_arc( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius, angle1*10, angle2*10 );
} else {
vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour);
vsl_width( self->vdi_handle, 1 );
vsf_perimeter( self->vdi_handle, 1);
v_arc( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius, angle1*10, angle2*10 );
}
//plotter_vdi_clip( self, 0);
return ( 1 );
}
static int disc(GEM_PLOTTER self,int x, int y, int radius, const plot_style_t * pstyle)
{
plotter_vdi_clip( self, 1);
if( pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
vsf_rgbcolor( self->vdi_handle, pstyle->stroke_colour );
vsf_perimeter( self->vdi_handle, 1);
vsf_interior( self->vdi_handle, 0 );
v_circle( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius );
} else {
vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour );
vsf_perimeter( self->vdi_handle, 0);
vsf_interior( self->vdi_handle, FIS_SOLID );
v_circle( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius );
}
plotter_vdi_clip( self, 0);
return ( 1 );
}
static int line(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle)
{
short pxy[4];
uint32_t lt;
int sw = pstyle->stroke_width;
pxy[0] = VIEW(self).x + x0;
pxy[1] = VIEW(self).y + y0;
pxy[2] = VIEW(self).x + x1;
pxy[3] = VIEW(self).y + y1;
plotter_vdi_clip( self, 1);
if( sw == 0)
sw = 1;
NSLT2VDI(lt, pstyle)
vsl_type( self->vdi_handle, (lt&0x0F) );
/* if the line style is not available within VDI system,define own style: */
if( (lt&0x0F) == 7 ){
vsl_udsty(self->vdi_handle, ((lt&0xFFFF00) >> 8) );
}
vsl_width( self->vdi_handle, (short)sw );
vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour );
v_pline(self->vdi_handle, 2, (short *)&pxy );
plotter_vdi_clip( self, 0);
return ( 1 );
}
static int rectangle(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle)
{
short pxy[4];
GRECT r, rclip, sclip;
int sw = pstyle->stroke_width;
uint32_t lt;
/* current canvas clip: */
rclip.g_x = VIEW( self ).clipping.x0;
rclip.g_y = VIEW( self ).clipping.y0;
rclip.g_w = VIEW( self ).clipping.x1 - VIEW( self ).clipping.x0;
rclip.g_h = VIEW( self ).clipping.y1 - VIEW( self ).clipping.y0;
/* physical clipping: */
sclip.g_x = rclip.g_x;
sclip.g_y = rclip.g_y;
sclip.g_w = VIEW(self).vis_w;
sclip.g_h = VIEW(self).vis_h;
rc_intersect(&sclip, &rclip);
r.g_x = x0;
r.g_y = y0;
r.g_w = x1 - x0;
r.g_h = y1 - y0;
if( !rc_intersect( &rclip, &r ) ) {
return( 1 );
}
if( pstyle->stroke_type != PLOT_OP_TYPE_NONE ){
/*
manually draw the line, because we do not need vdi clipping
for vertical / horizontal line draws.
*/
if( sw == 0)
sw = 1;
NSLT2VDI(lt, pstyle);
vsl_type( self->vdi_handle, (lt&0x0F) );
/*
if the line style is not available within VDI system,
define own style:
*/
if( (lt&0x0F) == 7 ){
vsl_udsty(self->vdi_handle, ((lt&0xFFFF00) >> 8) );
}
vsl_width( self->vdi_handle, (short)sw );
vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour );
/* top border: */
if( r.g_y == y0){
pxy[0] = VIEW(self).x + r.g_x;
pxy[1] = VIEW(self).y + r.g_y ;
pxy[2] = VIEW(self).x + r.g_x + r.g_w;
pxy[3] = VIEW(self).y + r.g_y;
v_pline(self->vdi_handle, 2, (short *)&pxy );
}
/* right border: */
if( r.g_x + r.g_w == x1 ){
pxy[0] = VIEW(self).x + r.g_x + r.g_w;
pxy[1] = VIEW(self).y + r.g_y;
pxy[2] = VIEW(self).x + r.g_x + r.g_w;
pxy[3] = VIEW(self).y + r.g_y + r.g_h;
v_pline(self->vdi_handle, 2, (short *)&pxy );
}
/* bottom border: */
if( r.g_y+r.g_h == y1 ){
pxy[0] = VIEW(self).x + r.g_x;
pxy[1] = VIEW(self).y + r.g_y+r.g_h;
pxy[2] = VIEW(self).x + r.g_x+r.g_w;
pxy[3] = VIEW(self).y + r.g_y+r.g_h;
v_pline(self->vdi_handle, 2, (short *)&pxy );
}
/* left border: */
if( r.g_x == x0 ){
pxy[0] = VIEW(self).x + r.g_x;
pxy[1] = VIEW(self).y + r.g_y;
pxy[2] = VIEW(self).x + r.g_x;
pxy[3] = VIEW(self).y + r.g_y + r.g_h;
v_pline(self->vdi_handle, 2, (short *)&pxy );
}
}
if( pstyle->fill_type != PLOT_OP_TYPE_NONE ){
short stroke_width = (short)(pstyle->stroke_type != PLOT_OP_TYPE_NONE) ?
pstyle->stroke_width : 0;
vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour );
vsf_perimeter( self->vdi_handle, 0);
vsf_interior( self->vdi_handle, FIS_SOLID );
pxy[0] = VIEW(self).x + r.g_x + stroke_width;
pxy[1] = VIEW(self).y + r.g_y + stroke_width;
pxy[2] = VIEW(self).x + r.g_x + r.g_w -1 - stroke_width ;
pxy[3] = VIEW(self).y + r.g_y + r.g_h -1 - stroke_width;
vsf_style( self->vdi_handle, 1);
v_bar( self->vdi_handle, (short*)&pxy );
}
return ( 1 );
}
static int polygon(GEM_PLOTTER self,const int *p, unsigned int n, const plot_style_t * pstyle)
{
short pxy[n*2];
unsigned int i=0;
short d[4];
if( vdi_sysinfo.maxpolycoords > 0 )
assert( (signed int)n < vdi_sysinfo.maxpolycoords );
plotter_vdi_clip( self, 1);
vsf_interior( self->vdi_handle, FIS_SOLID );
vsf_style( self->vdi_handle, 1);
for( i = 0; i<n*2; i=i+2 ) {
pxy[i] = (short)VIEW(self).x+p[i];
pxy[i+1] = (short)VIEW(self).y+p[i+1];
}
if( pstyle->fill_type == PLOT_OP_TYPE_SOLID){
vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour);
v_fillarea(self->vdi_handle, n, (short*)&pxy);
} else {
pxy[n*2]=pxy[0];
pxy[n*2+1]=pxy[1];
vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour);
v_pline(self->vdi_handle, n+1, (short *)&pxy );
}
plotter_vdi_clip( self, 0);
return ( 1 );
}
static int path(GEM_PLOTTER self,const float *p, unsigned int n, int fill, float width,
int c, const float transform[6])
{
LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__));
return ( 1 );
}
static inline uint32_t ablend(uint32_t pixel, uint32_t scrpixel)
{
int opacity = pixel & 0xFF;
int transp = 0x100 - opacity;
uint32_t rb, g;
pixel >>= 8;
scrpixel >>= 8;
rb = ((pixel & 0xFF00FF) * opacity +
(scrpixel & 0xFF00FF) * transp) >> 8;
g = ((pixel & 0x00FF00) * opacity +
(scrpixel & 0x00FF00) * transp) >> 8;
return ((rb & 0xFF00FF) | (g & 0xFF00)) << 8;
}
static int bitmap_resize( GEM_PLOTTER self, struct bitmap * img, int nw, int nh )
{
HermesFormat fmt;
short bpp = bitmap_get_bpp( img );
int stride = bitmap_get_rowstride( img );
int err;
if( img->resized != NULL ) {
if( img->resized->width != nw || img->resized->height != nh ) {
bitmap_destroy( img->resized );
img->resized = NULL;
} else {
/* the bitmap is already resized */
return( 0 );
}
}
/* allocate the mem for resized bitmap */
img->resized = bitmap_create_ex( nw, nh, bpp, nw*bpp, 0, NULL );
if( img->resized == NULL ) {
printf("W: %d, H: %d, bpp: %d\n", nw, nh, bpp);
assert( img->resized );
return ( -ERR_NO_MEM );
}
/* allocate an converter, only for resizing */
err = Hermes_ConverterRequest( hermes_res_h,
&DUMMY_PRIV(self)->nsfmt,
&DUMMY_PRIV(self)->nsfmt
);
if( err == 0 ) {
return( -ERR_PLOTTER_NOT_AVAILABLE );
}
err = Hermes_ConverterCopy( hermes_res_h,
img->pixdata,
0, /* x src coord of top left in pixel coords */
0, /* y src coord of top left in pixel coords */
bitmap_get_width( img ), bitmap_get_height( img ),
stride, /* stride as bytes */
img->resized->pixdata,
0, /* x dst coord of top left in pixel coords */
0, /* y dst coord of top left in pixel coords */
nw, nh,
bitmap_get_rowstride( img->resized ) /* stride as bytes */
);
if( err == 0 ) {
bitmap_destroy( img->resized );
img->resized = NULL;
return( -2 );
}
return( 0 );
}
// create snapshot, native screen format
static MFDB * snapshot_create_native_mfdb( GEM_PLOTTER self, int x, int y, int w, int h)
{
MFDB scr;
short pxy[8];
/* allocate memory for the snapshot */
{
int scr_stride = MFDB_STRIDE( w );
int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp );
if( DUMMY_PRIV(self)->size_buf_scr == 0 ){
/* init screen mfdb */
DUMMY_PRIV(self)->buf_scr.fd_addr = malloc( scr_size );
DUMMY_PRIV(self)->size_buf_scr = scr_size;
} else {
if( scr_size > DUMMY_PRIV(self)->size_buf_scr ) {
DUMMY_PRIV(self)->buf_scr.fd_addr = realloc(
DUMMY_PRIV(self)->buf_scr.fd_addr, scr_size
);
DUMMY_PRIV(self)->size_buf_scr = scr_size;
}
}
if( DUMMY_PRIV(self)->buf_scr.fd_addr == NULL ) {
DUMMY_PRIV(self)->size_buf_scr = 0;
return( NULL );
}
DUMMY_PRIV(self)->buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp;
DUMMY_PRIV(self)->buf_scr.fd_w = scr_stride;
DUMMY_PRIV(self)->buf_scr.fd_h = h;
DUMMY_PRIV(self)->buf_scr.fd_wdwidth = scr_stride >> 4;
assert( DUMMY_PRIV(self)->buf_scr.fd_addr != NULL );
}
init_mfdb( 0, w, h, 0, &scr );
pxy[0] = x;
pxy[1] = y;
pxy[2] = pxy[0] + w-1;
pxy[3] = pxy[1] + h-1;
pxy[4] = 0;
pxy[5] = 0;
pxy[6] = w-1;
pxy[7] = h-1;
vro_cpyfm(
self->vdi_handle, S_ONLY, (short*)&pxy,
&scr, &DUMMY_PRIV(self)->buf_scr
);
return( &DUMMY_PRIV(self)->buf_scr );
}
// create snapshot, vdi std. format
static MFDB * snapshot_create_std_mfdb(GEM_PLOTTER self, int x, int y, int w, int h)
{
/* allocate memory for the snapshot */
{
int scr_stride = MFDB_STRIDE( w );
int scr_size = ( ((scr_stride >> 3) * h) * app.nplanes );
if( DUMMY_PRIV(self)->size_buf_std == 0 ){
/* init screen mfdb */
DUMMY_PRIV(self)->buf_std.fd_addr = malloc( scr_size );
DUMMY_PRIV(self)->size_buf_std = scr_size;
} else {
if( scr_size > DUMMY_PRIV(self)->size_buf_std ) {
DUMMY_PRIV(self)->buf_std.fd_addr = realloc(
DUMMY_PRIV(self)->buf_std.fd_addr, scr_size
);
DUMMY_PRIV(self)->size_buf_std = scr_size;
}
}
if( DUMMY_PRIV(self)->buf_std.fd_addr == NULL ) {
DUMMY_PRIV(self)->size_buf_std = 0;
return( NULL );
}
DUMMY_PRIV(self)->buf_std.fd_nplanes = app.nplanes;
DUMMY_PRIV(self)->buf_std.fd_w = scr_stride;
DUMMY_PRIV(self)->buf_std.fd_h = h;
DUMMY_PRIV(self)->buf_std.fd_stand = 1;
DUMMY_PRIV(self)->buf_std.fd_wdwidth = scr_stride >> 4;
assert( DUMMY_PRIV(self)->buf_std.fd_addr != NULL );
}
MFDB * native = snapshot_create_native_mfdb( self, x,y,w,h );
assert( native );
vr_trnfm( self->vdi_handle, native, &DUMMY_PRIV(self)->buf_std );
return( &DUMMY_PRIV(self)->buf_std );
}
/*
This will create an snapshot of the screen in netsurf ABGR format
*/
static struct bitmap * snapshot_create(GEM_PLOTTER self, int x, int y, int w, int h)
{
int err;
MFDB * native;
native = snapshot_create_native_mfdb( self, x, y, w, h );
/* allocate buffer for result bitmap: */
if( DUMMY_PRIV(self)->buf_scr_compat == NULL ) {
DUMMY_PRIV(self)->buf_scr_compat = bitmap_create(w, h, 0);
} else {
DUMMY_PRIV(self)->buf_scr_compat = bitmap_realloc( w, h,
DUMMY_PRIV(self)->buf_scr_compat->bpp,
w * DUMMY_PRIV(self)->buf_scr_compat->bpp,
BITMAP_GROW,
DUMMY_PRIV(self)->buf_scr_compat );
}
/* convert screen buffer to ns format: */
err = Hermes_ConverterRequest( hermes_cnv_h,
&DUMMY_PRIV(self)->vfmt,
&DUMMY_PRIV(self)->nsfmt
);
assert( err != 0 );
err = Hermes_ConverterCopy( hermes_cnv_h,
native->fd_addr,
0, /* x src coord of top left in pixel coords */
0, /* y src coord of top left in pixel coords */
w, h,
native->fd_w * vdi_sysinfo.pixelsize, /* stride as bytes */
DUMMY_PRIV(self)->buf_scr_compat->pixdata,
0, /* x dst coord of top left in pixel coords */
0, /* y dst coord of top left in pixel coords */
w, h,
bitmap_get_rowstride(DUMMY_PRIV(self)->buf_scr_compat) /* stride as bytes */
);
assert( err != 0 );
return( (struct bitmap * )DUMMY_PRIV(self)->buf_scr_compat );
}
static void snapshot_suspend(GEM_PLOTTER self )
{
if( DUMMY_PRIV(self)->size_buf_scr > CONV_KEEP_LIMIT ) {
DUMMY_PRIV(self)->buf_scr.fd_addr = realloc(
DUMMY_PRIV(self)->buf_scr.fd_addr, CONV_KEEP_LIMIT
);
if( DUMMY_PRIV(self)->buf_scr.fd_addr != NULL ) {
DUMMY_PRIV(self)->size_buf_scr = CONV_KEEP_LIMIT;
} else {
DUMMY_PRIV(self)->size_buf_scr = 0;
}
}
if( DUMMY_PRIV(self)->size_buf_std > CONV_KEEP_LIMIT ) {
DUMMY_PRIV(self)->buf_std.fd_addr = realloc(
DUMMY_PRIV(self)->buf_std.fd_addr, CONV_KEEP_LIMIT
);
if( DUMMY_PRIV(self)->buf_std.fd_addr != NULL ) {
DUMMY_PRIV(self)->size_buf_std = CONV_KEEP_LIMIT;
} else {
DUMMY_PRIV(self)->size_buf_std = 0;
}
}
if( bitmap_buffer_size( DUMMY_PRIV(self)->buf_scr_compat ) > CONV_KEEP_LIMIT ) {
int w = 0;
int h = 1;
w = (CONV_KEEP_LIMIT / DUMMY_PRIV(self)->buf_scr_compat->bpp);
assert( CONV_KEEP_LIMIT == w*DUMMY_PRIV(self)->buf_scr_compat->bpp );
DUMMY_PRIV(self)->buf_scr_compat = bitmap_realloc( w, h,
DUMMY_PRIV(self)->buf_scr_compat->bpp,
CONV_KEEP_LIMIT, BITMAP_SHRINK, DUMMY_PRIV(self)->buf_scr_compat
);
}
}
static void snapshot_destroy( GEM_PLOTTER self )
{
if( DUMMY_PRIV(self)->buf_scr.fd_addr ) {
free( DUMMY_PRIV(self)->buf_scr.fd_addr );
DUMMY_PRIV(self)->buf_scr.fd_addr = NULL;
}
if( DUMMY_PRIV(self)->buf_std.fd_addr ) {
free( DUMMY_PRIV(self)->buf_std.fd_addr );
DUMMY_PRIV(self)->buf_std.fd_addr = NULL;
}
if( DUMMY_PRIV(self)->buf_scr_compat ) {
bitmap_destroy( DUMMY_PRIV(self)->buf_scr_compat );
DUMMY_PRIV(self)->buf_scr_compat = NULL;
}
}
static inline void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val )
{
short * buf;
short whichbit = (1<<(15-(x%16)));
buf = dst->fd_addr;
buf += ((dst->fd_wdwidth*(y))+(x>>4));
*buf = (val&1) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
buf += wdplanesz;
*buf = (val&(1<<1)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
buf += wdplanesz;
*buf = (val&(1<<2)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
buf += wdplanesz;
*buf = (val&(1<<3)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
buf += wdplanesz;
*buf = (val&(1<<4)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
buf += wdplanesz;
*buf = (val&(1<<5)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
buf += wdplanesz;
*buf = (val&(1<<6)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
buf += wdplanesz;
*buf = (val&(1<<7)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
}
static inline unsigned char get_stdpx(MFDB * dst, int wdplanesz, int x, int y )
{
unsigned char ret=0;
short * buf;
short whichbit = (1<<(15-(x%16)));
buf = dst->fd_addr;
buf += ((dst->fd_wdwidth*(y))+(x>>4));
if( *buf & whichbit )
ret |= 1;
buf += wdplanesz;
if( *buf & whichbit )
ret |= 2;
buf += wdplanesz;
if( *buf & whichbit )
ret |= 4;
buf += wdplanesz;
if( *buf & whichbit )
ret |= 8;
buf += wdplanesz;
if( *buf & whichbit )
ret |= 16;
buf += wdplanesz;
if( *buf & whichbit )
ret |= 32;
buf += wdplanesz;
if( *buf & whichbit )
ret |= 64;
buf += wdplanesz;
if( *buf & whichbit )
ret |= 128;
return( ret );
}
#ifdef WITH_8BPP_SUPPORT
static int bitmap_convert_8( GEM_PLOTTER self,
struct bitmap * img,
int x,
int y,
GRECT * clip,
uint32_t bg,
uint32_t flags,
MFDB *out )
{
int dststride; /* stride of dest. image */
int dstsize; /* size of dest. in byte */
int err;
int bw;
struct bitmap * scrbuf = NULL;
struct bitmap * bm;
bool transp = ( ( (img->opaque == false) || ( (flags & BITMAP_MONOGLYPH) != 0) )
&& ((self->flags & PLOT_FLAG_TRANS) != 0) );
assert( clip->g_h > 0 );
assert( clip->g_w > 0 );
bm = img;
bw = bitmap_get_width( img );
dststride = MFDB_STRIDE( clip->g_w );
dstsize = ( ((dststride >> 3) * clip->g_h) * self->bpp_virt );
/* (re)allocate buffer for out image: */
/* altough the buffer is named "buf_packed" on 8bit systems */
/* it's not... */
if( dstsize > DUMMY_PRIV(self)->size_buf_packed) {
int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
if( DUMMY_PRIV(self)->buf_packed == NULL )
DUMMY_PRIV(self)->buf_packed =(void*)malloc( blocks * CONV_BLOCK_SIZE );
else
DUMMY_PRIV(self)->buf_packed =(void*)realloc(
DUMMY_PRIV(self)->buf_packed,
blocks * CONV_BLOCK_SIZE
);
assert( DUMMY_PRIV(self)->buf_packed );
if( DUMMY_PRIV(self)->buf_packed == NULL ) {
return( 0-ERR_NO_MEM );
}
DUMMY_PRIV(self)->size_buf_packed = blocks * CONV_BLOCK_SIZE;
}
/*
on 8 bit systems we must convert the TC (ABGR) image
to vdi standard format. ( only tested for 256 colors )
and then convert it to native format
*/
// realloc mem for stdform
MFDB stdform;
if( transp ){
if( ((self->flags & PLOT_FLAG_TRANS) != 0) || ( (flags & BITMAP_MONOGLYPH) != 0) ) {
// point image to snapshot buffer, otherwise allocate mem
MFDB * bg = snapshot_create_std_mfdb( self, x+clip->g_x,y+clip->g_y, clip->g_w, clip->g_h );
stdform.fd_addr = bg->fd_addr;
} else {
if( dstsize > DUMMY_PRIV(self)->size_buf_planar) {
int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
if( DUMMY_PRIV(self)->buf_planar == NULL )
DUMMY_PRIV(self)->buf_planar =(void*)malloc( blocks * CONV_BLOCK_SIZE );
else
DUMMY_PRIV(self)->buf_planar =(void*)realloc(
DUMMY_PRIV(self)->buf_planar,
blocks * CONV_BLOCK_SIZE
);
assert( DUMMY_PRIV(self)->buf_planar );
if( DUMMY_PRIV(self)->buf_planar == NULL ) {
return( 0-ERR_NO_MEM );
}
DUMMY_PRIV(self)->size_buf_planar = blocks * CONV_BLOCK_SIZE;
}
stdform.fd_addr = DUMMY_PRIV(self)->buf_planar;
}
}
stdform.fd_w = dststride;
stdform.fd_h = clip->g_h;
stdform.fd_wdwidth = dststride >> 4;
stdform.fd_stand = 1;
stdform.fd_nplanes = (short)self->bpp_virt;
stdform.fd_r1 = stdform.fd_r2 = stdform.fd_r3 = 0;
int img_stride = bitmap_get_rowstride(bm);
uint32_t prev_pixel = 0x12345678;
unsigned long col = 0;
unsigned char val = 0;
uint32_t * row;
uint32_t pixel;
int wdplanesize = stdform.fd_wdwidth*stdform.fd_h;
// apply transparency.
if( transp ){
unsigned long bgcol = 0;
unsigned char prev_col = 0;
for( y=0; y<clip->g_h; y++ ){
row = (uint32_t *)(bm->pixdata + (img_stride * (y+clip->g_y)));
for( x=0; x<clip->g_w; x++ ){
pixel = row[x+clip->g_x];
if( (pixel&0xFF) == 0 ){
continue;
}
if( (pixel&0xFF) < 0xF0 ){
col = get_stdpx( &stdform, wdplanesize,x,y );
if( (col != prev_col) || (y == 0) )
bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8);
if( prev_col != col || prev_pixel != pixel ){
prev_col = col;
pixel = ablend( pixel, bgcol );
prev_pixel = pixel;
pixel = pixel >> 8;
/* convert pixel value to vdi color index: */
col = ( ((pixel&0xFF)<<16)
| (pixel&0xFF00)
| ((pixel&0xFF0000)>>16) );
val = RGB_TO_VDI( col );
}
set_stdpx( &stdform, wdplanesize, x,y, val );
} else {
if( pixel != prev_pixel ){
/* convert pixel value to vdi color index: */
pixel = pixel >> 8;
col = ( ((pixel&0xFF)<<16)
| (pixel&0xFF00)
| ((pixel&0xFF0000)>>16) );
val = RGB_TO_VDI( col );
prev_pixel = pixel;
}
set_stdpx( &stdform, wdplanesize, x,y, val );
}
}
}
} else {
for( y=0; y<clip->g_h; y++ ){
row = (uint32_t *)(bm->pixdata + (img_stride * (y+clip->g_y)));
for( x=0; x<clip->g_w; x++ ){
pixel = row[x+clip->g_x];
if( pixel != prev_pixel ){
/* convert pixel value to vdi color index: */
pixel = pixel >> 8;
col = ( ((pixel&0xFF)<<16)
| (pixel&0xFF00)
| ((pixel&0xFF0000)>>16) );
val = RGB_TO_VDI( col );
prev_pixel = pixel;
}
set_stdpx( &stdform, wdplanesize, x,y, val );
}
}
}
// convert into native format:
MFDB native;
native.fd_addr = DUMMY_PRIV(self)->buf_packed;
native.fd_w = dststride;
native.fd_h = clip->g_h;
native.fd_wdwidth = dststride >> 4;
native.fd_stand = 0;
native.fd_nplanes = (short)self->bpp_virt;
native.fd_r1 = native.fd_r2 = native.fd_r3 = 0;
vr_trnfm( self->vdi_handle, &stdform, &native );
*out = native;
return(0);
}
#endif
/* convert bitmap to the virutal (chunked) framebuffer format */
static int bitmap_convert( GEM_PLOTTER self,
struct bitmap * img,
int x,
int y,
GRECT * clip,
uint32_t bg,
uint32_t flags,
MFDB *out )
{
int dststride; /* stride of dest. image */
int dstsize; /* size of dest. in byte */
int err;
int bw;
struct bitmap * scrbuf = NULL;
struct bitmap * bm;
assert( clip->g_h > 0 );
assert( clip->g_w > 0 );
bm = img;
bw = bitmap_get_width( img );
/* rem. if eddi xy is installed, we could directly access the screen! */
/* apply transparency to the image: */
if( (img->opaque == false)
&& ( (self->flags & PLOT_FLAG_TRANS) != 0)
&& (
(vdi_sysinfo.vdiformat == VDI_FORMAT_PACK )
||
( (flags & BITMAP_MONOGLYPH) != 0)
) ) {
uint32_t * imgpixel;
uint32_t * screenpixel;
int img_x, img_y; /* points into old bitmap */
int screen_x, screen_y; /* pointers into new bitmap */
/* copy the screen to an temp buffer: */
scrbuf = snapshot_create(self, x, y, clip->g_w, clip->g_h );
if( scrbuf != NULL ) {
/* copy blended pixels the new buffer (which contains screen content): */
int img_stride = bitmap_get_rowstride(bm);
int screen_stride = bitmap_get_rowstride(scrbuf);
for( img_y = clip->g_y, screen_y = 0; screen_y < clip->g_h; screen_y++, img_y++) {
imgpixel = (uint32_t *)(bm->pixdata + (img_stride * img_y));
screenpixel = (uint32_t *)(scrbuf->pixdata + (screen_stride * screen_y));
for( img_x = clip->g_x, screen_x = 0; screen_x < clip->g_w; screen_x++, img_x++ ) {
if( (imgpixel[img_x] & 0xFF) == 0xFF ) {
screenpixel[screen_x] = imgpixel[img_x];
} else {
if( (imgpixel[img_x] & 0x0FF) != 0 ) {
screenpixel[screen_x] = ablend( imgpixel[img_x], screenpixel[screen_x]);
}
}
}
}
clip->g_x = 0;
clip->g_y = 0;
bm = scrbuf;
}
}
/* (re)allocate buffer for framebuffer image: */
dststride = MFDB_STRIDE( clip->g_w );
dstsize = ( ((dststride >> 3) * clip->g_h) * self->bpp_virt);
if( dstsize > DUMMY_PRIV(self)->size_buf_packed) {
int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
if( DUMMY_PRIV(self)->buf_packed == NULL )
DUMMY_PRIV(self)->buf_packed =(void*)malloc( blocks * CONV_BLOCK_SIZE );
else
DUMMY_PRIV(self)->buf_packed =(void*)realloc(
DUMMY_PRIV(self)->buf_packed,
blocks * CONV_BLOCK_SIZE
);
assert( DUMMY_PRIV(self)->buf_packed );
if( DUMMY_PRIV(self)->buf_packed == NULL ) {
if( scrbuf != NULL )
bitmap_destroy( scrbuf );
return( 0-ERR_NO_MEM );
}
DUMMY_PRIV(self)->size_buf_packed = blocks * CONV_BLOCK_SIZE;
}
out->fd_addr = DUMMY_PRIV(self)->buf_packed;
out->fd_w = dststride;
out->fd_h = clip->g_h;
out->fd_wdwidth = dststride >> 4;
out->fd_stand = 0;
out->fd_nplanes = (short)self->bpp_virt;
out->fd_r1 = out->fd_r2 = out->fd_r3 = 0;
err = Hermes_ConverterRequest(
hermes_cnv_h,
&DUMMY_PRIV(self)->nsfmt,
&DUMMY_PRIV(self)->vfmt
);
assert( err != 0 );
/* convert image to virtual format: */
err = Hermes_ConverterCopy( hermes_cnv_h,
bm->pixdata,
clip->g_x, /* x src coord of top left in pixel coords */
clip->g_y, /* y src coord of top left in pixel coords */
clip->g_w, clip->g_h,
bm->rowstride, /* stride as bytes */
out->fd_addr,
0, /* x dst coord of top left in pixel coords */
0, /* y dst coord of top left in pixel coords */
clip->g_w, clip->g_h,
(dststride >> 3) * self->bpp_virt /* stride as bytes */
);
assert( err != 0 );
return( 0 );
}
static void convert_bitmap_done( GEM_PLOTTER self )
{
if( DUMMY_PRIV(self)->size_buf_packed > CONV_KEEP_LIMIT ) {
/* free the mem if it was an large allocation ... */
DUMMY_PRIV(self)->buf_packed = realloc( DUMMY_PRIV(self)->buf_packed, CONV_KEEP_LIMIT );
DUMMY_PRIV(self)->size_buf_packed = CONV_KEEP_LIMIT;
}
snapshot_suspend( self );
}
static int bitmap( GEM_PLOTTER self, struct bitmap * bmp, int x, int y,
unsigned long bg, unsigned long flags )
{
MFDB src_mf;
MFDB scrmf;
short pxy[8];
GRECT off, clip, loc, vis;
src_mf.fd_addr = NULL;
scrmf.fd_addr = NULL;
off.g_x = x;
off.g_y = y;
off.g_h = bmp->height;
off.g_w = bmp->width;
clip.g_x = VIEW( self ).clipping.x0;
clip.g_y = VIEW( self ).clipping.y0;
clip.g_w = VIEW( self ).clipping.x1 - VIEW( self ).clipping.x0;
clip.g_h = VIEW( self ).clipping.y1 - VIEW( self ).clipping.y0;
if( !rc_intersect( &clip, &off) ) {
return( true );
}
plotter_get_visible_grect( self, &vis );
if( !rc_intersect( &vis, &off) ) {
return( true );
}
loc = off;
off.g_x = MAX(0, off.g_x - x);
off.g_y = MAX(0, off.g_y - y);
loc.g_x = MAX(0, loc.g_x);
loc.g_y = MAX(0, loc.g_y);
pxy[0] = 0;
pxy[1] = 0;
pxy[2] = off.g_w-1;
pxy[3] = off.g_h-1;
pxy[4] = VIEW(self).x + loc.g_x;
pxy[5] = VIEW(self).y + loc.g_y;
pxy[6] = VIEW(self).x + loc.g_x + off.g_w-1;
pxy[7] = VIEW(self).y + loc.g_y + off.g_h-1;
/* Convert the Bitmap to native screen format - ready for output*/
/* This includes blending transparent pixels */
if( self->bitmap_convert( self, bmp, pxy[4], pxy[5], &off, bg, flags, &src_mf) != 0 ) {
return( true );
}
vro_cpyfm( self->vdi_handle, S_ONLY, (short*)&pxy, &src_mf, &scrmf);
convert_bitmap_done( self );
return( true );
}
static int plot_mfdb (GEM_PLOTTER self, GRECT * loc, MFDB * insrc, unsigned char fgcolor, uint32_t flags)
{
MFDB screen, tran;
MFDB * src;
short pxy[8];
short c[2] = {fgcolor, WHITE};
GRECT off;
plotter_get_clip_grect( self, &off );
if( rc_intersect(loc, &off) == 0 ){
return( 1 );
}
init_mfdb( 0, loc->g_w, loc->g_h, 0, &screen );
if( insrc->fd_stand ){
int size = init_mfdb( insrc->fd_nplanes, loc->g_w, loc->g_h,
MFDB_FLAG_NOALLOC,
&tran
);
if( DUMMY_PRIV(self)->size_buf_scr == 0 ){
DUMMY_PRIV(self)->buf_scr.fd_addr = malloc( size );
DUMMY_PRIV(self)->size_buf_scr = size;
} else {
if( size > DUMMY_PRIV(self)->size_buf_scr ) {
DUMMY_PRIV(self)->buf_scr.fd_addr = realloc(
DUMMY_PRIV(self)->buf_scr.fd_addr, size
);
DUMMY_PRIV(self)->size_buf_scr = size;
}
}
tran.fd_addr = DUMMY_PRIV(self)->buf_scr.fd_addr;
vr_trnfm( self->vdi_handle, insrc, &tran );
src = &tran;
} else {
src = insrc;
}
pxy[0] = off.g_x - loc->g_x;
pxy[1] = off.g_y - loc->g_y;
pxy[2] = pxy[0] + off.g_w - 1;
pxy[3] = pxy[1] + off.g_h - 1;
pxy[4] = VIEW(self).x + off.g_x;
pxy[5] = VIEW(self).y + off.g_y;
pxy[6] = pxy[4] + off.g_w-1;
pxy[7] = pxy[5] + off.g_h-1;
if( flags & PLOT_FLAG_TRANS && src->fd_nplanes == 1){
vrt_cpyfm( self->vdi_handle, MD_TRANS, (short*)pxy, src, &screen, (short*)&c );
} else {
/* this method only plots transparent bitmaps, right now... */
}
return( 1 );
}
static int text(GEM_PLOTTER self, int x, int y, const char *text, size_t length, const plot_font_style_t *fstyle)
{
self->font_plotter->text( self->font_plotter, x, y,
text, length, fstyle
);
return ( 1 );
}