trying to port some C++ structures to C# problem.

  • Thread starter Thread starter Olaf Baeyens
  • Start date Start date
If understand your example correctly, then you actually do the copying
via
ReadFile() which is a great idea, but I doubt that it would work if the
source is coming from a byte[] source.

If you mean "coming from a Memory stream", then the obvious answer is no.
But still it is a wonderfull idea you gave me.
I have to remember this one, you never know that one day I might need this.
:-)
 
Ok, see my other reply regarding the Copy stuff which is IMO not needed.
Pretty sure at the end you will say "let's do this in MC++", goodluck
anyway.
I finally managed to make it work, and I got a big supprise that I do not
lose any noticable speed compared to the unmanaged C++ code. Even with the
copy thing.

The only explanation I can come up with is that although I lose speed about
this copying thing and managed code tricks needing properties instead of
working directly with pointers like I could do in C++, somehow I gain speed
at other locations because that one STL load function does more than only
loading a file and copy data, it also have to calculate and correct a lot of
vector stuff, like normals... A pretty complex function.

Another explanation might be that the GC thing is the cause of gaining
speed, by not having to allocate and dispose memory all the time. Something
that the C++ version needed to do.

And also something else might be that copying the data might not be that
slow since the data might end into the cache memory of the processor so
accsessing it a second times is much faster than accessing it a first time.

At this point I am happy that I did the transition to C#, I can really
produce much faster results because the compiler is lightning fast compared
to the C++. And the intellisense is faster en more accurate. Also if I have
errors, then I do not get hunderds of errors because somewhere out there I
forgot a ";".. The errors are underlined. C# is clearly the way to go. But
that does not mean that I do not use C++ anymore. ;-) I still need it for
the biggest part of my code.
 
Ravichandran J.V. said:
Have you tried the Marshal.Sizeof instead of sizeof ?

The complete solution for me is this:
Much more complicated than expected but nevertheless fast and reliable.
Maybe in a next step I might lose the unsafe and fixed keywords too if I can
find some time. ;-)

----------------------------
internal struct STLHEADER {
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 80)]
public byte [] title;
public int dwCount;
}

internal struct STLFACET {
public STLVECTOR Normal;
public STLVECTOR V1;
public STLVECTOR V2;
public STLVECTOR V3;
public ushort dwColor;
}
----------------------------

The function to access the header and STL triangles is something like this:

----------------------------
unsafe {
...
int iSTLHeaderSize=Marshal.SizeOf(typeof(STLHEADER));
...
IntPtr ptr = IntPtr.Zero;
try {
ptr = Marshal.AllocHGlobal(iSTLHeaderSize);
Marshal.Copy(STLFile.BufferPtr, 0x0, ptr, iSTLHeaderSize);
STLHEADER header = (STLHEADER)
Marshal.PtrToStructure(ptr,typeof(STLHEADER));
...
ASCIIEncoding enc = new ASCIIEncoding();
aModelBuffer.m_sTitle = enc.GetString(header.title);
...
int iCount=(int)header.dwCount;
if (iCount>iNrOfTriangles) {
...
fixed (byte *p=&STLFile.BufferPtr[iSTLHeaderSize]) {
STLFACET *pTriangle=(STLFACET *) p;
...
Vertex1.x=pTriangle->V1.x;
Vertex1.y=pTriangle->V1.y;
Vertex1.z=pTriangle->V1.z;
...
aModelBuffer.m_Model.m_Vertex[iIndex]=Vertex1;
....
}
...
}
}
}

----------------------------
And aModelBuffer.m_Model.m_Vertex[iIndex]=Vertex1 is defined like this:
----------------------------

public struct CVERTEX {
public float x;
public float y;
public float z;
}

public CVERTEX this[int aiIndex] {
get {
long iPos=Buffer.RecGetRecPosAt(aiIndex);
CVERTEX ReturnVertex=new CVERTEX();
unsafe {
fixed (void *pSource=&Buffer.BufferPtr[iPos]) {
CVERTEX *pSourceVertex=(CVERTEX *)pSource;
CVERTEX *pDestinationVertex=(CVERTEX *)&ReturnVertex;
*pDestinationVertex=*pSourceVertex;
}
}
return ReturnVertex;
}
set {
long iPos=Buffer.RecGetRecPosAt(aiIndex);
unsafe {
fixed (void *pDestination=&Buffer.BufferPtr[iPos]) {
CVERTEX *pSourceVertex=(CVERTEX *)&value;
CVERTEX *pDestinationVertex=(CVERTEX *)pDestination;
*pDestinationVertex=*pSourceVertex;
}
}
}
}
 
Looks good!

By the way, you might want to change:
ASCIIEncoding enc = new ASCIIEncoding();
aModelBuffer.m_sTitle = enc.GetString(header.title);
into
aModelBuffer.m_sTitle =
System.Text.Encoding.ASCII.GetString(header.title);

to use a potentially existing instance of System.Text.ASCIIEncoding.

--
Regards,
Dennis JD Myrén
Oslo Kodebureau
Olaf Baeyens said:
Ravichandran J.V. said:
Have you tried the Marshal.Sizeof instead of sizeof ?

The complete solution for me is this:
Much more complicated than expected but nevertheless fast and reliable.
Maybe in a next step I might lose the unsafe and fixed keywords too if I
can
find some time. ;-)

----------------------------
internal struct STLHEADER {
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 80)]
public byte [] title;
public int dwCount;
}

internal struct STLFACET {
public STLVECTOR Normal;
public STLVECTOR V1;
public STLVECTOR V2;
public STLVECTOR V3;
public ushort dwColor;
}
----------------------------

The function to access the header and STL triangles is something like
this:

----------------------------
unsafe {
...
int iSTLHeaderSize=Marshal.SizeOf(typeof(STLHEADER));
...
IntPtr ptr = IntPtr.Zero;
try {
ptr = Marshal.AllocHGlobal(iSTLHeaderSize);
Marshal.Copy(STLFile.BufferPtr, 0x0, ptr, iSTLHeaderSize);
STLHEADER header = (STLHEADER)
Marshal.PtrToStructure(ptr,typeof(STLHEADER));
...
ASCIIEncoding enc = new ASCIIEncoding();
aModelBuffer.m_sTitle = enc.GetString(header.title);
...
int iCount=(int)header.dwCount;
if (iCount>iNrOfTriangles) {
...
fixed (byte *p=&STLFile.BufferPtr[iSTLHeaderSize]) {
STLFACET *pTriangle=(STLFACET *) p;
...
Vertex1.x=pTriangle->V1.x;
Vertex1.y=pTriangle->V1.y;
Vertex1.z=pTriangle->V1.z;
...
aModelBuffer.m_Model.m_Vertex[iIndex]=Vertex1;
....
}
...
}
}
}

----------------------------
And aModelBuffer.m_Model.m_Vertex[iIndex]=Vertex1 is defined like this:
----------------------------

public struct CVERTEX {
public float x;
public float y;
public float z;
}

public CVERTEX this[int aiIndex] {
get {
long iPos=Buffer.RecGetRecPosAt(aiIndex);
CVERTEX ReturnVertex=new CVERTEX();
unsafe {
fixed (void *pSource=&Buffer.BufferPtr[iPos]) {
CVERTEX *pSourceVertex=(CVERTEX *)pSource;
CVERTEX *pDestinationVertex=(CVERTEX *)&ReturnVertex;
*pDestinationVertex=*pSourceVertex;
}
}
return ReturnVertex;
}
set {
long iPos=Buffer.RecGetRecPosAt(aiIndex);
unsafe {
fixed (void *pDestination=&Buffer.BufferPtr[iPos]) {
CVERTEX *pSourceVertex=(CVERTEX *)&value;
CVERTEX *pDestinationVertex=(CVERTEX *)pDestination;
*pDestinationVertex=*pSourceVertex;
}
}
}
}
 
By the way, you might want to change:
ASCIIEncoding enc = new ASCIIEncoding();
aModelBuffer.m_sTitle = enc.GetString(header.title);
into
aModelBuffer.m_sTitle =
System.Text.Encoding.ASCII.GetString(header.title);

to use a potentially existing instance of System.Text.ASCIIEncoding.

Changed and tested! :-)
Thanks.
 
Back
Top