add BLI_strcpy_rlen, replace strcat, which was used in misleading way.
[blender.git] / intern / cycles / render / attribute.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "mesh.h"
20 #include "attribute.h"
21
22 #include "util_debug.h"
23 #include "util_foreach.h"
24
25 CCL_NAMESPACE_BEGIN
26
27 /* Attribute */
28
29 void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
30 {
31         name = name_;
32         type = type_;
33         element = element_;
34         std = ATTR_STD_NONE;
35
36         /* string and matrix not supported! */
37         assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
38                 type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
39                 type == TypeDesc::TypeNormal);
40 }
41
42 void Attribute::reserve(int numverts, int numtris, int numcurves, int numkeys)
43 {
44         buffer.resize(buffer_size(numverts, numtris, numcurves, numkeys), 0);
45 }
46
47 void Attribute::add(const float& f)
48 {
49         char *data = (char*)&f;
50         size_t size = sizeof(f);
51
52         for(size_t i = 0; i < size; i++)
53                 buffer.push_back(data[i]);
54 }
55
56 void Attribute::add(const float3& f)
57 {
58         char *data = (char*)&f;
59         size_t size = sizeof(f);
60
61         for(size_t i = 0; i < size; i++)
62                 buffer.push_back(data[i]);
63 }
64
65 size_t Attribute::data_sizeof() const
66 {
67         if(type == TypeDesc::TypeFloat)
68                 return sizeof(float);
69         else
70                 return sizeof(float3);
71 }
72
73 size_t Attribute::element_size(int numverts, int numtris, int numcurves, int numkeys) const
74 {
75         size_t size;
76         
77         switch(element) {
78                 case ATTR_ELEMENT_VALUE:
79                         size = 1;
80                         break;
81                 case ATTR_ELEMENT_VERTEX:
82                         size = numverts;
83                         break;
84                 case ATTR_ELEMENT_FACE:
85                         size = numtris;
86                         break;
87                 case ATTR_ELEMENT_CORNER:
88                         size = numtris*3;
89                         break;
90                 case ATTR_ELEMENT_CURVE:
91                         size = numcurves;
92                         break;
93                 case ATTR_ELEMENT_CURVE_KEY:
94                         size = numkeys;
95                         break;
96                 default:
97                         size = 0;
98                         break;
99         }
100         
101         return size;
102 }
103
104 size_t Attribute::buffer_size(int numverts, int numtris, int numcurves, int numkeys) const
105 {
106         return element_size(numverts, numtris, numcurves, numkeys)*data_sizeof();
107 }
108
109 bool Attribute::same_storage(TypeDesc a, TypeDesc b)
110 {
111         if(a == b)
112                 return true;
113         
114         if(a == TypeDesc::TypeColor || a == TypeDesc::TypePoint ||
115            a == TypeDesc::TypeVector || a == TypeDesc::TypeNormal)
116         {
117                 if(b == TypeDesc::TypeColor || b == TypeDesc::TypePoint ||
118                    b == TypeDesc::TypeVector || b == TypeDesc::TypeNormal)
119                 {
120                         return true;
121                 }
122         }
123         return false;
124 }
125
126 const char *Attribute::standard_name(AttributeStandard std)
127 {
128         if(std == ATTR_STD_VERTEX_NORMAL)
129                 return "N";
130         else if(std == ATTR_STD_FACE_NORMAL)
131                 return "Ng";
132         else if(std == ATTR_STD_UV)
133                 return "uv";
134         else if(std == ATTR_STD_GENERATED)
135                 return "generated";
136         else if(std == ATTR_STD_UV_TANGENT)
137                 return "tangent";
138         else if(std == ATTR_STD_UV_TANGENT_SIGN)
139                 return "tangent_sign";
140         else if(std == ATTR_STD_POSITION_UNDEFORMED)
141                 return "undeformed";
142         else if(std == ATTR_STD_POSITION_UNDISPLACED)
143                 return "undisplaced";
144         else if(std == ATTR_STD_MOTION_PRE)
145                 return "motion_pre";
146         else if(std == ATTR_STD_MOTION_POST)
147                 return "motion_post";
148         else if(std == ATTR_STD_PARTICLE)
149                 return "particle";
150         else if(std == ATTR_STD_CURVE_TANGENT)
151                 return "curve_tangent";
152         else if(std == ATTR_STD_CURVE_INTERCEPT)
153                 return "curve_intercept";
154         
155         return "";
156 }
157
158 /* Attribute Set */
159
160 AttributeSet::AttributeSet()
161 {
162         triangle_mesh = NULL;
163         curve_mesh = NULL;
164 }
165
166 AttributeSet::~AttributeSet()
167 {
168 }
169
170 Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
171 {
172         Attribute *attr = find(name);
173
174         if(attr) {
175                 /* return if same already exists */
176                 if(attr->type == type && attr->element == element)
177                         return attr;
178
179                 /* overwrite attribute with same name but different type/element */
180                 remove(name);
181         }
182
183         attributes.push_back(Attribute());
184         attr = &attributes.back();
185
186         attr->set(name, type, element);
187         
188         /* this is weak .. */
189         if(triangle_mesh)
190                 attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0);
191         if(curve_mesh)
192                 attr->reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size());
193         
194         return attr;
195 }
196
197 Attribute *AttributeSet::find(ustring name) const
198 {
199         foreach(const Attribute& attr, attributes)
200                 if(attr.name == name)
201                         return (Attribute*)&attr;
202
203         return NULL;
204 }
205
206 void AttributeSet::remove(ustring name)
207 {
208         Attribute *attr = find(name);
209
210         if(attr) {
211                 list<Attribute>::iterator it;
212
213                 for(it = attributes.begin(); it != attributes.end(); it++) {
214                         if(&*it == attr) {
215                                 attributes.erase(it);
216                                 return;
217                         }
218                 }
219         }
220 }
221
222 Attribute *AttributeSet::add(AttributeStandard std, ustring name)
223 {
224         Attribute *attr = NULL;
225
226         if(name == ustring())
227                 name = Attribute::standard_name(std);
228
229         if(triangle_mesh) {
230                 switch(std) {
231                         case ATTR_STD_VERTEX_NORMAL:
232                                 attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
233                                 break;
234                         case ATTR_STD_FACE_NORMAL:
235                                 attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE);
236                                 break;
237                         case ATTR_STD_UV:
238                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
239                                 break;
240                         case ATTR_STD_UV_TANGENT:
241                                 attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
242                                 break;
243                         case ATTR_STD_UV_TANGENT_SIGN:
244                                 attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
245                                 break;
246                         case ATTR_STD_GENERATED:
247                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
248                                 break;
249                         case ATTR_STD_POSITION_UNDEFORMED:
250                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
251                                 break;
252                         case ATTR_STD_POSITION_UNDISPLACED:
253                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
254                                 break;
255                         case ATTR_STD_MOTION_PRE:
256                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
257                                 break;
258                         case ATTR_STD_MOTION_POST:
259                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
260                                 break;
261                         default:
262                                 assert(0);
263                                 break;
264                 }
265         }
266         else if(curve_mesh) {
267                 switch(std) {
268                         case ATTR_STD_UV:
269                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
270                                 break;
271                         case ATTR_STD_GENERATED:
272                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
273                                 break;
274                         case ATTR_STD_MOTION_PRE:
275                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY);
276                                 break;
277                         case ATTR_STD_MOTION_POST:
278                                 attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY);
279                                 break;
280                         case ATTR_STD_CURVE_TANGENT:
281                                 attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CURVE_KEY);
282                                 break;
283                         case ATTR_STD_CURVE_INTERCEPT:
284                                 attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
285                                 break;
286                         default:
287                                 assert(0);
288                                 break;
289                 }
290         }
291
292         attr->std = std;
293         
294         return attr;
295 }
296
297 Attribute *AttributeSet::find(AttributeStandard std) const
298 {
299         foreach(const Attribute& attr, attributes)
300                 if(attr.std == std)
301                         return (Attribute*)&attr;
302
303         return NULL;
304 }
305
306 void AttributeSet::remove(AttributeStandard std)
307 {
308         Attribute *attr = find(std);
309
310         if(attr) {
311                 list<Attribute>::iterator it;
312
313                 for(it = attributes.begin(); it != attributes.end(); it++) {
314                         if(&*it == attr) {
315                                 attributes.erase(it);
316                                 return;
317                         }
318                 }
319         }
320 }
321
322 Attribute *AttributeSet::find(AttributeRequest& req)
323 {
324         if(req.std == ATTR_STD_NONE)
325                 return find(req.name);
326         else
327                 return find(req.std);
328 }
329
330 void AttributeSet::reserve()
331 {
332         foreach(Attribute& attr, attributes) {
333                 if(triangle_mesh)
334                         attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0);
335                 if(curve_mesh)
336                         attr.reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size());
337         }
338 }
339
340 void AttributeSet::clear()
341 {
342         attributes.clear();
343 }
344
345 /* AttributeRequest */
346
347 AttributeRequest::AttributeRequest(ustring name_)
348 {
349         name = name_;
350         std = ATTR_STD_NONE;
351
352         triangle_type = TypeDesc::TypeFloat;
353         triangle_element = ATTR_ELEMENT_NONE;
354         triangle_offset = 0;
355
356         curve_type = TypeDesc::TypeFloat;
357         curve_element = ATTR_ELEMENT_NONE;
358         curve_offset = 0;
359 }
360
361 AttributeRequest::AttributeRequest(AttributeStandard std_)
362 {
363         name = ustring();
364         std = std_;
365
366         triangle_type = TypeDesc::TypeFloat;
367         triangle_element = ATTR_ELEMENT_NONE;
368         triangle_offset = 0;
369
370         curve_type = TypeDesc::TypeFloat;
371         curve_element = ATTR_ELEMENT_NONE;
372         curve_offset = 0;
373 }
374
375 /* AttributeRequestSet */
376
377 AttributeRequestSet::AttributeRequestSet()
378 {
379 }
380
381 AttributeRequestSet::~AttributeRequestSet()
382 {
383 }
384
385 bool AttributeRequestSet::modified(const AttributeRequestSet& other)
386 {
387         if(requests.size() != other.requests.size())
388                 return true;
389
390         for(size_t i = 0; i < requests.size(); i++) {
391                 bool found = false;
392
393                 for(size_t j = 0; j < requests.size() && !found; j++)
394                         if(requests[i].name == other.requests[j].name &&
395                            requests[i].std == other.requests[j].std)
396                         {
397                                 found = true;
398                         }
399
400                 if(!found) {
401                         return true;
402                 }
403         }
404
405         return false;
406 }
407
408 void AttributeRequestSet::add(ustring name)
409 {
410         foreach(AttributeRequest& req, requests)
411                 if(req.name == name)
412                         return;
413
414         requests.push_back(AttributeRequest(name));
415 }
416
417 void AttributeRequestSet::add(AttributeStandard std)
418 {
419         foreach(AttributeRequest& req, requests)
420                 if(req.std == std)
421                         return;
422
423         requests.push_back(AttributeRequest(std));
424 }
425
426 void AttributeRequestSet::add(AttributeRequestSet& reqs)
427 {
428         foreach(AttributeRequest& req, reqs.requests) {
429                 if(req.std == ATTR_STD_NONE)
430                         add(req.name);
431                 else
432                         add(req.std);
433         }
434 }
435
436 bool AttributeRequestSet::find(ustring name)
437 {
438         foreach(AttributeRequest& req, requests)
439                 if(req.name == name)
440                         return true;
441         
442         return false;
443 }
444
445 bool AttributeRequestSet::find(AttributeStandard std)
446 {
447         foreach(AttributeRequest& req, requests)
448                 if(req.std == std)
449                         return true;
450
451         return false;
452 }
453
454 size_t AttributeRequestSet::size()
455 {
456         return requests.size();
457 }
458
459 void AttributeRequestSet::clear()
460 {
461         requests.clear();
462 }
463
464 CCL_NAMESPACE_END
465