Remove prefix of filenames that is the same as the folder name. This used to help when #includes were using individual files, but now they are always relative to the cycles root directory and so the prefixes are redundant. For patches and branches, git merge and rebase should be able to detect the renames and move over code to the right file.
471 lines
14 KiB
C++
471 lines
14 KiB
C++
/*
|
|
* Based on code from OpenSubdiv released under this license:
|
|
*
|
|
* Copyright 2013 Pixar
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "Apache License")
|
|
* with the following modification; you may not use this file except in
|
|
* compliance with the Apache License and the following modification to it:
|
|
* Section 6. Trademarks. is deleted and replaced with:
|
|
*
|
|
* 6. Trademarks. This License does not grant permission to use the trade
|
|
* names, trademarks, service marks, or product names of the Licensor
|
|
* and its affiliates, except as required to comply with Section 4(c) of
|
|
* the License and to reproduce the content of the NOTICE file.
|
|
*
|
|
* You may obtain a copy of the Apache License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the Apache License with the above modification is
|
|
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the Apache License for the specific
|
|
* language governing permissions and limitations under the Apache License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "util/color.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
typedef struct PatchHandle {
|
|
int array_index, patch_index, vert_index;
|
|
} PatchHandle;
|
|
|
|
ccl_device_inline int patch_map_resolve_quadrant(float median,
|
|
ccl_private float *u,
|
|
ccl_private float *v)
|
|
{
|
|
int quadrant = -1;
|
|
|
|
if (*u < median) {
|
|
if (*v < median) {
|
|
quadrant = 0;
|
|
}
|
|
else {
|
|
quadrant = 1;
|
|
*v -= median;
|
|
}
|
|
}
|
|
else {
|
|
if (*v < median) {
|
|
quadrant = 3;
|
|
}
|
|
else {
|
|
quadrant = 2;
|
|
*v -= median;
|
|
}
|
|
*u -= median;
|
|
}
|
|
|
|
return quadrant;
|
|
}
|
|
|
|
/* retrieve PatchHandle from patch coords */
|
|
|
|
ccl_device_inline PatchHandle
|
|
patch_map_find_patch(KernelGlobals kg, int object, int patch, float u, float v)
|
|
{
|
|
PatchHandle handle;
|
|
|
|
kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
|
|
|
|
int node = (object_patch_map_offset(kg, object) + patch) / 2;
|
|
float median = 0.5f;
|
|
|
|
for (int depth = 0; depth < 0xff; depth++) {
|
|
float delta = median * 0.5f;
|
|
|
|
int quadrant = patch_map_resolve_quadrant(median, &u, &v);
|
|
kernel_assert(quadrant >= 0);
|
|
|
|
uint child = kernel_tex_fetch(__patches, node + quadrant);
|
|
|
|
/* is the quadrant a hole? */
|
|
if (!(child & PATCH_MAP_NODE_IS_SET)) {
|
|
handle.array_index = -1;
|
|
return handle;
|
|
}
|
|
|
|
uint index = child & PATCH_MAP_NODE_INDEX_MASK;
|
|
|
|
if (child & PATCH_MAP_NODE_IS_LEAF) {
|
|
handle.array_index = kernel_tex_fetch(__patches, index + 0);
|
|
handle.patch_index = kernel_tex_fetch(__patches, index + 1);
|
|
handle.vert_index = kernel_tex_fetch(__patches, index + 2);
|
|
|
|
return handle;
|
|
}
|
|
else {
|
|
node = index;
|
|
}
|
|
|
|
median = delta;
|
|
}
|
|
|
|
/* no leaf found */
|
|
kernel_assert(0);
|
|
|
|
handle.array_index = -1;
|
|
return handle;
|
|
}
|
|
|
|
ccl_device_inline void patch_eval_bspline_weights(float t,
|
|
ccl_private float *point,
|
|
ccl_private float *deriv)
|
|
{
|
|
/* The four uniform cubic B-Spline basis functions evaluated at t */
|
|
float inv_6 = 1.0f / 6.0f;
|
|
|
|
float t2 = t * t;
|
|
float t3 = t * t2;
|
|
|
|
point[0] = inv_6 * (1.0f - 3.0f * (t - t2) - t3);
|
|
point[1] = inv_6 * (4.0f - 6.0f * t2 + 3.0f * t3);
|
|
point[2] = inv_6 * (1.0f + 3.0f * (t + t2 - t3));
|
|
point[3] = inv_6 * t3;
|
|
|
|
/* Derivatives of the above four basis functions at t */
|
|
deriv[0] = -0.5f * t2 + t - 0.5f;
|
|
deriv[1] = 1.5f * t2 - 2.0f * t;
|
|
deriv[2] = -1.5f * t2 + t + 0.5f;
|
|
deriv[3] = 0.5f * t2;
|
|
}
|
|
|
|
ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits,
|
|
ccl_private float *s,
|
|
ccl_private float *t)
|
|
{
|
|
int boundary = ((bits >> 8) & 0xf);
|
|
|
|
if (boundary & 1) {
|
|
t[2] -= t[0];
|
|
t[1] += 2 * t[0];
|
|
t[0] = 0;
|
|
}
|
|
|
|
if (boundary & 2) {
|
|
s[1] -= s[3];
|
|
s[2] += 2 * s[3];
|
|
s[3] = 0;
|
|
}
|
|
|
|
if (boundary & 4) {
|
|
t[1] -= t[3];
|
|
t[2] += 2 * t[3];
|
|
t[3] = 0;
|
|
}
|
|
|
|
if (boundary & 8) {
|
|
s[2] -= s[0];
|
|
s[1] += 2 * s[0];
|
|
s[0] = 0;
|
|
}
|
|
}
|
|
|
|
ccl_device_inline int patch_eval_depth(uint patch_bits)
|
|
{
|
|
return (patch_bits & 0xf);
|
|
}
|
|
|
|
ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
|
|
{
|
|
bool non_quad_root = (patch_bits >> 4) & 0x1;
|
|
int depth = patch_eval_depth(patch_bits);
|
|
|
|
if (non_quad_root) {
|
|
return 1.0f / (float)(1 << (depth - 1));
|
|
}
|
|
else {
|
|
return 1.0f / (float)(1 << depth);
|
|
}
|
|
}
|
|
|
|
ccl_device_inline void patch_eval_normalize_coords(uint patch_bits,
|
|
ccl_private float *u,
|
|
ccl_private float *v)
|
|
{
|
|
float frac = patch_eval_param_fraction(patch_bits);
|
|
|
|
int iu = (patch_bits >> 22) & 0x3ff;
|
|
int iv = (patch_bits >> 12) & 0x3ff;
|
|
|
|
/* top left corner */
|
|
float pu = (float)iu * frac;
|
|
float pv = (float)iv * frac;
|
|
|
|
/* normalize uv coordinates */
|
|
*u = (*u - pu) / frac;
|
|
*v = (*v - pv) / frac;
|
|
}
|
|
|
|
/* retrieve patch control indices */
|
|
|
|
ccl_device_inline int patch_eval_indices(KernelGlobals kg,
|
|
ccl_private const PatchHandle *handle,
|
|
int channel,
|
|
int indices[PATCH_MAX_CONTROL_VERTS])
|
|
{
|
|
int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
|
|
|
|
/* XXX: regular patches only */
|
|
for (int i = 0; i < 16; i++) {
|
|
indices[i] = kernel_tex_fetch(__patches, index_base + i);
|
|
}
|
|
|
|
return 16;
|
|
}
|
|
|
|
/* evaluate patch basis functions */
|
|
|
|
ccl_device_inline void patch_eval_basis(KernelGlobals kg,
|
|
ccl_private const PatchHandle *handle,
|
|
float u,
|
|
float v,
|
|
float weights[PATCH_MAX_CONTROL_VERTS],
|
|
float weights_du[PATCH_MAX_CONTROL_VERTS],
|
|
float weights_dv[PATCH_MAX_CONTROL_VERTS])
|
|
{
|
|
uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
|
|
float d_scale = 1 << patch_eval_depth(patch_bits);
|
|
|
|
bool non_quad_root = (patch_bits >> 4) & 0x1;
|
|
if (non_quad_root) {
|
|
d_scale *= 0.5f;
|
|
}
|
|
|
|
patch_eval_normalize_coords(patch_bits, &u, &v);
|
|
|
|
/* XXX: regular patches only for now. */
|
|
|
|
float s[4], t[4], ds[4], dt[4];
|
|
|
|
patch_eval_bspline_weights(u, s, ds);
|
|
patch_eval_bspline_weights(v, t, dt);
|
|
|
|
patch_eval_adjust_boundary_weights(patch_bits, s, t);
|
|
patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
|
|
|
|
for (int k = 0; k < 4; k++) {
|
|
for (int l = 0; l < 4; l++) {
|
|
weights[4 * k + l] = s[l] * t[k];
|
|
weights_du[4 * k + l] = ds[l] * t[k] * d_scale;
|
|
weights_dv[4 * k + l] = s[l] * dt[k] * d_scale;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* generic function for evaluating indices and weights from patch coords */
|
|
|
|
ccl_device_inline int patch_eval_control_verts(KernelGlobals kg,
|
|
int object,
|
|
int patch,
|
|
float u,
|
|
float v,
|
|
int channel,
|
|
int indices[PATCH_MAX_CONTROL_VERTS],
|
|
float weights[PATCH_MAX_CONTROL_VERTS],
|
|
float weights_du[PATCH_MAX_CONTROL_VERTS],
|
|
float weights_dv[PATCH_MAX_CONTROL_VERTS])
|
|
{
|
|
PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
|
|
kernel_assert(handle.array_index >= 0);
|
|
|
|
int num_control = patch_eval_indices(kg, &handle, channel, indices);
|
|
patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
|
|
|
|
return num_control;
|
|
}
|
|
|
|
/* functions for evaluating attributes on patches */
|
|
|
|
ccl_device float patch_eval_float(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
int offset,
|
|
int patch,
|
|
float u,
|
|
float v,
|
|
int channel,
|
|
ccl_private float *du,
|
|
ccl_private float *dv)
|
|
{
|
|
int indices[PATCH_MAX_CONTROL_VERTS];
|
|
float weights[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
|
|
|
int num_control = patch_eval_control_verts(
|
|
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
|
|
|
|
float val = 0.0f;
|
|
if (du)
|
|
*du = 0.0f;
|
|
if (dv)
|
|
*dv = 0.0f;
|
|
|
|
for (int i = 0; i < num_control; i++) {
|
|
float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
|
|
|
|
val += v * weights[i];
|
|
if (du)
|
|
*du += v * weights_du[i];
|
|
if (dv)
|
|
*dv += v * weights_dv[i];
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
ccl_device float2 patch_eval_float2(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
int offset,
|
|
int patch,
|
|
float u,
|
|
float v,
|
|
int channel,
|
|
ccl_private float2 *du,
|
|
ccl_private float2 *dv)
|
|
{
|
|
int indices[PATCH_MAX_CONTROL_VERTS];
|
|
float weights[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
|
|
|
int num_control = patch_eval_control_verts(
|
|
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
|
|
|
|
float2 val = make_float2(0.0f, 0.0f);
|
|
if (du)
|
|
*du = make_float2(0.0f, 0.0f);
|
|
if (dv)
|
|
*dv = make_float2(0.0f, 0.0f);
|
|
|
|
for (int i = 0; i < num_control; i++) {
|
|
float2 v = kernel_tex_fetch(__attributes_float2, offset + indices[i]);
|
|
|
|
val += v * weights[i];
|
|
if (du)
|
|
*du += v * weights_du[i];
|
|
if (dv)
|
|
*dv += v * weights_dv[i];
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
ccl_device float3 patch_eval_float3(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
int offset,
|
|
int patch,
|
|
float u,
|
|
float v,
|
|
int channel,
|
|
ccl_private float3 *du,
|
|
ccl_private float3 *dv)
|
|
{
|
|
int indices[PATCH_MAX_CONTROL_VERTS];
|
|
float weights[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
|
|
|
int num_control = patch_eval_control_verts(
|
|
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
|
|
|
|
float3 val = make_float3(0.0f, 0.0f, 0.0f);
|
|
if (du)
|
|
*du = make_float3(0.0f, 0.0f, 0.0f);
|
|
if (dv)
|
|
*dv = make_float3(0.0f, 0.0f, 0.0f);
|
|
|
|
for (int i = 0; i < num_control; i++) {
|
|
float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
|
|
|
|
val += v * weights[i];
|
|
if (du)
|
|
*du += v * weights_du[i];
|
|
if (dv)
|
|
*dv += v * weights_dv[i];
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
ccl_device float4 patch_eval_float4(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
int offset,
|
|
int patch,
|
|
float u,
|
|
float v,
|
|
int channel,
|
|
ccl_private float4 *du,
|
|
ccl_private float4 *dv)
|
|
{
|
|
int indices[PATCH_MAX_CONTROL_VERTS];
|
|
float weights[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
|
|
|
int num_control = patch_eval_control_verts(
|
|
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
|
|
|
|
float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
if (du)
|
|
*du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
if (dv)
|
|
*dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
for (int i = 0; i < num_control; i++) {
|
|
float4 v = kernel_tex_fetch(__attributes_float3, offset + indices[i]);
|
|
|
|
val += v * weights[i];
|
|
if (du)
|
|
*du += v * weights_du[i];
|
|
if (dv)
|
|
*dv += v * weights_dv[i];
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
ccl_device float4 patch_eval_uchar4(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
int offset,
|
|
int patch,
|
|
float u,
|
|
float v,
|
|
int channel,
|
|
ccl_private float4 *du,
|
|
ccl_private float4 *dv)
|
|
{
|
|
int indices[PATCH_MAX_CONTROL_VERTS];
|
|
float weights[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
|
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
|
|
|
int num_control = patch_eval_control_verts(
|
|
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
|
|
|
|
float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
if (du)
|
|
*du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
if (dv)
|
|
*dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
for (int i = 0; i < num_control; i++) {
|
|
float4 v = color_srgb_to_linear_v4(
|
|
color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, offset + indices[i])));
|
|
|
|
val += v * weights[i];
|
|
if (du)
|
|
*du += v * weights_du[i];
|
|
if (dv)
|
|
*dv += v * weights_dv[i];
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|