I am working on the following structure:
Buffer
XBuffer
extends Buffer
XYBuffer
extends XBuffer
All objects should be instantiable, so no abstract
, in order to support forward compatability.
I have came up with the following, with pitfalls/issues I will describe below:
public class Buffer<S extends Buffer<S>> {
protected final int bufferType;
protected final int bufferDataType;
protected int bufferId;
protected boolean created;
public Buffer(final int bufferType, final int bufferDataType) {
this.bufferType = bufferType;
this.bufferDataType = bufferDataType;
}
@SuppressWarnings("unchecked")
public S create() {
assertNotCreated();
bufferId = GL15.glGenBuffers();
created = true;
return (S)this;
}
@SuppressWarnings("unchecked")
public S bind() {
assertCreated();
GL15.glBindBuffer(bufferType, bufferId);
return (S)this;
}
@SuppressWarnings("unchecked")
public S fillData(final float[] data) {
assertCreated();
FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(data.length).put(data);
dataBuffer.flip();
GL15.glBufferData(bufferType, dataBuffer, bufferDataType);
return (S)this;
}
public void delete() {
assertCreated();
GL15.glDeleteBuffers(bufferId);
}
public int getBufferId() {
return bufferId;
}
public boolean hasBeenCreated() {
return created;
}
private void assertCreated() {
if (!hasBeenCreated()) {
throw new RuntimeException("Buffer has not been created.");
}
}
private void assertNotCreated() {
if (hasBeenCreated()) {
throw new RuntimeException("Buffer has been created already.");
}
}
@Override
public String toString() {
return "Buffer(" + bufferType + ", " + bufferDataType + ", " + bufferId + ", " + created + ")";
}
}
public class ArrayBuffer<S extends ArrayBuffer<S>> extends Buffer<S> {
public ArrayBuffer(final int bufferDataType) {
super(GL15.GL_ARRAY_BUFFER, bufferDataType);
}
}
public class StaticDrawArrayBuffer extends ArrayBuffer<StaticDrawArrayBuffer> {
public StaticDrawArrayBuffer() {
super(GL15.GL_STATIC_DRAW);
}
}
Now the following happens:
StaticDrawArrayBuffer
works as expected.ArrayBuffer
does not work as expected, as I cannot instantiate it anymore without using generics. (Keep in mind: The generics used here are only there to help me, not to actually provide generic functionality)Buffer
does not work as expected either with the same issue as ArrayBuffer
.What do I want?
Buffer
and ArrayBuffer
without using generics.How would I do this?
To clarify more, these statements should all compile:
Buffer buffer = new Buffer().create().bind();
ArrayBuffer arrayBuffer = new ArrayBuffer().create.bind();
StaticDrawArrayBuffer staticDrawArrayBuffer = new StaticDrawArrayBuffer().create.bind()
If I would not use any generics at all, then new ArayBuffer().create()
will return a Buffer
, resulting in that it cannot be assigned to ArrayBuffer
anymore. It does leave chaining of Buffer
methods intact, but it would furthermore also break if the chain would contain methods only available to ArrayBuffer
.
If it helps, I have the ability to use Java 8 if it is a almost bugfree (it should be now, I think?), considering this project won't see real daylight for a long while anyway.
What about Covariant return types instead of generics?
public class ArrayBuffer extends Buffer {
public ArrayBuffer(final int bufferDataType) {
super(GL15.GL_ARRAY_BUFFER, bufferDataType);
}
public ArrayBuffer create() {
super.create();
return this;
}
public ArrayBuffer bind() {
super.bind();
return this;
}
}
public class StaticDrawArrayBuffer extends ArrayBuffer {
public StaticDrawArrayBuffer() {
super(GL15.GL_STATIC_DRAW);
}
public StaticDrawArrayBuffer bind() {
super.bind();
return this;
}
}
AFAIK this should compile now:
Buffer buffer = new Buffer().create().bind();
ArrayBuffer arrayBuffer = new ArrayBuffer().create().bind();
StaticDrawArrayBuffer staticDrawArrayBuffer = new StaticDrawArrayBuffer().create().bind()