diff options
Diffstat (limited to 'intern/cycles/subd')
-rw-r--r-- | intern/cycles/subd/CMakeLists.txt | 9 | ||||
-rw-r--r-- | intern/cycles/subd/subd_build.cpp | 669 | ||||
-rw-r--r-- | intern/cycles/subd/subd_build.h | 73 | ||||
-rw-r--r-- | intern/cycles/subd/subd_dice.cpp | 100 | ||||
-rw-r--r-- | intern/cycles/subd/subd_dice.h | 42 | ||||
-rw-r--r-- | intern/cycles/subd/subd_edge.h | 70 | ||||
-rw-r--r-- | intern/cycles/subd/subd_face.h | 109 | ||||
-rw-r--r-- | intern/cycles/subd/subd_mesh.cpp | 493 | ||||
-rw-r--r-- | intern/cycles/subd/subd_mesh.h | 40 | ||||
-rw-r--r-- | intern/cycles/subd/subd_patch.cpp | 163 | ||||
-rw-r--r-- | intern/cycles/subd/subd_patch.h | 40 | ||||
-rw-r--r-- | intern/cycles/subd/subd_ring.cpp | 236 | ||||
-rw-r--r-- | intern/cycles/subd/subd_ring.h | 75 | ||||
-rw-r--r-- | intern/cycles/subd/subd_split.cpp | 31 | ||||
-rw-r--r-- | intern/cycles/subd/subd_split.h | 11 | ||||
-rw-r--r-- | intern/cycles/subd/subd_stencil.cpp | 101 | ||||
-rw-r--r-- | intern/cycles/subd/subd_stencil.h | 65 | ||||
-rw-r--r-- | intern/cycles/subd/subd_vert.h | 121 |
18 files changed, 427 insertions, 2021 deletions
diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt index 838776d60bf..2641f6d9c0c 100644 --- a/intern/cycles/subd/CMakeLists.txt +++ b/intern/cycles/subd/CMakeLists.txt @@ -12,26 +12,17 @@ set(INC_SYS ) set(SRC - subd_build.cpp subd_dice.cpp subd_mesh.cpp subd_patch.cpp - subd_ring.cpp subd_split.cpp - subd_stencil.cpp ) set(SRC_HEADERS - subd_build.h subd_dice.h - subd_edge.h - subd_face.h subd_mesh.h subd_patch.h - subd_ring.h subd_split.h - subd_stencil.h - subd_vert.h ) include_directories(${INC}) diff --git a/intern/cycles/subd/subd_build.cpp b/intern/cycles/subd/subd_build.cpp deleted file mode 100644 index f3c2837c37c..00000000000 --- a/intern/cycles/subd/subd_build.cpp +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com> - * - * Modifications copyright (c) 2011, Blender Foundation. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "subd_build.h" -#include "subd_edge.h" -#include "subd_face.h" -#include "subd_ring.h" -#include "subd_mesh.h" -#include "subd_patch.h" -#include "subd_stencil.h" -#include "subd_vert.h" - -#include "util_algorithm.h" -#include "util_debug.h" -#include "util_math.h" -#include "util_string.h" - -CCL_NAMESPACE_BEGIN - -/* Subd Builder */ - -SubdBuilder *SubdBuilder::create(bool linear) -{ - if(linear) - return new SubdLinearBuilder(); - else - return new SubdAccBuilder(); -} - -/* Gregory ACC Stencil */ - -class GregoryAccStencil { -public: - SubdFaceRing *ring; - StencilMask stencil[20]; - - GregoryAccStencil(SubdFaceRing *ring_) - { - ring = ring_; - - for(int i = 0; i < 20; i++) - stencil[i].resize(ring->num_verts()); - } - - StencilMask& get(int i) - { - assert(i < 20); - return stencil[i]; - } - - float& get(int i, SubdVert *vert) - { - assert(i < 20); - return stencil[i][ring->vert_index(vert)]; - } -}; - -static float pseudoValence(SubdVert *vert) -{ - float valence = (float)vert->valence(); - - if(vert->is_boundary()) { - /* we treat boundary verts as being half a closed mesh. corners are - * special case. n = 4 for corners and n = 2*(n-1) for boundaries. */ - if(valence == 2) return 4; - return (valence - 1)*2; - } - - return valence; -} - -/* Subd ACC Builder */ - -SubdAccBuilder::SubdAccBuilder() -{ -} - -SubdAccBuilder::~SubdAccBuilder() -{ -} - -Patch *SubdAccBuilder::run(SubdFace *face) -{ - SubdFaceRing ring(face, face->edge); - GregoryAccStencil stencil(&ring); - float3 position[20]; - - computeCornerStencil(&ring, &stencil); - computeEdgeStencil(&ring, &stencil); - computeInteriorStencil(&ring, &stencil); - - ring.evaluate_stencils(position, stencil.stencil, 20); - - if(face->num_edges() == 3) { - GregoryTrianglePatch *patch = new GregoryTrianglePatch(); - memcpy(patch->hull, position, sizeof(float3)*20); - return patch; - } - else if(face->num_edges() == 4) { - GregoryQuadPatch *patch = new GregoryQuadPatch(); - memcpy(patch->hull, position, sizeof(float3)*20); - return patch; - } - - assert(0); /* n-gons should have been split already */ - return NULL; -} - -/* Gregory Patch */ - -void SubdAccBuilder::computeCornerStencil(SubdFaceRing *ring, GregoryAccStencil *stencil) -{ - const int cornerIndices[7] = {8, 11, 19, 16, 6, 9, 12}; - int primitiveOffset = ring->is_quad()? 0: 4; - - SubdEdge *firstEdge = ring->firstEdge(); - - /* compute corner control points */ - int v = 0; - - for(SubdFace::EdgeIterator it(firstEdge); !it.isDone(); it.advance(), v++) { - SubdVert *vert = it.current()->from(); - int valence = vert->valence(); - int cid = cornerIndices[primitiveOffset+v]; - - if(vert->is_boundary()) { - /* compute vertex limit position */ - SubdEdge *edge0 = vert->edge; - SubdEdge *edge1 = vert->edge->prev; - - assert(edge0->face == NULL); - assert(edge0->to() != vert); - assert(edge1->face == NULL); - assert(edge1->from() != vert); - - stencil->get(cid, vert) = 2.0f/3.0f; - stencil->get(cid, edge0->to()) = 1.0f/6.0f; - stencil->get(cid, edge1->from()) = 1.0f/6.0f; - - assert(stencil->get(cid).is_normalized()); - } - else { - stencil->get(cid, vert) = 3.0f*valence*valence; - - for(SubdVert::EdgeIterator eit(vert->edge); !eit.isDone(); eit.advance()) { - SubdEdge *edge = eit.current(); - assert(vert->co == edge->from()->co); - - stencil->get(cid, edge->to()) = 12.0f; - - if(SubdFaceRing::is_triangle(edge->face)) { - /* distribute weight to all verts */ - stencil->get(cid, vert) += 1.0f; - stencil->get(cid, edge->to()) += 1.0f; - stencil->get(cid, edge->next->to()) += 1.0f; - } - else - stencil->get(cid, edge->next->to()) = 3.0f; - } - - /* normalize stencil. */ - stencil->get(cid).normalize(); - } - } -} - -void SubdAccBuilder::computeEdgeStencil(SubdFaceRing *ring, GregoryAccStencil *stencil) -{ - const int cornerIndices[7] = {8, 11, 19, 16, 6, 9, 12}; - const int edge1Indices[7] = {9, 13, 18, 14, 7, 10, 13}; - const int edge2Indices[7] = {12, 10, 15, 17, 14, 8, 11}; - int primitiveOffset = ring->is_quad()? 0: 4; - - float tangentScales[14] = { - 0.0f, 0.0f, 0.0f, 0.667791f, 1.0f, - 1.11268f, 1.1284f, 1.10289f, 1.06062f, - 1.01262f, 0.963949f, 0.916926f, 0.872541f, 0.831134f - }; - - SubdEdge *firstEdge = ring->firstEdge(); - - /* compute corner / edge control points */ - int v = 0; - - for(SubdFace::EdgeIterator it(firstEdge); !it.isDone(); it.advance(), v++) { - SubdVert *vert = it.current()->from(); - int valence = vert->valence(); - int cid = cornerIndices[primitiveOffset+v]; - - int i1 = 0, i2 = 0, j = 0; - - for(SubdVert::EdgeIterator eit(vert->edge); !eit.isDone(); eit.advance(), j++) { - SubdEdge *edge = eit.current(); - - /* find index of "our" edge for edge control points */ - if(edge == it.current()) - i1 = j; - if(edge == it.current()->prev->pair) - i2 = j; - } - - if(vert->is_boundary()) { - int num_verts = ring->num_verts(); - StencilMask r0(num_verts); - StencilMask r1(num_verts); - - computeBoundaryTangentStencils(ring, vert, r0, r1); - - int k = valence - 1; - float omega = M_PI_F / k; - - int eid1 = edge1Indices[primitiveOffset + v]; - int eid2 = edge2Indices[primitiveOffset + v]; - - if(it.current()->is_boundary()) { - assert(it.current()->from() == vert); - - stencil->get(eid1, vert) = 2.0f / 3.0f; - stencil->get(eid1, it.current()->to()) = 1.0f / 3.0f; - - assert(stencil->get(eid1).is_normalized()); - - if(valence == 2) { - for(int i = 0; i < num_verts; i++) - stencil->get(eid1)[i] += r0[i] * 0.0001f; - } - } - else { - stencil->get(eid1) = stencil->get(cid); - - /* compute index of it.current() around vert */ - int idx = 0; - - for(SubdVert::EdgeIterator eit(vert->edges()); !eit.isDone(); eit.advance(), idx++) - if(eit.current() == it.current()) - break; - - assert(idx != valence); - - float c = cosf(idx * omega); - float s = sinf(idx * omega); - - for(int i = 0; i < num_verts; i++) - stencil->get(eid1)[i] += (r0[i] * s + r1[i] * c) / 3.0f; - } - - if(it.current()->prev->is_boundary()) { - assert(it.current()->prev->pair->from() == vert); - - stencil->get(eid2, vert) = 2.0f / 3.0f; - stencil->get(eid2, it.current()->prev->pair->to()) = 1.0f / 3.0f; - - assert(stencil->get(eid2).is_normalized()); - - if(valence == 2) { - for(int i = 0; i < num_verts; i++) - stencil->get(eid2)[i] += r0[i] * 0.0001f; - } - } - else { - stencil->get(eid2) = stencil->get(cid); - - /* compute index of it.current() around vert */ - int idx = 0; - - for(SubdVert::EdgeIterator eit(vert->edges()); !eit.isDone(); eit.advance(), idx++) - if(eit.current() == it.current()->prev->pair) - break; - - assert(idx != valence); - - float c = cosf(idx * omega); - float s = sinf(idx * omega); - - for(int i = 0; i < num_verts; i++) - stencil->get(eid2)[i] += (r0[i] * s + r1[i] * c) / 3; - } - } - else { - float costerm = cosf(M_PI_F / valence); - float sqrtterm = sqrtf(4.0f + costerm*costerm); - - /* float tangentScale = 1.0f; */ - float tangentScale = tangentScales[min(valence, 13U)]; - - float alpha = (1.0f + costerm / sqrtterm) / (3.0f * valence) * tangentScale; - float beta = 1.0f / (3.0f * valence * sqrtterm) * tangentScale; - - - int eid1 = edge1Indices[primitiveOffset + v]; - int eid2 = edge2Indices[primitiveOffset + v]; - - stencil->get(eid1) = stencil->get(cid); - stencil->get(eid2) = stencil->get(cid); - - j = 0; - for(SubdVert::EdgeIterator eit(vert->edges()); !eit.isDone(); eit.advance(), j++) { - SubdEdge *edge = eit.current(); - assert(vert->co == edge->from()->co); - - float costerm1_a = cosf(M_PI_F * 2 * (j-i1) / valence); - float costerm1_b = cosf(M_PI_F * (2 * (j-i1)-1) / valence); /* -1 instead of +1 b/c of edge->next->to() */ - - float costerm2_a = cosf(M_PI_F * 2 * (j-i2) / valence); - float costerm2_b = cosf(M_PI_F * (2 * (j-i2)-1) / valence); /* -1 instead of +1 b/c of edge->next->to() */ - - - stencil->get(eid1, edge->to()) += alpha * costerm1_a; - stencil->get(eid2, edge->to()) += alpha * costerm2_a; - - if(SubdFaceRing::is_triangle(edge->face)) { - /* @@ this probably does not provide watertight results!! (1/3 + 1/3 + 1/3 != 1) */ - - /* distribute weight to all verts */ - stencil->get(eid1, vert) += beta * costerm1_b / 3.0f; - stencil->get(eid1, edge->to()) += beta * costerm1_b / 3.0f; - stencil->get(eid1, edge->next->to()) += beta * costerm1_b / 3.0f; - - stencil->get(eid2, vert) += beta * costerm2_b / 3.0f; - stencil->get(eid2, edge->to()) += beta * costerm2_b / 3.0f; - stencil->get(eid2, edge->next->to()) += beta * costerm2_b / 3.0f; - } - else { - stencil->get(eid1, edge->next->to()) += beta * costerm1_b; - stencil->get(eid2, edge->next->to()) += beta * costerm2_b; - } - } - } - } -} - -void SubdAccBuilder::computeInteriorStencil(SubdFaceRing *ring, GregoryAccStencil *stencil) -{ - static int corner1Indices[7] = {8, 11, 19, 16, 6, 9, 12}; - static int corner2Indices[7] = {11, 19, 16, 8, 9, 12, 6}; - static int edge1Indices[7] = {9, 13, 18, 14, 7, 10, 13}; - static int edge2Indices[7] = {10, 15, 17, 12, 8, 11, 14}; - static int interior1Indices[7] = {1, 3, 6, 4, 1, 3, 5}; - static int interior2Indices[7] = {2, 7, 5, 0, 2, 4, 0}; - - int primitiveOffset = ring->is_quad()? 0: 4; - - SubdFace * face = ring->face(); - SubdEdge *firstEdge = ring->firstEdge(); - - /* interior control points */ - int v = 0; - for(SubdFace::EdgeIterator it(firstEdge); !it.isDone(); it.advance(), v++) { - SubdEdge *edge = it.current(); - - if(edge->is_boundary()) { - float valence1 = pseudoValence(edge->from()); - float valence2 = pseudoValence(edge->to()); - - float weights1[4]; - float weights2[4]; - - if(ring->is_quad()) { - weights1[0] = 3 * valence1; - weights1[1] = 6; - weights1[2] = 3; - weights1[3] = 6; - - weights2[0] = 6; - weights2[1] = 3 * valence2; - weights2[2] = 6; - weights2[3] = 3; - } - else { - assert(ring->is_triangle()); - weights1[0] = 3 * valence1 + 1; - weights1[1] = 7; - weights1[2] = 7; - - weights2[0] = 7; - weights2[1] = 3 * valence2 + 1; - weights2[2] = 7; - } - - int idx1 = interior1Indices[primitiveOffset+v]; - int idx2 = interior2Indices[primitiveOffset+v]; - - int i = 0; - for(SubdFace::EdgeIterator it_sub(face->edges(edge)); !it_sub.isDone(); it_sub.advance(), i++) { - SubdVert *vert = it_sub.current()->from(); - stencil->get(idx1, vert) += weights1[i]; - stencil->get(idx2, vert) += weights2[i]; - } - - stencil->get(idx1).normalize(); - stencil->get(idx2).normalize(); - } - else { - SubdVert *e0 = edge->from(); - float costerm0 = cosf(M_2PI_F / pseudoValence(e0)); - - SubdVert *f0 = edge->to(); - float costerm1 = cosf(M_2PI_F / pseudoValence(f0)); - - /* p0 +------+ q0 - * | | - * f0 +======+ e0 <=== current edge - * | | - * p1 +------+ q1 - */ - - SubdVert *q0 = edge->next->to(); - SubdVert *p0 = edge->prev->from(); - - SubdVert *p1 = edge->pair->next->to(); - SubdVert *q1 = edge->pair->prev->from(); - - - StencilMask x(ring->num_verts()); - StencilMask y(ring->num_verts()); - - for(int i = 0; i < ring->num_verts(); i++) { - x[i] = - (costerm1 * stencil->get(corner1Indices[primitiveOffset+v])[i] - - (2*costerm0 + costerm1) * stencil->get(edge1Indices[primitiveOffset+v])[i] + - 2*costerm0 * stencil->get(edge2Indices[primitiveOffset+v])[i]) / 3.0f; - } - - /* y = (2*( midedgeA1 - midedgeB1) + 4*(centroidA - centroidB))/18.0f; */ - y[ring->vert_index(p0)] = 1; - y[ring->vert_index(p1)] = -1; - - /* add centroidA */ - if(ring->is_triangle()) { - y[ring->vert_index(p0)] += 4.0f / 3.0f; - y[ring->vert_index(e0)] += 4.0f / 3.0f; - y[ring->vert_index(f0)] += 4.0f / 3.0f; - } - else { - y[ring->vert_index(p0)] += 1; - y[ring->vert_index(q0)] += 1; - y[ring->vert_index(e0)] += 1; - y[ring->vert_index(f0)] += 1; - } - - /* sub centroidB */ - if(SubdFaceRing::is_triangle(edge->pair->face)) { - y[ring->vert_index(p1)] -= 4.0f / 3.0f; - y[ring->vert_index(e0)] -= 4.0f / 3.0f; - y[ring->vert_index(f0)] -= 4.0f / 3.0f; - - } - else { - y[ring->vert_index(p1)] -= 1; - y[ring->vert_index(q1)] -= 1; - y[ring->vert_index(e0)] -= 1; - y[ring->vert_index(f0)] -= 1; - } - - y /= 18.0f; - - if(ring->is_triangle()) { - x *= 3.0f / 4.0f; - y *= 3.0f / 4.0f; - } - - /* this change makes the triangle boundaries smoother, but distorts the quads next to them */ -#if 0 - if(ring->is_triangle() || SubdFaceRing::is_triangle(edge->pair->face)) { - y *= 4.0f / 3.0f; - } -#endif - - stencil->get(interior1Indices[primitiveOffset+v]) = stencil->get(edge1Indices[primitiveOffset+v]); - stencil->get(interior1Indices[primitiveOffset+v]) += x; - stencil->get(interior1Indices[primitiveOffset+v]) += y; - - for(int i = 0; i < ring->num_verts(); i++) { - x[i] = - (costerm0 * stencil->get(corner2Indices[primitiveOffset+v])[i] - - (2*costerm1 + costerm0) * stencil->get(edge2Indices[primitiveOffset+v])[i] + - 2*costerm1 * stencil->get(edge1Indices[primitiveOffset+v])[i]) / 3.0f; - } - - /* y = (2*( midedgeA2 - midedgeB2) + 4*(centroidA - centroidB))/18.0f; */ - y = 0.0f; - - /* (2*( midedgeA2 - midedgeB2) */ - y[ring->vert_index(q0)] = 1; - y[ring->vert_index(q1)] = -1; - - /* add centroidA */ - if(ring->is_triangle()) { - y[ring->vert_index(p0)] += 4.0f / 3.0f; - y[ring->vert_index(e0)] += 4.0f / 3.0f; - y[ring->vert_index(f0)] += 4.0f / 3.0f; - } - else { - y[ring->vert_index(p0)] += 1; - y[ring->vert_index(q0)] += 1; - y[ring->vert_index(e0)] += 1; - y[ring->vert_index(f0)] += 1; - } - - /* sub centroidB */ - if(SubdFaceRing::is_triangle(edge->pair->face)) { - y[ring->vert_index(p1)] -= 4.0f / 3.0f; - y[ring->vert_index(e0)] -= 4.0f / 3.0f; - y[ring->vert_index(f0)] -= 4.0f / 3.0f; - - } - else { - y[ring->vert_index(p1)] -= 1; - y[ring->vert_index(q1)] -= 1; - y[ring->vert_index(e0)] -= 1; - y[ring->vert_index(f0)] -= 1; - } - - y /= 18.0f; - - if(ring->is_triangle()) { - x *= 3.0f / 4.0f; - y *= 3.0f / 4.0f; - } - - /* this change makes the triangle boundaries smoother, but distorts the quads next to them. */ -#if 0 - if(ring->is_triangle() || SubdFaceRing::is_triangle(edge->pair->face)) - y *= 4.0f / 3.0f; -#endif - - stencil->get(interior2Indices[primitiveOffset+v]) = stencil->get(edge2Indices[primitiveOffset+v]); - stencil->get(interior2Indices[primitiveOffset+v]) += x; - stencil->get(interior2Indices[primitiveOffset+v]) += y; - } - } -} - -void SubdAccBuilder::computeBoundaryTangentStencils(SubdFaceRing *ring, SubdVert *vert, StencilMask & r0, StencilMask & r1) -{ - assert(vert->is_boundary()); - assert(r0.size() == ring->num_verts()); - assert(r1.size() == ring->num_verts()); - - SubdEdge *edge0 = vert->edge; - assert(edge0->face == NULL); - assert(edge0->to() != vert); - - SubdEdge *edgek = vert->edge->prev; - assert(edgek->face == NULL); - assert(edgek->from() != vert); - - int valence = vert->valence(); - - int k = valence - 1; - float omega = M_PI_F / k; - float s = sinf(omega); - float c = cosf(omega); - - float factor = 1.0f / (3 * k + c); - - float gamma = -4 * s * factor; - r0[ring->vert_index(vert)] = gamma; - /* r1[ring->vert_index(vert)] = 0; */ - - float salpha0 = -((1 + 2 * c) * sqrtf(1 + c)) * factor / sqrtf(1 - c); - float calpha0 = 1.0f / 2.0f; - - r0[ring->vert_index(edge0->to())] = salpha0; - r1[ring->vert_index(edge0->to())] = calpha0; - - float salphak = salpha0; - float calphak = -1.0f / 2.0f; - - r0[ring->vert_index(edgek->from())] = salphak; - r1[ring->vert_index(edgek->from())] = calphak; - - int j = 0; - for(SubdVert::EdgeIterator it(vert->edges()); !it.isDone(); it.advance(), j++) { - SubdEdge *edge = it.current(); - - if(j == k) break; - - SubdVert *p = edge->to(); - SubdVert *q = edge->pair->prev->from(); - - float alphaj = 4 * sinf(j * omega) * factor; - float betaj = (sinf(j * omega) + sinf((j + 1) * omega)) * factor; - - if(j != 0) - r0[ring->vert_index(p)] += alphaj; - - if(edge->pair->prev->prev->prev == edge->pair) { - r0[ring->vert_index(vert)] += betaj / 3.0f; - r0[ring->vert_index(edge->pair->from())] += betaj / 3.0f; - r0[ring->vert_index(q)] += betaj / 3.0f; - } - else - r0[ring->vert_index(q)] += betaj; - } - - if(valence == 2) { - /* r0 perpendicular to r1 */ - r0[ring->vert_index(vert)] = -4.0f / 3.0f; - r0[ring->vert_index(edgek->from())] = 1.0f / 2.0f; - r0[ring->vert_index(edge0->to())] = 1.0f / 2.0f; - r0[ring->vert_index(edge0->next->to())] = 1.0f / 3.0f; - } -} - -/* Subd Linear Builder */ - -SubdLinearBuilder::SubdLinearBuilder() -{ -} - -SubdLinearBuilder::~SubdLinearBuilder() -{ -} - -Patch *SubdLinearBuilder::run(SubdFace *face) -{ - Patch *patch; - float3 *hull; - - if(face->num_edges() == 3) { - LinearTrianglePatch *lpatch = new LinearTrianglePatch(); - hull = lpatch->hull; - patch = lpatch; - } - else if(face->num_edges() == 4) { - LinearQuadPatch *lpatch = new LinearQuadPatch(); - hull = lpatch->hull; - patch = lpatch; - } - else { - assert(0); /* n-gons should have been split already */ - return NULL; - } - - int i = 0; - - for(SubdFace::EdgeIterator it(face->edge); !it.isDone(); it.advance()) - hull[i++] = it.current()->from()->co; - - if(face->num_edges() == 4) - swap(hull[2], hull[3]); - - return patch; -} - -CCL_NAMESPACE_END - diff --git a/intern/cycles/subd/subd_build.h b/intern/cycles/subd/subd_build.h deleted file mode 100644 index 8353fb5993a..00000000000 --- a/intern/cycles/subd/subd_build.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 - */ - -#ifndef __SUBD_BUILD_H__ -#define __SUBD_BUILD_H__ - -CCL_NAMESPACE_BEGIN - -class SubdFace; -class SubdFaceRing; -class SubdVert; -class GregoryAccStencil; -class Patch; -class StencilMask; - -/* Builder */ - -class SubdBuilder -{ -public: - virtual ~SubdBuilder() {}; - virtual Patch *run(SubdFace *face) = 0; - static SubdBuilder *create(bool linear); -}; - -/* Approximate Catmull Clark using Loop's approximation */ - -class SubdAccBuilder : public SubdBuilder -{ -public: - SubdAccBuilder(); - ~SubdAccBuilder(); - - Patch *run(SubdFace *face); - -protected: - /* Gregory Patch */ - void computeCornerStencil(SubdFaceRing *ring, GregoryAccStencil *stencil); - void computeEdgeStencil(SubdFaceRing *ring, GregoryAccStencil *stencil); - void computeInteriorStencil(SubdFaceRing *ring, GregoryAccStencil *stencil); - void computeBoundaryTangentStencils(SubdFaceRing *ring, - SubdVert *vert, - StencilMask & r0, StencilMask & r1); -}; - -/* Linear Subdivision */ - -class SubdLinearBuilder : public SubdBuilder -{ -public: - SubdLinearBuilder(); - ~SubdLinearBuilder(); - - Patch *run(SubdFace *face); -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_BUILD_H__ */ - diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index a42a2fc833b..05ff5ca4b65 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -26,22 +26,25 @@ CCL_NAMESPACE_BEGIN /* EdgeDice Base */ -EdgeDice::EdgeDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_) +EdgeDice::EdgeDice(const SubdParams& params_) +: params(params_) { - mesh = mesh_; mesh_P = NULL; mesh_N = NULL; vert_offset = 0; - dicing_rate = dicing_rate_; - shader = shader_; - smooth = smooth_; - camera = NULL; - mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); + params.mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); + + if(params.ptex) { + params.mesh->attributes.add(ATTR_STD_PTEX_UV); + params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID); + } } void EdgeDice::reserve(int num_verts, int num_tris) { + Mesh *mesh = params.mesh; + vert_offset = mesh->verts.size(); tri_offset = mesh->triangles.size(); @@ -60,20 +63,38 @@ int EdgeDice::add_vert(Patch *patch, float2 uv) patch->eval(&P, &dPdu, &dPdv, uv.x, uv.y); N = normalize(cross(dPdu, dPdv)); - assert(vert_offset < mesh->verts.size()); + assert(vert_offset < params.mesh->verts.size()); mesh_P[vert_offset] = P; mesh_N[vert_offset] = N; + if(params.ptex) { + Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV); + params.mesh->attributes.reserve(); + + float3 *ptex_uv = attr_ptex_uv->data_float3(); + ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f); + } + return vert_offset++; } -void EdgeDice::add_triangle(int v0, int v1, int v2) +void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2) { - mesh->add_triangle(v0, v1, v2, shader, smooth); + params.mesh->add_triangle(v0, v1, v2, params.shader, params.smooth); + + if(params.ptex) { + Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID); + params.mesh->attributes.reserve(); + + float *ptex_face_id = attr_ptex_face_id->data_float(); + ptex_face_id[tri_offset] = (float)patch->ptex_face_id(); + } + + tri_offset++; } -void EdgeDice::stitch_triangles(vector<int>& outer, vector<int>& inner) +void EdgeDice::stitch_triangles(Patch *patch, vector<int>& outer, vector<int>& inner) { if(inner.size() == 0 || outer.size() == 0) return; // XXX avoid crashes for Mu or Mv == 1, missing polygons @@ -106,14 +127,14 @@ void EdgeDice::stitch_triangles(vector<int>& outer, vector<int>& inner) v2 = inner[++i]; } - add_triangle(v0, v1, v2); + add_triangle(patch, v0, v1, v2); } } /* QuadDice */ -QuadDice::QuadDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_) -: EdgeDice(mesh_, shader_, smooth_, dicing_rate_) +QuadDice::QuadDice(const SubdParams& params_) +: EdgeDice(params_) { } @@ -121,7 +142,8 @@ void QuadDice::reserve(EdgeFactors& ef, int Mu, int Mv) { /* XXX need to make this also work for edge factor 0 and 1 */ int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1)*(Mv - 1); - EdgeDice::reserve(num_verts, 0); + int num_tris = 0; + EdgeDice::reserve(num_verts, num_tris); } float2 QuadDice::map_uv(SubPatch& sub, float u, float v) @@ -138,8 +160,8 @@ float3 QuadDice::eval_projected(SubPatch& sub, float u, float v) float3 P; sub.patch->eval(&P, NULL, NULL, uv.x, uv.y); - if(camera) - P = transform_perspective(&camera->worldtoraster, P); + if(params.camera) + P = transform_perspective(¶ms.camera->worldtoraster, P); return P; } @@ -222,7 +244,7 @@ float QuadDice::scale_factor(SubPatch& sub, EdgeFactors& ef, int Mu, int Mv) float Apatch = max(A1, max(A2, max(A3, A4)))*4.0f; /* solve for scaling factor */ - float Atri = dicing_rate*dicing_rate*0.5f; + float Atri = params.dicing_rate*params.dicing_rate*0.5f; float Ntris = Apatch/Atri; // XXX does the -sqrt solution matter @@ -270,8 +292,8 @@ void QuadDice::add_grid(SubPatch& sub, int Mu, int Mv, int offset) int i3 = offset + 4 + i + j*(Mu-1); int i4 = offset + 4 + (i-1) + j*(Mu-1); - add_triangle(i1, i2, i3); - add_triangle(i1, i3, i4); + add_triangle(sub.patch, i1, i2, i3); + add_triangle(sub.patch, i1, i3, i4); } } } @@ -288,7 +310,7 @@ void QuadDice::dice(SubPatch& sub, EdgeFactors& ef) Mv = max((int)ceil(S*Mv), 2); // XXX handle 0 & 1? /* reserve space for new verts */ - int offset = mesh->verts.size(); + int offset = params.mesh->verts.size(); reserve(ef, Mu, Mv); /* corners and inner grid */ @@ -299,27 +321,27 @@ void QuadDice::dice(SubPatch& sub, EdgeFactors& ef) vector<int> outer, inner; add_side_u(sub, outer, inner, Mu, Mv, ef.tu0, 0, offset); - stitch_triangles(outer, inner); + stitch_triangles(sub.patch, outer, inner); /* top side */ add_side_u(sub, outer, inner, Mu, Mv, ef.tu1, 1, offset); - stitch_triangles(inner, outer); + stitch_triangles(sub.patch, inner, outer); /* left side */ add_side_v(sub, outer, inner, Mu, Mv, ef.tv0, 0, offset); - stitch_triangles(inner, outer); + stitch_triangles(sub.patch, inner, outer); /* right side */ add_side_v(sub, outer, inner, Mu, Mv, ef.tv1, 1, offset); - stitch_triangles(outer, inner); + stitch_triangles(sub.patch, outer, inner); - assert(vert_offset == mesh->verts.size()); + assert(vert_offset == params.mesh->verts.size()); } /* TriangleDice */ -TriangleDice::TriangleDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_) -: EdgeDice(mesh_, shader_, smooth_, dicing_rate_) +TriangleDice::TriangleDice(const SubdParams& params_) +: EdgeDice(params_) { } @@ -417,9 +439,9 @@ void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M) inner_w.push_back(corner_v); /* stitch together inner/outer with triangles */ - stitch_triangles(outer_u, inner_u); - stitch_triangles(outer_v, inner_v); - stitch_triangles(outer_w, inner_w); + stitch_triangles(sub.patch, outer_u, inner_u); + stitch_triangles(sub.patch, outer_v, inner_v); + stitch_triangles(sub.patch, outer_w, inner_w); outer_u = inner_u; outer_v = inner_v; @@ -429,18 +451,18 @@ void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M) /* fill up last part */ if(m == -1) { /* single triangle */ - add_triangle(outer_w[0], outer_u[0], outer_v[0]); + add_triangle(sub.patch, outer_w[0], outer_u[0], outer_v[0]); } else { /* center vertex + 6 triangles */ int center = add_vert(sub, make_float2(1.0f/3.0f, 1.0f/3.0f)); - add_triangle(outer_w[0], outer_w[1], center); - add_triangle(outer_w[1], outer_w[2], center); - add_triangle(outer_u[0], outer_u[1], center); - add_triangle(outer_u[1], outer_u[2], center); - add_triangle(outer_v[0], outer_v[1], center); - add_triangle(outer_v[1], outer_v[2], center); + add_triangle(sub.patch, outer_w[0], outer_w[1], center); + add_triangle(sub.patch, outer_w[1], outer_w[2], center); + add_triangle(sub.patch, outer_u[0], outer_u[1], center); + add_triangle(sub.patch, outer_u[1], outer_u[2], center); + add_triangle(sub.patch, outer_v[0], outer_v[1], center); + add_triangle(sub.patch, outer_v[1], outer_v[2], center); } } @@ -452,7 +474,7 @@ void TriangleDice::dice(SubPatch& sub, EdgeFactors& ef) reserve(ef, M); add_grid(sub, ef, M); - assert(vert_offset == mesh->verts.size()); + assert(vert_offset == params.mesh->verts.size()); } CCL_NAMESPACE_END diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h index 250de59c6c3..9cf5b0d50b8 100644 --- a/intern/cycles/subd/subd_dice.h +++ b/intern/cycles/subd/subd_dice.h @@ -31,28 +31,50 @@ class Camera; class Mesh; class Patch; +struct SubdParams { + Mesh *mesh; + int shader; + bool smooth; + bool ptex; + + int test_steps; + int split_threshold; + float dicing_rate; + Camera *camera; + + SubdParams(Mesh *mesh_, int shader_, bool smooth_ = true, bool ptex_ = false) + { + mesh = mesh_; + shader = shader_; + smooth = smooth_; + ptex = ptex_; + + test_steps = 3; + split_threshold = 1; + dicing_rate = 0.1f; + camera = NULL; + } + +}; + /* EdgeDice Base */ class EdgeDice { public: - Camera *camera; - Mesh *mesh; + SubdParams params; float3 *mesh_P; float3 *mesh_N; - float dicing_rate; size_t vert_offset; size_t tri_offset; - int shader; - bool smooth; - EdgeDice(Mesh *mesh, int shader, bool smooth, float dicing_rate); + EdgeDice(const SubdParams& params); void reserve(int num_verts, int num_tris); int add_vert(Patch *patch, float2 uv); - void add_triangle(int v0, int v1, int v2); + void add_triangle(Patch *patch, int v0, int v1, int v2); - void stitch_triangles(vector<int>& outer, vector<int>& inner); + void stitch_triangles(Patch *patch, vector<int>& outer, vector<int>& inner); }; /* Quad EdgeDice @@ -86,7 +108,7 @@ public: int tv1; }; - QuadDice(Mesh *mesh, int shader, bool smooth, float dicing_rate); + QuadDice(const SubdParams& params); void reserve(EdgeFactors& ef, int Mu, int Mv); float3 eval_projected(SubPatch& sub, float u, float v); @@ -140,7 +162,7 @@ public: int tw; }; - TriangleDice(Mesh *mesh, int shader, bool smooth, float dicing_rate); + TriangleDice(const SubdParams& params); void reserve(EdgeFactors& ef, int M); diff --git a/intern/cycles/subd/subd_edge.h b/intern/cycles/subd/subd_edge.h deleted file mode 100644 index edf98c8a5a0..00000000000 --- a/intern/cycles/subd/subd_edge.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Original code in the public domain -- castanyo@yahoo.es - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SUBD_EDGE_H__ -#define __SUBD_EDGE_H__ - -#include "subd_mesh.h" - -CCL_NAMESPACE_BEGIN - -/* Subd Half Edge */ - -class SubdEdge -{ -public: - int id; - - SubdEdge *next; - SubdEdge *prev; - SubdEdge *pair; - SubdVert *vert; - SubdFace *face; - - SubdEdge(int id_) - { - id = id_; - next = NULL; - prev = NULL; - pair = NULL; - vert = NULL; - face = NULL; - } - - /* vertex queries */ - SubdVert *from() { return vert; } - SubdVert *to() { return next->vert; } - - /* face queries */ - bool is_boundary() { return !(face && pair->face); } -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_EDGE_H__ */ - diff --git a/intern/cycles/subd/subd_face.h b/intern/cycles/subd/subd_face.h deleted file mode 100644 index 8f8a9ec3f47..00000000000 --- a/intern/cycles/subd/subd_face.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Original code in the public domain -- castanyo@yahoo.es - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SUBD_FACE_H__ -#define __SUBD_FACE_H__ - -#include "subd_edge.h" -#include "subd_mesh.h" - -CCL_NAMESPACE_BEGIN - -/* Subd Face */ - -class SubdFace -{ -public: - int id; - SubdEdge *edge; - - SubdFace(int id_) - { - id = id_; - edge = NULL; - } - - bool contains(SubdEdge *e) - { - for(EdgeIterator it(edges()); !it.isDone(); it.advance()) - if(it.current() == e) - return true; - - return false; - } - - int num_edges() - { - int num = 0; - - for(EdgeIterator it(edges()); !it.isDone(); it.advance()) - num++; - - return num; - } - - bool is_boundary() - { - for(EdgeIterator it(edges()); !it.isDone(); it.advance()) { - SubdEdge *edge = it.current(); - - if(edge->pair->face == NULL) - return true; - } - - return false; - } - - /* iterate over edges in clockwise order */ - class EdgeIterator - { - public: - EdgeIterator(SubdEdge *e) : end(NULL), cur(e) { } - - virtual void advance() - { - if (end == NULL) end = cur; - cur = cur->next; - } - - virtual bool isDone() { return end == cur; } - virtual SubdEdge *current() { return cur; } - - private: - SubdEdge *end; - SubdEdge *cur; - }; - - EdgeIterator edges() { return EdgeIterator(edge); } - EdgeIterator edges(SubdEdge *edge) { return EdgeIterator(edge); } -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_FACE_H__ */ - diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp index becd5b9b5ec..0db20656f39 100644 --- a/intern/cycles/subd/subd_mesh.cpp +++ b/intern/cycles/subd/subd_mesh.cpp @@ -28,282 +28,391 @@ #include <stdio.h> -#include "subd_build.h" -#include "subd_edge.h" -#include "subd_face.h" #include "subd_mesh.h" #include "subd_patch.h" #include "subd_split.h" -#include "subd_vert.h" #include "util_debug.h" #include "util_foreach.h" +#ifdef WITH_OPENSUBDIV + +#include <osd/vertex.h> +#include <osd/mesh.h> +#include <osd/cpuComputeController.h> +#include <osd/cpuVertexBuffer.h> +#include <osd/cpuEvalLimitController.h> +#include <osd/evalLimitContext.h> + CCL_NAMESPACE_BEGIN -SubdMesh::SubdMesh() +/* typedefs */ +typedef OpenSubdiv::OsdVertex OsdVertex; +typedef OpenSubdiv::FarMesh<OsdVertex> OsdFarMesh; +typedef OpenSubdiv::FarMeshFactory<OsdVertex> OsdFarMeshFactory; +typedef OpenSubdiv::HbrCatmarkSubdivision<OsdVertex> OsdHbrCatmarkSubdivision; +typedef OpenSubdiv::HbrFace<OsdVertex> OsdHbrFace; +typedef OpenSubdiv::HbrHalfedge<OsdVertex> OsdHbrHalfEdge; +typedef OpenSubdiv::HbrMesh<OsdVertex> OsdHbrMesh; +typedef OpenSubdiv::HbrVertex<OsdVertex> OsdHbrVertex; +typedef OpenSubdiv::OsdCpuComputeContext OsdCpuComputeContext; +typedef OpenSubdiv::OsdCpuComputeController OsdCpuComputeController; +typedef OpenSubdiv::OsdCpuEvalLimitContext OsdCpuEvalLimitContext; +typedef OpenSubdiv::OsdCpuEvalLimitController OsdCpuEvalLimitController; +typedef OpenSubdiv::OsdCpuVertexBuffer OsdCpuVertexBuffer; +typedef OpenSubdiv::OsdEvalCoords OsdEvalCoords; +typedef OpenSubdiv::OsdVertexBufferDescriptor OsdVertexBufferDescriptor; + +/* OpenSubdiv Patch */ + +class OpenSubdPatch : public Patch { +public: + int face_id; + + OpenSubdPatch(OsdFarMesh *farmesh, OsdCpuVertexBuffer *vbuf_base) + { + face_id = 0; + + /* create buffers for evaluation */ + vbuf_P = OsdCpuVertexBuffer::Create(3, 1); + vbuf_dPdu = OsdCpuVertexBuffer::Create(3, 1); + vbuf_dPdv = OsdCpuVertexBuffer::Create(3, 1); + + P = vbuf_P->BindCpuBuffer(); + dPdu = vbuf_dPdu->BindCpuBuffer(); + dPdv = vbuf_dPdv->BindCpuBuffer(); + + /* setup evaluation context */ + OsdVertexBufferDescriptor in_desc(0, 3, 3), out_desc(0, 3, 3); /* offset, length, stride */ + + evalctx = OsdCpuEvalLimitContext::Create(farmesh, false); + evalctx->GetVertexData().Bind(in_desc, vbuf_base, out_desc, vbuf_P, vbuf_dPdu, vbuf_dPdv); + } + + ~OpenSubdPatch() + { + evalctx->GetVertexData().Unbind(); + + delete evalctx; + delete vbuf_P; + delete vbuf_dPdu; + delete vbuf_dPdv; + } + + void eval(float3 *P_, float3 *dPdu_, float3 *dPdv_, float u, float v) + { + OsdEvalCoords coords; + coords.u = u; + coords.v = v; + coords.face = face_id; + + evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0); + + *P_ = make_float3(P[0], P[1], P[2]); + if (dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]); + if (dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]); + + /* optimize: skip evaluating derivatives when not needed */ + /* todo: swapped derivatives, different winding convention? */ + } + + BoundBox bound() + { + /* not implemented */ + BoundBox bbox = BoundBox::empty; + return bbox; + } + + int ptex_face_id() + { + return face_id; + } + +protected: + OsdCpuEvalLimitController evalctrl; + OsdCpuEvalLimitContext *evalctx; + OsdCpuVertexBuffer *vbuf_P; + OsdCpuVertexBuffer *vbuf_dPdu; + OsdCpuVertexBuffer *vbuf_dPdv; + float *P; + float *dPdu; + float *dPdv; +}; + +/* OpenSubdiv Mesh */ + +OpenSubdMesh::OpenSubdMesh() { + /* create osd mesh */ + static OsdHbrCatmarkSubdivision catmark; + OsdHbrMesh *hbrmesh = new OsdHbrMesh(&catmark); + + /* initialize class */ + num_verts = 0; + num_ptex_faces = 0; + _hbrmesh = (void*)hbrmesh; } -SubdMesh::~SubdMesh() +OpenSubdMesh::~OpenSubdMesh() { - pair<Key, SubdEdge*> em; - - foreach(SubdVert *vertex, verts) - delete vertex; - foreach(em, edge_map) - delete em.second; - foreach(SubdFace *face, faces) - delete face; + OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - verts.clear(); - edges.clear(); - edge_map.clear(); - faces.clear(); + if(hbrmesh) + delete hbrmesh; } -SubdVert *SubdMesh::add_vert(const float3& co) +void OpenSubdMesh::add_vert(const float3& co) { - SubdVert *v = new SubdVert(verts.size()); - v->co = co; - verts.push_back(v); + OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - return v; + OsdVertex v; + positions.push_back(co.x); + positions.push_back(co.y); + positions.push_back(co.z); + hbrmesh->NewVertex(num_verts++, v); } -SubdFace *SubdMesh::add_face(int v0, int v1, int v2) +void OpenSubdMesh::add_face(int v0, int v1, int v2) { int index[3] = {v0, v1, v2}; return add_face(index, 3); } -SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3) +void OpenSubdMesh::add_face(int v0, int v1, int v2, int v3) { int index[4] = {v0, v1, v2, v3}; - return add_face(index, 4); + add_face(index, 4); } -SubdFace *SubdMesh::add_face(int *index, int num) +void OpenSubdMesh::add_face(int *index, int num) { - /* test non-manifold cases */ - if(!can_add_face(index, num)) { - /* we could try to add face in opposite winding instead .. */ - fprintf(stderr, "Warning: non manifold mesh, invalid face '%lu'.\n", (unsigned long)faces.size()); - return NULL; - } - - SubdFace *f = new SubdFace(faces.size()); - - SubdEdge *first_edge = NULL; - SubdEdge *last = NULL; - SubdEdge *current = NULL; - - /* add edges */ - for(int i = 0; i < num-1; i++) { - current = add_edge(index[i], index[i+1]); - assert(current != NULL); - - current->face = f; - - if(last != NULL) { - last->next = current; - current->prev = last; - } - else - first_edge = current; - - last = current; - } + OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - current = add_edge(index[num-1], index[0]); - assert(current != NULL); - - current->face = f; +#ifndef NDEBUG + /* sanity checks */ + for(int j = 0; j < num; j++) { + OsdHbrVertex *origin = hbrmesh->GetVertex(index[j]); + OsdHbrVertex *destination = hbrmesh->GetVertex(index[(j+1)%num]); + OsdHbrHalfEdge *opposite = destination->GetEdge(origin); - last->next = current; - current->prev = last; + if(origin==NULL || destination==NULL) + assert("An edge was specified that connected a nonexistent vertex\n"); - current->next = first_edge; - first_edge->prev = current; + if(origin == destination) + assert("An edge was specified that connected a vertex to itself\n"); - f->edge = first_edge; - faces.push_back(f); + if(opposite && opposite->GetOpposite()) + assert("A non-manifold edge incident to more than 2 faces was found\n"); - return f; -} + if(origin->GetEdge(destination)) + assert("An edge connecting two vertices was specified more than once." + "It's likely that an incident face was flipped\n"); + } +#endif -bool SubdMesh::can_add_face(int *index, int num) -{ - /* manifold check */ - for(int i = 0; i < num-1; i++) - if(!can_add_edge(index[i], index[i+1])) - return false; + OsdHbrFace *face = hbrmesh->NewFace(num, index, 0); + + /* this is required for limit eval patch table? */ + face->SetPtexIndex(num_ptex_faces); - return can_add_edge(index[num-1], index[0]); + if(num == 4) + num_ptex_faces++; + else + num_ptex_faces += num; } -bool SubdMesh::can_add_edge(int i, int j) +bool OpenSubdMesh::finish() { - /* check for degenerate edge */ - if(i == j) - return false; + OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - /* make sure edge has not been added yet. */ - return find_edge(i, j) == NULL; -} + /* finish hbr mesh construction */ + hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly); + hbrmesh->Finish(); -SubdEdge *SubdMesh::add_edge(int i, int j) -{ - SubdEdge *edge; - - /* find pair */ - SubdEdge *pair = find_edge(j, i); - - if(pair != NULL) { - /* create edge with same id */ - edge = new SubdEdge(pair->id + 1); - - /* link edge pairs */ - edge->pair = pair; - pair->pair = edge; - - /* not sure this is necessary? */ - pair->vert->edge = pair; - } - else { - /* create edge */ - edge = new SubdEdge(2*edges.size()); - - /* add only unpaired edges */ - edges.push_back(edge); - } - - /* assign vertex and put into map */ - edge->vert = verts[i]; - edge_map[Key(i, j)] = edge; - - /* face and next are set by add_face */ - - return edge; + return true; } -SubdEdge *SubdMesh::find_edge(int i, int j) +void OpenSubdMesh::tessellate(DiagSplit *split) { - map<Key, SubdEdge*>::const_iterator it = edge_map.find(Key(i, j)); + if (num_ptex_faces == 0) + return; - return (it == edge_map.end())? NULL: it->second; -} + const int level = 3; + const bool requirefvar = false; -bool SubdMesh::link_boundary() -{ - /* link boundary edges once the mesh has been created */ - int num = 0; - - /* create boundary edges */ - int num_edges = edges.size(); + /* convert HRB to FAR mesh */ + OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - for(int e = 0; e < num_edges; e++) { - SubdEdge *edge = edges[e]; + OsdFarMeshFactory meshFactory(hbrmesh, level, true); + OsdFarMesh *farmesh = meshFactory.Create(requirefvar); + int num_hbr_verts = hbrmesh->GetNumVertices(); - if(edge->pair == NULL) { - SubdEdge *pair = new SubdEdge(edge->id + 1); + delete hbrmesh; + hbrmesh = NULL; + _hbrmesh = NULL; - int i = edge->from()->id; - int j = edge->to()->id; + /* refine HBR mesh with vertex coordinates */ + OsdCpuComputeController *compute_controller = new OsdCpuComputeController(); + OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh); - assert(edge_map.find(Key(j, i)) == edge_map.end()); + OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts); + vbuf_base->UpdateData(&positions[0], 0, num_verts); - pair->vert = verts[j]; - edge_map[Key(j, i)] = pair; - - edge->pair = pair; - pair->pair = edge; - - num++; - } - } + compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base); + compute_controller->Synchronize(); - /* link boundary edges */ - for(int e = 0; e < num_edges; e++) { - SubdEdge *edge = edges[e]; + /* split & dice patches */ + OpenSubdPatch patch(farmesh, vbuf_base); - if(edge->pair->face == NULL) - link_boundary_edge(edge->pair); + for(int f = 0; f < num_ptex_faces; f++) { + patch.face_id = f; + split->split_quad(&patch); } - - /* detect boundary intersections */ - int boundaryIntersections = 0; - int num_verts = verts.size(); - for(int v = 0; v < num_verts; v++) { - SubdVert *vertex = verts[v]; + /* clean up */ + delete farmesh; + delete compute_controller; + delete compute_context; + delete vbuf_base; +} - int boundarySubdEdges = 0; - for(SubdVert::EdgeIterator it(vertex->edges()); !it.isDone(); it.advance()) - if(it.current()->is_boundary()) - boundarySubdEdges++; +CCL_NAMESPACE_END - if(boundarySubdEdges > 2) { - assert((boundarySubdEdges & 1) == 0); - boundaryIntersections++; - } +#else /* WITH_OPENSUBDIV */ + +CCL_NAMESPACE_BEGIN + +/* Subd Vertex */ + +class SubdVert +{ +public: + int id; + float3 co; + + SubdVert(int id_) + { + id = id_; + co = make_float3(0.0f, 0.0f, 0.0f); } +}; - if(boundaryIntersections != 0) { - fprintf(stderr, "Invalid mesh, boundary intersections found!\n"); - return false; +/* Subd Face */ + +class SubdFace +{ +public: + int id; + int numverts; + int verts[4]; + + SubdFace(int id_) + { + id = id_; + numverts = 0; } +}; - return true; +/* Subd Mesh */ + +SubdMesh::SubdMesh() +{ } -void SubdMesh::link_boundary_edge(SubdEdge *edge) +SubdMesh::~SubdMesh() { - /* link this boundary edge. */ + foreach(SubdVert *vertex, verts) + delete vertex; + foreach(SubdFace *face, faces) + delete face; - /* make sure next pointer has not been set. */ - assert(edge->face == NULL); - assert(edge->next == NULL); - - SubdEdge *next = edge; + verts.clear(); + faces.clear(); +} - while(next->pair->face != NULL) { - /* get pair prev */ - SubdEdge *e = next->pair->next; +SubdVert *SubdMesh::add_vert(const float3& co) +{ + SubdVert *v = new SubdVert(verts.size()); + v->co = co; + verts.push_back(v); - while(e->next != next->pair) - e = e->next; + return v; +} - next = e; - } +SubdFace *SubdMesh::add_face(int v0, int v1, int v2) +{ + int index[3] = {v0, v1, v2}; + return add_face(index, 3); +} - edge->next = next->pair; - next->pair->prev = edge; - - /* adjust vertex edge, so that it's the boundary edge. (required for is_boundary()) */ - if(edge->vert->edge != edge) - edge->vert->edge = edge; +SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3) +{ + int index[4] = {v0, v1, v2, v3}; + return add_face(index, 4); +} + +SubdFace *SubdMesh::add_face(int *index, int num) +{ + /* skip ngons */ + if(num < 3 || num > 4) + return NULL; + + SubdFace *f = new SubdFace(faces.size()); + + for(int i = 0; i < num; i++) + f->verts[i] = index[i]; + + f->numverts = num; + faces.push_back(f); + + return f; +} + +bool SubdMesh::finish() +{ + return true; } -void SubdMesh::tessellate(DiagSplit *split, bool linear, Mesh *mesh, int shader, bool smooth) +void SubdMesh::tessellate(DiagSplit *split) { - SubdBuilder *builder = SubdBuilder::create(linear); int num_faces = faces.size(); for(int f = 0; f < num_faces; f++) { SubdFace *face = faces[f]; - Patch *patch = builder->run(face); + Patch *patch; + float3 *hull; + + if(face->numverts == 3) { + LinearTrianglePatch *lpatch = new LinearTrianglePatch(); + hull = lpatch->hull; + patch = lpatch; + } + else if(face->numverts == 4) { + LinearQuadPatch *lpatch = new LinearQuadPatch(); + hull = lpatch->hull; + patch = lpatch; + } + else { + assert(0); /* n-gons should have been split already */ + continue; + } + + for(int i = 0; i < face->numverts; i++) + hull[i] = verts[face->verts[i]]->co; + + if(face->numverts == 4) + swap(hull[2], hull[3]); if(patch->is_triangle()) - split->split_triangle(mesh, patch, shader, smooth); + split->split_triangle(patch); else - split->split_quad(mesh, patch, shader, smooth); + split->split_quad(patch); delete patch; } - - delete builder; } CCL_NAMESPACE_END +#endif /* WITH_OPENSUBDIV */ + diff --git a/intern/cycles/subd/subd_mesh.h b/intern/cycles/subd/subd_mesh.h index e4bd5f192ab..f6aefc20318 100644 --- a/intern/cycles/subd/subd_mesh.h +++ b/intern/cycles/subd/subd_mesh.h @@ -35,22 +35,19 @@ CCL_NAMESPACE_BEGIN -class SubdFace; +#ifndef WITH_OPENSUBDIV class SubdVert; -class SubdEdge; +class SubdFace; +#endif class DiagSplit; class Mesh; -/* Subd Mesh, half edge based for dynamic mesh manipulation */ +/* Subd Mesh with simple linear subdivision */ class SubdMesh { public: - vector<SubdVert*> verts; - vector<SubdEdge*> edges; - vector<SubdFace*> faces; - SubdMesh(); ~SubdMesh(); @@ -60,28 +57,19 @@ public: SubdFace *add_face(int v0, int v1, int v2, int v3); SubdFace *add_face(int *index, int num); - bool link_boundary(); - void tessellate(DiagSplit *split, bool linear, - Mesh *mesh, int shader, bool smooth); + bool finish(); + void tessellate(DiagSplit *split); protected: - bool can_add_face(int *index, int num); - bool can_add_edge(int i, int j); - SubdEdge *add_edge(int i, int j); - SubdEdge *find_edge(int i, int j); - void link_boundary_edge(SubdEdge *edge); - - struct Key { - Key() {} - Key(int v0, int v1) : p0(v0), p1(v1) {} - - bool operator<(const Key& k) const - { return (p0 < k.p0 || (p0 == k.p0 && p1 < k.p1)); } - - int p0, p1; - }; +#ifdef WITH_OPENSUBDIV + void *_hbrmesh; + vector<float> positions; + int num_verts, num_ptex_faces; +#else + vector<SubdVert*> verts; + vector<SubdFace*> faces; +#endif - map<Key, SubdEdge *> edge_map; }; CCL_NAMESPACE_END diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp index 4a029277370..fe9fa791813 100644 --- a/intern/cycles/subd/subd_patch.cpp +++ b/intern/cycles/subd/subd_patch.cpp @@ -27,14 +27,6 @@ CCL_NAMESPACE_BEGIN /* De Casteljau Evaluation */ -static float3 decasteljau_quadratic(float t, const float3 cp[3]) -{ - float3 d0 = cp[0] + t*(cp[1] - cp[0]); - float3 d1 = cp[1] + t*(cp[2] - cp[1]); - - return d0 + t*(d1 - d0); -} - static void decasteljau_cubic(float3 *P, float3 *dt, float t, const float3 cp[4]) { float3 d0 = cp[0] + t*(cp[1] - cp[0]); @@ -63,17 +55,6 @@ static void decasteljau_bicubic(float3 *P, float3 *du, float3 *dv, const float3 if(du) decasteljau_cubic(du, NULL, v, utn); } -static float3 decasteljau_tangent(const float3 cp[12], float u, float v) -{ - float3 ucp[3]; - - decasteljau_cubic(ucp+0, NULL, v, cp); - decasteljau_cubic(ucp+1, NULL, v, cp+4); - decasteljau_cubic(ucp+2, NULL, v, cp+8); - - return decasteljau_quadratic(u, ucp); -} - /* Linear Quad Patch */ void LinearQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v) @@ -138,149 +119,5 @@ BoundBox BicubicPatch::bound() return bbox; } -/* Bicubic Patch with Tangent Fields */ - -void BicubicTangentPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v) -{ - decasteljau_bicubic(P, NULL, NULL, hull, u, v); - - if(dPdu) *dPdu = decasteljau_tangent(utan, u, v); - if(dPdv) *dPdv = decasteljau_tangent(vtan, v, u); -} - -BoundBox BicubicTangentPatch::bound() -{ - BoundBox bbox = BoundBox::empty; - - for(int i = 0; i < 16; i++) - bbox.grow(hull[i]); - - return bbox; -} - -/* Gregory Patch */ - -static float no_zero_div(float f) -{ - if(f == 0.0f) return 1.0f; - return f; -} - -void GregoryQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v) -{ - float3 bicubic[16]; - - float U = 1 - u; - float V = 1 - v; - - /* 8 9 10 11 - * 12 0\1 2/3 13 - * 14 4/5 6\7 15 - * 16 17 18 19 - */ - - bicubic[5] = (u*hull[1] + v*hull[0])/no_zero_div(u + v); - bicubic[6] = (U*hull[2] + v*hull[3])/no_zero_div(U + v); - bicubic[9] = (u*hull[5] + V*hull[4])/no_zero_div(u + V); - bicubic[10] = (U*hull[6] + V*hull[7])/no_zero_div(U + V); - - // Map gregory control points to bezier control points. - bicubic[0] = hull[8]; - bicubic[1] = hull[9]; - bicubic[2] = hull[10]; - bicubic[3] = hull[11]; - bicubic[4] = hull[12]; - bicubic[7] = hull[13]; - bicubic[8] = hull[14]; - bicubic[11] = hull[15]; - bicubic[12] = hull[16]; - bicubic[13] = hull[17]; - bicubic[14] = hull[18]; - bicubic[15] = hull[19]; - - decasteljau_bicubic(P, dPdu, dPdv, bicubic, u, v); -} - -BoundBox GregoryQuadPatch::bound() -{ - BoundBox bbox = BoundBox::empty; - - for(int i = 0; i < 20; i++) - bbox.grow(hull[i]); - - return bbox; -} - -void GregoryTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v) -{ - /* 6 - * - * 14 0/1 7 - * - * 13 5/4 3\2 8 - * - * 12 11 10 9 - */ - - float w = 1 - u - v; - float uu = u * u; - float vv = v * v; - float ww = w * w; - float uuu = uu * u; - float vvv = vv * v; - float www = ww * w; - - float U = 1 - u; - float V = 1 - v; - float W = 1 - w; - - float3 C0 = ( v*U * hull[5] + u*V * hull[4] ) / no_zero_div(v*U + u*V); - float3 C1 = ( w*V * hull[3] + v*W * hull[2] ) / no_zero_div(w*V + v*W); - float3 C2 = ( u*W * hull[1] + w*U * hull[0] ) / no_zero_div(u*W + w*U); - - *P = - (hull[12] * www + 3*hull[11] * ww*u + 3*hull[10] * w*uu + hull[ 9]*uuu) * (w + u) + - (hull[ 9] * uuu + 3*hull[ 8] * uu*v + 3*hull[ 7] * u*vv + hull[ 6]*vvv) * (u + v) + - (hull[ 6] * vvv + 3*hull[14] * vv*w + 3*hull[13] * v*ww + hull[12]*www) * (v + w) - - (hull[12] * www*w + hull[ 9] * uuu*u + hull[ 6] * vvv*v) + - 12*(C0 * u*v*ww + C1 * uu*v*w + C2 * u*vv*w); - - if(dPdu || dPdv) { - float3 E1 = (hull[12]*www + 3*hull[11]*ww*u + 3*hull[10]*w*uu + hull[ 9]*uuu); - float3 E2 = (hull[ 9]*uuu + 3*hull[ 8]*uu*v + 3*hull[ 7]*u*vv + hull[ 6]*vvv); - float3 E3 = (hull[ 6]*vvv + 3*hull[14]*vv*w + 3*hull[13]*v*ww + hull[12]*www); - - if(dPdu) { - float3 E1u = 3*( - hull[12]*ww + hull[11]*(ww-2*u*w) + hull[10]*(2*u*w-uu) + hull[ 9]*uu); - float3 E2u = 3*( hull[ 9]*uu + 2*hull[ 8]*u*v + hull[ 7]*vv ); - float3 E3u = 3*( - hull[14]*vv - 2*hull[13]*v*w - hull[12]*ww); - float3 Su = 4*( -hull[12]*www + hull[9]*uuu); - float3 Cu = 12*( C0*(ww*v-2*u*v*w) + C1*(2*u*v*w-uu*v) + C2*vv*(w-u) ); - - *dPdu = E1u*(w+u) + (E2+E2u*(u+v)) + (E3u*(v+w)-E3) - Su + Cu; - } - - if(dPdv) { - float3 E1v = 3*(-hull[12]*ww - 2*hull[11]*w*u - hull[10]*uu ); - float3 E2v = 3*( hull[ 8]*uu + 2*hull[ 7]*u*v + hull[ 6]*vv); - float3 E3v = 3*( hull[ 6]*vv + hull[14]*(2*w*v-vv) + hull[13]*(ww-2*w*v) - hull[12]*ww); - float3 Sv = 4*(-hull[12]*www + hull[ 6]*vvv); - float3 Cv = 12*(C0*(u*ww-2*u*v*w) + C1*uu*(w-v) + C2*(2*u*v*w-u*vv)); - - *dPdv = ((E1v*(w+u)-E1) + (E2+E2v*(u+v)) + E3v*(v+w) - Sv + Cv ); - } - } -} - -BoundBox GregoryTrianglePatch::bound() -{ - BoundBox bbox = BoundBox::empty; - - for(int i = 0; i < 20; i++) - bbox.grow(hull[i]); - - return bbox; -} - CCL_NAMESPACE_END diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h index 7755740ea0c..48f35d78711 100644 --- a/intern/cycles/subd/subd_patch.h +++ b/intern/cycles/subd/subd_patch.h @@ -22,16 +22,13 @@ CCL_NAMESPACE_BEGIN -class Mesh; - -/* Base */ - class Patch { public: virtual ~Patch() {} virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v) = 0; - virtual bool is_triangle() = 0; + virtual bool is_triangle() { return false; } virtual BoundBox bound() = 0; + virtual int ptex_face_id() { return -1; } }; /* Linear Quad Patch */ @@ -67,39 +64,6 @@ public: BoundBox bound(); }; -/* Bicubic Patch with Tangent Fields */ - -class BicubicTangentPatch : public Patch { -public: - float3 hull[16]; - float3 utan[12]; - float3 vtan[12]; - - void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v); - bool is_triangle() { return false; } - BoundBox bound(); -}; - -/* Gregory Patches */ - -class GregoryQuadPatch : public Patch { -public: - float3 hull[20]; - - void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v); - bool is_triangle() { return false; } - BoundBox bound(); -}; - -class GregoryTrianglePatch : public Patch { -public: - float3 hull[20]; - - void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v); - bool is_triangle() { return true; } - BoundBox bound(); -}; - CCL_NAMESPACE_END #endif /* __SUBD_PATCH_H__ */ diff --git a/intern/cycles/subd/subd_ring.cpp b/intern/cycles/subd/subd_ring.cpp deleted file mode 100644 index 66eab02231c..00000000000 --- a/intern/cycles/subd/subd_ring.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com> - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "subd_face.h" -#include "subd_ring.h" -#include "subd_stencil.h" -#include "subd_vert.h" - -#include "util_algorithm.h" -#include "util_debug.h" -#include "util_math.h" - -CCL_NAMESPACE_BEGIN - -/* Utility for sorting verts by index */ - -class vertex_compare -{ -public: - const vector<int>& index; - vertex_compare(const vector<int>& index_) : index(index_) {} - bool operator()(int a, int b) const { return index[a] < index[b]; } -}; - -/* Subd Face Ring */ - -SubdFaceRing::SubdFaceRing(SubdFace *face, SubdEdge *firstEdge) -{ - m_face = face; - m_firstEdge = firstEdge; - m_num_edges = face->num_edges(); - - assert(m_num_edges == 3 || m_num_edges == 4); - - initVerts(); -} - -int SubdFaceRing::num_verts() -{ - return m_verts.size(); -} - -SubdVert *SubdFaceRing::vertexAt(int i) -{ - return m_verts[i]; -} - -int SubdFaceRing::vert_index(SubdVert *vertex) -{ - int count = this->num_verts(); - - for(int i = 0; i < count; i++) - if(m_verts[i] == vertex) - return i; - - assert(0); - return 0; -} - -void SubdFaceRing::evaluate_stencils(float3 *P, StencilMask *mask, int num) -{ - /* first we sort verts by id. this way verts will always be added - * in the same order to ensure the exact same float ops happen for control - * points of other patches, so we get water-tight patches */ - int num_verts = m_verts.size(); - - vector<int> vmap(num_verts); - vector<int> vertid(num_verts); - - for(int v = 0; v < num_verts; v++) { - vmap[v] = v; - vertid[v] = m_verts[v]->id; - } - - sort(vmap.begin(), vmap.end(), vertex_compare(vertid)); - - /* then evaluate the stencils */ - for(int j = 0; j < num; j++) { - float3 p = make_float3(0.0f, 0.0f, 0.0f); - - for(int i = 0; i < num_verts; i++) { - int idx = vmap[i]; - p += m_verts[idx]->co * mask[j][idx]; - } - - P[j] = p; - } -} - -bool SubdFaceRing::is_triangle() -{ - return m_num_edges == 3; -} - -bool SubdFaceRing::is_quad() -{ - return m_num_edges == 4; -} - -int SubdFaceRing::num_edges() -{ - return m_num_edges; -} - -bool SubdFaceRing::is_regular(SubdFace *face) -{ - if(!is_quad(face)) - return false; - - for(SubdFace::EdgeIterator it(face->edges()); !it.isDone(); it.advance()) { - SubdEdge *edge = it.current(); - - /* regular faces don't have boundary edges */ - if(edge->is_boundary()) - return false; - - /* regular faces only have ordinary verts */ - if(edge->vert->valence() != 4) - return false; - - /* regular faces are only adjacent to quads */ - for(SubdVert::EdgeIterator eit(edge); !eit.isDone(); eit.advance()) - if(eit.current()->face == NULL || eit.current()->face->num_edges() != 4) - return false; - } - - return true; -} - -bool SubdFaceRing::is_triangle(SubdFace *face) -{ - return face->num_edges() == 3; -} -bool SubdFaceRing::is_quad(SubdFace *face) -{ - return face->num_edges() == 4; -} - -bool SubdFaceRing::is_boundary(SubdFace *face) -{ - /* note that face->is_boundary() returns a different result. That function - * returns true when any of the *edges* are on the boundary. however, this - * function returns true if any of the face *verts* are on the boundary. */ - - for(SubdFace::EdgeIterator it(face->edges()); !it.isDone(); it.advance()) { - SubdEdge *edge = it.current(); - - if(edge->vert->is_boundary()) - return true; - } - - return false; -} - -void SubdFaceRing::initVerts() -{ - m_verts.reserve(16); - - /* add face verts */ - for(SubdFace::EdgeIterator it(m_firstEdge); !it.isDone(); it.advance()) { - SubdEdge *edge = it.current(); - m_verts.push_back(edge->from()); - } - - // @@ Add support for non manifold surfaces! - // The fix: - // - not all colocals should point to the same edge. - // - multiple colocals could belong to different boundaries, make sure they point to the right one. - - // @@ When the face neighborhood wraps that could result in overlapping stencils. - - // Add surronding verts. - for(SubdFace::EdgeIterator it(m_firstEdge); !it.isDone(); it.advance()) { - SubdEdge *firstEdge = it.current(); - - int i = 0; - - /* traverse edges around vertex */ - for(SubdVert::ReverseEdgeIterator eit(firstEdge); !eit.isDone(); eit.advance(), i++) { - SubdEdge *edge = eit.current(); - - assert(edge->from()->co == firstEdge->from()->co); - - add_vert(edge->to()); - - if(edge->face != NULL) - add_vert(edge->next->to()); - } - - assert(i == firstEdge->from()->valence()); - } -} - - -void SubdFaceRing::add_vert(SubdVert *vertex) -{ - /* avoid having duplicate verts */ - if(!has_vert(vertex)) - m_verts.push_back(vertex); -} - -bool SubdFaceRing::has_vert(SubdVert *vertex) -{ - int num_verts = m_verts.size(); - - for(int i = 0; i < num_verts; i++) - if(m_verts[i]->co == vertex->co) - return true; - - return false; -} - -CCL_NAMESPACE_END - diff --git a/intern/cycles/subd/subd_ring.h b/intern/cycles/subd/subd_ring.h deleted file mode 100644 index f25342233b0..00000000000 --- a/intern/cycles/subd/subd_ring.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com> - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef __SUBD_FACE_RING_H__ -#define __SUBD_FACE_RING_H__ - -CCL_NAMESPACE_BEGIN - -class StencilMask; -class SubdVert; -class SubdEdge; -class SubdFace; - -class SubdFaceRing -{ -public: - SubdFaceRing(SubdFace *face, SubdEdge *edge); - - SubdFace *face() { return m_face; } - SubdEdge *firstEdge() { return m_firstEdge; } - - int num_verts(); - SubdVert *vertexAt(int i); - int vert_index(SubdVert *vertex); - - void evaluate_stencils(float3 *P, StencilMask *mask, int num); - - bool is_triangle(); - bool is_quad(); - int num_edges(); - - static bool is_regular(SubdFace *face); - static bool is_triangle(SubdFace *face); - static bool is_quad(SubdFace *face); - static bool is_boundary(SubdFace *face); - -protected: - void initVerts(); - void add_vert(SubdVert *vertex); - bool has_vert(SubdVert *vertex); - -protected: - SubdFace *m_face; - SubdEdge *m_firstEdge; - - int m_num_edges; - vector<SubdVert*> m_verts; -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_FACE_RING_H__ */ - diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp index 6c1486cecca..417ecfffd49 100644 --- a/intern/cycles/subd/subd_split.cpp +++ b/intern/cycles/subd/subd_split.cpp @@ -29,12 +29,9 @@ CCL_NAMESPACE_BEGIN /* DiagSplit */ -DiagSplit::DiagSplit() +DiagSplit::DiagSplit(const SubdParams& params_) +: params(params_) { - test_steps = 3; - split_threshold = 1; - dicing_rate = 0.1f; - camera = NULL; } void DiagSplit::dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef) @@ -54,8 +51,8 @@ float3 DiagSplit::project(Patch *patch, float2 uv) float3 P; patch->eval(&P, NULL, NULL, uv.x, uv.y); - if(camera) - P = transform_perspective(&camera->worldtoraster, P); + if(params.camera) + P = transform_perspective(¶ms.camera->worldtoraster, P); return P; } @@ -66,8 +63,8 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend) float Lsum = 0.0f; float Lmax = 0.0f; - for(int i = 0; i < test_steps; i++) { - float t = i/(float)(test_steps-1); + for(int i = 0; i < params.test_steps; i++) { + float t = i/(float)(params.test_steps-1); float3 P = project(patch, Pstart + t*(Pend - Pstart)); @@ -80,10 +77,10 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend) Plast = P; } - int tmin = (int)ceil(Lsum/dicing_rate); - int tmax = (int)ceil((test_steps-1)*Lmax/dicing_rate); // XXX paper says N instead of N-1, seems wrong? + int tmin = (int)ceil(Lsum/params.dicing_rate); + int tmax = (int)ceil((params.test_steps-1)*Lmax/params.dicing_rate); // XXX paper says N instead of N-1, seems wrong? - if(tmax - tmin > split_threshold) + if(tmax - tmin > params.split_threshold) return DSPLIT_NON_UNIFORM; return tmax; @@ -244,7 +241,7 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de dispatch(sub, ef); } -void DiagSplit::split_triangle(Mesh *mesh, Patch *patch, int shader, bool smooth) +void DiagSplit::split_triangle(Patch *patch) { TriangleDice::SubPatch sub_split; TriangleDice::EdgeFactors ef_split; @@ -260,8 +257,7 @@ void DiagSplit::split_triangle(Mesh *mesh, Patch *patch, int shader, bool smooth split(sub_split, ef_split); - TriangleDice dice(mesh, shader, smooth, dicing_rate); - dice.camera = camera; + TriangleDice dice(params); for(size_t i = 0; i < subpatches_triangle.size(); i++) { TriangleDice::SubPatch& sub = subpatches_triangle[i]; @@ -282,7 +278,7 @@ void DiagSplit::split_triangle(Mesh *mesh, Patch *patch, int shader, bool smooth edgefactors_triangle.clear(); } -void DiagSplit::split_quad(Mesh *mesh, Patch *patch, int shader, bool smooth) +void DiagSplit::split_quad(Patch *patch) { QuadDice::SubPatch sub_split; QuadDice::EdgeFactors ef_split; @@ -300,8 +296,7 @@ void DiagSplit::split_quad(Mesh *mesh, Patch *patch, int shader, bool smooth) split(sub_split, ef_split); - QuadDice dice(mesh, shader, smooth, dicing_rate); - dice.camera = camera; + QuadDice dice(params); for(size_t i = 0; i < subpatches_quad.size(); i++) { QuadDice::SubPatch& sub = subpatches_quad[i]; diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h index 9dd10f8af8f..3f9a2721977 100644 --- a/intern/cycles/subd/subd_split.h +++ b/intern/cycles/subd/subd_split.h @@ -41,12 +41,9 @@ public: vector<TriangleDice::SubPatch> subpatches_triangle; vector<TriangleDice::EdgeFactors> edgefactors_triangle; - int test_steps; - int split_threshold; - float dicing_rate; - Camera *camera; + SubdParams params; - DiagSplit(); + DiagSplit(const SubdParams& params); float3 project(Patch *patch, float2 uv); int T(Patch *patch, float2 Pstart, float2 Pend); @@ -59,8 +56,8 @@ public: void dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef); void split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth=0); - void split_triangle(Mesh *mesh, Patch *patch, int shader, bool smooth); - void split_quad(Mesh *mesh, Patch *patch, int shader, bool smooth); + void split_triangle(Patch *patch); + void split_quad(Patch *patch); }; CCL_NAMESPACE_END diff --git a/intern/cycles/subd/subd_stencil.cpp b/intern/cycles/subd/subd_stencil.cpp deleted file mode 100644 index 5f76a942a59..00000000000 --- a/intern/cycles/subd/subd_stencil.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 "subd_stencil.h" - -#include "util_debug.h" -#include "util_math.h" - -CCL_NAMESPACE_BEGIN - -StencilMask::StencilMask() -{ -} - -StencilMask::StencilMask(int size) -{ - /* initialize weights to zero. */ - weights.resize(size, 0.0f); -} - -void StencilMask::resize(int size) -{ - weights.resize(size, 0.0f); -} - -StencilMask& StencilMask::operator=(float value) -{ - const int size = weights.size(); - for(int i = 0; i < size; i++) - weights[i] = value; - - return *this; -} - -void StencilMask::operator+=(const StencilMask& mask) -{ - assert(mask.size() == size()); - - const int size = weights.size(); - for(int i = 0; i < size; i++) - weights[i] += mask.weights[i]; -} - -void StencilMask::operator-=(const StencilMask& mask) -{ - assert(mask.size() == size()); - - const int size = weights.size(); - for(int i = 0; i < size; i++) - weights[i] -= mask.weights[i]; -} - -void StencilMask::operator*=(float scale) -{ - const int size = weights.size(); - - for(int i = 0; i < size; i++) - weights[i] *= scale; -} - -void StencilMask::operator/=(float scale) -{ - *this *= 1.0f/scale; -} - -float StencilMask::sum() const -{ - float total = 0.0f; - const int size = weights.size(); - - for(int i = 0; i < size; i++) - total += weights[i]; - - return total; -} - -bool StencilMask::is_normalized() const -{ - return fabsf(sum() - 1.0f) < 0.0001f; -} - -void StencilMask::normalize() -{ - *this /= sum(); -} - -CCL_NAMESPACE_END - diff --git a/intern/cycles/subd/subd_stencil.h b/intern/cycles/subd/subd_stencil.h deleted file mode 100644 index e11d8f37cd3..00000000000 --- a/intern/cycles/subd/subd_stencil.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com> - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef __SUBD_STENCIL__ -#define __SUBD_STENCIL__ - -#include "util_types.h" -#include "util_vector.h" - -CCL_NAMESPACE_BEGIN - -class StencilMask -{ -public: - StencilMask(); - StencilMask(int size); - - void resize(int size); - - StencilMask& operator=(float value); - - void operator+=(const StencilMask& mask); - void operator-=(const StencilMask& mask); - void operator*=(float scale); - void operator/=(float scale); - - int size() const { return weights.size(); } - - float operator[](int i) const { return weights[i]; } - float& operator[](int i) { return weights[i]; } - - float sum() const; - bool is_normalized() const; - void normalize(); - -private: - vector<float> weights; -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_STENCIL__ */ - diff --git a/intern/cycles/subd/subd_vert.h b/intern/cycles/subd/subd_vert.h deleted file mode 100644 index 638019547ae..00000000000 --- a/intern/cycles/subd/subd_vert.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Original code in the public domain -- castanyo@yahoo.es - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SUBD_VERTEX_H__ -#define __SUBD_VERTEX_H__ - -#include "subd_edge.h" -#include "subd_mesh.h" - -CCL_NAMESPACE_BEGIN - -/* Subd Vertex */ - -class SubdVert -{ -public: - int id; - float3 co; - - SubdEdge *edge; - SubdVert *next; - SubdVert *prev; - - SubdVert(int id_) - { - id = id_; - edge = NULL; - co = make_float3(0.0f, 0.0f, 0.0f); - - next = this; - prev = this; - } - - /* valence */ - int valence() - { - int num = 0; - - for(EdgeIterator it(edges()); !it.isDone(); it.advance()) - num++; - - return num; - } - - /* edge queries */ - bool is_boundary() { return (edge && !edge->face); } - - /* iterator over edges in counterclockwise order */ - class EdgeIterator - { - public: - EdgeIterator(SubdEdge *e) : end(NULL), cur(e) { } - - virtual void advance() - { - if(end == NULL) end = cur; - cur = cur->pair->next; - //cur = cur->prev->pair; - } - - virtual bool isDone() { return end == cur; } - virtual SubdEdge *current() { return cur; } - - private: - SubdEdge *end; - SubdEdge *cur; - }; - - /* iterator over edges in clockwise order */ - class ReverseEdgeIterator - { - public: - ReverseEdgeIterator(SubdEdge *e) : end(NULL), cur(e) { } - - virtual void advance() - { - if(end == NULL) end = cur; - cur = cur->prev->pair; - } - - virtual bool isDone() { return end == cur; } - virtual SubdEdge *current() { return cur; } - - private: - SubdEdge *end; - SubdEdge *cur; - }; - - EdgeIterator edges() { return EdgeIterator(edge); } - EdgeIterator edges(SubdEdge *edge) { return EdgeIterator(edge); } -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_VERTEX_H__ */ - |