1 module moggle.xxx.buffer;
2 
3 import moggle.core.vbo;
4 
5 /++ Manages a OpenGL vertex buffer object (Vbo).
6 
7 Contains both a Vbo!T object and a T[], which it can keep in sync.
8 
9 Basically, a Vbo!T has data stored in the GPU memory (for OpenGL),
10 while the T[] has data stored in the CPU memory (for us).
11 If you modify the T[] and want the changes to be reflected on the GPU,
12 call markDirty(). Then, the next call to sync() will (re)upload the data to the GPU.
13 If you don't want to keep a copy of the data in the CPU memory, just empty the T[]
14 and don't call markDirty().
15 syncBack() can be used to download the data again from the GPU into the CPU memory.
16 
17 Note that a Vbo!T is only allocated on the GPU (in OpenGL) the first time it is used.
18 So until the first time sync() uploads the data, there is nothing allocated in OpenGL,
19 not even an empty Vbo. (Unless vbo.create() is called explicitly, of course.)
20 +/
21 class Buffer(T) : GenericBuffer {
22 
23 	/// The Vbo!T holding the GPU's (OpenGL's) copy of the data.
24 	@property auto ref vbo() inout { return cast(inout(Vbo!T))vbo_; }
25 
26 	/++ The T[] containing the CPU's (our) copy of the data.
27 
28 	This member is aliassed as 'this', so you can use a Buffer!T object directly
29 	as if it is a T[]:
30 	---
31 	auto b = new Buffer!T([1,2,3]);
32 	x[1] = 10;
33 	---
34 	+/
35 	T[] data;
36 	alias data this;
37 
38 	private bool dirty_ = false;
39 
40 	/// Check if the Buffer is marked as dirty. (i.e. sync() would do anything.)
41 	@property bool is_dirty() const { return dirty_; }
42 
43 	/// Mark the Buffer as dirty, such that the next call to sync() will upload the data to the GPU memory.
44 	void markDirty() { dirty_ = true; }
45 
46 	/++ Allocate a new Buffer to hold the given data.
47 
48 	The Buffer is directly marked as dirty if d is not empty.
49 	+/
50 	this(T[] d ...) {
51 		data = d;
52 		dirty_ = data.length != 0;
53 	}
54 
55 	/// If the Buffer is marked as dirty, uploads the data from the T[] (CPU/us) to the Vbo!T (GPU/OpenGL). Resets is_dirty.
56 	override void sync() {
57 		if (dirty_) vbo.data(data);
58 		dirty_ = false;
59 	}
60 
61 	/// Download the data form the Vbo!T (GPU/OpenGL) to the T[] (CPU/us).
62 	void syncBack() {
63 		auto m = vbo.mapReadOnly();
64 		data.length = m.length;
65 		data[] = m[];
66 		dirty_ = false;
67 	}
68 
69 }
70 
71 /++ The base class of all Buffer!T objects.
72 
73 Doesn't know what type of objects are stored in the Buffer, but can still sync() it and access the Vbo.
74 +/
75 class GenericBuffer {
76 
77 	protected GenericVbo vbo_;
78 
79 	/// If the Buffer is marked as dirty, uploads the data from the T[] (CPU/us) to the Vbo!T (GPU/OpenGL). Resets is_dirty.
80 	abstract void sync();
81 
82 	/// The GenericVbo holding the GPU's (OpenGL's) copy of the data.
83 	@property final auto ref vbo() inout { return vbo_; }
84 
85 }
86