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

Started by
15 comments, last by Ramon Wong 14 years ago
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"?
Advertisement
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.
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
I wouldn't recommend using skeletal animation (what milkshape3d is using) as that will be slow on Android. Instead you should use vertex/keyframe animation.
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.
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?
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 bufferint 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.
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

I'm a newbie in Java
and I haven't seen that much buffers usages before in a short simple functions...



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?

This topic is closed to new replies.

Advertisement