-
Notifications
You must be signed in to change notification settings - Fork 7
Improve demo, simplify user experience #20
base: master
Are you sure you want to change the base?
Changes from 11 commits
651e3e9
fdc7f03
6d75f79
0b50a51
1c7a155
80e728b
f2a2a47
2ef49bd
942adca
51ea0ce
2fc4d0b
f0bad0b
b02e3f1
41feeb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
dist/js | ||
dist/index.html |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
const replace = require('replace-in-file'); | ||
const fse = require('fs-extra'); | ||
const path = require('path'); | ||
|
||
const YMLUtil = require('binaris/lib/binarisYML'); | ||
|
||
const { getAccountId, getAPIKey, getRealm } = require('binaris/lib/userConf'); | ||
const { forceRealm } = require('binaris/sdk'); | ||
|
||
const backendYAMLPath = path.join(__dirname, 'fractal_backend'); | ||
const servingYAMLPath = path.join(__dirname, 'dist'); | ||
|
||
async function getServingFuncName() { | ||
const binarisConf = await YMLUtil.loadBinarisConf(servingYAMLPath); | ||
return YMLUtil.getFuncName(binarisConf); | ||
} | ||
|
||
async function getBackendFuncName() { | ||
const binarisConf = await YMLUtil.loadBinarisConf(backendYAMLPath); | ||
return YMLUtil.getFuncName(binarisConf); | ||
} | ||
|
||
async function getPublicPath(accountID, endpoint) { | ||
process.env.BINARIS_INVOKE_ENDPOINT = endpoint; | ||
const { getInvokeUrl } = require('binaris/sdk/url'); | ||
const servingName = await getServingFuncName(); | ||
const savedEndpoint = process.env.BINARIS_INVOKE_ENDPOINT; | ||
const invokeURL = await getInvokeUrl(accountID, servingName); | ||
process.env.BINARIS_INVOKE_ENDPOINT = savedEndpoint; | ||
return invokeURL; | ||
} | ||
|
||
async function getFractalURL(accountID) { | ||
const { getInvokeUrl } = require('binaris/sdk/url'); | ||
const backendName = await getBackendFuncName(); | ||
return getInvokeUrl(accountID, backendName); | ||
} | ||
|
||
async function replaceHTMLAccountID(accountID) { | ||
const templatePath = path.join(__dirname, 'template.html'); | ||
const destPath = path.join(__dirname, 'dist', 'index.html'); | ||
await fse.copy(templatePath, destPath, { overwrite: true, errorOnExist: false }); | ||
|
||
const options = { | ||
files: destPath, | ||
from: /<BINARIS_ACCOUNT_NUMBER>/g, | ||
to: accountID, | ||
}; | ||
await replace(options) | ||
} | ||
|
||
async function prebuild() { | ||
const realm = await getRealm(); | ||
if (realm) { | ||
forceRealm(realm); | ||
} | ||
const accountID = await getAccountId(undefined); | ||
await replaceHTMLAccountID(accountID); | ||
const FRACTAL_ENDPOINT = await getFractalURL(accountID); | ||
const PUBLIC_PATH = (await getPublicPath(accountID, ' ')).slice(8); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we |
||
return { | ||
FRACTAL_ENDPOINT, | ||
PUBLIC_PATH, | ||
}; | ||
} | ||
|
||
module.exports = { prebuild }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "fractal-frontend", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "servePage.js", | ||
"scripts": {}, | ||
"keywords": [], | ||
"author": "Ryland Goldstein", | ||
"license": "MIT", | ||
"dependencies": { | ||
"mime-types": "^2.1.21", | ||
"mz": "^2.7.0", | ||
"path": "^0.12.7" | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
functions: | ||
public_fractal: | ||
file: fractal.js | ||
entrypoint: handler | ||
runtime: node8 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* eslint-disable no-console,no-bitwise */ | ||
const noiseGen = require('./noiseGen'); | ||
const simplify = require('./simplify'); | ||
|
||
function makeHeaders(blockCount, maxHeight, | ||
payloadBytes, genTime) { | ||
const statusHeaders = { | ||
'X-Gen-Data-Blockcount': blockCount, | ||
'X-Gen-Data-Max-Height': maxHeight, | ||
'X-Gen-Data-Payload-Bytes': payloadBytes, | ||
'X-Gen-Data-Time-Running-MS': genTime, | ||
}; | ||
const customHeaders = { | ||
'Access-Control-Expose-Headers': Object.keys(statusHeaders).join(', '), | ||
'Content-Type': 'application/octet-stream', | ||
'Access-Control-Allow-Origin': '*', | ||
'Access-Control-Allow-Headers': 'Origin X-Requested-With, Content-Type, Accept', | ||
... statusHeaders, | ||
}; | ||
return customHeaders; | ||
} | ||
|
||
exports.handler = async (body, ctx) => { | ||
const { | ||
downscale, | ||
heightFactor, | ||
numTex, | ||
size, | ||
xPos, | ||
yPos, | ||
zPos, | ||
} = ctx.request.query; | ||
|
||
let respBody; | ||
let headers; | ||
let statusCode = 500; | ||
const genStartTime = process.hrtime(); | ||
|
||
const { blockCount, data, maxHeight } = noiseGen( | ||
parseInt(xPos, 10), parseInt(yPos, 10), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be cleaner to have all |
||
parseInt(zPos, 10), parseInt(size, 10), | ||
numTex, downscale, parseInt(heightFactor, 10) | ||
); | ||
if (blockCount === 0) { | ||
const failedGenTime = process.hrtime(genStartTime); | ||
const genStr = (failedGenTime[0] * 1000) + (failedGenTime[1] / 1000000); | ||
headers = makeHeaders(blockCount, maxHeight, 0, genStr); | ||
respBody = new Buffer(2); | ||
statusCode = 200; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code-style: my preference would be to have an early-return here (but would require moving into a separate function). |
||
} else { | ||
const { indices, mats, normals, tex, verts } = simplify( | ||
data, size, size, size, | ||
parseInt(xPos, 10), parseInt(yPos, 10), | ||
parseInt(zPos, 10), heightFactor, numTex, | ||
); | ||
|
||
// how many elements make up the lookup table | ||
const tableElements = 4; | ||
|
||
const mergedData = new Int16Array(verts.length + indices.length | ||
+ normals.length + tex.length + mats.length + tableElements); | ||
|
||
// this is an unfortunate bit of logic required to make sure | ||
// that our buffers length value doesn't get truncated/overflowed | ||
// in the lookup table. | ||
function split32BitValue(value) { | ||
return [value & 0xFFFF, (value >> 16) & 0xFFFF]; | ||
} | ||
const splitVertsLength = split32BitValue(verts.length); | ||
const splitTexLength = split32BitValue(tex.length); | ||
mergedData[0] = splitVertsLength[0]; | ||
mergedData[1] = splitVertsLength[1]; | ||
mergedData[2] = splitTexLength[0]; | ||
mergedData[3] = splitTexLength[1]; | ||
|
||
mergedData.set(verts, tableElements); | ||
mergedData.set(normals, tableElements + verts.length); | ||
mergedData.set(tex, tableElements + verts.length + normals.length); | ||
mergedData.set(mats, tableElements + verts.length + normals.length + tex.length); | ||
mergedData.set(indices, verts.length + tableElements + normals.length + tex.length + mats.length); | ||
|
||
respBody = Buffer.from(mergedData.buffer); | ||
console.log(`buffer size is ${respBody.length / 1000}`); | ||
|
||
const genTime = process.hrtime(genStartTime); | ||
const genDataTimeStr = (genTime[0] * 1000) + (genTime[1] / 1000000); | ||
headers = makeHeaders(blockCount, maxHeight, respBody.length, genDataTimeStr); | ||
statusCode = 200; | ||
} | ||
if (ctx.request.query.express_server) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about instead of adding a fake |
||
ctx.set(headers); | ||
return ctx.send(respBody); | ||
} | ||
return new ctx.HTTPResponse({ | ||
statusCode, | ||
headers, | ||
body: respBody, | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,16 @@ const SimplexNoise = require('simplex-noise'); | |
|
||
const simplex = new SimplexNoise('default'); | ||
|
||
function getMat(currHeight, maxHeight, numColors) { | ||
const heightIncr = maxHeight / numColors; | ||
for (let i = 0; i < numColors; i += 1) { | ||
if (currHeight <= i * heightIncr) { | ||
return i; | ||
} | ||
} | ||
return numColors - 1; | ||
} | ||
|
||
/** | ||
* Create a volumetric density field representing the state | ||
* of a given region of terrain. | ||
|
@@ -14,7 +24,7 @@ const simplex = new SimplexNoise('default'); | |
* @param {number} scaleHeight - sets the defacto maxHeight of the volume | ||
* @return {object} - generated data and metadata | ||
*/ | ||
function createDensities(cX, cZ, size, downscale = 1000, scaleHeight = 50) { | ||
function createDensities(cX, cY, cZ, size, numColors, downscale = 1000, scaleHeight = 50) { | ||
let maxHeight = -1; | ||
let minHeight = 10000; | ||
let blockCount = 0; | ||
|
@@ -42,20 +52,34 @@ function createDensities(cX, cZ, size, downscale = 1000, scaleHeight = 50) { | |
} | ||
} | ||
} | ||
// if the calculated max height isn't divisible by | ||
// the volume size granularity, we need to modify it | ||
// to be an increment of size. | ||
if (maxHeight % size !== 0) { | ||
maxHeight = Math.ceil(maxHeight / size) * size; | ||
|
||
if ((minHeight) > (cY + size)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: extra parentheses? |
||
return { | ||
blockCount: 0, | ||
data: [], | ||
maxHeight, | ||
minHeight, | ||
}; | ||
} | ||
const densities = new Int8Array(size * size * maxHeight).fill(1); | ||
|
||
let maxRelevantHeight = maxHeight; | ||
if (maxHeight > (cY + size)) { | ||
maxRelevantHeight = size; | ||
} else { | ||
maxRelevantHeight = maxHeight - cY; | ||
} | ||
|
||
const densities = new Int8Array(size * size * size).fill(1); | ||
let currIdx = -1; | ||
for (let i = 0; i < size; i += 1) { | ||
for (let j = 0; j < maxHeight; j += 1) { | ||
for (let j = 0; j < size; j += 1) { | ||
for (let k = 0; k < size; k += 1) { | ||
currIdx = i + (j * size) + (k * maxHeight * size); | ||
densities[currIdx] = (j <= heights[i + (k * size)]) ? 1 : 0; | ||
blockCount += densities[currIdx]; | ||
currIdx = i + (j * size) + (k * size * size); | ||
densities[currIdx] = ((j + cY) <= heights[i + (k * size)]) ? 1 : 0; | ||
if (densities[currIdx] !== 0) { | ||
densities[currIdx] = getMat(j + cY, scaleHeight, numColors); | ||
blockCount += 1; | ||
} | ||
} | ||
} | ||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is overriding
process.env.BINARIS_INVOKE_ENDPOINT
before storing it insavedEndpoint
a bug?Also, this assumes that
binaris/sdk/url
behaves in a certain way - if you need a specific functionality from the SDK maybe this function should be in the SDK?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this whole function with the sandbox shutdown?