Sign in to follow this  
Ramon Wong

[java] Porting from C/C++ to Java: loading an 3d Object

Recommended Posts

Hey. I'm currently working on the Android Platform and I'm trying to port some of my C/C++ ancient codes(Borland C++ 4.5 XD) to Java which I can run on Dalvik VM one of these are my Milkshape 3d codes I'm figuring out which is the best way to open and read the file and close it. for example what is the best Java functions to substitute C functions "fopen" and "fread"?

Share this post


Link to post
Share on other sites
There are two ways to do that:


String fileName = ...; // <-- This can be relative to the current directory.
InputStream in = new FileInputStream(new File(fileName));

while(true) {
int b = in.read();
if(b == -1) break; // EOF
...
}

in.close();




String url = ...;
InputStream in = new URL(url).openStream();

while(true) {
int b = in.read();
if(b == -1) break; // EOF
...
}

in.close();



See the java.io package for wrapper classes that facilitate tokenization and I/O of non-ASCII character encodings.

Share this post


Link to post
Share on other sites
I see



BOOL MS3D::LoadHeader(FILE * File)
{
fread( Header.Id, sizeof(char), 10, File);
fread(&Header.Version, 1, sizeof(int), File);

if(strncmp( Header.Id, "MS3D000000", 10 ) != 0) return FALSE;
if(Header.Version != 3 && Header.Version != 4) return FALSE;

return TRUE;
}




I'll see what i can port over to Java
Thanks BTW

Share this post


Link to post
Share on other sites
That wouldn't be fun..with Vertex/KeyFrame animations
XD

But I will use some native functions to calculate some critical calculations and
milk out some speed
So I believe it would be possible.
Btw I'm also aiming at capped 25/30 fps

well for the fread substitute


fread( Header.Id, sizeof(char), 10, File);





FileStream IS.read( Header.ID, sizeof(int), 10);
FileStream IS.read( Header.Version, sizeof(char), 1);
blah blah blah



I'm going to do some testing with txt files to be sure.

Share this post


Link to post
Share on other sites
any help with Inputsream.read(yada yada yada)?


fread( Header.Id, sizeof(char), 10, File);
fread(&Header.Version, 1, sizeof(int), File);

is there a way to convert Byte(James Gosling touching himself) into ints or chars?

Share this post


Link to post
Share on other sites
String has a constructor that receives an array of bytes and converts that to a string. One thing to note however is that an array of bytes cannot be determined to only have 1 byte per character as it might be in wide character format. But there are constructors that allow for converting the type of ascii encoding if need be.

To get the first 10 bytes from a stream or even the first n bytes, use the following.

byte header[] = new byte[10];
is.read(header);

String headerString = new String(header);





Now to read in the integer version.

byte versionBuf[] = new byte[Integer.SIZE/8];
is.read(versionBuf);
ByteBuffer bb = ByteBuffer.wrap(versionBuf);
IntBuffer ib = bb.asIntBuffer();
ib.rewind(); //must have to go back to the beginning of the buffer
int version = ib.get();





Likewise there are multiple types of buffers in the java.nio package. Both are included in the android API so you should be good there.

You may also be interested in DataInputStream which might make things easier for you if you are having trouble getting your head around how the ByteBuffer's work.

Here would be one way to convert your function LoadHeader.

	private String id = null;
private int version = -1; //default to an invalid version

public boolean loadHeader(File file) throws IOException {
//keep is a generic input stream, so that we can use any type of subclass of
//InputStream in the future without needing to change the loading code.
InputStream is = new FileInputStream(file);

byte header[] = new byte[10];
is.read(header);
id = new String(header);

byte versionBuf[] = new byte[Integer.SIZE/8];
is.read(versionBuf);
ByteBuffer bb = ByteBuffer.wrap(versionBuf);
IntBuffer ib = bb.asIntBuffer();
ib.rewind();
version = ib.get();

if(!id.equals("MS3D000000")) {
return false;
}

if(version != 3 && version != 4) {
return false;
}

return true;

//that whole thing can be shortened to, if the first is false it won't
//evaluate the second and third expressions.
//return !header.equals("MS3D000000") && version != 3 && version != 4;
}





C to Java caveat
Java is a much more strongly typed language than C, so there is an abstraction between memory and your program. Unlike C where everything is just memory and you can manipulate it however you want and use neat pointer and memory address manipulations to do anything you want to it, in java there is a more strict contract between memory and the language everything essentially in java is an Object rather than memory. While java allows binary operations on primitive types an Array in java such as int[] array; is basically an object not like in C where it is just a sequence of bytes somewhere in memory. Thus you cannot guarantee the format of memory, so a by product of using java is to adhere to this strict contract. In java you must write code to specifically convert between types or properly use inheritance to solve your problems. Hope this helps, and also the reference documentation for Android is your friend, use it until you know every bit of it because it could save you a lot of time hunting down problems or writing low-level routines that have more stable and tested solutions. Just something to keep in mind as you convert your code.

Skeletal Animation vs Keyframed on Android
As far as Skeletal animation versus key framed. I am not sure what the programmable shader support is for the OpenGL ES specification. But if it is supported it might limit the amount of array size for matrices which would limit your Skeletal animation shader but it might still be doable. If there is no shader support then key framed is the way to go since doing skeletal animation without a shader would result in modifying the vertex buffer for an object and applying matrix transforms for the bones either every frame or just converting the skeletal animation to keyframed when loading the program, and applying the animation matrix transforms while loading.

Share this post


Link to post
Share on other sites
Okay I've succesfully ported most of my opengl C/C++ camera and Frustum functions
codes to Java through JNI.
And I like the performance very well on the emulator.

so I'm going to load the model through Java
and do the animations with JNI

Share this post


Link to post
Share on other sites
The codes work.
but for some reasons
java read 1 step ahead of it self.
so instead of reading MS3D000000 I get S3D00000? instead
and also I got version 40 instead of 4.



byte vertexBuf[] = new byte[Short.SIZE/8];

Is.read(vertexBuf);

ByteBuffer bb = ByteBuffer.wrap(vertexBuf);

ShortBuffer sb = bb.asShortBuffer();
sb.rewind();
vertices = sb.get();




for some where reason vertices is constantly 0
I think I've enter a wrong value for the size of Short.

question that I have is why do I have to divide the size with 8?

Share this post


Link to post
Share on other sites
Quote:
Original post by Ramon Wong
question that I have is why do I have to divide the size with 8?

The primitive type object wrappers provide constants for the size of the primitive type, but those are in bits, a short would usually be 16 bits, integer usually 32 bits.

I guess this was for flexibility or maybe just completeness. I didn't think about it too much when I wrote the example but it would be more appropriate to do the following:

Integer.SIZE/Byte.SIZE


Since what you really are making is an array of Bytes. But I guess for file reading you need an exact number of bytes that your reading in, so I would say constants are just fine as long as the file format specifies the number of bytes for the field your trying to read.

As a side note, when converting from C to Java the following would be very close. Where n is the size of the array.
C
char *buf = new char[n];

Java
byte buf = new byte[n];


You can do most of the same operations in a similar manor. E.g.
C
memcpy(dst, buf, n);

Java
System.arrayCopy(buf, 0, dst, 0, buf.length);


Feel free to post any other conversion questions you have.

Share this post


Link to post
Share on other sites
yeah ...
XD
16/8, 32/8, 64/8, 128/8 .... etc etc
now I remember...

ok.
I'm having some weird problems
reading the headers and comparing the byte size from the ms3d sdk
The value of the header was no big problem
it returns "MS3D000000"

but for some reason the version (Integer) is all wrong.
it returns 67108864.

and for the num_vertices (Short) is above the 3000 for a very small size 3d model.(tested it with two different models)
And I'm even using the DataInputstream and the result is still the same.



I'm going to redo a C++ loader and see if the result is the same.

Share this post


Link to post
Share on other sites
They are the same code as posted above by you earlier on how to read and convert bytes into ints.

I've tried every thing I can find on the net
including using DataInputStream or how to convert Bytes codes into Integer or shorts.
.....

Share this post


Link to post
Share on other sites
Most devices using Android don't support OpenGL ES 2.0, some of them have hardware skinning with OpenGL ES 1.1 though via some extension.
On devices without hardware skinning, you should do the skinning in native code, since in Android's Java, accessing native memory is very slow and copying java memory to native memory is just as slow (really it seems like a bug in the Delvik VM..)

Share this post


Link to post
Share on other sites
I have to read the ms3d files in Java.
I can't used native code to open zipped files
(I can but do you really want to add compression into your codes as well?)

apparently...
I think I found my answer
the value is hidden in the byte[0]
and they are the same with the C/C++ version.

not by adding it all up shift the byte
and doing things the Overbloated java way.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this