/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "Licence").
 * You may not use this file except in compliance with the Licence.
 *
 * You can obtain a copy of the licence at RISC OS path @.^.LICENCE
 * or  http://www.riscosdev.com/lanman98/LICENCE.CDDL
 * See the Licence for the specific language governing permissions
 * and limitations under the Licence.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the Licence file. If applicable, add the
 * following below this CDDL HEADER, with the fields enclosed by
 * brackets "[]" replaced with your own identifying information:
 * Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
 
/*
 *   Portions Copyright 1996 Warm Silence Software Ltd.
 */

/******************************************************/
/*                                                    */
/* Name: PGmode.c                                     */
/* Author: Paul Gardiner.                             */
/*                                                    */ 
/******************************************************/

#include <stdlib.h>
#include <string.h>
#include "kernel.h"
#include "swis.h"
#include "PGmode.h"

static _kernel_swi_regs regs;

int ModeGet(void)
{
    int i;
    int *mspec, *mspec_copy;
    
    regs.r[0] = 135;
    _kernel_swi(OS_Byte, &regs, &regs);
    if(regs.r[2] & ~0xFF)
    {
        mspec = (int *) (regs.r[2]);
        for(i = 5; mspec[i] != -1; i++);
        i++;
        mspec_copy = malloc(i * sizeof(int));
        if(mspec_copy == 0)
            return (int) mspec;
        memcpy(mspec_copy, mspec, i * sizeof(int));
        return (int) mspec_copy;
    }
    else
    {
        return regs.r[2];
    }
}

void ModeSet(int mode)
{
    regs.r[0] = mode;
    _kernel_swi(Wimp_SetMode, &regs, &regs);
}

void ModeSetXYC(int x, int y, int c)
{
    int mode[6];
    
    mode[0] = 1;
    mode[1] = x;
    mode[2] = y;
    mode[3] = c;
    mode[4] = -1;
    mode[5] = -1;
    regs.r[0] = (int) mode;
    _kernel_swi(Wimp_SetMode, &regs, &regs);
}

int ModeValid(int mode)
{
    int res;
    
    regs.r[0] = mode;
    regs.r[1] = 0;
    _kernel_swi_c(OS_ReadModeVariable, &regs, &regs, &res);
    return !res;
}

int ModePossible(int mode)
{
    int res;
    
    regs.r[0] = mode;
    _kernel_swi_c(OS_CheckModeValid, &regs, &regs, &res);
    if(res)
        return regs.r[0] == -2;
    else
        return 1;
}

int ModePlanes(int mode)
{
    regs.r[0] = mode;
    regs.r[1] = 9;
    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
    return 1<<(regs.r[2]);
}

void ModeSize(int mode, int *x, int *y)
{
    regs.r[0] = mode;
    regs.r[1] = 11;
    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
    *x = regs.r[2] + 1;
    regs.r[1] = 12;
    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
    *y = regs.r[2] + 1;
}

void ModeEig(int mode, int *x, int *y)
{
    regs.r[0] = mode;
    regs.r[1] = 4;
    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
    *x = regs.r[2];
    regs.r[1] = 5;
    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
    *y = regs.r[2];
}

void ModeShadowOn(void)
{
    int required;
    
    regs.r[0] = -1;
    regs.r[1] = 7;
    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
    required = regs.r[2] * 2;
    regs.r[0] = 2;
    _kernel_swi(OS_ReadDynamicArea, &regs, &regs);
    required -= regs.r[1];
    regs.r[0] = 2;
    regs.r[1] = required;
    _kernel_swi(OS_ChangeDynamicArea, &regs, &regs);
    regs.r[0] = 113;
    regs.r[1] = 1;
    _kernel_swi(OS_Byte, &regs, &regs);
    regs.r[0] = 112;
    regs.r[1] = 2;
    _kernel_swi(OS_Byte, &regs, &regs);
}

void ModeShadowOff(void)
{
    int required;
    
    regs.r[0] = -1;
    regs.r[1] = 7;
    _kernel_swi(OS_ReadModeVariable, &regs, &regs);
    required = regs.r[2];
    regs.r[0] = 2;
    _kernel_swi(OS_ReadDynamicArea, &regs, &regs);
    required -= regs.r[1];
    regs.r[0] = 2;
    regs.r[1] = required;
    _kernel_swi(OS_ChangeDynamicArea, &regs, &regs);
    regs.r[0] = 113;
    regs.r[1] = 1;
    _kernel_swi(OS_Byte, &regs, &regs);
    regs.r[0] = 112;
    regs.r[1] = 1;
    _kernel_swi(OS_Byte, &regs, &regs);
}

void ModeSwapBank(void)
{
    int read, write;
    
    regs.r[0] = 250;
    regs.r[1] = 0;
    regs.r[2] = 255;
    _kernel_swi(OS_Byte, &regs, &regs);
    write = regs.r[1];
    read = regs.r[2];
    regs.r[0] = 113;
    regs.r[1] = write;
    _kernel_swi(OS_Byte, &regs, &regs);
    regs.r[0] = 112;
    regs.r[1] = read;
    _kernel_swi(OS_Byte, &regs, &regs);
}
