Skip to content

Instantly share code, notes, and snippets.

@profexorgeek
Last active May 22, 2019 14:02
Show Gist options
  • Save profexorgeek/05c882de8414166ad02b6cd3198d9c62 to your computer and use it in GitHub Desktop.
Save profexorgeek/05c882de8414166ad02b6cd3198d9c62 to your computer and use it in GitHub Desktop.
Single page web application that allows quick and easy mapping of spritesheet textures
<!DOCTYPE html>
<html lang="en">
<head>
<title>Texture Mapping Helper</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
html, body, div, img {
margin:0;
padding:0;
font-family: Arial, Helvetica, sans-serif;
font-size: 10pt;
color: #444;
}
h1, h2, h3, h4, h5, h6 {
font-size: 12pt;
}
div#imagediv {
min-width: 100px;
min-height: 100px;
display: inline-block;
background: slategrey;
}
div.rect {
outline:1px dashed yellow;
outline-offset: -1px;
z-index: 999;
}
div.rect:hover {
outline:1px dashed red;
}
div.controls {
padding:8px;
}
div#output {
border: 1px dashed slategray;
margin:10px;
min-height: 10px;
}
p.instructions {
font-size:9pt;
font-style:italic;
}
</style>
</head>
<body>
<div class="container">
<div id="imagediv"></div>
<div class="controls">
<h1>Texture Mapping Helper</h1>
<p class="instructions">Drag and drop an image on the box above. Click and drag to create texture rectangles. Click an existing rectangle to delete it. Change the snapping below.</p>
<p><label for="snapincrement">Snap To: </label><input id="snapincrement" type="text" size="2" value="32"/>px</p>
<h2>Output</h2>
<div id="output"></div>
</div>
</div>
<script type="text/javascript">
var imageLoaded = false;
var rects = [];
var currentRect = null;
var dropZone = document.getElementById('imagediv');
var snapIncrement = document.getElementById('snapincrement');
var output = document.getElementById('output');
var gridImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkQ1Rjk3NTkwN0M0MTExRTlBRDdEQUY1OTFBMDU2Q0VFIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkQ1Rjk3NTkxN0M0MTExRTlBRDdEQUY1OTFBMDU2Q0VFIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RDVGOTc1OEU3QzQxMTFFOUFEN0RBRjU5MUEwNTZDRUUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RDVGOTc1OEY3QzQxMTFFOUFEN0RBRjU5MUEwNTZDRUUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6ZiAjnAAACH0lEQVR42uzdQW7aQBSAYWdsqMUCKRsS9QrkKu0JeuzkChVZZBMFpKj2TB16AT+pxlh8/4IVTIb3JUaKbHP34+evqqrqp9dqXHXdVJFyeyrH9fjnR9fv+y70/OvZf355HB6bf9Pvnx9GvuyuWcUGtPko79/GPz+6ftm95d/b6dafbv9pfxgMUmj6+o99TX9/SAYxbwAAABAAAAIAQAAACAAAAbidmrpuQv+h7bo/oR+wapoy7fqrtNj9133nL8AhCIAAABAAAAIAQAAACAAAAQCgC9Tk9tRvPsa/YNXEzq/vuq6acv3cHvMmLXT/aZubclyHzn8vwfPrq+D59dH1S7vg/Q/DdwjyGQBAAAAIAAABACAAAAQAgADcRq4PmHP/rg9wCAJgBAAACAAAAQAgAAAEAIAAAFhKJXLr9Cus6fuu7N7Gv2AVPL07t8fSridaf5h+Pt++Pn1/X+L+0+7z62qC0P33U/QNbFLo/Prw+ufNj38LV7X/cn9a/CFo/O++zwABACAAAAQAgAAAEAAAAIwAwE3n+oA59+/6AIcgAEYAAIAAABAAAAIAQAAACAAAXSbfHzDn/n1/wMz79/0BPgMAGAEAAAIAQAAACAAAAQAgADeT6wPm3L/rAxyCABgBAAACAEAAAAgAAAEAoAsC5JfHtD8YxOWrn17754fz3dMjBnXfxYS3uRwDt38Pr7/7LPenCdefbP/D9IfHvwIMANUw7ym/L+NBAAAAAElFTkSuQmCC";
dropZone.addEventListener('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = "copy";
console.log("File has been dragged over drop zone.");
});
dropZone.addEventListener('drop', function (e) {
e.stopPropagation();
e.preventDefault();
console.log("File has been dropped in drop zone.");
var files = e.dataTransfer.files;
for(var i = 0, file; file = files[i]; i++) {
if(file.type.match(/image.*/)) {
var reader = new FileReader();
reader.onload = function (e2) {
var img = document.createElement('img');
img.src = e2.target.result;
dropZone.appendChild(img);
imageLoaded = true;
applyBackground();
console.log("Adding image...")
}
console.log("Reading image file...");
reader.readAsDataURL(file);
}
}
});
dropZone.addEventListener('mousedown', function (e) {
if(imageLoaded) {
e.stopPropagation();
e.preventDefault();
var x = e.clientX + document.documentElement.scrollLeft;
var y = e.clientY + document.documentElement.scrollTop;
currentRect = createRect(x, y);
}
});
dropZone.addEventListener('mousemove', function (e) {
if(imageLoaded && currentRect != null) {
var rectLeft = parseInt(currentRect.style.left);
var rectTop = parseInt(currentRect.style.top)
var x = e.clientX + document.documentElement.scrollLeft;
var y = e.clientY + document.documentElement.scrollTop;
updateRect(currentRect, rectLeft, rectTop, x, y);
}
});
dropZone.addEventListener('mouseup', function (e) {
if(imageLoaded && currentRect != null) {
currentRect = null;
renderRectangleList();
}
});
function getOffset() {
return {
x: dropZone.offsetLeft - dropZone.scrollLeft + dropZone.clientLeft,
y: dropZone.offsetTop - dropZone.scrollTop + dropZone.clientTop
};
}
function getSnap() {
return parseInt(snapIncrement.value);
}
function updateRect(rect, left, top, right, bottom) {
var snap = getSnap();
var offset = getOffset();
left = Math.floor(left / snap) * snap + offset.x;
top = Math.floor(top / snap) * snap + offset.y;
right = Math.round(right / snap) * snap + offset.x;
bottom = Math.round(bottom / snap) * snap + offset.y;
width = Math.max(right - left, snap);
height = Math.max(bottom - top, snap);
console.log('Updating rect to: ' + left + ',' + top + ',' + width + ',' + height);
rect.style.position = 'absolute';
rect.style.top = top + 'px';
rect.style.left = left + 'px';
rect.style.width = width + 'px';
rect.style.height = height + 'px';
}
function createRect(x, y) {
var snap = getSnap();
var rect = document.createElement('div');
rect.classList.add('rect');
updateRect(rect, x, y, x + snap, y + snap);
dropZone.insertBefore(rect, dropZone.firstChild);
rects.push(rect);
console.log('Created rect at ' + x + ', ' + y);
rect.addEventListener('mousedown', function (e) {
e.stopPropagation();
e.preventDefault();
dropZone.removeChild(rect);
var index = rects.indexOf(rect);
rects.splice(index, 1,);
renderRectangleList();
});
return rect;
}
function renderRectangleList() {
var rectList = "";
for(var i = 0; i < rects.length; i++) {
var x = parseInt(rects[i].style.left) - dropZone.offsetLeft;
var y = parseInt(rects[i].style.top) - dropZone.offsetTop;
var width = parseInt(rects[i].style.width);
var height = parseInt(rects[i].style.height);
rectList += 'new Rectangle(' + x + ',' + y + ',' + width + ',' + height + '),<br />';
}
output.innerHTML = rectList;
}
function applyBackground() {
dropZone.style.background = 'url("' + gridImg + '")';
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment