File:  [RetroPC.NET] / np2 / x11 / gtk2 / gtk_screen.c
Revision 1.4: download - view: text, annotated - select for diffs
Sat Mar 12 21:36:57 2005 JST (20 years, 7 months ago) by monaka
Branches: MAIN
CVS tags: VER_0_82_x64, VER_0_82, VER_0_81A, VER_0_81, HEAD
license

/*	$Id: gtk_screen.c,v 1.4 2005/03/12 12:36:57 monaka Exp $	*/

/*
 * Copyright (c) 2003 NONAKA Kimihiro
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "compiler.h"

#include "np2.h"
#include "palettes.h"
#include "scrndraw.h"

#include "scrnmng.h"

#include "gtk2/xnp2.h"
#include "gtk2/gtk_drawmng.h"


typedef struct {
	UINT8		scrnmode;
	UINT8		drawing;
	int		width;
	int		height;
	int		extend;
	int		clipping;

	PAL16MASK	pal16mask;

	RECT_T		scrn;
	RECT_T		rect;

	int		lpitch;
	int		scrw;
	int		scrh;

	/* toolkit depend */
	GdkImage	*surface;
	GdkPixmap	*backsurf;

	unsigned long	pixel[24];	/* pallete */
} DRAWMNG;

typedef struct {
	int	width;
	int	height;
	int	extend;
} SCRNSTAT;

typedef struct {
	SCRNSURF	ss;

	UINT8		renewal[SURFACE_HEIGHT];
} X11SCRNSURF;

static SCRNMNG scrnmng;
static DRAWMNG drawmng;
static SCRNSTAT scrnstat;
static X11SCRNSURF scrnsurf;

SCRNMNG *scrnmngp = &scrnmng;

GtkWidget *main_window;
GtkWidget *drawarea;


static void
set_window_size(int width, int height)
{

	drawmng.scrw = width + np2oscfg.paddingx * 2;
	drawmng.scrh = height + np2oscfg.paddingy * 2;

	gtk_widget_set_size_request(drawarea, drawmng.scrw, drawmng.scrh);
}

static void
renewal_client_size(void)
{
	int width;
	int height;
	int extend;
	int scrnwidth;
	int scrnheight;

	width = min(scrnstat.width, drawmng.width);
	height = min(scrnstat.height, drawmng.height);
	extend = 0;

#if notyet
	if (drawmng.scrnmode & SCRNMODE_FULLSCREEN) {
	} else
#endif
	{
		if (!(drawmng.scrnmode & SCRNMODE_ROTATE)) {
			if (np2oscfg.paddingx > 0) {
				extend = min(scrnstat.extend, drawmng.extend);
			}
			scrnwidth = width;
			scrnheight = height;
			drawmng.rect.right = width + extend;
			drawmng.rect.bottom = height;
			drawmng.scrn.left = np2oscfg.paddingx - extend;
			drawmng.scrn.top = np2oscfg.paddingy;
		} else {
			if (np2oscfg.paddingy > 0) {
				extend = min(scrnstat.extend, drawmng.extend);
			}
			scrnwidth = height;
			scrnheight = width;
			drawmng.rect.right = height;
			drawmng.rect.bottom = width + extend;
			drawmng.scrn.left = np2oscfg.paddingx;
			drawmng.scrn.top = np2oscfg.paddingy - extend;
		}
		drawmng.scrn.right = np2oscfg.paddingx + scrnwidth;
		drawmng.scrn.bottom = np2oscfg.paddingy + scrnheight;
		set_window_size(scrnwidth, scrnheight);
	}
	scrnsurf.ss.width = width;
	scrnsurf.ss.height = height;
	scrnsurf.ss.extend = extend;
}

static void
clear_out_of_rect(const RECT_T *target, const RECT_T *base)
{
	GdkDrawable *d = drawarea->window;
	GdkGC *gc = drawarea->style->black_gc;
	RECT_T rect;

	rect.left = base->left;
	rect.right = base->right;
	rect.top = base->top;
	rect.bottom = target->top;
	if (rect.top < rect.bottom) {
		gdk_draw_rectangle(d, gc, TRUE,
		    rect.left, rect.top, rect.right, rect.bottom);
	}
	rect.top = target->bottom;
	rect.bottom = base->bottom;
	if (rect.top < rect.bottom) {
		gdk_draw_rectangle(d, gc, TRUE,
		    rect.left, rect.top, rect.right, rect.bottom);
	}

	rect.top = max(base->top, target->top);
	rect.bottom = min(base->bottom, target->bottom);
	if (rect.top < rect.bottom) {
		rect.left = base->left;
		rect.right = target->left;
		if (rect.left < rect.right) {
			gdk_draw_rectangle(d, gc, TRUE,
			    rect.left, rect.top, rect.right, rect.bottom);
		}
		rect.left = target->right;
		rect.right = base->right;
		if (rect.left < rect.right) {
			gdk_draw_rectangle(d, gc, TRUE,
			    rect.left, rect.top, rect.right, rect.bottom);
		}
	}
}

static void
clear_outscreen(void)
{
	RECT_T target;
	RECT_T base;

	base.left = base.top = 0;
	base.right = drawmng.scrw;
	base.bottom = drawmng.scrh;
	target = drawmng.scrn;
	clear_out_of_rect(&target, &base);
}

static void
palette_init(void)
{
	GdkColor color;
	GdkColormap *cmap;
	int rv;
	int i;

	cmap = gdk_colormap_get_system();
	rv = gdk_colors_alloc(cmap, TRUE, NULL, 0, drawmng.pixel, 24);
	if (rv == 0) {
		g_error("Can't allocate enough color.\n");
		return;
	}

	for (i = 0; i < 8; i++) {
		color.pixel = drawmng.pixel[NP2PAL_TEXT + i + 1];
		color.red = np2_pal32[NP2PAL_TEXT + i + 1].p.r << 8;
		color.green = np2_pal32[NP2PAL_TEXT + i + 1].p.g << 8;
		color.blue = np2_pal32[NP2PAL_TEXT + i + 1].p.b << 8;
		gdk_colormap_alloc_color(cmap, &color, TRUE, FALSE);
	}
}

static void
palette_set(void)
{
	GdkColor color;
	GdkColormap *cmap;
	int i;

	cmap = gdk_colormap_get_system();
	for (i = 0; i < NP2PALS_GRPH; i++) {
		color.pixel = drawmng.pixel[NP2PAL_GRPH + i];
		color.red = np2_pal32[NP2PAL_GRPH + i].p.r << 8;
		color.green = np2_pal32[NP2PAL_GRPH + i].p.g << 8;
		color.blue = np2_pal32[NP2PAL_GRPH + i].p.b << 8;
		gdk_colormap_alloc_color(cmap, &color, TRUE, FALSE);
	}
}

void
scrnmng_initialize(void)
{

	drawmng.drawing = FALSE;
	scrnstat.width = 640;
	scrnstat.height = 400;
	scrnstat.extend = 1;
	set_window_size(scrnstat.width, scrnstat.height);
}

BOOL
scrnmng_create(UINT8 mode)
{
	GdkVisual *visual;
	RECT_T rect;
	int height;
	UINT lpitch;
	UINT8 bytes_per_pixel;
	pixmap_format_t fmt;
	int padding;

	while (drawmng.drawing)
		gtk_main_iteration_do(FALSE);
	drawmng.drawing = TRUE;

#if notyet
	if (mode & SCRNMODE_FULLSCREEN) {
		mode &= ~SCRNMODE_ROTATEMASK;
		drawmng.extend = 0;
		return FAILURE;
	} else
#endif
	{
		scrnmng.flag = SCRNFLAG_HAVEEXTEND;

		visual = gtk_widget_get_visual(drawarea);
		if (!gtkdrawmng_getformat(drawarea, main_window, &fmt))
			return FAILURE;

		switch (fmt.bits_per_pixel) {
		case 16:
			drawmng_make16mask(&drawmng.pal16mask, visual->blue_mask, visual->red_mask, visual->green_mask);
			break;

		case 8:
			palette_init();
			break;
		}
		drawmng.extend = 1;
		bytes_per_pixel = (UINT8)(fmt.bits_per_pixel / 8);

		if (!(mode & SCRNMODE_ROTATE)) {
			rect.right = 641;
			rect.bottom = 480;
		} else {
			rect.right = 480;
			rect.bottom = 641;
		}
		lpitch = rect.right * bytes_per_pixel;
		padding = lpitch % (fmt.scanline_pad / 8);
		if (padding > 0) {
			rect.right += padding / bytes_per_pixel;
			lpitch = rect.right * bytes_per_pixel;
		}
		height = 480;

		drawmng.surface = gdk_image_new(GDK_IMAGE_FASTEST, visual,
		    rect.right, rect.bottom);
		if (drawmng.surface == NULL) {
			g_message("can't create surface.");
			return FAILURE;
		}

		drawmng.backsurf = gdk_pixmap_new(drawarea->window,
		    rect.right, rect.bottom, visual->depth);
		if (drawmng.backsurf == NULL) {
			g_message("can't create pixmap.");
			return FAILURE;
		}
		gdk_draw_rectangle(drawmng.backsurf, drawarea->style->black_gc,
		    TRUE, 0, 0, rect.right, rect.bottom);
	}
	scrnmng.bpp = (UINT8)fmt.bits_per_pixel;
	drawmng.lpitch = lpitch;
	scrnsurf.ss.bpp = fmt.bits_per_pixel;
	drawmng.scrnmode = mode;
	drawmng.width = 640;
	drawmng.height = height;
	drawmng.clipping = 0;
	renewal_client_size();

	drawmng.drawing = FALSE;

	return SUCCESS;
}

void
scrnmng_destroy(void)
{

	if (drawmng.backsurf) {
		gdk_pixmap_unref(drawmng.backsurf);
		drawmng.backsurf = NULL;
	}
	if (drawmng.surface) {
		gdk_image_destroy(drawmng.surface);
		drawmng.surface = NULL;
	}
}

RGB16
scrnmng_makepal16(RGB32 pal32)
{

	return drawmng_makepal16(&drawmng.pal16mask, pal32);
}

void
scrnmng_setwidth(int posx, int width)
{

	UNUSED(posx);

	scrnstat.width = width;
	renewal_client_size();
}

void
scrnmng_setheight(int posy, int height)
{

	UNUSED(posy);

	scrnstat.height = height;
	renewal_client_size();
}

void
scrnmng_setextend(int extend)
{

	scrnstat.extend = extend;
	renewal_client_size();
}

const SCRNSURF *
scrnmng_surflock(void)
{
	int lpitch = drawmng.lpitch;
	int bytes_per_pixel = scrnsurf.ss.bpp >> 3;

#if !defined(USE_SCREEN_INVALIDATE)
	memcpy(scrnsurf.renewal, renewal_line, sizeof(scrnsurf.renewal));
#endif

	scrnsurf.ss.ptr = (UINT8 *)drawmng.surface->mem;
	if (!(drawmng.scrnmode & SCRNMODE_ROTATE)) {
		scrnsurf.ss.xalign = bytes_per_pixel;
		scrnsurf.ss.yalign = lpitch;
	} else if (!(drawmng.scrnmode & SCRNMODE_ROTATEDIR)) {
		/* rotate left */
		scrnsurf.ss.ptr += (scrnsurf.ss.width + scrnsurf.ss.extend - 1) * lpitch;
		scrnsurf.ss.xalign = -lpitch;
		scrnsurf.ss.yalign = bytes_per_pixel;
	} else {
		/* rotate right */
		scrnsurf.ss.ptr += (drawmng.rect.right - 1) * bytes_per_pixel;
		scrnsurf.ss.xalign = lpitch;
		scrnsurf.ss.yalign = -bytes_per_pixel;
	}
	return &scrnsurf.ss;
}

void
scrnmng_surfunlock(const SCRNSURF *surf)
{
	GdkDrawable *d = drawarea->window;
	GdkGC *gc = drawarea->style->fg_gc[GTK_WIDGET_STATE(drawarea)];
	X11SCRNSURF *ss = (X11SCRNSURF *)surf;
	UINT8 *delta = ss->renewal;
	RECT_T r;
	gint h, s;

	r.left = drawmng.scrn.left;
	r.top = drawmng.scrn.top;
	r.right = drawmng.rect.right;
	r.bottom = drawmng.rect.bottom;

#if !defined(USE_SCREEN_INVALIDATE)
	if (!(drawmng.scrnmode & SCRNMODE_ROTATE)) {
		/* normal */
		for (s = h = 0; h < r.bottom; h++) {
			if ((renewal_line[h] != delta[h]) || (s == h))
				continue;

			gdk_draw_image(drawmng.backsurf, gc, drawmng.surface,
			    0, s, r.left, r.top + s, r.right, h - s);
			s = h + 1;
		}
		if (s != h) {
			gdk_draw_image(drawmng.backsurf, gc, drawmng.surface,
			    0, s, r.left, r.top + s, r.right, h - s);
		}
	} else if (!(drawmng.scrnmode & SCRNMODE_ROTATEDIR)) {
		/* rotate left */
		for (s = h = 0; h < r.right; h++) {
			if ((renewal_line[h] != delta[h]) || (s == h))
				continue;

			gdk_draw_image(drawmng.backsurf, gc, drawmng.surface,
			    s, 0, r.left + s, r.top, h - s, r.bottom);
			s = h + 1;
		}
		if (s != h) {
			gdk_draw_image(drawmng.backsurf, gc, drawmng.surface,
			    s, 0, r.left + s, r.top, h - s, r.bottom);
		}
	} else {
		/* rotate right */
		for (s = h = 0; h < r.right; h++) {
			if ((renewal_line[h] != delta[h]) || (s == h))
				continue;

			gdk_draw_image(drawmng.backsurf, gc, drawmng.surface,
			    r.right - h, 0,
			    drawmng.scrn.right - h, r.top, h - s, r.bottom);
			s = h + 1;
		}
		if (s != h) {
			gdk_draw_image(drawmng.backsurf, gc, drawmng.surface,
			    r.right - h, 0,
			    drawmng.scrn.right - h, r.top, h - s, r.bottom);
		}
	}
#else
	gtk_widget_queue_draw_area(drawarea, r.left, r.top, r.right, r.bottom);
#endif

	if (scrnmng.palchanged) {
		scrnmng.palchanged = FALSE;
		palette_set();
	}

#if !defined(USE_SCREEN_INVALIDATE)
	if (drawmng.drawing)
		return;

	drawmng.drawing = TRUE;
#if notyet
	if (drawmng.scrnmode & SCRNMODE_FULLSCREEN) {
	} else
#endif
	{
		if (scrnmng.allflash) {
			scrnmng.allflash = 0;
			if (np2oscfg.paddingx || np2oscfg.paddingy) {
				clear_outscreen();
			}
		}
		gdk_draw_pixmap(d, gc, drawmng.backsurf,
		    0, 0,                                     /* src  */
		    drawmng.scrn.left, drawmng.scrn.top,      /* dest */
		    drawmng.rect.right, drawmng.rect.bottom); /* w/h  */
	}
	drawmng.drawing = FALSE;
#endif
}

void
scrnmng_draw(RECT_T *r)
{
	GdkDrawable *d = drawarea->window;
	GdkGC *gc = drawarea->style->fg_gc[GTK_WIDGET_STATE(drawarea)];

	if (drawmng.drawing)
		return;

	drawmng.drawing = TRUE;

	if (r->right > drawmng.rect.right)
		r->right = drawmng.rect.right;
	if (r->bottom > drawmng.rect.bottom)
		r->bottom = drawmng.rect.bottom;

#if notyet
	if (drawmng.scrnmode & SCRNMODE_FULLSCREEN) {
	} else
#endif
	{
		if (scrnmng.allflash) {
			scrnmng.allflash = 0;
			if (np2oscfg.paddingx || np2oscfg.paddingy) {
				clear_outscreen();
			}
		}
#if !defined(USE_SCREEN_INVALIDATE)
		gdk_draw_pixmap(d, gc, drawmng.backsurf,
		    r->left, r->top,
		    r->left, r->top, r->right, r->bottom);
#else
		gdk_draw_image(d, gc, drawmng.surface,
		    r->left, r->top,
		    r->left, r->top, r->right, r->bottom);
#endif
	}
	drawmng.drawing = FALSE;
}

RetroPC.NET-CVS <cvs@retropc.net>