view exporters.pde @ 197:4bdb6d0df3ca

Oops, wrong variable name.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 23 Aug 2018 20:42:39 +0300
parents 5c08f024e542
children 823672f83ae9
line wrap: on
line source

//
// machine definitions
// source writer and other export/import functions
// remember hexdump -C !
//


public class MPWriteCtx
{
    public int m_offs, m_bpl, m_bytes, m_indent, m_state, m_intmode;
    public String m_byteDef, m_eol, m_src, m_prefix;
    public byte[] m_data;

    MPWriteCtx()
    {
        m_offs = 0;
        m_data = new byte[1*1024];

        setBPLOff();
        m_bytes = 0;
        m_state = -1;

        m_indent = 4;

        m_byteDef = ".byte";
        m_src = "";
        m_eol = "\n";

        m_intmode = 0;
        m_prefix = "";
    }

    void setOffs(int offs)
    {
        m_offs = offs;
    }

    void setBPL(int bpl)
    {
        m_bpl = bpl;
    }

    void setBPLOff()
    {
        m_bpl = -1;
    }

    void loadTemplate(String fname)
    {
        m_data = mpLoadBinaryFile("templates/" + fname);
    }

    byte[] getData()
    {
        return m_data;
    }

    byte[] getSource()
    {
        return m_src;
    }

    String getHexValue(int dval, int dlen)
    {
        static final String mpHexChars[16] = "0123456789abcdef";
        char[] dstr = new char[dlen];

        for (i = dlen - 1; i >= 0; i--)
        {
            dstr[i] = mpHexChars[dval & 0x0f];
            dval >>= 4;
        }

        return dstr.join('');
    }

    String getByteStr(int val)
    {
        switch (m_intmode)
        {
            case 0: return str(val & 0xff);
            case 1: return "$"+ getHexValue(val & 0xff, 2);
            case 2: return getHexValue(val & 0xff, 2) +"h";
        }
    }

    void addIndent()
    {
        for (int n = 0; n < m_indent; n++)
            m_src += " ";
    }

    void addByteSep()
    {
        m_src += ",";
    }

    void addEOL()
    {
        m_state = 4;
        m_src += m_eol;
    }

    void addByteDef(boolean force)
    {
        if (m_state != 2 || force)
        {
            m_src += m_eol;
            addIndent();
        }

        m_src += m_byteDef +" ";
        m_bytes = 0;
        m_state = 2;
    }

    void addLabel(String blabel, boolean nl)
    {
        if (m_state != 3)
            addEOL();

        m_src += m_prefix + blabel +":"+ (nl ? " " : "");
        m_state = 3;
    }

    void addComment(String bstr)
    {
        if (m_state != 4)
            addEOL();

        m_src += "; "+ bstr + m_eol;
        m_state = 4;
    }

    void addLine(String bstr)
    {
        if (m_state != 4)
            addEOL();

        m_src += bstr.replace("@@", m_prefix) + m_eol;
        m_state = 4;
    }

    void writeByte(int bval, String blabel)
    {
        m_data[m_offs++] = byte(bval);

        if (blabel != null)
        {
            addLabel(blabel, true);
            m_state = 2;
            addByteDef(false);
            m_src += getByteStr(bval);
            m_src += m_eol;
        }
        else
        {
            if (m_state != 2)
                addByteDef(true);
            else
            if (m_bpl > 0 && m_bytes >= m_bpl)
                addByteDef(true);

            if (m_bytes++ > 0)
                addByteSep();

            m_src += getByteStr(bval);
        }
    }

    void writeByteAt(int boffs, int bval, String blabel)
    {
        m_offs = boffs;
        writeByte(bval, blabel);
    }
}


void mpCopyByte(byte[] fdata, int moffs, int toffs)
{
    g_map[moffs    ] = byte((fdata[toffs] & 128) >> 7);
    g_map[moffs + 1] = byte((fdata[toffs] & 64) >> 6);
    g_map[moffs + 2] = byte((fdata[toffs] & 32) >> 5);
    g_map[moffs + 3] = byte((fdata[toffs] & 16) >> 4);
    g_map[moffs + 4] = byte((fdata[toffs] & 8) >> 3);
    g_map[moffs + 5] = byte((fdata[toffs] & 4) >> 2);
    g_map[moffs + 6] = byte((fdata[toffs] & 2) >> 1);
    g_map[moffs + 7] = byte( fdata[toffs] & 1);
}


boolean mpImportFormat(byte[] fdata)
{
    int x, y, x2, y2, y3, head, xx, yy, yp, ad, valu;
    int p1, p2, p3;

    head = 0;

    if (g_machine == SPECTRUM) //SCR=SCREEN$
    {
        // 32*24*8 bytes of bitmap
        // 32*24 bytes of attributes
        if (fdata.length < 6912) {
            return false;
        }
        for (y = 0; y < 3; y++)
        for (y2 = 0; y2 < 8; y2++)
        for (yy = 0; yy < 8; yy++)
        for (x = 0; x < 32; x++)
        {
            yp = y * 64 + yy * 8 + y2;
            ad = 1024 + yp * 256 + x * 8;
            mpCopyByte(fdata, ad, head);
            head++;
        }

        for (y = 0; y < 24; y++)
        for (x = 0; x < 32; x++)
        {
            ad = 65536 + x + y * (32 * 8);
            valu = fdata[head];
            int bri = (valu >> 6) & 1;
            int ink = (valu & 7) + bri * 8;
            int pap = ((valu >> 3) & 7) + bri * 8;
            if (pap == 8)
                pap = 0;

            for (y2 = 0; y2 < 8; y2++)
            {
                g_map[ad + y2 * 32] = byte(ink);
                g_map[ad + y2 * 32 + MX * MY * 8] = byte(pap);
            }
            head++;
        }
    }
    else
    if (g_machine == C64) {
        //0x0002->bitmap
        //0x1f42->colormap
        //0x232a=border (take the lower nybble)
        if (fdata.length < 9006) {
            return false;
        }
        if (fdata.length >= 0x232a) {
            g_map[0] = byte(fdata[0x232a] & 0x0f);
        }
        for (y = 0; y < 25; y++)
        for (x = 0; x < 40; x++)
        for (y2 = 0; y2 < 8; y2++)
        {
            head = 2 + x * 8 + y * (40 * 8) + y2;
            ad = 1024 + x * 8 + y * (320 * 8) + y2 * 320;
            mpCopyByte(fdata, ad, head);
            p1 = fdata[0x1f42 + x + y * 40] & 0x0f;
            p2 = (fdata[0x1f42 + x + y * 40] >> 4) & 0x0f;

            g_map[65536 + x + y * 40 * 8 + y2 * 40] = byte(p2);
            g_map[65536 + MX * MY * 8 + x + y * 40 * 8 + y2 * 40] = byte(p1);
        }
    }
    else
    if (g_machine == PLUS4) { // Botticelli
        //g.hires.prg = botticelli
        //2 - luminance 40*25
        //1026 - colors 40*25
        //2050 - bitmappi 40*25*8
        if (fdata.length < 10050) {
            return false;
        }
        int l1, l2;
        for (y = 0; y < 25; y++)
        for (x = 0; x < 40; x++)
        for (y2 = 0; y2 < 8; y2++)
        {
            head = 2050 + x * 8 + y * (40 * 8) + y2;
            ad = 1024 + x * 8 + y * (320 * 8) + y2 * 320;
            mpCopyByte(fdata, ad, head);

            p1 = fdata[1026 + x + y * 40] & 0x0f;
            p2 = (fdata[1026 + x + y * 40] >> 4) & 0x0f;
            l1 = fdata[2 + x + y * 40] & 0x0f;
            l2 = (fdata[2 + x + y * 40] >> 4) & 0x0f;

            g_map[65536 + x + y * 40 * 8 + y2 * 40] = byte(convertluminance(l1, p2));
            g_map[65536 + MX * MY * 8 + x + y * 40 * 8 + y2 * 40] = byte(convertluminance(l2, p1));
        }
    }
    else
    if (g_machine == PLUS4M) { // Multi Botticelli
        //m.multi.prg = multi botticelli
        //2- lumins 40*25
        //1024 - bäkki1
        //1025 - bäkki2
        //1026 - colors 40*25
        //2050 - bitmap 40*25*8
        if (fdata.length < 10050) {
            return false;
        }
        int l1, l2;
        for (y = 0; y < 25; y++)
        for (x = 0; x < 40; x++)
        for (y2 = 0; y2 < 8; y2++)
        {
            head = 2050 + x * 8 + y * (40 * 8) + y2;
            ad = 1024 + x * 8 + y * (320 * 8) + y2 * 320;
            mpCopyByte(fdata, ad, head);

            p1 = fdata[1026 + x + y * 40] & 0x0f;
            p2 = (fdata[1026 + x + y * 40] >> 4) & 0x0f;
            l1 = fdata[2 + x + y * 40] & 0x0f;
            l2 = (fdata[2 + x + y * 40] >> 4) & 0x0f;

            g_map[65536 + x + y * 40 + 1000] = byte(convertluminance(l1, p2));
            g_map[65536 + x + y * 40 + 0000] = byte(convertluminance(l2, p1));
        }

        p1 = (int(fdata[1025]) >> 4) & 0x0f;
        l1 = int(fdata[1025]) & 0x0f;
        g_map[1] = byte(convertluminance(l1, p1));

        p1 = (int(fdata[1024]) >> 4) & 0x0f;
        l1 = int(fdata[1024]) & 0x0f;
        g_map[2] = byte(convertluminance(l1, p1));
    }
    else
    if (g_machine == C64M) { //advanced art studio
        //adv. art studio (=multicolor) 10018 bytes
        //0x0002 bitmap (40*25*8)
        //0x1f42 colors1 (40*25)
        //0x232a border
        //0x232b background
        //0x233a colors2 (40*25)
        if (fdata.length < 10018) {
            return false;
        }
        for (y = 0; y < 25; y++)
        for (x = 0; x < 40; x++)
        for (y2 = 0; y2 < 8; y2++)
        {
            ad = 1024 + x * 8 + y * (320 * 8) + y2 * 320;
            head = 2 + x * 8 + y * (40 * 8) + y2;
            mpCopyByte(fdata, ad, head);

            p1 = fdata[0x1f42 + x + y * 40] & 0x0f;
            p2 = (fdata[0x1f42 + x + y * 40] >> 4) & 0x0f;
            p3 = fdata[0x233a + x + y * 40] & 0x0f;

            g_map[65536 + x + y * 40] = byte(p1);
            g_map[65536 + x + y * 40 + 1000] = byte(p2);
            g_map[65536 + x + y * 40 + 2000] = byte(p3);
        }
        g_map[0] = byte(fdata[0x232a] & 0x0f); //bord
        g_map[1] = byte(fdata[0x232b] & 0x0f); //baku
    }
    else
    if (g_machine == MSX) { // sc2
        // 7=bitmap 32*24*8
        // 7+(32*24*8)=colormap 32*24
        if (fdata.length < 14343) {
            return false;
        }
        for (y = 0; y < 24; y++)
        for (x = 0; x < 32; x++)
        for (y2 = 0; y2 < 8; y2++)
        {
            head = 7 + x * 8 + y * (32 * 8) + y2;
            ad = 1024 + x * 8 + y * (256 * 8) + y2 * 256;
            mpCopyByte(fdata, ad, head);
            p1 = fdata[(8199) + x * 8 + ((y * 8 * 32) + y2)] & 0x0f;
            p2 = (fdata[(8199) + x * 8 + ((y * 8 * 32) + y2)] >> 4) & 0x0f;

            if (p1 == 0)
                p1 = 1;
            if (p2 == 0)
                p2 = 1;

            g_map[65536 + x + y * 32 * 8 + y2 * 32] = byte(p2);
            g_map[65536 + MX * MY * 8 + x + y * 32 * 8 + y2 * 32] = byte(p1);
        }
    }
    else
    if (g_machine == CPC) { // a studio?
        return false;
    }

    consistency();
    refresh();
    g_boxreconstruct = 2;
    return true;
}


boolean mpExportFormat(MPWriteCtx ctx, int subformat)
{
    int val1, val2, val3;
    int y, y2, yy, x, yp, xp, ad, valu, valu2, bri;

    if (g_machine == PLUS4) { // botticelli hires
        ctx.loadTemplate("g.hires.prg");

        ctx.setOffs(0x02);
        mpExportColorData(ctx, 40, 25, 65536, 5); //lumis

        ctx.setOffs(1026);
        mpExportColorData(ctx, 40, 25, 65536, 4); //colors

        ctx.setOffs(2050);
        mpExportBitmapData(ctx, 40, 25);
    }
    else
    if (g_machine == PLUS4M) { // multi botticelli multicolor
        ctx.loadTemplate("m.multi.prg");

        val2 = getpluscolor(int(g_map[1]));
        val1 = getplusluminance(int(g_map[1]));
        val3 = val2 * 16 + val1;
        ctx.writeByteAt(1025, val3);

        val2 = getpluscolor(int(g_map[2]));
        val1 = getplusluminance(int(g_map[2]));
        val3 = val2 * 16 + val1;
        ctx.writeByteAt(1024, val3);

        ctx.setOffs(1026);
        mpExportColorData(ctx, 40, 25, 65536, 6); //colors

        ctx.setOffs(2);
        mpExportColorData(ctx, 40, 25, 65536, 7); //lumis

        ctx.setOffs(2050);
        mpExportBitmapData(ctx, 40, 25);
    }
    else
    if (g_machine == C64) {
        ctx.loadTemplate("hires.art");

        ctx.setOffs(2);
        mpExportBitmapData(ctx, 40, 25);

        ctx.setOffs(0x1f42);
        mpExportColorData(ctx, 40, 25, 65536, 0);

        ctx.writeByteAt(0x232a, g_map[0]);
    }
    else
    if (g_machine == C64M) {
        if (subformat == 0)
        {
            // Advanced Art Studio
            ctx.loadTemplate("multic.ocp");

            ctx.setOffs(2);
            mpExportBitmapData(ctx, 40, 25);

            ctx.setOffs(0x1f42);
            mpExportColorData(ctx, 40, 25, 65536, 1);

            ctx.setOffs(0x233a);
            mpExportColorData(ctx, 40, 25, 65536 + 2000, 2);

            ctx.writeByteAt(0x232a, g_map[0]);
            ctx.writeByteAt(0x232b, g_map[1]);
        }
        else
        {
            // Koala Painter
            ctx.loadTemplate("multic.kla");

            ctx.setOffs(2);
            mpExportBitmapData(ctx, 40, 25);

            ctx.setOffs(0x1f42);
            mpExportColorData(ctx, 40, 25, 65536, 1);

            ctx.setOffs(0x232a);
            mpExportColorData(ctx, 40, 25, 65536 + 2000, 2);

            ctx.writeByteAt(0x2712, g_map[1] & 0x0f);
        }
    }
    else
    if (g_machine == MSX) {
        ctx.loadTemplate("msx-screen2.sc2");

        ctx.setOffs(7);
        mpExportBitmapData(ctx, 32, 24);

        ctx.setOffs(7 + (32 * 24 * 8) + 768 + 1280);
        mpExportColorData(ctx, 32, 24, 65536, 3); //there's an exception for msx-style
    }
    else
    if (g_machine == SPECTRUM) {
        ctx.loadTemplate("zx-screen.scr");

        ctx.setOffs(0);
        for (y = 0; y < 3; y++)
        for (y2 = 0; y2 < 8; y2++)
        for (yy = 0; yy < 8; yy++)
        for (x = 0; x < 32; x++)
        {
            yp = y * 64 + yy * 8 + y2;
            ad = 1024 + yp * 256 + x * 8;

            valu = g_map[ad + 0] * 128 +
                   g_map[ad + 1] * 64 +
                   g_map[ad + 2] * 32 +
                   g_map[ad + 3] * 16 +
                   g_map[ad + 4] * 8 +
                   g_map[ad + 5] * 4 +
                   g_map[ad + 6] * 2 +
                   g_map[ad + 7] * 1;

            ctx.writeByte(valu);
        }

        for (y = 0; y < 24; y++)
        for (x = 0; x <= 31; x++)
        {
            ad = 65536 + x + y * 256;
            valu = int(g_map[ad]);
            valu2 = int(g_map[ad + MX * MY * 8]);
            bri = 0;
            if (valu >= 8) {
                bri = 1;
                valu = valu - 8;
                valu2 = valu2 - 8;
                if (valu2 <= 0) {
                    valu2 = 0;
                }
            }
            if (bri == 1) {
                valu += 64;
            }
            ctx.writeByte(valu + valu2 * 8);
        }
    }
    else
        return false;

    return true;
}


boolean mpExportMachinePRG(MPWriteCtx ctx)
{
    // any common text headers
    ctx.addComment("g_machine=" + str(g_machine) + " (" + g_name + ")");

    if (g_machine == C64) { //C64 HIRES
        ctx.loadTemplate("c64show.prg");

        ctx.setOffs(0x0227);
        ctx.addLabel("_bitmap");
        mpExportBitmapData(ctx, 40, 25);

        ctx.writeByteAt(0x2167, g_map[0], "_border"); //=border
        ctx.writeByteAt(0x2168, g_map[1], "_backg"); //=background mutta ei tarvita

        ctx.setOffs(0x2169);
        ctx.addLabel("_screenram");
        mpExportColorData(ctx, 40, 25, 65536, 0);

        //c64show.prg
        //offsets
        //0x0227->bitmappi (40x25 x 8 bytee)
        //0x2167:borderi väri
        //0x2169->värikartta (40x25 bytee, nyppelit foreg/backg)
    }
    else
    if (g_machine == C64M) { //C64 MULTICOLOR
        ctx.loadTemplate("c64mshow.prg");

        ctx.setOffs(0x0239);
        ctx.addLabel("_bitmap");
        mpExportBitmapData(ctx, 40, 25);

        // first color information
        ctx.writeByteAt(0x2179, g_map[0], "_border");
        ctx.writeByteAt(0x217a, g_map[1], "_backg");

        ctx.setOffs(0x217B);
        ctx.addLabel("_screenram");
        mpExportColorData(ctx, 40, 25, 65536, 1);

        // second color information
        ctx.setOffs(0x2563);
        ctx.addLabel("_colorram");
        mpExportColorData(ctx, 40, 25, 65536 + 2000, 2);

        //c64 multicolor
        //offsets
        //0x0239->bitmappi (40x25 x 8 bytee)
        //0x2179:borderi väri
        //0x217A:bäkkis väri
        //0x217B->värikartta 1 (40x25 bytee, nyppelit foreg/backg ilmeisesti)
        //0x2563->värikartta 2 (40x25 bytee, nyppeli 3-väri nepan osoitteessa $d800-)
    }
    else
    if (g_machine == PLUS4M) { //PLUS4 MULTICOLOR
        ctx.loadTemplate("showpfourm.prg");

        ctx.addLine(".global @@_bitmap");
        ctx.addLine(".global @@_color1");
        ctx.addLine(".global @@_color2");
        ctx.addLine(".global @@_border");
        ctx.addLine(".global @@_back1");
        ctx.addLine(".global @@_back2");

        ctx.addLabel("_bitmap");
        ctx.setOffs(0x013e);
        mpExportBitmapData(ctx, 40, 25);

        val1 = getpluscolor(int(g_map[0]));
        val2 = getplusluminance(int(g_map[0]));
        val3 = val2 * 16 + val1;
        ctx.addLabel("_border");
        ctx.setOffs(0x207e);
        ctx.writeByte(val3);

        val1 = getpluscolor(int(g_map[1]));
        val2 = getplusluminance(int(g_map[1]));
        val3 = val2 * 16 + val1;
        ctx.addLabel("_back1");
        ctx.setOffs(0x207f);
        ctx.writeByte(val3);

        val1 = getpluscolor(int(g_map[2]));
        val2 = getplusluminance(int(g_map[2]));
        val3 = val2 * 16 + val1;
        ctx.addLabel("_back2");
        ctx.setOffs(0x2080);
        ctx.writeByte(val3);

        ctx.addLabel("_color1");
        ctx.setOffs(0x2081);
        mpExportColorData(ctx, 40, 25, 65536, 6);

        ctx.addLabel("_color2");
        ctx.setOffs(0x2469);
        mpExportColorData(ctx, 40, 25, 65536, 7);

        //plus4 multic
        //0x013e bitmap (40 x 25 x 8)
        //0x207e border
        //0x207f background 1
        //0x2080 background 2
        //0x2081 colors (40 x 25)
        //0x2469 luminance (40 x 25)
    }
    else
    if (g_machine == PLUS4) { // Plus 4 hires
        ctx.loadTemplate("showpfour.prg");

        ctx.addLine(".global @@_bitmap");
        ctx.addLine(".global @@_color");
        ctx.addLine(".global @@_lumi");
        ctx.addLine(".global @@_border");

        ctx.setOffs(0x0137);
        ctx.addLabel("_bitmap");
        mpExportBitmapData(ctx, 40, 25);

        val1 = getpluscolor(int(g_map[0]));
        val2 = getplusluminance(int(g_map[0]));
        val3 = val2 * 16 + val1;
        ctx.writeByteAt(0x2077, val3, "_border"); //border

        ctx.setOffs(0x2078);
        ctx.addLabel("_color");
        mpExportColorData(ctx, 40, 25, 65536, 4); //colors

        ctx.setOffs(0x2460);
        ctx.addLabel("_lumi");
        mpExportColorData(ctx, 40, 25, 65536, 5); //lumis

        //plus4 hires
        //0x0137   bitmap (40 x 25 x 8)
        //0x2077   borderi
        //0x2078   colors (40 x 25)
        //0x2460   luminance (40 x 25)
    }
    else
    if (g_machine == MSX) { // MSX
        ctx.loadTemplate("msxshow.com");

        ctx.addLine(".globl @@_bitmap,@@_nimi2");
        ctx.addLine(".area _CODE");

        ctx.setOffs(0x00f9);
        ctx.addLabel("_bitmap");
        mpExportBitmapData(ctx, 32, 24);


        //ctx.writeByte(g_map[1]); //backg
        //ctx.addComment("The first following value is background");
        ctx.addLabel("_nimi2");
        ctx.setOffs(0x18f9);
        mpExportColorData(ctx, 32, 24, 65536, 3); //there's an exception for msx-style

        //msx comm
        //0x00f9 bitmap (32x24 x 8 bytes)
        //0x18f9 background color
        //0x18fa colors (32*24 bytes)
    }
    else
    if (g_machine == SPECTRUM) { // ZX Spectrum

        //would need some cleaning up

        //  ctx.addLine(".area  _DATA");
        //  ctx.addLine(".globl @@_taustakuva");
        //  ctx.addLabel("_taustakuva");
        ctx.loadTemplate("specshow.tap");

        int checksum = 0xc9;
        for (y = 0x1d24; y < 0x1d3e; y++)
        {
            checksum = checksum ^ int(g_template[y]);
        }

        //TAP requires fiddling with the checksum
        //println("Checksum:"+hex(checksum,2));
        ctx.writeByteAt(0x0223, g_map[0], "_something1");
        checksum = checksum ^ int(g_map[0]);

        ctx.addLabel("_something2");
        ctx.setBPL(32);
        for (int y = 0; y <= 2; y++)
        for (int y2 = 0; y2 < 8; y2++)
        for (int yy = 0; yy < 8; yy++)
        for (int x = 0; x < 32; x++)
        {
            int yp = y * 64 + yy * 8 + y2,
                ad = 1024 + yp * 256 + x * 8,
                valu =
                    g_map[ad + 0] * 128 +
                    g_map[ad + 1] * 64 +
                    g_map[ad + 2] * 32 +
                    g_map[ad + 3] * 16 +
                    g_map[ad + 4] * 8 +
                    g_map[ad + 5] * 4 +
                    g_map[ad + 6] * 2 +
                    g_map[ad + 7] * 1;

            ctx.writeByte(valu);
            checksum = checksum ^ int(valu);
        }

        ctx.addLabel("_attributes");
        for (int y = 0; y < 24; y++)
        for (int x = 0; x < 32; x++)
        {
            int ad = 65536 + x + y * 256,
                valu = int(g_map[ad]),
                valu2 = int(g_map[ad + MX * MY * 8]),
                bri = 0;

            if (valu >= 8)
            {
                bri = 1;
                valu = valu - 8;
                valu2 = valu2 - 8;
                if (valu2 <= 0) {
                    valu2 = 0;
                }
            }
            if (bri == 1) {
                valu = valu + 64;
            }

            ctx.writeByte(valu + valu2 * 8);
            checksum = checksum ^ int(valu + valu2 * 8);
        }
        ctx.setBPLOff();

        ctx.writeByteAt(0x1d3e, int(checksum), "_checksum");
    }
    else
    if (g_machine == CPC) {
        int val1, val2, val3, valu;
        ctx.loadTemplate("cpc-mode0.bin");

        ctx.setOffs(69); //bitmap offset
        ctx.addLabel("_bitmap");
        mpExportBitmapData_CPC(ctx, 160, 200);

        //fixed # of palette entries, just trying to be generic
        ctx.setOffs(16453);
        ctx.setBPL(32);
        ctx.addLabel("_palette");
        for (int i = 0; i < g_maxcolors; i++)
        {
            val1 = int(g_g[i] / (256 / g_palsteps));
            val2 = int(g_r[i] / (256 / g_palsteps));
            val3 = int(g_b[i] / (256 / g_palsteps));

            ctx.writeByte(val1 * 9 + val2 * 3 + val3);
        }
        ctx.setBPLOff();

        valu = int(g_map[0]);
        val1 = int(g_g[valu] / (256 / g_palsteps));
        val2 = int(g_r[valu] / (256 / g_palsteps));
        val3 = int(g_b[valu] / (256 / g_palsteps));

        ctx.setOffs(16469);
        ctx.addLabel("_border");
        ctx.writeByte(val1 * 9 + val2 * 3 + val3);

        //cpc
        //69    bitmap 16384 bytes
        //16453 palette 16 bytes (0..26)
        //16469 border color (0..26)
    }
    else
        return false;

    ctx.addEOL();
    return true;
}


void mpExportBitmapData_CPC(MPWriteCtx ctx, int mwidth, int mheight)
{
    int x, y, ad, val1, val2, y2;
    int pix0b0, pix0b1, pix0b2, pix0b3;
    int pix1b0, pix1b1, pix1b2, pix1b3;

    ctx.setBPL(32);

    for (y2 = 0; y2 < 8; y2++)
    {
        ctx.addByteDef(true);

        for (y = 0; y < int(mheight / 8); y++)
        for (x = 0; x < int(mwidth / 2); x++)
        {
            ad = 1024 + (y * 8) * X + (y2 * X) + x * 4;

            val1 = int(g_map[ad]);
            pix0b0 = 0;
            pix0b1 = 0;
            pix0b2 = 0;
            pix0b3 = 0;
            if ((val1 & 1) != 0) pix0b0 = 1;
            if ((val1 & 2) != 0) pix0b1 = 1;
            if ((val1 & 4) != 0) pix0b2 = 1;
            if ((val1 & 8) != 0) pix0b3 = 1;

            val1 = int(g_map[ad + 2]);

            pix1b0 = 0;
            pix1b1 = 0;
            pix1b2 = 0;
            pix1b3 = 0;
            if ((val1 & 1) != 0) pix1b0 = 1;
            if ((val1 & 2) != 0) pix1b1 = 1;
            if ((val1 & 4) != 0) pix1b2 = 1;
            if ((val1 & 8) != 0) pix1b3 = 1;

            val2 = pix1b3 + pix0b3 * 2 + pix1b1 * 4 + pix0b1 * 8 + pix1b2 * 16 + pix0b2 * 32 + pix1b0 * 64 + pix0b0 * 128;

            ctx.writeByte(val2);
        }

        ctx.addByteDef(true);
        for (int j = 0; j <= 47; j++)
            ctx.writeByte(0);
    }

    ctx.setBPLOff();
    ctx.addEOL();
}


void mpExportBitmapData(MPWriteCtx ctx, int mwidth, int mheight)
{
    int xwid = mwidth * 8,
        ywid = mheight * 8;

    ctx.setBPL(32);
    ctx.addByteDef(true);

    for (int y = 0; y < mheight; y++)
    for (int x = 0; x < mwidth; x++)
    for (int y2 = 0; y2 < 8; y2++)
    {
        int ad = 1024 + y * (xwid * 8) + (y2 * xwid) + x * 8;
        int value =
            g_map[ad + 0] * 128 +
            g_map[ad + 1] * 64 +
            g_map[ad + 2] * 32 +
            g_map[ad + 3] * 16 +
            g_map[ad + 4] * 8 +
            g_map[ad + 5] * 4 +
            g_map[ad + 6] * 2 +
            g_map[ad + 7] * 1;

        ctx.writeByte(value);
    }

    ctx.setBPLOff();
    ctx.addEOL();
}


int convertluminance(int l, int f)
{
    int res = 0;
    if (f == 0) return 0;
    if (l == 0) res = 0 + f;
    if (l == 1) res = 15 + f;
    if (l == 2) res = 30 + f;
    if (l == 3) res = 45 + f;
    if (l == 4) res = 60 + f;
    if (l == 5) res = 75 + f;
    if (l == 6) res = 90 + f;
    if (l == 7) res = 105 + f;
    return res;
}


int getplusluminance(int c)
{
    int res = 0;
    if (c == 0) res = 0;
    if (c >= 1 && c <= 15) res = 0;
    if (c >= 16 && c <= 30) res = 1;
    if (c >= 31 && c <= 45) res = 2;
    if (c >= 46 && c <= 60) res = 3;
    if (c >= 61 && c <= 75) res = 4;
    if (c >= 76 && c <= 90) res = 5;
    if (c >= 91 && c <= 105) res = 6;
    if (c >= 106 && c <= 120) res = 7;
    return res;
}


int getpluscolor(int c)
{
    int res = 0;
    if (c == 0) res = 0;
    if (c >= 1 && c <= 15) res = c;
    if (c >= 16 && c <= 30) res = c - 15;
    if (c >= 31 && c <= 45) res = c - 30;
    if (c >= 46 && c <= 60) res = c - 45;
    if (c >= 61 && c <= 75) res = c - 60;
    if (c >= 76 && c <= 90) res = c - 75;
    if (c >= 91 && c <= 105) res = c - 90;
    if (c >= 106 && c <= 120) res = c - 105;
    return res;
}


void mpExportColorData(MPWriteCtx ctx, int width, int height, int srcoffs, int param)
{
    int xmult, myrpsi;

    myrpsi = 0;

    if (param == 0 || param == 3 || param == 4 || param == 5)
        xmult = width * 8;
    else
        xmult = width;

    if (g_machine == MSX) {
        myrpsi = 7;
    }

    for (int yc = 0; yc < height; yc++)
    {
        ctx.addByteDef(true);
        for (int xc = 0; xc < width; xc++)
        for (int yline = 0; yline <= myrpsi; yline++)
        {
            int valu1, valu2, ad = srcoffs + xc + yc * xmult + yline * width;

            switch (param)
            {
                case 0:
                    valu1 = int(g_map[ad]);
                    valu2 = int(g_map[ad + MX * MY * 8]);
                    break;

                case 1:
                    valu2 = int(g_map[ad]);
                    valu1 = int(g_map[ad + 1000]);
                    break;

                case 2:
                    valu2 = int(g_map[ad]);
                    valu1 = 0;
                    break;

                case 3:
                    valu1 = int(g_map[ad]);
                    valu2 = int(g_map[ad + MX * MY * 8]);
                    break;

                case 4:
                    //plus4 colortable
                    valu1 = getpluscolor(int(g_map[ad]));
                    valu2 = getpluscolor(int(g_map[ad + MX * MY * 8]));
                    break;

                case 5:
                    //plus4 lumitable
                    valu1 = getplusluminance(int(g_map[ad + MX * MY * 8]));
                    valu2 = getplusluminance(int(g_map[ad]));
                    break;

                case 6:
                    //plus4 multic1
                    valu2 = getpluscolor(int(g_map[ad]));
                    valu1 = getpluscolor(int(g_map[ad + 1000]));
                    break;

                case 7:
                    //plus4 multic2
                    valu1 = getplusluminance(int(g_map[ad]));
                    valu2 = getplusluminance(int(g_map[ad + 1000]));
                    break;

                default:
                    return null;
            }

            ctx.writeByte(valu1 * 16 + valu2);
        }
    }
    ctx.addEOL();
}


boolean mpImportFromImage(PImage image)
{
    if (image == null)
        return false;

    if (image.width <= 16 || image.height <= 16)
        return false;

    int balx, baly, xx, yy, x2, y2, rr, gg, bb, avg, i, j, target;
    int cx, cy;
    int swap, idefix, avx, avy;
    int[] pixut = new int[260];
    int[] idx = new int[260];
    int[] histog = new int[8192];
    float ww, hh, fld, compa;
    color c;
    int xcolors, limitter, vertti, erkki;
    int rh, gh, bh;

    xcolors = g_maxcolors;
    vertti = 8;
    erkki = 1;
    limitter = 2;
    if (g_britemode == 1) {
        xcolors = 8;
    }
    if (g_attrimode == 0) {
        vertti = 1;
        erkki = 8;
    }
    if (g_multic == 1)
        limitter = 4;
    else
    //because zero color can be anywhere?
    if (g_multic == 2)
        limitter = 16;

    command(int('O')); //special clear screen

    balx = int(image.width / X) * g_pixelw;
    baly = int(image.height / Y);
    if (balx < 1)
        balx = 1;
    if (baly < 1)
        baly = 1;

    if (g_palsteps > 0)
    {
        int psteps = int(g_palsteps - 1),
            maxhis = 0,
            palls = int(255 / psteps);

        for (i = 0; i < g_maxcolors; i++)
            makecolor(i, 0, 0, 0);

        for (cy = 0; cy < MY * erkki; cy++)
        for (cx = 0; cx < MX; cx++)
        for (yy = cy * vertti; yy <= cy * vertti + vertti - 1; yy++)
        for (xx = cx * 8; xx <= cx * 8 + 7; xx = xx + g_pixelw)
        {
            x2 = int(image.width / X) * xx;
            y2 = int(image.height / Y) * yy;
            rr = 0;
            gg = 0;
            bb = 0;
            avg = 0;

            for (avy = 0; avy < baly; avy++)
            for (avx = 0; avx < balx; avx++)
            {
                c = image.get(x2 + avx, y2 + avy);
                rr = rr + int(red(c));
                gg = gg + int(green(c));
                bb = bb + int(blue(c));
                avg++;
            }

            rh = int(int(rr / avg) / palls);
            gh = int(int(gg / avg) / palls);
            bh = int(int(bb / avg) / palls);

            int hindex = int(rh * (g_palsteps * g_palsteps) + gh * (g_palsteps) + bh);
            if (++histog[hindex] > maxhis)
                maxhis = histog[hindex];
        }

        int step = 0;
        for (j = maxhis; j > 0; j--)
        for (i = 0; i <= 4096; i++)
        {
            if (histog[i] == j)
            {
                rh = i / int(g_palsteps * g_palsteps);
                gh = i - int(rh * (g_palsteps * g_palsteps));
                gh = gh / int(g_palsteps);
                bh = i - int(rh * (g_palsteps * g_palsteps));
                bh = bh - int(gh * g_palsteps);
                rh = rh * int(palls);
                gh = gh * int(palls);
                bh = bh * int(palls);
                if (step < g_maxcolors)
                {
                    makecolor(step, rh, gh, bh);
                    step++;
                }
            }
        }
    }

    for (cy = 0; cy < MY * erkki; cy++)
    for (cx = 0; cx < MX; cx++)
    {
        for (i = 0; i < xcolors; i++)
        {
            pixut[i] = 0;
            idx[i] = i;
        }
        for (yy = cy * vertti; yy <= cy * vertti + vertti - 1; yy++)
        for (xx = cx * 8; xx <= cx * 8 + 7; xx = xx + g_pixelw)
        {
            x2 = int(image.width / X) * xx;
            y2 = int(image.height / Y) * yy;
            rr = 0;
            gg = 0;
            bb = 0;
            avg = 0;

            for (avy = 0; avy < baly; avy++)
            for (avx = 0; avx < balx; avx++)
            {
                c = image.get(x2 + avx, y2 + avy);
                rr += int(red(c));
                gg += int(green(c));
                bb += int(blue(c));
                avg++;
            }

            rr = int(rr / avg);
            gg = int(gg / avg);
            bb = int(bb / avg);
            g_farge = 0;
            target = -1;
            compa = 9999;
            for (i = 0; i < xcolors; i++)
            {
                fld = dist(rr, gg, bb, g_r[i], g_g[i], g_b[i]);
                if (fld < compa)
                {
                    compa = fld;
                    target = i;
                }
            }

            g_farge = target;
            pixut[target]++; //histogramming
        }

        for (int aas = 0; aas < xcolors; aas++)
        for (int bbs = 0; bbs <= aas; bbs++)
        {
            if (pixut[aas] > pixut[bbs])
            {
                swap = pixut[aas];
                pixut[aas] = pixut[bbs];
                pixut[bbs] = swap;
                swap = idx[aas];
                idx[aas] = idx[bbs];
                idx[bbs] = swap;
            }
        }

        for (idefix = 0; idefix < limitter; idefix++)
        {
            i = idx[idefix];

            for (yy = cy * vertti; yy <= cy * vertti + vertti - 1; yy++)
            for (xx = cx * 8; xx <= cx * 8 + 7; xx = xx + g_pixelw)
            {
                x2 = int(image.width / X) * xx;
                y2 = int(image.height / Y) * yy;

                rr = 0;
                gg = 0;
                bb = 0;
                avg = 0;
                for (avy = 0; avy < baly; avy++)
                for (avx = 0; avx < balx; avx++)
                {
                    c = image.get(x2 + avx, y2 + avy);
                    rr = rr + int(red(c));
                    gg = gg + int(green(c));
                    bb = bb + int(blue(c));
                    avg++;
                }

                rr = int(rr / avg);
                gg = int(gg / avg);
                bb = int(bb / avg);

                g_farge = 0;
                target = -1;
                compa = 9999;
                for (j = 0; j < limitter; j++)
                {
                    fld = dist(rr, gg, bb, g_r[idx[j]], g_g[idx[j]], g_b[idx[j]]);
                    if (fld < compa)
                    {
                        compa = fld;
                        target = idx[j];
                    }
                }
                if (i == target)
                {
                    g_farge = target;
                    makepoint(xx, yy);
                }
            }

            if (idefix == 0)
            {
                for (yy = cy * vertti; yy <= cy * vertti + vertti - 1; yy++)
                for (xx = cx * 8; xx <= cx * 8 + 7; xx = xx + g_pixelw)
                {
                    g_farge = idx[0];
                    makepoint(xx, yy);
                }
            }
        }
    }
}


void mpRenderToImageAt(PImage output, int xoffs, int yoffs, int omag)
{
    if (output == null)
        return;

    color c = color(g_r[259], g_g[259], g_b[259]);
    for (int yy = 0; yy < output.width; yy++)
    for (int xx = 0; xx < output.width; xx++)
        output.set(xx, yy, c);

    for (int yy = 0; yy < Y; yy++)
    for (int xx = 0; xx < X; xx++)
    {
        int f;
        if (g_pixelw == 2)
            f = getmultic(chop2(xx), yy, 0);
        else
            f = easygetcolor(xx, yy);
//            f = getabsa(xx, yy, 0);

        if (g_machine == MSX && f == 0)
            f = g_map[1];

        c = color(g_r[f], g_g[f], g_b[f]);

        for (int vertti = 0; vertti <= omag; vertti++)
        for (int mortti = 0; mortti <= omag; mortti++)
        {
            output.set(
                xx * omag + xoffs + mortti,
                yy * omag + yoffs + vertti,
                c);
        }
    }
}


PImage mpRenderImage(boolean border, int bordh, int bordv, int omag)
{
    PImage output;

    if (border)
    {
        output = createImage(
            (X + bordh) * omag,
            (Y + bordv) * omag,
            RGB);

        mpRenderToImageAt(output, int((bordh * omag) / 2), int((bordv * omag) / 2), omag);
    }
    else
    {
        output = createImage(X * omag, Y * omag, RGB);
        mpRenderToImageAt(output, 0, 0, omag);
    }

    return output;
}


void make_c64_palette()
{
    // Pepto's murky C64 palette: http://www.pepto.de/projects/colorvic
    int rgb[] =
    {
        0x000000,
        0xFFFFFF,
        0x68372B,
        0x70A4B2,
        0x6F3D86,
        0x588D43,
        0x352879,
        0xB8C76F,
        0x6F4F25,
        0x433900,
        0x9A6759,
        0x444444,
        0x6C6C6C,
        0x9AD284,
        0x6C5EB5,
        0x959595
    };
    for (int i = 0; i < g_maxcolors; i++)
    {
        g_grids[i] = (rgb[i] + 0x282828) | 0xff000000;
        makecolor(i, (rgb[i] >> 16) & 0xff, (rgb[i] >> 8) & 0xff, rgb[i] & 0xff);
    }
    g_grids[1] = 0xffd0d0d0;
    g_gridmode = GRIDMODE_NEW;
    g_map[13] = byte(C64);
}


void make_coco_palette()
{
}


void make_plus4_palette()
{
    int rgb[] =
    {
        0x000000,
        0x2C2C2C,
        0x621307,
        0x00424C,
        0x510378,
        0x004E00,
        0x27188E,
        0x303E00,
        0x582100,
        0x463000,
        0x244400,
        0x630448,
        0x004E0C,
        0x0E2784,
        0x33118E,
        0x184800,
        0x3B3B3B,
        0x702419,
        0x00505A,
        0x601685,
        0x125D00,
        0x36289B,
        0x3F4C00,
        0x663100,
        0x553F00,
        0x345200,
        0x711656,
        0x005C1D,
        0x1F3691,
        0x42229B,
        0x285700,
        0x424242,
        0x772C21,
        0x055861,
        0x661E8C,
        0x1B6400,
        0x3E30A2,
        0x475400,
        0x6D3900,
        0x5C4700,
        0x3B5900,
        0x771F5D,
        0x046325,
        0x273E98,
        0x492AA1,
        0x305E00,
        0x515151,
        0x843B31,
        0x17656F,
        0x742E99,
        0x2B7100,
        0x4C3FAF,
        0x556200,
        0x7A4709,
        0x6A5500,
        0x4A6700,
        0x852F6B,
        0x177135,
        0x364CA5,
        0x5739AE,
        0x3F6B00,
        0x7A7A7A,
        0xAC665C,
        0x468E97,
        0x9C5AC0,
        0x57992E,
        0x766AD5,
        0x7E8A13,
        0xA2713A,
        0x927E20,
        0x748F14,
        0xAC5A93,
        0x459960,
        0x6276CB,
        0x8064D4,
        0x6A9419,
        0x959595,
        0xC58178,
        0x62A8B1,
        0xB675D9,
        0x73B34C,
        0x9185ED,
        0x99A433,
        0xBB8C57,
        0xAC993E,
        0x8FAA34,
        0xC676AD,
        0x62B37B,
        0x7D91E4,
        0x9B80ED,
        0x85AE38,
        0xAFAFAF,
        0xDE9B93,
        0x7DC2CA,
        0xCF90F2,
        0x8DCD68,
        0xAB9FFF,
        0xB3BE51,
        0xD5A673,
        0xC6B35B,
        0xA9C351,
        0xDF91C7,
        0x7DCC96,
        0x97ABFD,
        0xB59AFF,
        0x9FC755,
        0xE1E1E1,
        0xFFCFC6,
        0xB2F4FC,
        0xFFC4FF,
        0xC1FE9D,
        0xDDD2FF,
        0xE5F088,
        0xFFD9A8,
        0xF7E591,
        0xDBF588,
        0xFFC4F9,
        0xB1FEC9,
        0xCBDDFF,
        0xE7CDFF,
        0xD2F98C
    };
    for (int i = 0; i < g_maxcolors; i++)
    {
        makecolor(i, (rgb[i] >> 16) & 0xff, (rgb[i] >> 8) & 0xff, rgb[i] & 0xff);
    }
}


void make_bk_palette()
{
    int rgb[] =
    {
        0x000000,
        0x0000ff,
        0x00ff00,
        0xff0000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
        0x000000,
    };
    for (int i = 0; i < g_maxcolors; i++)
    {
        if (i <= 8)
            g_grids[i] = rgb[i] + 0xff282828;

        makecolor(i, (rgb[i] >> 16) & 0xff, (rgb[i] >> 8) & 0xff, rgb[i] & 0xff);
    }
}


void make_ql_palette()
{
    int rgb[] =
    {
        0x000000,
        0x0000ff,
        0xff0000,
        0xff00ff,
        0x00ff00,
        0x00ffff,
        0xffff00,
        0xffffff
    };
    g_grids[0] = 0xff282828;
    g_grids[1] = 0xff0000d8;
    g_grids[2] = 0xffd80000;
    g_grids[3] = 0xffd800d8;
    g_grids[4] = 0xff00d800;
    g_grids[5] = 0xff00d8d8;
    g_grids[6] = 0xffd8d800;
    g_grids[7] = 0xffd8d8d8;

    for (int i = 0; i < g_maxcolors; i++)
    {
        // if(i<=8){g_grids[i]=rgb[i]+0xff282828;}
        makecolor(i, (rgb[i] >> 16) & 0xff, (rgb[i] >> 8) & 0xff, rgb[i] & 0xff);
    }
    g_gridmode = GRIDMODE_NEW;
}


void make_msx_palette()
{
    int rgb[] =
    {
        0x000000,
        0x000000,
        0x3EB849,
        0x74D07D,
        0x5955E0,
        0x8076F1,
        0xB95E51,
        0x65DBEF,
        0xDB6559,
        0xFF897D,
        0xCCC35E,
        0xDED087,
        0x3AA241,
        0xB766B5,
        0xCCCCCC,
        0xFFFFFF
    };

    for (int i = 0; i < g_maxcolors; i++)
    {
        g_grids[i] = (rgb[i] + 0x1f1f1f) | 0xff000000;
        makecolor(i, (rgb[i] >> 16) & 0xff, (rgb[i] >> 8) & 0xff, rgb[i] & 0xff);
    }

    g_grids[5] = 0xff9f95Ff;
    g_grids[7] = 0xff84faEF;
    g_grids[9] = 0xffffa99d;
    g_grids[15] = 0xffd8d8d8;
    g_gridmode = GRIDMODE_NEW;
}


void make_spectrum_palette()
{
    int rgb[] =
    {
        0x000000,
        0x0000C0,
        0xC00000,
        0xC000C0,
        0x00C000,
        0x00C0C0,
        0xC0C000,
        0xC0C0C0,
        0x000000,
        0x0000FF,
        0xFF0000,
        0xFF00FF,
        0x00FF00,
        0x00FFFF,
        0xFFFF00,
        0xFFFFFF
    };

    g_grids[9] = 0xff0000d8;
    g_grids[10] = 0xffd80000;
    g_grids[11] = 0xffd800d8;
    g_grids[12] = 0xff00d800;
    g_grids[13] = 0xff00d8d8;
    g_grids[14] = 0xffd8d800;
    g_grids[15] = 0xffd8d8d8;

    for (int i = 0; i < g_maxcolors; i++)
    {
        if (i <= 8)
            g_grids[i] = (rgb[i] + 0x282828) | 0xff000000;

        makecolor(i, (rgb[i] >> 16) & 0xff, (rgb[i] >> 8) & 0xff, rgb[i] & 0xff);
    }
    g_gridmode = GRIDMODE_NEW;
}


void mpSetupMachine(int m)
{
    g_machine = m;

    g_name = "ERROR";
    g_exportext = "none";
    g_exportname = "";
    g_formatname = "";
    g_formatext = "";
    g_formatname = "";
    g_formatext = "";

    g_aspect = AR_SQUARE;

    g_map[3] = byte(g_machine);
    g_map[13] = byte(g_machine);
    g_palsteps = 0;
    g_farge = 1;
    g_backg = 0;
    g_britemode = 0;
    g_charlimit = 0;
    g_hzoomer = 1;
    g_backmode = 0;
    g_maxcolors = 16;
    X = 320;
    Y = 200;

    if (g_machine == C64)
    {
        //c64 hires
        g_name = "c64";
        g_exportext = "prg";
        g_exportname = "PRG file";
        g_formatname = "Art Studio";
        g_formatext = "art";

        g_attrimode = 1;
        g_map[1] = byte(255);
        g_map[0] = 6;
        make_c64_palette();
    }
    else
    if (g_machine == CPC)
    {
        //Amstrad CPC mode 0
        g_name = "cpc";
        g_exportext = "bin";
        g_exportname = "BIN file"
        g_formatname = "";
        g_formatext = "";

        g_hzoomer = 2;
        g_palsteps = 3;
        g_multic = 2;
        g_attrimode = 2;
        g_map[1] = byte(255);
        g_map[0] = 1;

        makecolor(0, 0, 0, 0);
        makecolor(1, 0x0, 0x0, 0x80);
        makecolor(2, 0x00, 0x00, 0xFF);
        makecolor(3, 0x80, 0x00, 0x00);
        makecolor(4, 0x80, 0x00, 0x80);
        makecolor(5, 0x80, 0x00, 0xFF);
        makecolor(6, 0xFF, 0x00, 0x00);
        makecolor(7, 0xFF, 0x00, 0x80);
        makecolor(8, 0xFF, 0x00, 0xFF);
        makecolor(9, 0x00, 0x80, 0x00);
        makecolor(10, 0x00, 0x80, 0x80);
        makecolor(11, 0x00, 0x80, 0xFF);
        makecolor(12, 0x80, 0x80, 0x00);
        makecolor(13, 0x80, 0x80, 0x80);
        makecolor(14, 0x80, 0x80, 0xFF);
        makecolor(15, 0xFF, 0xFF, 0xFF);
    }
    else
    if (g_machine == MSX)
    {
        // MSX
        g_name = "msx";
        g_exportext = "com";
        g_exportname = "COM file";
        g_formatname = "Screen 2";
        g_formatext = "sc2";

        X = 256;
        Y = 192;
        g_attrimode = 0;
        g_backmode = 1;
        g_aspect = AR_FLAT;
        g_farge = 15;
        g_backg = 0;

        //TI99 variant
        /*
        makecolor(0,0,0,0);
        makecolor(1,0,0,0);

        makecolor(2,0x21,0xc8,0x42); //21c842 medgreen
        makecolor(3,0x5e,0xdc,0x78);//5edc78 light green
        makecolor(4,0x54,0x55,0xed);//5455ed dark blue
        makecolor(5,0x7d,0x76,0xFc);//7d76fc light blue

        makecolor(6,0xd4,0x52,0x4d); //d4524d dark red
        makecolor(7,0x42,0xeb,0xf5); //42ebf5 cyan
        makecolor(8,0xfc,0x55,0x54); //fc5554 medium red
        makecolor(9,0xff,0x79,0x78); //ff7978 light red
        makecolor(10,0xd4,0xc1,0x54);// d4c154 dark yellow
        makecolor(11,0xe6,0xce,0x80);// e6ce80 light yellow
        makecolor(12,0x21,0xb0,0x3b);// 21b03b dark green
        makecolor(13,0xc9,0x5b,0xba);// c95bba magenta
        makecolor(14,0xCc,0xcc,0xCc);// gray
        makecolor(15,0xFF,0xFF,0xFF);
        */
        make_msx_palette();
    }
    else
    if (g_machine == SPECTRUM)
    {
        // ZX Spectrum
        g_name = "spec";
        g_exportext = "tap";
        g_exportname = "TAP file";
        g_formatname = "Screen$";
        g_formatext = "scr";

        X = 256;
        Y = 192;
        g_farge = 7;
        g_backg = 0;
        g_attrimode = 1;
        g_britemode = 1;
        g_map[0] = 1;
        g_map[1] = byte(255);
        make_spectrum_palette();
    }
    else
    if (g_machine == TIMEX)
    {
        // timex sinclair
        g_name = "tmx";

        X = 256;
        Y = 192;
        g_farge = 7;
        g_backg = 0;
        g_attrimode = 0;
        g_britemode = 1;
        g_map[1] = byte(255);
        make_spectrum_palette();
    }
    else
    if (g_machine == JR200)
    {
        // Panasonic JR200
        g_name = "jr200";

        X = 256;
        Y = 192;
        g_maxcolors = 8;
        g_farge = 7;
        g_backg = 0;
        g_attrimode = 1;
        g_map[1] = byte(255);
        make_spectrum_palette(); //cheating
    }
    else
    if (g_machine == PLUS4M || g_machine == PLUS4)
    {
        // Commodore plus/4
        g_name = "plus4m";
        g_exportext = "prg";
        g_exportname = "PRG file";
        g_formatname = "M.Botticelli";
        g_formatext = "prg";

        g_backmode = 1;
        g_multic = 1;
        g_attrimode = 1;
        g_maxcolors = 121;
        g_charlimit = 2;
        g_map[0] = 6;
        g_map[1] = 0;
        g_map[2] = 61;
        g_farge = 61;

        if (g_machine == PLUS4)
        {
            // plus/4 hires
            g_name = "plus4";
            g_formatname = "Botticelli";
            g_formatext = "prg";
            g_multic = 0;
            g_backmode = 0;
            g_charlimit = 0;
            g_attrimode = 1;
            g_map[1] = byte(255);
        }
        make_plus4_palette();
    }
    else
    if (g_machine == C64M)
    {
        //c64 multicolor
        g_name = "c64m";
        g_exportext = "prg";
        g_exportname = "PRG file";
        g_formatname = "A. A. Studio";
        g_formatext = "ocp";

        g_backmode = 1;
        g_charlimit = 3;
        g_multic = 1;
        g_attrimode = 1;
        g_map[1] = byte(0);
        g_map[0] = 6;
        make_c64_palette();
    }
    else
    if (g_machine == QLLOW)
    {
        // Sinclair QL low
        g_backmode = 0;
        g_maxcolors = 8;
        X = 256;
        Y = 256;
        g_name = "QL";
        g_multic = 2;
        g_attrimode = 2;
        g_aspect = AR_FLAT;
        g_map[1] = byte(0);
        make_ql_palette();
    }
    else
    if (g_machine == BK0010)
    {
        // BK0010 patch
        g_backmode = 0;
        g_maxcolors = 4;
        X = 256;
        Y = 256;
        g_name = "BK";
        g_multic = 2;
        g_attrimode = 2;
        g_aspect = AR_FLAT;
        g_map[1] = byte(0);
        make_bk_palette();
    }
    else
    if (g_machine == AMIGA)
    {
        g_name = "amiga";
        g_exportext = "";
        g_exportname = "";
        g_formatname = "";
        g_formatext = "";

        g_backmode = 1;
        g_maxcolors = 32;
        g_palsteps = 16;
        g_multic = 2;
        g_attrimode = 2;
        g_map[1] = byte(0);

        for (int cindex = 0; cindex < g_maxcolors; cindex++)
        {
            if (cindex < 16)
                makecolor(cindex, cindex * 17, cindex * 17, cindex * 17);
            else
                makecolor(cindex, (cindex - 16) * 17, 0, 0);
        }
    }
    else
    if (g_machine == ATARIST)
    {
        //ATARI ST 512 color
        g_name = "st";
        g_exportext = "";
        g_exportname = "";
        g_formatname = "";
        g_formatext = "";

        g_backmode = 1;
        g_maxcolors = 16;
        g_palsteps = 8;
        g_multic = 2;
        g_attrimode = 2;
        g_map[1] = byte(0);

        for (int cindex = 0; cindex < 8; cindex++)
        {
            makecolor(cindex, cindex * 36, cindex * 36, cindex * 36);
            makecolor(cindex + 8, cindex * 36, 36, 0);
        }
    }
    else
    if (g_machine == C64FLI)
    {
        //c64 hires FLI = AFLI
        g_name = "afli";
        g_exportext = "prg";
        g_exportname = "PRG file";
        g_formatname = "";
        g_formatext = "";

        g_attrimode = 0;
        g_map[1] = byte(255);
        g_map[0] = 6;
        make_c64_palette();
    }
    else
    if (g_machine == C64FLIM)
    {
        //C64 FLI multicolor
        g_name = "fli";
        g_exportext = "";
        g_exportname = "PRG file";
        g_formatname = "";
        g_formatext = "";

        g_hzoomer = 2;
        g_maxcolors = 16;
        g_multic = 2;
        g_attrimode = 0;
        g_map[1] = byte(255);
        g_map[0] = 6;
        make_c64_palette();
    }
    else
    if (g_machine == C64NOLIMIT)
    {
        g_name = "c64hino";
        g_exportext = "";
        g_exportname = "";
        g_formatname = "";
        g_formatext = "";

        X = 320;
        Y = 256;
        g_multic = 2;
        g_attrimode = 2; //g_palsteps=4;
        g_farge = 15;
        g_backg = 0;
        make_c64_palette();
    }
    else
    if (g_machine == PICO8)
    {
        // Pico-8 fantasy console
        g_name = "pico8";
        g_exportext = "";
        g_exportname = "";
        g_formatname = "";
        g_formatext = "";

        X = 128;
        Y = 128;
        g_farge = 15;
        g_backg = 0;
        g_multic = 2;
        g_attrimode = 2;
        makecolor(0, 0, 0, 0);
        makecolor(1, 32, 51, 123);
        makecolor(2, 126, 37, 83);
        makecolor(3, 0, 144, 61);
        makecolor(4, 171, 82, 54);
        makecolor(5, 52, 54, 53);
        makecolor(6, 194, 195, 199);
        makecolor(7, 255, 241, 232);
        makecolor(8, 255, 0, 77);
        makecolor(9, 255, 155, 0);
        makecolor(10, 255, 231, 39);
        makecolor(11, 0, 226, 50);
        makecolor(12, 41, 173, 255);
        makecolor(13, 132, 112, 169);
        makecolor(14, 255, 119, 168);
        makecolor(15, 255, 214, 197);
    }
    else
    if (g_machine == COCO3)
    {
        //6-bit RGB, 16 out of 64 possible
        g_name = "coco";
        g_exportext = "";
        g_exportname = "";
        g_formatname = "";
        g_formatext = "";

        g_backmode = 1;
        g_maxcolors = 16;
        g_palsteps = 4; //00 00 00
        g_multic = 2;
        g_attrimode = 2;
        g_map[1] = byte(0);
        make_coco_palette();
    }
    else
    if (g_machine == UNIA)
    {
        // Unia digital palette
        g_name = "unia";
        g_exportext = "";
        g_exportname = "";
        g_formatname = "";
        g_formatext = "";

        X = 256;
        Y = 192;
        g_farge = 15;
        g_backg = 0;
        g_multic = 2;
        g_attrimode = 2;
        makecolor(0, 0, 0, 0);
        makecolor(1, 0xff, 0xff, 0xff);
        makecolor(2, 0xff, 0xfd, 0x38);
        makecolor(3, 0xff, 0xc5, 0x00);
        makecolor(4, 0xff, 0x00, 0x00);
        makecolor(5, 0xff, 0x3c, 0xb4);
        makecolor(6, 0xa0, 0x23, 0xbc);
        makecolor(7, 0x1b, 0xa1, 0xfc);
        makecolor(8, 0xe1, 0xe1, 0xe1);
        makecolor(9, 0xb9, 0x63, 0x00);
        makecolor(10, 0xff, 0xaa, 0xbe);
        makecolor(11, 0xd2, 0x9b, 0xd7);
        makecolor(12, 0xad, 0xad, 0xad);
        makecolor(13, 0x00, 0xb7, 0xb7);
        makecolor(14, 0x23, 0xaf, 0x32);
        makecolor(15, 0x29, 0xf7, 0xa7);
    }

    // Compute pixel width
    if (g_multic == 1 || g_hzoomer == 2)
        g_pixelw = 2;
    else
        g_pixelw = 1;
}