vbo.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. "github.com/g3n/engine/math32"
  7. "unsafe"
  8. )
  9. // VBO abstracts an OpenGL Vertex Buffer Object
  10. type VBO struct {
  11. gs *GLS // reference to GLS state
  12. handle uint32 // OpenGL handle for this VBO
  13. usage uint32 // Expected usage patter of the buffer
  14. update bool // Update flag
  15. buffer math32.ArrayF32 // Data buffer
  16. attribs []VBOattrib // List of attributes
  17. }
  18. // VBOattrib describes one attribute of an OpenGL Vertex Buffer Object
  19. type VBOattrib struct {
  20. Name string // Name of of the attribute
  21. ItemSize int32 // Number of elements for each item (1,2,3 or 4)
  22. Stride int32 // Specifies the byte offset between consecutive attributes
  23. Offset uint32 // Byte offset of this attribute from the start of the buffer
  24. }
  25. // NewVBO creates and returns a pointer to a new OpenGL Vertex Buffer Object
  26. func NewVBO() *VBO {
  27. vbo := new(VBO)
  28. vbo.init()
  29. return vbo
  30. }
  31. // init initializes this VBO
  32. func (vbo *VBO) init() {
  33. vbo.gs = nil
  34. vbo.handle = 0
  35. vbo.usage = STATIC_DRAW
  36. vbo.update = true
  37. vbo.attribs = make([]VBOattrib, 0)
  38. }
  39. // AddAttrib adds a new attribute to this VBO with the specified item size (1,2,3 or 4)
  40. // The attribute stride and offset are set to 0.
  41. // Use AddAttribEx to specify the stride and offset
  42. func (vbo *VBO) AddAttrib(name string, itemSize int32) *VBO {
  43. vbo.attribs = append(vbo.attribs, VBOattrib{
  44. Name: name,
  45. ItemSize: itemSize,
  46. })
  47. return vbo
  48. }
  49. func (vbo *VBO) AddAttribEx(name string, itemSize, stride int32, offset uint32) *VBO {
  50. vbo.attribs = append(vbo.attribs, VBOattrib{
  51. Name: name,
  52. ItemSize: itemSize,
  53. Stride: stride,
  54. Offset: offset,
  55. })
  56. return vbo
  57. }
  58. // Attrib finds and returns pointer the attribute with the specified name
  59. // or nil if not found
  60. func (vbo *VBO) Attrib(name string) *VBOattrib {
  61. for _, attr := range vbo.attribs {
  62. if attr.Name == name {
  63. return &attr
  64. }
  65. }
  66. return nil
  67. }
  68. // AttribAt returns pointer to the VBO attribute at the specified index
  69. func (vbo *VBO) AttribAt(idx int) *VBOattrib {
  70. return &vbo.attribs[idx]
  71. }
  72. // AttribCount returns the current number of attributes for this VBO
  73. func (vbo *VBO) AttribCount() int {
  74. return len(vbo.attribs)
  75. }
  76. // Dispose disposes of this VBO OpenGL resources
  77. // As currently the VBO is used only by the Geometry object
  78. // it is not referenced counted.
  79. func (vbo *VBO) Dispose() {
  80. if vbo.gs != nil {
  81. vbo.gs.DeleteBuffers(vbo.handle)
  82. }
  83. vbo.gs = nil
  84. }
  85. // Sets the VBO buffer
  86. func (vbo *VBO) SetBuffer(buffer math32.ArrayF32) *VBO {
  87. vbo.buffer = buffer
  88. vbo.update = true
  89. return vbo
  90. }
  91. // Sets the expected usage pattern of the buffer.
  92. // The default value is GL_STATIC_DRAW.
  93. func (vbo *VBO) SetUsage(usage uint32) {
  94. vbo.usage = usage
  95. }
  96. // Buffer returns pointer to the VBO buffer
  97. func (vbo *VBO) Buffer() *math32.ArrayF32 {
  98. return &vbo.buffer
  99. }
  100. // Updates sets the update flag to force the VBO update
  101. func (vbo *VBO) Update() {
  102. vbo.update = true
  103. }
  104. // Stride returns the stride of this VBO which is the number of bytes
  105. // used by one group attributes side by side in the buffer
  106. // Ex: x y z r g b x y z r g b ...x y z r g b
  107. // The stride will be: sizeof(float) * 6 = 24
  108. func (vbo *VBO) Stride() int {
  109. stride := 0
  110. elsize := int(unsafe.Sizeof(float32(0)))
  111. for _, attrib := range vbo.attribs {
  112. stride += elsize * int(attrib.ItemSize)
  113. }
  114. return stride
  115. }
  116. // Transfer is called internally and transfer the data in the VBO buffer to OpenGL if necessary
  117. func (vbo *VBO) Transfer(gs *GLS) {
  118. // If the VBO buffer is empty, ignore
  119. if vbo.buffer.Bytes() == 0 {
  120. return
  121. }
  122. // First time initialization
  123. if vbo.gs == nil {
  124. vbo.handle = gs.GenBuffer()
  125. gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
  126. for _, attrib := range vbo.attribs {
  127. // Get attribute location in the current program
  128. loc := gs.prog.GetAttribLocation(attrib.Name)
  129. if loc < 0 {
  130. continue
  131. }
  132. // Enables attribute and sets its stride and offset in the buffer
  133. gs.EnableVertexAttribArray(uint32(loc))
  134. gs.VertexAttribPointer(uint32(loc), attrib.ItemSize, FLOAT, false, attrib.Stride, attrib.Offset)
  135. }
  136. vbo.gs = gs // this indicates that the vbo was initialized
  137. }
  138. if !vbo.update {
  139. return
  140. }
  141. // Transfer the VBO data to OpenGL
  142. gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
  143. gs.BufferData(ARRAY_BUFFER, vbo.buffer.Bytes(), &vbo.buffer[0], vbo.usage)
  144. vbo.update = false
  145. }
  146. //// Transfer is called internally and transfer the data in the VBO buffer to OpenGL if necessary
  147. //func (vbo *VBO) Transfer(gs *GLS) {
  148. //
  149. // // If the VBO buffer is empty, ignore
  150. // if vbo.buffer.Bytes() == 0 {
  151. // return
  152. // }
  153. //
  154. // // First time initialization
  155. // if vbo.gs == nil {
  156. // vbo.handle = gs.GenBuffer()
  157. // gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
  158. // // Calculates stride
  159. // stride := vbo.Stride()
  160. // // For each attribute
  161. // var items uint32 = 0
  162. // var offset uint32 = 0
  163. // elsize := int32(unsafe.Sizeof(float32(0)))
  164. // for _, attrib := range vbo.attribs {
  165. // // Get attribute location in the current program
  166. // loc := gs.prog.GetAttribLocation(attrib.Name)
  167. // if loc < 0 {
  168. // continue
  169. // }
  170. // // Enables attribute and sets its stride and offset in the buffer
  171. // gs.EnableVertexAttribArray(uint32(loc))
  172. // gs.VertexAttribPointer(uint32(loc), attrib.ItemSize, FLOAT, false, int32(stride), offset)
  173. // items += uint32(attrib.ItemSize)
  174. // offset = uint32(elsize) * items
  175. // }
  176. // vbo.gs = gs // this indicates that the vbo was initialized
  177. // }
  178. // if !vbo.update {
  179. // return
  180. // }
  181. // // Transfer the VBO data to OpenGL
  182. // gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
  183. // gs.BufferData(ARRAY_BUFFER, vbo.buffer.Bytes(), &vbo.buffer[0], vbo.usage)
  184. // vbo.update = false
  185. //}