/// /// const BYTES_PER_FLOAT = 4; /** * Initializes a new circle object for the WebGL context. * * @param {WebGLRenderingContext} pGl * @param {number} pRadius * @param {number} pSegments * @param {Array} pColorList * @param {vec2} pInitialPosition * @param {number} pMass */ function circle(pGl, pRadius, pSegments, pColorList, pInitialPosition, pMass) { const lBuffer = pGl.createBuffer(); pGl.bindBuffer(pGl.ARRAY_BUFFER, lBuffer); var lBufferedData = []; vertexCount = 0; const lAngleIncrements = (360.0 / pSegments) * (Math.PI / 180.0); for (let lSegIdx = 0; lSegIdx < pSegments; lSegIdx++) { const lAngle = lAngleIncrements * lSegIdx, lNextAngle = lAngleIncrements * (lSegIdx + 1), lColorIndex = Math.floor(pColorList.length * (lSegIdx / pSegments)), lColor = pColorList[lColorIndex]; // TODO: Calculate which one to use lBufferedData = lBufferedData.concat([ 0, 0, lColor.x, lColor.y, lColor.z, lColor.w, pRadius * Math.sin(lAngle), pRadius * Math.cos(lAngle), lColor.x, lColor.y, lColor.z, lColor.w, pRadius * Math.sin(lNextAngle), pRadius * Math.cos(lNextAngle), lColor.x, lColor.y, lColor.z, lColor.w ]); vertexCount += 3; } pGl.bufferData(pGl.ARRAY_BUFFER, new Float32Array(lBufferedData), pGl.STATIC_DRAW) pGl.bindBuffer(pGl.ARRAY_BUFFER, undefined); return { buffer: lBuffer, vertexCount: vertexCount, prevPos: vec2(), position: pInitialPosition || vec2(), prevVelocity: vec2(), velocity: vec2(), force: vec2(), torque: 0, mass: pMass === undefined ? 1 : pMass, rotationVelocity: 0, rotationRadians: 0, model: translateMatrix(mat4(), pInitialPosition ? pInitialPosition.x : 0, pInitialPosition ? pInitialPosition.y : 0, 0), radius: pRadius }; } function renderCircle(pGl, pProgramInfo, pCircle) { pGl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, pCircle.model); pGl.bindBuffer(pGl.ARRAY_BUFFER, pCircle.buffer); { pGl.enableVertexAttribArray(pProgramInfo.attributeLocations.position); pGl.vertexAttribPointer(pProgramInfo.attributeLocations.position, 2, pGl.FLOAT, false, BYTES_PER_FLOAT * 6, 0); pGl.enableVertexAttribArray(pProgramInfo.attributeLocations.color); pGl.vertexAttribPointer(pProgramInfo.attributeLocations.color, 4, pGl.FLOAT, false, BYTES_PER_FLOAT * 6, BYTES_PER_FLOAT * 2); } pGl.drawArrays(pGl.TRIANGLE_STRIP, 0, pCircle.vertexCount); } function getMomentOfInertia(pCircle) { return (Math.PI * Math.pow(pCircle.radius, 4)) / 4; } function doCirclesIntersect(pFirst, pSecond) { const lDistanceBetween = Math.pow(pFirst.position.x - pSecond.position.x, 2) + Math.pow(pFirst.position.y - pSecond.position.y, 2) return lDistanceBetween <= Math.pow(pFirst.radius + pSecond.radius, 2); } /** * Returns intersection information about the intersecting circles. * * Warning! Only use this if doCirclesIntersect returned true for these circles. * * @param {circle} pFirst * @param {circle} pSecond */ function getIntersectionDataForCircles(pFirst, pSecond) { // The collision normal is simply the difference between the two current positions const lCollisionNormal = normalize2(subVec2(pFirst.position, pSecond.position)); const lCollisionPoint = vec2( ((pFirst.position.x * pSecond.radius) + (pSecond.position.x * pFirst.radius)) / (pFirst.radius + pSecond.radius), ((pFirst.position.y * pSecond.radius) + (pSecond.position.y * pFirst.radius)) / (pFirst.radius + pSecond.radius) ); return { relativeVelocity: subVec2(pFirst.velocity, pSecond.velocity), collisionNormal: lCollisionNormal, //firstPointOfApplication: addVec2(scaleVec2(normalize2(pFirst.velocity), pFirst.radius), pFirst.position), //secondPointOfApplication: addVec2(scaleVec2(normalize2(pSecond.velocity), pSecond.radius), pSecond.position) firstPointOfApplication: subVec2(lCollisionPoint, pFirst.position), secondPointOfApplication: subVec2(lCollisionPoint, pSecond.position) } } function freeCircle(pGl, pCircle) { pGl.deleteBuffer(pCircle.buffer); }