program.go 15 KB

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