Fortran · 4081 bytes Raw Blame History
1 module shader_mod
2 use, intrinsic :: iso_c_binding
3 use gl_bindings
4 implicit none
5 private
6
7 public :: shader_t
8 public :: shader_create, shader_destroy, shader_use
9 public :: shader_set_projection, shader_set_int
10
11 type :: shader_t
12 integer :: program_id = 0
13 integer :: projection_loc = -1
14 integer :: atlas_loc = -1
15 logical :: valid = .false.
16 end type shader_t
17
18 contains
19
20 ! Create a shader program from vertex and fragment source
21 function shader_create(vert_source, frag_source) result(shader)
22 character(len=*), intent(in) :: vert_source, frag_source
23 type(shader_t) :: shader
24 integer :: vert_id, frag_id
25 integer :: success
26 character(len=512) :: log_buffer
27
28 ! Compile vertex shader
29 vert_id = glCreateShader(GL_VERTEX_SHADER)
30 call glShaderSource(vert_id, vert_source // c_null_char)
31 call glCompileShader(vert_id)
32
33 success = glGetShaderCompileStatus(vert_id)
34 if (success == 0) then
35 call glGetShaderInfoLog(vert_id, log_buffer, 512)
36 print *, "Error: Vertex shader compilation failed:"
37 print *, trim(log_buffer)
38 call glDeleteShader(vert_id)
39 return
40 end if
41
42 ! Compile fragment shader
43 frag_id = glCreateShader(GL_FRAGMENT_SHADER)
44 call glShaderSource(frag_id, frag_source // c_null_char)
45 call glCompileShader(frag_id)
46
47 success = glGetShaderCompileStatus(frag_id)
48 if (success == 0) then
49 call glGetShaderInfoLog(frag_id, log_buffer, 512)
50 print *, "Error: Fragment shader compilation failed:"
51 print *, trim(log_buffer)
52 call glDeleteShader(vert_id)
53 call glDeleteShader(frag_id)
54 return
55 end if
56
57 ! Link program
58 shader%program_id = glCreateProgram()
59 call glAttachShader(shader%program_id, vert_id)
60 call glAttachShader(shader%program_id, frag_id)
61 call glLinkProgram(shader%program_id)
62
63 success = glGetProgramLinkStatus(shader%program_id)
64 if (success == 0) then
65 call glGetProgramInfoLog(shader%program_id, log_buffer, 512)
66 print *, "Error: Shader program linking failed:"
67 print *, trim(log_buffer)
68 call glDeleteShader(vert_id)
69 call glDeleteShader(frag_id)
70 call glDeleteProgram(shader%program_id)
71 shader%program_id = 0
72 return
73 end if
74
75 ! Clean up shaders (they're linked into the program now)
76 call glDeleteShader(vert_id)
77 call glDeleteShader(frag_id)
78
79 ! Get uniform locations
80 shader%projection_loc = glGetUniformLocation(shader%program_id, &
81 "u_projection" // c_null_char)
82 shader%atlas_loc = glGetUniformLocation(shader%program_id, &
83 "u_atlas" // c_null_char)
84
85 shader%valid = .true.
86
87 end function shader_create
88
89 ! Use this shader program
90 subroutine shader_use(shader)
91 type(shader_t), intent(in) :: shader
92 if (shader%valid) then
93 call glUseProgram(shader%program_id)
94 end if
95 end subroutine shader_use
96
97 ! Set the projection matrix uniform
98 subroutine shader_set_projection(shader, matrix)
99 type(shader_t), intent(in) :: shader
100 real(c_float), intent(in) :: matrix(4,4)
101
102 if (shader%valid .and. shader%projection_loc >= 0) then
103 call glUniformMatrix4fv(shader%projection_loc, 1, GL_FALSE, matrix)
104 end if
105 end subroutine shader_set_projection
106
107 ! Set an integer uniform
108 subroutine shader_set_int(shader, name, value)
109 type(shader_t), intent(in) :: shader
110 character(len=*), intent(in) :: name
111 integer, intent(in) :: value
112 integer :: loc
113
114 if (shader%valid) then
115 loc = glGetUniformLocation(shader%program_id, name // c_null_char)
116 if (loc >= 0) then
117 call glUniform1i(loc, value)
118 end if
119 end if
120 end subroutine shader_set_int
121
122 ! Destroy shader program
123 subroutine shader_destroy(shader)
124 type(shader_t), intent(inout) :: shader
125
126 if (shader%program_id > 0) then
127 call glDeleteProgram(shader%program_id)
128 shader%program_id = 0
129 end if
130 shader%valid = .false.
131 end subroutine shader_destroy
132
133 end module shader_mod
134