emilib
gl_lib.hpp
1 // By Emil Ernerfeldt 2012-2016
2 // LICENSE:
3 // This software is dual-licensed to the public domain and under the following
4 // license: you are granted a perpetual, irrevocable license to copy, modify,
5 // publish, and distribute this file as you see fit.
6 // HISTORY:
7 // Some code dating back to 2012 (at least).
8 // Made into free-standing library for face_morpher in late 2015.
9 // Adopted for PipeDreams 2016-02
10 
11 #pragma once
12 
13 #include <algorithm>
14 #include <memory>
15 #include <string>
16 #include <vector>
17 
18 #include <loguru.hpp>
19 
20 #include "gl_lib_fwd.hpp"
21 
22 #ifndef GLLIB_GLES
23  #error GLLIB_GLES not defined
24 #endif
25 #ifndef GLLIB_OPENGL_VERSION
26  #error GLLIB_OPENGL_VERSION not defined
27 #endif
28 
30 namespace gl {
31 
32 using GLenum = unsigned int;
33 using GLuint = unsigned int;
34 
35 // ----------------------------------------------------------------------------
36 
37 void init_glew();
38 
39 // ----------------------------------------------------------------------------
40 
41 bool supports_mipmaps_for(Size size);
42 
48 class Texture
49 {
50 public:
52  Texture();
53 
54  Texture(GLuint id, Size size, TexParams params_arg, ImageFormat format, std::string debug_name);
55  Texture(std::string debug_name, TexParams params = {}, ImageFormat format = {}, Size size = {0, 0}, const void* data = nullptr);
56 
57  ~Texture();
58 
59  Texture(const Texture&) = delete;
60  Texture& operator=(const Texture&) = delete;
61 
62  Texture(Texture&& other) { this->swap(other); }
63  void operator=(Texture&& other) { this->swap(other); }
64 
65  void swap(Texture& other);
66 
68  void free();
69 
70  void set_data(const void* data, Size size, ImageFormat format);
71 
73  void set_data(const void* data);
74 
75  void set_mip_data(const void* data, Size size, unsigned level);
76 
77  const ImageFormat& format() const { return _format; }
78 
79  const TexParams& params() const { return _params; }
80  void set_params(const TexParams& params);
81 
82  bool has_data() const { return _has_data; }
83 
84  bool is_power_of_two() const;
85 
86  const std::string& debug_name() const { return _debug_name; }
87  void set_debug_name(const std::string& debug_name);
88 
90  void bind(unsigned tu = 0) const;
91 
92  unsigned width() const { return _size.x; }
93  unsigned height() const { return _size.y; }
94  const Size& size() const { return _size; }
95 
97  void set_bits_per_pixel(unsigned bpp);
98  unsigned bits_per_pixel() const;
99  size_t memory_usage() const;
100 
102  GLuint id() const { return _id; }
103  bool has_id() const { return _id != 0; }
104 
105  void generate_mipmaps();
106 
107 protected:
108  void init(const void* data);
109 
110  void set_wrap_mode(WrapMode s, WrapMode t) const;
111  void set_filtering(TexFilter filter) const;
112 
113 private:
114  Size _size{0, 0};
115  ImageFormat _format;
116  std::string _debug_name;
117 
118  GLuint _id = 0;
119  bool _has_data = false;
120  unsigned _bpp = 0;
121 
122  // The effecto of set_params is deferred until bind() so we can set_params from non-render thread.
123  mutable TexParams _params;
124  mutable bool _params_dirty = false;
125 };
126 
127 // ----------------------------------------------------------------------------
128 
132  const void* data, size_t num_bytes,
133  TexParams params, std::string debug_name);
134 
135 // ----------------------------------------------------------------------------
136 
137 class Program
138 {
139 public:
140  struct Uniform
141  {
142  std::string name;
143  int size;
144  unsigned type;
145  int location;
146  };
147 
148  struct Attribute
149  {
150  std::string name;
151  int size;
152  unsigned type;
153  int location;
154  };
155 
156  using Uniforms = std::vector<Uniform>;
157  using Attributes = std::vector<Attribute>;
158 
159  // ---------------------------------------------
160 
161  Program() {}
162 
164  Program(const std::string& vs, const std::string& fs, std::string debug_name);
165  Program(Program&&);
166  Program& operator=(Program&&);
167  ~Program();
168 
169  void swap(Program& other);
170 
171  const std::string& debug_name() const { return _debug_name; }
172  unsigned id() const { return _program; }
173 
175  void validate() const;
176 
177  void bind() const;
178 
179  int get_attribute_loc(const std::string& attrib_name) const;
180  int get_uniform_loc(const std::string& attrib_name) const;
181 
182  bool has_attribute(const std::string& name) const;
183  bool has_uniform(const std::string& name) const;
184 
185  template<typename T>
186  void set_uniform(const std::string& name, const T& value) const
187  {
188  set_uniform(get_uniform_loc(name), value);
189  }
190 
192  template<typename T>
193  void set_uniform(int location, const T& value) const;
194 
195 private:
196  Program(Program&) = delete;
197  Program& operator=(Program&) = delete;
198 
199  unsigned _program = 0;
200  std::string _debug_name;
201  Uniforms _uniforms;
202  Attributes _attributes;
203 };
204 
208 Program compile_program(const std::string& vs, const std::string& fs, const std::string& debug_name);
209 Program compile_program(const ProgramSource& program_source);
210 
211 // ----------------------------------------------------------------------------
212 
214 namespace FF
215 {
217  enum FF_Flags
218  {
219  Texture = (1<<0),
220  a_color = (1<<1),
221  u_color = (1<<2),
222  dim3 = (1<<3),
223  };
224 }
225 
227 ProgramSource create_ff(int flags);
228 
230 Program compile_ff_program(int flags);
231 
232 // ----------------------------------------------------------------------------
233 
234 enum Normalize { DONT_NORMALIZE, NORMALIZE };
235 
236 struct VertComp
237 {
238  std::string name;
239  unsigned num_comps;
240  unsigned type;
241  Normalize normalize;
242  size_t offset;
243 
244  size_t sizeBytes() const;
245 
246  VertComp() {}
247 
248  VertComp(const char* name_, unsigned num_comps_, unsigned type_, Normalize normalize_)
249  : name(name_), num_comps(num_comps_), type(type_), normalize(normalize_) {}
250 
251  // Static constructor helpers:
252  static VertComp Float(const char* name);
253  static VertComp Vec2(const char* name, Normalize normalize = DONT_NORMALIZE);
254  static VertComp RGBA32(const char* name);
255 };
256 
258 {
259 public:
260  using CompIter = std::vector<VertComp>::const_iterator;
261 
262  VertexFormat(std::initializer_list<VertComp> components);
263 
264  auto begin() const { return _comps.begin(); }
265  auto end() const { return _comps.end(); }
266 
267  size_t stride() const { return _stride; }
268 
269 private:
270  size_t _stride;
271  std::vector<VertComp> _comps;
272 };
273 
274 void bind_prog_and_attributes(const VertexFormat& vf, const Program& program);
275 
276 // ----------------------------------------------------------------------------
277 
278 class VBO
279 {
280 public:
281  enum Type
282  {
283  Vertex, Index
284  };
285 
286  VBO(Type type, Usage usage);
287  ~VBO();
288 
289  template<typename ElementType>
290  const ElementType* data() const { return reinterpret_cast<const ElementType*>(_buffer.data()); }
291 
293  template<typename ElementType>
294  ElementType* allocate(size_t count)
295  {
296  _count = count;
297  _buffer.resize(count * sizeof(ElementType));
298  _dirty = true;
299  return reinterpret_cast<ElementType*>( _buffer.data() );
300  }
301 
302  template<typename ElementType>
303  void append(const ElementType* elements, size_t count)
304  {
305  _count += count;
306  auto elements_ptr = reinterpret_cast<const char*>(elements);
307  _buffer.insert(_buffer.end(), elements_ptr, elements_ptr + count * sizeof(ElementType));
308  _dirty |= count > 0;
309  }
310 
311  void clear()
312  {
313  _dirty = !empty();
314  _count = 0;
315  _buffer.clear();
316  }
317 
318  void invalidate() { _dirty = true; }
319 
320  bool empty() const { return _count == 0; }
321  size_t count() const { return _count; }
322  size_t size_bytes() const { return _buffer.size(); }
323 
324  void upload();
325  void bind();
326 
327 private:
328  unsigned _id = -1;
329  Type _type;
330  Usage _usage;
331  std::vector<char> _buffer;
332  size_t _count = 0;
333  bool _dirty = true;
334 };
335 
336 // ----------------------------------------------------------------------------
337 
338 class VAO
339 {
340 public:
341  VAO();
342  ~VAO();
343  void bind();
344  void unbind();
345 
346 private:
347  VAO(VAO&);
348  VAO(VAO&&);
349  VAO& operator=(VAO&);
350  VAO& operator=(VAO&&);
351 
352  unsigned _id = -1;
353 };
354 
355 // ----------------------------------------------------------------------------
356 
358 {
359 public:
360  MeshPainter(Usage usage, VertexFormat vf);
361 
362  // --------------------------
363 
364  const VertexFormat& vertex_format() const { return _vf; }
365  VBO& vert_vbo() { return _vertices; }
366  const VBO& vert_vbo() const { return _vertices; }
367 
369  template<typename Vertex>
370  Vertex* allocate_vert(size_t count)
371  {
372  CHECK_F(sizeof(Vertex) == _vf.stride(), "Unexpected vertex size");
373  return _vertices.allocate<Vertex>(count);
374  }
375 
376  template<typename Vertex>
377  void set_verts(const std::vector<Vertex>& vertices)
378  {
379  std::copy_n(vertices.data(), vertices.size(), allocate_vert<Vertex>(vertices.size()));
380  }
381 
384  uint32_t* allocate_indices(size_t count)
385  {
386  if (!_indices) {
387  _indices.reset(new VBO(VBO::Index, _usage));
388  }
389  return _indices->allocate<uint32_t>(count);
390  }
391 
392  void set_indices(const std::vector<uint32_t>& indices)
393  {
394  std::copy_n(indices.data(), indices.size(), allocate_indices(indices.size()));
395  }
396 
397  // --------------------------
398 
400  void paint(const Program& prog, GLenum mode);
401 
402  void paint_strip(const Program& prog);
403 
404  void invalidate_verts() { _vertices.invalidate(); }
405 
406 private:
407  Usage _usage;
408  VBO _vertices;
409  std::unique_ptr<VBO> _indices;
410  std::unique_ptr<VAO> _vao;
411  VertexFormat _vf;
412 };
413 
414 // ----------------------------------------------------------------------------
415 
418 template<typename Vertex>
420 {
421 public:
422  TriangleStrip(Usage usage, VertexFormat vf) : _mesh_painter(usage, std::move(vf))
423  {
424  CHECK_EQ_F(sizeof(Vertex), _mesh_painter.vertex_format().stride());
425  }
426 
427  bool empty() { return _mesh_painter.vert_vbo().empty(); }
428 
430  int count() const { return _mesh_painter.vert_vbo().count(); }
431 
432  int size_bytes() const { return _mesh_painter.vert_vbo().size_bytes(); }
433 
434  void clear() { _mesh_painter.vert_vbo().clear(); }
435 
436  void add_strip(const Vertex* ptr, size_t n)
437  {
438  if (n == 0) { return; }
439  CHECK_GT_F(n, 2u);
440  VBO& vbo = _mesh_painter.vert_vbo();
441  if (!vbo.empty()) {
442  // Connector by degenerate triangles:
443  Vertex last_vertex = vbo.data<Vertex>()[vbo.count() - 1u];
444  vbo.append<Vertex>(&last_vertex, 1u);
445  vbo.append<Vertex>(ptr, 1u);
446  }
447  vbo.append<Vertex>(ptr, n);
448  }
449 
450  void add_strip(const Vertex* start, const Vertex* end) { add_strip(start, end - start); }
451  void add_strip(const std::vector<Vertex>& verts) { add_strip(verts.data(), verts.size()); }
452  void add_strip(std::initializer_list<Vertex> verts) { add_strip(verts.begin(), verts.size()); }
453 
454  void paint_strip(const Program& prog) { _mesh_painter.paint_strip(prog); }
455 
456 private:
457  MeshPainter _mesh_painter;
458 };
459 
460 // ------------------------------------------------
461 
464 {
465 public:
466  explicit TempViewPort(Rectangle bb);
467  explicit TempViewPort(Size size);
468  explicit TempViewPort(unsigned width, unsigned height) : TempViewPort(Size{width, height}) {}
469  ~TempViewPort();
470 
472  static void set_back_buffer(Rectangle bb);
473 
475  static void set_back_buffer_size(Size size)
476  {
477  set_back_buffer(Rectangle{0, 0, (int)size.x, (int)size.y});
478  }
479 
481  static void set_back_buffer_size(int width, int height)
482  {
483  set_back_buffer(Rectangle{0, 0, width, height});
484  }
485 
486  static const Rectangle& back_buffer();
487  static Size back_buffer_size();
488 
489 private:
490  TempViewPort(TempViewPort&) = delete;
491  TempViewPort& operator=(TempViewPort&) = delete;
492 
493  Rectangle _old_vp;
494 };
495 
496 // ----------------------------------------------------------------------------
497 
499 class FBO
500 {
501 public:
503  class Lock
504  {
505  public:
506  explicit Lock(const FBO* fbo);
507  ~Lock();
508 
509  private:
510  Lock(const Lock&)=delete;
511  Lock& operator=(const Lock&)=delete;
512 
513  GLuint _old; // Bound before us
514  const FBO* _fbo;
515  };
516 
517  struct Params
518  {
519 #if !GLLIB_GLES
520  bool with_depth = false;
521 #endif // !GLLIB_GLES
522  bool color_mipmap = false;
523  ImageFormat color_format = ImageFormat::RGBA32;
524  };
525 
526  // ------------------------------------------------
527 
528  FBO(const std::string& debug_name, Size size, const Params& params);
529  FBO(const std::string& debug_name, Size size) : FBO(debug_name, size, Params()) {}
530  ~FBO();
531 
532  FBO(const FBO&) = delete;
533  FBO(FBO&&) = delete;
534  void operator=(const FBO&) = delete;
535  void operator=(FBO&&) = delete;
536 
537  GLuint id() const;
538  const Size& size() const { return _size; }
539  unsigned width() const { return _size.x; }
540  unsigned height() const { return _size.y; }
541 
543  void generate_color_mipmap();
544 
545  const gl::Texture& color_texture() const { return _color_tex; }
546  gl::Texture release_color_texture() { return std::move(_color_tex); }
547 
548 private:
549  std::string _debug_name;
550  Size _size;
551  Params _params;
552  GLuint _fbo_id;
553  gl::Texture _color_tex;
554 #if !GLLIB_GLES
555  GLuint _depth_rbo_id = 0;
556 #endif // !GLLIB_GLES
557 };
558 
559 // ----------------------------------------------------------------------------
560 
561 } // namespace gl
ElementType * allocate(size_t count)
Will re-use memory if same size.
Definition: gl_lib.hpp:294
Normalize normalize
If we normalize, values are rescaled to [0, 1].
Definition: gl_lib.hpp:241
Definition: gl_lib.hpp:419
size_t memory_usage() const
in bytes
Texture load_uncompressed_pvr2_from_memory(const void *data, size_t num_bytes, TexParams params, std::string debug_name)
uint32_t * allocate_indices(size_t count)
Definition: gl_lib.hpp:384
void set_bits_per_pixel(unsigned bpp)
Use to override when you know the format is compressed.
Bind/unbind FBO:
Definition: gl_lib.hpp:503
unsigned type
e.g. GL_FLOAT_VEC2
Definition: gl_lib.hpp:152
TexFilter
Definition: gl_lib_fwd.hpp:135
ImageFormat
Definition: gl_lib_fwd.hpp:103
static void set_back_buffer_size(int width, int height)
Call when we acquire context or resize window.
Definition: gl_lib.hpp:481
ProgramSource create_ff(int flags)
flags should be a combo if FF::FF_Flags
Definition: file_system.hpp:18
Definition: gl_lib.hpp:236
unsigned num_comps
1 for scalars, 2 for Vec2 etc
Definition: gl_lib.hpp:239
static void set_back_buffer_size(Size size)
Call when we acquire context or resize window.
Definition: gl_lib.hpp:475
int count() const
Number of vertices.
Definition: gl_lib.hpp:430
Vertex * allocate_vert(size_t count)
Will re-use memory if same size.
Definition: gl_lib.hpp:370
FF_Flags
Fixed function flags.
Definition: gl_lib.hpp:217
Definition: gl_lib_fwd.hpp:151
Definition: gl_lib.hpp:137
void bind(unsigned tu=0) const
We must have an id.
Definition: gl_lib.hpp:338
Definition: gl_lib.hpp:278
unsigned type
e.g. GL_FLOAT
Definition: gl_lib.hpp:240
Definition: gl_lib.hpp:48
Definition: gl_lib_fwd.hpp:89
int size
Mostly 1, maybe non-1 for arrays?
Definition: gl_lib.hpp:151
void free()
Free allocated texture, if any. sets id = 0.ß
GLuint id() const
0 if not generated
Definition: gl_lib.hpp:102
size_t offset
Byte offset, filled in by VertexFormat::VertexFormat.
Definition: gl_lib.hpp:242
Definition: gl_lib.hpp:140
Definition: gl_lib.hpp:257
Definition: gl_lib.hpp:517
unsigned type
e.g. GL_FLOAT_VEC2
Definition: gl_lib.hpp:144
Definition: gl_lib.hpp:357
Texture()
Will create an invalid texture!
Program compile_program(const std::string &vs, const std::string &fs, const std::string &debug_name)
Definition: gl_lib_fwd.hpp:48
Program compile_ff_program(int flags)
flags should be a combo if FF::FF_Flags
Definition: gl_lib.hpp:148
int size
Mostly 1, maybe non-1 for arrays?
Definition: gl_lib.hpp:143
Usage
For VBO:s and the like.
Definition: gl_lib_fwd.hpp:82
An off-screen buffer you can draw onto.
Definition: gl_lib.hpp:499
Will set a viewport and restore the old viewport on death.
Definition: gl_lib.hpp:463
OpenGL wrapper classes.
Definition: gl_lib.hpp:30
Definition: gl_lib_fwd.hpp:94