Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# MarbleGeneratorJS
|
||||||
|
|
||||||
|
Generate a marble-like pattern
|
||||||
|
|
||||||
|
[Live vesrion](https://klemek.github.io/MarbleGeneratorJS/)
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Procedural Marble Generator</title>
|
||||||
|
<link rel="stylesheet" href="marble.css">
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<div id="pan1">
|
||||||
|
<label id="sl">Size of squares</label>
|
||||||
|
<br/>
|
||||||
|
<input type="range" id="s" max="50" min="1"/>
|
||||||
|
<br/>
|
||||||
|
<label id="slol">Slope</label>
|
||||||
|
<br/>
|
||||||
|
<input type="range" id="slo" max="100" min="0" />
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<label id="color">Base Color</label>
|
||||||
|
<br/>
|
||||||
|
<input type="checkbox" id="rand">Random color</input>
|
||||||
|
<br/>
|
||||||
|
<label>Red:</label>
|
||||||
|
<input type="range" id="r" max="255" min="0"/>
|
||||||
|
<br/>
|
||||||
|
<label>Green:</label>
|
||||||
|
<input type="range" id="g" max="255" min="0"/>
|
||||||
|
<br/>
|
||||||
|
<label>Blue:</label>
|
||||||
|
<input type="range" id="b" max="255" min="0"/>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<label id="divl">Divergence</label>
|
||||||
|
<br/>
|
||||||
|
<input type="range" id="divn" max="255" min="0"/>
|
||||||
|
<br/>
|
||||||
|
<label>Red:</label>
|
||||||
|
<input type="range" id="rdiv" max="255" min="0"/>
|
||||||
|
<br/>
|
||||||
|
<label>Green:</label>
|
||||||
|
<input type="range" id="gdiv" max="255" min="0"/>
|
||||||
|
<br/>
|
||||||
|
<label>Blue:</label>
|
||||||
|
<input type="range" id="bdiv" max="255" min="0"/>
|
||||||
|
<br/>
|
||||||
|
<input type="submit" id="reset" value="Reset" />
|
||||||
|
<input type="submit" id="amaze" value="Amaze me !" />
|
||||||
|
</div>
|
||||||
|
<div id="pan2">
|
||||||
|
<label id="sl">Seed</label>
|
||||||
|
<br/>
|
||||||
|
<input id="seedt" type="text" />
|
||||||
|
<br/>
|
||||||
|
<input type="checkbox" id="lock">Lock seed</input>
|
||||||
|
<input type="submit" id="newseed" value="New seed" />
|
||||||
|
</div>
|
||||||
|
<script src="marble.js"></script>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pan1,
|
||||||
|
#pan2 {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
border-radius:5px;
|
||||||
|
z-index: 1;
|
||||||
|
top: .25em;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
background: #262626;
|
||||||
|
color: #aaa;
|
||||||
|
text-align: center;
|
||||||
|
font: 1em trebuchet ms, verdana, sans serif;
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pan1 {
|
||||||
|
left: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pan2 {
|
||||||
|
right: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pan1:hover,
|
||||||
|
#pan2:hover {
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------- Range input -------- */
|
||||||
|
|
||||||
|
input[type='range'] {
|
||||||
|
display: inline-block;
|
||||||
|
margin: .25em auto 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 10em;
|
||||||
|
height: 1.75em;
|
||||||
|
background: none;
|
||||||
|
font-size: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='range']
|
||||||
|
/*input[type='range']::-webkit-slider-runnable-track,
|
||||||
|
input[type='range']::-webkit-slider-thumb*/ {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*input[type='range']::-webkit-slider-runnable-track {
|
||||||
|
width: 10em;
|
||||||
|
height: 0.25em;
|
||||||
|
background: #aaa;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
input[type='range']::-moz-range-track {
|
||||||
|
width: 10em;
|
||||||
|
height: 0.25em;
|
||||||
|
background: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*input[type='range']::-ms-track {
|
||||||
|
border: none;
|
||||||
|
width: 10em;
|
||||||
|
height: 0.25em;
|
||||||
|
background: #aaa;
|
||||||
|
color: transparent;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
input[type='range']::-moz-range-progress {
|
||||||
|
height: 0.25em;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*input[type='range']::-ms-fill-lower {
|
||||||
|
background: white;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*input[type='range']::-webkit-slider-thumb {
|
||||||
|
margin-top: -0.5em;
|
||||||
|
border: none;
|
||||||
|
width: 1.25em;
|
||||||
|
height: 1.25em;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: white;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
input[type='range']::-moz-range-thumb {
|
||||||
|
border: none;
|
||||||
|
width: 1.25em;
|
||||||
|
height: 1.25em;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*input[type='range']::-ms-thumb {
|
||||||
|
border: none;
|
||||||
|
width: 1.25em;
|
||||||
|
height: 1.25em;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: white;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*input[type='range']::-ms-tooltip {
|
||||||
|
display: none;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
input[type='range'] + label {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='range']:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='range']:focus + label {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
'floor|round|max|min|sqrt|pow'
|
||||||
|
.split('|')
|
||||||
|
.forEach(function (p) {
|
||||||
|
window[p] = Math[p];
|
||||||
|
});
|
||||||
|
|
||||||
|
var ctx = canvas.getContext('2d'),
|
||||||
|
width, height, T, Kr, seed0,
|
||||||
|
Kg, Kb, S, w, h, map;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ctx.lineWidth = 0;
|
||||||
|
|
||||||
|
window.onresize = function () {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
var seed = seed0 = Math.random();
|
||||||
|
|
||||||
|
function random() {
|
||||||
|
var x = Math.sin(seed++) * 10000;
|
||||||
|
return x - Math.floor(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
function randint(mi, ma) {
|
||||||
|
return floor(random() * (ma - mi) + mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
function div(k) {
|
||||||
|
return round(random() * 2 * k) - k;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgb(hsl) {
|
||||||
|
var h = hsl[0] / 60,
|
||||||
|
s = hsl[1],
|
||||||
|
l = hsl[2],
|
||||||
|
c = s * (1 - abs(2 * l - 1)),
|
||||||
|
x = c * (1 - abs(h % 2 - 1)),
|
||||||
|
m = l - c / 2,
|
||||||
|
rgb;
|
||||||
|
if (isNaN(h)) {
|
||||||
|
rgb = [0, 0, 0];
|
||||||
|
} else if (h < 1) {
|
||||||
|
rgb = [c, x, 0];
|
||||||
|
} else if (h < 2) {
|
||||||
|
rgb = [x, c, 0];
|
||||||
|
} else if (h < 3) {
|
||||||
|
rgb = [0, c, x];
|
||||||
|
} else if (h < 4) {
|
||||||
|
rgb = [0, x, c];
|
||||||
|
} else if (h < 5) {
|
||||||
|
rgb = [x, 0, c];
|
||||||
|
} else {
|
||||||
|
rgb = [c, 0, x];
|
||||||
|
}
|
||||||
|
return [floor((rgb[0] + m) * 255), floor((rgb[1] + m) * 255), floor((rgb[2] + m) * 255)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function padleft(s, v, n) {
|
||||||
|
while (s.length < n) {
|
||||||
|
s = v + s;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexa(rgb) {
|
||||||
|
return "#" + padleft(rgb[0].toString(16), "0", 2) + padleft(rgb[1].toString(16), "0", 2) + padleft(rgb[2].toString(16), "0", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw(map, T, w, h) {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
for (var j = 0; j < h; j += 1) {
|
||||||
|
map = gen(map, w, j);
|
||||||
|
for (var i = 0; i < w; i += 1) {
|
||||||
|
ctx.fillStyle = hexa(map[i]);
|
||||||
|
ctx.fillRect(i * T, j * T, (i + 1) * T, (j + 1) * T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat(w) {
|
||||||
|
var map = [],
|
||||||
|
i;
|
||||||
|
for (i = 0; i < w; i += 1) {
|
||||||
|
map.push([0, 0, 0]);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gen(map, w, y) {
|
||||||
|
|
||||||
|
map2 = mat(w);
|
||||||
|
|
||||||
|
if (y === 0) {
|
||||||
|
if (rand.checked) {
|
||||||
|
map2[0] = [randint(0, 256), randint(0, 256), randint(0, 256)];
|
||||||
|
} else {
|
||||||
|
map2[0] = [parseInt(r.value), parseInt(g.value), parseInt(b.value)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < w; i += 1) {
|
||||||
|
if (i > 0 && y === 0) {
|
||||||
|
var a1 = map2[i - 1][0],
|
||||||
|
a2 = map2[i - 1][1],
|
||||||
|
a3 = map2[i - 1][2];
|
||||||
|
} else if (y > 0 && i === 0) {
|
||||||
|
var a1 = map[i][0],
|
||||||
|
a2 = map[i][1],
|
||||||
|
a3 = map[i][2];
|
||||||
|
} else if (i > 0 && y > 0) {
|
||||||
|
var a1 = round(S * map2[i - 1][0] + (1 - S) * map[i][0]),
|
||||||
|
a2 = round(S * map2[i - 1][1] + (1 - S) * map[i][1]),
|
||||||
|
a3 = round(S * map2[i - 1][2] + (1 - S) * map[i][2]);
|
||||||
|
}
|
||||||
|
if (i !== 0 || y !== 0) {
|
||||||
|
var v1 = a1 + div(Kr * fn(i, y)),
|
||||||
|
v2 = a2 + div(Kg * fn(i, y)),
|
||||||
|
v3 = a3 + div(Kb * fn(i, y));
|
||||||
|
v1 = max(min(v1, 255), 0);
|
||||||
|
v2 = max(min(v2, 255), 0);
|
||||||
|
v3 = max(min(v3, 255), 0);
|
||||||
|
map2[i] = [v1, v2, v3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fn(x, y) {
|
||||||
|
return 1;
|
||||||
|
/*var r = round(sqrt(pow(x, 2) + pow(y, 2)));
|
||||||
|
if (r % 30 <= 5) {
|
||||||
|
return 3;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
newseed(false);
|
||||||
|
update2();
|
||||||
|
height = canvas.height = window.innerHeight;
|
||||||
|
width = canvas.width = window.innerWidth;
|
||||||
|
T = s.value;
|
||||||
|
Kr = rdiv.value;
|
||||||
|
Kg = gdiv.value;
|
||||||
|
Kb = bdiv.value;
|
||||||
|
S = slo.value / 100;
|
||||||
|
w = floor(width / T) + 1;
|
||||||
|
h = floor(height / T) + 1;
|
||||||
|
draw(map, T, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update2() {
|
||||||
|
sl.textContent = "Size of squares : " + s.value;
|
||||||
|
if (rand.checked) {
|
||||||
|
color.textContent = "Base Color : Random";
|
||||||
|
} else {
|
||||||
|
color.textContent = "Base Color : (" + r.value + "," + g.value + "," + b.value + ")";
|
||||||
|
}
|
||||||
|
if (rdiv.value === gdiv.value && rdiv.value === bdiv.value) {
|
||||||
|
$("div").val(rdiv.value);
|
||||||
|
divl.textContent = "Divergence : " + divn.value;
|
||||||
|
} else {
|
||||||
|
divl.textContent = "Divergence : (" + rdiv.value + "," +
|
||||||
|
gdiv.value + "," + bdiv.value + ")";
|
||||||
|
}
|
||||||
|
slol.textContent = "Slope : " + (slo.value / 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function update3() {
|
||||||
|
rdiv.value = gdiv.value = bdiv.value = divn.value;
|
||||||
|
update2();
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
s.value = 10;
|
||||||
|
rand.checked = true;
|
||||||
|
lock.checked = false;
|
||||||
|
r.value = g.value = b.value = 0;
|
||||||
|
slo.value = 50;
|
||||||
|
divn.value = rdiv.value = gdiv.value = bdiv.value = 20;
|
||||||
|
newseed(false);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
function amaze() {
|
||||||
|
newseed(true);
|
||||||
|
s.value = randint(5, 15);
|
||||||
|
rand.checked = false;
|
||||||
|
r.value = randint(0, 256);
|
||||||
|
g.value = randint(0, 256);
|
||||||
|
b.value = randint(0, 256);
|
||||||
|
slo.value = randint(30, 70);
|
||||||
|
divn.value = 0;
|
||||||
|
rdiv.value = randint(0, 50);
|
||||||
|
gdiv.value = randint(0, 50);
|
||||||
|
bdiv.value = randint(0, 50);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
function newseed(ignore) {
|
||||||
|
if (!lock.checked || ignore) {
|
||||||
|
seedt.value = random();
|
||||||
|
}
|
||||||
|
seed = seed0 = seedt.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function newseedbutton() {
|
||||||
|
newseed(true);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeseed() {
|
||||||
|
lock.checked = true;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
function wheel(e) {
|
||||||
|
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
|
||||||
|
s.value = max(min(parseInt(s.value) + delta, 50), 1);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('input[type=range]').on('input change',function(event){
|
||||||
|
if(event.currentTarget.id != 'div'){
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('#seedt').on('input change',changeseed);
|
||||||
|
$('div').on('input change',update3);
|
||||||
|
$('input[type=checkbox]').on('input',update);
|
||||||
|
|
||||||
|
$('#newseed').click(newseedbutton);
|
||||||
|
$('#reset').click(reset);
|
||||||
|
$('#amaze').click(amaze);
|
||||||
|
|
||||||
|
document.addEventListener("mousewheel", wheel, false);
|
||||||
|
document.addEventListener("DOMMouseScroll", wheel, false);
|
||||||
|
reset();
|
||||||
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user