From cc3a007251f4329708c21563df6312ff476a500a Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Tue, 19 Nov 2024 11:38:43 +0000
Subject: [PATCH 01/10] Add files via upload
---
.../Cool_skratcher/abbreviations.js | 318 ++++++++++++++++++
static/extensions/Cool_skratcher/noise.js | 185 ++++++++++
static/extensions/Cool_skratcher/vectors.js | 305 +++++++++++++++++
3 files changed, 808 insertions(+)
create mode 100644 static/extensions/Cool_skratcher/abbreviations.js
create mode 100644 static/extensions/Cool_skratcher/noise.js
create mode 100644 static/extensions/Cool_skratcher/vectors.js
diff --git a/static/extensions/Cool_skratcher/abbreviations.js b/static/extensions/Cool_skratcher/abbreviations.js
new file mode 100644
index 00000000..ef542672
--- /dev/null
+++ b/static/extensions/Cool_skratcher/abbreviations.js
@@ -0,0 +1,318 @@
+// Name: Number Abbiviation!
+// ID: abbreviate
+// Description: Adds blocks to convert any big number to way less text like: 1200000 -> 1.2M.
+// By: cool_skratcher
+// License: MIT
+
+(function (Scratch) {
+ "use strict";
+
+ class Abbreviation {
+ getInfo() {
+ return {
+ id: "abbreviate",
+ name: "Abbreviation!",
+ color1: "#9dd13d",
+ color2: "#8fbe37",
+ blocks: [
+ {
+ opcode: "abbriviate",
+ blockType: Scratch.BlockType.REPORTER,
+ text: "abbreviate: [NUM]",
+ arguments: {
+ NUM: {
+ type: Scratch.ArgumentType.NUMBER,
+ },
+ },
+ },
+ {
+ opcode: "unabbriviate",
+ blockType: Scratch.BlockType.REPORTER,
+ text: "un-abbreviate: [NUM]",
+ arguments: {
+ NUM: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ {
+ opcode: "addabbriviated",
+ blockType: Scratch.BlockType.REPORTER,
+ text: "add abbreviated [NUM1] + [NUM2]",
+ arguments: {
+ NUM1: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ NUM2: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ {
+ opcode: "subabbriviated",
+ blockType: Scratch.BlockType.REPORTER,
+ text: "subtract abbreviated [NUM1] - [NUM2]",
+ arguments: {
+ NUM1: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ NUM2: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ {
+ opcode: "multiabbriviated",
+ blockType: Scratch.BlockType.REPORTER,
+ text: "multiply abbreviated [NUM1] * [NUM2]",
+ arguments: {
+ NUM1: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ NUM2: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ {
+ opcode: "divabbriviated",
+ blockType: Scratch.BlockType.REPORTER,
+ text: "divide abbreviated [NUM1] / [NUM2]",
+ arguments: {
+ NUM1: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ NUM2: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ {
+ opcode: "equalabbriviated",
+ blockType: Scratch.BlockType.BOOLEAN,
+ text: "is equal abbreviated [NUM1] = [NUM2]",
+ arguments: {
+ NUM1: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ NUM2: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ {
+ opcode: "moreabbriviated",
+ blockType: Scratch.BlockType.BOOLEAN,
+ text: "is greater abbreviated [NUM1] > [NUM2]",
+ arguments: {
+ NUM1: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ NUM2: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ {
+ opcode: "lessabbriviated",
+ blockType: Scratch.BlockType.BOOLEAN,
+ text: "is less abbreviated [NUM1] < [NUM2]",
+ arguments: {
+ NUM1: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ NUM2: {
+ type: Scratch.ArgumentType.STRING,
+ },
+ },
+ },
+ ],
+ };
+ }
+ abbriviate(args) {
+ return abbreviateNumber(args.NUM);
+ }
+ unabbriviate(args) {
+ return unAbbreviateNumber(args.NUM);
+ }
+ addabbriviated(args) {
+ return addAbbreviated(args.NUM1, args.NUM2);
+ }
+ subabbriviated(args) {
+ return subtractAbbreviated(args.NUM1, args.NUM2);
+ }
+ multiabbriviated(args) {
+ return multiplyAbbreviated(args.NUM1, args.NUM2);
+ }
+ divabbriviated(args) {
+ return divideAbbreviated(args.NUM1, args.NUM2);
+ }
+ equalabbriviated(args) {
+ if (compareAbbreviated(args.NUM1, args.NUM2) === 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ moreabbriviated(args) {
+ if (compareAbbreviated(args.NUM1, args.NUM2) === 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ lessabbriviated(args) {
+ if (compareAbbreviated(args.NUM1, args.NUM2) === -1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ function abbreviateNumber(number) {
+ const suffixes = [
+ "",
+ "K",
+ "M",
+ "B",
+ "T",
+ "Q",
+ "Qi",
+ "Sx",
+ "Sp",
+ "Oc",
+ "Nn",
+ "Dc",
+ "Ud",
+ "Dd",
+ "Td",
+ "Qd",
+ "Qid",
+ "Sxd",
+ "Spd",
+ "Ocd",
+ "Nnd",
+ "Vg",
+ "Uvg",
+ "Dvg",
+ "Tvg",
+ "Qvg",
+ "Qivg",
+ "Sxvg",
+ "Spvg",
+ "Ocvg",
+ "Nnvg",
+ "Ce",
+ ];
+
+ if (Math.abs(number) < 1000) return number.toString();
+
+ const suffixIndex = Math.floor(Math.log10(Math.abs(number)) / 3);
+ if (suffixIndex >= suffixes.length) {
+ return number.toExponential(1);
+ }
+
+ const abbreviatedNumber = (number / Math.pow(1000, suffixIndex)).toFixed(1);
+ return `${abbreviatedNumber}${suffixes[suffixIndex]}`;
+ }
+
+ function unAbbreviateNumber(abbreviated) {
+ const suffixes = {
+ K: 1e3,
+ M: 1e6,
+ B: 1e9,
+ T: 1e12,
+ Q: 1e15,
+ QI: 1e18,
+ SX: 1e21,
+ SP: 1e24,
+ OC: 1e27,
+ NN: 1e30,
+ DC: 1e33,
+ UD: 1e36,
+ DD: 1e39,
+ TD: 1e42,
+ QD: 1e45,
+ QID: 1e48,
+ SXD: 1e51,
+ SPD: 1e54,
+ OCD: 1e57,
+ NND: 1e60,
+ VG: 1e63,
+ UVG: 1e66,
+ DVG: 1e69,
+ TVG: 1e72,
+ QVG: 1e75,
+ QIVG: 1e78,
+ SXVG: 1e81,
+ SPVG: 1e84,
+ OCVG: 1e87,
+ NNVG: 1e90,
+ CE: 1e303,
+ };
+
+ const regex = /^(-?\d+(\.\d+)?)([a-zA-Z]*)$/;
+ const match = abbreviated.match(regex);
+
+ if (!match) return NaN;
+
+ const numberPart = parseFloat(match[1]);
+ const suffix = match[3].toUpperCase();
+
+ if (!suffix) return numberPart;
+
+ const multiplier = suffixes[suffix];
+ if (!multiplier) return NaN;
+
+ return numberPart * multiplier;
+ }
+
+ function addAbbreviated(a, b) {
+ const num1 = unAbbreviateNumber(a);
+ const num2 = unAbbreviateNumber(b);
+ if (isNaN(num1) || isNaN(num2)) return NaN;
+
+ const sum = num1 + num2;
+ return abbreviateNumber(sum);
+ }
+
+ function subtractAbbreviated(a, b) {
+ const num1 = unAbbreviateNumber(a);
+ const num2 = unAbbreviateNumber(b);
+ if (isNaN(num1) || isNaN(num2)) return NaN;
+
+ const difference = num1 - num2;
+ return abbreviateNumber(difference);
+ }
+
+ function multiplyAbbreviated(a, b) {
+ const num1 = unAbbreviateNumber(a);
+ const num2 = unAbbreviateNumber(b);
+ if (isNaN(num1) || isNaN(num2)) return NaN;
+
+ const product = num1 * num2;
+ return abbreviateNumber(product);
+ }
+
+ function divideAbbreviated(a, b) {
+ const num1 = unAbbreviateNumber(a);
+ const num2 = unAbbreviateNumber(b);
+ if (isNaN(num1) || isNaN(num2) || num2 === 0) return NaN;
+
+ const quotient = num1 / num2;
+ return abbreviateNumber(quotient);
+ }
+
+ function compareAbbreviated(a, b) {
+ const num1 = unAbbreviateNumber(a);
+ const num2 = unAbbreviateNumber(b);
+ if (isNaN(num1) || isNaN(num2)) return NaN;
+
+ if (num1 > num2) return 1;
+ if (num1 < num2) return -1;
+ return 0;
+ }
+
+ Scratch.extensions.register(new Abbreviation());
+})(Scratch);
diff --git a/static/extensions/Cool_skratcher/noise.js b/static/extensions/Cool_skratcher/noise.js
new file mode 100644
index 00000000..7e2846e1
--- /dev/null
+++ b/static/extensions/Cool_skratcher/noise.js
@@ -0,0 +1,185 @@
+(function(Scratch) {
+ 'use strict';
+
+ // Perlin Noise algorithm from Noise.js
+ const Perlin = {
+ perm: new Array(512),
+ gradP: new Array(512),
+ grad3: [
+ [1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0],
+ [1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1],
+ [0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1]
+ ],
+ seed(seed) {
+ let p = [];
+ for (let i = 0; i < 256; i++) {
+ p[i] = i;
+ }
+ let n, q;
+ for (let i = 255; i > 0; i--) {
+ n = Math.floor(seed * (i + 1)) % 256;
+ q = p[i];
+ p[i] = p[n];
+ p[n] = q;
+ }
+ for (let i = 0; i < 512; i++) {
+ this.perm[i] = p[i & 255];
+ this.gradP[i] = this.grad3[this.perm[i] % 12];
+ }
+ },
+ fade(t) {
+ return t * t * t * (t * (t * 6 - 15) + 10);
+ },
+ lerp(t, a, b) {
+ return a + t * (b - a);
+ },
+ dot(g, x, y) {
+ return g[0] * x + g[1] * y;
+ },
+ noise(x, y) {
+ const X = Math.floor(x) & 255;
+ const Y = Math.floor(y) & 255;
+ x = x - Math.floor(x);
+ y = y - Math.floor(y);
+
+ const u = this.fade(x);
+ const v = this.fade(y);
+
+ const grad00 = this.gradP[X + this.perm[Y]];
+ const grad01 = this.gradP[X + this.perm[Y + 1]];
+ const grad10 = this.gradP[X + 1 + this.perm[Y]];
+ const grad11 = this.gradP[X + 1 + this.perm[Y + 1]];
+
+ const n00 = this.dot(grad00, x, y);
+ const n10 = this.dot(grad10, x - 1, y);
+ const n01 = this.dot(grad01, x, y - 1);
+ const n11 = this.dot(grad11, x - 1, y - 1);
+
+ const nx0 = this.lerp(u, n00, n10);
+ const nx1 = this.lerp(u, n01, n11);
+
+ return this.lerp(v, nx0, nx1);
+ }
+ };
+
+ class PerlinNoiseExtension {
+ constructor() {
+ this.noiseMap = {};
+ }
+
+ // Pre-generate Perlin noise based on seed and store it
+ generateNoise(seed, octaves) {
+ Perlin.seed(seed);
+ this.noiseMap[seed] = { octaves };
+ }
+
+ // Get pre-generated noise at X, Y
+ getNoiseAt({ seed, x, y }) {
+ const noiseData = this.noiseMap[seed];
+ if (!noiseData) {
+ return 0; // Return 0 if noise is not pre-generated
+ }
+
+ const { octaves } = noiseData;
+ let total = 0;
+ let frequency = 1;
+ let amplitude = 1;
+ let maxValue = 0;
+
+ for (let i = 0; i < octaves; i++) {
+ total += Perlin.noise(x * frequency, y * frequency) * amplitude;
+ maxValue += amplitude;
+ amplitude /= 2;
+ frequency *= 2;
+ }
+
+ return total / maxValue; // Normalize the result
+ }
+
+ // Get Perlin noise directly without pre-generation
+ getDirectNoise({ seed, x, y, octaves }) {
+ Perlin.seed(seed);
+ let total = 0;
+ let frequency = 1;
+ let amplitude = 1;
+ let maxValue = 0;
+
+ for (let i = 0; i < octaves; i++) {
+ total += Perlin.noise(x * frequency, y * frequency) * amplitude;
+ maxValue += amplitude;
+ amplitude /= 2;
+ frequency *= 2;
+ }
+
+ return total / maxValue; // Normalize the result
+ }
+
+ getInfo() {
+ return {
+ id: 'perlinNoise',
+ name: 'Perlin Noise',
+ blocks: [
+ {
+ opcode: 'generateNoise',
+ blockType: Scratch.BlockType.COMMAND,
+ text: 'pre-generate perlin noise Seed: [SEED] Octave: [OCTAVE]',
+ arguments: {
+ SEED: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 1234,
+ },
+ OCTAVE: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 4,
+ },
+ },
+ },
+ {
+ opcode: 'getNoiseAt',
+ blockType: Scratch.BlockType.REPORTER,
+ text: 'get pre-generated perlin noise Seed: [SEED] at X: [X] Y: [Y]',
+ arguments: {
+ SEED: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 1234,
+ },
+ X: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 0,
+ },
+ Y: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 0,
+ },
+ },
+ },
+ {
+ opcode: 'getDirectNoise',
+ blockType: Scratch.BlockType.REPORTER,
+ text: 'get direct perlin noise Seed: [SEED] X: [X] Y: [Y] Octave: [OCTAVE]',
+ arguments: {
+ SEED: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 1234,
+ },
+ X: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 0,
+ },
+ Y: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 0,
+ },
+ OCTAVE: {
+ type: Scratch.ArgumentType.NUMBER,
+ defaultValue: 4,
+ },
+ },
+ }
+ ],
+ };
+ }
+ }
+
+ Scratch.extensions.register(new PerlinNoiseExtension());
+})(Scratch);
\ No newline at end of file
diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js
new file mode 100644
index 00000000..230d3362
--- /dev/null
+++ b/static/extensions/Cool_skratcher/vectors.js
@@ -0,0 +1,305 @@
+// Name: Vectors!
+// ID: vectors
+// Description: Adds a set of blocks for vector operations in 2D and 3D space.
+// By: cool_skratcher
+// License: MIT
+
+(function(Scratch) {
+ 'use strict';
+
+ class VecMath3D {
+ constructor() {
+ this.camera = { pos: { x: 0, y: 0, z: 0 }, rot: { yaw: 0, pitch: 0, roll: 0 }, fov: 100 };
+ }
+
+ getInfo() {
+ return {
+ id: 'vectors',
+ name: 'Vectors',
+ color1: "#57a3e5",
+ color2: "#0063ba",
+ blocks: [
+ "---",
+ { text: 'Vector Operations', blockType: Scratch.BlockType.LABEL},
+ { opcode: 'vec2', blockType: Scratch.BlockType.REPORTER, text: 'vec2 [x] [y]', arguments: { x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }},
+ { opcode: 'vec3', blockType: Scratch.BlockType.REPORTER, text: 'vec3 [x] [y] [z]', arguments: { x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}},
+ { opcode: 'getComponent', blockType: Scratch.BlockType.REPORTER, text: '[component] of [v]', arguments: { component: { type: Scratch.ArgumentType.STRING, menu: 'components' }, v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'add', blockType: Scratch.BlockType.REPORTER, text: 'add [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'sub', blockType: Scratch.BlockType.REPORTER, text: 'sub [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'mul', blockType: Scratch.BlockType.REPORTER, text: 'mul [v] by [scalar]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, scalar: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }}},
+ { opcode: 'div', blockType: Scratch.BlockType.REPORTER, text: 'div [v] by [scalar]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, scalar: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }}},
+ { opcode: 'mag', blockType: Scratch.BlockType.REPORTER, text: 'mag [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'dot', blockType: Scratch.BlockType.REPORTER, text: 'dot [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'cross', blockType: Scratch.BlockType.REPORTER, text: 'cross [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'rotateVec3', blockType: Scratch.BlockType.REPORTER, text: 'rotate [v] by x: [rx] y: [ry] z: [rz]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, rx: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, ry: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, rz: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}},
+ { opcode: 'rotateAroundOrigin', blockType: Scratch.BlockType.REPORTER, text: 'rotate [v] around [origin] by x: [rx] y: [ry] z: [rz]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, origin: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, rx: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, ry: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, rz: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}},
+ "---",
+ { text: 'Culling', blockType: Scratch.BlockType.LABEL},
+ { opcode: 'isCulled', blockType: Scratch.BlockType.BOOLEAN, text: 'is [v] culled', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'cullAgainstPlane', blockType: Scratch.BlockType.BOOLEAN, text: 'is [v] culled against plane [plane]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, plane: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,1' }}},
+ { opcode: 'frustumCull', blockType: Scratch.BlockType.BOOLEAN, text: 'is [v] inside frustum with near: [near] far: [far]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, near: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0.1 }, far: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }}},
+ { opcode: 'backFaceCull', blockType: Scratch.BlockType.BOOLEAN, text: 'is face [v1] [v2] [v3] culled', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '1,0,0' }, v3: { type: Scratch.ArgumentType.STRING, defaultValue: '0,1,0' }}},
+ "---",
+ { text: 'Projection and Camera', blockType: Scratch.BlockType.LABEL},
+ { opcode: 'project', blockType: Scratch.BlockType.REPORTER, text: 'project [v] to screen', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'setCamPos', blockType: Scratch.BlockType.COMMAND, text: 'set camera pos to [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'changeCamPos', blockType: Scratch.BlockType.COMMAND, text: 'change camera pos by [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'changeCamComponent', blockType: Scratch.BlockType.COMMAND, text: 'change camera [component] by [val]', arguments: { component: { type: Scratch.ArgumentType.STRING, menu: 'components' }, val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}},
+ { opcode: 'getCamPos', blockType: Scratch.BlockType.REPORTER, text: 'camera pos' },
+
+ { opcode: 'setCamRot', blockType: Scratch.BlockType.COMMAND, text: 'set camera rotation to [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'changeCamRot', blockType: Scratch.BlockType.COMMAND, text: 'change camera rotation by [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}},
+ { opcode: 'changeCamAngle', blockType: Scratch.BlockType.COMMAND, text: 'change camera [angle] by [val]', arguments: { angle: { type: Scratch.ArgumentType.STRING, menu: 'angles' }, val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}},
+ { opcode: 'getCamRot', blockType: Scratch.BlockType.REPORTER, text: 'camera rotation' },
+
+ { opcode: 'setFOV', blockType: Scratch.BlockType.COMMAND, text: 'set FOV to [val]', arguments: { val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }}},
+ { opcode: 'changeFOV', blockType: Scratch.BlockType.COMMAND, text: 'change FOV by [val]', arguments: { val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 10 }}},
+ { opcode: 'getFOV', blockType: Scratch.BlockType.REPORTER, text: 'FOV' },
+ "---",
+ { text: 'Sprite Movement', blockType: Scratch.BlockType.LABEL },
+ { opcode: 'moveByVec2', blockType: Scratch.BlockType.COMMAND, text: 'change pos by vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}},
+ { opcode: 'goToVec2', blockType: Scratch.BlockType.COMMAND, text: 'go to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}},
+ { opcode: 'getPosVec2', blockType: Scratch.BlockType.REPORTER, text: 'get position as vec2' },
+ { opcode: 'getSizeVec2', blockType: Scratch.BlockType.REPORTER, text: 'get size as vec2' },
+ ],
+ menus: {
+ components: { items: ['x', 'y', 'z'] },
+ angles: { items: ['yaw', 'pitch', 'roll'] },
+ }
+ };
+ }
+
+ // Vector creation
+ vec2(args) { return `${args.x},${args.y},0`; }
+ vec3(args) { return `${args.x},${args.y},${args.z}`; }
+
+ // Vector component access
+ getComponent(args) {
+ const [x, y, z = 0] = args.v.split(',').map(Number);
+ return args.component === 'x' ? x : args.component === 'y' ? y : z;
+ }
+
+ // Basic vector math
+ add(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a + b); }
+ sub(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a - b); }
+ mul(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a * b); }
+ div(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a / b); }
+ mag(args) { return Math.hypot(...args.v.split(',').map(Number)); }
+ dot(args) {
+ const [x1, y1, z1] = args.v1.split(',').map(Number);
+ const [x2, y2, z2] = args.v2.split(',').map(Number);
+ return x1 * x2 + y1 * y2 + z1 * z2;
+ }
+ cross(args) {
+ const [x1, y1, z1] = args.v1.split(',').map(Number);
+ const [x2, y2, z2] = args.v2.split(',').map(Number);
+ return `${y1 * z2 - z1 * y2},${z1 * x2 - x1 * z2},${x1 * y2 - y1 * x2}`;
+ }
+
+ rotateVec3(args) {
+ const [x, y, z] = args.v.split(',').map(Number);
+ return this._rotate3D({ x, y, z }, args.rx, args.ry, args.rz);
+ }
+
+ // Camera Controls
+ setCamPos(args) { this._setVec(this.camera.pos, args.v); }
+ changeCamPos(args) { this._addVec(this.camera.pos, args.v); }
+ changeCamComponent(args) { this.camera.pos[args.component] += args.val; }
+ getCamPos() { return `${this.camera.pos.x},${this.camera.pos.y},${this.camera.pos.z}`; }
+
+ setCamRot(args) { this._setRot(this.camera.rot, args.v); }
+ changeCamRot(args) { this._addRot(this.camera.rot, args.v); }
+ changeCamAngle(args) { this.camera.rot[args.angle] += args.val; }
+ getCamRot() { return `${this.camera.rot.yaw},${this.camera.rot.pitch},${this.camera.rot.roll}`; }
+
+ setFOV(args) { this.camera.fov = args.val; }
+ changeFOV(args) { this.camera.fov += args.val; }
+ getFOV() { return this.camera.fov; }
+
+ // Projection
+ project(args) {
+ const [x, y, z] = args.v.split(',').map(Number);
+ const cam = this.camera;
+ const dx = x - cam.pos.x, dy = y - cam.pos.y, dz = z - cam.pos.z;
+
+ // Apply yaw rotation
+ const camZ = dz * Math.cos(cam.rot.yaw) + dx * Math.sin(cam.rot.yaw);
+ const camX = dx * Math.cos(cam.rot.yaw) - dz * Math.sin(cam.rot.yaw);
+
+ // Apply pitch rotation
+ const tempY = dy * Math.cos(cam.rot.pitch) - camZ * Math.sin(cam.rot.pitch);
+ const tempZ = dy * Math.sin(cam.rot.pitch) + camZ * Math.cos(cam.rot.pitch);
+ const finalZ = tempZ; // This is now the new Z after pitch rotation
+ const finalY = tempY; // This is now the new Y after pitch rotation
+
+ // Apply roll rotation
+ const finalX = finalY * Math.sin(cam.rot.roll) + camX * Math.cos(cam.rot.roll);
+ const adjustedY = finalY * Math.cos(cam.rot.roll) - camX * Math.sin(cam.rot.roll);
+
+ // Calculate screen coordinates
+ const screenX = (finalX / finalZ) * cam.fov;
+ const screenY = (adjustedY / finalZ) * cam.fov;
+ return `${screenX},${screenY}`;
+ }
+
+ rotateAroundOrigin(args) {
+ const [vx, vy, vz] = args.v.split(',').map(Number);
+ const [ox, oy, oz] = args.origin.split(',').map(Number);
+ const rx = (Math.PI / 180) * args.rx;
+ const ry = (Math.PI / 180) * args.ry;
+ const rz = (Math.PI / 180) * args.rz;
+
+ // Translate vector to origin
+ let x = vx - ox;
+ let y = vy - oy;
+ let z = vz - oz;
+
+ // Rotate around Z-axis
+ let tempX = x * Math.cos(rz) - y * Math.sin(rz);
+ let tempY = x * Math.sin(rz) + y * Math.cos(rz);
+ x = tempX; y = tempY;
+
+ // Rotate around Y-axis
+ tempX = x * Math.cos(ry) + z * Math.sin(ry);
+ let tempZ = -x * Math.sin(ry) + z * Math.cos(ry);
+ x = tempX; z = tempZ;
+
+ // Rotate around X-axis
+ tempY = y * Math.cos(rx) - z * Math.sin(rx);
+ tempZ = y * Math.sin(rx) + z * Math.cos(rx);
+ y = tempY; z = tempZ;
+
+ // Translate back to original position
+ x += ox;
+ y += oy;
+ z += oz;
+
+ return `${x},${y},${z}`;
+ }
+
+ isCulled(args) {
+ const [x, y, z] = args.v.split(',').map(Number);
+ const { pos, rot } = this.camera;
+
+ // Transform point relative to camera
+ const dx = x - pos.x;
+ const dy = y - pos.y;
+ const dz = z - pos.z;
+
+ // Simple culling: check if behind the camera (z <= 0 in camera space)
+ const camZ = dz * Math.cos(rot.yaw) + dx * Math.sin(rot.yaw);
+ return camZ <= 0;
+ }
+
+ cullAgainstPlane(args) {
+ const [x, y, z] = args.v.split(',').map(Number);
+ const [nx, ny, nz] = args.plane.split(',').map(Number);
+
+ // Plane culling: check if point is behind the plane (dot product <= 0)
+ const dot = x * nx + y * ny + z * nz;
+ return dot <= 0;
+ }
+
+ frustumCull(args) {
+ const [x, y, z] = args.v.split(',').map(Number);
+ const { pos, rot, fov } = this.camera;
+ const near = args.near, far = args.far;
+
+ // Translate point relative to camera
+ const dx = x - pos.x;
+ const dy = y - pos.y;
+ const dz = z - pos.z;
+
+ // Rotate point relative to camera
+ const cx = dx * Math.cos(rot.yaw) - dz * Math.sin(rot.yaw);
+ const cz = dx * Math.sin(rot.yaw) + dz * Math.cos(rot.yaw);
+ const cy = dy;
+
+ // Check depth (near and far planes)
+ if (cz < near || cz > far) return true;
+
+ // Check horizontal FOV
+ const hHalf = Math.tan((fov / 2) * (Math.PI / 180)) * cz;
+ if (cx < -hHalf || cx > hHalf) return true;
+
+ // Check vertical FOV
+ const vHalf = hHalf * (3 / 4); // Assuming aspect ratio of 4:3
+ if (cy < -vHalf || cy > vHalf) return true;
+
+ return false;
+ }
+
+ backFaceCull(args) {
+ const [x1, y1, z1] = args.v1.split(',').map(Number);
+ const [x2, y2, z2] = args.v2.split(',').map(Number);
+ const [x3, y3, z3] = args.v3.split(',').map(Number);
+ const { pos } = this.camera;
+
+ // Calculate face normal
+ const ux = x2 - x1, uy = y2 - y1, uz = z2 - z1;
+ const vx = x3 - x1, vy = y3 - y1, vz = z3 - z1;
+ const nx = uy * vz - uz * vy;
+ const ny = uz * vx - ux * vz;
+ const nz = ux * vy - uy * vx;
+
+ // Vector from camera to one vertex
+ const cx = x1 - pos.x, cy = y1 - pos.y, cz = z1 - pos.z;
+
+ // Dot product of face normal and camera vector
+ const dot = nx * cx + ny * cy + nz * cz;
+
+ return dot >= 0;
+ }
+
+ // Utility Functions
+ _vectorOp(v1, v2, op) {
+ const [x1, y1, z1] = v1.split(',').map(Number);
+ const [x2, y2, z2] = v2.split(',').map(Number);
+ return `${op(x1, x2)},${op(y1, y2)},${op(z1, z2)}`;
+ }
+
+ _scalarOp(v, scalar, op) {
+ const [x, y, z] = v.split(',').map(Number);
+ return `${op(x, scalar)},${op(y, scalar)},${op(z, scalar)}`;
+ }
+
+ _setVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x = x; target.y = y; target.z = z; }
+ _addVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x += x; target.y += y; target.z += z; }
+ _setRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw = x; target.pitch = y; target.roll = z; }
+ _addRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw += x; target.pitch += y; target.roll += z; }
+
+ _rotate3D(v, rx, ry, rz) {
+ const cos = Math.cos, sin = Math.sin;
+ let { x, y, z } = v;
+ [y, z] = [y * cos(rx) - z * sin(rx), y * sin(rx) + z * cos(rx)];
+ [x, z] = [x * cos(ry) + z * sin(ry), -x * sin(ry) + z * cos(ry)];
+ [x, y] = [x * cos(rz) - y * sin(rz), x * sin(rz) + y * cos(rz)];
+ return `${x},${y},${z}`;
+ }
+
+ moveByVec2(args, util) {
+ const [dx, dy] = args.v.split(',').map(Number);
+ const x = Scratch.Cast.toNumber(dx);
+ const y = Scratch.Cast.toNumber(dy);
+ util.target.setXY(util.target.x + x, util.target.y + y);
+ }
+
+ goToVec2(args, util) {
+ const [dx, dy] = args.v.split(',').map(Number);
+ const x = Scratch.Cast.toNumber(dx);
+ const y = Scratch.Cast.toNumber(dy);
+ util.target.setXY(x, y);
+ }
+
+ getPosVec2(args, util) {
+ return `${util.target.x},${util.target.y}`;
+ }
+
+ getSizeVec2(args, util) {
+ const bounds = Scratch.vm.renderer.getBounds(util.target.drawableID)
+ return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`;
+ }
+ }
+
+ Scratch.extensions.register(new VecMath3D());
+})(Scratch);
From 18190b9a68aefe4c647ad9180369de316918bd55 Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Tue, 19 Nov 2024 11:39:40 +0000
Subject: [PATCH 02/10] Delete
static/extensions/Cool_skratcher/abbreviations.js
---
.../Cool_skratcher/abbreviations.js | 318 ------------------
1 file changed, 318 deletions(-)
delete mode 100644 static/extensions/Cool_skratcher/abbreviations.js
diff --git a/static/extensions/Cool_skratcher/abbreviations.js b/static/extensions/Cool_skratcher/abbreviations.js
deleted file mode 100644
index ef542672..00000000
--- a/static/extensions/Cool_skratcher/abbreviations.js
+++ /dev/null
@@ -1,318 +0,0 @@
-// Name: Number Abbiviation!
-// ID: abbreviate
-// Description: Adds blocks to convert any big number to way less text like: 1200000 -> 1.2M.
-// By: cool_skratcher
-// License: MIT
-
-(function (Scratch) {
- "use strict";
-
- class Abbreviation {
- getInfo() {
- return {
- id: "abbreviate",
- name: "Abbreviation!",
- color1: "#9dd13d",
- color2: "#8fbe37",
- blocks: [
- {
- opcode: "abbriviate",
- blockType: Scratch.BlockType.REPORTER,
- text: "abbreviate: [NUM]",
- arguments: {
- NUM: {
- type: Scratch.ArgumentType.NUMBER,
- },
- },
- },
- {
- opcode: "unabbriviate",
- blockType: Scratch.BlockType.REPORTER,
- text: "un-abbreviate: [NUM]",
- arguments: {
- NUM: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- {
- opcode: "addabbriviated",
- blockType: Scratch.BlockType.REPORTER,
- text: "add abbreviated [NUM1] + [NUM2]",
- arguments: {
- NUM1: {
- type: Scratch.ArgumentType.STRING,
- },
- NUM2: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- {
- opcode: "subabbriviated",
- blockType: Scratch.BlockType.REPORTER,
- text: "subtract abbreviated [NUM1] - [NUM2]",
- arguments: {
- NUM1: {
- type: Scratch.ArgumentType.STRING,
- },
- NUM2: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- {
- opcode: "multiabbriviated",
- blockType: Scratch.BlockType.REPORTER,
- text: "multiply abbreviated [NUM1] * [NUM2]",
- arguments: {
- NUM1: {
- type: Scratch.ArgumentType.STRING,
- },
- NUM2: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- {
- opcode: "divabbriviated",
- blockType: Scratch.BlockType.REPORTER,
- text: "divide abbreviated [NUM1] / [NUM2]",
- arguments: {
- NUM1: {
- type: Scratch.ArgumentType.STRING,
- },
- NUM2: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- {
- opcode: "equalabbriviated",
- blockType: Scratch.BlockType.BOOLEAN,
- text: "is equal abbreviated [NUM1] = [NUM2]",
- arguments: {
- NUM1: {
- type: Scratch.ArgumentType.STRING,
- },
- NUM2: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- {
- opcode: "moreabbriviated",
- blockType: Scratch.BlockType.BOOLEAN,
- text: "is greater abbreviated [NUM1] > [NUM2]",
- arguments: {
- NUM1: {
- type: Scratch.ArgumentType.STRING,
- },
- NUM2: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- {
- opcode: "lessabbriviated",
- blockType: Scratch.BlockType.BOOLEAN,
- text: "is less abbreviated [NUM1] < [NUM2]",
- arguments: {
- NUM1: {
- type: Scratch.ArgumentType.STRING,
- },
- NUM2: {
- type: Scratch.ArgumentType.STRING,
- },
- },
- },
- ],
- };
- }
- abbriviate(args) {
- return abbreviateNumber(args.NUM);
- }
- unabbriviate(args) {
- return unAbbreviateNumber(args.NUM);
- }
- addabbriviated(args) {
- return addAbbreviated(args.NUM1, args.NUM2);
- }
- subabbriviated(args) {
- return subtractAbbreviated(args.NUM1, args.NUM2);
- }
- multiabbriviated(args) {
- return multiplyAbbreviated(args.NUM1, args.NUM2);
- }
- divabbriviated(args) {
- return divideAbbreviated(args.NUM1, args.NUM2);
- }
- equalabbriviated(args) {
- if (compareAbbreviated(args.NUM1, args.NUM2) === 0) {
- return true;
- } else {
- return false;
- }
- }
- moreabbriviated(args) {
- if (compareAbbreviated(args.NUM1, args.NUM2) === 1) {
- return true;
- } else {
- return false;
- }
- }
- lessabbriviated(args) {
- if (compareAbbreviated(args.NUM1, args.NUM2) === -1) {
- return true;
- } else {
- return false;
- }
- }
- }
-
- function abbreviateNumber(number) {
- const suffixes = [
- "",
- "K",
- "M",
- "B",
- "T",
- "Q",
- "Qi",
- "Sx",
- "Sp",
- "Oc",
- "Nn",
- "Dc",
- "Ud",
- "Dd",
- "Td",
- "Qd",
- "Qid",
- "Sxd",
- "Spd",
- "Ocd",
- "Nnd",
- "Vg",
- "Uvg",
- "Dvg",
- "Tvg",
- "Qvg",
- "Qivg",
- "Sxvg",
- "Spvg",
- "Ocvg",
- "Nnvg",
- "Ce",
- ];
-
- if (Math.abs(number) < 1000) return number.toString();
-
- const suffixIndex = Math.floor(Math.log10(Math.abs(number)) / 3);
- if (suffixIndex >= suffixes.length) {
- return number.toExponential(1);
- }
-
- const abbreviatedNumber = (number / Math.pow(1000, suffixIndex)).toFixed(1);
- return `${abbreviatedNumber}${suffixes[suffixIndex]}`;
- }
-
- function unAbbreviateNumber(abbreviated) {
- const suffixes = {
- K: 1e3,
- M: 1e6,
- B: 1e9,
- T: 1e12,
- Q: 1e15,
- QI: 1e18,
- SX: 1e21,
- SP: 1e24,
- OC: 1e27,
- NN: 1e30,
- DC: 1e33,
- UD: 1e36,
- DD: 1e39,
- TD: 1e42,
- QD: 1e45,
- QID: 1e48,
- SXD: 1e51,
- SPD: 1e54,
- OCD: 1e57,
- NND: 1e60,
- VG: 1e63,
- UVG: 1e66,
- DVG: 1e69,
- TVG: 1e72,
- QVG: 1e75,
- QIVG: 1e78,
- SXVG: 1e81,
- SPVG: 1e84,
- OCVG: 1e87,
- NNVG: 1e90,
- CE: 1e303,
- };
-
- const regex = /^(-?\d+(\.\d+)?)([a-zA-Z]*)$/;
- const match = abbreviated.match(regex);
-
- if (!match) return NaN;
-
- const numberPart = parseFloat(match[1]);
- const suffix = match[3].toUpperCase();
-
- if (!suffix) return numberPart;
-
- const multiplier = suffixes[suffix];
- if (!multiplier) return NaN;
-
- return numberPart * multiplier;
- }
-
- function addAbbreviated(a, b) {
- const num1 = unAbbreviateNumber(a);
- const num2 = unAbbreviateNumber(b);
- if (isNaN(num1) || isNaN(num2)) return NaN;
-
- const sum = num1 + num2;
- return abbreviateNumber(sum);
- }
-
- function subtractAbbreviated(a, b) {
- const num1 = unAbbreviateNumber(a);
- const num2 = unAbbreviateNumber(b);
- if (isNaN(num1) || isNaN(num2)) return NaN;
-
- const difference = num1 - num2;
- return abbreviateNumber(difference);
- }
-
- function multiplyAbbreviated(a, b) {
- const num1 = unAbbreviateNumber(a);
- const num2 = unAbbreviateNumber(b);
- if (isNaN(num1) || isNaN(num2)) return NaN;
-
- const product = num1 * num2;
- return abbreviateNumber(product);
- }
-
- function divideAbbreviated(a, b) {
- const num1 = unAbbreviateNumber(a);
- const num2 = unAbbreviateNumber(b);
- if (isNaN(num1) || isNaN(num2) || num2 === 0) return NaN;
-
- const quotient = num1 / num2;
- return abbreviateNumber(quotient);
- }
-
- function compareAbbreviated(a, b) {
- const num1 = unAbbreviateNumber(a);
- const num2 = unAbbreviateNumber(b);
- if (isNaN(num1) || isNaN(num2)) return NaN;
-
- if (num1 > num2) return 1;
- if (num1 < num2) return -1;
- return 0;
- }
-
- Scratch.extensions.register(new Abbreviation());
-})(Scratch);
From 0e29c7dcc35a9ae5a34dc7dc18efb494d9ff2abb Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Tue, 19 Nov 2024 11:39:49 +0000
Subject: [PATCH 03/10] Delete static/extensions/Cool_skratcher/noise.js
---
static/extensions/Cool_skratcher/noise.js | 185 ----------------------
1 file changed, 185 deletions(-)
delete mode 100644 static/extensions/Cool_skratcher/noise.js
diff --git a/static/extensions/Cool_skratcher/noise.js b/static/extensions/Cool_skratcher/noise.js
deleted file mode 100644
index 7e2846e1..00000000
--- a/static/extensions/Cool_skratcher/noise.js
+++ /dev/null
@@ -1,185 +0,0 @@
-(function(Scratch) {
- 'use strict';
-
- // Perlin Noise algorithm from Noise.js
- const Perlin = {
- perm: new Array(512),
- gradP: new Array(512),
- grad3: [
- [1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0],
- [1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1],
- [0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1]
- ],
- seed(seed) {
- let p = [];
- for (let i = 0; i < 256; i++) {
- p[i] = i;
- }
- let n, q;
- for (let i = 255; i > 0; i--) {
- n = Math.floor(seed * (i + 1)) % 256;
- q = p[i];
- p[i] = p[n];
- p[n] = q;
- }
- for (let i = 0; i < 512; i++) {
- this.perm[i] = p[i & 255];
- this.gradP[i] = this.grad3[this.perm[i] % 12];
- }
- },
- fade(t) {
- return t * t * t * (t * (t * 6 - 15) + 10);
- },
- lerp(t, a, b) {
- return a + t * (b - a);
- },
- dot(g, x, y) {
- return g[0] * x + g[1] * y;
- },
- noise(x, y) {
- const X = Math.floor(x) & 255;
- const Y = Math.floor(y) & 255;
- x = x - Math.floor(x);
- y = y - Math.floor(y);
-
- const u = this.fade(x);
- const v = this.fade(y);
-
- const grad00 = this.gradP[X + this.perm[Y]];
- const grad01 = this.gradP[X + this.perm[Y + 1]];
- const grad10 = this.gradP[X + 1 + this.perm[Y]];
- const grad11 = this.gradP[X + 1 + this.perm[Y + 1]];
-
- const n00 = this.dot(grad00, x, y);
- const n10 = this.dot(grad10, x - 1, y);
- const n01 = this.dot(grad01, x, y - 1);
- const n11 = this.dot(grad11, x - 1, y - 1);
-
- const nx0 = this.lerp(u, n00, n10);
- const nx1 = this.lerp(u, n01, n11);
-
- return this.lerp(v, nx0, nx1);
- }
- };
-
- class PerlinNoiseExtension {
- constructor() {
- this.noiseMap = {};
- }
-
- // Pre-generate Perlin noise based on seed and store it
- generateNoise(seed, octaves) {
- Perlin.seed(seed);
- this.noiseMap[seed] = { octaves };
- }
-
- // Get pre-generated noise at X, Y
- getNoiseAt({ seed, x, y }) {
- const noiseData = this.noiseMap[seed];
- if (!noiseData) {
- return 0; // Return 0 if noise is not pre-generated
- }
-
- const { octaves } = noiseData;
- let total = 0;
- let frequency = 1;
- let amplitude = 1;
- let maxValue = 0;
-
- for (let i = 0; i < octaves; i++) {
- total += Perlin.noise(x * frequency, y * frequency) * amplitude;
- maxValue += amplitude;
- amplitude /= 2;
- frequency *= 2;
- }
-
- return total / maxValue; // Normalize the result
- }
-
- // Get Perlin noise directly without pre-generation
- getDirectNoise({ seed, x, y, octaves }) {
- Perlin.seed(seed);
- let total = 0;
- let frequency = 1;
- let amplitude = 1;
- let maxValue = 0;
-
- for (let i = 0; i < octaves; i++) {
- total += Perlin.noise(x * frequency, y * frequency) * amplitude;
- maxValue += amplitude;
- amplitude /= 2;
- frequency *= 2;
- }
-
- return total / maxValue; // Normalize the result
- }
-
- getInfo() {
- return {
- id: 'perlinNoise',
- name: 'Perlin Noise',
- blocks: [
- {
- opcode: 'generateNoise',
- blockType: Scratch.BlockType.COMMAND,
- text: 'pre-generate perlin noise Seed: [SEED] Octave: [OCTAVE]',
- arguments: {
- SEED: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 1234,
- },
- OCTAVE: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 4,
- },
- },
- },
- {
- opcode: 'getNoiseAt',
- blockType: Scratch.BlockType.REPORTER,
- text: 'get pre-generated perlin noise Seed: [SEED] at X: [X] Y: [Y]',
- arguments: {
- SEED: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 1234,
- },
- X: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 0,
- },
- Y: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 0,
- },
- },
- },
- {
- opcode: 'getDirectNoise',
- blockType: Scratch.BlockType.REPORTER,
- text: 'get direct perlin noise Seed: [SEED] X: [X] Y: [Y] Octave: [OCTAVE]',
- arguments: {
- SEED: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 1234,
- },
- X: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 0,
- },
- Y: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 0,
- },
- OCTAVE: {
- type: Scratch.ArgumentType.NUMBER,
- defaultValue: 4,
- },
- },
- }
- ],
- };
- }
- }
-
- Scratch.extensions.register(new PerlinNoiseExtension());
-})(Scratch);
\ No newline at end of file
From 57487db43b297de247cc40c77b11d9854a76b58d Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Tue, 19 Nov 2024 11:40:36 +0000
Subject: [PATCH 04/10] Add files via upload
---
static/images/Cool_skratcher/vectors.svg | 1 +
1 file changed, 1 insertion(+)
create mode 100644 static/images/Cool_skratcher/vectors.svg
diff --git a/static/images/Cool_skratcher/vectors.svg b/static/images/Cool_skratcher/vectors.svg
new file mode 100644
index 00000000..bc388ede
--- /dev/null
+++ b/static/images/Cool_skratcher/vectors.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
From f907dc0699cde4310b3f7b17884e7db103574b84 Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Tue, 19 Nov 2024 11:42:45 +0000
Subject: [PATCH 05/10] Update vectors.js
---
static/extensions/Cool_skratcher/vectors.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js
index 230d3362..e039a53d 100644
--- a/static/extensions/Cool_skratcher/vectors.js
+++ b/static/extensions/Cool_skratcher/vectors.js
@@ -1,5 +1,5 @@
// Name: Vectors!
-// ID: vectors
+// ID: vectorscoolskratcher
// Description: Adds a set of blocks for vector operations in 2D and 3D space.
// By: cool_skratcher
// License: MIT
@@ -14,7 +14,7 @@
getInfo() {
return {
- id: 'vectors',
+ id: 'vectorscoolskratcher',
name: 'Vectors',
color1: "#57a3e5",
color2: "#0063ba",
From 835c2c44476ba5d78217193443020e33d29c7353 Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Tue, 19 Nov 2024 14:05:28 +0000
Subject: [PATCH 06/10] Update vectors.js
---
static/extensions/Cool_skratcher/vectors.js | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js
index e039a53d..b460032c 100644
--- a/static/extensions/Cool_skratcher/vectors.js
+++ b/static/extensions/Cool_skratcher/vectors.js
@@ -1,5 +1,5 @@
// Name: Vectors!
-// ID: vectorscoolskratcher
+// ID: vectors
// Description: Adds a set of blocks for vector operations in 2D and 3D space.
// By: cool_skratcher
// License: MIT
@@ -7,14 +7,14 @@
(function(Scratch) {
'use strict';
- class VecMath3D {
+ class VecMath {
constructor() {
this.camera = { pos: { x: 0, y: 0, z: 0 }, rot: { yaw: 0, pitch: 0, roll: 0 }, fov: 100 };
}
getInfo() {
return {
- id: 'vectorscoolskratcher',
+ id: 'vectors',
name: 'Vectors',
color1: "#57a3e5",
color2: "#0063ba",
@@ -98,7 +98,7 @@
rotateVec3(args) {
const [x, y, z] = args.v.split(',').map(Number);
- return this._rotate3D({ x, y, z }, args.rx, args.ry, args.rz);
+ return this._rotate3D({ x, y, z }, this._toRadians(args.rx), this._toRadians(args.ry), this._toRadians(args.rz));
}
// Camera Controls
@@ -145,9 +145,9 @@
rotateAroundOrigin(args) {
const [vx, vy, vz] = args.v.split(',').map(Number);
const [ox, oy, oz] = args.origin.split(',').map(Number);
- const rx = (Math.PI / 180) * args.rx;
- const ry = (Math.PI / 180) * args.ry;
- const rz = (Math.PI / 180) * args.rz;
+ const rx = this._toRadians(args.rx);
+ const ry = this._toRadians(args.ry);
+ const rz = this._toRadians(args.rz);
// Translate vector to origin
let x = vx - ox;
@@ -299,7 +299,12 @@
const bounds = Scratch.vm.renderer.getBounds(util.target.drawableID)
return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`;
}
+
+ // New utility function to convert degrees to radians
+ _toRadians(degrees) {
+ return degrees * (Math.PI / 180);
+ }
}
- Scratch.extensions.register(new VecMath3D());
+ Scratch.extensions.register(new VecMath());
})(Scratch);
From 32934a8b65bccd287f6351fb95fdf3980543dd63 Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Wed, 20 Nov 2024 09:17:38 +0000
Subject: [PATCH 07/10] Update vectors.js
added pen+ to draw triangles with vectors and fixed some bugs
---
static/extensions/Cool_skratcher/vectors.js | 78 ++++++++++++++++++---
1 file changed, 67 insertions(+), 11 deletions(-)
diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js
index b460032c..710ba8d8 100644
--- a/static/extensions/Cool_skratcher/vectors.js
+++ b/static/extensions/Cool_skratcher/vectors.js
@@ -6,6 +6,30 @@
(function(Scratch) {
'use strict';
+ const vm = Scratch.vm;
+
+ let penPLoaded = false;
+ let penPModule = null;
+ const penPCheck = () => {
+ if (penPLoaded) {
+ return;
+ } // Return if pen+ integration is loaded
+ if (vm.runtime.ext_penP) {
+ penPLoaded = true;
+ }
+ penPModule = vm.runtime.ext_penP;
+
+ if (penPModule) {
+ penPModule.turnAdvancedSettingOff({
+ Setting: "wValueUnderFlow",
+ onOrOff: "on",
+ });
+ }
+
+ vm.runtime.extensionManager.refreshBlocks();
+ };
+ penPCheck();
+ vm.runtime.on("EXTENSION_ADDED", penPCheck);
class VecMath {
constructor() {
@@ -61,6 +85,9 @@
{ opcode: 'goToVec2', blockType: Scratch.BlockType.COMMAND, text: 'go to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}},
{ opcode: 'getPosVec2', blockType: Scratch.BlockType.REPORTER, text: 'get position as vec2' },
{ opcode: 'getSizeVec2', blockType: Scratch.BlockType.REPORTER, text: 'get size as vec2' },
+ "---",
+ { hideFromPalette: !penPLoaded, text: 'Pen+', blockType: Scratch.BlockType.LABEL },
+ { hideFromPalette: !penPLoaded, opcode: 'drawTriangle', blockType: Scratch.BlockType.COMMAND, text: 'triangle between [v1] [v2] [v3]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '1,0' }, v3: { type: Scratch.ArgumentType.STRING, defaultValue: '0,1' }}},
],
menus: {
components: { items: ['x', 'y', 'z'] },
@@ -122,19 +149,19 @@
const cam = this.camera;
const dx = x - cam.pos.x, dy = y - cam.pos.y, dz = z - cam.pos.z;
- // Apply yaw rotation
- const camZ = dz * Math.cos(cam.rot.yaw) + dx * Math.sin(cam.rot.yaw);
- const camX = dx * Math.cos(cam.rot.yaw) - dz * Math.sin(cam.rot.yaw);
+ // Apply yaw rotation (now in degrees)
+ const camZ = dz * Math.cos(this._toRadians(cam.rot.yaw)) + dx * Math.sin(this._toRadians(cam.rot.yaw));
+ const camX = dx * Math.cos(this._toRadians(cam.rot.yaw)) - dz * Math.sin(this._toRadians(cam.rot.yaw));
- // Apply pitch rotation
- const tempY = dy * Math.cos(cam.rot.pitch) - camZ * Math.sin(cam.rot.pitch);
- const tempZ = dy * Math.sin(cam.rot.pitch) + camZ * Math.cos(cam.rot.pitch);
+ // Apply pitch rotation (now in degrees)
+ const tempY = dy * Math.cos(this._toRadians(cam.rot.pitch)) - camZ * Math.sin(this._toRadians(cam.rot.pitch));
+ const tempZ = dy * Math.sin(this._toRadians(cam.rot.pitch)) + camZ * Math.cos(this._toRadians(cam.rot.pitch));
const finalZ = tempZ; // This is now the new Z after pitch rotation
const finalY = tempY; // This is now the new Y after pitch rotation
- // Apply roll rotation
- const finalX = finalY * Math.sin(cam.rot.roll) + camX * Math.cos(cam.rot.roll);
- const adjustedY = finalY * Math.cos(cam.rot.roll) - camX * Math.sin(cam.rot.roll);
+ // Apply roll rotation (now in degrees)
+ const finalX = finalY * Math.sin(this._toRadians(cam.rot.roll)) + camX * Math.cos(this._toRadians(cam.rot.roll));
+ const adjustedY = finalY * Math.cos(this._toRadians(cam.rot.roll)) - camX * Math.sin(this._toRadians(cam.rot.roll));
// Calculate screen coordinates
const screenX = (finalX / finalZ) * cam.fov;
@@ -265,8 +292,19 @@
_setVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x = x; target.y = y; target.z = z; }
_addVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x += x; target.y += y; target.z += z; }
- _setRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw = x; target.pitch = y; target.roll = z; }
- _addRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw += x; target.pitch += y; target.roll += z; }
+ _setRot(target, v) {
+ const [yaw, pitch, roll] = v.split(',').map(Number);
+ target.yaw = yaw;
+ target.pitch = pitch;
+ target.roll = roll;
+ }
+
+ _addRot(target, v) {
+ const [yaw, pitch, roll] = v.split(',').map(Number);
+ target.yaw += yaw;
+ target.pitch += pitch;
+ target.roll += roll;
+ }
_rotate3D(v, rx, ry, rz) {
const cos = Math.cos, sin = Math.sin;
@@ -300,6 +338,24 @@
return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`;
}
+ drawTriangle(args, util) {
+ const [x1, y1] = args.v1.split(',').map(Number);
+ const [x2, y2] = args.v2.split(',').map(Number);
+ const [x3, y3] = args.v3.split(',').map(Number);
+
+ penPModule.drawSolidTri(
+ {
+ x1: x1,
+ y1: y1,
+ x2: x2,
+ y2: y2,
+ x3: x3,
+ y3: y3,
+ },
+ util
+ );
+ }
+
// New utility function to convert degrees to radians
_toRadians(degrees) {
return degrees * (Math.PI / 180);
From f0c2788e4976867da741f03b94772a35d6aba4f1 Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Wed, 20 Nov 2024 12:20:37 +0000
Subject: [PATCH 08/10] Update vectors.js
added some more sprite move blocks fixed frustum culling and added better error handeling
---
static/extensions/Cool_skratcher/vectors.js | 252 ++++++++++++++------
1 file changed, 180 insertions(+), 72 deletions(-)
diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js
index 710ba8d8..2db9f524 100644
--- a/static/extensions/Cool_skratcher/vectors.js
+++ b/static/extensions/Cool_skratcher/vectors.js
@@ -7,26 +7,27 @@
(function(Scratch) {
'use strict';
const vm = Scratch.vm;
+ const mouse = vm.runtime.ioDevices.mouse;
let penPLoaded = false;
let penPModule = null;
const penPCheck = () => {
if (penPLoaded) {
return;
- } // Return if pen+ integration is loaded
+ }
if (vm.runtime.ext_penP) {
penPLoaded = true;
- }
- penPModule = vm.runtime.ext_penP;
+ penPModule = vm.runtime.ext_penP;
- if (penPModule) {
- penPModule.turnAdvancedSettingOff({
- Setting: "wValueUnderFlow",
- onOrOff: "on",
- });
- }
+ if (penPModule) {
+ penPModule.turnAdvancedSettingOff({
+ Setting: "wValueUnderFlow",
+ onOrOff: "on",
+ });
+ }
- vm.runtime.extensionManager.refreshBlocks();
+ vm.runtime.extensionManager.refreshBlocks();
+ }
};
penPCheck();
vm.runtime.on("EXTENSION_ADDED", penPCheck);
@@ -83,8 +84,10 @@
{ text: 'Sprite Movement', blockType: Scratch.BlockType.LABEL },
{ opcode: 'moveByVec2', blockType: Scratch.BlockType.COMMAND, text: 'change pos by vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}},
{ opcode: 'goToVec2', blockType: Scratch.BlockType.COMMAND, text: 'go to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}},
+ { opcode: 'pointTo', blockType: Scratch.BlockType.COMMAND, text: 'point to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}},
{ opcode: 'getPosVec2', blockType: Scratch.BlockType.REPORTER, text: 'get position as vec2' },
{ opcode: 'getSizeVec2', blockType: Scratch.BlockType.REPORTER, text: 'get size as vec2' },
+ { opcode: 'getMousePosVec2', blockType: Scratch.BlockType.REPORTER, text: 'mouse pos vec2' },
"---",
{ hideFromPalette: !penPLoaded, text: 'Pen+', blockType: Scratch.BlockType.LABEL },
{ hideFromPalette: !penPLoaded, opcode: 'drawTriangle', blockType: Scratch.BlockType.COMMAND, text: 'triangle between [v1] [v2] [v3]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '1,0' }, v3: { type: Scratch.ArgumentType.STRING, defaultValue: '0,1' }}},
@@ -97,8 +100,18 @@
}
// Vector creation
- vec2(args) { return `${args.x},${args.y},0`; }
- vec3(args) { return `${args.x},${args.y},${args.z}`; }
+ vec2(args) {
+ const x = Scratch.Cast.toNumber(args.x) || 0;
+ const y = Scratch.Cast.toNumber(args.y) || 0;
+ return `${x},${y}`;
+ }
+
+ vec3(args) {
+ const x = Scratch.Cast.toNumber(args.x) || 0;
+ const y = Scratch.Cast.toNumber(args.y) || 0;
+ const z = Scratch.Cast.toNumber(args.z) || 0;
+ return `${x},${y},${z}`;
+ }
// Vector component access
getComponent(args) {
@@ -107,25 +120,54 @@
}
// Basic vector math
- add(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a + b); }
- sub(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a - b); }
- mul(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a * b); }
- div(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a / b); }
- mag(args) { return Math.hypot(...args.v.split(',').map(Number)); }
+ add(args) {
+ return this._vectorOp(args.v1, args.v2, (a, b) => (a || 0) + (b || 0));
+ }
+
+ sub(args) {
+ return this._vectorOp(args.v1, args.v2, (a, b) => (a || 0) - (b || 0));
+ }
+
+ mul(args) {
+ const scalar = Scratch.Cast.toNumber(args.scalar) || 0;
+ return this._scalarOp(args.v, scalar, (a, b) => (a || 0) * b);
+ }
+
+ div(args) {
+ const scalar = Scratch.Cast.toNumber(args.scalar) || 1;
+ return this._scalarOp(args.v, scalar, (a, b) => b !== 0 ? (a || 0) / b : 0);
+ }
+
+ mag(args) {
+ const components = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ return Math.hypot(...components);
+ }
+
+ // Fixed dot product with validation
dot(args) {
- const [x1, y1, z1] = args.v1.split(',').map(Number);
- const [x2, y2, z2] = args.v2.split(',').map(Number);
+ const v1 = args.v1.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ const v2 = args.v2.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ const [x1 = 0, y1 = 0, z1 = 0] = v1;
+ const [x2 = 0, y2 = 0, z2 = 0] = v2;
return x1 * x2 + y1 * y2 + z1 * z2;
}
+
+ // Improved cross product
cross(args) {
- const [x1, y1, z1] = args.v1.split(',').map(Number);
- const [x2, y2, z2] = args.v2.split(',').map(Number);
+ const v1 = args.v1.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ const v2 = args.v2.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ const [x1 = 0, y1 = 0, z1 = 0] = v1;
+ const [x2 = 0, y2 = 0, z2 = 0] = v2;
return `${y1 * z2 - z1 * y2},${z1 * x2 - x1 * z2},${x1 * y2 - y1 * x2}`;
}
+ // Fixed rotation functions
rotateVec3(args) {
- const [x, y, z] = args.v.split(',').map(Number);
- return this._rotate3D({ x, y, z }, this._toRadians(args.rx), this._toRadians(args.ry), this._toRadians(args.rz));
+ const [x = 0, y = 0, z = 0] = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ const rx = this._toRadians(Scratch.Cast.toNumber(args.rx) || 0);
+ const ry = this._toRadians(Scratch.Cast.toNumber(args.ry) || 0);
+ const rz = this._toRadians(Scratch.Cast.toNumber(args.rz) || 0);
+ return this._rotate3D({ x, y, z }, rx, ry, rz);
}
// Camera Controls
@@ -145,27 +187,43 @@
// Projection
project(args) {
- const [x, y, z] = args.v.split(',').map(Number);
+ const [x = 0, y = 0, z = 0] = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
const cam = this.camera;
- const dx = x - cam.pos.x, dy = y - cam.pos.y, dz = z - cam.pos.z;
-
- // Apply yaw rotation (now in degrees)
- const camZ = dz * Math.cos(this._toRadians(cam.rot.yaw)) + dx * Math.sin(this._toRadians(cam.rot.yaw));
- const camX = dx * Math.cos(this._toRadians(cam.rot.yaw)) - dz * Math.sin(this._toRadians(cam.rot.yaw));
-
- // Apply pitch rotation (now in degrees)
- const tempY = dy * Math.cos(this._toRadians(cam.rot.pitch)) - camZ * Math.sin(this._toRadians(cam.rot.pitch));
- const tempZ = dy * Math.sin(this._toRadians(cam.rot.pitch)) + camZ * Math.cos(this._toRadians(cam.rot.pitch));
- const finalZ = tempZ; // This is now the new Z after pitch rotation
- const finalY = tempY; // This is now the new Y after pitch rotation
-
- // Apply roll rotation (now in degrees)
- const finalX = finalY * Math.sin(this._toRadians(cam.rot.roll)) + camX * Math.cos(this._toRadians(cam.rot.roll));
- const adjustedY = finalY * Math.cos(this._toRadians(cam.rot.roll)) - camX * Math.sin(this._toRadians(cam.rot.roll));
+
+ // Apply transformations in correct order
+ const dx = x - cam.pos.x;
+ const dy = y - cam.pos.y;
+ const dz = z - cam.pos.z;
+
+ // Convert angles to radians for consistency
+ const yawRad = this._toRadians(cam.rot.yaw);
+ const pitchRad = this._toRadians(cam.rot.pitch);
+ const rollRad = this._toRadians(cam.rot.roll);
+
+ // Apply rotations in correct order: yaw -> pitch -> roll
+ // First yaw (around Y axis)
+ let cx = dx * Math.cos(yawRad) - dz * Math.sin(yawRad);
+ let cz = dx * Math.sin(yawRad) + dz * Math.cos(yawRad);
+ let cy = dy;
+
+ // Then pitch (around X axis)
+ const tempZ = cz * Math.cos(pitchRad) - cy * Math.sin(pitchRad);
+ cy = cz * Math.sin(pitchRad) + cy * Math.cos(pitchRad);
+ cz = tempZ;
+
+ // Finally roll (around Z axis)
+ const finalX = cx * Math.cos(rollRad) - cy * Math.sin(rollRad);
+ const finalY = cx * Math.sin(rollRad) + cy * Math.cos(rollRad);
+
+ // Prevent division by zero
+ if (Math.abs(cz) < 0.0001) {
+ return '0,0';
+ }
+
+ // Calculate screen coordinates with FOV
+ const screenX = (finalX / cz) * cam.fov;
+ const screenY = (finalY / cz) * cam.fov;
- // Calculate screen coordinates
- const screenX = (finalX / finalZ) * cam.fov;
- const screenY = (adjustedY / finalZ) * cam.fov;
return `${screenX},${screenY}`;
}
@@ -228,32 +286,45 @@
}
frustumCull(args) {
- const [x, y, z] = args.v.split(',').map(Number);
+ const [x = 0, y = 0, z = 0] = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
const { pos, rot, fov } = this.camera;
- const near = args.near, far = args.far;
-
- // Translate point relative to camera
+ const near = Math.max(0.1, Scratch.Cast.toNumber(args.near) || 0.1);
+ const far = Math.max(near + 0.1, Scratch.Cast.toNumber(args.far) || 100);
+
+ // Transform point to camera space
const dx = x - pos.x;
const dy = y - pos.y;
const dz = z - pos.z;
-
- // Rotate point relative to camera
- const cx = dx * Math.cos(rot.yaw) - dz * Math.sin(rot.yaw);
- const cz = dx * Math.sin(rot.yaw) + dz * Math.cos(rot.yaw);
- const cy = dy;
-
- // Check depth (near and far planes)
+
+ // Convert angles to radians
+ const yawRad = this._toRadians(rot.yaw);
+ const pitchRad = this._toRadians(rot.pitch);
+
+ // Apply rotations (yaw then pitch)
+ let cx = dx * Math.cos(yawRad) - dz * Math.sin(yawRad);
+ let cz = dx * Math.sin(yawRad) + dz * Math.cos(yawRad);
+ let cy = dy;
+
+ // Apply pitch
+ const temp_z = cz * Math.cos(pitchRad) - cy * Math.sin(pitchRad);
+ cy = cz * Math.sin(pitchRad) + cy * Math.cos(pitchRad);
+ cz = temp_z;
+
+ // Early exit if behind camera
+ if (cz <= 0) return true;
+
+ // Check against near/far planes
if (cz < near || cz > far) return true;
-
- // Check horizontal FOV
- const hHalf = Math.tan((fov / 2) * (Math.PI / 180)) * cz;
- if (cx < -hHalf || cx > hHalf) return true;
-
- // Check vertical FOV
- const vHalf = hHalf * (3 / 4); // Assuming aspect ratio of 4:3
- if (cy < -vHalf || cy > vHalf) return true;
-
- return false;
+
+ // Calculate FOV bounds with correct aspect ratio (4:3)
+ const hFovRad = this._toRadians(fov);
+ const vFovRad = 2 * Math.atan(Math.tan(hFovRad / 2) * (3/4));
+
+ // Check against frustum planes
+ const hHalf = Math.abs(Math.tan(hFovRad / 2) * cz);
+ const vHalf = Math.abs(Math.tan(vFovRad / 2) * cz);
+
+ return Math.abs(cx) > hHalf || Math.abs(cy) > vHalf;
}
backFaceCull(args) {
@@ -280,8 +351,10 @@
// Utility Functions
_vectorOp(v1, v2, op) {
- const [x1, y1, z1] = v1.split(',').map(Number);
- const [x2, y2, z2] = v2.split(',').map(Number);
+ const vec1 = v1.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ const vec2 = v2.split(',').map(n => Scratch.Cast.toNumber(n) || 0);
+ const [x1 = 0, y1 = 0, z1 = 0] = vec1;
+ const [x2 = 0, y2 = 0, z2 = 0] = vec2;
return `${op(x1, x2)},${op(y1, y2)},${op(z1, z2)}`;
}
@@ -307,11 +380,26 @@
}
_rotate3D(v, rx, ry, rz) {
- const cos = Math.cos, sin = Math.sin;
+ const cos = Math.cos;
+ const sin = Math.sin;
let { x, y, z } = v;
- [y, z] = [y * cos(rx) - z * sin(rx), y * sin(rx) + z * cos(rx)];
- [x, z] = [x * cos(ry) + z * sin(ry), -x * sin(ry) + z * cos(ry)];
- [x, y] = [x * cos(rz) - y * sin(rz), x * sin(rz) + y * cos(rz)];
+
+ // Apply rotations in order: X -> Y -> Z
+ // X rotation
+ let temp = y;
+ y = y * cos(rx) - z * sin(rx);
+ z = temp * sin(rx) + z * cos(rx);
+
+ // Y rotation
+ temp = x;
+ x = x * cos(ry) + z * sin(ry);
+ z = -temp * sin(ry) + z * cos(ry);
+
+ // Z rotation
+ temp = x;
+ x = x * cos(rz) - y * sin(rz);
+ y = temp * sin(rz) + y * cos(rz);
+
return `${x},${y},${z}`;
}
@@ -322,6 +410,23 @@
util.target.setXY(util.target.x + x, util.target.y + y);
}
+ pointTo(args, util) {
+ const [dx, dy] = args.v.split(',').map(Number);
+ const x = Scratch.Cast.toNumber(dx);
+ const y = Scratch.Cast.toNumber(dy);
+ if (util.target.y > y) {
+ util.target.setDirection(
+ (180 / Math.PI) *
+ Math.atan((x - util.target.x) / (y - util.target.y)) +
+ 180
+ );
+ } else {
+ util.target.setDirection(
+ (180 / Math.PI) * Math.atan((x - util.target.x) / (y - util.target.y))
+ );
+ }
+ }
+
goToVec2(args, util) {
const [dx, dy] = args.v.split(',').map(Number);
const x = Scratch.Cast.toNumber(dx);
@@ -329,14 +434,17 @@
util.target.setXY(x, y);
}
- getPosVec2(args, util) {
+ getPosVec2(util) {
return `${util.target.x},${util.target.y}`;
}
- getSizeVec2(args, util) {
+ getSizeVec2(util) {
const bounds = Scratch.vm.renderer.getBounds(util.target.drawableID)
return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`;
}
+ getMousePosVec2() {
+ return `${Math.round(mouse._scratchX)},${Math.round(mouse._scratchY)}`;
+ }
drawTriangle(args, util) {
const [x1, y1] = args.v1.split(',').map(Number);
@@ -358,7 +466,7 @@
// New utility function to convert degrees to radians
_toRadians(degrees) {
- return degrees * (Math.PI / 180);
+ return (degrees || 0) * (Math.PI / 180);
}
}
From de3ac697d3f21b711abd9759ae3d7c97b0ab7c6f Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Wed, 20 Nov 2024 15:57:28 +0000
Subject: [PATCH 09/10] Update vectors.js
---
static/extensions/Cool_skratcher/vectors.js | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js
index 2db9f524..a6d4ab2c 100644
--- a/static/extensions/Cool_skratcher/vectors.js
+++ b/static/extensions/Cool_skratcher/vectors.js
@@ -1,5 +1,5 @@
// Name: Vectors!
-// ID: vectors
+// ID: cooldevvectors
// Description: Adds a set of blocks for vector operations in 2D and 3D space.
// By: cool_skratcher
// License: MIT
@@ -30,16 +30,19 @@
}
};
penPCheck();
- vm.runtime.on("EXTENSION_ADDED", penPCheck);
class VecMath {
constructor() {
this.camera = { pos: { x: 0, y: 0, z: 0 }, rot: { yaw: 0, pitch: 0, roll: 0 }, fov: 100 };
+ Scratch.vm.runtime.on("EXTENSION_ADDED", () => {
+ penPCheck();
+ console.log(vm.runtime.ext_penP)
+ });
}
getInfo() {
return {
- id: 'vectors',
+ id: 'cooldevvectors',
name: 'Vectors',
color1: "#57a3e5",
color2: "#0063ba",
From 495214b31eb447b81cb83342dc846d43ebf92274 Mon Sep 17 00:00:00 2001
From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com>
Date: Wed, 20 Nov 2024 17:45:20 +0000
Subject: [PATCH 10/10] Update extensions.js
---
src/lib/extensions.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/lib/extensions.js b/src/lib/extensions.js
index 09657d34..ee15a425 100644
--- a/src/lib/extensions.js
+++ b/src/lib/extensions.js
@@ -13,6 +13,14 @@ export default [
creator: "MikeDev101",
isGitHub: true,
},
+ {
+ name: "Vectors",
+ description: "Adds a set of blocks for vector operations in 2D and 3D space.",
+ code: "Cool_skratcher/vectors.js",
+ banner: "Cool_skratcher/vectors.svg",
+ creator: "cool_dev",
+ isGitHub: true,
+ },
{
name: "Pen+",
description: "Extended pen section! Adds blocks for drawing triangles using textures and tints, drawing images and editing their pixels, etc.",