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