├── README ├── dots ├── csg.js ├── dev.js ├── favicon.ico ├── game.js ├── glMatrix-0.9.5.min.js ├── index.html ├── meshes.js ├── package.json ├── particles.js ├── physics.js ├── reference.txt ├── server.js ├── shaders.js ├── tedge.js ├── textures.js ├── thick.png └── thin.png ├── ducks ├── convert.html ├── converth.html ├── duck.js ├── duck.zip ├── game.js ├── glMatrix-0.9.5.min.js ├── gun.h ├── index.html ├── meshes.js ├── node_modules │ └── socket.io │ │ ├── .gitignore │ │ ├── .npmignore │ │ ├── History.md │ │ ├── Makefile │ │ ├── Readme.md │ │ ├── index.js │ │ ├── lib │ │ ├── logger.js │ │ ├── manager.js │ │ ├── namespace.js │ │ ├── parser.js │ │ ├── socket.io.js │ │ ├── socket.js │ │ ├── store.js │ │ ├── stores │ │ │ ├── memory.js │ │ │ └── redis.js │ │ ├── transport.js │ │ ├── transports │ │ │ ├── flashsocket.js │ │ │ ├── htmlfile.js │ │ │ ├── http-polling.js │ │ │ ├── http.js │ │ │ ├── index.js │ │ │ ├── jsonp-polling.js │ │ │ ├── websocket.js │ │ │ └── xhr-polling.js │ │ └── util.js │ │ └── package.json ├── physics.js ├── server.js ├── tedge.js └── thick.png ├── rift ├── build-docs.bat ├── csg.js ├── dev.js ├── game.js ├── glMatrix-0.9.5.min.js ├── ideas.txt ├── index.html ├── meshes.js ├── model.html ├── particles.js ├── physics.js ├── reference.txt ├── release │ ├── compiled.js │ ├── index.html │ └── introspection.mp3 ├── shaders.js ├── tedge notes.txt ├── tedge.js ├── texture.html ├── textures.js └── tools │ └── documentation.js ├── space ├── dev.js ├── game.js ├── glMatrix-0.9.5.min.js ├── lab │ ├── advanced.html │ ├── compiled.html │ ├── dev.js │ ├── game.js │ ├── glMatrix-0.9.5.min.js │ ├── index.html │ ├── meshes.js │ ├── noise.txt │ ├── physics.js │ ├── print.html │ ├── shaders.js │ ├── tedge.js │ ├── tedge.js.bak │ └── tunnel.html ├── meshes.js ├── physics.js ├── shaders.js ├── stars.html └── tedge.js └── tanks ├── favicon.ico ├── game.js ├── glMatrix-0.9.5.min.js ├── index.html ├── link ├── meshes.js ├── package.json ├── server.js ├── singleplayer.html ├── tedge.js ├── thick.png └── thin.png /README: -------------------------------------------------------------------------------- 1 | A collection of 3D JavaScript games using WebGL. 2 | 3 | Developed by Team Duck. -------------------------------------------------------------------------------- /dots/csg.js: -------------------------------------------------------------------------------- 1 | // constructive solid geometry -- needs some work 2 | // todo: support UVs 3 | // check intersection direction 4 | 5 | function LineIntersection(lineVertex, lineVector, pointA, pointB) 6 | { 7 | debugger; 8 | var c = VecSub(lineVertex, pointA); 9 | var v = VecSub(pointB, pointA); 10 | var d = VecLength(v); 11 | var t = VecDot(v, c); 12 | var q = VecAdd(pointA, VecScale(v, t/d)); 13 | var vq = VecSub(q, lineVertex); 14 | var r = VecLength(vq) / VecDot(q, vq); 15 | var F = VecAdd(lineVertex, VecScale(lineVector, r)); 16 | return F; 17 | //var r = VecDot(v, q); 18 | //t = (t + r) / d; 19 | // if 0 <= t <= d, then it's on the segment; otherwise it's off in space 20 | //if (t >= 0 && t <= d) 21 | // return VecAdd(pointA, VecScale(v, t / d)); 22 | return; 23 | } 24 | 25 | function LineOverlap(segmentA, segmentB, lineVector) 26 | { 27 | var aVector = VecSub(segmentA[1], segmentA[0]); 28 | var bVector = VecSub(segmentB[1], segmentB[0]); 29 | if (VecDot(aVector, lineVector) < 0) { 30 | var swap = segmentA[0]; 31 | segmentA[0] = segmentA[1]; 32 | segmentA[1] = swap; 33 | } 34 | if (VecDot(bVector, lineVector) < 0) { 35 | var swap = segmentB[0]; 36 | segmentB[0] = segmentB[1]; 37 | segmentB[1] = swap; 38 | } 39 | // a and b are both facing the same direction 40 | var q; 41 | if (VecDot(segmentA[0], lineVector) >= VecDot(segmentB[0], lineVector)) { 42 | q = segmentA[0]; 43 | } else { 44 | q = segmentB[0]; 45 | } 46 | 47 | var r; 48 | if (VecDot(segmentA[1], lineVector) <= VecDot(segmentB[1], lineVector)) { 49 | r = segmentA[1]; 50 | } else { 51 | r = segmentB[1]; 52 | } 53 | 54 | if (VecDot(VecSub(r, q), lineVector) > 0) 55 | return [q, r]; 56 | return; 57 | } 58 | 59 | function CSG() { 60 | var csg = { 61 | mesh: {vertices: [], normals: [], uvs: [], count: 0}, 62 | 63 | append: function(subMesh, transform, uvTransform) { 64 | if (transform) { 65 | subMesh = CloneMesh(subMesh); 66 | subMesh = TransformMesh(subMesh, transform); 67 | if (uvTransform) 68 | TransformMeshUVs(subMesh, uvTransform); 69 | } 70 | 71 | csg.mesh.count += subMesh.count; 72 | csg.mesh.vertices = csg.mesh.vertices.concat(subMesh.vertices); 73 | if (subMesh.normals) 74 | csg.mesh.normals = csg.mesh.normals.concat(subMesh.normals); 75 | if (subMesh.uvs) 76 | csg.mesh.uvs = csg.mesh.uvs.concat(subMesh.uvs); 77 | }, 78 | 79 | subtract: function(subMesh, transform) { 80 | if (transform) { 81 | subMesh = CloneMesh(subMesh); 82 | subMesh = TransformMesh(subMesh, transform); 83 | } 84 | 85 | var mesh = csg.mesh; 86 | var culled = {count: 0, vertices: [], normals: [], uvs: []} 87 | var intersection = false; 88 | 89 | // go through each triangle in the mesh 90 | for (var i = 0; i < mesh.vertices.length; i+=9) 91 | { 92 | var segments = []; var linkedVertices = []; 93 | var linkedNormals = []; 94 | // go through each triangle of the subtrahend 95 | for (var j = 0; j < subMesh.vertices.length; j+=9) 96 | { 97 | // check if the triangles collide and find the overlapping segment 98 | 99 | // find the line of the intersection of the planes 100 | var mNormal = [mesh.normals[i], mesh.normals[i+1], mesh.normals[i+2]]; 101 | var sNormal = [subMesh.normals[j], subMesh.normals[j+1], subMesh.normals[j+2]]; 102 | var lineVector = VecCross(mNormal, sNormal); 103 | if (VecLengthSqr(lineVector) < 0.5) continue; 104 | 105 | var lineVertex; 106 | var mAnchor = Vector3(mesh.vertices[i], mesh.vertices[i+1], mesh.vertices[i+2]); 107 | var sAnchor = Vector3(subMesh.vertices[j], subMesh.vertices[j+1], subMesh.vertices[j+2]); 108 | lineVertex = VecDot(VecSub(mAnchor, sAnchor), mNormal); 109 | lineVertex = VecAdd(VecScale(mNormal, lineVertex), sAnchor); 110 | 111 | // clip segment along mTriangle 112 | var mSegment = []; var mK; 113 | for (var k = 0; k < 3; k++) { 114 | var m0 = Vector3(mesh.vertices[i+k*3], mesh.vertices[i+k*3+1], mesh.vertices[i+k*3+2]); 115 | var m1 = Vector3(mesh.vertices[i+((k+1)%3)*3], 116 | mesh.vertices[i+((k+1)%3)*3+1], 117 | mesh.vertices[i+((k+1)%3)*3+2]); 118 | var mV = LineIntersection(lineVertex, lineVector, m0, m1); 119 | if (mV) { 120 | mSegment.push(mV); 121 | } else { 122 | mK = k; 123 | } 124 | } 125 | if (mSegment.length < 2) continue; 126 | 127 | // clip segment along sTriangle 128 | var sSegment = []; 129 | for (var k = 0; k < 3; k++) { 130 | var s0 = Vector3(subMesh.vertices[j+k*3], subMesh.vertices[j+k*3+1], subMesh.vertices[j+k*3+2]); 131 | var s1 = Vector3(subMesh.vertices[j+((k+1)%3)*3], 132 | subMesh.vertices[j+((k+1)%3)*3+1], 133 | subMesh.vertices[j+((k+1)%3)*3+2]); 134 | var sV = LineIntersection(lineVertex, lineVector, s0, s1); 135 | if (sV) { 136 | sSegment.push(sV); 137 | } 138 | } 139 | if (sSegment.length < 2) continue; 140 | 141 | var segment = LineOverlap(mSegment, sSegment, lineVector); 142 | if (segment) { 143 | segments.push(segment); 144 | linkedVertices.push([ 145 | Vector3(mesh.vertices[i+mK*3], 146 | mesh.vertices[i+mK*3+1], 147 | mesh.vertices[i+mK*3+2]), 148 | Vector3(mesh.vertices[i+((mK+1)%3)*3], 149 | mesh.vertices[i+((mK+1)%3)*3+1], 150 | mesh.vertices[i+((mK+1)%3)*3+2]) 151 | ]); 152 | linkedNormals.push(mNormal); 153 | } 154 | } 155 | if (segments.length > 0) { 156 | // create new faces 157 | intersection = true; 158 | for (var k = 0; k < segments.length; k++) { 159 | culled.count += 2; 160 | culled.vertices = culled.vertices.concat(segments[k][0]); 161 | culled.vertices = culled.vertices.concat(segments[k][1]); 162 | culled.vertices = culled.vertices.concat(linkedVertices[k][0]); 163 | culled.vertices = culled.vertices.concat(segments[k][1]); 164 | culled.vertices = culled.vertices.concat(linkedVertices[k][1]); 165 | culled.vertices = culled.vertices.concat(linkedVertices[k][0]); 166 | for (var q = 0; q < 6; q++) 167 | culled.normals = culled.normals.concat(linkedNormals[k]); 168 | } 169 | } else { 170 | // no intersection, so keep this triangle 171 | culled.count++; 172 | for (var k = 0; k < 9; k++) { 173 | culled.vertices.push(mesh.vertices[i+k]); 174 | culled.normals.push(mesh.normals[i+k]); 175 | } 176 | if (mesh.uvs) { 177 | var ui = i*2/3; 178 | for (var k = 0; k < 6; k++) { 179 | culled.uvs.push(mesh.uvs[ui+k]); 180 | } 181 | } 182 | } 183 | } 184 | 185 | csg.mesh = culled; 186 | csg.mesh.uvs = []; 187 | }, 188 | 189 | compile: function(transform) { 190 | var mesh = {vertices: csg.mesh.vertices, count: csg.mesh.count}; 191 | if (csg.mesh.normals.length) mesh.normals = csg.mesh.normals; 192 | if (csg.mesh.uvs.length) mesh.uvs = csg.mesh.uvs; 193 | if (transform) 194 | mesh = TransformMesh(mesh, transform); 195 | return BufferMesh(mesh); 196 | } 197 | }; 198 | return csg; 199 | } 200 | -------------------------------------------------------------------------------- /dots/dev.js: -------------------------------------------------------------------------------- 1 | function TextSprite(text, style, font, x, y) { 2 | if (style === undefined) style = "white"; 3 | if (font === undefined) font = "32px lucida console"; 4 | if (x === undefined) x = 0; 5 | if (y === undefined) y = 0; 6 | 7 | var t = {"x": x, "y": y}; 8 | var bitmap; 9 | var size; 10 | var texture = gl.createTexture(); 11 | var mesh = BufferMesh(SQUARE_MESH); 12 | 13 | 14 | context.clearRect(0, 0, canvas2D.width, canvas2D.height); 15 | context.fillStyle = style; 16 | context.font = font; 17 | context.textBaseline = "top"; 18 | context.fillText(text, 0, 0); 19 | size = context.measureText(text); 20 | t.size = size; 21 | var width = 1; while (width < size.width) width *= 2; 22 | bitmap = context.getImageData(0, 0, width, width); 23 | StoreTexture(texture, bitmap); 24 | 25 | var identity = Mat4List(Matrix4()); 26 | var screen = Matrix4(); 27 | screen = Mat4Mult(screen, Mat4Translate([1, -1, 0])); 28 | screen = Mat4Mult(screen, Mat4Scale(width/2, width/2, 1)); 29 | screen = Mat4Mult(screen, Mat4Translate([-canvas.width/2, -canvas.height/2, 0])); 30 | screen = Mat4Mult(screen, Mat4Scale(2/canvas.width, 2/canvas.height, 1)); 31 | screen = Mat4List(screen); 32 | 33 | if (x < 0) t.x = canvas.width - size.width + t.x; 34 | 35 | t.render = function (mtx) { 36 | // set up texture shader 37 | TEX_SHADER.enable(); 38 | 39 | // orthogonal 40 | gl.uniformMatrix4fv(TEX_SHADER.pMatrix, false, identity); 41 | gl.uniformMatrix4fv(TEX_SHADER.vMatrix, false, screen); 42 | 43 | // blending for transparency 44 | gl.enable(gl.BLEND); 45 | gl.blendFunc(gl.SRC_ALPHA, gl.ONE); 46 | gl.depthMask(false); 47 | 48 | // bind texture 49 | gl.activeTexture(gl.TEXTURE0); 50 | gl.bindTexture(gl.TEXTURE_2D, texture); 51 | gl.uniform1i(TEX_SHADER.samplerUniform, 0); 52 | DrawMesh(mesh, Mat4List(Mat4Translate([2*t.x/width, 2*(canvas.height - t.y)/width, 0])), TEX_SHADER); 53 | 54 | gl.disable(gl.BLEND); 55 | gl.depthMask(true); 56 | 57 | // draw 58 | gl.uniformMatrix4fv(TEX_SHADER.pMatrix, false, pMatrix); 59 | gl.uniformMatrix4fv(TEX_SHADER.vMatrix, false, vMatrix); 60 | TEX_SHADER.disable(); 61 | STD_SHADER.enable(); 62 | } 63 | return t; 64 | } 65 | -------------------------------------------------------------------------------- /dots/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamduck/gametube/40e8ea4b963148dadadea1f7d28f6d10e0a07953/dots/favicon.ico -------------------------------------------------------------------------------- /dots/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | DOTS 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 24 | 25 | 26 | 27 | 28 |