1 #pragma once 2 // ----------------------------------------------------------------------------- 3 #include "GraphicsUtil.h" 4 #include "Vector.h" 5 #include <vector> 6 #include <tuple> 7 #include <map> 8 #include <array> 9 #include <type_traits> 10 #include <cstdlib> 11 #include <string.h> 12 #include <glm/vec2.hpp> 13 // ----------------------------------------------------------------------------- 14 // DESCRIPTORS 15 // ----------------------------------------------------------------------------- 16 // Describes a single array held in the vbo 17 struct BufferDesc { BufferDescBufferDesc18 BufferDesc(const char * _attr_name, GLenum _type_size, size_t _type_dim, 19 size_t _data_size, const void * _data_ptr, bool _data_norm) 20 : attr_name(_attr_name), type_size(_type_size), type_dim(_type_dim), 21 data_size(_data_size), data_ptr(_data_ptr), data_norm(_data_norm) 22 {} 23 24 // Constructor for just layout BufferDescBufferDesc25 BufferDesc(const char * _attr_name, GLenum _type_size, size_t _type_dim, 26 size_t _offset, bool _data_norm) 27 : attr_name(_attr_name), type_size(_type_size), type_dim(_type_dim), 28 data_norm(_data_norm), offset(_offset) {} 29 30 // Constructor used for index buffers 31 BufferDesc(GLenum _type_size, size_t _data_size, const void * _data_ptr, size_t _offset = 0) type_sizeBufferDesc32 : type_size(_type_size), data_size(_data_size), data_ptr(_data_ptr), 33 offset(_offset) {} 34 35 // Constructor used for data replication BufferDescBufferDesc36 BufferDesc(const char * _attr_name, GLuint _gl_id) : 37 attr_name(_attr_name), gl_id(_gl_id) {} 38 39 const char * attr_name { nullptr }; 40 GLenum type_size { GL_FLOAT }; 41 size_t type_dim { 0 }; 42 size_t data_size { 0 }; 43 const void * data_ptr { nullptr }; 44 bool data_norm { false }; 45 GLuint gl_id { 0 }; 46 size_t offset { 0 }; 47 }; 48 using BufferDataDesc = std::vector< BufferDesc >; 49 50 /* different types of AttribOp */ 51 enum attrib_op_type { 52 NO_COPY = 0, 53 FLOAT_TO_FLOAT, 54 FLOAT2_TO_FLOAT2, 55 FLOAT3_TO_FLOAT3, 56 FLOAT4_TO_FLOAT4, 57 FLOAT3_TO_UB3, 58 FLOAT1_TO_UB_4TH, 59 UB3_TO_UB3, 60 UINT_INT_TO_PICK_DATA, 61 UB1_INTERP_TO_CAP, 62 FLOAT1_TO_INTERP, 63 UB4_TO_UB4, 64 PICK_DATA_TO_PICK_DATA, 65 CYL_CAP_TO_CAP, 66 FLOAT1_INTERP_TO_CAP, 67 UB1_TO_INTERP, 68 CYL_CAPS_ARE_ROUND, 69 CYL_CAPS_ARE_FLAT, 70 CYL_CAPS_ARE_CUSTOM, 71 FLOAT4_TO_UB4 72 }; 73 74 struct AttribDesc; 75 76 typedef void (*AttribOpFuncDataFunctionPtr)(void *varData, const float * pc, void *globalData, int idx); 77 78 /* AttribOpFuncData : This structure holds information a callback that sets/post-processes 79 data for a particular attribute. Currently, a list of these functions 80 are attached to the AttribOp so that when vertices are created (i.e., incr_vertices > 0) 81 then for each vertex, this function is called for the particular attribute attribName. 82 83 funcDataConversion - pointer to function that sets/post-processes the attribute data 84 funcDataGlobalArg - pointer to global structure that can be used in each call to the callback 85 attribName - attribute name this function is processing. (this calling function specifies the name, and the 86 CGOConvertToShader() sets attrib to the associated AttribDesc. 87 */ 88 struct AttribOpFuncData { 89 void (*funcDataConversion)(void *varData, const float * pc, void *globalData, int idx); // if set, should be called on every output value for this attribute 90 void *funcDataGlobalArg; 91 const char *attribName; 92 AttribDesc *attrib; 93 AttribOpFuncDataFunctionPtr _funcDataConversion; AttribOpFuncDataAttribOpFuncData94 AttribOpFuncData(AttribOpFuncDataFunctionPtr _funcDataConversion, 95 void *_funcDataGlobalArg, 96 const char *_attribName) 97 : funcDataConversion(_funcDataConversion), funcDataGlobalArg(_funcDataGlobalArg), attribName(_attribName), attrib(NULL){} 98 }; 99 100 using AttribOpFuncDataDesc = std::vector< AttribOpFuncData >; 101 102 /* 103 * defines an operation that copies and (optionally) creates new vertices in 104 * a VBO operation for a particular CGO operation (op). 105 * 106 * op - the CGO operation 107 * order - the order for this operation to be executed for the given CGO operation 108 * offset - the offset into the CGO operation to copy 109 * conv_type - type of copy (can be general or specific, see above, e.g. FLOAT3_TO_FLOAT3, UB1_TO_INTERP) 110 * incr_vertices - the number of vertices (if any) that are generated for the VBO after this operation 111 * is executed. 112 * 113 */ 114 struct AttribOp { 115 AttribOp(unsigned short _op, size_t _order, size_t _conv_type, size_t _offset, size_t _incr_vertices=0, int _copyFromAttr=-1) opAttribOp116 : op(_op) 117 , order(_order) 118 , offset(_offset) 119 , conv_type(_conv_type) 120 , incr_vertices(_incr_vertices) 121 , copyFromAttr(_copyFromAttr) 122 {} 123 unsigned short op { 0 }; 124 size_t order { 0 }; 125 size_t offset { 0 }; 126 size_t conv_type { 0 }; 127 size_t incr_vertices { 0 }; 128 int copyFromAttr { -1 }; 129 struct AttribDesc *desc { 0 }; 130 struct AttribDesc *copyAttribDesc { 0 }; 131 std::vector<AttribOpFuncData> funcDataConversions; 132 }; 133 using AttribDataOp = std::vector< AttribOp >; 134 135 /* 136 * defines an attribute that is used in a shader. this description has all of the necessary information 137 * for our "optimize" function to generate either an array for input into the VBO or a call to the 138 * related glVertexAttrib() call when this attribute has the same value throughout the CGO. 139 * 140 * attr_name - the name of this attribute inside the shaders 141 * order - order of attribute used in VBO 142 * attrOps - all AttribOp for this particular attribute. This allows the user to define how this 143 * attribute gets populated from the primitive CGO's one or many CGO operations. 144 * default_value - pointer to the default value of this attribute (optional, needs to be the same 145 * size of the attribute's type) 146 * repeat_value/repeat_value_length - specified if the attribute has repeating values 147 * repeat_value - a pointer to the type and data for repeat values 148 * repeat_value_length - number of repeat values 149 * type_size - size of type for this attribute (e.g., GL_FLOAT, GL_UNSIGNED_BYTE) 150 * type_dim - number of primitives (i.e., type_size) for each vertex of this attribute 151 * data_norm - whether this attribute is normalized when passed to the VBO (GL_TRUE or GL_FALSE) 152 * 153 */ 154 struct AttribDesc { 155 AttribDesc(const char * _attr_name, GLenum _type_size, size_t _type_dim, bool _data_norm, AttribDataOp _attrOps={}) attr_nameAttribDesc156 : attr_name(_attr_name) 157 , attrOps(_attrOps) 158 , default_value(NULL) 159 , type_size(_type_size) 160 , type_dim(_type_dim) 161 , data_norm(_data_norm) 162 {} 163 const char * attr_name { nullptr }; 164 int order { 0 }; 165 AttribDataOp attrOps { }; 166 unsigned char *default_value { nullptr }; 167 unsigned char *repeat_value { nullptr }; 168 int repeat_value_length { 0 }; 169 GLenum type_size { GL_FLOAT }; 170 size_t type_dim { 0 }; 171 bool data_norm { false }; 172 }; 173 using AttribDataDesc = std::vector< AttribDesc >; 174 175 class gpuBuffer_t { 176 friend class CShaderMgr; 177 public: ~gpuBuffer_t()178 virtual ~gpuBuffer_t() {}; get_hash_id()179 virtual size_t get_hash_id() { return _hashid; } 180 virtual void bind() const = 0; 181 protected: set_hash_id(size_t id)182 virtual void set_hash_id(size_t id) { _hashid = id; } 183 private: 184 size_t _hashid { 0 }; 185 }; 186 187 // ----------------------------------------------------------------------------- 188 /* Vertexbuffer rules: 189 * ----------------------------------------------------------------------------- 190 * - If the buffer data is interleaved then buffer sub data functionality cannot 191 * be used. 192 * - The same order of buffer data must be maintained when uploading and binding 193 * 194 *----------------------------------------------------------------------- 195 * USAGE_PATTERN: 196 * SEPARATE: 197 * vbo1 [ data1 ] 198 * vbo2 [ data2 ] 199 * ... 200 * vboN [ dataN ] 201 * SEQUENTIAL: 202 * vbo [ data1 | data2 | ... | dataN ] 203 * INTERLEAVED: 204 * vbo [ data1[0], data2[0], ..., dataN[0] | ... | data1[M], data2[M], ..., dataN[M] ] 205 */ 206 template <GLenum _TYPE> 207 class GenericBuffer : public gpuBuffer_t { 208 friend class CShaderMgr; 209 public: 210 static const GLenum TYPE = _TYPE; 211 212 enum buffer_layout { 213 SEPARATE, // multiple vbos 214 SEQUENTIAL, // single vbo 215 INTERLEAVED // single vbo 216 }; 217 218 GenericBuffer( buffer_layout layout = SEPARATE, GLenum usage = GL_STATIC_DRAW ) : m_buffer_usage(usage)219 m_buffer_usage(usage), m_layout(layout) {} 220 ~GenericBuffer()221 ~GenericBuffer() { 222 for (auto &d : m_desc) { 223 if (d.gl_id) { 224 glDeleteBuffers(1, &d.gl_id); 225 } 226 } 227 if (m_interleavedID) { 228 glDeleteBuffers(1, &m_interleavedID); 229 } 230 } 231 232 /*********************************************************************** 233 * bufferData 234 *---------------------------------------------------------------------- 235 * Takes a vector of the struct at the top of this file which describes 236 * the layout of the vbo object. The supplied data ptr in the struct can 237 * be zero, in which case if the default usage is STATIC_DRAW then no 238 * opengl buffer will be generated for that, else it is assumed that the 239 * data will be supplied at a later point because it's dynamic draw. 240 ***********************************************************************/ bufferData(BufferDataDesc && desc)241 bool bufferData(BufferDataDesc && desc) { 242 m_desc = std::move(desc); 243 return evaluate(); 244 } 245 bufferData(BufferDataDesc && desc,const void * data,size_t len,size_t stride)246 bool bufferData(BufferDataDesc && desc, const void * data, size_t len, size_t stride) { 247 bool ok = true; 248 m_desc = std::move(desc); 249 m_interleaved = true; 250 m_stride = stride; 251 ok = genBuffer(m_interleavedID, len, data); 252 return ok; 253 } 254 255 // ----------------------------------------------------------------------------- 256 // bufferSubData : 257 // This function assumes that the data layout hasn't change 258 bool bufferSubData(const void * data, size_t index = 0) { 259 auto &d = m_desc[index]; 260 if (m_interleavedID) { 261 glBindBuffer(TYPE, m_interleavedID); 262 } else { 263 glBindBuffer(TYPE, d.gl_id); 264 } 265 glBufferSubData(TYPE, 0, d.data_size, data); 266 return glCheckOkay(); 267 } 268 269 void bufferSubData(size_t offset, size_t size, void * data, size_t index = 0) { 270 // maybe assert that the index is within range 271 if (m_interleavedID) { 272 glBindBuffer(TYPE, m_interleavedID); 273 } else { 274 glBindBuffer(TYPE, m_desc[index].gl_id); 275 } 276 glBufferSubData(TYPE, offset, size, data); 277 } 278 279 // for interleaved dat only, replaces the whole interleaved vbo bufferReplaceData(size_t offset,size_t len,const void * data)280 void bufferReplaceData(size_t offset, size_t len, const void * data) { 281 glBindBuffer(TYPE, m_interleavedID); 282 glBufferSubData(TYPE, offset, len, data); 283 } 284 285 286 protected: 287 evaluate()288 bool evaluate() { 289 bool ok = true; 290 if (TYPE == GL_ELEMENT_ARRAY_BUFFER) { 291 ok = seqBufferData(); 292 } else { 293 switch (m_layout) { 294 case SEPARATE: 295 ok = sepBufferData(); 296 break; 297 case SEQUENTIAL: 298 ok = seqBufferData(); 299 break; 300 case INTERLEAVED: 301 ok = interleaveBufferData(); 302 break; 303 } 304 } 305 return ok; 306 } 307 308 // USAGE PATTERNS sepBufferData()309 bool sepBufferData() { 310 for ( auto &d : m_desc ) { 311 // If the specified size is 0 but we have a valid pointer 312 // then we are going to glVertexAttribXfv X in {1,2,3,4} 313 if (d.data_ptr && (m_buffer_usage == GL_STATIC_DRAW)) { 314 if (d.data_size) { 315 if (!genBuffer(d.gl_id, d.data_size, d.data_ptr)) 316 return false; 317 } 318 } 319 } 320 return true; 321 } 322 seqBufferData()323 bool seqBufferData() { 324 // this is only going to use a single opengl vbo 325 m_interleaved = true; 326 327 size_t buffer_size { 0 }; 328 for ( auto & d : m_desc ) { 329 buffer_size += d.data_size; 330 } 331 332 uint8_t * buffer_data = new uint8_t[buffer_size]; 333 uint8_t * data_ptr = buffer_data; 334 size_t offset = 0; 335 336 for ( auto & d : m_desc ) { 337 d.offset = offset; 338 if (d.data_ptr) 339 memcpy(data_ptr, d.data_ptr, d.data_size); 340 else 341 memset(data_ptr, 0, d.data_size); 342 data_ptr += d.data_size; 343 offset += d.data_size; 344 } 345 346 bool ok = true; 347 ok = genBuffer(m_interleavedID, buffer_size, buffer_data); 348 delete[] buffer_data; 349 return ok; 350 } 351 interleaveBufferData()352 bool interleaveBufferData() { 353 size_t interleaved_size = 0; 354 const size_t buffer_count = m_desc.size(); 355 size_t stride = 0; 356 std::vector<uint8_t *> data_table(buffer_count); 357 std::vector<uint8_t *> ptr_table(buffer_count); 358 std::vector<size_t> size_table(buffer_count); 359 size_t count = m_desc[0].data_size / (gl_sizeof(m_desc[0].type_size) * m_desc[0].type_dim); 360 361 // Maybe assert that all pointers in d_desc are valid? 362 for ( size_t i = 0; i < buffer_count; ++i ) { 363 auto &d = m_desc[i]; 364 size_t size = gl_sizeof(d.type_size); 365 366 // offset is the current stride 367 d.offset = stride; 368 369 // These must come after so that offset starts at 0 370 // Size of 3 normals or whatever the current type is 371 size_table[i] = size * d.type_dim; 372 373 // Increase our current estimate of the stride by this amount 374 stride += size_table[i]; 375 376 // Does the addition of that previous stride leave us on a word boundry? 377 int m = stride % 4; 378 stride = (m ? (stride + (4 - m)) : stride); 379 380 // data_table a pointer to the begining of each array 381 data_table[i] = (uint8_t *)d.data_ptr; 382 383 // We will move these pointers along by the values in the size table 384 ptr_table[i] = data_table[i]; 385 386 } 387 388 m_stride = stride; 389 390 interleaved_size = count * stride; 391 392 uint8_t *interleaved_data = (uint8_t *)calloc(interleaved_size, sizeof(uint8_t)); 393 uint8_t *i_ptr = interleaved_data; 394 395 while (i_ptr != (interleaved_data + interleaved_size)) { 396 for ( size_t i = 0; i < buffer_count; ++i ) { 397 if (ptr_table[i]){ 398 memcpy( i_ptr, ptr_table[i], size_table[i] ); 399 ptr_table[i] += size_table[i]; 400 } 401 i_ptr += size_table[i]; 402 } 403 } 404 405 bool ok = true; 406 ok = genBuffer(m_interleavedID, interleaved_size, interleaved_data); 407 m_interleaved = true; 408 free(interleaved_data); 409 return ok; 410 } 411 genBuffer(GLuint & id,size_t size,const void * ptr)412 bool genBuffer(GLuint &id, size_t size, const void * ptr) { 413 glGenBuffers(1, &id); 414 if (!glCheckOkay()) 415 return false; 416 glBindBuffer(TYPE, id); 417 if (!glCheckOkay()) 418 return false; 419 glBufferData(TYPE, size, ptr, GL_STATIC_DRAW); 420 if (!glCheckOkay()) 421 return false; 422 return true; 423 } 424 425 protected: 426 bool m_status { false }; 427 bool m_interleaved { false }; 428 GLuint m_interleavedID { 0 }; 429 const GLenum m_buffer_usage { GL_STATIC_DRAW }; 430 const buffer_layout m_layout { SEPARATE }; 431 size_t m_stride { 0 }; 432 BufferDataDesc m_desc; 433 }; 434 435 /* 436 * Vertex buffer specialization 437 */ 438 class VertexBuffer : public GenericBuffer<GL_ARRAY_BUFFER> { bind_attrib(GLuint prg,const BufferDesc & d)439 void bind_attrib(GLuint prg, const BufferDesc & d) { 440 GLint loc = glGetAttribLocation(prg, d.attr_name); 441 bool masked = false; 442 for (GLint lid : m_attribmask) 443 if (lid == loc) 444 masked = true; 445 if ( loc >= 0 ) 446 m_locs.push_back(loc); 447 if ( loc >= 0 && !masked ) { 448 if (!m_interleaved && d.gl_id) 449 glBindBuffer( TYPE, d.gl_id ); 450 glEnableVertexAttribArray( loc ); 451 glVertexAttribPointer( loc, d.type_dim, d.type_size, d.data_norm, m_stride, (const void *)d.offset ); 452 } 453 }; 454 455 public: 456 VertexBuffer( buffer_layout layout = SEPARATE, GLenum usage = GL_STATIC_DRAW ) : GenericBuffer<GL_ARRAY_BUFFER>(layout, usage){} 457 bind()458 void bind() const { 459 // we shouldn't use this one 460 if (m_interleaved) 461 glBindBuffer(TYPE, m_interleavedID); 462 } 463 464 void bind(GLuint prg, int index = -1) { 465 if (index >= 0) { 466 glBindBuffer( TYPE, m_interleavedID ); 467 bind_attrib(prg, m_desc[index]); 468 } else { 469 if (m_interleaved && m_interleavedID) 470 glBindBuffer( TYPE, m_interleavedID ); 471 for (auto & d : m_desc) { 472 bind_attrib(prg, d); 473 } 474 m_attribmask.clear(); 475 } 476 } 477 unbind()478 void unbind() { 479 for (auto &d : m_locs) { 480 glDisableVertexAttribArray(d); 481 } 482 m_locs.clear(); 483 glBindBuffer(TYPE, 0); 484 } 485 maskAttributes(std::vector<GLint> attrib_locs)486 void maskAttributes(std::vector<GLint> attrib_locs) { 487 m_attribmask = std::move(attrib_locs); 488 } 489 maskAttribute(GLint attrib_loc)490 void maskAttribute(GLint attrib_loc) { 491 m_attribmask.push_back(attrib_loc); 492 } 493 replicate_data(const char * attrib_name,int index)494 void replicate_data(const char * attrib_name, int index) { 495 auto & d = m_desc[index]; 496 BufferDesc newdesc(attrib_name, d.gl_id); 497 newdesc.offset = d.offset; 498 newdesc.data_norm = d.data_norm; 499 newdesc.type_size = d.type_size; 500 newdesc.type_dim = d.type_dim; 501 m_desc.push_back(newdesc); 502 } 503 504 private: 505 // m_locs is only for interleaved data 506 std::vector<GLint> m_locs; 507 std::vector<GLint> m_attribmask; 508 }; 509 510 /* 511 * Index buffer specialization 512 */ 513 class IndexBuffer : public GenericBuffer<GL_ELEMENT_ARRAY_BUFFER> { 514 public: 515 using GenericBuffer::GenericBuffer; 516 bind()517 void bind() const { 518 glBindBuffer(TYPE, m_interleavedID); 519 } 520 unbind()521 void unbind() { 522 glBindBuffer(TYPE, 0); 523 } 524 }; 525 526 // Forward Decls 527 class frameBuffer_t; 528 class renderBuffer_t; 529 530 /*********************************************************************** 531 * RENDERBUFFER 532 ***********************************************************************/ 533 namespace rbo { 534 enum storage { 535 DEPTH16 = 0, 536 DEPTH24, 537 COUNT 538 }; 539 540 void unbind(); 541 }; 542 543 class renderBuffer_t : public gpuBuffer_t { 544 friend class frameBuffer_t; 545 friend class CShaderMgr; 546 public: renderBuffer_t(int width,int height,rbo::storage storage)547 renderBuffer_t(int width, int height, rbo::storage storage) : 548 _width(width), _height(height), _storage(storage) { 549 genBuffer(); 550 } ~renderBuffer_t()551 ~renderBuffer_t() { 552 freeBuffer(); 553 } 554 555 void bind() const; 556 void unbind() const; 557 558 private: 559 void genBuffer(); 560 void freeBuffer(); 561 562 protected: 563 uint32_t _id; 564 int _dim[2]; 565 int _width; 566 int _height; 567 rbo::storage _storage; 568 }; 569 570 /*********************************************************************** 571 * TEXTURE 572 ***********************************************************************/ 573 namespace tex { 574 enum class dim : int { 575 D1 = 0, 576 D2, 577 D3, 578 COUNT 579 }; 580 enum class format : int { 581 R = (int)dim::COUNT, 582 RG, 583 RGB, 584 RGBA, 585 COUNT 586 }; 587 enum class data_type : int { 588 UBYTE = (int)format::COUNT, 589 FLOAT, 590 HALF_FLOAT, 591 COUNT 592 }; 593 enum class filter : int { 594 NEAREST = (int)data_type::COUNT, 595 LINEAR, 596 NEAREST_MIP_NEAREST, 597 NEAREST_MIP_LINEAR, 598 LINEAR_MIP_NEAREST, 599 LINEAR_MIP_LINEAR, 600 COUNT 601 }; 602 enum class wrap : int { 603 REPEAT = (int)filter::COUNT, 604 CLAMP, 605 MIRROR_REPEAT, 606 CLAMP_TO_EDGE, 607 CLAMP_TO_BORDER, 608 MIRROR_CLAMP_TO_EDGE, 609 COUNT 610 }; 611 enum class env_name : int { 612 ENV_MODE = (int)wrap::COUNT, 613 COUNT 614 }; 615 enum class env_param : int { 616 REPLACE = (int)env_name::COUNT, 617 COUNT 618 }; 619 const uint32_t max_params = (int)env_param::COUNT; 620 621 void env(tex::env_name, tex::env_param); 622 }; 623 624 class textureBuffer_t : public gpuBuffer_t { 625 friend class frameBuffer_t; 626 public: 627 // Generates a 1D texture textureBuffer_t(tex::format format,tex::data_type type,tex::filter mag,tex::filter min,tex::wrap wrap_s)628 textureBuffer_t(tex::format format, tex::data_type type, 629 tex::filter mag, tex::filter min, 630 tex::wrap wrap_s) : 631 _dim(tex::dim::D1), _format(format), _type(type), 632 _sampling({(int)mag, (int)min, (int)wrap_s, 0, 0}) 633 { 634 genBuffer(); 635 }; 636 // Generates a 2D texture textureBuffer_t(tex::format format,tex::data_type type,tex::filter mag,tex::filter min,tex::wrap wrap_s,tex::wrap wrap_t)637 textureBuffer_t(tex::format format, tex::data_type type, 638 tex::filter mag, tex::filter min, 639 tex::wrap wrap_s, tex::wrap wrap_t) : 640 _dim(tex::dim::D2), _format(format), _type(type), 641 _sampling({(int)mag, (int)min, (int)wrap_s, (int)wrap_t, 0}) 642 { 643 genBuffer(); 644 }; 645 // Generates a 3D texture textureBuffer_t(tex::format format,tex::data_type type,tex::filter mag,tex::filter min,tex::wrap wrap_s,tex::wrap wrap_t,tex::wrap wrap_r)646 textureBuffer_t(tex::format format, tex::data_type type, 647 tex::filter mag, tex::filter min, 648 tex::wrap wrap_s, tex::wrap wrap_t, 649 tex::wrap wrap_r) : 650 _dim(tex::dim::D3), _format(format), _type(type), 651 _sampling({(int)mag, (int)min, (int)wrap_s, (int)wrap_t, (int)wrap_r}) 652 { 653 genBuffer(); 654 }; ~textureBuffer_t()655 ~textureBuffer_t() { 656 freeBuffer(); 657 } 658 659 void bind() const; 660 void unbind() const; 661 662 void texture_data_1D(int width, const void * data); 663 void texture_data_2D(int width, int height, const void * data); 664 void texture_data_3D(int width, int height, int depth, const void * data); 665 private: 666 void genBuffer(); 667 void freeBuffer(); 668 669 private: 670 const tex::dim _dim; 671 const tex::format _format; 672 const tex::data_type _type; 673 const std::array<int, 5> _sampling; 674 uint32_t _id { 0 }; 675 int _width { 0 }; 676 int _height { 0 }; 677 int _depth { 0 }; 678 }; 679 680 /*********************************************************************** 681 * FRAMEBUFFER 682 ***********************************************************************/ 683 namespace fbo { 684 enum attachment { 685 COLOR0 = 0, 686 COLOR1, 687 COLOR2, 688 COLOR3, 689 DEPTH, 690 COUNT 691 }; 692 693 // global unbind for fbos 694 void unbind(); 695 } 696 697 class frameBuffer_t : public gpuBuffer_t { 698 friend class CShaderMgr; 699 public: frameBuffer_t()700 frameBuffer_t() { 701 genBuffer(); 702 } ~frameBuffer_t()703 ~frameBuffer_t() { 704 freeBuffer(); 705 } 706 707 void attach_texture(textureBuffer_t * texture, fbo::attachment loc); 708 void attach_renderbuffer(renderBuffer_t * renderbuffer, fbo::attachment loc); 709 void print_fbo(); 710 711 void bind() const; 712 void unbind() const; 713 private: 714 void genBuffer(); 715 void freeBuffer(); 716 void checkStatus(); 717 718 protected: 719 uint32_t _id { 0 }; 720 std::vector<std::tuple<size_t, fbo::attachment>> _attachments; 721 }; 722 723 724 /*********************************************************************** 725 * RENDERTARGET 726 *---------------------------------------------------------------------- 727 * A 2D render target that automatically has depth, used for postprocess 728 ***********************************************************************/ 729 struct rt_layout_t { 730 enum data_type { UBYTE, FLOAT }; rt_layout_trt_layout_t731 rt_layout_t(uint8_t _nchannels, data_type _type) 732 : nchannels(_nchannels), type(_type) {} rt_layout_trt_layout_t733 rt_layout_t(uint8_t _nchannels, data_type _type, int _width, int _height) 734 : nchannels(_nchannels), type(_type), width(_width), height(_height) {} 735 uint8_t nchannels; 736 data_type type; 737 int width { 0 }; 738 int height { 0 }; 739 }; 740 741 class renderTarget_t : public gpuBuffer_t { 742 friend class CShaderMgr; 743 public: 744 using shape_type = glm::ivec2; 745 renderTarget_t(shape_type size)746 renderTarget_t(shape_type size) : _size(size) {} renderTarget_t(int width,int height)747 renderTarget_t(int width, int height) : _size(width, height) {} 748 ~renderTarget_t(); 749 bind()750 void bind() const { bind(true); }; 751 void bind(bool clear) const; bindFBORBO()752 void bindFBORBO() const 753 { 754 _fbo->bind(); 755 _rbo->bind(); 756 } 757 758 void layout(std::vector<rt_layout_t>&& desc, renderBuffer_t * with_rbo = nullptr); 759 void resize(shape_type size); 760 size()761 const shape_type& size() const { return _size; }; 762 rbo()763 renderBuffer_t* rbo() const noexcept { return _rbo; } fbo()764 frameBuffer_t* fbo() const noexcept { return _fbo; } textures()765 const std::vector<textureBuffer_t*>& textures() const noexcept { return _textures; } 766 767 protected: 768 bool _shared_rbo { false }; 769 shape_type _size; 770 frameBuffer_t * _fbo; 771 renderBuffer_t * _rbo; 772 std::vector<rt_layout_t> _desc; 773 std::vector<textureBuffer_t *> _textures; 774 }; 775