├── .gitignore ├── src └── main │ ├── resources │ ├── graphics │ │ ├── icon.png │ │ └── tool_setup.png │ └── code │ │ ├── sprites │ │ ├── effect.png │ │ ├── light.png │ │ └── target.png │ │ ├── shaders │ │ ├── tint.frag │ │ ├── color.frag │ │ ├── debug.frag │ │ ├── tint.vert │ │ ├── interface.frag │ │ ├── debug.vert │ │ ├── map_mesh_shadow.frag │ │ ├── text.vert │ │ ├── interface.vert │ │ ├── map_sky.frag │ │ ├── color.vert │ │ ├── effect.vert │ │ ├── effect.frag │ │ ├── text.frag │ │ ├── map_sky.vert │ │ ├── map_mesh_shadow.vert │ │ ├── map_mesh.vert │ │ ├── model_mesh.vert │ │ ├── map_mesh.frag │ │ └── model_mesh.frag │ │ ├── main │ │ ├── input_touch.js │ │ ├── character.js │ │ ├── setup.js │ │ ├── background.js │ │ └── menu.js │ │ ├── game │ │ ├── cube.js │ │ ├── liquid_tint.js │ │ └── touch_button.js │ │ ├── map │ │ ├── map_spot.js │ │ ├── map_path_node.js │ │ ├── map_cube.js │ │ ├── map_cube_list.js │ │ ├── map_model_list.js │ │ ├── map_spot_list.js │ │ ├── map_sound_list.js │ │ ├── map_sky.js │ │ ├── map_liquid_list.js │ │ ├── map.js │ │ └── map_light_list.js │ │ ├── generate │ │ └── shadowmap │ │ │ ├── shadowmap_mesh_run.js │ │ │ └── shadowmap_light.js │ │ ├── shader │ │ ├── shader_light.js │ │ ├── tint_shader.js │ │ ├── color_shader.js │ │ ├── debug_shader.js │ │ ├── text_shader.js │ │ ├── interface_shader.js │ │ ├── effect_shader.js │ │ ├── map_mesh_shadow_shader.js │ │ ├── map_sky_shader.js │ │ ├── shader_list.js │ │ └── shader.js │ │ ├── mesh │ │ ├── mesh_shadowmap_run.js │ │ └── mesh_move.js │ │ ├── model │ │ ├── model_skin.js │ │ ├── model_animation_channel_pose.js │ │ ├── model_joint.js │ │ ├── model_entity_alter_skin.js │ │ ├── animation_def.js │ │ ├── model_node.js │ │ ├── model_animation.js │ │ ├── model_entity_alter_node.js │ │ ├── model_animation_channel.js │ │ ├── model_skeleton.js │ │ └── model.js │ │ ├── sound │ │ ├── sound_def.js │ │ ├── sound.js │ │ └── music.js │ │ ├── sequence │ │ └── sequence_sound.js │ │ ├── utility │ │ ├── grid.js │ │ ├── rect.js │ │ ├── plane.js │ │ ├── bound.js │ │ ├── color.js │ │ ├── line.js │ │ ├── matrix3.js │ │ └── quaternion.js │ │ ├── developer │ │ ├── upload.js │ │ └── developer_sprite.js │ │ ├── dialog │ │ ├── dialog_control_static.js │ │ ├── dialog_control_base.js │ │ ├── dialog_error.js │ │ ├── dialog_node.js │ │ ├── dialog_control_keyboard.js │ │ └── dialog_developer.js │ │ ├── bitmap │ │ ├── bitmap_color.js │ │ ├── bitmap_effect.js │ │ ├── bitmap_interface.js │ │ ├── bitmap_shadowmap.js │ │ └── bitmap.js │ │ └── light │ │ ├── light.js │ │ └── shadowmap_load.js │ ├── java │ └── com │ │ └── klinksoftware │ │ └── wsjs │ │ ├── application │ │ ├── Main.java │ │ ├── ProjectList.java │ │ └── Storage.java │ │ ├── ui │ │ ├── UserPanel.java │ │ ├── StatusUpdater.java │ │ ├── LogPanel.java │ │ ├── GradientLabel.java │ │ └── StatusCanvas.java │ │ ├── http │ │ ├── HTTPListener.java │ │ └── HTTPUpload.java │ │ └── websockets │ │ └── WebSocketListener.java │ └── docs │ ├── tasks.txt │ ├── developer_docs.txt │ └── misc_util_code.txt ├── LICENSE ├── nb-configuration.xml ├── pom.xml ├── nbactions.xml └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /dist/ 3 | /output/ 4 | /target/ 5 | .DS_Store 6 | /projects/ 7 | -------------------------------------------------------------------------------- /src/main/resources/graphics/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ggadwa/WSJS/HEAD/src/main/resources/graphics/icon.png -------------------------------------------------------------------------------- /src/main/resources/code/sprites/effect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ggadwa/WSJS/HEAD/src/main/resources/code/sprites/effect.png -------------------------------------------------------------------------------- /src/main/resources/code/sprites/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ggadwa/WSJS/HEAD/src/main/resources/code/sprites/light.png -------------------------------------------------------------------------------- /src/main/resources/code/sprites/target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ggadwa/WSJS/HEAD/src/main/resources/code/sprites/target.png -------------------------------------------------------------------------------- /src/main/resources/graphics/tool_setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ggadwa/WSJS/HEAD/src/main/resources/graphics/tool_setup.png -------------------------------------------------------------------------------- /src/main/resources/code/shaders/tint.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp vec4 color; 4 | 5 | out lowp vec4 outputPixel; 6 | 7 | void main(void) 8 | { 9 | outputPixel=color; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/color.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in lowp vec4 fragColor; 4 | 5 | out lowp vec4 outputPixel; 6 | 7 | void main(void) 8 | { 9 | outputPixel=fragColor; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/code/main/input_touch.js: -------------------------------------------------------------------------------- 1 | export default class InputTouchClass 2 | { 3 | constructor(id,x,y) 4 | { 5 | this.id=id; 6 | this.x=x; 7 | this.y=y; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/debug.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp vec3 color; 4 | 5 | out lowp vec4 outputPixel; 6 | 7 | void main(void) 8 | { 9 | outputPixel.rgb=color; 10 | outputPixel.a=1.0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/tint.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | 5 | uniform highp mat4 orthoMatrix; 6 | 7 | void main(void) 8 | { 9 | gl_Position=orthoMatrix*vec4(vertexPosition,1.0); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/code/game/cube.js: -------------------------------------------------------------------------------- 1 | 2 | export default class CubeClass 3 | { 4 | constructor(core) 5 | { 6 | this.core=core; 7 | } 8 | 9 | enter(entity) 10 | { 11 | } 12 | 13 | leave(entity) 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/interface.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp sampler2D baseTex; 4 | uniform lowp vec4 color; 5 | 6 | in highp vec2 fragUV; 7 | 8 | out lowp vec4 outputPixel; 9 | 10 | void main(void) 11 | { 12 | outputPixel=texture(baseTex,fragUV)*color; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_spot.js: -------------------------------------------------------------------------------- 1 | export default class MapSpotClass 2 | { 3 | constructor(position,data) 4 | { 5 | this.position=position; 6 | this.data=data; 7 | 8 | this.used=false; 9 | 10 | Object.seal(this); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/debug.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | 5 | uniform highp mat4 perspectiveMatrix; 6 | uniform highp mat4 viewMatrix; 7 | 8 | void main(void) 9 | { 10 | gl_Position=perspectiveMatrix*viewMatrix*vec4(vertexPosition,1.0); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/map_mesh_shadow.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp sampler2D shadowTex; 4 | 5 | in highp vec2 shadowUV; 6 | 7 | out lowp vec4 outputPixel; 8 | 9 | void main(void) 10 | { 11 | outputPixel.rgb=texture(shadowTex,shadowUV).rgb; 12 | outputPixel.a=1.0; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/main/java/com/klinksoftware/wsjs/application/Main.java: -------------------------------------------------------------------------------- 1 | package com.klinksoftware.wsjs.application; 2 | 3 | public class Main 4 | { 5 | private static App app; 6 | 7 | public static void main(String[] args) 8 | { 9 | app=new App(); 10 | app.run(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/code/generate/shadowmap/shadowmap_mesh_run.js: -------------------------------------------------------------------------------- 1 | export default class ShadowmapMeshRunClass 2 | { 3 | constructor(shadowmapIdx,startTrigIdx,endTrigIdx) 4 | { 5 | this.shadowmapIdx=shadowmapIdx; 6 | this.startTrigIdx=startTrigIdx; 7 | this.endTrigIdx=endTrigIdx; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/text.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | in highp vec2 vertexUV; 5 | 6 | uniform highp mat4 orthoMatrix; 7 | 8 | out highp vec2 fragUV; 9 | 10 | void main(void) 11 | { 12 | gl_Position=orthoMatrix*vec4(vertexPosition,1.0); 13 | fragUV=vertexUV; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/shader_light.js: -------------------------------------------------------------------------------- 1 | // 2 | // generic shader light class 3 | // 4 | 5 | export default class ShaderLightClass 6 | { 7 | constructor() 8 | { 9 | this.positionIntensityUniform=null; 10 | this.colorExponentUniform=null; 11 | 12 | Object.seal(this); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/interface.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | in highp vec2 vertexUV; 5 | 6 | uniform highp mat4 orthoMatrix; 7 | 8 | out highp vec2 fragUV; 9 | 10 | void main(void) 11 | { 12 | gl_Position=orthoMatrix*vec4(vertexPosition,1.0); 13 | fragUV=vertexUV; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/map_sky.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp sampler2D baseTex; 4 | uniform lowp vec3 color; 5 | 6 | in highp vec2 fragUV; 7 | 8 | out lowp vec4 outputPixel; 9 | 10 | void main(void) 11 | { 12 | outputPixel.rgb=texture(baseTex,fragUV).rgb*color; 13 | outputPixel.a=1.0; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/color.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | in lowp vec4 vertexColor; 5 | 6 | uniform highp mat4 orthoMatrix; 7 | 8 | out lowp vec4 fragColor; 9 | 10 | void main(void) 11 | { 12 | gl_Position=orthoMatrix*vec4(vertexPosition,1.0); 13 | fragColor=vertexColor; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/code/mesh/mesh_shadowmap_run.js: -------------------------------------------------------------------------------- 1 | export default class MeshShadowmapRunClass 2 | { 3 | constructor(bitmap,startTrigIdx,endTrigIdx) 4 | { 5 | this.bitmap=bitmap; // generator sticks an interger in here, at runtime it's a bitmap 6 | this.startTrigIdx=startTrigIdx; 7 | this.endTrigIdx=endTrigIdx; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_skin.js: -------------------------------------------------------------------------------- 1 | // 2 | // model skin class 3 | // 4 | 5 | export default class ModelSkinClass 6 | { 7 | constructor() 8 | { 9 | // all the joints for this skin 10 | // each joint is additional information 11 | // for a node in the skeleton 12 | 13 | this.joints=[]; 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/effect.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | in highp vec2 vertexUV; 5 | 6 | uniform highp mat4 perspectiveMatrix; 7 | uniform highp mat4 viewMatrix; 8 | 9 | out highp vec2 fragUV; 10 | 11 | void main(void) 12 | { 13 | gl_Position=perspectiveMatrix*viewMatrix*vec4(vertexPosition,1.0); 14 | fragUV=vertexUV; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/effect.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp sampler2D baseTex; 4 | uniform lowp vec4 colorAlpha; 5 | 6 | in highp vec2 fragUV; 7 | 8 | out lowp vec4 outputPixel; 9 | 10 | void main(void) 11 | { 12 | lowp vec4 tex=texture(baseTex,fragUV); 13 | 14 | outputPixel.rgb=colorAlpha.rgb*tex.rgb; 15 | outputPixel.a=tex.a*colorAlpha.a; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/main/resources/code/sound/sound_def.js: -------------------------------------------------------------------------------- 1 | export default class SoundDefClass 2 | { 3 | constructor(name,rate,randomRateAdd,distance,loopStart,loopEnd,loop) 4 | { 5 | this.name=name; 6 | this.rate=rate; 7 | this.randomRateAdd=randomRateAdd; 8 | this.distance=distance; 9 | this.loopStart=loopStart; 10 | this.loopEnd=loopEnd; 11 | this.loop=loop; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/text.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp sampler2D baseTex; 4 | uniform lowp vec4 color; 5 | 6 | in highp vec2 fragUV; 7 | 8 | out lowp vec4 outputPixel; 9 | 10 | void main(void) 11 | { 12 | lowp vec4 tex=texture(baseTex,fragUV); 13 | 14 | outputPixel.rgb=color.rgb; // treat as gray scale, use that for alpha, fill rest with color 15 | outputPixel.a=tex.r*color.a; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_animation_channel_pose.js: -------------------------------------------------------------------------------- 1 | // 2 | // model animation channel pose class 3 | // 4 | 5 | export default class ModelAnimationChannelPoseClass 6 | { 7 | constructor(tick,data) 8 | { 9 | this.tick=tick; // time for this pose, in milliseconds 10 | this.data=data; // an array of 3 (translation/scale) or 4 (rotation) components 11 | 12 | Object.seal(this); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/map_sky.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | in highp vec2 vertexUV; 5 | 6 | uniform highp mat4 perspectiveMatrix; 7 | uniform highp mat4 viewMatrix; 8 | uniform highp mat4 transformMatrix; 9 | 10 | out highp vec2 fragUV; 11 | 12 | void main(void) 13 | { 14 | gl_Position=perspectiveMatrix*viewMatrix*transformMatrix*vec4(vertexPosition,1.0); 15 | 16 | fragUV=vertexUV; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/map_mesh_shadow.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPositionShadow; 4 | in highp vec2 vertexUVShadow; 5 | 6 | uniform highp mat4 perspectiveMatrix; 7 | uniform highp mat4 viewMatrix; 8 | 9 | out highp vec2 shadowUV; 10 | 11 | void main(void) 12 | { 13 | gl_Position=perspectiveMatrix*viewMatrix*vec4(vertexPositionShadow,1.0); 14 | 15 | // the varying uvs 16 | 17 | shadowUV=vertexUVShadow; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/main/resources/code/mesh/mesh_move.js: -------------------------------------------------------------------------------- 1 | // 2 | // single move class 3 | // 4 | 5 | export default class MeshMoveClass 6 | { 7 | constructor(lifeTick,movePnt,rotateAngle,pauseType,pauseData,sound,triggerName) 8 | { 9 | this.lifeTick=lifeTick; 10 | this.movePnt=movePnt; 11 | this.rotateAngle=rotateAngle; 12 | this.pauseType=pauseType; 13 | this.pauseData=pauseData; 14 | this.sound=(sound===undefined)?null:sound; 15 | this.triggerName=(triggerName===undefined)?null:triggerName; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_joint.js: -------------------------------------------------------------------------------- 1 | import Matrix4Class from '../utility/matrix4.js'; 2 | 3 | // 4 | // model joint class 5 | // 6 | 7 | export default class ModelJointClass 8 | { 9 | constructor(nodeIdx,inverseBindMatrix) 10 | { 11 | this.nodeIdx=nodeIdx; 12 | this.inverseBindMatrix=inverseBindMatrix; 13 | 14 | this.translateMatrix=new Matrix4Class(); // pre loaded to avoid GC 15 | this.rotMatrix=new Matrix4Class(); 16 | this.scaleMatrix=new Matrix4Class(); 17 | 18 | Object.seal(this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_entity_alter_skin.js: -------------------------------------------------------------------------------- 1 | import Matrix4Class from '../utility/matrix4.js'; 2 | 3 | // 4 | // model skin class 5 | // 6 | 7 | export default class ModelEntityAlterSkinClass 8 | { 9 | constructor(jointCount) 10 | { 11 | let n; 12 | 13 | // these are matrixes that contain the 14 | // final movement of the joint, in a separate 15 | // list outside of the shared models 16 | 17 | this.jointMatrixes=[]; 18 | 19 | for (n=0;n!==jointCount;n++) { 20 | this.jointMatrixes.push(new Matrix4Class()); 21 | } 22 | 23 | Object.seal(this); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/main/resources/code/model/animation_def.js: -------------------------------------------------------------------------------- 1 | class AnimationMeshHideClass 2 | { 3 | constructor(name,hide) 4 | { 5 | this.name=name; 6 | this.hide=hide; 7 | } 8 | } 9 | 10 | export default class AnimationDefClass 11 | { 12 | constructor(startFrame,endFrame,actionFrame) 13 | { 14 | this.startFrame=startFrame; 15 | this.endFrame=endFrame; 16 | this.actionFrame=actionFrame; 17 | this.meshes=null; 18 | } 19 | 20 | addMeshHide(name,hide) 21 | { 22 | if (this.meshes===null) this.meshes=[]; 23 | this.meshes.push(new AnimationMeshHideClass(name,hide)); 24 | 25 | return(this); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/docs/tasks.txt: -------------------------------------------------------------------------------- 1 | 2 | - rework multiplayer 3 | - first log in needs to pick game/map 4 | - needs to pass back game/map/etc 5 | - what's going on with the sync? 6 | - update game label when combo changes 7 | - check for dup names 8 | - check for project versions 9 | - predictions 10 | - need open system for passing message (like firing weapons, etc) 11 | 12 | 13 | [NEW KART MAP - get rid of ground and put flat ground segments, fix seams] 14 | 15 | - if no pose, just set ONCE 16 | 17 | 18 | 19 | INTERFACE 20 | - menu by keys 21 | - gamepad support 22 | 23 | DEMOS 24 | - kart: crashes have weight effect 25 | - kart: going backwards 26 | 27 | MISC 28 | - run some more profiling 29 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_node.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | import Matrix4Class from '../utility/matrix4.js'; 3 | import QuaternionClass from '../utility/quaternion.js'; 4 | 5 | // 6 | // model node class 7 | // 8 | 9 | export default class ModelNodeClass 10 | { 11 | constructor(name,childNodeIdxs,translation,rotation,scale) 12 | { 13 | this.name=name; 14 | this.childNodeIdxs=childNodeIdxs; 15 | this.translation=translation; // a point 16 | this.rotation=rotation; // a quaternion 17 | this.scale=scale; // a point 18 | 19 | this.parentNodeIdx=-1; // set later in import 20 | 21 | Object.seal(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_path_node.js: -------------------------------------------------------------------------------- 1 | // 2 | // map path node class 3 | // 4 | 5 | export default class MapPathNodeClass 6 | { 7 | constructor(nodeIdx,position,links,key,spawn,pathHints,data) 8 | { 9 | this.nodeIdx=nodeIdx; 10 | this.position=position; 11 | this.links=links; 12 | this.key=(key===undefined)?null:key; 13 | this.spawn=(spawn===undefined)?false:spawn; 14 | this.pathHints=pathHints; 15 | this.data=(data===undefined)?null:data; 16 | 17 | this.pathHintCounts=null; // used in path hints construction 18 | this.perpendicularLine=null; // a line that can be used for certain AI routines 19 | 20 | Object.seal(this); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_animation.js: -------------------------------------------------------------------------------- 1 | // 2 | // model animation class 3 | // 4 | 5 | export default class ModelAnimationClass 6 | { 7 | constructor(name) 8 | { 9 | this.name=name; 10 | 11 | this.channels=[]; 12 | 13 | this.tickLength=0; 14 | 15 | Object.seal(this); 16 | } 17 | 18 | calcAnimationLength() 19 | { 20 | let n,tick,channel; 21 | 22 | this.tickLength=0; 23 | 24 | for (n=0;n!==this.channels.length;n++) { 25 | channel=this.channels[n]; 26 | 27 | tick=channel.poses[channel.poses.length-1].tick; 28 | if (tick>this.tickLength) this.tickLength=tick; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_cube.js: -------------------------------------------------------------------------------- 1 | // 2 | // map cube class 3 | // 4 | 5 | export default class MapCubeClass 6 | { 7 | constructor(cube,xBound,yBound,zBound,data) 8 | { 9 | this.cube=cube; 10 | this.xBound=xBound.copy(); 11 | this.yBound=yBound.copy(); 12 | this.zBound=zBound.copy(); 13 | this.data=(data===undefined)?null:data; 14 | } 15 | 16 | entityInCube(entity) 17 | { 18 | if ((entity.position.xthis.xBound.max)) return(false); 19 | if ((entity.position.ythis.yBound.max)) return(false); 20 | return((entity.position.z>=this.zBound.min) && (entity.position.z'+data.length); 15 | 16 | // get the upload path 17 | 18 | path=window.location.pathname; 19 | pathTokens=path.split('/'); 20 | projectName=pathTokens[2]; 21 | 22 | url=window.location.protocol+'//'+window.location.host+'/'+encodeURIComponent(projectName)+'/'+encodeURIComponent(this.core.game.map.name)+'/'+uploadName+'/'+uploadIndex; 23 | 24 | // upload 25 | 26 | try { 27 | resp=await fetch(url,{method:'POST',headers:{'Content-Type':'application/octet-stream'},body:data}); 28 | } 29 | catch (e) { 30 | throw new Error('Unable to post to server '+uploadName+'; '+e.message); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Brian Barnes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_cube_list.js: -------------------------------------------------------------------------------- 1 | import CoreClass from '../main/core.js'; 2 | import MapCubeClass from '../map/map_cube.js'; 3 | 4 | // 5 | // map cube list class 6 | // 7 | 8 | export default class MapCubeListClass 9 | { 10 | constructor(core) 11 | { 12 | this.core=core; 13 | this.cubes=[]; 14 | 15 | Object.seal(this); 16 | } 17 | 18 | // 19 | // initialize/release cube list 20 | // 21 | 22 | initialize() 23 | { 24 | this.cubes=[]; 25 | return(true); 26 | } 27 | 28 | release() 29 | { 30 | } 31 | 32 | // 33 | // cube list 34 | // 35 | 36 | add(cube) 37 | { 38 | this.cubes.push(cube); 39 | } 40 | 41 | clear() 42 | { 43 | this.cubes=[]; 44 | } 45 | 46 | // 47 | // find cube for entity 48 | // 49 | 50 | findCubeContainingEntity(entity) 51 | { 52 | let cube; 53 | 54 | for (cube of this.cubes) { 55 | if (cube.entityInCube(entity)) return(cube); 56 | } 57 | 58 | return(null); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_entity_alter_node.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | import Matrix4Class from '../utility/matrix4.js'; 3 | import QuaternionClass from '../utility/quaternion.js'; 4 | 5 | // 6 | // local entity alter node class for per 7 | // entity model changes 8 | // 9 | 10 | export default class ModelEntityAlterNodeClass 11 | { 12 | constructor(name,parentNodeIdx,childNodeIdxs,translation,rotation,scale) 13 | { 14 | this.name=name; 15 | this.parentNodeIdx=parentNodeIdx; 16 | this.childNodeIdxs=childNodeIdxs; 17 | this.translation=translation.copy(); // a point, static translation 18 | this.rotation=rotation.copy(); // a quaternion, static rotation 19 | this.scale=scale.copy(); // a point, static scale 20 | 21 | // the pose versions 22 | 23 | this.poseTranslation=translation.copy(); 24 | this.poseRotation=rotation.copy(); 25 | this.poseScale=scale.copy(); 26 | 27 | this.curPoseMatrix=new Matrix4Class(); 28 | this.curPosePosition=new PointClass(0,0,0); 29 | 30 | Object.seal(this); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_animation_channel.js: -------------------------------------------------------------------------------- 1 | // 2 | // model animation channel class 3 | // 4 | 5 | export default class ModelAnimationChannelClass 6 | { 7 | constructor(nodeIdx,trsTypeName) 8 | { 9 | this.TRS_TYPE_TRANSLATION=0; 10 | this.TRS_TYPE_ROTATION=1; 11 | this.TRS_TYPE_SCALE=2; 12 | 13 | this.nodeIdx=nodeIdx; 14 | 15 | switch (trsTypeName) { 16 | case 'translation': 17 | this.trsType=this.TRS_TYPE_TRANSLATION; 18 | break; 19 | case 'rotation': 20 | this.trsType=this.TRS_TYPE_ROTATION; 21 | break; 22 | case 'scale': 23 | this.trsType=this.TRS_TYPE_SCALE; 24 | break; 25 | } 26 | 27 | this.poses=[]; 28 | 29 | Object.seal(this); 30 | } 31 | 32 | getPoseDataForTick(tick) 33 | { 34 | let n; 35 | 36 | for (n=0;n!==this.poses.length;n++) { 37 | if (tickMAX_LOG_LINE) { 25 | try { 26 | replaceRange(null,0,getLineEndOffset(0)); 27 | } 28 | catch (BadLocationException e) { 29 | // eat this one, there should never be a time when this can't happen 30 | } 31 | } 32 | 33 | // append the log 34 | 35 | append(str); 36 | append("\n"); 37 | setCaretPosition(getDocument().getLength()); 38 | 39 | System.out.println(str); // always write logs to standard out, just in case 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/map_mesh.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | in highp vec3 vertexNormal; 5 | in highp vec3 vertexTangent; 6 | in highp vec2 vertexUV; 7 | 8 | uniform highp mat4 perspectiveMatrix; 9 | uniform highp mat4 viewMatrix; 10 | uniform highp mat3 normalMatrix; 11 | 12 | out highp vec3 eyeVector,eyePosition; 13 | out highp vec2 fragUV; 14 | out mediump vec3 tangentSpaceTangent,tangentSpaceBinormal,tangentSpaceNormal; 15 | 16 | void main(void) 17 | { 18 | gl_Position=perspectiveMatrix*viewMatrix*vec4(vertexPosition,1.0); 19 | eyePosition=vec3(viewMatrix*vec4(vertexPosition,1.0)); 20 | 21 | // get the tangent space 22 | // this gets passed to the fragment so we can calculate lights 23 | 24 | tangentSpaceTangent=normalize(normalMatrix*vertexTangent); 25 | tangentSpaceBinormal=normalize(normalMatrix*cross(vertexNormal,vertexTangent)); 26 | tangentSpaceNormal=normalize(normalMatrix*vertexNormal); 27 | 28 | // translate the eye vector 29 | 30 | eyeVector.x=dot(-eyePosition,tangentSpaceTangent); 31 | eyeVector.y=dot(-eyePosition,tangentSpaceBinormal); 32 | eyeVector.z=dot(-eyePosition,tangentSpaceNormal); 33 | 34 | // the varying uv 35 | 36 | fragUV=vertexUV; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | none 17 | false 18 | ECMA7 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/resources/code/utility/rect.js: -------------------------------------------------------------------------------- 1 | export default class RectClass 2 | { 3 | constructor(lft,top,rgt,bot) 4 | { 5 | this.lft=lft; 6 | this.top=top; 7 | this.rgt=rgt; 8 | this.bot=bot; 9 | 10 | Object.seal(this); 11 | } 12 | 13 | setFromValues(lft,top,rgt,bot) 14 | { 15 | this.lft=lft; 16 | this.top=top; 17 | this.rgt=rgt; 18 | this.bot=bot; 19 | } 20 | 21 | isSquare() 22 | { 23 | return((this.rgt-this.lft)===(this.bot-this.top)); 24 | } 25 | 26 | isXLarger() 27 | { 28 | return((this.rgt-this.lft)>(this.bot-this.top)); 29 | } 30 | 31 | overlap(rect) 32 | { 33 | if (this.lft>=rect.rgt) return(false); 34 | if (this.rgt<=rect.lft) return(false); 35 | if (this.top>=rect.bot) return(false); 36 | return(!(this.bot<=rect.top)); 37 | } 38 | 39 | pointIn(x,y) 40 | { 41 | return((x>=this.lft) && (x=this.top) && (y0.0) return(true); 34 | if (((this.a*xMax)+(this.b*yMin)+(this.c*zMin)+this.d)>0.0) return(true); 35 | if (((this.a*xMin)+(this.b*yMax)+(this.c*zMin)+this.d)>0.0) return(true); 36 | if (((this.a*xMax)+(this.b*yMax)+(this.c*zMin)+this.d)>0.0) return(true); 37 | if (((this.a*xMin)+(this.b*yMin)+(this.c*zMax)+this.d)>0.0) return(true); 38 | if (((this.a*xMax)+(this.b*yMin)+(this.c*zMax)+this.d)>0.0) return(true); 39 | if (((this.a*xMin)+(this.b*yMax)+(this.c*zMax)+this.d)>0.0) return(true); 40 | if (((this.a*xMax)+(this.b*yMax)+(this.c*zMax)+this.d)>0.0) return(true); 41 | 42 | return(false); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model_skeleton.js: -------------------------------------------------------------------------------- 1 | // 2 | // model skeleton class 3 | // 4 | 5 | export default class ModelSkeletonClass 6 | { 7 | constructor(core) 8 | { 9 | this.core=core; 10 | 11 | // nodes 12 | // we need all nodes, as certain non-joint modes 13 | // also effect the children joints 14 | 15 | this.nodes=[]; 16 | 17 | // skins 18 | // these are a collections of node indexes 19 | // used to create skin matrixes 20 | 21 | this.skins=[]; 22 | 23 | // the single animation track 24 | 25 | this.animation=null; 26 | 27 | // the root node, right now we consider 28 | // that there is only one root node in the skeleton 29 | 30 | this.rootNodeIdx=0; 31 | 32 | Object.seal(this); 33 | } 34 | 35 | // 36 | // initialize and release 37 | // 38 | 39 | initialize() 40 | { 41 | } 42 | 43 | release() 44 | { 45 | this.nodes=[]; 46 | } 47 | 48 | // 49 | // finds 50 | // 51 | 52 | findNodeIndex(name) 53 | { 54 | let n; 55 | let nNode=this.nodes.length; 56 | 57 | for (n=0;n!==nNode;n++) { 58 | if (this.nodes[n].name===name) return(n); 59 | } 60 | 61 | return(-1); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.klinksoftware.wsjs 5 | WSJS 6 | 1.0 7 | jar 8 | 9 | 10 | 11 | org.apache.maven.plugins 12 | maven-compiler-plugin 13 | 2.3.2 14 | 15 | false 16 | 17 | 18 | 19 | 20 | 21 | 22 | com.fasterxml.jackson.core 23 | jackson-core 24 | 2.15.0 25 | 26 | 27 | com.fasterxml.jackson.core 28 | jackson-databind 29 | 2.14.0-rc1 30 | jar 31 | 32 | 33 | 34 | UTF-8 35 | 15 36 | 15 37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_spot_list.js: -------------------------------------------------------------------------------- 1 | import CoreClass from '../main/core.js'; 2 | import MapSpotClass from '../map/map_spot.js'; 3 | 4 | // 5 | // map spot list class 6 | // 7 | 8 | export default class MapCubeListClass 9 | { 10 | constructor(core) 11 | { 12 | this.core=core; 13 | this.spots=new Map(); 14 | 15 | Object.seal(this); 16 | } 17 | 18 | // 19 | // initialize/release spot list 20 | // 21 | 22 | initialize() 23 | { 24 | this.spots.clear(); 25 | return(true); 26 | } 27 | 28 | release() 29 | { 30 | this.spots.clear(); 31 | } 32 | 33 | // 34 | // spot list 35 | // 36 | 37 | add(name,position,data) 38 | { 39 | this.spots.set(name,new MapSpotClass(position,data)); 40 | } 41 | 42 | clear() 43 | { 44 | this.spots.clear(); 45 | } 46 | 47 | // 48 | // find spots 49 | // 50 | 51 | getRandomUnusedSpotAndMark() 52 | { 53 | let spot; 54 | let count=this.spots.size; 55 | let idx=Math.trunc(Math.random()*count); 56 | let idx2=0; 57 | 58 | while (idx2 projects; 10 | 11 | public ProjectList(App app) 12 | { 13 | this.app=app; 14 | 15 | projects=new TreeMap<>(); 16 | } 17 | 18 | // 19 | // build the list of projects and start/stop list 20 | // we do this separately so appwindow can be initiated and 21 | // log can be started 22 | // 23 | 24 | public void scanForProjects(String projectPath) 25 | { 26 | String name; 27 | File projectDir; 28 | 29 | projectDir=new File(projectPath); 30 | 31 | for (File file:projectDir.listFiles()) { 32 | if (!file.isDirectory()) continue; 33 | 34 | name=file.getName(); 35 | projects.put(name,new Project(app,name,file.getAbsolutePath())); 36 | } 37 | } 38 | 39 | public void start() 40 | { 41 | for (Project project:projects.values()) { 42 | project.start(); 43 | } 44 | } 45 | 46 | public void stop() 47 | { 48 | for (Project project:projects.values()) { 49 | project.stop(); 50 | } 51 | } 52 | 53 | // 54 | // getters 55 | // 56 | 57 | public String[] getListAsStringArray() 58 | { 59 | return((String[])projects.keySet().toArray(new String[projects.size()])); 60 | } 61 | 62 | public Project get(String name) 63 | { 64 | return(projects.get(name)); 65 | } 66 | 67 | public Collection getProjects() 68 | { 69 | return(projects.values()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/resources/code/bitmap/bitmap_effect.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import BitmapClass from '../bitmap/bitmap.js'; 3 | 4 | export default class BitmapEffectClass extends BitmapClass 5 | { 6 | constructor(core,colorURL) 7 | { 8 | super(core); 9 | 10 | this.colorURL=colorURL; 11 | 12 | this.loaded=false; 13 | 14 | Object.seal(this); 15 | } 16 | 17 | async load() 18 | { 19 | let gl=this.core.gl; 20 | 21 | this.colorImage=null; 22 | 23 | if (this.colorBase===null) { 24 | await this.loadImagePromise(this.colorURL) 25 | .then 26 | ( 27 | // resolved 28 | 29 | value=>{ 30 | this.colorImage=value; 31 | }, 32 | 33 | // rejected 34 | 35 | value=>{ 36 | console.log('Unable to load '+value); 37 | } 38 | ); 39 | } 40 | 41 | if (this.colorImage===null) return(false); 42 | 43 | this.colorTexture=gl.createTexture(); 44 | gl.bindTexture(gl.TEXTURE_2D,this.colorTexture); 45 | gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,this.colorImage); 46 | 47 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR); 48 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR); 49 | 50 | gl.bindTexture(gl.TEXTURE_2D,null); 51 | 52 | this.loaded=true; 53 | 54 | return(true); 55 | } 56 | 57 | attach(shader) 58 | { 59 | let gl=this.core.gl; 60 | 61 | gl.activeTexture(gl.TEXTURE0); 62 | gl.bindTexture(gl.TEXTURE_2D,this.colorTexture); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/resources/code/bitmap/bitmap_interface.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import BitmapClass from '../bitmap/bitmap.js'; 3 | 4 | export default class BitmapInterfaceClass extends BitmapClass 5 | { 6 | constructor(core,colorURL) 7 | { 8 | super(core); 9 | 10 | this.colorURL=colorURL; 11 | 12 | this.loaded=false; 13 | 14 | Object.seal(this); 15 | } 16 | 17 | async load() 18 | { 19 | let gl=this.core.gl; 20 | 21 | this.colorImage=null; 22 | 23 | if (this.colorBase===null) { 24 | await this.loadImagePromise(this.colorURL) 25 | .then 26 | ( 27 | // resolved 28 | 29 | value=>{ 30 | this.colorImage=value; 31 | }, 32 | 33 | // rejected 34 | 35 | value=>{ 36 | console.log('Unable to load '+value); 37 | } 38 | ); 39 | } 40 | 41 | if (this.colorImage===null) return(false); 42 | 43 | this.colorTexture=gl.createTexture(); 44 | gl.bindTexture(gl.TEXTURE_2D,this.colorTexture); 45 | gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,this.colorImage); 46 | 47 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR); 48 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR); 49 | 50 | gl.bindTexture(gl.TEXTURE_2D,null); 51 | 52 | this.loaded=true; 53 | 54 | return(true); 55 | } 56 | 57 | attach(shader) 58 | { 59 | let gl=this.core.gl; 60 | 61 | gl.activeTexture(gl.TEXTURE0); 62 | gl.bindTexture(gl.TEXTURE_2D,this.colorTexture); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/resources/code/main/setup.js: -------------------------------------------------------------------------------- 1 | export default class SetupClass 2 | { 3 | constructor() 4 | { 5 | this.showFPS=false; 6 | 7 | this.mouseXSensitivity=0.3; 8 | this.mouseXAcceleration=0.4; 9 | this.mouseXInvert=false; 10 | this.mouseYSensitivity=0.2; 11 | this.mouseYAcceleration=0.1; 12 | this.mouseYInvert=false; 13 | 14 | this.touchStickLeftXDeadZone=0.5; 15 | this.touchStickLeftXAcceleration=1; 16 | this.touchStickLeftYDeadZone=0.5; 17 | this.touchStickLeftYAcceleration=1; 18 | 19 | this.touchStickRightXDeadZone=0.25; 20 | this.touchStickRightXAcceleration=3; 21 | this.touchStickRightYDeadZone=0.75; 22 | this.touchStickRightYAcceleration=2; 23 | 24 | this.snapLook=false; 25 | this.fullScreen=false; 26 | this.shadowmaps=true; 27 | 28 | this.soundVolume=0.3; 29 | this.musicVolume=0.5; 30 | this.musicOn=true; 31 | 32 | this.multiplayerName='Player'; 33 | this.multiplayerCharacter=''; 34 | this.multiplayerGameName=''; 35 | this.multiplayerMapName=''; 36 | this.multiplayerRespawnTime=5; 37 | this.multiplayerServerURL='127.0.0.1'; 38 | this.multiplayerRecentServerURLs=['127.0.0.1']; 39 | this.multiplayerBotCharacters=['','','','','','','','','','']; 40 | 41 | this.skipShadowMapNormals=false; 42 | } 43 | 44 | getStorageName() 45 | { 46 | let paths=window.location.pathname.split('/'); 47 | return(paths[1]+'_setup'); 48 | } 49 | 50 | load() 51 | { 52 | let jsonStr=window.localStorage.getItem(this.getStorageName()); 53 | if (jsonStr!==null) Object.assign(this,JSON.parse(jsonStr)); 54 | } 55 | 56 | save() 57 | { 58 | window.localStorage.setItem(this.getStorageName(),JSON.stringify(this)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_sound_list.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | import SoundClass from '../sound/sound.js'; 3 | 4 | // 5 | // map sound list class 6 | // 7 | 8 | export default class MapSoundListClass 9 | { 10 | constructor(core) 11 | { 12 | this.core=core; 13 | 14 | this.sounds=new Map(); 15 | 16 | Object.seal(this); 17 | } 18 | 19 | // 20 | // initialize and release 21 | // 22 | 23 | initialize() 24 | { 25 | this.sounds.clear(); 26 | 27 | return(true); 28 | } 29 | 30 | release() 31 | { 32 | let sound; 33 | 34 | // buffers 35 | 36 | for (sound of this.sounds.values()) { 37 | sound.release(); 38 | } 39 | 40 | this.sounds.clear(); 41 | } 42 | 43 | // 44 | // loading 45 | // 46 | 47 | buildSoundList() 48 | { 49 | let name,sound; 50 | let soundList=this.core.project.getSoundList(this.core.game.multiplayerMode===this.core.game.MULTIPLAYER_MODE_NONE); 51 | 52 | for (name of soundList) { 53 | sound=new SoundClass(this.core,name); 54 | sound.initialize(); 55 | this.sounds.set(name,sound); 56 | } 57 | 58 | } 59 | 60 | // 61 | // gets milliseconds length of sample 62 | // 63 | 64 | getMillisecondDuration(name) 65 | { 66 | let sound; 67 | 68 | sound=this.sounds.get(name); 69 | if (sound===undefined) return(0); 70 | 71 | return(sound.buffer.duration*1000); 72 | } 73 | 74 | getMillisecondDurationJson(obj) 75 | { 76 | if ((obj===undefined) || (obj===null)) return(0); 77 | if ((obj.name===undefined) || (obj.name==='')) return(0); 78 | 79 | return(this.getMillisecondDuration(obj.name)); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/color_shader.js: -------------------------------------------------------------------------------- 1 | import ShaderClass from '../shader/shader.js'; 2 | 3 | // 4 | // color shader class 5 | // 6 | 7 | export default class ColorShaderClass extends ShaderClass 8 | { 9 | constructor(core) 10 | { 11 | super(core); 12 | 13 | this.shaderName='color'; 14 | 15 | this.vertexPositionAttribute=null; 16 | this.vertexColorAttribute=null; 17 | this.orthoMatrixUniform=null; 18 | 19 | Object.seal(this); 20 | } 21 | 22 | // 23 | // load finish 24 | // 25 | 26 | loadFinish() 27 | { 28 | let gl=this.core.gl; 29 | 30 | // setup uniforms 31 | 32 | gl.useProgram(this.program); 33 | 34 | this.vertexPositionAttribute=gl.getAttribLocation(this.program,'vertexPosition'); 35 | this.vertexColorAttribute=gl.getAttribLocation(this.program,'vertexColor'); 36 | 37 | this.orthoMatrixUniform=gl.getUniformLocation(this.program,'orthoMatrix'); 38 | 39 | gl.useProgram(null); 40 | } 41 | 42 | // 43 | // start/stop interface shader drawing 44 | // 45 | 46 | drawStart() 47 | { 48 | let gl=this.core.gl; 49 | 50 | gl.useProgram(this.program); 51 | 52 | // setup the uniforms 53 | 54 | gl.uniformMatrix4fv(this.orthoMatrixUniform,false,this.core.orthoMatrix.data); 55 | 56 | // enable the vertex attributes 57 | 58 | gl.enableVertexAttribArray(this.vertexPositionAttribute); 59 | gl.enableVertexAttribArray(this.vertexColorAttribute); 60 | } 61 | 62 | drawEnd() 63 | { 64 | let gl=this.core.gl; 65 | 66 | // disable vertex attributes 67 | 68 | gl.disableVertexAttribArray(this.vertexPositionAttribute); 69 | gl.disableVertexAttribArray(this.vertexColorAttribute); 70 | 71 | // no longer using program 72 | 73 | gl.useProgram(null); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 11 | 12 | 13 | -Xmx1024m -Xms1024m -classpath %classpath com.klinksoftware.wsjs.application.Main 14 | java 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | process-classes 24 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 25 | 26 | 27 | -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} -Xmx1024m -Xms1024m -classpath %classpath com.klinksoftware.wsjs.application.Main 28 | java 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 40 | 41 | 42 | -Xmx1024m -Xms1024m -classpath %classpath com.klinksoftware.wsjs.application.Main 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/main/resources/code/bitmap/bitmap_shadowmap.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import BitmapClass from '../bitmap/bitmap.js'; 3 | 4 | export default class BitmapShadowmapClass extends BitmapClass 5 | { 6 | constructor(core,colorURL) 7 | { 8 | super(core); 9 | 10 | this.colorURL=colorURL; 11 | 12 | this.loaded=false; 13 | 14 | Object.seal(this); 15 | } 16 | 17 | async load() 18 | { 19 | let gl=this.core.gl; 20 | 21 | // shadows only have a color image 22 | 23 | this.colorImage=null; 24 | 25 | if (this.colorBase===null) { 26 | await this.loadImagePromise(this.colorURL) 27 | .then 28 | ( 29 | // resolved 30 | 31 | value=>{ 32 | this.colorImage=value; 33 | }, 34 | 35 | // rejected 36 | 37 | value=>{ 38 | console.log('Unable to load '+value); 39 | } 40 | ); 41 | } 42 | 43 | 44 | this.colorTexture=gl.createTexture(); 45 | gl.bindTexture(gl.TEXTURE_2D,this.colorTexture); 46 | gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,this.colorImage); 47 | 48 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR); 49 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR); 50 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE); 51 | gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE); 52 | 53 | gl.bindTexture(gl.TEXTURE_2D,null); 54 | 55 | return(true); 56 | } 57 | 58 | attach(shader) 59 | { 60 | let gl=this.core.gl; 61 | 62 | gl.activeTexture(gl.TEXTURE0); 63 | gl.bindTexture(gl.TEXTURE_2D,this.colorTexture); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/resources/code/utility/bound.js: -------------------------------------------------------------------------------- 1 | export default class BoundClass 2 | { 3 | constructor(value1,value2) 4 | { 5 | if (value1this.max) this.max=value; 67 | } 68 | 69 | enlargeForSign(value) 70 | { 71 | if (value<0) { 72 | this.min+=value; 73 | } 74 | else { 75 | this.max+=value; 76 | } 77 | } 78 | 79 | trunc() 80 | { 81 | this.min=Math.trunc(this.min); 82 | this.max=Math.trunc(this.max); 83 | } 84 | 85 | copy() 86 | { 87 | return(new BoundClass(this.min,this.max)); 88 | } 89 | 90 | toString() 91 | { 92 | return('('+this.min+','+this.max+')'); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/debug_shader.js: -------------------------------------------------------------------------------- 1 | import ShaderClass from '../shader/shader.js'; 2 | 3 | // 4 | // debug shader class 5 | // 6 | 7 | export default class DebugShaderClass extends ShaderClass 8 | { 9 | constructor(core) 10 | { 11 | super(core); 12 | 13 | this.shaderName='debug'; 14 | 15 | this.vertexPositionAttribute=null; 16 | 17 | this.perspectiveMatrixUniform=null; 18 | this.viewMatrixUniform=null; 19 | 20 | this.colorUniform=null; 21 | 22 | Object.seal(this); 23 | } 24 | 25 | // 26 | // load finish 27 | // 28 | 29 | loadFinish() 30 | { 31 | let gl=this.core.gl; 32 | 33 | // setup uniforms 34 | 35 | gl.useProgram(this.program); 36 | 37 | this.vertexPositionAttribute=gl.getAttribLocation(this.program,'vertexPosition'); 38 | 39 | this.perspectiveMatrixUniform=gl.getUniformLocation(this.program,'perspectiveMatrix'); 40 | this.viewMatrixUniform=gl.getUniformLocation(this.program,'viewMatrix'); 41 | 42 | this.colorUniform=gl.getUniformLocation(this.program,'color'); 43 | 44 | gl.useProgram(null); 45 | } 46 | 47 | // 48 | // start/stop skeleton shader drawing 49 | // 50 | 51 | drawStart() 52 | { 53 | let gl=this.core.gl; 54 | 55 | // using the skeleton shader 56 | 57 | gl.useProgram(this.program); 58 | 59 | // matrix 60 | 61 | gl.uniformMatrix4fv(this.perspectiveMatrixUniform,false,this.core.perspectiveMatrix.data); 62 | gl.uniformMatrix4fv(this.viewMatrixUniform,false,this.core.viewMatrix.data); 63 | 64 | // enable the vertex attributes 65 | 66 | gl.enableVertexAttribArray(this.vertexPositionAttribute); 67 | } 68 | 69 | drawEnd() 70 | { 71 | let gl=this.core.gl; 72 | 73 | // disable vertex attributes 74 | 75 | gl.disableVertexAttribArray(this.vertexPositionAttribute); 76 | 77 | // no longer using shader 78 | 79 | gl.useProgram(null); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/text_shader.js: -------------------------------------------------------------------------------- 1 | import ShaderClass from '../shader/shader.js'; 2 | 3 | // 4 | // text shader class 5 | // 6 | 7 | export default class TextShaderClass extends ShaderClass 8 | { 9 | constructor(core) 10 | { 11 | super(core); 12 | 13 | this.shaderName='text'; 14 | 15 | this.vertexPositionAttribute=null; 16 | this.vertexUVAttribute=null; 17 | this.orthoMatrixUniform=null; 18 | this.colorUniform=null; 19 | 20 | Object.seal(this); 21 | } 22 | 23 | // 24 | // load finish 25 | // 26 | 27 | loadFinish() 28 | { 29 | let gl=this.core.gl; 30 | 31 | // setup uniforms 32 | 33 | gl.useProgram(this.program); 34 | 35 | this.vertexPositionAttribute=gl.getAttribLocation(this.program,'vertexPosition'); 36 | this.vertexUVAttribute=gl.getAttribLocation(this.program,'vertexUV'); 37 | 38 | this.orthoMatrixUniform=gl.getUniformLocation(this.program,'orthoMatrix'); 39 | this.colorUniform=gl.getUniformLocation(this.program,'color'); 40 | 41 | // these uniforms are always the same 42 | 43 | gl.uniform1i(gl.getUniformLocation(this.program,'baseTex'),0); 44 | 45 | gl.useProgram(null); 46 | } 47 | 48 | // 49 | // start/stop text shader drawing 50 | // 51 | 52 | drawStart() 53 | { 54 | let gl=this.core.gl; 55 | 56 | gl.useProgram(this.program); 57 | 58 | // setup the uniforms 59 | 60 | gl.uniformMatrix4fv(this.orthoMatrixUniform,false,this.core.orthoMatrix.data); 61 | 62 | // enable the vertex attributes 63 | 64 | gl.enableVertexAttribArray(this.vertexPositionAttribute); 65 | gl.enableVertexAttribArray(this.vertexUVAttribute); 66 | } 67 | 68 | drawEnd() 69 | { 70 | let gl=this.core.gl; 71 | 72 | // disable vertex attributes 73 | 74 | gl.disableVertexAttribArray(this.vertexPositionAttribute); 75 | gl.disableVertexAttribArray(this.vertexUVAttribute); 76 | 77 | // no longer using program 78 | 79 | gl.useProgram(null); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/interface_shader.js: -------------------------------------------------------------------------------- 1 | import ShaderClass from '../shader/shader.js'; 2 | 3 | // 4 | // interface shader class 5 | // 6 | 7 | export default class InterfaceShaderClass extends ShaderClass 8 | { 9 | constructor(core) 10 | { 11 | super(core); 12 | 13 | this.shaderName='interface'; 14 | 15 | this.vertexPositionAttribute=null; 16 | this.vertexUVAttribute=null; 17 | this.orthoMatrixUniform=null; 18 | this.colorUniform=null; 19 | 20 | Object.seal(this); 21 | } 22 | 23 | // 24 | // load finish 25 | // 26 | 27 | loadFinish() 28 | { 29 | let gl=this.core.gl; 30 | 31 | // setup uniforms 32 | 33 | gl.useProgram(this.program); 34 | 35 | this.vertexPositionAttribute=gl.getAttribLocation(this.program,'vertexPosition'); 36 | this.vertexUVAttribute=gl.getAttribLocation(this.program,'vertexUV'); 37 | 38 | this.orthoMatrixUniform=gl.getUniformLocation(this.program,'orthoMatrix'); 39 | this.colorUniform=gl.getUniformLocation(this.program,'color'); 40 | 41 | // texture uniforms never change 42 | 43 | gl.uniform1i(gl.getUniformLocation(this.program,'baseTex'),0); 44 | 45 | gl.useProgram(null); 46 | } 47 | 48 | // 49 | // start/stop interface shader drawing 50 | // 51 | 52 | drawStart() 53 | { 54 | let gl=this.core.gl; 55 | 56 | gl.useProgram(this.program); 57 | 58 | // setup the uniforms 59 | 60 | gl.uniformMatrix4fv(this.orthoMatrixUniform,false,this.core.orthoMatrix.data); 61 | 62 | // enable the vertex attributes 63 | 64 | gl.enableVertexAttribArray(this.vertexPositionAttribute); 65 | gl.enableVertexAttribArray(this.vertexUVAttribute); 66 | } 67 | 68 | drawEnd() 69 | { 70 | let gl=this.core.gl; 71 | 72 | // disable vertex attributes 73 | 74 | gl.disableVertexAttribArray(this.vertexPositionAttribute); 75 | gl.disableVertexAttribArray(this.vertexUVAttribute); 76 | 77 | // no longer using program 78 | 79 | gl.useProgram(null); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/resources/code/dialog/dialog_error.js: -------------------------------------------------------------------------------- 1 | import DialogBaseClass from '../dialog/dialog_base.js'; 2 | import SetupClass from '../main/setup.js'; 3 | 4 | export default class DialogErrorClass extends DialogBaseClass 5 | { 6 | constructor(core) 7 | { 8 | super(core); 9 | 10 | this.errorTitle=null; 11 | this.errorDescription=null; 12 | 13 | Object.seal(this); 14 | } 15 | 16 | // 17 | // initialize and release 18 | // 19 | 20 | initialize() 21 | { 22 | let x,y; 23 | 24 | if (!super.initialize()) return(false); 25 | 26 | // tabs 27 | 28 | this.addDialogTab('error','Error',true); 29 | 30 | // dialog buttons 31 | 32 | x=(this.core.canvas.width-this.DIALOG_CONTROL_RIGHT_MARGIN)-this.DIALOG_BUTTON_SMALL_WIDTH; 33 | y=(this.core.canvas.height-this.DIALOG_CONTROL_BOTTOM_MARGIN)-this.DIALOG_BUTTON_HIGH; 34 | this.addDialogButton('ok',x,y,this.DIALOG_BUTTON_SMALL_WIDTH,this.DIALOG_BUTTON_HIGH,'Ok',true); 35 | 36 | // node controls 37 | 38 | x=Math.trunc(this.core.canvas.width*0.5); 39 | y=Math.trunc(this.core.canvas.height*0.5); 40 | 41 | y+=this.addDialogControlStatic(this,'error','errorTitle',x,y); 42 | this.addDialogControlStatic(this,'error','errorDescription',x,y); 43 | 44 | return(true); 45 | } 46 | 47 | // 48 | // dialog controls 49 | // 50 | 51 | loadDialogControls() 52 | { 53 | this.setDialogControl('errorTitle',this.errorTitle); 54 | this.setDialogControl('errorDescription',this.errorDescription); 55 | } 56 | 57 | // 58 | // setup 59 | // 60 | 61 | setup(errorTitle,errorDescription) 62 | { 63 | this.errorTitle=errorTitle; 64 | this.errorDescription=errorDescription; 65 | } 66 | 67 | // 68 | // running 69 | // 70 | 71 | run() 72 | { 73 | let id=super.runInternal(); 74 | 75 | if (id==='ok') { 76 | this.core.switchLoop(this.core.LOOP_TITLE); // all errors go back to title 77 | return(false); 78 | } 79 | 80 | return(true); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/model_mesh.vert: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in highp vec3 vertexPosition; 4 | in highp vec3 vertexNormal; 5 | in highp vec3 vertexTangent; 6 | in highp vec2 vertexUV; 7 | in highp vec4 vertexJoint; 8 | in highp vec4 vertexWeight; 9 | 10 | uniform highp mat4 perspectiveMatrix; 11 | uniform highp mat4 viewMatrix; 12 | uniform highp mat4 modelMatrix; 13 | 14 | uniform bool noSkin; 15 | uniform highp mat4 noSkinAttachedNodeMatrix; 16 | uniform highp mat4 jointMatrix[64]; 17 | 18 | out highp vec3 eyeVector,eyePosition; 19 | out highp vec2 fragUV; 20 | out mediump vec3 tangentSpaceTangent,tangentSpaceBinormal,tangentSpaceNormal; 21 | 22 | void main(void) 23 | { 24 | // calculate the skin animation 25 | // and vertex position, if skinning, calc 26 | // the skin matrix otherwise just attach to node 27 | // by its matrix 28 | 29 | // note we build the normalMatrix here, 30 | // this is costly but has to be done because of the 31 | // skin matrix 32 | 33 | highp vec4 pos; 34 | highp mat3 normalMatrix; 35 | 36 | if (!noSkin) { 37 | highp mat4 skinMatrix=(vertexWeight.x*jointMatrix[int(vertexJoint.x)])+(vertexWeight.y*jointMatrix[int(vertexJoint.y)])+(vertexWeight.z*jointMatrix[int(vertexJoint.z)])+(vertexWeight.w*jointMatrix[int(vertexJoint.w)]); 38 | pos=viewMatrix*modelMatrix*skinMatrix*vec4(vertexPosition,1.0); 39 | normalMatrix=transpose(inverse(mat3(viewMatrix)*mat3(modelMatrix)*mat3(skinMatrix))); 40 | } 41 | else { 42 | pos=viewMatrix*modelMatrix*noSkinAttachedNodeMatrix*vec4(vertexPosition,1.0); 43 | normalMatrix=transpose(inverse(mat3(viewMatrix)*mat3(modelMatrix)*mat3(noSkinAttachedNodeMatrix))); 44 | } 45 | 46 | gl_Position=perspectiveMatrix*pos; 47 | eyePosition=vec3(pos); 48 | 49 | // get the tangent space 50 | // this gets passed to the fragment so we can calculate lights 51 | 52 | tangentSpaceTangent=normalize(normalMatrix*vertexTangent); 53 | tangentSpaceBinormal=normalize(normalMatrix*cross(vertexNormal,vertexTangent)); 54 | tangentSpaceNormal=normalize(normalMatrix*vertexNormal); 55 | 56 | // translate the eye vector 57 | 58 | eyeVector.x=dot(-eyePosition,tangentSpaceTangent); 59 | eyeVector.y=dot(-eyePosition,tangentSpaceBinormal); 60 | eyeVector.z=dot(-eyePosition,tangentSpaceNormal); 61 | 62 | // the varying uv 63 | 64 | fragUV=vertexUV; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/main/docs/misc_util_code.txt: -------------------------------------------------------------------------------- 1 | ############################## 2 | ######### quick triangle OBJ importer 3 | 4 | let str=`[obj here]`; 5 | 6 | let n,k,tokens,faceTokens; 7 | let lines=str.split('\n'); 8 | let vertex=[]; 9 | let uv=[]; 10 | let fv,fvt; 11 | let vOut=''; 12 | let vtOut=''; 13 | 14 | for (n=0;n!==lines.length;n++) { 15 | tokens=lines[n].split(' '); 16 | if (tokens[0]==='v') vertex.push([parseFloat(tokens[1]),-parseFloat(tokens[2]),parseFloat(tokens[3])]); // - for y flip, remove if not needed 17 | if (tokens[0]==='vt') uv.push([parseFloat(tokens[1]),parseFloat(tokens[2])]); 18 | if (tokens[0]==='f') { 19 | fv=[]; 20 | fvt=[]; 21 | for (k=1;k!==4;k++) { 22 | faceTokens=tokens[k].split('/'); 23 | fv.push(parseInt(faceTokens[0])-1); 24 | fvt.push(parseInt(faceTokens[1])-1); 25 | } 26 | if (vOut.length!==0) { 27 | vOut+=',\n'; 28 | vtOut+=',\n'; 29 | } 30 | vOut+=(vertex[fv[0]][0]+','+vertex[fv[0]][1]+','+vertex[fv[0]][2]+','); 31 | vOut+=(vertex[fv[1]][0]+','+vertex[fv[1]][1]+','+vertex[fv[1]][2]+','); 32 | vOut+=(vertex[fv[2]][0]+','+vertex[fv[2]][1]+','+vertex[fv[2]][2]); 33 | vtOut+=(uv[fvt[0]][0]+','+uv[fvt[0]][1]+','); 34 | vtOut+=(uv[fvt[1]][0]+','+uv[fvt[1]][1]+','); 35 | vtOut+=(uv[fvt[2]][0]+','+uv[fvt[2]][1]); 36 | } 37 | } 38 | 39 | console.info('this.vertexes=new Float32Array([\n'+vOut+'\n]);\n'); 40 | console.info('this.uvs=new Float32Array([\n'+vtOut+'\n]);\n'); 41 | 42 | 43 | ############################## 44 | ######### updated (held weapon) player animations 45 | 46 | Berreta_COMBAT_mode 0-50 47 | Berreta_Grenade_throw 51-91 48 | Berreta_Looking_around 92-177 49 | Berreta_RightFoot_kick 178-208 50 | Berreta_Die_on_back 209-247 51 | Berreta_Die_on_belt 252-359 52 | Berreta_fire_staying 364-401 53 | Berreta_Casual_walk 406-442 54 | Berreta_Cautious_walk 447-487 55 | Berreta_Combat_run 492-518 56 | Berreta_Fire_run 523-549 57 | Berreta_Fire_walk 554-594 58 | Berreta_Fire_walking_back 599-634 59 | Berreta_run 639-665 60 | Berreta_Walking_back 670-705 61 | M16_Combat_Mode 710-760 62 | M16_Fire_Belt 765-770 63 | M16_Fire_standing 775-815 64 | M16_Grenade_throw 820-860 65 | M16_Fire_Runing 865-887 66 | M16_Fire_walking 892-928 67 | M16_Run 933-955 68 | M16_Walking 960-996 69 | M16_Walking_back 1001-1036 70 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/effect_shader.js: -------------------------------------------------------------------------------- 1 | import ShaderClass from '../shader/shader.js'; 2 | 3 | // 4 | // effect shader class 5 | // 6 | 7 | export default class EffectShaderClass extends ShaderClass 8 | { 9 | constructor(core) 10 | { 11 | super(core); 12 | 13 | this.shaderName='effect'; 14 | 15 | this.vertexPositionAttribute=null; 16 | this.vertexUVAttribute=null; 17 | this.perspectiveMatrixUniform=null; 18 | this.viewMatrixUniform=null; 19 | this.colorAlphaUniform=null; 20 | 21 | Object.seal(this); 22 | } 23 | 24 | // 25 | // load finish 26 | // 27 | 28 | loadFinish() 29 | { 30 | let gl=this.core.gl; 31 | 32 | // setup uniforms 33 | 34 | gl.useProgram(this.program); 35 | 36 | this.vertexPositionAttribute=gl.getAttribLocation(this.program,'vertexPosition'); 37 | this.vertexUVAttribute=gl.getAttribLocation(this.program,'vertexUV'); 38 | 39 | this.perspectiveMatrixUniform=gl.getUniformLocation(this.program,'perspectiveMatrix'); 40 | this.viewMatrixUniform=gl.getUniformLocation(this.program,'viewMatrix'); 41 | 42 | this.colorAlphaUniform=gl.getUniformLocation(this.program,'colorAlpha'); 43 | 44 | // texture uniforms never change 45 | 46 | gl.uniform1i(gl.getUniformLocation(this.program,'baseTex'),0); 47 | 48 | gl.useProgram(null); 49 | } 50 | 51 | // 52 | // start/stop effect drawing 53 | // 54 | 55 | drawStart() 56 | { 57 | let gl=this.core.gl; 58 | 59 | // using the map shader 60 | 61 | gl.useProgram(this.program); 62 | 63 | // matrix 64 | 65 | gl.uniformMatrix4fv(this.perspectiveMatrixUniform,false,this.core.perspectiveMatrix.data); 66 | gl.uniformMatrix4fv(this.viewMatrixUniform,false,this.core.viewMatrix.data); 67 | 68 | // enable the vertex attributes 69 | 70 | gl.enableVertexAttribArray(this.vertexPositionAttribute); 71 | gl.enableVertexAttribArray(this.vertexUVAttribute); 72 | } 73 | 74 | drawEnd() 75 | { 76 | let gl=this.core.gl; 77 | 78 | // disable vertex attributes 79 | 80 | gl.disableVertexAttribArray(this.vertexPositionAttribute); 81 | gl.disableVertexAttribArray(this.vertexUVAttribute); 82 | 83 | // no longer using shader 84 | 85 | gl.useProgram(null); 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /src/main/resources/code/generate/shadowmap/shadowmap_light.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../../utility/point.js'; 2 | import BoundClass from '../../utility/bound.js'; 3 | 4 | // 5 | // this object contains one of the lights in the scene, 6 | // plus a list of all it's collision meshes to speed 7 | // up the tracing 8 | // 9 | 10 | export default class ShadowmapLightClass 11 | { 12 | constructor(meshes,mapLight) 13 | { 14 | this.meshes=meshes; 15 | 16 | this.position=mapLight.position; 17 | this.intensity=mapLight.intensity; 18 | this.invertIntensity=mapLight.invertIntensity; 19 | this.exponent=mapLight.exponent; 20 | 21 | // if being used on this trig 22 | 23 | this.inUse=false; 24 | 25 | // some ray trace optimization values 26 | 27 | this.lastBlockMeshIdx=-1; 28 | this.lastBlockTriangleIdx=-1; 29 | 30 | // all the meshes that collide with 31 | // the light globe 32 | 33 | this.collideMeshes=[]; 34 | } 35 | 36 | calculateCollisionList() 37 | { 38 | let n,mesh; 39 | let xBound,yBound,zBound; 40 | 41 | // this check is loose, we treat the light 42 | // like a cube and then collide them, if we did 43 | // something like check corners/centers we'd 44 | // miss many meshes 45 | 46 | xBound=new BoundClass((this.position.x-this.intensity),(this.position.x+this.intensity)); 47 | yBound=new BoundClass((this.position.y-this.intensity),(this.position.y+this.intensity)); 48 | zBound=new BoundClass((this.position.z-this.intensity),(this.position.z+this.intensity)); 49 | 50 | for (n=0;n!==this.meshes.length;n++) { 51 | mesh=this.meshes[n]; 52 | 53 | // moveable meshes and meshes with 54 | // no collisions are skipped 55 | 56 | if ((mesh.moveable) || (mesh.noCollisions)) continue; 57 | 58 | // the bounds check 59 | 60 | if (xBound.min>=mesh.xBound.max) continue; 61 | if (xBound.max<=mesh.xBound.min) continue; 62 | if (yBound.min>=mesh.yBound.max) continue; 63 | if (yBound.max<=mesh.yBound.min) continue; 64 | if (zBound.min>=mesh.zBound.max) continue; 65 | if (zBound.max<=mesh.zBound.min) continue; 66 | 67 | this.collideMeshes.push(n); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/code/utility/color.js: -------------------------------------------------------------------------------- 1 | export default class ColorClass 2 | { 3 | constructor(r,g,b) 4 | { 5 | this.r=r; 6 | this.g=g; 7 | this.b=b; 8 | 9 | Object.seal(this); 10 | } 11 | 12 | setFromValues(r,g,b) 13 | { 14 | this.r=r; 15 | this.g=g; 16 | this.b=b; 17 | } 18 | 19 | setFromColor(col) 20 | { 21 | this.r=col.r; 22 | this.g=col.g; 23 | this.b=col.b; 24 | } 25 | 26 | setFromColorFactor(col1,col2,factor) 27 | { 28 | let f2=1.0-factor; 29 | 30 | this.r=(col1.r*factor)+(col2.r*f2); 31 | this.g=(col1.g*factor)+(col2.g*f2); 32 | this.b=(col1.b*factor)+(col2.b*f2); 33 | } 34 | 35 | add(col) 36 | { 37 | this.r+=col.r; 38 | this.g+=col.g; 39 | this.b+=col.b; 40 | } 41 | 42 | addFromValues(r,g,b) 43 | { 44 | this.r+=r; 45 | this.g+=g; 46 | this.b+=b; 47 | } 48 | 49 | addAttenuate(col,att) 50 | { 51 | this.r+=(col.r*att); 52 | this.g+=(col.g*att); 53 | this.b+=(col.b*att); 54 | } 55 | 56 | factor(f) 57 | { 58 | this.r*=f; 59 | this.g*=f; 60 | this.b*=f; 61 | } 62 | 63 | fixOverflow() 64 | { 65 | let f; 66 | 67 | // find the largest overflow 68 | // and reduce that to 1 so we don't 69 | // end up clipping to white all the time 70 | 71 | if ((this.r>this.g) && (this.r>this.b)) { 72 | if (this.r>1.0) { 73 | f=this.r-1.0; 74 | this.g-=f; 75 | this.b-=f; 76 | this.r=1.0; 77 | } 78 | } 79 | else { 80 | if (this.g>this.b) { 81 | if (this.g>1.0) { 82 | f=this.g-1.0; 83 | this.r-=f; 84 | this.b-=f; 85 | this.g=1.0; 86 | } 87 | } 88 | else { 89 | if (this.b>1.0) { 90 | f=this.b-1.0; 91 | this.r-=f; 92 | this.g-=f; 93 | this.b=1.0; 94 | } 95 | } 96 | } 97 | 98 | // clip to black 99 | 100 | if (this.r<0.0) this.r=0.0; 101 | if (this.g<0.0) this.g=0.0; 102 | if (this.b<0.0) this.b=0.0; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/map_mesh_shadow_shader.js: -------------------------------------------------------------------------------- 1 | import CoreClass from '../main/core.js'; 2 | import ShaderClass from '../shader/shader.js'; 3 | import ShaderLightClass from '../shader/shader_light.js'; 4 | 5 | // 6 | // map shader object 7 | // 8 | // this version has a shadow map 9 | // 10 | 11 | export default class MapMeshShadowShaderClass extends ShaderClass 12 | { 13 | constructor(core) 14 | { 15 | super(core); 16 | 17 | this.shaderName='map_mesh_shadow'; 18 | 19 | this.vertexPositionShadowAttribute=null; 20 | this.vertexUVShadowAttribute=null; 21 | 22 | this.perspectiveMatrixUniform=null; 23 | this.viewMatrixUniform=null; 24 | 25 | Object.seal(this); 26 | } 27 | 28 | // 29 | // load finish 30 | // 31 | 32 | loadFinish() 33 | { 34 | let gl=this.core.gl; 35 | 36 | // setup uniforms 37 | 38 | gl.useProgram(this.program); 39 | 40 | this.vertexPositionShadowAttribute=gl.getAttribLocation(this.program,'vertexPositionShadow'); 41 | this.vertexUVShadowAttribute=gl.getAttribLocation(this.program,'vertexUVShadow'); 42 | 43 | this.perspectiveMatrixUniform=gl.getUniformLocation(this.program,'perspectiveMatrix'); 44 | this.viewMatrixUniform=gl.getUniformLocation(this.program,'viewMatrix'); 45 | 46 | // these uniforms are always the same 47 | 48 | gl.uniform1i(gl.getUniformLocation(this.program,'shadowTex'),0); 49 | 50 | gl.useProgram(null); 51 | } 52 | 53 | // 54 | // start/stop map shader drawing 55 | // 56 | 57 | drawStart() 58 | { 59 | let gl=this.core.gl; 60 | 61 | gl.useProgram(this.program); 62 | 63 | // matrix 64 | // normal is set on a per mesh level as some have 65 | // model matrixes which need to be calculated in 66 | 67 | gl.uniformMatrix4fv(this.perspectiveMatrixUniform,false,this.core.perspectiveMatrix.data); 68 | gl.uniformMatrix4fv(this.viewMatrixUniform,false,this.core.viewMatrix.data); 69 | 70 | // enable the vertex attributes 71 | 72 | gl.enableVertexAttribArray(this.vertexPositionShadowAttribute); 73 | gl.enableVertexAttribArray(this.vertexUVShadowAttribute); 74 | } 75 | 76 | drawEnd() 77 | { 78 | let gl=this.core.gl; 79 | 80 | // disable vertex attributes 81 | 82 | gl.disableVertexAttribArray(this.vertexPositionShadowAttribute); 83 | gl.disableVertexAttribArray(this.vertexUVShadowAttribute); 84 | 85 | // no longer using shader 86 | 87 | gl.useProgram(null); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/resources/code/utility/line.js: -------------------------------------------------------------------------------- 1 | import BoundClass from '../utility/bound.js'; 2 | 3 | export default class LineClass 4 | { 5 | constructor(p1,p2) 6 | { 7 | this.p1=p1; 8 | this.p2=p2; 9 | 10 | this.xBound=new BoundClass(0,0); // cached to avoid GC 11 | this.yBound=new BoundClass(0,0); 12 | this.zBound=new BoundClass(0,0); 13 | 14 | Object.seal(this); 15 | } 16 | 17 | setFromValues(p1,p2) 18 | { 19 | this.p1=p1; 20 | this.p2=p2; 21 | } 22 | 23 | addPoint(pnt) 24 | { 25 | this.p1.addPoint(pnt); 26 | this.p2.addPoint(pnt); 27 | } 28 | 29 | average(pnt1,pnt2) 30 | { 31 | this.p1.average(pnt1); 32 | this.p2.average(pnt2); 33 | } 34 | 35 | equals(line) 36 | { 37 | if ((this.p1.equals(line.p1)) && (this.p2.equals(line.p2))) return(true); 38 | return((this.p1.equals(line.p2)) && (this.p2.equals(line.p1))); 39 | } 40 | 41 | length() 42 | { 43 | return(this.p1.distance(this.p2)); 44 | } 45 | 46 | getFactorForXZPointOnLine(pnt) 47 | { 48 | let len,hitLen; 49 | 50 | len=this.p1.distanceScrubY(this.p2); 51 | hitLen=this.p1.distanceScrubY(pnt); 52 | 53 | return(hitLen/len); 54 | } 55 | 56 | getXZPointOnLineForFactor(f,pnt) 57 | { 58 | let len; 59 | 60 | len=this.p1.distance(this.p2); 61 | 62 | pnt.x=this.p2.x-this.p1.x; 63 | pnt.y=0; 64 | pnt.z=this.p2.z-this.p1.z; 65 | pnt.normalize(); 66 | pnt.scale(len*f); 67 | 68 | pnt.x+=this.p1.x; 69 | pnt.z+=this.p1.z; 70 | } 71 | 72 | boxBoundCollision(xBound,yBound,zBound) 73 | { 74 | if ((this.p1.xxBound.max) && (this.p2.x>xBound.max)) return(false); 76 | if ((this.p1.yyBound.max) && (this.p2.y>yBound.max)) return(false); 78 | if ((this.p1.zzBound.max) && (this.p2.z>zBound.max))); 80 | } 81 | 82 | getXBound() 83 | { 84 | this.xBound.setFromValues(this.p1.x,this.p2.x); 85 | return(this.xBound); 86 | } 87 | 88 | getYBound() 89 | { 90 | this.yBound.setFromValues(this.p1.y,this.p2.y); 91 | return(this.yBound); 92 | } 93 | 94 | getZBound() 95 | { 96 | this.zBound.setFromValues(this.p1.z,this.p2.z); 97 | return(this.zBound); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/resources/code/game/liquid_tint.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import RectClass from '../utility/rect.js'; 3 | 4 | export default class LiquidTintClass 5 | { 6 | constructor(core) 7 | { 8 | this.core=core; 9 | 10 | this.vertexBuffer=null; 11 | 12 | Object.seal(this); 13 | } 14 | 15 | // 16 | // initialize/release 17 | // 18 | 19 | initialize() 20 | { 21 | let vertexArray; 22 | let gl=this.core.gl; 23 | 24 | // liquid tint vertexes 25 | // (two triangles so we can array draw) 26 | 27 | vertexArray=new Float32Array(2*6); 28 | 29 | vertexArray[0]=0; 30 | vertexArray[1]=0; 31 | vertexArray[2]=this.core.canvas.width; 32 | vertexArray[3]=0; 33 | vertexArray[4]=this.core.canvas.width; 34 | vertexArray[5]=this.core.canvas.height; 35 | 36 | vertexArray[6]=0; 37 | vertexArray[7]=0; 38 | vertexArray[8]=this.core.canvas.width; 39 | vertexArray[9]=this.core.canvas.height; 40 | vertexArray[10]=0; 41 | vertexArray[11]=this.core.canvas.height; 42 | 43 | this.vertexBuffer=gl.createBuffer(); 44 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 45 | gl.bufferData(gl.ARRAY_BUFFER,vertexArray,gl.STATIC_DRAW); 46 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 47 | 48 | return(true); 49 | } 50 | 51 | release() 52 | { 53 | this.core.gl.deleteBuffer(this.vertexBuffer); 54 | } 55 | 56 | // 57 | // draw liquid 58 | // 59 | 60 | draw() 61 | { 62 | let liquidIdx,liquid; 63 | let player=this.core.game.map.entityList.getPlayer(); 64 | let shader=this.core.shaderList.tintShader; 65 | let gl=this.core.gl; 66 | 67 | // setup tint 68 | 69 | liquidIdx=player.getUnderLiquidIndex(); 70 | if (liquidIdx===-1) return; 71 | 72 | liquid=this.core.game.map.liquidList.liquids[liquidIdx]; 73 | 74 | // draw tint 75 | 76 | shader.drawStart(); 77 | 78 | gl.blendFunc(gl.ONE,gl.SRC_COLOR); 79 | 80 | gl.uniform4f(shader.colorUniform,liquid.tint.r,liquid.tint.g,liquid.tint.b,1.0); 81 | 82 | // setup the buffers 83 | 84 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 85 | gl.vertexAttribPointer(shader.vertexPositionAttribute,2,gl.FLOAT,false,0,0); 86 | 87 | // draw the quad 88 | 89 | gl.drawArrays(gl.TRIANGLES,0,6); 90 | 91 | // remove the buffers 92 | 93 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 94 | 95 | shader.drawEnd(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/resources/code/dialog/dialog_node.js: -------------------------------------------------------------------------------- 1 | import DialogBaseClass from '../dialog/dialog_base.js'; 2 | import SetupClass from '../main/setup.js'; 3 | 4 | export default class DialogNodeClass extends DialogBaseClass 5 | { 6 | constructor(core) 7 | { 8 | super(core); 9 | 10 | this.node=null; 11 | 12 | Object.seal(this); 13 | } 14 | 15 | // 16 | // initialize and release 17 | // 18 | 19 | initialize() 20 | { 21 | let x,y; 22 | 23 | if (!super.initialize()) return(false); 24 | 25 | // tabs 26 | 27 | this.addDialogTab('node','Node',true); 28 | 29 | // dialog buttons 30 | 31 | x=(this.core.canvas.width-this.DIALOG_CONTROL_RIGHT_MARGIN)-this.DIALOG_BUTTON_SMALL_WIDTH; 32 | y=(this.core.canvas.height-this.DIALOG_CONTROL_BOTTOM_MARGIN)-this.DIALOG_BUTTON_HIGH; 33 | this.addDialogButton('ok',x,y,this.DIALOG_BUTTON_SMALL_WIDTH,this.DIALOG_BUTTON_HIGH,'Ok',true); 34 | 35 | x-=(this.DIALOG_BUTTON_SMALL_WIDTH+this.DIALOG_BUTTON_MARGIN); 36 | this.addDialogButton('cancel',x,y,this.DIALOG_BUTTON_SMALL_WIDTH,this.DIALOG_BUTTON_HIGH,'Cancel',false); 37 | 38 | // node controls 39 | 40 | x=Math.trunc(this.core.canvas.width*0.45); 41 | y=this.DIALOG_CONTROL_TOP_MARGIN; 42 | 43 | y+=this.addDialogControlText(this,'node','key',x,y,'Key (blank for none):'); 44 | this.addDialogControlCheckbox(this,'node','spawn',x,y,'Allows spawns:'); 45 | 46 | return(true); 47 | } 48 | 49 | // 50 | // dialog controls 51 | // 52 | 53 | loadDialogControls() 54 | { 55 | this.setDialogControl('key',this.node.key); 56 | this.setDialogControl('spawn',this.node.spawn); 57 | 58 | this.currentTextInputControl=this.controls.get('key'); 59 | } 60 | 61 | saveDialogControls() 62 | { 63 | this.node.key=this.getDialogControl('key'); 64 | if (this.node.key.length===0) this.node.key=null; 65 | 66 | this.node.spawn=this.getDialogControl('spawn'); 67 | } 68 | 69 | // 70 | // setup 71 | // 72 | 73 | setup(node) 74 | { 75 | this.node=node; 76 | } 77 | 78 | // 79 | // running 80 | // 81 | 82 | run() 83 | { 84 | let id=super.runInternal(); 85 | 86 | if (id==='cancel') { 87 | this.core.switchLoop(this.core.previousLoop); 88 | return(false); 89 | } 90 | 91 | if (id==='ok') { 92 | this.saveDialogControls(); 93 | this.core.switchLoop(this.core.previousLoop); 94 | return(false); 95 | } 96 | 97 | return(true); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/resources/code/utility/matrix3.js: -------------------------------------------------------------------------------- 1 | export default class Matrix4Class 2 | { 3 | constructor() 4 | { 5 | this.data=new Float32Array(9); 6 | 7 | // start with identity matrix 8 | // this is in COLUMN MAJOR order 9 | 10 | this.data[0]=1.0; 11 | this.data[4]=1.0; 12 | this.data[8]=1.0; 13 | 14 | Object.seal(this); 15 | } 16 | 17 | setIdentity() 18 | { 19 | this.data[0]=1.0; 20 | this.data[1]=0.0; 21 | this.data[2]=0.0; 22 | this.data[3]=0.0; 23 | this.data[4]=1.0; 24 | this.data[5]=0.0; 25 | this.data[6]=0.0; 26 | this.data[7]=0.0; 27 | this.data[8]=1.0; 28 | } 29 | 30 | fromArray(array) 31 | { 32 | let n; 33 | 34 | for (n=0;n!==9;n++) { 35 | this.data[n]=array[n]; 36 | } 37 | } 38 | 39 | setInvertTransposeFromMat4(mat4) 40 | { 41 | // create the inversion 42 | 43 | let m00=(mat4.data[0]*mat4.data[5])-(mat4.data[1]*mat4.data[4]); 44 | let m01=(mat4.data[0]*mat4.data[6])-(mat4.data[2]*mat4.data[4]); 45 | let m02=(mat4.data[0]*mat4.data[7])-(mat4.data[3]*mat4.data[4]); 46 | let m03=(mat4.data[1]*mat4.data[6])-(mat4.data[2]*mat4.data[5]); 47 | let m04=(mat4.data[1]*mat4.data[7])-(mat4.data[3]*mat4.data[5]); 48 | let m05=(mat4.data[2]*mat4.data[7])-(mat4.data[3]*mat4.data[6]); 49 | let m06=(mat4.data[8]*mat4.data[13])-(mat4.data[9]*mat4.data[12]); 50 | let m07=(mat4.data[8]*mat4.data[14])-(mat4.data[10]*mat4.data[12]); 51 | let m08=(mat4.data[8]*mat4.data[15])-(mat4.data[11]*mat4.data[12]); 52 | let m09=(mat4.data[9]*mat4.data[14])-(mat4.data[10]*mat4.data[13]); 53 | let m10=(mat4.data[9]*mat4.data[15])-(mat4.data[11]*mat4.data[13]); 54 | let m11=(mat4.data[10]*mat4.data[15])-(mat4.data[11]*mat4.data[14]); 55 | 56 | let det=(m00*m11)-(m01*m10)+(m02*m09)+(m03*m08)-(m04*m07)+(m05*m06); 57 | if (det!==0.0) det=1.0/det; 58 | 59 | // transpose while finishing the inversion 60 | // and dropping into 3x3 61 | 62 | this.data[0]=((mat4.data[5]*m11)-(mat4.data[6]*m10)+(mat4.data[7]*m09))*det; 63 | this.data[3]=((mat4.data[2]*m10)-(mat4.data[1]*m11)-(mat4.data[3]*m09))*det; 64 | this.data[6]=((mat4.data[13]*m05)-(mat4.data[14]*m04)+(mat4.data[15]*m03))*det; 65 | this.data[1]=((mat4.data[6]*m08)-(mat4.data[4]*m11)-(mat4.data[7]*m07))*det; 66 | this.data[4]=((mat4.data[0]*m11)-(mat4.data[2]*m08)+(mat4.data[3]*m07))*det; 67 | this.data[7]=((mat4.data[14]*m02)-(mat4.data[12]*m05)-(mat4.data[15]*m01))*det; 68 | this.data[2]=((mat4.data[4]*m10)-(mat4.data[5]*m08)+(mat4.data[7]*m06))*det; 69 | this.data[5]=((mat4.data[1]*m08)-(mat4.data[0]*m10)-(mat4.data[3]*m06))*det; 70 | this.data[8]=((mat4.data[12]*m04)-(mat4.data[13]*m02)+(mat4.data[15]*m00))*det; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/resources/code/light/light.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | import BoundClass from '../utility/bound.js'; 3 | import ColorClass from '../utility/color.js'; 4 | 5 | // 6 | // map light class 7 | // 8 | // generic class for map, particle, etc lights 9 | // 10 | 11 | export default class LightClass 12 | { 13 | constructor(position,color,intensity,exponent,ambient) 14 | { 15 | this.position=position; // should be PointClass 16 | this.eyePosition=new PointClass(0,0,0); // the eye position in the current render, set by the view 17 | this.color=color; // should be ColorClass 18 | this.intensity=intensity; 19 | this.invertIntensity=1.0/intensity; 20 | this.exponent=exponent; 21 | this.ambient=ambient; // these lights always make it into the light list, so be careful with them, usually a single light source (like sun) 22 | 23 | this.dist=0.0; // used to sort lights 24 | 25 | this.frustumXBound=new BoundClass(0,0); // set here to avoid gc 26 | this.frustumYBound=new BoundClass(0,0); 27 | this.frustumZBound=new BoundClass(0,0); 28 | 29 | Object.seal(this); 30 | } 31 | 32 | setPosition(x,y,z) 33 | { 34 | this.position.setFromValues(x,y,z); 35 | } 36 | 37 | setColor(r,g,b) 38 | { 39 | this.color.setFromValues(r,g,b); 40 | } 41 | 42 | setIntensity(intensity) 43 | { 44 | this.intensity=intensity; 45 | this.invertIntensity=1.0/intensity; 46 | } 47 | 48 | clear() 49 | { 50 | this.intensity=0.0; 51 | this.invertIntensity=0.0; 52 | } 53 | 54 | distance(pt) 55 | { 56 | return(this.position.distance(pt)); 57 | } 58 | 59 | distanceByTriplet(x,y,z) 60 | { 61 | return(this.position.distanceByTriplet(x,y,z)); 62 | } 63 | 64 | withinLightRadius(pt) 65 | { 66 | return(this.position.distance(pt)> db; 14 | 15 | private static final ObjectMapper objectMapper=new ObjectMapper(); 16 | 17 | public Storage(App app,Project project) 18 | { 19 | this.app=app; 20 | this.project=project; 21 | 22 | dbPath=app.getDataPath()+File.separator+"wsjs_"+project.getName()+"_db.json"; 23 | } 24 | 25 | public void load() throws Exception 26 | { 27 | File file; 28 | 29 | // is there a file to pick up? 30 | 31 | file=new File(dbPath); 32 | if (!file.exists()) throw new Exception("File does not exist"); 33 | 34 | // translate the db to json 35 | 36 | db=objectMapper.readValue(file,new TypeReference>>(){}); 37 | } 38 | 39 | public void save() throws Exception 40 | { 41 | File file; 42 | 43 | file=new File(dbPath); 44 | 45 | // covert to file 46 | 47 | objectMapper.writeValue(file,db); 48 | } 49 | 50 | public void start() 51 | { 52 | try { 53 | load(); 54 | app.log("Read persistant storage from disk: "+dbPath); 55 | } 56 | catch (Exception e) { 57 | app.log("Unable to load persistant storage, starting with empty: "+dbPath+" ("+e.getMessage()+")"); 58 | db=new HashMap<>(); 59 | } 60 | } 61 | 62 | public void stop() 63 | { 64 | try { 65 | save(); 66 | app.log("Wrote persistant storage to disk: "+dbPath); 67 | } 68 | catch (Exception e) { 69 | app.log("Unable to write persistant storage to disk: "+dbPath+" ("+e.getMessage()+")"); 70 | } 71 | } 72 | 73 | public void addUser(String userId) 74 | { 75 | if (!db.containsKey(userId)) db.put(userId,new HashMap<>()); 76 | } 77 | 78 | public ArrayList getUserList() 79 | { 80 | return(new ArrayList<>(db.keySet())); 81 | } 82 | 83 | public void setUserValue(String userId,String name,Object value) 84 | { 85 | HashMap userValues; 86 | 87 | userValues=db.get(userId); 88 | if (userValues!=null) userValues.put(name,value); 89 | } 90 | 91 | public Object getUserValue(String userId,String name) 92 | { 93 | HashMap userValues; 94 | 95 | userValues=db.get(userId); 96 | if (userValues==null) return(null); 97 | 98 | return(userValues.get(name)); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/resources/code/sound/sound.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | 3 | // 4 | // sound class 5 | // 6 | 7 | export default class SoundClass 8 | { 9 | constructor(core,name) 10 | { 11 | this.core=core; 12 | this.name=name; 13 | 14 | this.buffer=null; 15 | this.loaded=false; 16 | 17 | Object.seal(this); 18 | } 19 | 20 | // 21 | // initialize and release 22 | // 23 | 24 | initialize() 25 | { 26 | this.buffer=null; 27 | this.loaded=false; 28 | 29 | return(true); 30 | } 31 | 32 | release() 33 | { 34 | this.buffer=null; 35 | this.loaded=false; 36 | } 37 | 38 | // 39 | // load wav file 40 | // 41 | 42 | async loadWAV() 43 | { 44 | let resp; 45 | let url='../sounds/'+this.name+'.wav'; 46 | 47 | try { 48 | resp=await fetch(url); 49 | if (!resp.ok) return(Promise.reject('Unable to load '+url+'; '+resp.statusText)); 50 | return(await resp.arrayBuffer()); 51 | } 52 | catch (e) { 53 | return(Promise.reject('Unable to load '+url+'; '+e.message)); 54 | } 55 | } 56 | 57 | decodeAudioPromise(data) 58 | { 59 | // safari doesn't have the promise version of this 60 | 61 | return( 62 | new Promise((resolve,reject) => 63 | { 64 | this.core.audio.audioCTX.decodeAudioData(data,resolve,reject); 65 | } 66 | ) 67 | ); 68 | } 69 | 70 | async load() 71 | { 72 | let data=null; 73 | 74 | // load the wav file 75 | 76 | await this.loadWAV() 77 | .then 78 | ( 79 | // resolved 80 | 81 | value=>{ 82 | data=value; 83 | }, 84 | 85 | // rejected 86 | 87 | err=>{ 88 | console.log(err); 89 | } 90 | ); 91 | 92 | if (data==null) return(false); 93 | 94 | // decode the wav file to get an audio buffer 95 | 96 | this.buffer=null; 97 | 98 | await this.decodeAudioPromise(data) 99 | //await this.core.audio.audioCTX.decodeAudioData(data) // safari doesn't have the promise version of this 100 | .then 101 | ( 102 | // resolved 103 | 104 | decodedData=>{ 105 | this.buffer=decodedData; 106 | }, 107 | 108 | // rejected 109 | 110 | ()=>{ 111 | console.log('Unable to decode wav file '+this.name); 112 | } 113 | ); 114 | 115 | return(this.buffer!==null); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/resources/code/dialog/dialog_control_keyboard.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import TextClass from '../main/text.js'; 3 | import DialogControlBaseClass from '../dialog/dialog_control_base.js'; 4 | 5 | export default class DialogControlKeyboardClass extends DialogControlBaseClass 6 | { 7 | constructor(core,dialog,tabId,x,y,title) 8 | { 9 | super(core,dialog,tabId,x,y,title); 10 | 11 | this.CHARACTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 ._-/ <'; 12 | 13 | this.fontSize=0; 14 | this.width=0; 15 | this.height=0; 16 | 17 | this.keyText=null; 18 | 19 | Object.seal(this); 20 | } 21 | 22 | // 23 | // initialize and release 24 | // 25 | 26 | initialize() 27 | { 28 | this.fontSize=Math.trunc(this.CONTROL_HEIGHT*0.9); 29 | this.width=this.fontSize*10; 30 | this.height=this.fontSize*7; 31 | 32 | this.keyText=new TextClass(this.core,'',0,0,this.fontSize,this.core.TEXT_ALIGN_CENTER,this.widgetTopColor,1); 33 | this.keyText.initialize(); 34 | 35 | return(this.height); 36 | } 37 | 38 | release() 39 | { 40 | this.keyText.release(); 41 | } 42 | 43 | clicked() 44 | { 45 | let keyIdx=this.keyIndexIn(); 46 | this.value=(keyIdx===-1)?'':this.CHARACTERS.charAt(keyIdx); 47 | return(true); 48 | } 49 | 50 | cursorIn() 51 | { 52 | return((this.core.cursor.x>=this.x) && (this.core.cursor.x<((this.x+this.width)+this.TEXT_INPUT_WIDTH)) && (this.core.cursor.y>this.y) && (this.core.cursor.y<(this.y+this.height))); 53 | } 54 | 55 | keyIndexIn() 56 | { 57 | let x,y; 58 | 59 | x=Math.trunc((this.core.cursor.x-this.x)/this.fontSize); 60 | y=Math.trunc((this.core.cursor.y-this.y)/this.fontSize); 61 | if ((x<0) || (x>=10) || (y<0) || (y>=7)) return(-1); 62 | 63 | return((y*10)+x); 64 | } 65 | 66 | draw(highlight) 67 | { 68 | let n; 69 | let keyIdx=this.keyIndexIn(); 70 | 71 | this.core.shaderList.textShader.drawStart(); 72 | 73 | this.keyText.x=this.x+Math.trunc(this.fontSize*0.5); 74 | this.keyText.y=this.y+this.fontSize; 75 | 76 | for (n=0;n!=this.CHARACTERS.length;n++) { 77 | 78 | // highlight 79 | 80 | if ((n===keyIdx) && (highlight)) { 81 | this.keyText.color=this.highlightOutlineColor; 82 | } 83 | else { 84 | this.keyText.color=this.widgetTopColor; 85 | } 86 | 87 | // the key 88 | 89 | this.keyText.str=this.CHARACTERS.charAt(n); 90 | this.keyText.draw(); 91 | 92 | // next position 93 | 94 | if (((n+1)%10)===0) { 95 | this.keyText.x=this.x+Math.trunc(this.fontSize*0.5); 96 | this.keyText.y+=this.fontSize; 97 | } 98 | else { 99 | this.keyText.x+=this.fontSize; 100 | } 101 | } 102 | 103 | this.core.shaderList.textShader.drawEnd(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/map_sky_shader.js: -------------------------------------------------------------------------------- 1 | import CoreClass from '../main/core.js'; 2 | import ShaderClass from '../shader/shader.js'; 3 | import ShaderLightClass from '../shader/shader_light.js'; 4 | 5 | // 6 | // map shader object 7 | // 8 | 9 | export default class MapSkyShaderClass extends ShaderClass 10 | { 11 | constructor(core) 12 | { 13 | super(core); 14 | 15 | this.shaderName='map_sky'; 16 | 17 | this.vertexPositionAttribute=null; 18 | this.vertexUVAttribute=null; 19 | 20 | this.perspectiveMatrixUniform=null; 21 | this.viewMatrixUniform=null; 22 | this.transformMatrixUniform=null; 23 | 24 | this.colorUniform=null; 25 | 26 | Object.seal(this); 27 | } 28 | 29 | // 30 | // load finish 31 | // 32 | 33 | loadFinish() 34 | { 35 | let gl=this.core.gl; 36 | 37 | // setup uniforms 38 | 39 | gl.useProgram(this.program); 40 | 41 | this.vertexPositionAttribute=gl.getAttribLocation(this.program,'vertexPosition'); 42 | this.vertexUVAttribute=gl.getAttribLocation(this.program,'vertexUV'); 43 | 44 | this.perspectiveMatrixUniform=gl.getUniformLocation(this.program,'perspectiveMatrix'); 45 | this.viewMatrixUniform=gl.getUniformLocation(this.program,'viewMatrix'); 46 | this.transformMatrixUniform=gl.getUniformLocation(this.program,'transformMatrix'); 47 | 48 | this.colorUniform=gl.getUniformLocation(this.program,'color'); 49 | 50 | // these uniforms are always the same 51 | // need the unused textures as we are using a common routine that binds to them 52 | 53 | gl.uniform1i(gl.getUniformLocation(this.program,'baseTex'),0); 54 | gl.uniform1i(gl.getUniformLocation(this.program,'normalTex'),1); 55 | gl.uniform1i(gl.getUniformLocation(this.program,'metallicRoughnessTex'),2); 56 | gl.uniform1i(gl.getUniformLocation(this.program,'emissiveTex'),3); 57 | gl.uniform1i(gl.getUniformLocation(this.program,'maskTex'),4); 58 | 59 | gl.useProgram(null); 60 | } 61 | 62 | // 63 | // start/stop map shader drawing 64 | // 65 | 66 | drawStart() 67 | { 68 | let core=this.core; 69 | let gl=this.core.gl; 70 | 71 | gl.useProgram(this.program); 72 | 73 | // matrix 74 | 75 | gl.uniformMatrix4fv(this.perspectiveMatrixUniform,false,core.perspectiveMatrix.data); 76 | gl.uniformMatrix4fv(this.viewMatrixUniform,false,core.viewMatrix.data); 77 | gl.uniformMatrix4fv(this.transformMatrixUniform,false,core.game.map.sky.transformMatrix.data); // repositions/resizes/etc the sky globe 78 | 79 | // the color 80 | 81 | gl.uniform3f(this.colorUniform,core.game.map.sky.color.r,core.game.map.sky.color.g,core.game.map.sky.color.b); 82 | 83 | // enable the vertex attributes 84 | 85 | gl.enableVertexAttribArray(this.vertexPositionAttribute); 86 | gl.enableVertexAttribArray(this.vertexUVAttribute); 87 | } 88 | 89 | drawEnd() 90 | { 91 | let gl=this.core.gl; 92 | 93 | // disable vertex attributes 94 | 95 | gl.disableVertexAttribArray(this.vertexPositionAttribute); 96 | gl.disableVertexAttribArray(this.vertexUVAttribute); 97 | 98 | // no longer using shader 99 | 100 | gl.useProgram(null); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/klinksoftware/wsjs/http/HTTPListener.java: -------------------------------------------------------------------------------- 1 | package com.klinksoftware.wsjs.http; 2 | 3 | import com.klinksoftware.wsjs.application.*; 4 | 5 | import java.io.*; 6 | import java.net.*; 7 | import java.util.concurrent.*; 8 | 9 | public class HTTPListener implements Runnable 10 | { 11 | private static final String BIND_IP="0.0.0.0"; 12 | private static final int PORT=80; 13 | private static final int CONCURRENT_REQUEST=50; 14 | 15 | private final App app; 16 | private boolean running,inShutdown; 17 | private ServerSocket serverSocket; 18 | 19 | public HTTPListener(App app) 20 | { 21 | this.app=app; 22 | } 23 | 24 | // 25 | // shutdown the http listener 26 | // 27 | 28 | public void shutdown() 29 | { 30 | if (!running) return; // never started up 31 | 32 | inShutdown=true; 33 | try { serverSocket.close(); } catch(Exception e) {} // force the server socket to cancel out 34 | } 35 | 36 | // 37 | // run the listener, this waits for connections and 38 | // passes them off to the client threads 39 | // 40 | 41 | @Override 42 | public void run() 43 | { 44 | InetAddress bindAddr; 45 | Socket clientSocket; 46 | ExecutorService threadPool; 47 | 48 | // not running yet 49 | 50 | running=false; 51 | inShutdown=false; 52 | 53 | app.log("HTTP listener starting on port: "+Integer.toString(PORT)); 54 | 55 | // start the server socket 56 | 57 | try { 58 | bindAddr=InetAddress.getByName(BIND_IP); 59 | serverSocket=new ServerSocket(PORT,CONCURRENT_REQUEST,bindAddr); 60 | } 61 | catch (IOException e) { 62 | app.log("Unable to create http server socket: "+e.getMessage()); 63 | app.triggerHTTPStartUpFinished(); 64 | return; 65 | } 66 | 67 | // start the pool 68 | 69 | threadPool=Executors.newFixedThreadPool(CONCURRENT_REQUEST); 70 | 71 | // running 72 | 73 | running=true; 74 | app.triggerHTTPStartUpFinished(); 75 | 76 | app.log("HTTP listener is running"); 77 | 78 | while (!inShutdown) { 79 | try { 80 | clientSocket=serverSocket.accept(); 81 | threadPool.execute(new HTTPClient(app,clientSocket)); 82 | } 83 | catch (Exception e) 84 | { 85 | if (!inShutdown) { 86 | app.log("Error in HTTP listener accept: "+e.getMessage()); 87 | } 88 | break; 89 | } 90 | } 91 | 92 | app.log("HTTP listener shutting down"); 93 | 94 | // shut the pool 95 | 96 | threadPool.shutdown(); 97 | try { 98 | threadPool.awaitTermination(5000,TimeUnit.MILLISECONDS); 99 | } 100 | catch (InterruptedException e) { 101 | app.log("Unable to properly shutdown thread pool: "+e.getMessage()); 102 | } 103 | 104 | // shutdown the socket 105 | 106 | try { 107 | serverSocket.close(); 108 | } 109 | catch (Exception e) 110 | { 111 | app.log("Unable to properly shutdown HTTP listener socket: "+e.getMessage()); 112 | } 113 | 114 | running=false; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/resources/code/model/model.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | import Matrix4Class from '../utility/matrix4.js'; 3 | import CoreClass from '../main/core.js'; 4 | import MeshListClass from '../mesh/mesh_list.js'; 5 | import ModelSkeletonClass from '../model/model_skeleton.js'; 6 | import ImportGLTFClass from '../import/import_gltf.js'; 7 | 8 | // 9 | // model object 10 | // 11 | 12 | export default class ModelClass 13 | { 14 | constructor(core,json) 15 | { 16 | this.core=core; 17 | this.json=json; 18 | 19 | this.loaded=false; 20 | 21 | this.meshList=new MeshListClass(core); 22 | this.skeleton=new ModelSkeletonClass(core); 23 | 24 | Object.seal(this); 25 | } 26 | 27 | // 28 | // initialize and release 29 | // 30 | 31 | initialize() 32 | { 33 | if (!this.meshList.initialize()) return(false); 34 | this.skeleton.initialize(); 35 | 36 | this.loaded=false; 37 | 38 | return(true); 39 | } 40 | 41 | release() 42 | { 43 | this.meshList.release(); 44 | this.skeleton.release(); 45 | } 46 | 47 | // 48 | // async model loading 49 | // 50 | 51 | async load() 52 | { 53 | let importGLTF,bitmapList,bitmap; 54 | 55 | // no import settings, nothing to load 56 | 57 | if (this.json==null) return(true); 58 | 59 | // the model 60 | 61 | importGLTF=new ImportGLTFClass(this.core,this.json.name); 62 | bitmapList=[]; 63 | if (!(await importGLTF.import(null,this.meshList,this.skeleton,bitmapList))) return(false); 64 | 65 | this.setupBuffers(); 66 | 67 | // bitmaps 68 | 69 | for (bitmap of bitmapList) { 70 | if (!(await bitmap.load())) return(false); 71 | } 72 | 73 | this.loaded=true; 74 | 75 | return(true); 76 | } 77 | 78 | // 79 | // setup buffers 80 | // 81 | 82 | setupBuffers() 83 | { 84 | this.meshList.setupBuffers(); 85 | } 86 | 87 | // 88 | // draw model 89 | // 90 | 91 | draw(entity) 92 | { 93 | let modelEntityAlter=entity.modelEntityAlter; 94 | 95 | modelEntityAlter.setupModelMatrix(true); 96 | 97 | // models cull on entire model 98 | // instead of per mesh 99 | 100 | if (!modelEntityAlter.boundBoxInFrustum()) return; 101 | 102 | // draw the meshlist 103 | 104 | this.meshList.drawModel(modelEntityAlter); 105 | } 106 | 107 | drawDeveloper(entity,selected,drawSkeleton) 108 | { 109 | let modelEntityAlter=entity.modelEntityAlter; 110 | 111 | modelEntityAlter.setupModelMatrix(true); 112 | 113 | // models cull on entire model 114 | // instead of per mesh 115 | 116 | if (!modelEntityAlter.boundBoxInFrustum()) return; 117 | 118 | // draw the meshlist 119 | 120 | this.meshList.drawModel(modelEntityAlter); 121 | 122 | // debugging for skeletons 123 | 124 | modelEntityAlter.setupModelMatrix(false); 125 | if (drawSkeleton) modelEntityAlter.drawSkeleton(); 126 | 127 | // developer bounds drawing 128 | 129 | modelEntityAlter.drawBounds(selected); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_sky.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | import ColorClass from '../utility/color.js'; 3 | import Matrix4Class from '../utility/matrix4.js'; 4 | import GlobeClass from '../utility/globe.js'; 5 | 6 | // 7 | // sky class 8 | // 9 | 10 | export default class MapSkyClass 11 | { 12 | constructor(core) 13 | { 14 | this.core=core; 15 | 16 | this.on=false; 17 | 18 | this.offset=new PointClass(0,0,0); 19 | this.scale=new PointClass(1,1,1); 20 | this.rotate=new PointClass(0,0,0); 21 | this.color=new ColorClass(0,0,0); 22 | this.bitmap=null; 23 | 24 | this.vertexBuffer=null; 25 | this.uvBuffer=null; 26 | 27 | this.position=new PointClass(0,0,0); 28 | 29 | this.tempMatrix=new Matrix4Class(); 30 | this.transformMatrix=new Matrix4Class(); 31 | 32 | // this object has vertexes and UVs for a globe 33 | 34 | this.globe=new GlobeClass(); 35 | 36 | this.trigCount=Math.trunc(this.globe.vertexes.length/3); 37 | 38 | Object.seal(this); 39 | } 40 | 41 | // 42 | // initialize/release interface 43 | // 44 | 45 | initialize() 46 | { 47 | let gl=this.core.gl; 48 | 49 | // build the globe vertex and uv buffers 50 | 51 | this.vertexBuffer=gl.createBuffer(); 52 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 53 | gl.bufferData(gl.ARRAY_BUFFER,this.globe.vertexes,gl.STATIC_DRAW); 54 | 55 | this.uvBuffer=gl.createBuffer(); 56 | gl.bindBuffer(gl.ARRAY_BUFFER,this.uvBuffer); 57 | gl.bufferData(gl.ARRAY_BUFFER,this.globe.uvs,gl.STATIC_DRAW); 58 | 59 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 60 | 61 | return(true); 62 | } 63 | 64 | release() 65 | { 66 | let gl=this.core.gl; 67 | 68 | gl.deleteBuffer(this.vertexBuffer); 69 | gl.deleteBuffer(this.uvBuffer); 70 | } 71 | 72 | // 73 | // draw 74 | // 75 | 76 | draw() 77 | { 78 | let gl=this.core.gl; 79 | let shader=this.core.shaderList.mapSkyShader; 80 | 81 | if (!this.on) return; 82 | 83 | // set the globe transforms 84 | 85 | this.position.setFromAddPoint(this.core.game.camera.position,this.offset); 86 | 87 | this.transformMatrix.setTranslationFromPoint(this.position); 88 | this.tempMatrix.setScaleFromPoint(this.scale); 89 | this.transformMatrix.multiply(this.tempMatrix); 90 | this.tempMatrix.setRotationFromYAngle(this.rotate.y); 91 | this.transformMatrix.multiply(this.tempMatrix); 92 | 93 | // setup shader 94 | 95 | shader.drawStart(); 96 | 97 | // the sky texture 98 | 99 | this.bitmap.attach(shader); 100 | 101 | gl.disable(gl.DEPTH_TEST); 102 | 103 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 104 | gl.vertexAttribPointer(shader.vertexPositionAttribute,3,gl.FLOAT,false,0,0); 105 | 106 | gl.bindBuffer(gl.ARRAY_BUFFER,this.uvBuffer); 107 | gl.vertexAttribPointer(shader.vertexUVAttribute,2,gl.FLOAT,false,0,0); 108 | 109 | gl.drawArrays(gl.TRIANGLES,0,this.trigCount); 110 | 111 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 112 | 113 | // end shader 114 | 115 | shader.drawEnd(); 116 | 117 | gl.enable(gl.DEPTH_TEST); 118 | } 119 | 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/main/resources/code/dialog/dialog_developer.js: -------------------------------------------------------------------------------- 1 | import DialogBaseClass from '../dialog/dialog_base.js'; 2 | import SetupClass from '../main/setup.js'; 3 | 4 | export default class DialogDeveloperClass extends DialogBaseClass 5 | { 6 | constructor(core) 7 | { 8 | super(core); 9 | 10 | Object.seal(this); 11 | } 12 | 13 | // 14 | // initialize and release 15 | // 16 | 17 | initialize() 18 | { 19 | let x,y; 20 | 21 | if (!super.initialize()) return(false); 22 | 23 | // tabs 24 | 25 | this.addDialogTab('developer','Developer',true); 26 | 27 | // dialog buttons 28 | 29 | x=(this.core.canvas.width-this.DIALOG_CONTROL_RIGHT_MARGIN)-this.DIALOG_BUTTON_SMALL_WIDTH; 30 | y=(this.core.canvas.height-this.DIALOG_CONTROL_BOTTOM_MARGIN)-this.DIALOG_BUTTON_HIGH; 31 | this.addDialogButton('ok',x,y,this.DIALOG_BUTTON_SMALL_WIDTH,this.DIALOG_BUTTON_HIGH,'Ok',true); 32 | 33 | x-=(this.DIALOG_BUTTON_SMALL_WIDTH+this.DIALOG_BUTTON_MARGIN); 34 | this.addDialogButton('cancel',x,y,this.DIALOG_BUTTON_SMALL_WIDTH,this.DIALOG_BUTTON_HIGH,'Cancel',false); 35 | 36 | x=this.DIALOG_CONTROL_LEFT_MARGIN; 37 | this.addDialogButton('pathHints',x,y,this.DIALOG_BUTTON_LARGE_WIDTH,this.DIALOG_BUTTON_HIGH,'Save Path & Build Hints',false); 38 | 39 | x+=(this.DIALOG_BUTTON_LARGE_WIDTH+this.DIALOG_BUTTON_MARGIN); 40 | this.addDialogButton('shadowMaps',x,y,this.DIALOG_BUTTON_LARGE_WIDTH,this.DIALOG_BUTTON_HIGH,'Build Shadow Maps',false); 41 | 42 | // developer controls 43 | 44 | x=Math.trunc(this.core.canvas.width*0.5); 45 | y=this.DIALOG_CONTROL_TOP_MARGIN; 46 | y+=this.addDialogControlCheckbox(this,'developer','skipShadowMapNormals',x,y,'Skip Normals on Shadowmap Build:'); 47 | 48 | return(true); 49 | } 50 | 51 | // 52 | // dialog controls 53 | // 54 | 55 | loadDialogControls() 56 | { 57 | // no selected text 58 | 59 | this.currentTextInputControl=null; 60 | 61 | // the values 62 | 63 | this.setDialogControl('skipShadowMapNormals',this.core.setup.skipShadowMapNormals); 64 | } 65 | 66 | saveDialogControls() 67 | { 68 | this.core.setup.skipShadowMapNormals=this.getDialogControl('skipShadowMapNormals'); 69 | 70 | this.core.setup.save(); 71 | } 72 | 73 | // 74 | // running 75 | // 76 | 77 | run() 78 | { 79 | let id=super.runInternal(); 80 | 81 | if (id==='cancel') { 82 | this.core.switchLoop(this.core.previousLoop); 83 | return(false); 84 | } 85 | 86 | if (id==='ok') { 87 | this.saveDialogControls(); 88 | this.core.switchLoop(this.core.previousLoop); 89 | return(false); 90 | } 91 | 92 | if (id==='pathHints') { 93 | this.saveDialogControls(); 94 | this.core.developer.developerBuilders.buildPathHints(); 95 | this.core.switchLoop(this.core.previousLoop); 96 | return(false); 97 | } 98 | 99 | if (id==='shadowMaps') { 100 | this.saveDialogControls(); 101 | this.core.developer.developerBuilders.buildShadowmap(this.core.setup.skipShadowMapNormals); 102 | this.core.switchLoop(this.core.previousLoop); 103 | return(false); 104 | } 105 | 106 | return(true); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/resources/code/sound/music.js: -------------------------------------------------------------------------------- 1 | // 2 | // sound class 3 | // 4 | 5 | export default class MusicClass 6 | { 7 | constructor(core) 8 | { 9 | this.core=core; 10 | 11 | this.name=null; 12 | this.loopStart=0; 13 | this.loopEnd=0; 14 | this.autoStop=false; 15 | 16 | this.buffer=null; 17 | this.loaded=false; 18 | 19 | Object.seal(this); 20 | } 21 | 22 | // 23 | // initialize and release 24 | // 25 | 26 | initialize() 27 | { 28 | this.buffer=null; 29 | this.loaded=false; 30 | 31 | return(true); 32 | } 33 | 34 | release() 35 | { 36 | this.buffer=null; 37 | this.loaded=false; 38 | } 39 | 40 | // 41 | // set the music 42 | // 43 | 44 | setMusic(name,loopStart,loopEnd,autoStop) 45 | { 46 | this.name=name; 47 | this.loopStart=loopStart; 48 | this.loopEnd=loopEnd; 49 | this.autoStop=autoStop; 50 | } 51 | 52 | // 53 | // load mp3 file 54 | // 55 | 56 | async loadMP3() 57 | { 58 | let resp; 59 | let url='../music/'+this.name+'.mp3'; 60 | 61 | try { 62 | resp=await fetch(url); 63 | if (!resp.ok) return(Promise.reject('Unable to load '+url+'; '+resp.statusText)); 64 | return(await resp.arrayBuffer()); 65 | } 66 | catch (e) { 67 | return(Promise.reject('Unable to load '+url+'; '+e.message)); 68 | } 69 | } 70 | 71 | decodeAudioPromise(data) 72 | { 73 | // safari doesn't have the promise version of this 74 | 75 | return( 76 | new Promise((resolve,reject) => 77 | { 78 | this.core.audio.audioCTX.decodeAudioData(data,resolve,reject); 79 | } 80 | ) 81 | ); 82 | } 83 | 84 | async load() 85 | { 86 | let data=null; 87 | 88 | // any music? 89 | 90 | if (this.name===null) return(true); 91 | 92 | // load the mp3 file 93 | 94 | await this.loadMP3() 95 | .then 96 | ( 97 | // resolved 98 | 99 | value=>{ 100 | data=value; 101 | }, 102 | 103 | // rejected 104 | 105 | err=>{ 106 | console.log(err); 107 | } 108 | ); 109 | 110 | if (data==null) return(false); 111 | 112 | // decode the mp3 file to get an audio buffer 113 | 114 | this.buffer=null; 115 | 116 | await this.decodeAudioPromise(data) 117 | //await this.core.audio.audioCTX.decodeAudioData(data) // safari doesn't have the promise version of this 118 | .then 119 | ( 120 | // resolved 121 | 122 | decodedData=>{ 123 | this.buffer=decodedData; 124 | }, 125 | 126 | // rejected 127 | 128 | ()=>{ 129 | console.log('Unable to decode mp3 file '+this.name); 130 | } 131 | ); 132 | 133 | return(this.buffer!==null); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/main/resources/code/shaders/map_mesh.frag: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform lowp sampler2D baseTex; 4 | uniform lowp sampler2D normalTex; 5 | uniform lowp sampler2D metallicRoughnessTex; 6 | uniform lowp sampler2D emissiveTex; 7 | uniform lowp sampler2D maskTex; 8 | 9 | uniform bool hasMask,hasNormal,hasMetallicRoughness,hasEmissive; 10 | uniform mediump vec3 emissiveFactor; 11 | 12 | uniform lowp vec3 lightMin,lightMax; 13 | 14 | struct lightType { 15 | highp vec4 positionIntensity; 16 | mediump vec4 colorExponent; 17 | }; 18 | 19 | uniform lightType lights[24]; 20 | 21 | in highp vec3 eyeVector,eyePosition; 22 | in highp vec2 fragUV; 23 | in mediump vec3 tangentSpaceTangent,tangentSpaceBinormal,tangentSpaceNormal; 24 | 25 | out lowp vec4 outputPixel; 26 | 27 | void main(void) 28 | { 29 | lowp float att; 30 | highp float intensity,dist; 31 | highp vec3 lightVector,lightVertexVector; 32 | lowp vec3 bumpMap,metallicRoughnessMap; 33 | lowp vec4 pixel,tex; 34 | 35 | // the texture fragment 36 | 37 | tex=texture(baseTex,fragUV); 38 | 39 | // the bump map 40 | 41 | if (hasNormal) bumpMap=normalize((texture(normalTex,fragUV).rgb*2.0)-1.0); 42 | highp vec3 bumpLightVertexVector; 43 | lowp float bump=0.0; 44 | 45 | // the metallic-roughness map 46 | 47 | if (hasMetallicRoughness) metallicRoughnessMap=texture(metallicRoughnessTex,fragUV).rgb; 48 | lowp vec3 metallicHalfVector; 49 | lowp float metallic; 50 | 51 | // lights 52 | 53 | lowp vec3 lightCol=vec3(0,0,0); 54 | 55 | for (int n=0;n!=24;n++) { 56 | 57 | // if intensity = 0.0, then light is off 58 | 59 | intensity=lights[n].positionIntensity.w; 60 | if (intensity==0.0) continue; 61 | 62 | // get vector for light 63 | 64 | lightVector=lights[n].positionIntensity.xyz-eyePosition; 65 | 66 | dist=length(lightVector); 67 | if (distliquid.xBound.max)) continue; 76 | if ((pnt.yliquid.yBound.max)) continue; 77 | if ((pnt.zliquid.zBound.max)) continue; 78 | 79 | return(n); 80 | } 81 | 82 | return(-1); 83 | } 84 | 85 | getLiquidForEyePoint(pnt,eyeOffset) 86 | { 87 | this.tempEyePoint.setFromValues(pnt.x,(pnt.y+eyeOffset),pnt.z); 88 | return(this.getLiquidForPoint(this.tempEyePoint)); 89 | } 90 | 91 | // 92 | // setup liquid buffers 93 | // 94 | 95 | setupBuffers() 96 | { 97 | let n; 98 | let nLiquid=this.liquids.length; 99 | 100 | for (n=0;n!==nLiquid;n++) { 101 | this.liquids[n].setupBuffers(); 102 | } 103 | } 104 | 105 | // 106 | // draw map liquids 107 | // 108 | 109 | draw() 110 | { 111 | let n,liquid; 112 | let nLiquid=this.liquids.length; 113 | let currentBitmap; 114 | let shader=this.core.shaderList.mapMeshShader; 115 | let gl=this.core.gl; 116 | 117 | // change the blend 118 | 119 | gl.enable(gl.BLEND); 120 | gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); 121 | 122 | gl.depthMask(false); 123 | 124 | shader.drawStart(); 125 | 126 | // setup liquid drawing 127 | 128 | currentBitmap=null; 129 | 130 | // draw the liquids 131 | 132 | for (n=0;n!==nLiquid;n++) { 133 | liquid=this.liquids[n]; 134 | 135 | // skip if not in view frustum 136 | 137 | if (!this.core.game.boundBoxInFrustum(liquid.xBound,liquid.yBound,liquid.zBound)) continue; 138 | 139 | // time to change bitmap 140 | 141 | if (liquid.bitmap!==currentBitmap) { 142 | currentBitmap=liquid.bitmap; 143 | liquid.bitmap.attach(shader); 144 | } 145 | 146 | // draw the liquid 147 | 148 | liquid.updateBuffers(); 149 | liquid.bindBuffers(); 150 | liquid.draw(); 151 | } 152 | 153 | // reset the blend 154 | 155 | shader.drawEnd(); 156 | 157 | gl.disable(gl.BLEND); 158 | gl.depthMask(true); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/com/klinksoftware/wsjs/websockets/WebSocketListener.java: -------------------------------------------------------------------------------- 1 | package com.klinksoftware.wsjs.websockets; 2 | 3 | import com.klinksoftware.wsjs.application.*; 4 | 5 | import java.io.*; 6 | import java.net.*; 7 | 8 | public class WebSocketListener implements Runnable 9 | { 10 | private static final String IP="0.0.0.0"; 11 | private static final int PORT=52419; 12 | private static final int CONCURRENT_REQUEST=15; 13 | 14 | private final App app; 15 | 16 | private int nextId; 17 | private boolean running,inShutdown; 18 | private ServerSocket serverSocket; 19 | 20 | public WebSocketListener(App app) 21 | { 22 | this.app=app; 23 | } 24 | 25 | public void shutdown() 26 | { 27 | if (!running) return; // never started up 28 | 29 | inShutdown=true; 30 | try { serverSocket.close(); } catch(Exception e) {} // force the server socket to cancel out 31 | } 32 | 33 | 34 | // 35 | // run the listener, this waits for connections and 36 | // passes them off to the client threads 37 | // 38 | 39 | @Override 40 | public void run() 41 | { 42 | boolean shutdownOK; 43 | InetAddress bindAddr; 44 | Socket clientSocket; 45 | WebSocketClient client; 46 | Thread clientThread; 47 | 48 | running=false; 49 | inShutdown=false; 50 | 51 | app.log("WS listener starting on port: "+Integer.toString(PORT)); 52 | 53 | // start the server socket 54 | 55 | try { 56 | bindAddr=InetAddress.getByName(IP); 57 | serverSocket=new ServerSocket(PORT,CONCURRENT_REQUEST,bindAddr); 58 | } 59 | catch (IOException e) { 60 | app.log("Unable to create WS listener socket: "+e.getMessage()); 61 | app.triggerWebSocketStartUpFinished(); 62 | return; 63 | } 64 | 65 | running=true; 66 | app.log("WS listener is running"); 67 | app.triggerWebSocketStartUpFinished(); 68 | 69 | // accept client connections 70 | // the threads themselves add to the right 71 | // project if they succeed in logging on 72 | // (otherwise they just return and fail) 73 | 74 | while (!inShutdown) { 75 | try { 76 | clientSocket=serverSocket.accept(); 77 | 78 | client=new WebSocketClient(app,this,nextId,clientSocket); 79 | clientThread=new Thread(client,("ws_client_thread")); 80 | clientThread.start(); 81 | 82 | nextId=(nextId+1)&0x7FFF; // these are shorts, yes, this wraps and it's a TODO here 83 | } 84 | catch (Exception e) 85 | { 86 | if (!inShutdown) { 87 | app.log("Error in WS listener accept: "+e.getMessage()); 88 | } 89 | break; 90 | } 91 | } 92 | 93 | app.log("WS listener shutting down"); 94 | 95 | // shutdown the server 96 | 97 | try { 98 | serverSocket.close(); 99 | } 100 | catch (Exception e) 101 | { 102 | app.log("Unable to properly shutdown WS listener socket: "+e.getMessage()); 103 | } 104 | 105 | // shutdown any client threads and 106 | // wait for them to have cleared the list 107 | 108 | while (true) { 109 | shutdownOK=true; 110 | 111 | for (Project project:app.getProjectList().getProjects()) { 112 | shutdownOK=shutdownOK&&project.shutdownAllClients(); 113 | } 114 | 115 | if (shutdownOK) break; 116 | 117 | try { Thread.sleep(100); } catch (InterruptedException e) { break; } 118 | } 119 | 120 | running=false; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/resources/code/game/touch_button.js: -------------------------------------------------------------------------------- 1 | import BitmapInterfaceClass from '../bitmap/bitmap_interface.js'; 2 | 3 | export default class TouchButtonClass 4 | { 5 | constructor(core,bitmapPath,position,size) 6 | { 7 | this.core=core; 8 | this.bitmapPath=bitmapPath; 9 | this.position=position; 10 | this.size=size; 11 | 12 | this.id=null; 13 | 14 | this.bitmap=null; 15 | 16 | this.vertexBuffer=null; 17 | this.uvBuffer=null; 18 | this.indexBuffer=null; 19 | } 20 | 21 | async initialize() 22 | { 23 | let vertexArray,uvArray,indexArray; 24 | let gl=this.core.gl; 25 | 26 | // any bitmaps 27 | 28 | this.bitmap=new BitmapInterfaceClass(this.core,this.bitmapPath); 29 | if (!(await this.bitmap.load())) return(false); 30 | 31 | // vertex buffer 32 | 33 | vertexArray=new Float32Array(8); 34 | 35 | vertexArray[0]=vertexArray[6]=this.position.x; 36 | vertexArray[1]=vertexArray[3]=this.position.y; 37 | vertexArray[2]=vertexArray[4]=this.position.x+this.size; 38 | vertexArray[5]=vertexArray[7]=this.position.y+this.size; 39 | 40 | this.vertexBuffer=gl.createBuffer(); 41 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 42 | gl.bufferData(gl.ARRAY_BUFFER,vertexArray,gl.STATIC_DRAW); 43 | 44 | uvArray=new Float32Array(8); 45 | 46 | uvArray[0]=0; 47 | uvArray[1]=0; 48 | uvArray[2]=1; 49 | uvArray[3]=0; 50 | uvArray[4]=1; 51 | uvArray[5]=1; 52 | uvArray[6]=0; 53 | uvArray[7]=1; 54 | 55 | this.uvBuffer=gl.createBuffer(); 56 | gl.bindBuffer(gl.ARRAY_BUFFER,this.uvBuffer); 57 | gl.bufferData(gl.ARRAY_BUFFER,uvArray,gl.STATIC_DRAW); 58 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 59 | 60 | indexArray=new Uint16Array(6); 61 | 62 | indexArray[0]=0; 63 | indexArray[1]=1; 64 | indexArray[2]=2; 65 | indexArray[3]=0; 66 | indexArray[4]=2; 67 | indexArray[5]=3; 68 | 69 | this.indexBuffer=gl.createBuffer(); 70 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.indexBuffer); 71 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indexArray,gl.STATIC_DRAW); 72 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null); 73 | 74 | return(true); 75 | } 76 | 77 | release() 78 | { 79 | let gl=this.core.gl; 80 | 81 | gl.deleteBuffer(this.vertexBuffer); 82 | gl.deleteBuffer(this.uvBuffer); 83 | gl.deleteBuffer(this.indexBuffer); 84 | 85 | this.bitmap.release(); 86 | } 87 | 88 | isTouchInButton(x,y) 89 | { 90 | if ((x(this.position.x+this.size))) return(false); 91 | return((y>=this.position.y) && (y<=(this.position.y+this.size))); 92 | } 93 | 94 | touchDown(id) 95 | { 96 | this.id=id; 97 | } 98 | 99 | touchUp() 100 | { 101 | this.id=null; 102 | } 103 | 104 | draw() 105 | { 106 | let shader=this.core.shaderList.interfaceShader; 107 | let gl=this.core.gl; 108 | 109 | gl.uniform4f(shader.colorUniform,1,1,1,1); 110 | 111 | // setup the drawing 112 | 113 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 114 | gl.vertexAttribPointer(shader.vertexPositionAttribute,2,gl.FLOAT,false,0,0); 115 | 116 | gl.bindBuffer(gl.ARRAY_BUFFER,this.uvBuffer); 117 | gl.vertexAttribPointer(shader.vertexUVAttribute,2,gl.FLOAT,false,0,0); 118 | 119 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.indexBuffer); 120 | 121 | // draw the button 122 | 123 | this.bitmap.attach(); 124 | gl.drawElements(gl.TRIANGLES,6,gl.UNSIGNED_SHORT,0); 125 | 126 | // remove the buffers 127 | 128 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 129 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null); 130 | } 131 | 132 | 133 | } 134 | 135 | -------------------------------------------------------------------------------- /src/main/resources/code/utility/quaternion.js: -------------------------------------------------------------------------------- 1 | export default class QuaternionClass 2 | { 3 | constructor(x,y,z,w) 4 | { 5 | this.x=x; 6 | this.y=y; 7 | this.z=z; 8 | this.w=w; 9 | 10 | Object.seal(this); 11 | } 12 | 13 | setIdentity() 14 | { 15 | this.x=0; 16 | this.y=0; 17 | this.z=0; 18 | this.w=1; 19 | } 20 | 21 | setFromValues(x,y,z,w) 22 | { 23 | this.x=x; 24 | this.y=y; 25 | this.z=z; 26 | this.w=w; 27 | } 28 | 29 | setFromQuaternion(quat) 30 | { 31 | this.x=quat.x; 32 | this.y=quat.y; 33 | this.z=quat.z; 34 | this.w=quat.w; 35 | } 36 | 37 | setFromArray(arr) 38 | { 39 | this.x=arr[0]; 40 | this.y=arr[1]; 41 | this.z=arr[2]; 42 | this.w=arr[3]; 43 | } 44 | 45 | setFromVectorAndAngle(x,y,z,ang) 46 | { 47 | let rd=ang*(Math.PI/180.0); 48 | let sn=Math.sin(rd*0.5); 49 | 50 | this.x=sn*x; 51 | this.y=sn*y; 52 | this.z=sn*z; 53 | this.w=Math.cos(rd*0.5); 54 | } 55 | 56 | normalize() 57 | { 58 | let f=Math.sqrt((this.x*this.x)+(this.y*this.y)+(this.z*this.z)+(this.w*this.w)); 59 | if (f!==0.0) f=1.0/f; 60 | 61 | this.x*=f; 62 | this.y*=f; 63 | this.z*=f; 64 | this.w*=f; 65 | } 66 | 67 | setFromMultiply(q1,q2) 68 | { 69 | this.x=(q1.x*q2.w)+(q1.y*q2.z)-(q1.z*q2.y)+(q1.w*q2.x); 70 | this.y=(-q1.x*q2.z)+(q1.y*q2.w)+(q1.z*q2.x)+(q1.w*q2.y); 71 | this.z=(q1.x*q2.y)-(q1.y*q2.x)+(q1.z*q2.w)+(q1.w*q2.z); 72 | this.w=(-q1.x*q2.x)-(q1.y*q2.y)-(q1.z*q2.z)+(q1.w*q2.w); 73 | } 74 | 75 | multiply(quat) 76 | { 77 | let x2=(this.x*quat.w)+(this.y*quat.z)-(this.z*quat.y)+(this.w*quat.x); 78 | let y2=(-this.x*quat.z)+(this.y*quat.w)+(this.z*quat.x)+(this.w*quat.y); 79 | let z2=(this.x*quat.y)-(this.y*quat.x)+(this.z*quat.w)+(this.w*quat.z); 80 | let w2=(-this.x*quat.x)-(this.y*quat.y)-(this.z*quat.z)+(this.w*quat.w); 81 | 82 | this.x=x2; 83 | this.y=y2; 84 | this.z=z2; 85 | this.w=w2; 86 | } 87 | 88 | multiplyValues(qx,qy,qz,qw) 89 | { 90 | let x2=(this.x*qw)+(this.y*qz)-(this.z*qy)+(this.w*qx); 91 | let y2=(-this.x*qz)+(this.y*qw)+(this.z*qx)+(this.w*qy); 92 | let z2=(this.x*qy)-(this.y*qx)+(this.z*qw)+(this.w*qz); 93 | let w2=(-this.x*qx)-(this.y*qy)-(this.z*qz)+(this.w*qw); 94 | 95 | this.x=x2; 96 | this.y=y2; 97 | this.z=z2; 98 | this.w=w2; 99 | } 100 | 101 | fromMatrix(mat) 102 | { 103 | let w4; 104 | 105 | this.w=Math.sqrt(1.0+mat.data[0]+mat.data[5]+mat.data[10])/2.0; 106 | 107 | w4=this.w*4.0; 108 | this.x=(mat.data[6]-mat.data[9])/w4; 109 | this.y=(mat.data[8]-mat.data[2])/w4; 110 | this.z=(mat.data[1]-mat.data[4])/w4; 111 | } 112 | 113 | getEulerAngle(ang) 114 | { 115 | let f,fx,fy,fz,fw; 116 | let aFactor,sq; 117 | 118 | fx=this.x; 119 | fy=this.y; 120 | fz=this.z; 121 | fw=this.w; 122 | 123 | // might need to normalize 124 | 125 | if (fw>1.0) { 126 | f=Math.sqrt((fx*fx)+(fy*fy)+(fz*fz)+(fw*fw)); 127 | if (f!==0.0) f=1.0/f; 128 | 129 | fx*=f; 130 | fy*=f; 131 | fz*=f; 132 | fw*=f; 133 | } 134 | 135 | // find the angles 136 | 137 | aFactor=(2*Math.acos(fw))*(180.0/Math.PI); 138 | sq=Math.sqrt(1-(fw*fw)); 139 | if (sq<0.001) { 140 | ang.x=fx*aFactor; 141 | ang.y=fy*aFactor; 142 | ang.z=fz*aFactor; 143 | } 144 | else { 145 | ang.x=(fx/sq)*aFactor; 146 | ang.y=(fy/sq)*aFactor; 147 | ang.z=(fz/sq)*aFactor; 148 | } 149 | } 150 | 151 | copy() 152 | { 153 | return(new QuaternionClass(this.x,this.y,this.z,this.w)); 154 | } 155 | 156 | toString() 157 | { 158 | return('('+this.x+','+this.y+','+this.z+','+this.w+')'); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/resources/code/main/background.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import BitmapInterfaceClass from '../bitmap/bitmap_interface.js'; 3 | 4 | export default class InterfaceBackgroundClass 5 | { 6 | constructor(core) 7 | { 8 | this.core=core; 9 | 10 | this.titleBitmap=null; 11 | 12 | this.vertexArray=new Float32Array(2*4); // 2D, only 2 vertex coordinates 13 | 14 | this.vertexBuffer=null; 15 | this.uvBuffer=null; 16 | this.indexBuffer=null; 17 | 18 | Object.seal(this); 19 | } 20 | 21 | // 22 | // initialize and release 23 | // 24 | 25 | async initialize() 26 | { 27 | let vertexArray,uvArray,indexArray; 28 | let gl=this.core.gl; 29 | 30 | // title bitmap 31 | 32 | this.titleBitmap=new BitmapInterfaceClass(this.core,'textures/ui_title.png'); 33 | if (!(await this.titleBitmap.load())) return(false); 34 | 35 | // vertex array 36 | 37 | vertexArray=new Float32Array(8); 38 | 39 | vertexArray[0]=vertexArray[6]=0; 40 | vertexArray[1]=vertexArray[3]=0; 41 | vertexArray[2]=vertexArray[4]=this.core.canvas.width; 42 | vertexArray[5]=vertexArray[7]=this.core.canvas.height; 43 | 44 | this.vertexBuffer=gl.createBuffer(); 45 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 46 | gl.bufferData(gl.ARRAY_BUFFER,vertexArray,gl.DYNAMIC_DRAW); 47 | 48 | // index array 49 | 50 | uvArray=new Float32Array(8); 51 | 52 | uvArray[0]=0; 53 | uvArray[1]=0; 54 | uvArray[2]=1; 55 | uvArray[3]=0; 56 | uvArray[4]=1; 57 | uvArray[5]=1; 58 | uvArray[6]=0; 59 | uvArray[7]=1; 60 | 61 | this.uvBuffer=gl.createBuffer(); 62 | gl.bindBuffer(gl.ARRAY_BUFFER,this.uvBuffer); 63 | gl.bufferData(gl.ARRAY_BUFFER,uvArray,gl.STATIC_DRAW); 64 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 65 | 66 | // always drawing a single quad 67 | 68 | indexArray=new Uint16Array(6); 69 | indexArray[0]=0; 70 | indexArray[1]=1; 71 | indexArray[2]=2; 72 | indexArray[3]=0; 73 | indexArray[4]=2; 74 | indexArray[5]=3; 75 | 76 | this.indexBuffer=gl.createBuffer(); 77 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.indexBuffer); 78 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indexArray,gl.STATIC_DRAW); 79 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null); 80 | 81 | return(true); 82 | } 83 | 84 | release() 85 | { 86 | let gl=this.core.gl; 87 | 88 | gl.deleteBuffer(this.vertexBuffer); 89 | gl.deleteBuffer(this.uvBuffer); 90 | gl.deleteBuffer(this.indexBuffer); 91 | 92 | this.titleBitmap.release(); 93 | } 94 | 95 | // 96 | // drawing 97 | // 98 | 99 | draw(inDialog) 100 | { 101 | let shader=this.core.shaderList.interfaceShader; 102 | let gl=this.core.gl; 103 | 104 | shader.drawStart(); // we set these here instead of globally as UI interfaces have multiple shaders 105 | 106 | if (!inDialog) { 107 | gl.uniform4f(shader.colorUniform,1,1,1,1); 108 | } 109 | else { 110 | gl.uniform4f(shader.colorUniform,0.2,0.2,0.2,1); 111 | } 112 | 113 | // setup the drawing 114 | 115 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 116 | gl.vertexAttribPointer(shader.vertexPositionAttribute,2,gl.FLOAT,false,0,0); 117 | 118 | gl.bindBuffer(gl.ARRAY_BUFFER,this.uvBuffer); 119 | gl.vertexAttribPointer(shader.vertexUVAttribute,2,gl.FLOAT,false,0,0); 120 | 121 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.indexBuffer); 122 | 123 | // draw 124 | 125 | this.titleBitmap.attach(); 126 | gl.drawElements(gl.TRIANGLES,6,gl.UNSIGNED_SHORT,0); 127 | 128 | // remove the buffers 129 | 130 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 131 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,null); 132 | 133 | shader.drawEnd(); 134 | } 135 | 136 | } 137 | 138 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map.js: -------------------------------------------------------------------------------- 1 | import BoundClass from '../utility/bound.js'; 2 | import ImportGLTFClass from '../import/import_gltf.js'; 3 | import MeshListClass from '../mesh/mesh_list.js'; 4 | import MapLiquidListClass from '../map/map_liquid_list.js'; 5 | import MapLightListClass from '../map/map_light_list.js'; 6 | import MapEntityListClass from '../map/map_entity_list.js'; 7 | import MapEffectListClass from '../map/map_effect_list.js'; 8 | import MapCubeListClass from '../map/map_cube_list.js'; 9 | import MapSpotListClass from '../map/map_spot_list.js'; 10 | import MapPathClass from '../map/map_path.js'; 11 | import MapSkyClass from '../map/map_sky.js'; 12 | import MapBackgroundClass from '../map/map_background.js'; 13 | import MapModelListClass from '../map/map_model_list.js'; 14 | import MapSoundListClass from '../map/map_sound_list.js'; 15 | import MusicClass from '../sound/music.js'; 16 | 17 | // 18 | // map class 19 | // 20 | 21 | export default class MapClass 22 | { 23 | constructor(core,name) 24 | { 25 | this.core=core; 26 | this.name=name; 27 | 28 | this.bumpHeight=0; 29 | 30 | this.viewSetup=null; 31 | 32 | this.gravityMinValue=0; 33 | this.gravityMaxValue=0; 34 | this.gravityAcceleration=0; 35 | 36 | this.meshList=new MeshListClass(core); 37 | this.liquidList=new MapLiquidListClass(core); 38 | this.lightList=new MapLightListClass(core); 39 | this.entityList=new MapEntityListClass(core); 40 | this.effectList=new MapEffectListClass(core); 41 | this.cubeList=new MapCubeListClass(core); 42 | this.spotList=new MapSpotListClass(core); 43 | this.path=new MapPathClass(core); 44 | this.sky=new MapSkyClass(core); 45 | this.background=new MapBackgroundClass(core); 46 | this.modelList=new MapModelListClass(core); 47 | this.soundList=new MapSoundListClass(core); 48 | this.ambientSound=null; 49 | this.music=new MusicClass(core); 50 | 51 | this.hasShadowmap=false; 52 | 53 | Object.seal(this); 54 | } 55 | 56 | // 57 | // initialize and release 58 | // 59 | 60 | initialize() 61 | { 62 | if (!this.meshList.initialize()) return(false); 63 | if (!this.liquidList.initialize()) return(false); 64 | if (!this.lightList.initialize()) return(false); 65 | if (!this.entityList.initialize()) return(false); 66 | if (!this.effectList.initialize()) return(false); 67 | if (!this.cubeList.initialize()) return(false); 68 | if (!this.spotList.initialize()) return(false); 69 | if (!this.sky.initialize()) return(false); 70 | if (!this.background.initialize()) return(false); 71 | if (!this.modelList.initialize()) return(false); 72 | return(this.soundList.initialize()); 73 | } 74 | 75 | release() 76 | { 77 | this.core.audio.ambientStop(); 78 | this.core.audio.musicStop(); 79 | this.core.audio.soundStopAll(); 80 | 81 | this.meshList.release(); 82 | this.liquidList.release(); 83 | this.lightList.release(); 84 | this.entityList.release(); 85 | this.effectList.release(); 86 | this.cubeList.release(); 87 | this.spotList.release(); 88 | this.sky.release(); 89 | this.background.release(); 90 | this.modelList.release(); 91 | this.soundList.release(); 92 | } 93 | 94 | // 95 | // setup all the mesh buffers 96 | // 97 | 98 | setupBuffers() 99 | { 100 | this.meshList.setupBuffers(); 101 | this.liquidList.setupBuffers(); 102 | } 103 | 104 | // 105 | // load the map and required json caches 106 | // 107 | 108 | async loadMap(bitmapList) 109 | { 110 | let importGLTF; 111 | 112 | importGLTF=new ImportGLTFClass(this.core,this.name); 113 | if (!(await importGLTF.import(this,this.meshList,null,bitmapList))) return(false); 114 | 115 | return(true); 116 | } 117 | 118 | // 119 | // ready the map 120 | // 121 | 122 | ready() 123 | { 124 | let camera; 125 | 126 | // setup camera 127 | 128 | camera=this.core.game.camera; 129 | 130 | camera.gotoFirstPerson(); // default until player script runs 131 | camera.setViewDistance(this.viewSetup.nearZ,this.viewSetup.farZ); 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/main/resources/code/bitmap/bitmap.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | 3 | 4 | export default class BitmapClass 5 | { 6 | constructor(core) 7 | { 8 | this.core=core; 9 | 10 | this.colorURL=null; 11 | this.colorBase=null; 12 | this.normalURL=null; 13 | this.metallicRoughnessURL=null; 14 | this.emissiveURL=null; 15 | this.emissiveFactor=new ColorClass(1,1,1); 16 | this.scale=[1,1]; 17 | 18 | this.colorImage=null; 19 | this.normalImage=null; 20 | this.metallicRoughnessImage=null; 21 | this.emissiveImage=null; 22 | 23 | this.colorTexture=null; 24 | this.normalTexture=null; 25 | this.metallicRoughnessTexture=null; 26 | this.emissiveTexture=null; 27 | this.maskTexture=null; 28 | 29 | this.hasColorImageAlpha=false; 30 | 31 | this.loaded=false; 32 | 33 | // no seal, these are extended 34 | } 35 | 36 | release() 37 | { 38 | let gl=this.core.gl; 39 | 40 | if (this.colorTexture!==null) gl.deleteTexture(this.colorTexture); 41 | if (this.normalTexture!==null) gl.deleteTexture(this.normalTexture); 42 | if (this.metallicRoughnessTexture!==null) gl.deleteTexture(this.metallicRoughnessTexture); 43 | if (this.emissiveTexture!==null) gl.deleteTexture(this.emissiveTexture); 44 | if (this.maskTexture!==null) gl.deleteTexture(this.maskTexture); 45 | 46 | this.colorImage=null; 47 | this.normalImage=null; 48 | this.metallicRoughnessImage=null; 49 | this.emissiveImage=null; 50 | this.maskTexture=null; 51 | 52 | this.loaded=false; 53 | } 54 | 55 | // 56 | // bitmap utilities 57 | // 58 | 59 | checkImageForAlpha(img) 60 | { 61 | let n,nPixel,idx; 62 | let canvas,ctx,imgData,data; 63 | 64 | // draw the image onto a canvas 65 | // and then check for alpha 66 | 67 | canvas=document.createElement('canvas'); 68 | canvas.width=img.width; 69 | canvas.height=img.height; 70 | ctx=canvas.getContext('2d'); 71 | 72 | ctx.drawImage(img,0,0); 73 | 74 | imgData=ctx.getImageData(0,0,img.width,img.height); 75 | data=imgData.data; 76 | 77 | nPixel=img.width*img.height; 78 | idx=0; 79 | 80 | for (n=0;n!=nPixel;n++) { 81 | idx+=3; 82 | if (data[idx++]!==255) return(true); 83 | } 84 | 85 | return(false); 86 | } 87 | 88 | createSolidColorImage(r,g,b) 89 | { 90 | let n,idx; 91 | let canvas,ctx,imgData,data; 92 | 93 | // create a solid image 94 | // of a single color 95 | 96 | canvas=document.createElement('canvas'); 97 | canvas.width=8; 98 | canvas.height=8; 99 | ctx=canvas.getContext('2d'); 100 | 101 | imgData=ctx.getImageData(0,0,8,8); 102 | data=imgData.data; 103 | 104 | idx=0; 105 | 106 | for (n=0;n!=64;n++) { 107 | data[idx++]=r; 108 | data[idx++]=g; 109 | data[idx++]=b; 110 | data[idx++]=255; 111 | } 112 | 113 | ctx.putImageData(imgData,0,0); 114 | 115 | return(canvas); 116 | } 117 | 118 | isImagePowerOf2(image) 119 | { 120 | if (image.width!==image.height) return(false); 121 | return(Math.ceil(Math.log2(image.width))===Math.floor(Math.log2(image.width))); 122 | } 123 | 124 | loadImagePromise(url) 125 | { 126 | // special check for embedded images, everything 127 | // else needs to escape out of the current HTML folder 128 | 129 | if (!url.startsWith('data:image')) url='../'+url; 130 | 131 | // return a image load promise 132 | 133 | return( 134 | new Promise((resolve,reject) => 135 | { 136 | let img=new Image(); 137 | img.onload=()=>resolve(img); 138 | img.onerror=()=>reject(url); 139 | img.src=url; 140 | } 141 | ) 142 | ); 143 | } 144 | 145 | // 146 | // overrides 147 | // 148 | 149 | async load() 150 | { 151 | } 152 | 153 | attach() 154 | { 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/resources/code/developer/developer_sprite.js: -------------------------------------------------------------------------------- 1 | import PointClass from '../utility/point.js'; 2 | 3 | export default class DeveloperSpriteClass 4 | { 5 | constructor(core) 6 | { 7 | this.core=core; 8 | 9 | this.RADIUS=500; 10 | 11 | this.vertexes=null; 12 | 13 | this.vertexBuffer=null; 14 | this.vertexUVBuffer=null; 15 | 16 | // pre-allocates 17 | 18 | this.tempPoint=new PointClass(0,0,0); 19 | } 20 | 21 | initialize() 22 | { 23 | let uvs; 24 | let gl=this.core.gl; 25 | 26 | // gl buffers 27 | 28 | this.vertexes=new Float32Array(6*3); 29 | 30 | this.vertexBuffer=gl.createBuffer(); 31 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 32 | gl.bufferData(gl.ARRAY_BUFFER,this.vertexes,gl.DYNAMIC_DRAW); 33 | 34 | uvs=new Float32Array(6*2); 35 | uvs[0]=0.0; 36 | uvs[1]=0.0; 37 | uvs[2]=1.0; 38 | uvs[3]=0.0; 39 | uvs[4]=0.0; 40 | uvs[5]=1.0; 41 | uvs[6]=1.0; 42 | uvs[7]=0.0; 43 | uvs[8]=1.0; 44 | uvs[9]=1.0; 45 | uvs[10]=0.0; 46 | uvs[11]=1.0; 47 | 48 | this.vertexUVBuffer=gl.createBuffer(); 49 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexUVBuffer); 50 | gl.bufferData(gl.ARRAY_BUFFER,uvs,gl.STATIC_DRAW); 51 | 52 | gl.bindBuffer(gl.ARRAY_BUFFER,null); 53 | 54 | return(true); 55 | } 56 | 57 | release() 58 | { 59 | let gl=this.core.gl; 60 | 61 | gl.deleteBuffer(this.vertexBuffer); 62 | gl.deleteBuffer(this.vertexUVBuffer); 63 | } 64 | 65 | drawBillboardSprite(bitmap,position,selected) 66 | { 67 | let gl=this.core.gl; 68 | let shader=this.core.shaderList.effectShader; 69 | 70 | // sprite billboard location 71 | 72 | // top left 73 | 74 | this.tempPoint.x=this.RADIUS; 75 | this.tempPoint.y=this.RADIUS; 76 | this.tempPoint.z=0.0; 77 | this.tempPoint.matrixMultiplyIgnoreTransform(this.core.game.billboardMatrix); 78 | 79 | this.vertexes[0]=this.tempPoint.x+position.x; 80 | this.vertexes[1]=this.tempPoint.y+position.y; 81 | this.vertexes[2]=this.tempPoint.z+position.z; 82 | 83 | // top right 84 | 85 | this.tempPoint.x=-this.RADIUS; 86 | this.tempPoint.y=this.RADIUS; 87 | this.tempPoint.z=0.0; 88 | this.tempPoint.matrixMultiplyIgnoreTransform(this.core.game.billboardMatrix); 89 | 90 | this.vertexes[3]=this.vertexes[9]=this.tempPoint.x+position.x; 91 | this.vertexes[4]=this.vertexes[10]=this.tempPoint.y+position.y; 92 | this.vertexes[5]=this.vertexes[11]=this.tempPoint.z+position.z; 93 | 94 | // bottom left 95 | 96 | this.tempPoint.x=this.RADIUS; 97 | this.tempPoint.y=-this.RADIUS; 98 | this.tempPoint.z=0.0; 99 | this.tempPoint.matrixMultiplyIgnoreTransform(this.core.game.billboardMatrix); 100 | 101 | this.vertexes[6]=this.vertexes[15]=this.tempPoint.x+position.x; 102 | this.vertexes[7]=this.vertexes[16]=this.tempPoint.y+position.y; 103 | this.vertexes[8]=this.vertexes[17]=this.tempPoint.z+position.z; 104 | 105 | // bottom right 106 | 107 | this.tempPoint.x=-this.RADIUS; 108 | this.tempPoint.y=-this.RADIUS; 109 | this.tempPoint.z=0.0; 110 | this.tempPoint.matrixMultiplyIgnoreTransform(this.core.game.billboardMatrix); 111 | 112 | this.vertexes[12]=this.tempPoint.x+position.x; 113 | this.vertexes[13]=this.tempPoint.y+position.y; 114 | this.vertexes[14]=this.tempPoint.z+position.z; 115 | 116 | // draw it 117 | 118 | shader.drawStart(); 119 | 120 | gl.uniform4f(shader.colorAlphaUniform,1,1,(selected?0:1),1); 121 | 122 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); 123 | gl.bufferData(gl.ARRAY_BUFFER,this.vertexes,gl.DYNAMIC_DRAW); 124 | gl.vertexAttribPointer(shader.vertexPositionAttribute,3,gl.FLOAT,false,0,0); 125 | 126 | gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexUVBuffer); 127 | gl.vertexAttribPointer(shader.vertexUVAttribute,2,gl.FLOAT,false,0,0); 128 | 129 | bitmap.attach(shader); 130 | 131 | gl.drawArrays(gl.TRIANGLES,0,6); 132 | 133 | shader.drawEnd(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/shader_list.js: -------------------------------------------------------------------------------- 1 | import MapMeshShaderClass from '../shader/map_mesh_shader.js'; 2 | import MapMeshShadowShaderClass from '../shader/map_mesh_shadow_shader.js'; 3 | import MapSkyShaderClass from '../shader/map_sky_shader.js'; 4 | import ModelMeshShaderClass from '../shader/model_mesh_shader.js'; 5 | import DebugShaderClass from '../shader/debug_shader.js'; 6 | import EffectShaderClass from '../shader/effect_shader.js'; 7 | import InterfaceShaderClass from '../shader/interface_shader.js'; 8 | import TintShaderClass from '../shader/tint_shader.js'; 9 | import TextShaderClass from '../shader/text_shader.js'; 10 | import ColorShaderClass from '../shader/color_shader.js'; 11 | 12 | // 13 | // class to handle loading global shaders 14 | // 15 | 16 | export default class ShaderListClass 17 | { 18 | constructor(core) 19 | { 20 | this.core=core; 21 | 22 | this.mapMeshShader=null; 23 | this.mapMeshShadowShader=null; 24 | this.mapSkyShader=null; 25 | this.modelMeshShader=null; 26 | this.debugShader=null; 27 | this.effectShader=null; 28 | this.interfaceShader=null; 29 | this.tintShader=null; 30 | this.textShader=null; 31 | this.colorShader=null; 32 | 33 | Object.seal(this); 34 | } 35 | 36 | // 37 | // initialize/release 38 | // 39 | 40 | initialize() 41 | { 42 | this.mapMeshShader=null; 43 | this.mapMeshShadowShader=null; 44 | this.mapSkyShader=null; 45 | this.modelMeshShader=null; 46 | this.debugShader=null; 47 | this.effectShader=null; 48 | this.interfaceShader=null; 49 | this.tintShader=null; 50 | this.textShader=null; 51 | this.colorShader=null; 52 | } 53 | 54 | 55 | release() 56 | { 57 | if (this.mapMeshShader!==null) this.mapMeshShader.release(); 58 | if (this.mapMeshShadowShader!==null) this.mapMeshShadowShader.release(); 59 | if (this.mapSkyShader!==null) this.mapSkyShader.release(); 60 | if (this.modelMeshShader!==null) this.modelMeshShader.release(); 61 | if (this.debugShader!==null) this.debugShader.release(); 62 | if (this.effectShader!==null) this.effectShader.release(); 63 | if (this.interfaceShader!==null) this.interfaceShader.release(); 64 | if (this.tintShader!==null) this.tintShader.release(); 65 | if (this.textShader!==null) this.textShader.release(); 66 | if (this.colorShader!==null) this.colorShader.release(); 67 | } 68 | 69 | // 70 | // load shaders 71 | // 72 | 73 | async loadShaders() 74 | { 75 | this.mapMeshShader=new MapMeshShaderClass(this.core); 76 | this.mapMeshShader.initialize(); 77 | if (!(await this.mapMeshShader.load())) return(false); 78 | 79 | this.mapMeshShadowShader=new MapMeshShadowShaderClass(this.core); 80 | this.mapMeshShadowShader.initialize(); 81 | if (!(await this.mapMeshShadowShader.load())) return(false); 82 | 83 | this.mapSkyShader=new MapSkyShaderClass(this.core); 84 | this.mapSkyShader.initialize(); 85 | if (!(await this.mapSkyShader.load())) return(false); 86 | 87 | this.modelMeshShader=new ModelMeshShaderClass(this.core); 88 | this.modelMeshShader.initialize(); 89 | if (!(await this.modelMeshShader.load())) return(false); 90 | 91 | this.debugShader=new DebugShaderClass(this.core); 92 | this.debugShader.initialize(); 93 | if (!(await this.debugShader.load())) return(false); 94 | 95 | this.effectShader=new EffectShaderClass(this.core); 96 | this.effectShader.initialize(); 97 | if (!(await this.effectShader.load())) return(false); 98 | 99 | this.interfaceShader=new InterfaceShaderClass(this.core); 100 | this.interfaceShader.initialize(); 101 | if (!(await this.interfaceShader.load())) return(false); 102 | 103 | this.tintShader=new TintShaderClass(this.core); 104 | this.tintShader.initialize(); 105 | if (!(await this.tintShader.load())) return(false); 106 | 107 | this.textShader=new TextShaderClass(this.core); 108 | this.textShader.initialize(); 109 | if (!(await this.textShader.load())) return(false); 110 | 111 | this.colorShader=new ColorShaderClass(this.core); 112 | this.colorShader.initialize(); 113 | return(await this.colorShader.load()); 114 | } 115 | 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/klinksoftware/wsjs/ui/StatusCanvas.java: -------------------------------------------------------------------------------- 1 | package com.klinksoftware.wsjs.ui; 2 | 3 | import java.util.*; 4 | import java.awt.*; 5 | 6 | public class StatusCanvas extends Canvas 7 | { 8 | private static final int FONT_SIZE=14; 9 | 10 | private int valueLen, 11 | networkByteCount,maxNetworkByteCount; 12 | private float[] memValues,netValues; 13 | private Image drawBuffer; 14 | 15 | public StatusCanvas() 16 | { 17 | memValues=null; 18 | netValues=null; 19 | 20 | networkByteCount=0; 21 | maxNetworkByteCount=1; 22 | 23 | drawBuffer=null; 24 | } 25 | 26 | public void addStatusNetworkBytes(int byteCount) 27 | { 28 | networkByteCount+=byteCount; // this isn't meant to be super accurate but an estimate, but will be close to K per second, there will be drift in timers 29 | } 30 | 31 | private void drawChart(Graphics2D g2D,Color color,String title,int wid,int top,int bot,float maxValue,float[] data) 32 | { 33 | int x,y,fontWid; 34 | float fHigh; 35 | String str; 36 | 37 | // the chart 38 | 39 | g2D.setColor(color); 40 | 41 | fHigh=(float)(bot-top); 42 | 43 | for (x=0;x!=valueLen;x++) { 44 | if (data[x]==0) { 45 | y=bot-1; 46 | } 47 | else { 48 | y=bot-(int)(fHigh*(data[x]/maxValue)); 49 | if (y==bot) y=bot-1; 50 | } 51 | 52 | g2D.drawLine(x,y,x,bot); 53 | } 54 | 55 | // the label 56 | 57 | g2D.setColor(Color.BLACK); 58 | 59 | str=String.format(title,maxValue); 60 | 61 | fontWid=g2D.getFontMetrics().stringWidth(str); 62 | g2D.drawString(str,((wid-fontWid)/2),(bot-10)); 63 | } 64 | 65 | @Override 66 | public void paint(Graphics g) 67 | { 68 | int wid,high,mid; 69 | float maxValue; 70 | Graphics2D g2D; 71 | Runtime rt; 72 | 73 | // draw to back image 74 | 75 | wid=this.getWidth(); 76 | high=this.getHeight(); 77 | mid=high/2; 78 | 79 | if (drawBuffer==null) { 80 | drawBuffer=createImage(wid,high); 81 | drawBuffer.getGraphics().setFont(new Font("Arial",Font.PLAIN,FONT_SIZE)); 82 | } 83 | 84 | g2D=(Graphics2D)drawBuffer.getGraphics(); 85 | g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); 86 | 87 | // if this is the first paint, we need 88 | // to initialize the items 89 | 90 | if (memValues==null) { 91 | valueLen=super.getBounds().width; 92 | memValues=new float[valueLen]; 93 | netValues=new float[valueLen]; 94 | } 95 | 96 | // clear 97 | 98 | g2D.setColor(Color.white); 99 | g2D.fillRect(0,0,wid,high); 100 | 101 | // draw memory 102 | 103 | rt=Runtime.getRuntime(); 104 | 105 | System.arraycopy(memValues,1,memValues,0,(valueLen-1)); 106 | memValues[valueLen-1]=(float)(rt.totalMemory()-rt.freeMemory())/(1024.0f*1024.0f); 107 | 108 | maxValue=(float)(rt.maxMemory()/(1024.0f*1024.0f)); 109 | 110 | drawChart(g2D,Color.green,"Memory %,.1fM",wid,0,mid,maxValue,memValues); 111 | 112 | // draw network 113 | // we depend on this to be drawn every second, so we use that 114 | // to move the byte count forward, as this is an estimate and 115 | // writing to a variable is atomic we don't block 116 | 117 | System.arraycopy(netValues,1,netValues,0,(valueLen-1)); 118 | netValues[valueLen-1]=((float)networkByteCount)/1024.0f; 119 | if (networkByteCount>maxNetworkByteCount) maxNetworkByteCount=networkByteCount; 120 | 121 | networkByteCount=0; 122 | 123 | drawChart(g2D,Color.red,"Network %,.1fK",wid,mid,high,(((float)maxNetworkByteCount)/1024.0f),netValues); 124 | 125 | // the line 126 | 127 | g2D.setColor(Color.black); 128 | g2D.drawLine(0,mid,wid,mid); 129 | 130 | // flip the buffer 131 | 132 | g.drawImage(drawBuffer,0,0,this); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/resources/code/map/map_light_list.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import CoreClass from '../main/core.js'; 3 | 4 | // 5 | // map light list class 6 | // 7 | 8 | export default class MapLightListClass 9 | { 10 | constructor(core) 11 | { 12 | this.core=core; 13 | 14 | this.lightMin=new ColorClass(0,0,0); 15 | this.lightMax=new ColorClass(1.5,1.5,1.5); 16 | 17 | this.lights=[]; 18 | 19 | Object.seal(this); 20 | } 21 | 22 | // 23 | // initialize and release 24 | // 25 | 26 | initialize() 27 | { 28 | return(true); 29 | } 30 | 31 | release() 32 | { 33 | } 34 | 35 | // 36 | // clear lights 37 | // 38 | 39 | clear() 40 | { 41 | this.lights=[]; 42 | } 43 | 44 | // 45 | // add light to map 46 | // 47 | 48 | add(light) 49 | { 50 | this.lights.push(light); 51 | } 52 | 53 | // 54 | // check if point is in light 55 | // 56 | 57 | pointInLight(pt) 58 | { 59 | let n; 60 | let nLight=this.lights.length; 61 | 62 | for (n=0;n!==nLight;n++) { 63 | if (this.lights[n].position.distance(pt)light.dist) { 119 | idx=k; 120 | break; 121 | } 122 | } 123 | 124 | // add the light 125 | 126 | if (idx===-1) { 127 | if (this.core.game.lights.lengththis.core.MAX_LIGHT_COUNT) this.core.game.lights.pop(); 132 | } 133 | } 134 | } 135 | 136 | addLightsToViewLightsAmbients() 137 | { 138 | let n,light; 139 | let nLight; 140 | 141 | nLight=this.lights.length; 142 | 143 | for (n=0;n!==nLight;n++) { 144 | light=this.lights[n]; 145 | if (!light.ambient) continue; 146 | 147 | this.core.game.lights.splice(0,0,light); 148 | if (this.core.game.lights.length>this.core.MAX_LIGHT_COUNT) this.core.game.lights.pop(); 149 | } 150 | } 151 | 152 | // 153 | // draw all lights 154 | // this is used for developer 155 | // 156 | 157 | drawDeveloper() 158 | { 159 | let n,light; 160 | 161 | for (n=0;n!==this.lights.length;n++) { 162 | light=this.lights[n]; 163 | this.core.developer.developerSprite.drawBillboardSprite(this.core.developer.bitmapLight,light.position,this.core.developer.isLightSelected(n)); 164 | } 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /src/main/resources/code/main/menu.js: -------------------------------------------------------------------------------- 1 | import ColorClass from '../utility/color.js'; 2 | import RectClass from '../utility/rect.js'; 3 | import TextClass from '../main/text.js'; 4 | 5 | export default class MenuClass 6 | { 7 | constructor(core,items) 8 | { 9 | this.core=core; 10 | this.items=items; 11 | 12 | this.texts=[]; 13 | this.ids=[]; 14 | 15 | this.rect=new RectClass(0,0,0,0); 16 | 17 | this.currentSelectIndex=-1; 18 | 19 | Object.seal(this); 20 | } 21 | 22 | // 23 | // initialize and release 24 | // 25 | 26 | async initialize() 27 | { 28 | let n,x,y,high,margin,align,itemCount,text; 29 | let textSize=this.core.project.menuFontSize; 30 | 31 | itemCount=this.items.length; 32 | margin=Math.trunc(textSize*0.1) 33 | high=textSize+margin; 34 | 35 | // the alignment 36 | 37 | switch (this.core.project.menuAlignX) { 38 | case this.core.MENU_X_ALIGN_LEFT: 39 | x=margin; 40 | align=this.core.TEXT_ALIGN_LEFT; 41 | break; 42 | case this.core.MENU_X_ALIGN_CENTER: 43 | x=Math.trunc(this.core.canvas.width*0.5); 44 | align=this.core.TEXT_ALIGN_CENTER; 45 | break; 46 | case this.core.MENU_X_ALIGN_RIGHT: 47 | x=this.core.canvas.width-margin; 48 | align=this.core.TEXT_ALIGN_RIGHT; 49 | break; 50 | } 51 | 52 | switch (this.core.project.menuAlignY) { 53 | case this.core.MENU_Y_ALIGN_TOP: 54 | y=high+margin; 55 | break; 56 | case this.core.MENU_Y_ALIGN_CENTER: 57 | y=(Math.trunc(this.core.canvas.height*0.5)-Math.trunc((high*itemCount)*0.5))+textSize; 58 | break; 59 | case this.core.MENU_Y_ALIGN_BOTTOM: 60 | y=this.core.canvas.height-((high*(itemCount-1))+margin); 61 | break; 62 | } 63 | 64 | // the items 65 | 66 | for (n=0;n!==itemCount;n++) { 67 | text=new TextClass(this.core,this.items[n][1],x,y,textSize,align,this.core.project.menuColor,1,false); 68 | text.initialize(); 69 | this.texts.push(text); 70 | 71 | this.ids.push(this.items[n][0]); 72 | 73 | y+=high; 74 | } 75 | 76 | this.currentSelectIndex=-1; 77 | 78 | return(true); 79 | } 80 | 81 | release() 82 | { 83 | let n; 84 | 85 | for (n=0;n!==this.texts.length;n++) { 86 | this.texts[n].release(); 87 | } 88 | } 89 | 90 | // 91 | // running 92 | // 93 | 94 | cursorInItemForIndex(idx) 95 | { 96 | let text; 97 | 98 | text=this.texts[idx]; 99 | text.getStringDrawBox(this.rect); 100 | return(this.rect.pointIn(this.core.cursor.x,this.core.cursor.y)); 101 | } 102 | 103 | cursorInItem(itemId) 104 | { 105 | let n; 106 | 107 | for (n=0;n!==this.texts.length;n++) { 108 | if (this.ids[n]===itemId) return(this.cursorInItemForIndex(n)); 109 | } 110 | 111 | return(false); 112 | } 113 | 114 | // 115 | // drawing 116 | // 117 | 118 | draw() 119 | { 120 | let n,text,selectIdx; 121 | 122 | // draw the list 123 | 124 | this.core.shaderList.textShader.drawStart(); 125 | 126 | selectIdx=-1; 127 | 128 | for (n=0;n!==this.texts.length;n++) { 129 | text=this.texts[n]; 130 | 131 | if (this.cursorInItemForIndex(n)) { 132 | text.fontSize=this.core.project.menuFontSizeHighlight; 133 | text.color=this.core.project.menuColorHighlight; 134 | selectIdx=n; 135 | } 136 | else { 137 | text.fontSize=this.core.project.menuFontSize; 138 | text.color=this.core.project.menuColor; 139 | } 140 | 141 | text.draw(); 142 | } 143 | 144 | this.core.shaderList.textShader.drawEnd(); 145 | 146 | // noise is select changes 147 | 148 | if (selectIdx!==-1) { 149 | if (selectIdx!==this.currentSelectIndex) { 150 | this.core.audio.soundStartUI(this.core.title.selectSound); 151 | } 152 | } 153 | 154 | this.currentSelectIndex=selectIdx; 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/main/resources/code/light/shadowmap_load.js: -------------------------------------------------------------------------------- 1 | import BitmapShadowmapClass from '../bitmap/bitmap_shadowmap.js'; 2 | import MeshShadowmapRunClass from '../mesh/mesh_shadowmap_run.js'; 3 | 4 | export default class ShadowmapLoadClass 5 | { 6 | constructor(core) 7 | { 8 | this.core=core; 9 | } 10 | 11 | // 12 | // load shadow maps 13 | // 14 | 15 | async loadShadowmapBin() 16 | { 17 | let resp; 18 | let url='../shadowmaps/'+this.core.game.map.name+'/shadowmap.bin'; 19 | 20 | try { 21 | resp=await fetch(url); 22 | if (!resp.ok) return(Promise.reject('Unable to load '+url+'; '+resp.statusText)); 23 | return(await resp.arrayBuffer()); 24 | } 25 | catch (e) { 26 | return(Promise.reject('Unable to load '+url+'; '+e.message)); 27 | } 28 | } 29 | 30 | async load(loadBitmapList) 31 | { 32 | let n,k,nMesh,mesh,offset; 33 | let runCount,vertexCount,uvCount; 34 | let bitmapIdx,bitmaps,bitmap; 35 | let startTrigIdx,endTrigIdx; 36 | let binData,dataView; 37 | let map=this.core.game.map; 38 | 39 | // start with no shadowmap 40 | 41 | map.hasShadowmap=false; 42 | 43 | // if bin exists, then we have a shadowmap, 44 | // otherwise just ignore 45 | 46 | binData=null; 47 | 48 | await this.loadShadowmapBin() 49 | .then 50 | ( 51 | value=>{ 52 | binData=value; 53 | }, 54 | value=>{} 55 | ); 56 | 57 | if (binData===null) return(true); 58 | 59 | // translate the data 60 | 61 | dataView=new DataView(binData,0,binData.length); 62 | 63 | nMesh=dataView.getInt32(0); 64 | if (nMesh!==map.meshList.meshes.length) { 65 | console.log('Shadowmap does not match glTF, might need to be regenerated.'); 66 | return(true); 67 | } 68 | 69 | offset=4; 70 | bitmaps=new Map(); 71 | 72 | for (n=0;n!==nMesh;n++) { 73 | mesh=map.meshList.meshes[n]; 74 | 75 | // counts 76 | 77 | runCount=dataView.getInt32(offset); 78 | offset+=4; 79 | 80 | vertexCount=dataView.getInt32(offset); 81 | offset+=4; 82 | 83 | uvCount=dataView.getInt32(offset); 84 | offset+=4; 85 | 86 | // if no vertexes, than this is 87 | // a mesh we can skip 88 | 89 | if (runCount===0) { 90 | mesh.shadowmapRuns=null; 91 | mesh.vertexShadowArray=null; 92 | mesh.uvShadowArray=null; 93 | continue; 94 | } 95 | 96 | // the runs 97 | 98 | mesh.shadowmapRuns=[]; 99 | 100 | for (k=0;k!==runCount;k++) { 101 | bitmapIdx=dataView.getInt32(offset); 102 | offset+=4; 103 | 104 | startTrigIdx=dataView.getInt32(offset); 105 | offset+=4; 106 | 107 | endTrigIdx=dataView.getInt32(offset); 108 | offset+=4; 109 | 110 | bitmap=bitmaps.get(bitmapIdx); 111 | if (bitmap===undefined) { 112 | bitmap=new BitmapShadowmapClass(this.core,('shadowmaps/'+map.name+'/shadowmap_'+bitmapIdx+'.png')); 113 | loadBitmapList.push(bitmap); // list for game_load so we can load bitmaps between animation requests 114 | bitmaps.set(bitmapIdx,bitmap); // internal list so we can keep track of bitmaps we loaded 115 | } 116 | 117 | mesh.shadowmapRuns.push(new MeshShadowmapRunClass(bitmap,startTrigIdx,endTrigIdx)); 118 | } 119 | 120 | // vertex and uvs 121 | 122 | mesh.vertexShadowArray=new Float32Array(vertexCount); 123 | 124 | for (k=0;k!==vertexCount;k++) { 125 | mesh.vertexShadowArray[k]=dataView.getFloat32(offset); 126 | offset+=4; 127 | } 128 | 129 | mesh.uvShadowArray=new Float32Array(uvCount); 130 | 131 | for (k=0;k!==uvCount;k++) { 132 | mesh.uvShadowArray[k]=dataView.getFloat32(offset); 133 | offset+=4; 134 | } 135 | } 136 | 137 | // finally mark it as having a shadowmap 138 | 139 | map.hasShadowmap=true; 140 | 141 | return(true); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/resources/code/shader/shader.js: -------------------------------------------------------------------------------- 1 | // 2 | // shader base class 3 | // 4 | 5 | export default class ShaderClass 6 | { 7 | constructor(core) 8 | { 9 | this.SHADER_BASE_PATH='../../../code/shaders/'; 10 | 11 | this.core=core; 12 | 13 | this.shaderName=null; 14 | 15 | this.vertexShader=null; 16 | this.fragmentShader=null; 17 | this.program=null; 18 | 19 | // no seal, this class is extended 20 | } 21 | 22 | // 23 | // initialize/release shader 24 | // 25 | 26 | initialize() 27 | { 28 | } 29 | 30 | release() 31 | { 32 | let gl=this.core.gl; 33 | 34 | if (this.program===null) return; 35 | 36 | if (this.vertexShader!==null) { 37 | gl.detachShader(this.program,this.vertexShader); 38 | gl.deleteShader(this.vertexShader); 39 | } 40 | 41 | if (this.fragmentShader!==null) { 42 | gl.detachShader(this.program,this.fragmentShader); 43 | gl.deleteShader(this.fragmentShader); 44 | } 45 | 46 | gl.deleteProgram(this.program); 47 | 48 | this.vertexShader=null; 49 | this.fragmentShader=null; 50 | this.program=null; 51 | } 52 | 53 | // 54 | // load shader 55 | // 56 | 57 | async loadShader(url) 58 | { 59 | let resp; 60 | 61 | try { 62 | resp=await fetch(url); 63 | if (!resp.ok) return(Promise.reject('Unable to load '+url+'; '+resp.statusText)); 64 | return(await resp.text()); 65 | } 66 | catch (e) { 67 | return(Promise.reject('Unable to load '+url+'; '+e.message)); 68 | } 69 | } 70 | 71 | async load() 72 | { 73 | let vertexShaderSource,fragmentShaderSource; 74 | let gl=this.core.gl; 75 | 76 | // load vertex shader 77 | 78 | vertexShaderSource=null; 79 | 80 | await this.loadShader(this.SHADER_BASE_PATH+this.shaderName+'.vert') 81 | .then 82 | ( 83 | // resolved 84 | 85 | value=>{ 86 | vertexShaderSource=value; 87 | }, 88 | 89 | // rejected 90 | 91 | value=>{ 92 | console.log(value); 93 | } 94 | ); 95 | 96 | if (vertexShaderSource===null) return(false); 97 | 98 | // load fragment shader 99 | 100 | fragmentShaderSource=null; 101 | 102 | await this.loadShader(this.SHADER_BASE_PATH+this.shaderName+'.frag') 103 | .then 104 | ( 105 | // resolved 106 | 107 | value=>{ 108 | fragmentShaderSource=value; 109 | }, 110 | 111 | // rejected 112 | 113 | value=>{ 114 | console.log(value); 115 | } 116 | ); 117 | 118 | if (fragmentShaderSource===null) return(false); 119 | 120 | // compile vertex shader 121 | 122 | this.vertexShader=gl.createShader(gl.VERTEX_SHADER); 123 | gl.shaderSource(this.vertexShader,vertexShaderSource); 124 | gl.compileShader(this.vertexShader); 125 | 126 | if (!gl.getShaderParameter(this.vertexShader,gl.COMPILE_STATUS)) { 127 | this.writeError(this.shaderName,"vertex",gl.getShaderInfoLog(this.vertexShader)); 128 | this.release(); 129 | return(false); 130 | } 131 | 132 | // compile fragment shader 133 | 134 | this.fragmentShader=gl.createShader(gl.FRAGMENT_SHADER); 135 | gl.shaderSource(this.fragmentShader,fragmentShaderSource); 136 | gl.compileShader(this.fragmentShader); 137 | 138 | if (!gl.getShaderParameter(this.fragmentShader,gl.COMPILE_STATUS)) { 139 | this.writeError(this.shaderName,"fragment",gl.getShaderInfoLog(this.fragmentShader)); 140 | this.release(); 141 | return(false); 142 | } 143 | 144 | // compile the program 145 | 146 | this.program=gl.createProgram(); 147 | gl.attachShader(this.program,this.vertexShader); 148 | gl.attachShader(this.program,this.fragmentShader); 149 | gl.linkProgram(this.program); 150 | 151 | if (!gl.getProgramParameter(this.program,gl.LINK_STATUS)) { 152 | this.writeError(name,"program",gl.getProgramInfoLog(this.program)); 153 | this.release(); 154 | return(false); 155 | } 156 | 157 | // do the variables and final setup 158 | 159 | this.loadFinish(); 160 | 161 | return(true); 162 | } 163 | 164 | loadFinish() 165 | { 166 | } 167 | 168 | // 169 | // shader errors 170 | // 171 | 172 | writeError(name,nameType,errStr) 173 | { 174 | console.log('Shader Error: '+name+'('+nameType+')'); 175 | console.log('-----------------------------------------'); 176 | console.log(errStr); 177 | } 178 | 179 | } 180 | 181 | --------------------------------------------------------------------------------