RuneScape:Adventurer's Log 3D Viewer UI

The Adventurer's Log 3D Viewer UI, also known as ALog3D Viewer UI, is a userscript created by the fansite RuneApps. Contributors to the project include Skillbert II, creator of the project, as well as RSW editors Cook Me Plox and Ryan PM. This project is released under the GNU Public License.


 * For additional information on GPL, see: http://www.gnu.org/copyleft/gpl.html

Features

 * Bobbleheads
 * Camera zoom
 * Camera vertical movement
 * X-Axis and Y-Axis movement
 * Autopaint switch (Slower frames drawing)
 * Detail switch (top-down view for item images)
 * Player Kit Hex table modifying with item ID's
 * Easy inputs for: Players, NPC ID, Model ID and Animation ID

Userscript
";   root = document.createElement("div");    root.style.position = "fixed";    root.id = "streditroot";    root.style.left = "0px";    root.style.top = "0px";    root.style.zIndex = "10000";    root.style.background = "url(http://www.runescape.com/img/rs3/6-box-top.jpg) -1px 0px no-repeat, url(http://www.runescape.com/img/rs3/content_repeat_y.jpg) -1px 310px no-repeat";    root.style.padding = "2px";    root.style.border = "2px solid black";    root.style.boxShadow = "2px 2px 10px 1px rgba(0, 0, 0, 0.7)";    root.style.maxHeight = "100%";    root.style.overflowX = "auto";    root.style.width = "220px";    root.style.overflowX = "hidden";    root.onmousewheel = function(e) {      root.scrollTop -= e.wheelDeltaY;      return false;    };    root.innerHTML = r;    if (imgcapt.editel) {      imgcapt.editel.remove;    }    document.body.appendChild(root);    imgcapt.editel = root;    imgcapt.stredit.blocks = blocks; imgcapt.stredit.hextail = hex; }; imgcapt.blockkeydown = function(index, e) { var block, key; key = String.fromCharCode(e.keyCode); block = imgcapt.stredit.blocks[index]; if (key == "Q") { block.hex = numToHex(parseInt(block.hex, 16) + 1, block.l * 2); e.preventDefault; imgcapt.buildstr; }   if (key == "W") { block.hex = numToHex(parseInt(block.hex, 16) - 1, block.l * 2); e.preventDefault; imgcapt.buildstr; } };  imgcapt.resetblock = function(index) { var block; block = imgcapt.stredit.blocks[index]; block.reset(block); imgcapt.buildstr; }; imgcapt.editblockhex = function(index, value) { var block; value = value.toLowerCase; value = value.replace(/[^\da-f]/g, ""); block = imgcapt.stredit.blocks[index]; block.hex = value; imgcapt.buildstr; }; imgcapt.editblock = function(index, value) { var block; block = imgcapt.stredit.blocks[index]; block.control.func(block, value); imgcapt.buildstr; }; imgcapt.buildstr = function { var a, b, str, block, nth, nth2, selectstart, root, scroll; str = ""; for (a = 0; a < imgcapt.stredit.blocks.length; a++) { block = imgcapt.stredit.blocks[a]; str += block.hex; }   str += imgcapt.stredit.hextail; if (window.event) { root = document.getElementById("streditroot"); if (root) { scroll = root.scrollTop; }     a = window.event.target; if (a) { if (a.type == "text") { selectstart = a.selectionStart; }       a = a.parentElement; }     if (a) { nth2 = 1; b = a;       while (b.nodeType === Node.ELEMENT_NODE && (b = b.previousSibling)) { nth2++; }       a = a.parentElement; }     if (a) { nth = 1; b = a;       while (b.nodeType === Node.ELEMENT_NODE && (b = b.previousSibling)) { nth++; }     }    }    imgcapt.setstring(hexToBase64(str)); if (nth !== undefined) { a = "#streditroot > table > tbody > tr:nth-child(" + nth + ") > td:nth-child(" + nth2 + ") > *"; b = document.querySelector(a); if (b) { b.focus; if (selectstart !== undefined) { b.selectionStart = selectstart; }     }      root = document.getElementById("streditroot"); if (root && scroll !== undefined) { root.scrollTop = scroll; }   }  };  imgcapt.waitpaint = function(func) { imgcapt.waitpaintlist.push(func); imgcapt.trypaint; }; imgcapt.trypaint = function { if (imgcapt.manualpaint && imgcapt.paintfunc) { imgcapt.paintfunc; } };  imgcapt.setNpc = function(id) { var str; str = "00ffbe" + numToHex(+id, 4) + "0000000000000000000000ffbe"; str = hexToBase64(str); callString(str); /*dlpage("http://services.runescape.com/m=itemdb_rs/bestiary/beastData.json?beastid=" + id, function (t) {           var a, b, c, str, obj;            obj = JSON.parse(t);            str = "";            for (a in obj.animations) {                str += "" + escapeHtml(a) + " ";            }            document.getElementById("imgcaptanims")                .innerHTML = str;        });*/ imgcapt.setMessage("Loaded NPC: " + id); imgcapt.setstring(str); $("#streditroot").remove; }; imgcapt.overrideGetFrame = function { imgcapt.oldGetFrame = imgcapt.oldGetFrame || window.requestAnimationFrame; window.requestAnimationFrame = function(func) { var a, b;     if (!imgcapt.paintfunc) { imgcapt.paintfunc = func; } //capture the frame making code b = []; //clone the event array to prevent problems with multiple getframe calls in the stack for (a = imgcapt.waitpaintlist.length - 1; a >= 0; a--) { b.push(imgcapt.waitpaintlist[a]); imgcapt.waitpaintlist.length--; }     for (a = b.length - 1; a >= 0; a--) { b[a]; b.length--; }     if (!imgcapt.manualpaint) { return imgcapt.oldGetFrame.apply(this, arguments); }   };  };  imgcapt.setSize = function(w, h) { Module.setCanvasSize(w, h); }; imgcapt.makeGif = function(template, format) { var cnv, ctx, trans, encoder; var addframe, finish, log; var framenumber, animended; var starttime, intervaltimer, lastframetime, start, lastframeduration; if (!format) { format = "gif"; }   if (!template.crop) { template.crop = { x: 0, y: 0, w: imgcapt.el.width, h: imgcapt.el.height };   }    starttime = Date.now; trans = 0xFFFFFF; animended = false; framenumber = 0; cnv = document.createElement("canvas"); ctx = cnv.getContext("2d"); log = function(t) { console.log(new Date       .toLocaleTimeString, t); };   setframecam = function { var camprogress, totalsteps; if (!template.realtime) { totalsteps = template.frames; if (!template.frames || !totalsteps) { camprogress = 0; } else { camprogress = framenumber / totalsteps; }     } else { camprogress = (Date.now - starttime) / template.recordtime; }     imgcapt.cam.angle[0] = template.cam.angle[0] + template.anim.angle[0] * camprogress; imgcapt.cam.angle[1] = template.cam.angle[1] + template.anim.angle[1] * camprogress; imgcapt.cam.angle[2] = template.cam.angle[2] + template.anim.angle[2] * camprogress; imgcapt.cam.pos[0] = template.cam.pos[0] + template.anim.pos[0] * camprogress; imgcapt.cam.pos[1] = template.cam.pos[1] + template.anim.pos[1] * camprogress; imgcapt.cam.pos[2] = template.cam.pos[2] + template.anim.pos[2] * camprogress; imgcapt.cam.fov = template.cam.fov + template.anim.fov * camprogress; imgcapt.setCam; };   finish = function { var url; log("finished - " + (Date.now - starttime) + "ms"); animended = true; if (format == "gif") { encoder.finish; url = "data:image/gif;base64," + btoa(encoder.stream         .getData); }     if (format == "webm") { url = (window.webkitURL || window.URL) .createObjectURL(encoder.compile); }     if (format == "gif2") { encoder.on('finished', function(blob) {         window.open(URL.createObjectURL(blob));        }); encoder.render; }     if (url) { window.open(url); }   };    addframe = function { var islastframe, frametime; if (animended) { return; }     //check if this is last frame islastframe = false; if (template.frames) { if (framenumber >= template.frames - 1) { islastframe = true; }     } else if (template.recordtime) { if (Date.now + lastframeduration * (template.startisend ? 0.5 : -0.5) > starttime + template.recordtime) { islastframe = true; }     }      //make sure the image is drawn if on timer if (template.recordinterval) { if (islastframe) { clearInterval(intervaltimer); }       imgcapt.trypaint; }     //get the frame duration if (template.realtime) { frametime = Date.now - lastframetime; } else { frametime = template.interval; }     //copy frame cnv.width = template.crop.w;     cnv.height = template.crop.h;      ctx.fillStyle = "#" + numToHex(trans, 6); ctx.fillRect(0, 0, width, height); ctx.drawImage(imgcapt.el, -template.crop.x, -template.crop.y); //send to one of the encoders if (format == "gif") { encoder.addFrame(ctx); }     if (format == "webm") { encoder.add(ctx); }     if (format == "gif2") { encoder.addFrame(ctx, {         copy: true,          delay: frametime * 3        }); }     //finish up if done log("frame finished: " + framenumber + ", frametime: " + (Date.now - lastframetime)); lastframeduration = Date.now - lastframetime; lastframetime = Date.now; if (islastframe) { finish; return; }     //start next frame framenumber++; setframecam; if (!template.recordinterval) { imgcapt.waitpaint(addframe); }   };    start = function { lastframeduration = 0; lastframetime = Date.now; setframecam; if (template.recordinterval) { intervaltimer = setInterval(addframe, template.recordinterval); } else { addframe; }   };    width = imgcapt.el.width; height = imgcapt.el.height; if (format == "gif") { encoder = new GIFEncoder; encoder.start; encoder.setSize(width, height); encoder.setDelay(template.interval); encoder.setRepeat(0); }   if (format == "webm") { encoder = new Whammy.Video(1000 / template.interval); }   if (format == "gif2") { encoder = new GIF({       workers: 8,        quality: 10,        workerScript: imgcapt.getUrlForWorker(imgcapt.gif2workerstr),        width: template.crop.w,        height: template.crop.h,        transparent: trans      }); }   start; }; imgcapt.setAnim = function(id) { Module.avatar.SetAnimID(+id); if (id === undefined){ Module.avatar.SetAnimID(0); } };  imgcapt.stackstart = function { imgcapt.stacks = {}; imgcapt.stackcapt = true; }; imgcapt.stackend = function { imgcapt.stackcapt = false; console.log(imgcapt.stacks); }; imgcapt.getUrlForWorker = function(bodyString) { //convert js string into an url to run a web worker from, allows cross-domain worker injection var blob = new Blob([bodyString], {     type: 'text/javascript'    }); // pass a useful mime type here return URL.createObjectURL(blob); }; imgcapt.overrideCam = function { imgcapt.oldUniformMatrix4fv = imgcapt.oldUniformMatrix4fv || WebGLRenderingContext.prototype.uniformMatrix4fv; WebGLRenderingContext.prototype.uniformMatrix4fv = function { if (imgcapt.overrideCam) { //override 3d rasterizer if (imgcapt.overrideCam && arguments[2][0] != 1) { for (var a = 0; a < 16; a++) { arguments[2][a] = imgcapt.verticleMatrix[a]; }       } else { //vertical lock if (imgcapt.overridecenter && arguments[2][13] < -200) { arguments[2][13] = -400; }       }        //*detection stacks if (imgcapt.stackcapt) { var stack = new Error .stack; var stackstr = ""; stack.replace(/:(\d+:\d+)\)/g, function(a, b) { stackstr += b + " - "; });         if (!imgcapt.stacks[stackstr]) {            imgcapt.stacks[stackstr] = {};          }          var arstr = "";          for (a = 0; a < 16; a++) {            arstr += arguments[2][a].toFixed(1) + ",";          }          if (!imgcapt.stacks[stackstr][arstr]) {            imgcapt.stacks[stackstr][arstr] = 0;          }          imgcapt.stacks[stackstr][arstr]++;        }        //detection stacks */      }      imgcapt.oldUniformMatrix4fv.apply(this, arguments);    };  };  imgcapt.logupload = function(str) {    if (!imgcapt.uploadlog) {      return;    }    console.log(new Date .toLocaleTimeString, str); };  imgcapt.overrideContext = function {    imgcapt.oldGetContext = HTMLCanvasElement.prototype.getContext;    HTMLCanvasElement.prototype.getContext = function(type, args) {      if (type == "webgl") {        args.preserveDrawingBuffer = true;        console.log("Webgl context created.");      }      return imgcapt.oldGetContext.apply(this, arguments);    };  };  imgcapt.start = setTimeout(function { console.clear; // Log ASM events Module.addOnInit(function {     console.log("init");    }); Module.addOnPreRun(function {     console.log("prerun");    }); Module.addOnPreMain(function {     console.log("premain");    }); Module.addOnPostRun(function {     console.log("postrun");    }); Module.addOnExit(function {     console.log("exit");    }); imgcapt.el = document.getElementById("canvas"); imgcapt.captCnv = document.createElement("canvas"); imgcapt.captCtx = imgcapt.captCnv.getContext("2d"); imgcapt.saveCnv = document.createElement("canvas"); imgcapt.saveCtx = imgcapt.saveCnv.getContext("2d"); if (imgcapt.firstLoad) { imgcapt.overrideContext; imgcapt.loadlibs; }   imgcapt.overrideGetFrame; imgcapt.overrideCam; imgcapt.controlPanel; imgcapt.setCam; document.location.search.replace(/searchName=([\w%_]+)(\&|$)/, function(a, b) {     imgcapt.setplayer(b);    }); }, 3000); imgcapt.loadlibs = function {    var a;    for (a in imgcapt.libs) {      scr = document.createElement("script");      scr.src = imgcapt.liborigin + imgcapt.libs[a];      document.head.appendChild(scr);    }    for (a in imgcapt.libstrings) {      (function { // Make closure to copy the index value var strname = a;       dlpage(imgcapt.liborigin + imgcapt.libstrings[a], function(t) {          imgcapt[strname] = t;        }); });   }  };  imgcapt.startuploading = function {    if (!imgcapt.uploadpass) {      imgcapt.uploadpass = prompt("This function will start updating runeapps image database\n\npassword?");      if (!imgcapt.uploadpass) {        return;      }    }    imgcapt.setCam(imgcapt.uploadcam);    if (imgcapt.el.width != 1000 || imgcapt.el.height != 700) {      console.log("Wrong canvas size to start upload (not 1000x700)");      return;    }    dlpage(imgcapt.uploadpage + "?pass=" + imgcapt.uploadpass, function(t) { var obj; obj = JSON.parse(t); imgcapt.strlist = obj.todo; imgcapt.logupload("upload started"); imgcapt.uploading = true; imgcapt.checkImg; document.getElementById("imgcaptupload") .style.background = "green"; document.getElementById("imgcaptupload") .innerHTML = "Cancel upload"; }); };  imgcapt.stopUpload = function {    if (!imgcapt.uploading) {      return;    }    imgcapt.logupload("upload stopped");    imgcapt.uploading = false;    document.getElementById("imgcaptupload")      .style.background = "red";    document.getElementById("imgcaptupload")      .innerHTML = "Start upload";    return;  };  imgcapt.checkImg = function {    var a, b, c, buffer;    if (!imgcapt.uploading) {      return;    }    imgcapt.captCnv.width = imgcapt.el.width;    imgcapt.captCnv.height = imgcapt.el.height;    imgcapt.trypaint;    imgcapt.captCtx.drawImage(imgcapt.el, 0, 0);    buffer = imgcapt.captCtx.getImageData(imgcapt.captCnv.width / 2 - 20, imgcapt.captCnv.height / 2 - 20, 40, 40);    c = 0;    for (a = 0; a < buffer.width; a++) {      for (b = 0; b < buffer.height; b++) {        c += buffer.data[a * 4 + b * 4 * buffer.width + 3];      }    }    c /= 255 * 40 * 40; if (c > 0.5 && imgcapt.lastLoad < Date.now - imgcapt.unloadTime) { imgcapt.logupload("load completed"); setTimeout(function {       imgcapt.logupload("load settled");        var a, b;        b = true;        for (a in imgcapt.captured) {          if (imgcapt.captured[a].str == imgcapt.currentStr) {            b = false;            break;          }        }        if (imgcapt.firstLoad) {          imgcapt.firstLoad = false;        } else if (b) {          imgcapt.uploadImg;          imgcapt.lastLoad = Date.now;          imgcapt.captured.push({ str: imgcapt.currentStr, success: true });       }        imgcapt.setNextPlayer;      }, imgcapt.settleTime); return; }   if (c < 0.5 && imgcapt.lastLoad < Date.now - imgcapt.skipTime && !imgcapt.firstLoad) { imgcapt.logupload("load failed"); imgcapt.lastLoad = Date.now; imgcapt.captured.push({       str: imgcapt.currentStr,        success: false      }); imgcapt.setNextPlayer; return; }   setTimeout(imgcapt.checkImg, imgcapt.checkTime); }; imgcapt.getImg = function { imgcapt.saveCnv.width = imgcapt.uploadcrop.w;   imgcapt.saveCnv.height = imgcapt.uploadcrop.h;    imgcapt.saveCtx.drawImage(imgcapt.el, -imgcapt.uploadcrop.x, -imgcapt.uploadcrop.y); return imgcapt.saveCnv.toDataURL("image/png"); }; imgcapt.uploadImg = function { var imgdata, name, str; name = imgcapt.currentPlayer; str = imgcapt.currentStr; imgdata = imgcapt.getImg; dlpagepost(imgcapt.uploadpage, {     pass: imgcapt.uploadpass,      img: imgdata,      avatarstr: str    }, function(t) {      if (t.indexOf("Fatal error") === 0) {        console.log(t);        return;      }      var obj = JSON.parse(t);      imgcapt.logupload(imgcapt.uploadview.replace("$0", obj.uploaded));    }, function {      console.log("Upload failed.");    }); }; imgcapt.displayImg = function { var cnv, ctx; cnv = document.createElement("canvas"); cnv.width = imgcapt.el.width; cnv.height = imgcapt.el.height; ctx = cnv.getContext("2d"); ctx.drawImage(imgcapt.el, 0, 0); window.open(cnv.toDataURL("image/png")); }; imgcapt.setNextPlayer = function { var a, b, c;   for (a in imgcapt.strlist) { b = true; for (c in imgcapt.captured) { if (imgcapt.captured[c].str == imgcapt.strlist[a].avatarstr) { b = false; break; }     }      if (b) { imgcapt.setstring(imgcapt.strlist[a].avatarstr); imgcapt.logupload("new string: " + imgcapt.currentStr); setTimeout(imgcapt.checkImg, imgcapt.unloadTime); return; }   }    imgcapt.stopUpload; console.log("Upload done."); }; imgcapt.setplayer = function(player) { player = player.replace(/( |\-|\u00a0|%A0|%20)/g, "_"); imgcapt.currentPlayer = player; //avatarViewer.avatarChange(player); dlpage("http://services.runescape.com/m=avatar-rs/" + encodeURIComponent(player) + "/appearance.dat", function(t) {     if (t.indexOf(" ") != -1) {        imgcapt.setMessage("Failed to load: " + player);        return;      }      else {        imgcapt.setMessage("Loaded player: " + player);      }      imgcapt.setstring(t);    }); }; imgcapt.setmodel = function (n) { var index = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-*"; n = n * 4; var model = index.charAt((n / 262144)) + index.charAt(((n % 262144) / 4096)) + index.charAt(((n % 4096) / 64)) + index.charAt(((n % 64) / 1)); imgcapt.setMessage("Model (string): " + n / 4 + " (" + model + ")"); Module.avatar.module.ccall("SetAppearance", "void", ["string"], ['AEABQAFAAUABQAFAAUABQAFAAUABQAFAAUABnHoAACAAAYA' + model + 'eAASMyDDcQAwAADAAAAAqL']); imgcapt.setstring("AEABQAFAAUABQAFAAUABQAFAAUABQAFAAUABnHoAACAAAYA" + model + "eAASMyDDcQAwAADAAAAAqL"); $("#streditroot").remove; }; imgcapt.setstring = function(str) { Module.ccall("SetAppearance", "void", ["string"], [str]); imgcapt.currentStr = str; document.getElementById("imgcaptstring") .value = str; document.getElementById("imgcaptstringhex") .value = base64ToHex(str); imgcapt.drawstr(str); }; imgcapt.setstringbin = function(str) { imgcapt.setstring(binToBase64(str)); }; imgcapt.setstringhex = function(str) { imgcapt.setstring(hexToBase64(str)); };

function dlpagepost(url, data, func, errorfunc) { var req, post, a, b;     if (window.XMLHttpRequest) { req = new XMLHttpRequest; }     if (func) { req.onload = function { func(req.responseText); };     }      if (errorfunc) { req.onerror = errorfunc; }     post = ""; b = ""; for (a in data) { post += b + encodeURIComponent(a) + "=" + encodeURIComponent(data[a]); b = "&"; }     req.open("POST", url, true); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); req.send(post); }   //math

function vmpr(v, m) { //vector-matrix product var a, b, r, vl; r = []; vl = v.length; for (a = 0; a < vl; a++) { r[a] = 0; for (b = 0; b * vl < m.length; b++) { r[a] += v[b] * m[a + b * vl]; }   }    return r;  }

function mmpr(m1, m2) { var a, b, c, size, r;   size = Math.sqrt(m1.length); r = []; for (b = 0; b < size; b++) { for (a = 0; a < size; a++) { r[a + size * b] = 0; for (c = 0; c < size; c++) { r[a + size * b] += m1[c + size * b] * m2[a + size * c]; }     }    }    return r;  } imgcapt.setCam = function(camobj) { var tr1, tr2, tr3, r, initial, aspect; var aa, ab, ac, x, y, z;   if (camobj) { aa = camobj.angle[0]; ab = camobj.angle[1]; ac = camobj.angle[2]; x = camobj.pos[0]; y = camobj.pos[1]; z = camobj.pos[2]; imgcapt.fov = camobj.fov; } else { aa = imgcapt.cam.angle[0]; ab = imgcapt.cam.angle[1]; ac = imgcapt.cam.angle[2]; x = imgcapt.cam.pos[0]; y = imgcapt.cam.pos[1]; z = imgcapt.cam.pos[2]; }   imgcapt.cam.angle = [aa, ab, ac]; imgcapt.cam.pos = [x, y, z]; initial = [ 1, 0, 0, 0,     0, 1, 0, 0,      0, 0, 1, 0,      0, 0, 0, 1    ];    tr1 = [1, 0, 0, 0, 0, Math.cos(aa), -Math.sin(aa), 0, 0, Math.sin(aa), Math.cos(aa), 0, 0, 0, 0, 1]; tr2 = [Math.cos(ab), 0, Math.sin(ab), 0, 0, 1, 0, 0, -Math.sin(ab), 0, Math.cos(ab), 0, 0, 0, 0, 1]; tr3 = [Math.cos(ac), -Math.sin(ac), 0, 0, Math.sin(ac), Math.cos(ac), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; r = mmpr(mmpr(mmpr(initial, tr2), tr1), tr3); aspect = imgcapt.el.height / imgcapt.el.width; //fix aspect ratio, scale x   r[0] *= aspect; r[4] *= aspect; r[8] *= aspect; r[3] = r[2] * imgcapt.cam.fov; r[7] = r[6] * imgcapt.cam.fov; r[11] = r[10] * imgcapt.cam.fov; r[12] = x;   r[13] = y;    r[14] = 200; r[15] = z;   if (imgcapt.bobblehead) { r[7] = -1; r[13] -= 200; }   imgcapt.verticleMatrix = r;    return r;  }; imgcapt.controlPanel = function { if (imgcapt.controlel) { imgcapt.controlel.remove; }   var a, root, str, funcs, sp, di, db, re, rc, bobble, paint, up, orc, hh; root = document.createElement("div"); root.style.position = "fixed"; root.style.top = "0px"; root.style.right = "0px"; root.style.zIndex = "100000"; root.style.display = "flex"; root.style.alignItems = "flex-end"; root.style.flexDirection = "column"; root.style.fontFamily = "sans-serif"; root.style.fontSize = "14px"; root.style.textAlign = "center"; root.style.color = "white"; root.style.padding = "2px"; root.style.border = "2px solid black"; root.style.background = "url(http://www.runescape.com/img/rs3/6-box-top.jpg) -1px 0"; root.style.boxShadow = "-2px 2px 10px 1px rgba(0, 0, 0, 0.7)"; root.dragstart = false; root.dragstartangle = false; //override previous funcs if (imgcapt.controlfuncs) { imgcapt.el.removeEventListener("mousedown", imgcapt.controlfuncs.mousedown); imgcapt.el.removeEventListener("mouseup", imgcapt.controlfuncs.mouseup); imgcapt.el.removeEventListener("mousemove", imgcapt.controlfuncs.mousemove); imgcapt.el.removeEventListener("mousewheel", imgcapt.controlfuncs.mousewheel); }   funcs = { mousemove: function(e) { e.preventDefault; if (root.dragstart) { imgcapt.cam.angle = [ (e.offsetY - root.dragstart[0]) * Math.PI / 180 + root.dragstartangle[0], (e.offsetX - root.dragstart[1]) * Math.PI / 180 + root.dragstartangle[1], imgcapt.cam.angle[2] ];         imgcapt.setCam; imgcapt.trypaint; }     },      mousedown: function(e) { e.preventDefault; root.dragstart = [e.offsetY, e.offsetX, 0]; root.dragstartangle = [imgcapt.cam.angle[0], imgcapt.cam.angle[1], imgcapt.cam.angle[2]]; e.preventDefault; },     mouseup: function(e) { e.preventDefault; root.dragstart = false; },     mousewheel: function(e) { imgcapt.cam.pos[2] += e.deltaY; imgcapt.setCam; imgcapt.trypaint; }   };    for (a in imgcapt.controlfuncs) { imgcapt.el.removeEventListener(a, imgcapt.controlfuncs[a], true); }   for (a in funcs) { imgcapt.el.addEventListener(a, funcs[a], true); }   imgcapt.controlfuncs = funcs;

str = ""; //str+=" " sp = " "; re = '$("#3d-yaxis").val(0);$("#3d-xaxis").val(0);imgcapt.cam.pos[0]=0;imgcapt.cam.pos[1]=0;imgcapt.cam.pos[2]=560;imgcapt.cam.angle[0]=0.05;imgcapt.cam.angle[1]=0.25;imgcapt.setCam;imgcapt.setMessage("Default camera position");'; rc = " Reset "; di = '$("#3d-yaxis").val(0);$("#3d-xaxis").val(0);imgcapt.cam.pos[0]=0;imgcapt.cam.pos[1]=0;imgcapt.cam.pos[2]=560;imgcapt.cam.angle[0]=1.5;imgcapt.cam.angle[1]=0;imgcapt.setCam;imgcapt.setMessage("Detailed item image position (top-down)");'; db = " Detail "; orc = "Center Y "; bobble = "Bobble "; paint = "Autopaint "; up = "" + (imgcapt.uploading ? "Cancel" : "Upload") + " "; hh = "Hex Table ";

str = ""; str += "Adventurer's Log 3D Character Viewer UI "; str += ""; str += ""; str += ""; str += " "; str += " " + hh + sp + "Player:  "; str += " " + orc + sp + "Model: <input type='number' min=0 max=250000 style='width:150px;' placeholder='Model (Number)' onkeydown='if(event.keyCode==13){imgcapt.setmodel(this.value);}'/> "; str += " " + paint + sp + "Anim: <input type='number' min=0 max=50000 style='width:150px;' placeholder='Animation ID (Number)' onkeydown='if(event.keyCode==13){imgcapt.setAnim(this.value);}'/> "; str += " " + bobble + sp + "NPC: <input type='number' min=0 max=50000 style='width:150px;' placeholder='NPC ID (Number)' onkeydown='if(event.keyCode==13){imgcapt.setNpc(this.value);}'/> "; str += db + sp + "Y-Axis: <input type='range' value='" + imgcapt.cam.pos[0] + "' min='-600' max='600' step='5' style='width:150px;' oninput='imgcapt.cam.pos[0]=this.value; imgcapt.setCam;' id='3d-yaxis'/> "; str += rc + sp + "X-Axis: <input type='range' value='" + imgcapt.cam.pos[1] + "' min='-600' max='600' step='5' style='width:150px;' oninput='imgcapt.cam.pos[1]=this.value; imgcapt.setCam;' id='3d-xaxis'/> "; str += " "; str += " "; $(up).insertBefore('#advlog-search'); root.innerHTML = str; document.body.appendChild(root); imgcapt.controlel = root; }; imgcapt.printmatrix = function { var str, a, b;   str = "[\n"; for (a = 0; a < 4; a++) { str += " "; for (b = 0; b < 4; b++) { str += imgcapt.verticleMatrix[a * 4 + b].toFixed(1) + ", "; }     str += "\n"; }   return str + "]"; }; imgcapt.printcam = function { console.log(JSON.stringify(imgcapt.cam)); }; imgcapt.setMessage = function(str) { document.getElementById("imgcaptmes") .innerHTML = str; };   // String detect part // API calls

function callString(str) { Module.ccall("SetAppearance", "void", ["string"], [str]); }

function callHex(str) { callString(hexToBase64(str)); }

function callBin(str) { callString(binToBase64(str)); }

function callEquip(itemlist) { var a, b, str; str = "1"; for (a = 0; a < 19; a++) { if (itemlist[a] !== undefined) { b = itemlist[a] + 1 << 14; } else { b = 0; }       str += numToBin(b, 16); }     str += "000000000000000000001001100000111000001110100011000000100000001000000000000000000000000000000000000010101001010000000000000000000000000000"; callBin(str); console.log(str); }   //======== binary stuff ========= curbin = "000000001111111110111110000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

function flipbit(index) { curbin = curbin.substr(0, index) + (curbin[index] == "1" ? "0" : "1") + curbin.substr(index + 1); callBin(curbin); } binindex = 0;

function flipnext { flipbit(binindex); binindex++; return (binindex - 1) .toString(8); }

function flipcurrent { flipbit(binindex - 1); return (binindex - 1) .toString(8); }   //======== conversions ========= chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-*";

function binToBase64(str) { var a, b, r;   r = ""; for (a = 0; a < str.length; a += 6) { b = parseInt(str.substr(a, 6), 2) | 0; r += chars[b]; }   return r;  }

function base64ToBin(str) { var a, b, r;   r = ""; for (a = 0; a < str.length; a++) { b = chars.indexOf(str[a]); r += numToBin(b, 6); }   return r;  }

function hexToBase64(str) { var a, b, r, len; str = str.toUpperCase; len = str.length; str += "000"; //ensure we pad it   r = ""; for (a = 0; a < len; a += 3) { b = parseInt(str.substr(a, 3), 16); r += chars[b >> 6] + chars[b % 64]; }   return r;  }

function base64ToHex(str) { var a, b, r;   r = ""; for (a = 0; a < str.length; a += 2) { b = chars.indexOf(str[a]) * 64; b += chars.indexOf(str[a + 1]); r += numToHex(b, 3); }   return r;  }

function numToHex(n, length) { var a, r;   r = n.toString(16); for (a = r.length; a < length; a++) { r = "0" + r;   } return r.slice(-length); }

function numToBin(n, length) { var a, r;   r = n.toString(2); for (a = r.length; a < length; a++) { r = "0" + r;   } return r; } //======= player info ========== loadedStr = "";

function loadphex(player) { dlpage("http://services.runescape.com/m=avatar-rs/" + encodeURIComponent(player) + "/appearance.dat", function(t) {     if (t.indexOf(" ") != -1) {        return;      }      var hex = base64ToHex(t);      console.log(hex);      loadedStr = hex;      callHex(hex);    }); }

function loadpbin(player) { dlpage("http://services.runescape.com/m=avatar-rs/" + encodeURIComponent(player) + "/appearance.dat", function(t) {     if (t.indexOf(" ") != -1) {        return;      }      var bin = base64ToBin(t);      console.log(bin);      loadedStr = bin;      callBin(bin);    }); }

function hslToRgb(hsl) { var num, rgb, h, s, l;   num = parseInt(hsl, 16); h = num >> 10; s = (num >> 7) & 0x7; l = num & 0x7f; rgb = _hslToRgb(h / 63, s / 7, l / 127); return numToHex((rgb[0] << 16) + (rgb[1] << 8) + rgb[2], 6); }

function rgbToHsl(rgb) { var num, hsl, r, g, b;   num = parseInt(rgb, 16); r = num >> 16; g = (num >> 8) & 0xff; b = num & 0xff; hsl = _rgbToHsl(r, g, b); return numToHex((Math.round(hsl[0] * 63) << 10) + (Math.round(hsl[1] * 7) << 7) + Math.round(hsl[2] * 127), 4); }

function _hslToRgb(h, s, l) { var r, g, b;   if (s === 0) { r = g = b = l; // achromatic } else { var hue2rgb = function hue2rgb(p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t;       if (t < 1 / 2) return q;        if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p;     }; var q = l < 0.5 ? l * (1 + s) : l + s - l * s;     var p = 2 * l - q;      r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); }   return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; }

function _rgbToHsl(r, g, b) { r /= 255, g /= 255, b /= 255; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2; if (max == min) { h = s = 0; // achromatic } else { var d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r:           h = (g - b) / d + (g < b ? 6 : 0); break; case g:           h = (b - r) / d + 2; break; case b:           h = (r - g) / d + 4; break; }       h /= 6; }     return [h, s, l]; }   //======= lib =======

function dlpage(url, func, errorfunc) { var req; req = new XMLHttpRequest; if (func) { req.onload = function { func(req.responseText); };     }      if (errorfunc) { req.onerror = function { errorfunc; };     }      req.open("GET", url, true); req.send; }   //======= other =======

function scanmem(str) { var a, b, r;   r = []; for (a = 0; a < Module.HEAP8.length; a++) { if (a % 10000000 === 0) { console.log("memscan:", a); }     for (b = 0; b < str.length; b++) { if (Module.HEAP8[a + b] != str.charCodeAt(b)) { break; }     }      if (b == str.length) { r.push(a); }   }    console.log(r); }

function testwithmem(str) { callString(str); scanmem(str); }

function escapeHtml(unsafe) { return unsafe.replace(/&/g, "&amp;") .replace(/</g, "&lt;") .replace(/>/g, "&gt;") .replace(/"/g, "&quot;")     .replace(/'/g, "&#039;");  }  function test{    vmpr;    callEquip;    flipnext;    flipcurrent;    loadphex;    loadpbin;    testwithmem;    escapeHtml;  } } setTimeout(ab, 3000);