@ -6,8 +6,7 @@ function init_listeners(state, context) {
context . canvas . addEventListener ( 'pointerdown' , ( e ) => pointerdown ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointerdown' , ( e ) => pointerdown ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointermove' , ( e ) => pointermove ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointermove' , ( e ) => pointermove ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointerup' , ( e ) => pointerup ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointerup' , ( e ) => pointerup ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointercancel' , ( e ) => pointerup ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointercancel' , ( e ) => pointercancel ( e , state , context ) ) ;
//context.canvas.addEventListener('pointerleave', (e) => pointerup(e, state, context));
context . canvas . addEventListener ( 'pointerleave' , ( e ) => pointerleave ( e , state , context ) ) ;
context . canvas . addEventListener ( 'pointerleave' , ( e ) => pointerleave ( e , state , context ) ) ;
context . canvas . addEventListener ( 'contextmenu' , cancel ) ;
context . canvas . addEventListener ( 'contextmenu' , cancel ) ;
context . canvas . addEventListener ( 'wheel' , ( e ) => wheel ( e , state , context ) ) ;
context . canvas . addEventListener ( 'wheel' , ( e ) => wheel ( e , state , context ) ) ;
@ -42,6 +41,141 @@ function debug_panel_init(state, context) {
schedule _draw ( state , context ) ;
schedule _draw ( state , context ) ;
} ) ;
} ) ;
document . getElementById ( 'debug-render' ) . addEventListener ( 'click' , async ( e ) => {
const encoded _chunks = [ ] ;
let total _chunk _bytes = 0 ;
const handle _encoded _chunk = ( chunk , metadata ) => {
encoded _chunks . push ( chunk ) ;
total _chunk _bytes += chunk . byteLength ;
} ;
const canvas = document . getElementById ( 'c' ) ;
const init = {
output : handle _encoded _chunk ,
error : ( e ) => {
console . log ( e . message ) ;
} ,
} ;
const render _framerate = 240 ;
const render _frames = 720 ;
const start _movement _frame = 240 ;
const start _movement2 _frame = 480 ;
let updated _zoom = false ;
const encoder _config = {
codec : "vp8" ,
width : canvas . width ,
height : canvas . height ,
displayWidth : canvas . width ,
displayHeight : canvas . height ,
bitrate : 100_000_000 ,
framerate : render _framerate ,
} ;
const { supported } = await VideoEncoder . isConfigSupported ( encoder _config ) ;
if ( supported ) {
const encoder = new VideoEncoder ( init ) ;
encoder . configure ( encoder _config ) ;
let zoom _level = 5 ;
const dz = ( zoom _level > 0 ? config . zoom _delta : - config . zoom _delta ) ;
state . canvas . zoom _screenp = { 'x' : canvas . width / 2 , 'y' : canvas . height / 2 } ;
state . canvas . zoom _level = zoom _level ;
state . canvas . target _zoom = Math . pow ( 1.0 + dz , Math . abs ( zoom _level ) )
for ( let i = 0 ; i < render _frames ; ++ i ) {
const time _now = i / render _framerate ;
await draw ( state , context , i > 0 , time _now * 1000 , true ) ;
const frame = new VideoFrame ( canvas , { timestamp : time _now } ) ;
encoder . encode ( frame , { keyFrame : true } ) ;
frame . close ( ) ;
await encoder . flush ( ) ;
if ( start _movement _frame <= i && i < start _movement2 _frame ) {
state . canvas . offset . x += ( 1000 - state . canvas . offset . x ) * 0.05 ;
state . canvas . offset . y += ( 1000 - state . canvas . offset . y ) * 0.05 ;
}
if ( i > start _movement2 _frame ) {
if ( ! updated _zoom ) {
zoom _level = - 25 ;
const dz = ( zoom _level > 0 ? config . zoom _delta : - config . zoom _delta ) ;
state . canvas . zoom _level = zoom _level ;
state . canvas . target _zoom = Math . pow ( 1.0 + dz , Math . abs ( zoom _level ) )
updated _zoom = true ;
}
//state.canvas.offset.x += (3500 - state.canvas.offset.x) * 0.05;
//state.canvas.offset.y += (5000 - state.canvas.offset.y) * 0.05;
}
}
const data = new Uint8Array ( 32 + render _frames * 12 + total _chunk _bytes ) ;
data [ 0 ] = 0x44 ;
data [ 1 ] = 0x4B ;
data [ 2 ] = 0x49 ;
data [ 3 ] = 0x46 ;
data [ 6 ] = 32 ;
data [ 8 ] = 0x56 ;
data [ 9 ] = 0x50 ;
data [ 10 ] = 0x38 ;
data [ 11 ] = 0x30 ;
data [ 12 ] = encoder _config . width & 0xFF ;
data [ 13 ] = ( encoder _config . width >> 8 ) & 0xFF ;
data [ 14 ] = encoder _config . height & 0xFF ;
data [ 15 ] = ( encoder _config . height >> 8 ) & 0xFF ;
data [ 16 ] = render _framerate ; // timebase denom
data [ 20 ] = 1 ; // timebase numenator..?
data [ 24 ] = render _frames ; // frame count
let offset = 32 ;
for ( let i = 0 ; i < render _frames ; ++ i ) {
const chunk = encoded _chunks [ i ] ;
// frame header
// frame length
data [ offset + 0 ] = chunk . byteLength & 0xFF ;
data [ offset + 1 ] = ( chunk . byteLength >> 8 ) & 0xFF ;
data [ offset + 2 ] = ( chunk . byteLength >> 16 ) & 0xFF ;
data [ offset + 3 ] = ( chunk . byteLength >> 24 ) & 0xFF ;
// PTS
// set to frame number for now
data [ offset + 4 ] = i & 0xFF ;
data [ offset + 5 ] = ( i >> 8 ) & 0xFF ;
data [ offset + 6 ] = ( i >> 16 ) & 0xFF ;
data [ offset + 7 ] = ( i >> 24 ) & 0xFF ;
chunk . copyTo ( new Uint8Array ( data . buffer , offset + 12 ) ) ;
offset += 12 + chunk . byteLength ;
}
const blob = new Blob ( [ data . buffer ] , { type : 'application/octet-stream' } ) ;
const url = URL . createObjectURL ( blob ) ;
const a = document . createElement ( 'a' ) ;
a . href = url ;
a . style . display = 'none' ;
a . download = 'rendered_stream.ivf' ; // Set the suggested filename
document . body . appendChild ( a ) ;
a . click ( ) ;
} else {
console . error ( 'Encoding config not supported' ) ;
}
} ) ;
document . getElementById ( 'debug-begin-benchmark' ) . addEventListener ( 'click' , ( e ) => {
document . getElementById ( 'debug-begin-benchmark' ) . addEventListener ( 'click' , ( e ) => {
state . canvas . zoom _level = config . benchmark . zoom _level ;
state . canvas . zoom _level = config . benchmark . zoom _level ;
state . canvas . offset . x = config . benchmark . offset . x ;
state . canvas . offset . x = config . benchmark . offset . x ;
@ -92,7 +226,7 @@ function zenmode() {
}
}
function enter _picker _mode ( state , context ) {
function enter _picker _mode ( state , context ) {
if ( state . tools . active === 'pencil' ) { // or other drawing tools
if ( [ 'pencil' , 'ruler' ] . includes ( state . tools . active ) ) { // or other drawing tools
document . querySelector ( 'canvas' ) . classList . add ( 'picker' ) ;
document . querySelector ( 'canvas' ) . classList . add ( 'picker' ) ;
document . querySelector ( '.picker-preview-outer' ) . classList . remove ( 'dhide' ) ;
document . querySelector ( '.picker-preview-outer' ) . classList . remove ( 'dhide' ) ;
document . querySelector ( '.brush-dom' ) . classList . add ( 'dhide' ) ;
document . querySelector ( '.brush-dom' ) . classList . add ( 'dhide' ) ;
@ -170,7 +304,7 @@ function keydown(e, state, context) {
function keyup ( e , state , context ) {
function keyup ( e , state , context ) {
if ( config . debug _print ) {
if ( config . debug _print ) {
console . debug ( 'keydown ' , e . code ) ;
console . debug ( 'keyup ' , e . code ) ;
}
}
if ( e . code === 'Space' && state . spacedown ) {
if ( e . code === 'Space' && state . spacedown ) {
@ -361,22 +495,16 @@ function pointermove(e, state, context) {
}
}
if ( state . colorpicking ) {
if ( state . colorpicking ) {
update _color _picker _color ( state , context , canvasp ) ;
if ( ! e . ctrlKey ) {
exit _picker _mode ( state ) ;
} else {
update _color _picker _color ( state , context , canvasp ) ;
}
}
}
if ( state . zooming ) {
if ( state . zooming ) {
const zooming _in = e . movementY > 0 ;
const zoom _level _increment = Math . round ( Math . sign ( e . movementY ) * Math . sqrt ( Math . abs ( e . movementY ) ) ) ;
const zooming _out = e . movementY < 0 ;
let zoom _level = state . canvas . zoom _level + zoom _level _increment ;
let zoom _level = null ;
if ( zooming _in ) {
zoom _level = state . canvas . zoom _level + 1
} else if ( zooming _out ) {
zoom _level = state . canvas . zoom _level - 1 ;
} else {
return ;
}
if ( zoom _level < config . min _zoom _level || zoom _level > config . max _zoom _level ) {
if ( zoom _level < config . min _zoom _level || zoom _level > config . max _zoom _level ) {
return ;
return ;
@ -590,8 +718,11 @@ function pointerleave(e, state, context) {
context . canvas . classList . remove ( 'movemode' ) ;
context . canvas . classList . remove ( 'movemode' ) ;
}
}
//exit_picker_mode(state);
// exit_picker_mode(state);
// something else?
}
function pointercancel ( e , state , context ) {
console . log ( 'CANCEL' ) ;
}
}
function update _cursor ( state ) {
function update _cursor ( state ) {