You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2522 lines
67 KiB
2522 lines
67 KiB
/*
|
|
* Copyright 2010 Ole Loots <ole@monochrom.net>
|
|
*
|
|
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
|
*
|
|
* NetSurf is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* NetSurf is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <sys/types.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
#include <stdbool.h>
|
|
#include <mt_gem.h>
|
|
#include <mint/osbind.h>
|
|
|
|
#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 <screen.g_y)
|
|
view.vis_y = frame.g_h - common.g_h;
|
|
else
|
|
view.vis_y = 0;
|
|
} else {
|
|
view.vis_w = view.vis_h = 0;
|
|
view.vis_x = view.vis_y = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the visible parts of the box
|
|
*
|
|
* The returned values are relative coords within framebuffer,
|
|
* relative to screen coords (normally starting at 0,0 )
|
|
*/
|
|
inline static bool fbrect_to_screen(GRECT box, GRECT * ret)
|
|
{
|
|
GRECT out, vis, screen;
|
|
|
|
screen.g_x = 0;
|
|
screen.g_y = 0;
|
|
screen.g_w = vdi_sysinfo.scr_w;
|
|
screen.g_h = vdi_sysinfo.scr_h;
|
|
|
|
/* get visible region: */
|
|
vis.g_x = view.x;
|
|
vis.g_y = view.y;
|
|
vis.g_w = view.w;
|
|
vis.g_h = view.h;
|
|
|
|
if ( !rc_intersect( &screen, &vis ) ) {
|
|
return( false );
|
|
}
|
|
vis.g_x = view.w - vis.g_w;
|
|
vis.g_y = view.h - vis.g_h;
|
|
|
|
/* clip box to visible region: */
|
|
if( !rc_intersect(&vis, &box) ) {
|
|
return( false );
|
|
}
|
|
out.g_x = box.g_x + view.x;
|
|
out.g_y = box.g_y + view.y;
|
|
out.g_w = box.g_w;
|
|
out.g_h = box.g_h;
|
|
*ret = out;
|
|
return ( true );
|
|
}
|
|
|
|
|
|
/**
|
|
* copy an rectangle from the plot buffer to screen
|
|
*
|
|
* because this is an on-screen plotter, this is an screen to screen copy.
|
|
*/
|
|
bool plot_copy_rect(GRECT src, GRECT dst)
|
|
{
|
|
MFDB devmf;
|
|
MFDB scrmf;
|
|
short pxy[8];
|
|
GRECT vis;
|
|
|
|
/* clip to visible rect, only needed for onscreen renderer: */
|
|
plot_get_visible_grect(&vis );
|
|
|
|
if( !rc_intersect(&vis, &src) )
|
|
return(true);
|
|
if( !rc_intersect(&vis, &dst) )
|
|
return(true);
|
|
|
|
src.g_x = view.x + src.g_x;
|
|
src.g_y = view.y + src.g_y;
|
|
dst.g_x = view.x + dst.g_x;
|
|
dst.g_y = view.y + dst.g_y;
|
|
|
|
devmf.fd_addr = NULL;
|
|
devmf.fd_w = src.g_w;
|
|
devmf.fd_h = src.g_h;
|
|
devmf.fd_wdwidth = 0;
|
|
devmf.fd_stand = 0;
|
|
devmf.fd_nplanes = 0;
|
|
devmf.fd_r1 = devmf.fd_r2 = devmf.fd_r3 = 0;
|
|
|
|
scrmf.fd_addr = NULL;
|
|
scrmf.fd_w = dst.g_w;
|
|
scrmf.fd_h = dst.g_h;
|
|
scrmf.fd_wdwidth = 0 ;
|
|
scrmf.fd_stand = 0;
|
|
scrmf.fd_nplanes = 0;
|
|
scrmf.fd_r1 = scrmf.fd_r2 = scrmf.fd_r3 = 0;
|
|
|
|
pxy[0] = src.g_x;
|
|
pxy[1] = src.g_y;
|
|
pxy[2] = pxy[0] + src.g_w-1;
|
|
pxy[3] = pxy[1] + src.g_h-1;
|
|
pxy[4] = dst.g_x;
|
|
pxy[5] = dst.g_y;
|
|
pxy[6] = pxy[4] + dst.g_w-1;
|
|
pxy[7] = pxy[5] + dst.g_h-1;
|
|
plot_lock();
|
|
vro_cpyfm( atari_plot_vdi_handle, S_ONLY, (short*)&pxy, &devmf, &scrmf);
|
|
plot_unlock();
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
/**
|
|
* Fill the screen info structure.
|
|
*
|
|
* \param vdih The handle
|
|
* \param[out] info The infor structure to fill.
|
|
*/
|
|
static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info)
|
|
{
|
|
/** \todo this long is being cast to a pointer */
|
|
unsigned long cookie_EdDI=0;
|
|
short out[300];
|
|
memset( info, 0, sizeof(struct s_vdi_sysinfo) );
|
|
|
|
info->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 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; y<clip->g_h; y++ ){
|
|
row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y)));
|
|
for( x=0; x<clip->g_w; x++ ){
|
|
pixel = row[x+clip->g_x];
|
|
if( (pixel&0xFF) == 0 ){
|
|
continue;
|
|
}
|
|
if( (pixel&0xFF) < 0xF0 ){
|
|
col = get_stdpx( &stdform, wdplanesize,x,y );
|
|
if( (col != prev_col) || (y == 0) )
|
|
bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8);
|
|
if( prev_col != col || prev_pixel != pixel ){
|
|
prev_col = col;
|
|
pixel = ablend( pixel, bgcol );
|
|
prev_pixel = pixel;
|
|
pixel = pixel >> 8;
|
|
/* convert pixel value to vdi color index: */
|
|
col = ( ((pixel&0xFF)<<16)
|
|
| (pixel&0xFF00)
|
|
| ((pixel&0xFF0000)>>16) );
|
|
val = RGB_TO_VDI( col );
|
|
}
|
|
set_stdpx( &stdform, wdplanesize, x, y, val );
|
|
} else {
|
|
if( pixel != prev_pixel ){
|
|
/* convert pixel value to vdi color index: */
|
|
pixel = pixel >> 8;
|
|
col = ( ((pixel&0xFF)<<16)
|
|
| (pixel&0xFF00)
|
|
| ((pixel&0xFF0000)>>16) );
|
|
val = RGB_TO_VDI( col );
|
|
prev_pixel = pixel;
|
|
}
|
|
set_stdpx( &stdform, wdplanesize, x, y, val );
|
|
}
|
|
}
|
|
}
|
|
// 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);
|
|
NSLOG(netsurf, INFO, "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);
|
|
NSLOG(netsurf, INFO, "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<OFFSET_WEB_PAL ) {
|
|
pal[i][0] = sys_pal[i][0];
|
|
pal[i][1] = sys_pal[i][1];
|
|
pal[i][2] = sys_pal[i][2];
|
|
} else if( vdi_sysinfo.scr_bpp >= 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 && i<OFFSET_CUST_PAL+16 ) {
|
|
/* here we define 20 additional gray colors... */
|
|
rgbcol[1] = rgbcol[2] = rgbcol[3] = ((graytone&0x0F) << 4);
|
|
rgb_to_vdi1000( &rgbcol[0], &pal[i][0] );
|
|
vs_color(atari_plot_vdi_handle, i, &pal[i][0]);
|
|
graytone++;
|
|
}
|
|
|
|
}
|
|
vdi1000_to_rgb( &pal[i][0], &rgb_lookup[i][0] );
|
|
}
|
|
|
|
} else {
|
|
/* no need to change the palette - its application specific */
|
|
}
|
|
#else
|
|
bitmap_convert = bitmap_convert_tc;
|
|
#endif
|
|
|
|
/* Setup Hermes conversion handles */
|
|
unsigned long hermesflags = (atari_plot_flags & PLOT_FLAG_DITHER) ? HERMES_CONVERT_DITHER : 0;
|
|
hermes_cnv_h = Hermes_ConverterInstance(hermesflags);
|
|
assert( hermes_cnv_h );
|
|
hermes_res_h = Hermes_ConverterInstance(hermesflags);
|
|
assert( hermes_res_h );
|
|
|
|
/* set up the src & dst format: */
|
|
/* netsurf uses RGBA ... */
|
|
nsfmt.a = 0xFFUL;
|
|
nsfmt.b = 0x0FF00UL;
|
|
nsfmt.g = 0x0FF0000UL;
|
|
nsfmt.r = 0x0FF000000UL;
|
|
nsfmt.bits = 32;
|
|
nsfmt.indexed = false;
|
|
nsfmt.has_colorkey = false;
|
|
|
|
vfmt.r = vdi_sysinfo.mask_r;
|
|
vfmt.g = vdi_sysinfo.mask_g;
|
|
vfmt.b = vdi_sysinfo.mask_b;
|
|
vfmt.a = vdi_sysinfo.mask_a;
|
|
vfmt.bits = atari_plot_bpp_virt;
|
|
vfmt.indexed = (atari_plot_bpp_virt <= 8) ? 1 : 0;
|
|
vfmt.has_colorkey = 0;
|
|
|
|
return( err );
|
|
}
|
|
|
|
|
|
int plot_finalise( void )
|
|
{
|
|
|
|
delete_font_plotter(fplotter);
|
|
|
|
#ifdef WITH_8BPP_SUPPORT
|
|
if (vfmt.indexed) {
|
|
int i;
|
|
for (i=OFFSET_WEB_PAL; i<OFFSET_CUST_PAL+16; i++) {
|
|
vs_color(atari_plot_vdi_handle, i, &sys_pal[i][0]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* close Hermes stuff: */
|
|
Hermes_ConverterReturn(hermes_cnv_h);
|
|
Hermes_Done();
|
|
|
|
/* free up temporary buffers */
|
|
free(buf_packed );
|
|
free(buf_planar);
|
|
snapshot_destroy();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool plot_lock(void)
|
|
{
|
|
if ((atari_plot_flags & PLOT_FLAG_LOCKED) != 0)
|
|
return(true);
|
|
if( !wind_update(BEG_UPDATE|0x100) )
|
|
return(false);
|
|
if( !wind_update(BEG_MCTRL|0x100) ){
|
|
wind_update(END_UPDATE);
|
|
return(false);
|
|
}
|
|
atari_plot_flags |= PLOT_FLAG_LOCKED;
|
|
graf_mouse(M_OFF, NULL);
|
|
return(true);
|
|
}
|
|
|
|
|
|
bool plot_unlock(void)
|
|
{
|
|
if( (atari_plot_flags & PLOT_FLAG_LOCKED) == 0 )
|
|
return(true);
|
|
wind_update(END_MCTRL);
|
|
wind_update(END_UPDATE);
|
|
graf_mouse(M_ON, NULL);
|
|
vs_clip_off(atari_plot_vdi_handle);
|
|
atari_plot_flags &= ~PLOT_FLAG_LOCKED;
|
|
return(false);
|
|
}
|
|
|
|
|
|
/* exported interface documented in atari/plot.h */
|
|
bool
|
|
plot_set_dimensions(const struct redraw_context *ctx, int x, int y, int w, int h)
|
|
{
|
|
bool doupdate = false;
|
|
struct rect newclip = {0, 0, w, h};
|
|
GRECT absclip = {x, y, w, h};
|
|
|
|
if (!(w == view.w && h == view.h)) {
|
|
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();
|
|
|
|
//dbg_rect("plot_set_dimensions", &newclip);
|
|
|
|
plot_set_abs_clipping(&absclip);
|
|
ctx->plot->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 = plot_style_fixed_to_int(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 = plot_style_fixed_to_int(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) ?
|
|
plot_style_fixed_to_int(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; i<n*2; i=i+2) {
|
|
pxy[i] = (short)view.x+p[i];
|
|
pxy[i+1] = (short)view.y+p[i+1];
|
|
}
|
|
|
|
if (pstyle->fill_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 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,
|
|
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
|
|
};
|