/* * 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 #include #include "utils/log.h" #include "utils/utf8.h" #include "utils/utils.h" #include "netsurf/bitmap.h" #include "netsurf/plotters.h" #include "netsurf/mouse.h" #include "atari/gui.h" #include "atari/osspec.h" #include "atari/misc.h" #include "atari/bitmap.h" #include "utils/nsoption.h" #include "atari/plot/eddi.h" #include "atari/plot/fontplot.h" #include "atari/plot/plot.h" void vq_scrninfo(VdiHdl handle, short *work_out); 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 abs_clipping; /**< The toplevel clipping rectangle */ struct rect clipping; /**< actual clipping rectangle */ float scale; }; /** * 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); #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; 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; VdiHdl atari_plot_vdi_handle = -1; 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; /* exported interface documented in atari/plot.h */ const char* plot_err_str(int i) { return (plot_error_codes[abs(i)]); } /** * Set line drawing color by passing netsurf XBGR "colour" type. * * \param vdih The vdi handle * \param cin The netsurf colour value */ inline static void vsl_rgbcolor(short vdih, colour cin) { #ifdef WITH_8BPP_SUPPORT if( vdi_sysinfo.scr_bpp > 8 ) { #endif RGB1000 c; /* a struct with three (RGB) shorts */ rgb_to_vdi1000( (unsigned char*)&cin, &c); vs_color(vdih, OFFSET_CUSTOM_COLOR, (short *)&c); 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 } /** * Set fill color by passing netsurf XBGR "colour" type. * * \param vdih The vdi handle * \param cin The netsurf colour value */ inline static void vsf_rgbcolor(short vdih, colour cin) { #ifdef WITH_8BPP_SUPPORT if( vdi_sysinfo.scr_bpp > 8 ) { #endif RGB1000 c; /* a struct with three (RGB) shorts */ rgb_to_vdi1000( (unsigned char*)&cin, &c); vs_color( vdih, OFFSET_CUSTOM_COLOR, (short *)&c); 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; // dimensions of the screen GRECT frame; // dimensions of the drawing area GRECT common; // dimensions of intersection of both 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, (long *)&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, RGB1000 *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->red = 1000 * r + 0.5; out->green = 1000 * g + 0.5; out->blue = 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 /** * Set pixel within an 8 bit VDI standard bitmap. */ 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)); } /** * Read pixel from an 8 bit VDI standard bitmap. */ 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 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) && (b!=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: %lu\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: %lu\n", temp.screensize); printf(" unsigned long mask_r: 0x0%08lx\n", temp.mask_r); printf(" unsigned long mask_g: 0x0%08lx\n", temp.mask_g); printf(" unsigned long mask_b: 0x0%08lx\n", temp.mask_b); printf(" unsigned long mask_a: 0x0%08lx\n", temp.mask_a); printf(" short maxintin: %d\n", temp.maxintin); printf(" short maxpolycoords: %d\n", temp.maxpolycoords); printf(" unsigned long EdDiVersion: 0x0%03lx\n", temp.EdDiVersion); printf(" unsigned short rasterscale: 0x%2x\n", temp.rasterscale); printf("};\n"); } /** * Create an snapshot of the screen image in device 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 an snapshot of the screen in netsurf ABGR format * * This creates an snapshot in RGBA format (NetSurf's native format) * * 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 */ 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 = atari_bitmap_create(w, h, 0); } else { buf_scr_compat = atari_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, atari_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 ); } /** * Notify the snapshot interface that the last snapshot is no longer in use. */ 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; } } #ifdef WITH_8BPP_SUPPORT 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; } } #endif if(buf_scr_compat != NULL ) { size_t bs = atari_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 = atari_bitmap_realloc( w, h, buf_scr_compat->bpp, CONV_KEEP_LIMIT, BITMAP_SHRINK,buf_scr_compat ); } } } /** * Shut down the snapshot interface. */ static void snapshot_destroy(void) { free(buf_scr.fd_addr); if( buf_scr_compat != NULL) { atari_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= atari_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 onto thebackground images. * * 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 = atari_bitmap_get_rowstride(img); bg_stride = atari_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 /** * Create an snapshot of the screen image in VDI standard format (8 bit). */ 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) * vdi_sysinfo.scr_bpp ); 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 = 8; 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 ); } /** * Convert an bitmap to an 8 bit device dependant MFDB * \param img the bitmap (only tested with 32bit bitmaps) * \param x screen coord of the background * \param y screen coord of the background * \param clip the region of the image that get's converted * \param bg the background used for cheap transparency * \param flags * \param out receives the converted bitmap (still owned by the plot API) * */ 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 bw, bh; struct bitmap * scrbuf = NULL; bool cache = ( flags & BITMAPF_BUFFER_NATIVE ); bool opaque = atari_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 = atari_bitmap_get_width( img ); bh = atari_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; void *buf; if (buf_packed == NULL) { buf = malloc( blocks * CONV_BLOCK_SIZE); } else { buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE); } if (buf == NULL) { return( 0-ERR_NO_MEM ); } buf_packed = buf; 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 = malloc( dstsize ); if (native.fd_addr == NULL){ if (scrbuf != NULL) atari_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; void *buf; if (buf_planar == NULL) { buf = malloc(blocks * CONV_BLOCK_SIZE); } else { buf = realloc(buf_planar, blocks * CONV_BLOCK_SIZE); } if (buf == NULL ) { if (cache) { free(native.fd_addr); } return( 0-ERR_NO_MEM ); } buf_planar = buf; 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 = atari_bitmap_get_rowstride(img); uint32_t prev_pixel = 0x12345678; //TODO: check for collision in first pixel 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 * * \param img the bitmap * \param x coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) * \param y coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) * \param clip which area of the bitmap shall be drawn * \param bg background color * \param flags blit flags * \param 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 = atari_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 = atari_bitmap_get_width( img ); bh = atari_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) { /* ensure cache buffer is large enough */ if (dstsize > size_buf_packed) { int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; void *buf; if (buf_packed == NULL) { buf = malloc(blocks * CONV_BLOCK_SIZE); } else { buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE); } if (buf == NULL ) { if (scrbuf != NULL) { atari_bitmap_destroy(scrbuf); } return( 0-ERR_NO_MEM ); } buf_packed = buf; 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 ) atari_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) { void *buf; /* free the mem if it was an large allocation ... */ buf = realloc(buf_packed, CONV_KEEP_LIMIT); if (buf != NULL) { buf_packed = buf; 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, short fgcolor, uint32_t flags) { MFDB screen; // MFDB tran; MFDB * src; short pxy[8]; short c[2] = {fgcolor, 0}; 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){ // printf("st\n"); // 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_REPLACE/*MD_TRANS*/, (short*)pxy, src, &screen, (short*)&c); } else { /* this method only plots transparent bitmaps, right now... */ } return( 1 ); } /* exported interface documented in atari/plot.h */ int plot_init(const struct redraw_context *ctx, char *fdrvrname) { GRECT loc_pos = { 0, 0, 360, 400 }; int err=0; 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; if (atari_plot_vdi_handle == -1) { short dummy; short work_in[12] = {Getrez()+2,1,1,1,1,1,1,1,1,1,2,1}; short work_out[57]; atari_plot_vdi_handle=graf_handle(&dummy, &dummy, &dummy, &dummy); v_opnvwk(work_in, &atari_plot_vdi_handle, work_out); LOG("Plot VDI handle: %d", atari_plot_vdi_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); LOG("Unable to load font plotter %s -> %s", fdrvrname, desc ); die("font plotter"); } memset(&view, 0, sizeof(struct s_view)); atari_plot_bpp_virt = vdi_sysinfo.scr_bpp; 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; } plot_set_scale(1.0); update_visible_rect(); struct rect clip; clip.x0 = 0; clip.y0 = 0; clip.x1 = view.w; clip.y1 = view.h; ctx->plot->clip(ctx, &clip); assert(Hermes_Init()); #ifdef WITH_8BPP_SUPPORT bitmap_convert = (vdi_sysinfo.scr_bpp > 8) ? bitmap_convert_tc : bitmap_convert_8; /* Setup color lookup tables and palette */ unsigned char rgbcol[4]; if( vdi_sysinfo.scr_bpp <= 8 ){ unsigned char graytone=0; int i; 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 && iplot->clip(ctx, &newclip); return(true); } /** * Get current canvas size * * \param dst the GRECT * which receives the canvas size */ bool plot_get_dimensions(GRECT *dst) { dst->g_x = view.x; dst->g_y = view.y; dst->g_w = view.w; dst->g_h = view.h; return(true); } /** * set scale of plotter. * \param scale the new scale value * \return the old scale value */ float plot_set_scale(float scale) { float ret = view.scale; view.scale = scale; return(ret); } float plot_get_scale(void) { return(view.scale); } /** * Subsequent calls to plot_clip will be clipped by the absolute clip. * * \param area the maximum clipping rectangle (absolute screen coords) */ void plot_set_abs_clipping(const GRECT *area) { GRECT canvas; plot_get_dimensions(&canvas); if(!rc_intersect(area, &canvas)){ view.abs_clipping.x0 = 0; view.abs_clipping.x1 = 0; view.abs_clipping.y0 = 0; view.abs_clipping.y1 = 0; } else { view.abs_clipping.x0 = area->g_x; view.abs_clipping.x1 = area->g_x + area->g_w; view.abs_clipping.y0 = area->g_y; view.abs_clipping.y1 = area->g_y + area->g_h; } } /** * Get the maximum clip extent, in absolute screen coords * \param dst the structure that receives the absolute clipping */ void plot_get_abs_clipping(struct rect *dst) { *dst = view.abs_clipping; } /** * Get the maximum clip extent, in absolute screen coords * \param dst the structure that receives the absolute clipping */ void plot_get_abs_clipping_grect(GRECT *dst) { dst->g_x = view.abs_clipping.x0; dst->g_w = view.abs_clipping.x1 - view.abs_clipping.x0; dst->g_y = view.abs_clipping.y0; dst->g_h = view.abs_clipping.y1 - view.abs_clipping.y0; } VdiHdl plot_get_vdi_handle(void) { return(atari_plot_vdi_handle); } long plot_get_flags(void) { return(atari_plot_flags); } 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; } FONT_PLOTTER plot_get_text_plotter() { return(fplotter); } void plot_set_text_plotter(FONT_PLOTTER font_plotter) { fplotter = font_plotter; } /** * \brief Sets a clip rectangle for subsequent plot operations. * * \param ctx The current redraw context. * \param clip The rectangle to limit all subsequent plot * operations within. * \return NSERROR_OK on success else error code. */ static nserror plot_clip(const struct redraw_context *ctx, const struct rect *clip) { GRECT canvas, screen, gclip, maxclip; short pxy[4]; screen.g_x = 0; screen.g_y = 0; screen.g_w = vdi_sysinfo.scr_w; screen.g_h = vdi_sysinfo.scr_h; plot_get_dimensions(&canvas); view.clipping.y0 = clip->y0; view.clipping.y1 = clip->y1; view.clipping.x0 = clip->x0; view.clipping.x1 = clip->x1; plot_get_clip_grect(&gclip); gclip.g_x += canvas.g_x; gclip.g_y += canvas.g_y; rc_intersect(&canvas, &gclip); if(gclip.g_h < 0){ gclip.g_h = 0; } if (!rc_intersect(&screen, &gclip)) { //dbg_rect("cliprect: ", &view.clipping); //dbg_grect("screen: ", &canvas); //dbg_grect("canvas clipped: ", &gclip); //assert(1 == 0); } // When setting VDI clipping, obey to maximum cliping rectangle: plot_get_abs_clipping_grect(&maxclip); rc_intersect(&maxclip, &gclip); //dbg_grect("canvas clipped to screen", &gclip); pxy[0] = gclip.g_x; pxy[1] = gclip.g_y; pxy[2] = pxy[0] + gclip.g_w; pxy[3] = pxy[1] + gclip.g_h; vs_clip(atari_plot_vdi_handle, 1, (short*)&pxy); return NSERROR_OK; } /** * Plots an arc * * plot an arc segment around (x,y), anticlockwise from angle1 * to angle2. Angles are measured anticlockwise from * horizontal, in degrees. * * \param ctx The current redraw context. * \param pstyle Style controlling the arc plot. * \param x The x coordinate of the arc. * \param y The y coordinate of the arc. * \param radius The radius of the arc. * \param angle1 The start angle of the arc. * \param angle2 The finish angle of the arc. * \return NSERROR_OK on success else error code. */ static nserror plot_arc(const struct redraw_context *ctx, const plot_style_t *pstyle, int x, int y, int radius, int angle1, int angle2) { vswr_mode(atari_plot_vdi_handle, MD_REPLACE); if (pstyle->fill_type == PLOT_OP_TYPE_NONE) { return NSERROR_OK; } 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); } return NSERROR_OK; } /** * Plots a circle * * Plot a circle centered on (x,y), which is optionally filled. * * \param ctx The current redraw context. * \param pstyle Style controlling the circle plot. * \param x x coordinate of circle centre. * \param y y coordinate of circle centre. * \param radius circle radius. * \return NSERROR_OK on success else error code. */ static nserror plot_disc(const struct redraw_context *ctx, const plot_style_t *pstyle, int x, int y, int radius) { 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); } return NSERROR_OK; } /** * Plots a line * * plot a line from (x0,y0) to (x1,y1). Coordinates are at * centre of line width/thickness. * * \param ctx The current redraw context. * \param pstyle Style controlling the line plot. * \param line A rectangle defining the line to be drawn * \return NSERROR_OK on success else error code. */ static nserror plot_line(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *line) { short pxy[4]; uint32_t lt; int sw = pstyle->stroke_width; if (((line->x0 < 0) && (line->x1 < 0)) || ((line->y0 < 0) && (line->y1 < 0))) { return NSERROR_OK; } pxy[0] = view.x + MAX(0, line->x0); pxy[1] = view.y + MAX(0, line->y0); pxy[2] = view.x + MAX(0, line->x1); pxy[3] = view.y + MAX(0, line->y1); if ((line->y0 > view.h-1) && (line->y1 > view.h-1)) { return NSERROR_OK; } //printf("view: %d,%d,%d,%d\n", view.x, view.y, view.w, view.h); //printf("line: %d,%d,%d,%d\n", x0, y0, x1, 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 NSERROR_OK; } /** * Plots a rectangle. * * The rectangle can be filled an outline or both controlled * by the plot style The line can be solid, dotted or * dashed. Top left corner at (x0,y0) and rectangle has given * width and height. * * \param ctx The current redraw context. * \param pstyle Style controlling the rectangle plot. * \param rect A rectangle defining the line to be drawn * \return NSERROR_OK on success else error code. */ static nserror plot_rectangle(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *rect) { short pxy[4]; GRECT r, rclip, sclip; int sw = pstyle->stroke_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 = rect->x0; r.g_y = rect->y0; r.g_w = rect->x1 - rect->x0; r.g_h = rect->y1 - rect->y0; if (!rc_intersect(&rclip, &r)) { return NSERROR_OK; } 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 == rect->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 == rect->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 == rect->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 == rect->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 NSERROR_OK; } /** * Plot a polygon * * Plots a filled polygon with straight lines between * points. The lines around the edge of the ploygon are not * plotted. The polygon is filled with the non-zero winding * rule. * * \param ctx The current redraw context. * \param pstyle Style controlling the polygon plot. * \param p verticies of polygon * \param n number of verticies. * \return NSERROR_OK on success else error code. */ static nserror plot_polygon(const struct redraw_context *ctx, const plot_style_t *pstyle, const int *p, unsigned int n) { short pxy[n*2]; unsigned int i = 0; if (vdi_sysinfo.maxpolycoords > 0) assert( (signed int)n < vdi_sysinfo.maxpolycoords); 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); } return NSERROR_OK; } /** * Plots a path. * * Path plot consisting of cubic Bezier curves. Line and fill colour is * controlled by the plot style. * * \param ctx The current redraw context. * \param pstyle Style controlling the path plot. * \param p elements of path * \param n nunber of elements on path * \param width The width of the path * \param transform A transform to apply to the path. * \return NSERROR_OK on success else error code. */ static nserror plot_path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, float width, const float transform[6]) { /** \todo Implement atari path plot */ return NSERROR_OK; } /** * Plot a bitmap * * Tiled plot of a bitmap image. (x,y) gives the top left * coordinate of an explicitly placed tile. From this tile the * image can repeat in all four directions -- up, down, left * and right -- to the extents given by the current clip * rectangle. * * The bitmap_flags say whether to tile in the x and y * directions. If not tiling in x or y directions, the single * image is plotted. The width and height give the dimensions * the image is to be scaled to. * * \param ctx The current redraw context. * \param bitmap The bitmap to plot * \param x The x coordinate to plot the bitmap * \param y The y coordiante to plot the bitmap * \param width The width of area to plot the bitmap into * \param height The height of area to plot the bitmap into * \param bg the background colour to alpha blend into * \param flags the flags controlling the type of plot operation * \return NSERROR_OK on success else error code. */ static nserror plot_bitmap(const struct redraw_context *ctx, struct bitmap *bitmap, int x, int y, int width, int height, 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 = atari_bitmap_get_width(bitmap); bmph = atari_bitmap_get_height(bitmap); if(view.scale != 1.0){ width = (int)(((float)width)*view.scale); height = (int)(((float)height)*view.scale); } 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) { atari_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 NSERROR_NOMEM; } 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 NSERROR_OK; } /** * Text plotting. * * \param ctx The current redraw context. * \param fstyle plot style for this text * \param x x coordinate * \param y y coordinate * \param text UTF-8 string to plot * \param length length of string, in bytes * \return NSERROR_OK on success else error code. */ static nserror plot_text(const struct redraw_context *ctx, const struct plot_font_style *fstyle, int x, int y, const char *text, size_t length) { if (view.scale != 1.0) { plot_font_style_t newstyle = *fstyle; newstyle.size = (int)((float)fstyle->size*view.scale); fplotter->text(fplotter, x, y, text, length, &newstyle); } else { fplotter->text(fplotter, x, y, text, length, fstyle); } return NSERROR_OK; } /** atari plottr operation table */ 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 };