Answer legacy stack and client state queries from GLSM (#2211)

This commit is contained in:
Jason Mitchell authored and GitHub committed 2026-10-04 11:43:56 -07:00
1 parent 0a4d48964e
commit 6dfb0312b1
13 files changed
+1110 -149

No files matched your search

@@ -30,7 +30,7 @@ import com.gtnewhorizons.angelica.glsm.states.AlphaState;
import com.gtnewhorizons.angelica.glsm.states.BlendState;
import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
import com.gtnewhorizons.angelica.glsm.states.Color4;
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
import com.gtnewhorizons.angelica.glsm.states.ImageUnitArray;
import com.gtnewhorizons.angelica.glsm.states.SamplerUnitArray;
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
@@ -231,9 +231,16 @@ public class GLContextState {
public int boundCopyReadBuffer;
public int boundCopyWriteBuffer;
public final Int2IntMap boundOtherBuffers = new Int2IntOpenHashMap();
public PixelUnpackState pixelUnpackState = PixelUnpackState.DEFAULT;
public PixelStoreState pixelUnpackState = PixelStoreState.DEFAULT;
public PixelStoreState pixelPackState = PixelStoreState.DEFAULT;
public final int[] clientAttribSavedMask = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public final PixelStoreState[] clientAttribSavedPixelUnpack = new PixelStoreState[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public final PixelStoreState[] clientAttribSavedPixelPack = new PixelStoreState[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public final int[] clientAttribSavedUnpackBuffer = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public final int[] clientAttribSavedPackBuffer = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public final int[] clientAttribSavedTextureUnit = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public final int[] clientAttribSavedVertexFlags = new int[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public final boolean[] clientAttribSavedVertexArray = new boolean[GLStateManager.CLIENT_ATTRIB_STACK_DEPTH];
public int clientAttribStackPointer = 0;
public int restoreChangedMask;
public long restoreUnitChangedMask;
@@ -61,7 +61,7 @@ import com.gtnewhorizons.angelica.glsm.states.BlendState;
import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
import com.gtnewhorizons.angelica.glsm.states.Color4;
import com.gtnewhorizons.angelica.glsm.states.ColorMask;
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
import com.gtnewhorizons.angelica.glsm.states.PolygonState;
import com.gtnewhorizons.angelica.glsm.states.SamplerUnitArray;
import com.gtnewhorizons.angelica.glsm.states.ImageUnitBinding;
@@ -327,6 +327,7 @@ public class GLStateManager {
public static final int MAX_TEXTURE_STACK_DEPTH = 4;
public static final int MAX_CLIP_PLANES = 8;
public static final int MAX_TEXTURE_UNITS = RENDER_BACKEND.getInteger(GL20.GL_MAX_TEXTURE_IMAGE_UNITS);
public static final int MAX_LEGACY_TEXTURE_UNITS = Math.min(VertexKey.MAX_UNITS, MAX_TEXTURE_UNITS);
public static final GLFeatureSet HAS_MULTIPLE_SET = new GLFeatureSet();
@@ -1192,11 +1193,35 @@ public class GLStateManager {
case GL11.GL_LINE_STIPPLE_PATTERN -> glCtx.lineState.getStipplePattern() & 0xFFFF;
case GL11.GL_LINE_STIPPLE_REPEAT -> glCtx.lineState.getStippleFactor();
case GL11.GL_LIST_INDEX -> DisplayListManager.isRecording() ? Math.max(DisplayListManager.getRecordingListId(), 0) : 0;
case GL11.GL_ATTRIB_STACK_DEPTH -> glCtx.attribDepth;
case GL11.GL_CLIENT_ATTRIB_STACK_DEPTH -> glCtx.clientAttribStackPointer;
case GL11.GL_TEXTURE_STACK_DEPTH -> getMatrixStackDepth(glCtx.textures.getTextureUnitMatrix(glCtx.activeTextureUnit.getValue()));
case GL11.GL_MAX_ATTRIB_STACK_DEPTH -> MAX_ATTRIB_STACK_DEPTH;
case GL11.GL_MAX_CLIENT_ATTRIB_STACK_DEPTH -> CLIENT_ATTRIB_STACK_DEPTH;
case GL11.GL_MAX_MODELVIEW_STACK_DEPTH -> MAX_MODELVIEW_STACK_DEPTH;
case GL11.GL_MAX_PROJECTION_STACK_DEPTH -> MAX_PROJECTION_STACK_DEPTH;
case GL11.GL_MAX_TEXTURE_STACK_DEPTH -> MAX_TEXTURE_STACK_DEPTH;
case GL13.GL_MAX_TEXTURE_UNITS -> MAX_LEGACY_TEXTURE_UNITS;
case GL11.GL_MAX_LIGHTS -> glCtx.lightStates.length;
case GL11.GL_STENCIL_BITS -> drawFramebufferBits(glCtx, true);
case GL11.GL_DEPTH_BITS -> drawFramebufferBits(glCtx, false);
default -> RENDER_BACKEND.getInteger(pname);
};
};
}
private static int drawFramebufferBits(GLContextState glCtx, boolean stencil) {
final int sizePname = stencil ? GL30.GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE : GL30.GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE;
if (glCtx.drawFramebuffer == 0) {
return RENDER_BACKEND.getFramebufferAttachmentParameteri(GL30.GL_DRAW_FRAMEBUFFER, stencil ? GL11.GL_STENCIL : GL11.GL_DEPTH, sizePname);
}
final int attachment = stencil ? GL30.GL_STENCIL_ATTACHMENT : GL30.GL_DEPTH_ATTACHMENT;
if (RENDER_BACKEND.getFramebufferAttachmentParameteri(GL30.GL_DRAW_FRAMEBUFFER, attachment, GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) == GL11.GL_NONE) {
return 0;
}
return RENDER_BACKEND.getFramebufferAttachmentParameteri(GL30.GL_DRAW_FRAMEBUFFER, attachment, sizePname);
}
public static void glGetInteger(int pname, IntBuffer params) {
if (!isCachingEnabled()) {
RENDER_BACKEND.getInteger(pname, params);
@@ -1245,6 +1270,48 @@ public class GLStateManager {
}
}
private static void putLightingInts(FloatBuffer values, int pname, boolean material, IntBuffer params) {
final int count = switch (pname) {
case GL11.GL_AMBIENT, GL11.GL_DIFFUSE, GL11.GL_SPECULAR -> 4;
case GL11.GL_EMISSION -> material ? 4 : 0;
case GL11.GL_COLOR_INDEXES -> material ? 3 : 0;
case GL11.GL_SHININESS -> material ? 1 : 0;
case GL11.GL_POSITION -> material ? 0 : 4;
case GL11.GL_SPOT_DIRECTION -> material ? 0 : 3;
case GL11.GL_SPOT_EXPONENT, GL11.GL_SPOT_CUTOFF, GL11.GL_CONSTANT_ATTENUATION, GL11.GL_LINEAR_ATTENUATION,
GL11.GL_QUADRATIC_ATTENUATION -> material ? 0 : 1;
default -> 0;
};
final boolean color = count == 4 && pname != GL11.GL_POSITION;
final int pos = params.position();
for (int i = 0; i < count; i++) {
final float value = values.get(i);
final int converted;
if (color) {
converted = (int) (2147483647.0 * value);
} else if (material) {
converted = value < 0 ? -Math.round(-value) : Math.round(value);
} else {
converted = (int) value;
}
params.put(pos + i, converted);
}
}
public static void glGetMaterial(int face, int pname, IntBuffer params) {
final FloatBuffer scratch = ctx().queryScratch;
scratch.clear();
glGetMaterial(face, pname, scratch);
putLightingInts(scratch, pname, true, params);
}
public static void glGetLight(int light, int pname, IntBuffer params) {
final FloatBuffer scratch = ctx().queryScratch;
scratch.clear();
glGetLight(light, pname, scratch);
putLightingInts(scratch, pname, false, params);
}
public static void glGetLight(int light, int pname, FloatBuffer params) {
final LightStateStack state = ctx().lightDataStates[light - GL11.GL_LIGHT0];
switch (pname) {
@@ -1297,12 +1364,25 @@ public class GLStateManager {
params.put(pos + 2, normal.z);
}
case GL11.GL_CURRENT_TEXTURE_COORDS -> {
final Vector4f tc = glCtx.ffp.currentTexCoords[0];
final int unit = glCtx.activeTextureUnit.getValue();
final int pos = params.position();
params.put(pos, tc.x);
params.put(pos + 1, tc.y);
params.put(pos + 2, tc.z);
params.put(pos + 3, tc.w);
if (unit == 1) {
params.put(pos, glCtx.lastBrightnessX);
params.put(pos + 1, glCtx.lastBrightnessY);
params.put(pos + 2, 0.0f);
params.put(pos + 3, 1.0f);
} else if (unit >= 0 && unit < glCtx.ffp.currentTexCoords.length) {
final Vector4f tc = glCtx.ffp.currentTexCoords[unit];
params.put(pos, tc.x);
params.put(pos + 1, tc.y);
params.put(pos + 2, tc.z);
params.put(pos + 3, tc.w);
} else {
params.put(pos, 0.0f);
params.put(pos + 1, 0.0f);
params.put(pos + 2, 0.0f);
params.put(pos + 3, 1.0f);
}
}
case GL11.GL_FOG_COLOR -> {
final FloatBuffer fogBuf = glCtx.fogState.getFogColorBuffer();
@@ -3258,22 +3338,63 @@ public class GLStateManager {
};
}
private static boolean isPositionArrayEnabled(GLContextState glCtx) {
final VAOManager.Attrib position = glCtx.vaos.attrib(Usage.POSITION.getAttributeLocation());
return position != null && position.enabled;
}
static final int CLIENT_ATTRIB_STACK_DEPTH = 16;
public static void glPushClientAttrib(int mask) {
final GLContextState glCtx = ctx();
if (glCtx.clientAttribStackPointer < CLIENT_ATTRIB_STACK_DEPTH) {
glCtx.clientAttribSavedTextureUnit[glCtx.clientAttribStackPointer] = glCtx.clientActiveTextureUnit;
glCtx.clientAttribSavedVertexFlags[glCtx.clientAttribStackPointer] = glCtx.vaos.getVertexFlags();
glCtx.clientAttribStackPointer++;
final int sp = glCtx.clientAttribStackPointer;
if (sp < CLIENT_ATTRIB_STACK_DEPTH) {
glCtx.clientAttribSavedMask[sp] = mask;
if ((mask & GL11.GL_CLIENT_PIXEL_STORE_BIT) != 0) {
glCtx.clientAttribSavedPixelPack[sp] = glCtx.pixelPackState;
glCtx.clientAttribSavedPixelUnpack[sp] = glCtx.pixelUnpackState;
glCtx.clientAttribSavedPackBuffer[sp] = glCtx.boundPixelPackBuffer;
glCtx.clientAttribSavedUnpackBuffer[sp] = glCtx.boundPixelUnpackBuffer;
}
if ((mask & GL11.GL_CLIENT_VERTEX_ARRAY_BIT) != 0) {
glCtx.clientAttribSavedTextureUnit[sp] = glCtx.clientActiveTextureUnit;
glCtx.clientAttribSavedVertexFlags[sp] = glCtx.vaos.getVertexFlags();
glCtx.clientAttribSavedVertexArray[sp] = isPositionArrayEnabled(glCtx);
}
glCtx.clientAttribStackPointer = sp + 1;
}
}
public static void glPopClientAttrib() {
final GLContextState glCtx = ctx();
if (glCtx.clientAttribStackPointer > 0) {
glCtx.clientAttribStackPointer--;
glCtx.clientActiveTextureUnit = glCtx.clientAttribSavedTextureUnit[glCtx.clientAttribStackPointer];
glCtx.vaos.setVertexFlags(glCtx.clientAttribSavedVertexFlags[glCtx.clientAttribStackPointer]);
final int sp = --glCtx.clientAttribStackPointer;
final int mask = glCtx.clientAttribSavedMask[sp];
if ((mask & GL11.GL_CLIENT_PIXEL_STORE_BIT) != 0) {
final PixelStoreState pack = glCtx.clientAttribSavedPixelPack[sp];
final PixelStoreState unpack = glCtx.clientAttribSavedPixelUnpack[sp];
glCtx.clientAttribSavedPixelPack[sp] = null;
glCtx.clientAttribSavedPixelUnpack[sp] = null;
PixelStoreState.applyDiff(glCtx.pixelPackState, pack, true);
glCtx.pixelPackState = pack;
PixelStoreState.applyDiff(glCtx.pixelUnpackState, unpack, false);
glCtx.pixelUnpackState = unpack;
final int packBuffer = glCtx.clientAttribSavedPackBuffer[sp];
if (glCtx.boundPixelPackBuffer != packBuffer) glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, packBuffer);
final int unpackBuffer = glCtx.clientAttribSavedUnpackBuffer[sp];
if (glCtx.boundPixelUnpackBuffer != unpackBuffer) glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
}
if ((mask & GL11.GL_CLIENT_VERTEX_ARRAY_BIT) != 0) {
glCtx.clientActiveTextureUnit = glCtx.clientAttribSavedTextureUnit[sp];
glCtx.vaos.setVertexFlags(glCtx.clientAttribSavedVertexFlags[sp]);
final boolean vertexArray = glCtx.clientAttribSavedVertexArray[sp];
if (isPositionArrayEnabled(glCtx) != vertexArray) {
if (vertexArray) {
glEnableClientState(GL11.GL_VERTEX_ARRAY);
} else {
glDisableClientState(GL11.GL_VERTEX_ARRAY);
}
}
}
}
}
@@ -4530,6 +4651,10 @@ public class GLStateManager {
return;
}
}
if (ctx().attribDepth == 0) {
warnOnce("popattrib-underflow", "glPopAttrib called with an empty attrib stack; ignoring");
return;
}
GLDebug.popGroup();
GLDebug.pushGroup("popState");
try {
@@ -6411,7 +6536,11 @@ public class GLStateManager {
public static void glPixelStorei(int pname, int param) {
final GLContextState glCtx = ctx();
if (isCachingEnabled()) {
glCtx.pixelUnpackState = glCtx.pixelUnpackState.with(pname, param);
if (PixelStoreState.isPack(pname)) {
glCtx.pixelPackState = glCtx.pixelPackState.with(pname, param);
} else {
glCtx.pixelUnpackState = glCtx.pixelUnpackState.with(pname, param);
}
}
RENDER_BACKEND.pixelStorei(pname, param);
}
@@ -6712,12 +6841,12 @@ public class GLStateManager {
}
}
public static void forcePixelUnpackState(PixelUnpackState target) {
PixelUnpackState.applyDiff(ctx().pixelUnpackState, target);
public static void forcePixelUnpackState(PixelStoreState target) {
PixelStoreState.applyDiff(ctx().pixelUnpackState, target, false);
}
public static void restorePixelUnpackState(PixelUnpackState applied) {
PixelUnpackState.applyDiff(applied, ctx().pixelUnpackState);
public static void restorePixelUnpackState(PixelStoreState applied) {
PixelStoreState.applyDiff(applied, ctx().pixelUnpackState, false);
}
private static boolean warnedUntrackedPixelBuffer;
@@ -1,6 +1,6 @@
package com.gtnewhorizons.angelica.glsm;
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
@@ -25,10 +25,10 @@ public final class LTWWorkaround {
oneTexel = BufferUtils.createByteBuffer(4);
}
oneTexel.clear();
GLStateManager.forcePixelUnpackState(PixelUnpackState.DEFAULT);
GLStateManager.forcePixelUnpackState(PixelStoreState.DEFAULT);
GLStateManager.suspendPixelUnpackBuffer();
RENDER_BACKEND.texSubImage2D(target, level, 0, 0, 1, 1, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, oneTexel);
GLStateManager.restorePixelUnpackBuffer();
GLStateManager.restorePixelUnpackState(PixelUnpackState.DEFAULT);
GLStateManager.restorePixelUnpackState(PixelStoreState.DEFAULT);
}
}
@@ -3,7 +3,7 @@ package com.gtnewhorizons.angelica.glsm.recording.commands;
import com.gtnewhorizons.angelica.glsm.GLDebug;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.GLTypes;
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,7 +28,7 @@ public record TexImage2DCmd(
int format,
int type,
@Nullable ByteBuffer pixels,
@Nullable PixelUnpackState unpack
@Nullable PixelStoreState unpack
) implements DisplayListCommand {
public TexImage2DCmd {
@@ -37,19 +37,19 @@ public record TexImage2DCmd(
}
}
public static TexImage2DCmd fromIntBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable IntBuffer pixels, PixelUnpackState unpack) {
public static TexImage2DCmd fromIntBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable IntBuffer pixels, PixelStoreState unpack) {
return new TexImage2DCmd(target, level, internalformat, width, height, border, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
public static TexImage2DCmd fromFloatBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable FloatBuffer pixels, PixelUnpackState unpack) {
public static TexImage2DCmd fromFloatBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable FloatBuffer pixels, PixelStoreState unpack) {
return new TexImage2DCmd(target, level, internalformat, width, height, border, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
public static TexImage2DCmd fromDoubleBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable DoubleBuffer pixels, PixelUnpackState unpack) {
public static TexImage2DCmd fromDoubleBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable DoubleBuffer pixels, PixelStoreState unpack) {
return new TexImage2DCmd(target, level, internalformat, width, height, border, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
public static TexImage2DCmd fromByteBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable ByteBuffer pixels, PixelUnpackState unpack) {
public static TexImage2DCmd fromByteBuffer(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable ByteBuffer pixels, PixelStoreState unpack) {
return new TexImage2DCmd(target, level, internalformat, width, height, border, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
@@ -3,7 +3,7 @@ package com.gtnewhorizons.angelica.glsm.recording.commands;
import com.gtnewhorizons.angelica.glsm.GLDebug;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.GLTypes;
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,7 +28,7 @@ public record TexSubImage2DCmd(
int format,
int type,
@Nullable ByteBuffer pixels,
@Nullable PixelUnpackState unpack
@Nullable PixelStoreState unpack
) implements DisplayListCommand {
public TexSubImage2DCmd {
@@ -37,19 +37,19 @@ public record TexSubImage2DCmd(
}
}
public static TexSubImage2DCmd fromIntBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable IntBuffer pixels, PixelUnpackState unpack) {
public static TexSubImage2DCmd fromIntBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable IntBuffer pixels, PixelStoreState unpack) {
return new TexSubImage2DCmd(target, level, xoffset, yoffset, width, height, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
public static TexSubImage2DCmd fromFloatBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable FloatBuffer pixels, PixelUnpackState unpack) {
public static TexSubImage2DCmd fromFloatBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable FloatBuffer pixels, PixelStoreState unpack) {
return new TexSubImage2DCmd(target, level, xoffset, yoffset, width, height, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
public static TexSubImage2DCmd fromDoubleBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable DoubleBuffer pixels, PixelUnpackState unpack) {
public static TexSubImage2DCmd fromDoubleBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable DoubleBuffer pixels, PixelStoreState unpack) {
return new TexSubImage2DCmd(target, level, xoffset, yoffset, width, height, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
public static TexSubImage2DCmd fromByteBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable ByteBuffer pixels, PixelUnpackState unpack) {
public static TexSubImage2DCmd fromByteBuffer(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, @Nullable ByteBuffer pixels, PixelStoreState unpack) {
return new TexSubImage2DCmd(target, level, xoffset, yoffset, width, height, format, type, PixelDataSnapshot.copy(pixels), unpack);
}
@@ -626,6 +626,7 @@ public class GLSMRedirector {
.add("glGenRenderbuffers")
.add("glRenderbufferStorage")
.add("glFramebufferRenderbuffer")
.add("glGenerateMipmap")
);
methodRedirects.put(EXTFramebufferObject, RedirectMap.newMap()
.add("glBindFramebufferEXT", "glBindFramebuffer")
@@ -638,6 +639,7 @@ public class GLSMRedirector {
.add("glGenRenderbuffersEXT", "glGenRenderbuffers")
.add("glRenderbufferStorageEXT", "glRenderbufferStorage")
.add("glFramebufferRenderbufferEXT", "glFramebufferRenderbuffer")
.add("glGenerateMipmapEXT", "glGenerateMipmap")
);
methodRedirects.put(ARBOcclusionQuery, RedirectMap.newMap()
.add("glGenQueriesARB", "glGenQueries")
@@ -0,0 +1,57 @@
package com.gtnewhorizons.angelica.glsm.states;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
public record PixelStoreState(
int alignment,
int rowLength,
int skipRows,
int skipPixels,
int imageHeight,
int skipImages,
boolean swapBytes,
boolean lsbFirst
) {
public static final PixelStoreState DEFAULT = new PixelStoreState(4, 0, 0, 0, 0, 0, false, false);
public boolean isDefault() {
return this.equals(DEFAULT);
}
public static boolean isPack(int pname) {
return switch (pname) {
case GL11.GL_PACK_ALIGNMENT, GL11.GL_PACK_ROW_LENGTH, GL11.GL_PACK_SKIP_ROWS, GL11.GL_PACK_SKIP_PIXELS,
GL12.GL_PACK_IMAGE_HEIGHT, GL12.GL_PACK_SKIP_IMAGES, GL11.GL_PACK_SWAP_BYTES, GL11.GL_PACK_LSB_FIRST -> true;
default -> false;
};
}
public PixelStoreState with(int pname, int param) {
return switch (pname) {
case GL11.GL_UNPACK_ALIGNMENT, GL11.GL_PACK_ALIGNMENT -> (param == alignment || (param != 1 && param != 2 && param != 4 && param != 8)) ? this : new PixelStoreState(param, rowLength, skipRows, skipPixels, imageHeight, skipImages, swapBytes, lsbFirst);
case GL11.GL_UNPACK_ROW_LENGTH, GL11.GL_PACK_ROW_LENGTH -> (param == rowLength || param < 0) ? this : new PixelStoreState(alignment, param, skipRows, skipPixels, imageHeight, skipImages, swapBytes, lsbFirst);
case GL11.GL_UNPACK_SKIP_ROWS, GL11.GL_PACK_SKIP_ROWS -> (param == skipRows || param < 0) ? this : new PixelStoreState(alignment, rowLength, param, skipPixels, imageHeight, skipImages, swapBytes, lsbFirst);
case GL11.GL_UNPACK_SKIP_PIXELS, GL11.GL_PACK_SKIP_PIXELS -> (param == skipPixels || param < 0) ? this : new PixelStoreState(alignment, rowLength, skipRows, param, imageHeight, skipImages, swapBytes, lsbFirst);
case GL12.GL_UNPACK_IMAGE_HEIGHT, GL12.GL_PACK_IMAGE_HEIGHT -> (param == imageHeight || param < 0) ? this : new PixelStoreState(alignment, rowLength, skipRows, skipPixels, param, skipImages, swapBytes, lsbFirst);
case GL12.GL_UNPACK_SKIP_IMAGES, GL12.GL_PACK_SKIP_IMAGES -> (param == skipImages || param < 0) ? this : new PixelStoreState(alignment, rowLength, skipRows, skipPixels, imageHeight, param, swapBytes, lsbFirst);
case GL11.GL_UNPACK_SWAP_BYTES, GL11.GL_PACK_SWAP_BYTES -> (param != 0) == swapBytes ? this : new PixelStoreState(alignment, rowLength, skipRows, skipPixels, imageHeight, skipImages, param != 0, lsbFirst);
case GL11.GL_UNPACK_LSB_FIRST, GL11.GL_PACK_LSB_FIRST -> (param != 0) == lsbFirst ? this : new PixelStoreState(alignment, rowLength, skipRows, skipPixels, imageHeight, skipImages, swapBytes, param != 0);
default -> this;
};
}
public static void applyDiff(PixelStoreState from, PixelStoreState to, boolean pack) {
if (from == to) return;
if (from.alignment != to.alignment) RENDER_BACKEND.pixelStorei(pack ? GL11.GL_PACK_ALIGNMENT : GL11.GL_UNPACK_ALIGNMENT, to.alignment);
if (from.rowLength != to.rowLength) RENDER_BACKEND.pixelStorei(pack ? GL11.GL_PACK_ROW_LENGTH : GL11.GL_UNPACK_ROW_LENGTH, to.rowLength);
if (from.skipRows != to.skipRows) RENDER_BACKEND.pixelStorei(pack ? GL11.GL_PACK_SKIP_ROWS : GL11.GL_UNPACK_SKIP_ROWS, to.skipRows);
if (from.skipPixels != to.skipPixels) RENDER_BACKEND.pixelStorei(pack ? GL11.GL_PACK_SKIP_PIXELS : GL11.GL_UNPACK_SKIP_PIXELS, to.skipPixels);
if (from.imageHeight != to.imageHeight) RENDER_BACKEND.pixelStorei(pack ? GL12.GL_PACK_IMAGE_HEIGHT : GL12.GL_UNPACK_IMAGE_HEIGHT, to.imageHeight);
if (from.skipImages != to.skipImages) RENDER_BACKEND.pixelStorei(pack ? GL12.GL_PACK_SKIP_IMAGES : GL12.GL_UNPACK_SKIP_IMAGES, to.skipImages);
if (from.swapBytes != to.swapBytes) RENDER_BACKEND.pixelStorei(pack ? GL11.GL_PACK_SWAP_BYTES : GL11.GL_UNPACK_SWAP_BYTES, to.swapBytes ? 1 : 0);
if (from.lsbFirst != to.lsbFirst) RENDER_BACKEND.pixelStorei(pack ? GL11.GL_PACK_LSB_FIRST : GL11.GL_UNPACK_LSB_FIRST, to.lsbFirst ? 1 : 0);
}
}
@@ -1,51 +0,0 @@
package com.gtnewhorizons.angelica.glsm.states;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
/**
* Immutable client-side pixel unpack state (glPixelStore UNPACK_* params)
*/
public record PixelUnpackState(
int alignment,
int rowLength,
int skipRows,
int skipPixels,
int imageHeight,
int skipImages,
boolean swapBytes,
boolean lsbFirst
) {
public static final PixelUnpackState DEFAULT = new PixelUnpackState(4, 0, 0, 0, 0, 0, false, false);
public boolean isDefault() {
return this.equals(DEFAULT);
}
public PixelUnpackState with(int pname, int param) {
return switch (pname) {
case GL11.GL_UNPACK_ALIGNMENT -> (param == 1 || param == 2 || param == 4 || param == 8) ? new PixelUnpackState(param, rowLength, skipRows, skipPixels, imageHeight, skipImages, swapBytes, lsbFirst) : this;
case GL11.GL_UNPACK_ROW_LENGTH -> param >= 0 ? new PixelUnpackState(alignment, param, skipRows, skipPixels, imageHeight, skipImages, swapBytes, lsbFirst) : this;
case GL11.GL_UNPACK_SKIP_ROWS -> param >= 0 ? new PixelUnpackState(alignment, rowLength, param, skipPixels, imageHeight, skipImages, swapBytes, lsbFirst) : this;
case GL11.GL_UNPACK_SKIP_PIXELS -> param >= 0 ? new PixelUnpackState(alignment, rowLength, skipRows, param, imageHeight, skipImages, swapBytes, lsbFirst) : this;
case GL12.GL_UNPACK_IMAGE_HEIGHT -> param >= 0 ? new PixelUnpackState(alignment, rowLength, skipRows, skipPixels, param, skipImages, swapBytes, lsbFirst) : this;
case GL12.GL_UNPACK_SKIP_IMAGES -> param >= 0 ? new PixelUnpackState(alignment, rowLength, skipRows, skipPixels, imageHeight, param, swapBytes, lsbFirst) : this;
case GL11.GL_UNPACK_SWAP_BYTES -> new PixelUnpackState(alignment, rowLength, skipRows, skipPixels, imageHeight, skipImages, param != 0, lsbFirst);
case GL11.GL_UNPACK_LSB_FIRST -> new PixelUnpackState(alignment, rowLength, skipRows, skipPixels, imageHeight, skipImages, swapBytes, param != 0);
default -> this;
};
}
public static void applyDiff(PixelUnpackState from, PixelUnpackState to) {
if (from.alignment != to.alignment) RENDER_BACKEND.pixelStorei(GL11.GL_UNPACK_ALIGNMENT, to.alignment);
if (from.rowLength != to.rowLength) RENDER_BACKEND.pixelStorei(GL11.GL_UNPACK_ROW_LENGTH, to.rowLength);
if (from.skipRows != to.skipRows) RENDER_BACKEND.pixelStorei(GL11.GL_UNPACK_SKIP_ROWS, to.skipRows);
if (from.skipPixels != to.skipPixels) RENDER_BACKEND.pixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, to.skipPixels);
if (from.imageHeight != to.imageHeight) RENDER_BACKEND.pixelStorei(GL12.GL_UNPACK_IMAGE_HEIGHT, to.imageHeight);
if (from.skipImages != to.skipImages) RENDER_BACKEND.pixelStorei(GL12.GL_UNPACK_SKIP_IMAGES, to.skipImages);
if (from.swapBytes != to.swapBytes) RENDER_BACKEND.pixelStorei(GL11.GL_UNPACK_SWAP_BYTES, to.swapBytes ? 1 : 0);
if (from.lsbFirst != to.lsbFirst) RENDER_BACKEND.pixelStorei(GL11.GL_UNPACK_LSB_FIRST, to.lsbFirst ? 1 : 0);
}
}
@@ -0,0 +1,737 @@
package com.gtnewhorizons.angelica.glsm;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormatElement.Usage;
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
import com.gtnewhorizons.angelica.glsm.ffp.VertexKey;
import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
import org.junit.jupiter.api.Test;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL21;
import org.lwjgl.opengl.GL30;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@GLCoreTest
public class GLSM_LegacyStackQueries_GLTest {
private static final int[] SINGLE_VALUE_QUERIES = {
GL11.GL_ATTRIB_STACK_DEPTH,
GL11.GL_CLIENT_ATTRIB_STACK_DEPTH,
GL11.GL_TEXTURE_STACK_DEPTH,
GL11.GL_MAX_ATTRIB_STACK_DEPTH,
GL11.GL_MAX_CLIENT_ATTRIB_STACK_DEPTH,
GL11.GL_MAX_MODELVIEW_STACK_DEPTH,
GL11.GL_MAX_PROJECTION_STACK_DEPTH,
GL11.GL_MAX_TEXTURE_STACK_DEPTH,
GL13.GL_MAX_TEXTURE_UNITS,
GL11.GL_MAX_LIGHTS,
GL11.GL_STENCIL_BITS,
GL11.GL_DEPTH_BITS,
};
private static boolean positionArrayEnabled() {
final VAOManager.Attrib position = GLStateManager.ctx().vaos.attrib(Usage.POSITION.getAttributeLocation());
return position != null && position.enabled;
}
private static boolean colorArrayEnabled() {
return (GLStateManager.ctx().vaos.getVertexFlags() & VertexFlags.COLOR_BIT) != 0;
}
private static void drainErrors() {
while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
}
private static void drainClientAttribStack() {
while (GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH) > 0) {
GLStateManager.glPopClientAttrib();
}
}
private static void drainAttribStack() {
while (GLStateManager.getAttribDepth() > 0) {
GLStateManager.glPopAttrib();
}
}
private static int pushToLimit(int depthPname, int maxPname) {
final int max = GLStateManager.glGetInteger(maxPname);
for (int i = 0; i < max + 4; i++) {
GLStateManager.glPushMatrix();
}
return GLStateManager.glGetInteger(depthPname);
}
private static void popToBase(int depthPname) {
for (int i = 0; i < 128 && GLStateManager.glGetInteger(depthPname) > 1; i++) {
GLStateManager.glPopMatrix();
}
}
@Test
void attribDepthTracksPushAndPop() {
final int base = GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH);
try {
GLStateManager.glPushAttrib(GL11.GL_ENABLE_BIT);
assertEquals(base + 1, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
GLStateManager.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT);
assertEquals(base + 2, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
GLStateManager.glPopAttrib();
assertEquals(base + 1, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
GLStateManager.glPopAttrib();
assertEquals(base, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
assertEquals(GLStateManager.MAX_ATTRIB_STACK_DEPTH, GLStateManager.glGetInteger(GL11.GL_MAX_ATTRIB_STACK_DEPTH));
} finally {
while (GLStateManager.getAttribDepth() > base) {
GLStateManager.glPopAttrib();
}
}
}
@Test
void clientAttribDepthTracksPushAndPop() {
try {
assertEquals(0, GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH));
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_PIXEL_STORE_BIT);
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH));
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_VERTEX_ARRAY_BIT);
assertEquals(2, GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH));
GLStateManager.glPopClientAttrib();
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH));
GLStateManager.glPopClientAttrib();
assertEquals(0, GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH));
GLStateManager.glPopClientAttrib();
assertEquals(0, GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH));
final int max = GLStateManager.glGetInteger(GL11.GL_MAX_CLIENT_ATTRIB_STACK_DEPTH);
for (int i = 0; i < max + 2; i++) {
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_PIXEL_STORE_BIT);
}
assertEquals(max, GLStateManager.glGetInteger(GL11.GL_CLIENT_ATTRIB_STACK_DEPTH));
} finally {
drainClientAttribStack();
}
}
@Test
void textureStackDepthIsPerActiveUnit() {
try {
GLStateManager.glMatrixMode(GL11.GL_TEXTURE);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_TEXTURE_STACK_DEPTH));
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.glPushMatrix();
assertEquals(2, GLStateManager.glGetInteger(GL11.GL_TEXTURE_STACK_DEPTH));
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_TEXTURE_STACK_DEPTH));
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
assertEquals(2, GLStateManager.glGetInteger(GL11.GL_TEXTURE_STACK_DEPTH));
GLStateManager.glPopMatrix();
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_TEXTURE_STACK_DEPTH));
} finally {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.glMatrixMode(GL11.GL_TEXTURE);
popToBase(GL11.GL_TEXTURE_STACK_DEPTH);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
}
}
@Test
void maxModelviewStackDepthIsExactlyReachable() {
try {
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_MODELVIEW_STACK_DEPTH));
assertEquals(GLStateManager.glGetInteger(GL11.GL_MAX_MODELVIEW_STACK_DEPTH), pushToLimit(GL11.GL_MODELVIEW_STACK_DEPTH, GL11.GL_MAX_MODELVIEW_STACK_DEPTH));
} finally {
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
popToBase(GL11.GL_MODELVIEW_STACK_DEPTH);
}
}
@Test
void maxProjectionStackDepthIsExactlyReachable() {
try {
GLStateManager.glMatrixMode(GL11.GL_PROJECTION);
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_PROJECTION_STACK_DEPTH));
assertEquals(GLStateManager.glGetInteger(GL11.GL_MAX_PROJECTION_STACK_DEPTH), pushToLimit(GL11.GL_PROJECTION_STACK_DEPTH, GL11.GL_MAX_PROJECTION_STACK_DEPTH));
} finally {
GLStateManager.glMatrixMode(GL11.GL_PROJECTION);
popToBase(GL11.GL_PROJECTION_STACK_DEPTH);
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
}
}
@Test
void maxTextureStackDepthIsExactlyReachable() {
try {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.glMatrixMode(GL11.GL_TEXTURE);
assertEquals(1, GLStateManager.glGetInteger(GL11.GL_TEXTURE_STACK_DEPTH));
assertEquals(GLStateManager.glGetInteger(GL11.GL_MAX_TEXTURE_STACK_DEPTH), pushToLimit(GL11.GL_TEXTURE_STACK_DEPTH, GL11.GL_MAX_TEXTURE_STACK_DEPTH));
} finally {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.glMatrixMode(GL11.GL_TEXTURE);
popToBase(GL11.GL_TEXTURE_STACK_DEPTH);
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
}
}
@Test
void constantQueriesReportEmulatedLimits() {
assertEquals(Math.min(VertexKey.MAX_UNITS, GLStateManager.MAX_TEXTURE_UNITS), GLStateManager.glGetInteger(GL13.GL_MAX_TEXTURE_UNITS));
assertEquals(8, GLStateManager.glGetInteger(GL11.GL_MAX_LIGHTS));
}
@Test
void stencilAndDepthBitsMatchDefaultFramebuffer() {
final GLContextState glCtx = GLStateManager.ctx();
final int savedDraw = glCtx.drawFramebuffer;
final int savedRead = glCtx.readFramebuffer;
try {
GLStateManager.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
drainErrors();
assertEquals(
GL30.glGetFramebufferAttachmentParameteri(GL30.GL_DRAW_FRAMEBUFFER, GL11.GL_STENCIL, GL30.GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE),
GLStateManager.glGetInteger(GL11.GL_STENCIL_BITS));
assertEquals(
GL30.glGetFramebufferAttachmentParameteri(GL30.GL_DRAW_FRAMEBUFFER, GL11.GL_DEPTH, GL30.GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE),
GLStateManager.glGetInteger(GL11.GL_DEPTH_BITS));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
GLStateManager.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, savedDraw);
GLStateManager.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, savedRead);
}
}
@Test
void stencilAndDepthBitsFollowBoundDrawFramebuffer() {
final GLContextState glCtx = GLStateManager.ctx();
final int savedDraw = glCtx.drawFramebuffer;
final int savedRead = glCtx.readFramebuffer;
final int fbo = GLStateManager.glGenFramebuffers();
final int depthOnly = GLStateManager.glGenRenderbuffers();
final int depthStencil = GLStateManager.glGenRenderbuffers();
try {
drainErrors();
GLStateManager.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthOnly);
GLStateManager.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL14.GL_DEPTH_COMPONENT24, 16, 16);
GLStateManager.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthStencil);
GLStateManager.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, 16, 16);
GLStateManager.glBindRenderbuffer(GL30.GL_RENDERBUFFER, 0);
GLStateManager.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
assertEquals(0, GLStateManager.glGetInteger(GL11.GL_STENCIL_BITS));
assertEquals(0, GLStateManager.glGetInteger(GL11.GL_DEPTH_BITS));
GLStateManager.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, depthOnly);
assertEquals(0, GLStateManager.glGetInteger(GL11.GL_STENCIL_BITS));
final int depthOnlyBits = GL30.glGetFramebufferAttachmentParameteri(GL30.GL_DRAW_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE);
assertTrue(depthOnlyBits >= 24, "driver depth size " + depthOnlyBits);
assertEquals(depthOnlyBits, GLStateManager.glGetInteger(GL11.GL_DEPTH_BITS));
GLStateManager.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, depthStencil);
GLStateManager.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depthStencil);
assertEquals(8, GLStateManager.glGetInteger(GL11.GL_STENCIL_BITS));
assertEquals(24, GLStateManager.glGetInteger(GL11.GL_DEPTH_BITS));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
GLStateManager.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, savedDraw);
GLStateManager.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, savedRead);
GLStateManager.glDeleteFramebuffers(fbo);
GLStateManager.glDeleteRenderbuffers(depthOnly);
GLStateManager.glDeleteRenderbuffers(depthStencil);
}
}
@Test
void intBufferOverloadMatchesAndDriverIsNotAsked() {
final int base = GLStateManager.getAttribDepth();
final IntBuffer buf = BufferUtils.createIntBuffer(16);
try {
GLStateManager.glPushAttrib(GL11.GL_ENABLE_BIT);
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_PIXEL_STORE_BIT);
GLStateManager.glClientActiveTexture(GL13.GL_TEXTURE1);
drainErrors();
GL11.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH);
assumeTrue(GL11.glGetError() != GL11.GL_NO_ERROR, "driver accepts GL_ATTRIB_STACK_DEPTH, so a clean error state proves nothing");
for (final int pname : SINGLE_VALUE_QUERIES) {
final int direct = GLStateManager.glGetInteger(pname);
buf.put(0, -12345);
GLStateManager.glGetInteger(pname, buf);
assertEquals(direct, buf.get(0), "IntBuffer overload for 0x" + Integer.toHexString(pname));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "driver error after querying 0x" + Integer.toHexString(pname));
}
} finally {
GLStateManager.glClientActiveTexture(GL13.GL_TEXTURE0);
drainClientAttribStack();
while (GLStateManager.getAttribDepth() > base) {
GLStateManager.glPopAttrib();
}
}
}
@Test
void attribDepthUnchangedWhileCompilingDisplayList() {
final int base = GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH);
final int list = GLStateManager.glGenLists(1);
try {
GLStateManager.glNewList(list, GL11.GL_COMPILE);
GLStateManager.glPushAttrib(GL11.GL_ENABLE_BIT);
assertEquals(base, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
GLStateManager.glPopAttrib();
assertEquals(base, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
GLStateManager.glEndList();
assertEquals(base, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
} finally {
if (DisplayListManager.isRecording()) {
GLStateManager.glEndList();
}
GLStateManager.glDeleteLists(list, 1);
}
}
@Test
void popAttribOnEmptyStackIsIgnored() {
drainAttribStack();
drainErrors();
assertEquals(0, GLStateManager.getAttribDepth());
assertDoesNotThrow(GLStateManager::glPopAttrib);
assertEquals(0, GLStateManager.glGetInteger(GL11.GL_ATTRIB_STACK_DEPTH));
assertDoesNotThrow(GLStateManager::glPopAttrib);
assertEquals(0, GLStateManager.getAttribDepth());
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
}
@Test
void pixelStoreBitRestoresPixelStoreAndPboBindings() {
final GLContextState glCtx = GLStateManager.ctx();
final int unpackBuffer = GLStateManager.glGenBuffers();
final int packBuffer = GLStateManager.glGenBuffers();
try {
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, 0);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, 0);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);
final PixelStoreState unpackBefore = glCtx.pixelUnpackState;
final PixelStoreState packBefore = glCtx.pixelPackState;
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_PIXEL_STORE_BIT);
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 2);
GLStateManager.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, 7);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, packBuffer);
assertEquals(1, glCtx.pixelUnpackState.alignment());
assertEquals(2, glCtx.pixelPackState.alignment());
assertEquals(7, glCtx.pixelPackState.rowLength());
assertEquals(2, GL11.glGetInteger(GL11.GL_PACK_ALIGNMENT));
GLStateManager.glPopClientAttrib();
assertSame(unpackBefore, glCtx.pixelUnpackState);
assertSame(packBefore, glCtx.pixelPackState);
assertEquals(4, GLStateManager.glGetInteger(GL11.GL_UNPACK_ALIGNMENT));
assertEquals(0, GLStateManager.glGetInteger(GL21.GL_PIXEL_UNPACK_BUFFER_BINDING));
assertEquals(0, GLStateManager.glGetInteger(GL21.GL_PIXEL_PACK_BUFFER_BINDING));
assertEquals(4, GL11.glGetInteger(GL11.GL_UNPACK_ALIGNMENT));
assertEquals(4, GL11.glGetInteger(GL11.GL_PACK_ALIGNMENT));
assertEquals(0, GL11.glGetInteger(GL11.GL_PACK_ROW_LENGTH));
assertEquals(0, GL11.glGetInteger(GL21.GL_PIXEL_UNPACK_BUFFER_BINDING));
assertEquals(0, GL11.glGetInteger(GL21.GL_PIXEL_PACK_BUFFER_BINDING));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
drainClientAttribStack();
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, 0);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, 0);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);
GLStateManager.glDeleteBuffers(unpackBuffer);
GLStateManager.glDeleteBuffers(packBuffer);
}
}
@Test
void pixelStoreIsNotRestoredWithoutPixelStoreBit() {
final GLContextState glCtx = GLStateManager.ctx();
final int unpackBuffer = GLStateManager.glGenBuffers();
final int packBuffer = GLStateManager.glGenBuffers();
try {
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 4);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, 0);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_VERTEX_ARRAY_BIT);
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 2);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, packBuffer);
GLStateManager.glPopClientAttrib();
assertEquals(1, glCtx.pixelUnpackState.alignment());
assertEquals(2, glCtx.pixelPackState.alignment());
assertEquals(unpackBuffer, GLStateManager.glGetInteger(GL21.GL_PIXEL_UNPACK_BUFFER_BINDING));
assertEquals(packBuffer, GLStateManager.glGetInteger(GL21.GL_PIXEL_PACK_BUFFER_BINDING));
assertEquals(1, GL11.glGetInteger(GL11.GL_UNPACK_ALIGNMENT));
assertEquals(2, GL11.glGetInteger(GL11.GL_PACK_ALIGNMENT));
assertEquals(unpackBuffer, GL11.glGetInteger(GL21.GL_PIXEL_UNPACK_BUFFER_BINDING));
assertEquals(packBuffer, GL11.glGetInteger(GL21.GL_PIXEL_PACK_BUFFER_BINDING));
} finally {
drainClientAttribStack();
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 4);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_UNPACK_BUFFER, 0);
GLStateManager.glBindBuffer(GL21.GL_PIXEL_PACK_BUFFER, 0);
GLStateManager.glDeleteBuffers(unpackBuffer);
GLStateManager.glDeleteBuffers(packBuffer);
}
}
@Test
void pixelStoreWithReturnsSameInstanceForUnchangedValue() {
final GLContextState glCtx = GLStateManager.ctx();
try {
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 9);
GLStateManager.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, 11);
final PixelStoreState unpack = glCtx.pixelUnpackState;
final PixelStoreState pack = glCtx.pixelPackState;
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 9);
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, unpack.alignment());
GLStateManager.glPixelStorei(GL11.GL_UNPACK_SWAP_BYTES, 0);
GLStateManager.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, 11);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, pack.alignment());
GLStateManager.glPixelStorei(GL11.GL_PACK_LSB_FIRST, 0);
assertSame(unpack, glCtx.pixelUnpackState);
assertSame(pack, glCtx.pixelPackState);
assertSame(unpack, unpack.with(GL11.GL_UNPACK_ROW_LENGTH, 9));
assertSame(pack, pack.with(GL11.GL_PACK_ROW_LENGTH, 11));
} finally {
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0);
GLStateManager.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, 0);
}
}
@Test
void packAndUnpackRestoreToTheirOwnPriorValues() {
final GLContextState glCtx = GLStateManager.ctx();
try {
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 2);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 8);
GLStateManager.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, 3);
GLStateManager.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, 5);
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_PIXEL_STORE_BIT);
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, 6);
GLStateManager.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, 7);
assertEquals(1, glCtx.pixelUnpackState.alignment());
assertEquals(4, glCtx.pixelPackState.alignment());
assertEquals(6, glCtx.pixelUnpackState.skipRows());
assertEquals(7, glCtx.pixelPackState.skipRows());
assertEquals(6, GL11.glGetInteger(GL11.GL_UNPACK_SKIP_ROWS));
assertEquals(7, GL11.glGetInteger(GL11.GL_PACK_SKIP_ROWS));
GLStateManager.glPopClientAttrib();
assertEquals(2, glCtx.pixelUnpackState.alignment());
assertEquals(8, glCtx.pixelPackState.alignment());
assertEquals(3, glCtx.pixelUnpackState.skipRows());
assertEquals(5, glCtx.pixelPackState.skipRows());
assertEquals(2, GL11.glGetInteger(GL11.GL_UNPACK_ALIGNMENT));
assertEquals(8, GL11.glGetInteger(GL11.GL_PACK_ALIGNMENT));
assertEquals(3, GL11.glGetInteger(GL11.GL_UNPACK_SKIP_ROWS));
assertEquals(5, GL11.glGetInteger(GL11.GL_PACK_SKIP_ROWS));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
drainClientAttribStack();
GLStateManager.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 4);
GLStateManager.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, 0);
GLStateManager.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, 0);
}
}
@Test
void vertexArrayEnableRestoredOnlyWithVertexArrayBit() {
final int savedVao = GLStateManager.getBoundVAO();
final int vao = GLStateManager.glGenVertexArrays();
final IntBuffer enabled = BufferUtils.createIntBuffer(16);
final int position = Usage.POSITION.getAttributeLocation();
try {
GLStateManager.glBindVertexArray(vao);
drainErrors();
assertFalse(positionArrayEnabled());
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_VERTEX_ARRAY_BIT);
GLStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY);
assertTrue(positionArrayEnabled());
GLStateManager.glPopClientAttrib();
assertFalse(positionArrayEnabled());
GL20.glGetVertexAttrib(position, GL20.GL_VERTEX_ATTRIB_ARRAY_ENABLED, enabled);
assertEquals(GL11.GL_FALSE, enabled.get(0));
GLStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_VERTEX_ARRAY_BIT);
GLStateManager.glDisableClientState(GL11.GL_VERTEX_ARRAY);
GLStateManager.glPopClientAttrib();
assertTrue(positionArrayEnabled());
GL20.glGetVertexAttrib(position, GL20.GL_VERTEX_ATTRIB_ARRAY_ENABLED, enabled);
assertEquals(GL11.GL_TRUE, enabled.get(0));
GLStateManager.glDisableClientState(GL11.GL_VERTEX_ARRAY);
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_PIXEL_STORE_BIT);
GLStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GLStateManager.glPopClientAttrib();
assertTrue(positionArrayEnabled());
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
drainClientAttribStack();
GLStateManager.glDisableClientState(GL11.GL_VERTEX_ARRAY);
GLStateManager.glBindVertexArray(savedVao);
GLStateManager.glDeleteVertexArrays(vao);
}
}
@Test
void vertexArrayStateRestoredOnlyWithVertexArrayBit() {
final int savedVao = GLStateManager.getBoundVAO();
final int vao = GLStateManager.glGenVertexArrays();
try {
GLStateManager.glBindVertexArray(vao);
GLStateManager.glClientActiveTexture(GL13.GL_TEXTURE0);
final int flagsBefore = GLStateManager.ctx().vaos.getVertexFlags();
assertFalse(colorArrayEnabled());
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_VERTEX_ARRAY_BIT);
GLStateManager.glEnableClientState(GL11.GL_COLOR_ARRAY);
GLStateManager.glClientActiveTexture(GL13.GL_TEXTURE1);
assertTrue(colorArrayEnabled());
GLStateManager.glPopClientAttrib();
assertFalse(colorArrayEnabled());
assertEquals(flagsBefore, GLStateManager.ctx().vaos.getVertexFlags());
assertEquals(0, GLStateManager.getClientActiveTextureUnit());
GLStateManager.glPushClientAttrib(GL11.GL_CLIENT_PIXEL_STORE_BIT);
GLStateManager.glEnableClientState(GL11.GL_COLOR_ARRAY);
GLStateManager.glClientActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.glPopClientAttrib();
assertTrue(colorArrayEnabled());
assertEquals(1, GLStateManager.getClientActiveTextureUnit());
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
drainClientAttribStack();
GLStateManager.glClientActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.glDisableClientState(GL11.GL_COLOR_ARRAY);
GLStateManager.glBindVertexArray(savedVao);
GLStateManager.glDeleteVertexArrays(vao);
}
}
@Test
void intLightGettersConvertLikeMesa() {
final FloatBuffer savedDiffuse = BufferUtils.createFloatBuffer(16);
final FloatBuffer savedPosition = BufferUtils.createFloatBuffer(16);
final FloatBuffer savedDirection = BufferUtils.createFloatBuffer(16);
final FloatBuffer savedCutoff = BufferUtils.createFloatBuffer(16);
final FloatBuffer savedAttenuation = BufferUtils.createFloatBuffer(16);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, savedDiffuse);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_POSITION, savedPosition);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_SPOT_DIRECTION, savedDirection);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_SPOT_CUTOFF, savedCutoff);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_LINEAR_ATTENUATION, savedAttenuation);
final IntBuffer ints = BufferUtils.createIntBuffer(16);
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
GLStateManager.glPushMatrix();
try {
GLStateManager.glLoadIdentity();
final FloatBuffer values = BufferUtils.createFloatBuffer(4);
values.put(0, 0.25f).put(1, 0.5f).put(2, 1.0f).put(3, -0.5f);
GLStateManager.glLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, values);
values.put(0, 3.9f).put(1, -2.7f).put(2, 0.5f).put(3, 1.0f);
GLStateManager.glLight(GL11.GL_LIGHT1, GL11.GL_POSITION, values);
values.put(0, 2.5f).put(1, -1.5f).put(2, -3.9f).put(3, 0.0f);
GLStateManager.glLight(GL11.GL_LIGHT1, GL11.GL_SPOT_DIRECTION, values);
GLStateManager.glLightf(GL11.GL_LIGHT1, GL11.GL_SPOT_CUTOFF, 45.75f);
GLStateManager.glLightf(GL11.GL_LIGHT1, GL11.GL_LINEAR_ATTENUATION, 2.5f);
drainErrors();
ints.position(2);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, ints);
assertEquals(2, ints.position());
assertEquals(536870911, ints.get(2));
assertEquals(1073741823, ints.get(3));
assertEquals(2147483647, ints.get(4));
assertEquals(-1073741823, ints.get(5));
ints.position(0);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_POSITION, ints);
assertEquals(3, ints.get(0));
assertEquals(-2, ints.get(1));
assertEquals(0, ints.get(2));
assertEquals(1, ints.get(3));
ints.put(3, -777);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_SPOT_DIRECTION, ints);
assertEquals(2, ints.get(0));
assertEquals(-1, ints.get(1));
assertEquals(-3, ints.get(2));
assertEquals(-777, ints.get(3));
ints.put(1, -777);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_SPOT_CUTOFF, ints);
assertEquals(45, ints.get(0));
assertEquals(-777, ints.get(1));
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_LINEAR_ATTENUATION, ints);
assertEquals(2, ints.get(0));
ints.put(0, -777);
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_EMISSION, ints);
assertEquals(-777, ints.get(0));
GLStateManager.glGetLight(GL11.GL_LIGHT1, GL11.GL_SHININESS, ints);
assertEquals(-777, ints.get(0));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
GLStateManager.glLoadIdentity();
savedDiffuse.limit(4);
GLStateManager.glLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, savedDiffuse);
savedPosition.limit(4);
GLStateManager.glLight(GL11.GL_LIGHT1, GL11.GL_POSITION, savedPosition);
savedDirection.limit(4);
GLStateManager.glLight(GL11.GL_LIGHT1, GL11.GL_SPOT_DIRECTION, savedDirection);
GLStateManager.glLightf(GL11.GL_LIGHT1, GL11.GL_SPOT_CUTOFF, savedCutoff.get(0));
GLStateManager.glLightf(GL11.GL_LIGHT1, GL11.GL_LINEAR_ATTENUATION, savedAttenuation.get(0));
GLStateManager.glPopMatrix();
}
}
@Test
void intMaterialGettersConvertLikeMesa() {
final FloatBuffer savedSpecular = BufferUtils.createFloatBuffer(16);
final FloatBuffer savedShininess = BufferUtils.createFloatBuffer(16);
final FloatBuffer savedIndexes = BufferUtils.createFloatBuffer(16);
GLStateManager.glGetMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, savedSpecular);
GLStateManager.glGetMaterial(GL11.GL_FRONT, GL11.GL_SHININESS, savedShininess);
GLStateManager.glGetMaterial(GL11.GL_BACK, GL11.GL_COLOR_INDEXES, savedIndexes);
final IntBuffer ints = BufferUtils.createIntBuffer(16);
try {
final FloatBuffer values = BufferUtils.createFloatBuffer(4);
values.put(0, 0.5f).put(1, 0.75f).put(2, 1.0f).put(3, 0.0f);
GLStateManager.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, values);
GLStateManager.glMaterialf(GL11.GL_FRONT, GL11.GL_SHININESS, 12.6f);
values.put(0, 2.5f).put(1, -2.5f).put(2, 7.4f).put(3, 0.0f);
GLStateManager.glMaterial(GL11.GL_BACK, GL11.GL_COLOR_INDEXES, values);
drainErrors();
ints.position(1);
GLStateManager.glGetMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, ints);
assertEquals(1, ints.position());
assertEquals(1073741823, ints.get(1));
assertEquals(1610612735, ints.get(2));
assertEquals(2147483647, ints.get(3));
assertEquals(0, ints.get(4));
ints.position(0);
ints.put(1, -777);
GLStateManager.glGetMaterial(GL11.GL_FRONT, GL11.GL_SHININESS, ints);
assertEquals(13, ints.get(0));
assertEquals(-777, ints.get(1));
ints.put(3, -777);
GLStateManager.glGetMaterial(GL11.GL_BACK, GL11.GL_COLOR_INDEXES, ints);
assertEquals(3, ints.get(0));
assertEquals(-3, ints.get(1));
assertEquals(7, ints.get(2));
assertEquals(-777, ints.get(3));
ints.put(0, -777);
GLStateManager.glGetMaterial(GL11.GL_FRONT, GL11.GL_POSITION, ints);
assertEquals(-777, ints.get(0));
GLStateManager.glGetMaterial(GL11.GL_FRONT, GL11.GL_SPOT_CUTOFF, ints);
assertEquals(-777, ints.get(0));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
savedSpecular.limit(4);
GLStateManager.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, savedSpecular);
GLStateManager.glMaterialf(GL11.GL_FRONT, GL11.GL_SHININESS, savedShininess.get(0));
savedIndexes.limit(4);
GLStateManager.glMaterial(GL11.GL_BACK, GL11.GL_COLOR_INDEXES, savedIndexes);
}
}
@Test
void currentTextureCoordsFollowActiveUnit() {
final FloatBuffer buf = BufferUtils.createFloatBuffer(16);
final float[][] saved = new float[4][4];
try {
for (int unit = 0; unit < 4; unit++) {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + unit);
GLStateManager.glGetFloat(GL11.GL_CURRENT_TEXTURE_COORDS, buf);
for (int i = 0; i < 4; i++) {
saved[unit][i] = buf.get(i);
}
}
GLStateManager.glMultiTexCoord2f(GL13.GL_TEXTURE0, 0.25f, 0.5f);
GLStateManager.glMultiTexCoord2f(GL13.GL_TEXTURE1, 240.0f, 16.0f);
GLStateManager.glMultiTexCoord2f(GL13.GL_TEXTURE2, 0.75f, 0.125f);
GLStateManager.glMultiTexCoord2f(GL13.GL_TEXTURE3, 0.375f, 0.625f);
drainErrors();
final float[][] expected = { { 0.25f, 0.5f }, { 240.0f, 16.0f }, { 0.75f, 0.125f }, { 0.375f, 0.625f } };
for (int unit = 0; unit < 4; unit++) {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + unit);
GLStateManager.glGetFloat(GL11.GL_CURRENT_TEXTURE_COORDS, buf);
assertEquals(expected[unit][0], buf.get(0), "s of unit " + unit);
assertEquals(expected[unit][1], buf.get(1), "t of unit " + unit);
assertEquals(0.0f, buf.get(2), "r of unit " + unit);
assertEquals(1.0f, buf.get(3), "q of unit " + unit);
}
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
for (int unit = 0; unit < 4; unit++) {
GLStateManager.glMultiTexCoord2f(GL13.GL_TEXTURE0 + unit, saved[unit][0], saved[unit][1]);
}
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
}
}
@Test
void currentTextureCoordsOfUntrackedUnitAreInitialValue() {
final FloatBuffer buf = BufferUtils.createFloatBuffer(16);
final int unit = GLStateManager.ctx().ffp.currentTexCoords.length + 1;
try {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.glMultiTexCoord2f(GL13.GL_TEXTURE0, 0.25f, 0.5f);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + unit);
drainErrors();
for (int i = 0; i < 4; i++) {
buf.put(i, -7.0f);
}
GLStateManager.glGetFloat(GL11.GL_CURRENT_TEXTURE_COORDS, buf);
assertEquals(0.0f, buf.get(0));
assertEquals(0.0f, buf.get(1));
assertEquals(0.0f, buf.get(2));
assertEquals(1.0f, buf.get(3));
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
} finally {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
GLStateManager.glMultiTexCoord2f(GL13.GL_TEXTURE0, 0.0f, 0.0f);
}
}
}
@@ -252,6 +252,32 @@ class GLSMRedirectorTest {
assertTrue(unmappedSeen().isEmpty());
}
@Test
void arbGenerateMipmapAliasIsRedirected() {
final ClassNode cn = makeClassWithMethodCall("org/lwjgl/opengl/ARBFramebufferObject", "glGenerateMipmap", "(I)V");
final boolean changed = new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
assertTrue(changed);
assertEquals(GLSM, firstCall(cn).owner);
assertEquals("glGenerateMipmap", firstCall(cn).name);
assertEquals("(I)V", firstCall(cn).desc);
assertTrue(unmappedSeen().isEmpty());
}
@Test
void extGenerateMipmapAliasIsRedirected() {
final ClassNode cn = makeClassWithMethodCall("org/lwjgl/opengl/EXTFramebufferObject", "glGenerateMipmapEXT", "(I)V");
final boolean changed = new GLSMRedirector().transformClassNode("com.example.TestClass", cn);
assertTrue(changed);
assertEquals(GLSM, firstCall(cn).owner);
assertEquals("glGenerateMipmap", firstCall(cn).name);
assertEquals("(I)V", firstCall(cn).desc);
assertTrue(unmappedSeen().isEmpty());
}
@Test
void newlyMappedReadPixelsIsRedirected() {
final ClassNode cn = makeClassWithMethodCall("org/lwjgl/opengl/GL11", "glReadPixels", "(IIIIIILjava/nio/IntBuffer;)V");
@@ -0,0 +1,115 @@
package com.gtnewhorizons.angelica.glsm.states;
import org.junit.jupiter.api.Test;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
class PixelStoreStateTest {
@Test
void defaults() {
assertTrue(PixelStoreState.DEFAULT.isDefault());
assertEquals(4, PixelStoreState.DEFAULT.alignment());
assertEquals(0, PixelStoreState.DEFAULT.rowLength());
assertFalse(PixelStoreState.DEFAULT.swapBytes());
assertFalse(PixelStoreState.DEFAULT.lsbFirst());
}
@Test
void withUpdatesUnpackParams() {
PixelStoreState s = PixelStoreState.DEFAULT
.with(GL11.GL_UNPACK_ALIGNMENT, 1)
.with(GL11.GL_UNPACK_ROW_LENGTH, 64)
.with(GL11.GL_UNPACK_SKIP_ROWS, 2)
.with(GL11.GL_UNPACK_SKIP_PIXELS, 3)
.with(GL12.GL_UNPACK_IMAGE_HEIGHT, 32)
.with(GL12.GL_UNPACK_SKIP_IMAGES, 1)
.with(GL11.GL_UNPACK_SWAP_BYTES, 1)
.with(GL11.GL_UNPACK_LSB_FIRST, 1);
assertEquals(new PixelStoreState(1, 64, 2, 3, 32, 1, true, true), s);
assertFalse(s.isDefault());
}
@Test
void invalidValuesIgnored() {
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(GL11.GL_UNPACK_ALIGNMENT, 3));
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(GL11.GL_UNPACK_ALIGNMENT, 0));
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(GL11.GL_UNPACK_ROW_LENGTH, -1));
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(GL11.GL_UNPACK_SKIP_ROWS, -5));
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(GL12.GL_UNPACK_IMAGE_HEIGHT, -1));
}
@Test
void booleansAcceptAnyNonzero() {
assertTrue(PixelStoreState.DEFAULT.with(GL11.GL_UNPACK_SWAP_BYTES, 2).swapBytes());
assertTrue(PixelStoreState.DEFAULT.with(GL11.GL_UNPACK_LSB_FIRST, -1).lsbFirst());
PixelStoreState on = PixelStoreState.DEFAULT.with(GL11.GL_UNPACK_SWAP_BYTES, 1);
assertFalse(on.with(GL11.GL_UNPACK_SWAP_BYTES, 0).swapBytes());
}
@Test
void packPnamesSetTheSameFields() {
PixelStoreState s = PixelStoreState.DEFAULT
.with(GL11.GL_PACK_ALIGNMENT, 1)
.with(GL11.GL_PACK_ROW_LENGTH, 64)
.with(GL11.GL_PACK_SKIP_ROWS, 2)
.with(GL11.GL_PACK_SKIP_PIXELS, 3)
.with(GL12.GL_PACK_IMAGE_HEIGHT, 32)
.with(GL12.GL_PACK_SKIP_IMAGES, 1)
.with(GL11.GL_PACK_SWAP_BYTES, 1)
.with(GL11.GL_PACK_LSB_FIRST, 1);
assertEquals(new PixelStoreState(1, 64, 2, 3, 32, 1, true, true), s);
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(GL11.GL_PACK_ALIGNMENT, 3));
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(GL11.GL_PACK_ROW_LENGTH, -1));
}
@Test
void unknownPnamesIgnored() {
assertSame(PixelStoreState.DEFAULT, PixelStoreState.DEFAULT.with(0x1234, 1));
}
@Test
void unchangedValueReturnsSameInstance() {
final PixelStoreState s = new PixelStoreState(1, 64, 2, 3, 32, 1, true, true);
assertSame(s, s.with(GL11.GL_UNPACK_ALIGNMENT, 1));
assertSame(s, s.with(GL11.GL_PACK_ALIGNMENT, 1));
assertSame(s, s.with(GL11.GL_UNPACK_ROW_LENGTH, 64));
assertSame(s, s.with(GL11.GL_PACK_ROW_LENGTH, 64));
assertSame(s, s.with(GL11.GL_UNPACK_SKIP_ROWS, 2));
assertSame(s, s.with(GL11.GL_PACK_SKIP_ROWS, 2));
assertSame(s, s.with(GL11.GL_UNPACK_SKIP_PIXELS, 3));
assertSame(s, s.with(GL11.GL_PACK_SKIP_PIXELS, 3));
assertSame(s, s.with(GL12.GL_UNPACK_IMAGE_HEIGHT, 32));
assertSame(s, s.with(GL12.GL_PACK_IMAGE_HEIGHT, 32));
assertSame(s, s.with(GL12.GL_UNPACK_SKIP_IMAGES, 1));
assertSame(s, s.with(GL12.GL_PACK_SKIP_IMAGES, 1));
assertSame(s, s.with(GL11.GL_UNPACK_SWAP_BYTES, 5));
assertSame(s, s.with(GL11.GL_PACK_SWAP_BYTES, 5));
assertSame(s, s.with(GL11.GL_UNPACK_LSB_FIRST, 1));
assertSame(s, s.with(GL11.GL_PACK_LSB_FIRST, 1));
}
@Test
void isPackSeparatesTheFamilies() {
final int[] pack = {
GL11.GL_PACK_ALIGNMENT, GL11.GL_PACK_ROW_LENGTH, GL11.GL_PACK_SKIP_ROWS, GL11.GL_PACK_SKIP_PIXELS,
GL12.GL_PACK_IMAGE_HEIGHT, GL12.GL_PACK_SKIP_IMAGES, GL11.GL_PACK_SWAP_BYTES, GL11.GL_PACK_LSB_FIRST,
};
final int[] unpack = {
GL11.GL_UNPACK_ALIGNMENT, GL11.GL_UNPACK_ROW_LENGTH, GL11.GL_UNPACK_SKIP_ROWS, GL11.GL_UNPACK_SKIP_PIXELS,
GL12.GL_UNPACK_IMAGE_HEIGHT, GL12.GL_UNPACK_SKIP_IMAGES, GL11.GL_UNPACK_SWAP_BYTES, GL11.GL_UNPACK_LSB_FIRST,
};
for (final int pname : pack) {
assertTrue(PixelStoreState.isPack(pname));
}
for (final int pname : unpack) {
assertFalse(PixelStoreState.isPack(pname));
}
assertFalse(PixelStoreState.isPack(0x1234));
}
}
@@ -1,61 +0,0 @@
package com.gtnewhorizons.angelica.glsm.states;
import org.junit.jupiter.api.Test;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
class PixelUnpackStateTest {
@Test
void defaults() {
assertTrue(PixelUnpackState.DEFAULT.isDefault());
assertEquals(4, PixelUnpackState.DEFAULT.alignment());
assertEquals(0, PixelUnpackState.DEFAULT.rowLength());
assertFalse(PixelUnpackState.DEFAULT.swapBytes());
assertFalse(PixelUnpackState.DEFAULT.lsbFirst());
}
@Test
void withUpdatesUnpackParams() {
PixelUnpackState s = PixelUnpackState.DEFAULT
.with(GL11.GL_UNPACK_ALIGNMENT, 1)
.with(GL11.GL_UNPACK_ROW_LENGTH, 64)
.with(GL11.GL_UNPACK_SKIP_ROWS, 2)
.with(GL11.GL_UNPACK_SKIP_PIXELS, 3)
.with(GL12.GL_UNPACK_IMAGE_HEIGHT, 32)
.with(GL12.GL_UNPACK_SKIP_IMAGES, 1)
.with(GL11.GL_UNPACK_SWAP_BYTES, 1)
.with(GL11.GL_UNPACK_LSB_FIRST, 1);
assertEquals(new PixelUnpackState(1, 64, 2, 3, 32, 1, true, true), s);
assertFalse(s.isDefault());
}
@Test
void invalidValuesIgnored() {
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(GL11.GL_UNPACK_ALIGNMENT, 3));
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(GL11.GL_UNPACK_ALIGNMENT, 0));
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(GL11.GL_UNPACK_ROW_LENGTH, -1));
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(GL11.GL_UNPACK_SKIP_ROWS, -5));
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(GL12.GL_UNPACK_IMAGE_HEIGHT, -1));
}
@Test
void booleansAcceptAnyNonzero() {
assertTrue(PixelUnpackState.DEFAULT.with(GL11.GL_UNPACK_SWAP_BYTES, 2).swapBytes());
assertTrue(PixelUnpackState.DEFAULT.with(GL11.GL_UNPACK_LSB_FIRST, -1).lsbFirst());
PixelUnpackState on = PixelUnpackState.DEFAULT.with(GL11.GL_UNPACK_SWAP_BYTES, 1);
assertFalse(on.with(GL11.GL_UNPACK_SWAP_BYTES, 0).swapBytes());
}
@Test
void packAndUnknownPnamesIgnored() {
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(GL11.GL_PACK_ALIGNMENT, 1));
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(GL11.GL_PACK_ROW_LENGTH, 16));
assertSame(PixelUnpackState.DEFAULT, PixelUnpackState.DEFAULT.with(0x1234, 1));
}
}
@@ -1,7 +1,7 @@
package com.gtnewhorizons.angelica.sdlgpu.glsm;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
import com.gtnewhorizons.angelica.sdlgpu.SDLGPULWJGLService;
import org.junit.jupiter.api.BeforeAll;
@@ -35,7 +35,7 @@ class GlsmSdlLWJGLServiceRoutingTest {
}
private static int glsmUnpackAlignment() {
final PixelUnpackState state = Reflect.get(glsmContext(), "pixelUnpackState");
final PixelStoreState state = Reflect.get(glsmContext(), "pixelUnpackState");
return state.alignment();
}