2
0

helpers.odin 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package vendor_gl
  2. // Helper for loading shaders into a program
  3. import "core:os"
  4. import "core:fmt"
  5. import "core:strings"
  6. _ :: fmt
  7. Shader_Type :: enum i32 {
  8. NONE = 0x0000,
  9. FRAGMENT_SHADER = 0x8B30,
  10. VERTEX_SHADER = 0x8B31,
  11. GEOMETRY_SHADER = 0x8DD9,
  12. COMPUTE_SHADER = 0x91B9,
  13. TESS_EVALUATION_SHADER = 0x8E87,
  14. TESS_CONTROL_SHADER = 0x8E88,
  15. SHADER_LINK = -1, // @Note: Not an OpenGL constant, but used for error checking.
  16. }
  17. @(private, thread_local)
  18. last_compile_error_message: []byte
  19. @(private, thread_local)
  20. last_link_error_message: []byte
  21. @(private, thread_local)
  22. last_compile_error_type: Shader_Type
  23. @(private, thread_local)
  24. last_link_error_type: Shader_Type
  25. get_last_error_messages :: proc() -> (compile_message: string, compile_type: Shader_Type, link_message: string, link_type: Shader_Type) {
  26. compile_message = string(last_compile_error_message[:max(0, len(last_compile_error_message)-1)])
  27. compile_type = last_compile_error_type
  28. link_message = string(last_link_error_message[:max(0, len(last_link_error_message)-1)])
  29. link_type = last_link_error_type
  30. return
  31. }
  32. get_last_error_message :: proc() -> (compile_message: string, compile_type: Shader_Type) {
  33. compile_message = string(last_compile_error_message[:max(0, len(last_compile_error_message)-1)])
  34. compile_type = last_compile_error_type
  35. return
  36. }
  37. // Shader checking and linking checking are identical
  38. // except for calling differently named GL functions
  39. // it's a bit ugly looking, but meh
  40. when GL_DEBUG {
  41. import "core:runtime"
  42. @private
  43. check_error :: proc(
  44. id: u32, type: Shader_Type, status: u32,
  45. iv_func: proc "c" (u32, u32, [^]i32, runtime.Source_Code_Location),
  46. log_func: proc "c" (u32, i32, ^i32, [^]u8, runtime.Source_Code_Location),
  47. loc := #caller_location,
  48. ) -> (success: bool) {
  49. result, info_log_length: i32
  50. iv_func(id, status, &result, loc)
  51. iv_func(id, INFO_LOG_LENGTH, &info_log_length, loc)
  52. if result == 0 {
  53. if log_func == GetShaderInfoLog {
  54. delete(last_compile_error_message)
  55. last_compile_error_message = make([]byte, info_log_length)
  56. last_compile_error_type = type
  57. log_func(id, i32(info_log_length), nil, raw_data(last_compile_error_message), loc)
  58. //fmt.printf_err("Error in %v:\n%s", type, string(last_compile_error_message[0:len(last_compile_error_message)-1]));
  59. } else {
  60. delete(last_link_error_message)
  61. last_link_error_message = make([]byte, info_log_length)
  62. last_compile_error_type = type
  63. log_func(id, i32(info_log_length), nil, raw_data(last_link_error_message), loc)
  64. //fmt.printf_err("Error in %v:\n%s", type, string(last_link_error_message[0:len(last_link_error_message)-1]));
  65. }
  66. return false
  67. }
  68. return true
  69. }
  70. } else {
  71. @private
  72. check_error :: proc(
  73. id: u32, type: Shader_Type, status: u32,
  74. iv_func: proc "c" (u32, u32, [^]i32),
  75. log_func: proc "c" (u32, i32, ^i32, [^]u8),
  76. ) -> (success: bool) {
  77. result, info_log_length: i32
  78. iv_func(id, status, &result)
  79. iv_func(id, INFO_LOG_LENGTH, &info_log_length)
  80. if result == 0 {
  81. if log_func == GetShaderInfoLog {
  82. delete(last_compile_error_message)
  83. last_compile_error_message = make([]u8, info_log_length)
  84. last_link_error_type = type
  85. log_func(id, i32(info_log_length), nil, raw_data(last_compile_error_message))
  86. fmt.eprintf("Error in %v:\n%s", type, string(last_compile_error_message[0:len(last_compile_error_message)-1]))
  87. } else {
  88. delete(last_link_error_message)
  89. last_link_error_message = make([]u8, info_log_length)
  90. last_link_error_type = type
  91. log_func(id, i32(info_log_length), nil, raw_data(last_link_error_message))
  92. fmt.eprintf("Error in %v:\n%s", type, string(last_link_error_message[0:len(last_link_error_message)-1]))
  93. }
  94. return false
  95. }
  96. return true
  97. }
  98. }
  99. // Compiling shaders are identical for any shader (vertex, geometry, fragment, tesselation, (maybe compute too))
  100. @private
  101. compile_shader_from_source :: proc(shader_data: string, shader_type: Shader_Type) -> (shader_id: u32, ok: bool) {
  102. shader_id = CreateShader(cast(u32)shader_type)
  103. length := i32(len(shader_data))
  104. shader_data_copy := cstring(raw_data(shader_data))
  105. ShaderSource(shader_id, 1, &shader_data_copy, &length)
  106. CompileShader(shader_id)
  107. check_error(shader_id, shader_type, COMPILE_STATUS, GetShaderiv, GetShaderInfoLog) or_return
  108. ok = true
  109. return
  110. }
  111. // only used once, but I'd just make a subprocedure(?) for consistency
  112. @private
  113. create_and_link_program :: proc(shader_ids: []u32, binary_retrievable := false) -> (program_id: u32, ok: bool) {
  114. program_id = CreateProgram()
  115. for id in shader_ids {
  116. AttachShader(program_id, id)
  117. }
  118. if binary_retrievable {
  119. ProgramParameteri(program_id, PROGRAM_BINARY_RETRIEVABLE_HINT, 1/*true*/)
  120. }
  121. LinkProgram(program_id)
  122. check_error(program_id, Shader_Type.SHADER_LINK, LINK_STATUS, GetProgramiv, GetProgramInfoLog) or_return
  123. ok = true
  124. return
  125. }
  126. load_compute_file :: proc(filename: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
  127. cs_data := os.read_entire_file(filename) or_return
  128. defer delete(cs_data)
  129. // Create the shaders
  130. compute_shader_id := compile_shader_from_source(string(cs_data), Shader_Type(COMPUTE_SHADER)) or_return
  131. return create_and_link_program([]u32{compute_shader_id}, binary_retrievable)
  132. }
  133. load_compute_source :: proc(cs_data: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
  134. // Create the shaders
  135. compute_shader_id := compile_shader_from_source(cs_data, Shader_Type(COMPUTE_SHADER)) or_return
  136. return create_and_link_program([]u32{compute_shader_id}, binary_retrievable)
  137. }
  138. load_shaders_file :: proc(vs_filename, fs_filename: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
  139. vs_data := os.read_entire_file(vs_filename) or_return
  140. defer delete(vs_data)
  141. fs_data := os.read_entire_file(fs_filename) or_return
  142. defer delete(fs_data)
  143. return load_shaders_source(string(vs_data), string(fs_data), binary_retrievable)
  144. }
  145. load_shaders_source :: proc(vs_source, fs_source: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
  146. // actual function from here
  147. vertex_shader_id := compile_shader_from_source(vs_source, Shader_Type.VERTEX_SHADER) or_return
  148. defer DeleteShader(vertex_shader_id)
  149. fragment_shader_id := compile_shader_from_source(fs_source, Shader_Type.FRAGMENT_SHADER) or_return
  150. defer DeleteShader(fragment_shader_id)
  151. return create_and_link_program([]u32{vertex_shader_id, fragment_shader_id}, binary_retrievable)
  152. }
  153. load_shaders :: proc{load_shaders_file}
  154. when ODIN_OS == .Windows {
  155. update_shader_if_changed :: proc(
  156. vertex_name, fragment_name: string,
  157. program: u32,
  158. last_vertex_time, last_fragment_time: os.File_Time,
  159. ) -> (
  160. old_program: u32,
  161. current_vertex_time, current_fragment_time: os.File_Time,
  162. updated: bool,
  163. ) {
  164. current_vertex_time, _ = os.last_write_time_by_name(vertex_name)
  165. current_fragment_time, _ = os.last_write_time_by_name(fragment_name)
  166. old_program = program
  167. if current_vertex_time != last_vertex_time || current_fragment_time != last_fragment_time {
  168. new_program, success := load_shaders(vertex_name, fragment_name)
  169. if success {
  170. DeleteProgram(old_program)
  171. old_program = new_program
  172. fmt.println("Updated shaders")
  173. updated = true
  174. } else {
  175. fmt.println("Failed to update shaders")
  176. }
  177. }
  178. return old_program, current_vertex_time, current_fragment_time, updated
  179. }
  180. update_shader_if_changed_compute :: proc(
  181. compute_name: string,
  182. program: u32,
  183. last_compute_time: os.File_Time,
  184. ) -> (
  185. old_program: u32,
  186. current_compute_time: os.File_Time,
  187. updated: bool,
  188. ) {
  189. current_compute_time, _ = os.last_write_time_by_name(compute_name)
  190. old_program = program
  191. if current_compute_time != last_compute_time {
  192. new_program, success := load_compute_file(compute_name)
  193. if success {
  194. DeleteProgram(old_program)
  195. old_program = new_program
  196. fmt.println("Updated shaders")
  197. updated = true
  198. } else {
  199. fmt.println("Failed to update shaders")
  200. }
  201. }
  202. return old_program, current_compute_time, updated
  203. }
  204. }
  205. Uniform_Type :: enum i32 {
  206. FLOAT = 0x1406,
  207. FLOAT_VEC2 = 0x8B50,
  208. FLOAT_VEC3 = 0x8B51,
  209. FLOAT_VEC4 = 0x8B52,
  210. DOUBLE = 0x140A,
  211. DOUBLE_VEC2 = 0x8FFC,
  212. DOUBLE_VEC3 = 0x8FFD,
  213. DOUBLE_VEC4 = 0x8FFE,
  214. INT = 0x1404,
  215. INT_VEC2 = 0x8B53,
  216. INT_VEC3 = 0x8B54,
  217. INT_VEC4 = 0x8B55,
  218. UNSIGNED_INT = 0x1405,
  219. UNSIGNED_INT_VEC2 = 0x8DC6,
  220. UNSIGNED_INT_VEC3 = 0x8DC7,
  221. UNSIGNED_INT_VEC4 = 0x8DC8,
  222. BOOL = 0x8B56,
  223. BOOL_VEC2 = 0x8B57,
  224. BOOL_VEC3 = 0x8B58,
  225. BOOL_VEC4 = 0x8B59,
  226. FLOAT_MAT2 = 0x8B5A,
  227. FLOAT_MAT3 = 0x8B5B,
  228. FLOAT_MAT4 = 0x8B5C,
  229. FLOAT_MAT2x3 = 0x8B65,
  230. FLOAT_MAT2x4 = 0x8B66,
  231. FLOAT_MAT3x2 = 0x8B67,
  232. FLOAT_MAT3x4 = 0x8B68,
  233. FLOAT_MAT4x2 = 0x8B69,
  234. FLOAT_MAT4x3 = 0x8B6A,
  235. DOUBLE_MAT2 = 0x8F46,
  236. DOUBLE_MAT3 = 0x8F47,
  237. DOUBLE_MAT4 = 0x8F48,
  238. DOUBLE_MAT2x3 = 0x8F49,
  239. DOUBLE_MAT2x4 = 0x8F4A,
  240. DOUBLE_MAT3x2 = 0x8F4B,
  241. DOUBLE_MAT3x4 = 0x8F4C,
  242. DOUBLE_MAT4x2 = 0x8F4D,
  243. DOUBLE_MAT4x3 = 0x8F4E,
  244. SAMPLER_1D = 0x8B5D,
  245. SAMPLER_2D = 0x8B5E,
  246. SAMPLER_3D = 0x8B5F,
  247. SAMPLER_CUBE = 0x8B60,
  248. SAMPLER_1D_SHADOW = 0x8B61,
  249. SAMPLER_2D_SHADOW = 0x8B62,
  250. SAMPLER_1D_ARRAY = 0x8DC0,
  251. SAMPLER_2D_ARRAY = 0x8DC1,
  252. SAMPLER_1D_ARRAY_SHADOW = 0x8DC3,
  253. SAMPLER_2D_ARRAY_SHADOW = 0x8DC4,
  254. SAMPLER_2D_MULTISAMPLE = 0x9108,
  255. SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910B,
  256. SAMPLER_CUBE_SHADOW = 0x8DC5,
  257. SAMPLER_BUFFER = 0x8DC2,
  258. SAMPLER_2D_RECT = 0x8B63,
  259. SAMPLER_2D_RECT_SHADOW = 0x8B64,
  260. INT_SAMPLER_1D = 0x8DC9,
  261. INT_SAMPLER_2D = 0x8DCA,
  262. INT_SAMPLER_3D = 0x8DCB,
  263. INT_SAMPLER_CUBE = 0x8DCC,
  264. INT_SAMPLER_1D_ARRAY = 0x8DCE,
  265. INT_SAMPLER_2D_ARRAY = 0x8DCF,
  266. INT_SAMPLER_2D_MULTISAMPLE = 0x9109,
  267. INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910C,
  268. INT_SAMPLER_BUFFER = 0x8DD0,
  269. INT_SAMPLER_2D_RECT = 0x8DCD,
  270. UNSIGNED_INT_SAMPLER_1D = 0x8DD1,
  271. UNSIGNED_INT_SAMPLER_2D = 0x8DD2,
  272. UNSIGNED_INT_SAMPLER_3D = 0x8DD3,
  273. UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4,
  274. UNSIGNED_INT_SAMPLER_1D_ARRAY = 0x8DD6,
  275. UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7,
  276. UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 0x910A,
  277. UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910D,
  278. UNSIGNED_INT_SAMPLER_BUFFER = 0x8DD8,
  279. UNSIGNED_INT_SAMPLER_2D_RECT = 0x8DD5,
  280. IMAGE_1D = 0x904C,
  281. IMAGE_2D = 0x904D,
  282. IMAGE_3D = 0x904E,
  283. IMAGE_2D_RECT = 0x904F,
  284. IMAGE_CUBE = 0x9050,
  285. IMAGE_BUFFER = 0x9051,
  286. IMAGE_1D_ARRAY = 0x9052,
  287. IMAGE_2D_ARRAY = 0x9053,
  288. IMAGE_CUBE_MAP_ARRAY = 0x9054,
  289. IMAGE_2D_MULTISAMPLE = 0x9055,
  290. IMAGE_2D_MULTISAMPLE_ARRAY = 0x9056,
  291. INT_IMAGE_1D = 0x9057,
  292. INT_IMAGE_2D = 0x9058,
  293. INT_IMAGE_3D = 0x9059,
  294. INT_IMAGE_2D_RECT = 0x905A,
  295. INT_IMAGE_CUBE = 0x905B,
  296. INT_IMAGE_BUFFER = 0x905C,
  297. INT_IMAGE_1D_ARRAY = 0x905D,
  298. INT_IMAGE_2D_ARRAY = 0x905E,
  299. INT_IMAGE_CUBE_MAP_ARRAY = 0x905F,
  300. INT_IMAGE_2D_MULTISAMPLE = 0x9060,
  301. INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x9061,
  302. UNSIGNED_INT_IMAGE_1D = 0x9062,
  303. UNSIGNED_INT_IMAGE_2D = 0x9063,
  304. UNSIGNED_INT_IMAGE_3D = 0x9064,
  305. UNSIGNED_INT_IMAGE_2D_RECT = 0x9065,
  306. UNSIGNED_INT_IMAGE_CUBE = 0x9066,
  307. UNSIGNED_INT_IMAGE_BUFFER = 0x9067,
  308. UNSIGNED_INT_IMAGE_1D_ARRAY = 0x9068,
  309. UNSIGNED_INT_IMAGE_2D_ARRAY = 0x9069,
  310. UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 0x906A,
  311. UNSIGNED_INT_IMAGE_2D_MULTISAMPLE = 0x906B,
  312. UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x906C,
  313. UNSIGNED_INT_ATOMIC_COUNTER = 0x92DB,
  314. }
  315. Uniform_Info :: struct {
  316. location: i32,
  317. size: i32,
  318. kind: Uniform_Type,
  319. name: string, // NOTE: This will need to be freed
  320. }
  321. Uniforms :: map[string]Uniform_Info
  322. destroy_uniforms :: proc(u: Uniforms) {
  323. for _, v in u {
  324. delete(v.name)
  325. }
  326. delete(u)
  327. }
  328. get_uniforms_from_program :: proc(program: u32) -> (uniforms: Uniforms) {
  329. uniform_count: i32
  330. GetProgramiv(program, ACTIVE_UNIFORMS, &uniform_count)
  331. if uniform_count > 0 {
  332. reserve(&uniforms, int(uniform_count))
  333. }
  334. for i in 0..<uniform_count {
  335. uniform_info: Uniform_Info
  336. length: i32
  337. cname: [256]u8
  338. GetActiveUniform(program, u32(i), 256, &length, &uniform_info.size, cast(^u32)&uniform_info.kind, &cname[0])
  339. uniform_info.location = GetUniformLocation(program, cstring(&cname[0]))
  340. uniform_info.name = strings.clone(string(cname[:length])) // @NOTE: These need to be freed
  341. uniforms[uniform_info.name] = uniform_info
  342. }
  343. return uniforms
  344. }