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 }