1 module des.gl.simple.object;
2 
3 import std.exception;
4 import std.stdio;
5 import std.string;
6 
7 public import des.gl.base;
8 
9 ///
10 abstract class GLSimpleObject : GLObject
11 {
12 private:
13     size_t draw_count;
14     size_t index_count;
15 
16     GLBuffer elem_buffer = null;
17 
18 protected:
19 
20     ///
21     void setDrawCount( size_t cnt ) { draw_count = cnt; }
22 
23     ///
24     void setIndexCount( size_t cnt ) { index_count = cnt; }
25 
26     ///
27     CommonGLShaderProgram shader;
28 
29     ///
30     bool warn_if_empty = true;
31 
32     ///
33     auto createArrayBuffer()
34     {
35         auto buf = newEMM!GLBuffer( GLBuffer.Target.ARRAY_BUFFER );
36         connect( buf.elementCountCB, &setDrawCount );
37         return buf;
38     }
39 
40     /+ ??? под вопросом +/
41     static struct APInfo
42     {
43         string name;
44         string attrib;
45         uint per_element;
46         GLType type;
47         size_t stride = 0;
48         size_t offset = 0;
49         bool required = true;
50 
51         this( string n, uint pe, GLType t, bool req=true )
52         {
53             name = n;
54             attrib = n;
55             per_element = pe;
56             type = t; 
57             required = req;
58         }
59 
60         this( string n, string a, uint pe, GLType t, size_t st, size_t of, bool req=true )
61         {
62             this( n, pe, t, req );
63             attrib = a;
64             stride = st;
65             offset = of;
66         }
67     }
68 
69     /+ ??? под вопросом +/
70     auto createArrayBuffersFromAttributeInfo( in APInfo[] infos... )
71     {
72         GLBuffer[string] ret;
73         foreach( info; infos )
74         {
75             auto loc = shader.getAttribLocation( info.attrib );
76 
77             if( loc < 0 )
78             {
79                 if( info.required )
80                     assert( 0, format( "no attrib '%s' in shader", info.attrib ) );
81                 else
82                 {
83                     logger.warn( "no attrib '%s' in shader", info.attrib );
84                     continue;
85                 }
86             }
87 
88             if( info.name !in ret )
89                 ret[info.name] = createArrayBuffer();
90                 
91             auto buf = ret[info.name];
92             setAttribPointer( buf, loc, info.per_element, info.type,
93                               info.stride, info.offset );
94         }
95         return ret;
96     }
97 
98     ///
99     auto createIndexBuffer()
100     {
101         auto buf = newEMM!GLBuffer( GLBuffer.Target.ELEMENT_ARRAY_BUFFER );
102         connect( buf.elementCountCB, &setIndexCount );
103         connect( buf.elementSizeCB, (size_t sz){
104             enforce( sz == uint.sizeof, "set to index buffer not uint data" );
105         });
106         elem_buffer = buf;
107         return buf;
108     }
109 
110     ///
111     bool draw_flag = true;
112 
113     ///
114     void preDraw()
115     {
116         vao.bind();
117         shader.use();
118         if( elem_buffer !is null )
119             elem_buffer.bind();
120         debug checkGL;
121     }
122 
123     ///
124     void drawArrays( DrawMode mode )
125     {
126         if( !draw_flag ) return;
127         preDraw();
128         if( draw_count > 0 )
129             glDrawArrays( mode, 0, cast(uint)draw_count );
130         else if( warn_if_empty )
131             logger.warn( "simple object draw empty object" );
132 
133         debug checkGL;
134         debug logger.trace( "mode [%s], count [%d]", mode, draw_count );
135     }
136 
137     ///
138     void drawElements( DrawMode mode )
139     {
140         if( !draw_flag ) return;
141         preDraw();
142         if( index_count > 0 && draw_count > 0 )
143             glDrawElements( mode, cast(uint)index_count, GL_UNSIGNED_INT, null );
144         else if( warn_if_empty )
145             logger.warn( "simple object draw empty object" );
146 
147         debug checkGL;
148         debug logger.trace( "mode [%s], count [%d]", mode, index_count );
149     }
150 
151 public:
152 
153     ///
154     this( string shader_source )
155     {
156         shader = newEMM!CommonGLShaderProgram( parseGLShaderSource( shader_source ) );
157     }
158 
159     ///
160     this( CommonGLShaderProgram sh )
161     in{ assert( sh !is null ); } body
162     { shader = sh; }
163 
164     ///
165     enum DrawMode
166     {
167         POINTS                   = GL_POINTS,                  /// GL_POINTS,
168         LINES                    = GL_LINES,                   /// GL_LINES,
169         LINE_STRIP               = GL_LINE_STRIP,              /// GL_LINE_STRIP,
170         LINE_LOOP                = GL_LINE_LOOP,               /// GL_LINE_LOOP,
171         TRIANGLES                = GL_TRIANGLES,               /// GL_TRIANGLES,
172         TRIANGLE_STRIP           = GL_TRIANGLE_STRIP,          /// GL_TRIANGLE_STRIP,
173         TRIANGLE_FAN             = GL_TRIANGLE_FAN,            /// GL_TRIANGLE_FAN,
174         LINES_ADJACENCY          = GL_LINES_ADJACENCY,         /// GL_LINES_ADJACENCY,
175         LINE_STRIP_ADJACENCY     = GL_LINE_STRIP_ADJACENCY,    /// GL_LINE_STRIP_ADJACENCY,
176         TRIANGLES_ADJACENCY      = GL_TRIANGLES_ADJACENCY,     /// GL_TRIANGLES_ADJACENCY,
177         TRIANGLE_STRIP_ADJACENCY = GL_TRIANGLE_STRIP_ADJACENCY /// GL_TRIANGLE_STRIP_ADJACENCY,
178     }
179 }