Commit e0595bbb authored by Flemming Stäbler's avatar Flemming Stäbler
Browse files

changes from monday

parent 2299fb15
......@@ -27,7 +27,7 @@
<a href="https://nubes.helmholtz-berlin.de/s/jDtA3rEMzzSJGys" target="_blank"><div title="User Manual..." class="button symbol continue"><SvgIcon name="book-help"></SvgIcon></div></a>
</div>
<div class="button-group">
<div title="Record" class="button symbol continue" @click="showRecording"><SvgIcon name="record"></SvgIcon></div>
<div title="Record" class="button symbol continue record" @click="showRecording"><SvgIcon name="record"></SvgIcon></div>
</div>
<!--<div class="button-group">
......@@ -38,6 +38,13 @@
<style lang="scss" scoped>
@import '../_guikit.scss';
div.button.record {
color: $guikit_lightred;
}
div.button.record:active{
color: $bg_color;
}
div.button-group {
display: flex;
}
......
......@@ -5,7 +5,7 @@
<div>Playback: {{isPlayingBack}} ({{playbackEventCount}} actions)</div>
<div id="recording-buttons" class="row">
<div class="button symbol continue" @click="start()"><SvgIcon name="fast-start"></SvgIcon></div>
<div class="button symbol continue" :recording="isRecording" @mousedown.stop="record()"><SvgIcon name="record"></SvgIcon></div>
<div class="button symbol continue record" :recording="isRecording" @mousedown.stop="record()"><SvgIcon name="record"></SvgIcon></div>
<div class="button symbol continue" @click="playpause()"><span v-if="isPlayingBack"><SvgIcon name="pause"></SvgIcon></span><span v-else><SvgIcon name="play"></SvgIcon></span></div>
<div class="button symbol continue" @click="end()"><SvgIcon name="fast-end"></SvgIcon></div>
</div>
......@@ -88,6 +88,15 @@ export default class RecordingPlaybackComponent extends Vue{
<style lang="scss" scoped>
@import '../_guikit.scss';
div.button.record {
color: $guikit_lightred;
}
div.button.record:active, div.button.record[recording]{
color: $bg_color;
background-color: $guikit_lightred;
}
#playback{
display: flex;
flex-direction: column;
......@@ -100,11 +109,6 @@ export default class RecordingPlaybackComponent extends Vue{
justify-content: center;
margin-top: $grid;
}
.symbol[recording]{
color: $bg_color;
background-color: $warn_color;
}
.symbol{
transition: color 0.5s, background-color 0.5s;
}
......
......@@ -3,7 +3,6 @@ import { ServiceBarrier, Services } from "./Services";
import { SynchronizationMessageEvent, TimeRangeMessage } from "./SynchronizationService";
import {SynchronizationMessage} from "./SynchronizationService";
import { FormattingService } from "./FormattingService";
import { thresholdScott } from "@/d3";
import { TarBall } from "@/modules/tar";
export class RecordingMessage{
......@@ -36,7 +35,7 @@ export class RecordingStateEvent extends Event{
}
export class RecordingService extends EventTarget{
event_number: number = 0;
private first_event_index: number = 0;
public isRecording: boolean = false;
public isPlayingBack: boolean = false;
public recordingActions: RecordingMessage[] = [];
......@@ -73,9 +72,9 @@ export class RecordingService extends EventTarget{
}
this.stopRecording();
this.isPlayingBack = true;
this.event_number = 0;
this.first_event_index = 0;
this.playbackStartTime = Services.FlexibleTimeBaseService.now();
this.dispatchEvent(new PlaybackStateEvent(true, this.event_number));
this.dispatchEvent(new PlaybackStateEvent(true, this.first_event_index));
let first_time_event = this.recordingActions.find(a => a.message.type = "TimeRange");
if(first_time_event){
this.playback_state_helper.time_warp_state = first_time_event.message.data;
......@@ -83,7 +82,6 @@ export class RecordingService extends EventTarget{
this.playback_state_helper.time_warp_target_time = first_time_event.timeOffset;
this.playback_state_helper.time_warp_start_time = 0;
}
requestAnimationFrame(() => this.playbackHelper());
Services.AdaptivePerformanceService.RequestRerender();
}
......@@ -99,82 +97,100 @@ export class RecordingService extends EventTarget{
return ymin + (status * (ymax - ymin));
}
private playbackHelper(){
public handlePlayback(){
if(!this.isPlayingBack)return;
let tdiff = Services.FlexibleTimeBaseService.now() - this.playbackStartTime;
let current_action = this.recordingActions[this.event_number];
if(this.playback_state_helper.time_warp_target_time != null && tdiff >= this.playback_state_helper.time_warp_target_time){//Time to find a new time target
let time_range_message : TimeRangeMessage = {
type: "TimeRange",
data: {
min: this.playback_state_helper.time_warp_target.min,
max: this.playback_state_helper.time_warp_target.max
}
};
this.broadcastSynchronizationMessage(time_range_message);
let next_time_message_found = false;
for(let i = this.event_number + 1; i < this.recordingActions.length; i++){
let action = this.recordingActions[i];
if(action.message.type == "TimeRange"){
this.playback_state_helper.time_warp_target = action.message.data;
this.playback_state_helper.time_warp_target_time = action.timeOffset;
next_time_message_found = true;
break;
}
}
if(!next_time_message_found){
console.error("No next time message found");
this.playback_state_helper.time_warp_target = null;
this.playback_state_helper.time_warp_target_time = null;
//handle non-time events
let last_event_index = this.recordingActions.length;
for(var i = this.first_event_index; i < this.recordingActions.length; i++){
if(this.recordingActions[i].timeOffset > tdiff){
last_event_index = i;
break;
}
}else{
if(this.playback_state_helper.time_warp_start_time != null){
let xmin = this.playback_state_helper.time_warp_start_time;
let xmax = this.playback_state_helper.time_warp_target_time;
let time_range_message : TimeRangeMessage = {
type: "TimeRange",
data: {
min: this.lerp(xmin, xmax, this.playback_state_helper.time_warp_state.min, this.playback_state_helper.time_warp_target.min, tdiff),
max: this.lerp(xmin, xmax, this.playback_state_helper.time_warp_state.max, this.playback_state_helper.time_warp_target.max, tdiff)
}
};
console.log("Interpolated Time", (time_range_message.data.min + time_range_message.data.max) / 2);
this.broadcastSynchronizationMessage(time_range_message);
}
if(last_event_index > this.first_event_index){
this.dispatchEvent(new PlaybackStateEvent(true, last_event_index));
}
let this_frame_events = this.recordingActions.slice(this.first_event_index, last_event_index).filter((x) => x.message.type != "TimeRange");
this.first_event_index = last_event_index;
let handledMessageTypes = new Set();
for(var i = this_frame_events.length - 1; i >= 0; i--){
if(!handledMessageTypes.has(this_frame_events[i].message.type)){
handledMessageTypes.add(this_frame_events[i].message.type);
this.broadcastSynchronizationMessage(this_frame_events[i].message);
}
}
if(tdiff > current_action.timeOffset){ //Dispatch event if necessary
if(current_action.message.type != "TimeRange"){
this.broadcastSynchronizationMessage(current_action.message);
};
this.dispatchEvent(new PlaybackStateEvent(true, this.event_number));
this.event_number ++;
if(this.event_number >= this.recordingActions.length){ //Stop playing if we're over the edge
this.isPlayingBack = false;
Services.FlexibleTimeBaseService.set_lock_state(false);
this.saveZipFrames();
this.dispatchEvent(new PlaybackStateEvent(false, this.event_number));
//handle time events
let first_time_range = null;
let last_time_range = null;
for(var i = 0; i < this.recordingActions.length; i++){
let x = this.recordingActions[i];
if(x.timeOffset <= tdiff && x.message.type == "TimeRange"){
last_time_range = x;
}
if(x.timeOffset > tdiff)break;
}
if(this.isPlayingBack){
Services.AdaptivePerformanceService.RequestRerender();
requestAnimationFrame(() => this.playbackHelper());
for(var i = this.recordingActions.length - 1; i >= 0; i--){
let x = this.recordingActions[i];
if(x.timeOffset >= tdiff && x.message.type == "TimeRange"){
last_time_range = x;
}
if(x.timeOffset < tdiff)break;
}
if(first_time_range && last_time_range){
let xmin = first_time_range.timeOffset;
let xmax = last_time_range.timeOffset;
this.broadcastSynchronizationMessage({
type: "TimeRange",
data: {
min: this.lerp(xmin, xmax, first_time_range.message.data.min, last_time_range.message.data.min, tdiff),
max: this.lerp(xmin, xmax, first_time_range.message.data.max, last_time_range.message.data.max, tdiff)
}
});
} else if(first_time_range){
this.broadcastSynchronizationMessage({
type: "TimeRange",
data: {
min: first_time_range.message.data.min,
max: first_time_range.message.data.max
}
});
} else if(last_time_range){
this.broadcastSynchronizationMessage({
type: "TimeRange",
data: {
min: last_time_range.message.data.min,
max: last_time_range.message.data.max
}
});
}
if(this.first_event_index >= this.recordingActions.length){ //Stop playing if we're over the edge
this.isPlayingBack = false;
Services.FlexibleTimeBaseService.set_lock_state(false);
this.saveZipFrames();
this.dispatchEvent(new PlaybackStateEvent(false, this.first_event_index));
}
Services.AdaptivePerformanceService.RequestRerender();
}
private saveZipFrames(){
console.log(this.frameArray);
if(this.frameArray){
//Append save script
let encode_string = new TextEncoder().encode("ffmpeg -i %05d.png -r 30 -c:v libx264 -crf 18 -pix_fmt yuv420p video.mp4\n");
this.frameArray.push(TarBall.gen_header("create_mp4_video.sh", encode_string.length));
let scene_name_string = Services.InitializationService.SceneName;
scene_name_string = scene_name_string.replaceAll(/[^a-zA-Z0-9]/ig, "_");
let encode_string = new TextEncoder().encode(`ffmpeg -i %05d.png -r 30 -c:v libx264 -crf 18 -pix_fmt yuv420p ${scene_name_string}.mp4\n`);
this.frameArray.push(TarBall.gen_header("create_mp4_video.sh", encode_string.byteLength));
this.frameArray.push(encode_string);
if(encode_string.length % 512)
this.frameArray.push(new ArrayBuffer(512 - (encode_string.length % 512)));
//Save blob
let b = new Blob(this.frameArray);
let a_elem = document.getElementById('downloadlink') as HTMLAnchorElement;
a_elem.setAttribute("download", "frames.tar");
a_elem.setAttribute("download", `${scene_name_string}.tar`);
a_elem.setAttribute("href", URL.createObjectURL(b));
a_elem.click();
}
......@@ -189,22 +205,22 @@ export class RecordingService extends EventTarget{
this.isPlayingBack = false;
Services.FlexibleTimeBaseService.set_lock_state(false);
this.saveZipFrames();
this.dispatchEvent(new PlaybackStateEvent(false, this.event_number));
this.dispatchEvent(new PlaybackStateEvent(false, this.first_event_index));
}
public goEndPlayback(){
if(this.recordingActions.length == 0) return;
this.stopPlayback();
this.event_number = this.recordingActions.length;
this.first_event_index = this.recordingActions.length;
this.isPlayingBack = false;
this.broadcastSynchronizationMessage(this.recordingActions[this.recordingActions.length - 1].message);
this.dispatchEvent(new PlaybackStateEvent(false, this.event_number));
this.dispatchEvent(new PlaybackStateEvent(false, this.first_event_index));
}
public goStartPlayback(){
if(this.recordingActions.length == 0) return;
this.stopPlayback();
this.event_number = 0;
this.first_event_index = 0;
this.isPlayingBack = false;
this.broadcastSynchronizationMessage(this.recordingActions[0].message);
this.dispatchEvent(new PlaybackStateEvent(false, 0));
......@@ -235,13 +251,11 @@ export class RecordingService extends EventTarget{
}
public submitFrameBlob(b: Blob) {
console.log(this.frameArray);
if(!this.frameArray)return;
this.frameArray.push(TarBall.gen_header(FormattingService.leftpad("" + this.render_frame_number , "0", 5) + ".png", b.size));
this.frameArray.push(b);
if(b.size % 512)
this.frameArray.push(new ArrayBuffer(512 - (b.size % 512)));
console.log(this.frameArray);
this.render_frame_number += 1;
}
......
......@@ -20,6 +20,7 @@ class DisplaySection {
}
export class RenderService{
blob_submission_complete: boolean = true;
context: glenv;
layerPipeline: LayerPipelineFramebuffer;
......@@ -273,7 +274,8 @@ export class RenderService{
this.resized();
} else if(needs_rerender){
Services.AdaptivePerformanceService.StartMeasurement();
}
}
Services.RecordingService.handlePlayback();
Services.PositionService.filterUpdate();
Services.PlaybackService.update();
if(needs_rerender){
......@@ -292,11 +294,13 @@ export class RenderService{
if(this.is_complete_frame || !Services.RecordingService.acceptsFrames())
Services.ParticlesService.prepareParticles();
this.renderPipeline();
this.is_complete_frame = Services.TileCacheService.is_complete();
this.is_complete_frame = Services.TileCacheService.is_complete() && this.blob_submission_complete;
if(this.is_complete_frame && Services.RecordingService.acceptsFrames()){
console.log("Complete frame.", Services.FlexibleTimeBaseService.now());
this.blob_submission_complete = false;
this.context.gl.canvas.toBlob((blob) => {
Services.RecordingService.submitFrameBlob(blob);
this.blob_submission_complete = true;
});
}
Services.GLService.raiseFrameDoneEvent();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment