Blender V5.0
scene/attribute.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "scene/attribute.h"
6#include "scene/hair.h"
7#include "scene/image.h"
8#include "scene/mesh.h"
9#include "scene/pointcloud.h"
10
11#include "util/log.h"
12#include "util/transform.h"
13
15
16/* Attribute */
17
19 const TypeDesc type,
21 Geometry *geom,
24{
25 /* string and matrix not supported! */
26 assert(type == TypeFloat || type == TypeColor || type == TypePoint || type == TypeVector ||
27 type == TypeNormal || type == TypeMatrix || type == TypeFloat2 || type == TypeFloat4 ||
28 type == TypeRGBA);
29
31 buffer.resize(sizeof(ImageHandle));
32 new (buffer.data()) ImageHandle();
33 }
34 else {
35 resize(geom, prim, false);
36 }
37}
38
40{
41 /* For voxel data, we need to free the image handle. */
42 if (element == ATTR_ELEMENT_VOXEL && !buffer.empty()) {
43 ImageHandle &handle = data_voxel();
44 handle.~ImageHandle();
45 }
46}
47
48void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only)
49{
51 if (reserve_only) {
52 buffer.reserve(buffer_size(geom, prim));
53 }
54 else {
55 buffer.resize(buffer_size(geom, prim), 0);
56 }
57 }
58}
59
60void Attribute::resize(const size_t num_elements)
61{
63 buffer.resize(num_elements * data_sizeof(), 0);
64 }
65}
66
67void Attribute::add(const float &f)
68{
69 assert(data_sizeof() == sizeof(float));
70
71 char *data = (char *)&f;
72 const size_t size = sizeof(f);
73
74 for (size_t i = 0; i < size; i++) {
75 buffer.push_back(data[i]);
76 }
77
78 modified = true;
79}
80
81void Attribute::add(const uchar4 &f)
82{
83 assert(data_sizeof() == sizeof(uchar4));
84
85 char *data = (char *)&f;
86 const size_t size = sizeof(f);
87
88 for (size_t i = 0; i < size; i++) {
89 buffer.push_back(data[i]);
90 }
91
92 modified = true;
93}
94
95void Attribute::add(const float2 &f)
96{
97 assert(data_sizeof() == sizeof(float2));
98
99 char *data = (char *)&f;
100 const size_t size = sizeof(f);
101
102 for (size_t i = 0; i < size; i++) {
103 buffer.push_back(data[i]);
104 }
105
106 modified = true;
107}
108
109void Attribute::add(const float3 &f)
110{
111 assert(data_sizeof() == sizeof(float3));
112
113 char *data = (char *)&f;
114 const size_t size = sizeof(f);
115
116 for (size_t i = 0; i < size; i++) {
117 buffer.push_back(data[i]);
118 }
119
120 modified = true;
121}
122
124{
125 assert(data_sizeof() == sizeof(Transform));
126
127 char *data = (char *)&f;
128 const size_t size = sizeof(f);
129
130 for (size_t i = 0; i < size; i++) {
131 buffer.push_back(data[i]);
132 }
133
134 modified = true;
135}
136
137void Attribute::add(const char *data)
138{
139 const size_t size = data_sizeof();
140
141 for (size_t i = 0; i < size; i++) {
142 buffer.push_back(data[i]);
143 }
144
145 modified = true;
146}
147
149{
150 assert(other.std == std);
151 assert(other.type == type);
152 assert(other.element == element);
153
154 this->flags = other.flags;
155
156 if (this->buffer.size() != other.buffer.size()) {
157 this->buffer = std::move(other.buffer);
158 modified = true;
159 }
160 else if (memcmp(this->data(), other.data(), other.buffer.size()) != 0) {
161 this->buffer = std::move(other.buffer);
162 modified = true;
163 }
164}
165
167{
169 return sizeof(ImageHandle);
170 }
172 return sizeof(uchar4);
173 }
174 if (type == TypeFloat) {
175 return sizeof(float);
176 }
177 if (type == TypeFloat2) {
178 return sizeof(float2);
179 }
180 if (type == TypeMatrix) {
181 return sizeof(Transform);
182 // The float3 type is not interchangeable with float4
183 // as it is now a packed type.
184 }
185 if (type == TypeFloat4) {
186 return sizeof(float4);
187 }
188 if (type == TypeRGBA) {
189 return sizeof(float4);
190 }
191 return sizeof(float3);
192}
193
195{
196 size_t size = 0;
197
198 switch (element) {
202 size = 1;
203 break;
205 if (geom->is_mesh() || geom->is_volume()) {
206 Mesh *mesh = static_cast<Mesh *>(geom);
207 if (prim == ATTR_PRIM_SUBD) {
209 }
210 else {
211 size = mesh->get_verts().size();
212 }
213 }
214 else if (geom->is_pointcloud()) {
215 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
216 size = pointcloud->num_points();
217 }
218 break;
220 if (geom->is_mesh()) {
221 Mesh *mesh = static_cast<Mesh *>(geom);
222 DCHECK_GT(mesh->get_motion_steps(), 0);
223 if (prim == ATTR_PRIM_SUBD) {
224 size = mesh->get_num_subd_base_verts() * (mesh->get_motion_steps() - 1);
225 }
226 else {
227 size = mesh->get_verts().size() * (mesh->get_motion_steps() - 1);
228 }
229 }
230 else if (geom->is_pointcloud()) {
231 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
232 size = pointcloud->num_points() * (pointcloud->get_motion_steps() - 1);
233 }
234 break;
236 if (geom->is_mesh() || geom->is_volume()) {
237 Mesh *mesh = static_cast<Mesh *>(geom);
238 if (prim == ATTR_PRIM_SUBD) {
239 size = mesh->get_num_subd_faces();
240 }
241 else {
242 size = mesh->num_triangles();
243 }
244 }
245 break;
248 if (geom->is_mesh()) {
249 Mesh *mesh = static_cast<Mesh *>(geom);
250 if (prim == ATTR_PRIM_SUBD) {
251 size = mesh->get_subd_face_corners().size();
252 }
253 else {
254 size = mesh->num_triangles() * 3;
255 }
256 }
257 break;
259 if (geom->is_hair()) {
260 Hair *hair = static_cast<Hair *>(geom);
261 size = hair->num_curves();
262 }
263 break;
265 if (geom->is_hair()) {
266 Hair *hair = static_cast<Hair *>(geom);
267 size = hair->get_curve_keys().size();
268 }
269 break;
271 if (geom->is_hair()) {
272 Hair *hair = static_cast<Hair *>(geom);
273 DCHECK_GT(hair->get_motion_steps(), 0);
274 size = hair->get_curve_keys().size() * (hair->get_motion_steps() - 1);
275 }
276 break;
277 default:
278 break;
279 }
280
281 return size;
282}
283
285{
286 return element_size(geom, prim) * data_sizeof();
287}
288
289bool Attribute::same_storage(const TypeDesc a, const TypeDesc b)
290{
291 if (a == b) {
292 return true;
293 }
294
295 if (a == TypeColor || a == TypePoint || a == TypeVector || a == TypeNormal) {
296 if (b == TypeColor || b == TypePoint || b == TypeVector || b == TypeNormal) {
297 return true;
298 }
299 }
300 return false;
301}
302
303void Attribute::zero_data(void *dst)
304{
305 memset(dst, 0, data_sizeof());
306}
307
309{
310 switch (std) {
312 return "N";
313 case ATTR_STD_UV:
314 return "uv";
316 return "generated";
318 return "generated_transform";
320 return "tangent";
322 return "tangent_sign";
324 return "undisplaced_tangent";
326 return "undisplaced_tangent_sign";
328 return "vertex_color";
330 return "undeformed";
332 return "undisplaced";
334 return "undisplaced_N";
336 return "motion_P";
338 return "motion_N";
340 return "particle";
342 return "curve_intercept";
344 return "curve_length";
346 return "curve_random";
348 return "point_random";
350 return "ptex_face_id";
351 case ATTR_STD_PTEX_UV:
352 return "ptex_uv";
354 return "density";
356 return "color";
358 return "flame";
360 return "heat";
362 return "temperature";
364 return "velocity";
366 return "velocity_x";
368 return "velocity_y";
370 return "velocity_z";
372 return "pointiness";
374 return "random_per_island";
376 return "shadow_transparency";
378 case ATTR_STD_NONE:
379 case ATTR_STD_NUM:
380 return "";
381 }
382
383 return "";
384}
385
387{
388 if (name) {
389 for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) {
391 return (AttributeStandard)std;
392 }
393 }
394 }
395
396 return ATTR_STD_NONE;
397}
398
400{
401 if (attr.element == ATTR_ELEMENT_CORNER) {
403 }
404
405 if (attr.type == TypeFloat) {
407 }
408
409 if (attr.type == TypeFloat2) {
411 }
412
413 if (attr.type == TypeFloat4 || attr.type == TypeRGBA || attr.type == TypeMatrix) {
415 }
416
418}
419
422 unordered_set<int> &tiles) const
423{
424 if (type != TypeFloat2) {
425 return;
426 }
427
428 const int num = element_size(geom, prim);
429 const float2 *uv = data_float2();
430 for (int i = 0; i < num; i++, uv++) {
431 const float u = uv->x;
432 const float v = uv->y;
433 int x = (int)u;
434 int y = (int)v;
435
436 if (x < 0 || y < 0 || x >= 10) {
437 continue;
438 }
439
440 /* Be conservative in corners - precisely touching the right or upper edge of a tile
441 * should not load its right/upper neighbor as well. */
442 if (x > 0 && (u < x + 1e-6f)) {
443 x--;
444 }
445 if (y > 0 && (v < y + 1e-6f)) {
446 y--;
447 }
448
449 tiles.insert(1001 + 10 * y + x);
450 }
451}
452
453/* Attribute Set */
454
459
461
463{
464 Attribute *attr = find(name);
465
466 if (attr) {
467 /* return if same already exists */
468 if (attr->type == type && attr->element == element) {
469 return attr;
470 }
471
472 /* overwrite attribute with same name but different type/element */
473 remove(name);
474 }
475
476 Attribute new_attr(name, type, element, geometry, prim);
477 attributes.emplace_back(std::move(new_attr));
478 tag_modified(attributes.back());
479 return &attributes.back();
480}
481
483{
484 for (const Attribute &attr : attributes) {
485 if (attr.name == name) {
486 return (Attribute *)&attr;
487 }
488 }
489
490 return nullptr;
491}
492
494{
495 Attribute *attr = find(name);
496
497 if (attr) {
498 list<Attribute>::iterator it;
499
500 for (it = attributes.begin(); it != attributes.end(); it++) {
501 if (&*it == attr) {
502 remove(it);
503 return;
504 }
505 }
506 }
507}
508
510{
511 Attribute *attr = nullptr;
512
513 if (name.empty()) {
515 }
516
517 if (geometry->is_mesh()) {
518 switch (std) {
521 attr = add(name, TypeNormal, ATTR_ELEMENT_VERTEX);
522 break;
523 case ATTR_STD_UV:
524 attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER);
525 break;
528 attr = add(name, TypeVector, ATTR_ELEMENT_CORNER);
529 break;
532 attr = add(name, TypeFloat, ATTR_ELEMENT_CORNER);
533 break;
536 break;
540 attr = add(name, TypePoint, ATTR_ELEMENT_VERTEX);
541 break;
543 attr = add(name, TypePoint, ATTR_ELEMENT_VERTEX_MOTION);
544 break;
546 attr = add(name, TypeNormal, ATTR_ELEMENT_VERTEX_MOTION);
547 break;
549 attr = add(name, TypeFloat, ATTR_ELEMENT_FACE);
550 break;
551 case ATTR_STD_PTEX_UV:
552 attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER);
553 break;
555 attr = add(name, TypeMatrix, ATTR_ELEMENT_MESH);
556 break;
558 attr = add(name, TypeFloat, ATTR_ELEMENT_VERTEX);
559 break;
561 attr = add(name, TypeFloat, ATTR_ELEMENT_FACE);
562 break;
563 default:
564 assert(0);
565 break;
566 }
567 }
568 else if (geometry->is_pointcloud()) {
569 switch (std) {
570 case ATTR_STD_UV:
571 attr = add(name, TypeFloat2, ATTR_ELEMENT_VERTEX);
572 break;
574 attr = add(name, TypePoint, ATTR_ELEMENT_VERTEX);
575 break;
577 attr = add(name, TypeFloat4, ATTR_ELEMENT_VERTEX_MOTION);
578 break;
580 attr = add(name, TypeFloat, ATTR_ELEMENT_VERTEX);
581 break;
583 attr = add(name, TypeMatrix, ATTR_ELEMENT_MESH);
584 break;
585 default:
586 assert(0);
587 break;
588 }
589 }
590 else if (geometry->is_volume()) {
591 switch (std) {
593 attr = add(name, TypeNormal, ATTR_ELEMENT_VERTEX);
594 break;
602 attr = add(name, TypeFloat, ATTR_ELEMENT_VOXEL);
603 break;
605 attr = add(name, TypeColor, ATTR_ELEMENT_VOXEL);
606 break;
608 attr = add(name, TypeVector, ATTR_ELEMENT_VOXEL);
609 break;
610 default:
611 assert(0);
612 break;
613 }
614 }
615 else if (geometry->is_hair()) {
616 switch (std) {
618 attr = add(name, TypeNormal, ATTR_ELEMENT_CURVE_KEY);
619 break;
620 case ATTR_STD_UV:
621 attr = add(name, TypeFloat2, ATTR_ELEMENT_CURVE);
622 break;
624 attr = add(name, TypePoint, ATTR_ELEMENT_CURVE);
625 break;
627 attr = add(name, TypeFloat4, ATTR_ELEMENT_CURVE_KEY_MOTION);
628 break;
630 attr = add(name, TypeFloat, ATTR_ELEMENT_CURVE_KEY);
631 break;
633 attr = add(name, TypeFloat, ATTR_ELEMENT_CURVE);
634 break;
636 attr = add(name, TypeFloat, ATTR_ELEMENT_CURVE);
637 break;
639 attr = add(name, TypeMatrix, ATTR_ELEMENT_MESH);
640 break;
642 attr = add(name, TypeFloat, ATTR_ELEMENT_VERTEX);
643 break;
645 attr = add(name, TypeFloat, ATTR_ELEMENT_FACE);
646 break;
648 attr = add(name, TypeFloat, ATTR_ELEMENT_CURVE_KEY);
649 break;
650 default:
651 assert(0);
652 break;
653 }
654 }
655
656 attr->std = std;
657
658 return attr;
659}
660
662{
663 Attribute &copy_attr = *add(attr.name, attr.type, attr.element);
664 copy_attr.std = attr.std;
665 return copy_attr;
666}
667
669{
670 for (const Attribute &attr : attributes) {
671 if (attr.std == std) {
672 return (Attribute *)&attr;
673 }
674 }
675
676 return nullptr;
677}
678
680{
681 for (Attribute &attr : attributes) {
682 if (attr.name != other.name) {
683 continue;
684 }
685 if (attr.std != other.std) {
686 continue;
687 }
688 if (attr.type != other.type) {
689 continue;
690 }
691 if (attr.element != other.element) {
692 continue;
693 }
694 return &attr;
695 }
696 return nullptr;
697}
698
700{
701 Attribute *attr = find(std);
702
703 if (attr) {
704 list<Attribute>::iterator it;
705
706 for (it = attributes.begin(); it != attributes.end(); it++) {
707 if (&*it == attr) {
708 remove(it);
709 return;
710 }
711 }
712 }
713}
714
716{
717 if (req.std == ATTR_STD_NONE) {
718 return find(req.name);
719 }
720 return find(req.std);
721}
722
724{
725 if (attribute->std == ATTR_STD_NONE) {
726 remove(attribute->name);
727 }
728 else {
729 remove(attribute->std);
730 }
731}
732
733void AttributeSet::remove(list<Attribute>::iterator it)
734{
735 tag_modified(*it);
736 attributes.erase(it);
737}
738
739void AttributeSet::resize(bool reserve_only)
740{
741 for (Attribute &attr : attributes) {
742 attr.resize(geometry, prim, reserve_only);
743 }
744}
745
746void AttributeSet::clear(bool preserve_voxel_data)
747{
748 if (preserve_voxel_data) {
749 list<Attribute>::iterator it;
750
751 for (it = attributes.begin(); it != attributes.end();) {
752 if (it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) {
753 it++;
754 }
755 else {
756 attributes.erase(it++);
757 }
758 }
759 }
760 else {
761 attributes.clear();
762 }
763}
764
765void AttributeSet::update(AttributeSet &&new_attributes)
766{
767 /* Remove any attributes not on new_attributes. */
768 list<Attribute>::iterator it;
769 for (it = attributes.begin(); it != attributes.end();) {
770 const Attribute &old_attr = *it;
771 if (new_attributes.find_matching(old_attr) == nullptr) {
772 remove(it++);
773 continue;
774 }
775 it++;
776 }
777
778 /* Add or update old_attributes based on the new_attributes. */
779 for (Attribute &attr : new_attributes.attributes) {
780 Attribute *nattr = add(attr.name, attr.type, attr.element);
781 nattr->std = attr.std;
782 nattr->set_data_from(std::move(attr));
783 }
784
785 /* If all attributes were replaced, transform is no longer applied. */
786 geometry->transform_applied = false;
787}
788
790{
791 for (Attribute &attr : attributes) {
792 attr.modified = false;
793 }
794
795 modified_flag = 0;
796}
797
798void AttributeSet::tag_modified(const Attribute &attr)
799{
800 /* Some attributes are not stored in the various kernel attribute arrays
801 * (DeviceScene::attribute_*), so the modified flags are only set if the associated standard
802 * corresponds to an attribute which will be stored in the kernel's attribute arrays. */
803 const bool modifies_device_array = (attr.std != ATTR_STD_VERTEX_NORMAL);
804
805 if (modifies_device_array) {
806 const AttrKernelDataType kernel_type = Attribute::kernel_type(attr);
807 modified_flag |= (1u << kernel_type);
808 }
809}
810
812{
813 return (modified_flag & (1u << kernel_type)) != 0;
814}
815
816/* AttributeRequest */
817
819{
820 name = name_;
822
823 type = TypeFloat;
824 desc.element = ATTR_ELEMENT_NONE;
825 desc.offset = 0;
826 desc.type = NODE_ATTR_FLOAT;
827}
828
830{
831 name = ustring();
832 std = std_;
833
834 type = TypeFloat;
835 desc.element = ATTR_ELEMENT_NONE;
836 desc.offset = 0;
837 desc.type = NODE_ATTR_FLOAT;
838}
839
840/* AttributeRequestSet */
841
843
845
847{
848 if (requests.size() != other.requests.size()) {
849 return true;
850 }
851
852 for (size_t i = 0; i < requests.size(); i++) {
853 bool found = false;
854
855 for (size_t j = 0; j < requests.size() && !found; j++) {
856 if (requests[i].name == other.requests[j].name && requests[i].std == other.requests[j].std) {
857 found = true;
858 }
859 }
860
861 if (!found) {
862 return true;
863 }
864 }
865
866 return false;
867}
868
870{
871 for (const AttributeRequest &req : requests) {
872 if (req.name == name) {
873 return;
874 }
875 }
876
877 requests.push_back(AttributeRequest(name));
878}
879
881{
882 for (const AttributeRequest &req : requests) {
883 if (req.std == std) {
884 return;
885 }
886 }
887
888 requests.push_back(AttributeRequest(std));
889}
890
892{
893 for (const AttributeRequest &req : reqs.requests) {
894 if (req.std == ATTR_STD_NONE) {
895 add(req.name);
896 }
897 else {
898 add(req.std);
899 }
900 }
901}
902
904{
905 if (name.empty()) {
906 return;
907 }
908
910
911 if (std) {
912 add(std);
913 }
914 else {
915 add(name);
916 }
917}
918
920{
921 for (const AttributeRequest &req : requests) {
922 if (req.name == name) {
923 return true;
924 }
925 }
926
927 return false;
928}
929
931{
932 for (const AttributeRequest &req : requests) {
933 if (req.std == std) {
934 return true;
935 }
936 }
937
938 return false;
939}
940
942{
943 return requests.size();
944}
945
947{
948 requests.clear();
949}
950
ATTR_WARN_UNUSED_RESULT const size_t num
return true
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
vector< AttributeRequest > requests
bool find(ustring name)
void add(ustring name)
bool modified(const AttributeRequestSet &other)
void add_standard(ustring name)
AttributeRequest(ustring name_)
AttributeDescriptor desc
AttributeStandard std
Geometry * geometry
void update(AttributeSet &&new_attributes)
Attribute & copy(const Attribute &attr)
list< Attribute > attributes
Attribute * find(ustring name) const
Attribute * find_matching(const Attribute &other)
bool modified(AttrKernelDataType kernel_type) const
Attribute * add(ustring name, const TypeDesc type, AttributeElement element)
void remove(ustring name)
AttributeSet(Geometry *geometry, AttributePrimitive prim)
void resize(bool reserve_only=false)
void clear(bool preserve_voxel_data=false)
AttributePrimitive prim
bool is_volume() const
bool is_pointcloud() const
bool is_hair() const
bool is_mesh() const
Definition hair.h:13
size_t num_curves() const
Definition hair.h:126
nullptr float
#define CCL_NAMESPACE_END
#define assert(assertion)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
@ NODE_ATTR_FLOAT
AttributeStandard
@ ATTR_STD_CURVE_INTERCEPT
@ ATTR_STD_GENERATED_TRANSFORM
@ ATTR_STD_UV
@ ATTR_STD_MOTION_VERTEX_NORMAL
@ ATTR_STD_VOLUME_VELOCITY_Y
@ ATTR_STD_VOLUME_TEMPERATURE
@ ATTR_STD_VERTEX_NORMAL
@ ATTR_STD_UV_TANGENT
@ ATTR_STD_NOT_FOUND
@ ATTR_STD_NONE
@ ATTR_STD_VOLUME_VELOCITY_Z
@ ATTR_STD_POINT_RANDOM
@ ATTR_STD_VERTEX_COLOR
@ ATTR_STD_VOLUME_DENSITY
@ ATTR_STD_NUM
@ ATTR_STD_POSITION_UNDISPLACED
@ ATTR_STD_VOLUME_FLAME
@ ATTR_STD_PTEX_FACE_ID
@ ATTR_STD_VOLUME_VELOCITY
@ ATTR_STD_POSITION_UNDEFORMED
@ ATTR_STD_VOLUME_COLOR
@ ATTR_STD_MOTION_VERTEX_POSITION
@ ATTR_STD_VOLUME_HEAT
@ ATTR_STD_NORMAL_UNDISPLACED
@ ATTR_STD_UV_TANGENT_SIGN
@ ATTR_STD_CURVE_RANDOM
@ ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED
@ ATTR_STD_SHADOW_TRANSPARENCY
@ ATTR_STD_UV_TANGENT_UNDISPLACED
@ ATTR_STD_PTEX_UV
@ ATTR_STD_POINTINESS
@ ATTR_STD_GENERATED
@ ATTR_STD_CURVE_LENGTH
@ ATTR_STD_VOLUME_VELOCITY_X
@ ATTR_STD_RANDOM_PER_ISLAND
@ ATTR_STD_PARTICLE
AttributeElement
@ ATTR_ELEMENT_NONE
@ ATTR_ELEMENT_CORNER_BYTE
@ ATTR_ELEMENT_CURVE_KEY
@ ATTR_ELEMENT_CURVE_KEY_MOTION
@ ATTR_ELEMENT_VOXEL
@ ATTR_ELEMENT_CORNER
@ ATTR_ELEMENT_OBJECT
@ ATTR_ELEMENT_VERTEX_MOTION
@ ATTR_ELEMENT_VERTEX
@ ATTR_ELEMENT_FACE
@ ATTR_ELEMENT_MESH
@ ATTR_ELEMENT_CURVE
AttributePrimitive
@ ATTR_PRIM_SUBD
#define DCHECK_GT(a, b)
Definition log.h:145
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
const char * name
AttrKernelDataType
@ FLOAT4
@ FLOAT2
@ UCHAR4
@ FLOAT3
@ FLOAT
const char * name
AttributeElement element
Attribute(ustring name, const TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim)
static AttrKernelDataType kernel_type(const Attribute &attr)
static AttributeStandard name_standard(const char *name)
TypeDesc type
void resize(Geometry *geom, AttributePrimitive prim, bool reserve_only)
size_t element_size(Geometry *geom, AttributePrimitive prim) const
void get_uv_tiles(Geometry *geom, AttributePrimitive prim, unordered_set< int > &tiles) const
vector< char > buffer
void set_data_from(Attribute &&other)
void zero_data(void *dst)
static const char * standard_name(AttributeStandard std)
size_t buffer_size(Geometry *geom, AttributePrimitive prim) const
AttributeStandard std
ImageHandle & data_voxel()
size_t data_sizeof() const
static bool same_storage(const TypeDesc a, const TypeDesc b)
void add(const float &f)
float2 * data_float2()
size_t get_num_subd_faces() const
Definition scene/mesh.h:235
size_t get_num_subd_base_verts() const
Definition scene/mesh.h:243
size_t num_triangles() const
Definition scene/mesh.h:77
size_t num_points() const
float x
float y
i
Definition text_draw.cc:230