emeraldengine 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +968 -0
- package/dist/types/imports/BitmapText.d.ts +79 -0
- package/dist/types/imports/Color.d.ts +17 -0
- package/dist/types/imports/Drawable.d.ts +157 -0
- package/dist/types/imports/Emerald.d.ts +73 -0
- package/dist/types/imports/FPSCounter.d.ts +19 -0
- package/dist/types/imports/GLUtils.d.ts +6 -0
- package/dist/types/imports/Instance.d.ts +87 -0
- package/dist/types/imports/InstancedTexture.d.ts +230 -0
- package/dist/types/imports/Physics.d.ts +139 -0
- package/dist/types/imports/Scene.d.ts +39 -0
- package/dist/types/imports/Shaders.d.ts +4 -0
- package/dist/types/imports/Shapes.d.ts +25 -0
- package/dist/types/imports/Storage.d.ts +46 -0
- package/dist/types/imports/Texture.d.ts +19 -0
- package/dist/types/imports/Time.d.ts +22 -0
- package/dist/types/imports/Transform.d.ts +41 -0
- package/dist/types/imports/components/BoxCollider.d.ts +41 -0
- package/dist/types/imports/components/BoxColliderDebug.d.ts +19 -0
- package/dist/types/imports/components/CircleCollider.d.ts +39 -0
- package/dist/types/imports/components/CircleColliderDebug.d.ts +19 -0
- package/dist/types/imports/components/Collider.d.ts +53 -0
- package/dist/types/imports/components/GameObject.d.ts +72 -0
- package/dist/types/imports/components/RigidBody.d.ts +104 -0
- package/dist/types/imports/lights/DirectionalLight.d.ts +26 -0
- package/dist/types/imports/lights/PointLight.d.ts +18 -0
- package/dist/types/imports/managers/AudioManager.d.ts +60 -0
- package/dist/types/imports/managers/CameraManager.d.ts +35 -0
- package/dist/types/imports/managers/EventManager.d.ts +187 -0
- package/dist/types/imports/managers/GLManager.d.ts +47 -0
- package/dist/types/imports/managers/IDManager.d.ts +21 -0
- package/dist/types/imports/managers/SceneManager.d.ts +22 -0
- package/dist/types/imports/particlesystem/Particle.d.ts +42 -0
- package/dist/types/imports/particlesystem/ParticleSettings.d.ts +49 -0
- package/dist/types/imports/particlesystem/Particles.d.ts +71 -0
- package/dist/types/index.d.ts +32 -0
- package/imports/BitmapText.js +245 -0
- package/imports/Color.js +18 -0
- package/imports/Drawable.js +550 -0
- package/imports/Emerald.js +459 -0
- package/imports/FPSCounter.js +43 -0
- package/imports/GLUtils.js +67 -0
- package/imports/Instance.js +187 -0
- package/imports/InstancedTexture.js +856 -0
- package/imports/Physics.js +242 -0
- package/imports/Scene.js +79 -0
- package/imports/Shaders.js +165 -0
- package/imports/Shapes.js +129 -0
- package/imports/Storage.js +63 -0
- package/imports/Texture.js +67 -0
- package/imports/Time.js +28 -0
- package/imports/Transform.js +59 -0
- package/imports/components/BoxCollider.js +67 -0
- package/imports/components/BoxColliderDebug.js +38 -0
- package/imports/components/CircleCollider.js +67 -0
- package/imports/components/CircleColliderDebug.js +36 -0
- package/imports/components/Collider.js +51 -0
- package/imports/components/GameObject.js +160 -0
- package/imports/components/RigidBody.js +169 -0
- package/imports/lights/DirectionalLight.js +68 -0
- package/imports/lights/PointLight.js +17 -0
- package/imports/managers/AudioManager.js +146 -0
- package/imports/managers/CameraManager.js +60 -0
- package/imports/managers/EventManager.js +479 -0
- package/imports/managers/GLManager.js +65 -0
- package/imports/managers/IDManager.js +32 -0
- package/imports/managers/SceneManager.js +27 -0
- package/imports/managers/ShaderManager.js +133 -0
- package/imports/particlesystem/Particle.js +75 -0
- package/imports/particlesystem/ParticleSettings.js +49 -0
- package/imports/particlesystem/Particles.js +226 -0
- package/index.js +67 -0
- package/package.json +38 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import * as planck from "planck";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @class Physics
|
|
5
|
+
* @description Represents the physics engine
|
|
6
|
+
* @param {number} gravity - The gravity of the physics engine
|
|
7
|
+
* @param {number} scale - The scale of the physics engine
|
|
8
|
+
* @param {number} velocityThreshold - The velocity threshold of the physics engine
|
|
9
|
+
*/
|
|
10
|
+
class Physics {
|
|
11
|
+
constructor(gravity, scale, velocityThreshold = 0.1) {
|
|
12
|
+
this.world = new planck.World({
|
|
13
|
+
gravity: new planck.Vec2(0, gravity),
|
|
14
|
+
});
|
|
15
|
+
planck.Settings.velocityThreshold = velocityThreshold;
|
|
16
|
+
this.gravity = gravity;
|
|
17
|
+
this.scale = scale;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @method createBody
|
|
22
|
+
* @description Creates a body in the physics engine
|
|
23
|
+
* @param {string} type - The type of the body
|
|
24
|
+
* @param {Vector2} position - The position of the body
|
|
25
|
+
* @param {boolean} fixedRotation - Whether the body should have a fixed rotation
|
|
26
|
+
* @param {boolean} attachFixture - Whether the body should have a fixture
|
|
27
|
+
* @param {Vector2} fixtureSize - The size of the fixture
|
|
28
|
+
* @param {number} density - The density of the fixture
|
|
29
|
+
* @param {number} friction - The friction of the fixture
|
|
30
|
+
* @param {number} restitution - The restitution of the fixture
|
|
31
|
+
* @returns {Body} - The body
|
|
32
|
+
*/
|
|
33
|
+
createBody(
|
|
34
|
+
type,
|
|
35
|
+
position = new Vector2(0, 0),
|
|
36
|
+
fixedRotation = false,
|
|
37
|
+
attachFixture = true,
|
|
38
|
+
fixtureSize = new Vector2(1, 1),
|
|
39
|
+
density = 0,
|
|
40
|
+
friction = 0,
|
|
41
|
+
restitution = 0
|
|
42
|
+
) {
|
|
43
|
+
const bodyRef = this.world.createBody({
|
|
44
|
+
type: type,
|
|
45
|
+
position: new planck.Vec2(
|
|
46
|
+
position.x / this.scale,
|
|
47
|
+
position.y / this.scale
|
|
48
|
+
),
|
|
49
|
+
fixedRotation: fixedRotation,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (attachFixture) {
|
|
53
|
+
bodyRef.createFixture(new planck.Box(fixtureSize.x, fixtureSize.y), {
|
|
54
|
+
density: density,
|
|
55
|
+
friction: friction,
|
|
56
|
+
restitution: restitution,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return bodyRef;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @method onCollisionEnter
|
|
65
|
+
* @description Handles the collision enter event
|
|
66
|
+
* @param {Function} callback - The callback function to handle the collision enter event
|
|
67
|
+
*/
|
|
68
|
+
onCollisionEnter(callback) {
|
|
69
|
+
this.world.on("begin-contact", (contact) => {
|
|
70
|
+
const fixtureA = contact.getFixtureA();
|
|
71
|
+
const fixtureB = contact.getFixtureB();
|
|
72
|
+
|
|
73
|
+
const bodyA = fixtureA.getBody();
|
|
74
|
+
const bodyB = fixtureB.getBody();
|
|
75
|
+
|
|
76
|
+
callback(bodyA, bodyB, contact);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @method onCollisionExit
|
|
82
|
+
* @description Handles the collision exit event
|
|
83
|
+
* @param {Function} callback - The callback function to handle the collision exit event
|
|
84
|
+
*/
|
|
85
|
+
onCollisionExit(callback) {
|
|
86
|
+
this.world.on("end-contact", (contact) => {
|
|
87
|
+
const fixtureA = contact.getFixtureA();
|
|
88
|
+
const fixtureB = contact.getFixtureB();
|
|
89
|
+
|
|
90
|
+
const bodyA = fixtureA.getBody();
|
|
91
|
+
const bodyB = fixtureB.getBody();
|
|
92
|
+
|
|
93
|
+
callback(bodyA, bodyB, contact);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @method process
|
|
99
|
+
* @description Processes the physics engine
|
|
100
|
+
* @param {number} dt - The delta time
|
|
101
|
+
*/
|
|
102
|
+
process(dt) {
|
|
103
|
+
this.world.step(dt);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @method clear
|
|
108
|
+
* @description Clears the physics engine objects and resets the gravity
|
|
109
|
+
*/
|
|
110
|
+
clear() {
|
|
111
|
+
this.world = new planck.World({
|
|
112
|
+
gravity: new planck.Vec2(0, this.gravity),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @method getGravity
|
|
118
|
+
* @description Returns the gravity of the physics engine
|
|
119
|
+
* @returns {number} - The gravity of the physics engine
|
|
120
|
+
*/
|
|
121
|
+
getGravity() {
|
|
122
|
+
return this.gravity;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @method getScale
|
|
127
|
+
* @description Returns the scale of the physics engine
|
|
128
|
+
* @returns {number} - The scale of the physics engine
|
|
129
|
+
*/
|
|
130
|
+
getScale() {
|
|
131
|
+
return this.scale;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @method scheduleAction
|
|
136
|
+
* @description Schedules an action to be executed as soon as possible
|
|
137
|
+
* @param {Function} callback - The callback function to execute
|
|
138
|
+
*/
|
|
139
|
+
static scheduleAction(callback) {
|
|
140
|
+
if (typeof callback === "function") {
|
|
141
|
+
setTimeout(() => {
|
|
142
|
+
callback();
|
|
143
|
+
}, 0);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @class Vector2
|
|
150
|
+
* @description Represents a 2D vector
|
|
151
|
+
* @param {number} x - The x coordinate of the vector
|
|
152
|
+
* @param {number} y - The y coordinate of the vector
|
|
153
|
+
*/
|
|
154
|
+
class Vector2 {
|
|
155
|
+
constructor(x, y) {
|
|
156
|
+
return new planck.Vec2(x, y);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @method equals
|
|
161
|
+
* @description Checks if the vector is equal to another vector
|
|
162
|
+
* @param {Vector2} other - The other vector
|
|
163
|
+
* @returns {boolean} - True if the vector is equal to the other vector
|
|
164
|
+
*/
|
|
165
|
+
equals(other) {
|
|
166
|
+
if (!other) return false;
|
|
167
|
+
if (!(other instanceof Vector2)) return false;
|
|
168
|
+
return this.x === other.x && this.y === other.y;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @method getX
|
|
173
|
+
* @description Returns the x coordinate of the vector
|
|
174
|
+
* @returns {number} - The x coordinate of the vector
|
|
175
|
+
*/
|
|
176
|
+
getX() {
|
|
177
|
+
return this.x;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @method getY
|
|
182
|
+
* @description Returns the y coordinate of the vector
|
|
183
|
+
* @returns {number} - The y coordinate of the vector
|
|
184
|
+
*/
|
|
185
|
+
getY() {
|
|
186
|
+
return this.y;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @class Vector3
|
|
192
|
+
* @description Represents a 3D vector
|
|
193
|
+
* @param {number} x - The x coordinate of the vector
|
|
194
|
+
* @param {number} y - The y coordinate of the vector
|
|
195
|
+
* @param {number} z - The z coordinate of the vector
|
|
196
|
+
*/
|
|
197
|
+
class Vector3 {
|
|
198
|
+
constructor(x, y, z) {
|
|
199
|
+
return new planck.Vec3(x, y, z);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @method equals
|
|
204
|
+
* @description Checks if the vector is equal to another vector
|
|
205
|
+
* @param {Vector3} other - The other vector
|
|
206
|
+
* @returns {boolean} - True if the vector is equal to the other vector
|
|
207
|
+
*/
|
|
208
|
+
equals(other) {
|
|
209
|
+
if (!other) return false;
|
|
210
|
+
if (!(other instanceof Vector3)) return false;
|
|
211
|
+
return this.x === other.x && this.y === other.y && this.z === other.z;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @method getX
|
|
216
|
+
* @description Returns the x coordinate of the vector
|
|
217
|
+
* @returns {number} - The x coordinate of the vector
|
|
218
|
+
*/
|
|
219
|
+
getX() {
|
|
220
|
+
return this.x;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @method getY
|
|
225
|
+
* @description Returns the y coordinate of the vector
|
|
226
|
+
* @returns {number} - The y coordinate of the vector
|
|
227
|
+
*/
|
|
228
|
+
getY() {
|
|
229
|
+
return this.y;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @method getZ
|
|
234
|
+
* @description Returns the z coordinate of the vector
|
|
235
|
+
* @returns {number} - The z coordinate of the vector
|
|
236
|
+
*/
|
|
237
|
+
getZ() {
|
|
238
|
+
return this.z;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export { Physics, Vector2, Vector3 };
|
package/imports/Scene.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import GameObject from "./components/GameObject.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @class Scene
|
|
5
|
+
* @description Represents a scene
|
|
6
|
+
* @param {Array} objects - The objects in the scene
|
|
7
|
+
*/
|
|
8
|
+
class Scene {
|
|
9
|
+
constructor(objects = []) {
|
|
10
|
+
this.objects = objects;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @method add
|
|
15
|
+
* @description Adds an object to the scene
|
|
16
|
+
* @param {GameObject} object - The object to add
|
|
17
|
+
*/
|
|
18
|
+
add(object) {
|
|
19
|
+
if (!(object instanceof GameObject)) {
|
|
20
|
+
throw new Error("Object is not a GameObject");
|
|
21
|
+
}
|
|
22
|
+
object.setIsActive(true);
|
|
23
|
+
if (!this.objects.some((obj) => obj.id === object.id)) {
|
|
24
|
+
this.objects.push(object);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @method remove
|
|
30
|
+
* @description Removes an object from the scene
|
|
31
|
+
* @param {GameObject} object - The object to remove
|
|
32
|
+
*/
|
|
33
|
+
remove(object) {
|
|
34
|
+
if (!(object instanceof GameObject)) {
|
|
35
|
+
throw new Error("Object is not a GameObject");
|
|
36
|
+
}
|
|
37
|
+
object.setIsActive(false);
|
|
38
|
+
this.objects = this.objects.filter((obj) => obj?.id !== object?.id);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @method setIsActive
|
|
43
|
+
* @description Sets the active state of the scene
|
|
44
|
+
* @param {boolean} bool - The active state
|
|
45
|
+
*/
|
|
46
|
+
setIsActive(bool) {
|
|
47
|
+
for (let object of this.objects) {
|
|
48
|
+
this.setActiveRecursive(object, bool);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @method setActiveRecursive
|
|
54
|
+
* @description Sets the active state of the scene recursively
|
|
55
|
+
* @param {Object} object - The object to set the active state of
|
|
56
|
+
* @param {boolean} bool - The active state
|
|
57
|
+
*/
|
|
58
|
+
setActiveRecursive(object, bool) {
|
|
59
|
+
object.setIsActive(bool);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator
|
|
63
|
+
[Symbol.iterator]() {
|
|
64
|
+
let index = -1;
|
|
65
|
+
const data = this.objects;
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
next: () => ({ value: data[++index], done: !(index in data) }),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
forEach(callback) {
|
|
73
|
+
for (const obj of this.objects) {
|
|
74
|
+
callback(obj);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default Scene;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const STANDARD_VERTEX_SHADER = `
|
|
2
|
+
attribute vec4 aVertexPosition;
|
|
3
|
+
attribute vec2 aTextureCoord;
|
|
4
|
+
|
|
5
|
+
// Instance matrix (each row as a separate attribute)
|
|
6
|
+
attribute vec4 aInstanceMatrix0;
|
|
7
|
+
attribute vec4 aInstanceMatrix1;
|
|
8
|
+
attribute vec4 aInstanceMatrix2;
|
|
9
|
+
attribute vec4 aInstanceMatrix3;
|
|
10
|
+
|
|
11
|
+
// Per-instance texture coordinates (one for each vertex of the quad)
|
|
12
|
+
attribute vec2 aInstanceTexCoord0;
|
|
13
|
+
attribute vec2 aInstanceTexCoord1;
|
|
14
|
+
attribute vec2 aInstanceTexCoord2;
|
|
15
|
+
attribute vec2 aInstanceTexCoord3;
|
|
16
|
+
|
|
17
|
+
uniform mat4 uModelViewMatrix;
|
|
18
|
+
uniform mat4 uInstancedModelViewMatrix;
|
|
19
|
+
uniform mat4 uProjectionMatrix;
|
|
20
|
+
uniform bool useInstances;
|
|
21
|
+
|
|
22
|
+
varying highp vec2 vTexCoord;
|
|
23
|
+
varying vec2 vFragPos;
|
|
24
|
+
|
|
25
|
+
void main() {
|
|
26
|
+
// Construct the instance matrix
|
|
27
|
+
mat4 instanceMatrix = mat4(
|
|
28
|
+
aInstanceMatrix0,
|
|
29
|
+
aInstanceMatrix1,
|
|
30
|
+
aInstanceMatrix2,
|
|
31
|
+
aInstanceMatrix3
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Apply the instance-specific transform, then the global transforms
|
|
35
|
+
if(useInstances) {
|
|
36
|
+
gl_Position = uProjectionMatrix * uInstancedModelViewMatrix * instanceMatrix * aVertexPosition;
|
|
37
|
+
vFragPos = (uInstancedModelViewMatrix * instanceMatrix * aVertexPosition).xy;
|
|
38
|
+
|
|
39
|
+
// Use per-instance texture coordinates based on vertex index
|
|
40
|
+
// Vertex order: top-right, top-left, bottom-right, bottom-left
|
|
41
|
+
int vertexIndex = int(aVertexPosition.x > 0.0 ? (aVertexPosition.y > 0.0 ? 0 : 2) : (aVertexPosition.y > 0.0 ? 1 : 3));
|
|
42
|
+
|
|
43
|
+
if(vertexIndex == 0) {
|
|
44
|
+
vTexCoord = aInstanceTexCoord0;
|
|
45
|
+
} else if(vertexIndex == 1) {
|
|
46
|
+
vTexCoord = aInstanceTexCoord1;
|
|
47
|
+
} else if(vertexIndex == 2) {
|
|
48
|
+
vTexCoord = aInstanceTexCoord2;
|
|
49
|
+
} else {
|
|
50
|
+
vTexCoord = aInstanceTexCoord3;
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
|
|
54
|
+
vFragPos = (uModelViewMatrix * aVertexPosition).xy;
|
|
55
|
+
vTexCoord = aTextureCoord;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
const STANDARD_FRAGMENT_SHADER = `
|
|
61
|
+
#ifdef GL_ES
|
|
62
|
+
precision highp float;
|
|
63
|
+
#endif
|
|
64
|
+
uniform bool useTexture;
|
|
65
|
+
uniform vec4 uColor;
|
|
66
|
+
uniform sampler2D uSampler;
|
|
67
|
+
uniform float uOpacity; // Global opacity multiplier per GameObject
|
|
68
|
+
|
|
69
|
+
uniform vec2 uLightPosition[4]; // Support up to 4 lights
|
|
70
|
+
uniform vec3 uLightColor[4]; // RGB colors for each light
|
|
71
|
+
uniform float uLightIntensity[4]; // Intensity of each light
|
|
72
|
+
uniform float uLightRadius[4]; // Radius of each light
|
|
73
|
+
uniform int uActiveLights; // Number of active lights
|
|
74
|
+
|
|
75
|
+
// Directional lights
|
|
76
|
+
uniform vec2 uDirLightPosition[4]; // Position of directional lights
|
|
77
|
+
uniform vec2 uDirLightDirection[4]; // Direction of directional lights
|
|
78
|
+
uniform vec3 uDirLightColor[4]; // RGB colors for each directional light
|
|
79
|
+
uniform float uDirLightIntensity[4]; // Intensity of each directional light
|
|
80
|
+
uniform float uDirLightWidth[4]; // Width of each directional light beam
|
|
81
|
+
uniform int uActiveDirLights; // Number of active directional lights
|
|
82
|
+
|
|
83
|
+
uniform vec3 uAmbientLightValues; // Ambient light values
|
|
84
|
+
uniform bool uUseLighting; // Whether to apply lighting to this object
|
|
85
|
+
|
|
86
|
+
varying vec2 vTexCoord;
|
|
87
|
+
varying vec2 vFragPos;
|
|
88
|
+
|
|
89
|
+
void main() {
|
|
90
|
+
vec4 ambientLight = vec4(uAmbientLightValues.xyz, 1.0); // Move ambient light here
|
|
91
|
+
|
|
92
|
+
vec4 texColor;
|
|
93
|
+
if (useTexture) {
|
|
94
|
+
texColor = texture2D(uSampler, vTexCoord);
|
|
95
|
+
// Discard only fully or nearly fully transparent texels to keep soft edges
|
|
96
|
+
if (texColor.a < 0.01) discard;
|
|
97
|
+
// Apply color tint to texture
|
|
98
|
+
texColor *= uColor;
|
|
99
|
+
} else {
|
|
100
|
+
texColor = uColor;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Start with ambient light
|
|
104
|
+
vec3 lighting = ambientLight.rgb;
|
|
105
|
+
|
|
106
|
+
// Calculate contribution from each point light
|
|
107
|
+
for(int i = 0; i < 4; i++) {
|
|
108
|
+
if(i >= uActiveLights) break;
|
|
109
|
+
|
|
110
|
+
float distance = length(uLightPosition[i] - vFragPos);
|
|
111
|
+
|
|
112
|
+
// Check if fragment is within light radius
|
|
113
|
+
if(distance < uLightRadius[i]) {
|
|
114
|
+
// Calculate attenuation (falloff)
|
|
115
|
+
float attenuation = 1.0 - distance / uLightRadius[i];
|
|
116
|
+
|
|
117
|
+
// Add this light's contribution
|
|
118
|
+
lighting += uLightColor[i] * attenuation * uLightIntensity[i];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Calculate contribution from each directional light
|
|
123
|
+
for(int i = 0; i < 4; i++) {
|
|
124
|
+
if(i >= uActiveDirLights) break;
|
|
125
|
+
|
|
126
|
+
vec2 lightPos = uDirLightPosition[i];
|
|
127
|
+
vec2 lightDir = normalize(uDirLightDirection[i]);
|
|
128
|
+
vec2 toFrag = vFragPos - lightPos;
|
|
129
|
+
|
|
130
|
+
// Check if fragment is in front of the light
|
|
131
|
+
float projection = dot(toFrag, lightDir);
|
|
132
|
+
if(projection < 0.0) continue;
|
|
133
|
+
|
|
134
|
+
// Calculate perpendicular distance from light beam center
|
|
135
|
+
float perpDistance = abs(dot(toFrag, vec2(-lightDir.y, lightDir.x)));
|
|
136
|
+
|
|
137
|
+
// Check if fragment is within light beam width
|
|
138
|
+
if(perpDistance > uDirLightWidth[i] * 0.5) continue;
|
|
139
|
+
|
|
140
|
+
// Simplified lighting without shadows for now
|
|
141
|
+
float widthFactor = 1.0 - (perpDistance / (uDirLightWidth[i] * 0.5));
|
|
142
|
+
|
|
143
|
+
// Optional: Add distance attenuation
|
|
144
|
+
float distance = length(toFrag);
|
|
145
|
+
float maxDistance = 1000.0; // Maximum effective distance
|
|
146
|
+
float distanceFactor = max(0.0, 1.0 - (distance / maxDistance));
|
|
147
|
+
|
|
148
|
+
// Add this directional light's contribution
|
|
149
|
+
lighting += uDirLightColor[i] * uDirLightIntensity[i] * widthFactor * distanceFactor;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Apply lighting to texture color only if lighting is enabled
|
|
153
|
+
vec4 outColor;
|
|
154
|
+
if (uUseLighting) {
|
|
155
|
+
outColor = vec4(texColor.rgb * lighting, texColor.a);
|
|
156
|
+
} else {
|
|
157
|
+
outColor = texColor;
|
|
158
|
+
}
|
|
159
|
+
// Apply global opacity multiplier
|
|
160
|
+
outColor.a *= clamp(uOpacity, 0.0, 1.0);
|
|
161
|
+
gl_FragColor = outColor;
|
|
162
|
+
}
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
export { STANDARD_VERTEX_SHADER, STANDARD_FRAGMENT_SHADER };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { initVertexBuffer } from "./GLUtils.js";
|
|
2
|
+
import Drawable from "./Drawable.js";
|
|
3
|
+
import GLManager from "./managers/GLManager.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @class Square2D
|
|
7
|
+
* @description Represents a square 2D shape
|
|
8
|
+
*/
|
|
9
|
+
class Square2D extends Drawable {
|
|
10
|
+
constructor() {
|
|
11
|
+
const vertices = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0];
|
|
12
|
+
const verticesBuffer = initVertexBuffer(GLManager.getGL(), vertices);
|
|
13
|
+
const textureCoordinates = [
|
|
14
|
+
1.0,
|
|
15
|
+
1.0, // Top-right
|
|
16
|
+
0.0,
|
|
17
|
+
1.0, // Top-left
|
|
18
|
+
1.0,
|
|
19
|
+
0.0, // Bottom-right
|
|
20
|
+
0.0,
|
|
21
|
+
0.0, // Bottom-left
|
|
22
|
+
];
|
|
23
|
+
const texCoordBuffer = initVertexBuffer(
|
|
24
|
+
GLManager.getGL(),
|
|
25
|
+
textureCoordinates
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
super(
|
|
29
|
+
GLManager.getGL(),
|
|
30
|
+
GLManager.getProgramInfo(),
|
|
31
|
+
verticesBuffer,
|
|
32
|
+
texCoordBuffer,
|
|
33
|
+
vertices,
|
|
34
|
+
false,
|
|
35
|
+
"",
|
|
36
|
+
0,
|
|
37
|
+
0,
|
|
38
|
+
0,
|
|
39
|
+
0,
|
|
40
|
+
0,
|
|
41
|
+
false
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @class Triangle2D
|
|
48
|
+
* @description Represents a triangle 2D shape
|
|
49
|
+
*/
|
|
50
|
+
class Triangle2D extends Drawable {
|
|
51
|
+
constructor() {
|
|
52
|
+
const vertices = [0.0, 1.0, 1.0, -1.0, -1.0, -1.0];
|
|
53
|
+
const verticesBuffer = initVertexBuffer(GLManager.getGL(), vertices);
|
|
54
|
+
|
|
55
|
+
const textureCoordinates = [0.5, 1.0, 1.0, 0.0, 0.0, 0.0];
|
|
56
|
+
const texCoordBuffer = initVertexBuffer(
|
|
57
|
+
GLManager.getGL(),
|
|
58
|
+
textureCoordinates
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
super(
|
|
62
|
+
GLManager.getGL(),
|
|
63
|
+
GLManager.getProgramInfo(),
|
|
64
|
+
verticesBuffer,
|
|
65
|
+
texCoordBuffer,
|
|
66
|
+
vertices,
|
|
67
|
+
false,
|
|
68
|
+
"",
|
|
69
|
+
0,
|
|
70
|
+
0,
|
|
71
|
+
0,
|
|
72
|
+
0,
|
|
73
|
+
0,
|
|
74
|
+
false
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @class Circle2D
|
|
81
|
+
* @description Represents a circle 2D shape
|
|
82
|
+
* @param {number} segments - The number of segments to use to draw the circle
|
|
83
|
+
*/
|
|
84
|
+
class Circle2D extends Drawable {
|
|
85
|
+
constructor(segments = 32) {
|
|
86
|
+
const radius = 1.0;
|
|
87
|
+
const vertices = [];
|
|
88
|
+
const textureCoordinates = [];
|
|
89
|
+
|
|
90
|
+
// Add center vertex
|
|
91
|
+
vertices.push(0, 0);
|
|
92
|
+
textureCoordinates.push(0.5, 0.5);
|
|
93
|
+
|
|
94
|
+
// Add perimeter vertices
|
|
95
|
+
for (let i = 0; i <= segments; i++) {
|
|
96
|
+
const angle = (i * 2 * Math.PI) / segments;
|
|
97
|
+
const x = radius * Math.cos(angle);
|
|
98
|
+
const y = radius * Math.sin(angle);
|
|
99
|
+
vertices.push(x, y);
|
|
100
|
+
textureCoordinates.push((x / radius + 1) / 2, (y / radius + 1) / 2);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const verticesBuffer = initVertexBuffer(GLManager.getGL(), vertices);
|
|
104
|
+
const texCoordBuffer = initVertexBuffer(
|
|
105
|
+
GLManager.getGL(),
|
|
106
|
+
textureCoordinates
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
super(
|
|
110
|
+
GLManager.getGL(),
|
|
111
|
+
GLManager.getProgramInfo(),
|
|
112
|
+
verticesBuffer,
|
|
113
|
+
texCoordBuffer,
|
|
114
|
+
vertices,
|
|
115
|
+
false,
|
|
116
|
+
"",
|
|
117
|
+
0,
|
|
118
|
+
0,
|
|
119
|
+
0,
|
|
120
|
+
0,
|
|
121
|
+
0,
|
|
122
|
+
false,
|
|
123
|
+
true,
|
|
124
|
+
false
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { Square2D, Triangle2D, Circle2D };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class Storage
|
|
3
|
+
* @description Manages the storage of the game
|
|
4
|
+
*/
|
|
5
|
+
class Storage {
|
|
6
|
+
/**
|
|
7
|
+
* @method writeToLocalStorage
|
|
8
|
+
* @description Writes to local storage
|
|
9
|
+
* @param {string} key - The key to write to
|
|
10
|
+
* @param {any} value - The value to write to
|
|
11
|
+
*/
|
|
12
|
+
static writeToLocalStorage(key, value) {
|
|
13
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @method readFromLocalStorage
|
|
18
|
+
* @description Reads from local storage
|
|
19
|
+
* @param {string} key - The key to read from
|
|
20
|
+
* @returns {any} - The value read from local storage
|
|
21
|
+
*/
|
|
22
|
+
static readFromLocalStorage(key) {
|
|
23
|
+
return JSON.parse(localStorage.getItem(key));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @method clearLocalStorage
|
|
28
|
+
* @description Clears local storage
|
|
29
|
+
*/
|
|
30
|
+
static clearLocalStorage() {
|
|
31
|
+
localStorage.clear();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @method writeToSessionStorage
|
|
36
|
+
* @description Writes to session storage
|
|
37
|
+
* @param {string} key - The key to write to
|
|
38
|
+
* @param {any} value - The value to write to
|
|
39
|
+
*/
|
|
40
|
+
static writeToSessionStorage(key, value) {
|
|
41
|
+
sessionStorage.setItem(key, JSON.stringify(value));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @method readFromSessionStorage
|
|
46
|
+
* @description Reads from session storage
|
|
47
|
+
* @param {string} key - The key to read from
|
|
48
|
+
* @returns {any} - The value read from session storage
|
|
49
|
+
*/
|
|
50
|
+
static readFromSessionStorage(key) {
|
|
51
|
+
return JSON.parse(sessionStorage.getItem(key));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @method clearSessionStorage
|
|
56
|
+
* @description Clears session storage
|
|
57
|
+
*/
|
|
58
|
+
static clearSessionStorage() {
|
|
59
|
+
sessionStorage.clear();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default Storage;
|