Skip to content

Commit

Permalink
Version 0.2.0: Support for portraits.
Browse files Browse the repository at this point in the history
This fixes #2
  • Loading branch information
Haroldo de Oliveira Pinheiro committed Dec 24, 2020
2 parents 2bc44f2 + aa38021 commit db69237
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 4 deletions.
9 changes: 9 additions & 0 deletions blockly/apps/blocklyduino/base-project/src/vn_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,15 @@ void waitJoyButtonRelease() {
}

void drawScene() {
unsigned char* chunk = 0;

LoadBitmap(backgroundImage);

LoadChunk(&chunk, actorImage);
if (chunk) {
SetChunk(chunk, 12, 8);
free(chunk);
}
}

void initGfx() {
Expand Down Expand Up @@ -206,6 +214,7 @@ void vnScene(char *scene) {

void vnShow(char *actor) {
actorImage = actor;
drawScene();
}

void vnChar(char *charName) {
Expand Down
125 changes: 124 additions & 1 deletion blockly/apps/blocklyduino/blockly_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ async function compile() {
await delay(500);
await copyImageFiles();
await convertImages();

const portraits = await copyPortraitFiles();
await generateChunkDefinitions(portraits);
await convertPortraits();

await generateBuildScripts();

printToConsole('Compilation done!');
Expand Down Expand Up @@ -226,16 +231,133 @@ const copyStandardSourceFiles = async () => {
const listBackgroundImages = () => Object.values(Blockly.Arduino.images_)
.filter(o => o.imgType === 'background');

const listPortraitImages = () => Object.values(Blockly.Arduino.images_)
.filter(o => o.imgType === 'portrait');

const copyImageFiles = async () => {
return Promise.all(listBackgroundImages().map(({imgName, imgAbbrev}) =>
copyFile(`${project.bg.path}/${imgName}.png`, `${targetPath()}/bitmaps/${imgAbbrev}.png`)))
}

const copyPortraitFiles = async () => {
return Promise.all(listPortraitImages().map(copyPortraitFile))
}

const copyPortraitFile = async ({imgName, imgAbbrev}) => {
const img = await loadImage(`${project.portrait.path}/${imgName}.png`);

const canvas = document.createElement('canvas');
canvas.width = 320;
canvas.height = 200;

const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);

// Calculate image size to fit
const maxHeight = 120;
let imgWidth = img.width;
let imgHeight = img.height;
if (imgHeight > maxHeight) {
imgWidth = Math.round(imgWidth * maxHeight / imgHeight);
imgHeight = maxHeight;
}

// Center horizontally, allign to bottom
const x = Math.round((canvas.width - imgWidth) / 2);
const y = canvas.height - imgHeight;
ctx.drawImage(img, x, y, imgWidth, imgHeight);

await saveCanvasToImage(canvas, `${targetPath()}/chunks/${imgAbbrev}.png`);

return {x, y, w: imgWidth, h: imgHeight, imgName, imgAbbrev};
}

const loadImage = async path => {
return await new Promise((resolve, reject) => {
const img = new Image();
img.src = 'file:/' + path.replace(/\\/g, '/');
img.onload = () => resolve(img);
img.onerror = reject;
});
}

const saveCanvasToImage = async (canvas, path) => {
return await new Promise((resolve, reject) => {
// Get the DataUrl from the Canvas
const url = canvas.toDataURL('image/png');

// remove Base64 stuff from the Image
const base64Data = url.replace(/^data:image\/png;base64,/, "");
fs.writeFile(path, base64Data, 'base64', err => {
if (err) {
reject(err);
return;
}

resolve();
});
});
}

const generateChunkDefinitions = async portraits => {
PLATFORMS = [
{name: 'apple', w: 140, h: 192, mulX: 7, mulY: 1},
{name: 'atari', w: 160, h: 200, mulX: 4, mulY: 1},
{name: 'c64', w: 160, h: 200, mulX: 4, mulY: 8},
{name: 'lynx', w: 160, h: 102, mulX: 2, mulY: 1},
{name: 'oric', w: 240, h: 200, mulX: 3, mulY: 2}
];

const definitions = PLATFORMS.map(platform => {
const lines = portraits.map(portrait => {
const scaleX = platform.w / 320;
const scaleY = platform.h / 200;

const x1 = Math.floor(portrait.x * scaleX / platform.mulX) * platform.mulX;
const y1 = Math.floor(portrait.y * scaleY / platform.mulY) * platform.mulY;

let x2 = Math.ceil((portrait.x + portrait.w) * scaleX / platform.mulX) * platform.mulX;
x2 = Math.min(platform.w, x2);
let y2 = Math.ceil((portrait.y + portrait.h) * scaleY / platform.mulY) * platform.mulY;
y2 = Math.min(platform.h, y2);

const w = x2 - x1;
const h = y2 - y1;

return `'${portrait.imgAbbrev}-${platform.name}.png', '${portrait.imgAbbrev}.cnk', [${x1}, ${y1}, ${w}, ${h}]\t# ${portrait.imgName}`;
});

return {
name: `chunks-${platform.name}.txt`,
content: `# Chunks definition file\n\n${lines.join('\n')}\n`
};
});

await Promise.all(definitions.map(({name, content}) => new Promise((resolve, reject) => {
fs.writeFile(`${targetPath()}/chunks/${name}`, content, function(err) {
if (err) {
console.warn('Error writing ' + name, err);
reject(err);
return;
}

printToConsole("The chunk file was saved: " + name);
resolve(name);
});
})));

}

const convertImages = async () => {
return Promise.all(listBackgroundImages().map(({imgAbbrev}) =>
execPython(`${path.resolve(scriptsPath())}/convert-images.py "${targetPath()}/bitmaps/${imgAbbrev}.png"`)))
}

const convertPortraits = async () => {
return Promise.all(listPortraitImages().map(({imgAbbrev}) =>
execPython(`${path.resolve(scriptsPath())}/convert-images.py "${targetPath()}/chunks/${imgAbbrev}.png"`)))
}

const generateBuildScripts = async () => {
return execBuilder(` -projectFile projects/${project.current.name}/test.builder ` +
'-useGUI False -callEmu True');
Expand All @@ -249,7 +371,8 @@ const generateBuilderProject = () => {
.map(platformName => {
return [platformName, {
bitmap: listBackgroundImages().map(({imgName, imgAbbrev}) =>
`${projDir}bitmaps/${imgAbbrev}-${platformName.toLowerCase()}.png`)
`${projDir}bitmaps/${imgAbbrev}-${platformName.toLowerCase()}.png`),
chunks: [ `${projDir}chunks/chunks-${platformName.toLowerCase()}.txt` ]
}];
});

Expand Down
4 changes: 2 additions & 2 deletions blockly/generators/arduino/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
(function(){

// Convert the filename into something that can be used by 8bit-Unity
const prepareFileName = name => name.toLowerCase().replace(/[^a-z0-9_]+/g, '').substring(0, 8);
const prepareFileName = name => name.toLowerCase().replace(/[^a-z0-9]+/g, '').substring(0, 8);

const getImageAbbreviation = imgName => {
let imgAbbrev = Blockly.Arduino.imageAbbrevs_.fullToAbbrev[imgName];
Expand Down Expand Up @@ -35,7 +35,7 @@ function getImage(component, imgType) {

let imgName = source.getText();
let imgAbbrev = getImageAbbreviation(imgName);
let imgExt = imgType == 'portrait' ? 'chk' : 'img';
let imgExt = imgType == 'portrait' ? 'cnk' : 'img';

Blockly.Arduino.images_[imgName] = {
imgType, imgName, imgAbbrev,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "BlocklyVN8bit",
"version": "0.1.1",
"version": "0.2.0",
"description": "Uses blockly to generate visual novels for 8bit-Unity",
"main": "main.js",
"scripts": {
Expand Down

0 comments on commit db69237

Please sign in to comment.