Mercurial > hg > forks > multipaint-js
view multipaint.pde @ 131:9d17f991f102
Move undo and spare page management into buffers.pde as in Multipaint 2018.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 05 Aug 2018 10:44:45 +0300 |
parents | 050a1ca8b106 |
children | f5c32f6470d0 |
line wrap: on
line source
// // Multipaint Metal Edition 22.5.2017 // Tero Heikkinen (Dr. TerrorZ) // ProcessingJS port and changes by Matti Hämäläinen (ccr/TNSP) // processing setup draw and file things here // final int C64 = 0, MSX = 5, SPECTRUM = 6, C64M = 10, PLUS4 = 9, PLUS4M = 19, CPC = 2; // supported final int TIMEX = 7, JR200 = 8, AMIGA = 11; // experimental or incomplete final int C64FLI = 20, C64FLIM = 21; // experimental final int PICO8 = 88; final int FAKEX = 32; // Commodore 64 without attribute limitations final int UNIA = 33; final int PEESEE = 0, MACOSX = 1, PSJS = 2; final int COMMAND = 157; // Marq's cmd/ctrl solution //-1 & -1 for normal operation int machine = -1; // change this to autoselect int platform = PSJS; int g_active, g_tooltrigger, g_prevtool; int g_rband, g_rbang, g_boxreconstruct, g_charlimit; int g_animx, g_animy, g_animframes, g_animno, g_animtime, g_animspeed; int g_omag, g_bordh, g_bordv, g_keymacpos; boolean g_control = false, g_shift = false, g_dirty; String filename = "", sfilename = "", g_name, g_exportext = "", g_exportname = "", g_keymacro = ""; int[] g_r = new int[266]; int[] g_g = new int[266]; int[] g_b = new int[266]; int[] g_rgb = new int[266]; byte[] g_map = new byte[88000]; byte[] g_fillmap = new byte[88000]; byte[] g_rmap = new byte[88000]; byte[] g_icons = new byte[88000]; byte[] g_brush = new byte[88000]; byte[] g_template = new byte[16384]; byte[] g_redo = new byte[1024]; byte[] g_remdo = new byte[1024]; int[] g_chaup = new int[64]; byte[] g_data = new byte[1024]; int[] g_magpix = new int[64]; int[] g_magpiy = new int[64]; byte g_realfront, g_realback; //dimensions int X, Y, MX, MY; //generic mouse int g_ofx, g_ofy, g_button, g_realbutton, g_klikkeri, g_mx, g_my, g_orx, g_ory, g_msx, g_msy; //rubberband,mouse int g_phase, g_rx, g_ry, g_rx2, g_ry2, g_rubbermode; int g_prex, g_prey, g_storedcoordx, g_storedcoordy; //window positioning int g_windowx, g_windowy, g_maglocx, g_maglocy; int g_hedge, g_vedge, g_uizoom, g_wzoom; //icons & gui stuff int g_iconx, g_icony, g_piconx, g_picony, g_iconmode; int g_gridx, g_gridy, g_spare; int g_farge, g_backg, g_ofarge, g_repanel, g_msgctr; //machine related color properties int g_attrimode, g_britemode, g_multic, g_backmode, g_maxcolors, g_hzoomer; float g_palsteps; //brush, tool parameters int g_bsourcex, g_bsourcey, g_bsourcex2, g_bsourcey2; int g_bsize, g_btype; void setup() { g_magpix[0] = 3; g_magpix[1] = 8; g_magpix[2] = 16; g_magpix[10] = 2; g_magpix[11] = 6; g_magpix[12] = 16; g_magpix[20] = 4; g_magpix[21] = 16; g_magpix[22] = 32; g_magpiy[0] = 3; g_magpiy[1] = 8; g_magpiy[2] = 16; g_magpiy[10] = 2; g_magpiy[11] = 6; g_magpiy[12] = 16; g_magpiy[20] = 4; g_magpiy[21] = 16; g_magpiy[22] = 32; g_omag = 1; g_bordh = 64; g_bordv = 32; // Set up UI g_uizoom = 2; g_animspeed = 1; // Get machine from Javascript runner, or default to C64 if (mpMachine) machine = mpMachine; else machine = C64; switch (g_uizoom) { case 1: g_wzoom = 2; size(700, 468); break; case 2: g_wzoom = 3; size(1058, 708); break; case 3: g_wzoom = 4; size(1460, 950); break; } g_hedge = 32 * g_uizoom; g_vedge = 32 * g_uizoom; g_uindex[0] = 0; g_utop[0] = 0; g_ubottom[0] = 0; g_uindex[1] = 0; g_utop[1] = 0; g_ubottom[1] = 0; g_spare = 0; g_bsize = 0; g_btype = 0; g_phase = 0; g_button = LEFT; g_data[int('f')] = 1; g_data[int('g')] = 1; g_icons = mpLoadBinaryFile("icons.bin"); set_tool(3); g_gridx = 8; g_gridy = 8; g_multic = 0; g_repanel = -2; //UI colors makecolor(256, 0xff, 0, 0xff); makecolor(257, 180, 180, 180); g_rgb[257] = 0xff808080; makecolor(258, 0, 0, 0); makecolor(259, 48, 48, 48); //R,G,B makecolor(260, 255, 0, 0); makecolor(261, 0, 255, 0); makecolor(262, 0, 0, 255); mpSetupMachine(machine); g_windowx = width - (g_hedge) - (g_wzoom * X); g_windowx = int(g_windowx / 2); g_windowy = height - (g_vedge) - (g_wzoom * Y); g_windowy = int(g_windowy / 2); switcher(3); g_map[4] = byte(g_maxcolors - 1); g_ofarge = g_farge; MX = int(X / 8); MY = int(Y / 8); g_realfront = byte(g_farge); g_realback = byte(g_backg); for (int y = 0; y < Y; y++) for (int x = 0; x < X; x++) absolute_clearpoint(x, y); switcher(2); noStroke(); background(g_r[259], g_g[259], g_b[259]); sussborder(); setup_raster(); message("Multipaint|Metal|v22.5.2017"); message("*"); g_dirty = true; } void mpSetTitle(String str) { console.log("TITLE: '" + str + "'"); } boolean mpHaveLocalStorage() { var test = 'mpLSTest'; try { localStorage.setItem(test, test); if (localStorage.getItem(test) == test) { localStorage.removeItem(test); return true; } } catch (e) { return false; } return false; } function mpLoadFileSelector(fmtname, fmtexts, fcallback) { var mpUI = stGE("mpUI"); if (mpUI) { stClearChildren(mpUI); mpUI.style.background = "red"; mpUI.style.padding = "0.5em"; mobj = stCE("input", "mpFileSelector"); mobj.type = "file"; mobj.name = "name"; mobj.multiple = false; if (fmtexts != null) mobj.accept = fmtexts; stAddEventOb(mobj.name, mobj, "change", function(evt) { var files = evt.target.files; if (files.length > 0) { var freader = new FileReader(); freader.onloadend = (function(theFile) { fcallback(theFile, new Uint8Array(freader.result)); }); freader.readAsArrayBuffer(files[0]); } stClearChildren(mpUI); mpUI.style.background = null; }); mpUI.appendChild(mobj); mobj = stCE("span", "mpFileInfo"); mobj.innerHTML = "Load / import an '<b>"+ fmtname +"</b>' file."; mpUI.appendChild(mobj); } else return null; } // // Basically the same as Processing loadBytes(), but it seems // that Processing.JS's loadBytes() is broken at least in v1.4.8 // and does not return byte-clean data. So roll a replacement of // our own design. --ccr // byte[] mpLoadBinaryFile(String url) { var xhr = new XMLHttpRequest(); xhr.open("GET", url, false); xhr.overrideMimeType("text/plain; charset=x-user-defined"); xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); xhr.send(null); if (xhr.status !== 200 && xhr.status !== 0) return null; var string = xhr.responseText; byte[] ret = new byte[string.length]; for (var i = 0; i < string.length; i++) { ret[i] = string.charCodeAt(i) & 0xff; } return ret; } Blob mpMakeBinaryBlob(byte[] data) { var blob = null; if (data == null) return null; if (typeof(data) == "string") blob = new Blob([data], {type: "application/octet-stream"}); else if (typeof(data) == "object") blob = new Blob([new Uint8Array(data)], {type: "application/octet-stream"}); return blob; } // // "Save" a byte array to file. Basically creates a blob URI // and dumps it in the DOM, giving user a download. // boolean mpSaveBinaryFile(String name, byte[] data) { var blob = mpMakeBinaryBlob(data); if (blob == null) { console.log("Could not create BLOB from data."); return false; } var url = window.URL.createObjectURL(blob); if (url == null) { console.log("Could not create URL from BLOB object."); return false; } var alink = stCE("a"); var mpUI = stGE("mpUI"); stClearChildren(mpUI); mpUI.appendChild(alink); alink.style = "display: none"; alink.href = url; alink.download = name; alink.click(); window.URL.revokeObjectURL(url); return true; } void mpSavePNGImage(String name, int fmt, boolean border) { PImage simg = mpRenderImage(border); // if (g_data[int('Q')] == 0) if (simg !== null) { // XXX TODO .. actually save the image, something like .. //simg.canvas.toBlob(function(idata){ mpSaveBinaryFile(name, idata); }, "image/png", 0.95); } } int mpLoadPNGImage(String name) { PImage simg = null; if (simg == null) return -1; int lefth = g_farge; int righth = g_backg; storeparameters(); g_data[int('d')] = 0; g_data[int('t')] = 0; g_data[int('b')] = 1; //old IQ if (!mpImportFromImage(simg)) return -2; restoreparameters(); refreshpalette(); refresh(); g_boxreconstruct = 2; selectcolor(0, lefth); selectcolor(1, righth); return 0; } byte[] mpGetNativeImage() { //save the picture page g_map[], make sure some essential parameters are correct g_map[3] = byte(machine); g_map[5] = byte(MX); g_map[7] = byte(MY); return g_map; } int mpSetNativeImage(byte[] data, boolean noError) { if (data == null) return -1; if (data[3] != machine && !noError) return -2; store_undo(); g_map = data; refreshpalette(); consistency(); g_farge = int(g_realfront); g_ofarge = g_farge; g_backg = int(g_realback); sussborder(); return 0; } int mpLoadNativeImage(String name, boolean noError) { return mpSetNativeImage( mpLoadBinaryFile(name), noError); } void draw() { if (!focused) { g_control = false; g_shift = false; } // If there should be no update, do not update. if (!g_dirty && !g_rubbermode) return; g_dirty = false; // Animate animbrush if (g_data[int('n')] == 1) { if (++g_animtime > 8 - g_animspeed * 2) { animbrush_do(); g_animtime = 0; } } // Update some mouse variables if (g_data[int('m')] == 0 && g_data[int('M')] == 0) { g_mx = g_msx - g_windowx; g_my = g_msy - g_windowy; } else { g_mx = mouseX; g_my = mouseY; } g_msx = mouseX; g_msy = mouseY; // Actual tool drawing if (g_tooltrigger == 1) { // comes from mousepressed, or mousedragged if (g_mx <= width - g_hedge && g_my <= height - g_vedge) do_tool(g_mx, g_my, g_button); } switcher(0); for (int i = 0; i < 1024; i++) { g_remdo[i] = 0; } // Tool drawing for shows int lipo = g_button; if (tool() != 5) { if (g_phase == 0) g_button = LEFT; do_tool(g_mx, g_my, LEFT); } if (tool() == 6) doline(g_rx, g_ry, g_rx2, g_ry2, 0); if (tool() == 7) docircle(g_rx, g_ry, g_rx2, g_ry2); if (tool() == 8) rectangle(g_rx, g_ry, g_rx2, g_ry2); g_button = lipo; // Screen update stuff loadPixels(); viewport(); //magport(); switcher(1); update_ui(); updatePixels(); // Message control if (g_msgctr > 0) g_msgctr--; // Macro handling if (g_keymacro.length() > g_keymacpos) { macro_command(g_keymacro.charAt(g_keymacpos)); g_keymacpos++; } }