vbo.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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 OpenGL state
  12. handle uint32 // OpenGL handle for this VBO
  13. usage uint32 // Expected usage pattern 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
  22. }
  23. // NewVBO creates and returns a pointer to a new OpenGL Vertex Buffer Object.
  24. func NewVBO() *VBO {
  25. vbo := new(VBO)
  26. vbo.init()
  27. return vbo
  28. }
  29. // init initializes the VBO.
  30. func (vbo *VBO) init() {
  31. vbo.gs = nil
  32. vbo.handle = 0
  33. vbo.usage = STATIC_DRAW
  34. vbo.update = true
  35. vbo.attribs = make([]VBOattrib, 0)
  36. }
  37. // AddAttrib adds a new attribute to the VBO.
  38. func (vbo *VBO) AddAttrib(name string, itemSize int32) *VBO {
  39. vbo.attribs = append(vbo.attribs, VBOattrib{
  40. Name: name,
  41. ItemSize: itemSize,
  42. })
  43. return vbo
  44. }
  45. // Attrib finds and returns a pointer to the VBO attribute with the specified name.
  46. // Returns nil if not found.
  47. func (vbo *VBO) Attrib(name string) *VBOattrib {
  48. for _, attr := range vbo.attribs {
  49. if attr.Name == name {
  50. return &attr
  51. }
  52. }
  53. return nil
  54. }
  55. // AttribAt returns a pointer to the VBO attribute at the specified index.
  56. func (vbo *VBO) AttribAt(idx int) *VBOattrib {
  57. return &vbo.attribs[idx]
  58. }
  59. // AttribCount returns the current number of attributes for this VBO.
  60. func (vbo *VBO) AttribCount() int {
  61. return len(vbo.attribs)
  62. }
  63. // Attributes returns the attributes for this VBO.
  64. func (vbo *VBO) Attributes() []VBOattrib {
  65. return vbo.attribs
  66. }
  67. // Dispose disposes of the OpenGL resources used by the VBO.
  68. // As currently the VBO is used only by Geometry objects
  69. // it is not referenced counted.
  70. func (vbo *VBO) Dispose() {
  71. if vbo.gs != nil {
  72. vbo.gs.DeleteBuffers(vbo.handle)
  73. }
  74. vbo.gs = nil
  75. }
  76. // SetBuffer sets the VBO buffer.
  77. func (vbo *VBO) SetBuffer(buffer math32.ArrayF32) *VBO {
  78. vbo.buffer = buffer
  79. vbo.update = true
  80. return vbo
  81. }
  82. // SetUsage sets the expected usage pattern of the buffer.
  83. // The default value is GL_STATIC_DRAW.
  84. func (vbo *VBO) SetUsage(usage uint32) {
  85. vbo.usage = usage
  86. }
  87. // Buffer returns a pointer to the VBO buffer.
  88. func (vbo *VBO) Buffer() *math32.ArrayF32 {
  89. return &vbo.buffer
  90. }
  91. // Update sets the update flag to force the VBO update.
  92. func (vbo *VBO) Update() {
  93. vbo.update = true
  94. }
  95. // AttribOffset returns the total number of elements from
  96. // all attributes preceding the specified attribute.
  97. func (vbo *VBO) AttribOffset(name string) int {
  98. elementCount := 0
  99. for _, attr := range vbo.attribs {
  100. if attr.Name == name {
  101. return elementCount
  102. }
  103. elementCount += int(attr.ItemSize)
  104. }
  105. return elementCount
  106. }
  107. // Stride returns the stride of the VBO, which is the number of elements in
  108. // one complete set of group attributes. E.g. for an interleaved VBO with two attributes:
  109. // "VertexPosition" (3 elements) and "VertexTexcoord" (2 elements), the stride would be 5:
  110. // [X, Y, Z, U, V], X, Y, Z, U, V, X, Y, Z, U, V... X, Y, Z, U, V.
  111. func (vbo *VBO) Stride() int {
  112. stride := 0
  113. for _, attrib := range vbo.attribs {
  114. stride += int(attrib.ItemSize)
  115. }
  116. return stride
  117. }
  118. // StrideSize returns the number of bytes used by one complete set of group attributes.
  119. // E.g. for an interleaved VBO with two attributes: "VertexPosition" (3 elements)
  120. // and "VertexTexcoord" (2 elements), the stride would be 5:
  121. // [X, Y, Z, U, V], X, Y, Z, U, V, X, Y, Z, U, V... X, Y, Z, U, V
  122. // and the stride size would be: sizeof(float)*stride = 4*5 = 20
  123. func (vbo *VBO) StrideSize() int {
  124. stride := vbo.Stride()
  125. elsize := int(unsafe.Sizeof(float32(0)))
  126. return stride * elsize
  127. }
  128. // Transfer (called internally) transfers the data from the VBO buffer to OpenGL if necessary.
  129. func (vbo *VBO) Transfer(gs *GLS) {
  130. // If the VBO buffer is empty, ignore
  131. if vbo.buffer.Bytes() == 0 {
  132. return
  133. }
  134. // First time initialization
  135. if vbo.gs == nil {
  136. vbo.handle = gs.GenBuffer()
  137. gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
  138. // Calculates stride size
  139. strideSize := vbo.StrideSize()
  140. // For each attribute
  141. var items uint32
  142. var offset uint32
  143. elsize := int32(unsafe.Sizeof(float32(0)))
  144. for _, attrib := range vbo.attribs {
  145. // Get attribute location in the current program
  146. loc := gs.prog.GetAttribLocation(attrib.Name)
  147. if loc < 0 {
  148. continue
  149. }
  150. // Enables attribute and sets its stride and offset in the buffer
  151. gs.EnableVertexAttribArray(uint32(loc))
  152. gs.VertexAttribPointer(uint32(loc), attrib.ItemSize, FLOAT, false, int32(strideSize), offset)
  153. items += uint32(attrib.ItemSize)
  154. offset = uint32(elsize) * items
  155. }
  156. vbo.gs = gs // this indicates that the vbo was initialized
  157. }
  158. // If nothing has changed, no need to transfer data to OpenGL
  159. if !vbo.update {
  160. return
  161. }
  162. // Transfer the VBO data to OpenGL
  163. gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
  164. gs.BufferData(ARRAY_BUFFER, vbo.buffer.Bytes(), &vbo.buffer[0], vbo.usage)
  165. vbo.update = false
  166. }
  167. // OperateOnVectors3 iterates over all 3-float32 items for the specified attribute
  168. // and calls the specified callback function with a pointer to each item as a Vector3.
  169. // The vector pointers can be modified inside the callback and the modifications will be applied to the buffer at each iteration.
  170. // The callback function returns false to continue or true to break.
  171. func (vbo *VBO) OperateOnVectors3(vboAttrib string, cb func(vec *math32.Vector3) bool) {
  172. stride := vbo.Stride()
  173. offset := vbo.AttribOffset(vboAttrib)
  174. buffer := vbo.Buffer()
  175. // Call callback for each vector3, updating the buffer afterward
  176. var vec math32.Vector3
  177. for i := offset; i < vbo.buffer.Size(); i += stride {
  178. buffer.GetVector3(i, &vec)
  179. brk := cb(&vec)
  180. buffer.SetVector3(i, &vec)
  181. if brk {
  182. break
  183. }
  184. }
  185. vbo.Update()
  186. }
  187. // ReadVectors3 iterates over all 3-float32 items for the specified attribute
  188. // and calls the specified callback function with the value of each item as a Vector3.
  189. // The callback function returns false to continue or true to break.
  190. func (vbo *VBO) ReadVectors3(vboAttrib string, cb func(vec math32.Vector3) bool) {
  191. stride := vbo.Stride()
  192. offset := vbo.AttribOffset(vboAttrib)
  193. positions := vbo.Buffer()
  194. // Call callback for each vector3
  195. var vec math32.Vector3
  196. for i := offset; i < positions.Size(); i += stride {
  197. positions.GetVector3(i, &vec)
  198. brk := cb(vec)
  199. if brk {
  200. break
  201. }
  202. }
  203. }
  204. // Read3Vectors3 iterates over all 3-float32 items (3 items at a time) for the specified attribute
  205. // and calls the specified callback function with the value of each of the 3 items as Vector3.
  206. // The callback function returns false to continue or true to break.
  207. func (vbo *VBO) ReadTripleVectors3(vboAttrib string, cb func(vec1, vec2, vec3 math32.Vector3) bool) {
  208. stride := vbo.Stride()
  209. offset := vbo.AttribOffset(vboAttrib)
  210. positions := vbo.Buffer()
  211. doubleStride := 2*stride
  212. loopStride := 3*stride
  213. // Call callback for each vector3 triple
  214. var vec1, vec2, vec3 math32.Vector3
  215. for i := offset; i < positions.Size(); i += loopStride {
  216. positions.GetVector3(i, &vec1)
  217. positions.GetVector3(i + stride, &vec2)
  218. positions.GetVector3(i + doubleStride, &vec3)
  219. brk := cb(vec1, vec2, vec3)
  220. if brk {
  221. break
  222. }
  223. }
  224. }