]> git.tdb.fi Git - libs/gl.git/blob - source/core/bufferable.cpp
Use default member initializers for simple types
[libs/gl.git] / source / core / bufferable.cpp
1 #include <stdexcept>
2 #include "buffer.h"
3 #include "bufferable.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9
10 Bufferable::~Bufferable()
11 {
12         unlink_from_buffer();
13 }
14
15 void Bufferable::use_buffer(Buffer *buf, Bufferable *prev)
16 {
17         if(prev && buf!=prev->buffer)
18                 throw invalid_argument("Bufferable::use_buffer");
19
20         if(buffer)
21                 unlink_from_buffer();
22
23         buffer = buf;
24         if(buffer)
25         {
26                 prev_in_buffer = prev;
27                 if(prev_in_buffer)
28                 {
29                         next_in_buffer = prev_in_buffer->next_in_buffer;
30                         prev_in_buffer->next_in_buffer = this;
31                 }
32         }
33
34         location_dirty = true;
35         dirty = true;
36         update_offset();
37 }
38
39 void Bufferable::change_buffer(Buffer *buf)
40 {
41         for(Bufferable *b=this; b; b=b->next_in_buffer)
42         {
43                 b->buffer = buf;
44                 b->location_dirty = true;
45                 b->dirty = true;
46         }
47         for(Bufferable *b=prev_in_buffer; b; b=b->prev_in_buffer)
48         {
49                 b->buffer = buf;
50                 b->location_dirty = true;
51                 b->dirty = true;
52         }
53 }
54
55 unsigned Bufferable::get_required_buffer_size() const
56 {
57         const Bufferable *last = this;
58         for(; last->next_in_buffer; last=last->next_in_buffer) ;
59         return last->offset+last->get_data_size();
60 }
61
62 Bufferable::AsyncUpdater *Bufferable::refresh_async() const
63 {
64         return dirty ? new AsyncUpdater(*this) : 0;
65 }
66
67 void Bufferable::unlink_from_buffer()
68 {
69         if(prev_in_buffer)
70                 prev_in_buffer->next_in_buffer = next_in_buffer;
71         if(next_in_buffer)
72         {
73                 next_in_buffer->prev_in_buffer = prev_in_buffer;
74                 next_in_buffer->update_offset();
75         }
76         prev_in_buffer = 0;
77         next_in_buffer = 0;
78         buffer = 0;
79         offset = 0;
80 }
81
82 void Bufferable::update_offset()
83 {
84         unsigned new_offset = 0;
85         if(prev_in_buffer)
86                 new_offset = prev_in_buffer->offset+prev_in_buffer->get_data_size();
87
88         unsigned align = get_alignment();
89         new_offset += align-1;
90         new_offset -= new_offset%align;
91         if(new_offset!=offset)
92         {
93                 offset = new_offset;
94                 location_dirty = true;
95                 dirty = true;
96         }
97
98         if(next_in_buffer)
99                 next_in_buffer->update_offset();
100         else if(buffer && offset+get_data_size()>buffer->get_size())
101         {
102                 location_dirty = true;
103                 dirty = true;
104         }
105 }
106
107 void Bufferable::upload_data(char *target) const
108 {
109         unsigned data_size = get_data_size();
110         if(location_dirty)
111         {
112                 buffer->require_size(offset+data_size);
113                 location_changed(buffer, offset, data_size);
114                 location_dirty = false;
115         }
116
117         if(target)
118         {
119                 const char *source = reinterpret_cast<const char *>(get_data_pointer());
120                 copy(source, source+data_size, target);
121         }
122         else
123                 buffer->sub_data(offset, data_size, get_data_pointer());
124         dirty = false;
125 }
126
127
128 Bufferable::AsyncUpdater::AsyncUpdater(const Bufferable &b):
129         bufferable(b)
130 {
131         bufferable.buffer->require_size(bufferable.get_required_buffer_size());
132         mapped_address = reinterpret_cast<char *>(bufferable.buffer->map());
133 }
134
135 Bufferable::AsyncUpdater::~AsyncUpdater()
136 {
137         bufferable.buffer->unmap();
138 }
139
140 void Bufferable::AsyncUpdater::upload_data()
141 {
142         bufferable.upload_data(mapped_address+bufferable.offset);
143         // Update all bufferables in the same buffer at once
144         for(const Bufferable *b=bufferable.prev_in_buffer; b; b=b->prev_in_buffer)
145                 if(b->dirty)
146                         b->upload_data(mapped_address+b->offset);
147         for(const Bufferable *b=bufferable.next_in_buffer; b; b=b->next_in_buffer)
148                 if(b->dirty)
149                         b->upload_data(mapped_address+b->offset);
150 }
151
152 } // namespace GL
153 } // namespace Msp