Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,23 @@ export class TimelineEventsRenderer implements IDisposableRenderer {
*
* @param gl The WebGL rendering context.
* @param logElementHighlights Map of log indices to their highlight state.
* @param activeLogsIndices Set of log indices that are currently active(not filtered out).
*/
updateDynamicBuffer(
gl: WebGLRenderingContext,
logElementHighlights: TimelineChartItemHighlight,
activeLogsIndices: Set<number>,
) {
for (let i = 0; i < this.timeline.events.length; i++) {
const selectionStatus =
logElementHighlights[this.timeline.events[i].logIndex] ?? 0;
const filterStatus = activeLogsIndices.has(
this.timeline.events[i].logIndex,
)
? 1
: 0;
this.intDynamicMetaVBOSource[i * 4 + 0] = selectionStatus;
this.intDynamicMetaVBOSource[i * 4 + 1] = filterStatus;
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.intDynamicMetaVBO);
gl.bufferData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,23 @@ export class TimelineRevisionsRenderer implements IDisposableRenderer {
*
* @param gl The WebGL rendering context.
* @param logElementHighlights Map of log indices to their highlight state.
* @param activeLogsIndices Set of log indices that are currently active(not filtered out).
*/
updateDynamicBuffer(
gl: WebGLRenderingContext,
logElementHighlights: TimelineChartItemHighlight,
activeLogsIndices: Set<number>,
) {
for (let i = 0; i < this.timeline.revisions.length; i++) {
const selectionStatus =
logElementHighlights[this.timeline.revisions[i].logIndex] ?? 0;
const filterStatus = activeLogsIndices.has(
this.timeline.revisions[i].logIndex,
)
? 1
: 0;
this.intDynamicMetaVBOSource[i * 4 + 0] = selectionStatus;
this.intDynamicMetaVBOSource[i * 4 + 1] = filterStatus;
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.intDynamicMetaVBO);
gl.bufferData(
Expand Down
3 changes: 2 additions & 1 deletion web/src/assets/event-v2.color-fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ void main(){
);

fragColor.rgb = colorWithBorder;
fragColor.a = mix(0.9,1.0,borderAlpha);
fragColor.a = mix(0.9,1.0,borderAlpha) * mix(0.2,1.0,float(eventModel.filterStatus));
fragColor.rgb *= fragColor.a; // Canvas expects premultiplied alpha.
}
3 changes: 3 additions & 0 deletions web/src/assets/event-v2.hittest-fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,8 @@ flat in EventModel eventModel;
void main(){
// Output the event index and the object type identifier (2 for events).
// This allows the CPU to read the pixel under the mouse and identify the clicked event.
if(eventModel.filterStatus == 0u){
discard;
}
hittestID = uvec2(eventModel.eventIndex, 2);
}
1 change: 1 addition & 0 deletions web/src/assets/event-v2.shared.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ struct EventModel{
// states
uint eventIndex; // Unique index of the event.
uint selectionStatus; // Selection state: 0=None, 1=Hover, 2=Selected.
uint filterStatus; // Filter state: 0 = filtered out, 1 = non filtered.
};
15 changes: 9 additions & 6 deletions web/src/assets/event-v2.vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ precision highp int;
// instanced rendering is used, so these attributes are per-instance (per-event).
layout(location = 0) in uvec2 time; // x: start time(s), y: start time(ns). High precision timestamp.
layout(location = 1) in uvec4 intStaticMeta; // x: eventIndex, y: logType, z: logSeverity. Static metadata.
layout(location = 2) in uvec4 intDynamicMeta; // x: selectionState. Dynamic metadata that can change frequently.
layout(location = 2) in uvec4 intDynamicMeta; // x: selectionState. y: filterState Dynamic metadata that can change frequently.

// Outputs to the fragment shader.
out vec2 uv; // UV coordinates for the quad (0.0 to 1.0).
Expand Down Expand Up @@ -60,6 +60,7 @@ void main(){
eventModel.logTypeColor = es.logTypeColors[intStaticMeta.y];
eventModel.logSeverityColor = es.logSeverityColors[intStaticMeta.z];
eventModel.selectionStatus = intDynamicMeta.x;
eventModel.filterStatus = intDynamicMeta.y;

// 4. Calculate the screen size of the event
// If the event is not selected/hovered (selectionStatus < 0.5), it is slightly smaller.
Expand All @@ -77,13 +78,15 @@ void main(){
vec3 moved = genTranslationScaleMatrixAffineSpace2D(translation,scale) * vec3(pos.xy,1.0);

// 7. Calculate final Depth (Z-coordinate) for correct layering
// Importance criteria 1: Selected > Hover > None
// Importance criteria 2: severity (higher severity -> closer to camera)
// Importance criteria 1: active > filtered out
// Importance criteria 2: Selected > Hover > None
// Importance criteria 3: severity (higher severity -> closer to camera)
// baseOffset ensures these events are rendered behind other UI elements (like revisions on Z=0).
float baseOffset = -0.5;
float selectionPriority = - 0.1 * float(SELECTION_STATE_TO_DEPTH_PRIORITY[eventModel.selectionStatus]);
float importancePriority = - 0.1 / float(MAX_LOG_SEVERITY_COUNT) * float(intStaticMeta.z);
pos.z = selectionPriority + importancePriority + baseOffset;
float filterPriority = - 0.1 * float(eventModel.filterStatus);
float selectionPriority = - 0.01 * float(SELECTION_STATE_TO_DEPTH_PRIORITY[eventModel.selectionStatus]);
float importancePriority = - 0.001 / float(MAX_LOG_SEVERITY_COUNT) * float(intStaticMeta.z);
pos.z = filterPriority + selectionPriority + importancePriority + baseOffset;

gl_Position = vec4(moved.xy,pos.z,1.0);
}
13 changes: 9 additions & 4 deletions web/src/assets/revision-v2.color-fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,19 @@ void main(){
// 2. Compute stripe patterns
float borderStripeAlpha = mix(1.0, borderStripePattern(rls.borderStripePitch), float(revisionModel.borderStripePatten));
float bodyStripeAlpha = mix(1.0, stripePattern(rls.bodyStripePitch), float(revisionModel.bodyStripePattern));
float borderAlpha = isBorder(rls.borderThickness) * borderStripeAlpha;
float isSelected = step(1.5,float(revisionModel.selectionStatus));
float isHovered = step(0.5, float(revisionModel.selectionStatus)) * (1.0 - isSelected);
float borderScale = 1.0 + isSelected * 0.5 + isHovered * 0.1;
float borderAlpha = isBorder(rls.borderThickness * borderScale) * borderStripeAlpha;
float alphaScale = 1.0 + isSelected * 0.5 + isHovered * 0.1;
float alpha = revisionModel.alphaTransparency * alphaScale;

// 3. Combine Alphas for "Dark" elements (Text, Icon, Border)
float darkAlpha = max(fontAlpha, max(iconAlpha, borderAlpha));

// 4. Calculate Selection and Highlight Borders
float selectionBorderAlpha = isBorder(rls.selectionBorderThickness) * step(1.5,float(revisionModel.selectionStatus)) * step(borderAlpha,0.5);
float highlightBorderAlpha = isBorder(rls.highlightBorderThickness) * step(0.5, float(revisionModel.selectionStatus)) * step(borderAlpha,0.5);
float selectionBorderAlpha = 0.;
float highlightBorderAlpha = 0.;
float darkAlphaWithBorder = max(darkAlpha,max(selectionBorderAlpha,highlightBorderAlpha));

// 5. Compose Final Color
Expand All @@ -165,6 +170,6 @@ void main(){
);

fragColor.rgb = baseColor;
fragColor.a = mix(revisionModel.alphaTransparency, 1.0, darkAlphaWithBorder);
fragColor.a = mix(alpha, 1.0, darkAlphaWithBorder) * mix(0.2,1.0,float(revisionModel.filterStatus));
fragColor.rgb *= fragColor.a; // Pre-multiplied alpha
}
3 changes: 3 additions & 0 deletions web/src/assets/revision-v2.hittest-fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ flat in float leftEdgeTimeMS;
layout(location = 0) out uvec2 hittestID; // x: revision index, y: object type (1 for revision)

void main(){
if(revisionModel.filterStatus == 0u){
discard;
}
// Return the revision index and object type 1 (Revision).
hittestID = uvec2(revisionModel.revisionIndex, 1);
}
1 change: 1 addition & 0 deletions web/src/assets/revision-v2.shared.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ struct RevisionModel {
uint revisionIndex;
uint revisionState;
uint selectionStatus;
uint filterStatus;
uint logIndex;
};
5 changes: 3 additions & 2 deletions web/src/assets/revision-v2.vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ precision highp int;
// Input attributes from the vertex buffer.
layout(location = 0) in uvec4 time; // x: start time(s), y: start time(ns), z: end time(s), w: end time(ns)
layout(location = 1) in uvec4 intStaticMeta; // x: revisionIndex, y: revisionState, z: logIndex. Static metadata.
layout(location = 2) in uvec4 intDynamicMeta; // x: selectionState. Dynamic metadata.
layout(location = 2) in uvec4 intDynamicMeta; // x: selectionState, y: filterStatus. Dynamic metadata.

// Outputs to the fragment shader.
out vec2 uv; // UV coordinates for the quad (0.0 to 1.0).
Expand Down Expand Up @@ -39,6 +39,7 @@ void main(){
revisionModel.revisionState = intStaticMeta.y;
revisionModel.logIndex = intStaticMeta.z;
revisionModel.selectionStatus = intDynamicMeta.x;
revisionModel.filterStatus = intDynamicMeta.y;

uv = pos.xy * 0.5 + 0.5;

Expand All @@ -51,7 +52,7 @@ void main(){
// Calculate the X position and width regarding the left edge time and the duration.
// 1. Calculate relative time difference from the viewport left edge.
ivec2 leftEdgeRelativeTime = ivec2(time.xy - vs.leftEdgeTime);
uvec2 durationTime = time.zw - time.xy;
ivec2 durationTime = ivec2(time.zw - time.xy);

// 2. Convert time to screen coordinates (pixels).
float leftEdgeXScreen = (float(leftEdgeRelativeTime.x)* 1e+3 + float(leftEdgeRelativeTime.y) * 1e-6) * vs.pixelsPerMs;
Expand Down