]> git.tdb.fi Git - libs/gl.git/blob - source/bufferable.cpp
Add support for multiple binding points in the RAII binders
[libs/gl.git] / source / bufferable.cpp
1 #include <stdexcept>
2 #include "bindable.h"
3 #include "buffer.h"
4 #include "bufferable.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace GL {
10
11 Bufferable::Bufferable():
12         buffer(0),
13         offset(0),
14         next_in_buffer(0),
15         prev_in_buffer(0),
16         dirty(false)
17 { }
18
19 Bufferable::~Bufferable()
20 {
21         unlink_from_buffer();
22 }
23
24 void Bufferable::use_buffer(Buffer *buf, Bufferable *prev)
25 {
26         if(prev && buf!=prev->buffer)
27                 throw invalid_argument("Bufferable::use_buffer");
28
29         if(buffer)
30                 unlink_from_buffer();
31
32         buffer = buf;
33         if(buffer)
34         {
35                 prev_in_buffer = prev;
36                 if(prev_in_buffer)
37                 {
38                         next_in_buffer = prev_in_buffer->next_in_buffer;
39                         prev_in_buffer->next_in_buffer = this;
40                 }
41         }
42
43         update_offset();
44 }
45
46 void Bufferable::unlink_from_buffer()
47 {
48         if(prev_in_buffer)
49                 prev_in_buffer->next_in_buffer = next_in_buffer;
50         if(next_in_buffer)
51         {
52                 next_in_buffer->prev_in_buffer = prev_in_buffer;
53                 next_in_buffer->update_offset();
54         }
55         prev_in_buffer = 0;
56         next_in_buffer = 0;
57         buffer = 0;
58 }
59
60 void Bufferable::update_offset()
61 {
62         unsigned new_offset = 0;
63         if(prev_in_buffer)
64                 new_offset = prev_in_buffer->offset+prev_in_buffer->get_data_size();
65
66         unsigned align = get_alignment();
67         new_offset += align-1;
68         new_offset -= new_offset%align;
69         if(new_offset!=offset)
70         {
71                 offset = new_offset;
72                 dirty = true;
73                 offset_changed();
74         }
75
76         if(next_in_buffer)
77                 next_in_buffer->update_offset();
78
79         /* Do not resize the buffer here, as more bufferables may be added before
80         the buffer is actually used. */
81 }
82
83 void Bufferable::update_buffer() const
84 {
85         BindRestore bind(buffer, buffer->get_type());
86         if(offset+get_data_size()>=buffer->get_size())
87         {
88                 const Bufferable *last = this;
89                 for(; last->next_in_buffer; last=last->next_in_buffer) ;
90
91                 unsigned total_size = last->offset+last->get_data_size();
92
93                 if(total_size>buffer->get_size())
94                 {
95                         buffer->data(total_size, 0);
96                         /* Resizing the buffer invalidates its contents.  Non-dirty data may
97                         be in use, so reupload it. */
98                         for(const Bufferable *b=last; b; b=b->prev_in_buffer)
99                                 if(!b->dirty)
100                                         b->upload_data();
101                 }
102         }
103
104         upload_data();
105         dirty = false;
106 }
107
108 } // namespace GL
109 } // namespace Msp