Hello!
I'm fairly new to both Android and Java (pretty experienced in C/C++),
and (stupidly, perhaps) took on a big project.  In it, I need to load
information about 3D models and their respective animations from a
text file (proprietary file format based on PSK/PSA).

The loading process on a sample (1000+ line) file is abysmally slow
(more than 4 minutes).  The good news is that there are lots and lots
of ways I can improve it.  What I'm hoping to find out here is if
there's anything in *particular* in my code that is very inefficient
that I can change.  Don't worry about offending me, I know this is
amateur code here.

Some possible causes for the slowness:
- Extensive use of parseFloat()
- Creating new StringTokenizer for every line
- Inefficiencies in for() loops (not caching as necessary?)
- Repeated use of the acos() and sqrt() functions

I'd like to find out from you gentlemen (ladies) what you think is the
major thing eating up my time here.  If there's some tool I can use to
find out what lines of code are taking up the most time that'd be
ideal.  I'm open to any possible solutions.  The file format can
change (and probably will).  I could even do something as drastic as
performing this load in a separate app (before distribution) and
somehow exporting the resulting object (KdfAnimation) that could more
easily be picked back up (this would work in C, but I'm doubtful Java
would allow such low-level memory copying).

One final note is that the "action" loading section of this code
occupies about 3/4 of the files being loaded (so this section may be
more important to optimize).

====Loader Code====
public class KdfLoader {


        public static KdfAnimation load(String file) throws IOException {
                KdfAnimation anim = new KdfAnimation();

                FileInputStream fis = new FileInputStream(file);
                String line = "[start]";
                LineNumberReader lnr = new LineNumberReader(new 
InputStreamReader
(fis));

                int boneNum = 0;

                try {

                for (line = lnr.readLine(); line != null; line = 
lnr.readLine()) {
                        if (line.length() > 0) {
                                if (line.startsWith("numbones")) {
                                        // Ignore it for now
                                }
                                else if (line.startsWith("bone")) {
                                        // Bone define
                                        StringTokenizer tok = new 
StringTokenizer(line);
                                        KdfBone bone = new KdfBone();

                                        // Toss out "bone"
                                        tok.nextToken();

                                        // Set name
                                        bone.boneName = tok.nextToken();

                                        if (boneNum == 0) {
                                                // Root bone.  Ignore children 
and parent id in file
                                                bone.parentId = 0;
                                                bone.parent = null;
                                                // ignore "numchildren x"
                                                // ignore "parentid x"
                                        }
                                        else
                                        {
                                                // ignore "numchildren x"
                                                tok.nextToken();
                                                tok.nextToken();
                                                // ignore "parentid" text
                                                tok.nextToken();
                                                bone.parentId = 
Integer.parseInt(tok.nextToken());
                                                bone.parent = 
anim.allBones.get(bone.parentId);
                                        }
                                        // get loc and rot
                                        line = lnr.readLine();
                                        bone.loc = parseLocLine(line);
                                        line = lnr.readLine();
                                        bone.rot = parseRotLine(line);

                                        // Handle explicit linkage
                                        while(true) {
                                                lnr.mark(1000);
                                                line = lnr.readLine();
                                                if (line.startsWith("obj")) {
                                                        tok = new 
StringTokenizer(line);
                                                        // ignore "obj"
                                                        tok.nextToken();
                                                        
bone.partLinks.add(tok.nextToken());
                                                        
anim.explicitPartLinkage = true;
                                                }
                                                else {
                                                        // Reset to previous 
line number
                                                        lnr.reset();
                                                        break;
                                                }
                                        }

                                        // Add bone to animation
                                        if (boneNum == 0) {
                                                anim.rootBone = bone;
                                        }
                                        else {
                                                // Add this bone to its 
parent's list of children
                                                bone.parent.children.add(bone);
                                        }
                                        anim.allBones.add(bone);

                                        boneNum++;
                                }
                                else if (line.startsWith("action")) {
                                        // Action define
                                        StringTokenizer tok = new 
StringTokenizer(line);
                                        KdfAction action = new KdfAction();

                                        // ignore "action"
                                        tok.nextToken();

                                        // Set name
                                        action.actionName = tok.nextToken();

                                        // ignore "numframes" text
                                        tok.nextToken();

                                        // Get number of frames
                                        action.numberOfFrames = 
Integer.parseInt(tok.nextToken());

                                        // Get all bone actions
                                        while(true) {
                                                //Mark the current line
                                                lnr.mark(1000);
                                                line = lnr.readLine();
                                                if (line == null) {
                                                        break;
                                                }
                                                if (!line.startsWith("bone")) {
                                                        // Go back to the 
previous line so the for() loop we're in
doesn't skip one
                                                        lnr.reset();
                                                        break;
                                                }

                                                KdfBoneAction bact = new 
KdfBoneAction();

                                                tok = new StringTokenizer(line);
                                                // ignore "bone"
                                                tok.nextToken();

                                                // Figure out the bone this 
using
                                                String boneName = 
tok.nextToken();
                                                for (int i = 0; i < 
anim.allBones.size(); i++) {
                                                        if 
(anim.allBones.get(i).boneName.equalsIgnoreCase(boneName)) {
                                                                bact.bone = 
anim.allBones.get(i);
                                                                break;
                                                        }
                                                }

                                                // Get [numberOfFrames] locs
                                                for (int i = 0; i < 
action.numberOfFrames; i++) {
                                                        line = lnr.readLine();
                                                        
bact.locs.add(parseLocLine(line));
                                                }

                                                // Get [numberOfFrames] rots
                                                for (int i = 0; i < 
action.numberOfFrames; i++) {
                                                        line = lnr.readLine();
                                                        
bact.rots.add(parseRotLine(line));
                                                }

                                                // Add the BoneAction to the 
action
                                                action.boneActions.add(bact);
                                        }

                                        // Add the action to the animation
                                        anim.actions.add(action);
                                }
                        }
                }

                } catch (Exception e) {
                        System.err.println("Error parsing file:");
                        System.err.println(lnr.getLineNumber()+" : "+line);
                }



                return anim;
        }

        private static float[] parseLocLine(String line) {
                float[] retFloat = new float[3];
                StringTokenizer tok = new StringTokenizer(line);

                // Ignore "loc"
                tok.nextToken();
                // x
                tok.nextToken();
                retFloat[0] = Float.parseFloat(tok.nextToken());
                // y
                tok.nextToken();
                retFloat[1] = Float.parseFloat(tok.nextToken());
                // z
                tok.nextToken();
                retFloat[2] = Float.parseFloat(tok.nextToken());

                return retFloat;
        }

        private static float[] parseRotLine(String line) {
                float[] retFloat = new float[4];
                StringTokenizer tok = new StringTokenizer(line);

                // Ignore "rot"
                tok.nextToken();
                // theta
                tok.nextToken();
                retFloat[0] = wToTheta(Float.parseFloat(tok.nextToken()));
                // x
                tok.nextToken();
                retFloat[1] = Float.parseFloat(tok.nextToken());
                // y
                tok.nextToken();
                retFloat[2] = Float.parseFloat(tok.nextToken());
                // z
                tok.nextToken();
                retFloat[3] = Float.parseFloat(tok.nextToken());

                // Need to scale this vector to make glRotate happy
                retFloat = scaleAxisAngleVector(retFloat);

                return retFloat;
        }

        private static float wToTheta(float w) {
                // w = cos(theta/2)
                float theta = (float)Math.acos((double)w) * 2;
                // convert theta to degrees
                theta = 180 * theta / (float)Math.PI;
                // The above calculation only gave us a value from 0 to 180 
because
of arccosine
                // TODO: Determine if this is a problem.  Note that w can be
negative, and this implies 180 degrees
                if (w < 0) {
                        theta += 180;
                }
                return theta;
        }

        private static float[] scaleAxisAngleVector(float[] unscaled) {
                float[] scaled = new float[4];
                // scale = sqrt(x^2 + y^2 + z^2);
                float scale = (float)Math.sqrt(unscaled[1] * unscaled[1] + 
unscaled
[2] * unscaled[2] + unscaled[3] * unscaled[3]);

                if (scale != 0) {
                        scaled[0] = unscaled[0];
                        scaled[1] = unscaled[1] / scale;
                        scaled[2] = unscaled[2] / scale;
                        scaled[3] = unscaled[3] / scale;
                }
                else
                {
                        // Scale can be 0, which means we're not rotating
                        // but dividing by zero is bad, and glRotate still
                        // needs a normalized vector.
                        scaled[0] = 0;
                        scaled[1] = 1;
                        scaled[2] = 0;
                        scaled[3] = 0;
                }
                return scaled;
        }
}
====End of Loader Code====

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Beginners" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-beginners?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to