Skip to content

Commit

Permalink
make it URL based
Browse files Browse the repository at this point in the history
  • Loading branch information
greggman committed Apr 30, 2024
1 parent 62c09ca commit cd247df
Show file tree
Hide file tree
Showing 5 changed files with 3,843 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<title>vertexshaderart.com</title>
<link rel="stylesheet" href="css/main.css">
<link href="/static/resources/images/vertexshaderart-icon.png" rel="shortcut icon" type="image/png">
<script src="lzma.js"></script>
</head>
<body>
<div id="art">
Expand Down
35 changes: 34 additions & 1 deletion src/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ define([

"use strict";


const compressor = new LZMA( 'lzma_worker.js' );

// There's really no good way to tell which browsers fail.
// Right now Safari doesn't expose AudioContext (it's still webkitAudioContext)
Expand All @@ -79,6 +79,8 @@ define([
var $ = document.querySelector.bind(document);
var gl;
var m4 = twgl.m4;
const { base64 } = misc;
let s_firstCompile = true;
var q = misc.parseUrlQuery();
var s = {
screenshotCanvas: document.createElement("canvas"),
Expand Down Expand Up @@ -1264,6 +1266,21 @@ define([
settings.shader = e.userData;
setShaderSuccessStatus(true);
clearLineErrors();
if (s_firstCompile) {
s_firstCompile = false;
return;
}
const art = {
settings,
};
const data = JSON.stringify(art);
compressor.compress(data, 1, function(bytes) {
const hex = base64.encode(bytes);
const params = new URLSearchParams({
s: hex
});
parent.history.replaceState({}, '', `/src/#${params.toString()}`);
});
});
s.programManager.on('failure', function(errors) {
setShaderSuccessStatus(false);
Expand Down Expand Up @@ -2188,6 +2205,22 @@ define([
}
}

if (window.location.hash.includes("s=")) {
try {
const p = new URLSearchParams(window.location.hash.substring(1));
const bytes = base64.decode(p.get('s'));
await new Promise((resolve, reject) => {
compressor.decompress(bytes, function(text) {
const art = JSON.parse(text);
settings = art.settings;
resolve();
}, () => {}, reject);
});
} catch {
settings = s.sets.default;
}
}

document.querySelectorAll('.parentLink').forEach(elem => {
elem.addEventListener('click', function(event) {
if (parent) {
Expand Down
8 changes: 8 additions & 0 deletions src/js/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,18 @@ define(function() {
return a === b;
}

const base64 = {
decode: s => Uint8Array.from(atob(s), c => c.charCodeAt(0)),
encode: b => btoa(String.fromCharCode(...new Uint8Array(b))),
decodeToString: s => new TextDecoder().decode(base64.decode(s)),
encodeString: s => base64.encode(new TextEncoder().encode(s)),
};

return {
applyObject: applyObject,
applyUrlSettings: applyUrlSettings,
applyListeners: applyListeners,
base64,
clamp: clamp,
clampPlusMinus: clampPlusMinus,
copyProperties: copyProperties,
Expand Down
126 changes: 126 additions & 0 deletions src/lzma.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/// This code is licensed under the MIT License. See LICENSE for more details.

/// Does the environment support web workers? If not, let's fake it.
if (!Worker) {
///NOTE: IE8 needs onmessage to be created first, IE9 cannot, IE7- do not care.
/*@cc_on
/// Is this IE8-?
@if (@_jscript_version < 9)
var onmessage = function () {};
@end
@*/

/// If this were a regular function statement, IE9 would run it first and therefore make the Worker variable truthy because of hoisting.
var Worker = function(script) {
var global_var,
return_object = {};

/// Determine the global variable (it's called "window" in browsers, "global" in Node.js).
if (typeof window !== "undefined") {
global_var = window;
} else if (global) {
global_var = global;
}

/// Is the environment is browser?
/// If not, create a require() function, if it doesn't have one.
if (global_var.document && !global_var.require) {
global_var.require = function (path) {
var script_tag = document.createElement("script");
script_tag.type ="text/javascript";
script_tag.src = path;
document.getElementsByTagName('head')[0].appendChild(script_tag);
};
}

/// Dummy onmessage() function.
return_object.onmessage = function () {};

/// This is the function that the main script calls to post a message to the "worker."
return_object.postMessage = function (message) {
/// Delay the call just in case the "worker" script has not had time to load.
setTimeout(function () {
/// Call the global onmessage() created by the "worker."
///NOTE: Wrap the message in an object.
global_var.onmessage({data: message});
}, 10);
};

/// Create a global postMessage() function for the "worker" to call.
global_var.postMessage = function (e) {
///NOTE: Wrap the message in an object.
///TODO: Add more properties.
return_object.onmessage({data: e, type: "message"});
};

require(script);

return return_object;
};
}


///NOTE: The "this" keyword is the global context ("window" variable) if loaded via a <script> tag
/// or the function context if loaded as a module (e.g., in Node.js).
this.LZMA = function (lzma_path) {
var action_compress = 1,
action_decompress = 2,
action_progress = 3,

callback_obj = {},

///NOTE: Node.js needs something like "./" or "../" at the beginning.
lzma_worker = new Worker((typeof lzma_path === "undefined" ? "./lzma_worker.js" : lzma_path));

lzma_worker.onmessage = function (e) {
if (e.data.action === action_progress) {
if (callback_obj[e.data.callback_num] && typeof callback_obj[e.data.callback_num].on_progress === "function") {
callback_obj[e.data.callback_num].on_progress(e.data.result);
}
} else {
if (callback_obj[e.data.callback_num] && typeof callback_obj[e.data.callback_num].on_finish === "function") {
callback_obj[e.data.callback_num].on_finish(e.data.result);

/// Since the (de)compression is complete, the callbacks are no longer needed.
delete callback_obj[e.data.callback_num];
}
}
};

/// Very simple error handling.
lzma_worker.onerror = function(event) {
throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
};

return (function () {

function send_to_worker(action, data, mode, on_finish, on_progress) {
var callback_num;

do {
callback_num = Math.floor(Math.random() * (10000000));
} while(typeof callback_obj[callback_num] !== "undefined");

callback_obj[callback_num] = {
on_finish: on_finish,
on_progress: on_progress
};

lzma_worker.postMessage({
action: action,
callback_num: callback_num,
data: data,
mode: mode
});
}

return {
compress: function (string, mode, on_finish, on_progress) {
send_to_worker(action_compress, String(string), mode, on_finish, on_progress);
},
decompress: function (byte_arr, on_finish, on_progress) {
send_to_worker(action_decompress, byte_arr, false, on_finish, on_progress);
}
};
}());
};
Loading

0 comments on commit cd247df

Please sign in to comment.