package com.mojang.blaze3d.opengl; import com.mojang.blaze3d.shaders.UniformType; import com.mojang.logging.LogUtils; import java.nio.FloatBuffer; import java.nio.IntBuffer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import org.joml.Matrix4f; import org.joml.Vector3f; import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; @Environment(EnvType.CLIENT) public class Uniform extends AbstractUniform implements AutoCloseable { private static final Logger LOGGER = LogUtils.getLogger(); private int location; private final UniformType type; private final IntBuffer intValues; private final FloatBuffer floatValues; private final String name; private boolean dirty; public Uniform(String name, UniformType type) { this.name = name; this.type = type; if (type.isIntStorage()) { this.intValues = MemoryUtil.memAllocInt(type.count()); this.floatValues = null; } else { this.intValues = null; this.floatValues = MemoryUtil.memAllocFloat(type.count()); } this.location = -1; } public static int glGetUniformLocation(int program, CharSequence name) { return GlStateManager._glGetUniformLocation(program, name); } public static void uploadInteger(int location, int value) { GlStateManager._glUniform1i(location, value); } public void close() { if (this.intValues != null) { MemoryUtil.memFree(this.intValues); } if (this.floatValues != null) { MemoryUtil.memFree(this.floatValues); } } public void setLocation(int location) { this.location = location; } public String getName() { return this.name; } public UniformType getType() { return this.type; } @Override public final void set(float value) { this.floatValues.position(0); this.floatValues.put(0, value); this.dirty = true; } @Override public final void set(float value1, float value2) { this.floatValues.position(0); this.floatValues.put(0, value1); this.floatValues.put(1, value2); this.dirty = true; } @Override public final void set(float value1, float value2, float value3) { this.floatValues.position(0); this.floatValues.put(0, value1); this.floatValues.put(1, value2); this.floatValues.put(2, value3); this.dirty = true; } @Override public final void set(Vector3f values) { this.floatValues.position(0); values.get(this.floatValues); this.dirty = true; } @Override public final void set(float value1, float value2, float value3, float value4) { this.floatValues.position(0); this.floatValues.put(value1); this.floatValues.put(value2); this.floatValues.put(value3); this.floatValues.put(value4); this.floatValues.flip(); this.dirty = true; } @Override public final void set(int value) { this.intValues.position(0); this.intValues.put(0, value); this.dirty = true; } @Override public final void set(int value1, int value2, int value3) { this.intValues.position(0); this.intValues.put(0, value1); this.intValues.put(1, value2); this.intValues.put(2, value3); this.dirty = true; } @Override public final void set(float[] values) { if (values.length < this.type.count()) { LOGGER.warn("Uniform.set called with a too-small value array (expected {}, got {}). Ignoring.", this.type.count(), values.length); } else { this.floatValues.position(0); this.floatValues.put(values); this.floatValues.position(0); this.dirty = true; } } @Override public final void set(int[] values) { if (values.length < this.type.count()) { LOGGER.warn("Uniform.set called with a too-small value array (expected {}, got {}). Ignoring.", this.type.count(), values.length); } else { this.intValues.position(0); this.intValues.put(values); this.intValues.position(0); this.dirty = true; } } @Override public final void set(Matrix4f values) { this.floatValues.position(0); values.get(this.floatValues); this.dirty = true; } public void upload() { if (this.dirty) { if (this.type.isIntStorage()) { switch (this.type) { case INT: GlStateManager._glUniform1(this.location, this.intValues); break; case IVEC3: GlStateManager._glUniform3(this.location, this.intValues); } } else { switch (this.type) { case FLOAT: GlStateManager._glUniform1(this.location, this.floatValues); break; case VEC2: GlStateManager._glUniform2(this.location, this.floatValues); break; case VEC3: GlStateManager._glUniform3(this.location, this.floatValues); break; case VEC4: GlStateManager._glUniform4(this.location, this.floatValues); break; case MATRIX4X4: GlStateManager._glUniformMatrix4(this.location, this.floatValues); } } this.dirty = false; } } }