]> git.tdb.fi Git - libs/gl.git/blob - source/bufferable.cpp
Refactor the internal interface of Bufferable a bit
[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 bool Bufferable::resize_buffer() const
84 {
85         if(offset+get_data_size()>=buffer->get_size())
86         {
87                 const Bufferable *last = this;
88                 for(; last->next_in_buffer; last=last->next_in_buffer) ;
89
90                 unsigned total_size = last->offset+last->get_data_size();
91
92                 if(total_size>buffer->get_size())
93                 {
94                         buffer->data(total_size, 0);
95                         return true;
96                 }
97         }
98
99         return false;
100 }
101
102 void Bufferable::update_buffer() const
103 {
104         BindRestore bind(buffer, buffer->get_type());
105         if(resize_buffer())
106         {
107                 /* Resizing the buffer invalidates its contents.  Non-dirty data may
108                 be in use, so reupload it. */
109                 for(const Bufferable *b=prev_in_buffer; b; b=b->prev_in_buffer)
110                         if(!b->dirty)
111                                 b->upload_data();
112                 for(const Bufferable *b=next_in_buffer; b; b=b->next_in_buffer)
113                         if(!b->dirty)
114                                 b->upload_data();
115         }
116
117         upload_data();
118         dirty = false;
119 }
120
121 void Bufferable::upload_data() const
122 {
123         buffer->sub_data(offset, get_data_size(), get_data_pointer());
124 }
125
126 } // namespace GL
127 } // namespace Msp