|
|
uae-0.6.8
/*
* UAE - The Un*x Amiga Emulator
*
* Amiga interface
*
* Copyright 1996 Samuel Devulder, Olaf `Olsen' Barthel.
*/
/*
* NOTE:
* - Im quite unhappy with the color allocation scheme in case of
* EXTRA_HALFBRITE...
* - It would be better to split this huge file into smaller pieces,
* but I think UAE has already too many different files, so please
* cope with that big one.
*/
/*
* History:
* 16/10/96 - Rewrote cybergfx support. (there is still a bug if the memory
* is not linear).
* 15/11/96 - Inhibit the drive in readdevice().
* 23/11/96 - Added call to rexx_init() and gui_handle_event().
* 14/12/96 - Added support for graffiti screens.
*/
#define USE_CYBERGFX /* undefine this if you don't have CYBERGFX includes */
/****************************************************************************/
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/devices.h>
#include <exec/io.h>
#include <dos/dos.h>
#include <graphics/gfxbase.h>
#include <graphics/displayinfo.h>
#include <libraries/asl.h>
#include <intuition/pointerclass.h>
#include <devices/trackdisk.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>
#include <proto/asl.h>
#include <proto/alib.h>
#include <proto/dos.h>
#ifdef USE_CYBERGFX
#include <inline/cybergraphics.h>
#endif
/****************************************************************************/
#include "sysconfig.h"
#include "sysdeps.h"
#include <ctype.h>
#include <signal.h>
/****************************************************************************/
#include "uae.h"
#include "config.h"
#include "options.h"
#include "../include/memory.h"
#include "custom.h"
#include "readcpu.h"
#include "newcpu.h"
#include "xwin.h"
#include "keyboard.h"
#include "keybuf.h"
#include "disk.h"
#include "debug.h"
#include "gui.h"
/****************************************************************************/
#define use_dither (!no_xhair)
static int need_dither; /* well.. guess :-) */
static int use_low_bandwidth; /* this will redraw only needed places */
static int use_cyb; /* this is for cybergfx */
static int use_graffiti;
xcolnr xcolors[4096];
/* Keyboard and mouse */
static int keystate[256];
int buttonstate[3];
int lastmx, lastmy;
int newmousecounters;
static int inwindow;
static char *oldpixbuf;
struct vidbuf_description gfxvidinfo;
/****************************************************************************/
/*
* prototypes & global vars
*/
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *AslBase;
struct Library *CyberGfxBase;
static UBYTE *Line;
static struct RastPort *RP;
static struct Screen *S;
static struct Window *W;
static struct RastPort *TempRPort;
static struct BitMap *BitMap;
static struct ColorMap *CM;
static Object *Pointer; /* for os 39 */
static UWORD *Sprite;
static int os39; /* kick 39 present */
static int usepub; /* use public screen */
static int halfv; /* halve height for non interlaced screen */
static int usecyb; /* use cybergraphics.library */
static int is_halfbrite;
static int get_color_failed;
static int maxpen;
static UBYTE pen[256];
static struct BitMap *myAllocBitMap(ULONG,ULONG,ULONG,ULONG,struct BitMap *);
static void set_title(void);
static void myFreeBitMap(struct BitMap *);
static LONG ObtainColor(ULONG, ULONG, ULONG);
static void ReleaseColors(void);
static void DoSizeWindow(struct Window *,int,int);
static void disk_hotkeys(void);
static void graffiti_SetRGB(int,int,int,int);
static void graffiti_WritePixelLine8(int,int,short,char*);
/****************************************************************************/
void main_window_led(int led, int on);
extern int rexx_init(void);
extern void rexx_exit(void);
extern void initpseudodevices(void);
extern void closepseudodevices(void);
extern char *to_unix_path(char *s);
extern char *from_unix_path(char *s);
extern void split_dir_file(char *src, char **dir, char **file);
/****************************************************************************/
static RETSIGTYPE sigbrkhandler(int foo)
{
activate_debugger();
}
void setup_brkhandler(void)
{
struct sigaction sa;
sa.sa_handler = sigbrkhandler;
sa.sa_flags = 0;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
}
/****************************************************************************/
__inline__ void flush_line(int y)
{
int xs = 0, len;
int yoffset = y*gfxvidinfo.rowbytes;
char *linebuf = gfxvidinfo.bufmem + yoffset;
char *src, *dst;
if(y<0 || y>=gfx_requested_height) {
/* printf("flush_line out of window: %d\n", y); */
return;
}
if(halfv && (y&1)) return;
/*
* cybergfx bitmap && no dither
*/
if(use_cyb && !need_dither) {
APTR handle;
char *baseaddr;
handle = LockBitMapTags(RP,LBMI_BASEADDRESS,(LONG)&baseaddr,TAG_DONE);
if(handle) {
CopyMem(linebuf, baseaddr + yoffset, gfxvidinfo.rowbytes);
UnLockBitMap(handle);
}
return;
}
#if 0
if(use_graffiti && !need_dither) {
graffiti_WritePixelLine8(0, y, gfxvidinfo.rowbytes, linebuf);
}
#endif
/*
* cybergfx && dither \_ LOW_BANDWIDTH and 1 byte per pixel in the output
* or standard screen /
*/
len = gfxvidinfo.maxlinetoscr?gfxvidinfo.maxlinetoscr:gfx_requested_width;
switch(gfxvidinfo.pixbytes) {
case 4:
{ /* sam: we should not arrive here on the amiga */
fprintf(stderr, "Bug in flush_line() !\n");
abort();
return;
} break;
case 2:
{ short *newp = (short *)linebuf;
short *oldp = (short *)(oldpixbuf + yoffset);
while (*newp++ == *oldp++) if(!--len) return;
src = (char *)--newp;
dst = (char *)--oldp;
newp += len;
oldp += len;
while (*--newp == *--oldp);
len = 1 + (oldp - (short *)dst);
xs = (src - linebuf)/2;
CopyMem (src, dst, len * 2);
} break;
case 1:
{ char *newp = (char *)linebuf;
char *oldp = (char *)(oldpixbuf + yoffset);
while (*newp++ == *oldp++) if(!--len) return;
src = (char *)--newp;
dst = (char *)--oldp;
newp += len;
oldp += len;
while (*--newp == *--oldp);
len = 1 + (oldp - (char *)dst);
xs = (src - linebuf);
CopyMem (src, dst, len);
} break;
default:
abort();
break;
}
if(halfv) y>>=1;
if (need_dither) {
DitherLine(Line, (UWORD *)dst, xs, y, (len+3)&~3, 8);
} else CopyMem(dst, Line, len);
if (use_cyb) { /* pixbyte == 1 */
APTR handle;
char *baseaddr;
handle = LockBitMapTags(RP,LBMI_BASEADDRESS,(LONG)&baseaddr,TAG_DONE);
if(handle) {
CopyMem(Line, baseaddr + yoffset + xs, len);
UnLockBitMap(handle);
}
} else if(use_graffiti) {
graffiti_WritePixelLine8(xs, y, len, Line);
} else WritePixelLine8(RP, xs, y, len, Line, TempRPort);
}
/****************************************************************************/
void flush_block (int ystart, int ystop)
{
int y;
for(y=ystart; y<=ystop; ++y) flush_line(y);
}
/****************************************************************************/
void flush_screen (int ystart, int ystop)
{
/* WaitBOVP() ? */
}
/****************************************************************************/
static int RPDepth(struct RastPort *RP)
{
#ifdef USE_CYBERGFX
if(use_cyb) return GetCyberMapAttr(RP->BitMap,CYBRMATTR_DEPTH);
#endif
if(use_graffiti) return 8;
return RP->BitMap->Depth;
}
/****************************************************************************/
static int get_color(int r, int g, int b, xcolnr *cnp)
{
int col;
r *= 0x11111111;
g *= 0x11111111;
b *= 0x11111111;
col = ObtainColor(r, g, b);
if(col == -1) {
get_color_failed = 1;
return 0;
}
*cnp = col;
return 1;
}
/****************************************************************************/
/*
* FIXME: find a better way to determine closeness of colors (closer to
* human perception).
*/
static __inline__ int calc_err(int r1, int g1, int b1,
int r2, int g2, int b2)
{
int err = 0;
if((r1>7 && r2<=7) || (r1<=7 && r2>7)) err += 1;
if((g1>7 && g2<=7) || (g1<=7 && g2>7)) err += 1;
if((b1>7 && b2<=7) || (b1<=7 && b2>7)) err += 1;
r1 -= r2; g1 -= g2; b1 -= b2;
r1 *= 2; g1 *= 3; b1 *= 1;
err += r1*r1 + g1*g1 + b1*b1;
return err;
}
/****************************************************************************/
static int get_nearest_color(int r, int g, int b)
{
int i, best, err, besterr;
int colors;
int br=0,bg=0,bb=0;
best = 0;
besterr = calc_err(0,0,0, 15,15,15);
colors = is_halfbrite?32:(1<<RPDepth(RP));
for(i=0; i<colors; i++ ) {
long rgb = GetRGB4(CM, i);
int cr, cg, cb;
cr = (rgb >> 8) & 15;
cg = (rgb >> 4) & 15;
cb = (rgb >> 0) & 15;
err = calc_err(r,g,b, cr,cg,cb);
if(err < besterr) {
best = i;
besterr = err;
br=cr; bg=cg; bb=cb;
}
if(is_halfbrite) {
cr /= 2; cg /= 2; cb /= 2;
err = calc_err(r,g,b, cr,cg,cb);
if(err < besterr) {
best = i + 32;
besterr = err;
br=cr; bg=cg; bb=cb;
}
}
}
return best;
}
/****************************************************************************/
static int init_colors(void)
{
if (need_dither) {
/* first try color allocation */
int bitdepth = usepub ? RPDepth(RP) : 8;
int maxcol;
if(bitdepth>=3)
do {
get_color_failed = 0;
setup_dither(bitdepth, get_color);
if(get_color_failed) ReleaseColors();
} while(get_color_failed && --bitdepth>=3);
if(bitdepth >= 3) {
printf("Color dithering with %d bits\n",bitdepth);
return 1;
}
/* if that fail then try grey allocation */
maxcol = 1<<(usepub ? RPDepth(RP) : 8);
do {
get_color_failed = 0;
setup_greydither_maxcol(maxcol, get_color);
if(get_color_failed) ReleaseColors();
} while(get_color_failed && --maxcol>=2);
if (maxcol >= 2) {
printf("Gray dither with %d shades\n",maxcol);
return 1;
}
return 0; /* everything failed :-( */
}
/* No dither */
switch(RPDepth(RP)) {
case 6: if (is_halfbrite) {
static int tab[]={
0x000, 0x00f, 0x0f0, 0x0ff, 0x08f, 0x0f8, 0xf00, 0xf0f,
0x80f, 0xff0, 0xfff, 0x88f, 0x8f0, 0x8f8, 0x8ff, 0xf08,
0xf80, 0xf88, 0xf8f, 0xff8, /* end of regular pattern */
0xa00, 0x0a0, 0xaa0, 0x00a, 0xa0a, 0x0aa, 0xaaa,
0xfaa, 0xf6a, 0xa80, 0x06a, 0x6af };
int i;
for(i=0;i<32;++i) get_color(tab[i]>>8, (tab[i]>>4)&15, tab[i]&15, xcolors);
for(i=0;i<4096;++i) xcolors[i] = get_nearest_color(i>>8, (i>>4)&15, i&15);
break;
}
case 1: case 2: case 3: case 4: case 5: case 7: case 8: {
int maxcol = 1<<RPDepth(RP);
if(maxcol>=8) do {
get_color_failed = 0;
setup_maxcol(maxcol);
alloc_colors256(get_color);
if(get_color_failed) ReleaseColors();
} while(get_color_failed && --maxcol>=8);
else {
int i;
for(i=0;i<maxcol;++i) {
get_color((i*15)/(maxcol-1), (i*15)/(maxcol-1),
(i*15)/(maxcol-1), xcolors);
}
}
printf("Using %d colors\n",maxcol);
for(maxcol=0;maxcol<4096;++maxcol)
xcolors[maxcol] = get_nearest_color(maxcol>>8, (maxcol>>4)&15,
maxcol&15);
} break;
case 15:
alloc_colors64k(5,5,5,10,5,0);
break;
case 16:
alloc_colors64k(5,6,5,11,5,0);
break;
case 24: case 32:
alloc_colors64k(8,8,8,16,8,0);
break;
}
return 1;
}
/****************************************************************************/
static void setup_sprite(struct Window *W)
{
Sprite = AllocVec(4+2, MEMF_CHIP|MEMF_CLEAR);
if(!Sprite) {
fprintf(stderr, "Warning: Can not alloc sprite buffer !\n");
return;
}
Sprite[2] = 0x8000; Sprite[3] = 0x8000;
SetPointer(W, Sprite, 1, 16, -1, 0);
}
/****************************************************************************/
static int setup_customscreen(void)
{
static struct NewScreen NewScreenStructure = {
0,0, 800,600, 3, 0,1,
LACE+HIRES, CUSTOMSCREEN|SCREENQUIET|SCREENBEHIND,
NULL, (void*)"UAE", NULL, NULL};
static struct NewWindow NewWindowStructure = {
0,0, 800,600, 0,1,
IDCMP_MOUSEBUTTONS|IDCMP_RAWKEY|IDCMP_DISKINSERTED|IDCMP_DISKREMOVED|
IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW|IDCMP_MOUSEMOVE,
WFLG_SMART_REFRESH|WFLG_BACKDROP|WFLG_RMBTRAP|WFLG_NOCAREREFRESH|
WFLG_BORDERLESS|WFLG_WINDOWACTIVE|WFLG_REPORTMOUSE,
NULL, NULL, (void*)"UAE", NULL, NULL, 5,5, 800,600,
CUSTOMSCREEN};
NewScreenStructure.Width = gfx_requested_width;
NewScreenStructure.Height = gfx_requested_height;
NewScreenStructure.Depth = os39?8:(gfx_requested_lores?5:4);
NewScreenStructure.ViewModes = SPRITES | (gfx_requested_lores ? NULL : HIRES) |
(correct_aspect ? LACE : NULL);
do S = (void*)OpenScreen(&NewScreenStructure);
while(!S && --NewScreenStructure.Depth);
if(!S) {
fprintf(stderr, "Can't open custom screen !\n");
return 0;
}
CM = S->ViewPort.ColorMap;
RP = &S->RastPort;
NewWindowStructure.Width = S->Width;
NewWindowStructure.Height = S->Height;
NewWindowStructure.Screen = S;
W = (void*)OpenWindow(&NewWindowStructure);
if(!W) {
fprintf(stderr, "Can't open window on custom screen !\n");
return 0;
}
setup_sprite(W);
return 1;
}
/****************************************************************************/
static int setup_publicscreen(void)
{
static struct NewWindow NewWindowStructure = {
0,0, 800,600, 0,1,
IDCMP_MOUSEBUTTONS|IDCMP_RAWKEY|IDCMP_DISKINSERTED|IDCMP_DISKREMOVED|
IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW|IDCMP_MOUSEMOVE|
IDCMP_CLOSEWINDOW,
WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_SMART_REFRESH|WFLG_REPORTMOUSE|
WFLG_RMBTRAP|WFLG_GIMMEZEROZERO|WFLG_ACTIVATE|WFLG_NOCAREREFRESH|
WFLG_CLOSEGADGET,
NULL, NULL, (void*)"UAE", NULL, NULL, 5,5, 800,600,
PUBLICSCREEN};
S = LockPubScreen(NULL);
if(!S) {
fprintf(stderr,"No public screen !\n");
return 0;
}
CM = S->ViewPort.ColorMap;
halfv = (S->ViewPort.Modes & (HIRES|LACE))==HIRES;
NewWindowStructure.Width = gfx_requested_width;
NewWindowStructure.Height = gfx_requested_height >> (halfv?1:0);
NewWindowStructure.Screen = S;
W = (void*)OpenWindow(&NewWindowStructure);
UnlockPubScreen(NULL, S);
if(!W) {
fprintf(stderr,"Can't open window on public screen !\n");
CM = NULL;
return 0;
}
DoSizeWindow(W, NewWindowStructure.Width, NewWindowStructure.Height);
RP = W->RPort;
setup_sprite(W);
return 1;
}
/****************************************************************************/
static int setup_userscreen(void)
{
struct ScreenModeRequester *ScreenRequest;
ULONG DisplayID;
static struct BitMap PointerBitMap;
UWORD *PointerLine;
LONG ScreenWidth=0,ScreenHeight=0,Depth=0;
UWORD OverscanType=0;
BOOL AutoScroll=0;
#ifdef USE_CYBERGFX
if(!CyberGfxBase) CyberGfxBase = OpenLibrary("cybergraphics.library",40);
#endif
if(!AslBase) AslBase = OpenLibrary("asl.library",38);
if(!AslBase) {
fprintf(stderr,"Can't open asl.library v38 !");
return 0;
}
ScreenRequest = AllocAslRequest(ASL_ScreenModeRequest,NULL);
if(!ScreenRequest) {
fprintf(stderr,"Unable to allocate screen mode requester.\n");
return 0;
}
if(AslRequestTags(ScreenRequest,
ASLSM_TitleText, (ULONG)"Select screen display mode",
ASLSM_InitialDisplayID, NULL,
ASLSM_InitialDisplayDepth, 8,
ASLSM_InitialDisplayWidth, gfx_requested_width,
ASLSM_InitialDisplayHeight,gfx_requested_height,
ASLSM_MinWidth, gfx_requested_width,
ASLSM_MinHeight, gfx_requested_height,
ASLSM_DoWidth, TRUE,
ASLSM_DoHeight, TRUE,
ASLSM_DoDepth, TRUE,
ASLSM_DoOverscanType, TRUE,
ASLSM_PropertyFlags, 0,
ASLSM_PropertyMask, DIPF_IS_DUALPF |
DIPF_IS_PF2PRI |
DIPF_IS_HAM |
0,
TAG_DONE)) {
ScreenWidth = ScreenRequest->sm_DisplayWidth;
ScreenHeight = ScreenRequest->sm_DisplayHeight;
Depth = ScreenRequest->sm_DisplayDepth;
DisplayID = ScreenRequest->sm_DisplayID;
OverscanType = ScreenRequest->sm_OverscanType;
AutoScroll = ScreenRequest->sm_AutoScroll;
if(ScreenWidth < gfx_requested_width) ScreenWidth = gfx_requested_width;
if(ScreenHeight < gfx_requested_height) ScreenHeight = gfx_requested_height;
}
else DisplayID = INVALID_ID;
FreeAslRequest(ScreenRequest);
if(DisplayID == (ULONG)INVALID_ID) return 0;
#ifdef USE_CYBERGFX
if(CyberGfxBase && IsCyberModeID(DisplayID)) use_cyb = 1;
#endif
S = OpenScreenTags(NULL,
SA_DisplayID, DisplayID,
SA_Width, ScreenWidth,
SA_Height, ScreenHeight,
SA_Depth, Depth,
SA_Overscan, OverscanType,
SA_AutoScroll, AutoScroll,
SA_ShowTitle, FALSE,
SA_Quiet, TRUE,
SA_Behind, TRUE,
/* v39 stuff here: */
(os39?SA_BackFill:TAG_DONE), (ULONG)LAYERS_NOBACKFILL,
SA_SharePens, TRUE,
SA_Exclusive, (use_cyb?TRUE:FALSE),
SA_Draggable, (use_cyb?FALSE:TRUE),
SA_Interleaved, TRUE,
TAG_DONE);
if(!S) {
fprintf(stderr,"Unable to open the screen.\n");
return 0;
}
RP = &S->RastPort;
CM = S->ViewPort.ColorMap;
is_halfbrite = (S->ViewPort.Modes & EXTRA_HALFBRITE);
#ifdef USE_CYBERGFX
if(CyberGfxBase && !GetCyberMapAttr(RP->BitMap,CYBRMATTR_ISLINEARMEM)) {
fprintf(stderr,"Cybergraphic screen is not in linear memory!\n");
CloseScreen(S); S = NULL;
use_cyb = 0;
return 0;
}
#endif
PointerLine = malloc(4);/* autodocs says it needs not be in chip memory */
if(PointerLine) PointerLine[0]=PointerLine[1]=0;
InitBitMap(&PointerBitMap,2,16,1);
PointerBitMap.Planes[0] = (PLANEPTR)&PointerLine[0];
PointerBitMap.Planes[1] = (PLANEPTR)&PointerLine[1];
Pointer = NewObject(NULL,POINTERCLASS,
POINTERA_BitMap, (ULONG)&PointerBitMap,
POINTERA_WordWidth, 1,
TAG_DONE);
if(!Pointer)
fprintf(stderr,"Warning: Unable to allocate blank mouse pointer.\n");
W = OpenWindowTags(NULL,
WA_Width, S->Width,
WA_Height, S->Height,
WA_CustomScreen, (ULONG)S,
WA_Backdrop, TRUE,
WA_Borderless, TRUE,
WA_RMBTrap, TRUE,
WA_ReportMouse, TRUE,
WA_IDCMP, IDCMP_MOUSEBUTTONS|
IDCMP_RAWKEY|
IDCMP_DISKINSERTED|
IDCMP_DISKREMOVED|
IDCMP_ACTIVEWINDOW|
IDCMP_INACTIVEWINDOW|
IDCMP_MOUSEMOVE,
(os39?WA_BackFill:TAG_IGNORE), (ULONG)LAYERS_NOBACKFILL,
(Pointer?WA_Pointer:TAG_IGNORE), (ULONG)Pointer,
TAG_DONE);
if(!W) {
fprintf(stderr,"Unable to open the window.\n");
CloseScreen(S);S=NULL;RP=NULL;CM=NULL;
return 0;
}
if(!Pointer) setup_sprite(W);
return 1;
}
/****************************************************************************/
static int setup_graffiti(void)
{
static struct NewScreen NewScreenStructure = {
0,-8, 800,600, 4, 0,1,
HIRES, CUSTOMSCREEN|SCREENQUIET|SCREENBEHIND,
NULL, (void*)"UAE", NULL, NULL};
static struct NewWindow NewWindowStructure = {
0,0, 800,600, 0,1,
IDCMP_MOUSEBUTTONS|IDCMP_RAWKEY|IDCMP_DISKINSERTED|IDCMP_DISKREMOVED|
IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW|IDCMP_MOUSEMOVE,
WFLG_SMART_REFRESH|WFLG_BACKDROP|WFLG_RMBTRAP|WFLG_NOCAREREFRESH|
WFLG_BORDERLESS|WFLG_WINDOWACTIVE|WFLG_REPORTMOUSE,
NULL, NULL, (void*)"UAE", NULL, NULL, 5,5, 800,600,
CUSTOMSCREEN};
static short colarr[] = {
0x000,0x001,0x008,0x009,0x080,0x081,0x088,0x089,
0x800,0x801,0x808,0x809,0x880,0x881,0x888,0x889};
int i;
NewScreenStructure.Width = 2*gfx_requested_width;
/* I leave 8 extra lines for palette & mode: */
NewScreenStructure.Height = gfx_requested_height+8;
NewScreenStructure.Depth = 4;
NewScreenStructure.ViewModes = HIRES|GENLOCK_AUDIO|GENLOCK_VIDEO;
S = (void*)OpenScreen(&NewScreenStructure);
if(!S) {
fprintf(stderr, "Can't open graffiti screen !\n");
return 0;
}
for(i=0;i<15;++i) {
unsigned int rgb = colarr[i];
SetRGB4(&S->ViewPort,i,(rgb>>8)&15,(rgb>>4)&15,rgb&15);
}
CM = S->ViewPort.ColorMap;
RP = &S->RastPort;
NewWindowStructure.Width = S->Width;
NewWindowStructure.Height = S->Height;
NewWindowStructure.Screen = S;
W = (void*)OpenWindow(&NewWindowStructure);
if(!W) {
fprintf(stderr, "Can't open window on graffiti screen !\n");
return 0;
}
setup_sprite(W);
{
/* make sure cmd part is cleared */
int d;
for(d = 0;d < 4; ++d) {
short *p;
int i;
p = (void*)RP->BitMap->Planes[d];
for(i=0;i<40*7;++i) p[i] = 0;
}
/* set graffiti mode to lores */
*((short*)RP->BitMap->Planes[3]+8*40-1) = 0x0800;
for(d=0;d<256;++d) graffiti_SetRGB(d,0,0,0);
}
return 1;
}
/****************************************************************************/
int graphics_init(void)
{
int i,bitdepth;
use_low_bandwidth = 0;
need_dither = 0;
use_cyb = 0;
if (gfx_requested_width < 320)
gfx_requested_width = 320;
if (gfx_requested_height < 200)
gfx_requested_height = 200;
gfx_requested_width += 7;
gfx_requested_width &= ~7;
gfxvidinfo.maxlinetoscr = gfx_requested_width;
gfxvidinfo.maxline = gfx_requested_height;
if(color_mode == 3) {
gfx_requested_width = 320;
gfx_requested_height = 320;
gfx_requested_lores = 1;
} /* graffiti */
if(SysBase->LibNode.lib_Version < 36) {
fprintf(stderr, "UAE needs OS 2.0+ !\n");
return 0;
}
os39 = (SysBase->LibNode.lib_Version>=39);
atexit(graphics_leave);
IntuitionBase = (void*)OpenLibrary("intuition.library",0L);
if(!IntuitionBase) {
fprintf(stderr,"No intuition.library ?\n");
return 0;
}
GfxBase = (void*)OpenLibrary("graphics.library",0L);
if(!GfxBase) {
fprintf(stderr,"No graphics.library ?\n");
return 0;
}
switch(color_mode) {
case 3:
if(setup_graffiti()) {use_graffiti = 1;break;}
fprintf(stderr,"Asking user for screen...\n");
/* fall trough */
case 2:
if(setup_userscreen()) break;
fprintf(stderr,"Trying on public screen...\n");
/* fall trough */
case 1:
is_halfbrite = 0;
if(setup_publicscreen()) {usepub = 1;break;}
fprintf(stderr,"Trying on custom screen...\n");
/* fall trough */
case 0:
default:
if(!setup_customscreen()) return 0;
break;
}
Line = AllocVec((gfx_requested_width + 15) & ~15,MEMF_ANY|MEMF_PUBLIC);
if(!Line) {
fprintf(stderr,"Unable to allocate raster buffer.\n");
return 0;
}
BitMap = myAllocBitMap(gfx_requested_width,1,8,BMF_CLEAR|BMF_MINPLANES,RP->BitMap);
if(!BitMap) {
fprintf(stderr,"Unable to allocate BitMap.\n");
return 0;
}
TempRPort = AllocVec(sizeof(struct RastPort),MEMF_ANY|MEMF_PUBLIC);
if(!TempRPort) {
fprintf(stderr,"Unable to allocate RastPort.\n");
return 0;
}
CopyMem(RP,TempRPort,sizeof(struct RastPort));
TempRPort->Layer = NULL;
TempRPort->BitMap = BitMap;
if(usepub) set_title();
bitdepth = RPDepth(RP);
if(bitdepth <= 8) {
/* chunk2planar is slow so we define use_low_bandwidth for all modes
except cybergraphics modes */
use_low_bandwidth = 1;
need_dither = use_dither || (bitdepth<=1);
gfxvidinfo.pixbytes = need_dither?2:1;
} else {
/* Cybergfx mode */
gfxvidinfo.pixbytes = (bitdepth == 24 || bitdepth == 32 ? 4
: bitdepth == 12 || bitdepth == 16 ? 2
: 1);
}
if (!use_cyb) {
gfxvidinfo.rowbytes = gfxvidinfo.pixbytes * gfx_requested_width;
gfxvidinfo.bufmem = (char *)calloc(gfxvidinfo.rowbytes, gfx_requested_height+1);
/* ^^ */
/* This is because DitherLine may read one extra row */
} else {
#ifdef USE_CYBERGFX
gfxvidinfo.rowbytes = GetCyberMapAttr(RP->BitMap,CYBRMATTR_XMOD);
gfxvidinfo.pixbytes = GetCyberMapAttr(RP->BitMap,CYBRMATTR_BPPIX);
gfxvidinfo.bufmem = (char *)calloc(gfxvidinfo.rowbytes, gfx_requested_height+1);
#endif
}
if(!gfxvidinfo.bufmem) {
fprintf(stderr,"Not enough memory.\n");
return 0;
}
if (use_low_bandwidth) {
gfxvidinfo.maxblocklines = gfx_requested_height-1; /* it seems to increase the speed */
oldpixbuf = (char *)calloc(gfxvidinfo.rowbytes, gfx_requested_height);
if(!oldpixbuf) {
fprintf(stderr,"Not enough memory for oldpixbuf.\n");
return 0;
}
} else {
gfxvidinfo.maxblocklines = 100; /* whatever... */
}
if (!init_colors())
return 0;
if(!usepub) ScreenToFront(S);
buttonstate[0] = buttonstate[1] = buttonstate[2] = 0;
for(i=0; i<256; i++)
keystate[i] = 0;
lastmx = lastmy = 0;
newmousecounters = 0;
inwindow = 0;
rexx_init();
initpseudodevices();
return 1;
}
/****************************************************************************/
void graphics_leave(void)
{
rexx_exit();
closepseudodevices();
if(BitMap) {
WaitBlit();
myFreeBitMap(BitMap);
BitMap = NULL;
}
if(TempRPort) {
FreeVec(TempRPort);
TempRPort = NULL;
}
if(Line) {
FreeVec(Line);
Line = NULL;
}
if(CM) {
ReleaseColors();
CM = NULL;
}
if(W) {
CloseWindow(W);
W = NULL;
}
if(Sprite) {
FreeVec(Sprite);
Sprite = NULL;
}
if(Pointer) {
DisposeObject(Pointer);
Pointer = NULL;
}
if(!usepub && S) {
CloseScreen(S);
S = NULL;
}
if(AslBase) {
CloseLibrary((void*)AslBase);
AslBase = NULL;
}
if(GfxBase) {
CloseLibrary((void*)GfxBase);
GfxBase = NULL;
}
if(IntuitionBase) {
CloseLibrary((void*)IntuitionBase);
IntuitionBase = NULL;
}
if(CyberGfxBase) {
CloseLibrary((void*)CyberGfxBase);
CyberGfxBase = NULL;
}
}
/***************************************************************************/
void handle_events(void)
{
struct IntuiMessage *msg;
int mx,my,class,code;
newmousecounters = 0;
/*
* This is a hack to simulate ^C as is seems that break_handler
* is lost when system() is called.
*/
if(SetSignal(0L, SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D) &
(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
activate_debugger();
}
while((msg=(struct IntuiMessage*)GetMsg(W->UserPort))) {
class = msg->Class;
code = msg->Code;
mx = msg->MouseX;
my = msg->MouseY;
ReplyMsg((struct Message*)msg);
if(usepub) {
mx -= W->BorderLeft;
my -= W->BorderTop;
}
if(use_graffiti) {
my -= 8;
}
switch(class) {
case CLOSEWINDOW:
activate_debugger();
break;
case RAWKEY: {
int kc = code&127;
int released = code&128?1:0;
if(released) {
keystate[kc] = 0;
record_key ((kc << 1) | 1);
} else if (!keystate[kc]) {
keystate[kc] = 1;
record_key (kc << 1);
}
} break;
case MOUSEMOVE:
if(inwindow) {
lastmx = mx >> (use_graffiti?1:0);
lastmy = my << (halfv?1:0);
} break;
case MOUSEBUTTONS:
if(code==SELECTDOWN) buttonstate[0]=1;
if(code==SELECTUP) buttonstate[0]=0;
if(code==MENUDOWN) buttonstate[2]=1;
if(code==MENUUP) buttonstate[2]=0;
break;
/* Those 2 could be of some use later. */
case DISKINSERTED:
/*printf("diskinserted(%d)\n",code);*/
break;
case DISKREMOVED:
/*printf("diskremoved(%d)\n",code);*/
break;
case ACTIVEWINDOW:
inwindow = 1;
newmousecounters = 1;
/* lastmx = mx >> ((use_graffiti?1:0);
lastmy = my<<(halfv?1:0); */
break;
case INACTIVEWINDOW:
inwindow = 0;
break;
default:
fprintf(stderr, "Unknown class: %d\n",class);
break;
}
}
/* "Affengriff" */
if(keystate[AK_CTRL] && keystate[AK_LAMI] && keystate[AK_RAMI])
m68k_reset();
/* PC-like :-) CTRL-ALT-DEL => reboot */
if(keystate[AK_CTRL] && (keystate[AK_LALT] || keystate[AK_RALT]) &&
keystate[AK_DEL])
m68k_reset();
/* CTRL+LSHIFT+LALT+F10 on amiga => F12 on X11 */
/* F9 => ScrollLock on X11 (inhibit_frame) */
if(keystate[AK_CTRL] && keystate[AK_LSH] && keystate[AK_LALT]) {
if(keystate[AK_F10]) togglemouse();
if(keystate[AK_F9]) {
inhibit_frame ^= 1;
if(inhibit_frame) printf("display disabled\n");
else printf("display enabled\n");
}
}
disk_hotkeys();
gui_handle_events();
}
/***************************************************************************/
void target_specific_usage(void)
{
printf("\n");
printf("----------------------------------------------------------------------------\n");
printf("AMIGA SPECIFIC USAGE:\n");
printf(" -S n : Sound emulation accuracy (n = 0, 1, 2 or 3)\n"
" For sound emulation, n = 2 is recommended\n");
printf(" -R n : Use n Hz to output sound. Common values are\n"
" 22050 Hz or 44100 Hz\n");
printf(" -B n : Use a sound buffer of n bytes (use small\n"
" values on fast machines)\n");
printf(" -p command : Use command to pipe printer output to.\n");
printf(" -I device : Name of the used serial device (i.e. /dev/ttyS1\n");
printf(" -x : Does not use dithering\n");
printf(" On the amiga, Valid resolution (see -d) are:\n");
printf(" 0, 1, 2 (320x256); 3 (640x512); 4 (800x600).\n");
printf(" And valid color modes (see -H) are:\n");
printf(" 0 => 256 cols max on customscreen;\n");
printf(" 1 => OpenWindow on default public screen;\n");
printf(" 2 => Ask the user to select a screen mode with ASL requester;\n");
printf(" 3 => use a 320x256 graffiti screen.\n");
printf("----------------------------------------------------------------------------\n");
printf("\n");
}
/***************************************************************************/
int debuggable(void)
{
return 1;
}
/***************************************************************************/
int needmousehack(void)
{
return 1;
}
/***************************************************************************/
void LED(int on)
{
}
/***************************************************************************/
static int led_state[5];
static void set_title(void)
{
static char title[80];
static char ScreenTitle[100];
if(!usepub) return;
sprintf(title,"UAE - Power: [%c] Drives: [%c] [%c] [%c] [%c]",
led_state[0]?'X':' ',
led_state[1]?'0':' ',
led_state[2]?'1':' ',
led_state[3]?'2':' ',
led_state[4]?'3':' ');
if(!*ScreenTitle) {
sprintf(ScreenTitle,
"UAE-%d.%d.%d � by Bernd Schmidt & contributors, "
"Amiga Port by Samuel Devulder.",
(version / 100) % 10, (version / 10) % 10, version % 10);
SetWindowTitles(W, title, ScreenTitle);
} else SetWindowTitles(W, title, (char*)-1);
}
/****************************************************************************/
void main_window_led(int led, int on) /* is used in amigui.c */
{
if(led>=0 && led<=4) led_state[led] = on;
set_title();
}
/****************************************************************************/
static void unrecord(int kc)
{
keystate[kc] = 0;
record_key ((kc << 1) | 1);
}
/****************************************************************************/
static void disk_hotkeys(void)
{
struct FileRequester *FileRequest;
char buff[80];
int drive;
char *last_file,*last_dir,*s;
if(!(keystate[AK_CTRL] && keystate[AK_LALT])) return;
/* CTRL-LSHIFT-LALT F1-F4 => eject_disk */
if(keystate[AK_LSH]) {
int ok = 0;
if(keystate[AK_F1]) {ok=1;disk_eject(0);
printf("drive DF0: ejected\n");}
if(keystate[AK_F2]) {ok=1;disk_eject(1);
printf("drive DF1: ejected\n");}
if(keystate[AK_F3]) {ok=1;disk_eject(2);
printf("drive DF2: ejected\n");}
if(keystate[AK_F4]) {ok=1;disk_eject(3);
printf("drive DF3: ejected\n");}
if(ok) {
unrecord(AK_CTRL);unrecord(AK_LALT);unrecord(AK_LSH);
unrecord(AK_F1);unrecord(AK_F2);
unrecord(AK_F3);unrecord(AK_F4);
}
return;
}
/* CTRL-LALT F1-F4 => insert_disk */
if(keystate[AK_F1]) {drive = 0;unrecord(AK_F1);}
else if(keystate[AK_F2]) {drive = 1;unrecord(AK_F2);}
else if(keystate[AK_F3]) {drive = 2;unrecord(AK_F3);}
else if(keystate[AK_F4]) {drive = 3;unrecord(AK_F4);}
else return;
unrecord(AK_CTRL);unrecord(AK_LALT);
switch(drive) {
case 0: last_file = df0; break;
case 1: last_file = df1; break;
case 2: last_file = df2; break;
case 3: last_file = df3; break;
default: return;
}
split_dir_file(from_unix_path(last_file), &last_dir, &last_file);
if(!last_file) return;
if(!last_dir) return;
if(!AslBase) AslBase = OpenLibrary("asl.library",36);
if(!AslBase) {
fprintf(stderr,"Can't open asl.library v36 !");
return;
}
FileRequest = AllocAslRequest(ASL_FileRequest,NULL);
if(!FileRequest) {
fprintf(stderr,"Unable to allocate file requester.\n");
return;
}
sprintf(buff,"Select file to use for drive DF%d:",drive);
if(AslRequestTags(FileRequest,
use_graffiti?TAG_IGNORE:
ASLFR_Window, (ULONG)W,
ASLFR_TitleText, (ULONG)buff,
ASLFR_InitialDrawer, (ULONG)last_dir,
ASLFR_InitialFile, (ULONG)last_file,
ASLFR_InitialPattern, (ULONG)"(#?.adf#?|df?|?)",
ASLFR_DoPatterns, TRUE,
ASLFR_RejectIcons, TRUE,
TAG_DONE)) {
free(last_file);
last_file = malloc(3 + strlen(FileRequest->fr_Drawer) +
strlen(FileRequest->fr_File));
if((last_file)) {
s = last_file;
strcpy(s,FileRequest->fr_Drawer);
if(*s && !(s[strlen(s)-1]==':' || s[strlen(s)-1]=='/'))
strcat(s,"/");
strcat(s,FileRequest->fr_File);
last_file = to_unix_path(s);free(s);
}
} else {
free(last_file);
last_file = NULL;
}
FreeAslRequest(FileRequest);
free(last_dir);
if(last_file) {
disk_insert(drive,last_file);
free(last_file);
}
}
/****************************************************************************/
/*
* Routines for OS2.0 (code taken out of mpeg_play by Michael Balzer)
*/
static struct BitMap *myAllocBitMap(ULONG sizex, ULONG sizey, ULONG depth,
ULONG flags, struct BitMap *friend_bitmap)
{
struct BitMap *bm;
unsigned long extra;
if(os39) return AllocBitMap(sizex, sizey, depth, flags, friend_bitmap);
extra = (depth > 8) ? depth - 8 : 0;
bm = AllocVec( sizeof *bm + (extra * 4), MEMF_CLEAR );
if( bm )
{
ULONG i;
InitBitMap(bm, depth, sizex, sizey);
for( i=0; i<depth; i++ )
{
if( !(bm->Planes[i] = AllocRaster(sizex, sizey)) )
{
while(i--) FreeRaster(bm->Planes[i], sizex, sizey);
FreeVec(bm);
bm = 0;
break;
}
}
}
return bm;
}
/****************************************************************************/
static void myFreeBitMap(struct BitMap *bm)
{
if(os39) {FreeBitMap(bm);return;}
while(bm->Depth--)
FreeRaster(bm->Planes[bm->Depth], bm->BytesPerRow*8, bm->Rows);
FreeVec(bm);
}
/****************************************************************************/
/*
* find the best appropriate color return -1 if none is available
*/
static LONG ObtainColor(ULONG r,ULONG g,ULONG b)
{
int i, crgb;
int colors;
if(use_graffiti) {
if(maxpen >= 256) {
fprintf(stderr,"Asking more than 256 colors for graffiti ?\n");
abort();
}
graffiti_SetRGB(maxpen, r>>24, g>>24, b>>24);
return maxpen++;
}
if(os39 && usepub) {
i = ObtainBestPen(CM,r,g,b,
OBP_Precision, PRECISION_EXACT,
OBP_FailIfBad, TRUE,
TAG_DONE);
if(i != -1) {
if(maxpen<256) pen[maxpen++] = i;
else i = -1;
}
return i;
}
r >>= 28; g >>= 28; b >>= 28;
colors = is_halfbrite?32:(1<<RP->BitMap->Depth);
/* private screen => standard allocation */
if(!usepub) {
if(maxpen >= colors) return -1; /* no more colors available */
SetRGB4(&S->ViewPort, maxpen, r, g, b);
return maxpen++;
}
/* public => find exact match */
crgb = (r<<8)|(g<<4)|b;
for(i=0; i<colors; i++ ) {
int rgb = GetRGB4(CM, i);
if(rgb == crgb) return i;
}
return -1;
}
/****************************************************************************/
/*
* free a color entry
*/
static void ReleaseColors(void)
{
if(os39 && usepub && CM)
while(maxpen>0) ReleasePen(CM, pen[--maxpen]);
else maxpen = 0;
}
/****************************************************************************/
static void DoSizeWindow(struct Window *W,int wi,int he)
{
register int x,y;
wi += W->BorderRight + W->BorderLeft;
he += W->BorderBottom + W->BorderTop;
x = W->LeftEdge;
y = W->TopEdge;
if(x + wi >= W->WScreen->Width) x = W->WScreen->Width - wi;
if(y + he >= W->WScreen->Height) y = W->WScreen->Height - he;
if(x<0 || y<0) {
fprintf(stderr, "Working screen too small to open window (%dx%d)!\n",
wi,he);
return;
}
x -= W->LeftEdge;
y -= W->TopEdge;
wi -= W->Width;
he -= W->Height;
if(x|y) MoveWindow(W,x,y);
if(wi|he) SizeWindow(W,wi,he);
}
/****************************************************************************/
/*
* support code for graffiti card
*/
static void graffiti_SetRGB(int i, int r, int g, int b)
{
UWORD **ptr = (void*)RP->BitMap->Planes;
*(*ptr++ + i) = 0x0406;
*(*ptr++ + i) = (i<<8)|((g>>2)&0x3f);
*(*ptr++ + i) = 0x0606;
*(*ptr + i) = ((r<<6)&0x3f00)|((b>>2)&0x3f);
}
/****************************************************************************/
static void graffiti_WritePixelLine8(int x, int y, short len, char *line)
{
#if 0
/* standard code */
char **ptr = (void*)RP->BitMap->Planes;
y += 8;
x += (y*80)<<2;
while(len--) {
*(ptr[x&3] + (x>>2)) = *line++;
++x;
}
#else
/* this one must be quite fast for 680x0 processor */
char **ptr;
char *ptr0,*ptr1,*ptr2,*ptr3;
ptr = (void*)RP->BitMap->Planes;
switch(x&3) {
case 0: ptr0=*ptr++; ptr1=*ptr++; ptr2=*ptr++; ptr3=*ptr; break;
case 1: ptr3=*ptr++ + 1; ptr0=*ptr++; ptr1=*ptr++; ptr2=*ptr; break;
case 2: ptr2=*ptr++ + 1; ptr3=*ptr++ + 1; ptr0=*ptr++; ptr1=*ptr; break;
default:
case 3: ptr1=*ptr++ + 1; ptr2=*ptr++ + 1; ptr3=*ptr++ + 1; ptr0=*ptr; break;
}
x >>= 2; x += (80*(y+8));
ptr0 += x; ptr1 += x; ptr2 += x; ptr3 += x;
++len;
/* full speed here */
while(1) {
if(--len) *ptr0++ = *line++; else break;
if(--len) *ptr1++ = *line++; else break;
if(--len) *ptr2++ = *line++; else break;
if(--len) *ptr3++ = *line++; else break;
}
#endif
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.