diff options
Diffstat (limited to 'intern')
93 files changed, 1640 insertions, 2568 deletions
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index c45e66cd77b..b7aff03a710 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -29,7 +29,6 @@ add_subdirectory(ghost) add_subdirectory(guardedalloc) add_subdirectory(memutil) add_subdirectory(opencolorio) -add_subdirectory(opennl) add_subdirectory(mikktspace) add_subdirectory(raskter) @@ -81,6 +80,10 @@ if(WITH_COMPOSITOR) add_subdirectory(opencl) endif() +if(WITH_OPENNL) + add_subdirectory(opennl) +endif() + # only windows needs utf16 converter if(WIN32) add_subdirectory(utfconv) diff --git a/intern/audaspace/intern/AUD_JOSResampleReader.cpp b/intern/audaspace/intern/AUD_JOSResampleReader.cpp index 87577da95cc..0448c75d777 100644 --- a/intern/audaspace/intern/AUD_JOSResampleReader.cpp +++ b/intern/audaspace/intern/AUD_JOSResampleReader.cpp @@ -36,6 +36,7 @@ /* MSVC does not have lrint */ #ifdef _MSC_VER +#if _MSC_VER < 1800 #ifdef _M_X64 #include <emmintrin.h> static inline int lrint(double d) @@ -56,6 +57,7 @@ static inline int lrint(double d) } #endif #endif +#endif // UNUSED // #define CC m_channels + channel diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 6821e93ad87..fc193d99a57 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -17,9 +17,11 @@ if(WIN32 AND MSVC) if(CMAKE_CL_64) set(CYCLES_SSE2_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") set(CYCLES_SSE3_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") + set(CYCLES_SSE41_KERNEL_FLAGS "/fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") else() set(CYCLES_SSE2_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") set(CYCLES_SSE3_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") + set(CYCLES_SSE41_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") @@ -29,10 +31,12 @@ if(WIN32 AND MSVC) elseif(CMAKE_COMPILER_IS_GNUCC) set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2 -mfpmath=sse") set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse") + set(CYCLES_SSE41_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mfpmath=sse") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math") elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2") set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3") + set(CYCLES_SSE41_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math") endif() @@ -58,6 +62,14 @@ if(WITH_CYCLES_NETWORK) add_definitions(-DWITH_NETWORK) endif() +if(WITH_CYCLES_PTEX) + add_definitions(-DWITH_PTEX) +endif() + +if(WITH_CYCLES_OPENSUBDIV) + add_definitions(-DWITH_OPENSUBDIV) +endif() + if(WITH_CYCLES_OSL) add_definitions(-DWITH_OSL) add_definitions(-DOSL_STATIC_LIBRARY) diff --git a/intern/cycles/SConscript b/intern/cycles/SConscript index e61018bc3dd..eeb60f37f92 100644 --- a/intern/cycles/SConscript +++ b/intern/cycles/SConscript @@ -37,6 +37,7 @@ sources = cycles.Glob('bvh/*.cpp') + cycles.Glob('device/*.cpp') + cycles.Glob(' sources.remove(path.join('util', 'util_view.cpp')) sources.remove(path.join('kernel', 'kernel_sse2.cpp')) sources.remove(path.join('kernel', 'kernel_sse3.cpp')) +sources.remove(path.join('kernel', 'kernel_sse41.cpp')) incs = [] defs = [] @@ -77,21 +78,30 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', ' if env['WITH_BF_RAYOPTIMIZATION']: sse2_cxxflags = Split(env['CXXFLAGS']) sse3_cxxflags = Split(env['CXXFLAGS']) + sse41_cxxflags = Split(env['CXXFLAGS']) if env['OURPLATFORM'] == 'win32-vc': # there is no /arch:SSE3, but intrinsics are available anyway sse2_cxxflags.append('/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) sse3_cxxflags.append('/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) + sse41_cxxflags.append('/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) elif env['OURPLATFORM'] == 'win64-vc': sse2_cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) sse3_cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) + sse41_cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) else: sse2_cxxflags.append('-ffast-math -msse -msse2 -mfpmath=sse'.split()) sse3_cxxflags.append('-ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse'.split()) + sse41_cxxflags.append('-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mfpmath=sse'.split()) defs.append('WITH_OPTIMIZED_KERNEL') optim_defs = defs[:] + # Disabled sse4+ patchs for now + #cycles_sse41 = cycles.Clone() + #sse41_sources = [path.join('kernel', 'kernel_sse41.cpp')] + #cycles_sse41.BlenderLib('bf_intern_cycles_sse41', sse41_sources, incs, optim_defs, libtype=['intern'], priority=[10], cxx_compileflags=sse41_cxxflags) + cycles_sse3 = cycles.Clone() sse3_sources = [path.join('kernel', 'kernel_sse3.cpp')] cycles_sse3.BlenderLib('bf_intern_cycles_sse3', sse3_sources, incs, optim_defs, libtype=['intern'], priority=[10], cxx_compileflags=sse3_cxxflags) diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index a2142d77a9e..8a81ddde1e1 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -30,6 +30,10 @@ set(LIBRARIES ${TIFF_LIBRARY} ) +if(UNIX) + list(APPEND LIBRARIES dl) +endif() + if(WIN32) list(APPEND LIBRARIES ${PTHREADS_LIBRARIES}) endif() @@ -41,7 +45,7 @@ if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) endif() if(WITH_CYCLES_OSL) - list(APPEND LIBRARIES cycles_kernel_osl ${OSL_LIBRARIES}) + list(APPEND LIBRARIES cycles_kernel_osl ${OSL_LIBRARIES} ${LLVM_LIBRARY}) endif() include_directories(${INC}) diff --git a/intern/cycles/app/cycles_server.cpp b/intern/cycles/app/cycles_server.cpp index e80fc0cb95f..f4cacb2d001 100644 --- a/intern/cycles/app/cycles_server.cpp +++ b/intern/cycles/app/cycles_server.cpp @@ -35,6 +35,7 @@ int main(int argc, const char **argv) string devicelist = ""; string devicename = "cpu"; bool list = false; + int threads = 0; vector<DeviceType>& types = Device::available_types(); @@ -51,6 +52,7 @@ int main(int argc, const char **argv) ap.options ("Usage: cycles_server [options]", "--device %s", &devicename, ("Devices to use: " + devicelist).c_str(), "--list-devices", &list, "List information about all available devices", + "--threads %d", &threads, "Number of threads to use for CPU device", NULL); if(ap.parse(argc, argv) < 0) { @@ -84,11 +86,11 @@ int main(int argc, const char **argv) } } - TaskScheduler::init(); + TaskScheduler::init(threads); while(1) { Stats stats; - Device *device = Device::create(device_info, stats); + Device *device = Device::create(device_info, stats, true); printf("Cycles Server with device: %s\n", device->info.description.c_str()); device->server_run(); delete device; diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 55a2a30b9a8..df187f046e5 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -703,15 +703,14 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) } /* finalize subd mesh */ - sdmesh.link_boundary(); - - /* subdivide */ - DiagSplit dsplit; - //dsplit.camera = state.scene->camera; - //dsplit.dicing_rate = 5.0f; - dsplit.dicing_rate = state.dicing_rate; - xml_read_float(&dsplit.dicing_rate, node, "dicing_rate"); - sdmesh.tessellate(&dsplit, false, mesh, shader, smooth); + sdmesh.finish(); + + /* parameters */ + SubdParams sdparams(mesh, shader, smooth); + xml_read_float(&sdparams.dicing_rate, node, "dicing_rate"); + + DiagSplit dsplit(sdparams);; + sdmesh.tessellate(&dsplit); } else { /* create vertices */ @@ -789,12 +788,11 @@ static void xml_read_patch(const XMLReadState& state, pugi::xml_node node) mesh->used_shaders.push_back(state.shader); /* split */ - DiagSplit dsplit; - //dsplit.camera = state.scene->camera; - //dsplit.dicing_rate = 5.0f; - dsplit.dicing_rate = state.dicing_rate; - xml_read_float(&dsplit.dicing_rate, node, "dicing_rate"); - dsplit.split_quad(mesh, patch, state.shader, state.smooth); + SubdParams sdparams(mesh, state.shader, state.smooth); + xml_read_float(&sdparams.dicing_rate, node, "dicing_rate"); + + DiagSplit dsplit(sdparams); + dsplit.split_quad(patch); delete patch; diff --git a/intern/cycles/blender/CCL_api.h b/intern/cycles/blender/CCL_api.h index 29d8ed0d98e..6532315cf39 100644 --- a/intern/cycles/blender/CCL_api.h +++ b/intern/cycles/blender/CCL_api.h @@ -30,7 +30,7 @@ typedef struct CCLDeviceInfo { int value; } CCLDeviceInfo; -CCLDeviceInfo *CCL_compute_device_list(int opencl); +CCLDeviceInfo *CCL_compute_device_list(int device_type); /* create python module _cycles used by addon */ diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 3f15e232de7..66dc5e78e5a 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -88,3 +88,7 @@ def available_devices(): def with_osl(): import _cycles return _cycles.with_osl + +def with_network(): + import _cycles + return _cycles.with_network diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index ac15acee0c5..f5c052e7f0c 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -25,9 +25,15 @@ from bpy.props import (BoolProperty, # enums +import _cycles + enum_devices = ( - ('CPU', "CPU", "Use CPU for rendering"), - ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in user preferences")) + ('CPU', "CPU", "Use CPU for rendering"), + ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in user preferences"), + ) + +if _cycles.with_network: + enum_devices += (('NETWORK', "Networked Device", "Use networked device for rendering"),) enum_feature_set = ( ('SUPPORTED', "Supported", "Only use finished and supported features"), @@ -621,6 +627,7 @@ class CyclesVisibilitySettings(bpy.types.PropertyGroup): @classmethod def unregister(cls): del bpy.types.Object.cycles_visibility + del bpy.types.World.cycles_visibility class CyclesMeshSettings(bpy.types.PropertyGroup): diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index cbf26fb8d0a..05d3c15d076 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -311,31 +311,6 @@ class CyclesRender_PT_opengl(CyclesButtonsPanel, Panel): col.prop(rd, "alpha_mode", text="") -class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): - bl_label = "Layer List" - bl_context = "render_layer" - bl_options = {'HIDE_HEADER'} - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render - rl = rd.layers.active - - row = layout.row() - row.template_list("RENDERLAYER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=1) - - col = row.column(align=True) - col.operator("scene.render_layer_add", icon='ZOOMIN', text="") - col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="") - - row = layout.row() - if rl: - row.prop(rl, "name") - row.prop(rd, "use_single_layer", text="", icon_only=True) - - class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel): bl_label = "Layer" bl_context = "render_layer" @@ -1275,9 +1250,7 @@ def draw_device(self, context): layout.prop(cscene, "feature_set") device_type = context.user_preferences.system.compute_device_type - if device_type == 'CUDA': - layout.prop(cscene, "device") - elif device_type == 'OPENCL': + if device_type in {'CUDA', 'OPENCL', 'NETWORK'}: layout.prop(cscene, "device") if engine.with_osl() and (cscene.device == 'CPU' or device_type == 'NONE'): @@ -1306,6 +1279,7 @@ def get_panels(): types.RENDER_PT_encoding, types.RENDER_PT_dimensions, types.RENDER_PT_stamp, + types.RENDERLAYER_PT_layers, types.SCENE_PT_scene, types.SCENE_PT_color_management, types.SCENE_PT_custom_props, diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index b780877a158..da4acf16a4d 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -400,6 +400,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, float3 RotC for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + if(CData->curve_length[curve] == 0.0f) + continue; float3 xbasis; float3 v1; @@ -460,6 +462,8 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + if(CData->curve_length[curve] == 0.0f) + continue; float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]); if(len_squared(firstxbasis)!= 0.0f) @@ -593,7 +597,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { - if(CData->curve_keynum[curve] <= 1) + if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; size_t num_curve_keys = 0; @@ -644,7 +648,7 @@ static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveDat continue; for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - if(CData->curve_keynum[curve] <= 1) + if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { @@ -683,6 +687,8 @@ void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + if(CData->curve_length[curve] == 0.0f) + continue; time = CData->curvekey_time[curvekey]/CData->curve_length[curve]; @@ -724,6 +730,8 @@ void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offs for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + if(CData->curve_length[curve] == 0.0f) + continue; for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index e42af60c27b..0e46903a50c 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -365,7 +365,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< } } -static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders) +static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders) { /* create subd mesh */ SubdMesh sdmesh; @@ -386,21 +386,25 @@ static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, con if(n == 4) sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]); -#if 0 else sdmesh.add_face(vi[0], vi[1], vi[2]); -#endif } /* finalize subd mesh */ - sdmesh.link_boundary(); + sdmesh.finish(); - /* subdivide */ - DiagSplit dsplit; - dsplit.camera = NULL; - dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate"); + /* parameters */ + bool need_ptex = mesh->need_attribute(scene, ATTR_STD_PTEX_FACE_ID) || + mesh->need_attribute(scene, ATTR_STD_PTEX_UV); - sdmesh.tessellate(&dsplit, false, mesh, used_shaders[0], true); + SubdParams sdparams(mesh, used_shaders[0], true, need_ptex); + sdparams.dicing_rate = RNA_float_get(cmesh, "dicing_rate"); + //scene->camera->update(); + //sdparams.camera = scene->camera; + + /* tesselate */ + DiagSplit dsplit(sdparams);; + sdmesh.tessellate(&dsplit); } /* Sync */ @@ -482,7 +486,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) - create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders); + create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders); else create_mesh(scene, mesh, b_mesh, used_shaders); } diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index ba584e172dc..0df8939bc18 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -267,13 +267,38 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P /* mesh sync */ object->mesh = sync_mesh(b_ob, object_updated, hide_tris); - /* sspecial case not tracked by object update flags */ + /* special case not tracked by object update flags */ + + /* holdout */ if(use_holdout != object->use_holdout) { object->use_holdout = use_holdout; scene->object_manager->tag_update(scene); object_updated = true; } + /* visibility flags for both parent and child */ + uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; + if(b_parent.ptr.data != b_ob.ptr.data) { + visibility &= object_ray_visibility(b_parent); + object->random_id ^= hash_int(hash_string(b_parent.name().c_str())); + } + + /* make holdout objects on excluded layer invisible for non-camera rays */ + if(use_holdout && (layer_flag & render_layer.exclude_layer)) + visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); + + /* camera flag is not actually used, instead is tested against render layer + * flags */ + if(visibility & PATH_RAY_CAMERA) { + visibility |= layer_flag << PATH_RAY_LAYER_SHIFT; + visibility &= ~PATH_RAY_CAMERA; + } + + if(visibility != object->visibility) { + object->visibility = visibility; + object_updated = true; + } + /* object sync * transform comparison should not be needed, but duplis don't work perfect * in the depsgraph and may not signal changes, so this is a workaround */ @@ -295,24 +320,10 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P else object->random_id = hash_int_2d(object->random_id, 0); - /* visibility flags for both parent */ - object->visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; - if(b_parent.ptr.data != b_ob.ptr.data) { - object->visibility &= object_ray_visibility(b_parent); + if(b_parent.ptr.data != b_ob.ptr.data) object->random_id ^= hash_int(hash_string(b_parent.name().c_str())); - } - - /* make holdout objects on excluded layer invisible for non-camera rays */ - if(use_holdout && (layer_flag & render_layer.exclude_layer)) - object->visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); - - /* camera flag is not actually used, instead is tested - * against render layer flags */ - if(object->visibility & PATH_RAY_CAMERA) { - object->visibility |= layer_flag << PATH_RAY_LAYER_SHIFT; - object->visibility &= ~PATH_RAY_CAMERA; - } + /* dupli texture coordinates */ if (b_dupli_ob) { object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f); object->dupli_uv = get_float2(b_dupli_ob.uv()); @@ -346,6 +357,7 @@ static bool object_render_hide(BL::Object b_ob, bool top_level, bool parent_hide bool hair_present = false; bool show_emitter = false; + bool hide_emitter = false; bool hide_as_dupli_parent = false; bool hide_as_dupli_child_original = false; @@ -356,8 +368,13 @@ static bool object_render_hide(BL::Object b_ob, bool top_level, bool parent_hide if(b_psys->settings().use_render_emitter()) show_emitter = true; + else + hide_emitter = true; } + if(show_emitter) + hide_emitter = false; + /* duplicators hidden by default, except dupliframes which duplicate self */ if(b_ob.is_duplicator()) if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES) @@ -369,16 +386,15 @@ static bool object_render_hide(BL::Object b_ob, bool top_level, bool parent_hide if(parent_hide) hide_as_dupli_child_original = true; + hide_triangles = hide_emitter; + if(show_emitter) { - hide_triangles = false; return false; } else if(hair_present) { - hide_triangles = true; return hide_as_dupli_child_original; } else { - hide_triangles = false; return (hide_as_dupli_parent || hide_as_dupli_child_original); } } diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 71c84869ff6..22c425aa332 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -475,19 +475,55 @@ void *CCL_python_module_init() PyObject *mod = PyModule_Create(&ccl::module); #ifdef WITH_OSL + /* TODO(sergey): This gives us library we've been linking against. + * In theory with dynamic OSL library it might not be + * accurate, but there's nothing in OSL API which we + * might use th get version in runtime. + */ + int curversion = OSL_LIBRARY_VERSION_CODE; PyModule_AddObject(mod, "with_osl", Py_True); Py_INCREF(Py_True); + PyModule_AddObject(mod, "osl_version", + Py_BuildValue("(iii)", + curversion / 10000, (curversion / 100) % 100, curversion % 100)); + PyModule_AddObject(mod, "osl_version_string", + PyUnicode_FromFormat("%2d, %2d, %2d", + curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else PyModule_AddObject(mod, "with_osl", Py_False); Py_INCREF(Py_False); + PyModule_AddStringConstant(mod, "osl_version", "unknown"); + PyModule_AddStringConstant(mod, "osl_version_string", "unknown"); #endif +#ifdef WITH_NETWORK + PyModule_AddObject(mod, "with_network", Py_True); + Py_INCREF(Py_True); +#else /* WITH_NETWORK */ + PyModule_AddObject(mod, "with_network", Py_False); + Py_INCREF(Py_False); +#endif /* WITH_NETWORK */ + return (void*)mod; } -CCLDeviceInfo *CCL_compute_device_list(int opencl) +CCLDeviceInfo *CCL_compute_device_list(int device_type) { - ccl::DeviceType type = (opencl)? ccl::DEVICE_OPENCL: ccl::DEVICE_CUDA; + ccl::DeviceType type; + switch(device_type) { + case 0: + type = ccl::DEVICE_CUDA; + break; + case 1: + type = ccl::DEVICE_OPENCL; + break; + case 2: + type = ccl::DEVICE_NETWORK; + break; + default: + type = ccl::DEVICE_NONE; + break; + } return ccl::compute_device_list(type); } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 84ff071171b..db673a8d625 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -625,28 +625,42 @@ void BlenderSession::get_progress(float& progress, double& total_time) void BlenderSession::update_status_progress() { string timestatus, status, substatus; + string scene = ""; float progress; - double total_time; + double total_time, remaining_time = 0; char time_str[128]; float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f; float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f; + int samples = session->tile_manager.state.sample + 1; + int total_samples = session->tile_manager.num_samples; get_status(status, substatus); get_progress(progress, total_time); - timestatus = string_printf("Mem:%.2fM, Peak:%.2fM", mem_used, mem_peak); + if(background) { - timestatus += " | " + b_scene.name(); + if(progress>0) + remaining_time = (1-progress) * (total_time / progress); + + scene += " | " + b_scene.name(); if(b_rlay_name != "") - timestatus += ", " + b_rlay_name; + scene += ", " + b_rlay_name; } else { - timestatus += " | "; - BLI_timestr(total_time, time_str, sizeof(time_str)); - timestatus += "Time:" + string(time_str); + timestatus = "Time:" + string(time_str) + " | "; + + if(samples > 0 && total_samples != USHRT_MAX) + remaining_time = (total_samples - samples) * (total_time / samples); } + + if(remaining_time>0) { + BLI_timestr(remaining_time, time_str, sizeof(time_str)); + timestatus += "Remaining:" + string(time_str) + " | "; + } + + timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", mem_used, mem_peak); if(status.size() > 0) status = " | " + status; @@ -654,12 +668,12 @@ void BlenderSession::update_status_progress() status += " | " + substatus; if(status != last_status) { - b_engine.update_stats("", (timestatus + status).c_str()); b_engine.update_memory_stats(mem_used, mem_peak); last_status = status; } if(progress != last_progress) { b_engine.update_progress(progress); + b_engine.update_stats("", (timestatus + scene + status).c_str()); last_progress = progress; } } diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt index fe2368b7ea8..825e82209aa 100644 --- a/intern/cycles/device/CMakeLists.txt +++ b/intern/cycles/device/CMakeLists.txt @@ -13,6 +13,10 @@ set(INC_SYS ${GLEW_INCLUDE_PATH} ) +if(WITH_CYCLES_OPTIMIZED_KERNEL_SSE41) + add_definitions(-DWITH_CYCLES_OPTIMIZED_KERNEL_SSE41=1) +endif() + set(SRC device.cpp device_cpu.cpp @@ -22,7 +26,7 @@ set(SRC device_task.cpp ) -if(WITH_NETWORK) +if(WITH_CYCLES_NETWORK) list(APPEND SRC device_network.cpp ) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 5c771aa1c8b..6283e34f563 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -127,7 +127,7 @@ Device *Device::create(DeviceInfo& info, Stats &stats, bool background) switch(info.type) { case DEVICE_CPU: - device = device_cpu_create(info, stats); + device = device_cpu_create(info, stats, background); break; #ifdef WITH_CUDA case DEVICE_CUDA: @@ -159,9 +159,6 @@ Device *Device::create(DeviceInfo& info, Stats &stats, bool background) return NULL; } - if(device) - device->info = info; - return device; } diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 18868d19a85..bd309e35788 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -71,7 +71,7 @@ public: class Device { protected: - Device(Stats &stats_) : stats(stats_) {} + Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), info(info_), stats(stats_) {} bool background; string error_msg; diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index d04c5df82fb..e084116c72d 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -45,11 +45,13 @@ class CPUDevice : public Device public: TaskPool task_pool; KernelGlobals kernel_globals; + #ifdef WITH_OSL OSLGlobals osl_globals; #endif - CPUDevice(Stats &stats) : Device(stats) + CPUDevice(DeviceInfo& info, Stats &stats, bool background) + : Device(info, stats, background) { #ifdef WITH_OSL kernel_globals.osl = &osl_globals; @@ -58,6 +60,7 @@ public: /* do now to avoid thread issues */ system_cpu_support_sse2(); system_cpu_support_sse3(); + system_cpu_support_sse41(); } ~CPUDevice() @@ -164,6 +167,28 @@ public: int end_sample = tile.start_sample + tile.num_samples; #ifdef WITH_OPTIMIZED_KERNEL +#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 + if(system_cpu_support_sse41()) { + for(int sample = start_sample; sample < end_sample; sample++) { + if (task.get_cancel() || task_pool.canceled()) { + if(task.need_finish_queue == false) + break; + } + + for(int y = tile.y; y < tile.y + tile.h; y++) { + for(int x = tile.x; x < tile.x + tile.w; x++) { + kernel_cpu_sse41_path_trace(&kg, render_buffer, rng_state, + sample, x, y, tile.offset, tile.stride); + } + } + + tile.sample = sample + 1; + + task.update_progress(tile); + } + } + else +#endif if(system_cpu_support_sse3()) { for(int sample = start_sample; sample < end_sample; sample++) { if (task.get_cancel() || task_pool.canceled()) { @@ -243,6 +268,15 @@ public: if(task.rgba_half) { #ifdef WITH_OPTIMIZED_KERNEL +#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 + if(system_cpu_support_sse41()) { + for(int y = task.y; y < task.y + task.h; y++) + for(int x = task.x; x < task.x + task.w; x++) + kernel_cpu_sse41_convert_to_half_float(&kernel_globals, (uchar4*)task.rgba_half, (float*)task.buffer, + sample_scale, x, y, task.offset, task.stride); + } + else +#endif if(system_cpu_support_sse3()) { for(int y = task.y; y < task.y + task.h; y++) for(int x = task.x; x < task.x + task.w; x++) @@ -266,6 +300,14 @@ public: } else { #ifdef WITH_OPTIMIZED_KERNEL +#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 + if(system_cpu_support_sse41()) { + for(int y = task.y; y < task.y + task.h; y++) + for(int x = task.x; x < task.x + task.w; x++) + kernel_cpu_sse41_convert_to_byte(&kernel_globals, (uchar4*)task.rgba_byte, (float*)task.buffer, + sample_scale, x, y, task.offset, task.stride); + } +#endif if(system_cpu_support_sse3()) { for(int y = task.y; y < task.y + task.h; y++) for(int x = task.x; x < task.x + task.w; x++) @@ -298,6 +340,16 @@ public: #endif #ifdef WITH_OPTIMIZED_KERNEL +#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 + if(system_cpu_support_sse41()) { + for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) { + kernel_cpu_sse41_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x); + + if(task_pool.canceled()) + break; + } + } +#endif if(system_cpu_support_sse3()) { for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) { kernel_cpu_sse3_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x); @@ -351,9 +403,9 @@ public: } }; -Device *device_cpu_create(DeviceInfo& info, Stats &stats) +Device *device_cpu_create(DeviceInfo& info, Stats &stats, bool background) { - return new CPUDevice(stats); + return new CPUDevice(info, stats, background); } void device_cpu_info(vector<DeviceInfo>& devices) diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 4ce7f6fd729..8db915f769c 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -171,7 +171,8 @@ public: cuda_assert(cuCtxSetCurrent(NULL)); } - CUDADevice(DeviceInfo& info, Stats &stats, bool background_) : Device(stats) + CUDADevice(DeviceInfo& info, Stats &stats, bool background_) + : Device(info, stats, background_) { first_error = true; background = background_; diff --git a/intern/cycles/device/device_intern.h b/intern/cycles/device/device_intern.h index d667478beed..7eb66c25a81 100644 --- a/intern/cycles/device/device_intern.h +++ b/intern/cycles/device/device_intern.h @@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN class Device; -Device *device_cpu_create(DeviceInfo& info, Stats &stats); +Device *device_cpu_create(DeviceInfo& info, Stats &stats, bool background); Device *device_opencl_create(DeviceInfo& info, Stats &stats, bool background); Device *device_cuda_create(DeviceInfo& info, Stats &stats, bool background); Device *device_network_create(DeviceInfo& info, Stats &stats, const char *address); diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 4df0fdbd4c7..27b9de0769e 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -45,25 +45,24 @@ public: device_ptr unique_ptr; MultiDevice(DeviceInfo& info, Stats &stats, bool background_) - : Device(stats), unique_ptr(1) + : Device(info, stats, background_), unique_ptr(1) { Device *device; - background = background_; foreach(DeviceInfo& subinfo, info.multi_devices) { device = Device::create(subinfo, stats, background); devices.push_back(SubDevice(device)); } -#if 0 //def WITH_NETWORK +#ifdef WITH_NETWORK /* try to add network devices */ ServerDiscovery discovery(true); time_sleep(1.0); - list<string> servers = discovery.get_server_list(); + vector<string> servers = discovery.get_server_list(); foreach(string& server, servers) { - device = device_network_create(info, server.c_str()); + device = device_network_create(info, stats, server.c_str()); if(device) devices.push_back(SubDevice(device)); } diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 23c1a10fa0a..90339b89cce 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -20,9 +20,25 @@ #include "util_foreach.h" +#if defined(WITH_NETWORK) + CCL_NAMESPACE_BEGIN -#ifdef WITH_NETWORK +typedef map<device_ptr, device_ptr> PtrMap; +typedef vector<uint8_t> DataVector; +typedef map<device_ptr, DataVector> DataMap; + +/* tile list */ +typedef vector<RenderTile> TileList; + +/* search a list of tiles and find the one that matches the passed render tile */ +static TileList::iterator tile_list_find(TileList& tile_list, RenderTile& tile) +{ + for(TileList::iterator it = tile_list.begin(); it != tile_list.end(); ++it) + if(tile.x == it->x && tile.y == it->y && tile.start_sample == it->start_sample) + return it; + return tile_list.end(); +} class NetworkDevice : public Device { @@ -32,8 +48,10 @@ public: device_ptr mem_counter; DeviceTask the_task; /* todo: handle multiple tasks */ - NetworkDevice(Stats &stats, const char *address) - : Device(stats), socket(io_service) + thread_mutex rpc_lock; + + NetworkDevice(DeviceInfo& info, Stats &stats, const char *address) + : Device(info, stats, true), socket(io_service) { stringstream portstr; portstr << SERVER_PORT; @@ -64,6 +82,8 @@ public: void mem_alloc(device_memory& mem, MemoryType type) { + thread_scoped_lock lock(rpc_lock); + mem.device_pointer = ++mem_counter; RPCSend snd(socket, "mem_alloc"); @@ -75,6 +95,8 @@ public: void mem_copy_to(device_memory& mem) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "mem_copy_to"); snd.add(mem); @@ -84,6 +106,10 @@ public: void mem_copy_from(device_memory& mem, int y, int w, int h, int elem) { + thread_scoped_lock lock(rpc_lock); + + size_t data_size = mem.memory_size(); + RPCSend snd(socket, "mem_copy_from"); snd.add(mem); @@ -94,11 +120,13 @@ public: snd.write(); RPCReceive rcv(socket); - rcv.read_buffer((void*)mem.data_pointer, mem.memory_size()); + rcv.read_buffer((void*)mem.data_pointer, data_size); } void mem_zero(device_memory& mem) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "mem_zero"); snd.add(mem); @@ -108,6 +136,8 @@ public: void mem_free(device_memory& mem) { if(mem.device_pointer) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "mem_free"); snd.add(mem); @@ -119,6 +149,8 @@ public: void const_copy_to(const char *name, void *host, size_t size) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "const_copy_to"); string name_string(name); @@ -131,6 +163,8 @@ public: void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic) { + thread_scoped_lock lock(rpc_lock); + mem.device_pointer = ++mem_counter; RPCSend snd(socket, "tex_alloc"); @@ -148,6 +182,8 @@ public: void tex_free(device_memory& mem) { if(mem.device_pointer) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "tex_free"); snd.add(mem); @@ -157,8 +193,25 @@ public: } } + bool load_kernels(bool experimental) + { + thread_scoped_lock lock(rpc_lock); + + RPCSend snd(socket, "load_kernels"); + snd.add(experimental); + snd.write(); + + bool result; + RPCReceive rcv(socket); + rcv.read(result); + + return result; + } + void task_add(DeviceTask& task) { + thread_scoped_lock lock(rpc_lock); + the_task = task; RPCSend snd(socket, "task_add"); @@ -168,55 +221,73 @@ public: void task_wait() { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "task_wait"); snd.write(); - list<RenderTile> the_tiles; + lock.unlock(); + + TileList the_tiles; /* todo: run this threaded for connecting to multiple clients */ for(;;) { - RPCReceive rcv(socket); RenderTile tile; + lock.lock(); + RPCReceive rcv(socket); + if(rcv.name == "acquire_tile") { + lock.unlock(); + /* todo: watch out for recursive calls! */ if(the_task.acquire_tile(this, tile)) { /* write return as bool */ the_tiles.push_back(tile); + lock.lock(); RPCSend snd(socket, "acquire_tile"); snd.add(tile); snd.write(); + lock.unlock(); } else { + lock.lock(); RPCSend snd(socket, "acquire_tile_none"); snd.write(); + lock.unlock(); } } else if(rcv.name == "release_tile") { rcv.read(tile); + lock.unlock(); - for(list<RenderTile>::iterator it = the_tiles.begin(); it != the_tiles.end(); it++) { - if(tile.x == it->x && tile.y == it->y && tile.start_sample == it->start_sample) { - tile.buffers = it->buffers; - the_tiles.erase(it); - break; - } + TileList::iterator it = tile_list_find(the_tiles, tile); + if (it != the_tiles.end()) { + tile.buffers = it->buffers; + the_tiles.erase(it); } assert(tile.buffers != NULL); the_task.release_tile(tile); + lock.lock(); RPCSend snd(socket, "release_tile"); snd.write(); + lock.unlock(); } - else if(rcv.name == "task_wait_done") + else if(rcv.name == "task_wait_done") { + lock.unlock(); break; + } + else + lock.unlock(); } } void task_cancel() { + thread_scoped_lock lock(rpc_lock); RPCSend snd(socket, "task_cancel"); snd.write(); } @@ -224,7 +295,7 @@ public: Device *device_network_create(DeviceInfo& info, Stats &stats, const char *address) { - return new NetworkDevice(stats, address); + return new NetworkDevice(info, stats, address); } void device_network_info(vector<DeviceInfo>& devices) @@ -243,8 +314,10 @@ void device_network_info(vector<DeviceInfo>& devices) class DeviceServer { public: + thread_mutex rpc_lock; + DeviceServer(Device *device_, tcp::socket& socket_) - : device(device_), socket(socket_) + : device(device_), socket(socket_), stop(false), blocked_waiting(false) { } @@ -252,56 +325,151 @@ public: { /* receive remote function calls */ for(;;) { - RPCReceive rcv(socket); + listen_step(); - if(rcv.name == "stop") + if(stop) break; - - process(rcv); } } protected: - void process(RPCReceive& rcv) + void listen_step() + { + thread_scoped_lock lock(rpc_lock); + RPCReceive rcv(socket); + + if(rcv.name == "stop") + stop = true; + else + process(rcv, lock); + } + + /* create a memory buffer for a device buffer and insert it into mem_data */ + DataVector &data_vector_insert(device_ptr client_pointer, size_t data_size) + { + /* create a new DataVector and insert it into mem_data */ + pair<DataMap::iterator,bool> data_ins = mem_data.insert( + DataMap::value_type(client_pointer, DataVector())); + + /* make sure it was a unique insertion */ + assert(data_ins.second); + + /* get a reference to the inserted vector */ + DataVector &data_v = data_ins.first->second; + + /* size the vector */ + data_v.resize(data_size); + + return data_v; + } + + DataVector &data_vector_find(device_ptr client_pointer) { - // fprintf(stderr, "receive process %s\n", rcv.name.c_str()); + DataMap::iterator i = mem_data.find(client_pointer); + assert(i != mem_data.end()); + return i->second; + } + + /* setup mapping and reverse mapping of client_pointer<->real_pointer */ + void pointer_mapping_insert(device_ptr client_pointer, device_ptr real_pointer) + { + pair<PtrMap::iterator,bool> mapins; + + /* insert mapping from client pointer to our real device pointer */ + mapins = ptr_map.insert(PtrMap::value_type(client_pointer, real_pointer)); + assert(mapins.second); + + /* insert reverse mapping from real our device pointer to client pointer */ + mapins = ptr_imap.insert(PtrMap::value_type(real_pointer, client_pointer)); + assert(mapins.second); + } + + device_ptr device_ptr_from_client_pointer(device_ptr client_pointer) + { + PtrMap::iterator i = ptr_map.find(client_pointer); + assert(i != ptr_map.end()); + return i->second; + } + + device_ptr device_ptr_from_client_pointer_erase(device_ptr client_pointer) + { + PtrMap::iterator i = ptr_map.find(client_pointer); + assert(i != ptr_map.end()); + + device_ptr result = i->second; + /* erase the mapping */ + ptr_map.erase(i); + + /* erase the reverse mapping */ + PtrMap::iterator irev = ptr_imap.find(result); + assert(irev != ptr_imap.end()); + ptr_imap.erase(irev); + + /* erase the data vector */ + DataMap::iterator idata = mem_data.find(client_pointer); + assert(idata != mem_data.end()); + mem_data.erase(idata); + + return result; + } + + /* note that the lock must be already acquired upon entry. + * This is necessary because the caller often peeks at + * the header and delegates control to here when it doesn't + * specifically handle the current RPC. + * The lock must be unlocked before returning */ + void process(RPCReceive& rcv, thread_scoped_lock &lock) + { if(rcv.name == "mem_alloc") { MemoryType type; network_device_memory mem; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(mem); rcv.read(type); - /* todo: CPU needs mem.data_pointer */ + lock.unlock(); + + client_pointer = mem.device_pointer; - remote_pointer = mem.device_pointer; + /* create a memory buffer for the device buffer */ + size_t data_size = mem.memory_size(); + DataVector &data_v = data_vector_insert(client_pointer, data_size); - mem_data[remote_pointer] = vector<uint8_t>(); - mem_data[remote_pointer].resize(mem.memory_size()); - if(mem.memory_size()) - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + if(data_size) + mem.data_pointer = (device_ptr)&(data_v[0]); else mem.data_pointer = 0; + /* perform the allocation on the actual device */ device->mem_alloc(mem, type); - ptr_map[remote_pointer] = mem.device_pointer; - ptr_imap[mem.device_pointer] = remote_pointer; + /* store a mapping to/from client_pointer and real device pointer */ + pointer_mapping_insert(client_pointer, mem.device_pointer); } else if(rcv.name == "mem_copy_to") { network_device_memory mem; rcv.read(mem); + lock.unlock(); - device_ptr remote_pointer = mem.device_pointer; - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + device_ptr client_pointer = mem.device_pointer; - rcv.read_buffer((uint8_t*)mem.data_pointer, mem.memory_size()); + DataVector &data_v = data_vector_find(client_pointer); - mem.device_pointer = ptr_map[remote_pointer]; + size_t data_size = mem.memory_size(); + /* get pointer to memory buffer for device buffer */ + mem.data_pointer = (device_ptr)&data_v[0]; + + /* copy data from network into memory buffer */ + rcv.read_buffer((uint8_t*)mem.data_pointer, data_size); + + /* translate the client pointer to a real device pointer */ + mem.device_pointer = device_ptr_from_client_pointer(client_pointer); + + /* copy the data from the memory buffer to the device buffer */ device->mem_copy_to(mem); } else if(rcv.name == "mem_copy_from") { @@ -314,37 +482,47 @@ protected: rcv.read(h); rcv.read(elem); - device_ptr remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[remote_pointer]; - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + device_ptr client_pointer = mem.device_pointer; + mem.device_pointer = device_ptr_from_client_pointer(client_pointer); + + DataVector &data_v = data_vector_find(client_pointer); + + mem.data_pointer = (device_ptr)&(data_v[0]); device->mem_copy_from(mem, y, w, h, elem); + size_t data_size = mem.memory_size(); + RPCSend snd(socket); snd.write(); - snd.write_buffer((uint8_t*)mem.data_pointer, mem.memory_size()); + snd.write_buffer((uint8_t*)mem.data_pointer, data_size); + lock.unlock(); } else if(rcv.name == "mem_zero") { network_device_memory mem; rcv.read(mem); - device_ptr remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[mem.device_pointer]; - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + lock.unlock(); + + device_ptr client_pointer = mem.device_pointer; + mem.device_pointer = device_ptr_from_client_pointer(client_pointer); + + DataVector &data_v = data_vector_find(client_pointer); + + mem.data_pointer = (device_ptr)&(data_v[0]); device->mem_zero(mem); } else if(rcv.name == "mem_free") { network_device_memory mem; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(mem); + lock.unlock(); + + client_pointer = mem.device_pointer; - remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[mem.device_pointer]; - ptr_map.erase(remote_pointer); - ptr_imap.erase(mem.device_pointer); - mem_data.erase(remote_pointer); + mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer); device->mem_free(mem); } @@ -357,6 +535,7 @@ protected: vector<char> host_vector(size); rcv.read_buffer(&host_vector[0], size); + lock.unlock(); device->const_copy_to(name_string.c_str(), &host_vector[0], size); } @@ -365,53 +544,76 @@ protected: string name; bool interpolation; bool periodic; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(name); rcv.read(mem); rcv.read(interpolation); rcv.read(periodic); + lock.unlock(); + + client_pointer = mem.device_pointer; + + size_t data_size = mem.memory_size(); - remote_pointer = mem.device_pointer; + DataVector &data_v = data_vector_insert(client_pointer, data_size); - mem_data[remote_pointer] = vector<uint8_t>(); - mem_data[remote_pointer].resize(mem.memory_size()); - if(mem.memory_size()) - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + if(data_size) + mem.data_pointer = (device_ptr)&(data_v[0]); else mem.data_pointer = 0; - rcv.read_buffer((uint8_t*)mem.data_pointer, mem.memory_size()); + rcv.read_buffer((uint8_t*)mem.data_pointer, data_size); device->tex_alloc(name.c_str(), mem, interpolation, periodic); - ptr_map[remote_pointer] = mem.device_pointer; - ptr_imap[mem.device_pointer] = remote_pointer; + pointer_mapping_insert(client_pointer, mem.device_pointer); } else if(rcv.name == "tex_free") { network_device_memory mem; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(mem); + lock.unlock(); - remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[mem.device_pointer]; - ptr_map.erase(remote_pointer); - ptr_map.erase(mem.device_pointer); - mem_data.erase(remote_pointer); + client_pointer = mem.device_pointer; + + mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer); device->tex_free(mem); } + else if(rcv.name == "load_kernels") { + bool experimental; + rcv.read(experimental); + + bool result; + result = device->load_kernels(experimental); + RPCSend snd(socket); + snd.add(result); + snd.write(); + lock.unlock(); + } else if(rcv.name == "task_add") { DeviceTask task; rcv.read(task); + lock.unlock(); + + if(task.buffer) + task.buffer = device_ptr_from_client_pointer(task.buffer); + + if(task.rgba_half) + task.rgba_half = device_ptr_from_client_pointer(task.rgba_half); + + if(task.rgba_byte) + task.rgba_byte = device_ptr_from_client_pointer(task.rgba_byte); + + if(task.shader_input) + task.shader_input = device_ptr_from_client_pointer(task.shader_input); + + if(task.shader_output) + task.shader_output = device_ptr_from_client_pointer(task.shader_output); - if(task.buffer) task.buffer = ptr_map[task.buffer]; - if(task.rgba_byte) task.rgba_byte = ptr_map[task.rgba_byte]; - if(task.rgba_half) task.rgba_half = ptr_map[task.rgba_half]; - if(task.shader_input) task.shader_input = ptr_map[task.shader_input]; - if(task.shader_output) task.shader_output = ptr_map[task.shader_output]; task.acquire_tile = function_bind(&DeviceServer::task_acquire_tile, this, _1, _2); task.release_tile = function_bind(&DeviceServer::task_release_tile, this, _1); @@ -422,14 +624,44 @@ protected: device->task_add(task); } else if(rcv.name == "task_wait") { + lock.unlock(); + + blocked_waiting = true; device->task_wait(); + blocked_waiting = false; + lock.lock(); RPCSend snd(socket, "task_wait_done"); snd.write(); + lock.unlock(); } else if(rcv.name == "task_cancel") { + lock.unlock(); device->task_cancel(); } + else if(rcv.name == "acquire_tile") { + AcquireEntry entry; + entry.name = rcv.name; + rcv.read(entry.tile); + acquire_queue.push_back(entry); + lock.unlock(); + } + else if(rcv.name == "acquire_tile_none") { + AcquireEntry entry; + entry.name = rcv.name; + acquire_queue.push_back(entry); + lock.unlock(); + } + else if(rcv.name == "release_tile") { + AcquireEntry entry; + entry.name = rcv.name; + acquire_queue.push_back(entry); + lock.unlock(); + } + else { + cout << "Error: unexpected RPC receive call \"" + rcv.name + "\"\n"; + lock.unlock(); + } } bool task_acquire_tile(Device *device, RenderTile& tile) @@ -441,23 +673,34 @@ protected: RPCSend snd(socket, "acquire_tile"); snd.write(); - while(1) { - RPCReceive rcv(socket); + do { + if(blocked_waiting) + listen_step(); - if(rcv.name == "acquire_tile") { - rcv.read(tile); + /* todo: avoid busy wait loop */ + thread_scoped_lock lock(rpc_lock); - if(tile.buffer) tile.buffer = ptr_map[tile.buffer]; - if(tile.rng_state) tile.rng_state = ptr_map[tile.rng_state]; + if(!acquire_queue.empty()) { + AcquireEntry entry = acquire_queue.front(); + acquire_queue.pop_front(); - result = true; - break; + if(entry.name == "acquire_tile") { + tile = entry.tile; + + if(tile.buffer) tile.buffer = ptr_map[tile.buffer]; + if(tile.rng_state) tile.rng_state = ptr_map[tile.rng_state]; + + result = true; + break; + } + else if(entry.name == "acquire_tile_none") { + break; + } + else { + cout << "Error: unexpected acquire RPC receive call \"" + entry.name + "\"\n"; + } } - else if(rcv.name == "acquire_tile_none") - break; - else - process(rcv); - } + } while(acquire_queue.empty() && !stop); return result; } @@ -479,18 +722,34 @@ protected: if(tile.buffer) tile.buffer = ptr_imap[tile.buffer]; if(tile.rng_state) tile.rng_state = ptr_imap[tile.rng_state]; - RPCSend snd(socket, "release_tile"); - snd.add(tile); - snd.write(); + { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "release_tile"); + snd.add(tile); + snd.write(); + lock.unlock(); + } - while(1) { - RPCReceive rcv(socket); + do { + if(blocked_waiting) + listen_step(); - if(rcv.name == "release_tile") - break; - else - process(rcv); - } + /* todo: avoid busy wait loop */ + thread_scoped_lock lock(rpc_lock); + + if(!acquire_queue.empty()) { + AcquireEntry entry = acquire_queue.front(); + acquire_queue.pop_front(); + + if(entry.name == "release_tile") { + lock.unlock(); + break; + } + else { + cout << "Error: unexpected release RPC receive call \"" + entry.name + "\"\n"; + } + } + } while(acquire_queue.empty() && !stop); } bool task_get_cancel() @@ -503,11 +762,20 @@ protected: tcp::socket& socket; /* mapping of remote to local pointer */ - map<device_ptr, device_ptr> ptr_map; - map<device_ptr, device_ptr> ptr_imap; - map<device_ptr, vector<uint8_t> > mem_data; + PtrMap ptr_map; + PtrMap ptr_imap; + DataMap mem_data; + + struct AcquireEntry { + string name; + RenderTile tile; + }; thread_mutex acquire_mutex; + list<AcquireEntry> acquire_queue; + + bool stop; + bool blocked_waiting; /* todo: free memory and device (osl) on network error */ }; @@ -540,7 +808,8 @@ void Device::server_run() } } +CCL_NAMESPACE_END + #endif -CCL_NAMESPACE_END diff --git a/intern/cycles/device/device_network.h b/intern/cycles/device/device_network.h index db399cf4240..d639450b9ea 100644 --- a/intern/cycles/device/device_network.h +++ b/intern/cycles/device/device_network.h @@ -28,6 +28,8 @@ #include <boost/thread.hpp> #include <iostream> +#include <sstream> +#include <deque> #include "buffers.h" @@ -70,12 +72,12 @@ public: : name(name_), socket(socket_), archive(archive_stream), sent(false) { archive & name_; + + fprintf(stderr, "rpc send %s\n", name.c_str()); } ~RPCSend() { - if(!sent) - fprintf(stderr, "Error: RPC %s not sent\n", name.c_str()); } void add(const device_memory& mem) @@ -98,13 +100,14 @@ public: archive & task.offset & task.stride; archive & task.shader_input & task.shader_output & task.shader_eval_type; archive & task.shader_x & task.shader_w; + archive & task.need_finish_queue; } void add(const RenderTile& tile) { archive & tile.x & tile.y & tile.w & tile.h; archive & tile.start_sample & tile.num_samples & tile.sample; - archive & tile.offset & tile.stride; + archive & tile.resolution & tile.offset & tile.stride; archive & tile.buffer & tile.rng_state; } @@ -178,6 +181,7 @@ public: size_t data_size; if((header_stream >> hex >> data_size)) { + vector<char> data(data_size); size_t len = boost::asio::read(socket, boost::asio::buffer(data)); @@ -191,15 +195,19 @@ public: archive = new boost::archive::text_iarchive(*archive_stream); *archive & name; + fprintf(stderr, "rpc receive %s\n", name.c_str()); + } + else { + cout << "Network receive error: data size doesn't match header\n"; } - else - cout << "Network receive error: data size doens't match header\n"; } - else + else { cout << "Network receive error: can't decode data size from header\n"; + } } - else + else { cout << "Network receive error: invalid header size\n"; + } } ~RPCReceive() @@ -235,9 +243,10 @@ public: *archive & type & task.x & task.y & task.w & task.h; *archive & task.rgba_byte & task.rgba_half & task.buffer & task.sample & task.num_samples; - *archive & task.resolution & task.offset & task.stride; + *archive & task.offset & task.stride; *archive & task.shader_input & task.shader_output & task.shader_eval_type; *archive & task.shader_x & task.shader_w; + *archive & task.need_finish_queue; task.type = (DeviceTask::Type)type; } @@ -247,7 +256,7 @@ public: *archive & tile.x & tile.y & tile.w & tile.h; *archive & tile.start_sample & tile.num_samples & tile.sample; *archive & tile.resolution & tile.offset & tile.stride; - *archive & tile.buffer & tile.rng_state & tile.rgba_byte & tile.rgba_half; + *archive & tile.buffer & tile.rng_state; tile.buffers = NULL; } @@ -303,12 +312,12 @@ public: delete work; } - list<string> get_server_list() + vector<string> get_server_list() { - list<string> result; + vector<string> result; mutex.lock(); - result = servers; + result = vector<string>(servers.begin(), servers.end()); mutex.unlock(); return result; @@ -333,11 +342,8 @@ private: mutex.lock(); /* add address if it's not already in the list */ - bool found = false; - - foreach(string& server, servers) - if(server == address) - found = true; + bool found = std::find(servers.begin(), servers.end(), + address) != servers.end(); if(!found) servers.push_back(address); @@ -393,10 +399,21 @@ private: /* buffer and endpoint for receiving messages */ char receive_buffer[256]; boost::asio::ip::udp::endpoint receive_endpoint; + + // os, version, devices, status, host name, group name, ip as far as fields go + struct ServerInfo { + string cycles_version; + string os; + int device_count; + string status; + string host_name; + string group_name; + string host_addr; + }; /* collection of server addresses in list */ bool collect_servers; - list<string> servers; + vector<string> servers; }; CCL_NAMESPACE_END diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 11c7bc6f099..98d3b07b7ee 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -423,9 +423,8 @@ public: } OpenCLDevice(DeviceInfo& info, Stats &stats, bool background_) - : Device(stats) + : Device(info, stats, background_) { - background = background_; cpPlatform = NULL; cdDevice = NULL; cxContext = NULL; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 56ba0e08743..39444b91131 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -190,13 +190,18 @@ endif() include_directories(${INC}) include_directories(SYSTEM ${INC_SYS}) -add_library(cycles_kernel ${SRC} ${SRC_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_SVM_HEADERS}) - if(WITH_CYCLES_OPTIMIZED_KERNEL) set_source_files_properties(kernel_sse2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS}") set_source_files_properties(kernel_sse3.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE3_KERNEL_FLAGS}") endif() +if(WITH_CYCLES_OPTIMIZED_KERNEL_SSE41) + set_source_files_properties(kernel_sse41.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS}") + list(APPEND SRC kernel_sse41.cpp) +endif() + +add_library(cycles_kernel ${SRC} ${SRC_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_SVM_HEADERS}) + if(WITH_CYCLES_CUDA) add_dependencies(cycles_kernel cycles_kernel_cuda) endif() diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h index f30b30c8c76..f4932568c1f 100644 --- a/intern/cycles/kernel/closure/volume.h +++ b/intern/cycles/kernel/closure/volume.h @@ -53,11 +53,6 @@ ccl_device float3 volume_transparent_eval_phase(const ShaderClosure *sc, const f ccl_device float3 volume_eval_phase(KernelGlobals *kg, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out) { -#ifdef __OSL__ - if(kg->osl && sc->prim) - return OSLShader::volume_eval_phase(sc, omega_in, omega_out); -#endif - float3 eval; switch(sc->type) { diff --git a/intern/cycles/kernel/kernel.h b/intern/cycles/kernel/kernel.h index 361f5b0856d..105a3887da0 100644 --- a/intern/cycles/kernel/kernel.h +++ b/intern/cycles/kernel/kernel.h @@ -61,6 +61,15 @@ void kernel_cpu_sse3_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, floa float sample_scale, int x, int y, int offset, int stride); void kernel_cpu_sse3_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i); + +void kernel_cpu_sse41_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, + int sample, int x, int y, int offset, int stride); +void kernel_cpu_sse41_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, + float sample_scale, int x, int y, int offset, int stride); +void kernel_cpu_sse41_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, + float sample_scale, int x, int y, int offset, int stride); +void kernel_cpu_sse41_shader(KernelGlobals *kg, uint4 *input, float4 *output, + int type, int i); #endif CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_primitive.h b/intern/cycles/kernel/kernel_primitive.h index ababad28f35..0e39c489fbc 100644 --- a/intern/cycles/kernel/kernel_primitive.h +++ b/intern/cycles/kernel/kernel_primitive.h @@ -89,6 +89,25 @@ ccl_device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd) return uv; } +ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, int *face_id) +{ + /* storing ptex data as attributes is not memory efficient but simple for tests */ + AttributeElement elem_face_id, elem_uv; + int offset_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID, &elem_face_id); + int offset_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV, &elem_uv); + + if(offset_face_id == ATTR_STD_NOT_FOUND || offset_uv == ATTR_STD_NOT_FOUND) + return false; + + float3 uv3 = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL); + float face_id_f = primitive_attribute_float(kg, sd, elem_face_id, offset_face_id, NULL, NULL); + + *uv = make_float2(uv3.x, uv3.y); + *face_id = (int)face_id_f; + + return true; +} + ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd) { #ifdef __HAIR__ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 77154ce3aef..dbc705ea791 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -764,11 +764,6 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b ccl_device float3 emissive_eval(KernelGlobals *kg, ShaderData *sd, ShaderClosure *sc) { -#ifdef __OSL__ - if(kg->osl && sc->prim) - return OSLShader::emissive_eval(sd, sc); -#endif - return emissive_simple_eval(sd->Ng, sd->I); } diff --git a/intern/cycles/kernel/kernel_sse41.cpp b/intern/cycles/kernel/kernel_sse41.cpp new file mode 100644 index 00000000000..0c68fd3651b --- /dev/null +++ b/intern/cycles/kernel/kernel_sse41.cpp @@ -0,0 +1,76 @@ +/* + * 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 + */ + +/* Optimized CPU kernel entry points. This file is compiled with SSE3/SSSE3 + * optimization flags and nearly all functions inlined, while kernel.cpp + * is compiled without for other CPU's. */ + +#ifdef WITH_OPTIMIZED_KERNEL + +/* SSE optimization disabled for now on 32 bit, see bug #36316 */ +#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) +#define __KERNEL_SSE2__ +#define __KERNEL_SSE3__ +#define __KERNEL_SSSE3__ +#define __KERNEL_SSE41__ +#endif + +#include "kernel.h" +#include "kernel_compat_cpu.h" +#include "kernel_math.h" +#include "kernel_types.h" +#include "kernel_globals.h" +#include "kernel_film.h" +#include "kernel_path.h" +#include "kernel_displace.h" + +CCL_NAMESPACE_BEGIN + +/* Path Tracing */ + +void kernel_cpu_sse41_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride) +{ +#ifdef __BRANCHED_PATH__ + if(kernel_data.integrator.branched) + kernel_branched_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride); + else +#endif + kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride); +} + +/* Film */ + +void kernel_cpu_sse41_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride) +{ + kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride); +} + +void kernel_cpu_sse41_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride) +{ + kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride); +} + +/* Shader Evaluate */ + +void kernel_cpu_sse41_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i) +{ + kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, i); +} + +CCL_NAMESPACE_END + +#endif + diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 3371c580c71..51a49348810 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -436,6 +436,8 @@ typedef enum AttributeStandard { ATTR_STD_MOTION_POST, ATTR_STD_PARTICLE, ATTR_STD_CURVE_INTERCEPT, + ATTR_STD_PTEX_FACE_ID, + ATTR_STD_PTEX_UV, ATTR_STD_NUM, ATTR_STD_NOT_FOUND = ~0 diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp index eed4446cddc..2facced0914 100644 --- a/intern/cycles/kernel/osl/background.cpp +++ b/intern/cycles/kernel/osl/background.cpp @@ -46,14 +46,9 @@ using namespace OSL; /// to return a color in background shaders. No methods, /// only the weight is taking into account /// -class GenericBackgroundClosure : public OSL::BackgroundClosure { +class GenericBackgroundClosure : public CClosurePrimitive { public: - GenericBackgroundClosure() {} - - void setup() {}; - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "background"; } - void print_on(std::ostream &out) const { out << name() << " ()"; } + GenericBackgroundClosure() : CClosurePrimitive(Background) {} }; /// Holdout closure @@ -63,14 +58,9 @@ public: /// point. No parameters, only the weight will be /// used /// -class HoldoutClosure : ClosurePrimitive { +class HoldoutClosure : CClosurePrimitive { public: - HoldoutClosure () : ClosurePrimitive(Holdout) {} - - void setup() {}; - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "holdout"; } - void print_on(std::ostream &out) const { out << name() << " ()"; } + HoldoutClosure () : CClosurePrimitive(Holdout) {} }; /// ambient occlusion closure @@ -79,14 +69,9 @@ public: /// to return a color in ambient occlusion shaders. No methods, /// only the weight is taking into account /// -class AmbientOcclusionClosure : public ClosurePrimitive { +class AmbientOcclusionClosure : public CClosurePrimitive { public: - AmbientOcclusionClosure () : ClosurePrimitive((ClosurePrimitive::Category)AmbientOcclusion) {} - - void setup() {}; - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "ambient_occlusion"; } - void print_on(std::ostream &out) const { out << name() << " ()"; } + AmbientOcclusionClosure () : CClosurePrimitive(AmbientOcclusion) {} }; ClosureParam *closure_background_params() @@ -98,7 +83,7 @@ ClosureParam *closure_background_params() return params; } -CLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure) +CCLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure) ClosureParam *closure_holdout_params() { @@ -108,7 +93,7 @@ ClosureParam *closure_holdout_params() return params; } -CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure) +CCLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure) ClosureParam *closure_ambient_occlusion_params() { @@ -119,7 +104,7 @@ ClosureParam *closure_ambient_occlusion_params() return params; } -CLOSURE_PREPARE(closure_ambient_occlusion_prepare, AmbientOcclusionClosure) +CCLOSURE_PREPARE(closure_ambient_occlusion_prepare, AmbientOcclusionClosure) CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp index a320bea118a..8f9c2efd470 100644 --- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp +++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp @@ -46,12 +46,11 @@ using namespace OSL; class DiffuseRampClosure : public CBSDFClosure { public: - DiffuseRampClosure() : CBSDFClosure(LABEL_DIFFUSE) {} Color3 colors[8]; float3 fcolors[8]; - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "diffuse_ramp"; } + DiffuseRampClosure() : CBSDFClosure(LABEL_DIFFUSE) + {} void setup() { @@ -62,21 +61,11 @@ public: fcolors[i] = TO_FLOAT3(colors[i]); } - bool mergeable(const ClosurePrimitive *other) const - { - return false; - } - void blur(float roughness) { bsdf_diffuse_ramp_blur(&sc, roughness); } - void print_on(std::ostream &out) const - { - out << name() << " ((" << sc.N[0] << ", " << sc.N[1] << ", " << sc.N[2] << "))"; - } - float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const { return bsdf_diffuse_ramp_eval_reflect(&sc, fcolors, omega_out, omega_in, &pdf); @@ -109,7 +98,7 @@ ClosureParam *closure_bsdf_diffuse_ramp_params() return params; } -CLOSURE_PREPARE(closure_bsdf_diffuse_ramp_prepare, DiffuseRampClosure) +CCLOSURE_PREPARE(closure_bsdf_diffuse_ramp_prepare, DiffuseRampClosure) CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp index ef656ee7d5f..c5851747b54 100644 --- a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp +++ b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp @@ -45,12 +45,11 @@ using namespace OSL; class PhongRampClosure : public CBSDFClosure { public: - PhongRampClosure() : CBSDFClosure(LABEL_GLOSSY) {} Color3 colors[8]; float3 fcolors[8]; - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "phong_ramp"; } + PhongRampClosure() : CBSDFClosure(LABEL_GLOSSY) + {} void setup() { @@ -61,21 +60,11 @@ public: fcolors[i] = TO_FLOAT3(colors[i]); } - bool mergeable(const ClosurePrimitive *other) const - { - return false; - } - void blur(float roughness) { bsdf_phong_ramp_blur(&sc, roughness); } - void print_on(std::ostream &out) const - { - out << name() << " ((" << sc.N[0] << ", " << sc.N[1] << ", " << sc.N[2] << "))"; - } - float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const { return bsdf_phong_ramp_eval_reflect(&sc, fcolors, omega_out, omega_in, &pdf); @@ -109,7 +98,7 @@ ClosureParam *closure_bsdf_phong_ramp_params() return params; } -CLOSURE_PREPARE(closure_bsdf_phong_ramp_prepare, PhongRampClosure) +CCLOSURE_PREPARE(closure_bsdf_phong_ramp_prepare, PhongRampClosure) CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp index 7d9fa81dbdd..02935542c56 100644 --- a/intern/cycles/kernel/osl/emissive.cpp +++ b/intern/cycles/kernel/osl/emissive.cpp @@ -50,18 +50,9 @@ using namespace OSL; /// outer_angle limit. It can also behave as a lambertian emitter /// if the provided angles are PI/2, which is the default /// -class GenericEmissiveClosure : public EmissiveClosure { +class GenericEmissiveClosure : public CClosurePrimitive { public: - GenericEmissiveClosure() { } - - void setup() {} - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "emission"; } - - void print_on(std::ostream &out) const - { - out << name() << "()"; - } + GenericEmissiveClosure() : CClosurePrimitive(Emissive) { } Color3 eval(const Vec3 &Ng, const Vec3 &omega_out) const { @@ -92,7 +83,7 @@ ClosureParam *closure_emission_params() return params; } -CLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure) +CCLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure) CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp index 975967c0bbb..94337290d20 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.cpp +++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp @@ -51,24 +51,14 @@ using namespace OSL; class CubicBSSRDFClosure : public CBSSRDFClosure { public: - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "bssrdf_cubic"; } + CubicBSSRDFClosure() + {} void setup() { sc.type = CLOSURE_BSSRDF_CUBIC_ID; sc.data0 = fabsf(average(radius)); } - - bool mergeable(const ClosurePrimitive *other) const - { - return false; - } - - void print_on(std::ostream &out) const - { - out << name() << " ((" << sc.N[0] << ", " << sc.N[1] << ", " << sc.N[2] << "))"; - } }; ClosureParam *closure_bssrdf_cubic_params() @@ -96,30 +86,20 @@ ClosureParam *closure_bssrdf_cubic_extended_params() return params; } -CLOSURE_PREPARE(closure_bssrdf_cubic_prepare, CubicBSSRDFClosure) +CCLOSURE_PREPARE(closure_bssrdf_cubic_prepare, CubicBSSRDFClosure) /* Gaussian */ class GaussianBSSRDFClosure : public CBSSRDFClosure { public: - size_t memsize() const { return sizeof(*this); } - const char *name() const { return "bssrdf_gaussian"; } + GaussianBSSRDFClosure() + {} void setup() { sc.type = CLOSURE_BSSRDF_GAUSSIAN_ID; sc.data0 = fabsf(average(radius)); } - - bool mergeable(const ClosurePrimitive *other) const - { - return false; - } - - void print_on(std::ostream &out) const - { - out << name() << " ((" << sc.N[0] << ", " << sc.N[1] << ", " << sc.N[2] << "))"; - } }; ClosureParam *closure_bssrdf_gaussian_params() @@ -146,7 +126,7 @@ ClosureParam *closure_bssrdf_gaussian_extended_params() return params; } -CLOSURE_PREPARE(closure_bssrdf_gaussian_prepare, GaussianBSSRDFClosure) +CCLOSURE_PREPARE(closure_bssrdf_gaussian_prepare, GaussianBSSRDFClosure) CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_bssrdf.h b/intern/cycles/kernel/osl/osl_bssrdf.h index fc1a4c587cc..6aee2c28ea8 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.h +++ b/intern/cycles/kernel/osl/osl_bssrdf.h @@ -37,20 +37,20 @@ #include <OSL/oslexec.h> #include <OSL/genclosure.h> +#include "osl_closures.h" + #include "kernel_types.h" #include "util_types.h" CCL_NAMESPACE_BEGIN -class CBSSRDFClosure : public OSL::ClosurePrimitive { +class CBSSRDFClosure : public CClosurePrimitive { public: ShaderClosure sc; float3 radius; - CBSSRDFClosure() : OSL::ClosurePrimitive(BSSRDF) { memset(&sc, 0, sizeof(sc)); } - ~CBSSRDFClosure() { } - + CBSSRDFClosure() : CClosurePrimitive(BSSRDF) { } int scattering() const { return LABEL_DIFFUSE; } }; diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index 221406a1716..340e4492584 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -171,25 +171,16 @@ BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission) /* Registration */ -static void generic_closure_setup(OSL::RendererServices *, int id, void *data) -{ - assert(data); - OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)data; - prim->setup(); -} - -static bool generic_closure_compare(int id, const void *dataA, const void *dataB) -{ - assert(dataA && dataB); - - OSL::ClosurePrimitive *primA = (OSL::ClosurePrimitive *)dataA; - OSL::ClosurePrimitive *primB = (OSL::ClosurePrimitive *)dataB; - return primA->mergeable(primB); -} - static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, OSL::ClosureParam *params, OSL::PrepareClosureFunc prepare) { - ss->register_closure(name, id, params, prepare, generic_closure_setup, generic_closure_compare); + /* optimization: it's possible to not use a prepare function at all and + * only initialize the actual class when accessing the closure component + * data, but then we need to map the id to the class somehow */ +#ifdef CLOSURE_PREPARE + ss->register_closure(name, id, params, prepare, NULL, NULL); +#else + ss->register_closure(name, id, params, prepare, NULL); +#endif } void OSLShader::register_closures(OSLShadingSystem *ss_) diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 6632c2c57e5..b6c38e01b23 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -66,36 +66,52 @@ void closure_westin_sheen_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data); -enum { - AmbientOcclusion = 100 -}; - -#define CLOSURE_PREPARE(name, classname) \ +#define CCLOSURE_PREPARE(name, classname) \ void name(RendererServices *, int id, void *data) \ { \ memset(data, 0, sizeof(classname)); \ new (data) classname(); \ } -#define CLOSURE_PREPARE_STATIC(name, classname) static CLOSURE_PREPARE(name, classname) +#define CCLOSURE_PREPARE_STATIC(name, classname) static CCLOSURE_PREPARE(name, classname) #define CLOSURE_FLOAT3_PARAM(st, fld) \ - { TypeDesc::TypeVector, reckless_offsetof(st, fld), NULL, sizeof(OSL::Vec3) } + { TypeDesc::TypeVector, reckless_offsetof(st, fld), NULL, sizeof(OSL::Vec3) } #define TO_VEC3(v) OSL::Vec3(v.x, v.y, v.z) #define TO_COLOR3(v) OSL::Color3(v.x, v.y, v.z) #define TO_FLOAT3(v) make_float3(v[0], v[1], v[2]) +/* Closure */ + +class CClosurePrimitive { +public: + enum Category { + BSDF, ///< Reflective and/or transmissive surface + BSSRDF, ///< Sub-surface light transfer + Emissive, ///< Light emission + Background, ///< Background emission + Volume, ///< Volume scattering + Holdout, ///< Holdout from alpha + AmbientOcclusion, ///< Ambient occlusion + }; + + CClosurePrimitive (Category category_) : category (category_) {} + virtual ~CClosurePrimitive() {} + virtual void setup() {} + + Category category; +}; + /* BSDF */ -class CBSDFClosure : public OSL::ClosurePrimitive { +class CBSDFClosure : public CClosurePrimitive { public: ShaderClosure sc; - CBSDFClosure(int scattering) : OSL::ClosurePrimitive(BSDF), + CBSDFClosure(int scattering) : CClosurePrimitive(BSDF), m_scattering_label(scattering), m_shaderdata_flag(0) - { memset(&sc, 0, sizeof(sc)); } - ~CBSDFClosure() { } + {} int scattering() const { return m_scattering_label; } int shaderdata_flag() const { return m_shaderdata_flag; } @@ -119,9 +135,9 @@ protected: \ class Upper##Closure : public CBSDFClosure { \ public: \ - Upper##Closure() : CBSDFClosure(TYPE) {} \ - size_t memsize() const { return sizeof(*this); } \ - const char *name() const { return #lower; } \ + Upper##Closure() : CBSDFClosure(TYPE) \ + { \ + } \ \ void setup() \ { \ @@ -129,21 +145,11 @@ public: \ m_shaderdata_flag = bsdf_##lower##_setup(&sc); \ } \ \ - bool mergeable(const ClosurePrimitive *other) const \ - { \ - return false; \ - } \ - \ void blur(float roughness) \ { \ bsdf_##svmlower##_blur(&sc, roughness); \ } \ \ - void print_on(std::ostream &out) const \ - { \ - out << name() << " ((" << sc.N[0] << ", " << sc.N[1] << ", " << sc.N[2] << "))"; \ - } \ -\ float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const \ { \ return bsdf_##svmlower##_eval_reflect(&sc, omega_out, omega_in, &pdf); \ @@ -178,7 +184,7 @@ static ClosureParam *bsdf_##lower##_params() \ return params; \ } \ \ -CLOSURE_PREPARE_STATIC(bsdf_##lower##_prepare, Upper##Closure) +CCLOSURE_PREPARE_STATIC(bsdf_##lower##_prepare, Upper##Closure) CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 309f5ded96d..d7d3301c0b0 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -44,6 +44,10 @@ #include "kernel_camera.h" #include "kernel_shader.h" +#ifdef WITH_PTEX +#include <Ptexture.h> +#endif + CCL_NAMESPACE_BEGIN /* RenderServices implementation */ @@ -98,10 +102,18 @@ OSLRenderServices::OSLRenderServices() { kernel_globals = NULL; osl_ts = NULL; + +#ifdef WITH_PTEX + size_t maxmem = 16384 * 1024; + ptex_cache = PtexCache::create(0, maxmem); +#endif } OSLRenderServices::~OSLRenderServices() { +#ifdef WITH_PTEX + ptex_cache->release(); +#endif } void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_, OSL::TextureSystem *osl_ts_) @@ -776,6 +788,45 @@ bool OSLRenderServices::texture(ustring filename, TextureOpt &options, OSL::TextureSystem *ts = osl_ts; ShaderData *sd = (ShaderData *)(sg->renderstate); KernelGlobals *kg = sd->osl_globals; + +#ifdef WITH_PTEX + /* todo: this is just a quick hack, only works with particular files and options */ + if(string_endswith(filename.string(), ".ptx")) { + float2 uv; + int faceid; + + if(!primitive_ptex(kg, sd, &uv, &faceid)) + return false; + + float u = uv.x; + float v = uv.y; + float dudx = 0.0f; + float dvdx = 0.0f; + float dudy = 0.0f; + float dvdy = 0.0f; + + Ptex::String error; + PtexPtr<PtexTexture> r(ptex_cache->get(filename.c_str(), error)); + + if(!r) { + //std::cerr << error.c_str() << std::endl; + return false; + } + + bool mipmaplerp = false; + float sharpness = 1.0f; + PtexFilter::Options opts(PtexFilter::f_bicubic, mipmaplerp, sharpness); + PtexPtr<PtexFilter> f(PtexFilter::getFilter(r, opts)); + + f->eval(result, options.firstchannel, options.nchannels, faceid, u, v, dudx, dvdx, dudy, dvdy); + + for(int c = r->numChannels(); c < options.nchannels; c++) + result[c] = result[0]; + + return true; + } +#endif + OSLThreadData *tdata = kg->osl_tdata; OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info; diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index f62895047b3..21609621b1d 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -28,6 +28,10 @@ #include <OSL/oslexec.h> #include <OSL/oslclosure.h> +#ifdef WITH_PTEX +class PtexCache; +#endif + CCL_NAMESPACE_BEGIN class Object; @@ -148,6 +152,9 @@ public: private: KernelGlobals *kernel_globals; OSL::TextureSystem *osl_ts; +#ifdef WITH_PTEX + PtexCache *ptex_cache; +#endif }; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index 18e8fee4348..f2be61eb535 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -146,7 +146,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, if (closure->type == OSL::ClosureColor::COMPONENT) { OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure; - OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data(); + CClosurePrimitive *prim = (CClosurePrimitive *)comp->data(); if (prim) { ShaderClosure sc; @@ -156,8 +156,10 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, sc.weight = weight; #endif - switch (prim->category()) { - case OSL::ClosurePrimitive::BSDF: { + prim->setup(); + + switch (prim->category) { + case CClosurePrimitive::BSDF: { CBSDFClosure *bsdf = (CBSDFClosure *)prim; int scattering = bsdf->scattering(); @@ -191,7 +193,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, } break; } - case OSL::ClosurePrimitive::Emissive: { + case CClosurePrimitive::Emissive: { /* sample weight */ float sample_weight = fabsf(average(weight)); @@ -208,7 +210,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, } break; } - case AmbientOcclusion: { + case CClosurePrimitive::AmbientOcclusion: { /* sample weight */ float sample_weight = fabsf(average(weight)); @@ -224,7 +226,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, } break; } - case OSL::ClosurePrimitive::Holdout: { + case CClosurePrimitive::Holdout: { sc.sample_weight = 0.0f; sc.type = CLOSURE_HOLDOUT_ID; sc.data0 = 0.0f; @@ -237,7 +239,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, } break; } - case OSL::ClosurePrimitive::BSSRDF: { + case CClosurePrimitive::BSSRDF: { CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim; float sample_weight = fabsf(average(weight)); @@ -280,10 +282,8 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, } break; } - case OSL::ClosurePrimitive::Debug: - break; /* not implemented */ - case OSL::ClosurePrimitive::Background: - case OSL::ClosurePrimitive::Volume: + case CClosurePrimitive::Background: + case CClosurePrimitive::Volume: break; /* not relevant */ } } @@ -332,9 +332,9 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure) if (closure->type == OSL::ClosureColor::COMPONENT) { OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure; - OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data(); + CClosurePrimitive *prim = (CClosurePrimitive *)comp->data(); - if (prim && prim->category() == OSL::ClosurePrimitive::Background) + if (prim && prim->category == CClosurePrimitive::Background) #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS return TO_FLOAT3(comp->w); #else @@ -387,7 +387,7 @@ static void flatten_volume_closure_tree(ShaderData *sd, if (closure->type == OSL::ClosureColor::COMPONENT) { OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure; - OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data(); + CClosurePrimitive *prim = (CClosurePrimitive *)comp->data(); if (prim) { ShaderClosure sc; @@ -397,8 +397,10 @@ static void flatten_volume_closure_tree(ShaderData *sd, sc.weight = weight; #endif - switch (prim->category()) { - case OSL::ClosurePrimitive::Volume: { + prim->setup(); + + switch (prim->category) { + case CClosurePrimitive::Volume: { /* sample weight */ float sample_weight = fabsf(average(weight)); @@ -413,13 +415,13 @@ static void flatten_volume_closure_tree(ShaderData *sd, sd->closure[sd->num_closure++] = sc; break; } - case OSL::ClosurePrimitive::Holdout: - case OSL::ClosurePrimitive::Debug: + case CClosurePrimitive::Holdout: break; /* not implemented */ - case OSL::ClosurePrimitive::Background: - case OSL::ClosurePrimitive::BSDF: - case OSL::ClosurePrimitive::Emissive: - case OSL::ClosurePrimitive::BSSRDF: + case CClosurePrimitive::Background: + case CClosurePrimitive::BSDF: + case CClosurePrimitive::Emissive: + case CClosurePrimitive::BSSRDF: + case CClosurePrimitive::AmbientOcclusion: break; /* not relevant */ } } @@ -509,25 +511,6 @@ void OSLShader::bsdf_blur(ShaderClosure *sc, float roughness) bsdf->blur(roughness); } -/* Emissive Closure */ - -float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc) -{ - OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure *)sc->prim; - OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I)); - - return TO_FLOAT3(emissive_eval); -} - -/* Volume Closure */ - -float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_in, const float3 omega_out) -{ - OSL::VolumeClosure *volume = (OSL::VolumeClosure *)sc->prim; - OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out)); - return TO_FLOAT3(volume_eval) * sc->weight; -} - /* Attributes */ int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem) diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h index 777ecb6af81..2520b703ab7 100644 --- a/intern/cycles/kernel/osl/osl_shader.h +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -66,11 +66,6 @@ public: const float3& omega_in, float& pdf); static void bsdf_blur(ShaderClosure *sc, float roughness); - static float3 emissive_eval(const ShaderData *sd, const ShaderClosure *sc); - - static float3 volume_eval_phase(const ShaderClosure *sc, - const float3 omega_in, const float3 omega_out); - /* attributes */ static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem); }; diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 47c5dc27f2b..d1d1222af44 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -412,13 +412,27 @@ matrix transpose (matrix m) BUILTIN; // Pattern generation -float step (float edge, float x) BUILTIN; color step (color edge, color x) BUILTIN; point step (point edge, point x) BUILTIN; vector step (vector edge, vector x) BUILTIN; normal step (normal edge, normal x) BUILTIN; +float step (float edge, float x) BUILTIN; float smoothstep (float edge0, float edge1, float x) BUILTIN; +float aastep (float edge, float s, float dedge, float ds) { + // Box filtered AA step + float width = fabs(dedge) + fabs(ds); + float halfwidth = 0.5*width; + float e1 = edge-halfwidth; + return (s <= e1) ? 0.0 : ((s >= (edge+halfwidth)) ? 1.0 : (s-e1)/width); +} +float aastep (float edge, float s, float ds) { + return aastep (edge, s, filterwidth(edge), ds); +} +float aastep (float edge, float s) { + return aastep (edge, s, filterwidth(edge), filterwidth(s)); +} + // Derivatives and area operators diff --git a/intern/cycles/kernel/svm/svm_fresnel.h b/intern/cycles/kernel/svm/svm_fresnel.h index bb70a3faa2a..0a3d576cfe1 100644 --- a/intern/cycles/kernel/svm/svm_fresnel.h +++ b/intern/cycles/kernel/svm/svm_fresnel.h @@ -39,10 +39,12 @@ ccl_device void svm_node_layer_weight(ShaderData *sd, float *stack, uint4 node) { uint blend_offset = node.y; uint blend_value = node.z; - float blend = (stack_valid(blend_offset))? stack_load_float(stack, blend_offset): __uint_as_float(blend_value); - uint type, out_offset; - decode_node_uchar4(node.w, &type, &out_offset, NULL, NULL); + uint type, normal_offset, out_offset; + decode_node_uchar4(node.w, &type, &normal_offset, &out_offset, NULL); + + float blend = (stack_valid(blend_offset))? stack_load_float(stack, blend_offset): __uint_as_float(blend_value); + float3 normal_in = (stack_valid(normal_offset))? stack_load_float3(stack, normal_offset): sd->N; float f; @@ -50,10 +52,10 @@ ccl_device void svm_node_layer_weight(ShaderData *sd, float *stack, uint4 node) float eta = fmaxf(1.0f - blend, 1e-5f); eta = (sd->flag & SD_BACKFACING)? eta: 1.0f/eta; - f = fresnel_dielectric_cos(dot(sd->I, sd->N), eta); + f = fresnel_dielectric_cos(dot(sd->I, normal_in), eta); } else { - f = fabsf(dot(sd->I, sd->N)); + f = fabsf(dot(sd->I, normal_in)); if(blend != 0.5f) { blend = clamp(blend, 0.0f, 1.0f-1e-5f); diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 319616450e1..6640439eca9 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -147,6 +147,10 @@ const char *Attribute::standard_name(AttributeStandard std) return "particle"; else if(std == ATTR_STD_CURVE_INTERCEPT) return "curve_intercept"; + else if(std == ATTR_STD_PTEX_FACE_ID) + return "ptex_face_id"; + else if(std == ATTR_STD_PTEX_UV) + return "ptex_uv"; return ""; } @@ -246,6 +250,12 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) case ATTR_STD_MOTION_POST: attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); 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; default: assert(0); break; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 4919222e81c..fcc92b641fd 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -217,6 +217,21 @@ ShaderNode *ImageTextureNode::clone() const return node; } +void ImageTextureNode::attributes(AttributeRequestSet *attributes) +{ +#ifdef WITH_PTEX + /* todo: avoid loading other texture coordinates when using ptex, + * and hide texture coordinate socket in the UI */ + if (string_endswith(filename, ".ptx")) { + /* ptex */ + attributes->add(ATTR_STD_PTEX_FACE_ID); + attributes->add(ATTR_STD_PTEX_UV); + } +#endif + + ShaderNode::attributes(attributes); +} + void ImageTextureNode::compile(SVMCompiler& compiler) { ShaderInput *vector_in = input("Vector"); @@ -352,6 +367,19 @@ ShaderNode *EnvironmentTextureNode::clone() const return node; } +void EnvironmentTextureNode::attributes(AttributeRequestSet *attributes) +{ +#ifdef WITH_PTEX + if (string_endswith(filename, ".ptx")) { + /* ptex */ + attributes->add(ATTR_STD_PTEX_FACE_ID); + attributes->add(ATTR_STD_PTEX_UV); + } +#endif + + ShaderNode::attributes(attributes); +} + void EnvironmentTextureNode::compile(SVMCompiler& compiler) { ShaderInput *vector_in = input("Vector"); @@ -3198,8 +3226,12 @@ LayerWeightNode::LayerWeightNode() void LayerWeightNode::compile(SVMCompiler& compiler) { + ShaderInput *normal_in = input("Normal"); ShaderInput *blend_in = input("Blend"); + if(normal_in->link) + compiler.stack_assign(normal_in); + if(blend_in->link) compiler.stack_assign(blend_in); @@ -3207,14 +3239,14 @@ void LayerWeightNode::compile(SVMCompiler& compiler) if(!fresnel_out->links.empty()) { compiler.stack_assign(fresnel_out); compiler.add_node(NODE_LAYER_WEIGHT, blend_in->stack_offset, __float_as_int(blend_in->value.x), - compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, fresnel_out->stack_offset)); + compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, normal_in->stack_offset, fresnel_out->stack_offset)); } ShaderOutput *facing_out = output("Facing"); if(!facing_out->links.empty()) { compiler.stack_assign(facing_out); compiler.add_node(NODE_LAYER_WEIGHT, blend_in->stack_offset, __float_as_int(blend_in->value.x), - compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, facing_out->stack_offset)); + compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, normal_in->stack_offset, facing_out->stack_offset)); } } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 430c37158f4..d7a110af83b 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -66,6 +66,7 @@ public: SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode) ~ImageTextureNode(); ShaderNode *clone() const; + void attributes(AttributeRequestSet *attributes); ImageManager *image_manager; int slot; @@ -87,6 +88,7 @@ public: SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode) ~EnvironmentTextureNode(); ShaderNode *clone() const; + void attributes(AttributeRequestSet *attributes); ImageManager *image_manager; int slot; diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index d0ed95cca34..4ed8ece0556 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -724,13 +724,17 @@ void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes) } while(!nodes_done); } -void OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type) +OSL::ShadingAttribStateRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type) { OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; current_type = type; +#if OSL_LIBRARY_VERSION_CODE >= 10501 + OSL::ShadingAttribStateRef group = ss->ShaderGroupBegin(shader->name.c_str()); +#else ss->ShaderGroupBegin(shader->name.c_str()); +#endif ShaderNode *output = graph->output(); set<ShaderNode*> dependencies; @@ -757,12 +761,19 @@ void OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty assert(0); ss->ShaderGroupEnd(); + +#if OSL_LIBRARY_VERSION_CODE >= 10501 + return group; +#else + OSL::ShadingAttribStateRef group = ss->state(); + ss->clear_state(); + return group; +#endif } void OSLCompiler::compile(OSLGlobals *og, Shader *shader) { if(shader->need_update) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; ShaderGraph *graph = shader->graph; ShaderNode *output = (graph)? graph->output(): NULL; @@ -788,19 +799,13 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader) /* generate surface shader */ if(shader->used && graph && output->input("Surface")->link) { - compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); - shader->osl_surface_ref = ss->state(); + shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); - if(shader->graph_bump) { - ss->clear_state(); - compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE); - shader->osl_surface_bump_ref = ss->state(); - } + if(shader->graph_bump) + shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE); else shader->osl_surface_bump_ref = shader->osl_surface_ref; - ss->clear_state(); - shader->has_surface = true; } else { @@ -810,21 +815,16 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader) /* generate volume shader */ if(shader->used && graph && output->input("Volume")->link) { - compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); + shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); shader->has_volume = true; - - shader->osl_volume_ref = ss->state(); - ss->clear_state(); } else shader->osl_volume_ref = OSL::ShadingAttribStateRef(); /* generate displacement shader */ if(shader->used && graph && output->input("Displacement")->link) { - compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); + shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); shader->has_displacement = true; - shader->osl_displacement_ref = ss->state(); - ss->clear_state(); } else shader->osl_displacement_ref = OSL::ShadingAttribStateRef(); diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index d6e514bdcaf..5824e2ace64 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -142,14 +142,16 @@ public: ImageManager *image_manager; private: +#ifdef WITH_OSL string id(ShaderNode *node); - void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type); + OSL::ShadingAttribStateRef compile_type(Shader *shader, ShaderGraph *graph, ShaderType type); bool node_skip_input(ShaderNode *node, ShaderInput *input); string compatible_name(ShaderNode *node, ShaderInput *input); string compatible_name(ShaderNode *node, ShaderOutput *output); void find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input); void generate_nodes(const set<ShaderNode*>& nodes); +#endif void *shadingsys; void *manager; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 6c15849d815..0805a685467 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -95,7 +95,7 @@ Session::~Session() wait(); } - if(display && params.output_path != "") { + if(display && !params.output_path.empty()) { tonemap(); progress.set_status("Writing Image", params.output_path); @@ -242,7 +242,7 @@ void Session::run_gpu() /* update scene */ update_scene(); - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); if(progress.get_cancel()) @@ -263,7 +263,7 @@ void Session::run_gpu() device->task_wait(); - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); /* update status and timing */ @@ -283,7 +283,7 @@ void Session::run_gpu() } } - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); tiles_written = update_progressive_refine(progress.get_cancel()); @@ -531,7 +531,7 @@ void Session::run_cpu() /* update scene */ update_scene(); - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); if(progress.get_cancel()) @@ -549,7 +549,7 @@ void Session::run_cpu() if(!params.background) need_tonemap = true; - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); } @@ -571,7 +571,7 @@ void Session::run_cpu() tonemap(); } - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); tiles_written = update_progressive_refine(progress.get_cancel()); @@ -592,7 +592,7 @@ void Session::run() if(!device->load_kernels(params.experimental)) { string message = device->error_message(); - if(message == "") + if(message.empty()) message = "Failed loading render kernel, see console for errors"; progress.set_status("Error", message); @@ -796,7 +796,7 @@ void Session::update_status_time(bool show_pause, bool show_done) } else { status = substatus; - substatus = ""; + substatus.clear(); } progress.set_status(status, substatus); 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__ */ - diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 6db532faf74..851c67b1189 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -462,7 +462,11 @@ ccl_device_inline float3 operator/=(float3& a, float f) ccl_device_inline float dot(const float3 a, const float3 b) { +#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) + return _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7F)); +#else return a.x*b.x + a.y*b.y + a.z*b.z; +#endif } ccl_device_inline float3 cross(const float3 a, const float3 b) @@ -475,7 +479,11 @@ ccl_device_inline float3 cross(const float3 a, const float3 b) ccl_device_inline float len(const float3 a) { +#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(a.m128, a.m128, 0x7F))); +#else return sqrtf(dot(a, a)); +#endif } ccl_device_inline float len_squared(const float3 a) @@ -487,7 +495,12 @@ ccl_device_inline float len_squared(const float3 a) ccl_device_inline float3 normalize(const float3 a) { +#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) + __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F)); + return _mm_div_ps(a.m128, norm); +#else return a/len(a); +#endif } #endif diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index 53603c54da0..61a16b63351 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -86,5 +86,24 @@ void string_split(vector<string>& tokens, const string& str, const string& separ tokens.push_back(token); } +bool string_endswith(const string& s, const char *end) +{ + size_t len = strlen(end); + + if(len > s.size()) + return 0; + else + return strncmp(s.c_str() + s.size() - len, end, len) == 0; +} + +string string_strip(const string& s) +{ + string result = s; + result.erase(0, result.find_first_not_of(' ')); + result.erase(result.find_last_not_of(' ') + 1); + return result; + +} + CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h index ee924340716..6808f085834 100644 --- a/intern/cycles/util/util_string.h +++ b/intern/cycles/util/util_string.h @@ -40,6 +40,8 @@ string string_printf(const char *format, ...) PRINTF_ATTRIBUTE; bool string_iequals(const string& a, const string& b); void string_split(vector<string>& tokens, const string& str, const string& separators = "\t "); +bool string_endswith(const string& s, const char *end); +string string_strip(const string& s); CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp index 345c76bdfab..79bf5fd26b7 100644 --- a/intern/cycles/util/util_system.cpp +++ b/intern/cycles/util/util_system.cpp @@ -101,9 +101,7 @@ string system_cpu_brand_string() replace_string(brand, "(TM)", ""); replace_string(brand, "(R)", ""); - size_t i; - if((i = brand.find(" ")) != string::npos) - brand = brand.substr(0, i); + brand = string_strip(brand); return brand; } @@ -195,6 +193,11 @@ bool system_cpu_support_sse3() return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3; } +bool system_cpu_support_sse41() +{ + CPUCapabilities& caps = system_cpu_capabilities(); + return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41; +} #else bool system_cpu_support_sse2() diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h index 333782c2d01..64cfa4906b3 100644 --- a/intern/cycles/util/util_system.h +++ b/intern/cycles/util/util_system.h @@ -26,6 +26,7 @@ string system_cpu_brand_string(); int system_cpu_bits(); bool system_cpu_support_sse2(); bool system_cpu_support_sse3(); +bool system_cpu_support_sse41(); CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index c53d67235f6..3fa1df6ab44 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -23,6 +23,12 @@ #endif +/* Bitness */ + +#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || defined(_M_X64) +#define __KERNEL_64_BIT__ +#endif + /* Qualifiers for kernel code shared by CPU and GPU */ #ifndef __KERNEL_GPU__ @@ -34,7 +40,11 @@ #if defined(_WIN32) && !defined(FREE_WINDOWS) #define ccl_device_inline static __forceinline +#ifdef __KERNEL_64_BIT__ #define ccl_align(...) __declspec(align(__VA_ARGS__)) +#else +#define ccl_align(...) /* not support for function arguments (error C2719) */ +#endif #define ccl_may_alias #else #define ccl_device_inline static inline __attribute__((always_inline)) @@ -47,12 +57,6 @@ #endif -/* Bitness */ - -#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || defined(_M_X64) -#define __KERNEL_64_BIT__ -#endif - /* SIMD Types */ #ifndef __KERNEL_GPU__ @@ -95,6 +99,10 @@ #include <tmmintrin.h> /* SSSE 3 */ #endif +#ifdef __KERNEL_SSE41__ +#include <smmintrin.h> /* SSE 4.1 */ +#endif + #else /* MinGW64 has conflicting declarations for these SSE headers in <windows.h>. @@ -199,7 +207,7 @@ struct ccl_align(16) int3 { __forceinline operator const __m128i&(void) const { return m128; } __forceinline operator __m128i&(void) { return m128; } #else -struct int3 { +struct ccl_align(16) int3 { int x, y, z, w; #endif @@ -219,7 +227,7 @@ struct ccl_align(16) int4 { __forceinline operator const __m128i&(void) const { return m128; } __forceinline operator __m128i&(void) { return m128; } #else -struct int4 { +struct ccl_align(16) int4 { int x, y, z, w; #endif @@ -267,7 +275,7 @@ struct ccl_align(16) float3 { __forceinline operator const __m128&(void) const { return m128; } __forceinline operator __m128&(void) { return m128; } #else -struct float3 { +struct ccl_align(16) float3 { float x, y, z, w; #endif @@ -287,7 +295,7 @@ struct ccl_align(16) float4 { __forceinline operator const __m128&(void) const { return m128; } __forceinline operator __m128&(void) { return m128; } #else -struct float4 { +struct ccl_align(16) float4 { float x, y, z, w; #endif diff --git a/intern/elbeem/intern/ntl_blenderdumper.cpp b/intern/elbeem/intern/ntl_blenderdumper.cpp index 4efff4337a6..ec05c25004d 100644 --- a/intern/elbeem/intern/ntl_blenderdumper.cpp +++ b/intern/elbeem/intern/ntl_blenderdumper.cpp @@ -164,7 +164,7 @@ int ntlBlenderDumper::renderScene( void ) boutfilename << ".bobj.gz"; gzf = gzopen(boutfilename.str().c_str(), "wb1"); // wb9 is slow for large meshes! if (!gzf) { - errMsg("ntlBlenderDumper::renderScene","Unable to open output '"<<boutfilename<<"' "); + errMsg("ntlBlenderDumper::renderScene","Unable to open output '" + boutfilename.str() + "' "); return 1; } // dont transform velocity output, this is handled in blender diff --git a/intern/elbeem/intern/particletracer.cpp b/intern/elbeem/intern/particletracer.cpp index 593b582d91f..2f1f5f8efbb 100644 --- a/intern/elbeem/intern/particletracer.cpp +++ b/intern/elbeem/intern/particletracer.cpp @@ -233,7 +233,7 @@ void ParticleTracer::checkDumpTextPositions(double simtime) { if(mDumpTextFile.length()>1) { boutfilename << mDumpTextFile << ".cpart2"; } else { - boutfilename << boutfilename <<"_particles" << ".cpart2"; + boutfilename << "_particles" << ".cpart2"; } debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" " , 7); diff --git a/intern/guardedalloc/intern/mmap_win.c b/intern/guardedalloc/intern/mmap_win.c index 6f03188a579..3096c589101 100644 --- a/intern/guardedalloc/intern/mmap_win.c +++ b/intern/guardedalloc/intern/mmap_win.c @@ -182,14 +182,14 @@ static void mmap_addtail(volatile mmapListBase *listbase, void *vlink) { struct mmapLink *link = vlink; - if (link == 0) return; - if (listbase == 0) return; + if (link == NULL) return; + if (listbase == NULL) return; link->next = 0; link->prev = listbase->last; if (listbase->last) ((struct mmapLink *)listbase->last)->next = link; - if (listbase->first == 0) listbase->first = link; + if (listbase->first == NULL) listbase->first = link; listbase->last = link; } @@ -197,8 +197,8 @@ static void mmap_remlink(volatile mmapListBase *listbase, void *vlink) { struct mmapLink *link = vlink; - if (link == 0) return; - if (listbase == 0) return; + if (link == NULL) return; + if (listbase == NULL) return; if (link->next) link->next->prev = link->prev; if (link->prev) link->prev->next = link->next; @@ -211,8 +211,8 @@ static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr) { MemMap *mm; - if (ptr == 0) return NULL; - if (listbase == 0) return NULL; + if (ptr == NULL) return NULL; + if (listbase == NULL) return NULL; mm = (MemMap *)listbase->first; while (mm) { diff --git a/intern/itasc/Armature.cpp b/intern/itasc/Armature.cpp index e6f5fda4066..0c736566b25 100644 --- a/intern/itasc/Armature.cpp +++ b/intern/itasc/Armature.cpp @@ -402,7 +402,7 @@ bool Armature::finalize() m_armlength = 0.0; for (i=0; i<m_neffector; i++) { length = 0.0; - KDL::SegmentMap::const_iterator sit = m_tree.getSegment(m_effectors[i].name); + KDL::SegmentMap::value_type const *sit = m_tree.getSegmentPtr(m_effectors[i].name); while (sit->first != "root") { Frame tip = sit->second.segment.pose(m_qKdl(sit->second.q_nr)); length += tip.p.Norm(); diff --git a/intern/itasc/kdl/tree.cpp b/intern/itasc/kdl/tree.cpp index 8776e43f5b4..a31ac79bdf5 100644 --- a/intern/itasc/kdl/tree.cpp +++ b/intern/itasc/kdl/tree.cpp @@ -64,7 +64,7 @@ bool Tree::addSegment(const Segment& segment, const std::string& segment_name, return false; pair<SegmentMap::iterator, bool> retval; //insert new element - TreeElement elem(segment, parent, nrOfJoints); + TreeElement elem(segment, *parent, nrOfJoints); std::pair<std::string, TreeElement> val(segment_name, elem); retval = segments.insert(val); diff --git a/intern/itasc/kdl/tree.hpp b/intern/itasc/kdl/tree.hpp index 82794f96b94..8f971200969 100644 --- a/intern/itasc/kdl/tree.hpp +++ b/intern/itasc/kdl/tree.hpp @@ -41,32 +41,28 @@ namespace KDL { //Forward declaration class TreeElement; -#if defined(__APPLE__) -# if MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 +#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 typedef std::map<std::string,TreeElement> SegmentMap; -# else - // Eigen allocator is needed for alignment of Eigen data types - typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<std::string, TreeElement> > > SegmentMap; -# endif /* MAC_OS_X_VERSION_MIN_REQUIRED */ #else // Eigen allocator is needed for alignment of Eigen data types typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<std::string, TreeElement> > > SegmentMap; #endif + class TreeElement { public: - TreeElement():q_nr(0) + TreeElement():q_nr(0),parent(0) {}; public: Segment segment; unsigned int q_nr; - SegmentMap::const_iterator parent; + SegmentMap::value_type const *parent; std::vector<SegmentMap::const_iterator > children; - TreeElement(const Segment& segment_in,const SegmentMap::const_iterator& parent_in,unsigned int q_nr_in) + TreeElement(const Segment& segment_in,const SegmentMap::value_type& parent_in,unsigned int q_nr_in) { q_nr=q_nr_in; segment=segment_in; - parent=parent_in; + parent=&parent_in; }; static TreeElement Root() { @@ -167,7 +163,15 @@ namespace KDL return segments.find(segment_name); }; + SegmentMap::value_type const* getSegmentPtr(const std::string& segment_name)const + { + SegmentMap::const_iterator it = segments.find(segment_name); + + if (it == segments.end()) + return 0; + return &*it; + }; const SegmentMap& getSegments()const { diff --git a/intern/itasc/kdl/treefksolverpos_recursive.cpp b/intern/itasc/kdl/treefksolverpos_recursive.cpp index 9103a2165bb..fd78c46f837 100644 --- a/intern/itasc/kdl/treefksolverpos_recursive.cpp +++ b/intern/itasc/kdl/treefksolverpos_recursive.cpp @@ -35,22 +35,22 @@ namespace KDL { int TreeFkSolverPos_recursive::JntToCart(const JntArray& q_in, Frame& p_out, const std::string& segmentName, const std::string& baseName) { - SegmentMap::const_iterator it = tree.getSegment(segmentName); - SegmentMap::const_iterator baseit = tree.getSegment(baseName); + SegmentMap::value_type const* it = tree.getSegmentPtr(segmentName); + SegmentMap::value_type const* baseit = tree.getSegmentPtr(baseName); if(q_in.rows() != tree.getNrOfJoints()) return -1; - else if(it == tree.getSegments().end()) //if the segment name is not found + else if(!it) //if the segment name is not found return -2; - else if(baseit == tree.getSegments().end()) //if the base segment name is not found + else if(!baseit) //if the base segment name is not found return -3; else{ - p_out = recursiveFk(q_in, it, baseit); - return 0; + p_out = recursiveFk(q_in, it, baseit); + return 0; } } - Frame TreeFkSolverPos_recursive::recursiveFk(const JntArray& q_in, const SegmentMap::const_iterator& it, const SegmentMap::const_iterator& baseit) + Frame TreeFkSolverPos_recursive::recursiveFk(const JntArray& q_in, SegmentMap::value_type const* it, SegmentMap::value_type const* baseit) { //gets the frame for the current element (segment) const TreeElement& currentElement = it->second; @@ -60,8 +60,7 @@ namespace KDL { } else{ Frame currentFrame = currentElement.segment.pose(((JntArray&)q_in)(currentElement.q_nr)); - SegmentMap::const_iterator parentIt = currentElement.parent; - return recursiveFk(q_in, parentIt, baseit) * currentFrame; + return recursiveFk(q_in, currentElement.parent, baseit) * currentFrame; } } diff --git a/intern/itasc/kdl/treefksolverpos_recursive.hpp b/intern/itasc/kdl/treefksolverpos_recursive.hpp index c22fe4af75b..2081f23a9ff 100644 --- a/intern/itasc/kdl/treefksolverpos_recursive.hpp +++ b/intern/itasc/kdl/treefksolverpos_recursive.hpp @@ -45,7 +45,7 @@ namespace KDL { private: const Tree tree; - Frame recursiveFk(const JntArray& q_in, const SegmentMap::const_iterator& it, const SegmentMap::const_iterator& baseit); + Frame recursiveFk(const JntArray& q_in, SegmentMap::value_type const* it, SegmentMap::value_type const* baseit); }; } diff --git a/intern/itasc/kdl/treejnttojacsolver.cpp b/intern/itasc/kdl/treejnttojacsolver.cpp index 624bbef7990..e8b4d385ab2 100644 --- a/intern/itasc/kdl/treejnttojacsolver.cpp +++ b/intern/itasc/kdl/treejnttojacsolver.cpp @@ -28,16 +28,16 @@ int TreeJntToJacSolver::JntToJac(const JntArray& q_in, Jacobian& jac, return -1; //Lets search the tree-element - SegmentMap::const_iterator it = tree.getSegments().find(segmentname); + SegmentMap::value_type const* it = tree.getSegmentPtr(segmentname); //If segmentname is not inside the tree, back out: - if (it == tree.getSegments().end()) + if (!it) return -2; //Let's make the jacobian zero: SetToZero(jac); - SegmentMap::const_iterator root = tree.getSegments().find("root"); + SegmentMap::value_type const* root = tree.getSegmentPtr("root"); Frame T_total = Frame::Identity(); Frame T_local, T_joint; diff --git a/intern/locale/SConscript b/intern/locale/SConscript index 42941e2105f..4136ac8237d 100644 --- a/intern/locale/SConscript +++ b/intern/locale/SConscript @@ -58,9 +58,9 @@ if env['WITH_BF_INTERNATIONAL']: os.makedirs(build_dir) msgfmt_tool = env.Clone() + msgfmt_tool.Append(LINKFLAGS = env['PLATFORM_LINKFLAGS']) + targetpath = root_build_dir + '/msgfmt' - if env['OURPLATFORM'] == 'darwin': - msgfmt_tool.Replace( LINKFLAGS = '/usr/lib/libgcc_s.1.dylib /usr/lib/libstdc++.6.dylib /usr/lib/libSystem.B.dylib') # only need these dependencies msgfmt_target = msgfmt_tool.Program(target = targetpath, source = ['msgfmt.cc']) diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h index dec4d0b1c30..32f97a21815 100644 --- a/intern/memutil/MEM_CacheLimiter.h +++ b/intern/memutil/MEM_CacheLimiter.h @@ -138,8 +138,8 @@ public: typedef size_t (*MEM_CacheLimiter_DataSize_Func) (void *data); typedef int (*MEM_CacheLimiter_ItemPriority_Func) (void *item, int default_priority); - MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func getDataSize_) - : getDataSize(getDataSize_) { + MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func data_size_func) + : data_size_func(data_size_func) { } ~MEM_CacheLimiter() { @@ -162,10 +162,16 @@ public: } size_t get_memory_in_use() { - if (getDataSize) - return total_size(); - else - return MEM_get_memory_in_use(); + size_t size = 0; + if (data_size_func) { + for (iterator it = queue.begin(); it != queue.end(); it++) { + size += data_size_func((*it)->get()->get_data()); + } + } + else { + size = MEM_get_memory_in_use(); + } + return size; } void enforce_limits() { @@ -188,15 +194,15 @@ public: if (!elem) break; - if (getDataSize) { - cur_size = getDataSize(elem->get()->get_data()); + if (data_size_func) { + cur_size = data_size_func(elem->get()->get_data()); } else { cur_size = mem_in_use; } if (elem->destroy_if_possible()) { - if (getDataSize) { + if (data_size_func) { mem_in_use -= cur_size; } else { @@ -207,15 +213,21 @@ public: } void touch(MEM_CacheLimiterHandle<T> * handle) { - queue.push_back(handle); - queue.erase(handle->me); - iterator it = queue.end(); - --it; - handle->me = it; + /* If we're using custom priority callback re-arranging the queue + * doesn't make much sense because we'll iterate it all to get + * least priority element anyway. + */ + if (item_priority_func == NULL) { + queue.push_back(handle); + queue.erase(handle->me); + iterator it = queue.end(); + --it; + handle->me = it; + } } void set_item_priority_func(MEM_CacheLimiter_ItemPriority_Func item_priority_func) { - getItemPriority = item_priority_func; + this->item_priority_func = item_priority_func; } private: @@ -223,41 +235,42 @@ private: typedef std::list<MEM_CacheElementPtr, MEM_Allocator<MEM_CacheElementPtr> > MEM_CacheQueue; typedef typename MEM_CacheQueue::iterator iterator; - size_t total_size() { - size_t size = 0; - for (iterator it = queue.begin(); it != queue.end(); it++) { - size+= getDataSize((*it)->get()->get_data()); - } - return size; - } - MEM_CacheElementPtr get_least_priority_destroyable_element(void) { if (queue.empty()) return NULL; - if (!getItemPriority) - return *queue.begin(); - MEM_CacheElementPtr best_match_elem = NULL; - int best_match_priority = 0; - iterator it; - int i; - - for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) { - MEM_CacheElementPtr elem = *it; - - if (!elem->can_destroy()) - continue; - /* by default 0 means highest priority element */ - /* casting a size type to int is questionable, - but unlikely to cause problems */ - int priority = -((int)(queue.size()) - i - 1); - priority = getItemPriority(elem->get()->get_data(), priority); - - if (priority < best_match_priority || best_match_elem == NULL) { - best_match_priority = priority; + if (!item_priority_func) { + for (iterator it = queue.begin(); it != queue.end(); it++) { + MEM_CacheElementPtr elem = *it; + if (!elem->can_destroy()) + continue; best_match_elem = elem; + break; + } + } + else { + int best_match_priority = 0; + iterator it; + int i; + + for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) { + MEM_CacheElementPtr elem = *it; + + if (!elem->can_destroy()) + continue; + + /* by default 0 means highest priority element */ + /* casting a size type to int is questionable, + but unlikely to cause problems */ + int priority = -((int)(queue.size()) - i - 1); + priority = item_priority_func(elem->get()->get_data(), priority); + + if (priority < best_match_priority || best_match_elem == NULL) { + best_match_priority = priority; + best_match_elem = elem; + } } } @@ -265,8 +278,8 @@ private: } MEM_CacheQueue queue; - MEM_CacheLimiter_DataSize_Func getDataSize; - MEM_CacheLimiter_ItemPriority_Func getItemPriority; + MEM_CacheLimiter_DataSize_Func data_size_func; + MEM_CacheLimiter_ItemPriority_Func item_priority_func; }; -#endif // __MEM_CACHELIMITER_H__ +#endif // __MEM_CACHELIMITER_H__ diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index ca999eab569..6383bbbb07f 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -431,3 +431,13 @@ void FallbackImpl::finishGLSLDraw(OCIO_GLSLDrawState * /*state*/) void FallbackImpl::freeGLState(struct OCIO_GLSLDrawState * /*state_r*/) { } + +const char *FallbackImpl::getVersionString(void) +{ + return "fallback"; +} + +int FallbackImpl::getVersionHex(void) +{ + return 0; +} diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc index 30668dff245..47ee3afddfd 100644 --- a/intern/opencolorio/ocio_capi.cc +++ b/intern/opencolorio/ocio_capi.cc @@ -338,3 +338,13 @@ void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state) { impl->freeGLState(state); } + +const char *OCIO_getVersionString(void) +{ + return impl->getVersionString(); +} + +int OCIO_getVersionHex(void) +{ + return impl->getVersionHex(); +} diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h index 5532ade1f3a..5abe104fcd4 100644 --- a/intern/opencolorio/ocio_capi.h +++ b/intern/opencolorio/ocio_capi.h @@ -193,6 +193,9 @@ int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorR void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state); void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state); +const char *OCIO_getVersionString(void); +int OCIO_getVersionHex(void); + #ifdef __cplusplus } #endif diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc index 2cffe1a89ef..663ca2d1c75 100644 --- a/intern/opencolorio/ocio_impl.cc +++ b/intern/opencolorio/ocio_impl.cc @@ -609,3 +609,13 @@ void OCIOImpl::matrixTransformScale(float *m44, float *offset4, const float *sca { MatrixTransform::Scale(m44, offset4, scale4f); } + +const char *OCIOImpl::getVersionString(void) +{ + return GetVersion(); +} + +int OCIOImpl::getVersionHex(void) +{ + return GetVersionHex(); +} diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h index 8b666e8ae14..4e7c1bcc832 100644 --- a/intern/opencolorio/ocio_impl.h +++ b/intern/opencolorio/ocio_impl.h @@ -110,6 +110,9 @@ public: OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide) = 0; virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0; virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0; + + virtual const char *getVersionString(void) = 0; + virtual int getVersionHex(void) = 0; }; class FallbackImpl : public IOCIOImpl { @@ -194,6 +197,9 @@ public: OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide); void finishGLSLDraw(struct OCIO_GLSLDrawState *state); void freeGLState(struct OCIO_GLSLDrawState *state_r); + + const char *getVersionString(void); + int getVersionHex(void); }; #ifdef WITH_OCIO @@ -279,6 +285,9 @@ public: OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide); void finishGLSLDraw(struct OCIO_GLSLDrawState *state); void freeGLState(struct OCIO_GLSLDrawState *state_r); + + const char *getVersionString(void); + int getVersionHex(void); }; #endif |