mirror of
https://github.com/boxgaming/qbjs.git
synced 2024-05-12 08:00:12 +00:00
Compare commits
5 commits
fe0bf4a223
...
0187c6ce84
Author | SHA1 | Date | |
---|---|---|---|
0187c6ce84 | |||
95b2be9d60 | |||
9005215ca0 | |||
030c8ac983 | |||
1c3d787ce4 |
173
gx/gx.js
173
gx/gx.js
|
@ -5,6 +5,7 @@ var GX = new function() {
|
|||
var _bg = [];
|
||||
var _images = [];
|
||||
var _entities = [];
|
||||
var _entities_active = [];
|
||||
var _entity_animations = [];
|
||||
var _scene = {};
|
||||
var _tileset = {};
|
||||
|
@ -37,8 +38,6 @@ var GX = new function() {
|
|||
var _vfs = new VFS();
|
||||
var _vfsCwd = null;
|
||||
|
||||
var _glcanvas = null;
|
||||
|
||||
// javascript specific
|
||||
var _onGameEvent = null;
|
||||
var _pressedKeys = {};
|
||||
|
@ -59,7 +58,6 @@ var GX = new function() {
|
|||
function _reset() {
|
||||
// stop any sounds that are currently playing
|
||||
_soundStopAll();
|
||||
|
||||
_framerate = 60;
|
||||
_bg = [];
|
||||
_images = [];
|
||||
|
@ -216,11 +214,6 @@ var GX = new function() {
|
|||
_canvas.height = height;
|
||||
_ctx = _canvas.getContext("2d");
|
||||
|
||||
//_glcanvas.width = width;
|
||||
//_glcanvas.height = height;
|
||||
//_glctx = _glcanvas.getContext("webgl");
|
||||
////__GL.init(_glctx);
|
||||
|
||||
var footer = document.getElementById("gx-footer");
|
||||
footer.style.width = width;
|
||||
|
||||
|
@ -297,8 +290,7 @@ var GX = new function() {
|
|||
// handled externally.
|
||||
function _sceneDraw() {
|
||||
if (_map_loading) { return; }
|
||||
var ei, ei2, frame;
|
||||
frame = _scene.frame % GX.frameRate() + 1;
|
||||
var frame = _scene.frame % GX.frameRate() + 1;
|
||||
|
||||
// If the screen has been resized, resize the destination screen image
|
||||
//If _Resize And Not GXSceneEmbedded Then
|
||||
|
@ -318,6 +310,17 @@ var GX = new function() {
|
|||
// Call out to any custom screen drawing
|
||||
_customDrawEvent(GX.EVENT_DRAWBG);
|
||||
|
||||
// Initialize the renderable entities
|
||||
_entities_active = [];
|
||||
for (var ei=1; ei <= _entities.length; ei++) {
|
||||
var e = _entities[ei-1];
|
||||
if (!e.screen) {
|
||||
if (_rectCollide(e.x, e.y, e.width, e.height, GX.sceneX(), GX.sceneY(), GX.sceneWidth(), GX.sceneHeight())) {
|
||||
_entities_active.push(ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the map tiles
|
||||
GX.mapDraw();
|
||||
|
||||
|
@ -325,19 +328,7 @@ var GX = new function() {
|
|||
_customDrawEvent(GX.EVENT_DRAWMAP);
|
||||
|
||||
// Draw the entities
|
||||
for (var ei = 1; ei <= _entities.length; ei++) {
|
||||
var e = _entities[ei-1];
|
||||
if (!e.screen) {
|
||||
if (_rectCollide(e.x, e.y, e.width, e.height, GX.sceneX(), GX.sceneY(), GX.sceneWidth(), GX.sceneHeight())) {
|
||||
_entityDraw(e);
|
||||
}
|
||||
}
|
||||
if (e.animate > 0) {
|
||||
if (frame % (GX.frameRate() / e.animate) == 0) {
|
||||
GX.entityFrameNext(ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
_drawEntityLayer(0);
|
||||
|
||||
// Draw the screen entities which should appear on top of the other game entities
|
||||
// and have a fixed position
|
||||
|
@ -345,6 +336,9 @@ var GX = new function() {
|
|||
var e = _entities[ei-1];
|
||||
if (e.screen) {
|
||||
_entityDraw(e);
|
||||
if (frame % (GX.frameRate() / e.animate) == 0) {
|
||||
GX.entityFrameNext(ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,12 +361,6 @@ var GX = new function() {
|
|||
// Call custom game update logic
|
||||
_customEvent(GX.EVENT_UPDATE);
|
||||
|
||||
// Perform any movement for registered player entities
|
||||
//Dim i As Integer
|
||||
//For i = 1 To __gx_player_count
|
||||
// __GX_PlayerAction i
|
||||
//Next i
|
||||
|
||||
// Check for entity movement and collisions
|
||||
// TODO: filter out non-moving entities
|
||||
_sceneMoveEntities();
|
||||
|
@ -767,19 +755,14 @@ var GX = new function() {
|
|||
newent.coRight = 0;
|
||||
newent.coBottom = 0;
|
||||
newent.applyGravity = false;
|
||||
newent.sequences = 0;
|
||||
newent.mapLayer = 0;
|
||||
|
||||
_entities.push(newent);
|
||||
|
||||
var animation = [];
|
||||
_entity_animations.push(animation);
|
||||
|
||||
/*
|
||||
newent.sequences = Math.floor(_images[newent.image-1].height / height);
|
||||
console.log(newent.sequences);
|
||||
for (var i=0; i < newent.sequences; i++) {
|
||||
animation.push({ frames: seqFrames });
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
return _entities.length;
|
||||
}
|
||||
|
||||
|
@ -818,7 +801,7 @@ var GX = new function() {
|
|||
return _entities[eid-1].seqFrames;
|
||||
}
|
||||
else {
|
||||
return _entity_animations[eid-1].frames;
|
||||
return a[seq-1].frames;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -912,12 +895,12 @@ var GX = new function() {
|
|||
return _entities[eid-1].sequences;
|
||||
}
|
||||
|
||||
function _entityFrames (eid, seq) {
|
||||
return _entityGetFrames(eid, seq); //_entity_animations[eid-1][seq-1].frames;
|
||||
}
|
||||
|
||||
function _entityFrames (eid, seq, frames) {
|
||||
_entity_animations[eid-1][seq-1] = { frames: frames };
|
||||
console.log(eid + ":" + seq + ":" + frames);
|
||||
if (frames != undefined) {
|
||||
_entity_animations[eid-1][seq-1] = { frames: frames };
|
||||
}
|
||||
return _entityGetFrames(eid, seq); //_entity_animations[eid-1][seq-1].frames;
|
||||
}
|
||||
|
||||
function _entityType (eid, etype) {
|
||||
|
@ -927,6 +910,30 @@ var GX = new function() {
|
|||
return _entities[eid-1].type
|
||||
}
|
||||
|
||||
function _entityMapLayer (eid, layer) {
|
||||
if (layer != undefined) {
|
||||
_entities[eid-1].mapLayer = layer;
|
||||
}
|
||||
return _entities[eid-1].mapLayer;
|
||||
}
|
||||
|
||||
function _drawEntityLayer (layer) {
|
||||
var frame = _scene.frame % GX.frameRate() + 1;
|
||||
|
||||
for (var i=0; i < _entities_active.length; i++) {
|
||||
var ei = _entities_active[i];
|
||||
var e = _entities[ei-1];
|
||||
if (e.mapLayer == layer) {
|
||||
_entityDraw(e);
|
||||
if (e.animate > 0) {
|
||||
if (frame % (GX.frameRate() / e.animate) == 0) {
|
||||
GX.entityFrameNext(ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _entityApplyGravity (eid, gravity) {
|
||||
if (gravity != undefined) {
|
||||
_entities[eid-1].applyGravity = gravity;
|
||||
|
@ -1052,41 +1059,33 @@ var GX = new function() {
|
|||
});
|
||||
_map_layers.push(_mapLayerInit());
|
||||
}
|
||||
|
||||
function _mapLayerInsert (beforeLayer) {
|
||||
if (beforeLayer < 1 || beforeLayer > GX.mapLayers()) { return; }
|
||||
|
||||
GX.mapLayerAdd();
|
||||
for (var layer = GX.mapLayers(); layer > beforeLayer; layer--) {
|
||||
for (var tile = 0; tile <= GX.mapRows() * GX.mapColumns(); tile++) {
|
||||
_map_layers[layer-1][tile] = _map_layers[layer - 2][tile];
|
||||
}
|
||||
}
|
||||
_map_layers[beforeLayer-1] = _mapLayerInit();
|
||||
}
|
||||
|
||||
function _mapLayerRemove (removeLayer) {
|
||||
if (removeLayer < 1 || removeLayer > GX.mapLayers() || GX.mapLayers < 2) { return; }
|
||||
|
||||
for (var layer = removeLayer; layer < GX.mapLayers(); layer++) {
|
||||
for (var tile = 0; tile <= GX.mapRows() * GX.mapColumns(); tile++) {
|
||||
_map_layers[layer-1][tile] = _map_layers[layer][tile];
|
||||
}
|
||||
}
|
||||
_map_layer_info.pop();
|
||||
_map_layers.pop();
|
||||
_map.layers = GX.mapLayers() - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Sub GXMapLayerInsert (beforeLayer As Integer)
|
||||
If beforeLayer < 1 Or beforeLayer > GXMapLayers Then Exit Sub
|
||||
|
||||
GXMapLayerAdd
|
||||
Dim layer As Integer
|
||||
Dim tile As Integer
|
||||
For layer = GXMapLayers To beforeLayer + 1 Step -1
|
||||
'gx_map_layer_info(layer) = gx_map_layer_info(layer - 1)
|
||||
For tile = 0 To GXMapRows * GXMapColumns
|
||||
__gx_map_layers(tile, layer) = __gx_map_layers(tile, layer - 1)
|
||||
Next tile
|
||||
Next layer
|
||||
Dim blankTile As GXMapTile
|
||||
For tile = 0 To GXMapRows * GXMapColumns
|
||||
__gx_map_layers(tile, beforeLayer) = blankTile
|
||||
Next tile
|
||||
End Sub
|
||||
|
||||
Sub GXMapLayerRemove (removeLayer As Integer)
|
||||
If removeLayer < 1 Or removeLayer > GXMapLayers Or GXMapLayers < 2 Then Exit Sub
|
||||
|
||||
Dim layer As Integer
|
||||
Dim tile As Integer
|
||||
For layer = removeLayer To GXMapLayers - 1
|
||||
For tile = 0 To GXMapRows * GXMapColumns
|
||||
__gx_map_layers(tile, layer) = __gx_map_layers(tile, layer + 1)
|
||||
Next tile
|
||||
Next layer
|
||||
|
||||
ReDim _Preserve __gx_map_layer_info(GXMapLayers - 1) As GXMapLayer
|
||||
ReDim _Preserve __gx_map_layers(GXMapRows * GXMapColumns, GXMapLayers - 1) As GXMapTile
|
||||
__gx_map.layers = GXMapLayers - 1
|
||||
End Sub
|
||||
|
||||
Sub GXMapResize (columns As Integer, rows As Integer)
|
||||
Dim tempMap(GXMapRows * GXMapColumns, GXMapLayers) As GXMapTile
|
||||
Dim m1 As _MEM: m1 = _Mem(__gx_map_layers())
|
||||
|
@ -1186,6 +1185,7 @@ var GX = new function() {
|
|||
srow = srow + 1;
|
||||
}
|
||||
} // layer is not hidden
|
||||
_drawEntityLayer(li);
|
||||
}
|
||||
|
||||
// Perform tile animation
|
||||
|
@ -1986,17 +1986,20 @@ var GX = new function() {
|
|||
|
||||
function _mouseY() {
|
||||
return Math.round((_mousePos.y - _scene.offsetY) / _scene.scaleY);
|
||||
};
|
||||
}
|
||||
|
||||
function _mouseButton(button) {
|
||||
// TODO: need to decide whether to keep this here
|
||||
// it is not needed for GX - only to support QB64
|
||||
return _mouseButtons[button-1];
|
||||
};
|
||||
}
|
||||
|
||||
function _mouseWheel() {
|
||||
return _mouseWheelFlag;
|
||||
var mw = _mouseWheelFlag;
|
||||
_mouseWheelFlag = false;
|
||||
return mw;
|
||||
}
|
||||
|
||||
function _touchInput() {
|
||||
var ti = _touchInputFlag;
|
||||
_touchInputFlag = false;
|
||||
|
@ -2488,8 +2491,6 @@ var GX = new function() {
|
|||
|
||||
this.ctx = function() { return _ctx; };
|
||||
this.canvas = function() { return _canvas; };
|
||||
this.gl = function() { return _glctx; };
|
||||
this.glcanvas = function() { return _glcanvas; };
|
||||
this.vfs = function() { return _vfs; };
|
||||
this.vfsCwd = function(cwd) {
|
||||
if (cwd != undefined) {
|
||||
|
@ -2550,8 +2551,10 @@ var GX = new function() {
|
|||
this.entityVX = _entityVX;
|
||||
this.entityVY = _entityVY;
|
||||
this.entityFrameNext = _entityFrameNext;
|
||||
this.entityFrames = _entityFrames;
|
||||
this.entityFrameSet = _entityFrameSet;
|
||||
this.entityType = _entityType;
|
||||
this.entityMapLayer = _entityMapLayer;
|
||||
this.entityCollisionOffset = _entityCollisionOffset;
|
||||
this.entityCollisionOffsetLeft = _entityCollisionOffsetLeft;
|
||||
this.entityCollisionOffsetTop = _entityCollisionOffsetTop;
|
||||
|
@ -2566,13 +2569,15 @@ var GX = new function() {
|
|||
this.entitySequences = _entitySequences;
|
||||
this.entityFrames = _entityFrames;
|
||||
|
||||
|
||||
|
||||
this.mapColumns = _mapColumns;
|
||||
this.mapCreate = _mapCreate;
|
||||
this.mapLoad = _mapLoad;
|
||||
this.mapDraw = _mapDraw;
|
||||
this.mapIsometric = _mapIsometric;
|
||||
this.mapLayerAdd = _mapLayerAdd;
|
||||
this.mapLayerInsert = _mapLayerInsert;
|
||||
this.mapLayerRemove = _mapLayerRemove;
|
||||
this.mapLayerInit = _mapLayerInit;
|
||||
this.mapLayerVisible = _mapLayerVisible;
|
||||
this.mapLayers = _mapLayers;
|
||||
|
|
228
qb.js
228
qb.js
|
@ -235,53 +235,74 @@ var QB = new function() {
|
|||
}
|
||||
};
|
||||
|
||||
// Runtime Assertions
|
||||
function _assertParam(param, arg) {
|
||||
if (arg == undefined) { arg = 1; }
|
||||
if (param == undefined) { throw new Error("Method argument " + arg + " is required"); }
|
||||
}
|
||||
|
||||
function _assertNumber(param, arg) {
|
||||
if (arg == undefined) { arg = 1; }
|
||||
if (isNaN(param)) { throw new Error("Number required for method argument " + arg); }
|
||||
}
|
||||
|
||||
// Extended QB64 Keywords
|
||||
// --------------------------------------------
|
||||
|
||||
this.func__Acos = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.acos(x);
|
||||
};
|
||||
|
||||
this.func__Acosh = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.acosh(x);
|
||||
};
|
||||
|
||||
this.func__Arccot = function(x) {
|
||||
_assertNumber(x);
|
||||
return 2 * Math.atan(1) - Math.atan(x);
|
||||
};
|
||||
|
||||
this.func__Arccsc = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.asin(1 / x);
|
||||
};
|
||||
|
||||
this.func__Arcsec = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.acos(1 / x);
|
||||
};
|
||||
|
||||
this.func__Alpha = function(rgb, imageHandle) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).a;
|
||||
};
|
||||
|
||||
this.func__Alpha32 = function(rgb) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).a;
|
||||
};
|
||||
|
||||
this.func__Asin = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.asin(x);
|
||||
};
|
||||
|
||||
this.func__Asinh = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.asinh(x);
|
||||
};
|
||||
|
||||
this.func__Atanh = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.atanh(x);
|
||||
};
|
||||
|
||||
this.func__Atan2 = function(y, x) {
|
||||
_assertNumber(x);
|
||||
return Math.atan2(y, x);
|
||||
};
|
||||
|
||||
|
@ -295,11 +316,13 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__Blue = function(rgb, imageHandle) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).b;
|
||||
};
|
||||
|
||||
this.func__Blue32 = function(rgb) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).b;
|
||||
};
|
||||
|
@ -309,6 +332,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__Ceil = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.ceil(x);
|
||||
};
|
||||
|
||||
|
@ -317,6 +341,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__CopyImage = function(srcImageId) {
|
||||
_assertNumber(srcImageId);
|
||||
var srcCanvas = _images[srcImageId].canvas;
|
||||
var destImageId = QB.func__NewImage(srcCanvas.width, srcCanvas.height);
|
||||
var ctx = _images[destImageId].ctx;
|
||||
|
@ -326,22 +351,27 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__Cosh = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.cosh(x);
|
||||
};
|
||||
|
||||
this.func__Cot = function(x) {
|
||||
_assertNumber(x);
|
||||
return 1 / Math.tan(x);
|
||||
}
|
||||
|
||||
this.func__Coth = function(x) {
|
||||
_assertNumber(x);
|
||||
return 1 / Math.tanh(x);
|
||||
};
|
||||
|
||||
this.func__Csc = function(x) {
|
||||
_assertNumber(x);
|
||||
return 1 / Math.sin(x);
|
||||
};
|
||||
|
||||
this.func__Csch = function(x) {
|
||||
_assertNumber(x);
|
||||
return 1 / Math.sinh(x);
|
||||
};
|
||||
|
||||
|
@ -350,10 +380,12 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__D2R = function(x) {
|
||||
_assertNumber(x);
|
||||
return x * Math.PI / 180;
|
||||
};
|
||||
|
||||
this.func__D2G = function(x) {
|
||||
_assertNumber(x);
|
||||
return (x * 10 / 9);
|
||||
};
|
||||
|
||||
|
@ -364,11 +396,13 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__Deflate = function(src) {
|
||||
_assertParam(src);
|
||||
var result = pako.deflate(src);//, { to: "string" });
|
||||
return String.fromCharCode.apply(String, result);
|
||||
};
|
||||
|
||||
this.sub__Delay = async function(seconds) {
|
||||
_assertNumber(seconds);
|
||||
await GX.sleep(seconds*1000);
|
||||
};
|
||||
|
||||
|
@ -385,6 +419,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub__Dest = function(imageId) {
|
||||
_assertNumber(imageId);
|
||||
_flushScreenCache(_images[_activeImage]);
|
||||
_activeImage = imageId;
|
||||
};
|
||||
|
@ -394,6 +429,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__DirExists = function(path) {
|
||||
_assertParam(path);
|
||||
var vfs = GX.vfs();
|
||||
var dir = vfs.getNode(path, GX.vfsCwd());
|
||||
if (dir && dir.type == vfs.DIRECTORY) {
|
||||
|
@ -411,6 +447,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub__Echo = function(msg) {
|
||||
_assertParam(msg);
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
|
@ -420,6 +457,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__FileExists = function(path) {
|
||||
_assertParam(path);
|
||||
var vfs = GX.vfs();
|
||||
var file = vfs.getNode(path, GX.vfsCwd());
|
||||
if (file && file.type == vfs.FILE) {
|
||||
|
@ -429,6 +467,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub__Font = function(fnt) {
|
||||
_assertNumber(fnt);
|
||||
_font = fnt;
|
||||
_locX = 0;
|
||||
_lastTextX = 0;
|
||||
|
@ -460,6 +499,9 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub__FreeImage = function(imageId) {
|
||||
if (imageId == undefined) {
|
||||
imageId = _activeImage;
|
||||
}
|
||||
_images[imageId] = undefined;
|
||||
};
|
||||
|
||||
|
@ -483,15 +525,18 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__G2R = function(x) {
|
||||
_assertNumber(x);
|
||||
return (x * 9/10) * Math.PI/180;
|
||||
};
|
||||
|
||||
this.func__Green = function(rgb, imageHandle) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).g;
|
||||
};
|
||||
|
||||
this.func__Green32 = function(rgb) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).g;
|
||||
};
|
||||
|
@ -510,28 +555,33 @@ var QB = new function() {
|
|||
}
|
||||
|
||||
this.func__Hypot = function(x, y) {
|
||||
_assertNumber(x, 1);
|
||||
_assertNumber(y, 1);
|
||||
return Math.hypot(x, y);
|
||||
};
|
||||
|
||||
this.func__Inflate = function(src) {
|
||||
_assertParam(src);
|
||||
var result = pako.inflate(GX.vfs().textToData(src), { to: "string" });
|
||||
return result;
|
||||
};
|
||||
|
||||
this.func__InStrRev = function(arg1, arg2, arg3) {
|
||||
var startIndex = +Infinity;
|
||||
var strSource = "";
|
||||
var strSearch = "";
|
||||
if (arg3 != undefined) {
|
||||
startIndex = arg1-1;
|
||||
strSource = String(arg2);
|
||||
strSearch = String(arg3);
|
||||
}
|
||||
else {
|
||||
strSource = String(arg1);
|
||||
strSearch = String(arg2);
|
||||
}
|
||||
return strSource.lastIndexOf(strSearch, startIndex)+1;
|
||||
_assertParam(arg1, 1);
|
||||
_assertParam(arg2, 2);
|
||||
var startIndex = +Infinity;
|
||||
var strSource = "";
|
||||
var strSearch = "";
|
||||
if (arg3 != undefined) {
|
||||
startIndex = arg1-1;
|
||||
strSource = String(arg2);
|
||||
strSearch = String(arg3);
|
||||
}
|
||||
else {
|
||||
strSource = String(arg1);
|
||||
strSearch = String(arg2);
|
||||
}
|
||||
return strSource.lastIndexOf(strSearch, startIndex)+1;
|
||||
};
|
||||
|
||||
this.sub__KeyClear = function(buffer) {
|
||||
|
@ -555,6 +605,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub__Limit = async function(fps) {
|
||||
_assertNumber(fps);
|
||||
_flushAllScreenCache();
|
||||
var frameMillis = 1000 / fps / 1.15;
|
||||
await GX.sleep(0);
|
||||
|
@ -574,6 +625,8 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__LoadFont = async function(name, size, opts) {
|
||||
_assertParam(name, 1);
|
||||
_assertParam(size, 2);
|
||||
if (!isNaN(size)) {
|
||||
size = size + "px";
|
||||
}
|
||||
|
@ -635,6 +688,7 @@ var QB = new function() {
|
|||
|
||||
|
||||
this.func__LoadImage = async function(url) {
|
||||
_assertParam(url);
|
||||
var vfs = GX.vfs();
|
||||
var vfsCwd = GX.vfsCwd();
|
||||
var img = null;
|
||||
|
@ -710,6 +764,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__MouseButton = function(button) {
|
||||
_assertNumber(button);
|
||||
return GX.mouseButton(button);
|
||||
};
|
||||
|
||||
|
@ -718,6 +773,8 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__NewImage = function(iwidth, iheight, mode) {
|
||||
_assertNumber(iwidth, 1);
|
||||
_assertNumber(iheight, 2);
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.id = "qb-canvas-" + _nextImageId;
|
||||
if (mode == 0) {
|
||||
|
@ -812,7 +869,8 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__PrintWidth = function(s) {
|
||||
if (!s) { return 0; }
|
||||
_assertParam(s);
|
||||
//if (!s) { return 0; }
|
||||
var ctx = GX.ctx();
|
||||
var f = _fonts[_font];
|
||||
ctx.font = f.size + " " + f.name;
|
||||
|
@ -824,6 +882,9 @@ var QB = new function() {
|
|||
if (m == undefined) {
|
||||
m = 1;
|
||||
}
|
||||
else {
|
||||
_assertNumber(m);
|
||||
}
|
||||
return Math.PI * m;
|
||||
}
|
||||
|
||||
|
@ -928,14 +989,18 @@ var QB = new function() {
|
|||
}
|
||||
|
||||
this.func__R2D = function(x) {
|
||||
_assertNumber(x);
|
||||
return x*180/Math.PI;
|
||||
};
|
||||
|
||||
this.func__R2G = function(x) {
|
||||
_assertNumber(x);
|
||||
return (x*(9/10))*180/Math.PI;
|
||||
};
|
||||
|
||||
this.func__Readbit= function(x, y) {
|
||||
this.func__Readbit = function(x, y) {
|
||||
_assertNumber(x, 1);
|
||||
_assertNumber(y, 2);
|
||||
var mask = 1 << y;
|
||||
if ((x & mask) != 0) {
|
||||
return -1;
|
||||
|
@ -945,16 +1010,20 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__Red = function(rgb, imageHandle) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).r;
|
||||
};
|
||||
|
||||
this.func__Red32 = function(rgb) {
|
||||
_assertParam(rgb);
|
||||
// TODO: implement corresponding logic when an image handle is supplied (maybe)
|
||||
return _color(rgb).r;
|
||||
};
|
||||
|
||||
this.func__Resetbit = function(x, y) {
|
||||
_assertNumber(x, 1);
|
||||
_assertNumber(y, 2);
|
||||
var mask = 1 << y;
|
||||
return x & ~mask;
|
||||
};
|
||||
|
@ -986,6 +1055,9 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__RGBA = function(r, g, b, a) {
|
||||
_assertNumber(r, 1);
|
||||
_assertNumber(g, 2);
|
||||
_assertNumber(b, 3);
|
||||
if (a == undefined) {
|
||||
a = 255;
|
||||
}
|
||||
|
@ -1004,6 +1076,7 @@ var QB = new function() {
|
|||
}
|
||||
|
||||
this.func__Round = function(value) {
|
||||
_assertNumber(value);
|
||||
if (value < 0) {
|
||||
return -Math.round(-value);
|
||||
} else {
|
||||
|
@ -1032,62 +1105,81 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func__Sec = function(x) {
|
||||
_assertNumber(x);
|
||||
return 1 / Math.cos(x);
|
||||
};
|
||||
|
||||
this.func__Sech = function(x) {
|
||||
_assertNumber(x);
|
||||
return 1 / Math.cosh(x);
|
||||
};
|
||||
|
||||
this.func__Setbit = function(x, y) {
|
||||
_assertNumber(x, 1);
|
||||
_assertNumber(y, 2);
|
||||
var mask = 1 << y;
|
||||
return x | mask;
|
||||
};
|
||||
|
||||
this.func__Shl = function(x, y) {
|
||||
_assertNumber(x, 1);
|
||||
_assertNumber(y, 2);
|
||||
return x << y;
|
||||
};
|
||||
|
||||
this.func__Shr = function(x, y) {
|
||||
_assertNumber(x, 1);
|
||||
_assertNumber(y, 2);
|
||||
return x >>> y;
|
||||
};
|
||||
|
||||
this.func__Sinh = function(x) {
|
||||
_assertNumber(x);
|
||||
return Math.sinh(x);
|
||||
};
|
||||
|
||||
this.func__Source = function() {
|
||||
return _sourceImage;
|
||||
}
|
||||
};
|
||||
|
||||
this.sub__Source = function(imageId) {
|
||||
_assertNumber(imageId);
|
||||
_sourceImage = imageId;
|
||||
}
|
||||
};
|
||||
|
||||
this.sub__SndClose = function(sid) {
|
||||
_assertNumber(sid);
|
||||
GX.soundClose(sid);
|
||||
};
|
||||
|
||||
this.func__SndOpen = function(filename) {
|
||||
_assertParam(filename);
|
||||
return GX.soundLoad(filename);
|
||||
};
|
||||
|
||||
this.sub__SndPlay = function(sid) {
|
||||
_assertNumber(sid);
|
||||
GX.soundPlay(sid);
|
||||
};
|
||||
|
||||
this.sub__SndLoop = function(sid) {
|
||||
_assertNumber(sid);
|
||||
GX.soundRepeat(sid);
|
||||
};
|
||||
|
||||
this.sub__SndPause = function(sid) {
|
||||
_assertNumber(sid);
|
||||
GX.soundPause(sid);
|
||||
};
|
||||
|
||||
this.sub__SndStop = function(sid) {
|
||||
_assertNumber(sid);
|
||||
GX.soundStop(sid);
|
||||
};
|
||||
|
||||
this.sub__SndVol = function(sid, v) {
|
||||
_assertNumber(sid, 1);
|
||||
_assertNumber(v, 2);
|
||||
GX.soundVolumne(sid, v);
|
||||
};
|
||||
|
||||
|
@ -1096,16 +1188,21 @@ var QB = new function() {
|
|||
}
|
||||
|
||||
this.func__Strcmp = function(x, y) {
|
||||
_assertParam(x, 1);
|
||||
_assertParam(y, 2);
|
||||
return (( x == y ) ? 0 : (( x > y ) ? 1 : -1 ));
|
||||
};
|
||||
|
||||
this.func__Stricmp = function(x, y) {
|
||||
_assertParam(x, 1);
|
||||
_assertParam(y, 2);
|
||||
var a = x.toLowerCase();
|
||||
var b = y.toLowerCase();
|
||||
return (( a == b ) ? 0 : (( a > b ) ? 1 : -1 ));
|
||||
};
|
||||
|
||||
this.func__Tanh = function(x) {
|
||||
_assertParam(x);
|
||||
return Math.tanh(x);
|
||||
};
|
||||
|
||||
|
@ -1114,14 +1211,18 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub__Title = function(title) {
|
||||
_assertParam(title);
|
||||
document.title = title;
|
||||
};
|
||||
|
||||
this.func__Trim = function(value) {
|
||||
_assertParam(value);
|
||||
return value.trim();
|
||||
};
|
||||
|
||||
this.func__Togglebit = function(x, y) {
|
||||
_assertNumber(x, 1);
|
||||
_assertNumber(y, 2);
|
||||
var mask = 1 << y;
|
||||
return x ^ mask;
|
||||
};
|
||||
|
@ -1143,19 +1244,25 @@ var QB = new function() {
|
|||
// QB45 Keywords
|
||||
// --------------------------------------------
|
||||
this.func_Abs = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.abs(value);
|
||||
};
|
||||
|
||||
this.func_Asc = function(value, pos) {
|
||||
_assertParam(value);
|
||||
if (pos == undefined) {
|
||||
pos = 0;
|
||||
}
|
||||
else { pos--; }
|
||||
else { p
|
||||
_assertNumber(pos, 2);
|
||||
os--;
|
||||
}
|
||||
|
||||
return String(value).charCodeAt(pos);
|
||||
}
|
||||
|
||||
this.func_Atn = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.atan(value);
|
||||
};
|
||||
|
||||
|
@ -1172,6 +1279,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub_ChDir = function(path) {
|
||||
_assertParam(path);
|
||||
var node = GX.vfs().getNode(path, GX.vfsCwd());
|
||||
if (node) {
|
||||
GX.vfsCwd(node);
|
||||
|
@ -1182,6 +1290,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Chr = function(charCode) {
|
||||
_assertNumber(charCode);
|
||||
return String.fromCharCode(charCode);
|
||||
};
|
||||
|
||||
|
@ -1242,12 +1351,12 @@ var QB = new function() {
|
|||
return _rgb(0,0,0);
|
||||
}
|
||||
|
||||
this.sub_Color = function(x, y) {
|
||||
this.sub_Color = function(fg, bg) {
|
||||
if (x != undefined) {
|
||||
_fgColor = _color(x);
|
||||
_fgColor = _color(fg);
|
||||
}
|
||||
if (y != undefined) {
|
||||
_bgColor = _color(y);
|
||||
_bgColor = _color(bg);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1256,6 +1365,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Cos = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.cos(value);
|
||||
};
|
||||
|
||||
|
@ -1264,6 +1374,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Cvi = function(numString) {
|
||||
_assertParam(numString);
|
||||
var result = 0;
|
||||
numString = numString.split("").reverse().join("");
|
||||
for (let i=1;i>=0;i--) {
|
||||
|
@ -1273,6 +1384,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Cvl = function(numString) {
|
||||
_assertParam(numString);
|
||||
var result = 0;
|
||||
numString = numString.split("").reverse().join("");
|
||||
for (let i=3;i>=0;i--) {
|
||||
|
@ -1290,7 +1402,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub_Draw = function(t) {
|
||||
|
||||
_assertParam(t);
|
||||
// Turn input string into array of characters.
|
||||
var u = t.toString();
|
||||
u = u.replace(/\s+/g, '');
|
||||
|
@ -1604,14 +1716,17 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub_Error = function(errorNumber) {
|
||||
_assertNumber(errorNumber);
|
||||
throw new Error("Unhandled Error #" + errorNumber);
|
||||
};
|
||||
|
||||
this.func_Exp = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.exp(value);
|
||||
};
|
||||
|
||||
this.func_Fix = function(value) {
|
||||
_assertNumber(value);
|
||||
if (value >=0) {
|
||||
return Math.floor(value);
|
||||
}
|
||||
|
@ -1632,6 +1747,7 @@ var QB = new function() {
|
|||
}
|
||||
|
||||
this.func_Hex = function(n) {
|
||||
_assertNumber(n);
|
||||
return n.toString(16).toUpperCase();
|
||||
};
|
||||
|
||||
|
@ -1801,6 +1917,8 @@ var QB = new function() {
|
|||
}
|
||||
|
||||
this.func_InStr = function(arg1, arg2, arg3) {
|
||||
_assertParam(arg1, 1);
|
||||
_assertParam(arg2, 2);
|
||||
var startIndex = 0;
|
||||
var strSource = "";
|
||||
var strSearch = "";
|
||||
|
@ -1817,18 +1935,23 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Int = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.floor(value);
|
||||
};
|
||||
|
||||
this.func_LCase = function(value) {
|
||||
_assertParam(value);
|
||||
return String(value).toLowerCase();
|
||||
};
|
||||
|
||||
this.func_Left = function(value, n) {
|
||||
_assertParam(value, 1);
|
||||
_assertNumber(n, 2);
|
||||
return String(value).substring(0, n);
|
||||
};
|
||||
|
||||
this.func_Len = function(value) {
|
||||
_assertParam(value);
|
||||
return String(value).length;
|
||||
};
|
||||
|
||||
|
@ -1841,10 +1964,12 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Log = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.log(value);
|
||||
};
|
||||
|
||||
this.func_Cdbl = function(value) {
|
||||
_assertNumber(value);
|
||||
const buffer = new ArrayBuffer(16);
|
||||
const view = new DataView(buffer);
|
||||
view.setFloat32(1, value);
|
||||
|
@ -1852,6 +1977,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Cint = function(value) {
|
||||
_assertNumber(value);
|
||||
if (value > 0) {
|
||||
return Math.round(value);
|
||||
} else {
|
||||
|
@ -1860,6 +1986,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Clng = function(value) {
|
||||
_assertNumber(value);
|
||||
if (value > 0) {
|
||||
return Math.round(value);
|
||||
} else {
|
||||
|
@ -2098,7 +2225,9 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub_Locate = function(row, col) {
|
||||
// TODO: implement cursor positioning/display
|
||||
// TODO: implement cursor positioning/display parameters
|
||||
if (row == undefined) { row = 1; } else { _assertNumber(row); }
|
||||
if (col == undefined) { col = 1; } else { _assertNumber(col); }
|
||||
if (row && row > 0 && row <= _textRows()) {
|
||||
_locY = row-1;
|
||||
}
|
||||
|
@ -2109,23 +2238,28 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_LTrim = function(value) {
|
||||
_assertParam(value);
|
||||
return String(value).trimStart();
|
||||
};
|
||||
|
||||
this.sub_Kill = function(path) {
|
||||
_assertParam(path);
|
||||
GX.vfs().removeFile(path, GX.vfsCwd());
|
||||
};
|
||||
|
||||
this.func_Mid = function(value, n, len) {
|
||||
if (len == undefined) {
|
||||
return String(value).substring(n-1);
|
||||
}
|
||||
else {
|
||||
return String(value).substring(n-1, n+len-1);
|
||||
}
|
||||
_assertParam(value, 1);
|
||||
_assertNumber(n, 2);
|
||||
if (len == undefined) {
|
||||
return String(value).substring(n-1);
|
||||
}
|
||||
else {
|
||||
return String(value).substring(n-1, n+len-1);
|
||||
}
|
||||
};
|
||||
|
||||
this.sub_MkDir = function(path) {
|
||||
_assertParam(path);
|
||||
var vfs = GX.vfs();
|
||||
var vfsCwd = GX.vfsCwd();
|
||||
var parent = vfs.getParentPath(path);
|
||||
|
@ -2136,6 +2270,7 @@ var QB = new function() {
|
|||
}
|
||||
|
||||
this.func_Mki = function(num) {
|
||||
_assertNumber(num);
|
||||
var ascii = "";
|
||||
for (var i=1; i >= 0; i--) {
|
||||
ascii += String.fromCharCode((num>>(8*i))&255);
|
||||
|
@ -2144,6 +2279,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Mkl = function(num) {
|
||||
_assertNumber(num);
|
||||
var ascii = "";
|
||||
for (var i=3; i >= 0; i--) {
|
||||
ascii += String.fromCharCode((num>>(8*i))&255);
|
||||
|
@ -2152,6 +2288,8 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub_Name = function(oldName, newName) {
|
||||
_assertParam(oldName, 1);
|
||||
_assertParam(newName, 2);
|
||||
var vfs = GX.vfs();
|
||||
var vfsCwd = GX.vfsCwd();
|
||||
var node = vfs.getNode(oldName, vfsCwd);
|
||||
|
@ -2159,6 +2297,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Oct = function(n) {
|
||||
_assertNumber(n);
|
||||
return n.toString(8).toUpperCase();
|
||||
};
|
||||
|
||||
|
@ -2888,10 +3027,15 @@ var QB = new function() {
|
|||
_readCursorPosition = 0;
|
||||
} else {
|
||||
_readCursorPosition = _dataLabelMap[t];
|
||||
if (_readCursorPosition == undefined) {
|
||||
throw new Error("Label '" + t + "' not defined");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.func_Right = function(value, n) {
|
||||
_assertParam(value, 1);
|
||||
_assertNumber(n, 2);
|
||||
if (value == undefined) {
|
||||
return "";
|
||||
}
|
||||
|
@ -2900,6 +3044,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_RTrim = function(value) {
|
||||
_assertParam(value);
|
||||
return String(value).trimEnd();
|
||||
}
|
||||
|
||||
|
@ -2925,6 +3070,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.sub_RmDir = function(path) {
|
||||
_assertParam(path);
|
||||
vfs.removeDirectory(path, vfsCwd);
|
||||
};
|
||||
|
||||
|
@ -3036,16 +3182,20 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Sgn = function(value) {
|
||||
_assertNumber(value);
|
||||
if (value > 0) { return 1; }
|
||||
else if (value < 0) { return -1; }
|
||||
else { return 0; }
|
||||
};
|
||||
|
||||
this.func_Space = function(ccount) {
|
||||
_assertNumber(ccount);
|
||||
return QB.func_String(ccount, " ");
|
||||
}
|
||||
|
||||
this.func_String = function(ccount, s) {
|
||||
_assertNumber(ccount, 1);
|
||||
_assertParam(s, 2);
|
||||
if (typeof s === "string") {
|
||||
s = s.substring(0, 1);
|
||||
}
|
||||
|
@ -3056,6 +3206,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Sin = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.sin(value);
|
||||
};
|
||||
|
||||
|
@ -3063,7 +3214,10 @@ var QB = new function() {
|
|||
var elapsed = 0;
|
||||
var totalWait = Infinity;
|
||||
if (seconds != undefined) {
|
||||
totalWait = seconds*1000;
|
||||
_assertNumber(seconds);
|
||||
if (seconds > 0) {
|
||||
totalWait = seconds*1000;
|
||||
}
|
||||
}
|
||||
|
||||
_lastKey = null;
|
||||
|
@ -3076,6 +3230,8 @@ var QB = new function() {
|
|||
|
||||
|
||||
this.sub_Sound = async function(freq, duration, shape, decay, gain) {
|
||||
_assertNumber(freq, 1);
|
||||
_assertNumber(duration, 2);
|
||||
if (shape == undefined || (typeof shape != 'string')) { shape = "square"; }
|
||||
if (decay == undefined || (typeof decay != 'number')) { decay = 0.0; }
|
||||
if (gain == undefined || (typeof gain != 'number')) { gain = 1.0; }
|
||||
|
@ -3106,6 +3262,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Sqr = function(value) {
|
||||
_assertNumber(value);
|
||||
return Math.sqrt(value);
|
||||
};
|
||||
|
||||
|
@ -3120,6 +3277,7 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_Tan = function(value) {
|
||||
__assertNumber(value);
|
||||
return Math.tan(value);
|
||||
};
|
||||
|
||||
|
@ -3140,24 +3298,34 @@ var QB = new function() {
|
|||
};
|
||||
|
||||
this.func_LBound = function(a, dimension) {
|
||||
_assertParam(a);
|
||||
if (dimension == undefined) {
|
||||
dimension = 1;
|
||||
}
|
||||
else {
|
||||
_assertNumber(dimension, 2);
|
||||
}
|
||||
return a._dimensions[dimension-1].l;
|
||||
};
|
||||
|
||||
this.func_UBound = function(a, dimension) {
|
||||
_assertParam(a);
|
||||
if (dimension == undefined) {
|
||||
dimension = 1;
|
||||
}
|
||||
else {
|
||||
_assertNumber(dimension, 2);
|
||||
}
|
||||
return a._dimensions[dimension-1].u;
|
||||
};
|
||||
|
||||
this.func_UCase = function(value) {
|
||||
_assertParam(value);
|
||||
return String(value).toUpperCase();
|
||||
};
|
||||
|
||||
this.func_Val = function(value) {
|
||||
_assertParam(value);
|
||||
var ret;
|
||||
value = value.toString();
|
||||
if (value.substring(0, 2) == "&H") {
|
||||
|
|
21
qbjs-ide.js
21
qbjs-ide.js
|
@ -264,6 +264,14 @@ var IDE = new function() {
|
|||
|
||||
await displayWarnings();
|
||||
|
||||
if (_hasError()) {
|
||||
consoleVisible = true;
|
||||
window.onresize();
|
||||
QB.halt();
|
||||
GX.sceneStop();
|
||||
return false;
|
||||
}
|
||||
|
||||
_e.jsCode.innerHTML = jsCode;
|
||||
window.onresize();
|
||||
|
||||
|
@ -301,6 +309,16 @@ var IDE = new function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
function _hasError() {
|
||||
var warnings = QBCompiler.getWarnings();
|
||||
for (var i=0; i < warnings.length; i++) {
|
||||
if (warnings[i].mtype == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function _stopProgram() {
|
||||
QB.halt();
|
||||
GX.sceneStop();
|
||||
|
@ -589,7 +607,8 @@ var IDE = new function() {
|
|||
var td1 = document.createElement("td");
|
||||
var td2 = document.createElement("td");
|
||||
var td3 = document.createElement("td");
|
||||
_addWarningCell(tr, "WARN");
|
||||
var mtype = (w[i].mtype == 1) ? "ERROR": "WARN";
|
||||
_addWarningCell(tr, mtype);
|
||||
_addWarningCell(tr, ":");
|
||||
_addWarningCell(tr, w[i].line);
|
||||
_addWarningCell(tr, ":");
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 44 KiB |
Binary file not shown.
Before Width: | Height: | Size: 55 KiB |
|
@ -2,9 +2,13 @@ Export Render
|
|||
|
||||
IncludeJS "https://cdnjs.cloudflare.com/ajax/libs/camanjs/4.0.0/caman.full.min.js"
|
||||
|
||||
Sub Render(opts)
|
||||
Dim lastOpts As Object
|
||||
|
||||
Sub Render(opts, imageId)
|
||||
$If Javascript Then
|
||||
Caman("#gx-canvas", function() {
|
||||
var complete = false;
|
||||
if (imageId == undefined) { imageId = 0; }
|
||||
Caman(QB.getImage(imageId), function() {
|
||||
if (opts.brightness) { this.brightness(opts.brightness); }
|
||||
if (opts.contrast) { this.contrast(opts.contrast); }
|
||||
if (opts.saturation) { this.saturation(opts.saturation); }
|
||||
|
@ -18,6 +22,9 @@ $If Javascript Then
|
|||
if (opts.sharpen) { this.sharpen(opts.sharpen); }
|
||||
if (opts.blur) { this.stackBlur(opts.blur); }
|
||||
this.render();
|
||||
lastOpts = opts;
|
||||
complete = true;
|
||||
});
|
||||
while (!complete) { await GX.sleep(10); }
|
||||
$End If
|
||||
End Sub
|
222
tools/qb2js.bas
222
tools/qb2js.bas
|
@ -6,8 +6,8 @@ $Console:Only
|
|||
'2) Compile to EXE only.
|
||||
'3) In console, run: qb2js qb2js.bas > ../qb2js.js
|
||||
|
||||
Const FILE = 1
|
||||
Const TEXT = 2
|
||||
Const FILE = 1, TEXT = 2
|
||||
Const MWARNING = 0, MERROR = 1
|
||||
Const False = 0
|
||||
Const True = Not False
|
||||
Const PrintDataTypes = True
|
||||
|
@ -18,6 +18,7 @@ Const PrintTokenizedLine = False
|
|||
Type CodeLine
|
||||
line As Integer
|
||||
text As String
|
||||
mtype As Integer
|
||||
End Type
|
||||
|
||||
Type Method
|
||||
|
@ -59,10 +60,11 @@ Type Label
|
|||
index As Integer
|
||||
End Type
|
||||
|
||||
Type LoopItem
|
||||
Type Container
|
||||
mode As Integer
|
||||
type As String
|
||||
label As String
|
||||
line As Integer
|
||||
End Type
|
||||
|
||||
ReDim Shared As CodeLine lines(0)
|
||||
|
@ -181,7 +183,8 @@ Sub QBToJS (source As String, sourceType As Integer, moduleName As String)
|
|||
AddJSLine 0, " for (var i=1; i <= QB.func_UBound(warnings); i++) {"
|
||||
AddJSLine 0, " w.push({"
|
||||
AddJSLine 0, " line: QB.arrayValue(warnings, [i]).value.line,"
|
||||
AddJSLine 0, " text: QB.arrayValue(warnings, [i]).value.text"
|
||||
AddJSLine 0, " text: QB.arrayValue(warnings, [i]).value.text,"
|
||||
AddJSLine 0, " mtype: QB.arrayValue(warnings, [i]).value.mtype"
|
||||
AddJSLine 0, " });"
|
||||
AddJSLine 0, " }"
|
||||
AddJSLine 0, " return w;"
|
||||
|
@ -294,12 +297,13 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
Dim totalIndent As Integer
|
||||
totalIndent = 1
|
||||
Dim caseCount As Integer
|
||||
Dim loopMode(100) As LoopItem ' TODO: only supports 100 levels of do/loop nesting
|
||||
Dim loopLevel As Integer
|
||||
Dim containers(10000) As Container ' TODO: replace hardcoded limit?
|
||||
Dim cindex As Integer
|
||||
Dim caseVar As String
|
||||
Dim currType As Integer
|
||||
Dim loopIndex As String
|
||||
Dim sfix As String
|
||||
Dim ctype As String
|
||||
|
||||
For i = firstLine To lastLine
|
||||
indent = 0
|
||||
|
@ -350,6 +354,8 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
DeclareTypeVar parts(), currType, i
|
||||
End If
|
||||
Else
|
||||
CheckParen lines(i).text, i
|
||||
|
||||
If first = "CONST" Then
|
||||
ReDim As String constParts(0)
|
||||
Dim As Integer constCount
|
||||
|
@ -374,6 +380,10 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
|
||||
|
||||
ElseIf first = "SELECT" Then
|
||||
cindex = cindex + 1
|
||||
containers(cindex).type = "SELECT CASE"
|
||||
containers(cindex).line = i
|
||||
|
||||
caseVar = GenJSVar
|
||||
js = "var " + caseVar + " = " + ConvertExpression(Join(parts(), 3, -1, " "), i) + "; "
|
||||
js = js + "switch (" + caseVar + ") {"
|
||||
|
@ -426,12 +436,13 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
|
||||
If Left$(_Trim$(fstep), 1) = "-" Then fcond = " >= "
|
||||
|
||||
loopLevel = loopLevel + 1
|
||||
loopMode(loopLevel).type = "FOR"
|
||||
loopMode(loopLevel).label = GenJSLabel
|
||||
cindex = cindex + 1
|
||||
containers(cindex).type = "FOR"
|
||||
containers(cindex).label = GenJSLabel
|
||||
containers(cindex).line = i
|
||||
|
||||
loopIndex = GenJSVar
|
||||
js = "var " + loopIndex + " = 0; " + loopMode(loopLevel).label + ":"
|
||||
js = "var " + loopIndex + " = 0; " + containers(cindex).label + ":"
|
||||
js = js + " for (" + fvar + "=" + sval + "; " + fvar + fcond + uval + "; " + fvar + "=" + fvar + " + " + fstep + ") {"
|
||||
js = js + " if (QB.halted()) { return; } "
|
||||
js = js + loopIndex + "++; "
|
||||
|
@ -440,6 +451,10 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
indent = 1
|
||||
|
||||
ElseIf first = "IF" Then
|
||||
cindex = cindex + 1
|
||||
containers(cindex).type = "IF"
|
||||
containers(cindex).line = i
|
||||
|
||||
Dim thenIndex As Integer
|
||||
For thenIndex = 2 To UBound(parts)
|
||||
If UCase$(parts(thenIndex)) = "THEN" Then Exit For
|
||||
|
@ -463,21 +478,42 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
Dim npi As Integer
|
||||
npcount = ListSplit(Join(parts(), 2, -1, " "), nparts())
|
||||
For npi = 1 To npcount
|
||||
js = js + "} "
|
||||
indent = indent - 1
|
||||
If CheckBlockEnd(containers(), cindex, first, i) Then
|
||||
js = js + "} "
|
||||
indent = -1
|
||||
cindex = cindex - 1
|
||||
Else
|
||||
Exit For
|
||||
End If
|
||||
Next npi
|
||||
Else
|
||||
js = js + "}"
|
||||
indent = -1
|
||||
If CheckBlockEnd(containers(), cindex, first, i) Then
|
||||
js = js + "}"
|
||||
indent = -1
|
||||
cindex = cindex - 1
|
||||
End If
|
||||
End If
|
||||
|
||||
ElseIf first = "END" Then
|
||||
If UBound(parts) = 1 Then
|
||||
js = "QB.halt(); return;"
|
||||
Else
|
||||
If UCase$(parts(2)) = "SELECT" Then js = "break;"
|
||||
js = js + "}"
|
||||
indent = -1
|
||||
second = UCase$(parts(2))
|
||||
If second = "IF" Then
|
||||
If CheckBlockEnd(containers(), cindex, "END IF", i) Then
|
||||
js = js + "}"
|
||||
indent = -1
|
||||
cindex = cindex - 1
|
||||
End If
|
||||
ElseIf second = "SELECT" Then
|
||||
If CheckBlockEnd(containers(), cindex, "END SELECT", i) Then
|
||||
js = "break;" + " }"
|
||||
indent = -1
|
||||
cindex = cindex - 1
|
||||
End If
|
||||
Else
|
||||
AddError i, "Syntax error after END"
|
||||
End If
|
||||
End If
|
||||
|
||||
ElseIf first = "SYSTEM" Then
|
||||
|
@ -494,12 +530,13 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
End If
|
||||
|
||||
ElseIf first = "DO" Then
|
||||
loopLevel = loopLevel + 1
|
||||
loopMode(loopLevel).label = GenJSLabel
|
||||
loopMode(loopLevel).type = "DO"
|
||||
cindex = cindex + 1
|
||||
containers(cindex).label = GenJSLabel
|
||||
containers(cindex).type = "DO"
|
||||
containers(cindex).line = i
|
||||
|
||||
loopIndex = GenJSVar
|
||||
js = "var " + loopIndex + " = 0; " + loopMode(loopLevel).label + ":"
|
||||
js = "var " + loopIndex + " = 0; " + containers(cindex).label + ":"
|
||||
|
||||
If UBound(parts) > 1 Then
|
||||
sfix = FixCondition(UCase$(parts(2)), parts(), 2, "DO ")
|
||||
|
@ -509,10 +546,10 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
Else
|
||||
js = js + " while (!(" + ConvertExpression(Join(parts(), 3, -1, " "), i) + ")) {"
|
||||
End If
|
||||
loopMode(loopLevel).mode = 1
|
||||
containers(cindex).mode = 1
|
||||
Else
|
||||
js = js + " do {"
|
||||
loopMode(loopLevel).mode = 2
|
||||
containers(cindex).mode = 2
|
||||
End If
|
||||
indent = 1
|
||||
js = js + " if (QB.halted()) { return; }"
|
||||
|
@ -521,12 +558,13 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
|
||||
|
||||
ElseIf first = "WHILE" Then
|
||||
loopLevel = loopLevel + 1
|
||||
loopMode(loopLevel).label = GenJSLabel
|
||||
loopMode(loopLevel).type = "WHILE"
|
||||
cindex = cindex + 1
|
||||
containers(cindex).label = GenJSLabel
|
||||
containers(cindex).type = "WHILE"
|
||||
containers(cindex).line = i
|
||||
|
||||
loopIndex = GenJSVar
|
||||
js = "var " + loopIndex + " = 0; " + loopMode(loopLevel).label + ":"
|
||||
js = "var " + loopIndex + " = 0; " + containers(cindex).label + ":"
|
||||
js = js + " while (" + ConvertExpression(Join(parts(), 2, -1, " "), i) + ") {"
|
||||
js = js + " if (QB.halted()) { return; }"
|
||||
js = js + loopIndex + "++; "
|
||||
|
@ -535,26 +573,35 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
indent = 1
|
||||
|
||||
ElseIf first = "WEND" Then
|
||||
js = "}"
|
||||
loopLevel = loopLevel - 1
|
||||
indent = -1
|
||||
'ctype = ""
|
||||
'If cindex > 0 Then ctype = containers(cindex).type
|
||||
'If ctype <> "WHILE" Then
|
||||
' AddWarning i, "WEND without WHILE"
|
||||
'Else
|
||||
If CheckBlockEnd(containers(), cindex, first, i) Then
|
||||
js = "}"
|
||||
cindex = cindex - 1
|
||||
indent = -1
|
||||
End If
|
||||
|
||||
ElseIf first = "LOOP" Then
|
||||
If loopMode(loopLevel).mode = 1 Then
|
||||
js = "}"
|
||||
Else
|
||||
sfix = FixCondition(UCase$(parts(2)), parts(), 2, "LOOP ")
|
||||
|
||||
js = "} while (("
|
||||
If UBound(parts) < 2 Then
|
||||
js = js + "1));"
|
||||
If CheckBlockEnd(containers(), cindex, first, i) Then
|
||||
If containers(cindex).mode = 1 Then
|
||||
js = "}"
|
||||
Else
|
||||
If UCase$(parts(2)) = "UNTIL" Then js = "} while (!("
|
||||
js = js + ConvertExpression(Join(parts(), 3, UBound(parts), " "), i) + "))"
|
||||
sfix = FixCondition(UCase$(parts(2)), parts(), 2, "LOOP ")
|
||||
|
||||
js = "} while (("
|
||||
If UBound(parts) < 2 Then
|
||||
js = js + "1));"
|
||||
Else
|
||||
If UCase$(parts(2)) = "UNTIL" Then js = "} while (!("
|
||||
js = js + ConvertExpression(Join(parts(), 3, UBound(parts), " "), i) + "))"
|
||||
End If
|
||||
End If
|
||||
cindex = cindex - 1
|
||||
indent = -1
|
||||
End If
|
||||
loopLevel = loopLevel - 1
|
||||
indent = -1
|
||||
|
||||
ElseIf first = "_CONTINUE" Or first = "CONTINUE" Then
|
||||
js = "continue;"
|
||||
|
@ -571,19 +618,19 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
|
||||
ElseIf second = "DO" Or second = "WHILE" Or second = "FOR" Then
|
||||
Dim lli As Integer
|
||||
For lli = loopLevel To 0 Step -1
|
||||
For lli = cindex To 0 Step -1
|
||||
If lli > 0 Then
|
||||
If loopMode(lli).type = second Then Exit For
|
||||
If containers(lli).type = second Then Exit For
|
||||
End If
|
||||
Next lli
|
||||
If lli > 0 Then
|
||||
js = "break " + loopMode(lli).label + ";"
|
||||
js = "break " + containers(lli).label + ";"
|
||||
Else
|
||||
AddWarning i, "EXIT " + second + " without " + second + " on current line"
|
||||
AddError i, "EXIT " + second + " without " + second
|
||||
End If
|
||||
|
||||
Else
|
||||
AddWarning i, "Syntax error after EXIT"
|
||||
AddError i, "Syntax error after EXIT"
|
||||
End If
|
||||
|
||||
ElseIf first = "TYPE" Then
|
||||
|
@ -697,8 +744,50 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
|
|||
|
||||
Next i
|
||||
|
||||
If cindex > 0 Then
|
||||
AddError containers(cindex).line, containers(cindex).type + " without " + EndPhraseFor(containers(cindex).type)
|
||||
End If
|
||||
|
||||
End Sub
|
||||
|
||||
Function BeginPhraseFor$ (endPhrase As String)
|
||||
Dim bp As String
|
||||
Select Case endPhrase
|
||||
Case "NEXT": bp = "FOR"
|
||||
Case "LOOP": bp = "DO"
|
||||
Case "WEND": bp = "WHILE"
|
||||
Case "END IF": bp = "IF"
|
||||
Case "END SELECT": bp = "SELECT CASE"
|
||||
End Select
|
||||
BeginPhraseFor = bp
|
||||
End Function
|
||||
|
||||
Function EndPhraseFor$ (beginPhrase As String)
|
||||
Dim ep As String
|
||||
Select Case beginPhrase
|
||||
Case "FOR": ep = "NEXT"
|
||||
Case "DO": ep = "LOOP"
|
||||
Case "WHILE": ep = "WEND"
|
||||
Case "IF": ep = "END IF"
|
||||
Case "SELECT CASE": ep = "END SELECT"
|
||||
End Select
|
||||
EndPhraseFor = ep
|
||||
End Function
|
||||
|
||||
Function CheckBlockEnd (cstack() As Container, cindex As Integer, endPhrase As String, lineNumber As Integer)
|
||||
Dim As String ctype, beginPhrase
|
||||
Dim success As Integer
|
||||
success = True
|
||||
beginPhrase = BeginPhraseFor(endPhrase)
|
||||
If cindex > 0 Then ctype = cstack(cindex).type
|
||||
If ctype <> beginPhrase Then
|
||||
AddError lineNumber, endPhrase + " without " + beginPhrase
|
||||
success = False
|
||||
End If
|
||||
|
||||
CheckBlockEnd = success
|
||||
End Function
|
||||
|
||||
Function FixCondition$ (word As String, parts() As String, idx As Integer, prefix As String)
|
||||
' The fact that we are doing this probably means we need to improve the initial "tokenizer"
|
||||
' Is this is a condition keyword with no space between the keyword and the open paren?
|
||||
|
@ -728,7 +817,7 @@ Sub ParseExport (s As String, lineIndex As Integer)
|
|||
Dim c As Integer
|
||||
c = SLSplit(s, parts(), False)
|
||||
|
||||
AddWarning lineIndex, "ParseExport: [" + s + "]"
|
||||
'AddWarning lineIndex, "ParseExport: [" + s + "]"
|
||||
|
||||
If FindMethod(parts(1), es, "SUB") Then
|
||||
If c > 2 Then
|
||||
|
@ -1924,9 +2013,9 @@ Function ConvertExpression$ (ex As String, lineNumber As Integer)
|
|||
If uword = "NOT" Then
|
||||
js = js + "!"
|
||||
ElseIf uword = "AND" Then
|
||||
js = js + " && "
|
||||
js = js + " & "
|
||||
ElseIf uword = "OR" Then
|
||||
js = js + " || "
|
||||
js = js + " | "
|
||||
ElseIf uword = "MOD" Then
|
||||
js = js + " % "
|
||||
ElseIf uword = "XOR" Then
|
||||
|
@ -2657,6 +2746,35 @@ Function FindOperator (c As String, c2 As String)
|
|||
End If
|
||||
End Function
|
||||
|
||||
Sub CheckParen (sourceString As String, lineNumber As Long)
|
||||
Dim i As Integer
|
||||
Dim quoteMode As Integer
|
||||
Dim paren As Integer
|
||||
For i = 1 To Len(sourceString)
|
||||
Dim c As String
|
||||
c = Mid$(sourceString, i, 1)
|
||||
|
||||
If c = Chr$(34) Then
|
||||
quoteMode = Not quoteMode
|
||||
|
||||
ElseIf quoteMode Then
|
||||
' skip the remaining checks and move to the next char
|
||||
|
||||
ElseIf c = "(" Then
|
||||
paren = paren + 1
|
||||
|
||||
ElseIf c = ")" Then
|
||||
paren = paren - 1
|
||||
End If
|
||||
Next i
|
||||
|
||||
If paren < 0 Then
|
||||
AddError lineNumber, "Missing ("
|
||||
ElseIf paren > 0 Then
|
||||
AddError lineNumber, "Missing )"
|
||||
End If
|
||||
End Sub
|
||||
|
||||
' String literal-aware split - copy
|
||||
Function SLSplit2 (sourceString As String, results() As String)
|
||||
Dim cstr As String
|
||||
|
@ -3000,6 +3118,10 @@ Sub AddWarning (sourceLine As Integer, msgText As String)
|
|||
warnings(lcount).text = msgText
|
||||
End Sub
|
||||
|
||||
Sub AddError (sourceLine As Integer, msgText As String)
|
||||
AddWarning sourceLine, msgText
|
||||
warnings(UBound(warnings)).mtype = MERROR
|
||||
End Sub
|
||||
|
||||
Sub AddConst (vname As String)
|
||||
Dim v As Variable
|
||||
|
|
Loading…
Reference in a new issue