Beispiel #1
0
        }                                                                 //places Model at start of list

        public bool addModel(OpenGLModel mod, int idx)
        {
            if (mod == null)
            {
                return(false);
            }
            ml.Insert(idx, mod); return(true);
        }                                                                                                                 //place Models with transparent textures last
Beispiel #2
0
 public bool Save(OpenGLModel model, IOStream os)
 {
     try {
         saveJF3D(model, os);
         return(true);
     } catch (Exception e) {
         Console.WriteLine("Error:" + e.ToString());
         return(false);
     }
 }
Beispiel #3
0
        /** Clones a pre-loaded model.
         * Use addModel() to add into the render scene.
         */
        public OpenGLModel CloneModel(String fn)
        {
            OpenGLModel mod = mtl.Get(fn);

            if (mod == null)
            {
                return(null);
            }
            mod.refcnt++;
            return((OpenGLModel)mod.Clone());
        }
Beispiel #4
0
 public bool Save(OpenGLModel model, String filename)
 {
     try {
         File fos = new File(filename);
         saveJF3D(model, fos);
         fos.Close();
         return(true);
     } catch (Exception e) {
         Console.WriteLine("Error:" + e.ToString());
         return(false);
     }
 }
Beispiel #5
0
        /**
         * Clones deep enough so that the cloned object will include seperate GLObjects, but share vertex, vertex point,
         * and animation data (except for the frame position).
         */
        public OpenGLModel Clone()
        {
            OpenGLModel c    = new OpenGLModel((Matrix4x4)m.Clone());
            int         objs = ol.Size();

            for (int a = 0; a < objs; a++)
            {
                c.ol.Add((OpenGLObject)ol.Get(a).Clone());
            }
            c.textures = textures;
            return(c);
        }
Beispiel #6
0
        private void saveJF3D(OpenGLModel model, IOStream os)
        {
            baos = new ByteArrayStream();
            tmp  = new byte[8];
            int size;

            writeuint32(MAGIC);
            writeuint32(VERSION);
            writeuint32(ID_MODEL);
            size = 0;
            int tcnt = model.textures.Size();

            for (int a = 0; a < tcnt; a++)
            {
                size += model.textures.Get(a).Length + 1;
            }
            writeuint32(size);
            writeuint32(tcnt);
            for (int a = 0; a < tcnt; a++)
            {
                writeString(model.textures.Get(a));
            }
            for (int o = 0; o < model.ol.Size(); o++)
            {
                OpenGLObject obj = model.ol.Get(o);
                writeuint32(ID_OBJECT);
                int vcnt = obj.GetVertexCount() * 3;
                int pcnt = obj.GetPolyCount();
                size = obj.GetName().Length + 1 + 4 + (4 * 3) + (4 + (vcnt * 4)) + (4 + (pcnt * 4));
                writeuint32(size);
                writeString(obj.GetName());
                writeuint32(obj.GetType());
                writefloat(obj.GetOrigin().x);
                writefloat(obj.GetOrigin().y);
                writefloat(obj.GetOrigin().z);
                writeuint32(vcnt / 3);
                float[] xyz = obj.GetVertexBuffer();
                for (int a = 0; a < vcnt; a++)
                {
                    writefloat(xyz[a]);
                }
                switch (obj.GetType())
                {
                case GL_TRIANGLES:
                    writeuint32(pcnt / 3);
                    break;

                case GL_QUADS:
                    writeuint32(pcnt / 4);
                    break;
                }
                int[] pts = obj.GetPolyBuffer();
                for (int a = 0; a < pcnt; a++)
                {
                    writeuint32(pts[a]);
                }
                int maps = obj.GetUVMaps().Size();
                if (maps == 0)
                {
                    Console.WriteLine("GL_JF3D:Warning:No UVMaps found for object:" + obj.GetName());
                }
                for (int m = 0; m < maps; m++)
                {
                    OpenGLUVMap map = obj.GetUVMaps().Get(m);
                    writeuint32(ID_UVMAP);
                    int uvcnt = map.GetUVCount() * 2;
                    size = map.GetName().Length + 1 + 4 + (4 + (uvcnt * 4));
                    writeuint32(size);
                    writeString(map.GetName());
                    writeuint32(map.GetTextureIndex());
                    writeuint32(uvcnt / 2);
                    float[] uv = map.GetBuffer();
                    for (int a = 0; a < uvcnt; a++)
                    {
                        writefloat(uv[a]);
                    }
                }
            }
            os.Write(baos.GetData().ToArray());
        }
Beispiel #7
0
        private OpenGLModel loadJF3D(IOStream fis)
        {
            datapos = 0;
            fis.Open(OpenMode.ReadOnly);
            data = fis.ReadAll().ToArray();

            int magic = readuint32();

            if (magic != MAGIC)
            {
                throw new Exception("GL_JF3D:Not JF3D file");
            }
            int version = readuint32();

            if (version < VERSION)
            {
                throw new Exception("GL_JF3D:Bad version");
            }

            int         fcnt, pcnt, vcnt, uvcnt;
            OpenGLUVMap map;

            while (!eof())
            {
                int head_id  = readuint32();
                int head_len = readuint32();
                skip = head_len;
                int head_ver = head_id & 0xffff;
                head_id &= 0x7fff0000;
                switch (head_id)
                {
                case ID_MODEL:
                    if (model != null)
                    {
                        throw new Exception("GL_JF3D:Multiple Model chunks found");
                    }
                    model = new OpenGLModel();
                    fcnt  = readuint32();
                    for (int a = 0; a < fcnt; a++)
                    {
                        String txt = readString();
                        model.textures.Add(txt);
//                        Console.WriteLine("Texture=" + txt);
                    }
                    if (head_ver > 0)
                    {
                        //future reserved
                    }
                    break;

                case ID_OBJECT:
                    obj = new OpenGLObject();
                    model.AddObject(obj);
                    obj.SetName(readString());
                    obj.SetType(readuint32());
                    obj.GetOrigin().x = readfloat();
                    obj.GetOrigin().y = readfloat();
                    obj.GetOrigin().z = readfloat();
                    vcnt = readuint32();    //vertex count
                    for (int v = 0; v < vcnt; v++)
                    {
                        float fx = readfloat();
                        float fy = readfloat();
                        float fz = readfloat();
                        obj.AddVertex(new float[] { fx, fy, fz });
                    }
                    pcnt = readuint32();    //poly count
                    switch (obj.GetType())
                    {
                    case GL_TRIANGLES:
                        pcnt *= 3;
                        break;

                    case GL_QUADS:
                        pcnt *= 4;
                        break;

                    default:
                        Console.WriteLine("GL_JF3D:Error Unknown GL Type:" + obj.GetType());
                        return(null);
                    }
                    for (int p = 0; p < pcnt; p++)
                    {
                        int pt = readuint32();
                        if (pt >= vcnt)
                        {
                            Console.WriteLine("Error:Poly includes invalid vertex !!!");
                        }
                        obj.AddPoly(new int[] { pt });
                    }
                    break;

                case ID_UVMAP:
                    map = obj.CreateUVMap();
                    map.SetName(readString());
                    map.SetTextureIndex(readuint32());
                    uvcnt = readuint32();
                    if (uvcnt != obj.GetVertexCount())
                    {
                        Console.WriteLine("Warning:UVMAP size != vertex count");
                    }
                    for (int i = 0; i < uvcnt; i++)
                    {
                        float u = readfloat();
                        float v = readfloat();
                        map.Add(new float[] { u, v });
                    }
                    break;

                default:
                    break;
                }
                if (skip > 0)
                {
                    datapos += skip;
                }
            }
            return(model);
        }
Beispiel #8
0
 public void UnloadModel(OpenGLModel mod)
 {
     mod.refcnt--;
 }
Beispiel #9
0
 public void removeModel(OpenGLModel mod)
 {
     ml.Remove(mod);
 }
Beispiel #10
0
        }                                                                                                                 //place Models with transparent textures last

        public int indexOfModel(OpenGLModel mod)
        {
            return(ml.IndexOf(mod));
        }
Beispiel #11
0
 public bool addModel(OpenGLModel mod)
 {
     return(addModel(mod, 0));
 }                                                                 //places Model at start of list
Beispiel #12
0
        private OpenGLModel loadBlend(IOStream fis)
        {
            setData(fis.ReadAll().ToArray());

            if (data.Length < 12)
            {
                throw new Exception("GL_BLEND:File too small");
            }

            model = new OpenGLModel();

            //load signature (12 bytes) "BLENDER_V100"
            if (!new String(data, 0, 7).Equals("BLENDER"))
            {
                throw new Exception("Not a blender file");
            }
            switch ((char)data[7])
            {
            case '-': x64 = true; break;

            case '_': x64 = false; break;

            default:
                throw new Exception("GL_BLEND:Unknown bit size");
            }

            switch ((char)data[8])
            {
            case 'v': le = true; break;

            case 'V': le = false; break;

            default:
                throw new Exception("GL_BLEND:Unknown Endianness");
            }

            String version = new String(data, 9, 3);
//        Console.WriteLine("Blender file version:" + version);
            int ver = Int32.ValueOf(version);

            if (ver < 263)
            {
                throw new Exception("Error:Blender file too old, can not read.");
            }

            datapos = 12; //skip main header

            //first phase - read raw chunks
            while (!eof())
            {
                BlendChunk chunk = new BlendChunk(this);
                chunk.filepos = datapos;
                chunk.read();
                BlendChunk ochunk = chunks.Get(chunk.ptr);
                if (ochunk != null)
                {
                    if (!haveDups)
                    {
                        Console.WriteLine("Warning:This file contains duplicate BHeads.");
                        haveDups = true;
                    }
                    ochunk.dup = true;
                    while (ochunk.nextdup != null)
                    {
                        ochunk = ochunk.nextdup;
                    }
                    ochunk.nextdup = chunk;
                }
                else
                {
                    chunks.Set(chunk.ptr, chunk);
                }
            }

            int chunkCnt = chunks.Size();

            BlendChunk[] chunkArray = chunks.Values();
            BlendChunk   raw;

            //2nd phase - parse DNA chunk
            for (int i = 0; i < chunkCnt; i++)
            {
                if (chunkArray[i].id == ID_DNA1)
                {
                    raw = chunkArray[i];
                    setData(raw.raw);
                    //SDNA
                    String SDNA = readString(4);
                    if (!SDNA.Equals("SDNA"))
                    {
                        throw new Exception("Bad DNA Struct:SDNA");
                    }
                    //NAME
                    String NAME = readString(4);
                    if (!NAME.Equals("NAME"))
                    {
                        throw new Exception("Bad DNA Struct:NAME");
                    }
                    int nr_names = readuint32();
                    for (int a = 0; a < nr_names; a++)
                    {
                        String str = readString();
//                    Console.WriteLine("name=" + str);
                        names.Add(str);
                    }
                    //align pointer
                    datapos += 3;
                    datapos &= 0x7ffffffc;
                    //TYPE
                    String TYPE = readString(4);
                    if (!TYPE.Equals("TYPE"))
                    {
                        throw new Exception("Bad DNA Struct:TYPE");
                    }
                    int nr_types = readuint32();
                    for (int a = 0; a < nr_types; a++)
                    {
                        String str = readString();
//                    Console.WriteLine("type=" + str);
                        types.Add(str);
                    }
                    //align pointer
                    datapos += 3;
                    datapos &= 0x7ffffffc;
                    //TLEN
                    String TLEN = readString(4);
                    if (!TLEN.Equals("TLEN"))
                    {
                        throw new Exception("Bad DNA Struct:TLEN");
                    }
                    for (int a = 0; a < nr_types; a++)
                    {
                        typelen.Add(readuint16());
                    }
                    //align pointer
                    datapos += 3;
                    datapos &= 0x7ffffffc;
                    //STRC
                    String STRC = readString(4);
                    if (!STRC.Equals("STRC"))
                    {
                        throw new Exception("Bad DNA Struct:STRC");
                    }
                    int nr_structs = readuint32();
                    for (int a = 0; a < nr_structs; a++)
                    {
                        BlendStruct s = new BlendStruct();
                        s.typeidx = readuint16();
                        s.nr      = readuint16();
                        s.name    = types.Get(s.typeidx);
//                    Console.WriteLine("Struct:" + s.name + "==" + a);
                        for (int b = 0; b < s.nr; b++)
                        {
                            BlendMember m = new BlendMember();
                            m.typelenidx = readuint16();
                            m.nameidx    = readuint16();
                            m.name       = names.Get(m.nameidx);
                            m.typelen    = typelen.Get(m.typelenidx);
                            m.size       = calcMemberSize(m);
//                        Console.WriteLine("    Member:" + m.name + "=" + m.Length);
                            s.members.Add(m);
                        }
                        structs.Add(s);
                    }
                    break;
                }
            }

            //3nd phase - now look for objects and piece together chunks
            for (int i = 0; i < chunkCnt; i++)
            {
                if (chunkArray[i].id == ID_SC)
                {
                    setData(chunkArray[i].raw);
                    BlendScene OpenGLScene = new BlendScene(this);
                    OpenGLScene.read();
                    long ptr = OpenGLScene.last;
                    while (ptr != 0)
                    {
                        BlendChunk chunk = findChunkByPtr(ptr);
                        if (chunk == null)
                        {
                            break;
                        }
                        setData(chunk.raw);
                        BlendBase _base = new BlendBase(this);
                        _base.read();
                        chunk = findChunkByPtr(_base.bobject);
                        if (chunk.id == ID_OB)
                        {
                            readObject(chunk);
                        }
                        ptr = _base.prev;
                    }
                }
            }

            return(model);
        }
Beispiel #13
0
        private OpenGLModel load3ds(IOStream fis)
        {
            OpenGLObject obj = null;
            int          head_id;
            int          head_len;
            int          _siz;

            float[] _float;
            int[]   _pts;
            bool    done_vertex = false;
            bool    done_pts    = false;
            int     vertexidx   = -1;
            int     vertexcnt   = -1;
            String  name;
            List <OpenGL3DS_Material> matlist; //materials (objects refer to material name)
            List <String>             objlist; //object names (keyframe data refers to object name)
            String             objname = "";
            int                objidx  = -1;
            OpenGL3DS_Material mat;
            String             matname = "", fn;
            int                a, b, keys, u32;
            bool               ok;
            int                u16;
            OpenGLTranslate    trans;
            OpenGLRotate       rot;
            OpenGLScale        scale;
            OpenGLModel        mod;
            OpenGLUVMap        map;
            int                mapidx = -1;
            int                skip   = 0;
            int                parent;
            int                frameno;
            int                s;

            datapos = 0;
            fis.Open(OpenMode.ReadOnly);
            data = fis.ReadAll().ToArray();

            matlist = new List <OpenGL3DS_Material>();
            objlist = new List <String>();

            mod = new OpenGLModel();

            while (!eof())
            {
                head_id  = readuint16();
                head_len = readuint32();
                if (head_len == -1)
                {
                    break;                //this does happen in some files
                }
                if (head_len < 6)
                {
                    throw new Exception("head_len < 6 (" + head_len + ")");              //bad file
                }
                head_len -= 6;
                switch (head_id)
                {
                case 0x4d4d:    //main chunk
                    break;

                case 0x3d3d:    //mesh chunk
                    break;

                case 0xafff:    //material chunk
                    matname = "";
                    break;

                case 0xa000:    //material chunk name
                    matname = readname(head_len);
                    break;

                case 0xa200:    //texture details
                    break;

                case 0xa300:    //texture filename
                    mat          = new OpenGL3DS_Material();
                    fn           = readname(head_len);
                    mat.name     = matname;
                    mat.filename = fn;
                    matlist.Add(mat);
                    break;

                case 0x4000:                //object chunk
                    objname = readname(-1); //don't skip the whole chunk
                    if (debug)
                    {
                        Console.WriteLine("obj=" + objname);
                    }
                    done_vertex = false;
                    done_pts    = false;
                    break;

                case 0x4100:    //triangular object chunk
                    break;

                case 0x4110:    //vertex list of a polygon
                    skip = head_len;
                    if (done_vertex)
                    {
                        Console.WriteLine("Warning : 2 vertex lists found for 1 object?"); break;
                    }
                    obj = new OpenGLObject();
                    obj.SetType(GL_TRIANGLES);    //3ds only supports triangles
                    obj.SetName(objname);
                    mapidx = -1;
                    mod.ol.Add(obj);
                    objlist.Add(objname);
                    _siz      = readuint16();
                    skip     -= 2;
                    vertexidx = obj.GetVertexCount() * 3;
                    vertexcnt = _siz;
                    if (_siz == 0)
                    {
                        break;
                    }
                    _float = new float[_siz * 3];
                    for (a = 0; a < _siz; a++)
                    {
                        for (b = 0; b < 3; b++)
                        {
                            _float[a * 3 + b] = readfloat();
                            skip -= 4;
                        }
                        if (debug)
                        {
//                            Console.WriteLine(String.format("v=%3.3f,%3.3f,%3.3f", _float[a*3+0] , _float[a*3+1] , _float[a*3+2]));
                        }
                    }
                    obj.AddVertex(_float);
                    _float      = null;
                    done_vertex = true;
                    break;

                case 0x4120:    //Points list
                    _siz = readuint16();
                    skip = _siz * 2 * 4;
                    if (!done_vertex)
                    {
                        Console.WriteLine("Warning : pts list before vertex list?"); break;
                    }
                    if (done_pts)
                    {
                        Console.WriteLine("Warning : 2 pts lists found for 1 object?"); break;
                    }
                    if (_siz == 0)
                    {
                        break;
                    }
                    _pts = new int[3];    //p1,p2,p3,flgs per triangle
                    for (a = 0; a < _siz; a++)
                    {
                        for (b = 0; b < 3; b++)
                        {
                            _pts[b] = (short)readuint16();
                            skip   -= 2;
                        }
                        readuint16();    //skip flgs
                        skip -= 2;
                        obj.AddPoly(_pts);
                        if (debug)
                        {
                            Console.WriteLine("p=" + _pts[0] + "," + _pts[1] + "," + _pts[2]);
                        }
                    }
                    _pts     = null;
                    done_pts = true;
                    break;

                case 0x4130:    //object material name
                    name = readname(head_len);
                    mapidx++;
                    map = obj.CreateUVMap();
                    map.SetName("uvmap" + mapidx);
                    if (obj != null)
                    {
                        //find name in matlist
                        ok = false;
                        for (a = 0; a < matlist.Size(); a++)
                        {
                            if (matlist.Get(a).name.Equals(name))
                            {
                                int idx = mod.AddTexture(matlist.Get(a).filename);
                                map.SetTextureIndex(idx);
                                ok = true;
                                break;
                            }
                        }
//                        if (!ok) throw new Exception("0x4130 : object material name not found in list : " + name);
                    }
                    if (debug)
                    {
                        Console.WriteLine("mat=" + map.GetTextureIndex());
                    }
                    break;

                case 0x4140:    //texture vertex list (UV)
                    _siz = readuint16();
                    skip = _siz * 2 * 4;
                    if (!done_vertex)
                    {
                        Console.WriteLine("Warning:Texture coords (UV) list before vertex list"); break;
                    }
                    if (_siz != vertexcnt)
                    {
                        Console.WriteLine("Warning:texture list siz != vertex list siz"); break;
                    }
                    if (_siz == 0)
                    {
                        break;
                    }
                    _float = new float[2];
                    for (a = 0; a < _siz; a++)
                    {
                        _float[0] = readfloat();        //U fis okay
                        skip     -= 4;
                        _float[1] = 1.0f - readfloat(); //V must be inverted
                        skip     -= 4;
                        obj.AddUV(_float, mapidx);
                        if (debug)
                        {
//                            Console.WriteLine(String.format("t=%3.3f,%3.3f", _float[0] , _float[1]));
                        }
                    }
                    _float = null;
                    break;

                case 0x4160:  //obj matrix
                    //read in 3x3 matrix and show for now
                    s = 0;    //padding to convert to 4x4 matrix
                    for (a = 0; a < 3 * 3; a++)
                    {
                        u32 = readuint32();
                        if ((a > 0) && (a % 3 == 0))
                        {
                            s++;
                        }
//not sure what this matrix fis for??? But I don't seem to need it
//                        obj.m.m[a+s] = readfloat();
//                        if (debug) Console.WriteLine("m=" + obj.m.m[a+s]);
                    }
                    obj.GetOrigin().x = readfloat();
                    obj.GetOrigin().y = readfloat();
                    obj.GetOrigin().z = readfloat();
                    if (debug)
                    {
                        Console.WriteLine("pos=" + obj.GetOrigin().x + "," + obj.GetOrigin().y + "," + obj.GetOrigin().z);
                    }
                    break;

                case 0xb000:    //keyframe header
                    break;

                case 0xb002:    //object node chunk
                    objidx = -1;
                    break;

                case 0xb010:               //keyframe object name
                    name = readname(-1);
                    readuint16();          //f1
                    readuint16();          //f2
                    parent = readuint16(); //parent
                    //find name in objlist
                    objidx = 0;
                    ok     = false;
                    for (a = 0; a < objlist.Size(); a++)
                    {
                        if (objlist.Get(a).Equals(name))
                        {
                            ok = true;
                            break;
                        }
                        objidx++;
                    }
                    if (!ok)
                    {
                        objidx = -1;
                    }
                    else
                    {
                        obj = mod.ol.Get(objidx);
                        if (parent != 65535)
                        {
                            obj.SetParent(parent);
                        }
                        obj = null;
                    }
//Console.WriteLine("0xb010 : name=" + name + ":objidx=" + objidx + ":parent=" + parent);
                    break;

                case 0xb020:    //keyframe pos
                    skip = head_len;
                    if (objidx == -1)
                    {
                        break;
                    }
                    obj    = mod.ol.Get(objidx);
                    u16    = readuint16(); //flgs
                    skip  -= 2;
                    u32    = readuint32(); //r1
                    skip  -= 4;
                    u32    = readuint32(); //r2
                    skip  -= 4;
                    keys   = readuint32(); //keys
                    skip  -= 4;
                    _float = new float[3];
                    for (a = 0; a < keys; a++)
                    {
                        frameno = readuint32(); //frame #
                        skip   -= 4;
                        u16     = readuint16(); //flgs
                        skip   -= 2;
                        u32     = 0;
                        if ((u16 & _3DS_FLG_TENSION) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_CONTINUITY) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_BIAS) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_EASE_TO) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_EASE_FROM) != 0)
                        {
                            u32++;
                        }
                        if (u32 > 0)
                        {
                            datapos += u32 * 4;        //all ignored
                            skip    -= u32 * 4;
                        }
                        trans = new OpenGLTranslate();
                        for (b = 0; b < 3; b++)
                        {
                            _float[b] = readfloat();
                            skip     -= 4;
                        }
                        trans.x = _float[0];
                        trans.y = _float[1];
                        trans.z = _float[2];
//Console.WriteLine("pos["+frameno+"]:"+pos.x+","+pos.y+","+pos.z+":flgs="+u16);
                        obj.GetTranslateMap().Set(frameno, trans);
                        if (obj.GetMaxFrameCount() < frameno)
                        {
                            obj.SetMaxFrameCount(frameno);
                        }
                    }
                    _float = null;
                    obj    = null;
                    break;

                case 0xb021:    //keyframe rotate
                    skip = head_len;
                    if (objidx == -1)
                    {
                        break;
                    }
                    obj    = mod.ol.Get(objidx);
                    u16    = readuint16(); //flgs
                    skip  -= 2;
                    u32    = readuint32(); //r1
                    skip  -= 4;
                    u32    = readuint32(); //r2
                    skip  -= 4;
                    keys   = readuint32(); //keys
                    skip  -= 4;
                    _float = new float[4];
                    for (a = 0; a < keys; a++)
                    {
                        frameno = readuint32(); //frame #
                        skip   -= 4;
                        u16     = readuint16(); //flgs
                        skip   -= 2;
                        u32     = 0;
                        if ((u16 & _3DS_FLG_TENSION) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_CONTINUITY) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_BIAS) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_EASE_TO) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_EASE_FROM) != 0)
                        {
                            u32++;
                        }
                        if (u32 > 0)
                        {
                            datapos += u32 * 4;        //all ignored
                            skip    -= u32 * 4;
                        }
                        rot = new OpenGLRotate();
                        for (b = 0; b < 4; b++)
                        {
                            _float[b] = readfloat();
                            skip     -= 4;
                        }
                        rot.angle = _float[0] * 57.2957795f;    //convert to degrees
                        rot.x     = _float[1];
                        rot.y     = _float[2];
                        rot.z     = _float[3];
//Console.WriteLine("rot["+frameno+"]:"+rot.angle+","+rot.x+","+rot.y+","+rot.z+":flgs="+u16);
                        obj.GetRotateMap().Set(frameno, rot);
                        if (obj.GetMaxFrameCount() < frameno)
                        {
                            obj.SetMaxFrameCount(frameno);
                        }
                    }
                    _float = null;
                    obj    = null;
                    break;

                case 0xb022:    //keyframe scale
                    skip = head_len;
                    if (objidx == -1)
                    {
                        break;
                    }
                    obj    = mod.ol.Get(objidx);
                    u16    = readuint16(); //flgs
                    skip  -= 2;
                    u32    = readuint32(); //r1
                    skip  -= 4;
                    u32    = readuint32(); //r2
                    skip  -= 4;
                    keys   = readuint32(); //keys
                    skip  -= 4;
                    _float = new float[3];
                    for (a = 0; a < keys; a++)
                    {
                        frameno = readuint32(); //frame #
                        skip   -= 4;
                        u16     = readuint16(); //flgs
                        skip   -= 2;
                        u32     = 0;
                        if ((u16 & _3DS_FLG_TENSION) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_CONTINUITY) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_BIAS) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_EASE_TO) != 0)
                        {
                            u32++;
                        }
                        if ((u16 & _3DS_FLG_EASE_FROM) != 0)
                        {
                            u32++;
                        }
                        if (u32 > 0)
                        {
                            datapos += u32 * 4;        //all ignored
                            skip    -= u32 * 4;
                        }
                        scale = new OpenGLScale();
                        for (b = 0; b < 3; b++)
                        {
                            _float[b] = readfloat();
                            skip     -= 4;
                        }
                        scale.x = _float[0];
                        scale.y = _float[1];
                        scale.z = _float[2];
//Console.WriteLine("scale["+frameno+"]:"+scale.x+","+scale.y+","+scale.z+":flgs="+u16);
                        obj.GetScaleMap().Set(frameno, scale);
                        if (obj.GetMaxFrameCount() < frameno)
                        {
                            obj.SetMaxFrameCount(frameno);
                        }
                    }
                    _float = null;
                    obj    = null;
                    break;

                default:
                    skip = head_len;
                    break;
                }
                if (skip > 0)
                {
                    datapos += skip;
                    skip     = 0;
                }
            }
            //setup any lights
            _siz = mod.ol.Size();
            for (a = 0; a < _siz; a++)
            {
                obj = mod.ol.Get(a);
            }
            //delete temp lists
            matlist.Clear();
            objlist.Clear();
            return(mod);
        }