Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serving pen and touch events #87

Merged
merged 36 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
95aa1eb
feat: new listening mechanism to be tested
owulveryck Nov 15, 2023
9d33525
feat: preparing the websocket
owulveryck Nov 15, 2023
1f04284
fix: websocket ok
owulveryck Nov 15, 2023
5878244
chore: housekeeping
owulveryck Nov 15, 2023
45c5d86
feat: pointer
owulveryck Nov 15, 2023
3d62145
fix: less events
owulveryck Nov 15, 2023
03fdb7c
feat(wip): pointer in orientation
owulveryck Nov 15, 2023
fc8b3ca
feat: control over the pointer
owulveryck Nov 15, 2023
7910d7e
feat: overlay
owulveryck Nov 15, 2023
a4f45f9
Merge branch 'overlay' into eventSender
owulveryck Nov 15, 2023
038b14d
fix
owulveryck Nov 15, 2023
021ccdd
feat: event is a worker now
owulveryck Nov 16, 2023
193846d
fix: major improvements
owulveryck Nov 17, 2023
5bc1daf
test: webgl
owulveryck Nov 17, 2023
08afb79
feat: image ok
owulveryck Nov 17, 2023
4de18b2
feat: webgl and rotation ok
owulveryck Nov 17, 2023
81d4f9e
feat: should work
owulveryck Nov 17, 2023
c4047b4
oups
owulveryck Nov 17, 2023
fe7bc19
fix errors and rotation
owulveryck Nov 17, 2023
41ee15d
feat: using the native binary encoding for perfoemances
owulveryck Nov 18, 2023
4e1e7b5
feat: housekeeping
owulveryck Nov 18, 2023
72002e1
feat: add a proper termination of the worker
owulveryck Nov 18, 2023
ac910ed
feat: add a done
owulveryck Nov 18, 2023
9d72d62
chore: lint
owulveryck Nov 19, 2023
eb5db2f
feat: content type and test
owulveryck Nov 19, 2023
5335413
feat: flush
owulveryck Nov 19, 2023
5210b48
fix: leak in the pubsub on reload
owulveryck Nov 19, 2023
8a678fa
fix: dealing with timeout
owulveryck Nov 19, 2023
5ff180e
feat: lint
owulveryck Nov 19, 2023
1b92a17
feat: lint
owulveryck Nov 19, 2023
b41dbf2
feat: rotate
owulveryck Nov 20, 2023
d7edab2
fix(wip): rotation
owulveryck Nov 20, 2023
a6ad70e
fix: pointer in landscape
owulveryck Nov 20, 2023
baad0cf
feat: add query parameters
owulveryck Nov 20, 2023
707dd5c
chore: housekeeping
owulveryck Nov 20, 2023
d5ec74b
chore
owulveryck Nov 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 17 additions & 59 deletions client/canvasHandling.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
function resizeVisibleCanvas() {
var container = document.getElementById("container");

if (rotate) {
if (portrait) {
var aspectRatio = 1404 / 1872;
} else {
var aspectRatio = 1872 / 1404;
Expand All @@ -14,70 +14,28 @@ function resizeVisibleCanvas() {
var containerAspectRatio = containerWidth / containerHeight;

if (containerAspectRatio > aspectRatio) {
// Canvas is relatively wider than container
//canvas.style.width = '100vw';
//canvas.style.width = '100%';
//canvas.style.height = 'auto';
visibleCanvas.style.width = containerHeight * aspectRatio + "px";
visibleCanvas.style.height = containerHeight + "px";
} else {
// Canvas is relatively taller than container
//canvas.style.width = 'auto';
//canvas.style.height = '100vh';
//canvas.style.height = '100%';
visibleCanvas.style.width = containerWidth + "px";
visibleCanvas.style.height = containerWidth / aspectRatio + "px";
}
renderCanvas(rawCanvas,visibleCanvas);
canvasPresent.style.width = visibleCanvas.style.width;
canvasPresent.style.height = visibleCanvas.style.height;
}
function waiting(message) {
var ctx = visibleCanvas.getContext("2d");
ctx.fillStyle = '#666666';
ctx.fillRect(0, 0, visibleCanvas.width, visibleCanvas.height);

var fontSize = 48;
var fontFamily = "Arial";
var textColor = "red";

// Calculate the text dimensions
ctx.font = fontSize + "px " + fontFamily;
var textWidth = ctx.measureText(message).width;
var textHeight = fontSize;

// Calculate the center position
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;

// Set the fill style and align the text in the center
ctx.fillStyle = textColor;
ctx.textAlign = "center";
ctx.textBaseline = "middle";

// Draw the text at the center
ctx.fillText(message, centerX, centerY);
// Clear the canvas
gl.clearColor(0, 0, 0, 1); // Set clear color (black, in this case)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// To show the message
messageDiv.textContent = message;
messageDiv.style.display = 'block';
}

function renderCanvas(srcCanvas, dstCanvas) {
let ctxSrc = srcCanvas.getContext('2d');
let ctxDst = dstCanvas.getContext('2d');

let w = srcCanvas.width;
let h = srcCanvas.height;

// Clear the destination canvas
ctxDst.clearRect(0, 0, w, h);
ctxDst.imageSmoothingEnabled = true;


if (rotate) {
// Swap width and height for dstCanvas to accommodate rotated content
dstCanvas.width = h;
dstCanvas.height = w;
ctxDst.translate(0,w); // Move the drawing origin to the right side of dstCanvas
ctxDst.rotate(-Math.PI / 2); // Rotate by 90 degrees


// Since the source canvas is now rotated, width and height are swapped
ctxDst.drawImage(srcCanvas, 0, 0);
} else {
dstCanvas.width = w;
dstCanvas.height = h;
ctxDst.drawImage(srcCanvas, 0, 0);
}

// Reset transformations for future calls
ctxDst.setTransform(1, 0, 0, 1, 0, 0);
}

222 changes: 222 additions & 0 deletions client/glCanvas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
// WebGL initialization
//const gl = visibleCanvas.getContext('webgl');
//const gl = canvas.getContext('webgl', { antialias: true, preserveDrawingBuffer: true });
const gl = canvas.getContext('webgl', { antialias: true });


if (!gl) {
alert('WebGL not supported');
}

// Vertex shader program
const vsSource = `
attribute vec4 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uRotationMatrix;
uniform float uScaleFactor;
varying highp vec2 vTextureCoord;

void main(void) {
gl_Position = uRotationMatrix * vec4(aVertexPosition.xy * uScaleFactor, aVertexPosition.zw);
vTextureCoord = aTextureCoord;
}
`;

// Fragment shader program
const fsSource = `
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;

void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
`;

function makeRotationZMatrix(angleInDegrees) {
var angleInRadians = angleInDegrees * Math.PI / 180;
var s = Math.sin(angleInRadians);
var c = Math.cos(angleInRadians);

return [
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
}

// Initialize a shader program
function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
return null;
}

return shaderProgram;
}

// Creates a shader of the given type, uploads the source and compiles it.
function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}

return shader;
}

const shaderProgram = initShaderProgram(gl, vsSource, fsSource);

// Collect all the info needed to use the shader program.
// Look up locations of attributes and uniforms used by our shader
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
},
uniformLocations: {
uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
},
};

// Create a buffer for the square's positions.
const positionBuffer = gl.createBuffer();

// Select the positionBuffer as the one to apply buffer operations to from here out.
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

// Now create an array of positions for the square.
const positions = [
1.0, 1.0,
-1.0, 1.0,
1.0, -1.0,
-1.0, -1.0,
];

// Pass the list of positions into WebGL to build the shape.
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

// Set up texture coordinates for the rectangle
const textureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);

const textureCoordinates = [
// 1.0, 0.0, // Bottom right
// 0.0, 0.0, // Bottom left
// 1.0, 1.0, // Top right
// 0.0, 1.0, // Top left
1.0, 1.0,
0.0, 1.0,
1.0, 0.0,
0.0, 0.0,
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);

// Create a texture.
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);


// Set the parameters so we can render any size image.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// To apply a smoothing algorithm, you'll likely want to adjust the texture filtering parameters in your WebGL setup.
// For smoothing, typically gl.LINEAR is used for both gl.TEXTURE_MIN_FILTER and gl.TEXTURE_MAG_FILTER
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

// Upload the image into the texture.
let imageData = new ImageData(width, height);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData);

// Draw the scene
function drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture) {
if (resizeGLCanvas(gl.canvas)) {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
}
gl.clearColor(0.5, 0.5, 0.5, 0.25); // Gray with 75% transparency
gl.clearDepth(1.0); // Clear everything
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things

// Clear the canvas before we start drawing on it.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// Tell WebGL to use our program when drawing
gl.useProgram(programInfo.program);

// Set the shader attributes
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);

gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
gl.vertexAttribPointer(programInfo.attribLocations.textureCoord, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(programInfo.attribLocations.textureCoord);

// Tell WebGL we want to affect texture unit 0
gl.activeTexture(gl.TEXTURE0);

// Bind the texture to texture unit 0
gl.bindTexture(gl.TEXTURE_2D, texture);

// Tell the shader we bound the texture to texture unit 0
gl.uniform1i(programInfo.uniformLocations.uSampler, 0);

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}

drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture);

// Update texture
function updateTexture(newRawData, shouldRotate, scaleFactor) {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, newRawData);

// Set rotation
const uRotationMatrixLocation = gl.getUniformLocation(shaderProgram, 'uRotationMatrix');
const rotationMatrix = shouldRotate ? makeRotationZMatrix(270) : makeRotationZMatrix(0);
gl.uniformMatrix4fv(uRotationMatrixLocation, false, rotationMatrix);

// Set scaling
const uScaleFactorLocation = gl.getUniformLocation(shaderProgram, 'uScaleFactor');
gl.uniform1f(uScaleFactorLocation, scaleFactor);

drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture);
}

// Call `updateTexture` with new data whenever you need to update the image

// Let's create a function that resizes the canvas element.
// This function will adjust the canvas's width and height attributes based on its display size, which can be set using CSS or directly in JavaScript.
function resizeGLCanvas(canvas) {
const displayWidth = canvas.clientWidth;
const displayHeight = canvas.clientHeight;

// Check if the canvas size is different from its display size
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
// Make the canvas the same size as its display size
canvas.width = displayWidth;
canvas.height = displayHeight;
return true; // indicates that the size was changed
}

return false; // indicates no change in size
}
28 changes: 18 additions & 10 deletions client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<head>
<title>goMarkableStream</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!-- Including the CSS stylesheet -->
<link rel="stylesheet" href="style.css">
<!-- Including the CSS stylesheet -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="menuContainer">
Expand All @@ -13,28 +13,36 @@
<ul class="menu">
<li><button id="rotate" class="apple-button">Rotate</button></li>
<li><button id="colors" class="apple-button">Colors</button></li>
<!--
<li><button id="startStopButton" class="apple-button">
<div class="icon" id="icon"></div>
<span id="label">Record</span>
</button></li>
<li><button id="startStopButtonWithSound" class="apple-button">
<div class="icon" id="icon2"></div>
<span id="label2">Record with audio</span>
</button></li>
<li><button id="screenshotButton" class="apple-button">Screenshot</button><a id="screenshot"></a></li>
<li><button id="startStopButtonWithSound" class="apple-button">
<div class="icon" id="icon2"></div>
<span id="label2">Record with audio</span>
</button></li>
<li><button id="screenshotButton" class="apple-button">Screenshot</button><a id="screenshot"></a></li>
-->
<li><button id="pointerButton" class="apple-button">Pointer</button></a></li>
<li><button id="switchOrderButton" class="apple-button">Mask drawing</button><a id="switch"></a></li>
</ul>
</div>
</div>
<div id="container">
<canvas id="canvas" width="1872" height="1404"></canvas>
<iframe id="content" allowfullscreen="true" frameborder="0" width="100%" height="100%" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">></iframe>
<canvas id="canvas"></canvas>
<div id="message" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: red;"> </div>
<canvas id="canvasPresent" width="1872" height="1404"></canvas>
<iframe id="content" allow="camera *;" allowfullscreen="true" frameborder="0" width="100%" height="100%" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">></iframe>
</div>
<!--<iframe id="content" src="https://docs.google.com/presentation/d/e/2PACX-1vQoU3OkrD499XPCjI1kl18dci2Um6eqCkZlKCMJaCVaUkonu6NOWZkLgDOdpTyJwLJlyZ9Yf8SAMTdE/embed?start=false&loop=false&delayms=3000" frameborder="0" width="100%" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>-->

</body>
<script src="main.js"></script> <!-- Include the JavaScript file -->
<script src="glCanvas.js"></script> <!-- Include the JavaScript file -->
<script src="pointer.js"></script> <!-- Include the JavaScript file -->
<script src="utilities.js"></script> <!-- Include the JavaScript file -->
<script src="recording.js"></script> <!-- Include the JavaScript file -->
<script src="canvasHandling.js"></script> <!-- Include the JavaScript file -->
<script src="uiInteractions.js"></script> <!-- Include the JavaScript file -->
<script src="workersHandling.js"></script>
</html>
Loading
Loading