Hi Peter,
See attachment for the full source code. I changed based on the
'MyNode.cpp' ( the one that I got problem with SceneView_knob last time ).
To clear any unknown compilation problem, I made the build in command line
with:
C:\build > cl.exe /I"C:\Program Files\Nuke7.0v1\include" /EHsc MyNode.cpp
/link /dll /OUT:MyNode.dll "C:\Program Files\Nuke7.0v1\DDImage.lib"
I also tried to add "/Zi" and linker flag "/DEBUG" to get
the accessible calling stack.
To replicate the crash:
- compiler MyNode.cpp
- create MyNode, type some letters in the 'file path'
- select some of the items in SceneView_knob, switch viewer to 3D --> crash
OR:
- create MyNode, connect to 'Scene', then connect to 'ScanlineRender', then
connect to 'viewer'
- press the 'calc hash' button in the panel --> crash
OR:
- create MyNode, connect to 'Scene', then connect to 'ScanlineRender', then
connect to 'viewer'
- save the scene
- launch Nuke 7 and load the scene --> crash
Here is the call stack:
> ntdll.dll!0000000077a932d0()
[Frames below may be incorrect and/or missing, no symbols loaded for
ntdll.dll]
kernel32.dll!00000000774d300a()
MyNode.dll!free(void * pBlock) Line 51 C
MyNode.dll!std::allocator<unsigned int>::deallocate(unsigned int * _Ptr,
unsigned __int64 __formal) Line 183 C++
MyNode.dll!std::vector<unsigned int,std::allocator<unsigned int>
>::_Tidy() Line 1309 C++
MyNode.dll!std::vector<unsigned int,std::allocator<unsigned int>
>::~vector<unsigned int,std::allocator<unsigned int> >() Line 705 + 0xa
bytes C++
MyNode.dll!MyNode::calcHash() Line 143 C++
MyNode.dll!MyNode::knob_changed(DD::Image::Knob * k) Line 207 C++
Nuke7.0.exe!00000001405af0e4()
Nuke7.0.exe!00000001405aea57()
Nuke7.0.exe!000000014092f2c4()
Nuke7.0.exe!0000000140930737()
QtCore4.dll!000000007274af1f()
QtGui4.dll!0000000071ae5f13()
QtGui4.dll!00000000718a1c0f()
QtGui4.dll!00000000718a3303()
QtGui4.dll!00000000718a35ea()
QtGui4.dll!00000000715dac05()
QtGui4.dll!00000000715903b6()
QtGui4.dll!000000007159210c()
Nuke7.0.exe!0000000140615c2e()
QtCore4.dll!0000000072737d92()
QtGui4.dll!000000007159163e()
QtGui4.dll!00000000715f2808()
QtGui4.dll!00000000715f5146()
user32.dll!00000000775e9bd1()
user32.dll!00000000775e98da()
QtCore4.dll!000000007275d05a()
QtGui4.dll!00000000715f46e5()
QtCore4.dll!000000007273734a()
QtCore4.dll!000000007273b450()
Nuke7.0.exe!0000000140603fe7()
Nuke7.0.exe!0000000140cd1f29()
Nuke7.0.exe!00000001410f3d16()
Nuke7.0.exe!0000000140cee3f6()
I might use SceneView_knob in a wrong way.
Thanks a lot,
Shing
On Mon, Dec 17, 2012 at 10:49 PM, Chishing Yip <[email protected]>wrote:
> Hi Peter,
>
> The suggested wrapper functions can be added to existing SceneView_KnobI
> interface without removing the STL version, my plugin runs fine on Linux
> and OSX with getSelectedItems() and getImportedItems() .
>
> I will dump the backtrace when I back to the office tomorrow ( GMT+8 ) and
> send the sample code to you asap.
>
> Best,
> Shing
>
>
>
> On Mon, Dec 17, 2012 at 10:11 PM, Peter Crossley <
> [email protected]> wrote:
>
>> Hi Shing,
>>
>> The additions to the interface you've detailed seem like a reasonable
>> request, however we can't break NDK compatibility until the next major
>> release. I would suggest you contact [email protected] directly
>> with a feature request for this.
>>
>> I would also like to get to the bottom of your crashes. There shouldn't
>> be any problems calling these functions unless you're mixing crt versions.
>>
>> Would it be possible for you to send us a code sample that causes the
>> crash?
>>
>> Regards,
>>
>> Peter.
>>
>>
>> On 17/12/2012 13:12, Chishing Yip wrote:
>>
>> Hi Tom,
>>
>> Thanks a lot for your reply.
>> We always make release build on windows, we have developed windows pluginfor
>> two years without any
>> STL/compiler version problem in Nuke 6.3, this problem is new to us.
>>
>> As I can see SceneView_knob is the only one that has this problem so
>> far in our plugins, is adding few wrappers an alternative? e.g. we are
>> using:
>> const std::vector< std::string >& SceneView_KnobI::menus() const;
>> const std::vector< std::string >& SceneView_KnobI::getItemNames() const;
>> void SceneView_KnobI::getImportedItems( std::vector< unsigned int >&
>> items ) const;
>> void SceneView_KnobI::getSelectedItems( std::vector< unsigned int >&
>> items ) const;
>>
>> but we could also do the same thing without any STL interface if we
>> could have wrappers like these:
>>
>> unsigned int SceneView_KnobI::numOfMenus() const;
>> const char* SceneView_KnobI::getMenuItem( unsigned int menuIndex ) const;
>>
>> unsigned int SceneView_KnobI::numOfItemNames() const;
>> const char* SceneView_KnobI::getItemName( unsigned int itemIndex ) const;
>>
>> unsigned int SceneView_KnobI::numOfItems() const;
>> bool SceneView_KnobI::isImportedItem( unsigned int itemIndex ) const;
>> bool SceneView_KnobI::isSelectedItem( unsigned int itemIndex ) const;
>>
>> in the private implementation in SceneView_KnobI.cpp ( or any private .
>> cpp implementation inside Nuke ):
>>
>> unsigned int SceneView_KnobI::numOfMenus() const
>> {
>> return menu.size();
>> }
>> const char* SceneView_KnobI::getMenuItem( unsigned int menuIndex ) const
>> {
>> return menu[ menuIndex ].c_str();
>> }
>>
>> unsigned int SceneView_KnobI::numOfItemNames() const
>> {
>> return getItemNames.size();
>> }
>> const char* SceneView_KnobI::getItemName( unsigned int itemIndex ) const
>> {
>> return getItemNames[ menuIndex ].c_str();
>> }
>>
>> unsigned int SceneView_KnobI::numOfItems() const
>> {
>> return /* the total items scene view knob holds*/ ;
>> }
>> bool SceneView_KnobI::isImportedItem( unsigned int itemIndex ) const
>> {
>> return /*if getImportedItems() contains the input itemIndex or not*/;
>> }
>> bool SceneView_KnobI::isSelectedItem( unsigned int itemIndex ) const
>> {
>> return /*if getSelectedItems() contains the input itemIndex or not*/;
>> }
>>
>> In this way, we don't need to deal with any STL interface but we could
>> construct the item list inside our plugin by ourselves, so there won't
>> be any STL compatibility issue between Nuke and any 3rd party plugins,
>> and since these are all wrappers I don't think that's difficult to
>> implement.
>>
>> We understand the API in Nuke 7.0 has been frozen, if above suggestion is
>> an acceptable alternative, we could wait until Nuke 7.1 release, what do
>> you think?
>>
>> Thanks again for your reply.
>> Best,
>> Shing
>> --
>> Zhicheng YE - Shing
>> the /*jupiter jazz*/ group - visual research
>> mercenaries of jupiter jazz limited - hong kong
>> www.jupiter-jazz.com
>>
>>
>> On Mon, Dec 17, 2012 at 6:58 AM, Tom Ward <[email protected]> wrote:
>>
>>> Hi Paolo,
>>>
>>> The version of VS2010 that Nuke is compiled against is indeed
>>> 16.00.30319.01 and as far as I know there have been no breaking CRT
>>> changes in 2010 (unlike 2005) so don't think that would be the problem
>>>
>>> Are you definitely always linking against the release version of the
>>> CRT? As we don't ship the debug versions of DDImage (or Nuke) you need to
>>> always build release versions of your plugins for Windows, not doing so
>>> usually results in STL problems like you're apparently seeing.
>>>
>>> Hope that helps
>>>
>>> Tom
>>>
>>> On Sun, Dec 16, 2012 at 12:33 PM, Paolo Berto
>>> <[email protected]>wrote:
>>>
>>>> Hi Fellaz,
>>>>
>>>> we mailed on nuke-dev but got no answers.
>>>>
>>>> In a nutshell, we have a plugin which uses SceneView_knob in Nuke
>>>> 7.0, it always crashes after accessing SceneView_KnobI::getSelectedItems()
>>>> or SceneView_KnobI::getImportedItems(), to us this looks like a STL version
>>>> related problem.
>>>>
>>>> Our compiler version:
>>>>
>>>> > cl.exe
>>>> Microsoft (R) C/C++ Optimizing Compiler Version 16.00.30319.01 for
>>>> x64
>>>> > link.exe
>>>> Microsoft (R) Incremental Linker Version 10.00.30319.01 for x64
>>>>
>>>> We installed MSVC 2010, without SDK 7.1, without 2010 SP1.
>>>>
>>>> How can we setup the correct development environment for Nuke 7.0 ?
>>>> Which compiler ( and /exact/ version ) Nuke 7.0 was compiled against?
>>>>
>>>> Best,
>>>>
>>>>
>>>> --
>>>> pbd
>>>>
>>>> paolo berto durante
>>>> space cowboy // jupiter jazz ltd // hong kong
>>>> https://atomkraft.hk
>>>> --
>>>>
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Tom Ward, Software Engineer
>>> The Foundry, 6th Floor, The Communications Building,
>>> 48 Leicester Square, London, UK, WC2H 7LT
>>> Tel: +44 (0)20 7434 0449 <%2B44%20%280%2920%207434%200449> Web:
>>> www.thefoundry.co.uk
>>>
>>> The Foundry Visionmongers Ltd.
>>> Registered in England and Wales No: 4642027
>>>
>>>
>>
>> --
>>
>>
>>
>>
>>
>
>
// Sphere.C
// Copyright (c) 2009 The Foundry Visionmongers Ltd. All Rights Reserved.
static const char* const CLASS = "MyNode";
static const char* const HELP = "Generates a 3D sphere";
#include <DDImage/SourceGeo.h>
#include <DDImage/Scene.h>
#include <DDImage/Triangle.h>
#include <DDImage/Knobs.h>
#include <DDImage/Knob.h>
#include <DDImage/SceneView_KnobI.h>
#include <DDImage/Channel3D.h>
#include <assert.h>
using namespace DD::Image;
#ifndef mFnStringize
#define mFnStringize2(A) # A
#define mFnStringize(A) mFnStringize2(A)
#endif
#define MAX_SPHERE_TESSELATION 512
class MyNode : public SourceGeo
{
private:
const char* filename;
SceneView_KnobI* mySceneViewKnob;
int initvalue;
double radius;
int columns, rows;
double my_u_extent, my_v_extent;
bool close_top, close_bottom;
// local matrix that Axis_Knob fills in
Matrix4 _local;
bool fix;
Knob* _pAxisKnob;
Hash sceneViewHash_;
protected:
void _validate(bool for_real)
{
// Clamp the mesh size to reasonable numbers:
columns = MIN(MAX(columns, 3), MAX_SPHERE_TESSELATION);
rows = MIN(MAX(rows, 3), MAX_SPHERE_TESSELATION);
my_u_extent = clamp( my_u_extent, 0.001, 360.0 );
my_v_extent = clamp( my_v_extent, 0.001, 180.0 );
SourceGeo::_validate(for_real);
}
public:
static const Description description;
const char* Class() const { return CLASS; }
const char* node_help() const { return HELP; }
MyNode(Node* node) : SourceGeo(node)
{
filename = "";
mySceneViewKnob = NULL;
int initvalue = 0;
radius = 1.0;
rows = columns = 30;
close_top = close_bottom = true;
my_u_extent = 360.0;
my_v_extent = 180.0;
_local.makeIdentity();
fix = false;
_pAxisKnob = NULL;
sceneViewHash_.reset( 0 );
}
void knobs(Knob_Callback f)
{
File_knob( f, &filename, "file" );
Divider( f);
static const char* const initnames[] = { 0x0 };
Knob* k = SceneView_knob( f, &initvalue, initnames, "my_scene_view", "" );
SetFlags( f, Knob::SAVE_MENU | Knob::ALWAYS_SAVE | Knob::KNOB_CHANGED_RECURSIVE);
mySceneViewKnob = k->sceneViewKnob();
Button( f, "calc_hash", "calc hash" );
Divider( f);
BeginClosedGroup( f, "group" );
SourceGeo::knobs(f);
Int_knob(f, &rows, "rows", "rows/columns");
Tooltip(f, "The maximum rows is "mFnStringize(MAX_SPHERE_TESSELATION));
Int_knob(f, &columns, "columns", "");
Tooltip(f, "The maximum columns is "mFnStringize(MAX_SPHERE_TESSELATION));
Double_knob(f, &radius, "radius");
Double_knob(f, &my_u_extent, "u_extent", "u extent" );
Double_knob(f, &my_v_extent, "v_extent", "v extent" );
Newline(f);
Bool_knob(f, &close_top, "close_top", "close top");
Bool_knob(f, &close_bottom, "close_bottom", "close bottom");
Obsolete_knob(f, "create_uvs", 0);
Obsolete_knob(f, "create_normals", 0);
Divider( f);
// transform knobs
_pAxisKnob = Axis_knob(f, &_local, "transform");
if (_pAxisKnob != NULL) {
if (GeoOp::selectable() == true)
_pAxisKnob->enable();
else
_pAxisKnob->disable();
}
// This knob is set by knob_default so that all new instances execute
// the "fix" code, which rotates the sphere 180 degrees so that the
// seam is on the far side from the default camera position.
Bool_knob(f, &fix, "fix", INVISIBLE);
EndGroup( f );
}
Hash calcHash() const
{
Hash myhash;
if ( mySceneViewKnob ) {
std::vector<unsigned int> selectedItems;
mySceneViewKnob->getSelectedItems( selectedItems );
std::size_t numItems = selectedItems.size();
for ( std::size_t i = 0; i < numItems; ++i ) {
myhash.append( selectedItems[ i ] );
}
}
return myhash;
}
void resetMySceneViewKnob()
{
std::vector< std::string > items;
if ( !filename || !strlen( filename ) ) {
mySceneViewKnob->menu( items );
return;
}
// FIXME: hard code all items, treat as loading from file
items.push_back( "/root/group1/item1" );
items.push_back( "/root/group1/item2" );
items.push_back( "/root/group1/item3" );
items.push_back( "/root/group2/item4" );
items.push_back( "/root/group2/item5" );
items.push_back( "/root/group2/item6" );
items.push_back( "/root/group3/item7" );
items.push_back( "/root/group3/item8" );
items.push_back( "/root/group3/item9" );
// set menu items
mySceneViewKnob->menu( items );
std::vector< unsigned int > selectedItems;
mySceneViewKnob->getSelectedItems( selectedItems );
std::cerr << "when script is loaded, size of previous selectedItems is " << selectedItems.size() << std::endl;
std::vector< unsigned int > importedItems;
for ( int i = 0; i < 9; ++i ) {
importedItems.push_back( i );
}
// set imported items
mySceneViewKnob->setImportedItems( importedItems );
// Restore old selected items.
mySceneViewKnob->setSelectedItems( selectedItems );
}
/*! The will handle the knob changes.
*/
int knob_changed(Knob* k)
{
if (k != NULL) {
if (strcmp(k->name(), "selectable") == 0) {
if (GeoOp::selectable() == true)
_pAxisKnob->enable();
else
_pAxisKnob->disable();
return 1;
}
if ( k->is( "calc_hash" ) ) {
Hash h = calcHash();
if ( sceneViewHash_ != h ) {
sceneViewHash_ = h;
}
}
if ( k->is( "file" ) ) {
resetMySceneViewKnob();
return 1;
}
if ( k == &Knob::showPanel ) {
resetMySceneViewKnob();
}
}
return SourceGeo::knob_changed(k);
}
// Hash up knobs that affect the Sphere:
void get_geometry_hash()
{
SourceGeo::get_geometry_hash(); // Get all hashes up-to-date
// Knobs that change the geometry structure:
geo_hash[Group_Primitives].append(columns);
geo_hash[Group_Primitives].append(rows);
geo_hash[Group_Primitives].append(close_top);
geo_hash[Group_Primitives].append(close_bottom);
// Knobs that change the point locations:
geo_hash[Group_Points].append(radius);
geo_hash[Group_Points].append(columns);
geo_hash[Group_Points].append(rows);
geo_hash[Group_Points].append(close_top);
geo_hash[Group_Points].append(close_bottom);
// Knobs that change the vertex attributes:
geo_hash[Group_Attributes].append(my_u_extent);
geo_hash[Group_Attributes].append(my_v_extent);
geo_hash[Group_Matrix].append(_local.a00);
geo_hash[Group_Matrix].append(_local.a01);
geo_hash[Group_Matrix].append(_local.a02);
geo_hash[Group_Matrix].append(_local.a03);
geo_hash[Group_Matrix].append(_local.a10);
geo_hash[Group_Matrix].append(_local.a11);
geo_hash[Group_Matrix].append(_local.a12);
geo_hash[Group_Matrix].append(_local.a13);
geo_hash[Group_Matrix].append(_local.a20);
geo_hash[Group_Matrix].append(_local.a21);
geo_hash[Group_Matrix].append(_local.a22);
geo_hash[Group_Matrix].append(_local.a23);
geo_hash[Group_Matrix].append(_local.a30);
geo_hash[Group_Matrix].append(_local.a31);
geo_hash[Group_Matrix].append(_local.a32);
geo_hash[Group_Matrix].append(_local.a33);
// append to hash
geo_hash[Group_Primitives].append(filename);
SceneView_KnobI* p( knob( "my_scene_view" )->sceneViewKnob() );
const std::vector<std::string>& items( p->getItemNames() );
for ( unsigned int i = 0; i < items.size(); ++i ) {
geo_hash[Group_Primitives].append( items[i] );
}
std::vector<unsigned int> selectedItems;
p->getSelectedItems( selectedItems );
for ( std::size_t i = 0; i < selectedItems.size(); ++i ) {
geo_hash[Group_Primitives].append( selectedItems[ i ] );
}
geo_hash[Group_Primitives].append( calcHash() );
}
// Apply the concat matrix to all the GeoInfos.
void geometry_engine(Scene& scene, GeometryList& out)
{
SourceGeo::geometry_engine(scene, out);
// multiply the node matrix
for (unsigned i = 0; i < out.size(); i++)
out[i].matrix = _local * out[i].matrix;
}
void create_geometry(Scene& scene, GeometryList& out)
{
int obj = 0;
unsigned num_points = (close_bottom ? 1 : 0) + (rows - 1) * columns + (close_top ? 1 : 0);
//=============================================================
// Build the primitives:
if (rebuild(Mask_Primitives)) {
out.delete_objects();
out.add_object(obj);
// Create poly primitives:
// Bottom endcap:
if (close_bottom) {
int j1 = 1;
for (int i = 0; i < columns; i++) {
int i0 = i % columns;
int i1 = (i + 1) % columns;
out.add_primitive(obj, new Triangle(0, i1 + j1, i0 + j1));
}
}
// Create the center poly mesh:
for (int j = 0; j < rows - 2; j++) {
int j0 = j * columns + (close_bottom ? 1 : 0);
int j1 = (j + 1) * columns + (close_bottom ? 1 : 0);
for (int i = 0; i < columns; i++) {
int i0 = i % columns;
int i1 = (i + 1) % columns;
// Create 2 triangles:
out.add_primitive(obj, new Triangle(i0 + j0, i1 + j0, i0 + j1));
out.add_primitive(obj, new Triangle(i0 + j1, i1 + j0, i1 + j1));
}
}
// Top endcap:
if (close_top) {
int top_point = num_points - 1;
int j0 = (close_bottom ? 1 : 0) + (rows - 2) * columns;
for (int i = 0; i < columns; i++) {
int i0 = i % columns;
int i1 = (i + 1) % columns;
out.add_primitive(obj, new Triangle(i0 + j0, i1 + j0, top_point));
}
}
// Force points and attributes to update:
set_rebuild(Mask_Points | Mask_Attributes);
}
//=============================================================
// Create points and assign their coordinates:
if (rebuild(Mask_Points)) {
// Generate points:
PointList* points = out.writable_points(obj);
points->resize(num_points);
// Assign the point locations:
int p = 0;
// Bottom center:
if (close_bottom)
(*points)[p++].set(0.0f, -radius, 0.0f);
// Middle mesh:
float drho = M_PI / rows;
float dtheta = (2.0 * M_PI) / columns;
float fix = this->fix ? -1 : 1;
for (int j = 1; j < rows; j++) {
float rho = j * drho;
for (int i = 0; i < columns; i++) {
float theta = i * dtheta;
float x = fix * sinf(theta) * sinf(rho);
float y = -cosf(rho);
float z = fix * cosf(theta) * sinf(rho);
(*points)[p].set(x * radius, y * radius, z * radius);
++p;
}
}
// Top center:
if (close_top)
(*points)[p].set(0.0f, radius, 0.0f);
}
//=============================================================
// Assign the normals and uvs:
if (rebuild(Mask_Attributes)) {
GeoInfo& info = out[obj];
//---------------------------------------------
// NORMALS:
const Vector3* PNTS = info.point_array();
Attribute* N = out.writable_attribute(obj, Group_Points, "N", NORMAL_ATTRIB);
assert(N);
for (unsigned p = 0; p < num_points; p++)
N->normal(p) = PNTS[p] / radius;
//---------------------------------------------
// UVs:
const Primitive** PRIMS = info.primitive_array();
Attribute* uv = out.writable_attribute(obj, Group_Vertices, "uv", VECTOR4_ATTRIB);
assert(uv);
float ds = (360.0f / float(my_u_extent)) / float(columns); // U change per column
float ss = 0.5f - (360.0f / float(my_u_extent)) / 2.0f; // Starting U
float dt = (180.0f / float(my_v_extent)) / float(rows); // V change per row
float st = 0.5 - (180.0 / my_v_extent) / 2.0; // Starting V
float s, t; // Current UV
t = st;
// Bottom center:
if (close_bottom) {
s = ss;
for (int i = 0; i < columns; i++) {
unsigned v = (*PRIMS++)->vertex_offset();
uv->vector4(v++).set( s, 0.0f, 0.0f, 1.0f);
uv->vector4(v++).set(s + ds, t + dt, 0.0f, 1.0f);
uv->vector4(v++).set( s, t + dt, 0.0f, 1.0f);
s += ds;
}
t += dt;
}
// Create the poly mesh in center:
for (int j = 0; j < rows - 2; j++) {
s = ss;
for (int i = 0; i < columns; i++) {
unsigned v = (*PRIMS++)->vertex_offset();
uv->vector4(v++).set( s, t, 0.0f, 1.0f);
uv->vector4(v++).set(s + ds, t, 0.0f, 1.0f);
uv->vector4(v++).set( s, t + dt, 0.0f, 1.0f);
v = (*PRIMS++)->vertex_offset();
uv->vector4(v++).set( s, t + dt, 0.0f, 1.0f);
uv->vector4(v++).set(s + ds, t, 0.0f, 1.0f);
uv->vector4(v++).set(s + ds, t + dt, 0.0f, 1.0f);
s += ds;
}
t += dt;
}
// Top endcap:
if (close_top) {
s = ss;
for (int i = 0; i < columns; i++) {
unsigned v = (*PRIMS++)->vertex_offset();
uv->vector4(v++).set( s, t, 0.0f, 1.0f);
uv->vector4(v++).set(s + ds, t, 0.0f, 1.0f);
uv->vector4(v++).set( s, 1.0f, 0.0f, 1.0f);
s += ds;
}
}
}
}
// virtual
void build_handles(ViewerContext* ctx)
{
// call build_matrix_handle to multiply the context model matrix with the local matrix so the
// nodes above it will display correctly
build_matrix_handles(ctx, _local);
}
};
static Op* build(Node* node) { return new MyNode(node); }
const Op::Description MyNode::description(CLASS, build);
// end of Sphere.C
_______________________________________________
Nuke-dev mailing list
[email protected], http://forums.thefoundry.co.uk/
http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev