1 module prova.graphics.rendertarget; 2 3 import prova.graphics, 4 prova.math, 5 std.typecons; 6 7 /// 8 class RenderTarget 9 { 10 static ShaderProgram flatShaderProgram; 11 private static uint currentFrameBuffer = -1; 12 13 /// 14 SpriteBatch spriteBatch; 15 /// 16 protected Matrix projection; 17 18 private uint renderBufferId; 19 private uint _frameBufferId; 20 private Texture _texture; 21 private int _width; 22 private int _height; 23 private bool begun; 24 25 /// 26 this(int width, int height) 27 { 28 if(!flatShaderProgram) 29 flatShaderProgram = new FlatShaderProgram(); 30 31 spriteBatch = new SpriteBatch(); 32 _texture = new Texture(width, height); 33 _width = width; 34 _height = height; 35 36 createFrameBuffer(); 37 createRenderBuffer(); 38 } 39 40 private void createFrameBuffer() 41 { 42 glGenFramebuffers(1, &_frameBufferId); 43 bindFrameBuffer(); 44 45 // attach texture to the frame buffer 46 glFramebufferTexture2D( 47 GL_FRAMEBUFFER, 48 GL_COLOR_ATTACHMENT0, 49 GL_TEXTURE_2D, 50 _texture.id, 51 0 52 ); 53 54 glDepthFunc(GL_LEQUAL); 55 glEnable(GL_BLEND); 56 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 57 glViewport(0, 0, width, height); 58 } 59 60 private void createRenderBuffer() 61 { 62 glGenRenderbuffers(1, &renderBufferId); 63 glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId); 64 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); 65 66 bindFrameBuffer(); 67 68 glFramebufferRenderbuffer( 69 GL_FRAMEBUFFER, 70 GL_DEPTH_ATTACHMENT, 71 GL_RENDERBUFFER, 72 renderBufferId 73 ); 74 } 75 76 /// 77 void resize(int width, int height) 78 { 79 _width = width; 80 _height = height; 81 82 texture.recreate(null, width, height); 83 84 glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId); 85 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); 86 87 // update settings 88 glViewport(0, 0, width, height); 89 } 90 91 /// 92 @property int width() 93 { 94 return _width; 95 } 96 97 /// 98 @property int height() 99 { 100 return _height; 101 } 102 103 /// 104 @property Texture texture() 105 { 106 return _texture; 107 } 108 109 /// 110 @property uint frameBufferId() 111 { 112 return _frameBufferId; 113 } 114 115 package(prova) void bindFrameBuffer() 116 { 117 bindFrameBuffer(_frameBufferId); 118 } 119 120 /// Updates projection and prepares batches 121 void begin(Matrix projection) 122 { 123 if(begun) 124 throw new Exception("RenderTarget already started"); 125 126 spriteBatch.begin(this, projection); 127 128 this.projection = projection; 129 begun = true; 130 } 131 132 /// Finishes the batch 133 void end() 134 { 135 if(!begun) 136 throw new Exception("RenderTarget not ready, call begin(Matrix projection)"); 137 138 spriteBatch.end(); 139 begun = false; 140 } 141 142 /// Draws mesh using a flat shader 143 void drawMesh(Mesh mesh, Matrix transform, DrawMode mode, Color color) 144 { 145 if(!begun) 146 throw new Exception("RenderTarget not ready, call begin(Matrix projection)"); 147 148 flatShaderProgram.setMatrix("transform", projection * transform); 149 flatShaderProgram.setVector4("color", color); 150 flatShaderProgram.drawMesh(mesh, this, mode); 151 } 152 153 /// 154 void drawSprite(Sprite sprite, Matrix transform) 155 { 156 spriteBatch.batchSprite(sprite, transform); 157 } 158 159 /// 160 void drawSprite(AnimatedSprite sprite, Matrix transform) 161 { 162 spriteBatch.batchSprite(sprite, transform); 163 } 164 165 /// 166 void clear() 167 { 168 bindFrameBuffer(); 169 170 glClearDepth(1); 171 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 172 } 173 174 package(prova) static void bindFrameBuffer(uint id) 175 { 176 if(id == currentFrameBuffer) 177 return; 178 179 glBindFramebuffer(GL_FRAMEBUFFER, id); 180 currentFrameBuffer = id; 181 } 182 183 ~this() 184 { 185 glDeleteFramebuffers(1, &_frameBufferId); 186 glDeleteRenderbuffers(1, &renderBufferId); 187 } 188 }