helpers.odin 13 KB

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