Skip to content

Commit

Permalink
Added support to toolbelt for autogenerating tilesheets based off images
Browse files Browse the repository at this point in the history
  • Loading branch information
Jbudone committed Jan 20, 2019
1 parent b97b948 commit ef8d224
Show file tree
Hide file tree
Showing 7 changed files with 1,192 additions and 26 deletions.
91 changes: 90 additions & 1 deletion resourceBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ const packageRoutines = {
tilesheet.dirty = true;
tilesheet.newDependencies = sheet.currentList;
tilesheet.sprites = sheet.sprites;

// This may be an image-based dep generated tilesheet, so already exists but output wasn't setup
if (!tilesheet.output) {
tilesheet.output = `sprites/${sheetId}.png`;
}

} else {
data.tilesheets.list.push({
id: sheetId,
Expand Down Expand Up @@ -1026,7 +1032,7 @@ const processGeneratedTilesheet = (package) => {
console.log(package);

const oldDependencies = package.dependencies,
newDependencies = package.newDependencies;
newDependencies = package.newDependencies || [];

const oldSprites = package.oldSprites,
modifiedSprites = package.sprites;
Expand Down Expand Up @@ -1155,6 +1161,81 @@ const processGeneratedTilesheet = (package) => {
});
});

// Append to package.sprites for image based deps
// Should have a different newDependencies list to process as opposed to checking oldDeps here
oldDependencies.forEach((dependency) => {
if (!dependency.imageSrc) return;
package.dependencies.push(dependency);

const relSource = "../" + dependency.previewSrc;

// Does relSource exist? If not then we need to create it first
if (!fs.existsSync(dependency.previewSrc)) {
const processedOutput = execSync(`convert ${dependency.imageSrc} ${dependency.processing} ${dependency.previewSrc}`);
console.log(processedOutput.toString('utf8'));
}

let minY = Number.MAX_SAFE_INTEGER,
minX = Number.MAX_SAFE_INTEGER,
maxY = 0,
maxX = 0;

const spriteIsland = [];
modifiedSprites.forEach((sprite) => {
if (sprite.source !== dependency.imageSrc) return;

package.sprites.push({
source: sprite.source,
sprite: -1,
dstX: sprite.dstX,
dstY: sprite.dstY,
srcX: sprite.srcX,
srcY: sprite.srcY
});

let x = sprite.srcX,
y = sprite.srcY;

minY = Math.min(minY, y);
minX = Math.min(minX, x);
maxY = Math.max(maxY, y);
maxX = Math.max(maxX, x);

let srcX = Math.floor(x / package.tilesize),
srcY = Math.floor(y / package.tilesize),
dstX = Math.floor(sprite.dstX / package.tilesize),
dstY = Math.floor(sprite.dstY / package.tilesize);

// Each dependency is an island
spriteIsland.push({
sprite: sprite.source,
srcX, srcY,
dstX, dstY
});

// FIXME: We should only ever need to extract the entire image, not each individual sprite
// Have an imagesToExtract list which are treated different than spritesToExtract
spritesToExtract.push({
source: relSource,
srcX: x,
srcY: y,
srcW: package.tilesize,
srcH: package.tilesize,
dstX: sprite.dstX,
dstY: sprite.dstY
});

});

genMaxY += (maxY - minY + 1);
genMaxX = Math.max(genMaxX, maxX - minX + 1);

spriteGroups.push({
spriteIsland
});
});


console.log("Generated tilesheet:");
console.log(` Width: ${package.tilesize * genMaxX}`);
console.log(` Height: ${package.tilesize * genMaxY}`);
Expand Down Expand Up @@ -1281,10 +1362,18 @@ const processGeneratedTilesheet = (package) => {
exec(convertCmd, (err, stdout, stderr) => {
if (err) {
console.error(`Error generating tilesheet ${package.id}`);
console.error(err);
console.error(stdout);
console.error(stderr);
fail();
return;
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// FIXME: Map shits expensive
success();
return;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

// Tilesheets are saved as .tsx files; find the .tsx file that refers to this tilesheet
//const matchingTsxBuf = execSync(`grep -ir -H '${package.output}' resources/maps/\*.tsx | awk -F: '{ print $1 }' | xargs`),
Expand Down
112 changes: 107 additions & 5 deletions tools/toolbelt/fs.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,113 @@
$success = file_put_contents($_POST['file'], $data);
$postReq = json_encode($_POST);

}
if ($success) {
echo '{ "success": true }';
} else {
echo '{ "success": false, "data": '.$postReq.' }';
}

exit;

} else if ($request === "fetchImages") {

// Fetch all images in subdirectory
//find resources/sprites -iname '*.png'

ob_start();
//passthru("find /resources/sprites -iname '*.png'");
passthru("find ../../resources/sprites -iname '*.png' | sed 's/^..\/..\///g' | xargs");
$fileListing = ob_get_contents();
ob_end_clean(); //Use this instead of ob_flush()

$fileListing = substr($fileListing, 0, -1); // Get rid of newline; thought xargs -d'\n' would work, but apparently not
$postReq = $fileListing;
echo '{ "success": true, "data": "'.$postReq.'" }';

exit;
} else if ($request === "waitAMin") {

// NOTE: Session will not be allowed to start/resume from further spawns of the same script until the previous
// session has closed. Therefore need to close the sessino before we do any long term synchronous processing
session_start();
if ($_SESSION['waiting']) {
echo '{ "success": false, "reason": "already waiting bro" }';
exit;
} else {

$_SESSION['waiting'] = true;

session_write_close();
sleep(3);
session_start();
echo '{ "success": true }';
$_SESSION['waiting'] = false;
session_write_close();
}
exit;
} else if ($request === "processImage") {

if ($success) {
echo '{ "success": true }';
} else {
echo '{ "success": false, "data": '.$postReq.' }';
// NOTE: Session will not be allowed to start/resume from further spawns of the same script until the previous
// session has closed. Therefore need to close the sessino before we do any long term synchronous processing
session_start();
if ($_SESSION['processingImage'] !== NULL) {
// Cancel previous session somehow (either halt the session/script, or actually kill the pid)
ob_start();
$processingOnPid = $_SESSION['processingImage'];
passthru("kill $processingOnPid");
//ob_get_contents();
ob_end_clean(); //Use this instead of ob_flush()
}

$imageSrc = $_POST['imageSrc'];
$imageProcess = $_POST['process'];
$imagePath = $_POST['outputPath'];
$imageOutput = $_POST['output'];
$imageBasename = $_POST['basename'];

// Does the file already exist?
if (file_exists("../../$imageOutput")) {
echo '{ "success": true, "results": "file already exists" }';
exit;
}

$_SESSION['processingImage'] = getmypid();
session_write_close();

// Process the image, close the session in case we want to make further calls (which will kill this synchronous
// process)
ob_start();
if (!file_exists("../../$imagePath")) {
mkdir("../../$imagePath", 0777);
}

$runCmd = "rm ../../$imagePath/$imageBasename* ; convert ../../$imageSrc $imageProcess ../../$imageOutput";
passthru($runCmd);
$results = ob_get_contents();
ob_end_clean(); //Use this instead of ob_flush()

session_start();
$_SESSION['processingImage'] = NULL;
session_write_close();

echo '{ "success": true, "results": "'.$results.'", "ranCmd": "'.$runCmd.'" }';
exit;
} else if ($request === "cancelProcessImage") {
// Explicitly cancel a previously established process
// This would be used in case we close the image options and no longer need a preview

session_start();
$results = "None";
if ($_SESSION['processingImage'] !== NULL) {
ob_start();
$processingOnPid = $_SESSION['processingImage'];
passthru("kill $processingOnPid");
$results = ob_get_contents();
ob_end_clean(); //Use this instead of ob_flush()
}

$_SESSION['processingImage'] = NULL;
echo '{ "success": true, "results": "'.$results.'" }';
}


82 changes: 82 additions & 0 deletions tools/toolbelt/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,83 @@

<div id="ModTilesheet" class="module">

<div id="tilesheetFolderHierarchyContainer" class="hidden">

<div id="tilesheetFolderHierarchy">

<div class="folderHierarchyFolder folderHierarchyFile level1">
<a href="#" class="folderHierarchyExpandFolder">></a>
<a href="#" class="folderHierarchyFolderName">Folder</a>

<div class="folderHierarchyFolder folderHierarchyFile level2">
<a href="#" class="folderHierarchyExpandFolder">></a>
<a href="#" class="folderHierarchyFolderName">Folder</a>
</div>

<div class="folderHierarchyFolder folderHierarchyFile level2">
<a href="#" class="folderHierarchyExpandFolder">></a>
<a href="#" class="folderHierarchyFolderName">Folder</a>

<div class="folderHierarchyFolder folderHierarchyFile level3">
<a href="#" class="folderHierarchyExpandFolder">></a>
<a href="#" class="folderHierarchyFolderName">Folder</a>
</div>

<div class="folderHierarchyImage folderHierarchyFile level3">
<a href="#" class="folderHierarchyExpandImage">></a>
<a href="#" class="folderHierarchyImageName">Image</a>
</div>

<div class="folderHierarchyImage folderHierarchyFile level3">
<a href="#" class="folderHierarchyExpandImage">></a>
<a href="#" class="folderHierarchyImageName">Image</a>
</div>
</div>

<div class="folderHierarchyFolder folderHierarchyFile level2">
<a href="#" class="folderHierarchyExpandFolder">></a>
<a href="#" class="folderHierarchyFolderName">Folder</a>
</div>
</div>

<div class="folderHierarchyFolder folderHierarchyFile level1">
<a href="#" class="folderHierarchyExpandFolder">></a>
<a href="#" class="folderHierarchyFolderName">Folder</a>
</div>

<div class="folderHierarchyFolder folderHierarchyFile level1">
<a href="#" class="folderHierarchyExpandFolder">></a>
<a href="#" class="folderHierarchyFolderName">Folder</a>
</div>


<div class="folderHierarchyImage folderHierarchyFile level1">
<a href="#" class="folderHierarchyExpandImage">></a>
<a href="#" class="folderHierarchyImageName">Image</a>
</div>
</div>

</div>

<div id="tilesheetFolderHierarchyImageCtrl" class="hidden">
<div class="tilesheetFolderHierarchyImageCtrlContainer">
<span>Image Size: </span>
<input type="text" placeholder="width" val="128" disabled id="tilesheetFolderHierarchyImageCtrlImgSrcW" class="tilesheetFolderHierarchyImageCtrlText" />
<input type="text" placeholder="height" val="64" disabled id="tilesheetFolderHierarchyImageCtrlImgSrcH" class="tilesheetFolderHierarchyImageCtrlText" />

<span> --&gt; </span>
<input type="text" placeholder="width" val="width" id="tilesheetFolderHierarchyImageCtrlImgDstW" class="tilesheetFolderHierarchyImageCtrlText" />
<input type="text" placeholder="height" val="height" id="tilesheetFolderHierarchyImageCtrlImgDstH" class="tilesheetFolderHierarchyImageCtrlText" />
</div>
<div class="tilesheetFolderHierarchyImageCtrlContainer">
<input type="text" placeholder=" -filter box -scale 20% -scale 500% -posterize 7" id="tilesheetFolderHierarchyImageCtrlImgProcess" class="tilesheetFolderHierarchyImageCtrlText" />
</div>
<div class="tilesheetFolderHierarchyImageCtrlContainer" id="tilesheetFolderHierarchyImageCtrlContainerPreview">
<img src="" id="tilesheetFolderHierarchyImageCtrlImgSrc" />
<img src="" id="tilesheetFolderHierarchyImageCtrlImgPreview" />
</div>
</div>

<canvas id='tilesheetCanvas'>
</canvas>

Expand Down Expand Up @@ -69,6 +146,11 @@
</div>
</div>

<div id="tilesheetGeneratedFromImagesContainer" class="tilesheetFieldContainer">
<span class="formLabel">Generate from Images: </span>
<input type="checkbox" id="tilesheetGenerateFromImages" class="right" />
</div>

<div class="tilesheetFieldContainer">
<span class="formLabel">Show Grid: </span>
<input type="checkbox" id="tilesheetShowgrid" class="right" />
Expand Down
4 changes: 0 additions & 4 deletions tools/toolbelt/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@
// Probably best to have post-processing per-extraction group for dependency. Just copies sheet's
// postprocessing initially, and can be edited
//
// - FIXME: Translating sprite island and changing minX/minY causes issues; changing columns is an
// issue? -- If oldColumns != newColumns, probably need to also go through oldSprites for sprite
// islands/collisions/etc. and update oldSprite -> newSprite pos ( % columns)
//
// - Trigger ResourceBuilder on save? Or fuckingtaskrunner to auto run it?
// - Update maps
// - Update other things??? (eg. icons, items, etc.) -- may be better to disallow this for now,
Expand Down
Loading

0 comments on commit ef8d224

Please sign in to comment.