]> git.tdb.fi Git - libs/gl.git/blob - source/core/batch.cpp
Use standard fixed-size integer types
[libs/gl.git] / source / core / batch.cpp
1 #include <msp/gl/extensions/msp_primitive_restart.h>
2 #include "batch.h"
3 #include "buffer.h"
4 #include "error.h"
5 #include "mesh.h"
6 #include "vertexarray.h"
7
8 using namespace std;
9
10 namespace {
11
12 template<typename T>
13 void append(vector<uint8_t> &data, T i)
14 {
15         data.insert(data.end(), sizeof(T), 0);
16         *(T *)(&data[data.size()-sizeof(T)]) = i;
17 }
18
19 template<typename T, typename U>
20 U convert(T n)
21 {
22         if(!static_cast<T>(~n))
23                 return ~0;
24         else
25                 return n;
26 }
27
28 template<typename T, typename U>
29 void expand(vector<uint8_t> &data)
30 {
31         unsigned count = data.size()/sizeof(T);
32         data.resize(count*sizeof(U));
33         for(unsigned i=count; i--;)
34                 *(U *)(&data[i*sizeof(U)]) = convert<T, U>(*(T *)(&data[i*sizeof(T)]));
35 }
36
37 template<typename T, typename U>
38 void shrink(vector<uint8_t> &data)
39 {
40         unsigned count = data.size()/sizeof(T);
41         for(unsigned i=0; i<count; ++i)
42                 *(U *)(&data[i*sizeof(U)]) = convert<T, U>(*(T *)(&data[i*sizeof(T)]));
43         data.resize(count*sizeof(U));
44 }
45
46 }
47
48 namespace Msp {
49 namespace GL {
50
51 Batch::Batch(PrimitiveType t):
52         prim_type(t),
53         gl_prim_type(GL::get_gl_primitive_type(prim_type)),
54         index_type(UNSIGNED_SHORT),
55         gl_index_type(get_gl_type(index_type)),
56         max_index(0)
57 { }
58
59 Batch::~Batch()
60 {
61 }
62
63 void Batch::set_index_type(DataType t)
64 {
65         if(t==index_type)
66                 return;
67         if(t!=UNSIGNED_SHORT && t!=UNSIGNED_INT)
68                 throw invalid_argument("Batch::set_data_type");
69         if(t==UNSIGNED_SHORT && max_index>0xFFFE)
70                 throw invalid_operation("Batch::set_data_type");
71
72         if(index_type==UNSIGNED_SHORT && t==UNSIGNED_INT)
73                 expand<uint16_t, uint32_t>(data);
74         else if(index_type==UNSIGNED_INT && t==UNSIGNED_SHORT)
75                 shrink<uint32_t, uint16_t>(data);
76
77         index_type = t;
78         gl_index_type = get_gl_type(t);
79         update_offset();
80         dirty = true;
81 }
82
83 Batch &Batch::append(unsigned i)
84 {
85         append_index(i);
86
87         update_offset();
88         dirty = true;
89
90         return *this;
91 }
92
93 Batch &Batch::append(const vector<unsigned> &ind)
94 {
95         if(ind.empty())
96                 return *this;
97
98         data.reserve(data.size()+ind.size()*get_index_size());
99         for(unsigned i: ind)
100                 append_index(i);
101
102         update_offset();
103         dirty = true;
104
105         return *this;
106 }
107
108 bool Batch::can_append(PrimitiveType other_type)
109 {
110         if(other_type!=prim_type)
111                 return false;
112         else if(prim_type==LINE_STRIP || prim_type==LINE_LOOP || prim_type==TRIANGLE_FAN)
113                 return MSP_primitive_restart;
114         else
115                 return true;
116 }
117
118 Batch &Batch::append(const Batch &other)
119 {
120         if(other.prim_type!=prim_type)
121                 throw invalid_argument("Batch::append");
122         if(prim_type==LINE_STRIP || prim_type==LINE_LOOP || prim_type==TRIANGLE_FAN)
123                 static Require _req(MSP_primitive_restart);
124
125         if(other.data.empty())
126                 return *this;
127
128         // TODO allow appending triangles to a triangle strip
129
130         if(prim_type==POINTS || prim_type==LINES || prim_type==TRIANGLES)
131                 ;
132         else if(MSP_primitive_restart)
133         {
134                 if(index_type==UNSIGNED_INT)
135                         ::append<uint32_t>(data, 0xFFFFFFFF);
136                 else
137                         ::append<uint16_t>(data, 0xFFFF);
138         }
139         else if(prim_type==TRIANGLE_STRIP)
140         {
141                 append(get_index(size()-1));
142                 append(other.get_index(0));
143                 if(size()&1)
144                         append(other.get_index(0));
145         }
146
147         unsigned count = other.size();
148         for(unsigned i=0; i<count; ++i)
149                 append_index(other.get_index(i));
150
151         update_offset();
152         dirty = true;
153
154         return *this;
155 }
156
157 void Batch::append_index(unsigned i)
158 {
159         if(data.empty())
160                 max_index = i;
161         else
162                 max_index = max(max_index, i);
163
164         if(index_type==UNSIGNED_SHORT && max_index>0xFFFE)
165                 set_index_type(UNSIGNED_INT);
166
167         if(index_type==UNSIGNED_INT)
168                 ::append<uint32_t>(data, i);
169         else
170                 ::append<uint16_t>(data, i);
171 }
172
173 unsigned Batch::get_index_size() const
174 {
175         return (index_type==UNSIGNED_INT ? sizeof(uint32_t) : sizeof(uint16_t));
176 }
177
178 unsigned Batch::get_index(unsigned i) const
179 {
180         if(index_type==UNSIGNED_INT)
181                 return *(uint32_t *)&data[i*sizeof(uint32_t)];
182         else
183                 return *(uint16_t *)&data[i*sizeof(uint16_t)];
184 }
185
186
187 Batch::Loader::Loader(Batch &b):
188         DataFile::ObjectLoader<Batch>(b)
189 {
190         add("indices", &Loader::indices);
191 }
192
193 void Batch::Loader::indices(const vector<unsigned> &ind)
194 {
195         obj.append(ind);
196 }
197
198 } // namespace GL
199 } // namespace Msp