blender/intern/cycles/render/attribute.cpp
2018-07-06 10:17:58 +02:00

709 lines
15 KiB
C++

/*
* 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_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_CURVE_RANDOM:
return "curve_random";
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_TEMPERATURE:
return "temperature";
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)
{
if(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<Attribute>::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:
case ATTR_STD_VOLUME_TEMPERATURE:
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_CURVE_RANDOM:
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE);
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<Attribute>::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::remove(Attribute *attribute)
{
if(attribute->std == ATTR_STD_NONE) {
remove(attribute->name);
}
else {
remove(attribute->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(bool preserve_voxel_data)
{
if(preserve_voxel_data) {
list<Attribute>::iterator it;
for(it = attributes.begin(); it != attributes.end();) {
if(it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) {
it++;
}
else {
attributes.erase(it++);
}
}
}
else {
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);
}
}
void AttributeRequestSet::add_standard(ustring name)
{
if(!name) {
return;
}
AttributeStandard std = Attribute::name_standard(name.c_str());
if(std) {
add(std);
}
else {
add(name);
}
}
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