1 module ws.gl.framebuffer;
2 
3 import
4 	std.string,
5 	std.conv,
6 	ws.gl.texture,
7 	ws.gl.gl;
8 
9 
10 string error(GLuint i){
11 	string[GLuint] ERRORS = [
12 		GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: "invalid attachment(s)",
13 	//	GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: "invalid dimensions",
14 		GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: "no attachments",
15 		GL_FRAMEBUFFER_UNSUPPORTED: "this framebuffer configuration is not supported"
16 	];
17 	//return ERRORS[i];
18 	return to!string(i);
19 }
20 
21 
22 
23 class FrameBuffer {
24 
25 	GLuint fbo;
26 	Texture depth;
27 	Texture[] textures;
28 	uint width, height;
29 
30 	this(int w, int h, int count, GLuint format=GL_RGBA32F, GLuint type=GL_FLOAT, GLuint colors=GL_RGB){
31 		width = w;
32 		height = h;
33 		glGenFramebuffers(1, &fbo); 
34 		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
35 		for(uint i = 0; i < count; i++){
36 			uint tex;
37 			glGenTextures(1, &tex);
38 			glBindTexture(GL_TEXTURE_2D, tex);
39     		glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, colors, type, null);
40 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
41 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
42 	        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, tex, 0);
43 			textures ~= new Texture(tex);
44 		}
45 		uint tex;
46 		glGenTextures(1, &tex);
47 		glBindTexture(GL_TEXTURE_2D, tex);
48 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
49 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
50 		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, null);
51 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, tex, 0);
52 		depth = new Texture(tex);
53 		
54 		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
55 		if(status != GL_FRAMEBUFFER_COMPLETE)
56 			throw new Exception("FB error: %s".format(error(status)));
57 
58 		glBindFramebuffer(GL_FRAMEBUFFER, 0);
59 	}
60 
61 	void destroy(){
62 		glDeleteFramebuffers(1, &fbo);
63 		foreach(t; textures)
64 			t.destroy;
65 		//glDeleteTextures(cast(int)textures.length, textures.ptr);
66 		depth.destroy;
67 	}
68 
69 	void draw(GLuint[] targets){
70 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
71 		GLuint[] drawBuffers;
72 		foreach(i, n; targets)
73 			drawBuffers ~= GL_COLOR_ATTACHMENT0+n;
74 		glDrawBuffers(cast(int)drawBuffers.length, drawBuffers.ptr);
75 	}
76 
77 	void clear(){
78 		float[3] clear = [0, 0, 0];
79 		float one = 1;
80 		foreach(i; 0..textures.length)
81 			glClearBufferfv(GL_COLOR, cast(int)i, clear.ptr);
82 		glClearBufferfv(GL_DEPTH, 0, &one);
83 	}
84 
85 	void read(GLuint target){
86 		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
87 		glReadBuffer(GL_COLOR_ATTACHMENT0+target);
88 	}
89 
90 	/+++
91 		Bind textures for reading
92 		tex: [shader offset: framebuffer index, ...]
93 	/
94 	void read(uint[uint] tex){
95 		foreach(i, n; tex){
96 			glActiveTexture(GL_TEXTURE0+i);
97 			glBindTexture(GL_TEXTURE_2D, textures[n]);
98 		}
99 	}
100 	+/
101 
102 	void blit(int which, int x, int y, int w){
103 		float aspect = width/cast(float)height;
104 		int h = cast(int)(w/aspect);
105 		read(which);
106 		glBlitFramebuffer(0,0,width,height,x,y,x+w,y+h,GL_COLOR_BUFFER_BIT,GL_LINEAR);
107 	}
108 
109 }