Hello again, This might be a bit of a long shot but I have noticed that in the Autodesk.max.dll from 2014+ the [] operator has gone missing from IBitArray. I know you no longer develop this so I’ve got a question about a workaround I was trying to use: I wanted to use EnumSet(IBitArrayCallback cb) method. However I seem to be unable to create a valid class that inherits from IBitArrayCallback. I get a 'System.InvalidCastException' error: Unable to cast object of type 'TestNewAssembly.TestCallback' to type 'Autodesk.Max.IImplementable'. IBitArray selVert = mesh.VertSel; TestCallback test = new TestCallback(); selVert.EnumSet(test); ... public class TestCallback : IBitArrayCallback { public void Proc(int n) {} public bool Equals(IBitArrayCallback other) {return false;} public void Dispose() {} public IntPtr NativePointer {get { return IntPtr.Zero; }} } This is the same error as when I tried to inherit from IRestoreObj instead of Autodesk.Max.Plugins.RestoreObj. But I can’t find another (I)BitArrayCallback class to inherit from… I’ve checked the Max SDK samples and they only inherit Proc(int n) but I get Equals, Dispose and NativePointer too. So I have a feeling I’m inheriting from the wrong class again but don’t know which one is the correct one? Also, do you know why the [] operator would’ve been removed from 2014+ .net SDK? The documentation does not mention this at all. Or am I missing something here? Thanks again! Vin |
| Hi Vin, I did not realize that the operator was gone and I can see that it, indeed, is. I looked through the SDK and there has been a new __forceinline keyword added to operator[] in C++ which is what could be throwing the wrapper generator off. Do you think you could submit a defect to Autodesk regarding this? I don't really know any other way of accessing the bits inside the bit array short of using unsafe code and looking through the pointer data yourself. IBitArrayCallback is not listed as a pluggable class so you cannot override it. However, please also submit a defect to Autodesk regarding this as it would relatively easy to make it pluggable. Marsel Khadiyev (Software Developer, EPHERE Inc.) |
| Hey Marsel, Thanks for the info, I was confused for a while when I couldn't find [], so I've submitted 2 defects to Autodesk: the missing [] operator and the IBitArrayCallback not being a pluggable class. Hopefully I'll hear back soon! About the workaround, I know this has little to do with the wrapper itself, but would IBitArray.Handle be the starting point of the array in memory? I've tried casting it to an int* and then iterating over it like this: int* start = (int*)bitArraySel.Handle.ToPointer(); for (int i = 0; i < bitArraySel.Size; i++) { var test1 = bitArraySel[i]; var test2 = start[i]; //var test3 = *(start + i); } This isn't really working and I assume it's because I need to cast it to something else than int*. I assumed it stored ints as the [] returned ints and Marshal.SizeOf(bitArraySel[i]) returns 4, just like sizeof(int) does. |
| You should try using bitArraySel.NativePointer instead of Handle, at least in newer versions of the wrapper. Marsel Khadiyev (Software Developer, EPHERE Inc.) |
| Thanks! I've tried the NativePointer method too, unfortunately it's still not working. I was only using the .Handle because I was testing the SizeOf(bitArrayElement) using the [] that are now missing. |
| I came up with this solution, got most of the code from the C++ SDK, if anyone is having similar problems... :) (Extension method: bitArray.GetBit(i)) public static class IBitArrayExtensions { private const int NSHIFT = 6; private const int CHAR_BIT = 8; private const int kMAX_LOCALBITS = CHAR_BIT*sizeof (ulong); private const int BITS_PER_DWORD_PTR = (CHAR_BIT*sizeof (ulong)); private const int BITS_PER_DWORD_PTR_MASK = BITS_PER_DWORD_PTR - 1; public static unsafe int GetBit(this IBitArray bitArray, int index) { //Number of bits in the bitArray int numBits = bitArray.Size; //Pointer to the start of either DWORD_PTR* bits or DWORD_PTR localBits //DWORD_PTR is of type ulong void* nativePtr = bitArray.NativePointer.ToPointer(); //Determines whether we use bits or localBits bool useLocal = numBits <= kMAX_LOCALBITS; if (useLocal) { ulong localBits = ((ulong*)nativePtr)[0]; ulong bitMask = (index < kMAX_LOCALBITS) ? (((ulong)1) << index) : 0; return ((localBits & bitMask) != 0) ? 1 : 0; } else { ulong* bits = ((ulong**)nativePtr)[0]; int bitIndex = index >> NSHIFT; var bitMaskParameter = index & BITS_PER_DWORD_PTR_MASK; ulong bitMask = (bitMaskParameter < kMAX_LOCALBITS) ? (((ulong)1) << bitMaskParameter) : 0; return ((bits[bitIndex] & bitMask) != 0) ? 1 : 0; } } } |
| Wow, that is elaborate :) Congrats and sorry for not being able to help more Marsel Khadiyev (Software Developer, EPHERE Inc.) |
| Hi Vincentt. I have the same issue than you and need to solve it. I've copied your code but I get this compilation error in this line "void* nativePtr = bitArray.NativePointer.ToPointer();": there's no NativePointer definition for IBitArray. Do you know what I'm missing? Thanks a lot for your help. |
| Hey aandres, I think in later versions of the wrapper the .Handle property has been changed to NativePointer. So maybe you could try and replace .NativePointer to .Handle |
| Correct, what is now NativePointer used to be Handle before. This was renamed to avoid name clashes. Marsel Khadiyev (Software Developer, EPHERE Inc.) |
| Thanks a lot! It works fine with "handle". You save my code! I'm using 3DSMax 2014. Is that IBitArray issue corrected in newer Max versions? It's really incredible a bug like that. |
| In 3dsmax 2013 and newer it should be NativePointer instead of Handle, with the Autodesk.Max.dll assembly which comes with 3dsmax Marsel Khadiyev (Software Developer, EPHERE Inc.) |
| Not for me... Perhaps it's because it's the Design version (2014). |
| Here I am again with IBitArrays... Is it just my 3DSMAX version or is it true that the OR operation doesn't exist for IBitArrays?? I just can find NOT, AND and XOR. Anyone can help me to solve this new issue? The only way I've found is: A OR B = B XOR (A XOR (A AND B)) |
| Hmm, you're right, I can't seem to find or operator as well. All I see is: // // Summary: // AND two BitArrays IBitArray BitwiseAnd( IBitArray param0 ); // // Summary: // AND= this Autodesk.Max.IBitArray with the specified Autodesk.Max.IBitArray. IBitArray BitwiseAndWith( IBitArray b ); // // Summary: // XOR two BitArrays IBitArray BitwiseXor( IBitArray param0 ); // // Summary: // XOR= this Autodesk.Max.IBitArray with the specified Autodesk.Max.IBitArray. IBitArray BitwiseXorWith( IBitArray b ); // // Summary: // Unary NOT function IBitArray BitwiseNot { get; } Marsel Khadiyev (Software Developer, EPHERE Inc.) |
| Yes. What is worse is that the OR operation is the only way to add IBitArrays (thus add differents selections of faces o verts) as the '+' operator between IBitArrays is not implemented either. And it's not like in MaxScript, where you can use an array of integers to make a selection. The only way are IBitArrays. |
| If anyone has a better solution, then insert mine in Vincentt 'public static class IBitArrayExtensions': public static IBitArray BitwiseOR(this IBitArray A, IBitArray B) { int sizeA = A.Size; int sizeB = B.Size; if (sizeA > sizeB) { B.SetSize(sizeA, 1); } else { A.SetSize(sizeB, 1); } return B.BitwiseXor(A.BitwiseXor(A.BitwiseAnd(B))); } |