├── 280 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 281 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 282 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 290 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 291 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 292 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 300 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 301 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 302 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 304 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 305 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 400 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 401 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 403 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 404 ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── .gitignore ├── 283_LTS ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 293_LTS ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 303_LTS ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ ├── testConsole.cpp │ └── testGlut.cpp ├── 306_LTS ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── 402_LTS ├── Blender.h ├── fbtBlend.h └── tests │ ├── stb_image.h │ └── testConsole.cpp ├── Blender.h ├── LICENSE ├── README.md ├── fbtBlend.h ├── fbtBlendUpdater └── fbtBlendUpdater.cpp ├── screenshots ├── testGlut.png ├── test_skeletal_animation.gif └── test_skeletal_animation_header.png ├── test_skeletal_animation ├── ManuelLab140_Test.blend ├── main.cpp ├── man4.blend ├── math_helper.hpp ├── mesh.cpp ├── mesh.h ├── meshBlender.cpp ├── openGLTextureShaderAndBufferHelpers.cpp ├── openGLTextureShaderAndBufferHelpers.h ├── opengl_includer.h ├── shared_ptr.hpp └── stb_image.h └── tests ├── stb_image.h ├── test.blend ├── testConsole.cpp └── testGlut.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Other Stuff 55 | **/reps/ 56 | reps/ 57 | **/*.sh 58 | **/*.blend 59 | **/*.blend1 60 | *Makefile* 61 | **/*.qmake.stash 62 | 63 | tests/freeglut.dll 64 | tests/glut.dll 65 | tests/glut32.dll 66 | tests/html/ 67 | tests/*.png 68 | tests/*.jpg 69 | !tests/test.blend 70 | docs/ 71 | reps/ 72 | tests/reps/ 73 | *.pro 74 | *.user 75 | *.cfg 76 | *.ini 77 | tests/Makefile 78 | tests/textures 79 | *.exe 80 | Tests/test_im* 81 | Tests/test_shadows 82 | Tests/test_teapot 83 | Tests/test_matrix_stack 84 | Tests/test_im 85 | Tests/test_sdf 86 | glImmediateMode.h 87 | obj.h 88 | Sdf/ 89 | fbtBlendUpdater/fbtBlendUpdater 90 | fbtBlendUpdater/test.blend 91 | fbtBlendUpdater/Blender.h 92 | fbtBlendUpdater/fbtBlend.h 93 | tests/testConsole 94 | tests/testGlut 95 | test_skeletal_animation/html 96 | test_skeletal_animation/glm 97 | 32bit/ 98 | test_skeletal_animation/test_skeletal_animation 99 | !test_skeletal_animation/ManuelLab140_Test.blend 100 | !test_skeletal_animation/man4.blend 101 | test_skeletal_animation/Makefile 102 | 280/tests/testConsole 103 | 280/tests/testGlut 104 | 281/tests/testConsole 105 | 281/tests/testGlut 106 | 282/tests/testConsole 107 | 282/tests/testGlut 108 | 283_LTS/tests/testConsole 109 | 283_LTS/tests/testGlut 110 | 290/tests/testConsole 111 | 290/tests/testGlut 112 | 291/tests/testConsole 113 | 291/tests/testGlut 114 | 292/tests/testConsole 115 | 292/tests/testGlut 116 | 293_LTS/tests/testConsole 117 | 293_LTS/tests/testGlut 118 | 300/tests/testConsole 119 | 300/tests/testGlut 120 | 301/tests/testConsole 121 | 301/tests/testGlut 122 | 301/tests/testGlut.cpp 123 | 302/tests/testConsole 124 | 302/tests/testGlut 125 | 302/tests/testGlut.cpp 126 | 303_LTS/tests/testConsole 127 | 303_LTS/tests/testGlut 128 | 303_LTS/tests/testGlut.cpp 129 | 304/tests/testConsole 130 | 304/tests/testGlut 131 | 304/tests/testGlut.cpp 132 | 305/tests/testConsole 133 | 305/tests/testGlut 134 | 305/tests/testGlut.cpp 135 | 306_LTS/tests/testConsole 136 | 306_LTS/tests/testGlut 137 | 306_LTS/tests/testGlut.cpp 138 | 400/tests/testConsole 139 | 400/tests/testGlut 140 | 400/tests/testGlut.cpp 141 | 401/tests/testConsole 142 | 401/tests/testGlut 143 | 401/tests/testGlut.cpp 144 | 402_LTS/tests/testConsole 145 | 402_LTS/tests/testGlut 146 | 402_LTS/tests/testGlut.cpp 147 | 403/tests/testConsole 148 | 403/tests/testGlut 149 | 403/tests/testGlut.cpp 150 | 404/tests/testConsole 151 | 404/tests/testGlut 152 | 404/tests/testGlut.cpp 153 | 405/tests/testConsole 154 | 405/tests/testGlut 155 | 405/tests/testGlut.cpp 156 | test_skeletal_animation/minimath.h 157 | **/issues.txt 158 | **/man_no_texture.blend 159 | test_skeletal_animation_software_skinning/ 160 | test_character2c/ 161 | LICENSE.txt 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /280/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d stackindex=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode,mdf->stackindex); 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /281/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d stackindex=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode,mdf->stackindex); 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /282/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d stackindex=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode,mdf->stackindex); 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /283_LTS/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d stackindex=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode,mdf->stackindex); 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /290/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d stackindex=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode,mdf->stackindex); 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /291/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender 2.91 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /292/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /293_LTS/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /300/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVE = 2, 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | BL_OBTYPE_LAMP = 10, 26 | BL_OBTYPE_CAMERA = 11, 27 | BL_OBTYPE_WAVE = 21, 28 | BL_OBTYPE_LATTICE = 22, 29 | BL_OBTYPE_ARMATURE = 25 30 | }; 31 | 32 | 33 | int main(int argc, const char* argv[]) { 34 | fbtBlend fp; 35 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 36 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 37 | 38 | // Object List (probably the only relevant in most cases) 39 | long cnt=-1; 40 | fbtList& objects = fp.m_object; 41 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 42 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 43 | if (!ob) break; 44 | ++cnt; 45 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 46 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 47 | continue; 48 | } 49 | // It's a Mesh 50 | 51 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 52 | 53 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 54 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 55 | 56 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 57 | { 58 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 59 | while (mdf) { 60 | // mdf->type(1= SubSurf 5=mirror 8=armature) 61 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 62 | if (mdf->error) { 63 | printf("Error: %s\n",mdf->error); 64 | } 65 | else { 66 | if (mdf->type==1) { 67 | // Subsurf modifier: 68 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 69 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 70 | } 71 | if (mdf->type==5) { 72 | //Mirror modifier: 73 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 74 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 75 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 76 | } 77 | else if (mdf->type==8) { 78 | //Armature Modifier: 79 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 80 | 81 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 82 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 83 | printf("Deform Group Name: %s\n",md->defgrp_name); 84 | 85 | } 86 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 87 | } 88 | mdf = mdf->next; 89 | } 90 | } 91 | //--------------------- 92 | } 93 | 94 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 95 | /* From the declaration of struct fbtBlend: 96 | fbtList m_scene; 97 | fbtList m_library; 98 | fbtList m_object; 99 | fbtList m_mesh; 100 | fbtList m_curve; 101 | fbtList m_mball; // MataBall 102 | fbtList m_mat; // Material 103 | fbtList m_tex; // Texture 104 | fbtList m_image; 105 | fbtList m_latt; // Lattice 106 | fbtList m_lamp; 107 | fbtList m_camera; 108 | fbtList m_ipo; // or FCurves 109 | fbtList m_key; // ShapeKey 110 | fbtList m_world; 111 | fbtList m_screen; 112 | fbtList m_script; // Python (used in older versions) 113 | fbtList m_vfont; // VectorFont 114 | fbtList m_text; 115 | fbtList m_speaker; 116 | fbtList m_sound; 117 | fbtList m_group; // Group/Collection 118 | fbtList m_armature; 119 | fbtList m_action; 120 | fbtList m_nodetree; 121 | fbtList m_brush; 122 | fbtList m_particle; // ParticleSettings 123 | fbtList m_wm; // WindowManager 124 | fbtList m_gpencil; 125 | fbtList m_movieClip; 126 | fbtList m_mask; 127 | fbtList m_freeStyleLineStyle; 128 | fbtList m_palette; 129 | fbtList m_paintCurve; 130 | fbtList m_cacheFile; 131 | fbtList m_workSpace; 132 | fbtList m_lightProbe; 133 | fbtList m_hair; 134 | fbtList m_pointCloud; 135 | fbtList m_volume; 136 | fbtList m_simulation;// GeometryNodeGroups 137 | */ 138 | 139 | // As an example: Image List 140 | cnt=-1; 141 | fbtList& images = fp.m_image; 142 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 143 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 144 | if (!im) break; 145 | ++cnt; 146 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 147 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 148 | } 149 | 150 | // As an example: Scene List 151 | cnt=-1; 152 | fbtList& scenes = fp.m_scene; 153 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 154 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 155 | if (!sc) break; 156 | ++cnt; 157 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 158 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 159 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 160 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 161 | } 162 | 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /301/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /302/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /303_LTS/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /304/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /305/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /306_LTS/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /400/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /401/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /402_LTS/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /403/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /404/tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_ZSTD_FILE=1" -lzstd 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_ZSTD_FILE=1" /link /out:testConsole.exe libzstd.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_ZSTD_FILE=1" and -lzstd (libzstd.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // Untested: (requires a -lzstd emscripten-compiled library... please see: https://github.com/kig/zstd-emscripten/ ) 10 | // [Include And Library Paths for zstd are missing] 11 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_ZSTD_FILE=1" -lzstd -s ALLOW_MEMORY_GROWTH=1 --closure 1 12 | 13 | #define FBTBLEND_IMPLEMENTATION 14 | #include "../fbtBlend.h" 15 | 16 | #include 17 | 18 | enum BlenderObjectType { 19 | BL_OBTYPE_EMPTY = 0, 20 | BL_OBTYPE_MESH = 1, 21 | BL_OBTYPE_CURVES_LEGACY = 2, // used to be BL_OBTYPE_CURVE before Blender 3.1 (deprecated: will be replaced by BL_OBTYPE_CURVES) 22 | BL_OBTYPE_SURF = 3, 23 | BL_OBTYPE_FONT = 4, 24 | BL_OBTYPE_MBALL = 5, 25 | 26 | BL_OBTYPE_LAMP = 10, 27 | BL_OBTYPE_CAMERA = 11, 28 | BL_OBTYPE_SPEAKER = 12, 29 | BL_OBTYPE_LIGHTPROBE = 13, 30 | 31 | BL_OBTYPE_WAVE = 21, // not sure if this is still in use... 32 | BL_OBTYPE_LATTICE = 22, 33 | 34 | BL_OBTYPE_ARMATURE = 25, 35 | BL_OBTYPE_GPENCIL = 26, // in 3D view (but no 2D annotation). 36 | BL_OBTYPE_CURVES = 27, // from Blender>=3.1 it should contain: hair. It will replace BL_OBTYPE_CURVES_LEGACY too. 37 | BL_OBTYPE_POINTCLOUD = 28, 38 | BL_OBTYPE_VOLUME = 29, 39 | 40 | BL_OBTYPE_COUNT 41 | }; 42 | 43 | 44 | 45 | int main(int argc, const char* argv[]) { 46 | fbtBlend fp; 47 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 48 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 49 | 50 | // Object List (probably the only relevant in most cases) 51 | long cnt=-1; 52 | fbtList& objects = fp.m_object; 53 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 54 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 55 | if (!ob) break; 56 | ++cnt; 57 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 58 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 59 | continue; 60 | } 61 | // It's a Mesh 62 | 63 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 64 | 65 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 66 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 67 | 68 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 69 | { 70 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 71 | while (mdf) { 72 | // mdf->type(1= SubSurf 5=mirror 8=armature) 73 | printf("Object '%s' had modifier: %s (type=%d mode=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode); // mdf->stackindex is not available in Blender >= 2.91 74 | if (mdf->error) { 75 | printf("Error: %s\n",mdf->error); 76 | } 77 | else { 78 | if (mdf->type==1) { 79 | // Subsurf modifier: 80 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 81 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d \n",md->subdivType,md->levels,md->renderLevels,md->flags); 82 | } 83 | if (mdf->type==5) { 84 | //Mirror modifier: 85 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 86 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 87 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 88 | } 89 | else if (mdf->type==8) { 90 | //Armature Modifier: 91 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 92 | 93 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 94 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 95 | printf("Deform Group Name: %s\n",md->defgrp_name); 96 | 97 | } 98 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 99 | } 100 | mdf = mdf->next; 101 | } 102 | } 103 | //--------------------- 104 | } 105 | 106 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 107 | /* From the declaration of struct fbtBlend (in fbtBlend.h): 108 | fbtList m_scene; 109 | fbtList m_library; 110 | fbtList m_object; 111 | fbtList m_mesh; 112 | fbtList m_curve; // In Blender>=3.1 it's obsolated and marked 'legacy'. New .blend files should use m_curves instead (see below) 113 | fbtList m_mball; // MataBall 114 | fbtList m_mat; // Material 115 | fbtList m_tex; // Texture 116 | fbtList m_image; 117 | fbtList m_latt; // Lattice 118 | fbtList m_lamp; 119 | fbtList m_camera; 120 | fbtList m_ipo; // or FCurves 121 | fbtList m_key; // ShapeKey 122 | fbtList m_world; 123 | fbtList m_screen; 124 | fbtList m_script; // Python (used in older versions) 125 | fbtList m_vfont; // VectorFont 126 | fbtList m_text; 127 | fbtList m_speaker; 128 | fbtList m_sound; 129 | fbtList m_group; // Group/Collection 130 | fbtList m_armature; 131 | fbtList m_action; 132 | fbtList m_nodetree; 133 | fbtList m_brush; 134 | fbtList m_particle; // ParticleSettings 135 | fbtList m_gpencil; 136 | fbtList m_wm; // WindowManager 137 | fbtList m_movieClip; 138 | fbtList m_mask; 139 | fbtList m_freeStyleLineStyle; 140 | fbtList m_palette; 141 | fbtList m_paintCurve; 142 | fbtList m_cacheFile; 143 | fbtList m_workSpace; 144 | fbtList m_lightProbe; 145 | fbtList m_hair; // Removed in Blender 3.1: replaced by m_curves. 146 | fbtList m_curves; // Replacement for m_hair (and m_curve) in Blender>=3.1 147 | fbtList m_pointCloud; 148 | fbtList m_volume; 149 | fbtList m_simulation;// GeometryNodeGroups 150 | */ 151 | 152 | // As an example: Image List 153 | cnt=-1; 154 | fbtList& images = fp.m_image; 155 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 156 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 157 | if (!im) break; 158 | ++cnt; 159 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 160 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 161 | } 162 | 163 | // As an example: Scene List 164 | cnt=-1; 165 | fbtList& scenes = fp.m_scene; 166 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 167 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 168 | if (!sc) break; 169 | ++cnt; 170 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 171 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 172 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 173 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ZLIB LICENSE 2 | 3 | Copyright (c) 2017-2024 (https://github.com/Flix01/fbtBlend-Header-Only) 4 | 5 | This software is provided ‘as-is’, without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fbtBlend-Header-Only 2 | 3 | 4 | **fbtBlend** is a C++ .blend file parser from https://github.com/gamekit-developers/gamekit (available in the repository subfolder: [./Tools/FileTools/FileFormats/Blend](https://github.com/gamekit-developers/gamekit/tree/master/Tools/FileTools/FileFormats/Blend)). 5 | 6 | Here there's a version updated to Blender 2.79 and amalgamated into two header files: **fbtBlend.h** and **Blender.h**. 7 | 8 | 9 | ## Demos 10 | 11 | Two demos are available: **testConsole.cpp** and **testGlut.cpp** (they contain build instructions for Linux/MacOS and Windows). 12 | 13 | A third demo is present in the subfolder **test_skeletal_animation** (build instructions are at the top of **test_skeletal_animation/main.cpp**). 14 | 15 | ## Dependencies (recommended, to load compressed .blend files) 16 | 17 | * zlib (for Blender versions < 3.0) 18 | * libzstd (for Blender versions >= 3.0) 19 | 20 | 21 | **testGlut.cpp and test_skeletal_animation need:** 22 | 23 | * glut (or freeglut) 24 | * glew (Windows only) 25 | 26 | ## Blender versions from 2.80 to 4.4 27 | 28 | In the *280*, *...*, *404* repository folders there are versions of **fbtBlend.h** and **Blender.h** updated for Blender 2.80, ..., 4.4. 29 | In the *280/tests*, *.../tests*, *404/tests* subfolders there are some test programs that should compile correctly with these versions. 30 | 31 | Please note that: 32 | - the files: **XXX/tests/testGlut.cpp**, when **XXX>=280**, are the same as the 2.79 version, except that all materials have been stripped, because Blender>=2.80 doesn't support "Blender Internal" materials anymore. 33 | - the files: **3xx/tests/testGlut.cpp**, when **3xx>=301**, are missing, because Blender 3.1 (or newer) has removed normals from the ```struct MVert```, and I don't know how to retrieve them. 34 | 35 | Of course I'll **NEVER** make a ```testGlut.cpp``` that can display physics-based materials... be warned! 36 | 37 | ## Screenshots 38 | ![testGlut](./screenshots/testGlut.png) 39 | 40 | ![test_skeletal_animation_header](./screenshots/test_skeletal_animation_header.png) 41 | ------------------------------------------------------------------------------------- 42 | ![test_skeletal_animation](./screenshots/test_skeletal_animation.gif) 43 | 44 | 45 | ## Useful Links: 46 | [Gamekit Github Page](https://github.com/gamekit-developers/gamekit) 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /screenshots/testGlut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flix01/fbtBlend-Header-Only/b91852a270ed6a93040199fe1c00b88d7b239919/screenshots/testGlut.png -------------------------------------------------------------------------------- /screenshots/test_skeletal_animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flix01/fbtBlend-Header-Only/b91852a270ed6a93040199fe1c00b88d7b239919/screenshots/test_skeletal_animation.gif -------------------------------------------------------------------------------- /screenshots/test_skeletal_animation_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flix01/fbtBlend-Header-Only/b91852a270ed6a93040199fe1c00b88d7b239919/screenshots/test_skeletal_animation_header.png -------------------------------------------------------------------------------- /test_skeletal_animation/ManuelLab140_Test.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flix01/fbtBlend-Header-Only/b91852a270ed6a93040199fe1c00b88d7b239919/test_skeletal_animation/ManuelLab140_Test.blend -------------------------------------------------------------------------------- /test_skeletal_animation/man4.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flix01/fbtBlend-Header-Only/b91852a270ed6a93040199fe1c00b88d7b239919/test_skeletal_animation/man4.blend -------------------------------------------------------------------------------- /test_skeletal_animation/mesh.h: -------------------------------------------------------------------------------- 1 | #ifndef MESH_H__ 2 | #define MESH_H__ 3 | #pragma once 4 | 5 | 6 | //#include 7 | //#include // glm::perspective(...), glm::value_ptr(...),etc. 8 | //#include // plain glm is not enough (Ogre Math would probably be enough...) 9 | 10 | #ifndef USE_MINIMATH_H 11 | #include 12 | #else 13 | #include 14 | #endif 15 | 16 | // GL types (and calls) are be included by this header----- 17 | #include "opengl_includer.h" 18 | #include "openGLTextureShaderAndBufferHelpers.h" 19 | 20 | #include 21 | using std::vector; 22 | 23 | /*#include // shared_ptr needs C++11 (is there some way to avoid it?) 24 | using std::shared_ptr;*/ // Probably without C++11 we can't use "using" with template classes (but this issue can be solved using multiple statements) 25 | #include "shared_ptr.hpp" // stand-alone version (no boost or C++11 required) 26 | //#define MESH_H_STD_MAP std::unordered_map 27 | //#include // Faster, but needs C++11 28 | #define MESH_H_STD_MAP std::map 29 | #include // Slower, but no C++11 30 | typedef MESH_H_STD_MAP MapStringUnsigned; 31 | 32 | 33 | struct Material { 34 | float amb[4]; 35 | float dif[4]; 36 | float spe[4]; 37 | float shi; // In [0,1], not in [0,128] 38 | float emi[4]; 39 | Material(); 40 | Material(float r,float g,float b,bool useSpecularColor = true,float ambFraction=0.4f,float speAddon=0.4f,float shininessIn01=(4.0f/128.0f)); 41 | // TODO: add ctrs for known colors 42 | void bind() const; // openGL method: btTriangleMesh.h/cpp shouldn't include gl stuff, we'll define it in another .cpp file. 43 | void lighten(float q=0.2f); 44 | void darken(float q=0.2f); 45 | void clamp(); // all in [0,1] 46 | void reset(); 47 | //Uses printf 48 | void displayDebugInfo() const; 49 | }; 50 | 51 | 52 | 53 | typedef glm::vec4 Vector4; 54 | typedef vector Vector4Array; 55 | typedef glm::vec3 Vector3; 56 | typedef vector Vector3Array; 57 | typedef glm::vec2 Vector2; 58 | typedef vector Vector2Array; 59 | #ifndef __EMSCRIPTEN__ 60 | typedef unsigned int IndexType; 61 | #else //__EMSCRIPTEN__ 62 | typedef unsigned short IndexType; 63 | #endif //__EMSCRIPTEN__ 64 | typedef vector IndexArray; 65 | 66 | typedef glm::quat Quaternion; 67 | typedef glm::mat3 Matrix3; 68 | typedef glm::mat4 Matrix; 69 | typedef float Scalar; 70 | 71 | #ifdef GLMINITRIANGLEBATCH_INTEGER_BONE_INDICES 72 | typedef glm::uvec4 BoneIdsType; 73 | #else //GLMINITRIANGLEBATCH_INTEGER_BONE_INDICES 74 | typedef glm::vec4 BoneIdsType; 75 | #endif //GLMINITRIANGLEBATCH_INTEGER_BONE_INDICES 76 | typedef glm::vec4 BoneWeightsType; 77 | 78 | typedef glm::mat4 Mat4; 79 | typedef glm::mat3 Mat3; 80 | 81 | #include 82 | typedef std::string string; 83 | 84 | class Mesh; 85 | class MeshInstance { 86 | public: 87 | static shared_ptr < MeshInstance > CreateFrom(shared_ptr < Mesh > meshPtr); 88 | shared_ptr clone() const {shared_ptr p(new MeshInstance(parentMesh));*p=*this; return p;} 89 | 90 | void shift(const Vector3& v); // Rotation agnostic 91 | void scale(const Vector3& s); // Rotation agnostic 92 | void rotate(Scalar degAngle,const glm::vec3& axis); 93 | void resetShiftScaleRotate(); 94 | 95 | // These methods are ROTATION AGNOSTIC: i.e. are not affected by any rotation you make 96 | Vector3 center(); 97 | Vector3 getHalfExtents() const; 98 | Vector3 getHalfFullExtents() const; 99 | Vector3 getCenterPoint() const; 100 | // These methods are ROTATION AWARE: i.e. y is always the vertical axis (it can be changed by a previous rotation) 101 | Vector3 setHeight(Scalar value); 102 | Vector3 setWidth(Scalar value); 103 | Vector3 setLength(Scalar value); 104 | Vector3 setFullExtents(const Vector3& extents); 105 | Vector3 setHalfExtents(const Vector3& extents); 106 | //-------------------------------------------------------------------------------------------- 107 | 108 | // Just fills the currentPose member: 109 | void setPose(unsigned animationIndex,float TimeInSeconds,float additionalPoseTransitionTime = 1.0f); 110 | void resetPose(unsigned animationIndex,int rotationKeyFrameNumber=0,int transitionKeyFrameNumber=0,int scalingKeyFrameNumber=0); 111 | void setBindingPose(); 112 | void manuallySetPoseToBone(unsigned boneIndex,const glm::mat4& bonePose,bool applyPoseOverCurrentBonePose=false,bool bonePoseIsInLocalSpace=true); 113 | void displaySkeleton(const glm::mat4& vpMatrix) const; 114 | 115 | //#ifndef TEST_SOFTWARE_SKINNING 116 | void render(const OpenGLSkinningShaderData& p, const GLfloat *vMatrix=NULL, int meshPartIndex=-1) const; 117 | inline void render(const OpenGLSkinningShaderData& p, const glm::mat4& vMatrix, int meshPartIndex=-1) const {render(p,glm::value_ptr(vMatrix),meshPartIndex);} 118 | //#endif //TEST_SOFTWARE_SKINNING 119 | #ifdef TEST_SOFTWARE_SKINNING 120 | void softwareRender(const GLfloat *vMatrix=NULL, int meshPartIndex=-1,bool autoUpdateVertsAndNorms=true) const; 121 | inline void softwareRender(const glm::mat4& vMatrix,int meshPartIndex=-1,bool autoUpdateVertsAndNorms=true) const {softwareRender(glm::value_ptr(vMatrix),meshPartIndex,autoUpdateVertsAndNorms);} 122 | protected: 123 | void softwareUpdateVertsAndNorms(); // exposed through 'autoUpdateVertsAndNorms' in the methods above this. 124 | public: 125 | #endif //TEST_SOFTWARE_SKINNING 126 | 127 | 128 | // use it to feed the shader: 129 | const vector < glm::mat4 >& getCurrentPoseTransforms() const {return currentPose;} 130 | 131 | // The following 2 members are here for convenience: the user should set up a 132 | // shader environment to properly use them (e.g. modelT *= translationAndRotationOffset, and pass scalingOffset as uniform if scaling is supported) 133 | // Update: when using the render(...) method with the valid shader these 2 are set automatically 134 | const glm::mat4& getTranslationAndRotationOffset() const {return translationAndRotationOffset;} 135 | const glm::vec3& getScalingOffset() const {return scalingOffset;} // available only for shaders that supports it (shader with separeted uniform value scaling). 136 | 137 | // position 138 | const GLfloat* glModelMatrixGet() const {return glm::value_ptr(mMatrix);} 139 | GLfloat* glModelMatrixGet() {return glm::value_ptr(mMatrix);} 140 | const glm::mat4& getModelMatrix() const {return mMatrix;} 141 | glm::mat4& getModelMatrix() {return mMatrix;} 142 | 143 | // Look customization: 144 | vector < Material* >& getMaterialOverrides() {return materialOverrides;} // overridden materials must be persistent 145 | vector < GLuint >& getTextureOverrides() {return textureOverrides;} 146 | vector& getVisibilityOverrides() {return visibilityOverrides;} 147 | 148 | size_t getNumMeshParts() const; 149 | 150 | /* 151 | struct AnimationSetter { 152 | float animationTransitionTime; // the time (seconds) needed to go from currentPose to currentAnimationKeys[0].value is: animationTransitionTime + currentAnimationKeys[0].time 153 | // this increases the effective currentAnimationTime of "animationTransitionTime" seconds. 154 | float animationSpeed; 155 | unsigned animationIndex; 156 | float AnimationStartTimeInTicks; 157 | int boneIndex; // -1 == all bones 158 | public: 159 | AnimationSetter(unsigned _animationIndex=0,float _animationTransitionTime=float(1.0),float _animationSpeed=float(1.0),int boneIndex=-1); 160 | void setAnimationTransitionTime(float value) {animationTransitionTime = value;} 161 | const float& getAnimationTransitionTime() const {return animationTransitionTime;} 162 | float& getAnimationTransitionTime() {return animationTransitionTime;} 163 | void setBoneIndex(int _boneIndex=-1) {boneIndex=_boneIndex;} 164 | const int getBoneIndex() const {return boneIndex;} 165 | friend class MeshInstance; 166 | friend class Mesh; 167 | }; 168 | 169 | void setPose(AnimationSetter& as,float TimeInSeconds); 170 | */ 171 | /* 172 | void setPose(AnimationSetter& as,float TimeInSeconds); 173 | void startAnimation(AnimationSetter& as,float TimeInSeconds); 174 | void pauseAnimation(AnimationSetter& as,float TimeInSeconds); 175 | void stopAnimation(AnimationSetter& as); 176 | void resetAnimation(MeshInstancePtr mi); 177 | */ 178 | protected: 179 | MeshInstance(shared_ptr < class Mesh > _parentMesh); 180 | // The following 2 members are here for convenience: the user should set up a 181 | // shader environment to properly use them (e.g. modelT *= translationAndRotationOffset, and pass scalingOffset as uniform if scaling is supported) 182 | glm::mat4 mMatrix; 183 | glm::mat4 translationAndRotationOffset; // must be orthonormal 184 | glm::vec3 scalingOffset; 185 | // -------------------------------------------------------------------------------- 186 | 187 | vector < glm::mat4 > currentPose; 188 | shared_ptr < class Mesh > parentMesh; 189 | struct BoneFootprint{ 190 | //------- Current Bone Pose ------------------------------------------------ 191 | glm::vec3 translation; 192 | glm::quat rotation; 193 | glm::vec3 scaling; 194 | //-------------------------------------------------------------------------- 195 | BoneFootprint() : translation(0,0,0),rotation(1,0,0,0),scaling(1,1,1), 196 | currentAnimationIndex(0),startTimeInTicksOfCurrentAnimationIndex(-1.0f), 197 | translationPoseTransitionTime(0),rotationPoseTransitionTime(0),scalingPoseTransitionTime(0) 198 | //,translationAtStart(0,0,0),rotationAtStart(1,0,0,0),scalingAtStart(1,1,1) 199 | {} 200 | void reset() {*this = BoneFootprint();} 201 | //-------------------------------------------------------------------------- 202 | int currentAnimationIndex; // unused 203 | float startTimeInTicksOfCurrentAnimationIndex; // unused 204 | //-------------------------------------------------------------------------- 205 | float translationPoseTransitionTime,rotationPoseTransitionTime,scalingPoseTransitionTime; // to remove 206 | // TODO:for fixing the initial 'blending' time----------------------------------- 207 | /*glm::vec3 translationAtStart; 208 | glm::quat rotationAtStart; 209 | glm::vec3 scalingAtStart; 210 | void initializeInitialBlending() { 211 | translationAtStart = translation; 212 | rotationAtStart = rotation; 213 | scalingAtStart = scaling; 214 | }*/ 215 | }; 216 | vector < BoneFootprint > boneFootprints; //This should be transparent to the user 217 | void resetBoneFootprints(); 218 | 219 | // look customization: 220 | vector < Material* > materialOverrides; // overridden materials must be persistent 221 | vector < GLuint > textureOverrides; 222 | vector visibilityOverrides; 223 | 224 | 225 | #ifdef TEST_SOFTWARE_SKINNING 226 | struct MeshPartFootprint { 227 | Vector3Array verts; 228 | Vector3Array norms; 229 | }; 230 | vector meshPartFootprints; 231 | // TODO: vertex array, VBO or VAO here... 232 | #endif //TEST_SOFTWARE_SKINNING 233 | 234 | friend class Mesh; 235 | }; 236 | typedef shared_ptr < MeshInstance > MeshInstancePtr; 237 | 238 | class Mesh { 239 | public: 240 | struct Part { 241 | Vector3Array verts; // if size()==0, inds refers to useVertexArrayInPartIndex if != -1 ot to the last "valid" verts in the previous subparts. 242 | Vector3Array norms; // valid only if verts.size()==norms.size() 243 | Vector2Array texcoords; // valid only if verts.size()==texcoords.size() 244 | vector< BoneIdsType > boneIds; 245 | vector< BoneWeightsType > boneWeights; 246 | string meshName; //optional 247 | 248 | IndexArray inds; 249 | int useVertexArrayInPartIndex; // Used only if verts.size()==0, useVertexArrayInPartIndex must be lesser than the current subpart index 250 | int parentBoneId; // (.blend only) -1 by default. When set it means that all the verts are transformed only by this single Bone (just as a possible future optimization, since boneIds and bone Weights are still present and used instead) 251 | 252 | Material material; 253 | string materialName; //optional 254 | //bf::GLTexturePtr textureId; 255 | GLuint textureId; 256 | string textureFilePath; //optional 257 | //fs::path textureFilePath; //optional 258 | 259 | GLMiniTriangleBatchPtr batch; 260 | /* 261 | bf::GLBufferPtr vbo; 262 | bf::GLBufferPtr ibo; 263 | 264 | bf::GLArrayBuffer vao; 265 | */ 266 | void generateVertexArrays(const Mesh& parentMesh); // Not actually used with TEST_SOFTWARE_SKINNING 267 | bool visible; 268 | 269 | Part(); 270 | Part(int _useVertexArrayInPartIndex); 271 | ~Part(); 272 | protected: 273 | void reset(); 274 | void normalizeBoneWeights(); 275 | bool addBoneWeights(size_t vertsId,unsigned int boneId,GLfloat boneWeight); 276 | friend class Mesh; 277 | }; 278 | typedef vector < Part > MeshPartVector; 279 | 280 | static shared_ptr < Mesh > Create(/*bool _uselocalTextureMapCollector=false*/); 281 | 282 | static GLuint WhiteTextureId; /* user can create one and delete it himself to support non-textured animated meshes */ 283 | 284 | protected: 285 | Mesh(/*bool _uselocalTextureMapCollector=false*/); 286 | public: 287 | virtual ~Mesh(); 288 | void reset(); 289 | 290 | bool loadFromAnimatedBlendFile(const char* filePath,int flags=0); 291 | bool loadFromFile(const char* filePath, int flags=0); 292 | void generateVertexArrays(int meshPartIndex=-1); 293 | //#ifndef TEST_SOFTWARE_SKINNING 294 | void render(int meshPartIndex=-1) const; 295 | void render(const OpenGLSkinningShaderData& p, int meshPartIndex, const vector *pOptionalMaterialOverrides=NULL, const vector *pOptionalTextureOverrides=NULL,const vector* pOptionalVisibilityOverrides=NULL) const; 296 | //#endif //TEST_SOFTWARE_SKINNING 297 | // The following actions are not persistent, but instantaneous. 298 | // optionalSubpartIndex!=-1 has undefined results if meshes[optionalSubpartIndex] does not own his own vertex array 299 | Vector3 center(int optionalMeshPartIndex=-1); // (returns the old center) 300 | Vector3 setHeight(Scalar height,int optionalMeshPartIndex=-1); // Y axis (returns the applied scaling factor) 301 | Vector3 setWidth(Scalar width,int optionalMeshPartIndex=-1); // X axis (returns the applied scaling factor) 302 | Vector3 setLength(Scalar length,int optionalMeshPartIndex=-1); // Z axis (returns the applied scaling factor) 303 | Vector3 setFullExtents(const Scalar& extents,int optionalMeshPartIndex=-1); // (returns the applied scaling factor) 304 | Vector3 setHalfExtents(const Scalar& extents,int optionalMeshPartIndex=-1); // (returns the applied scaling factor) 305 | void shift(const Vector3& shiftFactor,int optionalMeshPartIndex=-1); 306 | void scale(const Vector3& scaling,int optionalMeshPartIndex=-1); 307 | void rotate(const Matrix3& m,int optionalMeshPartIndex=-1); 308 | void rotate(const glm::quat& q,int optionalMeshPartIndex=-1); 309 | void transform(const glm::mat4& T,int optionalMeshPartIndex=-1); 310 | 311 | const Vector3 getAabbHalfExtents(int optionalMeshPartIndex=-1) const; 312 | const Vector3 getAabbFullExtents(int optionalMeshPartIndex=-1) const; 313 | const Vector3 getCenterPoint(int optionalMeshPartIndex=-1) const; 314 | int getIndexOfBoneContainingName(const string& name) const; 315 | bool getVerticesBelongingToBone(unsigned boneIndex,vector& vertsOut,int optionalMeshPartIndex=-1) const; 316 | 317 | //very big memory copy... slow 318 | Mesh(const Mesh& c); 319 | //very big memory copy... slow 320 | const Mesh& operator=(const Mesh& c); 321 | 322 | //Uses printf 323 | void displayDebugInfo(bool vertices=true,bool materials=true,bool bones=true,bool animations=true) const; 324 | 325 | 326 | 327 | const MeshPartVector& getMeshParts() const {return meshParts;} 328 | const Part* getMeshPart(int i) const {if (i>=0 && i<(int)meshParts.size()) return &meshParts[i];else return NULL;} 329 | const Material* getMeshPartMaterial(int i) const {if (i>=0 && i<(int)meshParts.size()) return &meshParts[i].material;else return NULL;} 330 | Material* getMeshPartMaterial(int i) {if (i>=0 && i<(int)meshParts.size()) return &meshParts[i].material;else return NULL;} 331 | 332 | void setMeshPartMaterial(int i,const Material& mat) {if (i>=0 && i<(int)meshParts.size()) meshParts[i].material = mat;} 333 | GLuint getMeshPartTexture(int i) const {if (i>=0 && i<(int)meshParts.size()) return meshParts[i].textureId;else return 0;} 334 | void setMeshPartTexture(int i,GLuint textureId) {if (i>=0 && i<(int)meshParts.size()) meshParts[i].textureId = textureId;} 335 | /* 336 | GLuint getMeshPartTextureId(int i) const {return ((i>=0 && i=0 && i=0 && i getMeshPartIndices(int optionalPartIndex) const; 346 | Vector3 GetAabbHalfExtents(Vector3* pOptionalCenterPointOut,int optionalPartIndex) const; 347 | Vector3 setFullExtents(const Vector3& extents,int optionalPartIndex); 348 | Vector3 setHalfExtents(const Vector3& extents,int optionalPartIndex); 349 | void GetAabbEdgePoints(Vector3& fullExts,Vector3& centerPoint,vector& aabbEdge6Vertices,const Vector3* pAabbFullExtsToScan=NULL,int _optionalPartIndex=-1) const; // If pAabbToScan!=NULL, centerPoint ia an In-Out argument. 350 | 351 | void getBoneTransforms(unsigned animationIndex,float TimeInSeconds, vector& Transforms); 352 | void getBindingPoseBoneTransforms(vector& Transforms); 353 | void getBoneTransforms(unsigned animationIndex,float TimeInSeconds,float additionalPoseTransitionTime, MeshInstance& mi); 354 | void getBoneTransformsForPose(unsigned animationIndex,int rotationKeyFrameNumber,int translationKeyFrameNumber,int scalingKeyFrameNumber, MeshInstance& mi); 355 | 356 | void displaySkeleton(const glm::mat4& mvpMatrix,const vector* pTransforms=NULL,const glm::mat4* pOptionalTranslationAndRotationOffset=NULL,const glm::vec3* pOptionalScaling=NULL) const; 357 | void manuallySetPoseToBone(unsigned boneIndex,const glm::mat4& bonePose,vector& Transforms,bool applyPoseOverCurrentBonePose=false,bool bonePoseIsInLocalSpace=false) const; 358 | 359 | 360 | unsigned getNumBones() const {return numValidBones;/*m_boneInfos.size();*/} 361 | unsigned getNumExtraDummyBones() const {return m_boneInfos.size()-numValidBones;} 362 | //unsigned getNumTotalBones() const {return m_boneInfos.size();} 363 | bool isSkeletalAnimated() const {return getNumBones()>0;} 364 | unsigned getNumAnimations() const {return m_animationInfos.size();} 365 | string getAnimationName(unsigned i) const {return isecond; 370 | return -1; 371 | } 372 | 373 | void setPlayAnimationAgainWhenOvertime(bool flag) {m_playAnimationsAgainWhenOvertime = flag;} 374 | bool getPlayAnimationsAgainWhenOvertime() {return m_playAnimationsAgainWhenOvertime;} 375 | 376 | protected: 377 | MeshPartVector meshParts; // I should use , but I want to keep things simple 378 | 379 | // Bone stuff 380 | MapStringUnsigned m_boneIndexMap; // maps a bone name to its index 381 | public: 382 | struct BoneInfo { 383 | unsigned index; // inside m_BoneInfos vector (bad design) 384 | unsigned indexMirror; // .blend only (when not set is == index) 385 | Mat4 boneOffset; //Problem: this depends on the mesh index (although I never experienced any problems so far) 386 | Mat4 boneOffsetInverse; //Never used, but useful to display skeleton (from bone space to global space) 387 | //Mat4 globalSpaceBoneOffset; //Never used 388 | bool isDummyBone; // Dummy bones have boneOffset = boneOffsetInverse = mat4(1), and are not counted in getNumBones() 389 | bool isUseless; // Dummy nodes can be marked as useless they could be erased by m_boneInfos, but it's too difficult to do it (see the references stored below) 390 | 391 | //---new-------------------------- 392 | Mat4 preTransform; // Must always be applied (if preTransformIsPresent == false) before all other transforms 393 | bool preTransformIsPresent; // When false preTransform = glm::mat(1) 394 | Mat4 preAnimationTransform; // When animation keys are simplyfied some of them (usually translation only) are inglobed in this transform. 395 | bool preAnimationTransformIsPresent; 396 | Mat4 multPreTransformPreAnimationTransform; // just to speed up things a bit 397 | Mat4 postAnimationTransform; // When animation keys are simplyfied some of them (usually rotation and scaling) are inglobed in this transform. 398 | bool postAnimationTransformIsPresent; 399 | 400 | enum EulerRotationMode { 401 | EULER_XYZ = 1, // 1 402 | EULER_XZY = 2, // 2 403 | EULER_YXZ = 3, // 3 404 | EULER_YZX = 4, // 4 405 | EULER_ZXY = 5, // 5 406 | EULER_ZYX = 6 // 6 407 | //AXIS_ANGLE = -1 // (these are used by Blender too) 408 | //QUATERNION_WXYZ = 0 409 | }; 410 | int eulerRotationMode; // Optional (default=0); 411 | 412 | Mat4 transform; // Must be used when no animation is present, and replaced by the BoneAnimation combined transform otherwise. 413 | struct BoneAnimationInfo { 414 | struct Vector3Key { 415 | glm::vec3 value; 416 | float time; 417 | }; 418 | struct QuaternionKey { 419 | glm::quat value; 420 | float time; 421 | }; 422 | enum BehaviorEnum { 423 | AB_DEFAULT = 0, //The value from the default node transformation is taken. 424 | AB_CONSTANT = 1, //The nearest key value is used without interpolation. 425 | AB_LINEAR = 2, //The value of the nearest two keys is linearly extrapolated for the current time value. 426 | AB_REPEAT = 3, //The animation is repeated. 427 | //If the animation key go from n to m and the current time is t, use the value at (t-n) % (|m-n|). 428 | AB_COUNT 429 | }; 430 | vector translationKeys; 431 | vector rotationKeys; 432 | vector scalingKeys; 433 | bool tkAndRkHaveUniqueTimePerKey; 434 | bool tkAndSkHaveUniqueTimePerKey; 435 | bool rkAndSkHaveUniqueTimePerKey; 436 | BehaviorEnum preState; //Defines how the animation behaves before the first key is encountered. 437 | BehaviorEnum postState; //Defines how the animation behaves after the last key was processed. 438 | void reset() { 439 | translationKeys.clear();rotationKeys.clear();scalingKeys.clear(); 440 | tkAndRkHaveUniqueTimePerKey = tkAndSkHaveUniqueTimePerKey = rkAndSkHaveUniqueTimePerKey = false; 441 | preState = postState = AB_DEFAULT; 442 | } 443 | }; 444 | typedef MESH_H_STD_MAP MapUnsignedBoneAnimationInfo; 445 | MapUnsignedBoneAnimationInfo boneAnimationInfoMap; 446 | inline const BoneAnimationInfo* getBoneAnimationInfo(unsigned animationIndex) const { 447 | MapUnsignedBoneAnimationInfo::const_iterator it = boneAnimationInfoMap.find(animationIndex); 448 | return (it!=boneAnimationInfoMap.end() ? &it->second : NULL); 449 | } 450 | inline BoneAnimationInfo* getBoneAnimationInfo(unsigned animationIndex) { 451 | MapUnsignedBoneAnimationInfo::iterator it = boneAnimationInfoMap.find(animationIndex); 452 | return (it!=boneAnimationInfoMap.end() ? &it->second : NULL); 453 | } 454 | //--------------------------------- 455 | 456 | // WARNING: Here we store POINTERS to other elements of the SAME vector m_bneInfos: 457 | // This mean that the vector must stay the same (no grow, and no deletions of elements at all) all the time 458 | BoneInfo* parentBoneInfo; 459 | vector < BoneInfo* > childBoneInfos; 460 | 461 | Mat4 finalTransformation; 462 | string boneName; 463 | }; 464 | 465 | typedef BoneInfo::BoneAnimationInfo BoneAnimationInfo; 466 | typedef BoneAnimationInfo::Vector3Key Vector3Key; 467 | typedef BoneAnimationInfo::QuaternionKey QuaternionKey; 468 | 469 | //typedef BoneAnimationInfo BoneAnimationInfo; 470 | //typedef BoneInfo BoneInfo; 471 | 472 | // name is both Bone and Node name: 473 | const BoneInfo* getBoneInfoFromName(const string& name) const { 474 | MapStringUnsigned::const_iterator it=m_boneIndexMap.find(name); 475 | if (it!=m_boneIndexMap.end()) return &m_boneInfos[it->second]; 476 | return NULL; 477 | } 478 | const BoneInfo* getBoneInfoFromBoneIndex(unsigned boneIndex) const {return boneIndex < m_boneInfos.size() ? &m_boneInfos[boneIndex] : NULL; } 479 | 480 | protected: 481 | vector< BoneInfo > m_boneInfos; 482 | unsigned numValidBones; // m_boneInfos.size() - numDummyBones; Dummy bones are appended after numValidBones in m_boneInfos. 483 | vector m_rootBoneInfos; 484 | 485 | 486 | MapStringUnsigned m_animationIndexMap; 487 | struct AnimationInfo { 488 | string name; 489 | float duration; 490 | float ticksPerSecond; 491 | float numTicks; 492 | }; 493 | vector< AnimationInfo > m_animationInfos; 494 | 495 | # ifdef LOAD_MESHES_FROM_ASSET_IMPORT_LIBRARY 496 | void fillBoneInfoStructs(const struct aiNode* pNode,const struct aiScene* m_pScene,Mesh::BoneInfo* pParentBone=NULL,const glm::mat4& preTransform=glm::mat4(1),bool preTransformIsPresent=false); 497 | void getNumAiNodesValidBonesAndDummyBones(const struct aiNode* pNode,unsigned& an,const vector< string >& boneNames,unsigned& vb,unsigned& db,const struct aiScene* m_pScene); 498 | # endif //LOAD_MESHES_FROM_ASSET_IMPORT_LIBRARY 499 | 500 | 501 | bool m_playAnimationsAgainWhenOvertime; // false, might be useful in some sort of 'IDE' (but animation that needs 'repeat mode' are handled in a different way) 502 | 503 | unsigned CalcInterpolatedPosition(glm::vec3& Out, float AnimationTime, const BoneAnimationInfo& nasi, unsigned* pAlreadyKnownPositionIndex = NULL); 504 | unsigned CalcInterpolatedRotation(glm::quat& Out, float AnimationTime, const BoneAnimationInfo& nasi, unsigned* pAlreadyKnownRotationIndex = NULL); 505 | unsigned CalcInterpolatedScaling(glm::vec3& Out, float AnimationTime, const BoneAnimationInfo& nasi, unsigned* pAlreadyKnownScalingIndex = NULL); 506 | void ReadBoneHeirarchy(unsigned animationIndex,float AnimationTime, BoneInfo& ni, const glm::mat4& ParentTransform); 507 | void ReadBoneHeirarchyForBindingPose(BoneInfo& ni, const glm::mat4& ParentTransform); 508 | 509 | unsigned CalcInterpolatedPosition(float AnimationTime,float additionalPoseTransitionTime, const BoneAnimationInfo& nasi, MeshInstance::BoneFootprint& bf,unsigned* pAlreadyKnownPositionIndex,float* pAlreadyKnownFactor,float* pFactorOut,int looping,const AnimationInfo& ai); 510 | unsigned CalcInterpolatedRotation(float AnimationTime,float additionalPoseTransitionTime, const BoneAnimationInfo& nasi, MeshInstance::BoneFootprint& bf,unsigned* pAlreadyKnownPositionIndex,float* pAlreadyKnownFactor,float* pFactorOut,int looping,const AnimationInfo& ai); 511 | unsigned CalcInterpolatedScaling(float AnimationTime,float additionalPoseTransitionTime, const BoneAnimationInfo& nasi, MeshInstance::BoneFootprint& bf,unsigned* pAlreadyKnownPositionIndex,float* pAlreadyKnownFactor,float* pFactorOut,int looping,const AnimationInfo& ai); 512 | void ReadBoneHeirarchy(unsigned animationIndex,float AnimationTime,float additionalPoseTransitionTime,const BoneInfo& ni, const glm::mat4& ParentTransform, MeshInstance& mi,int looping,const AnimationInfo& ai); 513 | void ReadBoneHeirarchyForPose(unsigned animationIndex,int rotationKeyFrameNumber,int translationKeyFrameNumber,int scalingKeyFrameNumber,const BoneInfo& bi, const glm::mat4& ParentTransform, MeshInstance& mi); 514 | 515 | static bool AllDescendantsAreDummy(const BoneInfo& bi); 516 | static void PremultiplyBoneDescendants(const BoneInfo& parentBone,const Mat4& T,vector& Transforms,const vector m_boneInfos); 517 | 518 | #ifdef TEST_SOFTWARE_SKINNING 519 | void softwareRender(int meshPartIndex,const MeshInstance& mi) const; 520 | void softwareUpdateVertsAndNorms(MeshInstance& mi,const Vector3 &scaling=Vector3(1,1,1)) const; 521 | #endif //TEST_SOFTWARE_SKINNING 522 | 523 | 524 | friend class MeshInstance; 525 | friend class MeshArmatureSetter; 526 | }; 527 | typedef vector < Mesh::Part > MeshPartVector; 528 | typedef shared_ptr < Mesh > MeshPtr; 529 | 530 | #undef MESH_H_STD_MAP 531 | 532 | #endif //MESH_H__ 533 | -------------------------------------------------------------------------------- /test_skeletal_animation/opengl_includer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __EMSCRIPTEN__ 4 | # undef USE_GLEW 5 | #endif //__EMSCRIPTEN__ 6 | 7 | // These path definitions can be passed to the compiler command-line (so that we don't need to modify code) 8 | #ifndef GLUT_PATH 9 | # define GLUT_PATH "GL/glut.h" // Mandatory 10 | #endif //GLEW_PATH 11 | #ifndef FREEGLUT_EXT_PATH 12 | # define FREEGLUT_EXT_PATH "GL/freeglut_ext.h" // Optional (used only if glut.h comes from the freeglut library) 13 | #endif //GLEW_PATH 14 | #ifndef GLEW_PATH 15 | # define GLEW_PATH "GL/glew.h" // Mandatory for Windows only 16 | #endif //GLEW_PATH 17 | 18 | #ifdef _WIN32 19 | # include "windows.h" 20 | # define USE_GLEW 21 | #endif //_WIN32 22 | 23 | #ifdef USE_GLEW 24 | # include GLEW_PATH 25 | #else //USE_GLEW 26 | # define GL_GLEXT_PROTOTYPES 27 | #endif //USE_GLEW 28 | 29 | #include GLUT_PATH 30 | #ifdef __FREEGLUT_STD_H__ 31 | # ifndef __EMSCRIPTEN__ 32 | # include FREEGLUT_EXT_PATH 33 | # endif //__EMSCRIPTEN__ 34 | #endif //__FREEGLUT_STD_H__ 35 | 36 | 37 | -------------------------------------------------------------------------------- /test_skeletal_animation/shared_ptr.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shared_ptr.hpp 3 | * @brief shared_ptr is a minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr. 4 | * 5 | * Copyright (c) 2013-2014 Sebastien Rombauts (sebastien.rombauts@gmail.com) 6 | * 7 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt 8 | * or copy at http://opensource.org/licenses/MIT) 9 | */ 10 | #pragma once 11 | 12 | #include // NULL 13 | #include // std::swap 14 | 15 | // can be replaced by other error mechanism 16 | #include 17 | #define SHARED_ASSERT(x) assert(x) 18 | 19 | 20 | /** 21 | * @brief implementation of reference counter for the following minimal smart pointer. 22 | * 23 | * shared_ptr_count is a container for the allocated pn reference counter. 24 | */ 25 | class shared_ptr_count 26 | { 27 | public: 28 | shared_ptr_count() : 29 | pn(NULL) 30 | { 31 | } 32 | shared_ptr_count(const shared_ptr_count& count) : 33 | pn(count.pn) 34 | { 35 | } 36 | /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method) 37 | void swap(shared_ptr_count& lhs) throw() // never throws 38 | { 39 | std::swap(pn, lhs.pn); 40 | } 41 | /// @brief getter of the underlying reference counter 42 | long use_count(void) const throw() // never throws 43 | { 44 | long count = 0; 45 | if (NULL != pn) 46 | { 47 | count = *pn; 48 | } 49 | return count; 50 | } 51 | /// @brief acquire/share the ownership of the pointer, initializing the reference counter 52 | template 53 | void acquire(U* p) // may throw std::bad_alloc 54 | { 55 | if (NULL != p) 56 | { 57 | if (NULL == pn) 58 | { 59 | try 60 | { 61 | pn = new long(1); // may throw std::bad_alloc 62 | } 63 | catch (std::bad_alloc&) 64 | { 65 | delete p; 66 | throw; // rethrow the std::bad_alloc 67 | } 68 | } 69 | else 70 | { 71 | ++(*pn); 72 | } 73 | } 74 | } 75 | /// @brief release the ownership of the px pointer, destroying the object when appropriate 76 | template 77 | void release(U* p) throw() // never throws 78 | { 79 | if (NULL != pn) 80 | { 81 | --(*pn); 82 | if (0 == *pn) 83 | { 84 | delete p; 85 | delete pn; 86 | } 87 | pn = NULL; 88 | } 89 | } 90 | 91 | public: 92 | long* pn; //!< Reference counter 93 | }; 94 | 95 | 96 | /** 97 | * @brief minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr. 98 | * 99 | * shared_ptr is a smart pointer retaining ownership of an object through a provided pointer, 100 | * and sharing this ownership with a reference counter. 101 | * It destroys the object when the last shared pointer pointing to it is destroyed or reset. 102 | */ 103 | template 104 | class shared_ptr 105 | { 106 | public: 107 | /// The type of the managed object, aliased as member type 108 | typedef T element_type; 109 | 110 | /// @brief Default constructor 111 | shared_ptr(void) throw() : // never throws 112 | px(NULL), 113 | pn() 114 | { 115 | } 116 | /// @brief Constructor with the provided pointer to manage 117 | explicit shared_ptr(T* p) : // may throw std::bad_alloc 118 | //px(p), would be unsafe as acquire() may throw, which would call release() in destructor 119 | pn() 120 | { 121 | acquire(p); // may throw std::bad_alloc 122 | } 123 | /// @brief Constructor to share ownership. Warning : to be used for pointer_cast only ! (does not manage two separate and pointers) 124 | template 125 | shared_ptr(const shared_ptr& ptr, T* p) : 126 | //px(p), would be unsafe as acquire() may throw, which would call release() in destructor 127 | pn(ptr.pn) 128 | { 129 | acquire(p); // may throw std::bad_alloc 130 | } 131 | /// @brief Copy constructor to convert from another pointer type 132 | template 133 | shared_ptr(const shared_ptr& ptr) throw() : // never throws (see comment below) 134 | //px(ptr.px), 135 | pn(ptr.pn) 136 | { 137 | SHARED_ASSERT((NULL == ptr.px) || (0 != ptr.pn.use_count())); // must be coherent : no allocation allowed in this path 138 | acquire(static_cast::element_type*>(ptr.px)); // will never throw std::bad_alloc 139 | } 140 | /// @brief Copy constructor (used by the copy-and-swap idiom) 141 | shared_ptr(const shared_ptr& ptr) throw() : // never throws (see comment below) 142 | //px(ptr.px), 143 | pn(ptr.pn) 144 | { 145 | SHARED_ASSERT((NULL == ptr.px) || (0 != ptr.pn.use_count())); // must be cohérent : no allocation allowed in this path 146 | acquire(ptr.px); // will never throw std::bad_alloc 147 | } 148 | /// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method) 149 | shared_ptr& operator=(shared_ptr ptr) throw() // never throws 150 | { 151 | swap(ptr); 152 | return *this; 153 | } 154 | /// @brief the destructor releases its ownership 155 | inline ~shared_ptr(void) throw() // never throws 156 | { 157 | release(); 158 | } 159 | /// @brief this reset releases its ownership 160 | inline void reset(void) throw() // never throws 161 | { 162 | release(); 163 | } 164 | /// @brief this reset release its ownership and re-acquire another one 165 | void reset(T* p) // may throw std::bad_alloc 166 | { 167 | SHARED_ASSERT((NULL == p) || (px != p)); // auto-reset not allowed 168 | release(); 169 | acquire(p); // may throw std::bad_alloc 170 | } 171 | 172 | /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method) 173 | void swap(shared_ptr& lhs) throw() // never throws 174 | { 175 | std::swap(px, lhs.px); 176 | pn.swap(lhs.pn); 177 | } 178 | 179 | // reference counter operations : 180 | inline operator bool() const throw() // never throws 181 | { 182 | return (0 < pn.use_count()); 183 | } 184 | inline bool unique(void) const throw() // never throws 185 | { 186 | return (1 == pn.use_count()); 187 | } 188 | long use_count(void) const throw() // never throws 189 | { 190 | return pn.use_count(); 191 | } 192 | 193 | // underlying pointer operations : 194 | inline T& operator*() const throw() // never throws 195 | { 196 | SHARED_ASSERT(NULL != px); 197 | return *px; 198 | } 199 | inline T* operator->() const throw() // never throws 200 | { 201 | SHARED_ASSERT(NULL != px); 202 | return px; 203 | } 204 | inline T* get(void) const throw() // never throws 205 | { 206 | // no assert, can return NULL 207 | return px; 208 | } 209 | 210 | private: 211 | /// @brief acquire/share the ownership of the px pointer, initializing the reference counter 212 | inline void acquire(T* p) // may throw std::bad_alloc 213 | { 214 | pn.acquire(p); // may throw std::bad_alloc 215 | px = p; // here it is safe to acquire the ownership of the provided raw pointer, where exception cannot be thrown any more 216 | } 217 | 218 | /// @brief release the ownership of the px pointer, destroying the object when appropriate 219 | inline void release(void) throw() // never throws 220 | { 221 | pn.release(px); 222 | px = NULL; 223 | } 224 | 225 | private: 226 | // This allow pointer_cast functions to share the reference counter between different shared_ptr types 227 | template 228 | friend class shared_ptr; 229 | 230 | private: 231 | T* px; //!< Native pointer 232 | shared_ptr_count pn; //!< Reference counter 233 | }; 234 | 235 | 236 | // comparaison operators 237 | template inline bool operator==(const shared_ptr& l, const shared_ptr& r) throw() // never throws 238 | { 239 | return (l.get() == r.get()); 240 | } 241 | template inline bool operator!=(const shared_ptr& l, const shared_ptr& r) throw() // never throws 242 | { 243 | return (l.get() != r.get()); 244 | } 245 | template inline bool operator<=(const shared_ptr& l, const shared_ptr& r) throw() // never throws 246 | { 247 | return (l.get() <= r.get()); 248 | } 249 | template inline bool operator<(const shared_ptr& l, const shared_ptr& r) throw() // never throws 250 | { 251 | return (l.get() < r.get()); 252 | } 253 | template inline bool operator>=(const shared_ptr& l, const shared_ptr& r) throw() // never throws 254 | { 255 | return (l.get() >= r.get()); 256 | } 257 | template inline bool operator>(const shared_ptr& l, const shared_ptr& r) throw() // never throws 258 | { 259 | return (l.get() > r.get()); 260 | } 261 | 262 | 263 | 264 | // static cast of shared_ptr 265 | template 266 | shared_ptr static_pointer_cast(const shared_ptr& ptr) // never throws 267 | { 268 | return shared_ptr(ptr, static_cast::element_type*>(ptr.get())); 269 | } 270 | 271 | // dynamic cast of shared_ptr 272 | template 273 | shared_ptr dynamic_pointer_cast(const shared_ptr& ptr) // never throws 274 | { 275 | T* p = dynamic_cast::element_type*>(ptr.get()); 276 | if (NULL != p) 277 | { 278 | return shared_ptr(ptr, p); 279 | } 280 | else 281 | { 282 | return shared_ptr(); 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /tests/test.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flix01/fbtBlend-Header-Only/b91852a270ed6a93040199fe1c00b88d7b239919/tests/test.blend -------------------------------------------------------------------------------- /tests/testConsole.cpp: -------------------------------------------------------------------------------- 1 | // Linux / MacOS: 2 | // g++ -Os -no-pie testConsole.cpp -I"./" -I"../" -o testConsole -D"FBT_USE_GZ_FILE=1" -lz 3 | // Windows: 4 | // cl ./testConsole.cpp /I"./" /I"../" /D"FBT_USE_GZ_FILE=1" /link /out:testConsole.exe zlib.lib Shell32.lib comdlg32.lib user32.lib kernel32.lib 5 | 6 | // Can be compiler without "FBT_USE_GZ_FILE=1" and -lz (zlib.lib) too, but test.blend must be uncompressed 7 | 8 | // Emscripten: (requires a file named test.blend to be preloaded) 9 | // em++ -O2 -fno-rtti -fno-exceptions -o html/test_console.html testConsole.cpp -I"./" -I"../" --preload-file test.blend -D"FBT_USE_GZ_FILE=1" -s ALLOW_MEMORY_GROWTH=1 -s USE_ZLIB=1 --closure 1 10 | 11 | #define FBTBLEND_IMPLEMENTATION 12 | #include "../fbtBlend.h" 13 | 14 | #include 15 | 16 | enum BlenderObjectType { 17 | BL_OBTYPE_EMPTY = 0, 18 | BL_OBTYPE_MESH = 1, 19 | BL_OBTYPE_CURVE = 2, 20 | BL_OBTYPE_SURF = 3, 21 | BL_OBTYPE_FONT = 4, 22 | BL_OBTYPE_MBALL = 5, 23 | BL_OBTYPE_LAMP = 10, 24 | BL_OBTYPE_CAMERA = 11, 25 | BL_OBTYPE_WAVE = 21, 26 | BL_OBTYPE_LATTICE = 22, 27 | BL_OBTYPE_ARMATURE = 25 28 | }; 29 | 30 | 31 | int main(int argc, const char* argv[]) { 32 | fbtBlend fp; 33 | const char* filePath = argc>1 ? argv[1] : "test.blend"; 34 | if (fp.parse(filePath)!=fbtFile::FS_OK) return 1; 35 | 36 | // Object List (probably the only relevant in most cases) 37 | long cnt=-1; 38 | fbtList& objects = fp.m_object; 39 | if (objects.first) printf("____________\nOBJECT LIST:\n____________\n"); 40 | for (Blender::Object* ob = (Blender::Object*)objects.first; ob; ob = (Blender::Object*)ob->id.next) { 41 | if (!ob) break; 42 | ++cnt; 43 | if (!ob->data || ob->type != (short) BL_OBTYPE_MESH) { 44 | printf("%ld)\tOBJECT: \"%s\"\ttype=%d\n",cnt,ob->id.name,ob->type); 45 | continue; 46 | } 47 | // It's a Mesh 48 | 49 | printf("%ld)\tOBJECT: \"%s\"\n",cnt,ob->id.name); // it's actually objectName 50 | 51 | const Blender::Mesh* me = (const Blender::Mesh*)ob->data; 52 | printf("\tMESH: \"%s\"\n",me->id.name); // it's actually meshName 53 | 54 | // Fill 'mirrorModifier' and 'bArmature' and skip mesh if not good or not skeletal animated 55 | { 56 | const Blender::ModifierData* mdf = (const Blender::ModifierData*) ob->modifiers.first; 57 | while (mdf) { 58 | // mdf->type(1= SubSurf 5=mirror 8=armature) 59 | printf("Object '%s' had modifier: %s (type=%d mode=%d stackindex=%d)\n",ob->id.name,mdf->name,mdf->type,mdf->mode,mdf->stackindex); 60 | if (mdf->error) { 61 | printf("Error: %s\n",mdf->error); 62 | } 63 | else { 64 | if (mdf->type==1) { 65 | // Subsurf modifier: 66 | const Blender::SubsurfModifierData* md = (const Blender::SubsurfModifierData*) mdf; 67 | printf("SubsurfModifier: subdivType:%d levels:%d renderLevels:%d flags:%d use_opensubdiv:%d\n",md->subdivType,md->levels,md->renderLevels,md->flags,md->use_opensubdiv); 68 | } 69 | if (mdf->type==5) { 70 | //Mirror modifier: 71 | const Blender::MirrorModifierData* md = (const Blender::MirrorModifierData*) mdf; 72 | printf("MirrorModifier: axis:%d flag:%d tolerance:%1.4f\n",md->axis,md->flag,md->tolerance); 73 | if (md->mirror_ob) printf("\nMirrorObj: %s\n",md->mirror_ob->id.name); 74 | } 75 | else if (mdf->type==8) { 76 | //Armature Modifier: 77 | const Blender::ArmatureModifierData* md = (const Blender::ArmatureModifierData*) mdf; 78 | 79 | printf("ArmatureModifier: deformflag:%d multi:%d\n",md->deformflag,md->multi); 80 | if (md->object) printf("Armature Object: %s\n",md->object->id.name); 81 | printf("Deform Group Name: %s\n",md->defgrp_name); 82 | 83 | } 84 | //else fprintf(stderr,"Detected unknown modifier: %d for object: %s\n",mdf->type,ob->id.name); 85 | } 86 | mdf = mdf->next; 87 | } 88 | } 89 | //--------------------- 90 | } 91 | 92 | // However we can directly list other structs (most of them are better accessed through the Object List I suppose) 93 | /* From the declaration of struct fbtBlend: 94 | fbtList m_scene; 95 | fbtList m_library; 96 | fbtList m_object; 97 | fbtList m_mesh; 98 | fbtList m_curve; 99 | fbtList m_mball; 100 | fbtList m_mat; 101 | fbtList m_tex; 102 | fbtList m_image; 103 | fbtList m_latt; 104 | fbtList m_lamp; 105 | fbtList m_camera; 106 | fbtList m_ipo; 107 | fbtList m_key; 108 | fbtList m_world; 109 | fbtList m_screen; 110 | fbtList m_script; 111 | fbtList m_vfont; 112 | fbtList m_text; 113 | fbtList m_sound; 114 | fbtList m_group; 115 | fbtList m_armature; 116 | fbtList m_action; 117 | fbtList m_nodetree; 118 | fbtList m_brush; 119 | fbtList m_particle; 120 | fbtList m_wm; 121 | fbtList m_gpencil;*/ 122 | 123 | // As an example: Image List 124 | cnt=-1; 125 | fbtList& images = fp.m_image; 126 | if (images.first) printf("\n___________\nIMAGE LIST:\n___________\n"); 127 | for (Blender::Image* im = (Blender::Image*)images.first; im; im = (Blender::Image*)im->id.next) { 128 | if (!im) break; 129 | ++cnt; 130 | printf("%ld)\tIMAGE: \"%s\"\ttype=%d\tpath=\"%s\"\tpacked:%s\n",cnt,im->id.name,im->type,im->name,im->packedfile && im->packedfile->size>0 ? "true" : "false"); // There's actually a ListBase im->packedfiles too (?) 131 | //if (im->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",im->preview->w[0],im->preview->h[0],im->preview->w[1],im->preview->h[1]); // No idea on what this is... (for sure it's not the image size). 132 | } 133 | 134 | // As an example: Scene List 135 | cnt=-1; 136 | fbtList& scenes = fp.m_scene; 137 | if (scenes.first) printf("\n___________\nSCENE LIST:\n___________\n"); 138 | for (Blender::Scene* sc = (Blender::Scene*)scenes.first; sc; sc = (Blender::Scene*)sc->id.next) { 139 | if (!sc) break; 140 | ++cnt; 141 | printf("%ld)\tSCENE: \"%s\"\n",cnt,sc->id.name); 142 | if (sc->preview) printf("\tPreview Image: Size[0](%d,%d) Size[1](%d,%d)\n",sc->preview->w[0],sc->preview->h[0],sc->preview->w[1],sc->preview->h[1]); 143 | if (sc->world) printf("\tWorld: \"%s\"\n",sc->world->id.name); 144 | if (sc->camera) printf("\tCamera: \"%s\"\n",sc->camera->id.name); 145 | } 146 | 147 | return 0; 148 | } 149 | --------------------------------------------------------------------------------