Skip to content

Commit 1673d9d

Browse files
authored
Merge branch 'master' into gamepad
2 parents c7126e2 + 2b00e52 commit 1673d9d

File tree

28 files changed

+2866
-14
lines changed

28 files changed

+2866
-14
lines changed

.github/workflows/bounty.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
name: Bounty detector
2+
3+
on:
4+
issues:
5+
types: [labeled]
6+
7+
permissions:
8+
issues: write
9+
pull-requests: read
10+
11+
jobs:
12+
notify:
13+
runs-on: ubuntu-latest
14+
if: startsWith(github.event.label.name, 'diff:')
15+
steps:
16+
- name: Comment bounty info
17+
uses: actions/github-script@v7
18+
env:
19+
FORUM_URL: "https://hub.jmonkeyengine.org/t/bounty-program-trial-starts-today/49394/"
20+
RESERVE_HOURS: "48"
21+
TIMER_SVG_BASE: "https://jme-bounty-reservation-indicator.rblb.workers.dev/timer.svg"
22+
with:
23+
script: |
24+
const issue = context.payload.issue;
25+
const actor = context.actor;
26+
const issueOwner = issue.user?.login;
27+
if (!issueOwner) return;
28+
29+
const forumUrl = process.env.FORUM_URL || "TBD";
30+
const reserveHours = Number(process.env.RESERVE_HOURS || "48");
31+
const svgBase = process.env.TIMER_SVG_BASE || "";
32+
33+
// "previous contributor" = has at least one merged PR authored in this repo
34+
const repoFull = `${context.repo.owner}/${context.repo.repo}`;
35+
const q = `repo:${repoFull} type:pr author:${issueOwner} is:merged`;
36+
37+
let isPreviousContributor = false;
38+
try {
39+
const search = await github.rest.search.issuesAndPullRequests({ q, per_page: 1 });
40+
isPreviousContributor = (search.data.total_count ?? 0) > 0;
41+
} catch (e) {
42+
isPreviousContributor = false;
43+
}
44+
45+
// Reserve only if previous contributor AND labeler is NOT the issue owner
46+
const shouldReserve = isPreviousContributor && (actor !== issueOwner);
47+
48+
const lines = [];
49+
lines.push(`## 💰 This issue has a bounty`);
50+
lines.push(`Resolve it to receive a reward.`);
51+
lines.push(`For details (amount, rules, eligibility), see: ${forumUrl}`);
52+
lines.push("");
53+
54+
lines.push(`If you want to start working on this, **comment on this issue** with your intent.`);
55+
lines.push(`If accepted by a maintainer, the issue will be **assigned** to you.`);
56+
lines.push("");
57+
58+
if (shouldReserve && svgBase) {
59+
const reservedUntil = new Date(Date.now() + reserveHours * 60 * 60 * 1000);
60+
const reservedUntilIso = reservedUntil.toISOString();
61+
62+
const svgUrl =
63+
`${svgBase}` +
64+
`?until=${encodeURIComponent(reservedUntilIso)}` +
65+
`&user=${encodeURIComponent(issueOwner)}` +
66+
`&theme=dark`;
67+
68+
lines.push(`![bounty reservation](${svgUrl})`);
69+
lines.push("");
70+
}
71+
72+
// Avoid duplicate comments for the same label
73+
const comments = await github.rest.issues.listComments({
74+
owner: context.repo.owner,
75+
repo: context.repo.repo,
76+
issue_number: issue.number,
77+
per_page: 100,
78+
});
79+
80+
const already = comments.data.some(c =>
81+
c.user?.login === "github-actions[bot]" &&
82+
typeof c.body === "string" &&
83+
c.body.includes("This issue has a bounty")
84+
);
85+
86+
if (already) return;
87+
88+
await github.rest.issues.createComment({
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
issue_number: issue.number,
92+
body: lines.join("\n"),
93+
});

jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ public void glGetBufferSubData(int target, long offset, ByteBuffer data) {
163163
throw new UnsupportedOperationException("OpenGL ES 2 does not support glGetBufferSubData");
164164
}
165165

166+
@Override
167+
public void glGetBufferSubData(int target, long offset, IntBuffer data) {
168+
throw new UnsupportedOperationException("OpenGL ES 2 does not support glGetBufferSubData");
169+
}
170+
166171
@Override
167172
public void glClear(int mask) {
168173
GLES20.glClear(mask);

jme3-core/src/main/java/com/jme3/light/PointLight.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,12 @@ public final void setRadius(float radius) {
165165
if (radius < 0) {
166166
throw new IllegalArgumentException("Light radius cannot be negative");
167167
}
168-
169-
if (radius == Float.POSITIVE_INFINITY) {
170-
radius = Float.MAX_VALUE;
168+
if(Float.isNaN(radius)){
169+
throw new IllegalArgumentException("Light radius cannot be a NaN (Not a Number) value");
171170
}
171+
172+
float maxSafeRadius = Float.MAX_VALUE / 4.0f;
173+
radius = Math.min(radius, maxSafeRadius); // Caps radius to a safe large value; avoids overflow in shaders from values reaching max float value
172174

173175
this.radius = radius;
174176
if (radius != 0f) {
@@ -259,3 +261,5 @@ public String toString() {
259261
+ "]";
260262
}
261263
}
264+
265+

jme3-core/src/main/java/com/jme3/renderer/Renderer.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import com.jme3.material.RenderState;
3535
import com.jme3.math.ColorRGBA;
36+
import com.jme3.renderer.opengl.GLFence;
3637
import com.jme3.scene.Mesh;
3738
import com.jme3.scene.VertexBuffer;
3839
import com.jme3.shader.bufferobject.BufferObject;
@@ -552,5 +553,11 @@ public default void pushDebugGroup(String name) {
552553

553554
public void setShaderStorageBufferObject(int bindingPoint, BufferObject bufferObject) ;
554555
public void setUniformBufferObject(int bindingPoint, BufferObject bufferObject) ;
555-
556+
557+
public void deleteFence(GLFence fence);
558+
559+
/**
560+
* Registers a NativeObject to be cleaned up by this renderer.
561+
*/
562+
public void registerNativeObject(NativeObject nativeObject);
556563
}

jme3-core/src/main/java/com/jme3/renderer/RendererException.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,7 @@ public class RendererException extends RuntimeException {
4747
public RendererException(String message) {
4848
super(message);
4949
}
50+
public RendererException(Exception e) {
51+
super(e);
52+
}
5053
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (c) 2009-2026 jMonkeyEngine
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are
7+
* met:
8+
*
9+
* * Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
*
12+
* * Redistributions in binary form must reproduce the above copyright
13+
* notice, this list of conditions and the following disclaimer in the
14+
* documentation and/or other materials provided with the distribution.
15+
*
16+
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17+
* may be used to endorse or promote products derived from this software
18+
* without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
package com.jme3.renderer.opengl;
33+
34+
import com.jme3.math.Matrix4f;
35+
import com.jme3.math.Vector2f;
36+
import com.jme3.math.Vector3f;
37+
import com.jme3.math.Vector4f;
38+
import com.jme3.renderer.RendererException;
39+
import com.jme3.util.BufferUtils;
40+
import com.jme3.util.NativeObject;
41+
42+
import java.nio.FloatBuffer;
43+
import java.nio.IntBuffer;
44+
45+
/**
46+
* A compute shader for general-purpose GPU computing (GPGPU).
47+
* <p>
48+
* Compute shaders require OpenGL 4.3 or higher.
49+
*/
50+
public class ComputeShader extends NativeObject {
51+
52+
private final GL4 gl;
53+
private final String source;
54+
/**
55+
* Creates a new compute shader from GLSL source code.
56+
*/
57+
public ComputeShader(GL4 gl, String source) {
58+
super();
59+
this.gl = gl;
60+
this.source = source;
61+
//Load this upfront to surface any problems at init time
62+
createComputeShader();
63+
}
64+
private ComputeShader(ComputeShader source){
65+
super();
66+
this.gl = source.gl;
67+
this.id = source.id;
68+
this.source = null;
69+
}
70+
71+
private void createComputeShader(){
72+
// Create and compile the shader
73+
int shaderId = gl.glCreateShader(GL4.GL_COMPUTE_SHADER);
74+
if (shaderId <= 0) {
75+
throw new RendererException("Failed to create compute shader");
76+
}
77+
78+
IntBuffer intBuf = BufferUtils.createIntBuffer(1);
79+
intBuf.clear();
80+
intBuf.put(0, source.length());
81+
gl.glShaderSource(shaderId, new String[]{source}, intBuf);
82+
gl.glCompileShader(shaderId);
83+
84+
// Check compilation status
85+
gl.glGetShader(shaderId, GL.GL_COMPILE_STATUS, intBuf);
86+
if (intBuf.get(0) != GL.GL_TRUE) {
87+
gl.glGetShader(shaderId, GL.GL_INFO_LOG_LENGTH, intBuf);
88+
String infoLog = gl.glGetShaderInfoLog(shaderId, intBuf.get(0));
89+
gl.glDeleteShader(shaderId);
90+
throw new RendererException("Compute shader compilation failed: " + infoLog);
91+
}
92+
93+
// Create program and link
94+
id = gl.glCreateProgram();
95+
if (id <= 0) {
96+
gl.glDeleteShader(shaderId);
97+
throw new RendererException("Failed to create shader program");
98+
}
99+
100+
gl.glAttachShader(id, shaderId);
101+
gl.glLinkProgram(id);
102+
103+
// Check link status
104+
gl.glGetProgram(id, GL.GL_LINK_STATUS, intBuf);
105+
if (intBuf.get(0) != GL.GL_TRUE) {
106+
gl.glGetProgram(id, GL.GL_INFO_LOG_LENGTH, intBuf);
107+
String infoLog = gl.glGetProgramInfoLog(id, intBuf.get(0));
108+
gl.glDeleteShader(shaderId);
109+
gl.glDeleteProgram(id);
110+
throw new RendererException("Compute shader program linking failed: " + infoLog);
111+
}
112+
113+
// Shader object can be deleted after linking
114+
gl.glDeleteShader(shaderId);
115+
116+
clearUpdateNeeded();
117+
}
118+
119+
/**
120+
* Activates this compute shader for use.
121+
* Must be called before setting uniforms or dispatching.
122+
*/
123+
public void makeActive() {
124+
if(isUpdateNeeded()){
125+
createComputeShader();
126+
}
127+
gl.glUseProgram(id);
128+
}
129+
130+
/**
131+
* Dispatches the compute shader with the specified number of work groups.
132+
*/
133+
public void dispatch(int numGroupsX, int numGroupsY, int numGroupsZ) {
134+
gl.glDispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
135+
}
136+
137+
public void setUniform(int location, int value) {
138+
gl.glUniform1i(location, value);
139+
}
140+
141+
public void setUniform(int location, float value) {
142+
gl.glUniform1f(location, value);
143+
}
144+
145+
public void setUniform(int location, Vector2f value) {
146+
gl.glUniform2f(location, value.x, value.y);
147+
}
148+
149+
public void setUniform(int location, Vector3f value) {
150+
gl.glUniform3f(location, value.x, value.y, value.z);
151+
}
152+
153+
public void setUniform(int location, Vector4f value) {
154+
gl.glUniform4f(location, value.x, value.y, value.z, value.w);
155+
}
156+
157+
public void setUniform(int location, Matrix4f value) {
158+
FloatBuffer floatBuf16 = BufferUtils.createFloatBuffer(16);
159+
value.fillFloatBuffer(floatBuf16, true);
160+
floatBuf16.clear();
161+
gl.glUniformMatrix4(location, false, floatBuf16);
162+
}
163+
164+
public int getUniformLocation(String name) {
165+
return gl.glGetUniformLocation(id, name);
166+
}
167+
168+
public void bindShaderStorageBuffer(int location, ShaderStorageBufferObject ssbo) {
169+
gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, location, ssbo.getId());
170+
}
171+
172+
@Override
173+
public void resetObject() {
174+
id = INVALID_ID;
175+
setUpdateNeeded();
176+
}
177+
178+
@Override
179+
public void deleteObject(Object rendererObject) {
180+
if(id != INVALID_ID){
181+
gl.glDeleteProgram(id);
182+
}
183+
resetObject();
184+
}
185+
186+
@Override
187+
public NativeObject createDestructableClone() {
188+
return new ComputeShader(this);
189+
}
190+
191+
@Override
192+
public long getUniqueId() {
193+
//Note this is the same type of ID as a regular shader.
194+
return ((long)OBJTYPE_SHADER << 32) | (0xffffffffL & (long)id);
195+
}
196+
}

jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,11 @@ public interface GL {
424424
*/
425425
public void glBufferData(int target, ByteBuffer data, int usage);
426426

427+
/**
428+
* See {@link #glBufferData(int, ByteBuffer, int)}
429+
*/
430+
public void glBufferData(int target, IntBuffer data, int usage);
431+
427432
/**
428433
* <p><a target="_blank" href="http://docs.gl/gl4/glBufferSubData">Reference Page</a></p>
429434
* <p>
@@ -824,6 +829,11 @@ public void glCompressedTexSubImage2D(int target, int level, int xoffset, int yo
824829
*/
825830
public void glGetBufferSubData(int target, long offset, ByteBuffer data);
826831

832+
/**
833+
* See {@link #glGetBufferSubData(int, long, ByteBuffer)}
834+
*/
835+
public void glGetBufferSubData(int target, long offset, IntBuffer data);
836+
827837
/**
828838
* <p><a target="_blank" href="http://docs.gl/gl4/glGetError">Reference Page</a></p>
829839
*

0 commit comments

Comments
 (0)