File:  [UNIX Amiga Emulator] / uae / src / md-amiga / ami-win.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:39:18 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, BSchmidt
CVS tags: uae068, HEAD
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
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.