lace_opengl_0.1.0_672a6415/source/lean/shader/opengl-program.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
with
     openGL.Tasks,

     GL.Pointers,
     GL.lean,

     ada.Characters.latin_1,
     interfaces.C.Strings;


package body openGL.Program
is
   use gl.lean,
       Interfaces;

   compiling_in_debug_Mode : constant Boolean := True;

   type Shader_view is access all Shader.item'Class;


   --------------
   --  Parameters
   --

   procedure Program_is (Self : in out Parameters;   Now : in openGL.Program.view)
   is
   begin
      Self.Program := Now;
   end Program_is;


   function Program (Self : in Parameters) return openGL.Program.view
   is
   begin
      return Self.Program;
   end Program;


   ---------
   --- Forge
   --

   procedure define (Self : in out Item;   use_vertex_Shader   : in Shader.view;
                                           use_fragment_Shader : in Shader.view)
   is
   begin
      Tasks.check;

      Self.gl_Program := glCreateProgram;

      glAttachShader (Self.gl_Program,    use_vertex_Shader.gl_Shader);
      glAttachShader (Self.gl_Program,  use_fragment_Shader.gl_Shader);

      Self.  vertex_Shader :=   use_vertex_Shader;
      Self.fragment_Shader := use_fragment_Shader;

      glLinkProgram (Self.gl_Program);

      declare
         use type C.int;
         Status : aliased gl.glInt;
      begin
         glGetProgramiv (Self.gl_Program,
                         GL_LINK_STATUS,
                         Status'unchecked_Access);

         if Status = 0
         then
            declare
               link_Log : constant String := Self.ProgramInfoLog;
            begin
               Self.destroy;
               raise Error with "Program link error ~ " & link_Log;
            end;
         end if;
      end;

      if compiling_in_debug_Mode
      then
         glValidateProgram (Self.gl_Program);
      end if;
   end define;



   procedure define (Self : in out Item;   use_vertex_Shader_File   : in String;
                                           use_fragment_Shader_File : in String)
   is
      use openGL.Shader;
      the_vertex_Shader   : constant Shader_view := new openGL.Shader.item;
      the_fragment_Shader : constant Shader_view := new openGL.Shader.item;
   begin
      the_vertex_Shader  .define (openGL.Shader.vertex,     use_vertex_Shader_File);
      the_fragment_Shader.define (openGL.Shader.fragment, use_fragment_Shader_File);

      Self.define (  the_vertex_Shader.all'Access,
                   the_fragment_Shader.all'Access);
   end define;



   procedure destroy (Self : in out Item)
   is
   begin
      Tasks.check;
      glDeleteProgram (Self.gl_Program);
   end destroy;


   --------------
   --  Attributes
   --

   function Attribute (Self : access Item'Class;   Named : in String) return openGL.Attribute.view
   is
   begin
      for Each in 1 .. Self.attribute_Count
      loop
         if Self.Attributes (Each).Name = Named
         then
            return Self.Attributes (Each);
         end if;
      end loop;

      raise Error with "'" & Named & "' is not a valid program attribute.";
   end Attribute;



   function attribute_Location (Self : access Item'Class;   Named : in String) return gl.GLuint
   is
      use      gl.Pointers;
      use type gl.GLint;

      attribute_Name : C.strings.chars_ptr := C.Strings.new_String (Named & ada.characters.Latin_1.NUL);

   begin
      Tasks.check;

      declare
         gl_Location : constant gl.GLint := glGetAttribLocation (Self.gl_Program,
                                                                 to_GLchar_access (attribute_Name));
      begin
         if gl_Location = -1
         then
            raise Error with "Requested attribute '" & Named & "' has no gl location in program.";
         end if;

         C.Strings.free (attribute_Name);

         return gl.GLuint (gl_Location);
      end;
   end attribute_Location;



   function is_defined (Self : in Item'Class) return Boolean
   is
      use type a_gl_Program;
   begin
      return Self.gl_Program /= 0;
   end is_defined;



   function ProgramInfoLog (Self : in Item) return String
   is
      use C, GL;

      info_log_Length : aliased glInt   := 0;
      chars_Written   : aliased glSizei := 0;

   begin
      Tasks.check;

      glGetProgramiv (Self.gl_Program,
                      GL_INFO_LOG_LENGTH,
                      info_log_Length'unchecked_Access);

      if info_log_Length = 0 then
         return "";
      end if;

      declare
         use GL.Pointers;
         info_Log     : aliased  C.char_array        := C.char_array' (1 .. C.size_t (info_log_Length) => <>);
         info_Log_ptr : constant C.strings.chars_ptr := C.strings.to_chars_ptr (info_Log'unchecked_Access);
      begin
         glGetProgramInfoLog (Self.gl_Program,
                              glSizei (info_log_Length),
                              chars_Written'unchecked_Access,
                              to_GLchar_access (info_Log_ptr));
         return C.to_Ada (info_Log);
      end;
   end ProgramInfoLog;



   function uniform_Variable (Self : access Item'Class;   Named : in String) return Variable.uniform.bool
   is
      the_Variable : Variable.uniform.bool;
   begin
      the_Variable.define (Self, Named);
      return the_Variable;
   end uniform_Variable;



   function uniform_Variable (Self : access Item'Class;   Named : in String) return Variable.uniform.int
   is
      the_Variable : Variable.uniform.int;
   begin
      the_Variable.define (Self, Named);
      return the_Variable;
   end uniform_Variable;



   function uniform_Variable (Self : access Item'Class;   Named : in String) return Variable.uniform.float
   is
      the_Variable : Variable.uniform.float;
   begin
      the_Variable.define (Self, Named);
      return the_Variable;
   end uniform_Variable;



   function uniform_Variable (Self : access Item'Class;   Named : in String) return Variable.uniform.vec3
   is
      the_Variable : Variable.uniform.vec3;
   begin
      the_Variable.define (Self, Named);
      return the_Variable;
   end uniform_Variable;



   function uniform_Variable (Self : access Item'Class;   Named : in String) return Variable.uniform.vec4
   is
      the_Variable : Variable.uniform.vec4;
   begin
      the_Variable.define (Self, Named);
      return the_Variable;
   end uniform_Variable;



   function uniform_Variable (Self : access Item'Class;   Named : in String) return Variable.uniform.mat3
   is
      the_Variable : Variable.uniform.mat3;
   begin
      the_Variable.define (Self, Named);
      return the_Variable;
   end uniform_Variable;



   function uniform_Variable (Self : access Item'Class;   Named : in String) return Variable.uniform.mat4
   is
      the_Variable : Variable.uniform.mat4;
   begin
      the_Variable.define (Self, Named);
      return the_Variable;
   end uniform_Variable;


   --------------
   --  Operations
   --

   procedure add (Self : in out Item;   Attribute : in openGL.Attribute.view)
   is
   begin
      Self.attribute_Count                   := Self.attribute_Count + 1;
      Self.Attributes (Self.attribute_Count) := Attribute;
   end add;



   procedure enable (Self : in out Item)
   is
      use type gl.GLuint;
   begin
      Tasks.check;

      if Self.gl_Program = 0
      then
         Item'Class (Self).define;     -- TODO: This appears to do nothing.
      end if;

      glUseProgram (self.gl_Program);
   end enable;



   procedure enable_Attributes (Self : in Item)
   is
   begin
      for Each in 1 .. Self.attribute_Count
      loop
         Self.Attributes (Each).enable;
      end loop;
   end enable_Attributes;



   procedure mvp_Transform_is (Self : in out Item;   Now : in Matrix_4x4)
   is
   begin
      Self.mvp_Transform := Now;
   end mvp_Transform_is;



   procedure Scale_is (Self : in out Item;   Now : in Vector_3)
   is
   begin
      Self.Scale := Now;
   end Scale_is;



   procedure set_Uniforms (Self : in Item)
   is
      the_mvp_Uniform   : constant Variable.uniform.mat4 := Self.uniform_Variable ("mvp_Transform");
      the_scale_Uniform : constant Variable.uniform.vec3 := Self.uniform_Variable ("Scale");
   begin
      the_mvp_Uniform  .Value_is (Self.mvp_Transform);
      the_scale_Uniform.Value_is (Self.Scale);
   end set_Uniforms;



   --  Privvy
   --

   function gl_Program (Self : in Item) return a_gl_Program
   is
   begin
      return Self.gl_Program;
   end gl_Program;


end openGL.Program;