program.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gls
  5. import (
  6. "bytes"
  7. "errors"
  8. "fmt"
  9. "github.com/g3n/engine/math32"
  10. "io"
  11. "strconv"
  12. "strings"
  13. )
  14. // Shader Program Object
  15. type Program struct {
  16. // Shows source code in error messages
  17. ShowSource bool
  18. gs *GLS
  19. handle uint32
  20. shaders []shaderInfo
  21. uniforms map[string]int32
  22. Specs interface{}
  23. }
  24. type shaderInfo struct {
  25. stype uint32
  26. source string
  27. defines map[string]interface{}
  28. handle uint32
  29. }
  30. // Map shader types to names
  31. var shaderNames = map[uint32]string{
  32. //gl.VERTEX_SHADER: "Vertex Shader",
  33. //gl.FRAGMENT_SHADER: "Fragment Shader",
  34. }
  35. // NewProgram creates a new empty shader program object.
  36. // Use this type methods to add shaders and build the final program.
  37. func (gs *GLS) NewProgram() *Program {
  38. prog := new(Program)
  39. prog.gs = gs
  40. prog.shaders = make([]shaderInfo, 0)
  41. prog.uniforms = make(map[string]int32)
  42. prog.ShowSource = true
  43. return prog
  44. }
  45. // AddShaders adds a shader to this program.
  46. // This must be done before the program is built.
  47. func (prog *Program) AddShader(stype uint32, source string, defines map[string]interface{}) {
  48. if prog.handle != 0 {
  49. log.Fatal("Program already built")
  50. }
  51. prog.shaders = append(prog.shaders, shaderInfo{stype, source, defines, 0})
  52. }
  53. // Build builds the program compiling and linking the previously supplied shaders.
  54. func (prog *Program) Build() error {
  55. if prog.handle != 0 {
  56. return fmt.Errorf("Program already built")
  57. }
  58. // Checks if shaders were provided
  59. if len(prog.shaders) == 0 {
  60. return fmt.Errorf("No shaders supplied")
  61. }
  62. // Create program
  63. prog.handle = prog.gs.CreateProgram()
  64. if prog.handle == 0 {
  65. return fmt.Errorf("Error creating program")
  66. }
  67. // Clean unused GL allocated resources
  68. defer func() {
  69. for _, sinfo := range prog.shaders {
  70. if sinfo.handle != 0 {
  71. prog.gs.DeleteShader(sinfo.handle)
  72. sinfo.handle = 0
  73. }
  74. }
  75. }()
  76. // Compiles and attach each shader
  77. for _, sinfo := range prog.shaders {
  78. // Creates string with defines from specified parameters
  79. deflines := make([]string, 0)
  80. if sinfo.defines != nil {
  81. for pname, pval := range sinfo.defines {
  82. line := "#define " + pname + " "
  83. switch val := pval.(type) {
  84. case bool:
  85. if val {
  86. deflines = append(deflines, line)
  87. }
  88. case float32:
  89. line += strconv.FormatFloat(float64(val), 'f', -1, 32)
  90. deflines = append(deflines, line)
  91. default:
  92. panic("Parameter type not supported")
  93. }
  94. }
  95. }
  96. deftext := strings.Join(deflines, "\n")
  97. // Compile shader
  98. shader, err := prog.CompileShader(sinfo.stype, sinfo.source+deftext)
  99. if err != nil {
  100. prog.gs.DeleteProgram(prog.handle)
  101. prog.handle = 0
  102. msg := fmt.Sprintf("Error compiling %s: %s", shaderNames[sinfo.stype], err)
  103. if prog.ShowSource {
  104. source := FormatSource(sinfo.source + deftext)
  105. msg += source
  106. }
  107. return errors.New(msg)
  108. }
  109. sinfo.handle = shader
  110. prog.gs.AttachShader(prog.handle, shader)
  111. }
  112. // Link program and checks for errors
  113. prog.gs.LinkProgram(prog.handle)
  114. var status int32
  115. prog.gs.GetProgramiv(prog.handle, LINK_STATUS, &status)
  116. if status == FALSE {
  117. log := prog.gs.GetProgramInfoLog(prog.handle)
  118. prog.handle = 0
  119. return fmt.Errorf("Error linking program: %v", log)
  120. }
  121. return nil
  122. }
  123. // Handle returns the handle of this program
  124. func (prog *Program) Handle() uint32 {
  125. return prog.handle
  126. }
  127. //// GetActiveUniformBlockSize returns the minimum number of bytes
  128. //// to contain the data for the uniform block specified by its index.
  129. //func (prog *Program) GetActiveUniformBlockSize(ubindex uint32) int32 {
  130. //
  131. // var uboSize int32
  132. // gl.GetActiveUniformBlockiv(prog.handle, ubindex, gl.UNIFORM_BLOCK_DATA_SIZE, &uboSize)
  133. // if prog.gs.CheckErrors() {
  134. // ecode := gl.GetError()
  135. // if ecode != 0 {
  136. // log.Fatal("GetUniformBlockSize(%v) error: %d", ubindex, ecode)
  137. // }
  138. // }
  139. // return uboSize
  140. //}
  141. //// GetActiveUniformsiv returns information about the specified uniforms
  142. //// specified by its indices
  143. //func (prog *Program) GetActiveUniformsiv(indices []uint32, pname uint32) []int32 {
  144. //
  145. // data := make([]int32, len(indices))
  146. // gl.GetActiveUniformsiv(prog.handle, int32(len(indices)), &indices[0], pname, &data[0])
  147. // if prog.gs.CheckErrors() {
  148. // ecode := gl.GetError()
  149. // if ecode != 0 {
  150. // log.Fatal("GetActiveUniformsiv() error: %d", ecode)
  151. // }
  152. // }
  153. // return data
  154. //}
  155. // GetAttributeLocation returns the location of the specified attribute
  156. // in this program. This location is internally cached.
  157. func (prog *Program) GetAttribLocation(name string) int32 {
  158. return prog.gs.GetAttribLocation(prog.handle, name)
  159. }
  160. //// GetUniformBlockIndex returns the index of the named uniform block.
  161. //// If the supplied name is not valid, the function returns gl.INVALID_INDEX
  162. //func (prog *Program) GetUniformBlockIndex(name string) uint32 {
  163. //
  164. // index := gl.GetUniformBlockIndex(prog.handle, gl.Str(name+"\x00"))
  165. // if prog.gs.CheckErrors() {
  166. // ecode := gl.GetError()
  167. // if ecode != 0 {
  168. // log.Fatal("GetUniformBlockIndex(%s) error", name)
  169. // }
  170. // }
  171. // return index
  172. //}
  173. //// GetUniformIndices returns the indices for each specified named
  174. //// uniform. If an specified name is not valid the corresponding
  175. //// index value will be gl.INVALID_INDEX
  176. //func (prog *Program) GetUniformIndices(names []string) []uint32 {
  177. //
  178. // // Add C terminators to uniform names
  179. // for _, s := range names {
  180. // s += "\x00"
  181. // }
  182. // unames, freefunc := gl.Strs(names...)
  183. //
  184. // indices := make([]uint32, len(names))
  185. // gl.GetUniformIndices(prog.handle, int32(len(names)), unames, &indices[0])
  186. // if prog.gs.CheckErrors() {
  187. // ecode := gl.GetError()
  188. // if ecode != 0 {
  189. // log.Fatal("GetUniformIndices() error: %d", ecode)
  190. // }
  191. // }
  192. // freefunc()
  193. // return indices
  194. //}
  195. // GetUniformLocation returns the location of the specified uniform in this program.
  196. // This location is internally cached.
  197. func (prog *Program) GetUniformLocation(name string) int32 {
  198. // Try to get from the cache
  199. loc, ok := prog.uniforms[name]
  200. if ok {
  201. return loc
  202. }
  203. // Get location from GL
  204. loc = prog.gs.GetUniformLocation(prog.handle, name)
  205. // Cache result
  206. prog.uniforms[name] = loc
  207. if loc < 0 {
  208. log.Warn("GetUniformLocation(%s) NOT FOUND", name)
  209. }
  210. return loc
  211. }
  212. // SetUniformInt sets this program uniform variable specified by
  213. // its location to the the value of the specified int
  214. func (prog *Program) SetUniformInt(loc int32, v int) {
  215. prog.gs.Uniform1i(loc, int32(v))
  216. }
  217. // SetUniformFloat sets this program uniform variable specified by
  218. // its location to the the value of the specified float
  219. func (prog *Program) SetUniformFloat(loc int32, v float32) {
  220. prog.gs.Uniform1f(loc, v)
  221. }
  222. // SetUniformVector2 sets this program uniform variable specified by
  223. // its location to the the value of the specified Vector2
  224. func (prog *Program) SetUniformVector2(loc int32, v *math32.Vector2) {
  225. prog.gs.Uniform2f(loc, v.X, v.Y)
  226. }
  227. // SetUniformVector3 sets this program uniform variable specified by
  228. // its location to the the value of the specified Vector3
  229. func (prog *Program) SetUniformVector3(loc int32, v *math32.Vector3) {
  230. prog.gs.Uniform3f(loc, v.X, v.Y, v.Z)
  231. }
  232. // SetUniformVector4 sets this program uniform variable specified by
  233. // its location to the the value of the specified Vector4
  234. func (prog *Program) SetUniformVector4(loc int32, v *math32.Vector4) {
  235. prog.gs.Uniform4f(loc, v.X, v.Y, v.Z, v.W)
  236. }
  237. // SetUniformMatrix3 sets this program uniform variable specified by
  238. // its location with the values from the specified Matrix3.
  239. func (prog *Program) SetUniformMatrix3(loc int32, m *math32.Matrix3) {
  240. prog.gs.UniformMatrix3fv(loc, 1, false, &m[0])
  241. }
  242. // SetUniformMatrix4 sets this program uniform variable specified by
  243. // its location with the values from the specified Matrix4.
  244. func (prog *Program) SetUniformMatrix4(loc int32, m *math32.Matrix4) {
  245. prog.gs.UniformMatrix4fv(loc, 1, false, &m[0])
  246. }
  247. // SetUniformIntByName sets this program uniform variable specified by
  248. // its name to the value of the specified int.
  249. // The specified name location is cached internally.
  250. func (prog *Program) SetUniformIntByName(name string, v int) {
  251. prog.gs.Uniform1i(prog.GetUniformLocation(name), int32(v))
  252. }
  253. // SetUniformFloatByName sets this program uniform variable specified by
  254. // its name to the value of the specified float32.
  255. // The specified name location is cached internally.
  256. func (prog *Program) SetUniformFloatByName(name string, v float32) {
  257. prog.gs.Uniform1f(prog.GetUniformLocation(name), v)
  258. }
  259. // SetUniformVector2ByName sets this program uniform variable specified by
  260. // its name to the values from the specified Vector2.
  261. // The specified name location is cached internally.
  262. func (prog *Program) SetUniformVector2ByName(name string, v *math32.Vector2) {
  263. prog.gs.Uniform2f(prog.GetUniformLocation(name), v.X, v.Y)
  264. }
  265. // SetUniformVector3ByName sets this program uniform variable specified by
  266. // its name to the values from the specified Vector3.
  267. // The specified name location is cached internally.
  268. func (prog *Program) SetUniformVector3ByName(name string, v *math32.Vector3) {
  269. prog.gs.Uniform3f(prog.GetUniformLocation(name), v.X, v.Y, v.Z)
  270. }
  271. // SetUniformVector4ByName sets this program uniform variable specified by
  272. // its name to the values from the specified Vector4.
  273. // The specified name location is cached internally.
  274. func (prog *Program) SetUniformVector4ByName(name string, v *math32.Vector4) {
  275. prog.gs.Uniform4f(prog.GetUniformLocation(name), v.X, v.Y, v.Z, v.W)
  276. }
  277. // SetUniformMatrix3ByName sets this program uniform variable specified by
  278. // its name with the values from the specified Matrix3.
  279. // The specified name location is cached internally.
  280. func (prog *Program) SetUniformMatrix3ByName(name string, m *math32.Matrix3) {
  281. prog.gs.UniformMatrix3fv(prog.GetUniformLocation(name), 1, false, &m[0])
  282. }
  283. // SetUniformMatrix4ByName sets this program uniform variable specified by
  284. // its name with the values from the specified Matrix4.
  285. // The location of the name is cached internally.
  286. func (prog *Program) SetUniformMatrix4ByName(name string, m *math32.Matrix4) {
  287. prog.gs.UniformMatrix4fv(prog.GetUniformLocation(name), 1, false, &m[0])
  288. }
  289. // SetUniformColorByName set this program uniform variable specified by
  290. // its name to the values from the specified Color
  291. // The specified name location is cached internally.
  292. func (prog *Program) SetUniformColorByName(name string, c *math32.Color) {
  293. prog.gs.Uniform3f(prog.GetUniformLocation(name), c.R, c.G, c.B)
  294. }
  295. // SetUniformColor4ByName set this program uniform variable specified by
  296. // its name to the values from the specified Color4
  297. // The specified name location is cached internally.
  298. func (prog *Program) SetUniformColor4ByName(name string, c *math32.Color4) {
  299. prog.gs.Uniform4f(prog.GetUniformLocation(name), c.R, c.G, c.B, c.A)
  300. }
  301. // CompileShader creates and compiles a shader of the specified type and with
  302. // the specified source code and returns a non-zero value by which
  303. // it can be referenced.
  304. func (prog *Program) CompileShader(stype uint32, source string) (uint32, error) {
  305. // Creates shader object
  306. shader := prog.gs.CreateShader(stype)
  307. if shader == 0 {
  308. return 0, fmt.Errorf("Error creating shader")
  309. }
  310. // Set shader source and compile it
  311. prog.gs.ShaderSource(shader, source)
  312. prog.gs.CompileShader(shader)
  313. // Get the shader compiler log
  314. slog := prog.gs.GetShaderInfoLog(shader)
  315. // Get the shader compile status
  316. var status int32
  317. prog.gs.GetShaderiv(shader, COMPILE_STATUS, &status)
  318. if status == FALSE {
  319. return shader, fmt.Errorf("%s", slog)
  320. }
  321. // If the shader compiled OK but the log has data,
  322. // logs this data instead of returning error
  323. if len(slog) > 2 {
  324. log.Warn("%s", slog)
  325. }
  326. return shader, nil
  327. }
  328. // FormatSource returns the supplied program source code with
  329. // line numbers prepended.
  330. func FormatSource(source string) string {
  331. // Reads all lines from the source string
  332. lines := make([]string, 0)
  333. buf := bytes.NewBuffer([]byte(source))
  334. for {
  335. line, err := buf.ReadBytes('\n')
  336. if err != nil {
  337. if err == io.EOF {
  338. break
  339. }
  340. panic(err)
  341. }
  342. lines = append(lines, string(line[:len(line)-1]))
  343. }
  344. // Adds a final line terminator
  345. lines = append(lines, "\n")
  346. // Prepends the line number for each line
  347. ndigits := len(strconv.Itoa(len(lines)))
  348. format := "%0" + strconv.Itoa(ndigits) + "d:%s"
  349. formatted := make([]string, 0)
  350. for pos, l := range lines {
  351. fline := fmt.Sprintf(format, pos+1, l)
  352. formatted = append(formatted, fline)
  353. }
  354. return strings.Join(formatted, "\n")
  355. }