1 module example_texture; 2 3 import std..string; 4 import std.conv; 5 import std.stdio; 6 7 import derelict.opengl3.gl3; 8 import derelict.sdl2.sdl; 9 import derelict.sdl2.image; 10 11 import glamour.vao: VAO; 12 import glamour.shader: Shader; 13 import glamour.vbo: Buffer, ElementBuffer; 14 import glamour.texture: Texture2D; 15 16 class Renderer 17 { 18 private: 19 uint width_, height_; 20 21 float[] vertices_, texture_coords_; 22 ushort[] indices_; 23 GLint position_, tex_coord_; 24 25 VAO vao_; 26 Shader program_; 27 Buffer vbo_, tbo_; 28 ElementBuffer ibo_; 29 Texture2D texture_; 30 31 /// ATTENTION! All shaders are placed in the single source. 32 /// Source contains up to three shaders: vertex shader, 33 /// geometry shader and fragment shader. 34 /// Every shader are prefixed by tag to separate from the others. 35 /// Tags are: 36 /// "vertex:" 37 /// "geometry:" 38 /// "fragment:" 39 /// Tag shall be the first token in the line and the rest of the line is ignored. 40 /// Shaders may be ordered in any way. But a shader will be replaced 41 /// by the next shader with the same tag - so there is only one shader with 42 /// the specific tag at the moment. 43 /// Directives are placed in the beginning of the source, not every shader and 44 /// effect on the total source consequently. 45 static immutable string example_program_src_ = ` 46 #version 120 47 vertex: 48 in vec2 position; 49 in vec2 inCoord; 50 51 out vec2 texCoord; 52 void main(void) 53 { 54 gl_Position = vec4(position, 0, 1); 55 texCoord = inCoord; 56 } 57 fragment: 58 in vec2 texCoord; 59 out vec4 outputColor; 60 61 uniform sampler2D gSampler; 62 63 void main(void) 64 { 65 outputColor = texture2D(gSampler, texCoord); 66 } 67 `; 68 69 public: 70 this() 71 { 72 vertices_ = [ -0.3, -0.3, 0.3, -0.3, -0.3, 0.3, 0.3, 0.3 ]; 73 indices_ = [0, 1, 2, 3]; 74 texture_coords_ = [ 0.00, 0.00, 01.00, 0.00, 0.00, 01.00, 01.00, 01.00 ]; 75 76 vao_ = new VAO(); 77 vao_.bind(); 78 79 // Create VBO 80 vbo_ = new Buffer(vertices_); 81 82 // Create IBO 83 ibo_ = new ElementBuffer(indices_); 84 85 // Create buffer object for texture coordinates 86 tbo_ = new Buffer(texture_coords_); 87 texture_ = Texture2D.from_image("example/texture.jpeg"); 88 texture_.set_parameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); 89 texture_.set_parameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); 90 91 // Create program 92 program_ = new Shader("example_program", example_program_src_); 93 program_.bind(); 94 position_ = program_.get_attrib_location("position"); 95 tex_coord_ = program_.get_attrib_location("inCoord"); 96 } 97 98 void draw() 99 { 100 glClearColor(1, 0.9, 0.8, 1); 101 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 102 103 vbo_.bind(); 104 glEnableVertexAttribArray(position_); 105 106 glVertexAttribPointer(position_, 2, GL_FLOAT, GL_FALSE, 0, null); 107 108 ibo_.bind(); 109 110 tbo_.bind(); 111 texture_.bind_and_activate(); 112 glEnableVertexAttribArray(tex_coord_); 113 glVertexAttribPointer(tex_coord_, 2, GL_FLOAT, GL_FALSE, 0, null); 114 115 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, null); 116 117 glDisableVertexAttribArray(tex_coord_); 118 glDisableVertexAttribArray(position_); 119 } 120 121 void close() 122 { 123 // free resources 124 texture_.remove(); 125 tbo_.remove(); 126 ibo_.remove(); 127 vbo_.remove(); 128 program_.remove(); 129 vao_.remove(); 130 } 131 } 132 133 class SDLApplication 134 { 135 private SDL_Window* sdlwindow_; 136 private OnDraw on_draw_; 137 138 alias void delegate() OnDraw; 139 140 @property 141 onDraw(OnDraw on_draw) 142 { 143 assert(on_draw); 144 on_draw_ = on_draw; 145 } 146 147 this() 148 { 149 DerelictSDL2.load(); 150 DerelictGL3.load(); 151 DerelictSDL2Image.load(); 152 153 if (SDL_Init(SDL_INIT_VIDEO) < 0) { 154 throw new Exception("Failed to initialize SDL: " ~ to!string(SDL_GetError())); 155 } 156 157 // Set OpenGL version 158 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 159 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 160 161 // Set OpenGL attributes 162 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 163 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 164 165 sdlwindow_ = SDL_CreateWindow("Glamour texture example application", 166 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 167 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); 168 169 if (!sdlwindow_) 170 throw new Exception("Failed to create a SDL window: " ~ to!string(SDL_GetError())); 171 172 SDL_GL_CreateContext(sdlwindow_); 173 DerelictGL3.reload(); 174 } 175 176 void run() 177 { 178 assert(on_draw_); 179 auto run = true; 180 while (run) { 181 SDL_Event event; 182 while (SDL_PollEvent(&event)) { 183 switch (event.type) { 184 case SDL_QUIT: 185 run = false; 186 break; 187 default: 188 break; 189 } 190 } 191 192 on_draw_(); 193 194 SDL_GL_SwapWindow(sdlwindow_); 195 } 196 } 197 } 198 199 void main() { 200 201 auto app = new SDLApplication(); 202 203 auto renderer = new Renderer(); 204 scope(exit) 205 renderer.close(); 206 207 app.onDraw = &renderer.draw; 208 app.run(); 209 }