/* * Copyright 2010 Ole Loots * * 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 . */ #include #include #include #include #include #include #include #include "image/bitmap.h" #include "utils/log.h" #include "utils/utf8.h" #include "utils/utils.h" #include "desktop/gui.h" #include "desktop/plotters.h" #include "atari/bitmap.h" #include "atari/gui.h" #include "desktop/options.h" #include "atari/plot/plot.h" struct s_view { short x; /* drawing (screen) offset x */ short y; /* drawing (screen) offset y */ short w; /* width of buffer, not in sync with vis_w */ short h; /* height of buffer, not in sync with vis_w */ short vis_x; /* visible rectangle of the screen buffer */ short vis_y; /* coords are relative to plot location */ short vis_w; /* clipped to screen dimensions */ short vis_h; /* visible width */ struct rect clipping; /* clipping rectangle */ }; /* * Capture the screen at x,y location * param self instance * param x absolute screen coords * param y absolute screen coords * param w width * param h height * * This creates an snapshot in RGBA format (NetSurf's native format) * */ static struct bitmap * snapshot_create(int x, int y, int w, int h); /* Garbage collection of the snapshot routine */ /* this should be called after you are done with the data returned by snapshot_create */ /* don't access the screenshot after you called this function */ static void snapshot_suspend(void); /* destroy memory used by screenshot */ static void snapshot_destroy(void); /* convert an bgra color to vdi1000 color */ void rgb_to_vdi1000( unsigned char * in, unsigned short * out ); /* convert an rgb color to an index into the web palette */ short rgb_to_666_index(unsigned char r, unsigned char g, unsigned char b); #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]; short web_std_colors[6] = {0, 51, 102, 153, 204, 255}; unsigned short vdi_web_pal[216][3] = { {0x000,0x000,0x000}, {0x0c8,0x000,0x000}, {0x190,0x000,0x000}, {0x258,0x000,0x000}, {0x320,0x000,0x000}, {0x3e8,0x000,0x000}, {0x000,0x0c8,0x000}, {0x0c8,0x0c8,0x000}, {0x190,0x0c8,0x000}, {0x258,0x0c8,0x000}, {0x320,0x0c8,0x000}, {0x3e8,0x0c8,0x000}, {0x000,0x190,0x000}, {0x0c8,0x190,0x000}, {0x190,0x190,0x000}, {0x258,0x190,0x000}, {0x320,0x190,0x000}, {0x3e8,0x190,0x000}, {0x000,0x258,0x000}, {0x0c8,0x258,0x000}, {0x190,0x258,0x000}, {0x258,0x258,0x000}, {0x320,0x258,0x000}, {0x3e8,0x258,0x000}, {0x000,0x320,0x000}, {0x0c8,0x320,0x000}, {0x190,0x320,0x000}, {0x258,0x320,0x000}, {0x320,0x320,0x000}, {0x3e8,0x320,0x000}, {0x000,0x3e8,0x000}, {0x0c8,0x3e8,0x000}, {0x190,0x3e8,0x000}, {0x258,0x3e8,0x000}, {0x320,0x3e8,0x000}, {0x3e8,0x3e8,0x000}, {0x000,0x000,0x0c8}, {0x0c8,0x000,0x0c8}, {0x190,0x000,0x0c8}, {0x258,0x000,0x0c8}, {0x320,0x000,0x0c8}, {0x3e8,0x000,0x0c8}, {0x000,0x0c8,0x0c8}, {0x0c8,0x0c8,0x0c8}, {0x190,0x0c8,0x0c8}, {0x258,0x0c8,0x0c8}, {0x320,0x0c8,0x0c8}, {0x3e8,0x0c8,0x0c8}, {0x000,0x190,0x0c8}, {0x0c8,0x190,0x0c8}, {0x190,0x190,0x0c8}, {0x258,0x190,0x0c8}, {0x320,0x190,0x0c8}, {0x3e8,0x190,0x0c8}, {0x000,0x258,0x0c8}, {0x0c8,0x258,0x0c8}, {0x190,0x258,0x0c8}, {0x258,0x258,0x0c8}, {0x320,0x258,0x0c8}, {0x3e8,0x258,0x0c8}, {0x000,0x320,0x0c8}, {0x0c8,0x320,0x0c8}, {0x190,0x320,0x0c8}, {0x258,0x320,0x0c8}, {0x320,0x320,0x0c8}, {0x3e8,0x320,0x0c8}, {0x000,0x3e8,0x0c8}, {0x0c8,0x3e8,0x0c8}, {0x190,0x3e8,0x0c8}, {0x258,0x3e8,0x0c8}, {0x320,0x3e8,0x0c8}, {0x3e8,0x3e8,0x0c8}, {0x000,0x000,0x190}, {0x0c8,0x000,0x190}, {0x190,0x000,0x190}, {0x258,0x000,0x190}, {0x320,0x000,0x190}, {0x3e8,0x000,0x190}, {0x000,0x0c8,0x190}, {0x0c8,0x0c8,0x190}, {0x190,0x0c8,0x190}, {0x258,0x0c8,0x190}, {0x320,0x0c8,0x190}, {0x3e8,0x0c8,0x190}, {0x000,0x190,0x190}, {0x0c8,0x190,0x190}, {0x190,0x190,0x190}, {0x258,0x190,0x190}, {0x320,0x190,0x190}, {0x3e8,0x190,0x190}, {0x000,0x258,0x190}, {0x0c8,0x258,0x190}, {0x190,0x258,0x190}, {0x258,0x258,0x190}, {0x320,0x258,0x190}, {0x3e8,0x258,0x190}, {0x000,0x320,0x190}, {0x0c8,0x320,0x190}, {0x190,0x320,0x190}, {0x258,0x320,0x190}, {0x320,0x320,0x190}, {0x3e8,0x320,0x190}, {0x000,0x3e8,0x190}, {0x0c8,0x3e8,0x190}, {0x190,0x3e8,0x190}, {0x258,0x3e8,0x190}, {0x320,0x3e8,0x190}, {0x3e8,0x3e8,0x190}, {0x000,0x000,0x258}, {0x0c8,0x000,0x258}, {0x190,0x000,0x258}, {0x258,0x000,0x258}, {0x320,0x000,0x258}, {0x3e8,0x000,0x258}, {0x000,0x0c8,0x258}, {0x0c8,0x0c8,0x258}, {0x190,0x0c8,0x258}, {0x258,0x0c8,0x258}, {0x320,0x0c8,0x258}, {0x3e8,0x0c8,0x258}, {0x000,0x190,0x258}, {0x0c8,0x190,0x258}, {0x190,0x190,0x258}, {0x258,0x190,0x258}, {0x320,0x190,0x258}, {0x3e8,0x190,0x258}, {0x000,0x258,0x258}, {0x0c8,0x258,0x258}, {0x190,0x258,0x258}, {0x258,0x258,0x258}, {0x320,0x258,0x258}, {0x3e8,0x258,0x258}, {0x000,0x320,0x258}, {0x0c8,0x320,0x258}, {0x190,0x320,0x258}, {0x258,0x320,0x258}, {0x320,0x320,0x258}, {0x3e8,0x320,0x258}, {0x000,0x3e8,0x258}, {0x0c8,0x3e8,0x258}, {0x190,0x3e8,0x258}, {0x258,0x3e8,0x258}, {0x320,0x3e8,0x258}, {0x3e8,0x3e8,0x258}, {0x000,0x000,0x320}, {0x0c8,0x000,0x320}, {0x190,0x000,0x320}, {0x258,0x000,0x320}, {0x320,0x000,0x320}, {0x3e8,0x000,0x320}, {0x000,0x0c8,0x320}, {0x0c8,0x0c8,0x320}, {0x190,0x0c8,0x320}, {0x258,0x0c8,0x320}, {0x320,0x0c8,0x320}, {0x3e8,0x0c8,0x320}, {0x000,0x190,0x320}, {0x0c8,0x190,0x320}, {0x190,0x190,0x320}, {0x258,0x190,0x320}, {0x320,0x190,0x320}, {0x3e8,0x190,0x320}, {0x000,0x258,0x320}, {0x0c8,0x258,0x320}, {0x190,0x258,0x320}, {0x258,0x258,0x320}, {0x320,0x258,0x320}, {0x3e8,0x258,0x320}, {0x000,0x320,0x320}, {0x0c8,0x320,0x320}, {0x190,0x320,0x320}, {0x258,0x320,0x320}, {0x320,0x320,0x320}, {0x3e8,0x320,0x320}, {0x000,0x3e8,0x320}, {0x0c8,0x3e8,0x320}, {0x190,0x3e8,0x320}, {0x258,0x3e8,0x320}, {0x320,0x3e8,0x320}, {0x3e8,0x3e8,0x320}, {0x000,0x000,0x3e8}, {0x0c8,0x000,0x3e8}, {0x190,0x000,0x3e8}, {0x258,0x000,0x3e8}, {0x320,0x000,0x3e8}, {0x3e8,0x000,0x3e8}, {0x000,0x0c8,0x3e8}, {0x0c8,0x0c8,0x3e8}, {0x190,0x0c8,0x3e8}, {0x258,0x0c8,0x3e8}, {0x320,0x0c8,0x3e8}, {0x3e8,0x0c8,0x3e8}, {0x000,0x190,0x3e8}, {0x0c8,0x190,0x3e8}, {0x190,0x190,0x3e8}, {0x258,0x190,0x3e8}, {0x320,0x190,0x3e8}, {0x3e8,0x190,0x3e8}, {0x000,0x258,0x3e8}, {0x0c8,0x258,0x3e8}, {0x190,0x258,0x3e8}, {0x258,0x258,0x3e8}, {0x320,0x258,0x3e8}, {0x3e8,0x258,0x3e8}, {0x000,0x320,0x3e8}, {0x0c8,0x320,0x3e8}, {0x190,0x320,0x3e8}, {0x258,0x320,0x3e8}, {0x320,0x320,0x3e8}, {0x3e8,0x320,0x3e8}, {0x000,0x3e8,0x3e8}, {0x0c8,0x3e8,0x3e8}, {0x190,0x3e8,0x3e8}, {0x258,0x3e8,0x3e8}, {0x320,0x3e8,0x3e8}, {0x3e8,0x3e8,0x3e8} }; #endif /* Error code translations: */ static const char * plot_error_codes[] = { "None", "ERR_BUFFERSIZE_EXCEEDS_SCREEN", "ERR_NO_MEM", "ERR_PLOTTER_NOT_AVAILABLE" }; FONT_PLOTTER fplotter = NULL; extern short vdih; /* temp buffer for bitmap conversion: */ static void * buf_packed; static int size_buf_packed; /* temp buffer for bitmap conversion: */ void * buf_planar; int size_buf_planar; /* buffer for plot operations that require device format, */ /* currently used for transparent mfdb blits and snapshots: */ static MFDB buf_scr; static int size_buf_scr; /* buffer for std form, used during 8bpp snapshot */ MFDB buf_std; int size_buf_std; struct bitmap * buf_scr_compat; /* intermediate bitmap format */ static HermesFormat vfmt; /* no screen format here, hermes may not suitable for it */ /* netsurf source bitmap format */ static HermesFormat nsfmt; static struct s_vdi_sysinfo vdi_sysinfo; /* bit depth of framebuffers: */ static int atari_plot_bpp_virt; static struct s_view view; 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]; static struct bitmap snapshot; int atari_plot_vdi_handle; unsigned long atari_plot_flags; unsigned long atari_font_flags; typedef bool (*bitmap_convert_fnc)( struct bitmap * img, int x, int y, GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out ); static bitmap_convert_fnc bitmap_convert; const char* plot_err_str(int i) { return(plot_error_codes[abs(i)]); } inline static void vsl_rgbcolor(short vdih, uint32_t cin) { #ifdef WITH_8BPP_SUPPORT if( vdi_sysinfo.scr_bpp > 8 ) { #endif 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); #ifdef WITH_8BPP_SUPPORT } else { if( vdi_sysinfo.scr_bpp >= 4 ){ vsl_color(vdih, RGB_TO_VDI(cin)); } else vsl_color(vdih, BLACK); } #endif } inline static void vsf_rgbcolor(short vdih, uint32_t cin) { #ifdef WITH_8BPP_SUPPORT if( vdi_sysinfo.scr_bpp > 8 ) { #endif 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 ); #ifdef WITH_8BPP_SUPPORT } else { if( vdi_sysinfo.scr_bpp >= 4 ){ vsf_color( vdih, RGB_TO_VDI(cin) ); } else vsf_color( vdih, WHITE ); } #endif } /* Get current visible coords */ inline static void plot_get_visible_grect(GRECT * out) { out->g_x = view.vis_x; out->g_y = view.vis_y; out->g_w = view.vis_w; out->g_h = view.vis_h; } /* calculate visible area of framebuffer in coords relative to framebuffer */ /* position */ /* result: */ /* this function should calculates an rectangle relative to the plot origin*/ /* and size. */ /* If the ploter coords do not fall within the screen region, */ /* all values of the region are set to zero. */ inline static void update_visible_rect(void) { 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.x; common.g_y = frame.g_y = view.y; common.g_w = frame.g_w = view.w; common.g_h = frame.g_h = view.h; if( rc_intersect( &screen, &common ) ) { view.vis_w = common.g_w; view.vis_h = common.g_h; if( view.x < screen.g_x ) view.vis_x = frame.g_w - common.g_w; else view.vis_x = 0; if( view.y vdi_handle = vdih; if ( tos_getcookie(C_EdDI, &cookie_EdDI) == C_NOTFOUND ) { info->EdDiVersion = 0; } else { info->EdDiVersion = EdDI_version( (void *)cookie_EdDI ); } memset( &out, 0, sizeof(short)*300 ); vq_extnd( vdih, 0, (short*)&out ); info->scr_w = out[0]+1; info->scr_h = out[1]+1; if( out[39] == 2 ) { info->scr_bpp = 1; info->colors = out[39]; } else { info->colors = out[39]; } memset( &out, 0, sizeof(short)*300 ); vq_extnd( vdih, 1, (short*)&out ); info->scr_bpp = out[4]; info->maxpolycoords = out[14]; info->maxintin = out[15]; if( out[30] & 1 ) { info->rasterscale = true; } else { info->rasterscale = false; } switch( info->scr_bpp ) { case 8: info->pixelsize=1; break; case 15: case 16: info->pixelsize=2; break; case 24: info->pixelsize=3; break; case 32: info->pixelsize=4; break; case 64: info->pixelsize=8; break; default: info->pixelsize=1; break; } info->pitch = info->scr_w * info->pixelsize; info->vdiformat = ( (info->scr_bpp <= 8) ? VDI_FORMAT_INTER : VDI_FORMAT_PACK); info->screensize = ( info->scr_w * info->pixelsize ) * info->scr_h; if( info->EdDiVersion >= EDDI_10 ) { memset( &out, 0, sizeof(short)*300 ); vq_scrninfo(vdih, (short*)&out); info->vdiformat = out[0]; info->clut = out[1]; info->scr_bpp = out[2]; info->hicolors = *((unsigned long*) &out[3]); if( info->EdDiVersion >= EDDI_11 ) { info->pitch = out[5]; info->screen = (void *) *((unsigned long *) &out[6]); } switch( info->clut ) { case VDI_CLUT_HARDWARE: { } break; case VDI_CLUT_SOFTWARE: { int component; /* red, green, blue, alpha, overlay */ int num_bit; unsigned short *tmp_p; /* We can build masks with info here */ tmp_p = (unsigned short *) &out[16]; for (component=0; component<5; component++) { for (num_bit=0; num_bit<16; num_bit++) { unsigned short val; val = *tmp_p++; if (val == 0xffff) { continue; } switch(component) { case 0: info->mask_r |= 1<< val; break; case 1: info->mask_g |= 1<< val; break; case 2: info->mask_b |= 1<< val; break; case 3: info->mask_a |= 1<< val; break; } } } } /* Remove lower green bits for Intel endian screen */ if ((info->mask_g == ((7<<13)|3)) || (info->mask_g == ((7<<13)|7))) { info->mask_g &= ~(7<<13); } break; case VDI_CLUT_NONE: break; } } } /* Convert an RGB color to an VDI Color */ inline void rgb_to_vdi1000(unsigned char * in, unsigned short * out) { double r = ((double)in[3]/255); /* prozentsatz red */ double g = ((double)in[2]/255); /* prozentsatz green */ double b = ((double)in[1]/255); /* prozentsatz blue */ out[0] = 1000 * r + 0.5; out[1] = 1000 * g + 0.5; out[2] = 1000 * b + 0.5; return; } inline void vdi1000_to_rgb(unsigned short * in, unsigned char * out) { double r = ((double)in[0]/1000); /* prozentsatz red */ double g = ((double)in[1]/1000); /* prozentsatz green */ double b = ((double)in[2]/1000); /* prozentsatz blue */ out[2] = 255 * r + 0.5; out[1] = 255 * g + 0.5; out[0] = 255 * b + 0.5; return; } #ifdef WITH_8BPP_SUPPORT inline static 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)); } inline static 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 ); } /* Convert an RGB color into an index into the 216 colors web pallette */ inline short rgb_to_666_index(unsigned char r, unsigned char g, unsigned char b) { short ret = 0; short i; unsigned char rgb[3] = {r,g,b}; unsigned char tval[3]; int diff_a, diff_b, diff_c; diff_a = abs(r-g); diff_b = abs(r-b); diff_c = abs(r-b); if( diff_a < 2 && diff_b < 2 && diff_c < 2 ) { if( (r!=0XFF) && (g!=0XFF) && (g!=0XFF) ) { if( ((r&0xF0)>>4) != 0 ) //printf("conv gray: %x -> %d\n", ((r&0xF0)>>4) , (OFFSET_CUST_PAL) + ((r&0xF0)>>4) ); return( (OFFSET_CUST_PAL - OFFSET_WEB_PAL) + ((r&0xF0)>>4) ); } } /* convert each 8bit color to 6bit web color: */ for( i=0; i<3; i++) { if(0 == rgb[i] % web_std_colors[1] ) { tval[i] = rgb[i] / web_std_colors[1]; } else { int pos = ((short)rgb[i] / web_std_colors[1]); if( abs(rgb[i] - web_std_colors[pos]) > abs(rgb[i] - web_std_colors[pos+1]) ) tval[i] = pos+1; else tval[i] = pos; } } return(tval[2]*36+tval[1]*6+tval[0]); } #endif static void dump_vdi_info(short vdih) { struct s_vdi_sysinfo temp; read_vdi_sysinfo( vdih, &temp ); printf("struct s_vdi_sysinfo {\n"); printf(" short vdi_handle: %d\n", temp.vdi_handle); printf(" short scr_w: %d \n", temp.scr_w); printf(" short scr_h: %d\n", temp.scr_h); printf(" short scr_bpp: %d\n", temp.scr_bpp); printf(" int colors: %d\n", temp.colors); printf(" ulong hicolors: %d\n", temp.hicolors); printf(" short pixelsize: %d\n", temp.pixelsize); printf(" unsigned short pitch: %d\n", temp.pitch); printf(" unsigned short vdiformat: %d\n", temp.vdiformat); printf(" unsigned short clut: %d\n", temp.clut); printf(" void * screen: 0x0%p\n", temp.screen); printf(" unsigned long screensize: %d\n", temp.screensize); printf(" unsigned long mask_r: 0x0%08x\n", temp.mask_r); printf(" unsigned long mask_g: 0x0%08x\n", temp.mask_g); printf(" unsigned long mask_b: 0x0%08x\n", temp.mask_b); printf(" unsigned long mask_a: 0x0%08x\n", temp.mask_a); printf(" short maxintin: %d\n", temp.maxintin); printf(" short maxpolycoords: %d\n", temp.maxpolycoords); printf(" unsigned long EdDiVersion: 0x0%03x\n", temp.EdDiVersion); printf(" unsigned short rasterscale: 0x%2x\n", temp.rasterscale); printf("};\n"); } // create snapshot, native screen format static MFDB * snapshot_create_native_mfdb(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(size_buf_scr == 0 ){ /* init screen mfdb */ buf_scr.fd_addr = malloc( scr_size ); size_buf_scr = scr_size; } else { if( scr_size >size_buf_scr ) { buf_scr.fd_addr = realloc( buf_scr.fd_addr, scr_size ); size_buf_scr = scr_size; } } if(buf_scr.fd_addr == NULL ) { size_buf_scr = 0; return( NULL ); } buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp; buf_scr.fd_w = scr_stride; buf_scr.fd_h = h; buf_scr.fd_wdwidth = scr_stride >> 4; assert(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( atari_plot_vdi_handle, S_ONLY, (short*)&pxy, &scr, &buf_scr ); return( &buf_scr ); } // create snapshot, vdi std. format static MFDB * snapshot_create_std_mfdb(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(size_buf_std == 0 ){ /* init screen mfdb */ buf_std.fd_addr = malloc( scr_size ); size_buf_std = scr_size; } else { if( scr_size >size_buf_std ) { buf_std.fd_addr = realloc( buf_std.fd_addr, scr_size ); size_buf_std = scr_size; } } if(buf_std.fd_addr == NULL ) { size_buf_std = 0; return( NULL ); } buf_std.fd_nplanes = app.nplanes; buf_std.fd_w = scr_stride; buf_std.fd_h = h; buf_std.fd_stand = 1; buf_std.fd_wdwidth = scr_stride >> 4; assert(buf_std.fd_addr != NULL ); } MFDB * native = snapshot_create_native_mfdb(x,y,w,h ); assert( native ); vr_trnfm(atari_plot_vdi_handle, native, &buf_std ); return( &buf_std ); } /* This will create an snapshot of the screen in netsurf ABGR format */ static struct bitmap * snapshot_create(int x, int y, int w, int h) { int err; MFDB * native; // uint32_t start = clock(); // FIXME: This can be optimized a lot. // 1. do not copy the snapshot to the bitmap buffer // when the format of screen and bitmap equals. // just point the bitmap to the native mfdb. // 2. if we have eddi 1.1, we could optimize that further // make snapshot_create_native_mfdb just returning a pointer // to the screen. native = snapshot_create_native_mfdb(x, y, w, h ); if(vfmt.bits == 32 ) goto no_copy; /* allocate buffer for result bitmap: */ if(buf_scr_compat == NULL ) { buf_scr_compat = bitmap_create(w, h, 0); } else { buf_scr_compat = bitmap_realloc( w, h, buf_scr_compat->bpp, w *buf_scr_compat->bpp, BITMAP_GROW, buf_scr_compat ); } /* convert screen buffer to ns format: */ err = Hermes_ConverterRequest( hermes_cnv_h, &vfmt, &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 */ 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(buf_scr_compat) /* stride as bytes */ ); assert( err != 0 ); return( (struct bitmap * )buf_scr_compat ); no_copy: snapshot.width = w; snapshot.height = h; snapshot.pixdata = native->fd_addr; snapshot.native = *native; snapshot.rowstride = MFDB_STRIDE( w )*4; uint32_t row, col; for (row = 0; row<(uint32_t)h; row++) { // fd_w matches stride! uint32_t *rowptr = ((uint32_t*)native->fd_addr + ((row*native->fd_w))); for (col=0; col<(uint32_t)w; col++) { *(rowptr+col) = (*(rowptr+col)<<8); } } return( &snapshot ); } static void snapshot_suspend(void) { if(size_buf_scr > CONV_KEEP_LIMIT ) { buf_scr.fd_addr = realloc( buf_scr.fd_addr, CONV_KEEP_LIMIT ); if(buf_scr.fd_addr != NULL ) { size_buf_scr = CONV_KEEP_LIMIT; } else { size_buf_scr = 0; } } if(size_buf_std > CONV_KEEP_LIMIT ) { buf_std.fd_addr = realloc( buf_std.fd_addr, CONV_KEEP_LIMIT ); if(buf_std.fd_addr != NULL ) { size_buf_std = CONV_KEEP_LIMIT; } else { size_buf_std = 0; } } if(buf_scr_compat != NULL ) { size_t bs = bitmap_buffer_size(buf_scr_compat ); if( bs > CONV_KEEP_LIMIT ) { int w = 0; int h = 1; w = (CONV_KEEP_LIMIT /buf_scr_compat->bpp); assert( CONV_KEEP_LIMIT == w*buf_scr_compat->bpp ); buf_scr_compat = bitmap_realloc( w, h, buf_scr_compat->bpp, CONV_KEEP_LIMIT, BITMAP_SHRINK,buf_scr_compat ); } } } static void snapshot_destroy(void) { free(buf_scr.fd_addr); if( buf_scr_compat != NULL) { bitmap_destroy(buf_scr_compat); } buf_scr.fd_addr = NULL; buf_scr_compat = NULL; #ifdef WITH_8BPP_SUPPORT free(buf_std.fd_addr); buf_std.fd_addr = NULL; #endif } inline static 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; } /* Alpha blends an image, using one pixel as the background. The bitmap receives the result. */ inline static bool ablend_pixel(struct bitmap * img, uint32_t bg, GRECT * clip) { uint32_t * imgrow; int img_x, img_y, img_stride; img_stride= bitmap_get_rowstride(img); for( img_y = 0; img_y < clip->g_h; img_y++) { imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y)); for( img_x = 0; img_x < clip->g_w; img_x++ ) { imgrow[img_x] = ablend( imgrow[img_x], bg ); } } return(true); } /* Aplha blends the foreground image (img) onto the background images (bg). The background receives the blended image pixels. */ inline static bool ablend_bitmap( struct bitmap * img, struct bitmap * bg, GRECT * img_clip, GRECT * bg_clip ) { uint32_t * imgrow; uint32_t * screenrow; int img_x, img_y, bg_x, bg_y, img_stride, bg_stride; bg_clip = bg_clip; img_stride= bitmap_get_rowstride(img); bg_stride = bitmap_get_rowstride(bg); for( img_y = img_clip->g_y, bg_y = 0; bg_y < img_clip->g_h; bg_y++, img_y++) { imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y)); screenrow = (uint32_t *)(bg->pixdata + (bg_stride * bg_y)); for( img_x = img_clip->g_x, bg_x = 0; bg_x < img_clip->g_w; bg_x++, img_x++ ) { // when the pixel isn't fully transparent,...: if( (imgrow[img_x] & 0x0FF) != 0 ){ screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); } // FIXME, maybe this loop would be faster??: // --- //if( (imgrow[img_x] & 0x0FF) != 0xFF ){ // imgrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); //} // or maybe even this??? // --- //if( (imgrow[img_x] & 0x0FF) == 0xFF ){ // screenrow[bg_x] = imgrow[img_x]; //} else if( (imgrow[img_x] & 0x0FF) != 0x00 ) { // screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); //} } } return(false); } #ifdef WITH_8BPP_SUPPORT static bool bitmap_convert_8(struct bitmap * img, int x, int y, GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out ) { MFDB native; MFDB stdform; int dststride; /* stride of dest. image */ int dstsize; /* size of dest. in byte */ int err; int bw, bh; int process_w, process_h; struct bitmap * scrbuf = NULL; struct bitmap * source; bool cache = ( flags & BITMAPF_BUFFER_NATIVE ); bool opaque = bitmap_get_opaque( img ); if( opaque == false ){ if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0) && ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ opaque = true; } } assert( clip->g_h > 0 ); assert( clip->g_w > 0 ); process_w = bw = bitmap_get_width( img ); process_h = bh = bitmap_get_height( img ); // The converted bitmap can be saved for subsequent blits, when // the bitmap is fully opaque if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){ if( img->converted == true ){ *out = img->native; return( 0 ); } if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ cache = true; } } if( ( flags & BITMAPF_MONOGLYPH ) != 0 ){ assert(cache == false); } /* (re)allocate buffer for out image: */ /* altough the buffer is named "buf_packed" on 8bit systems */ /* it's not... */ if( cache == false ){ // the size of the output will match the size of the clipping: dststride = MFDB_STRIDE( clip->g_w ); dstsize = ( ((dststride >> 3) * clip->g_h) * atari_plot_bpp_virt); if( dstsize > size_buf_packed) { int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; if( buf_packed == NULL ) buf_packed =(void*)malloc( blocks * CONV_BLOCK_SIZE); else buf_packed =(void*)realloc(buf_packed,blocks * CONV_BLOCK_SIZE); assert( buf_packed ); if( buf_packed == NULL ) { return( 0-ERR_NO_MEM ); } size_buf_packed = blocks * CONV_BLOCK_SIZE; } native.fd_addr = buf_packed; } else { // the output image will be completly saved, so size of the output // image will match the input image size. dststride = MFDB_STRIDE( bw ); dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt); assert( out->fd_addr == NULL ); native.fd_addr = (void*)malloc( dstsize ); if (native.fd_addr == NULL){ if (scrbuf != NULL) bitmap_destroy(scrbuf); return( 0-ERR_NO_MEM ); } } /* 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 with v_trnfm() */ // realloc mem for stdform if( opaque == false ){ // point image to snapshot buffer, otherwise allocate mem MFDB * bg = snapshot_create_std_mfdb(x, y, clip->g_w, clip->g_h); stdform.fd_addr = bg->fd_addr; bh = clip->g_h; } else { if( dstsize > size_buf_planar) { int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; if( buf_planar == NULL ) buf_planar =(void*)malloc( blocks * CONV_BLOCK_SIZE ); else buf_planar =(void*)realloc(buf_planar, blocks * CONV_BLOCK_SIZE); assert(buf_planar); if( buf_planar == NULL ) { return( 0-ERR_NO_MEM ); } size_buf_planar = blocks * CONV_BLOCK_SIZE; } stdform.fd_addr = buf_planar; } stdform.fd_w = dststride; stdform.fd_h = bh; stdform.fd_wdwidth = dststride >> 4; stdform.fd_stand = 1; stdform.fd_nplanes = (short)atari_plot_bpp_virt; stdform.fd_r1 = stdform.fd_r2 = stdform.fd_r3 = 0; int img_stride = bitmap_get_rowstride(img); 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; if( opaque == false ){ // apply transparency and convert to vdi std format unsigned long bgcol = 0; unsigned char prev_col = 0; for( y=0; yg_h; y++ ){ row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y))); for( x=0; xg_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 ); } } } // adjust output position: clip->g_x = 0; clip->g_y = 0; } else { // convert the whole image data to vdi std format. for( y=0; y < bh; y++ ){ row = (uint32_t *)(img->pixdata + (img_stride * y)); for( x=0; x < bw; x++ ){ pixel = row[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: native.fd_w = stdform.fd_w; native.fd_h = stdform.fd_h; native.fd_wdwidth = stdform.fd_wdwidth; native.fd_stand = 0; native.fd_nplanes = (short)atari_plot_bpp_virt; native.fd_r1 = native.fd_r2 = native.fd_r3 = 0; vr_trnfm(atari_plot_vdi_handle, &stdform, &native ); *out = native; if( cache == true ){ img->native = native; img->converted = true; } return(0); } #endif /* * * Convert bitmap to the native screen format * img: the bitmap * x: coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) * y: coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) * clip: which area of the bitmap shall be drawn * bg: background color * flags: blit flags * out: the result MFDB */ static bool bitmap_convert_tc(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, bh; struct bitmap * scrbuf = NULL; struct bitmap * source = NULL; bool cache = ( flags & BITMAPF_BUFFER_NATIVE ); bool opaque = bitmap_get_opaque( img ); if( opaque == false ){ if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0) && ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ opaque = true; } } assert( clip->g_h > 0 ); assert( clip->g_w > 0 ); bw = bitmap_get_width( img ); bh = bitmap_get_height( img ); // The converted bitmap can be saved for subsequent blits, WHEN: // A.) the bitmap is fully opaque OR // B.) the bitmap is completly inside the window // the latter one is important for alpha blits, // because we must get the window background to apply transparency // If the image is not completly within the window, // we can't get the whole background for the image. // this only works if the image isn't used at several different places. // In fact in case of alpha bitmap caching it is only used for the // toolbar buttons right now. if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){ if( img->converted == true ){ *out = img->native; return( 0 ); } if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ cache = true; } } /* rem. if eddi xy is installed, we could directly access the screen! */ /* apply transparency to the image: */ if (( opaque == false )) { /* copy the screen to an temp buffer: */ if ((flags & BITMAPF_BUFFER_NATIVE) == 0) { scrbuf = snapshot_create(x, y, clip->g_w, clip->g_h); if( scrbuf != NULL ) { assert( clip->g_w <= bw ); assert( clip->g_h <= bh ); // copy blended pixels to the screen buffer: ablend_bitmap( img, scrbuf, clip, NULL ); /* adjust size which gets converted: */ bw = clip->g_w; bh = clip->g_h; /* adjust output position: */ clip->g_x = 0; clip->g_y = 0; /* set the source of conversion: */ source = scrbuf; } } else { /* The whole bitmap can be transformed to an mfdb (and get's cached) */ GRECT region = { 0, 0, bw, bh }; ablend_pixel( img, bg, ®ion ); source = img; } } else { source = img; } /* (re)allocate buffer for converted image: */ dststride = MFDB_STRIDE(bw); dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt ); if (cache == false) { if (dstsize > size_buf_packed) { int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; if( buf_packed == NULL ) buf_packed =(void*)malloc( blocks * CONV_BLOCK_SIZE ); else buf_packed =(void*)realloc(buf_packed, blocks * CONV_BLOCK_SIZE); assert( buf_packed ); if( buf_packed == NULL ) { if( scrbuf != NULL ) bitmap_destroy( scrbuf ); return( 0-ERR_NO_MEM ); } size_buf_packed = blocks * CONV_BLOCK_SIZE; } out->fd_addr = buf_packed; } else { assert( out->fd_addr == NULL ); out->fd_addr = (void*)malloc( dstsize ); if( out->fd_addr == NULL ){ if( scrbuf != NULL ) bitmap_destroy( scrbuf ); return( 0-ERR_NO_MEM ); } } out->fd_w = dststride; out->fd_h = bh; out->fd_wdwidth = dststride >> 4; out->fd_stand = 0; out->fd_nplanes = (short)atari_plot_bpp_virt; out->fd_r1 = out->fd_r2 = out->fd_r3 = 0; err = Hermes_ConverterRequest( hermes_cnv_h, &nsfmt, &vfmt ); assert( err != 0 ); // FIXME: here we can use the same optimization which is used for // the snapshot creation. /* convert image to virtual format: */ err = Hermes_ConverterCopy( hermes_cnv_h, source->pixdata, 0, /* x src coord of top left in pixel coords */ 0, /* y src coord of top left in pixel coords */ bw, bh, source->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 */ bw, bh, (dststride >> 3) * atari_plot_bpp_virt /* stride as bytes */ ); assert( err != 0 ); if( cache == true ){ img->native = *out; img->converted = true; } return( 0 ); } inline static void convert_bitmap_done(void) { if (size_buf_packed > CONV_KEEP_LIMIT) { /* free the mem if it was an large allocation ... */ buf_packed = realloc(buf_packed, CONV_KEEP_LIMIT); size_buf_packed = CONV_KEEP_LIMIT; } } bool plot_blit_bitmap(struct bitmap * bmp, int x, int y, unsigned long bg, unsigned long flags ) { MFDB src_mf; MFDB scrmf; short pxy[8]; GRECT off, clip, vis; int screen_x, screen_y; 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 plotter clip rectangle: clip.g_x = view.clipping.x0; clip.g_y = view.clipping.y0; clip.g_w = view.clipping.x1 - view.clipping.x0; clip.g_h = view.clipping.y1 - view.clipping.y0; if( !rc_intersect( &clip, &off) ) { return(true); } // clip the visible rectangle of the plot area // this is the area of the plotter which falls into // screen region: plot_get_visible_grect(&vis); if( !rc_intersect( &vis, &off) ) { return(true); } screen_x = view.x + off.g_x; screen_y = view.y + off.g_y; // convert the clipping relative to bitmap: off.g_x = off.g_x - x; off.g_y = off.g_y - y; assert( (off.g_x >= 0) && (off.g_y >= 0) ); /* Convert the Bitmap to native screen format - ready for output. */ /* This includes blending transparent pixels: */ if (bitmap_convert(bmp, screen_x, screen_y, &off, bg, flags, &src_mf) != 0 ) { return(true); } // setup the src region: pxy[0] = off.g_x; pxy[1] = off.g_y; pxy[2] = off.g_x + off.g_w-1; pxy[3] = off.g_y + off.g_h-1; // setup the target region: pxy[4] = screen_x; pxy[5] = screen_y; pxy[6] = screen_x + off.g_w-1; pxy[7] = screen_y + off.g_h-1; vro_cpyfm(atari_plot_vdi_handle, S_ONLY, (short*)&pxy, &src_mf, &scrmf); convert_bitmap_done(); snapshot_suspend(); return(true); } bool plot_blit_mfdb(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; plot_get_clip_grect(&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( size_buf_scr == 0 ){ buf_scr.fd_addr = malloc( size ); size_buf_scr = size; } else { if( size > size_buf_scr ) { buf_scr.fd_addr = realloc( buf_scr.fd_addr, size ); size_buf_scr = size; } } tran.fd_addr = buf_scr.fd_addr; vr_trnfm(atari_plot_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.x + off.g_x; pxy[5] = view.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(atari_plot_vdi_handle, MD_TRANS, (short*)pxy, src, &screen, (short*)&c ); } else { /* this method only plots transparent bitmaps, right now... */ } return( 1 ); } /* Init screen and font driver objects. Returns non-zero value > -1 when the objects could be succesfully created. Returns value < 0 to indicate an error */ int plot_init(char * fdrvrname) { GRECT loc_pos= {0,0,360,400}; int err=0,i; if( nsoption_int(atari_dither) == 1) atari_plot_flags |= PLOT_FLAG_DITHER; if( nsoption_int(atari_transparency) == 1 ) atari_plot_flags |= PLOT_FLAG_TRANS; if( nsoption_int(atari_font_monochrom) == 1 ) atari_font_flags |= FONTPLOT_FLAG_MONOGLYPH; atari_plot_vdi_handle = app.graf.handle; read_vdi_sysinfo(atari_plot_vdi_handle, &vdi_sysinfo); if( verbose_log ) { dump_vdi_info( atari_plot_vdi_handle ) ; dump_font_drivers(); } fplotter = new_font_plotter(atari_plot_vdi_handle, fdrvrname, atari_font_flags, &err); if(err) { const char * desc = plot_err_str(err); die(("Unable to load font plotter %s -> %s", fdrvrname, desc )); } memset(&view, 0, sizeof(struct s_view)); atari_plot_bpp_virt = app.nplanes; view.x = loc_pos.g_x; view.y = loc_pos.g_y; view.w = loc_pos.g_w; view.h = loc_pos.g_h; size_buf_packed = 0; size_buf_planar = 0; buf_packed = NULL; buf_planar = NULL; if( vdi_sysinfo.vdiformat == VDI_FORMAT_PACK ) { atari_plot_bpp_virt = vdi_sysinfo.scr_bpp; } else { atari_plot_bpp_virt = 8; } update_visible_rect(); struct rect clip; clip.x0 = 0; clip.y0 = 0; clip.x1 = view.w; clip.y1 = view.h; plot_clip(&clip); assert(Hermes_Init()); #ifdef WITH_8BPP_SUPPORT bitmap_convert = (app.nplanes > 8) ? bitmap_convert_tc : bitmap_convert_8; /* Setup color lookup tables and palette */ 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(atari_plot_vdi_handle, i, 1, (unsigned short*)&sys_pal[i][0] ); if( i= 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(atari_plot_vdi_handle, i, &pal[i][0]); } if( i >= OFFSET_CUST_PAL && istroke_width; uint32_t lt; /* current canvas clip: */ rclip.g_x = view.clipping.x0; rclip.g_y = view.clipping.y0; rclip.g_w = view.clipping.x1 - view.clipping.x0; rclip.g_h = view.clipping.y1 - view.clipping.y0; /* physical clipping: */ sclip.g_x = rclip.g_x; sclip.g_y = rclip.g_y; sclip.g_w = view.vis_w; sclip.g_h = view.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(true); } 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(atari_plot_vdi_handle, (lt&0x0F)); /* if the line style is not available within VDI system, define own style: */ if( (lt&0x0F) == 7 ){ vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8)); } vsl_width(atari_plot_vdi_handle, (short)sw ); vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); /* top border: */ if( r.g_y == y0){ pxy[0] = view.x + r.g_x; pxy[1] = view.y + r.g_y ; pxy[2] = view.x + r.g_x + r.g_w; pxy[3] = view.y + r.g_y; v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); } /* right border: */ if( r.g_x + r.g_w == x1 ){ pxy[0] = view.x + r.g_x + r.g_w; pxy[1] = view.y + r.g_y; pxy[2] = view.x + r.g_x + r.g_w; pxy[3] = view.y + r.g_y + r.g_h; v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); } /* bottom border: */ if( r.g_y+r.g_h == y1 ){ pxy[0] = view.x + r.g_x; pxy[1] = view.y + r.g_y+r.g_h; pxy[2] = view.x + r.g_x+r.g_w; pxy[3] = view.y + r.g_y+r.g_h; v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); } /* left border: */ if( r.g_x == x0 ){ pxy[0] = view.x + r.g_x; pxy[1] = view.y + r.g_y; pxy[2] = view.x + r.g_x; pxy[3] = view.y + r.g_y + r.g_h; v_pline(atari_plot_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(atari_plot_vdi_handle, pstyle->fill_colour); vsf_perimeter(atari_plot_vdi_handle, 0); vsf_interior(atari_plot_vdi_handle, FIS_SOLID); pxy[0] = view.x + r.g_x + stroke_width; pxy[1] = view.y + r.g_y + stroke_width; pxy[2] = view.x + r.g_x + r.g_w -1 - stroke_width; pxy[3] = view.y + r.g_y + r.g_h -1 - stroke_width; vsf_style(atari_plot_vdi_handle, 1); v_bar(atari_plot_vdi_handle, (short*)&pxy); } return (true); } bool plot_line(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.x + x0; pxy[1] = view.y + y0; pxy[2] = view.x + x1; pxy[3] = view.y + y1; plot_vdi_clip(true); if( sw == 0) sw = 1; NSLT2VDI(lt, pstyle) vsl_type(atari_plot_vdi_handle, (lt&0x0F)); /* if the line style is not available within VDI system,define own style: */ if( (lt&0x0F) == 7 ){ vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8)); } vsl_width(atari_plot_vdi_handle, (short)sw); vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); v_pline(atari_plot_vdi_handle, 2, (short *)&pxy ); plot_vdi_clip(false); return ( true ); } static bool plot_polygon(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); plot_vdi_clip(true); vsf_interior(atari_plot_vdi_handle, FIS_SOLID); vsf_style(atari_plot_vdi_handle, 1); for (i = 0; ifill_type == PLOT_OP_TYPE_SOLID) { vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); v_fillarea(atari_plot_vdi_handle, n, (short*)&pxy); } else { pxy[n*2]=pxy[0]; pxy[n*2+1]=pxy[1]; vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); v_pline(atari_plot_vdi_handle, n+1, (short *)&pxy); } plot_vdi_clip(false); return ( true ); } bool plot_set_dimensions(int x, int y, int w, int h) { bool doupdate = false; if (!(w == view.w && h == view.h)) { struct rect newclip = { 0, 0, w-1, h-1 }; view.w = (short)w; view.h = (short)h; doupdate = true; } if (!(x == view.x && y == view.y)) { view.x = (short)x; view.y = (short)y; doupdate = true; } if (doupdate==true) update_visible_rect(); return(true); } bool plot_clip(const struct rect *clip) { // FIXME: consider the canvas size view.clipping.x0 = clip->x0; view.clipping.y0 = clip->y0; view.clipping.x1 = clip->x1; view.clipping.y1 = clip->y1; return ( true ); } bool plot_get_clip(struct rect * out) { out->x0 = view.clipping.x0; out->y0 = view.clipping.y0; out->x1 = view.clipping.x1; out->y1 = view.clipping.y1; return( true ); } void plot_get_clip_grect(GRECT * out) { struct rect clip={0,0,0,0}; plot_get_clip(&clip); out->g_x = clip.x0; out->g_y = clip.y0; out->g_w = clip.x1 - clip.x0; out->g_h = clip.y1 - clip.y0; } static bool plot_text(int x, int y, const char *text, size_t length, const plot_font_style_t *fstyle ) { fplotter->text(fplotter, x, y, text, length, fstyle); return ( true ); } static bool plot_disc(int x, int y, int radius, const plot_style_t *pstyle) { plot_vdi_clip(true); if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) { vsf_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); vsf_perimeter(atari_plot_vdi_handle, 1); vsf_interior(atari_plot_vdi_handle, 0); v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius); } else { vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); vsf_perimeter(atari_plot_vdi_handle, 0); vsf_interior(atari_plot_vdi_handle, FIS_SOLID); v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius); } plot_vdi_clip(false); return ( true ); } static bool plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle) { //plot_vdi_clip(true); vswr_mode(atari_plot_vdi_handle, MD_REPLACE ); if (pstyle->fill_type == PLOT_OP_TYPE_NONE) return(true); if ( pstyle->fill_type != PLOT_OP_TYPE_SOLID) { vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); vsf_perimeter(atari_plot_vdi_handle, 1); vsf_interior(atari_plot_vdi_handle, 1 ); v_arc(atari_plot_vdi_handle, view.x + x, view.y + y, radius, angle1*10, angle2*10); } else { vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); vsl_width(atari_plot_vdi_handle, 1 ); vsf_perimeter(atari_plot_vdi_handle, 1); v_arc(atari_plot_vdi_handle, view.x + x, view.y + y, radius, angle1*10, angle2*10); } //plot_vdi_clip(true); return (true); } static bool plot_bitmap(int x, int y, int width, int height, struct bitmap *bitmap, colour bg, bitmap_flags_t flags) { struct bitmap * bm = NULL; bool repeat_x = (flags & BITMAPF_REPEAT_X); bool repeat_y = (flags & BITMAPF_REPEAT_Y); int bmpw,bmph; struct rect clip = {0,0,0,0}; bmpw = bitmap_get_width(bitmap); bmph = bitmap_get_height(bitmap); if ( repeat_x || repeat_y ) { plot_get_clip(&clip); if( repeat_x && width == 1 && repeat_y && height == 1 ) { width = MAX( width, clip.x1 - x ); height = MAX( height, clip.y1 - y ); } else if( repeat_x && width == 1 ) { width = MAX( width, clip.x1 - x); } else if( repeat_y && height == 1) { height = MAX( height, clip.y1 - y ); } } if( width != bmpw || height != bmph ) { bitmap_resize(bitmap, hermes_res_h, &nsfmt, width, height ); if( bitmap->resized ) bm = bitmap->resized; else bm = bitmap; } else { bm = bitmap; } /* out of memory? */ if( bm == NULL ) { printf("plot: out of memory! bmp: %p, bmpres: %p\n", bitmap, bitmap->resized ); return( true ); } if (!(repeat_x || repeat_y) ) { plot_blit_bitmap(bm, x, y, bg, flags ); } else { int xf,yf; int xoff = x; int yoff = y; if (yoff > clip.y0 ) yoff = (clip.y0 - height) + ((yoff - clip.y0) % height); if (xoff > clip.x0 ) xoff = (clip.x0 - width) + ((xoff - clip.x0) % width); /* for now, repeating just works in the rigth / down direction */ /* if( repeat_x == true ) xoff = clip.x0; if(repeat_y == true ) yoff = clip.y0; */ for( xf = xoff; xf < clip.x1; xf += width ) { for( yf = yoff; yf < clip.y1; yf += height ) { plot_blit_bitmap(bm, xf, yf, bg, flags ); if (!repeat_y) break; } if (!repeat_x) break; } } return ( true ); } static bool plot_path(const float *p, unsigned int n, colour fill, float width, colour c, const float transform[6]) { return ( true ); } const struct plotter_table atari_plotters = { .rectangle = plot_rectangle, .line = plot_line, .polygon = plot_polygon, .clip = plot_clip, .text = plot_text, .disc = plot_disc, .arc = plot_arc, .bitmap = plot_bitmap, .path = plot_path, .flush = NULL, .group_start = NULL, .group_end = NULL, .option_knockout = true };