1 module ws.gl.gbuffer;
2 
3 import
4 	std.string,
5 	ws.gl.gl;
6 
7 
8 string error(GLuint i){
9 	string[GLuint] ERRORS = [
10 		GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: "invalid attachment(s)",
11 	//	GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: "invalid dimensions",
12 		GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: "no attachments",
13 		GL_FRAMEBUFFER_UNSUPPORTED: "this framebuffer configuration is not supported"
14 	];
15 	return ERRORS[i];
16 }
17 
18 
19 
20 class GBuffer {
21 
22 	private {
23 		GLuint fbo;
24 		GLuint[NUM] textures;
25 		GLuint depth;
26 		GLuint result;
27 	}
28 
29 	this(int w, int h){
30 
31 		// Create the FBO
32 		glGenFramebuffers(1, &fbo); 
33 		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
34 	
35 		// Create the gbuffer textures
36 		glGenTextures(textures.length, textures.ptr);
37 		for(uint i = 0; i < textures.length; i++){
38 			glBindTexture(GL_TEXTURE_2D, textures[i]);
39 			if(i == LIGHT)
40 				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, null);
41 			else
42         		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, w, h, 0, GL_RGB, GL_FLOAT, null);
43 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
44 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
45 	        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0);
46 		}
47 		// depth & stencil
48 		glGenTextures(1, &depth);
49 		glBindTexture(GL_TEXTURE_2D, depth);
50 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
51 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
52 		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, null);
53 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
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 		if(fbo)
63 			glDeleteFramebuffers(1, &fbo);
64 		if(textures[0])
65 			glDeleteTextures(textures.length, textures.ptr);
66 		if(depth)
67 			glDeleteRenderbuffers(1, &depth);
68 	}
69 
70 
71 	void startFrame(){
72 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
73 		glDrawBuffer(GL_COLOR_ATTACHMENT0+LIGHT);
74 		glClearColor(0.1,0.1,0.1,1);
75 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
76 	}
77 
78 	void bindGeom(){
79 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
80 		GLenum[] buffers;
81 		for(int i=0; i<NUM; i++)
82 			buffers ~= GL_COLOR_ATTACHMENT0 + i;
83 		glDrawBuffers(cast(uint)buffers.length, buffers.ptr);
84 	}
85 
86 	void bindStencil(){
87 		glDrawBuffer(GL_NONE);
88 	}
89 
90 	void bindTextures(){
91 		for(int i=0 ; i < LIGHT; i++){
92 			glActiveTexture(GL_TEXTURE0 + i);
93 			glBindTexture(GL_TEXTURE_2D, textures[i]);
94 		}
95 	}
96 
97 	void bindDepth(int where){
98 		glActiveTexture(GL_TEXTURE0 + where);
99 		glBindTexture(GL_TEXTURE_2D, depth);
100 	}
101 
102 	void bindLight(){
103 		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
104 		glDrawBuffer(GL_COLOR_ATTACHMENT0+LIGHT);
105 		bindTextures;
106 	}
107 
108 	void bindRead(int which){
109 		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
110 		glReadBuffer(GL_COLOR_ATTACHMENT0+which);
111 	}
112 
113 	enum: int { DIFFUSE, TEXCOORD, NORMAL, LIGHT, NUM };
114 
115 }