/* * Copyright 2011-2013 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "render/image.h" #include "render/mesh.h" #include "render/attribute.h" #include "util/util_debug.h" #include "util/util_foreach.h" #include "util/util_transform.h" CCL_NAMESPACE_BEGIN /* Attribute */ Attribute::~Attribute() { /* for voxel data, we need to remove the image from the image manager */ if(element == ATTR_ELEMENT_VOXEL) { VoxelAttribute *voxel_data = data_voxel(); if(voxel_data && voxel_data->slot != -1) { voxel_data->manager->remove_image(voxel_data->slot); } } } void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) { name = name_; type = type_; element = element_; std = ATTR_STD_NONE; flags = 0; /* string and matrix not supported! */ assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor || type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix); } void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only) { if(reserve_only) { buffer.reserve(buffer_size(mesh, prim)); } else { buffer.resize(buffer_size(mesh, prim), 0); } } void Attribute::resize(size_t num_elements) { buffer.resize(num_elements * data_sizeof(), 0); } void Attribute::add(const float& f) { char *data = (char*)&f; size_t size = sizeof(f); for(size_t i = 0; i < size; i++) buffer.push_back(data[i]); } void Attribute::add(const uchar4& f) { char *data = (char*)&f; size_t size = sizeof(f); for(size_t i = 0; i < size; i++) buffer.push_back(data[i]); } void Attribute::add(const float3& f) { char *data = (char*)&f; size_t size = sizeof(f); for(size_t i = 0; i < size; i++) buffer.push_back(data[i]); } void Attribute::add(const Transform& f) { char *data = (char*)&f; size_t size = sizeof(f); for(size_t i = 0; i < size; i++) buffer.push_back(data[i]); } void Attribute::add(const VoxelAttribute& f) { char *data = (char*)&f; size_t size = sizeof(f); for(size_t i = 0; i < size; i++) buffer.push_back(data[i]); } void Attribute::add(const char *data) { size_t size = data_sizeof(); for(size_t i = 0; i < size; i++) buffer.push_back(data[i]); } size_t Attribute::data_sizeof() const { if(element == ATTR_ELEMENT_VOXEL) return sizeof(VoxelAttribute); else if(element == ATTR_ELEMENT_CORNER_BYTE) return sizeof(uchar4); else if(type == TypeDesc::TypeFloat) return sizeof(float); else if(type == TypeDesc::TypeMatrix) return sizeof(Transform); else return sizeof(float3); } size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const { if(flags & ATTR_FINAL_SIZE) { return buffer.size() / data_sizeof(); } size_t size; switch(element) { case ATTR_ELEMENT_OBJECT: case ATTR_ELEMENT_MESH: case ATTR_ELEMENT_VOXEL: size = 1; break; case ATTR_ELEMENT_VERTEX: size = mesh->verts.size() + mesh->num_ngons; if(prim == ATTR_PRIM_SUBD) { size -= mesh->num_subd_verts; } break; case ATTR_ELEMENT_VERTEX_MOTION: size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1); if(prim == ATTR_PRIM_SUBD) { size -= mesh->num_subd_verts * (mesh->motion_steps - 1); } break; case ATTR_ELEMENT_FACE: if(prim == ATTR_PRIM_TRIANGLE) { size = mesh->num_triangles(); } else { size = mesh->subd_faces.size() + mesh->num_ngons; } break; case ATTR_ELEMENT_CORNER: case ATTR_ELEMENT_CORNER_BYTE: if(prim == ATTR_PRIM_TRIANGLE) { size = mesh->num_triangles()*3; } else { size = mesh->subd_face_corners.size() + mesh->num_ngons; } break; case ATTR_ELEMENT_CURVE: size = mesh->num_curves(); break; case ATTR_ELEMENT_CURVE_KEY: size = mesh->curve_keys.size(); break; case ATTR_ELEMENT_CURVE_KEY_MOTION: size = mesh->curve_keys.size() * (mesh->motion_steps - 1); break; default: size = 0; break; } return size; } size_t Attribute::buffer_size(Mesh *mesh, AttributePrimitive prim) const { return element_size(mesh, prim)*data_sizeof(); } bool Attribute::same_storage(TypeDesc a, TypeDesc b) { if(a == b) return true; if(a == TypeDesc::TypeColor || a == TypeDesc::TypePoint || a == TypeDesc::TypeVector || a == TypeDesc::TypeNormal) { if(b == TypeDesc::TypeColor || b == TypeDesc::TypePoint || b == TypeDesc::TypeVector || b == TypeDesc::TypeNormal) { return true; } } return false; } void Attribute::zero_data(void* dst) { memset(dst, 0, data_sizeof()); } void Attribute::add_with_weight(void* dst, void* src, float weight) { if(element == ATTR_ELEMENT_CORNER_BYTE) { for(int i = 0; i < 4; i++) { ((uchar*)dst)[i] += uchar(((uchar*)src)[i] * weight); } } else if(same_storage(type, TypeDesc::TypeFloat)) { *((float*)dst) += *((float*)src) * weight; } else if(same_storage(type, TypeDesc::TypeVector)) { *((float4*)dst) += *((float4*)src) * weight; } else { assert(!"not implemented for this type"); } } const char *Attribute::standard_name(AttributeStandard std) { switch(std) { case ATTR_STD_VERTEX_NORMAL: return "N"; case ATTR_STD_FACE_NORMAL: return "Ng"; case ATTR_STD_UV: return "uv"; case ATTR_STD_GENERATED: return "generated"; case ATTR_STD_GENERATED_TRANSFORM: return "generated_transform"; case ATTR_STD_UV_TANGENT: return "tangent"; case ATTR_STD_UV_TANGENT_SIGN: return "tangent_sign"; case ATTR_STD_POSITION_UNDEFORMED: return "undeformed"; case ATTR_STD_POSITION_UNDISPLACED: return "undisplaced"; case ATTR_STD_MOTION_VERTEX_POSITION: return "motion_P"; case ATTR_STD_MOTION_VERTEX_NORMAL: return "motion_N"; case ATTR_STD_PARTICLE: return "particle"; case ATTR_STD_CURVE_INTERCEPT: return "curve_intercept"; case ATTR_STD_PTEX_FACE_ID: return "ptex_face_id"; case ATTR_STD_PTEX_UV: return "ptex_uv"; case ATTR_STD_VOLUME_DENSITY: return "density"; case ATTR_STD_VOLUME_COLOR: return "color"; case ATTR_STD_VOLUME_FLAME: return "flame"; case ATTR_STD_VOLUME_HEAT: return "heat"; case ATTR_STD_VOLUME_VELOCITY: return "velocity"; case ATTR_STD_POINTINESS: return "pointiness"; case ATTR_STD_NOT_FOUND: case ATTR_STD_NONE: case ATTR_STD_NUM: return ""; } return ""; } AttributeStandard Attribute::name_standard(const char *name) { for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) if(strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0) return (AttributeStandard)std; return ATTR_STD_NONE; } /* Attribute Set */ AttributeSet::AttributeSet() { triangle_mesh = NULL; curve_mesh = NULL; subd_mesh = NULL; } AttributeSet::~AttributeSet() { } Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element) { Attribute *attr = find(name); if(attr) { /* return if same already exists */ if(attr->type == type && attr->element == element) return attr; /* overwrite attribute with same name but different type/element */ remove(name); } #if __cplusplus >= 201103L attributes.emplace_back(); attr = &attributes.back(); attr->set(name, type, element); #else { Attribute attr_temp; attr_temp.set(name, type, element); attributes.push_back(attr_temp); attr = &attributes.back(); } #endif /* this is weak .. */ if(triangle_mesh) attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false); if(curve_mesh) attr->resize(curve_mesh, ATTR_PRIM_CURVE, false); if(subd_mesh) attr->resize(subd_mesh, ATTR_PRIM_SUBD, false); return attr; } Attribute *AttributeSet::find(ustring name) const { foreach(const Attribute& attr, attributes) if(attr.name == name) return (Attribute*)&attr; return NULL; } void AttributeSet::remove(ustring name) { Attribute *attr = find(name); if(attr) { list::iterator it; for(it = attributes.begin(); it != attributes.end(); it++) { if(&*it == attr) { attributes.erase(it); return; } } } } Attribute *AttributeSet::add(AttributeStandard std, ustring name) { Attribute *attr = NULL; if(name == ustring()) name = Attribute::standard_name(std); if(triangle_mesh || subd_mesh) { switch(std) { case ATTR_STD_VERTEX_NORMAL: attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX); break; case ATTR_STD_FACE_NORMAL: attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE); break; case ATTR_STD_UV: attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); break; case ATTR_STD_UV_TANGENT: attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); break; case ATTR_STD_UV_TANGENT_SIGN: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); break; case ATTR_STD_GENERATED: case ATTR_STD_POSITION_UNDEFORMED: case ATTR_STD_POSITION_UNDISPLACED: attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); break; case ATTR_STD_MOTION_VERTEX_POSITION: attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX_MOTION); break; case ATTR_STD_MOTION_VERTEX_NORMAL: attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX_MOTION); break; case ATTR_STD_PTEX_FACE_ID: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE); break; case ATTR_STD_PTEX_UV: attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); break; case ATTR_STD_GENERATED_TRANSFORM: attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); break; case ATTR_STD_VOLUME_DENSITY: case ATTR_STD_VOLUME_FLAME: case ATTR_STD_VOLUME_HEAT: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); break; case ATTR_STD_VOLUME_COLOR: attr = add(name, TypeDesc::TypeColor, ATTR_ELEMENT_VOXEL); break; case ATTR_STD_VOLUME_VELOCITY: attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_VOXEL); break; case ATTR_STD_POINTINESS: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); break; default: assert(0); break; } } else if(curve_mesh) { switch(std) { case ATTR_STD_UV: case ATTR_STD_GENERATED: attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); break; case ATTR_STD_MOTION_VERTEX_POSITION: attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY_MOTION); break; case ATTR_STD_CURVE_INTERCEPT: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY); break; case ATTR_STD_GENERATED_TRANSFORM: attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); break; case ATTR_STD_POINTINESS: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); break; default: assert(0); break; } } attr->std = std; return attr; } Attribute *AttributeSet::find(AttributeStandard std) const { foreach(const Attribute& attr, attributes) if(attr.std == std) return (Attribute*)&attr; return NULL; } void AttributeSet::remove(AttributeStandard std) { Attribute *attr = find(std); if(attr) { list::iterator it; for(it = attributes.begin(); it != attributes.end(); it++) { if(&*it == attr) { attributes.erase(it); return; } } } } Attribute *AttributeSet::find(AttributeRequest& req) { if(req.std == ATTR_STD_NONE) return find(req.name); else return find(req.std); } void AttributeSet::resize(bool reserve_only) { foreach(Attribute& attr, attributes) { if(triangle_mesh) attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only); if(curve_mesh) attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only); if(subd_mesh) attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only); } } void AttributeSet::clear() { attributes.clear(); } /* AttributeRequest */ AttributeRequest::AttributeRequest(ustring name_) { name = name_; std = ATTR_STD_NONE; triangle_type = TypeDesc::TypeFloat; triangle_desc.element = ATTR_ELEMENT_NONE; triangle_desc.offset = 0; triangle_desc.type = NODE_ATTR_FLOAT; curve_type = TypeDesc::TypeFloat; curve_desc.element = ATTR_ELEMENT_NONE; curve_desc.offset = 0; curve_desc.type = NODE_ATTR_FLOAT; subd_type = TypeDesc::TypeFloat; subd_desc.element = ATTR_ELEMENT_NONE; subd_desc.offset = 0; subd_desc.type = NODE_ATTR_FLOAT; } AttributeRequest::AttributeRequest(AttributeStandard std_) { name = ustring(); std = std_; triangle_type = TypeDesc::TypeFloat; triangle_desc.element = ATTR_ELEMENT_NONE; triangle_desc.offset = 0; triangle_desc.type = NODE_ATTR_FLOAT; curve_type = TypeDesc::TypeFloat; curve_desc.element = ATTR_ELEMENT_NONE; curve_desc.offset = 0; curve_desc.type = NODE_ATTR_FLOAT; subd_type = TypeDesc::TypeFloat; subd_desc.element = ATTR_ELEMENT_NONE; subd_desc.offset = 0; subd_desc.type = NODE_ATTR_FLOAT; } /* AttributeRequestSet */ AttributeRequestSet::AttributeRequestSet() { } AttributeRequestSet::~AttributeRequestSet() { } bool AttributeRequestSet::modified(const AttributeRequestSet& other) { if(requests.size() != other.requests.size()) return true; for(size_t i = 0; i < requests.size(); i++) { bool found = false; for(size_t j = 0; j < requests.size() && !found; j++) if(requests[i].name == other.requests[j].name && requests[i].std == other.requests[j].std) { found = true; } if(!found) { return true; } } return false; } void AttributeRequestSet::add(ustring name) { foreach(AttributeRequest& req, requests) if(req.name == name) return; requests.push_back(AttributeRequest(name)); } void AttributeRequestSet::add(AttributeStandard std) { foreach(AttributeRequest& req, requests) if(req.std == std) return; requests.push_back(AttributeRequest(std)); } void AttributeRequestSet::add(AttributeRequestSet& reqs) { foreach(AttributeRequest& req, reqs.requests) { if(req.std == ATTR_STD_NONE) add(req.name); else add(req.std); } } bool AttributeRequestSet::find(ustring name) { foreach(AttributeRequest& req, requests) if(req.name == name) return true; return false; } bool AttributeRequestSet::find(AttributeStandard std) { foreach(AttributeRequest& req, requests) if(req.std == std) return true; return false; } size_t AttributeRequestSet::size() { return requests.size(); } void AttributeRequestSet::clear() { requests.clear(); } CCL_NAMESPACE_END