diff options
| -rw-r--r-- | app/Http/Controllers/SiteController.php | 10 | ||||
| -rw-r--r-- | app/Models/Traits/AutoFillable.php | 8 | ||||
| -rwxr-xr-x | config/filesystems.php | 3 | ||||
| -rw-r--r--[-rwxr-xr-x] | public/css/app.css (renamed from resources/css/app.css) | 0 | ||||
| -rw-r--r-- | public/css/jstoys.css (renamed from resources/css/jstoys.css) | 0 | ||||
| -rw-r--r--[-rwxr-xr-x] | public/css/normalize.css (renamed from resources/css/normalize.css) | 0 | ||||
| -rw-r--r-- | public/css/reset.css (renamed from resources/css/reset.css) | 0 | ||||
| -rw-r--r--[-rwxr-xr-x] | public/css/skeleton.css (renamed from resources/css/skeleton.css) | 0 | ||||
| -rw-r--r-- | public/css/style.css (renamed from resources/css/style.css) | 2 | ||||
| -rw-r--r-- | public/css/writings.css (renamed from resources/css/writings.css) | 0 | ||||
| -rw-r--r--[-rwxr-xr-x] | public/js/app.js (renamed from resources/js/app.js) | 0 | ||||
| -rw-r--r-- | public/js/blood.js (renamed from resources/js/blood.js) | 0 | ||||
| -rw-r--r-- | public/js/blood_gpu.js (renamed from resources/js/blood_gpu.js) | 0 | ||||
| -rw-r--r--[-rwxr-xr-x] | public/js/bootstrap.js (renamed from resources/js/bootstrap.js) | 0 | ||||
| -rw-r--r-- | public/js/echo.js (renamed from resources/js/echo.js) | 0 | ||||
| -rw-r--r-- | public/js/home.js (renamed from resources/js/home.js) | 0 | ||||
| -rw-r--r-- | public/js/lib.js | 15 | ||||
| -rw-r--r-- | public/js/main.js (renamed from resources/js/main.js) | 123 | ||||
| -rw-r--r-- | public/js/marked.js (renamed from resources/js/marked.js) | 0 | ||||
| -rw-r--r-- | public/js/socket.io.esm.min.js (renamed from resources/js/socket.io.esm.min.js) | 0 | ||||
| -rw-r--r-- | public/js/webgpu.js | 253 | ||||
| -rw-r--r-- | public/js/webgpu_gltf.js | 514 | ||||
| -rw-r--r-- | public/js/writing_create.js (renamed from resources/js/writing_create.js) | 0 | ||||
| -rw-r--r-- | public/js/writing_index.js (renamed from resources/js/writing_index.js) | 1 | ||||
| -rw-r--r-- | public/js/writing_show.js (renamed from resources/js/writing_show.js) | 0 | ||||
| -rwxr-xr-x | resources/views/home.blade.php | 6 | ||||
| -rw-r--r-- | resources/views/links/show.blade.php | 2 | ||||
| -rw-r--r-- | resources/views/marked.html | 31 | ||||
| -rwxr-xr-x | resources/views/template.blade.php | 9 | ||||
| -rw-r--r-- | resources/views/toys/blood-gpu.blade.php | 3 | ||||
| -rw-r--r-- | resources/views/toys/blood.blade.php | 4 | ||||
| -rw-r--r-- | resources/views/toys/fire.blade.php | 3 | ||||
| -rw-r--r-- | resources/views/writings/create.blade.php | 4 | ||||
| -rw-r--r-- | resources/views/writings/edit.blade.php | 4 | ||||
| -rw-r--r-- | resources/views/writings/index.blade.php | 3 | ||||
| -rw-r--r-- | resources/views/writings/show.blade.php | 3 | ||||
| -rwxr-xr-x | vite.config.js | 6 |
37 files changed, 941 insertions, 66 deletions
diff --git a/app/Http/Controllers/SiteController.php b/app/Http/Controllers/SiteController.php index 722cc91..8ef0d23 100644 --- a/app/Http/Controllers/SiteController.php +++ b/app/Http/Controllers/SiteController.php @@ -35,13 +35,14 @@ class SiteController extends Controller ]; //returns an env mapping to be used by client. pretty much a subset of laravel app's env, but might also have addition things - public static function jsenv(){ + public static function env(){ $vars = [ - 'API_URL' => $_ENV['API_URL'], + 'API_URL' => $_ENV['API_URL'], //TODO use config() here instead of env. env should only be used in the config files 'WS_URL' => $_ENV['WS_URL'], 'FILEUPLOAD_URL' => $_ENV['FILEUPLOAD_URL'] ?? '', //these 3 file vars are from old 'thesite'. fileup_url might end up being same as api_url 'FILEUPLOAD_MAX_MB' => $_ENV['FILEUPLOAD_MAX_MB'] ?? 10, - 'FILEUPLOAD_CHUNK_MB' => $_ENV['FILEUPLOAD_CHUNK_MB'] ?? '' + 'FILEUPLOAD_CHUNK_MB' => $_ENV['FILEUPLOAD_CHUNK_MB'] ?? '', + 'MODE' => config('app.env'), //dev, prod, ]; return $vars; } @@ -121,7 +122,8 @@ class SiteController extends Controller //used for testing various things, from /test routes public function test(Request $req){ - return $req->header('user_agent'); + //return $req->header('user_agent'); + return config('app.env'); } public function updateSession(){ diff --git a/app/Models/Traits/AutoFillable.php b/app/Models/Traits/AutoFillable.php index 044d5b8..3ef85c9 100644 --- a/app/Models/Traits/AutoFillable.php +++ b/app/Models/Traits/AutoFillable.php @@ -14,12 +14,4 @@ trait AutoFillable $protected = ['id', 'created_at', 'updated_at', 'deleted_at']; $this->fillable = array_diff($columns, $protected); } -} - -// Then in your model: -use App\Models\Traits\AutoFillable; - -class User extends Model -{ - use AutoFillable; }
\ No newline at end of file diff --git a/config/filesystems.php b/config/filesystems.php index b564035..4d06cdc 100755 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -74,4 +74,7 @@ return [ public_path('storage') => storage_path('app/public'), ], + 'max_upload_size' => env('FILEUPLOAD_MAX_MB', 10240), // Default to 10MB + 'max_chunk_size' => env('FILEUPLOAD_CHUNK_MB', 1024), // Default to 1GB + 'upload_dir' => env('FILEUPLOAD_DIR', 'uploads'), // Default upload directory ]; diff --git a/resources/css/app.css b/public/css/app.css index b5c61c9..b5c61c9 100755..100644 --- a/resources/css/app.css +++ b/public/css/app.css diff --git a/resources/css/jstoys.css b/public/css/jstoys.css index add19e2..add19e2 100644 --- a/resources/css/jstoys.css +++ b/public/css/jstoys.css diff --git a/resources/css/normalize.css b/public/css/normalize.css index 81c6f31..81c6f31 100755..100644 --- a/resources/css/normalize.css +++ b/public/css/normalize.css diff --git a/resources/css/reset.css b/public/css/reset.css index 905b080..905b080 100644 --- a/resources/css/reset.css +++ b/public/css/reset.css diff --git a/resources/css/skeleton.css b/public/css/skeleton.css index c3fda1c..c3fda1c 100755..100644 --- a/resources/css/skeleton.css +++ b/public/css/skeleton.css diff --git a/resources/css/style.css b/public/css/style.css index cdd0d3f..112b37a 100644 --- a/resources/css/style.css +++ b/public/css/style.css @@ -6,7 +6,7 @@ } html { - background-color: #efefef; + background-color: hsl(0, 0%, 94%); } body * { diff --git a/resources/css/writings.css b/public/css/writings.css index 7e23d51..7e23d51 100644 --- a/resources/css/writings.css +++ b/public/css/writings.css diff --git a/resources/js/app.js b/public/js/app.js index a8093be..a8093be 100755..100644 --- a/resources/js/app.js +++ b/public/js/app.js diff --git a/resources/js/blood.js b/public/js/blood.js index c45663a..c45663a 100644 --- a/resources/js/blood.js +++ b/public/js/blood.js diff --git a/resources/js/blood_gpu.js b/public/js/blood_gpu.js index 19d88c4..19d88c4 100644 --- a/resources/js/blood_gpu.js +++ b/public/js/blood_gpu.js diff --git a/resources/js/bootstrap.js b/public/js/bootstrap.js index deb2e10..deb2e10 100755..100644 --- a/resources/js/bootstrap.js +++ b/public/js/bootstrap.js diff --git a/resources/js/echo.js b/public/js/echo.js index 9349afa..9349afa 100644 --- a/resources/js/echo.js +++ b/public/js/echo.js diff --git a/resources/js/home.js b/public/js/home.js index e69de29..e69de29 100644 --- a/resources/js/home.js +++ b/public/js/home.js diff --git a/public/js/lib.js b/public/js/lib.js new file mode 100644 index 0000000..770efe5 --- /dev/null +++ b/public/js/lib.js @@ -0,0 +1,15 @@ +class AppSocket extends WebSocket { + send(msg){ + if (typeof(msg) !== 'string') { + try { + super.send(JSON.stringify(msg)); + } catch (e) { + console.error('cant json stringify msg', msg, e); + } + } else { + super.send(msg); + } + } +} + +export { AppSocket };
\ No newline at end of file diff --git a/resources/js/main.js b/public/js/main.js index e94f1e7..fcaa512 100644 --- a/resources/js/main.js +++ b/public/js/main.js @@ -1,5 +1,4 @@ -import { io } from './socket.io.esm.min.js'; -//import { drawScene } from './drawer.js'; +import { AppSocket } from './lib.js'; const CHUNK_SIZE = 4 * 1024 * 1024; // 4MB chunks const FILESIZE_THRESHOLD = 16 * 1024 * 1024; // 16MB // how big before use chunked upload @@ -7,11 +6,14 @@ const MAXFILESIZE = 2048 * 1024 * 1024; // 2GB const color_bg = "#dedede"; //TODO change color based on time -var ctx = null; -var cnv = null; +var ctx = null; //canvas context +var cnv = null; //canvas +var env = { + 'WS_URL': 'wss://belthelziquor.com:9002' +}; //environment variables from server. dev=true by default because if env not passed in not public/published instance var W = 800; var H = 600; -var socket = null; +var socket = null; //client's websocket var myID; var elemNumConnected; @@ -21,6 +23,7 @@ var friends = { }; +//todo move in appmodel var me = [0,0]; //my cursor position var myNickname = ''; @@ -37,15 +40,21 @@ function prepareFileInput(){ } //APP START HERE -$(document).ready(function() { - cnv = $('#bg')[0]; - if (cnv != null) { - if (env == null){ //env vars should've been passed in already, but just in case - getServerEnvVars(); - } - console.log(env); - initDOM(); +$(document).ready(async function() { + //the core loop of the client application + // 1. setup relationship with DOM and grab references to its elements + log('init DOM'); + await initDOM(); + + log('getting env vars'); + await getServerEnvVars(); + + log('connect ws'); + connectWebSocket(); + + //setup canvas stuff + if (cnv != null) { ctx = cnv.getContext("2d"); W = window.outerWidth; H = window.outerHeight; @@ -54,36 +63,49 @@ $(document).ready(function() { ctx.fillStyle = color_bg; ctx.fillRect(0,0,W,H); - if (connectWebSocket()){ + if (wsConnected()){ setInterval(() => { - socket.emit('update_pos', {pos: me, nick: myNickname}); + socket.emit('update_pos', {pos: me, nick: myNickname}); }, 100); - } else { - console.error('Failed to connect web sockets'); - domElems.debugInfo.innerHTML = 'Unable to connect to web socket server'; } + document.onmousemove = (e) => handleMouseMove(e); setInterval(() => { draw(); }, 20); - window.addEventListener('resize', resizeCanvas); + } else { console.error('Canvas element not found'); } + + window.addEventListener('resize', resizeCanvas); + //background color + /*setInterval(() => { + let now = new Date(); + let h = now.getHours(); + let m = now.getMinutes(); + let s = now.getSeconds(); + let ms = now.getMilliseconds(); + + let timeS = h * 3600 + m * 60 + s; + let timeMs = (timeS) * 1000 + ms; + + let hue = 10; // + let saturation = 0; // + let lightness = 94+2*Math.sin(timeMs) + Math.random(); // + let color = `hsl(${hue}, ${saturation}%, ${lightness}%)`; + domElems.body.style.backgroundColor = color; + log(`Background color: ${color}`, 0); + }, 100);*/ }); -/* -var canvas = document.getElementById('canvas');// $('#canvas')[0]; -console.log(canvas); -var context = canvas.getContext("2d"); -*/ - - -function getServerEnvVars(){ - console.log('getting env vars from main.js via axios'); - axios.get('/env').then((res)=>{ - console.log(res);//TODO set api url from this +async function getServerEnvVars(){ + await axios.get('/env').then((res)=>{ + env = res.data; + log(env); + }).catch((err)=>{ + log(err); }); } @@ -92,21 +114,26 @@ function initDOM(){ // temp disabled $('#fileupload')[0].hidden = false; domElems.numConnected = $('#numFriendsConnected')[0]; domElems.inputFile = $('#f')[0]; - domElems.debugInfo = $('#debugInfo')[0]; + domElems.debugInfo = $('#infolog')[0]; + domElems.debugInfo.style.display = env.MODE == 'local' ? 'block' : 'none'; domElems.fileUploadResult = $('#fileupload_result')[0]; domElems.inputFile.onchange = prepareFileInput; domElems.buttonFileUpload = $('#button_fileupload')[0]; + domElems.body = $('body')[0]; + domElems.cnv = $('#bg')[0]; + cnv = domElems.cnv; //for convenience //domElems.buttonFileUpload.enabled = false; domElems.buttonFileUpload.onclick = uploadFile; domElems.inputWho = $('#input_who')[0]; domElems.inputWho.onchange = ()=> { myNickname = domElems.inputWho.value; }; + } function resizeCanvas() { W = window.outerWidth; H = window.outerHeight; - cnv.width = W; - cnv.height = H; + domElems.cnv.width = W; + domElems.cnv.height = H; } //todo move the old code from file stuff etc to other file so that this file can be just for the canvas+graphics+networkedgame part of the client app @@ -185,13 +212,19 @@ function updateProgress(currentChunk, totalChunks) { } +function wsConnected(){ + return (socket != null && socket.connected); +} + function connectWebSocket(){ try { - - socket = io(env['WS_URL'], { + socket = new AppSocket(env['WS_URL']); + log(socket); + /*socket = io(env['WS_URL'], { + secure: true, rejectUnauthorized: false - }); + });*/ socket.on('connect_error', (err) => { console.log('connection error'); console.log(err); @@ -208,12 +241,20 @@ function connectWebSocket(){ //TODO $('').textContent = err; }); socket.on('connect', (err) => { - console.log('connected'); + log('connected'); if (err) console.log(err); //TODO $('').textContent = 'Connected'; socket.pingTimeout = 1000; socket.pingInterval = 500; }); + socket.on('open', (event) => { + log('connected'); + log(event); + //TODO $('').textContent = 'Connected'; + socket.pingTimeout = 1000; + socket.pingInterval = 500; + }); + socket.on('syncCanvas', (data) => { //TODO appShapes = data.shapes; //TODO ClearBake(); @@ -301,4 +342,12 @@ function handleMouseMove(e) { (doc && doc.clientTop || body && body.clientTop || 0 ); } me = getMousePos(cnv, e); +} + + +function log(msg, lvl=1){ + if (domElems.debugInfo){ + domElems.debugInfo.innerHTML = msg; //TODO running log + timestamp + } + console.log(msg); }
\ No newline at end of file diff --git a/resources/js/marked.js b/public/js/marked.js index 2eb226a..2eb226a 100644 --- a/resources/js/marked.js +++ b/public/js/marked.js diff --git a/resources/js/socket.io.esm.min.js b/public/js/socket.io.esm.min.js index 84cca0e..84cca0e 100644 --- a/resources/js/socket.io.esm.min.js +++ b/public/js/socket.io.esm.min.js diff --git a/public/js/webgpu.js b/public/js/webgpu.js new file mode 100644 index 0000000..b66f9ab --- /dev/null +++ b/public/js/webgpu.js @@ -0,0 +1,253 @@ +//import { mat4, vec3 } from './gl-matrix/dist/gl-matrix.js'; + +//import { formToJSON } from "axios"; + + +var ctx = null; +var cnv = null; +var wgc = null; +var W = 800; +var H = 600; + +const vertexShaderWGSL = ` +struct Uniforms { + modelViewProjectionMatrix : mat4x4<f32>, +} +@binding(0) @group(0) var<uniform> uniforms : Uniforms; + +struct VertexOutput { + @builtin(position) Position : vec4<f32>, + @location(0) color : vec4<f32>, +} + +@vertex +fn main( + @location(0) position : vec4<f32>, + @location(1) color : vec4<f32> +) -> VertexOutput { + var output : VertexOutput; + output.Position = uniforms.modelViewProjectionMatrix * position; + output.color = color; + return output; +} +`; + +const fragmentShaderWGSL = ` +@fragment +fn main(@location(0) color : vec4<f32>) -> @location(0) vec4<f32> { + return color; +} +`; + +$(document).ready(function() { + cnv = $('#c')[0]; + if (cnv != null) { + //initDOM(); + //ctx = cnv.getContext("2d"); + W = window.outerWidth; + H = window.outerHeight; + cnv.width = W; + cnv.height = H; + //ctx.fillRect(0,0,W,H); + + window.addEventListener('resize', resizeCanvas); + doWebGPUStuff(); + } else { + console.error('Canvas element not found'); + } +}); + +function resizeCanvas() { + W = window.outerWidth; + H = window.outerHeight; + cnv.width = W; + cnv.height = H; +} + +async function doWebGPUStuff(){ + console.log(navigator); + if (!navigator.gpu) { + console.error("WebGPU not supported on this browser."); + return; + } + const adapter = await navigator.gpu.requestAdapter(); + if (!adapter) { + console.error("No appropriate GPUAdapter found."); + return; + } + console.log(adapter); + + const device = await adapter.requestDevice(); + console.log(device); + + wgc = cnv.getContext("webgpu"); + console.log(wgc); + const cnvFormat = navigator.gpu.getPreferredCanvasFormat(); + wgc.configure({ + device: device, + format: cnvFormat + }); + + const vertices = new Float32Array([ + // Front face + -0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + -0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + // Back face + -0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + 0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + ]); + + const indices = new Uint16Array([ + 0, 1, 2, 0, 2, 3, + 1, 5, 6, 1, 6, 2, + 5, 4, 7, 5, 7, 6, + 4, 0, 3, 4, 3, 7, + 3, 2, 6, 3, 6, 7, + 4, 5, 1, 4, 1, 0 + ]); + + const vertexBuffer = device.createBuffer({ + size: vertices.byteLength, + usage: GPUBufferUsage.VERTEX, + mappedAtCreation: true, + }); + new Float32Array(vertexBuffer.getMappedRange()).set(vertices); + vertexBuffer.unmap(); + + const indexBuffer = device.createBuffer({ + size: indices.byteLength, + usage: GPUBufferUsage.INDEX, + mappedAtCreation: true, + }); + new Uint16Array(indexBuffer.getMappedRange()).set(indices); + indexBuffer.unmap(); + + const uniformBuffer = device.createBuffer({ + size: 16 * 4, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + + const pipeline = device.createRenderPipeline({ + layout: 'auto', + vertex: { + module: device.createShaderModule({ + code: vertexShaderWGSL, + }), + entryPoint: 'main', + buffers: [ + { + arrayStride: 7 * 4, + attributes: [ + { shaderLocation: 0, offset: 0, format: 'float32x3' }, + { shaderLocation: 1, offset: 3 * 4, format: 'float32x4' }, + ], + }, + ], + }, + fragment: { + module: device.createShaderModule({ + code: fragmentShaderWGSL, + }), + entryPoint: 'main', + targets: [ + { + format: cnvFormat, + }, + ], + }, + primitive: { + topology: 'triangle-list', + }, + depthStencil: { + depthWriteEnabled: true, + depthCompare: 'less', + format: 'depth24plus', + }, + }); + + const depthTexture = device.createTexture({ + size: [cnv.width, cnv.height], + format: 'depth24plus', + usage: GPUTextureUsage.RENDER_ATTACHMENT, + }); + + const uniformBindGroup = device.createBindGroup({ + layout: pipeline.getBindGroupLayout(0), + entries: [ + { + binding: 0, + resource: { + buffer: uniformBuffer, + }, + }, + ], + }); + + render(device); +} + +function render (device) { + const aspect = cnv.width / cnv.height; + const projectionMatrix = mat4.create(); + mat4.perspective(projectionMatrix, (2 * Math.PI) / 5, aspect, 1, 100.0); + + const viewMatrix = mat4.create(); + const eye = vec3.fromValues(0, 0, 4); + const center = vec3.fromValues(0, 0, 0); + const up = vec3.fromValues(0, 1, 0); + mat4.lookAt(viewMatrix, eye, center, up); + + const modelViewProjectionMatrix = mat4.create(); + const modelMatrix = mat4.create(); + mat4.translate(modelMatrix, modelMatrix, [ + (200 /*cursorPosition.x*/ / cnv.width) * 2 - 1, + -(( 200 /*cursorPosition.y*/ / cnv.height) * 2 - 1), + 0 + ]); + mat4.rotate(modelMatrix, modelMatrix, Date.now() * 0.001, vec3.fromValues(0, 1, 0)); + + mat4.multiply(modelViewProjectionMatrix, viewMatrix, modelMatrix); + mat4.multiply(modelViewProjectionMatrix, projectionMatrix, modelViewProjectionMatrix); + + device.queue.writeBuffer( + uniformBuffer, + 0, + modelViewProjectionMatrix.buffer, + modelViewProjectionMatrix.byteOffset, + modelViewProjectionMatrix.byteLength + ); + + const commandEncoder = device.createCommandEncoder(); + const textureView = wgc.getCurrentTexture().createView(); + + const renderPassDescriptor = { + colorAttachments: [ + { + view: textureView, + clearValue: { r: 0.1, g: 0.2, b: 0.3, a: 1.0 }, + loadOp: 'clear', + storeOp: 'store', + }, + ], + depthStencilAttachment: { + view: depthTexture.createView(), + depthClearValue: 1.0, + depthLoadOp: 'clear', + depthStoreOp: 'store', + }, + }; + const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); + passEncoder.setPipeline(pipeline); + passEncoder.setBindGroup(0, uniformBindGroup); + passEncoder.setVertexBuffer(0, vertexBuffer); + passEncoder.setIndexBuffer(indexBuffer, 'uint16'); + passEncoder.drawIndexed(36); + passEncoder.end(); + + device.queue.submit([commandEncoder.finish()]); + requestAnimationFrame(render); +} diff --git a/public/js/webgpu_gltf.js b/public/js/webgpu_gltf.js new file mode 100644 index 0000000..28e9742 --- /dev/null +++ b/public/js/webgpu_gltf.js @@ -0,0 +1,514 @@ +//import { mat4, vec3 } from './gl-matrix/dist/gl-matrix.js'; + +//import { formToJSON } from "axios"; + + +var ctx = null; +var cnv = null; +var wgc = null; +var W = 800; +var H = 600; + +const shaderCode = ` +struct Camera { + viewProjectionMatrix: mat4x4f, + cameraPosition: vec4f, +} + +struct Model { + modelMatrix: mat4x4f, +} + +@group(0) @binding(0) var<uniform> camera: Camera; +@group(0) @binding(1) var<uniform> model: Model; + +struct VertexInput { + @location(0) position: vec3f, + @location(1) normal: vec3f, + @location(2) uv: vec2f, +} + +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) worldPos: vec3f, + @location(1) normal: vec3f, + @location(2) uv: vec2f, +} + +@vertex +fn vertexMain(input: VertexInput) -> VertexOutput { + var output: VertexOutput; + let worldPosition = model.modelMatrix * vec4f(input.position, 1.0); + output.position = camera.viewProjectionMatrix * worldPosition; + output.worldPos = worldPosition.xyz; + output.normal = normalize((model.modelMatrix * vec4f(input.normal, 0.0)).xyz); + output.uv = input.uv; + return output; +} + +@fragment +fn fragmentMain(input: VertexOutput) -> @location(0) vec4f { + let lightDir = normalize(vec3f(1.0, 1.0, 1.0)); + let normal = normalize(input.normal); + let diffuse = max(dot(normal, lightDir), 0.0); + let ambient = 0.1; + let color = vec3f(0.7, 0.7, 0.7); + return vec4f(color * (diffuse + ambient), 1.0); +}`; + +class GLTFRenderer { + constructor(canvas) { + this.canvas = canvas; + this.rotation = 0; + } + + async initialize() { + if (!navigator.gpu) { + throw new Error('WebGPU not supported'); + } + + const adapter = await navigator.gpu.requestAdapter(); + if (!adapter) { + throw new Error('No GPU adapter found'); + } + + this.device = await adapter.requestDevice(); + this.context = this.canvas.getContext('webgpu'); + + const format = navigator.gpu.getPreferredCanvasFormat(); + this.context.configure({ + device: this.device, + format: format, + alphaMode: 'premultiplied', + }); + + // Create pipeline + this.pipeline = this.device.createRenderPipeline({ + layout: 'auto', + vertex: { + module: this.device.createShaderModule({ + code: shaderCode + }), + entryPoint: 'vertexMain', + buffers: [ + { + // position + arrayStride: 12, + attributes: [{ + shaderLocation: 0, + offset: 0, + format: 'float32x3' + }] + }, + { + // normal + arrayStride: 12, + attributes: [{ + shaderLocation: 1, + offset: 0, + format: 'float32x3' + }] + }, + { + // uv + arrayStride: 8, + attributes: [{ + shaderLocation: 2, + offset: 0, + format: 'float32x2' + }] + } + ] + }, + fragment: { + module: this.device.createShaderModule({ + code: shaderCode + }), + entryPoint: 'fragmentMain', + targets: [{ + format: format + }] + }, + primitive: { + topology: 'triangle-list', + cullMode: 'back' + }, + depthStencil: { + depthWriteEnabled: true, + depthCompare: 'less', + format: 'depth24plus' + } + }); + + // Create depth texture + const depthTexture = this.device.createTexture({ + size: [this.canvas.width, this.canvas.height], + format: 'depth24plus', + usage: GPUTextureUsage.RENDER_ATTACHMENT + }); + + this.depthView = depthTexture.createView(); + } + + async loadGLTF(url) { + const response = await fetch(url); + const gltfData = await response.json(); + + // For this example, we'll assume the first mesh, first primitive + const primitive = gltfData.meshes[0].primitives[0]; + + // Load buffers + const bufferResponse = await fetch(url.replace('gltf', 'bin')); + const bufferData = await bufferResponse.arrayBuffer(); + + // Process vertices + const positionAccessor = gltfData.accessors[primitive.attributes.POSITION]; + const positionView = gltfData.bufferViews[positionAccessor.bufferView]; + const positionData = new Float32Array(bufferData, positionView.byteOffset, positionAccessor.count * 3); + + // Create vertex buffer + this.vertexBuffer = this.device.createBuffer({ + size: positionData.byteLength, + usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, + }); + this.device.queue.writeBuffer(this.vertexBuffer, 0, positionData); + + // Process indices + const indexAccessor = gltfData.accessors[primitive.indices]; + const indexView = gltfData.bufferViews[indexAccessor.bufferView]; + const indexData = new Uint16Array(bufferData, indexView.byteOffset, indexAccessor.count); + + // Create index buffer + this.indexBuffer = this.device.createBuffer({ + size: indexData.byteLength, + usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, + }); + this.device.queue.writeBuffer(this.indexBuffer, 0, indexData); + + this.indexCount = indexAccessor.count; + } + + createMatrix4(values) { + return new Float32Array(values); + } + + async render() { + // Update rotation + this.rotation += 0.01; + + // Create uniform buffers for camera and model + const cameraUniformBuffer = this.device.createBuffer({ + size: 64 + 16, // mat4 + vec4 + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + + const modelUniformBuffer = this.device.createBuffer({ + size: 64, // mat4 + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + + // Create view-projection matrix + const aspect = this.canvas.width / this.canvas.height; + const projectionMatrix = this.createMatrix4([ + 1 / (aspect * Math.tan(Math.PI / 4)), 0, 0, 0, + 0, 1 / Math.tan(Math.PI / 4), 0, 0, + 0, 0, -1, -1, + 0, 0, -0.1, 0 + ]); + + const viewMatrix = this.createMatrix4([ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, -5, 1 + ]); + + // Create model matrix with rotation + const modelMatrix = this.createMatrix4([ + Math.cos(this.rotation), 0, Math.sin(this.rotation), 0, + 0, 1, 0, 0, + -Math.sin(this.rotation), 0, Math.cos(this.rotation), 0, + 0, 0, 0, 1 + ]); + + // Write uniform data + this.device.queue.writeBuffer(cameraUniformBuffer, 0, projectionMatrix); + this.device.queue.writeBuffer(cameraUniformBuffer, 64, new Float32Array([0, 0, -5, 1])); + this.device.queue.writeBuffer(modelUniformBuffer, 0, modelMatrix); + + // Create bind group + const bindGroup = this.device.createBindGroup({ + layout: this.pipeline.getBindGroupLayout(0), + entries: [ + { + binding: 0, + resource: { buffer: cameraUniformBuffer } + }, + { + binding: 1, + resource: { buffer: modelUniformBuffer } + } + ] + }); + + // Create command encoder + const commandEncoder = this.device.createCommandEncoder(); + const renderPass = commandEncoder.beginRenderPass({ + colorAttachments: [{ + view: this.context.getCurrentTexture().createView(), + clearValue: { r: 0.1, g: 0.1, b: 0.1, a: 1.0 }, + loadOp: 'clear', + storeOp: 'store' + }], + depthStencilAttachment: { + view: this.depthView, + depthClearValue: 1.0, + depthLoadOp: 'clear', + depthStoreOp: 'store', + } + }); + + renderPass.setPipeline(this.pipeline); + renderPass.setBindGroup(0, bindGroup); + renderPass.setVertexBuffer(0, this.vertexBuffer); + renderPass.setIndexBuffer(this.indexBuffer, 'uint16'); + renderPass.drawIndexed(this.indexCount); + renderPass.end(); + + // Submit commands + this.device.queue.submit([commandEncoder.finish()]); + } + + async start() { + const render = () => { + this.render(); + requestAnimationFrame(render); + }; + render(); + } +} + + +$(document).ready(async function() { + cnv = $('#c')[0]; + if (cnv != null) { + //initDOM(); + //ctx = cnv.getContext("2d"); + W = window.outerWidth; + H = window.outerHeight; + cnv.width = W; + cnv.height = H; + //ctx.fillRect(0,0,W,H); + + window.addEventListener('resize', resizeCanvas); + try { + const renderer = new GLTFRenderer(cnv); + await renderer.initialize(); + await renderer.loadGLTF('cube.gltf'); // Make sure to have your GLTF file available + renderer.start(); + } catch (error) { + const errorDiv = document.getElementById('error'); + errorDiv.style.display = 'block'; + errorDiv.textContent = 'Error: ' + error.message; + console.error(error); + } + doWebGPUStuff(); + } else { + console.error('Canvas element not found'); + } +}); + +function resizeCanvas() { + W = window.outerWidth; + H = window.outerHeight; + cnv.width = W; + cnv.height = H; +} + +async function doWebGPUStuff(){ + console.log(navigator); + if (!navigator.gpu) { + console.error("WebGPU not supported on this browser."); + return; + } + const adapter = await navigator.gpu.requestAdapter(); + if (!adapter) { + console.error("No appropriate GPUAdapter found."); + return; + } + console.log(adapter); + + const device = await adapter.requestDevice(); + console.log(device); + + wgc = cnv.getContext("webgpu"); + console.log(wgc); + const cnvFormat = navigator.gpu.getPreferredCanvasFormat(); + wgc.configure({ + device: device, + format: cnvFormat + }); + + const vertices = new Float32Array([ + // Front face + -0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + -0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, + // Back face + -0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + 0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + ]); + + const indices = new Uint16Array([ + 0, 1, 2, 0, 2, 3, + 1, 5, 6, 1, 6, 2, + 5, 4, 7, 5, 7, 6, + 4, 0, 3, 4, 3, 7, + 3, 2, 6, 3, 6, 7, + 4, 5, 1, 4, 1, 0 + ]); + + const vertexBuffer = device.createBuffer({ + size: vertices.byteLength, + usage: GPUBufferUsage.VERTEX, + mappedAtCreation: true, + }); + new Float32Array(vertexBuffer.getMappedRange()).set(vertices); + vertexBuffer.unmap(); + + const indexBuffer = device.createBuffer({ + size: indices.byteLength, + usage: GPUBufferUsage.INDEX, + mappedAtCreation: true, + }); + new Uint16Array(indexBuffer.getMappedRange()).set(indices); + indexBuffer.unmap(); + + const uniformBuffer = device.createBuffer({ + size: 16 * 4, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + + const pipeline = device.createRenderPipeline({ + layout: 'auto', + vertex: { + module: device.createShaderModule({ + code: vertexShaderWGSL, + }), + entryPoint: 'main', + buffers: [ + { + arrayStride: 7 * 4, + attributes: [ + { shaderLocation: 0, offset: 0, format: 'float32x3' }, + { shaderLocation: 1, offset: 3 * 4, format: 'float32x4' }, + ], + }, + ], + }, + fragment: { + module: device.createShaderModule({ + code: fragmentShaderWGSL, + }), + entryPoint: 'main', + targets: [ + { + format: cnvFormat, + }, + ], + }, + primitive: { + topology: 'triangle-list', + }, + depthStencil: { + depthWriteEnabled: true, + depthCompare: 'less', + format: 'depth24plus', + }, + }); + + const depthTexture = device.createTexture({ + size: [cnv.width, cnv.height], + format: 'depth24plus', + usage: GPUTextureUsage.RENDER_ATTACHMENT, + }); + + const uniformBindGroup = device.createBindGroup({ + layout: pipeline.getBindGroupLayout(0), + entries: [ + { + binding: 0, + resource: { + buffer: uniformBuffer, + }, + }, + ], + }); + + render(device); +} + +function render (device) { + const aspect = cnv.width / cnv.height; + const projectionMatrix = mat4.create(); + mat4.perspective(projectionMatrix, (2 * Math.PI) / 5, aspect, 1, 100.0); + + const viewMatrix = mat4.create(); + const eye = vec3.fromValues(0, 0, 4); + const center = vec3.fromValues(0, 0, 0); + const up = vec3.fromValues(0, 1, 0); + mat4.lookAt(viewMatrix, eye, center, up); + + const modelViewProjectionMatrix = mat4.create(); + const modelMatrix = mat4.create(); + mat4.translate(modelMatrix, modelMatrix, [ + (200 /*cursorPosition.x*/ / cnv.width) * 2 - 1, + -(( 200 /*cursorPosition.y*/ / cnv.height) * 2 - 1), + 0 + ]); + mat4.rotate(modelMatrix, modelMatrix, Date.now() * 0.001, vec3.fromValues(0, 1, 0)); + + mat4.multiply(modelViewProjectionMatrix, viewMatrix, modelMatrix); + mat4.multiply(modelViewProjectionMatrix, projectionMatrix, modelViewProjectionMatrix); + + device.queue.writeBuffer( + uniformBuffer, + 0, + modelViewProjectionMatrix.buffer, + modelViewProjectionMatrix.byteOffset, + modelViewProjectionMatrix.byteLength + ); + + const commandEncoder = device.createCommandEncoder(); + const textureView = wgc.getCurrentTexture().createView(); + + const renderPassDescriptor = { + colorAttachments: [ + { + view: textureView, + clearValue: { r: 0.1, g: 0.2, b: 0.3, a: 1.0 }, + loadOp: 'clear', + storeOp: 'store', + }, + ], + depthStencilAttachment: { + view: depthTexture.createView(), + depthClearValue: 1.0, + depthLoadOp: 'clear', + depthStoreOp: 'store', + }, + }; + const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); + passEncoder.setPipeline(pipeline); + passEncoder.setBindGroup(0, uniformBindGroup); + passEncoder.setVertexBuffer(0, vertexBuffer); + passEncoder.setIndexBuffer(indexBuffer, 'uint16'); + passEncoder.drawIndexed(36); + passEncoder.end(); + + device.queue.submit([commandEncoder.finish()]); + requestAnimationFrame(render); +} diff --git a/resources/js/writing_create.js b/public/js/writing_create.js index e1c88c0..e1c88c0 100644 --- a/resources/js/writing_create.js +++ b/public/js/writing_create.js diff --git a/resources/js/writing_index.js b/public/js/writing_index.js index d46bf77..de3159d 100644 --- a/resources/js/writing_index.js +++ b/public/js/writing_index.js @@ -1,4 +1,3 @@ - let dom = {}; $(function() { diff --git a/resources/js/writing_show.js b/public/js/writing_show.js index 92487eb..92487eb 100644 --- a/resources/js/writing_show.js +++ b/public/js/writing_show.js diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index dcfe2de..d46a1b7 100755 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -1,4 +1,7 @@ @extends('template') +@section('head') +<script type = "module" src = "/js/main.js"></script> +@endsection @section('body') <canvas id = "bg"> </canvas> @@ -80,6 +83,9 @@ <section id = "pingtest" hidden> <p hx-get = "ping" hx-swap = "innerHTML">Checking connection to API server...</p> </section> + <section id = "infolog" > + + </section> </main> {{-- diff --git a/resources/views/links/show.blade.php b/resources/views/links/show.blade.php index 41f0aba..cfa1aca 100644 --- a/resources/views/links/show.blade.php +++ b/resources/views/links/show.blade.php @@ -1,7 +1,7 @@ @extends('template') @section('head') -@vite(['resources/css/style.css']) +<link rel="stylesheet" href="/css/style.css"> @endsection @section('body') diff --git a/resources/views/marked.html b/resources/views/marked.html new file mode 100644 index 0000000..8013738 --- /dev/null +++ b/resources/views/marked.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <meta name="description" content="playing around with markup"> + <meta name="keywords" content="HTML, CSS, JavaScript"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <!--<link rel="stylesheet" type="text/css" href="static/reset.css">--> + <link rel="stylesheet" type="text/css" href="style.css"> + <script src="https://unpkg.com/htmx.org@2.0.1"></script> + <script src = "https://code.jquery.com/jquery-3.7.1.min.js"></script> + <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> + <script type = "module" src = "marked.js"></script> + <!--<base href = "http://192.168.4.32:9002/">--> + <!--<base href = "http://localhost:9002/">--> + <title>markup playground</title> + </head> + + <body> + <main> + </main> + <br> + <textarea id = "input_text" cols = "80" rows = "4"></textarea> + <button id = "button_save" >Save Markup</button> + + <div id="error"></div> + </body> + <footer> + <p>© 2024 Thomas Grothe</p> + </footer> +</html>
\ No newline at end of file diff --git a/resources/views/template.blade.php b/resources/views/template.blade.php index 6678d87..9f8b6a6 100755 --- a/resources/views/template.blade.php +++ b/resources/views/template.blade.php @@ -7,20 +7,21 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="author" content="Thomas Grothe"> <meta name="robots" content="index, follow"> - @yield('head') - <!--<link rel="stylesheet" type="text/css" href="static/reset.css">--> - @vite(['resources/css/style.css', 'resources/js/main.js']) + <link rel="stylesheet" href="/css/style.css"> + + <!--<link rel="stylesheet" type="text/css" href="static/reset.css">--> <meta name="htmx-config" content='{"selfRequestsOnly":false}'> <script src="https://unpkg.com/htmx.org@2.0.1"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src = "https://code.jquery.com/jquery-3.7.1.min.js"></script> <script type = "text/javascript"> - let env = {{ Js::from(App\Http\Controllers\SiteController::jsenv()) }}; + //let env = {{ Js::from(App\Http\Controllers\SiteController::env()) }}; </script> <!--<base href = "http://192.168.4.32:9002/">--> <!--<base href = "http://localhost:9002/">--> <title>Belthelziquor</title> + @yield('head') </head> <header> <a href = "/" class = "form-button" style = "marin-right: auto; margin-left: 1rem;"> diff --git a/resources/views/toys/blood-gpu.blade.php b/resources/views/toys/blood-gpu.blade.php index e5c898e..a40f617 100644 --- a/resources/views/toys/blood-gpu.blade.php +++ b/resources/views/toys/blood-gpu.blade.php @@ -2,7 +2,8 @@ @section('head') <title>WebGPU Blood Spray Effect</title> -@vite(['resources/css/jstoys.css', 'resources/js/blood_gpu.js']) +<link rel="stylesheet" href="/css/jstoys.css"> +<link rel="stylesheet" href="/css/blood_gpu.css"> @endsection @section('body') <h1>WebGPU Blood Spray Simulation</h1> diff --git a/resources/views/toys/blood.blade.php b/resources/views/toys/blood.blade.php index 4953033..521f440 100644 --- a/resources/views/toys/blood.blade.php +++ b/resources/views/toys/blood.blade.php @@ -1,7 +1,9 @@ @extends('template') @section('head') <h1>Blood Splatters</h1> -@vite(['resources/css/style.css', 'resources/css/jstoys.css', 'resources/js/blood.js']) +<link rel="stylesheet" href="/css/style.css"> +<link rel="stylesheet" href="/css/jstoys.css"> +<link rel="stylesheet" href="/css/blood.css"> @endsection @section('body') <div class="action-buttons"> diff --git a/resources/views/toys/fire.blade.php b/resources/views/toys/fire.blade.php index c82eebc..d518c74 100644 --- a/resources/views/toys/fire.blade.php +++ b/resources/views/toys/fire.blade.php @@ -1,7 +1,8 @@ @extends('template') @section('head') <h1>Animated Fire Effect</h1> -@vite(['resources/css/style.css', 'resources/css/jstoys.css']) +<link rel="stylesheet" href="/css/jstoys.css"> +<link rel="stylesheet" href="/css/blood.css"> @endsection @section('body') <canvas id="fireCanvas" width="1000" height="800"></canvas> diff --git a/resources/views/writings/create.blade.php b/resources/views/writings/create.blade.php index e83c908..2dec552 100644 --- a/resources/views/writings/create.blade.php +++ b/resources/views/writings/create.blade.php @@ -4,7 +4,9 @@ <meta charset="UTF-8"> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> -@vite(['resources/js/writing_create.js', 'resources/css/writings.css', 'resources/css/style.css']) +<script type = "module" src = "/js/writing_create.js"></script> +<link rel="stylesheet" href="/css/style.css"> +<link rel="stylesheet" href="/css/writings.css"> @endsection @section('body') diff --git a/resources/views/writings/edit.blade.php b/resources/views/writings/edit.blade.php index 3dbe36c..ff80273 100644 --- a/resources/views/writings/edit.blade.php +++ b/resources/views/writings/edit.blade.php @@ -1,7 +1,9 @@ @extends('template') @section('head') -@vite(['resources/js/writing_show.js', 'resources/css/writings.css']) +<link rel="stylesheet" href="/css/writings.css"> +<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> +<script type = "module" src = "/js/writing_show.js"></script> @endsection @section('body') diff --git a/resources/views/writings/index.blade.php b/resources/views/writings/index.blade.php index a9c2f54..b3ba2e0 100644 --- a/resources/views/writings/index.blade.php +++ b/resources/views/writings/index.blade.php @@ -1,6 +1,7 @@ @extends('template') @section('head') -@vite(['resources/js/writing_index.js']) +<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> +<script type = "module" src = "/js/writing_index.js"></script> @endsection @section('body') <main> diff --git a/resources/views/writings/show.blade.php b/resources/views/writings/show.blade.php index f67c5d3..9d05b21 100644 --- a/resources/views/writings/show.blade.php +++ b/resources/views/writings/show.blade.php @@ -1,8 +1,9 @@ @extends('template') @section('head') +<link rel="stylesheet" href="/css/writings.css"> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> -@vite(['resources/js/writing_show.js', 'resources/css/writings.css']) +<script type = "module" src = "/js/writing_show.js"></script> @endsection @section('nav') diff --git a/vite.config.js b/vite.config.js index 3d01ad3..84c2295 100755 --- a/vite.config.js +++ b/vite.config.js @@ -18,11 +18,11 @@ export default defineConfig({ 'resources/js/writing_show.js', 'resources/js/blood_gpu.js', 'resources/js/blood.js'], - refresh: true + refresh: true, }), ], server: { - host: true, - cors: true + host: '192.168.1.171', + cors: true, } }); |
