Skip to content

Commit 64d08f9

Browse files
authored
Merge branch 'jMonkeyEngine:master' into capdevon-TestReverb
2 parents 9ee8a33 + 2fa2101 commit 64d08f9

File tree

34 files changed

+1973
-180
lines changed

34 files changed

+1973
-180
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: Screenshot Test PR Comment
2+
3+
# This workflow is designed to safely comment on PRs from forks
4+
# It uses pull_request_target which has higher permissions than pull_request
5+
# Security note: This workflow does NOT check out or execute code from the PR
6+
# It only monitors the status of the ScreenshotTests job and posts comments
7+
# (If this commenting was done in the main worflow it would not have the permissions
8+
# to create a comment)
9+
10+
on:
11+
pull_request_target:
12+
types: [opened, synchronize, reopened]
13+
14+
jobs:
15+
monitor-screenshot-tests:
16+
name: Monitor Screenshot Tests and Comment
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 60
19+
permissions:
20+
pull-requests: write
21+
contents: read
22+
steps:
23+
- name: Wait for GitHub to register the workflow run
24+
run: sleep 15
25+
26+
- name: Wait for Screenshot Tests to complete
27+
uses: lewagon/wait-on-check-action@v1.3.1
28+
with:
29+
ref: ${{ github.event.pull_request.head.sha }}
30+
check-name: 'Run Screenshot Tests'
31+
repo-token: ${{ secrets.GITHUB_TOKEN }}
32+
wait-interval: 10
33+
allowed-conclusions: success,skipped,failure
34+
- name: Check Screenshot Tests status
35+
id: check-status
36+
uses: actions/github-script@v6
37+
with:
38+
github-token: ${{ secrets.GITHUB_TOKEN }}
39+
script: |
40+
const { owner, repo } = context.repo;
41+
const ref = '${{ github.event.pull_request.head.sha }}';
42+
43+
// Get workflow runs for the PR
44+
const runs = await github.rest.actions.listWorkflowRunsForRepo({
45+
owner,
46+
repo,
47+
head_sha: ref
48+
});
49+
50+
// Find the ScreenshotTests job
51+
let screenshotTestRun = null;
52+
for (const run of runs.data.workflow_runs) {
53+
if (run.name === 'Build jMonkeyEngine') {
54+
const jobs = await github.rest.actions.listJobsForWorkflowRun({
55+
owner,
56+
repo,
57+
run_id: run.id
58+
});
59+
60+
for (const job of jobs.data.jobs) {
61+
if (job.name === 'Run Screenshot Tests') {
62+
screenshotTestRun = job;
63+
break;
64+
}
65+
}
66+
67+
if (screenshotTestRun) break;
68+
}
69+
}
70+
71+
if (!screenshotTestRun) {
72+
console.log('Screenshot test job not found');
73+
return;
74+
}
75+
76+
// Check if the job failed
77+
if (screenshotTestRun.conclusion === 'failure') {
78+
core.setOutput('failed', 'true');
79+
} else {
80+
core.setOutput('failed', 'false');
81+
}
82+
- name: Find Existing Comment
83+
uses: peter-evans/find-comment@v3
84+
id: existingCommentId
85+
with:
86+
issue-number: ${{ github.event.pull_request.number }}
87+
comment-author: 'github-actions[bot]'
88+
body-includes: Screenshot tests have failed.
89+
90+
- name: Comment on PR if tests fail
91+
if: steps.check-status.outputs.failed == 'true'
92+
uses: peter-evans/create-or-update-comment@v4
93+
with:
94+
issue-number: ${{ github.event.pull_request.number }}
95+
body: |
96+
🖼️ **Screenshot tests have failed.**
97+
98+
The purpose of these tests is to ensure that changes introduced in this PR don't break visual features. They are visual unit tests.
99+
100+
📄 **Where to find the report:**
101+
- Go to the (failed run) > Summary > Artifacts > screenshot-test-report
102+
- Download the zip and open jme3-screenshot-tests/build/reports/ScreenshotDiffReport.html
103+
104+
⚠️ **If you didn't expect to change anything visual:**
105+
Fix your changes so the screenshot tests pass.
106+
107+
✅ **If you did mean to change things:**
108+
Review the replacement images in jme3-screenshot-tests/build/changed-images to make sure they really are improvements and then replace and commit the replacement images at jme3-screenshot-tests/src/test/resources.
109+
110+
✨ **If you are creating entirely new tests:**
111+
Find the new images in jme3-screenshot-tests/build/changed-images and commit the new images at jme3-screenshot-tests/src/test/resources.
112+
113+
**Note;** it is very important that the committed reference images are created on the build pipeline, locally created images are not reliable. Similarly tests will fail locally but you can look at the report to check they are "visually similar".
114+
115+
See https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-screenshot-tests/README.md for more information
116+
edit-mode: replace
117+
comment-id: ${{ steps.existingCommentId.outputs.comment-id }}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Version number: Major.Minor.SubMinor (e.g. 3.3.0)
2-
jmeVersion = 3.8.0
2+
jmeVersion = 3.9.0
33

44
# Leave empty to autogenerate
55
# (use -PjmeVersionName="myVersion" from commandline to specify a custom version name )

jme3-core/src/main/java/com/jme3/audio/Filter.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009-2020 jMonkeyEngine
2+
* Copyright (c) 2009-2025 jMonkeyEngine
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -35,9 +35,12 @@
3535
import com.jme3.export.JmeImporter;
3636
import com.jme3.export.Savable;
3737
import com.jme3.util.NativeObject;
38+
import com.jme3.util.clone.Cloner;
39+
import com.jme3.util.clone.JmeCloneable;
40+
3841
import java.io.IOException;
3942

40-
public abstract class Filter extends NativeObject implements Savable {
43+
public abstract class Filter extends NativeObject implements Savable, JmeCloneable {
4144

4245
public Filter() {
4346
super();
@@ -49,12 +52,28 @@ protected Filter(int id) {
4952

5053
@Override
5154
public void write(JmeExporter ex) throws IOException {
52-
// nothing to save
55+
// no-op
5356
}
5457

5558
@Override
5659
public void read(JmeImporter im) throws IOException {
57-
// nothing to read
60+
// no-op
61+
}
62+
63+
/**
64+
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
65+
*/
66+
@Override
67+
public Object jmeClone() {
68+
return super.clone();
69+
}
70+
71+
/**
72+
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
73+
*/
74+
@Override
75+
public void cloneFields(Cloner cloner, Object original) {
76+
// no-op
5877
}
5978

6079
@Override

jme3-core/src/main/java/com/jme3/audio/Listener.java

Lines changed: 105 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009-2012 jMonkeyEngine
2+
* Copyright (c) 2009-2025 jMonkeyEngine
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,11 @@
3434
import com.jme3.math.Quaternion;
3535
import com.jme3.math.Vector3f;
3636

37+
/**
38+
* Represents the audio listener in the 3D sound scene.
39+
* The listener defines the point of view from which sound is heard,
40+
* influencing spatial audio effects like panning and Doppler shift.
41+
*/
3742
public class Listener {
3843

3944
private final Vector3f location;
@@ -42,72 +47,159 @@ public class Listener {
4247
private float volume = 1;
4348
private AudioRenderer renderer;
4449

50+
/**
51+
* Constructs a new {@code Listener} with default parameters.
52+
*/
4553
public Listener() {
4654
location = new Vector3f();
4755
velocity = new Vector3f();
4856
rotation = new Quaternion();
4957
}
5058

59+
/**
60+
* Constructs a new {@code Listener} by copying the properties of another {@code Listener}.
61+
*
62+
* @param source The {@code Listener} to copy the properties from.
63+
*/
5164
public Listener(Listener source) {
52-
location = source.location.clone();
53-
velocity = source.velocity.clone();
54-
rotation = source.rotation.clone();
55-
volume = source.volume;
65+
this.location = source.location.clone();
66+
this.velocity = source.velocity.clone();
67+
this.rotation = source.rotation.clone();
68+
this.volume = source.volume;
69+
this.renderer = source.renderer; // Note: Renderer is also copied
5670
}
5771

72+
/**
73+
* Sets the {@link AudioRenderer} associated with this listener.
74+
* The renderer is responsible for applying the listener's parameters
75+
* to the audio output.
76+
*
77+
* @param renderer The {@link AudioRenderer} to associate with.
78+
*/
5879
public void setRenderer(AudioRenderer renderer) {
5980
this.renderer = renderer;
6081
}
6182

83+
/**
84+
* Gets the current volume of the listener.
85+
*
86+
* @return The current volume.
87+
*/
6288
public float getVolume() {
6389
return volume;
6490
}
6591

92+
/**
93+
* Sets the volume of the listener.
94+
* If an {@link AudioRenderer} is set, it will be notified of the volume change.
95+
*
96+
* @param volume The new volume.
97+
*/
6698
public void setVolume(float volume) {
6799
this.volume = volume;
68-
if (renderer != null)
69-
renderer.updateListenerParam(this, ListenerParam.Volume);
100+
updateListenerParam(ListenerParam.Volume);
70101
}
71102

103+
/**
104+
* Gets the current location of the listener in world space.
105+
*
106+
* @return The listener's location as a {@link Vector3f}.
107+
*/
72108
public Vector3f getLocation() {
73109
return location;
74110
}
75111

112+
/**
113+
* Gets the current rotation of the listener in world space.
114+
*
115+
* @return The listener's rotation as a {@link Quaternion}.
116+
*/
76117
public Quaternion getRotation() {
77118
return rotation;
78119
}
79120

121+
/**
122+
* Gets the current velocity of the listener.
123+
* This is used for Doppler effect calculations.
124+
*
125+
* @return The listener's velocity as a {@link Vector3f}.
126+
*/
80127
public Vector3f getVelocity() {
81128
return velocity;
82129
}
83130

131+
/**
132+
* Gets the left direction vector of the listener.
133+
* This vector is derived from the listener's rotation.
134+
*
135+
* @return The listener's left direction as a {@link Vector3f}.
136+
*/
84137
public Vector3f getLeft() {
85138
return rotation.getRotationColumn(0);
86139
}
87140

141+
/**
142+
* Gets the up direction vector of the listener.
143+
* This vector is derived from the listener's rotation.
144+
*
145+
* @return The listener's up direction as a {@link Vector3f}.
146+
*/
88147
public Vector3f getUp() {
89148
return rotation.getRotationColumn(1);
90149
}
91150

151+
/**
152+
* Gets the forward direction vector of the listener.
153+
* This vector is derived from the listener's rotation.
154+
*
155+
* @return The listener's forward direction.
156+
*/
92157
public Vector3f getDirection() {
93158
return rotation.getRotationColumn(2);
94159
}
95160

161+
/**
162+
* Sets the location of the listener in world space.
163+
* If an {@link AudioRenderer} is set, it will be notified of the position change.
164+
*
165+
* @param location The new location of the listener.
166+
*/
96167
public void setLocation(Vector3f location) {
97168
this.location.set(location);
98-
if (renderer != null)
99-
renderer.updateListenerParam(this, ListenerParam.Position);
169+
updateListenerParam(ListenerParam.Position);
100170
}
101171

172+
/**
173+
* Sets the rotation of the listener in world space.
174+
* If an {@link AudioRenderer} is set, it will be notified of the rotation change.
175+
*
176+
* @param rotation The new rotation of the listener.
177+
*/
102178
public void setRotation(Quaternion rotation) {
103179
this.rotation.set(rotation);
104-
if (renderer != null)
105-
renderer.updateListenerParam(this, ListenerParam.Rotation);
180+
updateListenerParam(ListenerParam.Rotation);
106181
}
107182

183+
/**
184+
* Sets the velocity of the listener.
185+
* This is used for Doppler effect calculations.
186+
* If an {@link AudioRenderer} is set, it will be notified of the velocity change.
187+
*
188+
* @param velocity The new velocity of the listener.
189+
*/
108190
public void setVelocity(Vector3f velocity) {
109191
this.velocity.set(velocity);
110-
if (renderer != null)
111-
renderer.updateListenerParam(this, ListenerParam.Velocity);
192+
updateListenerParam(ListenerParam.Velocity);
193+
}
194+
195+
/**
196+
* Updates the associated {@link AudioRenderer} with the specified listener parameter.
197+
*
198+
* @param param The {@link ListenerParam} to update on the renderer.
199+
*/
200+
private void updateListenerParam(ListenerParam param) {
201+
if (renderer != null) {
202+
renderer.updateListenerParam(this, param);
203+
}
112204
}
113205
}

0 commit comments

Comments
 (0)