summaryrefslogtreecommitdiffstats
path: root/3rdparty/lib3ds
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lib3ds')
-rw-r--r--3rdparty/lib3ds/README15
-rw-r--r--3rdparty/lib3ds/atmosphere.c296
-rw-r--r--3rdparty/lib3ds/atmosphere.h100
-rw-r--r--3rdparty/lib3ds/background.c255
-rw-r--r--3rdparty/lib3ds/background.h85
-rw-r--r--3rdparty/lib3ds/camera.c231
-rw-r--r--3rdparty/lib3ds/camera.h61
-rw-r--r--3rdparty/lib3ds/chunk.c320
-rw-r--r--3rdparty/lib3ds/chunk.h290
-rw-r--r--3rdparty/lib3ds/chunktable.h264
-rw-r--r--3rdparty/lib3ds/chunktable.sed62
-rw-r--r--3rdparty/lib3ds/ease.c62
-rw-r--r--3rdparty/lib3ds/ease.h41
-rw-r--r--3rdparty/lib3ds/file.c2029
-rw-r--r--3rdparty/lib3ds/file.h106
-rw-r--r--3rdparty/lib3ds/io.c524
-rw-r--r--3rdparty/lib3ds/io.h82
-rw-r--r--3rdparty/lib3ds/lib3ds.pri44
-rw-r--r--3rdparty/lib3ds/light.c414
-rw-r--r--3rdparty/lib3ds/light.h79
-rw-r--r--3rdparty/lib3ds/material.c1089
-rw-r--r--3rdparty/lib3ds/material.h170
-rw-r--r--3rdparty/lib3ds/matrix.c718
-rw-r--r--3rdparty/lib3ds/matrix.h63
-rw-r--r--3rdparty/lib3ds/mesh.c1056
-rw-r--r--3rdparty/lib3ds/mesh.h157
-rw-r--r--3rdparty/lib3ds/node.c1089
-rw-r--r--3rdparty/lib3ds/node.h188
-rw-r--r--3rdparty/lib3ds/quat.c418
-rw-r--r--3rdparty/lib3ds/quat.h61
-rw-r--r--3rdparty/lib3ds/shadow.c149
-rw-r--r--3rdparty/lib3ds/shadow.h59
-rw-r--r--3rdparty/lib3ds/tcb.c136
-rw-r--r--3rdparty/lib3ds/tcb.h62
-rw-r--r--3rdparty/lib3ds/tracks.c1556
-rw-r--r--3rdparty/lib3ds/tracks.h209
-rw-r--r--3rdparty/lib3ds/types.h159
-rw-r--r--3rdparty/lib3ds/types.txt96
-rw-r--r--3rdparty/lib3ds/vector.c376
-rw-r--r--3rdparty/lib3ds/vector.h58
-rw-r--r--3rdparty/lib3ds/viewport.c413
-rw-r--r--3rdparty/lib3ds/viewport.h137
42 files changed, 13779 insertions, 0 deletions
diff --git a/3rdparty/lib3ds/README b/3rdparty/lib3ds/README
new file mode 100644
index 000000000..71722ce8c
--- /dev/null
+++ b/3rdparty/lib3ds/README
@@ -0,0 +1,15 @@
+
+Lib3ds is a free toolkit for handling the "3DS" format for 3D model files.
+Its main goal is to simplify the creation of 3DS import and export filters.
+
+This project is not related in any form to Autodesk Inc. The library is
+based on unofficial information about the 3DS format found on the web.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+The official Lib3ds Homepage can be found under:
+ http://lib3ds.sourceforge.net
+
diff --git a/3rdparty/lib3ds/atmosphere.c b/3rdparty/lib3ds/atmosphere.c
new file mode 100644
index 000000000..3e51f9d43
--- /dev/null
+++ b/3rdparty/lib3ds/atmosphere.c
@@ -0,0 +1,296 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: atmosphere.c,v 1.12 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/atmosphere.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+
+
+/*!
+ * \defgroup atmosphere Atmosphere Settings
+ */
+
+
+static Lib3dsBool
+fog_read(Lib3dsFog *fog, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_FOG, io)) {
+ return(LIB3DS_FALSE);
+ }
+ fog->near_plane = lib3ds_io_read_float(io);
+ fog->near_density=lib3ds_io_read_float(io);
+ fog->far_plane=lib3ds_io_read_float(io);
+ fog->far_density=lib3ds_io_read_float(io);
+ lib3ds_chunk_read_tell(&c, io);
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_LIN_COLOR_F:
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ fog->col[i]=lib3ds_io_read_float(io);
+ }
+ }
+ break;
+ case LIB3DS_COLOR_F:
+ break;
+ case LIB3DS_FOG_BGND:
+ {
+ fog->fog_background=LIB3DS_TRUE;
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+layer_fog_read(Lib3dsLayerFog *fog, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ Lib3dsBool have_lin=LIB3DS_FALSE;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_LAYER_FOG, io)) {
+ return(LIB3DS_FALSE);
+ }
+ fog->near_y=lib3ds_io_read_float(io);
+ fog->far_y=lib3ds_io_read_float(io);
+ fog->density=lib3ds_io_read_float(io);
+ fog->flags=lib3ds_io_read_dword(io);
+ lib3ds_chunk_read_tell(&c, io);
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_LIN_COLOR_F:
+ lib3ds_io_read_rgb(io, fog->col);
+ have_lin=LIB3DS_TRUE;
+ break;
+ case LIB3DS_COLOR_F:
+ lib3ds_io_read_rgb(io, fog->col);
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+distance_cue_read(Lib3dsDistanceCue *cue, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_DISTANCE_CUE, io)) {
+ return(LIB3DS_FALSE);
+ }
+ cue->near_plane=lib3ds_io_read_float(io);
+ cue->near_dimming=lib3ds_io_read_float(io);
+ cue->far_plane=lib3ds_io_read_float(io);
+ cue->far_dimming=lib3ds_io_read_float(io);
+ lib3ds_chunk_read_tell(&c, io);
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_DCUE_BGND:
+ {
+ cue->cue_background=LIB3DS_TRUE;
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup atmosphere
+ */
+Lib3dsBool
+lib3ds_atmosphere_read(Lib3dsAtmosphere *atmosphere, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ if (!lib3ds_chunk_read(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ switch (c.chunk) {
+ case LIB3DS_FOG:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!fog_read(&atmosphere->fog, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_LAYER_FOG:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!layer_fog_read(&atmosphere->layer_fog, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_DISTANCE_CUE:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!distance_cue_read(&atmosphere->dist_cue, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_USE_FOG:
+ {
+ atmosphere->fog.use=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_USE_LAYER_FOG:
+ {
+ atmosphere->fog.use=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_USE_DISTANCE_CUE:
+ {
+ atmosphere->dist_cue.use=LIB3DS_TRUE;
+ }
+ break;
+ }
+
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup atmosphere
+ */
+Lib3dsBool
+lib3ds_atmosphere_write(Lib3dsAtmosphere *atmosphere, Lib3dsIo *io)
+{
+ if (atmosphere->fog.use) { /*---- LIB3DS_FOG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_FOG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_float(io, atmosphere->fog.near_plane);
+ lib3ds_io_write_float(io, atmosphere->fog.near_density);
+ lib3ds_io_write_float(io, atmosphere->fog.far_plane);
+ lib3ds_io_write_float(io, atmosphere->fog.far_density);
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_COLOR_F;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_rgb(io, atmosphere->fog.col);
+ }
+ if (atmosphere->fog.fog_background) {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_FOG_BGND;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+
+ if (atmosphere->layer_fog.use) { /*---- LIB3DS_LAYER_FOG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_LAYER_FOG;
+ c.size=40;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, atmosphere->layer_fog.near_y);
+ lib3ds_io_write_float(io, atmosphere->layer_fog.far_y);
+ lib3ds_io_write_float(io, atmosphere->layer_fog.near_y);
+ lib3ds_io_write_dword(io, atmosphere->layer_fog.flags);
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_COLOR_F;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_rgb(io, atmosphere->fog.col);
+ }
+ }
+
+ if (atmosphere->dist_cue.use) { /*---- LIB3DS_DISTANCE_CUE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DISTANCE_CUE;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_float(io, atmosphere->dist_cue.near_plane);
+ lib3ds_io_write_float(io, atmosphere->dist_cue.near_dimming);
+ lib3ds_io_write_float(io, atmosphere->dist_cue.far_plane);
+ lib3ds_io_write_float(io, atmosphere->dist_cue.far_dimming);
+ if (atmosphere->dist_cue.cue_background) {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DCUE_BGND;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+
+ if (atmosphere->fog.use) { /*---- LIB3DS_USE_FOG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_USE_FOG;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (atmosphere->layer_fog.use) { /*---- LIB3DS_USE_LAYER_FOG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_USE_LAYER_FOG;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (atmosphere->dist_cue.use) { /*---- LIB3DS_USE_DISTANCE_CUE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_USE_V_GRADIENT;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ return(LIB3DS_TRUE);
+}
+
+
diff --git a/3rdparty/lib3ds/atmosphere.h b/3rdparty/lib3ds/atmosphere.h
new file mode 100644
index 000000000..c261e7e24
--- /dev/null
+++ b/3rdparty/lib3ds/atmosphere.h
@@ -0,0 +1,100 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_ATMOSPHERE_H
+#define INCLUDED_LIB3DS_ATMOSPHERE_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: atmosphere.h,v 1.8 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Fog atmosphere settings
+ * \ingroup atmosphere
+ */
+typedef struct Lib3dsFog {
+ Lib3dsBool use;
+ Lib3dsRgb col;
+ Lib3dsBool fog_background;
+ Lib3dsFloat near_plane;
+ Lib3dsFloat near_density;
+ Lib3dsFloat far_plane;
+ Lib3dsFloat far_density;
+} Lib3dsFog;
+
+/**
+ * Layer fog atmosphere flags
+ * \ingroup atmosphere
+ */
+typedef enum Lib3dsLayerFogFlags {
+ LIB3DS_BOTTOM_FALL_OFF =0x00000001,
+ LIB3DS_TOP_FALL_OFF =0x00000002,
+ LIB3DS_FOG_BACKGROUND =0x00100000
+} Lib3dsLayerFogFlags;
+
+/**
+ * Layer fog atmosphere settings
+ * \ingroup atmosphere
+ */
+typedef struct Lib3dsLayerFog {
+ Lib3dsBool use;
+ Lib3dsDword flags;
+ Lib3dsRgb col;
+ Lib3dsFloat near_y;
+ Lib3dsFloat far_y;
+ Lib3dsFloat density;
+} Lib3dsLayerFog;
+
+/**
+ * Distance cue atmosphere settings
+ * \ingroup atmosphere
+ */
+typedef struct Lib3dsDistanceCue {
+ Lib3dsBool use;
+ Lib3dsBool cue_background;
+ Lib3dsFloat near_plane;
+ Lib3dsFloat near_dimming;
+ Lib3dsFloat far_plane;
+ Lib3dsFloat far_dimming;
+} Lib3dsDistanceCue;
+
+/**
+ * Atmosphere settings
+ * \ingroup atmosphere
+ */
+struct Lib3dsAtmosphere {
+ Lib3dsFog fog;
+ Lib3dsLayerFog layer_fog;
+ Lib3dsDistanceCue dist_cue;
+};
+
+extern LIB3DSAPI Lib3dsBool lib3ds_atmosphere_read(Lib3dsAtmosphere *atmosphere, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_atmosphere_write(Lib3dsAtmosphere *atmosphere, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/3rdparty/lib3ds/background.c b/3rdparty/lib3ds/background.c
new file mode 100644
index 000000000..a72c554df
--- /dev/null
+++ b/3rdparty/lib3ds/background.c
@@ -0,0 +1,255 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: background.c,v 1.12 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/background.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <string.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup background Background Settings
+ */
+
+
+static Lib3dsBool
+solid_bgnd_read(Lib3dsBackground *background, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ Lib3dsBool have_lin=LIB3DS_FALSE;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_SOLID_BGND, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_LIN_COLOR_F:
+ lib3ds_io_read_rgb(io, background->solid.col);
+ have_lin=LIB3DS_TRUE;
+ break;
+ case LIB3DS_COLOR_F:
+ lib3ds_io_read_rgb(io, background->solid.col);
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+v_gradient_read(Lib3dsBackground *background, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ int index[2];
+ Lib3dsRgb col[2][3];
+ int have_lin=0;
+
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_V_GRADIENT, io)) {
+ return(LIB3DS_FALSE);
+ }
+ background->gradient.percent=lib3ds_io_read_float(io);
+ lib3ds_chunk_read_tell(&c, io);
+
+ index[0]=index[1]=0;
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_COLOR_F:
+ lib3ds_io_read_rgb(io, col[0][index[0]]);
+ index[0]++;
+ break;
+ case LIB3DS_LIN_COLOR_F:
+ lib3ds_io_read_rgb(io, col[1][index[1]]);
+ index[1]++;
+ have_lin=1;
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ background->gradient.top[i]=col[have_lin][0][i];
+ background->gradient.middle[i]=col[have_lin][1][i];
+ background->gradient.bottom[i]=col[have_lin][2][i];
+ }
+ }
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup background
+ */
+Lib3dsBool
+lib3ds_background_read(Lib3dsBackground *background, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ if (!lib3ds_chunk_read(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ switch (c.chunk) {
+ case LIB3DS_BIT_MAP:
+ {
+ if (!lib3ds_io_read_string(io, background->bitmap.name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_SOLID_BGND:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!solid_bgnd_read(background, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_V_GRADIENT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!v_gradient_read(background, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_USE_BIT_MAP:
+ {
+ background->bitmap.use=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_USE_SOLID_BGND:
+ {
+ background->solid.use=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_USE_V_GRADIENT:
+ {
+ background->gradient.use=LIB3DS_TRUE;
+ }
+ break;
+ }
+
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+colorf_write(Lib3dsRgba rgb, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_COLOR_F;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_rgb(io, rgb);
+
+ c.chunk=LIB3DS_LIN_COLOR_F;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_rgb(io, rgb);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+colorf_defined(Lib3dsRgba rgb)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ if (fabs(rgb[i])>LIB3DS_EPSILON) {
+ break;
+ }
+ }
+ return(i<3);
+}
+
+
+/*!
+ * \ingroup background
+ */
+Lib3dsBool
+lib3ds_background_write(Lib3dsBackground *background, Lib3dsIo *io)
+{
+ if (strlen(background->bitmap.name)) { /*---- LIB3DS_BIT_MAP ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_BIT_MAP;
+ c.size=6+1+(Lib3dsDword)strlen(background->bitmap.name);
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_string(io, background->bitmap.name);
+ }
+
+ if (colorf_defined(background->solid.col)) { /*---- LIB3DS_SOLID_BGND ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_SOLID_BGND;
+ c.size=42;
+ lib3ds_chunk_write(&c,io);
+ colorf_write(background->solid.col, io);
+ }
+
+ if (colorf_defined(background->gradient.top) ||
+ colorf_defined(background->gradient.middle) ||
+ colorf_defined(background->gradient.bottom)) { /*---- LIB3DS_V_GRADIENT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_V_GRADIENT;
+ c.size=118;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, background->gradient.percent);
+ colorf_write(background->gradient.top,io);
+ colorf_write(background->gradient.middle,io);
+ colorf_write(background->gradient.bottom,io);
+ }
+
+ if (background->bitmap.use) { /*---- LIB3DS_USE_BIT_MAP ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_USE_BIT_MAP;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (background->solid.use) { /*---- LIB3DS_USE_SOLID_BGND ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_USE_SOLID_BGND;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (background->gradient.use) { /*---- LIB3DS_USE_V_GRADIENT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_USE_V_GRADIENT;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ return(LIB3DS_TRUE);
+}
+
diff --git a/3rdparty/lib3ds/background.h b/3rdparty/lib3ds/background.h
new file mode 100644
index 000000000..e1083708a
--- /dev/null
+++ b/3rdparty/lib3ds/background.h
@@ -0,0 +1,85 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_BACKGROUND_H
+#define INCLUDED_LIB3DS_BACKGROUND_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: background.h,v 1.8 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Bitmap background settings
+ * \ingroup background
+ */
+typedef struct Lib3dsBitmap {
+ Lib3dsBool use;
+ char name[64];
+} Lib3dsBitmap;
+
+/**
+ * Solid color background settings
+ * \ingroup background
+ */
+typedef struct Lib3dsSolid {
+ Lib3dsBool use;
+ Lib3dsRgb col;
+} Lib3dsSolid;
+
+/**
+ * Gradient background settings
+ * \ingroup background
+ */
+typedef struct Lib3dsGradient {
+ Lib3dsBool use;
+ Lib3dsFloat percent;
+ Lib3dsRgb top;
+ Lib3dsRgb middle;
+ Lib3dsRgb bottom;
+} Lib3dsGradient;
+
+/**
+ * Background settings
+ * \ingroup background
+ */
+struct Lib3dsBackground {
+ Lib3dsBitmap bitmap;
+ Lib3dsSolid solid;
+ Lib3dsGradient gradient;
+};
+
+extern LIB3DSAPI Lib3dsBool lib3ds_background_read(Lib3dsBackground *background, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_background_write(Lib3dsBackground *background, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
+
+
diff --git a/3rdparty/lib3ds/camera.c b/3rdparty/lib3ds/camera.c
new file mode 100644
index 000000000..7bbea0f78
--- /dev/null
+++ b/3rdparty/lib3ds/camera.c
@@ -0,0 +1,231 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: camera.c,v 1.17 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/camera.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+
+/*!
+ * \defgroup camera Cameras
+ */
+
+
+/*!
+ * Return a new Lib3dsCamera object.
+ *
+ * Object is initialized with the given name and fov=45. All other
+ * values are 0.
+ *
+ * \param name Name of this camera. Must not be NULL. Must be < 64 characters.
+ *
+ * \return Lib3dsCamera object or NULL on failure.
+ *
+ * \ingroup camera
+ */
+Lib3dsCamera*
+lib3ds_camera_new(const char *name)
+{
+ Lib3dsCamera *camera;
+
+ ASSERT(name);
+ ASSERT(strlen(name)<64);
+
+ camera=(Lib3dsCamera*)calloc(sizeof(Lib3dsCamera), 1);
+ if (!camera) {
+ return(0);
+ }
+ strcpy(camera->name, name);
+ camera->fov=45.0f;
+ return(camera);
+}
+
+
+/*!
+ * Free a Lib3dsCamera object and all of its resources.
+ *
+ * \param camera Lib3dsCamera object to be freed.
+ *
+ * \ingroup camera
+ */
+void
+lib3ds_camera_free(Lib3dsCamera *camera)
+{
+ memset(camera, 0, sizeof(Lib3dsCamera));
+ free(camera);
+}
+
+
+/*!
+ * Dump information about a Lib3dsCamera object to stdout.
+ *
+ * \param camera Object to be dumped.
+ *
+ * \see lib3ds_file_dump_cameras
+ *
+ * \ingroup camera
+ */
+void
+lib3ds_camera_dump(Lib3dsCamera *camera)
+{
+ ASSERT(camera);
+ printf(" name: %s\n", camera->name);
+ printf(" position: (%f, %f, %f)\n",
+ camera->position[0], camera->position[1], camera->position[2]);
+ printf(" target (%f, %f, %f)\n",
+ camera->target[0], camera->target[1], camera->target[2]);
+ printf(" roll: %f\n", camera->roll);
+ printf(" fov: %f\n", camera->fov);
+ printf(" see_cone: %s\n", camera->see_cone ? "yes" : "no");
+ printf(" near_range: %f\n", camera->near_range);
+ printf(" far_range: %f\n", camera->far_range);
+ printf("\n");
+}
+
+
+/*!
+ * Read a camera definition from a file.
+ *
+ * This function is called by lib3ds_file_read(), and you probably
+ * don't want to call it directly.
+ *
+ * \param camera A Lib3dsCamera to be filled in.
+ * \param io A Lib3dsIo object previously set up by the caller.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \see lib3ds_file_read
+ *
+ * \ingroup camera
+ */
+Lib3dsBool
+lib3ds_camera_read(Lib3dsCamera *camera, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_N_CAMERA, io)) {
+ return(LIB3DS_FALSE);
+ }
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ camera->position[i]=lib3ds_io_read_float(io);
+ }
+ for (i=0; i<3; ++i) {
+ camera->target[i]=lib3ds_io_read_float(io);
+ }
+ }
+ camera->roll=lib3ds_io_read_float(io);
+ {
+ float s;
+ s=lib3ds_io_read_float(io);
+ if (fabs(s)<LIB3DS_EPSILON) {
+ camera->fov=45.0;
+ }
+ else {
+ camera->fov=2400.0f/s;
+ }
+ }
+ lib3ds_chunk_read_tell(&c, io);
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_CAM_SEE_CONE:
+ {
+ camera->see_cone=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_CAM_RANGES:
+ {
+ camera->near_range=lib3ds_io_read_float(io);
+ camera->far_range=lib3ds_io_read_float(io);
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Write a camera definition to a file.
+ *
+ * This function is called by lib3ds_file_write(), and you probably
+ * don't want to call it directly.
+ *
+ * \param camera A Lib3dsCamera to be written.
+ * \param io A Lib3dsIo object previously set up by the caller.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \see lib3ds_file_write
+ *
+ * \ingroup camera
+ */
+Lib3dsBool
+lib3ds_camera_write(Lib3dsCamera *camera, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_N_CAMERA;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ lib3ds_io_write_vector(io, camera->position);
+ lib3ds_io_write_vector(io, camera->target);
+ lib3ds_io_write_float(io, camera->roll);
+ if (fabs(camera->fov)<LIB3DS_EPSILON) {
+ lib3ds_io_write_float(io, 2400.0f/45.0f);
+ }
+ else {
+ lib3ds_io_write_float(io, 2400.0f/camera->fov);
+ }
+
+ if (camera->see_cone) {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_CAM_SEE_CONE;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_CAM_RANGES;
+ c.size=14;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, camera->near_range);
+ lib3ds_io_write_float(io, camera->far_range);
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
diff --git a/3rdparty/lib3ds/camera.h b/3rdparty/lib3ds/camera.h
new file mode 100644
index 000000000..2d48db801
--- /dev/null
+++ b/3rdparty/lib3ds/camera.h
@@ -0,0 +1,61 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_CAMERA_H
+#define INCLUDED_LIB3DS_CAMERA_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: camera.h,v 1.11 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Camera object
+ * \ingroup camera
+ */
+struct Lib3dsCamera {
+ Lib3dsCamera *next;
+ char name[64];
+ Lib3dsDword object_flags; /*< @see Lib3dsObjectFlags */
+ Lib3dsVector position;
+ Lib3dsVector target;
+ Lib3dsFloat roll;
+ Lib3dsFloat fov;
+ Lib3dsBool see_cone;
+ Lib3dsFloat near_range;
+ Lib3dsFloat far_range;
+};
+
+extern LIB3DSAPI Lib3dsCamera* lib3ds_camera_new(const char *name);
+extern LIB3DSAPI void lib3ds_camera_free(Lib3dsCamera *mesh);
+extern LIB3DSAPI void lib3ds_camera_dump(Lib3dsCamera *camera);
+extern LIB3DSAPI Lib3dsBool lib3ds_camera_read(Lib3dsCamera *camera, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_camera_write(Lib3dsCamera *camera, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/chunk.c b/3rdparty/lib3ds/chunk.c
new file mode 100644
index 000000000..4a3773353
--- /dev/null
+++ b/3rdparty/lib3ds/chunk.c
@@ -0,0 +1,320 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: chunk.c,v 1.18 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <lib3ds/chunktable.h>
+#include <string.h>
+#include <stdarg.h>
+
+
+/*#define LIB3DS_CHUNK_DEBUG*/
+/*#define LIB3DS_CHUNK_WARNING*/
+
+
+/*!
+ * \defgroup chunk Chunk Handling
+ */
+
+
+static Lib3dsBool enable_dump=LIB3DS_FALSE;
+static Lib3dsBool enable_unknown=LIB3DS_FALSE;
+static char lib3ds_chunk_level[128]="";
+
+
+static void
+lib3ds_chunk_debug_enter(Lib3dsChunk *c)
+{
+ LIB3DS_UNUSED(c);
+ strcat(lib3ds_chunk_level, " ");
+}
+
+
+static void
+lib3ds_chunk_debug_leave(Lib3dsChunk *c)
+{
+ LIB3DS_UNUSED(c);
+ lib3ds_chunk_level[strlen(lib3ds_chunk_level)-2]=0;
+}
+
+
+static void
+lib3ds_chunk_debug_dump(Lib3dsChunk *c)
+{
+ if (enable_dump) {
+ printf("%s%s (0x%X) size=%lu\n",
+ lib3ds_chunk_level,
+ lib3ds_chunk_name(c->chunk),
+ c->chunk,
+ (unsigned long)(c->size)
+ );
+ }
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+void
+lib3ds_chunk_enable_dump(Lib3dsBool enable, Lib3dsBool unknown)
+{
+ enable_dump=enable;
+ enable_unknown=unknown;
+}
+
+
+/*!
+ * \ingroup chunk
+ *
+ * Reads a 3d-Studio chunk header from a little endian file stream.
+ *
+ * \param c The chunk to store the data.
+ * \param io The file stream.
+ *
+ * \return True on success, False otherwise.
+ */
+Lib3dsBool
+lib3ds_chunk_read(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ ASSERT(c);
+ ASSERT(io);
+ c->cur=lib3ds_io_tell(io);
+ c->chunk=lib3ds_io_read_word(io);
+ c->size=lib3ds_io_read_dword(io);
+ c->end=c->cur+c->size;
+ c->cur+=6;
+ if (lib3ds_io_error(io) || (c->size<6)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+Lib3dsBool
+lib3ds_chunk_read_start(Lib3dsChunk *c, Lib3dsWord chunk, Lib3dsIo *io)
+{
+ ASSERT(c);
+ ASSERT(io);
+ if (!lib3ds_chunk_read(c, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_debug_enter(c);
+ return((chunk==0) || (c->chunk==chunk));
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+void
+lib3ds_chunk_read_tell(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ c->cur=lib3ds_io_tell(io);
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+Lib3dsWord
+lib3ds_chunk_read_next(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ Lib3dsChunk d;
+
+ if (c->cur>=c->end) {
+ ASSERT(c->cur==c->end);
+ return(0);
+ }
+
+ lib3ds_io_seek(io, (long)c->cur, LIB3DS_SEEK_SET);
+ d.chunk=lib3ds_io_read_word(io);
+ d.size=lib3ds_io_read_dword(io);
+ lib3ds_chunk_debug_dump(&d);
+ c->cur+=d.size;
+ return(d.chunk);
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+void
+lib3ds_chunk_read_reset(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ LIB3DS_UNUSED(c);
+ lib3ds_io_seek(io, -6, LIB3DS_SEEK_CUR);
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+void
+lib3ds_chunk_read_end(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ lib3ds_chunk_debug_leave(c);
+ lib3ds_io_seek(io, c->end, LIB3DS_SEEK_SET);
+}
+
+
+/*!
+ * \ingroup chunk
+ *
+ * Writes a 3d-Studio chunk header into a little endian file stream.
+ *
+ * \param c The chunk to be written.
+ * \param io The file stream.
+ *
+ * \return True on success, False otherwise.
+ */
+Lib3dsBool
+lib3ds_chunk_write(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ ASSERT(c);
+ if (!lib3ds_io_write_word(io, c->chunk)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_io_write_dword(io, c->size)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+Lib3dsBool
+lib3ds_chunk_write_start(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ ASSERT(c);
+ c->size=0;
+ c->cur=lib3ds_io_tell(io);
+ if (!lib3ds_io_write_word(io, c->chunk)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_io_write_dword(io, c->size)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+Lib3dsBool
+lib3ds_chunk_write_end(Lib3dsChunk *c, Lib3dsIo *io)
+{
+ ASSERT(c);
+ c->size=lib3ds_io_tell(io) - c->cur;
+ lib3ds_io_seek(io, c->cur+2, LIB3DS_SEEK_SET);
+ if (!lib3ds_io_write_dword(io, c->size)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+
+ c->cur+=c->size;
+ lib3ds_io_seek(io, c->cur, LIB3DS_SEEK_SET);
+ if (lib3ds_io_error(io)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+* \ingroup chunk
+*/
+Lib3dsBool
+lib3ds_chunk_write_switch(Lib3dsWord chunk, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ c.chunk=chunk;
+ c.size=6;
+ return lib3ds_chunk_write(&c,io);
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+const char*
+lib3ds_chunk_name(Lib3dsWord chunk)
+{
+ Lib3dsChunkTable *p;
+
+ for (p=lib3ds_chunk_table; p->name!=0; ++p) {
+ if (p->chunk==chunk) {
+ return(p->name);
+ }
+ }
+ return("***UNKNOWN***");
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+void
+lib3ds_chunk_unknown(Lib3dsWord chunk)
+{
+ if (enable_unknown) {
+ printf("%s***WARNING*** Unknown Chunk: %s (0x%X)\n",
+ lib3ds_chunk_level,
+ lib3ds_chunk_name(chunk),
+ chunk
+ );
+ }
+}
+
+
+/*!
+ * \ingroup chunk
+ */
+void
+lib3ds_chunk_dump_info(const char *format, ...)
+{
+ if (enable_dump) {
+ char s[1024];
+ va_list marker;
+
+ va_start(marker, format);
+ vsprintf(s, format, marker);
+ va_end(marker);
+
+ printf("%s%s\n", lib3ds_chunk_level, s);
+ }
+}
+
+
+
+
+
+
+
diff --git a/3rdparty/lib3ds/chunk.h b/3rdparty/lib3ds/chunk.h
new file mode 100644
index 000000000..4cbda1b8f
--- /dev/null
+++ b/3rdparty/lib3ds/chunk.h
@@ -0,0 +1,290 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_CHUNK_H
+#define INCLUDED_LIB3DS_CHUNK_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: chunk.h,v 1.16 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum _Lib3dsChunks {
+ LIB3DS_NULL_CHUNK =0x0000,
+ LIB3DS_M3DMAGIC =0x4D4D, /*3DS file*/
+ LIB3DS_SMAGIC =0x2D2D,
+ LIB3DS_LMAGIC =0x2D3D,
+ LIB3DS_MLIBMAGIC =0x3DAA, /*MLI file*/
+ LIB3DS_MATMAGIC =0x3DFF,
+ LIB3DS_CMAGIC =0xC23D, /*PRJ file*/
+ LIB3DS_M3D_VERSION =0x0002,
+ LIB3DS_M3D_KFVERSION =0x0005,
+
+ LIB3DS_COLOR_F =0x0010,
+ LIB3DS_COLOR_24 =0x0011,
+ LIB3DS_LIN_COLOR_24 =0x0012,
+ LIB3DS_LIN_COLOR_F =0x0013,
+ LIB3DS_INT_PERCENTAGE =0x0030,
+ LIB3DS_FLOAT_PERCENTAGE =0x0031,
+
+ LIB3DS_MDATA =0x3D3D,
+ LIB3DS_MESH_VERSION =0x3D3E,
+ LIB3DS_MASTER_SCALE =0x0100,
+ LIB3DS_LO_SHADOW_BIAS =0x1400,
+ LIB3DS_HI_SHADOW_BIAS =0x1410,
+ LIB3DS_SHADOW_MAP_SIZE =0x1420,
+ LIB3DS_SHADOW_SAMPLES =0x1430,
+ LIB3DS_SHADOW_RANGE =0x1440,
+ LIB3DS_SHADOW_FILTER =0x1450,
+ LIB3DS_RAY_BIAS =0x1460,
+ LIB3DS_O_CONSTS =0x1500,
+ LIB3DS_AMBIENT_LIGHT =0x2100,
+ LIB3DS_BIT_MAP =0x1100,
+ LIB3DS_SOLID_BGND =0x1200,
+ LIB3DS_V_GRADIENT =0x1300,
+ LIB3DS_USE_BIT_MAP =0x1101,
+ LIB3DS_USE_SOLID_BGND =0x1201,
+ LIB3DS_USE_V_GRADIENT =0x1301,
+ LIB3DS_FOG =0x2200,
+ LIB3DS_FOG_BGND =0x2210,
+ LIB3DS_LAYER_FOG =0x2302,
+ LIB3DS_DISTANCE_CUE =0x2300,
+ LIB3DS_DCUE_BGND =0x2310,
+ LIB3DS_USE_FOG =0x2201,
+ LIB3DS_USE_LAYER_FOG =0x2303,
+ LIB3DS_USE_DISTANCE_CUE =0x2301,
+
+ LIB3DS_MAT_ENTRY =0xAFFF,
+ LIB3DS_MAT_NAME =0xA000,
+ LIB3DS_MAT_AMBIENT =0xA010,
+ LIB3DS_MAT_DIFFUSE =0xA020,
+ LIB3DS_MAT_SPECULAR =0xA030,
+ LIB3DS_MAT_SHININESS =0xA040,
+ LIB3DS_MAT_SHIN2PCT =0xA041,
+ LIB3DS_MAT_TRANSPARENCY =0xA050,
+ LIB3DS_MAT_XPFALL =0xA052,
+ LIB3DS_MAT_USE_XPFALL =0xA240,
+ LIB3DS_MAT_REFBLUR =0xA053,
+ LIB3DS_MAT_SHADING =0xA100,
+ LIB3DS_MAT_USE_REFBLUR =0xA250,
+ LIB3DS_MAT_SELF_ILLUM =0xA080,
+ LIB3DS_MAT_TWO_SIDE =0xA081,
+ LIB3DS_MAT_DECAL =0xA082,
+ LIB3DS_MAT_ADDITIVE =0xA083,
+ LIB3DS_MAT_SELF_ILPCT =0xA084,
+ LIB3DS_MAT_WIRE =0xA085,
+ LIB3DS_MAT_FACEMAP =0xA088,
+ LIB3DS_MAT_PHONGSOFT =0xA08C,
+ LIB3DS_MAT_WIREABS =0xA08E,
+ LIB3DS_MAT_WIRE_SIZE =0xA087,
+ LIB3DS_MAT_TEXMAP =0xA200,
+ LIB3DS_MAT_SXP_TEXT_DATA =0xA320,
+ LIB3DS_MAT_TEXMASK =0xA33E,
+ LIB3DS_MAT_SXP_TEXTMASK_DATA =0xA32A,
+ LIB3DS_MAT_TEX2MAP =0xA33A,
+ LIB3DS_MAT_SXP_TEXT2_DATA =0xA321,
+ LIB3DS_MAT_TEX2MASK =0xA340,
+ LIB3DS_MAT_SXP_TEXT2MASK_DATA =0xA32C,
+ LIB3DS_MAT_OPACMAP =0xA210,
+ LIB3DS_MAT_SXP_OPAC_DATA =0xA322,
+ LIB3DS_MAT_OPACMASK =0xA342,
+ LIB3DS_MAT_SXP_OPACMASK_DATA =0xA32E,
+ LIB3DS_MAT_BUMPMAP =0xA230,
+ LIB3DS_MAT_SXP_BUMP_DATA =0xA324,
+ LIB3DS_MAT_BUMPMASK =0xA344,
+ LIB3DS_MAT_SXP_BUMPMASK_DATA =0xA330,
+ LIB3DS_MAT_SPECMAP =0xA204,
+ LIB3DS_MAT_SXP_SPEC_DATA =0xA325,
+ LIB3DS_MAT_SPECMASK =0xA348,
+ LIB3DS_MAT_SXP_SPECMASK_DATA =0xA332,
+ LIB3DS_MAT_SHINMAP =0xA33C,
+ LIB3DS_MAT_SXP_SHIN_DATA =0xA326,
+ LIB3DS_MAT_SHINMASK =0xA346,
+ LIB3DS_MAT_SXP_SHINMASK_DATA =0xA334,
+ LIB3DS_MAT_SELFIMAP =0xA33D,
+ LIB3DS_MAT_SXP_SELFI_DATA =0xA328,
+ LIB3DS_MAT_SELFIMASK =0xA34A,
+ LIB3DS_MAT_SXP_SELFIMASK_DATA =0xA336,
+ LIB3DS_MAT_REFLMAP =0xA220,
+ LIB3DS_MAT_REFLMASK =0xA34C,
+ LIB3DS_MAT_SXP_REFLMASK_DATA =0xA338,
+ LIB3DS_MAT_ACUBIC =0xA310,
+ LIB3DS_MAT_MAPNAME =0xA300,
+ LIB3DS_MAT_MAP_TILING =0xA351,
+ LIB3DS_MAT_MAP_TEXBLUR =0xA353,
+ LIB3DS_MAT_MAP_USCALE =0xA354,
+ LIB3DS_MAT_MAP_VSCALE =0xA356,
+ LIB3DS_MAT_MAP_UOFFSET =0xA358,
+ LIB3DS_MAT_MAP_VOFFSET =0xA35A,
+ LIB3DS_MAT_MAP_ANG =0xA35C,
+ LIB3DS_MAT_MAP_COL1 =0xA360,
+ LIB3DS_MAT_MAP_COL2 =0xA362,
+ LIB3DS_MAT_MAP_RCOL =0xA364,
+ LIB3DS_MAT_MAP_GCOL =0xA366,
+ LIB3DS_MAT_MAP_BCOL =0xA368,
+
+ LIB3DS_NAMED_OBJECT =0x4000,
+ LIB3DS_N_DIRECT_LIGHT =0x4600,
+ LIB3DS_DL_OFF =0x4620,
+ LIB3DS_DL_OUTER_RANGE =0x465A,
+ LIB3DS_DL_INNER_RANGE =0x4659,
+ LIB3DS_DL_MULTIPLIER =0x465B,
+ LIB3DS_DL_EXCLUDE =0x4654,
+ LIB3DS_DL_ATTENUATE =0x4625,
+ LIB3DS_DL_SPOTLIGHT =0x4610,
+ LIB3DS_DL_SPOT_ROLL =0x4656,
+ LIB3DS_DL_SHADOWED =0x4630,
+ LIB3DS_DL_LOCAL_SHADOW2 =0x4641,
+ LIB3DS_DL_SEE_CONE =0x4650,
+ LIB3DS_DL_SPOT_RECTANGULAR =0x4651,
+ LIB3DS_DL_SPOT_ASPECT =0x4657,
+ LIB3DS_DL_SPOT_PROJECTOR =0x4653,
+ LIB3DS_DL_SPOT_OVERSHOOT =0x4652,
+ LIB3DS_DL_RAY_BIAS =0x4658,
+ LIB3DS_DL_RAYSHAD =0x4627,
+ LIB3DS_N_CAMERA =0x4700,
+ LIB3DS_CAM_SEE_CONE =0x4710,
+ LIB3DS_CAM_RANGES =0x4720,
+ LIB3DS_OBJ_HIDDEN =0x4010,
+ LIB3DS_OBJ_VIS_LOFTER =0x4011,
+ LIB3DS_OBJ_DOESNT_CAST =0x4012,
+ LIB3DS_OBJ_DONT_RCVSHADOW =0x4017,
+ LIB3DS_OBJ_MATTE =0x4013,
+ LIB3DS_OBJ_FAST =0x4014,
+ LIB3DS_OBJ_PROCEDURAL =0x4015,
+ LIB3DS_OBJ_FROZEN =0x4016,
+ LIB3DS_N_TRI_OBJECT =0x4100,
+ LIB3DS_POINT_ARRAY =0x4110,
+ LIB3DS_POINT_FLAG_ARRAY =0x4111,
+ LIB3DS_FACE_ARRAY =0x4120,
+ LIB3DS_MSH_MAT_GROUP =0x4130,
+ LIB3DS_SMOOTH_GROUP =0x4150,
+ LIB3DS_MSH_BOXMAP =0x4190,
+ LIB3DS_TEX_VERTS =0x4140,
+ LIB3DS_MESH_MATRIX =0x4160,
+ LIB3DS_MESH_COLOR =0x4165,
+ LIB3DS_MESH_TEXTURE_INFO =0x4170,
+
+ LIB3DS_KFDATA =0xB000,
+ LIB3DS_KFHDR =0xB00A,
+ LIB3DS_KFSEG =0xB008,
+ LIB3DS_KFCURTIME =0xB009,
+ LIB3DS_AMBIENT_NODE_TAG =0xB001,
+ LIB3DS_OBJECT_NODE_TAG =0xB002,
+ LIB3DS_CAMERA_NODE_TAG =0xB003,
+ LIB3DS_TARGET_NODE_TAG =0xB004,
+ LIB3DS_LIGHT_NODE_TAG =0xB005,
+ LIB3DS_L_TARGET_NODE_TAG =0xB006,
+ LIB3DS_SPOTLIGHT_NODE_TAG =0xB007,
+ LIB3DS_NODE_ID =0xB030,
+ LIB3DS_NODE_HDR =0xB010,
+ LIB3DS_PIVOT =0xB013,
+ LIB3DS_INSTANCE_NAME =0xB011,
+ LIB3DS_MORPH_SMOOTH =0xB015,
+ LIB3DS_BOUNDBOX =0xB014,
+ LIB3DS_POS_TRACK_TAG =0xB020,
+ LIB3DS_COL_TRACK_TAG =0xB025,
+ LIB3DS_ROT_TRACK_TAG =0xB021,
+ LIB3DS_SCL_TRACK_TAG =0xB022,
+ LIB3DS_MORPH_TRACK_TAG =0xB026,
+ LIB3DS_FOV_TRACK_TAG =0xB023,
+ LIB3DS_ROLL_TRACK_TAG =0xB024,
+ LIB3DS_HOT_TRACK_TAG =0xB027,
+ LIB3DS_FALL_TRACK_TAG =0xB028,
+ LIB3DS_HIDE_TRACK_TAG =0xB029,
+
+ LIB3DS_POLY_2D = 0x5000,
+ LIB3DS_SHAPE_OK = 0x5010,
+ LIB3DS_SHAPE_NOT_OK = 0x5011,
+ LIB3DS_SHAPE_HOOK = 0x5020,
+ LIB3DS_PATH_3D = 0x6000,
+ LIB3DS_PATH_MATRIX = 0x6005,
+ LIB3DS_SHAPE_2D = 0x6010,
+ LIB3DS_M_SCALE = 0x6020,
+ LIB3DS_M_TWIST = 0x6030,
+ LIB3DS_M_TEETER = 0x6040,
+ LIB3DS_M_FIT = 0x6050,
+ LIB3DS_M_BEVEL = 0x6060,
+ LIB3DS_XZ_CURVE = 0x6070,
+ LIB3DS_YZ_CURVE = 0x6080,
+ LIB3DS_INTERPCT = 0x6090,
+ LIB3DS_DEFORM_LIMIT = 0x60A0,
+
+ LIB3DS_USE_CONTOUR = 0x6100,
+ LIB3DS_USE_TWEEN = 0x6110,
+ LIB3DS_USE_SCALE = 0x6120,
+ LIB3DS_USE_TWIST = 0x6130,
+ LIB3DS_USE_TEETER = 0x6140,
+ LIB3DS_USE_FIT = 0x6150,
+ LIB3DS_USE_BEVEL = 0x6160,
+
+ LIB3DS_DEFAULT_VIEW = 0x3000,
+ LIB3DS_VIEW_TOP = 0x3010,
+ LIB3DS_VIEW_BOTTOM = 0x3020,
+ LIB3DS_VIEW_LEFT = 0x3030,
+ LIB3DS_VIEW_RIGHT = 0x3040,
+ LIB3DS_VIEW_FRONT = 0x3050,
+ LIB3DS_VIEW_BACK = 0x3060,
+ LIB3DS_VIEW_USER = 0x3070,
+ LIB3DS_VIEW_CAMERA = 0x3080,
+ LIB3DS_VIEW_WINDOW = 0x3090,
+
+ LIB3DS_VIEWPORT_LAYOUT_OLD = 0x7000,
+ LIB3DS_VIEWPORT_DATA_OLD = 0x7010,
+ LIB3DS_VIEWPORT_LAYOUT = 0x7001,
+ LIB3DS_VIEWPORT_DATA = 0x7011,
+ LIB3DS_VIEWPORT_DATA_3 = 0x7012,
+ LIB3DS_VIEWPORT_SIZE = 0x7020,
+ LIB3DS_NETWORK_VIEW = 0x7030
+} Lib3dsChunks;
+
+typedef struct Lib3dsChunk {
+ Lib3dsWord chunk;
+ Lib3dsDword size;
+ Lib3dsDword end;
+ Lib3dsDword cur;
+} Lib3dsChunk;
+
+extern LIB3DSAPI void lib3ds_chunk_enable_dump(Lib3dsBool enable, Lib3dsBool unknown);
+extern LIB3DSAPI Lib3dsBool lib3ds_chunk_read(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_chunk_read_start(Lib3dsChunk *c, Lib3dsWord chunk, Lib3dsIo *io);
+extern LIB3DSAPI void lib3ds_chunk_read_tell(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsWord lib3ds_chunk_read_next(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI void lib3ds_chunk_read_reset(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI void lib3ds_chunk_read_end(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_chunk_write(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_chunk_write_start(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_chunk_write_end(Lib3dsChunk *c, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_chunk_write_switch(Lib3dsWord chunk, Lib3dsIo *io);
+extern LIB3DSAPI const char* lib3ds_chunk_name(Lib3dsWord chunk);
+extern LIB3DSAPI void lib3ds_chunk_unknown(Lib3dsWord chunk);
+extern LIB3DSAPI void lib3ds_chunk_dump_info(const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/3rdparty/lib3ds/chunktable.h b/3rdparty/lib3ds/chunktable.h
new file mode 100644
index 000000000..2b50c0214
--- /dev/null
+++ b/3rdparty/lib3ds/chunktable.h
@@ -0,0 +1,264 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_CHUNKTABLE_H
+#define INCLUDED_LIB3DS_CHUNKTABLE_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: chunktable.h,v 1.16 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_CHUNK_H
+#include <lib3ds/chunk.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Lib3dsChunkTable {
+ Lib3dsDword chunk;
+ const char* name;
+} Lib3dsChunkTable;
+
+static Lib3dsChunkTable lib3ds_chunk_table[]={
+ {LIB3DS_NULL_CHUNK, "LIB3DS_NULL_CHUNK"},
+ {LIB3DS_M3DMAGIC, "LIB3DS_M3DMAGIC"},
+ {LIB3DS_SMAGIC, "LIB3DS_SMAGIC"},
+ {LIB3DS_LMAGIC, "LIB3DS_LMAGIC"},
+ {LIB3DS_MLIBMAGIC, "LIB3DS_MLIBMAGIC"},
+ {LIB3DS_MATMAGIC, "LIB3DS_MATMAGIC"},
+ {LIB3DS_CMAGIC, "LIB3DS_CMAGIC"},
+ {LIB3DS_M3D_VERSION, "LIB3DS_M3D_VERSION"},
+ {LIB3DS_M3D_KFVERSION, "LIB3DS_M3D_KFVERSION"},
+ {LIB3DS_COLOR_F, "LIB3DS_COLOR_F"},
+ {LIB3DS_COLOR_24, "LIB3DS_COLOR_24"},
+ {LIB3DS_LIN_COLOR_24, "LIB3DS_LIN_COLOR_24"},
+ {LIB3DS_LIN_COLOR_F, "LIB3DS_LIN_COLOR_F"},
+ {LIB3DS_INT_PERCENTAGE, "LIB3DS_INT_PERCENTAGE"},
+ {LIB3DS_FLOAT_PERCENTAGE, "LIB3DS_FLOAT_PERCENTAGE"},
+ {LIB3DS_MDATA, "LIB3DS_MDATA"},
+ {LIB3DS_MESH_VERSION, "LIB3DS_MESH_VERSION"},
+ {LIB3DS_MASTER_SCALE, "LIB3DS_MASTER_SCALE"},
+ {LIB3DS_LO_SHADOW_BIAS, "LIB3DS_LO_SHADOW_BIAS"},
+ {LIB3DS_HI_SHADOW_BIAS, "LIB3DS_HI_SHADOW_BIAS"},
+ {LIB3DS_SHADOW_MAP_SIZE, "LIB3DS_SHADOW_MAP_SIZE"},
+ {LIB3DS_SHADOW_SAMPLES, "LIB3DS_SHADOW_SAMPLES"},
+ {LIB3DS_SHADOW_RANGE, "LIB3DS_SHADOW_RANGE"},
+ {LIB3DS_SHADOW_FILTER, "LIB3DS_SHADOW_FILTER"},
+ {LIB3DS_RAY_BIAS, "LIB3DS_RAY_BIAS"},
+ {LIB3DS_O_CONSTS, "LIB3DS_O_CONSTS"},
+ {LIB3DS_AMBIENT_LIGHT, "LIB3DS_AMBIENT_LIGHT"},
+ {LIB3DS_BIT_MAP, "LIB3DS_BIT_MAP"},
+ {LIB3DS_SOLID_BGND, "LIB3DS_SOLID_BGND"},
+ {LIB3DS_V_GRADIENT, "LIB3DS_V_GRADIENT"},
+ {LIB3DS_USE_BIT_MAP, "LIB3DS_USE_BIT_MAP"},
+ {LIB3DS_USE_SOLID_BGND, "LIB3DS_USE_SOLID_BGND"},
+ {LIB3DS_USE_V_GRADIENT, "LIB3DS_USE_V_GRADIENT"},
+ {LIB3DS_FOG, "LIB3DS_FOG"},
+ {LIB3DS_FOG_BGND, "LIB3DS_FOG_BGND"},
+ {LIB3DS_LAYER_FOG, "LIB3DS_LAYER_FOG"},
+ {LIB3DS_DISTANCE_CUE, "LIB3DS_DISTANCE_CUE"},
+ {LIB3DS_DCUE_BGND, "LIB3DS_DCUE_BGND"},
+ {LIB3DS_USE_FOG, "LIB3DS_USE_FOG"},
+ {LIB3DS_USE_LAYER_FOG, "LIB3DS_USE_LAYER_FOG"},
+ {LIB3DS_USE_DISTANCE_CUE, "LIB3DS_USE_DISTANCE_CUE"},
+ {LIB3DS_MAT_ENTRY, "LIB3DS_MAT_ENTRY"},
+ {LIB3DS_MAT_NAME, "LIB3DS_MAT_NAME"},
+ {LIB3DS_MAT_AMBIENT, "LIB3DS_MAT_AMBIENT"},
+ {LIB3DS_MAT_DIFFUSE, "LIB3DS_MAT_DIFFUSE"},
+ {LIB3DS_MAT_SPECULAR, "LIB3DS_MAT_SPECULAR"},
+ {LIB3DS_MAT_SHININESS, "LIB3DS_MAT_SHININESS"},
+ {LIB3DS_MAT_SHIN2PCT, "LIB3DS_MAT_SHIN2PCT"},
+ {LIB3DS_MAT_TRANSPARENCY, "LIB3DS_MAT_TRANSPARENCY"},
+ {LIB3DS_MAT_XPFALL, "LIB3DS_MAT_XPFALL"},
+ {LIB3DS_MAT_USE_XPFALL, "LIB3DS_MAT_USE_XPFALL"},
+ {LIB3DS_MAT_REFBLUR, "LIB3DS_MAT_REFBLUR"},
+ {LIB3DS_MAT_SHADING, "LIB3DS_MAT_SHADING"},
+ {LIB3DS_MAT_USE_REFBLUR, "LIB3DS_MAT_USE_REFBLUR"},
+ {LIB3DS_MAT_SELF_ILLUM, "LIB3DS_MAT_SELF_ILLUM"},
+ {LIB3DS_MAT_TWO_SIDE, "LIB3DS_MAT_TWO_SIDE"},
+ {LIB3DS_MAT_DECAL, "LIB3DS_MAT_DECAL"},
+ {LIB3DS_MAT_ADDITIVE, "LIB3DS_MAT_ADDITIVE"},
+ {LIB3DS_MAT_SELF_ILPCT, "LIB3DS_MAT_SELF_ILPCT"},
+ {LIB3DS_MAT_WIRE, "LIB3DS_MAT_WIRE"},
+ {LIB3DS_MAT_FACEMAP, "LIB3DS_MAT_FACEMAP"},
+ {LIB3DS_MAT_PHONGSOFT, "LIB3DS_MAT_PHONGSOFT"},
+ {LIB3DS_MAT_WIREABS, "LIB3DS_MAT_WIREABS"},
+ {LIB3DS_MAT_WIRE_SIZE, "LIB3DS_MAT_WIRE_SIZE"},
+ {LIB3DS_MAT_TEXMAP, "LIB3DS_MAT_TEXMAP"},
+ {LIB3DS_MAT_SXP_TEXT_DATA, "LIB3DS_MAT_SXP_TEXT_DATA"},
+ {LIB3DS_MAT_TEXMASK, "LIB3DS_MAT_TEXMASK"},
+ {LIB3DS_MAT_SXP_TEXTMASK_DATA, "LIB3DS_MAT_SXP_TEXTMASK_DATA"},
+ {LIB3DS_MAT_TEX2MAP, "LIB3DS_MAT_TEX2MAP"},
+ {LIB3DS_MAT_SXP_TEXT2_DATA, "LIB3DS_MAT_SXP_TEXT2_DATA"},
+ {LIB3DS_MAT_TEX2MASK, "LIB3DS_MAT_TEX2MASK"},
+ {LIB3DS_MAT_SXP_TEXT2MASK_DATA, "LIB3DS_MAT_SXP_TEXT2MASK_DATA"},
+ {LIB3DS_MAT_OPACMAP, "LIB3DS_MAT_OPACMAP"},
+ {LIB3DS_MAT_SXP_OPAC_DATA, "LIB3DS_MAT_SXP_OPAC_DATA"},
+ {LIB3DS_MAT_OPACMASK, "LIB3DS_MAT_OPACMASK"},
+ {LIB3DS_MAT_SXP_OPACMASK_DATA, "LIB3DS_MAT_SXP_OPACMASK_DATA"},
+ {LIB3DS_MAT_BUMPMAP, "LIB3DS_MAT_BUMPMAP"},
+ {LIB3DS_MAT_SXP_BUMP_DATA, "LIB3DS_MAT_SXP_BUMP_DATA"},
+ {LIB3DS_MAT_BUMPMASK, "LIB3DS_MAT_BUMPMASK"},
+ {LIB3DS_MAT_SXP_BUMPMASK_DATA, "LIB3DS_MAT_SXP_BUMPMASK_DATA"},
+ {LIB3DS_MAT_SPECMAP, "LIB3DS_MAT_SPECMAP"},
+ {LIB3DS_MAT_SXP_SPEC_DATA, "LIB3DS_MAT_SXP_SPEC_DATA"},
+ {LIB3DS_MAT_SPECMASK, "LIB3DS_MAT_SPECMASK"},
+ {LIB3DS_MAT_SXP_SPECMASK_DATA, "LIB3DS_MAT_SXP_SPECMASK_DATA"},
+ {LIB3DS_MAT_SHINMAP, "LIB3DS_MAT_SHINMAP"},
+ {LIB3DS_MAT_SXP_SHIN_DATA, "LIB3DS_MAT_SXP_SHIN_DATA"},
+ {LIB3DS_MAT_SHINMASK, "LIB3DS_MAT_SHINMASK"},
+ {LIB3DS_MAT_SXP_SHINMASK_DATA, "LIB3DS_MAT_SXP_SHINMASK_DATA"},
+ {LIB3DS_MAT_SELFIMAP, "LIB3DS_MAT_SELFIMAP"},
+ {LIB3DS_MAT_SXP_SELFI_DATA, "LIB3DS_MAT_SXP_SELFI_DATA"},
+ {LIB3DS_MAT_SELFIMASK, "LIB3DS_MAT_SELFIMASK"},
+ {LIB3DS_MAT_SXP_SELFIMASK_DATA, "LIB3DS_MAT_SXP_SELFIMASK_DATA"},
+ {LIB3DS_MAT_REFLMAP, "LIB3DS_MAT_REFLMAP"},
+ {LIB3DS_MAT_REFLMASK, "LIB3DS_MAT_REFLMASK"},
+ {LIB3DS_MAT_SXP_REFLMASK_DATA, "LIB3DS_MAT_SXP_REFLMASK_DATA"},
+ {LIB3DS_MAT_ACUBIC, "LIB3DS_MAT_ACUBIC"},
+ {LIB3DS_MAT_MAPNAME, "LIB3DS_MAT_MAPNAME"},
+ {LIB3DS_MAT_MAP_TILING, "LIB3DS_MAT_MAP_TILING"},
+ {LIB3DS_MAT_MAP_TEXBLUR, "LIB3DS_MAT_MAP_TEXBLUR"},
+ {LIB3DS_MAT_MAP_USCALE, "LIB3DS_MAT_MAP_USCALE"},
+ {LIB3DS_MAT_MAP_VSCALE, "LIB3DS_MAT_MAP_VSCALE"},
+ {LIB3DS_MAT_MAP_UOFFSET, "LIB3DS_MAT_MAP_UOFFSET"},
+ {LIB3DS_MAT_MAP_VOFFSET, "LIB3DS_MAT_MAP_VOFFSET"},
+ {LIB3DS_MAT_MAP_ANG, "LIB3DS_MAT_MAP_ANG"},
+ {LIB3DS_MAT_MAP_COL1, "LIB3DS_MAT_MAP_COL1"},
+ {LIB3DS_MAT_MAP_COL2, "LIB3DS_MAT_MAP_COL2"},
+ {LIB3DS_MAT_MAP_RCOL, "LIB3DS_MAT_MAP_RCOL"},
+ {LIB3DS_MAT_MAP_GCOL, "LIB3DS_MAT_MAP_GCOL"},
+ {LIB3DS_MAT_MAP_BCOL, "LIB3DS_MAT_MAP_BCOL"},
+ {LIB3DS_NAMED_OBJECT, "LIB3DS_NAMED_OBJECT"},
+ {LIB3DS_N_DIRECT_LIGHT, "LIB3DS_N_DIRECT_LIGHT"},
+ {LIB3DS_DL_OFF, "LIB3DS_DL_OFF"},
+ {LIB3DS_DL_OUTER_RANGE, "LIB3DS_DL_OUTER_RANGE"},
+ {LIB3DS_DL_INNER_RANGE, "LIB3DS_DL_INNER_RANGE"},
+ {LIB3DS_DL_MULTIPLIER, "LIB3DS_DL_MULTIPLIER"},
+ {LIB3DS_DL_EXCLUDE, "LIB3DS_DL_EXCLUDE"},
+ {LIB3DS_DL_ATTENUATE, "LIB3DS_DL_ATTENUATE"},
+ {LIB3DS_DL_SPOTLIGHT, "LIB3DS_DL_SPOTLIGHT"},
+ {LIB3DS_DL_SPOT_ROLL, "LIB3DS_DL_SPOT_ROLL"},
+ {LIB3DS_DL_SHADOWED, "LIB3DS_DL_SHADOWED"},
+ {LIB3DS_DL_LOCAL_SHADOW2, "LIB3DS_DL_LOCAL_SHADOW2"},
+ {LIB3DS_DL_SEE_CONE, "LIB3DS_DL_SEE_CONE"},
+ {LIB3DS_DL_SPOT_RECTANGULAR, "LIB3DS_DL_SPOT_RECTANGULAR"},
+ {LIB3DS_DL_SPOT_ASPECT, "LIB3DS_DL_SPOT_ASPECT"},
+ {LIB3DS_DL_SPOT_PROJECTOR, "LIB3DS_DL_SPOT_PROJECTOR"},
+ {LIB3DS_DL_SPOT_OVERSHOOT, "LIB3DS_DL_SPOT_OVERSHOOT"},
+ {LIB3DS_DL_RAY_BIAS, "LIB3DS_DL_RAY_BIAS"},
+ {LIB3DS_DL_RAYSHAD, "LIB3DS_DL_RAYSHAD"},
+ {LIB3DS_N_CAMERA, "LIB3DS_N_CAMERA"},
+ {LIB3DS_CAM_SEE_CONE, "LIB3DS_CAM_SEE_CONE"},
+ {LIB3DS_CAM_RANGES, "LIB3DS_CAM_RANGES"},
+ {LIB3DS_OBJ_HIDDEN, "LIB3DS_OBJ_HIDDEN"},
+ {LIB3DS_OBJ_VIS_LOFTER, "LIB3DS_OBJ_VIS_LOFTER"},
+ {LIB3DS_OBJ_DOESNT_CAST, "LIB3DS_OBJ_DOESNT_CAST"},
+ {LIB3DS_OBJ_DONT_RCVSHADOW, "LIB3DS_OBJ_DONT_RCVSHADOW"},
+ {LIB3DS_OBJ_MATTE, "LIB3DS_OBJ_MATTE"},
+ {LIB3DS_OBJ_FAST, "LIB3DS_OBJ_FAST"},
+ {LIB3DS_OBJ_PROCEDURAL, "LIB3DS_OBJ_PROCEDURAL"},
+ {LIB3DS_OBJ_FROZEN, "LIB3DS_OBJ_FROZEN"},
+ {LIB3DS_N_TRI_OBJECT, "LIB3DS_N_TRI_OBJECT"},
+ {LIB3DS_POINT_ARRAY, "LIB3DS_POINT_ARRAY"},
+ {LIB3DS_POINT_FLAG_ARRAY, "LIB3DS_POINT_FLAG_ARRAY"},
+ {LIB3DS_FACE_ARRAY, "LIB3DS_FACE_ARRAY"},
+ {LIB3DS_MSH_MAT_GROUP, "LIB3DS_MSH_MAT_GROUP"},
+ {LIB3DS_SMOOTH_GROUP, "LIB3DS_SMOOTH_GROUP"},
+ {LIB3DS_MSH_BOXMAP, "LIB3DS_MSH_BOXMAP"},
+ {LIB3DS_TEX_VERTS, "LIB3DS_TEX_VERTS"},
+ {LIB3DS_MESH_MATRIX, "LIB3DS_MESH_MATRIX"},
+ {LIB3DS_MESH_COLOR, "LIB3DS_MESH_COLOR"},
+ {LIB3DS_MESH_TEXTURE_INFO, "LIB3DS_MESH_TEXTURE_INFO"},
+ {LIB3DS_KFDATA, "LIB3DS_KFDATA"},
+ {LIB3DS_KFHDR, "LIB3DS_KFHDR"},
+ {LIB3DS_KFSEG, "LIB3DS_KFSEG"},
+ {LIB3DS_KFCURTIME, "LIB3DS_KFCURTIME"},
+ {LIB3DS_AMBIENT_NODE_TAG, "LIB3DS_AMBIENT_NODE_TAG"},
+ {LIB3DS_OBJECT_NODE_TAG, "LIB3DS_OBJECT_NODE_TAG"},
+ {LIB3DS_CAMERA_NODE_TAG, "LIB3DS_CAMERA_NODE_TAG"},
+ {LIB3DS_TARGET_NODE_TAG, "LIB3DS_TARGET_NODE_TAG"},
+ {LIB3DS_LIGHT_NODE_TAG, "LIB3DS_LIGHT_NODE_TAG"},
+ {LIB3DS_L_TARGET_NODE_TAG, "LIB3DS_L_TARGET_NODE_TAG"},
+ {LIB3DS_SPOTLIGHT_NODE_TAG, "LIB3DS_SPOTLIGHT_NODE_TAG"},
+ {LIB3DS_NODE_ID, "LIB3DS_NODE_ID"},
+ {LIB3DS_NODE_HDR, "LIB3DS_NODE_HDR"},
+ {LIB3DS_PIVOT, "LIB3DS_PIVOT"},
+ {LIB3DS_INSTANCE_NAME, "LIB3DS_INSTANCE_NAME"},
+ {LIB3DS_MORPH_SMOOTH, "LIB3DS_MORPH_SMOOTH"},
+ {LIB3DS_BOUNDBOX, "LIB3DS_BOUNDBOX"},
+ {LIB3DS_POS_TRACK_TAG, "LIB3DS_POS_TRACK_TAG"},
+ {LIB3DS_COL_TRACK_TAG, "LIB3DS_COL_TRACK_TAG"},
+ {LIB3DS_ROT_TRACK_TAG, "LIB3DS_ROT_TRACK_TAG"},
+ {LIB3DS_SCL_TRACK_TAG, "LIB3DS_SCL_TRACK_TAG"},
+ {LIB3DS_MORPH_TRACK_TAG, "LIB3DS_MORPH_TRACK_TAG"},
+ {LIB3DS_FOV_TRACK_TAG, "LIB3DS_FOV_TRACK_TAG"},
+ {LIB3DS_ROLL_TRACK_TAG, "LIB3DS_ROLL_TRACK_TAG"},
+ {LIB3DS_HOT_TRACK_TAG, "LIB3DS_HOT_TRACK_TAG"},
+ {LIB3DS_FALL_TRACK_TAG, "LIB3DS_FALL_TRACK_TAG"},
+ {LIB3DS_HIDE_TRACK_TAG, "LIB3DS_HIDE_TRACK_TAG"},
+ {LIB3DS_POLY_2D, "LIB3DS_POLY_2D"},
+ {LIB3DS_SHAPE_OK, "LIB3DS_SHAPE_OK"},
+ {LIB3DS_SHAPE_NOT_OK, "LIB3DS_SHAPE_NOT_OK"},
+ {LIB3DS_SHAPE_HOOK, "LIB3DS_SHAPE_HOOK"},
+ {LIB3DS_PATH_3D, "LIB3DS_PATH_3D"},
+ {LIB3DS_PATH_MATRIX, "LIB3DS_PATH_MATRIX"},
+ {LIB3DS_SHAPE_2D, "LIB3DS_SHAPE_2D"},
+ {LIB3DS_M_SCALE, "LIB3DS_M_SCALE"},
+ {LIB3DS_M_TWIST, "LIB3DS_M_TWIST"},
+ {LIB3DS_M_TEETER, "LIB3DS_M_TEETER"},
+ {LIB3DS_M_FIT, "LIB3DS_M_FIT"},
+ {LIB3DS_M_BEVEL, "LIB3DS_M_BEVEL"},
+ {LIB3DS_XZ_CURVE, "LIB3DS_XZ_CURVE"},
+ {LIB3DS_YZ_CURVE, "LIB3DS_YZ_CURVE"},
+ {LIB3DS_INTERPCT, "LIB3DS_INTERPCT"},
+ {LIB3DS_DEFORM_LIMIT, "LIB3DS_DEFORM_LIMIT"},
+ {LIB3DS_USE_CONTOUR, "LIB3DS_USE_CONTOUR"},
+ {LIB3DS_USE_TWEEN, "LIB3DS_USE_TWEEN"},
+ {LIB3DS_USE_SCALE, "LIB3DS_USE_SCALE"},
+ {LIB3DS_USE_TWIST, "LIB3DS_USE_TWIST"},
+ {LIB3DS_USE_TEETER, "LIB3DS_USE_TEETER"},
+ {LIB3DS_USE_FIT, "LIB3DS_USE_FIT"},
+ {LIB3DS_USE_BEVEL, "LIB3DS_USE_BEVEL"},
+ {LIB3DS_DEFAULT_VIEW, "LIB3DS_DEFAULT_VIEW"},
+ {LIB3DS_VIEW_TOP, "LIB3DS_VIEW_TOP"},
+ {LIB3DS_VIEW_BOTTOM, "LIB3DS_VIEW_BOTTOM"},
+ {LIB3DS_VIEW_LEFT, "LIB3DS_VIEW_LEFT"},
+ {LIB3DS_VIEW_RIGHT, "LIB3DS_VIEW_RIGHT"},
+ {LIB3DS_VIEW_FRONT, "LIB3DS_VIEW_FRONT"},
+ {LIB3DS_VIEW_BACK, "LIB3DS_VIEW_BACK"},
+ {LIB3DS_VIEW_USER, "LIB3DS_VIEW_USER"},
+ {LIB3DS_VIEW_CAMERA, "LIB3DS_VIEW_CAMERA"},
+ {LIB3DS_VIEW_WINDOW, "LIB3DS_VIEW_WINDOW"},
+ {LIB3DS_VIEWPORT_LAYOUT_OLD, "LIB3DS_VIEWPORT_LAYOUT_OLD"},
+ {LIB3DS_VIEWPORT_DATA_OLD, "LIB3DS_VIEWPORT_DATA_OLD"},
+ {LIB3DS_VIEWPORT_LAYOUT, "LIB3DS_VIEWPORT_LAYOUT"},
+ {LIB3DS_VIEWPORT_DATA, "LIB3DS_VIEWPORT_DATA"},
+ {LIB3DS_VIEWPORT_DATA_3, "LIB3DS_VIEWPORT_DATA_3"},
+ {LIB3DS_VIEWPORT_SIZE, "LIB3DS_VIEWPORT_SIZE"},
+ {LIB3DS_NETWORK_VIEW, "LIB3DS_NETWORK_VIEW"},
+ {0,0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/chunktable.sed b/3rdparty/lib3ds/chunktable.sed
new file mode 100644
index 000000000..11a62fc0d
--- /dev/null
+++ b/3rdparty/lib3ds/chunktable.sed
@@ -0,0 +1,62 @@
+1 {
+ a\
+/* -*- c -*- */\
+#ifndef INCLUDED_LIB3DS_CHUNKTABLE_H\
+#define INCLUDED_LIB3DS_CHUNKTABLE_H\
+/*\
+ * The 3D Studio File Format Library\
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>\
+ * All rights reserved.\
+ *\
+ * This program is free software; you can redistribute it and/or modify it\
+ * under the terms of the GNU Lesser General Public License as published by\
+ * the Free Software Foundation; either version 2.1 of the License, or (at\
+ * your option) any later version.\
+ *\
+ * This program is distributed in the hope that it will be useful, but\
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public\
+ * License for more details.\
+ *\
+ * You should have received a copy of the GNU Lesser General Public License\
+ * along with this program; if not, write to the Free Software Foundation,\
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\
+ *\
+ * $Id: chunktable.sed,v 1.7 2007/06/14 09:59:10 jeh Exp $\
+ */\
+\
+#ifndef INCLUDED_LIB3DS_CHUNK_H\
+#include <lib3ds/chunk.h>\
+#endif\
+\
+#ifdef __cplusplus\
+extern "C" {\
+#endif\
+\
+typedef struct _Lib3dsChunkTable {\
+ Lib3dsDword chunk;\
+ const char* name;\
+} Lib3dsChunkTable;\
+\
+static Lib3dsChunkTable lib3ds_chunk_table[]={
+}
+/^ *LIB3DS_/ {
+ s/ *\([0-9A-Z_]*\).*/ {\1, "\1"},/
+ p
+}
+$ {
+ i\
+ {0,0}\
+};\
+\
+#ifdef __cplusplus\
+};\
+#endif\
+#endif\
+
+}
+d
+
+
+
+
diff --git a/3rdparty/lib3ds/ease.c b/3rdparty/lib3ds/ease.c
new file mode 100644
index 000000000..57b9504c5
--- /dev/null
+++ b/3rdparty/lib3ds/ease.c
@@ -0,0 +1,62 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: ease.c,v 1.6 2007/06/15 09:33:19 jeh Exp $
+ */
+#include <lib3ds/ease.h>
+
+
+/*!
+ * \defgroup ease Ease
+ */
+
+
+/*!
+ * \ingroup ease
+ */
+Lib3dsFloat
+lib3ds_ease(Lib3dsFloat fp, Lib3dsFloat fc, Lib3dsFloat fn,
+ Lib3dsFloat ease_from, Lib3dsFloat ease_to)
+{
+ Lib3dsDouble s,step;
+ Lib3dsDouble tofrom;
+ Lib3dsDouble a;
+
+ s=step=(Lib3dsFloat)(fc-fp)/(fn-fp);
+ tofrom=ease_to+ease_from;
+ if (tofrom!=0.0) {
+ if (tofrom>1.0) {
+ ease_to=(Lib3dsFloat)(ease_to/tofrom);
+ ease_from=(Lib3dsFloat)(ease_from/tofrom);
+ }
+ a=1.0/(2.0-(ease_to+ease_from));
+
+ if (step<ease_from) s=a/ease_from*step*step;
+ else {
+ if ((1.0-ease_to)<=step) {
+ step=1.0-step;
+ s=1.0-a/ease_to*step*step;
+ }
+ else {
+ s=((2.0*step)-ease_from)*a;
+ }
+ }
+ }
+ return((Lib3dsFloat)s);
+}
diff --git a/3rdparty/lib3ds/ease.h b/3rdparty/lib3ds/ease.h
new file mode 100644
index 000000000..456f39141
--- /dev/null
+++ b/3rdparty/lib3ds/ease.h
@@ -0,0 +1,41 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_EASE_H
+#define INCLUDED_LIB3DS_EASE_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: ease.h,v 1.6 2007/06/14 09:59:10 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern LIB3DSAPI Lib3dsFloat lib3ds_ease(Lib3dsFloat fp, Lib3dsFloat fc,
+ Lib3dsFloat fn, Lib3dsFloat ease_from, Lib3dsFloat ease_to);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/file.c b/3rdparty/lib3ds/file.c
new file mode 100644
index 000000000..01fc4bd49
--- /dev/null
+++ b/3rdparty/lib3ds/file.c
@@ -0,0 +1,2029 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: file.c,v 1.34 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/file.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <lib3ds/material.h>
+#include <lib3ds/mesh.h>
+#include <lib3ds/camera.h>
+#include <lib3ds/light.h>
+#include <lib3ds/node.h>
+#include <lib3ds/matrix.h>
+#include <lib3ds/vector.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+
+/*!
+ * \defgroup file Files
+ */
+
+
+static Lib3dsBool
+fileio_error_func(void *self)
+{
+ FILE *f = (FILE*)self;
+ return(ferror(f)!=0);
+}
+
+
+static long
+fileio_seek_func(void *self, long offset, Lib3dsIoSeek origin)
+{
+ FILE *f = (FILE*)self;
+ int o;
+ switch (origin) {
+ case LIB3DS_SEEK_SET:
+ o = SEEK_SET;
+ break;
+ case LIB3DS_SEEK_CUR:
+ o = SEEK_CUR;
+ break;
+ case LIB3DS_SEEK_END:
+ o = SEEK_END;
+ break;
+ default:
+ ASSERT(0);
+ return(0);
+ }
+ return (fseek(f, offset, o));
+}
+
+
+static long
+fileio_tell_func(void *self)
+{
+ FILE *f = (FILE*)self;
+ return(ftell(f));
+}
+
+
+static size_t
+fileio_read_func(void *self, void *buffer, size_t size)
+{
+ FILE *f = (FILE*)self;
+ return(fread(buffer, 1, size, f));
+}
+
+
+static size_t
+fileio_write_func(void *self, const void *buffer, size_t size)
+{
+ FILE *f = (FILE*)self;
+ return(fwrite(buffer, 1, size, f));
+}
+
+
+/*!
+ * Loads a .3DS file from disk into memory.
+ *
+ * \param filename The filename of the .3DS file
+ *
+ * \return A pointer to the Lib3dsFile structure containing the
+ * data of the .3DS file.
+ * If the .3DS file can not be loaded NULL is returned.
+ *
+ * \note To free the returned structure use lib3ds_free.
+ *
+ * \see lib3ds_file_save
+ * \see lib3ds_file_new
+ * \see lib3ds_file_free
+ *
+ * \ingroup file
+ */
+Lib3dsFile*
+lib3ds_file_load(const char *filename)
+{
+ FILE *f;
+ Lib3dsFile *file;
+ Lib3dsIo *io;
+
+ f = fopen(filename, "rb");
+ if (!f) {
+ return(0);
+ }
+ file = lib3ds_file_new();
+ if (!file) {
+ fclose(f);
+ return(0);
+ }
+
+ io = lib3ds_io_new(
+ f,
+ fileio_error_func,
+ fileio_seek_func,
+ fileio_tell_func,
+ fileio_read_func,
+ fileio_write_func
+ );
+ if (!io) {
+ lib3ds_file_free(file);
+ fclose(f);
+ return(0);
+ }
+
+ if (!lib3ds_file_read(file, io)) {
+ free(file);
+ lib3ds_io_free(io);
+ fclose(f);
+ return(0);
+ }
+
+ lib3ds_io_free(io);
+ fclose(f);
+ return(file);
+}
+
+
+/*!
+ * Saves a .3DS file from memory to disk.
+ *
+ * \param file A pointer to a Lib3dsFile structure containing the
+ * the data that should be stored.
+ * \param filename The filename of the .3DS file to store the data in.
+ *
+ * \return TRUE on success, FALSE otherwise.
+ *
+ * \see lib3ds_file_load
+ *
+ * \ingroup file
+ */
+Lib3dsBool
+lib3ds_file_save(Lib3dsFile *file, const char *filename)
+{
+ FILE *f;
+ Lib3dsIo *io;
+ Lib3dsBool result;
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ return(LIB3DS_FALSE);
+ }
+ io = lib3ds_io_new(
+ f,
+ fileio_error_func,
+ fileio_seek_func,
+ fileio_tell_func,
+ fileio_read_func,
+ fileio_write_func
+ );
+ if (!io) {
+ fclose(f);
+ return LIB3DS_FALSE;
+ }
+
+ result = lib3ds_file_write(file, io);
+
+ fclose(f);
+
+ lib3ds_io_free(io);
+ return(result);
+}
+
+
+/*!
+ * Creates and returns a new, empty Lib3dsFile object.
+ *
+ * \return A pointer to the Lib3dsFile structure.
+ * If the structure cannot be allocated, NULL is returned.
+ *
+ * \ingroup file
+ */
+Lib3dsFile*
+lib3ds_file_new()
+{
+ Lib3dsFile *file;
+
+ file=(Lib3dsFile*)calloc(sizeof(Lib3dsFile),1);
+ if (!file) {
+ return(0);
+ }
+ file->mesh_version=3;
+ file->master_scale=1.0f;
+ file->keyf_revision=5;
+ strcpy(file->name, "LIB3DS");
+
+ file->frames=100;
+ file->segment_from=0;
+ file->segment_to=100;
+ file->current_frame=0;
+
+ return(file);
+}
+
+
+/*!
+ * Free a Lib3dsFile object and all of its resources.
+ *
+ * \param file The Lib3dsFile object to be freed.
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_free(Lib3dsFile* file)
+{
+ ASSERT(file);
+ lib3ds_viewport_set_views(&file->viewport,0);
+ lib3ds_viewport_set_views(&file->viewport_keyf,0);
+ {
+ Lib3dsMaterial *p,*q;
+
+ for (p=file->materials; p; p=q) {
+ q=p->next;
+ lib3ds_material_free(p);
+ }
+ file->materials=0;
+ }
+ {
+ Lib3dsCamera *p,*q;
+
+ for (p=file->cameras; p; p=q) {
+ q=p->next;
+ lib3ds_camera_free(p);
+ }
+ file->cameras=0;
+ }
+ {
+ Lib3dsLight *p,*q;
+
+ for (p=file->lights; p; p=q) {
+ q=p->next;
+ lib3ds_light_free(p);
+ }
+ file->lights=0;
+ }
+ {
+ Lib3dsMesh *p,*q;
+
+ for (p=file->meshes; p; p=q) {
+ q=p->next;
+ lib3ds_mesh_free(p);
+ }
+ file->meshes=0;
+ }
+ {
+ Lib3dsNode *p,*q;
+
+ for (p=file->nodes; p; p=q) {
+ q=p->next;
+ lib3ds_node_free(p);
+ }
+ }
+ free(file);
+}
+
+
+/*!
+ * Evaluate all of the nodes in this Lib3dsFile object.
+ *
+ * \param file The Lib3dsFile object to be evaluated.
+ * \param t time value, between 0. and file->frames
+ *
+ * \see lib3ds_node_eval
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_eval(Lib3dsFile *file, Lib3dsFloat t)
+{
+ Lib3dsNode *p;
+
+ for (p=file->nodes; p!=0; p=p->next) {
+ lib3ds_node_eval(p, t);
+ }
+}
+
+
+static Lib3dsBool
+named_object_read(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ char name[64];
+ Lib3dsWord chunk;
+ Lib3dsMesh *mesh = NULL;
+ Lib3dsCamera *camera = NULL;
+ Lib3dsLight *light = NULL;
+ Lib3dsDword object_flags;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_NAMED_OBJECT, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_dump_info(" NAME=%s", name);
+ lib3ds_chunk_read_tell(&c, io);
+
+ object_flags = 0;
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_N_TRI_OBJECT:
+ {
+ mesh=lib3ds_mesh_new(name);
+ if (!mesh) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_mesh_read(mesh, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_mesh(file, mesh);
+ }
+ break;
+
+ case LIB3DS_N_CAMERA:
+ {
+ camera=lib3ds_camera_new(name);
+ if (!camera) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_camera_read(camera, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_camera(file, camera);
+ }
+ break;
+
+ case LIB3DS_N_DIRECT_LIGHT:
+ {
+ light=lib3ds_light_new(name);
+ if (!light) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_light_read(light, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_light(file, light);
+ }
+ break;
+
+ case LIB3DS_OBJ_HIDDEN:
+ object_flags |= LIB3DS_OBJECT_HIDDEN;
+ break;
+
+ case LIB3DS_OBJ_DOESNT_CAST:
+ object_flags |= LIB3DS_OBJECT_DOESNT_CAST;
+ break;
+
+ case LIB3DS_OBJ_VIS_LOFTER:
+ object_flags |= LIB3DS_OBJECT_VIS_LOFTER;
+ break;
+
+ case LIB3DS_OBJ_MATTE:
+ object_flags |= LIB3DS_OBJECT_MATTE;
+ break;
+
+ case LIB3DS_OBJ_DONT_RCVSHADOW:
+ object_flags |= LIB3DS_OBJECT_DONT_RCVSHADOW;
+ break;
+
+ case LIB3DS_OBJ_FAST:
+ object_flags |= LIB3DS_OBJECT_FAST;
+ break;
+
+ case LIB3DS_OBJ_FROZEN:
+ object_flags |= LIB3DS_OBJECT_FROZEN;
+ break;
+
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ if (mesh)
+ mesh->object_flags = object_flags;
+ if (camera)
+ camera->object_flags = object_flags;
+ if (light)
+ light->object_flags = object_flags;
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+ambient_read(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ Lib3dsBool have_lin=LIB3DS_FALSE;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_AMBIENT_LIGHT, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_LIN_COLOR_F:
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ file->ambient[i]=lib3ds_io_read_float(io);
+ }
+ }
+ have_lin=LIB3DS_TRUE;
+ break;
+ case LIB3DS_COLOR_F:
+ {
+ /* gamma corrected color chunk
+ replaced in 3ds R3 by LIN_COLOR_24 */
+ if (!have_lin) {
+ int i;
+ for (i=0; i<3; ++i) {
+ file->ambient[i]=lib3ds_io_read_float(io);
+ }
+ }
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+mdata_read(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_MDATA, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_MESH_VERSION:
+ {
+ file->mesh_version=lib3ds_io_read_intd(io);
+ }
+ break;
+ case LIB3DS_MASTER_SCALE:
+ {
+ file->master_scale=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_SHADOW_MAP_SIZE:
+ case LIB3DS_LO_SHADOW_BIAS:
+ case LIB3DS_HI_SHADOW_BIAS:
+ case LIB3DS_SHADOW_SAMPLES:
+ case LIB3DS_SHADOW_RANGE:
+ case LIB3DS_SHADOW_FILTER:
+ case LIB3DS_RAY_BIAS:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_shadow_read(&file->shadow, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_VIEWPORT_LAYOUT:
+ case LIB3DS_DEFAULT_VIEW:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_viewport_read(&file->viewport, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_O_CONSTS:
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ file->construction_plane[i]=lib3ds_io_read_float(io);
+ }
+ }
+ break;
+ case LIB3DS_AMBIENT_LIGHT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!ambient_read(file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_BIT_MAP:
+ case LIB3DS_SOLID_BGND:
+ case LIB3DS_V_GRADIENT:
+ case LIB3DS_USE_BIT_MAP:
+ case LIB3DS_USE_SOLID_BGND:
+ case LIB3DS_USE_V_GRADIENT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_background_read(&file->background, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_FOG:
+ case LIB3DS_LAYER_FOG:
+ case LIB3DS_DISTANCE_CUE:
+ case LIB3DS_USE_FOG:
+ case LIB3DS_USE_LAYER_FOG:
+ case LIB3DS_USE_DISTANCE_CUE:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_atmosphere_read(&file->atmosphere, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_ENTRY:
+ {
+ Lib3dsMaterial *material;
+
+ material=lib3ds_material_new();
+ if (!material) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_material_read(material, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_material(file, material);
+ }
+ break;
+ case LIB3DS_NAMED_OBJECT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!named_object_read(file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+kfdata_read(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ Lib3dsDword node_number = 0;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_KFDATA, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_KFHDR:
+ {
+ file->keyf_revision=lib3ds_io_read_word(io);
+ if (!lib3ds_io_read_string(io, file->name, 12+1)) {
+ return(LIB3DS_FALSE);
+ }
+ file->frames=lib3ds_io_read_intd(io);
+ }
+ break;
+ case LIB3DS_KFSEG:
+ {
+ file->segment_from=lib3ds_io_read_intd(io);
+ file->segment_to=lib3ds_io_read_intd(io);
+ }
+ break;
+ case LIB3DS_KFCURTIME:
+ {
+ file->current_frame=lib3ds_io_read_intd(io);
+ }
+ break;
+ case LIB3DS_VIEWPORT_LAYOUT:
+ case LIB3DS_DEFAULT_VIEW:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_viewport_read(&file->viewport_keyf, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_AMBIENT_NODE_TAG:
+ {
+ Lib3dsNode *node;
+
+ node=lib3ds_node_new_ambient();
+ if (!node) {
+ return(LIB3DS_FALSE);
+ }
+ node->node_id=node_number++;
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_node_read(node, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_node(file, node);
+ }
+ break;
+ case LIB3DS_OBJECT_NODE_TAG:
+ {
+ Lib3dsNode *node;
+
+ node=lib3ds_node_new_object();
+ if (!node) {
+ return(LIB3DS_FALSE);
+ }
+ node->node_id=node_number++;
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_node_read(node, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_node(file, node);
+ }
+ break;
+ case LIB3DS_CAMERA_NODE_TAG:
+ {
+ Lib3dsNode *node;
+
+ node=lib3ds_node_new_camera();
+ if (!node) {
+ return(LIB3DS_FALSE);
+ }
+ node->node_id=node_number++;
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_node_read(node, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_node(file, node);
+ }
+ break;
+ case LIB3DS_TARGET_NODE_TAG:
+ {
+ Lib3dsNode *node;
+
+ node=lib3ds_node_new_target();
+ if (!node) {
+ return(LIB3DS_FALSE);
+ }
+ node->node_id=node_number++;
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_node_read(node, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_node(file, node);
+ }
+ break;
+ case LIB3DS_LIGHT_NODE_TAG:
+ case LIB3DS_SPOTLIGHT_NODE_TAG:
+ {
+ Lib3dsNode *node;
+
+ node=lib3ds_node_new_light();
+ if (!node) {
+ return(LIB3DS_FALSE);
+ }
+ node->node_id=node_number++;
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_node_read(node, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_node(file, node);
+ }
+ break;
+ case LIB3DS_L_TARGET_NODE_TAG:
+ {
+ Lib3dsNode *node;
+
+ node=lib3ds_node_new_spot();
+ if (!node) {
+ return(LIB3DS_FALSE);
+ }
+ node->node_id=node_number++;
+ lib3ds_chunk_read_reset(&c, io);
+ if (!lib3ds_node_read(node, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_file_insert_node(file, node);
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Read 3ds file data into a Lib3dsFile object.
+ *
+ * \param file The Lib3dsFile object to be filled.
+ * \param io A Lib3dsIo object previously set up by the caller.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \ingroup file
+ */
+Lib3dsBool
+lib3ds_file_read(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, 0, io)) {
+ return(LIB3DS_FALSE);
+ }
+ switch (c.chunk) {
+ case LIB3DS_MDATA:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!mdata_read(file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_M3DMAGIC:
+ case LIB3DS_MLIBMAGIC:
+ case LIB3DS_CMAGIC:
+ {
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_M3D_VERSION:
+ {
+ file->mesh_version=lib3ds_io_read_dword(io);
+ }
+ break;
+ case LIB3DS_MDATA:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!mdata_read(file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_KFDATA:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!kfdata_read(file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(c.chunk);
+ return(LIB3DS_FALSE);
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+colorf_write(Lib3dsRgba rgb, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_COLOR_F;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_rgb(io, rgb);
+
+ c.chunk=LIB3DS_LIN_COLOR_F;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_rgb(io, rgb);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+object_flags_write(Lib3dsDword flags, Lib3dsIo *io)
+{
+ if (flags){
+ if (flags & LIB3DS_OBJECT_HIDDEN) {
+ if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_HIDDEN, io))
+ return LIB3DS_FALSE;
+ }
+ if (flags & LIB3DS_OBJECT_VIS_LOFTER) {
+ if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_VIS_LOFTER, io))
+ return LIB3DS_FALSE;
+ }
+ if (flags & LIB3DS_OBJECT_DOESNT_CAST) {
+ if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_DOESNT_CAST, io))
+ return LIB3DS_FALSE;
+ }
+ if (flags & LIB3DS_OBJECT_MATTE) {
+ if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_MATTE, io))
+ return LIB3DS_FALSE;
+ }
+ if (flags & LIB3DS_OBJECT_DONT_RCVSHADOW) {
+ if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_DOESNT_CAST, io))
+ return LIB3DS_FALSE;
+ }
+ if (flags & LIB3DS_OBJECT_FAST) {
+ if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_FAST, io))
+ return LIB3DS_FALSE;
+ }
+ if (flags & LIB3DS_OBJECT_FROZEN) {
+ if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_FROZEN, io))
+ return LIB3DS_FALSE;
+ }
+ }
+ return LIB3DS_TRUE;
+}
+
+
+static Lib3dsBool
+mdata_write(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_MDATA;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ { /*---- LIB3DS_MESH_VERSION ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MESH_VERSION;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intd(io, file->mesh_version);
+ }
+ { /*---- LIB3DS_MASTER_SCALE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MASTER_SCALE;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, file->master_scale);
+ }
+ { /*---- LIB3DS_O_CONSTS ----*/
+ int i;
+ for (i=0; i<3; ++i) {
+ if (fabs(file->construction_plane[i])>LIB3DS_EPSILON) {
+ break;
+ }
+ }
+ if (i<3) {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_O_CONSTS;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, file->construction_plane);
+ }
+ }
+
+ { /*---- LIB3DS_AMBIENT_LIGHT ----*/
+ int i;
+ for (i=0; i<3; ++i) {
+ if (fabs(file->ambient[i])>LIB3DS_EPSILON) {
+ break;
+ }
+ }
+ if (i<3) {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_AMBIENT_LIGHT;
+ c.size=42;
+ lib3ds_chunk_write(&c,io);
+ colorf_write(file->ambient,io);
+ }
+ }
+ lib3ds_background_write(&file->background, io);
+ lib3ds_atmosphere_write(&file->atmosphere, io);
+ lib3ds_shadow_write(&file->shadow, io);
+ lib3ds_viewport_write(&file->viewport, io);
+ {
+ Lib3dsMaterial *p;
+ for (p=file->materials; p!=0; p=p->next) {
+ if (!lib3ds_material_write(p,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ }
+ {
+ Lib3dsCamera *p;
+ Lib3dsChunk c;
+
+ for (p=file->cameras; p!=0; p=p->next) {
+ c.chunk=LIB3DS_NAMED_OBJECT;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_string(io, p->name);
+ lib3ds_camera_write(p,io);
+ object_flags_write(p->object_flags,io);
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ }
+ {
+ Lib3dsLight *p;
+ Lib3dsChunk c;
+
+ for (p=file->lights; p!=0; p=p->next) {
+ c.chunk=LIB3DS_NAMED_OBJECT;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_string(io,p->name);
+ lib3ds_light_write(p,io);
+ object_flags_write(p->object_flags,io);
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ }
+ {
+ Lib3dsMesh *p;
+ Lib3dsChunk c;
+
+ for (p=file->meshes; p!=0; p=p->next) {
+ c.chunk=LIB3DS_NAMED_OBJECT;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_string(io, p->name);
+ lib3ds_mesh_write(p,io);
+ object_flags_write(p->object_flags,io);
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+
+static Lib3dsBool
+nodes_write(Lib3dsNode *node, Lib3dsFile *file, Lib3dsIo *io)
+{
+ {
+ Lib3dsNode *p;
+ for (p=node->childs; p!=0; p=p->next) {
+ if (!lib3ds_node_write(p, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ nodes_write(p, file, io);
+ }
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+kfdata_write(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ if (!file->nodes) {
+ return(LIB3DS_TRUE);
+ }
+
+ c.chunk=LIB3DS_KFDATA;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ { /*---- LIB3DS_KFHDR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_KFHDR;
+ c.size=6 + 2 + (Lib3dsDword)strlen(file->name)+1 +4;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intw(io, file->keyf_revision);
+ lib3ds_io_write_string(io, file->name);
+ lib3ds_io_write_intd(io, file->frames);
+ }
+ { /*---- LIB3DS_KFSEG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_KFSEG;
+ c.size=14;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intd(io, file->segment_from);
+ lib3ds_io_write_intd(io, file->segment_to);
+ }
+ { /*---- LIB3DS_KFCURTIME ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_KFCURTIME;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intd(io, file->current_frame);
+ }
+ lib3ds_viewport_write(&file->viewport_keyf, io);
+
+ {
+ Lib3dsNode *p;
+ for (p=file->nodes; p!=0; p=p->next) {
+ if (!lib3ds_node_write(p, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!nodes_write(p, file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Write 3ds file data from a Lib3dsFile object to a file.
+ *
+ * \param file The Lib3dsFile object to be written.
+ * \param io A Lib3dsIo object previously set up by the caller.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \ingroup file
+ */
+Lib3dsBool
+lib3ds_file_write(Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_M3DMAGIC;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+
+ { /*---- LIB3DS_M3D_VERSION ----*/
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_M3D_VERSION;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_dword(io, file->mesh_version);
+ }
+
+ if (!mdata_write(file, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!kfdata_write(file, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Insert a new Lib3dsMaterial object into the materials list of
+ * a Lib3dsFile object.
+ *
+ * The new Lib3dsMaterial object is inserted into the materials list
+ * in alphabetic order by name.
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param material The Lib3dsMaterial object to be inserted into file->materials
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_insert_material(Lib3dsFile *file, Lib3dsMaterial *material)
+{
+ Lib3dsMaterial *p,*q;
+
+ ASSERT(file);
+ ASSERT(material);
+ ASSERT(!material->next);
+
+ q=0;
+ for (p=file->materials; p!=0; p=p->next) {
+ if (strcmp(material->name, p->name)<0) {
+ break;
+ }
+ q=p;
+ }
+ if (!q) {
+ material->next=file->materials;
+ file->materials=material;
+ }
+ else {
+ material->next=q->next;
+ q->next=material;
+ }
+}
+
+
+/*!
+ * Remove a Lib3dsMaterial object from the materials list of
+ * a Lib3dsFile object.
+ *
+ * If the Lib3dsMaterial is not found in the materials list, nothing is
+ * done (except that an error log message may be generated.)
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param material The Lib3dsMaterial object to be removed from file->materials
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_remove_material(Lib3dsFile *file, Lib3dsMaterial *material)
+{
+ Lib3dsMaterial *p,*q;
+
+ ASSERT(file);
+ ASSERT(material);
+ ASSERT(file->materials);
+ for (p=0,q=file->materials; q; p=q,q=q->next) {
+ if (q==material) {
+ break;
+ }
+ }
+ if (!q) {
+ ASSERT(LIB3DS_FALSE);
+ return;
+ }
+ if (!p) {
+ file->materials=material->next;
+ }
+ else {
+ p->next=q->next;
+ }
+ material->next=0;
+}
+
+
+/*!
+ * Return a Lib3dsMaterial object by name.
+ *
+ * \param file Lib3dsFile object to be searched.
+ * \param name Name of the Lib3dsMaterial object to be searched for.
+ *
+ * \return A pointer to the named Lib3dsMaterial, or NULL if not found.
+ *
+ * \ingroup file
+ */
+Lib3dsMaterial*
+lib3ds_file_material_by_name(Lib3dsFile *file, const char *name)
+{
+ Lib3dsMaterial *p;
+
+ ASSERT(file);
+ for (p=file->materials; p!=0; p=p->next) {
+ if (strcmp(p->name,name)==0) {
+ return(p);
+ }
+ }
+ return(0);
+}
+
+
+/*!
+ * Dump all Lib3dsMaterial objects found in a Lib3dsFile object.
+ *
+ * \param file Lib3dsFile object to be dumped.
+ *
+ * \see lib3ds_material_dump
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_dump_materials(Lib3dsFile *file)
+{
+ Lib3dsMaterial *p;
+
+ ASSERT(file);
+ for (p=file->materials; p!=0; p=p->next) {
+ lib3ds_material_dump(p);
+ }
+}
+
+
+/*!
+ * Insert a new Lib3dsMesh object into the meshes list of
+ * a Lib3dsFile object.
+ *
+ * The new Lib3dsMesh object is inserted into the meshes list
+ * in alphabetic order by name.
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param mesh The Lib3dsMesh object to be inserted into file->meshes
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_insert_mesh(Lib3dsFile *file, Lib3dsMesh *mesh)
+{
+ Lib3dsMesh *p,*q;
+
+ ASSERT(file);
+ ASSERT(mesh);
+ ASSERT(!mesh->next);
+
+ q=0;
+ for (p=file->meshes; p!=0; p=p->next) {
+ if (strcmp(mesh->name, p->name)<0) {
+ break;
+ }
+ q=p;
+ }
+ if (!q) {
+ mesh->next=file->meshes;
+ file->meshes=mesh;
+ }
+ else {
+ mesh->next=q->next;
+ q->next=mesh;
+ }
+}
+
+
+/*!
+ * Remove a Lib3dsMesh object from the meshes list of
+ * a Lib3dsFile object.
+ *
+ * If the Lib3dsMesh is not found in the meshes list, nothing is done
+ * (except that an error log message may be generated.)
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param mesh The Lib3dsMesh object to be removed from file->meshes
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_remove_mesh(Lib3dsFile *file, Lib3dsMesh *mesh)
+{
+ Lib3dsMesh *p,*q;
+
+ ASSERT(file);
+ ASSERT(mesh);
+ ASSERT(file->meshes);
+ for (p=0,q=file->meshes; q; p=q,q=q->next) {
+ if (q==mesh) {
+ break;
+ }
+ }
+ if (!q) {
+ ASSERT(LIB3DS_FALSE);
+ return;
+ }
+ if (!p) {
+ file->meshes=mesh->next;
+ }
+ else {
+ p->next=q->next;
+ }
+ mesh->next=0;
+}
+
+
+/*!
+ * Return a Lib3dsMesh object from a Lib3dsFile by name.
+ *
+ * \param file Lib3dsFile object to be searched.
+ * \param name Name of the Lib3dsMesh object to be searched for.
+ *
+ * \return A pointer to the named Lib3dsMesh, or NULL if not found.
+ *
+ * \ingroup file
+ */
+Lib3dsMesh*
+lib3ds_file_mesh_by_name(Lib3dsFile *file, const char *name)
+{
+ Lib3dsMesh *p;
+
+ ASSERT(file);
+ for (p=file->meshes; p!=0; p=p->next) {
+ if (strcmp(p->name,name)==0) {
+ return(p);
+ }
+ }
+ return(0);
+}
+
+
+/*!
+ * Dump all Lib3dsMesh objects found in a Lib3dsFile object.
+ *
+ * \param file Lib3dsFile object to be dumped.
+ *
+ * \see lib3ds_mesh_dump
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_dump_meshes(Lib3dsFile *file)
+{
+ Lib3dsMesh *p;
+
+ ASSERT(file);
+ for (p=file->meshes; p!=0; p=p->next) {
+ lib3ds_mesh_dump(p);
+ }
+}
+
+
+static void
+dump_instances(Lib3dsNode *node, const char* parent)
+{
+ Lib3dsNode *p;
+ char name[255];
+
+ ASSERT(node);
+ ASSERT(parent);
+ strcpy(name, parent);
+ strcat(name, ".");
+ strcat(name, node->name);
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ printf(" %s : %s\n", name, node->data.object.instance);
+ }
+ for (p=node->childs; p!=0; p=p->next) {
+ dump_instances(p, parent);
+ }
+}
+
+
+/*!
+ * Dump all Lib3dsNode object names found in a Lib3dsFile object.
+ *
+ * For each node of type OBJECT_NODE, its name and data.object.instance
+ * fields are printed to stdout. Consider using lib3ds_file_dump_nodes()
+ * instead, as that function dumps more information.
+ *
+ * Nodes are dumped recursively.
+ *
+ * \param file Lib3dsFile object to be dumped.
+ *
+ * \see lib3ds_file_dump_nodes
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_dump_instances(Lib3dsFile *file)
+{
+ Lib3dsNode *p;
+
+ ASSERT(file);
+ for (p=file->nodes; p!=0; p=p->next) {
+ dump_instances(p,"");
+ }
+}
+
+
+/*!
+ * Insert a new Lib3dsCamera object into the cameras list of
+ * a Lib3dsFile object.
+ *
+ * The new Lib3dsCamera object is inserted into the cameras list
+ * in alphabetic order by name.
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param camera The Lib3dsCamera object to be inserted into file->cameras
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_insert_camera(Lib3dsFile *file, Lib3dsCamera *camera)
+{
+ Lib3dsCamera *p,*q;
+
+ ASSERT(file);
+ ASSERT(camera);
+ ASSERT(!camera->next);
+
+ q=0;
+ for (p=file->cameras; p!=0; p=p->next) {
+ if (strcmp(camera->name, p->name)<0) {
+ break;
+ }
+ q=p;
+ }
+ if (!q) {
+ camera->next=file->cameras;
+ file->cameras=camera;
+ }
+ else {
+ camera->next=q->next;
+ q->next=camera;
+ }
+}
+
+
+/*!
+ * Remove a Lib3dsCamera object from the cameras list of
+ * a Lib3dsFile object.
+ *
+ * If the Lib3dsCamera is not found in the cameras list, nothing is done
+ * (except that an error log message may be generated.)
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param camera The Lib3dsCamera object to be removed from file->cameras
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_remove_camera(Lib3dsFile *file, Lib3dsCamera *camera)
+{
+ Lib3dsCamera *p,*q;
+
+ ASSERT(file);
+ ASSERT(camera);
+ ASSERT(file->cameras);
+ for (p=0,q=file->cameras; q; p=q,q=q->next) {
+ if (q==camera) {
+ break;
+ }
+ }
+ if (!q) {
+ ASSERT(LIB3DS_FALSE);
+ return;
+ }
+ if (!p) {
+ file->cameras=camera->next;
+ }
+ else {
+ p->next=q->next;
+ }
+ camera->next=0;
+}
+
+
+/*!
+ * Return a Lib3dsCamera object from a Lib3dsFile by name.
+ *
+ * \param file Lib3dsFile object to be searched.
+ * \param name Name of the Lib3dsCamera object to be searched for.
+ *
+ * \return A pointer to the named Lib3dsCamera, or NULL if not found.
+ *
+ * \ingroup file
+ */
+Lib3dsCamera*
+lib3ds_file_camera_by_name(Lib3dsFile *file, const char *name)
+{
+ Lib3dsCamera *p;
+
+ ASSERT(file);
+ for (p=file->cameras; p!=0; p=p->next) {
+ if (strcmp(p->name,name)==0) {
+ return(p);
+ }
+ }
+ return(0);
+}
+
+
+/*!
+ * Dump all Lib3dsCamera objects found in a Lib3dsFile object.
+ *
+ * \param file Lib3dsFile object to be dumped.
+ *
+ * \see lib3ds_camera_dump
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_dump_cameras(Lib3dsFile *file)
+{
+ Lib3dsCamera *p;
+
+ ASSERT(file);
+ for (p=file->cameras; p!=0; p=p->next) {
+ lib3ds_camera_dump(p);
+ }
+}
+
+
+/*!
+ * Insert a new Lib3dsLight object into the lights list of
+ * a Lib3dsFile object.
+ *
+ * The new Lib3dsLight object is inserted into the lights list
+ * in alphabetic order by name.
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param light The Lib3dsLight object to be inserted into file->lights
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_insert_light(Lib3dsFile *file, Lib3dsLight *light)
+{
+ Lib3dsLight *p,*q;
+
+ ASSERT(file);
+ ASSERT(light);
+ ASSERT(!light->next);
+
+ q=0;
+ for (p=file->lights; p!=0; p=p->next) {
+ if (strcmp(light->name, p->name)<0) {
+ break;
+ }
+ q=p;
+ }
+ if (!q) {
+ light->next=file->lights;
+ file->lights=light;
+ }
+ else {
+ light->next=q->next;
+ q->next=light;
+ }
+}
+
+
+/*!
+ * Remove a Lib3dsLight object from the lights list of
+ * a Lib3dsFile object.
+ *
+ * If the Lib3dsLight is not found in the lights list, nothing is done
+ * (except that an error log message may be generated.)
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param light The Lib3dsLight object to be removed from file->lights
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_remove_light(Lib3dsFile *file, Lib3dsLight *light)
+{
+ Lib3dsLight *p,*q;
+
+ ASSERT(file);
+ ASSERT(light);
+ ASSERT(file->lights);
+ for (p=0,q=file->lights; q; p=q,q=q->next) {
+ if (q==light) {
+ break;
+ }
+ }
+ if (!q) {
+ ASSERT(LIB3DS_FALSE);
+ return;
+ }
+ if (!p) {
+ file->lights=light->next;
+ }
+ else {
+ p->next=q->next;
+ }
+ light->next=0;
+}
+
+
+/*!
+ * Return a Lib3dsLight object from a Lib3dsFile by name.
+ *
+ * \param file Lib3dsFile object to be searched.
+ * \param name Name of the Lib3dsLight object to be searched for.
+ *
+ * \return A pointer to the named Lib3dsLight, or NULL if not found.
+ *
+ * \ingroup file
+ */
+Lib3dsLight*
+lib3ds_file_light_by_name(Lib3dsFile *file, const char *name)
+{
+ Lib3dsLight *p;
+
+ ASSERT(file);
+ for (p=file->lights; p!=0; p=p->next) {
+ if (strcmp(p->name,name)==0) {
+ return(p);
+ }
+ }
+ return(0);
+}
+
+
+/*!
+ * Dump all Lib3dsLight objects found in a Lib3dsFile object.
+ *
+ * \param file Lib3dsFile object to be dumped.
+ *
+ * \see lib3ds_light_dump
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_dump_lights(Lib3dsFile *file)
+{
+ Lib3dsLight *p;
+
+ ASSERT(file);
+ for (p=file->lights; p!=0; p=p->next) {
+ lib3ds_light_dump(p);
+ }
+}
+
+
+/*!
+ * Return a node object by name and type.
+ *
+ * This function performs a recursive search for the specified node.
+ * Both name and type must match.
+ *
+ * \param file The Lib3dsFile to be searched.
+ * \param name The target node name.
+ * \param type The target node type
+ *
+ * \return A pointer to the first matching node, or NULL if not found.
+ *
+ * \see lib3ds_node_by_name
+ *
+ * \ingroup file
+ */
+Lib3dsNode*
+lib3ds_file_node_by_name(Lib3dsFile *file, const char* name, Lib3dsNodeTypes type)
+{
+ Lib3dsNode *p,*q;
+
+ ASSERT(file);
+ for (p=file->nodes; p!=0; p=p->next) {
+ if ((p->type==type) && (strcmp(p->name, name)==0)) {
+ return(p);
+ }
+ q=lib3ds_node_by_name(p, name, type);
+ if (q) {
+ return(q);
+ }
+ }
+ return(0);
+}
+
+
+/*!
+ * Return a node object by id.
+ *
+ * This function performs a recursive search for the specified node.
+ *
+ * \param file The Lib3dsFile to be searched.
+ * \param node_id The target node id.
+ *
+ * \return A pointer to the first matching node, or NULL if not found.
+ *
+ * \see lib3ds_node_by_id
+ *
+ * \ingroup file
+ */
+Lib3dsNode*
+lib3ds_file_node_by_id(Lib3dsFile *file, Lib3dsWord node_id)
+{
+ Lib3dsNode *p,*q;
+
+ ASSERT(file);
+ for (p=file->nodes; p!=0; p=p->next) {
+ if (p->node_id==node_id) {
+ return(p);
+ }
+ q=lib3ds_node_by_id(p, node_id);
+ if (q) {
+ return(q);
+ }
+ }
+ return(0);
+}
+
+
+/*!
+ * Insert a new node into a Lib3dsFile object.
+ *
+ * If the node's parent_id structure is not LIB3DS_NO_PARENT and the
+ * specified parent is found inside the Lib3dsFile object, then the
+ * node is inserted as a child of that parent. If the parent_id
+ * structure is LIB3DS_NO_PARENT or the specified parent is not found,
+ * then the node is inserted at the top level.
+ *
+ * Node is inserted in alphabetic order by name.
+ *
+ * Finally, if any other top-level nodes in file specify this node as
+ * their parent, they are relocated as a child of this node.
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param node The node to be inserted into file
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_insert_node(Lib3dsFile *file, Lib3dsNode *node)
+{
+ Lib3dsNode *parent,*p,*n;
+
+ ASSERT(node);
+ ASSERT(!node->next);
+ ASSERT(!node->parent);
+
+ parent=0;
+ if (node->parent_id!=LIB3DS_NO_PARENT) {
+ parent=lib3ds_file_node_by_id(file, node->parent_id);
+ }
+ node->parent=parent;
+
+ if (!parent) {
+ for (p=0,n=file->nodes; n!=0; p=n,n=n->next) {
+ if (strcmp(n->name, node->name)>0) {
+ break;
+ }
+ }
+ if (!p) {
+ node->next=file->nodes;
+ file->nodes=node;
+ }
+ else {
+ node->next=p->next;
+ p->next=node;
+ }
+ }
+ else {
+ for (p=0,n=parent->childs; n!=0; p=n,n=n->next) {
+ if (strcmp(n->name, node->name)>0) {
+ break;
+ }
+ }
+ if (!p) {
+ node->next=parent->childs;
+ parent->childs=node;
+ }
+ else {
+ node->next=p->next;
+ p->next=node;
+ }
+ }
+
+ if (node->node_id!=LIB3DS_NO_PARENT) {
+ for (n=file->nodes; n!=0; n=p) {
+ p=n->next;
+ if (n->parent_id==node->node_id) {
+ lib3ds_file_remove_node(file, n);
+ lib3ds_file_insert_node(file, n);
+ }
+ }
+ }
+}
+
+
+/*!
+ * Remove a node from the a Lib3dsFile object.
+ *
+ * \param file The Lib3dsFile object to be modified.
+ * \param node The Lib3dsNode object to be removed from file
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE if node is not found in file
+ *
+ * \ingroup file
+ */
+Lib3dsBool
+lib3ds_file_remove_node(Lib3dsFile *file, Lib3dsNode *node)
+{
+ Lib3dsNode *p,*n;
+
+ if (node->parent) {
+ for (p=0,n=node->parent->childs; n; p=n,n=n->next) {
+ if (n==node) {
+ break;
+ }
+ }
+ if (!n) {
+ return(LIB3DS_FALSE);
+ }
+
+ if (!p) {
+ node->parent->childs=n->next;
+ }
+ else {
+ p->next=n->next;
+ }
+ }
+ else {
+ for (p=0,n=file->nodes; n; p=n,n=n->next) {
+ if (n==node) {
+ break;
+ }
+ }
+ if (!n) {
+ return(LIB3DS_FALSE);
+ }
+
+ if (!p) {
+ file->nodes=n->next;
+ }
+ else {
+ p->next=n->next;
+ }
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * This function computes the bounding box of meshes, cameras and lights
+ * defined in the 3D editor.
+ *
+ * \param file The Lib3dsFile object to be examined.
+ * \param include_meshes Include meshes in bounding box calculation.
+ * \param include_cameras Include cameras in bounding box calculation.
+ * \param include_lights Include lights in bounding box calculation.
+ * \param bmin Returned minimum x,y,z values.
+ * \param bmax Returned maximum x,y,z values.
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_bounding_box_of_objects(Lib3dsFile *file, Lib3dsBool include_meshes,
+ Lib3dsBool include_cameras, Lib3dsBool include_lights,
+ Lib3dsVector bmin, Lib3dsVector bmax)
+{
+ bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
+ bmax[0] = bmax[1] = bmax[2] = FLT_MIN;
+
+ if (include_meshes) {
+ Lib3dsVector lmin, lmax;
+ Lib3dsMesh *p=file->meshes;
+ while (p) {
+ lib3ds_mesh_bounding_box(p, lmin, lmax);
+ lib3ds_vector_min(bmin, lmin);
+ lib3ds_vector_max(bmax, lmax);
+ p=p->next;
+ }
+ }
+ if (include_cameras) {
+ Lib3dsCamera *p=file->cameras;
+ while (p) {
+ lib3ds_vector_min(bmin, p->position);
+ lib3ds_vector_max(bmax, p->position);
+ lib3ds_vector_min(bmin, p->target);
+ lib3ds_vector_max(bmax, p->target);
+ p=p->next;
+ }
+ }
+ if (include_lights) {
+ Lib3dsLight *p=file->lights;
+ while (p) {
+ lib3ds_vector_min(bmin, p->position);
+ lib3ds_vector_max(bmax, p->position);
+ if (p->spot_light) {
+ lib3ds_vector_min(bmin, p->spot);
+ lib3ds_vector_max(bmax, p->spot);
+ }
+ p=p->next;
+ }
+ }
+}
+
+
+static void
+file_bounding_box_of_nodes_impl(Lib3dsNode *node, Lib3dsFile *file, Lib3dsBool include_meshes,
+ Lib3dsBool include_cameras, Lib3dsBool include_lights,
+ Lib3dsVector bmin, Lib3dsVector bmax)
+{
+ switch (node->type)
+ {
+ case LIB3DS_OBJECT_NODE:
+ if (include_meshes) {
+ Lib3dsMesh *mesh;
+
+ mesh = lib3ds_file_mesh_by_name(file, node->data.object.instance);
+ if (!mesh)
+ mesh = lib3ds_file_mesh_by_name(file, node->name);
+ if (mesh) {
+ Lib3dsMatrix inv_matrix, M;
+ Lib3dsVector v;
+ unsigned i;
+
+ lib3ds_matrix_copy(inv_matrix, mesh->matrix);
+ lib3ds_matrix_inv(inv_matrix);
+ lib3ds_matrix_copy(M, node->matrix);
+ lib3ds_matrix_translate_xyz(M, -node->data.object.pivot[0], -node->data.object.pivot[1], -node->data.object.pivot[2]);
+ lib3ds_matrix_mult(M, inv_matrix);
+
+ for (i=0; i<mesh->points; ++i) {
+ lib3ds_vector_transform(v, M, mesh->pointL[i].pos);
+ lib3ds_vector_min(bmin, v);
+ lib3ds_vector_max(bmax, v);
+ }
+ }
+ }
+ break;
+ /*
+ case LIB3DS_CAMERA_NODE:
+ case LIB3DS_TARGET_NODE:
+ if (include_cameras) {
+ Lib3dsVector z,v;
+ lib3ds_vector_zero(z);
+ lib3ds_vector_transform(v, node->matrix, z);
+ lib3ds_vector_min(bmin, v);
+ lib3ds_vector_max(bmax, v);
+ }
+ break;
+
+ case LIB3DS_LIGHT_NODE:
+ case LIB3DS_SPOT_NODE:
+ if (include_lights) {
+ Lib3dsVector z,v;
+ lib3ds_vector_zero(z);
+ lib3ds_vector_transform(v, node->matrix, z);
+ lib3ds_vector_min(bmin, v);
+ lib3ds_vector_max(bmax, v);
+ }
+ break;
+ */
+ default: break;
+ }
+ {
+ Lib3dsNode *p=node->childs;
+ while (p) {
+ file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax);
+ p=p->next;
+ }
+ }
+}
+
+
+/*!
+ * This function computes the bounding box of mesh, camera and light instances
+ * defined in the Keyframer.
+ *
+ * \param file The Lib3dsFile object to be examined.
+ * \param include_meshes Include meshes in bounding box calculation.
+ * \param include_cameras Include cameras in bounding box calculation.
+ * \param include_lights Include lights in bounding box calculation.
+ * \param bmin Returned minimum x,y,z values.
+ * \param bmax Returned maximum x,y,z values.
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_bounding_box_of_nodes(Lib3dsFile *file, Lib3dsBool include_meshes,
+ Lib3dsBool include_cameras, Lib3dsBool include_lights,
+ Lib3dsVector bmin, Lib3dsVector bmax)
+{
+ Lib3dsNode *p;
+
+ bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
+ bmax[0] = bmax[1] = bmax[2] = FLT_MIN;
+ p=file->nodes;
+ while (p) {
+ file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax);
+ p=p->next;
+ }
+}
+
+
+/*!
+ * Dump all node objects found in a Lib3dsFile object.
+ *
+ * Nodes are dumped recursively.
+ *
+ * \param file Lib3dsFile object to be dumped.
+ *
+ * \see lib3ds_node_dump
+ *
+ * \ingroup file
+ */
+void
+lib3ds_file_dump_nodes(Lib3dsFile *file)
+{
+ Lib3dsNode *p;
+
+ ASSERT(file);
+ for (p=file->nodes; p!=0; p=p->next) {
+ lib3ds_node_dump(p,1);
+ }
+}
+
diff --git a/3rdparty/lib3ds/file.h b/3rdparty/lib3ds/file.h
new file mode 100644
index 000000000..fa8138a1d
--- /dev/null
+++ b/3rdparty/lib3ds/file.h
@@ -0,0 +1,106 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_FILE_H
+#define INCLUDED_LIB3DS_FILE_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: file.h,v 1.24 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_BACKGROUND_H
+#include <lib3ds/background.h>
+#endif
+#ifndef INCLUDED_LIB3DS_ATMOSPHERE_H
+#include <lib3ds/atmosphere.h>
+#endif
+#ifndef INCLUDED_LIB3DS_SHADOW_H
+#include <lib3ds/shadow.h>
+#endif
+#ifndef INCLUDED_LIB3DS_VIEWPORT_H
+#include <lib3ds/viewport.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * 3DS file structure
+ * \ingroup file
+ */
+struct Lib3dsFile {
+ Lib3dsDword mesh_version;
+ Lib3dsWord keyf_revision;
+ char name[12+1];
+ Lib3dsFloat master_scale;
+ Lib3dsVector construction_plane;
+ Lib3dsRgb ambient;
+ Lib3dsShadow shadow;
+ Lib3dsBackground background;
+ Lib3dsAtmosphere atmosphere;
+ Lib3dsViewport viewport;
+ Lib3dsViewport viewport_keyf;
+ Lib3dsIntd frames;
+ Lib3dsIntd segment_from;
+ Lib3dsIntd segment_to;
+ Lib3dsIntd current_frame;
+ Lib3dsMaterial *materials;
+ Lib3dsMesh *meshes;
+ Lib3dsCamera *cameras;
+ Lib3dsLight *lights;
+ Lib3dsNode *nodes;
+};
+
+extern LIB3DSAPI Lib3dsFile* lib3ds_file_load(const char *filename);
+extern LIB3DSAPI Lib3dsBool lib3ds_file_save(Lib3dsFile *file, const char *filename);
+extern LIB3DSAPI Lib3dsFile* lib3ds_file_new();
+extern LIB3DSAPI void lib3ds_file_free(Lib3dsFile *file);
+extern LIB3DSAPI void lib3ds_file_eval(Lib3dsFile *file, Lib3dsFloat t);
+extern LIB3DSAPI Lib3dsBool lib3ds_file_read(Lib3dsFile *file, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_file_write(Lib3dsFile *file, Lib3dsIo *io);
+extern LIB3DSAPI void lib3ds_file_insert_material(Lib3dsFile *file, Lib3dsMaterial *material);
+extern LIB3DSAPI void lib3ds_file_remove_material(Lib3dsFile *file, Lib3dsMaterial *material);
+extern LIB3DSAPI Lib3dsMaterial* lib3ds_file_material_by_name(Lib3dsFile *file, const char *name);
+extern LIB3DSAPI void lib3ds_file_dump_materials(Lib3dsFile *file);
+extern LIB3DSAPI void lib3ds_file_insert_mesh(Lib3dsFile *file, Lib3dsMesh *mesh);
+extern LIB3DSAPI void lib3ds_file_remove_mesh(Lib3dsFile *file, Lib3dsMesh *mesh);
+extern LIB3DSAPI Lib3dsMesh* lib3ds_file_mesh_by_name(Lib3dsFile *file, const char *name);
+extern LIB3DSAPI void lib3ds_file_dump_meshes(Lib3dsFile *file);
+extern LIB3DSAPI void lib3ds_file_dump_instances(Lib3dsFile *file);
+extern LIB3DSAPI void lib3ds_file_insert_camera(Lib3dsFile *file, Lib3dsCamera *camera);
+extern LIB3DSAPI void lib3ds_file_remove_camera(Lib3dsFile *file, Lib3dsCamera *camera);
+extern LIB3DSAPI Lib3dsCamera* lib3ds_file_camera_by_name(Lib3dsFile *file, const char *name);
+extern LIB3DSAPI void lib3ds_file_dump_cameras(Lib3dsFile *file);
+extern LIB3DSAPI void lib3ds_file_insert_light(Lib3dsFile *file, Lib3dsLight *light);
+extern LIB3DSAPI void lib3ds_file_remove_light(Lib3dsFile *file, Lib3dsLight *light);
+extern LIB3DSAPI Lib3dsLight* lib3ds_file_light_by_name(Lib3dsFile *file, const char *name);
+extern LIB3DSAPI void lib3ds_file_dump_lights(Lib3dsFile *file);
+extern LIB3DSAPI Lib3dsNode* lib3ds_file_node_by_name(Lib3dsFile *file, const char* name, Lib3dsNodeTypes type);
+extern LIB3DSAPI Lib3dsNode* lib3ds_file_node_by_id(Lib3dsFile *file, Lib3dsWord node_id);
+extern LIB3DSAPI void lib3ds_file_insert_node(Lib3dsFile *file, Lib3dsNode *node);
+extern LIB3DSAPI Lib3dsBool lib3ds_file_remove_node(Lib3dsFile *file, Lib3dsNode *node);
+extern LIB3DSAPI void lib3ds_file_bounding_box_of_objects(Lib3dsFile *file, Lib3dsBool include_meshes, Lib3dsBool include_cameras, Lib3dsBool include_lights, Lib3dsVector bmin, Lib3dsVector bmax);
+extern LIB3DSAPI void lib3ds_file_bounding_box_of_nodes(Lib3dsFile *file, Lib3dsBool include_meshes, Lib3dsBool include_cameras, Lib3dsBool include_lights, Lib3dsVector bmin, Lib3dsVector bmax);
+extern LIB3DSAPI void lib3ds_file_dump_nodes(Lib3dsFile *file);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/io.c b/3rdparty/lib3ds/io.c
new file mode 100644
index 000000000..508b845bf
--- /dev/null
+++ b/3rdparty/lib3ds/io.c
@@ -0,0 +1,524 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: io.c,v 1.9 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/io.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*!
+ * \defgroup io Binary Input/Ouput Abstraction Layer
+ */
+
+typedef union {
+ Lib3dsDword dword_value;
+ Lib3dsFloat float_value;
+} Lib3dsDwordFloat;
+
+
+struct Lib3dsIo {
+ void *self;
+ Lib3dsIoErrorFunc error_func;
+ Lib3dsIoSeekFunc seek_func;
+ Lib3dsIoTellFunc tell_func;
+ Lib3dsIoReadFunc read_func;
+ Lib3dsIoWriteFunc write_func;
+};
+
+
+Lib3dsIo*
+lib3ds_io_new(void *self, Lib3dsIoErrorFunc error_func, Lib3dsIoSeekFunc seek_func,
+ Lib3dsIoTellFunc tell_func, Lib3dsIoReadFunc read_func, Lib3dsIoWriteFunc write_func)
+{
+ Lib3dsIo *io = calloc(sizeof(Lib3dsIo),1);
+ ASSERT(io);
+ if (!io) {
+ return 0;
+ }
+
+ io->self = self;
+ io->error_func = error_func;
+ io->seek_func = seek_func;
+ io->tell_func = tell_func;
+ io->read_func = read_func;
+ io->write_func = write_func;
+
+ return io;
+}
+
+
+void
+lib3ds_io_free(Lib3dsIo *io)
+{
+ ASSERT(io);
+ if (!io) {
+ return;
+ }
+ free(io);
+}
+
+
+Lib3dsBool
+lib3ds_io_error(Lib3dsIo *io)
+{
+ ASSERT(io);
+ if (!io || !io->error_func) {
+ return 0;
+ }
+ return (*io->error_func)(io->self);
+}
+
+
+long
+lib3ds_io_seek(Lib3dsIo *io, long offset, Lib3dsIoSeek origin)
+{
+ ASSERT(io);
+ if (!io || !io->seek_func) {
+ return 0;
+ }
+ return (*io->seek_func)(io->self, offset, origin);
+}
+
+
+long
+lib3ds_io_tell(Lib3dsIo *io)
+{
+ ASSERT(io);
+ if (!io || !io->tell_func) {
+ return 0;
+ }
+ return (*io->tell_func)(io->self);
+}
+
+
+size_t
+lib3ds_io_read(Lib3dsIo *io, void *buffer, size_t size)
+{
+ ASSERT(io);
+ if (!io || !io->read_func) {
+ return 0;
+ }
+ return (*io->read_func)(io->self, buffer, size);
+}
+
+
+size_t
+lib3ds_io_write(Lib3dsIo *io, const void *buffer, size_t size)
+{
+ ASSERT(io);
+ if (!io || !io->write_func) {
+ return 0;
+ }
+ return (*io->write_func)(io->self, buffer, size);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a byte from a file stream.
+ */
+Lib3dsByte
+lib3ds_io_read_byte(Lib3dsIo *io)
+{
+ Lib3dsByte b;
+
+ ASSERT(io);
+ lib3ds_io_read(io, &b, 1);
+ return(b);
+}
+
+
+/**
+ * Read a word from a file stream in little endian format.
+ */
+Lib3dsWord
+lib3ds_io_read_word(Lib3dsIo *io)
+{
+ Lib3dsByte b[2];
+ Lib3dsWord w;
+
+ ASSERT(io);
+ lib3ds_io_read(io, b, 2);
+ w=((Lib3dsWord)b[1] << 8) |
+ ((Lib3dsWord)b[0]);
+ return(w);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a dword from file a stream in little endian format.
+ */
+Lib3dsDword
+lib3ds_io_read_dword(Lib3dsIo *io)
+{
+ Lib3dsByte b[4];
+ Lib3dsDword d;
+
+ ASSERT(io);
+ lib3ds_io_read(io, b, 4);
+ d=((Lib3dsDword)b[3] << 24) |
+ ((Lib3dsDword)b[2] << 16) |
+ ((Lib3dsDword)b[1] << 8) |
+ ((Lib3dsDword)b[0]);
+ return(d);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a signed byte from a file stream.
+ */
+Lib3dsIntb
+lib3ds_io_read_intb(Lib3dsIo *io)
+{
+ Lib3dsIntb b;
+
+ ASSERT(io);
+ lib3ds_io_read(io, &b, 1);
+ return(b);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a signed word from a file stream in little endian format.
+ */
+Lib3dsIntw
+lib3ds_io_read_intw(Lib3dsIo *io)
+{
+ Lib3dsByte b[2];
+ Lib3dsWord w;
+
+ ASSERT(io);
+ lib3ds_io_read(io, b, 2);
+ w=((Lib3dsWord)b[1] << 8) |
+ ((Lib3dsWord)b[0]);
+ return((Lib3dsIntw)w);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a signed dword a from file stream in little endian format.
+ */
+Lib3dsIntd
+lib3ds_io_read_intd(Lib3dsIo *io)
+{
+ Lib3dsByte b[4];
+ Lib3dsDword d;
+
+ ASSERT(io);
+ lib3ds_io_read(io, b, 4);
+ d=((Lib3dsDword)b[3] << 24) |
+ ((Lib3dsDword)b[2] << 16) |
+ ((Lib3dsDword)b[1] << 8) |
+ ((Lib3dsDword)b[0]);
+ return((Lib3dsIntd)d);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a float from a file stream in little endian format.
+ */
+Lib3dsFloat
+lib3ds_io_read_float(Lib3dsIo *io)
+{
+ Lib3dsByte b[4];
+ Lib3dsDwordFloat d;
+
+ ASSERT(io);
+ lib3ds_io_read(io, b, 4);
+ d.dword_value=((Lib3dsDword)b[3] << 24) |
+ ((Lib3dsDword)b[2] << 16) |
+ ((Lib3dsDword)b[1] << 8) |
+ ((Lib3dsDword)b[0]);
+ return d.float_value;
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a vector from a file stream in little endian format.
+ *
+ * \param io IO input handle.
+ * \param v The vector to store the data.
+ */
+Lib3dsBool
+lib3ds_io_read_vector(Lib3dsIo *io, Lib3dsVector v)
+{
+ ASSERT(io);
+
+ v[0]=lib3ds_io_read_float(io);
+ v[1]=lib3ds_io_read_float(io);
+ v[2]=lib3ds_io_read_float(io);
+
+ return(!lib3ds_io_error(io));
+}
+
+
+/*!
+ * \ingroup io
+ */
+Lib3dsBool
+lib3ds_io_read_rgb(Lib3dsIo *io, Lib3dsRgb rgb)
+{
+ ASSERT(io);
+
+ rgb[0]=lib3ds_io_read_float(io);
+ rgb[1]=lib3ds_io_read_float(io);
+ rgb[2]=lib3ds_io_read_float(io);
+
+ return(!lib3ds_io_error(io));
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Read a zero-terminated string from a file stream.
+ *
+ * \param io IO input handle.
+ * \param s The buffer to store the read string.
+ * \param buflen Buffer length.
+ *
+ * \return True on success, False otherwise.
+ */
+Lib3dsBool
+lib3ds_io_read_string(Lib3dsIo *io, char *s, int buflen)
+{
+ char c;
+ int k=0;
+
+ ASSERT(io);
+ for (;;) {
+ if (lib3ds_io_read(io, &c, 1)!=1) {
+ return LIB3DS_FALSE;
+ }
+ *s++ = c;
+ if (!c) {
+ break;
+ }
+ ++k;
+ if (k>=buflen) {
+ return(LIB3DS_FALSE);
+ }
+ }
+
+ return(!lib3ds_io_error(io));
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a byte into a file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_byte(Lib3dsIo *io, Lib3dsByte b)
+{
+ ASSERT(io);
+ if (lib3ds_io_write(io, &b, 1)!=1) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a word into a little endian file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_word(Lib3dsIo *io, Lib3dsWord w)
+{
+ Lib3dsByte b[2];
+
+ ASSERT(io);
+ b[1]=((Lib3dsWord)w & 0xFF00) >> 8;
+ b[0]=((Lib3dsWord)w & 0x00FF);
+ if (lib3ds_io_write(io, b, 2)!=2) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a dword into a little endian file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_dword(Lib3dsIo *io, Lib3dsDword d)
+{
+ Lib3dsByte b[4];
+
+ ASSERT(io);
+ b[3]=(Lib3dsByte)(((Lib3dsDword)d & 0xFF000000) >> 24);
+ b[2]=(Lib3dsByte)(((Lib3dsDword)d & 0x00FF0000) >> 16);
+ b[1]=(Lib3dsByte)(((Lib3dsDword)d & 0x0000FF00) >> 8);
+ b[0]=(Lib3dsByte)(((Lib3dsDword)d & 0x000000FF));
+ if (lib3ds_io_write(io, b, 4)!=4) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a signed byte in a file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_intb(Lib3dsIo *io, Lib3dsIntb b)
+{
+ ASSERT(io);
+ if (lib3ds_io_write(io, &b, 1)!=1) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a signed word into a little endian file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_intw(Lib3dsIo *io, Lib3dsIntw w)
+{
+ Lib3dsByte b[2];
+
+ ASSERT(io);
+ b[1]=((Lib3dsWord)w & 0xFF00) >> 8;
+ b[0]=((Lib3dsWord)w & 0x00FF);
+ if (lib3ds_io_write(io, b, 2)!=2) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a signed dword into a little endian file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_intd(Lib3dsIo *io, Lib3dsIntd d)
+{
+ Lib3dsByte b[4];
+
+ ASSERT(io);
+ b[3]=(Lib3dsByte)(((Lib3dsDword)d & 0xFF000000) >> 24);
+ b[2]=(Lib3dsByte)(((Lib3dsDword)d & 0x00FF0000) >> 16);
+ b[1]=(Lib3dsByte)(((Lib3dsDword)d & 0x0000FF00) >> 8);
+ b[0]=(Lib3dsByte)(((Lib3dsDword)d & 0x000000FF));
+ if (lib3ds_io_write(io, b, 4)!=4) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a float into a little endian file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_float(Lib3dsIo *io, Lib3dsFloat l)
+{
+ Lib3dsByte b[4];
+ Lib3dsDwordFloat d;
+
+ ASSERT(io);
+ d.float_value=l;
+ b[3]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0xFF000000) >> 24);
+ b[2]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0x00FF0000) >> 16);
+ b[1]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0x0000FF00) >> 8);
+ b[0]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0x000000FF));
+ if (lib3ds_io_write(io, b, 4)!=4) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a vector into a file stream in little endian format.
+ */
+Lib3dsBool
+lib3ds_io_write_vector(Lib3dsIo *io, Lib3dsVector v)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ if (!lib3ds_io_write_float(io, v[i])) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ */
+Lib3dsBool
+lib3ds_io_write_rgb(Lib3dsIo *io, Lib3dsRgb rgb)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ if (!lib3ds_io_write_float(io, rgb[i])) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup io
+ *
+ * Writes a zero-terminated string into a file stream.
+ */
+Lib3dsBool
+lib3ds_io_write_string(Lib3dsIo *io, const char *s)
+{
+ ASSERT(s);
+ ASSERT(io);
+ lib3ds_io_write(io, s, strlen(s)+1);
+ return(!lib3ds_io_error(io));
+}
diff --git a/3rdparty/lib3ds/io.h b/3rdparty/lib3ds/io.h
new file mode 100644
index 000000000..b69a973ad
--- /dev/null
+++ b/3rdparty/lib3ds/io.h
@@ -0,0 +1,82 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_IO_H
+#define INCLUDED_LIB3DS_IO_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: io.h,v 1.6 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum Lib3dsIoSeek {
+ LIB3DS_SEEK_SET =0,
+ LIB3DS_SEEK_CUR =1,
+ LIB3DS_SEEK_END =2
+} Lib3dsIoSeek;
+
+typedef Lib3dsBool (*Lib3dsIoErrorFunc)(void *self);
+typedef long (*Lib3dsIoSeekFunc)(void *self, long offset, Lib3dsIoSeek origin);
+typedef long (*Lib3dsIoTellFunc)(void *self);
+typedef size_t (*Lib3dsIoReadFunc)(void *self, void *buffer, size_t size);
+typedef size_t (*Lib3dsIoWriteFunc)(void *self, const void *buffer, size_t size);
+
+extern LIB3DSAPI Lib3dsIo* lib3ds_io_new(void *self, Lib3dsIoErrorFunc error_func,
+ Lib3dsIoSeekFunc seek_func, Lib3dsIoTellFunc tell_func,
+ Lib3dsIoReadFunc read_func, Lib3dsIoWriteFunc write_func);
+extern LIB3DSAPI void lib3ds_io_free(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_error(Lib3dsIo *io);
+extern LIB3DSAPI long lib3ds_io_seek(Lib3dsIo *io, long offset, Lib3dsIoSeek origin);
+extern LIB3DSAPI long lib3ds_io_tell(Lib3dsIo *io);
+extern LIB3DSAPI size_t lib3ds_io_read(Lib3dsIo *io, void *buffer, size_t size);
+extern LIB3DSAPI size_t lib3ds_io_write(Lib3dsIo *io, const void *buffer, size_t size);
+
+extern LIB3DSAPI Lib3dsByte lib3ds_io_read_byte(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsWord lib3ds_io_read_word(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsDword lib3ds_io_read_dword(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsIntb lib3ds_io_read_intb(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsIntw lib3ds_io_read_intw(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsIntd lib3ds_io_read_intd(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsFloat lib3ds_io_read_float(Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_read_vector(Lib3dsIo *io, Lib3dsVector v);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_read_rgb(Lib3dsIo *io, Lib3dsRgb rgb);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_read_string(Lib3dsIo *io, char *s, int buflen);
+
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_byte(Lib3dsIo *io, Lib3dsByte b);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_word(Lib3dsIo *io, Lib3dsWord w);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_dword(Lib3dsIo *io, Lib3dsDword d);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_intb(Lib3dsIo *io, Lib3dsIntb b);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_intw(Lib3dsIo *io, Lib3dsIntw w);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_intd(Lib3dsIo *io, Lib3dsIntd d);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_float(Lib3dsIo *io, Lib3dsFloat l);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_vector(Lib3dsIo *io, Lib3dsVector v);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_rgb(Lib3dsIo *io, Lib3dsRgb rgb);
+extern LIB3DSAPI Lib3dsBool lib3ds_io_write_string(Lib3dsIo *io, const char *s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/lib3ds.pri b/3rdparty/lib3ds/lib3ds.pri
new file mode 100644
index 000000000..4f08f981b
--- /dev/null
+++ b/3rdparty/lib3ds/lib3ds.pri
@@ -0,0 +1,44 @@
+INCLUDEPATH += $$PWD $$PWD/..
+VPATH += $$PWD
+
+HEADERS += \
+ atmosphere.h \
+ background.h \
+ camera.h \
+ chunk.h \
+ chunktable.h \
+ ease.h \
+ file.h \
+ io.h \
+ light.h \
+ material.h \
+ matrix.h \
+ mesh.h \
+ node.h \
+ quat.h \
+ shadow.h \
+ tcb.h \
+ tracks.h \
+ types.h \
+ vector.h \
+ viewport.h
+
+SOURCES += \
+ atmosphere.c \
+ background.c \
+ camera.c \
+ chunk.c \
+ ease.c \
+ file.c \
+ io.c \
+ light.c \
+ material.c \
+ matrix.c \
+ mesh.c \
+ node.c \
+ quat.c \
+ shadow.c \
+ tcb.c \
+ tracks.c \
+ vector.c \
+ viewport.c
diff --git a/3rdparty/lib3ds/light.c b/3rdparty/lib3ds/light.c
new file mode 100644
index 000000000..99a3ee682
--- /dev/null
+++ b/3rdparty/lib3ds/light.c
@@ -0,0 +1,414 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: light.c,v 1.15 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/light.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+
+/*!
+ * \defgroup light Lights
+ */
+
+
+/*!
+ * \ingroup light
+ */
+Lib3dsLight*
+lib3ds_light_new(const char *name)
+{
+ Lib3dsLight *light;
+
+ ASSERT(name);
+ ASSERT(strlen(name)<64);
+
+ light=(Lib3dsLight*)calloc(sizeof(Lib3dsLight), 1);
+ if (!light) {
+ return(0);
+ }
+ strcpy(light->name, name);
+ return(light);
+}
+
+
+/*!
+ * \ingroup light
+ */
+void
+lib3ds_light_free(Lib3dsLight *light)
+{
+ memset(light, 0, sizeof(Lib3dsLight));
+ free(light);
+}
+
+
+/*!
+ * \ingroup light
+ */
+void
+lib3ds_light_dump(Lib3dsLight *light)
+{
+ ASSERT(light);
+ printf(" name: %s\n", light->name);
+ printf(" spot_light: %s\n", light->spot_light ? "yes" : "no");
+ printf(" see_cone: %s\n", light->see_cone ? "yes" : "no");
+ printf(" color: (%f, %f, %f)\n",
+ light->color[0], light->color[1], light->color[2]);
+ printf(" position (%f, %f, %f)\n",
+ light->position[0], light->position[1], light->position[2]);
+ printf(" spot (%f, %f, %f)\n",
+ light->spot[0], light->spot[1], light->spot[2]);
+ printf(" roll: %f\n", light->roll);
+ printf(" off: %s\n", light->off ? "yes" : "no");
+ printf(" outer_range: %f\n", light->outer_range);
+ printf(" inner_range: %f\n", light->inner_range);
+ printf(" multiplier: %f\n", light->multiplier);
+ printf(" attenuation: %f\n", light->attenuation);
+ printf(" rectangular_spot: %s\n", light->rectangular_spot ? "yes" : "no");
+ printf(" shadowed: %s\n", light->shadowed ? "yes" : "no");
+ printf(" shadow_bias: %f\n", light->shadow_bias);
+ printf(" shadow_filter: %f\n", light->shadow_filter);
+ printf(" shadow_size: %d\n", light->shadow_size);
+ printf(" spot_aspect: %f\n", light->spot_aspect);
+ printf(" use_projector: %s\n", light->use_projector ? "yes" : "no");
+ printf(" projector: %s\n", light->projector);
+ printf(" spot_overshoot: %d\n", (int)light->spot_overshoot);
+ printf(" ray_shadows: %s\n", light->ray_shadows ? "yes" : "no");
+ printf(" ray_bias: %f\n", light->ray_bias);
+ printf(" hot_spot: %f\n", light->hot_spot);
+ printf(" fall_off: %f\n", light->fall_off);
+ printf("\n");
+}
+
+
+/*!
+ * \ingroup light
+ */
+static Lib3dsBool
+spotlight_read(Lib3dsLight *light, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ int i;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_DL_SPOTLIGHT, io)) {
+ return(LIB3DS_FALSE);
+ }
+ light->spot_light=LIB3DS_TRUE;
+ for (i=0; i<3; ++i) {
+ light->spot[i]=lib3ds_io_read_float(io);
+ }
+ light->hot_spot = lib3ds_io_read_float(io);
+ light->fall_off = lib3ds_io_read_float(io);
+ lib3ds_chunk_read_tell(&c, io);
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_DL_SPOT_ROLL:
+ {
+ light->roll=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_DL_SHADOWED:
+ {
+ light->shadowed=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_DL_LOCAL_SHADOW2:
+ {
+ light->shadow_bias=lib3ds_io_read_float(io);
+ light->shadow_filter=lib3ds_io_read_float(io);
+ light->shadow_size=lib3ds_io_read_intw(io);
+ }
+ break;
+ case LIB3DS_DL_SEE_CONE:
+ {
+ light->see_cone=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_DL_SPOT_RECTANGULAR:
+ {
+ light->rectangular_spot=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_DL_SPOT_ASPECT:
+ {
+ light->spot_aspect=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_DL_SPOT_PROJECTOR:
+ {
+ light->use_projector=LIB3DS_TRUE;
+ if (!lib3ds_io_read_string(io, light->projector, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ case LIB3DS_DL_SPOT_OVERSHOOT:
+ {
+ light->spot_overshoot=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_DL_RAY_BIAS:
+ {
+ light->ray_bias=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_DL_RAYSHAD:
+ {
+ light->ray_shadows=LIB3DS_TRUE;
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup light
+ */
+Lib3dsBool
+lib3ds_light_read(Lib3dsLight *light, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_N_DIRECT_LIGHT, io)) {
+ return(LIB3DS_FALSE);
+ }
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ light->position[i]=lib3ds_io_read_float(io);
+ }
+ }
+ lib3ds_chunk_read_tell(&c, io);
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_COLOR_F:
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ light->color[i]=lib3ds_io_read_float(io);
+ }
+ }
+ break;
+ case LIB3DS_DL_OFF:
+ {
+ light->off=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_DL_OUTER_RANGE:
+ {
+ light->outer_range=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_DL_INNER_RANGE:
+ {
+ light->inner_range=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_DL_MULTIPLIER:
+ {
+ light->multiplier=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_DL_EXCLUDE:
+ {
+ /* FIXME: */
+ lib3ds_chunk_unknown(chunk);
+ }
+ case LIB3DS_DL_ATTENUATE:
+ {
+ light->attenuation=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_DL_SPOTLIGHT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!spotlight_read(light, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup light
+ */
+Lib3dsBool
+lib3ds_light_write(Lib3dsLight *light, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_N_DIRECT_LIGHT;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_vector(io, light->position);
+ { /*---- LIB3DS_COLOR_F ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_COLOR_F;
+ c.size=18;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_rgb(io, light->color);
+ }
+ if (light->off) { /*---- LIB3DS_DL_OFF ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_OFF;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+ { /*---- LIB3DS_DL_OUTER_RANGE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_OUTER_RANGE;
+ c.size=10;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, light->outer_range);
+ }
+ { /*---- LIB3DS_DL_INNER_RANGE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_INNER_RANGE;
+ c.size=10;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, light->inner_range);
+ }
+ { /*---- LIB3DS_DL_MULTIPLIER ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_MULTIPLIER;
+ c.size=10;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, light->multiplier);
+ }
+ if (light->attenuation) { /*---- LIB3DS_DL_ATTENUATE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_ATTENUATE;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+
+ if (light->spot_light) {
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_DL_SPOTLIGHT;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_vector(io, light->spot);
+ lib3ds_io_write_float(io, light->hot_spot);
+ lib3ds_io_write_float(io, light->fall_off);
+
+ { /*---- LIB3DS_DL_SPOT_ROLL ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_SPOT_ROLL;
+ c.size=10;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, light->roll);
+ }
+ if (light->shadowed) { /*---- LIB3DS_DL_SHADOWED ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_SHADOWED;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+ if ((fabs(light->shadow_bias)>LIB3DS_EPSILON) ||
+ (fabs(light->shadow_filter)>LIB3DS_EPSILON) ||
+ (light->shadow_size!=0)) { /*---- LIB3DS_DL_LOCAL_SHADOW2 ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_LOCAL_SHADOW2;
+ c.size=16;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, light->shadow_bias);
+ lib3ds_io_write_float(io, light->shadow_filter);
+ lib3ds_io_write_intw(io, light->shadow_size);
+ }
+ if (light->see_cone) { /*---- LIB3DS_DL_SEE_CONE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_SEE_CONE;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+ if (light->rectangular_spot) { /*---- LIB3DS_DL_SPOT_RECTANGULAR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_SPOT_RECTANGULAR;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+ if (fabs(light->spot_aspect)>LIB3DS_EPSILON) { /*---- LIB3DS_DL_SPOT_ASPECT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_SPOT_ASPECT;
+ c.size=10;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, light->spot_aspect);
+ }
+ if (light->use_projector) { /*---- LIB3DS_DL_SPOT_PROJECTOR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_SPOT_PROJECTOR;
+ c.size=10;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_string(io, light->projector);
+ }
+ if (light->spot_overshoot) { /*---- LIB3DS_DL_SPOT_OVERSHOOT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_SPOT_OVERSHOOT;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+ if (fabs(light->ray_bias)>LIB3DS_EPSILON) { /*---- LIB3DS_DL_RAY_BIAS ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_RAY_BIAS;
+ c.size=10;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_float(io, light->ray_bias);
+ }
+ if (light->ray_shadows) { /*---- LIB3DS_DL_RAYSHAD ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_DL_RAYSHAD;
+ c.size=6;
+ lib3ds_chunk_write(&c, io);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
diff --git a/3rdparty/lib3ds/light.h b/3rdparty/lib3ds/light.h
new file mode 100644
index 000000000..d8010d936
--- /dev/null
+++ b/3rdparty/lib3ds/light.h
@@ -0,0 +1,79 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_LIGHT_H
+#define INCLUDED_LIB3DS_LIGHT_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: light.h,v 1.13 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Light
+ * \ingroup light
+ */
+struct Lib3dsLight {
+ Lib3dsLight *next;
+ char name[64];
+ Lib3dsDword object_flags; /*< @see Lib3dsObjectFlags */
+ Lib3dsBool spot_light;
+ Lib3dsBool see_cone;
+ Lib3dsRgb color;
+ Lib3dsVector position;
+ Lib3dsVector spot;
+ Lib3dsFloat roll;
+ Lib3dsBool off;
+ Lib3dsFloat outer_range;
+ Lib3dsFloat inner_range;
+ Lib3dsFloat multiplier;
+ /*const char** excludes;*/
+ Lib3dsFloat attenuation;
+ Lib3dsBool rectangular_spot;
+ Lib3dsBool shadowed;
+ Lib3dsFloat shadow_bias;
+ Lib3dsFloat shadow_filter;
+ Lib3dsIntw shadow_size;
+ Lib3dsFloat spot_aspect;
+ Lib3dsBool use_projector;
+ char projector[64];
+ Lib3dsIntd spot_overshoot;
+ Lib3dsBool ray_shadows;
+ Lib3dsFloat ray_bias;
+ Lib3dsFloat hot_spot;
+ Lib3dsFloat fall_off;
+};
+
+extern LIB3DSAPI Lib3dsLight* lib3ds_light_new(const char *name);
+extern LIB3DSAPI void lib3ds_light_free(Lib3dsLight *mesh);
+extern LIB3DSAPI void lib3ds_light_dump(Lib3dsLight *light);
+extern LIB3DSAPI Lib3dsBool lib3ds_light_read(Lib3dsLight *light, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_light_write(Lib3dsLight *light, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/material.c b/3rdparty/lib3ds/material.c
new file mode 100644
index 000000000..4cd64e951
--- /dev/null
+++ b/3rdparty/lib3ds/material.c
@@ -0,0 +1,1089 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: material.c,v 1.24 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/material.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+
+/*!
+ * \defgroup material Materials
+ */
+
+
+static void
+initialize_texture_map(Lib3dsTextureMap *map)
+{
+ map->flags = 0x10;
+ map->percent = 1.0f;
+ map->scale[0] = 1.0f;
+ map->scale[1] = 1.0f;
+}
+
+
+/*!
+ * Creates and returns a new, empty Lib3dsMaterial object.
+ *
+ * Initial value of the material is a shiny grey.
+ *
+ * \return A pointer to the Lib3dsMaterial structure.
+ * If the structure cannot be allocated, NULL is returned.
+ *
+ * \ingroup material
+ */
+Lib3dsMaterial*
+lib3ds_material_new()
+{
+ Lib3dsMaterial *mat;
+
+ mat = (Lib3dsMaterial*)calloc(sizeof(Lib3dsMaterial), 1);
+ if (!mat) {
+ return(0);
+ }
+
+ mat->ambient[0] = mat->ambient[1] = mat->ambient[2] = 0.588235f;
+ mat->diffuse[0] = mat->diffuse[1] = mat->diffuse[2] = 0.588235f;
+ mat->specular[0] = mat->specular[1] = mat->specular[2] = 0.898039f;
+ mat->shininess = 0.1f;
+ mat->wire_size = 1.0f;
+ mat->shading = 3;
+
+ initialize_texture_map(&mat->texture1_map);
+ initialize_texture_map(&mat->texture1_mask);
+ initialize_texture_map(&mat->texture2_map);
+ initialize_texture_map(&mat->texture2_mask);
+ initialize_texture_map(&mat->opacity_map);
+ initialize_texture_map(&mat->opacity_mask);
+ initialize_texture_map(&mat->bump_map);
+ initialize_texture_map(&mat->bump_mask);
+ initialize_texture_map(&mat->specular_map);
+ initialize_texture_map(&mat->specular_mask);
+ initialize_texture_map(&mat->shininess_map);
+ initialize_texture_map(&mat->shininess_mask);
+ initialize_texture_map(&mat->self_illum_map);
+ initialize_texture_map(&mat->self_illum_mask);
+ initialize_texture_map(&mat->reflection_map);
+ initialize_texture_map(&mat->reflection_mask);
+
+ return(mat);
+}
+
+
+/*!
+ * \ingroup material
+ */
+void
+lib3ds_material_free(Lib3dsMaterial *material)
+{
+ memset(material, 0, sizeof(Lib3dsMaterial));
+ free(material);
+}
+
+
+static Lib3dsBool
+color_read(Lib3dsRgba rgb, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ Lib3dsBool have_lin=LIB3DS_FALSE;
+
+ if (!lib3ds_chunk_read_start(&c, 0, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_LIN_COLOR_24:
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ rgb[i]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ }
+ rgb[3]=1.0f;
+ }
+ have_lin=LIB3DS_TRUE;
+ break;
+ case LIB3DS_COLOR_24:
+ /* gamma corrected color chunk
+ replaced in 3ds R3 by LIN_COLOR_24 */
+ if (!have_lin) {
+ int i;
+ for (i=0; i<3; ++i) {
+ rgb[i]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ }
+ rgb[3]=1.0f;
+ }
+ break;
+ case LIB3DS_LIN_COLOR_F:
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ rgb[i]=lib3ds_io_read_float(io);
+ }
+ rgb[3]=1.0f;
+ }
+ have_lin=LIB3DS_TRUE;
+ break;
+ case LIB3DS_COLOR_F:
+ if (!have_lin) {
+ int i;
+ for (i=0; i<3; ++i) {
+ rgb[i]=lib3ds_io_read_float(io);
+ }
+ rgb[3]=1.0f;
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+int_percentage_read(Lib3dsFloat *p, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, 0, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_INT_PERCENTAGE:
+ {
+ Lib3dsIntw i=lib3ds_io_read_intw(io);
+ *p=(Lib3dsFloat)(1.0*i/100.0);
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+texture_map_read(Lib3dsTextureMap *map, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, 0, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_INT_PERCENTAGE:
+ {
+ map->percent=1.0f*lib3ds_io_read_intw(io)/100.0f;
+ }
+ break;
+ case LIB3DS_MAT_MAPNAME:
+ {
+ if (!lib3ds_io_read_string(io, map->name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_dump_info(" NAME=%s", map->name);
+ }
+ break;
+ case LIB3DS_MAT_MAP_TILING:
+ {
+ map->flags=lib3ds_io_read_word(io);
+ }
+ break;
+ case LIB3DS_MAT_MAP_TEXBLUR:
+ {
+ map->blur=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_MAT_MAP_USCALE:
+ {
+ map->scale[0]=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_MAT_MAP_VSCALE:
+ {
+ map->scale[1]=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_MAT_MAP_UOFFSET:
+ {
+ map->offset[0]=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_MAT_MAP_VOFFSET:
+ {
+ map->offset[1]=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_MAT_MAP_ANG:
+ {
+ map->rotation=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_MAT_MAP_COL1:
+ {
+ map->tint_1[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_1[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_1[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ }
+ break;
+ case LIB3DS_MAT_MAP_COL2:
+ {
+ map->tint_2[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_2[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_2[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ }
+ break;
+ case LIB3DS_MAT_MAP_RCOL:
+ {
+ map->tint_r[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_r[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_r[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ }
+ break;
+ case LIB3DS_MAT_MAP_GCOL:
+ {
+ map->tint_g[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_g[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_g[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ }
+ break;
+ case LIB3DS_MAT_MAP_BCOL:
+ {
+ map->tint_b[0]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_b[1]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ map->tint_b[2]=1.0f*lib3ds_io_read_byte(io)/255.0f;
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup material
+ */
+static void
+texture_dump(const char *maptype, Lib3dsTextureMap *texture)
+{
+ ASSERT(texture);
+ if (strlen(texture->name)==0) {
+ return;
+ }
+ printf(" %s:\n", maptype);
+ printf(" name: %s\n", texture->name);
+ printf(" flags: %X\n", (unsigned)texture->flags);
+ printf(" percent: %f\n", texture->percent);
+ printf(" blur: %f\n", texture->blur);
+ printf(" scale: (%f, %f)\n", texture->scale[0], texture->scale[1]);
+ printf(" offset: (%f, %f)\n", texture->offset[0], texture->offset[1]);
+ printf(" rotation: %f\n", texture->rotation);
+ printf(" tint_1: (%f, %f, %f)\n",
+ texture->tint_1[0], texture->tint_1[1], texture->tint_1[2]);
+ printf(" tint_2: (%f, %f, %f)\n",
+ texture->tint_2[0], texture->tint_2[1], texture->tint_2[2]);
+ printf(" tint_r: (%f, %f, %f)\n",
+ texture->tint_r[0], texture->tint_r[1], texture->tint_r[2]);
+ printf(" tint_g: (%f, %f, %f)\n",
+ texture->tint_g[0], texture->tint_g[1], texture->tint_g[2]);
+ printf(" tint_b: (%f, %f, %f)\n",
+ texture->tint_b[0], texture->tint_b[1], texture->tint_b[2]);
+}
+
+
+/*!
+ * \ingroup material
+ */
+void
+lib3ds_material_dump(Lib3dsMaterial *material)
+{
+ ASSERT(material);
+ printf(" name: %s\n", material->name);
+ printf(" ambient: (%f, %f, %f)\n",
+ material->ambient[0], material->ambient[1], material->ambient[2]);
+ printf(" diffuse: (%f, %f, %f)\n",
+ material->diffuse[0], material->diffuse[1], material->diffuse[2]);
+ printf(" specular: (%f, %f, %f)\n",
+ material->specular[0], material->specular[1], material->specular[2]);
+ printf(" shininess: %f\n", material->shininess);
+ printf(" shin_strength: %f\n", material->shin_strength);
+ printf(" use_blur: %s\n", material->use_blur ? "yes" : "no");
+ printf(" blur: %f\n", material->blur);
+ printf(" falloff: %f\n", material->falloff);
+ printf(" additive: %s\n", material->additive ? "yes" : "no");
+ printf(" use_falloff: %s\n", material->use_falloff ? "yes" : "no");
+ printf(" self_illum: %s\n", material->self_illum ? "yes" : "no");
+ printf(" self_ilpct: %f\n", material->self_ilpct);
+ printf(" shading: %d\n", material->shading);
+ printf(" soften: %s\n", material->soften ? "yes" : "no");
+ printf(" face_map: %s\n", material->face_map ? "yes" : "no");
+ printf(" two_sided: %s\n", material->two_sided ? "yes" : "no");
+ printf(" map_decal: %s\n", material->map_decal ? "yes" : "no");
+ printf(" use_wire: %s\n", material->use_wire ? "yes" : "no");
+ printf(" use_wire_abs: %s\n", material->use_wire_abs ? "yes" : "no");
+ printf(" wire_size: %f\n", material->wire_size);
+ texture_dump("texture1_map", &material->texture1_map);
+ texture_dump("texture1_mask", &material->texture1_mask);
+ texture_dump("texture2_map", &material->texture2_map);
+ texture_dump("texture2_mask", &material->texture2_mask);
+ texture_dump("opacity_map", &material->opacity_map);
+ texture_dump("opacity_mask", &material->opacity_mask);
+ texture_dump("bump_map", &material->bump_map);
+ texture_dump("bump_mask", &material->bump_mask);
+ texture_dump("specular_map", &material->specular_map);
+ texture_dump("specular_mask", &material->specular_mask);
+ texture_dump("shininess_map", &material->shininess_map);
+ texture_dump("shininess_mask", &material->shininess_mask);
+ texture_dump("self_illum_map", &material->self_illum_map);
+ texture_dump("self_illum_mask", &material->self_illum_mask);
+ texture_dump("reflection_map", &material->reflection_map);
+ texture_dump("reflection_mask", &material->reflection_mask);
+ printf(" autorefl_map:\n");
+ printf(" flags %X\n", (unsigned)material->autorefl_map.flags);
+ printf(" level %d\n", (int)material->autorefl_map.level);
+ printf(" size %d\n", (int)material->autorefl_map.size);
+ printf(" frame_step %d\n", (int)material->autorefl_map.frame_step);
+ printf("\n");
+}
+
+
+/*!
+ * \ingroup material
+ */
+Lib3dsBool
+lib3ds_material_read(Lib3dsMaterial *material, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ ASSERT(material);
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_MAT_ENTRY, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_MAT_NAME:
+ {
+ if (!lib3ds_io_read_string(io, material->name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_chunk_dump_info(" NAME=%s", material->name);
+ }
+ break;
+ case LIB3DS_MAT_AMBIENT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!color_read(material->ambient, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_DIFFUSE:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!color_read(material->diffuse, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SPECULAR:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!color_read(material->specular, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SHININESS:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!int_percentage_read(&material->shininess, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SHIN2PCT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!int_percentage_read(&material->shin_strength, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_TRANSPARENCY:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!int_percentage_read(&material->transparency, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_XPFALL:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!int_percentage_read(&material->falloff, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SELF_ILPCT:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!int_percentage_read(&material->self_ilpct, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_USE_XPFALL:
+ {
+ material->use_falloff=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_REFBLUR:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!int_percentage_read(&material->blur, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_USE_REFBLUR:
+ {
+ material->use_blur=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_SHADING:
+ {
+ material->shading=lib3ds_io_read_intw(io);
+ }
+ break;
+ case LIB3DS_MAT_SELF_ILLUM:
+ {
+ material->self_illum=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_TWO_SIDE:
+ {
+ material->two_sided=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_DECAL:
+ {
+ material->map_decal=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_ADDITIVE:
+ {
+ material->additive=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_FACEMAP:
+ {
+ material->face_map=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_PHONGSOFT:
+ {
+ material->soften=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_WIRE:
+ {
+ material->use_wire=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_WIREABS:
+ {
+ material->use_wire_abs=LIB3DS_TRUE;
+ }
+ break;
+ case LIB3DS_MAT_WIRE_SIZE:
+ {
+ material->wire_size=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_MAT_TEXMAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->texture1_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_TEXMASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->texture1_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_TEX2MAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->texture2_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_TEX2MASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->texture2_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_OPACMAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->opacity_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_OPACMASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->opacity_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_BUMPMAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->bump_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_BUMPMASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->bump_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SPECMAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->specular_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SPECMASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->specular_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SHINMAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->shininess_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SHINMASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->shininess_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SELFIMAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->self_illum_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_SELFIMASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->self_illum_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_REFLMAP:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->reflection_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_REFLMASK:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!texture_map_read(&material->reflection_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MAT_ACUBIC:
+ {
+ lib3ds_io_read_intb(io);
+ material->autorefl_map.level=lib3ds_io_read_intb(io);
+ material->autorefl_map.flags=lib3ds_io_read_intw(io);
+ material->autorefl_map.size=lib3ds_io_read_intd(io);
+ material->autorefl_map.frame_step=lib3ds_io_read_intd(io);
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+color_write(Lib3dsRgba rgb, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_COLOR_24;
+ c.size=9;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[0]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[1]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[2]+0.5));
+
+ c.chunk=LIB3DS_LIN_COLOR_24;
+ c.size=9;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[0]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[1]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*rgb[2]+0.5));
+
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+int_percentage_write(Lib3dsFloat p, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_INT_PERCENTAGE;
+ c.size=8;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intw(io, (Lib3dsByte)floor(100.0*p+0.5));
+
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+texture_map_write(Lib3dsWord chunk, Lib3dsTextureMap *map, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ if (strlen(map->name)==0) {
+ return(LIB3DS_TRUE);
+ }
+ c.chunk=chunk;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ int_percentage_write(map->percent,io);
+
+ { /*---- LIB3DS_MAT_MAPNAME ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAPNAME;
+ c.size=6+(Lib3dsDword)strlen(map->name)+1;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_string(io, map->name);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_TILING ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_TILING;
+ c.size=8;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_word(io, (Lib3dsWord)map->flags);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_TEXBLUR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_TEXBLUR;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, map->blur);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_USCALE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_USCALE;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, map->scale[0]);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_VSCALE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_VSCALE;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, map->scale[1]);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_UOFFSET ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_UOFFSET;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, map->offset[0]);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_VOFFSET ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_VOFFSET;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, map->offset[1]);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_ANG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_ANG;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, map->rotation);
+ }
+
+ { /*---- LIB3DS_MAT_MAP_COL1 ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_COL1;
+ c.size=9;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_1[0]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_1[1]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_1[2]+0.5));
+ }
+
+ { /*---- LIB3DS_MAT_MAP_COL2 ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_COL2;
+ c.size=9;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_2[0]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_2[1]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_2[2]+0.5));
+ }
+
+ { /*---- LIB3DS_MAT_MAP_RCOL ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_RCOL;
+ c.size=9;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_r[0]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_r[1]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_r[2]+0.5));
+ }
+
+ { /*---- LIB3DS_MAT_MAP_GCOL ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_GCOL;
+ c.size=9;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_g[0]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_g[1]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_g[2]+0.5));
+ }
+
+ { /*---- LIB3DS_MAT_MAP_BCOL ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_MAP_BCOL;
+ c.size=9;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_b[0]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_b[1]+0.5));
+ lib3ds_io_write_byte(io, (Lib3dsByte)floor(255.0*map->tint_b[2]+0.5));
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup material
+ */
+Lib3dsBool
+lib3ds_material_write(Lib3dsMaterial *material, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_MAT_ENTRY;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ { /*---- LIB3DS_MAT_NAME ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_NAME;
+ c.size=6+(Lib3dsDword)strlen(material->name)+1;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_string(io, material->name);
+ }
+
+ { /*---- LIB3DS_MAT_AMBIENT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_AMBIENT;
+ c.size=24;
+ lib3ds_chunk_write(&c,io);
+ color_write(material->ambient,io);
+ }
+
+ { /*---- LIB3DS_MAT_DIFFUSE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_DIFFUSE;
+ c.size=24;
+ lib3ds_chunk_write(&c,io);
+ color_write(material->diffuse,io);
+ }
+
+ { /*---- LIB3DS_MAT_SPECULAR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_SPECULAR;
+ c.size=24;
+ lib3ds_chunk_write(&c,io);
+ color_write(material->specular,io);
+ }
+
+ { /*---- LIB3DS_MAT_SHININESS ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_SHININESS;
+ c.size=14;
+ lib3ds_chunk_write(&c,io);
+ int_percentage_write(material->shininess,io);
+ }
+
+ { /*---- LIB3DS_MAT_SHIN2PCT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_SHIN2PCT;
+ c.size=14;
+ lib3ds_chunk_write(&c,io);
+ int_percentage_write(material->shin_strength,io);
+ }
+
+ { /*---- LIB3DS_MAT_TRANSPARENCY ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_TRANSPARENCY;
+ c.size=14;
+ lib3ds_chunk_write(&c,io);
+ int_percentage_write(material->transparency,io);
+ }
+
+ { /*---- LIB3DS_MAT_XPFALL ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_XPFALL;
+ c.size=14;
+ lib3ds_chunk_write(&c,io);
+ int_percentage_write(material->falloff,io);
+ }
+
+ if (material->use_falloff) { /*---- LIB3DS_MAT_USE_XPFALL ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_USE_XPFALL;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ { /*---- LIB3DS_MAT_SHADING ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_SHADING;
+ c.size=8;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intw(io, material->shading);
+ }
+
+ { /*---- LIB3DS_MAT_REFBLUR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_REFBLUR;
+ c.size=14;
+ lib3ds_chunk_write(&c,io);
+ int_percentage_write(material->blur,io);
+ }
+
+ if (material->use_blur) { /*---- LIB3DS_MAT_USE_REFBLUR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_USE_REFBLUR;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (material->self_illum) { /*---- LIB3DS_MAT_SELF_ILLUM ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_SELF_ILLUM;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (material->two_sided) { /*---- LIB3DS_MAT_TWO_SIDE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_TWO_SIDE;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (material->map_decal) { /*---- LIB3DS_MAT_DECAL ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_DECAL;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (material->additive) { /*---- LIB3DS_MAT_ADDITIVE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_ADDITIVE;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (material->use_wire) { /*---- LIB3DS_MAT_WIRE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_WIRE;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (material->use_wire_abs) { /*---- LIB3DS_MAT_WIREABS ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_WIREABS;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ { /*---- LIB3DS_MAT_WIRE_SIZE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_WIRE_SIZE;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, material->wire_size);
+ }
+
+ if (material->face_map) { /*---- LIB3DS_MAT_FACEMAP ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_FACEMAP;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (material->soften) { /*---- LIB3DS_MAT_PHONGSOFT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MAT_PHONGSOFT;
+ c.size=6;
+ lib3ds_chunk_write(&c,io);
+ }
+
+ if (!texture_map_write(LIB3DS_MAT_TEXMAP, &material->texture1_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_TEXMASK, &material->texture1_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_TEX2MAP, &material->texture2_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_TEX2MASK, &material->texture2_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_OPACMAP, &material->opacity_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_OPACMASK, &material->opacity_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_BUMPMAP, &material->bump_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_BUMPMASK, &material->bump_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_SPECMAP, &material->specular_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_SPECMASK, &material->specular_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_SHINMAP, &material->shininess_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_SHINMASK, &material->shininess_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_SELFIMAP, &material->self_illum_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_SELFIMASK, &material->self_illum_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_REFLMAP, &material->reflection_map, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texture_map_write(LIB3DS_MAT_REFLMASK, &material->reflection_mask, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
diff --git a/3rdparty/lib3ds/material.h b/3rdparty/lib3ds/material.h
new file mode 100644
index 000000000..7e3e168e7
--- /dev/null
+++ b/3rdparty/lib3ds/material.h
@@ -0,0 +1,170 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_MATERIAL_H
+#define INCLUDED_LIB3DS_MATERIAL_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: material.h,v 1.18 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \ingroup material
+ */
+typedef enum Lib3dsTextureMapFlags {
+ LIB3DS_DECALE =0x0001,
+ LIB3DS_MIRROR =0x0002,
+ LIB3DS_NEGATE =0x0008,
+ LIB3DS_NO_TILE =0x0010,
+ LIB3DS_SUMMED_AREA =0x0020,
+ LIB3DS_ALPHA_SOURCE =0x0040,
+ LIB3DS_TINT =0x0080,
+ LIB3DS_IGNORE_ALPHA =0x0100,
+ LIB3DS_RGB_TINT =0x0200
+} Lib3dsTextureMapFlags;
+
+/**
+ * Mateial texture map
+ * \ingroup material
+ */
+typedef struct Lib3dsTextureMap {
+ Lib3dsUserData user;
+ char name[64];
+ Lib3dsDword flags;
+ Lib3dsFloat percent;
+ Lib3dsFloat blur;
+ Lib3dsFloat scale[2];
+ Lib3dsFloat offset[2];
+ Lib3dsFloat rotation;
+ Lib3dsRgb tint_1;
+ Lib3dsRgb tint_2;
+ Lib3dsRgb tint_r;
+ Lib3dsRgb tint_g;
+ Lib3dsRgb tint_b;
+} Lib3dsTextureMap;
+
+/**
+ * \ingroup material
+ */
+typedef enum Lib3dsAutoReflMapFlags {
+ LIB3DS_USE_REFL_MAP =0x0001,
+ LIB3DS_READ_FIRST_FRAME_ONLY =0x0004,
+ LIB3DS_FLAT_MIRROR =0x0008
+} Lib3dsAutoReflectionMapFlags;
+
+/**
+ * \ingroup material
+ */
+typedef enum Lib3dsAutoReflMapAntiAliasLevel {
+ LIB3DS_ANTI_ALIAS_NONE =0,
+ LIB3DS_ANTI_ALIAS_LOW =1,
+ LIB3DS_ANTI_ALIAS_MEDIUM =2,
+ LIB3DS_ANTI_ALIAS_HIGH =3
+} Lib3dsAutoReflMapAntiAliasLevel;
+
+/**
+ * Auto reflection map settings
+ * \ingroup material
+ */
+typedef struct Lib3dsAutoReflMap {
+ Lib3dsDword flags;
+ Lib3dsIntd level;
+ Lib3dsIntd size;
+ Lib3dsIntd frame_step;
+} Lib3dsAutoReflMap;
+
+/**
+ * \ingroup material
+ */
+typedef enum Lib3dsMaterialShading {
+ LIB3DS_WIRE_FRAME =0,
+ LIB3DS_FLAT =1,
+ LIB3DS_GOURAUD =2,
+ LIB3DS_PHONG =3,
+ LIB3DS_METAL =4
+} Lib3dsMaterialShading;
+
+/**
+ * Material
+ * \ingroup material
+ */
+struct Lib3dsMaterial {
+ Lib3dsUserData user; /*! Arbitrary user data */
+ Lib3dsMaterial *next;
+ char name[64]; /*! Material name */
+ Lib3dsRgba ambient; /*! Material ambient reflectivity */
+ Lib3dsRgba diffuse; /*! Material diffuse reflectivity */
+ Lib3dsRgba specular; /*! Material specular reflectivity */
+ Lib3dsFloat shininess; /*! Material specular exponent */
+ Lib3dsFloat shin_strength;
+ Lib3dsBool use_blur;
+ Lib3dsFloat blur;
+ Lib3dsFloat transparency;
+ Lib3dsFloat falloff;
+ Lib3dsBool additive;
+ Lib3dsFloat self_ilpct;
+ Lib3dsBool use_falloff;
+ Lib3dsBool self_illum;
+ Lib3dsIntw shading;
+ Lib3dsBool soften;
+ Lib3dsBool face_map;
+ Lib3dsBool two_sided; /*! Material visible from back */
+ Lib3dsBool map_decal;
+ Lib3dsBool use_wire;
+ Lib3dsBool use_wire_abs;
+ Lib3dsFloat wire_size;
+ Lib3dsTextureMap texture1_map;
+ Lib3dsTextureMap texture1_mask;
+ Lib3dsTextureMap texture2_map;
+ Lib3dsTextureMap texture2_mask;
+ Lib3dsTextureMap opacity_map;
+ Lib3dsTextureMap opacity_mask;
+ Lib3dsTextureMap bump_map;
+ Lib3dsTextureMap bump_mask;
+ Lib3dsTextureMap specular_map;
+ Lib3dsTextureMap specular_mask;
+ Lib3dsTextureMap shininess_map;
+ Lib3dsTextureMap shininess_mask;
+ Lib3dsTextureMap self_illum_map;
+ Lib3dsTextureMap self_illum_mask;
+ Lib3dsTextureMap reflection_map;
+ Lib3dsTextureMap reflection_mask;
+ Lib3dsAutoReflMap autorefl_map;
+};
+
+extern LIB3DSAPI Lib3dsMaterial* lib3ds_material_new();
+extern LIB3DSAPI void lib3ds_material_free(Lib3dsMaterial *material);
+extern LIB3DSAPI void lib3ds_material_dump(Lib3dsMaterial *material);
+extern LIB3DSAPI Lib3dsBool lib3ds_material_read(Lib3dsMaterial *material, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_material_write(Lib3dsMaterial *material, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
diff --git a/3rdparty/lib3ds/matrix.c b/3rdparty/lib3ds/matrix.c
new file mode 100644
index 000000000..58e7584a6
--- /dev/null
+++ b/3rdparty/lib3ds/matrix.c
@@ -0,0 +1,718 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: matrix.c,v 1.14 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/matrix.h>
+#include <lib3ds/quat.h>
+#include <lib3ds/vector.h>
+#include <string.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup matrix Matrix Mathematics
+ */
+
+
+/*!
+* \typedef Lib3dsMatrix
+* \ingroup matrix
+*/
+
+
+/*!
+ * Clear a matrix to all zeros.
+ *
+ * \param m Matrix to be cleared.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_zero(Lib3dsMatrix m)
+{
+ int i,j;
+
+ for (i=0; i<4; i++) {
+ for (j=0; j<4; j++) m[i][j]=0.0f;
+ }
+}
+
+
+/*!
+ * Set a matrix to identity.
+ *
+ * \param m Matrix to be set.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_identity(Lib3dsMatrix m)
+{
+ int i,j;
+
+ for (i=0; i<4; i++) {
+ for (j=0; j<4; j++) m[i][j]=0.0;
+ }
+ for (i=0; i<4; i++) m[i][i]=1.0;
+}
+
+
+/*!
+ * Copy a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_copy(Lib3dsMatrix dest, Lib3dsMatrix src)
+{
+ memcpy(dest, src, sizeof(Lib3dsMatrix));
+}
+
+
+/*!
+ * Negate a matrix -- all elements negated.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_neg(Lib3dsMatrix m)
+{
+ int i,j;
+
+ for (j=0; j<4; j++) {
+ for (i=0; i<4; i++) {
+ m[j][i]=-m[j][i];
+ }
+ }
+}
+
+
+/*!
+ * Set all matrix elements to their absolute value.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_abs(Lib3dsMatrix m)
+{
+ int i,j;
+
+ for (j=0; j<4; j++) {
+ for (i=0; i<4; i++) {
+ m[j][i]=(Lib3dsFloat)fabs(m[j][i]);
+ }
+ }
+}
+
+
+/*!
+ * Transpose a matrix in place.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_transpose(Lib3dsMatrix m)
+{
+ int i,j;
+ Lib3dsFloat swp;
+
+ for (j=0; j<4; j++) {
+ for (i=j+1; i<4; i++) {
+ swp=m[j][i];
+ m[j][i]=m[i][j];
+ m[i][j]=swp;
+ }
+ }
+}
+
+
+/*!
+ * Add two matrices.
+ *
+ * \ingroup matrix
+ */
+void
+_lib3ds_matrix_add(Lib3dsMatrix m, Lib3dsMatrix a, Lib3dsMatrix b)
+{
+ int i,j;
+
+ for (j=0; j<4; j++) {
+ for (i=0; i<4; i++) {
+ m[j][i]=a[j][i]+b[j][i];
+ }
+ }
+}
+
+
+/*!
+ * Subtract two matrices.
+ *
+ * \param m Result.
+ * \param a Addend.
+ * \param b Minuend.
+ *
+ * \ingroup matrix
+ */
+void
+_lib3ds_matrix_sub(Lib3dsMatrix m, Lib3dsMatrix a, Lib3dsMatrix b)
+{
+ int i,j;
+
+ for (j=0; j<4; j++) {
+ for (i=0; i<4; i++) {
+ m[j][i]=a[j][i]-b[j][i];
+ }
+ }
+}
+
+
+/*!
+ * Multiplies a matrix by a second one (m = m * n).
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_mult(Lib3dsMatrix m, Lib3dsMatrix n)
+{
+ Lib3dsMatrix tmp;
+ int i,j,k;
+ Lib3dsFloat ab;
+
+ memcpy(tmp, m, sizeof(Lib3dsMatrix));
+ for (j=0; j<4; j++) {
+ for (i=0; i<4; i++) {
+ ab=0.0f;
+ for (k=0; k<4; k++) ab+=tmp[k][i]*n[j][k];
+ m[j][i]=ab;
+ }
+ }
+}
+
+
+/*!
+ * Multiply a matrix by a scalar.
+ *
+ * \param m Matrix to be set.
+ * \param k Scalar.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_scalar(Lib3dsMatrix m, Lib3dsFloat k)
+{
+ int i,j;
+
+ for (j=0; j<4; j++) {
+ for (i=0; i<4; i++) {
+ m[j][i]*=k;
+ }
+ }
+}
+
+
+static Lib3dsFloat
+det2x2(
+ Lib3dsFloat a, Lib3dsFloat b,
+ Lib3dsFloat c, Lib3dsFloat d)
+{
+ return((a)*(d)-(b)*(c));
+}
+
+
+static Lib3dsFloat
+det3x3(
+ Lib3dsFloat a1, Lib3dsFloat a2, Lib3dsFloat a3,
+ Lib3dsFloat b1, Lib3dsFloat b2, Lib3dsFloat b3,
+ Lib3dsFloat c1, Lib3dsFloat c2, Lib3dsFloat c3)
+{
+ return(
+ a1*det2x2(b2,b3,c2,c3)-
+ b1*det2x2(a2,a3,c2,c3)+
+ c1*det2x2(a2,a3,b2,b3)
+ );
+}
+
+
+/*!
+ * Find determinant of a matrix.
+ *
+ * \ingroup matrix
+ */
+Lib3dsFloat
+lib3ds_matrix_det(Lib3dsMatrix m)
+{
+ Lib3dsFloat a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4;
+
+ a1 = m[0][0];
+ b1 = m[1][0];
+ c1 = m[2][0];
+ d1 = m[3][0];
+ a2 = m[0][1];
+ b2 = m[1][1];
+ c2 = m[2][1];
+ d2 = m[3][1];
+ a3 = m[0][2];
+ b3 = m[1][2];
+ c3 = m[2][2];
+ d3 = m[3][2];
+ a4 = m[0][3];
+ b4 = m[1][3];
+ c4 = m[2][3];
+ d4 = m[3][3];
+ return(
+ a1 * det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)-
+ b1 * det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)+
+ c1 * det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)-
+ d1 * det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4)
+ );
+}
+
+
+/*!
+ * Find the adjoint of a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_adjoint(Lib3dsMatrix m)
+{
+ Lib3dsFloat a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4;
+
+ a1 = m[0][0];
+ b1 = m[1][0];
+ c1 = m[2][0];
+ d1 = m[3][0];
+ a2 = m[0][1];
+ b2 = m[1][1];
+ c2 = m[2][1];
+ d2 = m[3][1];
+ a3 = m[0][2];
+ b3 = m[1][2];
+ c3 = m[2][2];
+ d3 = m[3][2];
+ a4 = m[0][3];
+ b4 = m[1][3];
+ c4 = m[2][3];
+ d4 = m[3][3];
+ m[0][0]= det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4);
+ m[0][1]= -det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4);
+ m[0][2]= det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4);
+ m[0][3]= -det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4);
+ m[1][0]= -det3x3 (b1, b3, b4, c1, c3, c4, d1, d3, d4);
+ m[1][1]= det3x3 (a1, a3, a4, c1, c3, c4, d1, d3, d4);
+ m[1][2]= -det3x3 (a1, a3, a4, b1, b3, b4, d1, d3, d4);
+ m[1][3]= det3x3 (a1, a3, a4, b1, b3, b4, c1, c3, c4);
+ m[2][0]= det3x3 (b1, b2, b4, c1, c2, c4, d1, d2, d4);
+ m[2][1]= -det3x3 (a1, a2, a4, c1, c2, c4, d1, d2, d4);
+ m[2][2]= det3x3 (a1, a2, a4, b1, b2, b4, d1, d2, d4);
+ m[2][3]= -det3x3 (a1, a2, a4, b1, b2, b4, c1, c2, c4);
+ m[3][0]= -det3x3 (b1, b2, b3, c1, c2, c3, d1, d2, d3);
+ m[3][1]= det3x3 (a1, a2, a3, c1, c2, c3, d1, d2, d3);
+ m[3][2]= -det3x3 (a1, a2, a3, b1, b2, b3, d1, d2, d3);
+ m[3][3]= det3x3 (a1, a2, a3, b1, b2, b3, c1, c2, c3);
+}
+
+
+/*!
+ * Invert a matrix in place.
+ *
+ * \param m Matrix to invert.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ * \ingroup matrix
+ *
+ * GGemsII, K.Wu, Fast Matrix Inversion
+ */
+Lib3dsBool
+lib3ds_matrix_inv(Lib3dsMatrix m)
+{
+ int i,j,k;
+ int pvt_i[4], pvt_j[4]; /* Locations of pivot elements */
+ Lib3dsFloat pvt_val; /* Value of current pivot element */
+ Lib3dsFloat hold; /* Temporary storage */
+ Lib3dsFloat determinat;
+
+ determinat = 1.0f;
+ for (k=0; k<4; k++) {
+ /* Locate k'th pivot element */
+ pvt_val=m[k][k]; /* Initialize for search */
+ pvt_i[k]=k;
+ pvt_j[k]=k;
+ for (i=k; i<4; i++) {
+ for (j=k; j<4; j++) {
+ if (fabs(m[i][j]) > fabs(pvt_val)) {
+ pvt_i[k]=i;
+ pvt_j[k]=j;
+ pvt_val=m[i][j];
+ }
+ }
+ }
+
+ /* Product of pivots, gives determinant when finished */
+ determinat*=pvt_val;
+ if (fabs(determinat)<LIB3DS_EPSILON) {
+ return(LIB3DS_FALSE); /* Matrix is singular (zero determinant) */
+ }
+
+ /* "Interchange" rows (with sign change stuff) */
+ i=pvt_i[k];
+ if (i!=k) { /* If rows are different */
+ for (j=0; j<4; j++) {
+ hold=-m[k][j];
+ m[k][j]=m[i][j];
+ m[i][j]=hold;
+ }
+ }
+
+ /* "Interchange" columns */
+ j=pvt_j[k];
+ if (j!=k) { /* If columns are different */
+ for (i=0; i<4; i++) {
+ hold=-m[i][k];
+ m[i][k]=m[i][j];
+ m[i][j]=hold;
+ }
+ }
+
+ /* Divide column by minus pivot value */
+ for (i=0; i<4; i++) {
+ if (i!=k) m[i][k]/=( -pvt_val) ;
+ }
+
+ /* Reduce the matrix */
+ for (i=0; i<4; i++) {
+ hold = m[i][k];
+ for (j=0; j<4; j++) {
+ if (i!=k && j!=k) m[i][j]+=hold*m[k][j];
+ }
+ }
+
+ /* Divide row by pivot */
+ for (j=0; j<4; j++) {
+ if (j!=k) m[k][j]/=pvt_val;
+ }
+
+ /* Replace pivot by reciprocal (at last we can touch it). */
+ m[k][k] = 1.0f/pvt_val;
+ }
+
+ /* That was most of the work, one final pass of row/column interchange */
+ /* to finish */
+ for (k=4-2; k>=0; k--) { /* Don't need to work with 1 by 1 corner*/
+ i=pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
+ if (i!=k) { /* If rows are different */
+ for (j=0; j<4; j++) {
+ hold = m[k][j];
+ m[k][j]=-m[i][j];
+ m[i][j]=hold;
+ }
+ }
+
+ j=pvt_i[k]; /* Columns to swap correspond to pivot ROW */
+ if (j!=k) /* If columns are different */
+ for (i=0; i<4; i++) {
+ hold=m[i][k];
+ m[i][k]=-m[i][j];
+ m[i][j]=hold;
+ }
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Apply a translation to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_translate_xyz(Lib3dsMatrix m, Lib3dsFloat x, Lib3dsFloat y, Lib3dsFloat z)
+{
+ int i;
+
+ for (i=0; i<3; i++) {
+ m[3][i]+= m[0][i]*x + m[1][i]*y + m[2][i]*z;
+ }
+}
+
+
+/*!
+ * Apply a translation to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_translate(Lib3dsMatrix m, Lib3dsVector t)
+{
+ int i;
+
+ for (i=0; i<3; i++) {
+ m[3][i]+= m[0][i]*t[0] + m[1][i]*t[1] + m[2][i]*t[2];
+ }
+}
+
+
+/*!
+ * Apply scale factors to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_scale_xyz(Lib3dsMatrix m, Lib3dsFloat x, Lib3dsFloat y, Lib3dsFloat z)
+{
+ int i;
+
+ for (i=0; i<4; i++) {
+ m[0][i]*=x;
+ m[1][i]*=y;
+ m[2][i]*=z;
+ }
+}
+
+
+/*!
+ * Apply scale factors to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_scale(Lib3dsMatrix m, Lib3dsVector s)
+{
+ int i;
+
+ for (i=0; i<4; i++) {
+ m[0][i]*=s[0];
+ m[1][i]*=s[1];
+ m[2][i]*=s[2];
+ }
+}
+
+
+/*!
+ * Apply a rotation about the x axis to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_rotate_x(Lib3dsMatrix m, Lib3dsFloat phi)
+{
+ Lib3dsFloat SinPhi,CosPhi;
+ Lib3dsFloat a1[4],a2[4];
+
+ SinPhi=(Lib3dsFloat)sin(phi);
+ CosPhi=(Lib3dsFloat)cos(phi);
+ memcpy(a1,m[1],4*sizeof(Lib3dsFloat));
+ memcpy(a2,m[2],4*sizeof(Lib3dsFloat));
+ m[1][0]=CosPhi*a1[0]+SinPhi*a2[0];
+ m[1][1]=CosPhi*a1[1]+SinPhi*a2[1];
+ m[1][2]=CosPhi*a1[2]+SinPhi*a2[2];
+ m[1][3]=CosPhi*a1[3]+SinPhi*a2[3];
+ m[2][0]=-SinPhi*a1[0]+CosPhi*a2[0];
+ m[2][1]=-SinPhi*a1[1]+CosPhi*a2[1];
+ m[2][2]=-SinPhi*a1[2]+CosPhi*a2[2];
+ m[2][3]=-SinPhi*a1[3]+CosPhi*a2[3];
+}
+
+
+/*!
+ * Apply a rotation about the y axis to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_rotate_y(Lib3dsMatrix m, Lib3dsFloat phi)
+{
+ Lib3dsFloat SinPhi,CosPhi;
+ Lib3dsFloat a0[4],a2[4];
+
+ SinPhi=(Lib3dsFloat)sin(phi);
+ CosPhi=(Lib3dsFloat)cos(phi);
+ memcpy(a0,m[0],4*sizeof(Lib3dsFloat));
+ memcpy(a2,m[2],4*sizeof(Lib3dsFloat));
+ m[0][0]=CosPhi*a0[0]-SinPhi*a2[0];
+ m[0][1]=CosPhi*a0[1]-SinPhi*a2[1];
+ m[0][2]=CosPhi*a0[2]-SinPhi*a2[2];
+ m[0][3]=CosPhi*a0[3]-SinPhi*a2[3];
+ m[2][0]=SinPhi*a0[0]+CosPhi*a2[0];
+ m[2][1]=SinPhi*a0[1]+CosPhi*a2[1];
+ m[2][2]=SinPhi*a0[2]+CosPhi*a2[2];
+ m[2][3]=SinPhi*a0[3]+CosPhi*a2[3];
+}
+
+
+/*!
+ * Apply a rotation about the z axis to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_rotate_z(Lib3dsMatrix m, Lib3dsFloat phi)
+{
+ Lib3dsFloat SinPhi,CosPhi;
+ Lib3dsFloat a0[4],a1[4];
+
+ SinPhi=(Lib3dsFloat)sin(phi);
+ CosPhi=(Lib3dsFloat)cos(phi);
+ memcpy(a0,m[0],4*sizeof(Lib3dsFloat));
+ memcpy(a1,m[1],4*sizeof(Lib3dsFloat));
+ m[0][0]=CosPhi*a0[0]+SinPhi*a1[0];
+ m[0][1]=CosPhi*a0[1]+SinPhi*a1[1];
+ m[0][2]=CosPhi*a0[2]+SinPhi*a1[2];
+ m[0][3]=CosPhi*a0[3]+SinPhi*a1[3];
+ m[1][0]=-SinPhi*a0[0]+CosPhi*a1[0];
+ m[1][1]=-SinPhi*a0[1]+CosPhi*a1[1];
+ m[1][2]=-SinPhi*a0[2]+CosPhi*a1[2];
+ m[1][3]=-SinPhi*a0[3]+CosPhi*a1[3];
+}
+
+
+/*!
+ * Apply a rotation about an arbitrary axis to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_rotate(Lib3dsMatrix m, Lib3dsQuat q)
+{
+ Lib3dsFloat s,xs,ys,zs,wx,wy,wz,xx,xy,xz,yy,yz,zz,l;
+ Lib3dsMatrix R;
+
+ l=q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
+ if (fabs(l)<LIB3DS_EPSILON) {
+ s=1.0f;
+ }
+ else {
+ s=2.0f/l;
+ }
+
+ xs = q[0] * s; ys = q[1] * s; zs = q[2] * s;
+ wx = q[3] * xs; wy = q[3] * ys; wz = q[3] * zs;
+ xx = q[0] * xs; xy = q[0] * ys; xz = q[0] * zs;
+ yy = q[1] * ys; yz = q[1] * zs; zz = q[2] * zs;
+
+ R[0][0]=1.0f - (yy +zz);
+ R[1][0]=xy - wz;
+ R[2][0]=xz + wy;
+ R[0][1]=xy + wz;
+ R[1][1]=1.0f - (xx +zz);
+ R[2][1]=yz - wx;
+ R[0][2]=xz - wy;
+ R[1][2]=yz + wx;
+ R[2][2]=1.0f - (xx + yy);
+ R[3][0]=R[3][1]=R[3][2]=R[0][3]=R[1][3]=R[2][3]=0.0f;
+ R[3][3]=1.0f;
+
+ lib3ds_matrix_mult(m,R);
+}
+
+
+/*!
+ * Apply a rotation about an arbitrary axis to a matrix.
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_rotate_axis(Lib3dsMatrix m, Lib3dsVector axis, Lib3dsFloat angle)
+{
+ Lib3dsQuat q;
+
+ lib3ds_quat_axis_angle(q,axis,angle);
+ lib3ds_matrix_rotate(m,q);
+}
+
+
+/*!
+ * Compute a camera matrix based on position, target and roll.
+ *
+ * Generates a translate/rotate matrix that maps world coordinates
+ * to camera coordinates. Resulting matrix does not include perspective
+ * transform.
+ *
+ * \param matrix Destination matrix.
+ * \param pos Camera position
+ * \param tgt Camera target
+ * \param roll Roll angle
+ *
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_camera(Lib3dsMatrix matrix, Lib3dsVector pos,
+ Lib3dsVector tgt, Lib3dsFloat roll)
+{
+ Lib3dsMatrix M;
+ Lib3dsVector x, y, z;
+
+ lib3ds_vector_sub(y, tgt, pos);
+ lib3ds_vector_normalize(y);
+
+ if (y[0] != 0. || y[1] != 0) {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 1.0;
+ }
+ else { /* Special case: looking straight up or down z axis */
+ z[0] = -1.0;
+ z[1] = 0;
+ z[2] = 0;
+ }
+
+ lib3ds_vector_cross(x, y, z);
+ lib3ds_vector_cross(z, x, y);
+ lib3ds_vector_normalize(x);
+ lib3ds_vector_normalize(z);
+
+ lib3ds_matrix_identity(M);
+ M[0][0] = x[0];
+ M[1][0] = x[1];
+ M[2][0] = x[2];
+ M[0][1] = y[0];
+ M[1][1] = y[1];
+ M[2][1] = y[2];
+ M[0][2] = z[0];
+ M[1][2] = z[1];
+ M[2][2] = z[2];
+
+ lib3ds_matrix_identity(matrix);
+ lib3ds_matrix_rotate_y(matrix, roll);
+ lib3ds_matrix_mult(matrix, M);
+ lib3ds_matrix_translate_xyz(matrix, -pos[0],-pos[1],-pos[2]);
+}
+
+
+/*!
+ * \ingroup matrix
+ */
+void
+lib3ds_matrix_dump(Lib3dsMatrix matrix)
+{
+ int i,j;
+
+ for (i=0; i<4; ++i) {
+ for (j=0; j<4; ++j) {
+ printf("%f ", matrix[j][i]);
+ }
+ printf("\n");
+ }
+}
+
+
+
+
+
diff --git a/3rdparty/lib3ds/matrix.h b/3rdparty/lib3ds/matrix.h
new file mode 100644
index 000000000..756b52d23
--- /dev/null
+++ b/3rdparty/lib3ds/matrix.h
@@ -0,0 +1,63 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_MATRIX_H
+#define INCLUDED_LIB3DS_MATRIX_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: matrix.h,v 1.8 2007/06/18 06:11:32 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern LIB3DSAPI void lib3ds_matrix_zero(Lib3dsMatrix m);
+extern LIB3DSAPI void lib3ds_matrix_identity(Lib3dsMatrix m);
+extern LIB3DSAPI void lib3ds_matrix_copy(Lib3dsMatrix dest, Lib3dsMatrix src);
+extern LIB3DSAPI void lib3ds_matrix_neg(Lib3dsMatrix m);
+extern LIB3DSAPI void lib3ds_matrix_abs(Lib3dsMatrix m);
+extern LIB3DSAPI void lib3ds_matrix_transpose(Lib3dsMatrix m);
+extern LIB3DSAPI void _lib3ds_matrix_add(Lib3dsMatrix m, Lib3dsMatrix a, Lib3dsMatrix b);
+extern LIB3DSAPI void _lib3ds_matrix_sub(Lib3dsMatrix m, Lib3dsMatrix a, Lib3dsMatrix b);
+extern LIB3DSAPI void lib3ds_matrix_mult(Lib3dsMatrix m, Lib3dsMatrix n);
+extern LIB3DSAPI void lib3ds_matrix_scalar(Lib3dsMatrix m, Lib3dsFloat k);
+extern LIB3DSAPI Lib3dsFloat lib3ds_matrix_det(Lib3dsMatrix m);
+extern LIB3DSAPI void lib3ds_matrix_adjoint(Lib3dsMatrix m);
+extern LIB3DSAPI Lib3dsBool lib3ds_matrix_inv(Lib3dsMatrix m);
+extern LIB3DSAPI void lib3ds_matrix_translate_xyz(Lib3dsMatrix m, Lib3dsFloat x, Lib3dsFloat y, Lib3dsFloat z);
+extern LIB3DSAPI void lib3ds_matrix_translate(Lib3dsMatrix m, Lib3dsVector t);
+extern LIB3DSAPI void lib3ds_matrix_scale_xyz(Lib3dsMatrix m, Lib3dsFloat x, Lib3dsFloat y, Lib3dsFloat z);
+extern LIB3DSAPI void lib3ds_matrix_scale(Lib3dsMatrix m, Lib3dsVector s);
+extern LIB3DSAPI void lib3ds_matrix_rotate_x(Lib3dsMatrix m, Lib3dsFloat phi);
+extern LIB3DSAPI void lib3ds_matrix_rotate_y(Lib3dsMatrix m, Lib3dsFloat phi);
+extern LIB3DSAPI void lib3ds_matrix_rotate_z(Lib3dsMatrix m, Lib3dsFloat phi);
+extern LIB3DSAPI void lib3ds_matrix_rotate(Lib3dsMatrix m, Lib3dsQuat q);
+extern LIB3DSAPI void lib3ds_matrix_rotate_axis(Lib3dsMatrix m, Lib3dsVector axis, Lib3dsFloat angle);
+extern LIB3DSAPI void lib3ds_matrix_camera(Lib3dsMatrix matrix, Lib3dsVector pos, Lib3dsVector tgt, Lib3dsFloat roll);
+extern LIB3DSAPI void lib3ds_matrix_dump(Lib3dsMatrix matrix);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/mesh.c b/3rdparty/lib3ds/mesh.c
new file mode 100644
index 000000000..6ff655544
--- /dev/null
+++ b/3rdparty/lib3ds/mesh.c
@@ -0,0 +1,1056 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: mesh.c,v 1.29 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/mesh.h>
+#include <lib3ds/io.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/vector.h>
+#include <lib3ds/matrix.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+
+/*!
+ * \defgroup mesh Meshes
+ */
+
+
+static Lib3dsBool
+face_array_read(Lib3dsMesh *mesh, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ int i;
+ int faces;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_FACE_ARRAY, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_mesh_free_face_list(mesh);
+
+ faces=lib3ds_io_read_word(io);
+ if (faces) {
+ if (!lib3ds_mesh_new_face_list(mesh, faces)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ for (i=0; i<faces; ++i) {
+ strcpy(mesh->faceL[i].material, "");
+ mesh->faceL[i].points[0]=lib3ds_io_read_word(io);
+ mesh->faceL[i].points[1]=lib3ds_io_read_word(io);
+ mesh->faceL[i].points[2]=lib3ds_io_read_word(io);
+ mesh->faceL[i].flags=lib3ds_io_read_word(io);
+ }
+ lib3ds_chunk_read_tell(&c, io);
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_SMOOTH_GROUP:
+ {
+ unsigned i;
+
+ for (i=0; i<mesh->faces; ++i) {
+ mesh->faceL[i].smoothing=lib3ds_io_read_dword(io);
+ }
+ }
+ break;
+ case LIB3DS_MSH_MAT_GROUP:
+ {
+ char name[64];
+ unsigned faces;
+ unsigned i;
+ unsigned index;
+
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ faces=lib3ds_io_read_word(io);
+ for (i=0; i<faces; ++i) {
+ index=lib3ds_io_read_word(io);
+ ASSERT(index<mesh->faces);
+ strcpy(mesh->faceL[index].material, name);
+ }
+ }
+ break;
+ case LIB3DS_MSH_BOXMAP:
+ {
+ char name[64];
+
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ strcpy(mesh->box_map.front, name);
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ strcpy(mesh->box_map.back, name);
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ strcpy(mesh->box_map.left, name);
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ strcpy(mesh->box_map.right, name);
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ strcpy(mesh->box_map.top, name);
+ if (!lib3ds_io_read_string(io, name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ strcpy(mesh->box_map.bottom, name);
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ }
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Create and return a new empty mesh object.
+ *
+ * Mesh is initialized with the name and an identity matrix; all
+ * other fields are zero.
+ *
+ * See Lib3dsFaceFlag for definitions of per-face flags.
+ *
+ * \param name Mesh name. Must not be NULL. Must be < 64 characters.
+ *
+ * \return mesh object or NULL on error.
+ *
+ * \ingroup mesh
+ */
+Lib3dsMesh*
+lib3ds_mesh_new(const char *name)
+{
+ Lib3dsMesh *mesh;
+
+ ASSERT(name);
+ ASSERT(strlen(name)<64);
+
+ mesh=(Lib3dsMesh*)calloc(sizeof(Lib3dsMesh), 1);
+ if (!mesh) {
+ return(0);
+ }
+ strcpy(mesh->name, name);
+ lib3ds_matrix_identity(mesh->matrix);
+ mesh->map_data.maptype=LIB3DS_MAP_NONE;
+ return(mesh);
+}
+
+
+/*!
+ * Free a mesh object and all of its resources.
+ *
+ * \param mesh Mesh object to be freed.
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_free(Lib3dsMesh *mesh)
+{
+ lib3ds_mesh_free_point_list(mesh);
+ lib3ds_mesh_free_flag_list(mesh);
+ lib3ds_mesh_free_texel_list(mesh);
+ lib3ds_mesh_free_face_list(mesh);
+ memset(mesh, 0, sizeof(Lib3dsMesh));
+ free(mesh);
+}
+
+
+/*!
+ * Allocate point list in mesh object.
+ *
+ * This function frees the current point list, if any, and allocates
+ * a new one large enough to hold the specified number of points.
+ *
+ * \param mesh Mesh object for which points are to be allocated.
+ * \param points Number of points in the new point list.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \ingroup mesh
+ */
+Lib3dsBool
+lib3ds_mesh_new_point_list(Lib3dsMesh *mesh, Lib3dsDword points)
+{
+ ASSERT(mesh);
+ if (mesh->pointL) {
+ ASSERT(mesh->points);
+ lib3ds_mesh_free_point_list(mesh);
+ }
+ ASSERT(!mesh->pointL && !mesh->points);
+ mesh->points=0;
+ mesh->pointL=calloc(sizeof(Lib3dsPoint)*points,1);
+ if (!mesh->pointL) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ mesh->points=points;
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Free point list in mesh object.
+ *
+ * The current point list is freed and set to NULL. mesh->points is
+ * set to zero.
+ *
+ * \param mesh Mesh object to be modified.
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_free_point_list(Lib3dsMesh *mesh)
+{
+ ASSERT(mesh);
+ if (mesh->pointL) {
+ ASSERT(mesh->points);
+ free(mesh->pointL);
+ mesh->pointL=0;
+ mesh->points=0;
+ }
+ else {
+ ASSERT(!mesh->points);
+ }
+}
+
+
+/*!
+ * Allocate flag list in mesh object.
+ *
+ * This function frees the current flag list, if any, and allocates
+ * a new one large enough to hold the specified number of flags.
+ * All flags are initialized to 0
+ *
+ * \param mesh Mesh object for which points are to be allocated.
+ * \param flags Number of flags in the new flag list.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \ingroup mesh
+ */
+Lib3dsBool
+lib3ds_mesh_new_flag_list(Lib3dsMesh *mesh, Lib3dsDword flags)
+{
+ ASSERT(mesh);
+ if (mesh->flagL) {
+ ASSERT(mesh->flags);
+ lib3ds_mesh_free_flag_list(mesh);
+ }
+ ASSERT(!mesh->flagL && !mesh->flags);
+ mesh->flags=0;
+ mesh->flagL=calloc(sizeof(Lib3dsWord)*flags,1);
+ if (!mesh->flagL) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ mesh->flags=flags;
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Free flag list in mesh object.
+ *
+ * The current flag list is freed and set to NULL. mesh->flags is
+ * set to zero.
+ *
+ * \param mesh Mesh object to be modified.
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_free_flag_list(Lib3dsMesh *mesh)
+{
+ ASSERT(mesh);
+ if (mesh->flagL) {
+ ASSERT(mesh->flags);
+ free(mesh->flagL);
+ mesh->flagL=0;
+ mesh->flags=0;
+ }
+ else {
+ ASSERT(!mesh->flags);
+ }
+}
+
+
+/*!
+ * Allocate texel list in mesh object.
+ *
+ * This function frees the current texel list, if any, and allocates
+ * a new one large enough to hold the specified number of texels.
+ *
+ * \param mesh Mesh object for which points are to be allocated.
+ * \param texels Number of texels in the new texel list.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \ingroup mesh
+ */
+Lib3dsBool
+lib3ds_mesh_new_texel_list(Lib3dsMesh *mesh, Lib3dsDword texels)
+{
+ ASSERT(mesh);
+ if (mesh->texelL) {
+ ASSERT(mesh->texels);
+ lib3ds_mesh_free_texel_list(mesh);
+ }
+ ASSERT(!mesh->texelL && !mesh->texels);
+ mesh->texels=0;
+ mesh->texelL=calloc(sizeof(Lib3dsTexel)*texels,1);
+ if (!mesh->texelL) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ mesh->texels=texels;
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Free texel list in mesh object.
+ *
+ * The current texel list is freed and set to NULL. mesh->texels is
+ * set to zero.
+ *
+ * \param mesh Mesh object to be modified.
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_free_texel_list(Lib3dsMesh *mesh)
+{
+ ASSERT(mesh);
+ if (mesh->texelL) {
+ ASSERT(mesh->texels);
+ free(mesh->texelL);
+ mesh->texelL=0;
+ mesh->texels=0;
+ }
+ else {
+ ASSERT(!mesh->texels);
+ }
+}
+
+
+/*!
+ * Allocate face list in mesh object.
+ *
+ * This function frees the current face list, if any, and allocates
+ * a new one large enough to hold the specified number of faces.
+ *
+ * \param mesh Mesh object for which points are to be allocated.
+ * \param faces Number of faces in the new face list.
+ *
+ * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
+ *
+ * \ingroup mesh
+ */
+Lib3dsBool
+lib3ds_mesh_new_face_list(Lib3dsMesh *mesh, Lib3dsDword faces)
+{
+ ASSERT(mesh);
+ if (mesh->faceL) {
+ ASSERT(mesh->faces);
+ lib3ds_mesh_free_face_list(mesh);
+ }
+ ASSERT(!mesh->faceL && !mesh->faces);
+ mesh->faces=0;
+ mesh->faceL=calloc(sizeof(Lib3dsFace)*faces,1);
+ if (!mesh->faceL) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ mesh->faces=faces;
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Free face list in mesh object.
+ *
+ * The current face list is freed and set to NULL. mesh->faces is
+ * set to zero.
+ *
+ * \param mesh Mesh object to be modified.
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_free_face_list(Lib3dsMesh *mesh)
+{
+ ASSERT(mesh);
+ if (mesh->faceL) {
+ ASSERT(mesh->faces);
+ free(mesh->faceL);
+ mesh->faceL=0;
+ mesh->faces=0;
+ }
+ else {
+ ASSERT(!mesh->faces);
+ }
+}
+
+
+/*!
+ * Find the bounding box of a mesh object.
+ *
+ * \param mesh The mesh object
+ * \param bmin Returned bounding box
+ * \param bmax Returned bounding box
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_bounding_box(Lib3dsMesh *mesh, Lib3dsVector bmin, Lib3dsVector bmax)
+{
+ unsigned i;
+ bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
+ bmax[0] = bmax[1] = bmax[2] = FLT_MIN;
+
+ for (i=0; i<mesh->points; ++i) {
+ lib3ds_vector_min(bmin, mesh->pointL[i].pos);
+ lib3ds_vector_max(bmax, mesh->pointL[i].pos);
+ }
+}
+
+
+typedef struct _Lib3dsFaces Lib3dsFaces;
+
+struct _Lib3dsFaces {
+ Lib3dsFaces *next;
+ Lib3dsFace *face;
+};
+
+
+/*!
+ * Calculates the vertex normals corresponding to the smoothing group
+ * settings for each face of a mesh.
+ *
+ * \param mesh A pointer to the mesh to calculate the normals for.
+ * \param normalL A pointer to a buffer to store the calculated
+ * normals. The buffer must have the size:
+ * 3*sizeof(Lib3dsVector)*mesh->faces.
+ *
+ * To allocate the normal buffer do for example the following:
+ * \code
+ * Lib3dsVector *normalL = malloc(3*sizeof(Lib3dsVector)*mesh->faces);
+ * \endcode
+ *
+ * To access the normal of the i-th vertex of the j-th face do the
+ * following:
+ * \code
+ * normalL[3*j+i]
+ * \endcode
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_calculate_normals(Lib3dsMesh *mesh, Lib3dsVector *normalL)
+{
+ Lib3dsFaces **fl;
+ Lib3dsFaces *fa;
+ unsigned i,j,k;
+
+ if (!mesh->faces) {
+ return;
+ }
+
+ fl=calloc(sizeof(Lib3dsFaces*),mesh->points);
+ ASSERT(fl);
+ fa=calloc(sizeof(Lib3dsFaces),3*mesh->faces);
+ ASSERT(fa);
+ k=0;
+ for (i=0; i<mesh->faces; ++i) {
+ Lib3dsFace *f=&mesh->faceL[i];
+ for (j=0; j<3; ++j) {
+ Lib3dsFaces* l=&fa[k++];
+ ASSERT(f->points[j]<mesh->points);
+ l->face=f;
+ l->next=fl[f->points[j]];
+ fl[f->points[j]]=l;
+ }
+ }
+
+ for (i=0; i<mesh->faces; ++i) {
+ Lib3dsFace *f=&mesh->faceL[i];
+ for (j=0; j<3; ++j) {
+ // FIXME: static array needs at least check!!
+ Lib3dsVector n,N[128];
+ Lib3dsFaces *p;
+ int k,l;
+ int found;
+
+ ASSERT(f->points[j]<mesh->points);
+
+ if (f->smoothing) {
+ lib3ds_vector_zero(n);
+ k=0;
+ for (p=fl[f->points[j]]; p; p=p->next) {
+ found=0;
+ for (l=0; l<k; ++l) {
+ if ( l >= 128 )
+ printf("array N overflow: i=%d, j=%d, k=%d\n", i,j,k);
+ if (fabs(lib3ds_vector_dot(N[l], p->face->normal)-1.0)<1e-5) {
+ found=1;
+ break;
+ }
+ }
+ if (!found) {
+ if (f->smoothing & p->face->smoothing) {
+ lib3ds_vector_add(n,n, p->face->normal);
+ lib3ds_vector_copy(N[k], p->face->normal);
+ ++k;
+ }
+ }
+ }
+ }
+ else {
+ lib3ds_vector_copy(n, f->normal);
+ }
+ lib3ds_vector_normalize(n);
+
+ lib3ds_vector_copy(normalL[3*i+j], n);
+ }
+ }
+
+ free(fa);
+ free(fl);
+}
+
+
+/*!
+ * This function prints data associated with the specified mesh such as
+ * vertex and point lists.
+ *
+ * \param mesh Points to a mesh that you wish to view the data for.
+ *
+ * \return None
+ *
+ * \warning WIN32: Should only be used in a console window not in a GUI.
+ *
+ * \ingroup mesh
+ */
+void
+lib3ds_mesh_dump(Lib3dsMesh *mesh)
+{
+ unsigned i;
+ Lib3dsVector p;
+
+ ASSERT(mesh);
+ printf(" %s vertices=%ld faces=%ld\n",
+ mesh->name,
+ (long)(mesh->points),
+ (long)(mesh->faces)
+ );
+ printf(" matrix:\n");
+ lib3ds_matrix_dump(mesh->matrix);
+ printf(" point list:\n");
+ for (i=0; i<mesh->points; ++i) {
+ lib3ds_vector_copy(p, mesh->pointL[i].pos);
+ printf (" %8f %8f %8f\n", p[0], p[1], p[2]);
+ }
+ printf(" facelist:\n");
+ for (i=0; i<mesh->faces; ++i) {
+ printf (" %4d %4d %4d smoothing:%X flags:%X material:\"%s\"\n",
+ mesh->faceL[i].points[0],
+ mesh->faceL[i].points[1],
+ mesh->faceL[i].points[2],
+ (unsigned)mesh->faceL[i].smoothing,
+ mesh->faceL[i].flags,
+ mesh->faceL[i].material
+ );
+ }
+}
+
+
+/*!
+ * \ingroup mesh
+ */
+Lib3dsBool
+lib3ds_mesh_read(Lib3dsMesh *mesh, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, LIB3DS_N_TRI_OBJECT, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_MESH_MATRIX:
+ {
+ int i,j;
+
+ lib3ds_matrix_identity(mesh->matrix);
+ for (i=0; i<4; i++) {
+ for (j=0; j<3; j++) {
+ mesh->matrix[i][j]=lib3ds_io_read_float(io);
+ }
+ }
+ }
+ break;
+ case LIB3DS_MESH_COLOR:
+ {
+ mesh->color=lib3ds_io_read_byte(io);
+ }
+ break;
+ case LIB3DS_POINT_ARRAY:
+ {
+ unsigned i,j;
+ unsigned points;
+
+ lib3ds_mesh_free_point_list(mesh);
+ points=lib3ds_io_read_word(io);
+ if (points) {
+ if (!lib3ds_mesh_new_point_list(mesh, points)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ for (i=0; i<mesh->points; ++i) {
+ for (j=0; j<3; ++j) {
+ mesh->pointL[i].pos[j]=lib3ds_io_read_float(io);
+ }
+ }
+ ASSERT((!mesh->flags) || (mesh->points==mesh->flags));
+ ASSERT((!mesh->texels) || (mesh->points==mesh->texels));
+ }
+ }
+ break;
+ case LIB3DS_POINT_FLAG_ARRAY:
+ {
+ unsigned i;
+ unsigned flags;
+
+ lib3ds_mesh_free_flag_list(mesh);
+ flags=lib3ds_io_read_word(io);
+ if (flags) {
+ if (!lib3ds_mesh_new_flag_list(mesh, flags)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ for (i=0; i<mesh->flags; ++i) {
+ mesh->flagL[i]=lib3ds_io_read_word(io);
+ }
+ ASSERT((!mesh->points) || (mesh->flags==mesh->points));
+ ASSERT((!mesh->texels) || (mesh->flags==mesh->texels));
+ }
+ }
+ break;
+ case LIB3DS_FACE_ARRAY:
+ {
+ lib3ds_chunk_read_reset(&c, io);
+ if (!face_array_read(mesh, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_MESH_TEXTURE_INFO:
+ {
+ int i,j;
+
+ for (i=0; i<2; ++i) {
+ mesh->map_data.tile[i]=lib3ds_io_read_float(io);
+ }
+ for (i=0; i<3; ++i) {
+ mesh->map_data.pos[i]=lib3ds_io_read_float(io);
+ }
+ mesh->map_data.scale=lib3ds_io_read_float(io);
+
+ lib3ds_matrix_identity(mesh->map_data.matrix);
+ for (i=0; i<4; i++) {
+ for (j=0; j<3; j++) {
+ mesh->map_data.matrix[i][j]=lib3ds_io_read_float(io);
+ }
+ }
+ for (i=0; i<2; ++i) {
+ mesh->map_data.planar_size[i]=lib3ds_io_read_float(io);
+ }
+ mesh->map_data.cylinder_height=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_TEX_VERTS:
+ {
+ unsigned i;
+ unsigned texels;
+
+ lib3ds_mesh_free_texel_list(mesh);
+ texels=lib3ds_io_read_word(io);
+ if (texels) {
+ if (!lib3ds_mesh_new_texel_list(mesh, texels)) {
+ LIB3DS_ERROR_LOG;
+ return(LIB3DS_FALSE);
+ }
+ for (i=0; i<mesh->texels; ++i) {
+ mesh->texelL[i][0]=lib3ds_io_read_float(io);
+ mesh->texelL[i][1]=lib3ds_io_read_float(io);
+ }
+ ASSERT((!mesh->points) || (mesh->texels==mesh->points));
+ ASSERT((!mesh->flags) || (mesh->texels==mesh->flags));
+ }
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ {
+ unsigned j;
+
+ for (j=0; j<mesh->faces; ++j) {
+ ASSERT(mesh->faceL[j].points[0]<mesh->points);
+ ASSERT(mesh->faceL[j].points[1]<mesh->points);
+ ASSERT(mesh->faceL[j].points[2]<mesh->points);
+ lib3ds_vector_normal(
+ mesh->faceL[j].normal,
+ mesh->pointL[mesh->faceL[j].points[0]].pos,
+ mesh->pointL[mesh->faceL[j].points[1]].pos,
+ mesh->pointL[mesh->faceL[j].points[2]].pos
+ );
+ }
+ }
+
+ if (lib3ds_matrix_det(mesh->matrix) < 0.0)
+ {
+ /* Flip X coordinate of vertices if mesh matrix
+ has negative determinant */
+ Lib3dsMatrix inv_matrix, M;
+ Lib3dsVector tmp;
+ unsigned i;
+
+ lib3ds_matrix_copy(inv_matrix, mesh->matrix);
+ lib3ds_matrix_inv(inv_matrix);
+
+ lib3ds_matrix_copy(M, mesh->matrix);
+ lib3ds_matrix_scale_xyz(M, -1.0f, 1.0f, 1.0f);
+ lib3ds_matrix_mult(M, inv_matrix);
+
+ for (i=0; i<mesh->points; ++i) {
+ lib3ds_vector_transform(tmp, M, mesh->pointL[i].pos);
+ lib3ds_vector_copy(mesh->pointL[i].pos, tmp);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+point_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ unsigned i;
+
+ if (!mesh->points || !mesh->pointL) {
+ return(LIB3DS_TRUE);
+ }
+ ASSERT(mesh->points<0x10000);
+ c.chunk=LIB3DS_POINT_ARRAY;
+ c.size=8+12*mesh->points;
+ lib3ds_chunk_write(&c, io);
+
+ lib3ds_io_write_word(io, (Lib3dsWord)mesh->points);
+
+ if (lib3ds_matrix_det(mesh->matrix) >= 0.0f) {
+ for (i=0; i<mesh->points; ++i) {
+ lib3ds_io_write_vector(io, mesh->pointL[i].pos);
+ }
+ }
+ else {
+ /* Flip X coordinate of vertices if mesh matrix
+ has negative determinant */
+ Lib3dsMatrix inv_matrix, M;
+ Lib3dsVector tmp;
+
+ lib3ds_matrix_copy(inv_matrix, mesh->matrix);
+ lib3ds_matrix_inv(inv_matrix);
+ lib3ds_matrix_copy(M, mesh->matrix);
+ lib3ds_matrix_scale_xyz(M, -1.0f, 1.0f, 1.0f);
+ lib3ds_matrix_mult(M, inv_matrix);
+
+ for (i=0; i<mesh->points; ++i) {
+ lib3ds_vector_transform(tmp, M, mesh->pointL[i].pos);
+ lib3ds_io_write_vector(io, tmp);
+ }
+ }
+
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+flag_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ unsigned i;
+
+ if (!mesh->flags || !mesh->flagL) {
+ return(LIB3DS_TRUE);
+ }
+ ASSERT(mesh->flags<0x10000);
+ c.chunk=LIB3DS_POINT_FLAG_ARRAY;
+ c.size=8+2*mesh->flags;
+ lib3ds_chunk_write(&c, io);
+
+ lib3ds_io_write_word(io, (Lib3dsWord)mesh->flags);
+ for (i=0; i<mesh->flags; ++i) {
+ lib3ds_io_write_word(io, mesh->flagL[i]);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+face_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ if (!mesh->faces || !mesh->faceL) {
+ return(LIB3DS_TRUE);
+ }
+ ASSERT(mesh->faces<0x10000);
+ c.chunk=LIB3DS_FACE_ARRAY;
+ if (!lib3ds_chunk_write_start(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+ {
+ unsigned i;
+
+ lib3ds_io_write_word(io, (Lib3dsWord)mesh->faces);
+ for (i=0; i<mesh->faces; ++i) {
+ lib3ds_io_write_word(io, mesh->faceL[i].points[0]);
+ lib3ds_io_write_word(io, mesh->faceL[i].points[1]);
+ lib3ds_io_write_word(io, mesh->faceL[i].points[2]);
+ lib3ds_io_write_word(io, mesh->faceL[i].flags);
+ }
+ }
+
+ { /*---- MSH_MAT_GROUP ----*/
+ Lib3dsChunk c;
+ unsigned i,j;
+ Lib3dsWord num;
+ char *matf=calloc(sizeof(char), mesh->faces);
+ if (!matf) {
+ return(LIB3DS_FALSE);
+ }
+
+ for (i=0; i<mesh->faces; ++i) {
+ if (!matf[i] && strlen(mesh->faceL[i].material)) {
+ matf[i]=1;
+ num=1;
+
+ for (j=i+1; j<mesh->faces; ++j) {
+ if (strcmp(mesh->faceL[i].material, mesh->faceL[j].material)==0) ++num;
+ }
+
+ c.chunk=LIB3DS_MSH_MAT_GROUP;
+ c.size=6+ (Lib3dsDword)strlen(mesh->faceL[i].material)+1 +2+2*num;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write_string(io, mesh->faceL[i].material);
+ lib3ds_io_write_word(io, num);
+ lib3ds_io_write_word(io, (Lib3dsWord)i);
+
+ for (j=i+1; j<mesh->faces; ++j) {
+ if (strcmp(mesh->faceL[i].material, mesh->faceL[j].material)==0) {
+ lib3ds_io_write_word(io, (Lib3dsWord)j);
+ matf[j]=1;
+ }
+ }
+ }
+ }
+ free(matf);
+ }
+
+ { /*---- SMOOTH_GROUP ----*/
+ Lib3dsChunk c;
+ unsigned i;
+
+ c.chunk=LIB3DS_SMOOTH_GROUP;
+ c.size=6+4*mesh->faces;
+ lib3ds_chunk_write(&c, io);
+
+ for (i=0; i<mesh->faces; ++i) {
+ lib3ds_io_write_dword(io, mesh->faceL[i].smoothing);
+ }
+ }
+
+ { /*---- MSH_BOXMAP ----*/
+ Lib3dsChunk c;
+
+ if (strlen(mesh->box_map.front) ||
+ strlen(mesh->box_map.back) ||
+ strlen(mesh->box_map.left) ||
+ strlen(mesh->box_map.right) ||
+ strlen(mesh->box_map.top) ||
+ strlen(mesh->box_map.bottom)) {
+
+ c.chunk=LIB3DS_MSH_BOXMAP;
+ if (!lib3ds_chunk_write_start(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ lib3ds_io_write_string(io, mesh->box_map.front);
+ lib3ds_io_write_string(io, mesh->box_map.back);
+ lib3ds_io_write_string(io, mesh->box_map.left);
+ lib3ds_io_write_string(io, mesh->box_map.right);
+ lib3ds_io_write_string(io, mesh->box_map.top);
+ lib3ds_io_write_string(io, mesh->box_map.bottom);
+
+ if (!lib3ds_chunk_write_end(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ }
+
+ if (!lib3ds_chunk_write_end(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+static Lib3dsBool
+texel_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ unsigned i;
+
+ if (!mesh->texels || !mesh->texelL) {
+ return(LIB3DS_TRUE);
+ }
+ ASSERT(mesh->texels<0x10000);
+ c.chunk=LIB3DS_TEX_VERTS;
+ c.size=8+8*mesh->texels;
+ lib3ds_chunk_write(&c, io);
+
+ lib3ds_io_write_word(io, (Lib3dsWord)mesh->texels);
+ for (i=0; i<mesh->texels; ++i) {
+ lib3ds_io_write_float(io, mesh->texelL[i][0]);
+ lib3ds_io_write_float(io, mesh->texelL[i][1]);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup mesh
+ */
+Lib3dsBool
+lib3ds_mesh_write(Lib3dsMesh *mesh, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_N_TRI_OBJECT;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!point_array_write(mesh, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!texel_array_write(mesh, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ if (mesh->map_data.maptype!=LIB3DS_MAP_NONE) { /*---- LIB3DS_MESH_TEXTURE_INFO ----*/
+ Lib3dsChunk c;
+ int i,j;
+
+ c.chunk=LIB3DS_MESH_TEXTURE_INFO;
+ c.size=92;
+ if (!lib3ds_chunk_write(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ lib3ds_io_write_word(io, mesh->map_data.maptype);
+
+ for (i=0; i<2; ++i) {
+ lib3ds_io_write_float(io, mesh->map_data.tile[i]);
+ }
+ for (i=0; i<3; ++i) {
+ lib3ds_io_write_float(io, mesh->map_data.pos[i]);
+ }
+ lib3ds_io_write_float(io, mesh->map_data.scale);
+
+ for (i=0; i<4; i++) {
+ for (j=0; j<3; j++) {
+ lib3ds_io_write_float(io, mesh->map_data.matrix[i][j]);
+ }
+ }
+ for (i=0; i<2; ++i) {
+ lib3ds_io_write_float(io, mesh->map_data.planar_size[i]);
+ }
+ lib3ds_io_write_float(io, mesh->map_data.cylinder_height);
+ }
+
+ if (!flag_array_write(mesh, io)) {
+ return(LIB3DS_FALSE);
+ }
+ { /*---- LIB3DS_MESH_MATRIX ----*/
+ Lib3dsChunk c;
+ int i,j;
+
+ c.chunk=LIB3DS_MESH_MATRIX;
+ c.size=54;
+ if (!lib3ds_chunk_write(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ for (i=0; i<4; i++) {
+ for (j=0; j<3; j++) {
+ lib3ds_io_write_float(io, mesh->matrix[i][j]);
+ }
+ }
+ }
+
+ if (mesh->color) { /*---- LIB3DS_MESH_COLOR ----*/
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_MESH_COLOR;
+ c.size=7;
+ if (!lib3ds_chunk_write(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_byte(io, mesh->color);
+ }
+ if (!face_array_write(mesh, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
diff --git a/3rdparty/lib3ds/mesh.h b/3rdparty/lib3ds/mesh.h
new file mode 100644
index 000000000..66282e267
--- /dev/null
+++ b/3rdparty/lib3ds/mesh.h
@@ -0,0 +1,157 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_MESH_H
+#define INCLUDED_LIB3DS_MESH_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: mesh.h,v 1.20 2007/06/20 17:04:08 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Triangular mesh point
+ * \ingroup mesh
+ */
+typedef struct Lib3dsPoint {
+ Lib3dsVector pos;
+} Lib3dsPoint;
+
+/**
+ * Triangular mesh face
+ * \ingroup mesh
+ * \sa Lib3dsFaceFlag
+ */
+struct Lib3dsFace {
+ Lib3dsUserData user; /*! Arbitrary user data */
+ char material[64]; /*! Material name */
+ Lib3dsWord points[3]; /*! Indices into mesh points list */
+ Lib3dsWord flags; /*! See Lib3dsFaceFlag, below */
+ Lib3dsDword smoothing; /*! Bitmask; each bit identifies a group */
+ Lib3dsVector normal;
+};
+
+
+/**
+ * Vertex flags
+ * Meaning of _Lib3dsFace::flags. ABC are points of the current face
+ * (A: is 1st vertex, B is 2nd vertex, C is 3rd vertex)
+ */
+typedef enum {
+ LIB3DS_FACE_FLAG_VIS_AC = 0x1, /*!< Bit 0: Edge visibility AC */
+ LIB3DS_FACE_FLAG_VIS_BC = 0x2, /*!< Bit 1: Edge visibility BC */
+ LIB3DS_FACE_FLAG_VIS_AB = 0x4, /*!< Bit 2: Edge visibility AB */
+ LIB3DS_FACE_FLAG_WRAP_U = 0x8, /*!< Bit 3: Face is at tex U wrap seam */
+ LIB3DS_FACE_FLAG_WRAP_V = 0x10, /*!< Bit 4: Face is at tex V wrap seam */
+ LIB3DS_FACE_FLAG_UNK7 = 0x80, /* Bit 5-8: Unused ? */
+ LIB3DS_FACE_FLAG_UNK10 = 0x400, /* Bit 9-10: Random ? */
+ /* Bit 11-12: Unused ? */
+ LIB3DS_FACE_FLAG_SELECT_3 = (1<<13), /*!< Bit 13: Selection of the face in selection 3*/
+ LIB3DS_FACE_FLAG_SELECT_2 = (1<<14), /*!< Bit 14: Selection of the face in selection 2*/
+ LIB3DS_FACE_FLAG_SELECT_1 = (1<<15), /*!< Bit 15: Selection of the face in selection 1*/
+} Lib3dsFaceFlag;
+
+/**
+ * Triangular mesh box mapping settings
+ * \ingroup mesh
+ */
+struct Lib3dsBoxMap {
+ char front[64];
+ char back[64];
+ char left[64];
+ char right[64];
+ char top[64];
+ char bottom[64];
+};
+
+/**
+ * Texture projection type
+ * \ingroup tracks
+ */
+typedef enum {
+ LIB3DS_MAP_NONE =0xFFFF,
+ LIB3DS_MAP_PLANAR =0,
+ LIB3DS_MAP_CYLINDRICAL =1,
+ LIB3DS_MAP_SPHERICAL =2
+} Lib3dsMapType;
+
+/**
+ * Triangular mesh texture mapping data
+ * \ingroup mesh
+ */
+struct Lib3dsMapData {
+ Lib3dsWord maptype;
+ Lib3dsVector pos;
+ Lib3dsMatrix matrix;
+ Lib3dsFloat scale;
+ Lib3dsFloat tile[2];
+ Lib3dsFloat planar_size[2];
+ Lib3dsFloat cylinder_height;
+};
+
+/**
+ * Triangular mesh object
+ * \ingroup mesh
+ */
+struct Lib3dsMesh {
+ Lib3dsUserData user; /*< Arbitrary user data */
+ Lib3dsMesh *next;
+ char name[64]; /*< Mesh name. Don't use more than 8 characters */
+ Lib3dsDword object_flags; /*< @see Lib3dsObjectFlags */
+ Lib3dsByte color;
+ Lib3dsMatrix matrix; /*< Transformation matrix for mesh data */
+ Lib3dsDword points; /*< Number of points in point list */
+ Lib3dsPoint *pointL; /*< Point list */
+ Lib3dsDword flags; /*< Number of flags in per-point flags list */
+ Lib3dsWord *flagL; /*< Per-point flags list */
+ Lib3dsDword texels; /*< Number of U-V texture coordinates */
+ Lib3dsTexel *texelL; /*< U-V texture coordinates */
+ Lib3dsDword faces; /*< Number of faces in face list */
+ Lib3dsFace *faceL; /*< Face list */
+ Lib3dsBoxMap box_map;
+ Lib3dsMapData map_data;
+};
+
+extern LIB3DSAPI Lib3dsMesh* lib3ds_mesh_new(const char *name);
+extern LIB3DSAPI void lib3ds_mesh_free(Lib3dsMesh *mesh);
+extern LIB3DSAPI Lib3dsBool lib3ds_mesh_new_point_list(Lib3dsMesh *mesh, Lib3dsDword points);
+extern LIB3DSAPI void lib3ds_mesh_free_point_list(Lib3dsMesh *mesh);
+extern LIB3DSAPI Lib3dsBool lib3ds_mesh_new_flag_list(Lib3dsMesh *mesh, Lib3dsDword flags);
+extern LIB3DSAPI void lib3ds_mesh_free_flag_list(Lib3dsMesh *mesh);
+extern LIB3DSAPI Lib3dsBool lib3ds_mesh_new_texel_list(Lib3dsMesh *mesh, Lib3dsDword texels);
+extern LIB3DSAPI void lib3ds_mesh_free_texel_list(Lib3dsMesh *mesh);
+extern LIB3DSAPI Lib3dsBool lib3ds_mesh_new_face_list(Lib3dsMesh *mesh, Lib3dsDword flags);
+extern LIB3DSAPI void lib3ds_mesh_free_face_list(Lib3dsMesh *mesh);
+extern LIB3DSAPI void lib3ds_mesh_bounding_box(Lib3dsMesh *mesh, Lib3dsVector bmin, Lib3dsVector bmax);
+extern LIB3DSAPI void lib3ds_mesh_calculate_normals(Lib3dsMesh *mesh, Lib3dsVector *normalL);
+extern LIB3DSAPI void lib3ds_mesh_dump(Lib3dsMesh *mesh);
+extern LIB3DSAPI Lib3dsBool lib3ds_mesh_read(Lib3dsMesh *mesh, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_mesh_write(Lib3dsMesh *mesh, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/node.c b/3rdparty/lib3ds/node.c
new file mode 100644
index 000000000..58f8a3971
--- /dev/null
+++ b/3rdparty/lib3ds/node.c
@@ -0,0 +1,1089 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: node.c,v 1.20 2007/06/20 17:04:08 jeh Exp $
+ */
+#include <lib3ds/node.h>
+#include <lib3ds/file.h>
+#include <lib3ds/io.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/matrix.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup node Animation Nodes
+ */
+
+
+/*!
+ * Create and return a new ambient node.
+ *
+ * The node is returned with an identity matrix. All other fields
+ * are zero.
+ *
+ * \return Lib3dsNode
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_new_ambient()
+{
+ Lib3dsNode *node=(Lib3dsNode*)calloc(sizeof(Lib3dsNode), 1);
+ node->type=LIB3DS_AMBIENT_NODE;
+ lib3ds_matrix_identity(node->matrix);
+ return(node);
+}
+
+
+/*!
+ * Create and return a new object node.
+ *
+ * The node is returned with an identity matrix. All other fields
+ * are zero.
+ *
+ * \return Lib3dsNode
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_new_object()
+{
+ Lib3dsNode *node=(Lib3dsNode*)calloc(sizeof(Lib3dsNode), 1);
+ node->type=LIB3DS_OBJECT_NODE;
+ lib3ds_matrix_identity(node->matrix);
+ return(node);
+}
+
+
+/*!
+ * Create and return a new camera node.
+ *
+ * The node is returned with an identity matrix. All other fields
+ * are zero.
+ *
+ * \return Lib3dsNode
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_new_camera()
+{
+ Lib3dsNode *node=(Lib3dsNode*)calloc(sizeof(Lib3dsNode), 1);
+ node->type=LIB3DS_CAMERA_NODE;
+ lib3ds_matrix_identity(node->matrix);
+ return(node);
+}
+
+
+/*!
+ * Create and return a new target node.
+ *
+ * The node is returned with an identity matrix. All other fields
+ * are zero.
+ *
+ * \return Lib3dsNode
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_new_target()
+{
+ Lib3dsNode *node=(Lib3dsNode*)calloc(sizeof(Lib3dsNode), 1);
+ node->type=LIB3DS_TARGET_NODE;
+ lib3ds_matrix_identity(node->matrix);
+ return(node);
+}
+
+
+/*!
+ * Create and return a new light node.
+ *
+ * The node is returned with an identity matrix. All other fields
+ * are zero.
+ *
+ * \return Lib3dsNode
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_new_light()
+{
+ Lib3dsNode *node=(Lib3dsNode*)calloc(sizeof(Lib3dsNode), 1);
+ node->type=LIB3DS_LIGHT_NODE;
+ lib3ds_matrix_identity(node->matrix);
+ return(node);
+}
+
+
+/*!
+ * Create and return a new spot node.
+ *
+ * The node is returned with an identity matrix. All other fields
+ * are zero.
+ *
+ * \return Lib3dsNode
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_new_spot()
+{
+ Lib3dsNode *node=(Lib3dsNode*)calloc(sizeof(Lib3dsNode), 1);
+ node->type=LIB3DS_SPOT_NODE;
+ lib3ds_matrix_identity(node->matrix);
+ return(node);
+}
+
+
+static void
+free_node_and_childs(Lib3dsNode *node)
+{
+ ASSERT(node);
+ switch (node->type) {
+ case LIB3DS_UNKNOWN_NODE:
+ break;
+ case LIB3DS_AMBIENT_NODE:
+ {
+ Lib3dsAmbientData *n=&node->data.ambient;
+ lib3ds_lin3_track_free_keys(&n->col_track);
+ }
+ break;
+ case LIB3DS_OBJECT_NODE:
+ {
+ Lib3dsObjectData *n=&node->data.object;
+
+ lib3ds_lin3_track_free_keys(&n->pos_track);
+ lib3ds_quat_track_free_keys(&n->rot_track);
+ lib3ds_lin3_track_free_keys(&n->scl_track);
+ lib3ds_bool_track_free_keys(&n->hide_track);
+ lib3ds_morph_track_free_keys(&n->morph_track);
+ }
+ break;
+ case LIB3DS_CAMERA_NODE:
+ {
+ Lib3dsCameraData *n=&node->data.camera;
+ lib3ds_lin3_track_free_keys(&n->pos_track);
+ lib3ds_lin1_track_free_keys(&n->fov_track);
+ lib3ds_lin1_track_free_keys(&n->roll_track);
+ }
+ break;
+ case LIB3DS_TARGET_NODE:
+ {
+ Lib3dsTargetData *n=&node->data.target;
+ lib3ds_lin3_track_free_keys(&n->pos_track);
+ }
+ break;
+ case LIB3DS_LIGHT_NODE:
+ {
+ Lib3dsLightData *n=&node->data.light;
+ lib3ds_lin3_track_free_keys(&n->pos_track);
+ lib3ds_lin3_track_free_keys(&n->col_track);
+ lib3ds_lin1_track_free_keys(&n->hotspot_track);
+ lib3ds_lin1_track_free_keys(&n->falloff_track);
+ lib3ds_lin1_track_free_keys(&n->roll_track);
+ }
+ break;
+ case LIB3DS_SPOT_NODE:
+ {
+ Lib3dsSpotData *n=&node->data.spot;
+ lib3ds_lin3_track_free_keys(&n->pos_track);
+ }
+ break;
+ }
+ {
+ Lib3dsNode *p,*q;
+ for (p=node->childs; p; p=q) {
+ q=p->next;
+ free_node_and_childs(p);
+ }
+ }
+ node->type=LIB3DS_UNKNOWN_NODE;
+ free(node);
+}
+
+
+/*!
+ * Free a node and all of its resources.
+ *
+ * \param node Lib3dsNode object to be freed.
+ *
+ * \ingroup node
+ */
+void
+lib3ds_node_free(Lib3dsNode *node)
+{
+ ASSERT(node);
+ free_node_and_childs(node);
+}
+
+
+/*!
+ * Evaluate an animation node.
+ *
+ * Recursively sets node and its children to their appropriate values
+ * for this point in the animation.
+ *
+ * \param node Node to be evaluated.
+ * \param t time value, between 0. and file->frames
+ *
+ * \ingroup node
+ */
+void
+lib3ds_node_eval(Lib3dsNode *node, Lib3dsFloat t)
+{
+ ASSERT(node);
+ switch (node->type) {
+ case LIB3DS_UNKNOWN_NODE:
+ {
+ ASSERT(LIB3DS_FALSE);
+ }
+ break;
+ case LIB3DS_AMBIENT_NODE:
+ {
+ Lib3dsAmbientData *n=&node->data.ambient;
+ if (node->parent) {
+ lib3ds_matrix_copy(node->matrix, node->parent->matrix);
+ }
+ else {
+ lib3ds_matrix_identity(node->matrix);
+ }
+ lib3ds_lin3_track_eval(&n->col_track, n->col, t);
+ }
+ break;
+ case LIB3DS_OBJECT_NODE:
+ {
+ Lib3dsMatrix M;
+ Lib3dsObjectData *n=&node->data.object;
+
+ lib3ds_lin3_track_eval(&n->pos_track, n->pos, t);
+ lib3ds_quat_track_eval(&n->rot_track, n->rot, t);
+ if (n->scl_track.keyL) {
+ lib3ds_lin3_track_eval(&n->scl_track, n->scl, t);
+ }
+ else {
+ n->scl[0] = n->scl[1] = n->scl[2] = 1.0f;
+ }
+ lib3ds_bool_track_eval(&n->hide_track, &n->hide, t);
+ lib3ds_morph_track_eval(&n->morph_track, n->morph, t);
+
+ lib3ds_matrix_identity(M);
+ lib3ds_matrix_translate(M, n->pos);
+ lib3ds_matrix_rotate(M, n->rot);
+ lib3ds_matrix_scale(M, n->scl);
+
+ if (node->parent) {
+ lib3ds_matrix_copy(node->matrix, node->parent->matrix);
+ lib3ds_matrix_mult(node->matrix, M);
+ }
+ else {
+ lib3ds_matrix_copy(node->matrix, M);
+ }
+ }
+ break;
+ case LIB3DS_CAMERA_NODE:
+ {
+ Lib3dsCameraData *n=&node->data.camera;
+ lib3ds_lin3_track_eval(&n->pos_track, n->pos, t);
+ lib3ds_lin1_track_eval(&n->fov_track, &n->fov, t);
+ lib3ds_lin1_track_eval(&n->roll_track, &n->roll, t);
+ if (node->parent) {
+ lib3ds_matrix_copy(node->matrix, node->parent->matrix);
+ }
+ else {
+ lib3ds_matrix_identity(node->matrix);
+ }
+ lib3ds_matrix_translate(node->matrix, n->pos);
+ }
+ break;
+ case LIB3DS_TARGET_NODE:
+ {
+ Lib3dsTargetData *n=&node->data.target;
+ lib3ds_lin3_track_eval(&n->pos_track, n->pos, t);
+ if (node->parent) {
+ lib3ds_matrix_copy(node->matrix, node->parent->matrix);
+ }
+ else {
+ lib3ds_matrix_identity(node->matrix);
+ }
+ lib3ds_matrix_translate(node->matrix, n->pos);
+ }
+ break;
+ case LIB3DS_LIGHT_NODE:
+ {
+ Lib3dsLightData *n=&node->data.light;
+ lib3ds_lin3_track_eval(&n->pos_track, n->pos, t);
+ lib3ds_lin3_track_eval(&n->col_track, n->col, t);
+ lib3ds_lin1_track_eval(&n->hotspot_track, &n->hotspot, t);
+ lib3ds_lin1_track_eval(&n->falloff_track, &n->falloff, t);
+ lib3ds_lin1_track_eval(&n->roll_track, &n->roll, t);
+ if (node->parent) {
+ lib3ds_matrix_copy(node->matrix, node->parent->matrix);
+ }
+ else {
+ lib3ds_matrix_identity(node->matrix);
+ }
+ lib3ds_matrix_translate(node->matrix, n->pos);
+ }
+ break;
+ case LIB3DS_SPOT_NODE:
+ {
+ Lib3dsSpotData *n=&node->data.spot;
+ lib3ds_lin3_track_eval(&n->pos_track, n->pos, t);
+ if (node->parent) {
+ lib3ds_matrix_copy(node->matrix, node->parent->matrix);
+ }
+ else {
+ lib3ds_matrix_identity(node->matrix);
+ }
+ lib3ds_matrix_translate(node->matrix, n->pos);
+ }
+ break;
+ }
+ {
+ Lib3dsNode *p;
+
+ for (p=node->childs; p!=0; p=p->next) {
+ lib3ds_node_eval(p, t);
+ }
+ }
+}
+
+
+/*!
+ * Return a node object by name and type.
+ *
+ * This function performs a recursive search for the specified node.
+ * Both name and type must match.
+ *
+ * \param node The parent node for the search
+ * \param name The target node name.
+ * \param type The target node type
+ *
+ * \return A pointer to the first matching node, or NULL if not found.
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_by_name(Lib3dsNode *node, const char* name, Lib3dsNodeTypes type)
+{
+ Lib3dsNode *p,*q;
+
+ for (p=node->childs; p!=0; p=p->next) {
+ if ((p->type==type) && (strcmp(p->name, name)==0)) {
+ return(p);
+ }
+ q=lib3ds_node_by_name(p, name, type);
+ if (q) {
+ return(q);
+ }
+ }
+ return(0);
+}
+
+
+/*!
+ * Return a node object by id.
+ *
+ * This function performs a recursive search for the specified node.
+ *
+ * \param node The parent node for the search
+ * \param node_id The target node id.
+ *
+ * \return A pointer to the first matching node, or NULL if not found.
+ *
+ * \ingroup node
+ */
+Lib3dsNode*
+lib3ds_node_by_id(Lib3dsNode *node, Lib3dsWord node_id)
+{
+ Lib3dsNode *p,*q;
+
+ for (p=node->childs; p!=0; p=p->next) {
+ if (p->node_id==node_id) {
+ return(p);
+ }
+ q=lib3ds_node_by_id(p, node_id);
+ if (q) {
+ return(q);
+ }
+ }
+ return(0);
+}
+
+
+static const char* node_names_table[]= {
+ "***Unknown***",
+ "Ambient",
+ "Object",
+ "Camera",
+ "Target",
+ "Light",
+ "Spot"
+};
+
+
+/*!
+ * Dump node and all descendants recursively.
+ *
+ * \param node The top-level node to be dumped.
+ * \param level current recursion depth
+ *
+ * \ingroup node
+ */
+void
+lib3ds_node_dump(Lib3dsNode *node, Lib3dsIntd level)
+{
+ Lib3dsNode *p;
+ char l[128];
+
+ ASSERT(node);
+ memset(l, ' ', 2*level);
+ l[2*level]=0;
+
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ printf("%s%s [%s] (%s)\n",
+ l,
+ node->name,
+ node->data.object.instance,
+ node_names_table[node->type]
+ );
+ }
+ else {
+ printf("%s%s (%s)\n",
+ l,
+ node->name,
+ node_names_table[node->type]
+ );
+ }
+
+ for (p=node->childs; p!=0; p=p->next) {
+ lib3ds_node_dump(p, level+1);
+ }
+}
+
+
+/*!
+ * \ingroup node
+ */
+Lib3dsBool
+lib3ds_node_read(Lib3dsNode *node, Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+ LIB3DS_UNUSED(file);
+
+ ASSERT(node);
+ if (!lib3ds_chunk_read_start(&c, 0, io)) {
+ return(LIB3DS_FALSE);
+ }
+ switch (c.chunk) {
+ case LIB3DS_AMBIENT_NODE_TAG:
+ case LIB3DS_OBJECT_NODE_TAG:
+ case LIB3DS_CAMERA_NODE_TAG:
+ case LIB3DS_TARGET_NODE_TAG:
+ case LIB3DS_LIGHT_NODE_TAG:
+ case LIB3DS_SPOTLIGHT_NODE_TAG:
+ case LIB3DS_L_TARGET_NODE_TAG:
+ break;
+ default:
+ return(LIB3DS_FALSE);
+ }
+
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_NODE_ID:
+ {
+ node->node_id=lib3ds_io_read_word(io);
+ lib3ds_chunk_dump_info(" ID = %d", (short)node->node_id);
+ }
+ break;
+ case LIB3DS_NODE_HDR:
+ {
+ if (!lib3ds_io_read_string(io, node->name, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ node->flags1=lib3ds_io_read_word(io);
+ node->flags2=lib3ds_io_read_word(io);
+ node->parent_id=lib3ds_io_read_word(io);
+ lib3ds_chunk_dump_info(" NAME =%s", node->name);
+ lib3ds_chunk_dump_info(" PARENT=%d", (short)node->parent_id);
+ }
+ break;
+ case LIB3DS_PIVOT:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ int i;
+ for (i=0; i<3; ++i) {
+ node->data.object.pivot[i]=lib3ds_io_read_float(io);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_INSTANCE_NAME:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ if (!lib3ds_io_read_string(io, node->data.object.instance, 64)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_BOUNDBOX:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ int i;
+ for (i=0; i<3; ++i) {
+ node->data.object.bbox_min[i]=lib3ds_io_read_float(io);
+ }
+ for (i=0; i<3; ++i) {
+ node->data.object.bbox_max[i]=lib3ds_io_read_float(io);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_COL_TRACK_TAG:
+ {
+ Lib3dsBool result=LIB3DS_TRUE;
+
+ switch (node->type) {
+ case LIB3DS_AMBIENT_NODE:
+ result=lib3ds_lin3_track_read(&node->data.ambient.col_track, io);
+ break;
+ case LIB3DS_LIGHT_NODE:
+ result=lib3ds_lin3_track_read(&node->data.light.col_track, io);
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ if (!result) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_POS_TRACK_TAG:
+ {
+ Lib3dsBool result=LIB3DS_TRUE;
+
+ switch (node->type) {
+ case LIB3DS_OBJECT_NODE:
+ result=lib3ds_lin3_track_read(&node->data.object.pos_track, io);
+ break;
+ case LIB3DS_CAMERA_NODE:
+ result=lib3ds_lin3_track_read(&node->data.camera.pos_track, io);
+ break;
+ case LIB3DS_TARGET_NODE:
+ result=lib3ds_lin3_track_read(&node->data.target.pos_track, io);
+ break;
+ case LIB3DS_LIGHT_NODE:
+ result=lib3ds_lin3_track_read(&node->data.light.pos_track, io);
+ break;
+ case LIB3DS_SPOT_NODE:
+ result=lib3ds_lin3_track_read(&node->data.spot.pos_track, io);
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ if (!result) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_ROT_TRACK_TAG:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ if (!lib3ds_quat_track_read(&node->data.object.rot_track, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_SCL_TRACK_TAG:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ if (!lib3ds_lin3_track_read(&node->data.object.scl_track, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_FOV_TRACK_TAG:
+ {
+ if (node->type==LIB3DS_CAMERA_NODE) {
+ if (!lib3ds_lin1_track_read(&node->data.camera.fov_track, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_HOT_TRACK_TAG:
+ {
+ if (node->type==LIB3DS_LIGHT_NODE) {
+ if (!lib3ds_lin1_track_read(&node->data.light.hotspot_track, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_FALL_TRACK_TAG:
+ {
+ if (node->type==LIB3DS_LIGHT_NODE) {
+ if (!lib3ds_lin1_track_read(&node->data.light.falloff_track, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_ROLL_TRACK_TAG:
+ {
+ Lib3dsBool result=LIB3DS_TRUE;
+
+ switch (node->type) {
+ case LIB3DS_CAMERA_NODE:
+ result=lib3ds_lin1_track_read(&node->data.camera.roll_track, io);
+ break;
+ case LIB3DS_LIGHT_NODE:
+ result=lib3ds_lin1_track_read(&node->data.light.roll_track, io);
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ if (!result) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_HIDE_TRACK_TAG:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ if (!lib3ds_bool_track_read(&node->data.object.hide_track, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_MORPH_SMOOTH:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ node->data.object.morph_smooth=lib3ds_io_read_float(io);
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ case LIB3DS_MORPH_TRACK_TAG:
+ {
+ if (node->type==LIB3DS_OBJECT_NODE) {
+ if (!lib3ds_morph_track_read(&node->data.object.morph_track, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ else {
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup node
+ */
+Lib3dsBool
+lib3ds_node_write(Lib3dsNode *node, Lib3dsFile *file, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ switch (node->type) {
+ case LIB3DS_AMBIENT_NODE:
+ c.chunk=LIB3DS_AMBIENT_NODE_TAG;
+ break;
+ case LIB3DS_OBJECT_NODE:
+ c.chunk=LIB3DS_OBJECT_NODE_TAG;
+ break;
+ case LIB3DS_CAMERA_NODE:
+ c.chunk=LIB3DS_CAMERA_NODE_TAG;
+ break;
+ case LIB3DS_TARGET_NODE:
+ c.chunk=LIB3DS_TARGET_NODE_TAG;
+ break;
+ case LIB3DS_LIGHT_NODE:
+ if (lib3ds_file_node_by_name(file, node->name, LIB3DS_SPOT_NODE)) {
+ c.chunk=LIB3DS_SPOTLIGHT_NODE_TAG;
+ }
+ else {
+ c.chunk=LIB3DS_LIGHT_NODE_TAG;
+ }
+ break;
+ case LIB3DS_SPOT_NODE:
+ c.chunk=LIB3DS_L_TARGET_NODE_TAG;
+ break;
+ default:
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ { /*---- LIB3DS_NODE_ID ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_NODE_ID;
+ c.size=8;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intw(io, node->node_id);
+ }
+
+ { /*---- LIB3DS_NODE_HDR ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_NODE_HDR;
+ c.size=6+ 1+(Lib3dsDword)strlen(node->name) +2+2+2;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_string(io, node->name);
+ lib3ds_io_write_word(io, node->flags1);
+ lib3ds_io_write_word(io, node->flags2);
+ lib3ds_io_write_word(io, node->parent_id);
+ }
+
+ switch (c.chunk) {
+ case LIB3DS_AMBIENT_NODE_TAG:
+ { /*---- LIB3DS_COL_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_COL_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.ambient.col_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_OBJECT_NODE_TAG:
+ { /*---- LIB3DS_PIVOT ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_PIVOT;
+ c.size=18;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, node->data.object.pivot);
+ }
+ { /*---- LIB3DS_INSTANCE_NAME ----*/
+ Lib3dsChunk c;
+ const char *name;
+ if (strlen(node->data.object.instance)) {
+ name=node->data.object.instance;
+
+ c.chunk=LIB3DS_INSTANCE_NAME;
+ c.size=6+1+(Lib3dsDword)strlen(name);
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_string(io, name);
+ }
+ }
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ if ((fabs(node->data.object.bbox_min[i])>LIB3DS_EPSILON) ||
+ (fabs(node->data.object.bbox_max[i])>LIB3DS_EPSILON)) {
+ break;
+ }
+ }
+
+ if (i<3) { /*---- LIB3DS_BOUNDBOX ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_BOUNDBOX;
+ c.size=30;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, node->data.object.bbox_min);
+ lib3ds_io_write_vector(io, node->data.object.bbox_max);
+ }
+ }
+ { /*---- LIB3DS_POS_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_POS_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.object.pos_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_ROT_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_ROT_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_quat_track_write(&node->data.object.rot_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_SCL_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_SCL_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.object.scl_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ if (node->data.object.hide_track.keyL) { /*---- LIB3DS_HIDE_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_HIDE_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_bool_track_write(&node->data.object.hide_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ if (fabs(node->data.object.morph_smooth)>LIB3DS_EPSILON){ /*---- LIB3DS_MORPH_SMOOTH ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_MORPH_SMOOTH;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, node->data.object.morph_smooth);
+ }
+ break;
+ case LIB3DS_CAMERA_NODE_TAG:
+ { /*---- LIB3DS_POS_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_POS_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.camera.pos_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_FOV_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_FOV_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin1_track_write(&node->data.camera.fov_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_ROLL_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_ROLL_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin1_track_write(&node->data.camera.roll_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_TARGET_NODE_TAG:
+ { /*---- LIB3DS_POS_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_POS_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.target.pos_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_LIGHT_NODE_TAG:
+ { /*---- LIB3DS_POS_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_POS_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.light.pos_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_COL_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_COL_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.light.col_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_SPOTLIGHT_NODE_TAG:
+ { /*---- LIB3DS_POS_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_POS_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.light.pos_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_COL_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_COL_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.light.col_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_HOT_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_HOT_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin1_track_write(&node->data.light.hotspot_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_FALL_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_FALL_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin1_track_write(&node->data.light.falloff_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ { /*---- LIB3DS_ROLL_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_ROLL_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin1_track_write(&node->data.light.roll_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ case LIB3DS_L_TARGET_NODE_TAG:
+ { /*---- LIB3DS_POS_TRACK_TAG ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_POS_TRACK_TAG;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_lin3_track_write(&node->data.spot.pos_track,io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ break;
+ default:
+ return(LIB3DS_FALSE);
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
diff --git a/3rdparty/lib3ds/node.h b/3rdparty/lib3ds/node.h
new file mode 100644
index 000000000..2b7de9af4
--- /dev/null
+++ b/3rdparty/lib3ds/node.h
@@ -0,0 +1,188 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_NODE_H
+#define INCLUDED_LIB3DS_NODE_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: node.h,v 1.12 2007/06/20 17:04:09 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TRACKS_H
+#include <lib3ds/tracks.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Scene graph ambient color node data
+ * \ingroup node
+ */
+typedef struct Lib3dsAmbientData {
+ Lib3dsRgb col;
+ Lib3dsLin3Track col_track;
+} Lib3dsAmbientData;
+
+/**
+ * Scene graph object instance node data
+ * \ingroup node
+ */
+typedef struct Lib3dsObjectData {
+ Lib3dsVector pivot;
+ char instance[64];
+ Lib3dsVector bbox_min;
+ Lib3dsVector bbox_max;
+ Lib3dsVector pos;
+ Lib3dsLin3Track pos_track;
+ Lib3dsQuat rot;
+ Lib3dsQuatTrack rot_track;
+ Lib3dsVector scl;
+ Lib3dsLin3Track scl_track;
+ Lib3dsFloat morph_smooth;
+ char morph[64];
+ Lib3dsMorphTrack morph_track;
+ Lib3dsBool hide;
+ Lib3dsBoolTrack hide_track;
+} Lib3dsObjectData;
+
+/**
+ * Scene graph camera node data
+ * \ingroup node
+ */
+typedef struct Lib3dsCameraData {
+ Lib3dsVector pos;
+ Lib3dsLin3Track pos_track;
+ Lib3dsFloat fov;
+ Lib3dsLin1Track fov_track;
+ Lib3dsFloat roll;
+ Lib3dsLin1Track roll_track;
+} Lib3dsCameraData;
+
+/**
+ * Scene graph camera target node data
+ * \ingroup node
+ */
+typedef struct Lib3dsTargetData {
+ Lib3dsVector pos;
+ Lib3dsLin3Track pos_track;
+} Lib3dsTargetData;
+
+/**
+ * Scene graph light node data
+ * \ingroup node
+ */
+typedef struct Lib3dsLightData {
+ Lib3dsVector pos;
+ Lib3dsLin3Track pos_track;
+ Lib3dsRgb col;
+ Lib3dsLin3Track col_track;
+ Lib3dsFloat hotspot;
+ Lib3dsLin1Track hotspot_track;
+ Lib3dsFloat falloff;
+ Lib3dsLin1Track falloff_track;
+ Lib3dsFloat roll;
+ Lib3dsLin1Track roll_track;
+} Lib3dsLightData;
+
+/**
+ * Scene graph spotlight target node data
+ * \ingroup node
+ */
+typedef struct Lib3dsSpotData {
+ Lib3dsVector pos;
+ Lib3dsLin3Track pos_track;
+} Lib3dsSpotData;
+
+/**
+ * Scene graph node data union
+ * \ingroup node
+ */
+typedef union Lib3dsNodeData {
+ Lib3dsAmbientData ambient;
+ Lib3dsObjectData object;
+ Lib3dsCameraData camera;
+ Lib3dsTargetData target;
+ Lib3dsLightData light;
+ Lib3dsSpotData spot;
+} Lib3dsNodeData;
+
+/*!
+ * \ingroup node
+ */
+#define LIB3DS_NO_PARENT 65535
+
+/**
+ * Scene graph node
+ * \ingroup node
+ */
+struct Lib3dsNode {
+ Lib3dsUserData user;
+ Lib3dsNode *next;
+ Lib3dsNode *childs;
+ Lib3dsNode *parent;
+ Lib3dsNodeTypes type;
+ Lib3dsWord node_id;
+ char name[64];
+ Lib3dsWord flags1;
+ Lib3dsWord flags2;
+ Lib3dsWord parent_id;
+ Lib3dsMatrix matrix;
+ Lib3dsNodeData data;
+};
+
+/**
+ * Node flags #1
+ * \ingroup node
+ */
+typedef enum {
+ LIB3DS_HIDDEN = 0x800
+} Lib3dsNodeFlags1;
+
+/**
+ * Node flags #2
+ * \ingroup node
+ */
+typedef enum {
+ LIB3DS_SHOW_PATH = 0x1,
+ LIB3DS_SMOOTHING = 0x2,
+ LIB3DS_MOTION_BLUR = 0x10,
+ LIB3DS_MORPH_MATERIALS = 0x40
+} Lib3dsNodeFlags2;
+
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_new_ambient();
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_new_object();
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_new_camera();
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_new_target();
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_new_light();
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_new_spot();
+extern LIB3DSAPI void lib3ds_node_free(Lib3dsNode *node);
+extern LIB3DSAPI void lib3ds_node_eval(Lib3dsNode *node, Lib3dsFloat t);
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_by_name(Lib3dsNode *node, const char* name,
+ Lib3dsNodeTypes type);
+extern LIB3DSAPI Lib3dsNode* lib3ds_node_by_id(Lib3dsNode *node, Lib3dsWord node_id);
+extern LIB3DSAPI void lib3ds_node_dump(Lib3dsNode *node, Lib3dsIntd level);
+extern LIB3DSAPI Lib3dsBool lib3ds_node_read(Lib3dsNode *node, Lib3dsFile *file, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_node_write(Lib3dsNode *node, Lib3dsFile *file, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/quat.c b/3rdparty/lib3ds/quat.c
new file mode 100644
index 000000000..3553a95fc
--- /dev/null
+++ b/3rdparty/lib3ds/quat.c
@@ -0,0 +1,418 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: quat.c,v 1.9 2007/06/20 17:04:09 jeh Exp $
+ */
+#include <lib3ds/quat.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup quat Quaternion Mathematics
+ */
+
+
+/*!
+* \typedef Lib3dsQuat
+* \ingroup quat
+*/
+
+
+/*!
+ * Clear a quaternion.
+ * \ingroup quat
+ */
+void
+lib3ds_quat_zero(Lib3dsQuat c)
+{
+ c[0]=c[1]=c[2]=c[3]=0.0f;
+}
+
+
+/*!
+ * Set a quaternion to Identity
+ * \ingroup quat
+ */
+void
+lib3ds_quat_identity(Lib3dsQuat c)
+{
+ c[0]=c[1]=c[2]=0.0f;
+ c[3]=1.0f;
+}
+
+
+/*!
+ * Copy a quaternion.
+ * \ingroup quat
+ */
+void
+lib3ds_quat_copy(Lib3dsQuat dest, Lib3dsQuat src)
+{
+ int i;
+ for (i=0; i<4; ++i) {
+ dest[i]=src[i];
+ }
+}
+
+
+/*!
+ * Compute a quaternion from axis and angle.
+ *
+ * \param c Computed quaternion
+ * \param axis Rotation axis
+ * \param angle Angle of rotation, radians.
+ *
+ * \ingroup quat
+ */
+void
+lib3ds_quat_axis_angle(Lib3dsQuat c, Lib3dsVector axis, Lib3dsFloat angle)
+{
+ Lib3dsDouble omega,s;
+ Lib3dsDouble l;
+
+ l=sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
+ if (l<LIB3DS_EPSILON) {
+ c[0]=c[1]=c[2]=0.0f;
+ c[3]=1.0f;
+ }
+ else {
+ omega=-0.5*angle;
+ s=sin(omega)/l;
+ c[0]=(Lib3dsFloat)s*axis[0];
+ c[1]=(Lib3dsFloat)s*axis[1];
+ c[2]=(Lib3dsFloat)s*axis[2];
+ c[3]=(Lib3dsFloat)cos(omega);
+ }
+}
+
+
+/*!
+ * Negate a quaternion
+ *
+ * \ingroup quat
+ */
+void
+lib3ds_quat_neg(Lib3dsQuat c)
+{
+ int i;
+ for (i=0; i<4; ++i) {
+ c[i]=-c[i];
+ }
+}
+
+
+/*!
+ * Compute the absolute value of a quaternion
+ *
+ * \ingroup quat
+ */
+void
+lib3ds_quat_abs(Lib3dsQuat c)
+{
+ int i;
+ for (i=0; i<4; ++i) {
+ c[i]=(Lib3dsFloat)fabs(c[i]);
+ }
+}
+
+
+/*!
+ * Compute the conjugate of a quaternion
+ *
+ * \ingroup quat
+ */
+void
+lib3ds_quat_cnj(Lib3dsQuat c)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]=-c[i];
+ }
+}
+
+
+/*!
+ * Multiply two quaternions.
+ *
+ * \param c Result
+ * \param a,b Inputs
+ * \ingroup quat
+ */
+void
+lib3ds_quat_mul(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat b)
+{
+ c[0]=a[3]*b[0] + a[0]*b[3] + a[1]*b[2] - a[2]*b[1];
+ c[1]=a[3]*b[1] + a[1]*b[3] + a[2]*b[0] - a[0]*b[2];
+ c[2]=a[3]*b[2] + a[2]*b[3] + a[0]*b[1] - a[1]*b[0];
+ c[3]=a[3]*b[3] - a[0]*b[0] - a[1]*b[1] - a[2]*b[2];
+}
+
+
+/*!
+ * Multiply a quaternion by a scalar.
+ *
+ * \ingroup quat
+ */
+void
+lib3ds_quat_scalar(Lib3dsQuat c, Lib3dsFloat k)
+{
+ int i;
+ for (i=0; i<4; ++i) {
+ c[i]*=k;
+ }
+}
+
+
+/*!
+ * Normalize a quaternion.
+ *
+ * \ingroup quat
+ */
+void
+lib3ds_quat_normalize(Lib3dsQuat c)
+{
+ Lib3dsDouble l,m;
+
+ l=sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2] + c[3]*c[3]);
+ if (fabs(l)<LIB3DS_EPSILON) {
+ c[0]=c[1]=c[2]=0.0f;
+ c[3]=1.0f;
+ }
+ else {
+ int i;
+ m=1.0f/l;
+ for (i=0; i<4; ++i) {
+ c[i]=(Lib3dsFloat)(c[i]*m);
+ }
+ }
+}
+
+
+/*!
+ * Compute the inverse of a quaternion.
+ *
+ * \ingroup quat
+ */
+void
+lib3ds_quat_inv(Lib3dsQuat c)
+{
+ Lib3dsDouble l,m;
+
+ l=sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2] + c[3]*c[3]);
+ if (fabs(l)<LIB3DS_EPSILON) {
+ c[0]=c[1]=c[2]=0.0f;
+ c[3]=1.0f;
+ }
+ else {
+ m=1.0f/l;
+ c[0]=(Lib3dsFloat)(-c[0]*m);
+ c[1]=(Lib3dsFloat)(-c[1]*m);
+ c[2]=(Lib3dsFloat)(-c[2]*m);
+ c[3]=(Lib3dsFloat)(c[3]*m);
+ }
+}
+
+
+/*!
+ * Compute the dot-product of a quaternion.
+ *
+ * \ingroup quat
+ */
+Lib3dsFloat
+lib3ds_quat_dot(Lib3dsQuat a, Lib3dsQuat b)
+{
+ return(a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]);
+}
+
+
+/*!
+ * \ingroup quat
+ */
+Lib3dsFloat
+lib3ds_quat_squared(Lib3dsQuat c)
+{
+ return(c[0]*c[0] + c[1]*c[1] + c[2]*c[2] + c[3]*c[3]);
+}
+
+
+/*!
+ * \ingroup quat
+ */
+Lib3dsFloat
+lib3ds_quat_length(Lib3dsQuat c)
+{
+ return((Lib3dsFloat)sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2] + c[3]*c[3]));
+}
+
+
+/*!
+ * \ingroup quat
+ */
+void
+lib3ds_quat_ln(Lib3dsQuat c)
+{
+ Lib3dsDouble om,s,t;
+
+ s=sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]);
+ om=atan2(s,c[3]);
+ if (fabs(s)<LIB3DS_EPSILON) {
+ t=0.0f;
+ }
+ else {
+ t=om/s;
+ }
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]=(Lib3dsFloat)(c[i]*t);
+ }
+ c[3]=0.0f;
+ }
+}
+
+
+/*!
+ * \ingroup quat
+ */
+void
+lib3ds_quat_ln_dif(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat b)
+{
+ Lib3dsQuat invp;
+
+ lib3ds_quat_copy(invp, a);
+ lib3ds_quat_inv(invp);
+ lib3ds_quat_mul(c, invp, b);
+ lib3ds_quat_ln(c);
+}
+
+
+/*!
+ * \ingroup quat
+ */
+void
+lib3ds_quat_exp(Lib3dsQuat c)
+{
+ Lib3dsDouble om,sinom;
+
+ om=sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]);
+ if (fabs(om)<LIB3DS_EPSILON) {
+ sinom=1.0f;
+ }
+ else {
+ sinom=sin(om)/om;
+ }
+ {
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]=(Lib3dsFloat)(c[i]*sinom);
+ }
+ c[3]=(Lib3dsFloat)cos(om);
+ }
+}
+
+
+/*!
+ * \ingroup quat
+ */
+void
+lib3ds_quat_slerp(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat b, Lib3dsFloat t)
+{
+ Lib3dsDouble l;
+ Lib3dsDouble om,sinom;
+ Lib3dsDouble sp,sq;
+ Lib3dsQuat q;
+
+ l=a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3];
+ if ((1.0+l)>LIB3DS_EPSILON) {
+ if (fabs(l)>1.0f) l/=fabs(l);
+ om=acos(l);
+ sinom=sin(om);
+ if (fabs(sinom)>LIB3DS_EPSILON) {
+ sp=sin((1.0f-t)*om)/sinom;
+ sq=sin(t*om)/sinom;
+ }
+ else {
+ sp=1.0f-t;
+ sq=t;
+ }
+ c[0]=(Lib3dsFloat)(sp*a[0] + sq*b[0]);
+ c[1]=(Lib3dsFloat)(sp*a[1] + sq*b[1]);
+ c[2]=(Lib3dsFloat)(sp*a[2] + sq*b[2]);
+ c[3]=(Lib3dsFloat)(sp*a[3] + sq*b[3]);
+ }
+ else {
+ q[0]=-a[1];
+ q[1]=a[0];
+ q[2]=-a[3];
+ q[3]=a[2];
+ sp=sin((1.0-t)*LIB3DS_HALFPI);
+ sq=sin(t*LIB3DS_HALFPI);
+ c[0]=(Lib3dsFloat)(sp*a[0] + sq*q[0]);
+ c[1]=(Lib3dsFloat)(sp*a[1] + sq*q[1]);
+ c[2]=(Lib3dsFloat)(sp*a[2] + sq*q[2]);
+ c[3]=(Lib3dsFloat)(sp*a[3] + sq*q[3]);
+ }
+}
+
+
+/*!
+ * \ingroup quat
+ */
+void
+lib3ds_quat_squad(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat p, Lib3dsQuat q,
+ Lib3dsQuat b, Lib3dsFloat t)
+{
+ Lib3dsQuat ab;
+ Lib3dsQuat pq;
+
+ lib3ds_quat_slerp(ab,a,b,t);
+ lib3ds_quat_slerp(pq,p,q,t);
+ lib3ds_quat_slerp(c,ab,pq,2*t*(1-t));
+}
+
+
+/*!
+ * \ingroup quat
+ */
+void
+lib3ds_quat_tangent(Lib3dsQuat c, Lib3dsQuat p, Lib3dsQuat q, Lib3dsQuat n)
+{
+ Lib3dsQuat dn,dp,x;
+ int i;
+
+ lib3ds_quat_ln_dif(dn, q, n);
+ lib3ds_quat_ln_dif(dp, q, p);
+
+ for (i=0; i<4; i++) {
+ x[i]=-1.0f/4.0f*(dn[i]+dp[i]);
+ }
+ lib3ds_quat_exp(x);
+ lib3ds_quat_mul(c,q,x);
+}
+
+
+/*!
+ * \ingroup quat
+ */
+void
+lib3ds_quat_dump(Lib3dsQuat q)
+{
+ printf("%f %f %f %f\n", q[0], q[1], q[2], q[3]);
+}
+
diff --git a/3rdparty/lib3ds/quat.h b/3rdparty/lib3ds/quat.h
new file mode 100644
index 000000000..28912829d
--- /dev/null
+++ b/3rdparty/lib3ds/quat.h
@@ -0,0 +1,61 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_QUAT_H
+#define INCLUDED_LIB3DS_QUAT_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: quat.h,v 1.7 2007/06/14 09:59:10 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern LIB3DSAPI void lib3ds_quat_zero(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_identity(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_copy(Lib3dsQuat dest, Lib3dsQuat src);
+extern LIB3DSAPI void lib3ds_quat_axis_angle(Lib3dsQuat c, Lib3dsVector axis, Lib3dsFloat angle);
+extern LIB3DSAPI void lib3ds_quat_neg(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_abs(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_cnj(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_mul(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat b);
+extern LIB3DSAPI void lib3ds_quat_scalar(Lib3dsQuat c, Lib3dsFloat k);
+extern LIB3DSAPI void lib3ds_quat_normalize(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_inv(Lib3dsQuat c);
+extern LIB3DSAPI Lib3dsFloat lib3ds_quat_dot(Lib3dsQuat a, Lib3dsQuat b);
+extern LIB3DSAPI Lib3dsFloat lib3ds_quat_squared(Lib3dsQuat c);
+extern LIB3DSAPI Lib3dsFloat lib3ds_quat_length(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_ln(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_ln_dif(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat b);
+extern LIB3DSAPI void lib3ds_quat_exp(Lib3dsQuat c);
+extern LIB3DSAPI void lib3ds_quat_slerp(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat b, Lib3dsFloat t);
+extern LIB3DSAPI void lib3ds_quat_squad(Lib3dsQuat c, Lib3dsQuat a, Lib3dsQuat p, Lib3dsQuat q,
+ Lib3dsQuat b, Lib3dsFloat t);
+extern LIB3DSAPI void lib3ds_quat_tangent(Lib3dsQuat c, Lib3dsQuat p, Lib3dsQuat q, Lib3dsQuat n);
+extern LIB3DSAPI void lib3ds_quat_dump(Lib3dsQuat q);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/shadow.c b/3rdparty/lib3ds/shadow.c
new file mode 100644
index 000000000..601dd3786
--- /dev/null
+++ b/3rdparty/lib3ds/shadow.c
@@ -0,0 +1,149 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: shadow.c,v 1.11 2007/06/20 17:04:09 jeh Exp $
+ */
+#include <lib3ds/shadow.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup shadow Shadow Map Settings
+ */
+
+
+/*!
+ * \ingroup shadow
+ */
+Lib3dsBool
+lib3ds_shadow_read(Lib3dsShadow *shadow, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+
+ if (!lib3ds_chunk_read(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ switch (c.chunk) {
+ case LIB3DS_SHADOW_MAP_SIZE:
+ {
+ shadow->map_size=lib3ds_io_read_intw(io);
+ }
+ break;
+ case LIB3DS_LO_SHADOW_BIAS:
+ {
+ shadow->lo_bias=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_HI_SHADOW_BIAS:
+ {
+ shadow->hi_bias=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_SHADOW_SAMPLES:
+ {
+ shadow->samples=lib3ds_io_read_intw(io);
+ }
+ break;
+ case LIB3DS_SHADOW_RANGE:
+ {
+ shadow->range=lib3ds_io_read_intd(io);
+ }
+ break;
+ case LIB3DS_SHADOW_FILTER:
+ {
+ shadow->filter=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_RAY_BIAS:
+ {
+ shadow->ray_bias=lib3ds_io_read_float(io);
+ }
+ break;
+ }
+
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup shadow
+ */
+Lib3dsBool
+lib3ds_shadow_write(Lib3dsShadow *shadow, Lib3dsIo *io)
+{
+ if (fabs(shadow->lo_bias)>LIB3DS_EPSILON) { /*---- LIB3DS_LO_SHADOW_BIAS ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_LO_SHADOW_BIAS;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, shadow->lo_bias);
+ }
+
+ if (fabs(shadow->hi_bias)>LIB3DS_EPSILON) { /*---- LIB3DS_HI_SHADOW_BIAS ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_HI_SHADOW_BIAS;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, shadow->hi_bias);
+ }
+
+ if (shadow->map_size) { /*---- LIB3DS_SHADOW_MAP_SIZE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_SHADOW_MAP_SIZE;
+ c.size=8;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intw(io, shadow->map_size);
+ }
+
+ if (shadow->samples) { /*---- LIB3DS_SHADOW_SAMPLES ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_SHADOW_SAMPLES;
+ c.size=8;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intw(io, shadow->samples);
+ }
+
+ if (shadow->range) { /*---- LIB3DS_SHADOW_RANGE ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_SHADOW_RANGE;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intd(io, shadow->range);
+ }
+
+ if (fabs(shadow->filter)>LIB3DS_EPSILON) { /*---- LIB3DS_SHADOW_FILTER ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_SHADOW_FILTER;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, shadow->filter);
+ }
+ if (fabs(shadow->ray_bias)>LIB3DS_EPSILON) { /*---- LIB3DS_RAY_BIAS ----*/
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_RAY_BIAS;
+ c.size=10;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_float(io, shadow->ray_bias);
+ }
+ return(LIB3DS_TRUE);
+}
+
diff --git a/3rdparty/lib3ds/shadow.h b/3rdparty/lib3ds/shadow.h
new file mode 100644
index 000000000..cc31ba956
--- /dev/null
+++ b/3rdparty/lib3ds/shadow.h
@@ -0,0 +1,59 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_SHADOW_H
+#define INCLUDED_LIB3DS_SHADOW_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: shadow.h,v 1.11 2007/06/20 17:04:09 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Shadow map settings
+ * \ingroup shadow
+ */
+struct Lib3dsShadow {
+ Lib3dsIntw map_size;
+ Lib3dsFloat lo_bias;
+ Lib3dsFloat hi_bias;
+ Lib3dsIntw samples;
+ Lib3dsIntd range;
+ Lib3dsFloat filter;
+ Lib3dsFloat ray_bias;
+};
+
+extern LIB3DSAPI Lib3dsBool lib3ds_shadow_read(Lib3dsShadow *shadow, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_shadow_write(Lib3dsShadow *shadow, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
+
+
diff --git a/3rdparty/lib3ds/tcb.c b/3rdparty/lib3ds/tcb.c
new file mode 100644
index 000000000..b1a0cac2b
--- /dev/null
+++ b/3rdparty/lib3ds/tcb.c
@@ -0,0 +1,136 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: tcb.c,v 1.11 2007/06/15 09:33:19 jeh Exp $
+ */
+#include <lib3ds/tcb.h>
+#include <lib3ds/io.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup tcb Tension/Continuity/Bias Splines
+ */
+
+
+/*!
+ * \ingroup tcb
+ */
+void
+lib3ds_tcb(Lib3dsTcb *p, Lib3dsTcb *pc, Lib3dsTcb *c, Lib3dsTcb *nc, Lib3dsTcb *n,
+ Lib3dsFloat *ksm, Lib3dsFloat *ksp, Lib3dsFloat *kdm, Lib3dsFloat *kdp)
+{
+ Lib3dsFloat tm,cm,cp,bm,bp,tmcm,tmcp,cc;
+ Lib3dsFloat dt,fp,fn;
+
+ if (!pc) {
+ pc=c;
+ }
+ if (!nc) {
+ nc=c;
+ }
+
+ fp=fn=1.0f;
+ if (p&&n) {
+ dt=0.5f*(Lib3dsFloat)(pc->frame-p->frame+n->frame-nc->frame);
+ fp=((Lib3dsFloat)(pc->frame-p->frame))/dt;
+ fn=((Lib3dsFloat)(n->frame-nc->frame))/dt;
+ cc=(Lib3dsFloat)fabs(c->cont);
+ fp=fp+cc-cc*fp;
+ fn=fn+cc-cc*fn;
+ }
+
+ cm=1.0f-c->cont;
+ tm=0.5f*(1.0f-c->tens);
+ cp=2.0f-cm;
+ bm=1.0f-c->bias;
+ bp=2.0f-bm;
+ tmcm=tm*cm;
+ tmcp=tm*cp;
+ *ksm=tmcm*bp*fp;
+ *ksp=tmcp*bm*fp;
+ *kdm=tmcp*bp*fn;
+ *kdp=tmcm*bm*fn;
+}
+
+
+/*!
+ * \ingroup tcb
+ */
+Lib3dsBool
+lib3ds_tcb_read(Lib3dsTcb *tcb, Lib3dsIo *io)
+{
+ Lib3dsWord flags;
+
+ tcb->frame=lib3ds_io_read_intd(io);
+ tcb->flags=flags=lib3ds_io_read_word(io);
+ if (flags&LIB3DS_USE_TENSION) {
+ tcb->tens=lib3ds_io_read_float(io);
+ }
+ if (flags&LIB3DS_USE_CONTINUITY) {
+ tcb->cont=lib3ds_io_read_float(io);
+ }
+ if (flags&LIB3DS_USE_BIAS) {
+ tcb->bias=lib3ds_io_read_float(io);
+ }
+ if (flags&LIB3DS_USE_EASE_TO) {
+ tcb->ease_to=lib3ds_io_read_float(io);
+ }
+ if (flags&LIB3DS_USE_EASE_FROM) {
+ tcb->ease_from=lib3ds_io_read_float(io);
+ }
+ if (lib3ds_io_error(io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tcb
+ */
+Lib3dsBool
+lib3ds_tcb_write(Lib3dsTcb *tcb, Lib3dsIo *io)
+{
+ lib3ds_io_write_intd(io, tcb->frame);
+ lib3ds_io_write_word(io, tcb->flags);
+ if (tcb->flags&LIB3DS_USE_TENSION) {
+ lib3ds_io_write_float(io, tcb->tens);
+ }
+ if (tcb->flags&LIB3DS_USE_CONTINUITY) {
+ lib3ds_io_write_float(io, tcb->cont);
+ }
+ if (tcb->flags&LIB3DS_USE_BIAS) {
+ lib3ds_io_write_float(io, tcb->bias);
+ }
+ if (tcb->flags&LIB3DS_USE_EASE_TO) {
+ lib3ds_io_write_float(io, tcb->ease_to);
+ }
+ if (tcb->flags&LIB3DS_USE_EASE_FROM) {
+ lib3ds_io_write_float(io, tcb->ease_from);
+ }
+ if (lib3ds_io_error(io)) {
+ return(LIB3DS_FALSE);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+
+
diff --git a/3rdparty/lib3ds/tcb.h b/3rdparty/lib3ds/tcb.h
new file mode 100644
index 000000000..3d8e3f63a
--- /dev/null
+++ b/3rdparty/lib3ds/tcb.h
@@ -0,0 +1,62 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_TCB_H
+#define INCLUDED_LIB3DS_TCB_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: tcb.h,v 1.11 2007/06/20 17:04:09 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum Lib3dsTcbFlags{
+ LIB3DS_USE_TENSION =0x0001,
+ LIB3DS_USE_CONTINUITY =0x0002,
+ LIB3DS_USE_BIAS =0x0004,
+ LIB3DS_USE_EASE_TO =0x0008,
+ LIB3DS_USE_EASE_FROM =0x0010
+} Lib3dsTcbFlags;
+
+typedef struct Lib3dsTcb {
+ Lib3dsIntd frame;
+ Lib3dsWord flags;
+ Lib3dsFloat tens;
+ Lib3dsFloat cont;
+ Lib3dsFloat bias;
+ Lib3dsFloat ease_to;
+ Lib3dsFloat ease_from;
+} Lib3dsTcb;
+
+extern LIB3DSAPI void lib3ds_tcb(Lib3dsTcb *p, Lib3dsTcb *pc, Lib3dsTcb *c,
+ Lib3dsTcb *nc, Lib3dsTcb *n, Lib3dsFloat *ksm, Lib3dsFloat *ksp,
+ Lib3dsFloat *kdm, Lib3dsFloat *kdp);
+extern LIB3DSAPI Lib3dsBool lib3ds_tcb_read(Lib3dsTcb *tcb, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_tcb_write(Lib3dsTcb *tcb, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/tracks.c b/3rdparty/lib3ds/tracks.c
new file mode 100644
index 000000000..cc24455a2
--- /dev/null
+++ b/3rdparty/lib3ds/tracks.c
@@ -0,0 +1,1556 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: tracks.c,v 1.20 2007/06/15 09:33:19 jeh Exp $
+ */
+#include <lib3ds/tracks.h>
+#include <lib3ds/io.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/vector.h>
+#include <lib3ds/quat.h>
+#include <lib3ds/node.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup tracks Keyframing Tracks
+ */
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBoolKey*
+lib3ds_bool_key_new()
+{
+ Lib3dsBoolKey* k;
+ k=(Lib3dsBoolKey*)calloc(sizeof(Lib3dsBoolKey), 1);
+ return(k);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_bool_key_free(Lib3dsBoolKey *key)
+{
+ ASSERT(key);
+ free(key);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_bool_track_free_keys(Lib3dsBoolTrack *track)
+{
+ Lib3dsBoolKey *p,*q;
+
+ ASSERT(track);
+ for (p=track->keyL; p; p=q) {
+ q=p->next;
+ lib3ds_bool_key_free(p);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_bool_track_insert(Lib3dsBoolTrack *track, Lib3dsBoolKey *key)
+{
+ ASSERT(track);
+ ASSERT(key);
+ ASSERT(!key->next);
+
+ if (!track->keyL) {
+ track->keyL=key;
+ key->next=0;
+ }
+ else {
+ Lib3dsBoolKey *k,*p;
+
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame>key->tcb.frame) {
+ break;
+ }
+ }
+ if (!p) {
+ key->next=track->keyL;
+ track->keyL=key;
+ }
+ else {
+ key->next=k;
+ p->next=key;
+ }
+
+ if (k && (key->tcb.frame==k->tcb.frame)) {
+ key->next=k->next;
+ lib3ds_bool_key_free(k);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_bool_track_remove(Lib3dsBoolTrack *track, Lib3dsIntd frame)
+{
+ Lib3dsBoolKey *k,*p;
+
+ ASSERT(track);
+ if (!track->keyL) {
+ return;
+ }
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame==frame) {
+ if (!p) {
+ track->keyL=track->keyL->next;
+ }
+ else {
+ p->next=k->next;
+ }
+ lib3ds_bool_key_free(k);
+ break;
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_bool_track_eval(Lib3dsBoolTrack *track, Lib3dsBool *p, Lib3dsFloat t)
+{
+ Lib3dsBoolKey *k;
+ Lib3dsBool result;
+
+ ASSERT(p);
+ if (!track->keyL) {
+ *p=LIB3DS_FALSE;
+ return;
+ }
+ if (!track->keyL->next) {
+ *p = LIB3DS_TRUE;
+ return;
+ }
+
+ result=LIB3DS_FALSE;
+ k=track->keyL;
+ while ((t<(Lib3dsFloat)k->tcb.frame) && (t>=(Lib3dsFloat)k->next->tcb.frame)) {
+ if (result) {
+ result=LIB3DS_FALSE;
+ }
+ else {
+ result=LIB3DS_TRUE;
+ }
+ if (!k->next) {
+ if (track->flags&LIB3DS_REPEAT) {
+ t-=(Lib3dsFloat)k->tcb.frame;
+ k=track->keyL;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ k=k->next;
+ }
+ }
+ *p=result;
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_bool_track_read(Lib3dsBoolTrack *track, Lib3dsIo *io)
+{
+ int keys;
+ int i;
+ Lib3dsBoolKey *k;
+
+ track->flags=lib3ds_io_read_word(io);
+ lib3ds_io_read_dword(io);
+ lib3ds_io_read_dword(io);
+ keys=lib3ds_io_read_intd(io);
+
+ for (i=0; i<keys; ++i) {
+ k=lib3ds_bool_key_new();
+ if (!lib3ds_tcb_read(&k->tcb, io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_bool_track_insert(track, k);
+ }
+
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_bool_track_write(Lib3dsBoolTrack *track, Lib3dsIo *io)
+{
+ Lib3dsBoolKey *k;
+ Lib3dsDword num=0;
+ for (k=track->keyL; k; k=k->next) {
+ ++num;
+ }
+ lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, num);
+
+ for (k=track->keyL; k; k=k->next) {
+ if (!lib3ds_tcb_write(&k->tcb,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsLin1Key*
+lib3ds_lin1_key_new()
+{
+ Lib3dsLin1Key* k;
+ k=(Lib3dsLin1Key*)calloc(sizeof(Lib3dsLin1Key), 1);
+ return(k);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin1_key_free(Lib3dsLin1Key *key)
+{
+ ASSERT(key);
+ free(key);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin1_track_free_keys(Lib3dsLin1Track *track)
+{
+ Lib3dsLin1Key *p,*q;
+
+ ASSERT(track);
+ for (p=track->keyL; p; p=q) {
+ q=p->next;
+ lib3ds_lin1_key_free(p);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin1_key_setup(Lib3dsLin1Key *p, Lib3dsLin1Key *cp, Lib3dsLin1Key *c,
+ Lib3dsLin1Key *cn, Lib3dsLin1Key *n)
+{
+ Lib3dsFloat np,nn;
+ Lib3dsFloat ksm,ksp,kdm,kdp;
+
+ ASSERT(c);
+ if (!cp) {
+ cp=c;
+ }
+ if (!cn) {
+ cn=c;
+ }
+ if (!p && !n) {
+ c->ds=0;
+ c->dd=0;
+ return;
+ }
+
+ if (n && p) {
+ lib3ds_tcb(&p->tcb, &cp->tcb, &c->tcb, &cn->tcb, &n->tcb, &ksm, &ksp, &kdm, &kdp);
+ np = c->value - p->value;
+ nn = n->value - c->value;
+
+ c->ds=ksm*np + ksp*nn;
+ c->dd=kdm*np + kdp*nn;
+ }
+ else {
+ if (p) {
+ np = c->value - p->value;
+ c->ds = np;
+ c->dd = np;
+ }
+ if (n) {
+ nn = n->value - c->value;
+ c->ds = nn;
+ c->dd = nn;
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin1_track_setup(Lib3dsLin1Track *track)
+{
+ Lib3dsLin1Key *pp,*pc,*pn,*pl;
+
+ ASSERT(track);
+ pc=track->keyL;
+ if (!pc) {
+ return;
+ }
+ if (!pc->next) {
+ pc->ds=0;
+ pc->dd=0;
+ return;
+ }
+
+ if (track->flags&LIB3DS_SMOOTH) {
+ for (pl=track->keyL; pl->next->next; pl=pl->next);
+ lib3ds_lin1_key_setup(pl, pl->next, pc, 0, pc->next);
+ }
+ else {
+ lib3ds_lin1_key_setup(0, 0, pc, 0, pc->next);
+ }
+ for (;;) {
+ pp=pc;
+ pc=pc->next;
+ pn=pc->next;
+ if (!pn) {
+ break;
+ }
+ lib3ds_lin1_key_setup(pp, 0, pc, 0, pn);
+ }
+
+ if (track->flags&LIB3DS_SMOOTH) {
+ lib3ds_lin1_key_setup(pp, 0, pc, track->keyL, track->keyL->next);
+ }
+ else {
+ lib3ds_lin1_key_setup(pp, 0, pc, 0, 0);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin1_track_insert(Lib3dsLin1Track *track, Lib3dsLin1Key *key)
+{
+ ASSERT(track);
+ ASSERT(key);
+ ASSERT(!key->next);
+
+ if (!track->keyL) {
+ track->keyL=key;
+ key->next=0;
+ }
+ else {
+ Lib3dsLin1Key *k,*p;
+
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame>key->tcb.frame) {
+ break;
+ }
+ }
+ if (!p) {
+ key->next=track->keyL;
+ track->keyL=key;
+ }
+ else {
+ key->next=k;
+ p->next=key;
+ }
+
+ if (k && (key->tcb.frame==k->tcb.frame)) {
+ key->next=k->next;
+ lib3ds_lin1_key_free(k);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin1_track_remove(Lib3dsLin1Track *track, Lib3dsIntd frame)
+{
+ Lib3dsLin1Key *k,*p;
+
+ ASSERT(track);
+ if (!track->keyL) {
+ return;
+ }
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame==frame) {
+ if (!p) {
+ track->keyL=track->keyL->next;
+ }
+ else {
+ p->next=k->next;
+ }
+ lib3ds_lin1_key_free(k);
+ break;
+ }
+ }
+}
+
+
+static Lib3dsFloat
+lib3ds_float_cubic(Lib3dsFloat a, Lib3dsFloat p, Lib3dsFloat q, Lib3dsFloat b, Lib3dsFloat t)
+{
+ Lib3dsDouble x,y,z,w;
+
+ x=2*t*t*t - 3*t*t + 1;
+ y=-2*t*t*t + 3*t*t;
+ z=t*t*t - 2*t*t + t;
+ w=t*t*t - t*t;
+ return((Lib3dsFloat)(x*a + y*b + z*p + w*q));
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin1_track_eval(Lib3dsLin1Track *track, Lib3dsFloat *p, Lib3dsFloat t)
+{
+ Lib3dsLin1Key *k;
+ Lib3dsFloat nt;
+ Lib3dsFloat u;
+
+ ASSERT(p);
+ if (!track->keyL) {
+ *p=0;
+ return;
+ }
+ if (!track->keyL->next || ((t<track->keyL->tcb.frame) && ((track->flags&LIB3DS_REPEAT) != 0))) {
+ *p = track->keyL->value;
+ return;
+ }
+
+ for (k=track->keyL; k->next!=0; k=k->next) {
+ if ((t>=(Lib3dsFloat)k->tcb.frame) && (t<(Lib3dsFloat)k->next->tcb.frame)) {
+ break;
+ }
+ }
+ if (!k->next) {
+ if (track->flags&LIB3DS_REPEAT) {
+ nt=(Lib3dsFloat)fmod(t - track->keyL->tcb.frame, k->tcb.frame - track->keyL->tcb.frame) + track->keyL->tcb.frame;
+ for (k=track->keyL; k->next!=0; k=k->next) {
+ if ((nt>=(Lib3dsFloat)k->tcb.frame) && (nt<(Lib3dsFloat)k->next->tcb.frame)) {
+ break;
+ }
+ }
+ ASSERT(k->next);
+ }
+ else {
+ *p = k->value;
+ return;
+ }
+ }
+ else {
+ nt=t;
+ }
+ u=nt - (Lib3dsFloat)k->tcb.frame;
+ u/=(Lib3dsFloat)(k->next->tcb.frame - k->tcb.frame);
+
+ *p = lib3ds_float_cubic(
+ k->value,
+ k->dd,
+ k->next->ds,
+ k->next->value,
+ u
+ );
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_lin1_track_read(Lib3dsLin1Track *track, Lib3dsIo *io)
+{
+ int keys;
+ int i;
+ Lib3dsLin1Key *k;
+
+ track->flags=lib3ds_io_read_word(io);
+ lib3ds_io_read_dword(io);
+ lib3ds_io_read_dword(io);
+ keys=lib3ds_io_read_intd(io);
+
+ for (i=0; i<keys; ++i) {
+ k=lib3ds_lin1_key_new();
+ if (!lib3ds_tcb_read(&k->tcb, io)) {
+ return(LIB3DS_FALSE);
+ }
+ k->value=lib3ds_io_read_float(io);
+ lib3ds_lin1_track_insert(track, k);
+ }
+ lib3ds_lin1_track_setup(track);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_lin1_track_write(Lib3dsLin1Track *track, Lib3dsIo *io)
+{
+ Lib3dsLin1Key *k;
+ Lib3dsDword num=0;
+ for (k=track->keyL; k; k=k->next) {
+ ++num;
+ }
+ lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, num);
+
+ for (k=track->keyL; k; k=k->next) {
+ if (!lib3ds_tcb_write(&k->tcb,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_float(io, k->value);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Create and return one keyframe in a Lin3 track. All values are
+ * initialized to zero.
+ *
+ * \ingroup tracks
+ */
+Lib3dsLin3Key*
+lib3ds_lin3_key_new()
+{
+ Lib3dsLin3Key* k;
+ k=(Lib3dsLin3Key*)calloc(sizeof(Lib3dsLin3Key), 1);
+ return(k);
+}
+
+
+/*!
+ * Free a Lin3 keyframe.
+ *
+ * \ingroup tracks
+ */
+void
+lib3ds_lin3_key_free(Lib3dsLin3Key *key)
+{
+ ASSERT(key);
+ free(key);
+}
+
+
+/*!
+ * Free all keyframes in a Lin3 track.
+ *
+ * \ingroup tracks
+ */
+void
+lib3ds_lin3_track_free_keys(Lib3dsLin3Track *track)
+{
+ Lib3dsLin3Key *p,*q;
+
+ ASSERT(track);
+ for (p=track->keyL; p; p=q) {
+ q=p->next;
+ lib3ds_lin3_key_free(p);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin3_key_setup(Lib3dsLin3Key *p, Lib3dsLin3Key *cp, Lib3dsLin3Key *c,
+ Lib3dsLin3Key *cn, Lib3dsLin3Key *n)
+{
+ Lib3dsVector np,nn;
+ Lib3dsFloat ksm,ksp,kdm,kdp;
+ int i;
+
+ ASSERT(c);
+ if (!cp) {
+ cp=c;
+ }
+ if (!cn) {
+ cn=c;
+ }
+ if (!p && !n) {
+ lib3ds_vector_zero(c->ds);
+ lib3ds_vector_zero(c->dd);
+ return;
+ }
+
+ if (n && p) {
+ lib3ds_tcb(&p->tcb, &cp->tcb, &c->tcb, &cn->tcb, &n->tcb, &ksm, &ksp, &kdm, &kdp);
+ lib3ds_vector_sub(np, c->value, p->value);
+ lib3ds_vector_sub(nn, n->value, c->value);
+
+ for (i=0; i<3; ++i) {
+ c->ds[i]=ksm*np[i] + ksp*nn[i];
+ c->dd[i]=kdm*np[i] + kdp*nn[i];
+ }
+ }
+ else {
+ if (p) {
+ lib3ds_vector_sub(np, c->value, p->value);
+ lib3ds_vector_copy(c->ds, np);
+ lib3ds_vector_copy(c->dd, np);
+ }
+ if (n) {
+ lib3ds_vector_sub(nn, n->value, c->value);
+ lib3ds_vector_copy(c->ds, nn);
+ lib3ds_vector_copy(c->dd, nn);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin3_track_setup(Lib3dsLin3Track *track)
+{
+ Lib3dsLin3Key *pp,*pc,*pn,*pl;
+
+ ASSERT(track);
+ pc=track->keyL;
+ if (!pc) {
+ return;
+ }
+ if (!pc->next) {
+ lib3ds_vector_zero(pc->ds);
+ lib3ds_vector_zero(pc->dd);
+ return;
+ }
+
+ if (track->flags&LIB3DS_SMOOTH) {
+ for (pl=track->keyL; pl->next->next; pl=pl->next);
+ lib3ds_lin3_key_setup(pl, pl->next, pc, 0, pc->next);
+ }
+ else {
+ lib3ds_lin3_key_setup(0, 0, pc, 0, pc->next);
+ }
+ for (;;) {
+ pp=pc;
+ pc=pc->next;
+ pn=pc->next;
+ if (!pn) {
+ break;
+ }
+ lib3ds_lin3_key_setup(pp, 0, pc, 0, pn);
+ }
+
+ if (track->flags&LIB3DS_SMOOTH) {
+ lib3ds_lin3_key_setup(pp, 0, pc, track->keyL, track->keyL->next);
+ }
+ else {
+ lib3ds_lin3_key_setup(pp, 0, pc, 0, 0);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin3_track_insert(Lib3dsLin3Track *track, Lib3dsLin3Key *key)
+{
+ ASSERT(track);
+ ASSERT(key);
+ ASSERT(!key->next);
+
+ if (!track->keyL) {
+ track->keyL=key;
+ key->next=0;
+ }
+ else {
+ Lib3dsLin3Key *k,*p;
+
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame>key->tcb.frame) {
+ break;
+ }
+ }
+ if (!p) {
+ key->next=track->keyL;
+ track->keyL=key;
+ }
+ else {
+ key->next=k;
+ p->next=key;
+ }
+
+ if (k && (key->tcb.frame==k->tcb.frame)) {
+ key->next=k->next;
+ lib3ds_lin3_key_free(k);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin3_track_remove(Lib3dsLin3Track *track, Lib3dsIntd frame)
+{
+ Lib3dsLin3Key *k,*p;
+
+ ASSERT(track);
+ if (!track->keyL) {
+ return;
+ }
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame==frame) {
+ if (!p) {
+ track->keyL=track->keyL->next;
+ }
+ else {
+ p->next=k->next;
+ }
+ lib3ds_lin3_key_free(k);
+ break;
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_lin3_track_eval(Lib3dsLin3Track *track, Lib3dsVector p, Lib3dsFloat t)
+{
+ Lib3dsLin3Key *k;
+ Lib3dsFloat nt;
+ Lib3dsFloat u;
+
+ if (!track->keyL) {
+ lib3ds_vector_zero(p);
+ return;
+ }
+ if (!track->keyL->next || ((t<track->keyL->tcb.frame) && ((track->flags&LIB3DS_REPEAT) != 0))) {
+ lib3ds_vector_copy(p, track->keyL->value);
+ return;
+ }
+
+ for (k=track->keyL; k->next!=0; k=k->next) {
+ if ((t>=(Lib3dsFloat)k->tcb.frame) && (t<(Lib3dsFloat)k->next->tcb.frame)) {
+ break;
+ }
+ }
+ if (!k->next) {
+ if (track->flags&LIB3DS_REPEAT) {
+ nt=(Lib3dsFloat)fmod(t - track->keyL->tcb.frame, k->tcb.frame - track->keyL->tcb.frame) + track->keyL->tcb.frame;
+ for (k=track->keyL; k->next!=0; k=k->next) {
+ if ((nt>=(Lib3dsFloat)k->tcb.frame) && (nt<(Lib3dsFloat)k->next->tcb.frame)) {
+ break;
+ }
+ }
+ ASSERT(k->next);
+ }
+ else {
+ lib3ds_vector_copy(p, k->value);
+ return;
+ }
+ }
+ else {
+ nt=t;
+ }
+ u=nt - (Lib3dsFloat)k->tcb.frame;
+ u/=(Lib3dsFloat)(k->next->tcb.frame - k->tcb.frame);
+
+ lib3ds_vector_cubic(
+ p,
+ k->value,
+ k->dd,
+ k->next->ds,
+ k->next->value,
+ u
+ );
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_lin3_track_read(Lib3dsLin3Track *track, Lib3dsIo *io)
+{
+ int keys;
+ int i,j;
+ Lib3dsLin3Key *k;
+
+ track->flags=lib3ds_io_read_word(io);
+ lib3ds_io_read_dword(io);
+ lib3ds_io_read_dword(io);
+ keys=lib3ds_io_read_intd(io);
+
+ for (i=0; i<keys; ++i) {
+ k=lib3ds_lin3_key_new();
+ if (!lib3ds_tcb_read(&k->tcb, io)) {
+ return(LIB3DS_FALSE);
+ }
+ for (j=0; j<3; ++j) {
+ k->value[j]=lib3ds_io_read_float(io);
+ }
+ lib3ds_lin3_track_insert(track, k);
+ }
+ lib3ds_lin3_track_setup(track);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_lin3_track_write(Lib3dsLin3Track *track, Lib3dsIo *io)
+{
+ Lib3dsLin3Key *k;
+ Lib3dsDword num=0;
+ for (k=track->keyL; k; k=k->next) {
+ ++num;
+ }
+ lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, num);
+
+ for (k=track->keyL; k; k=k->next) {
+ if (!lib3ds_tcb_write(&k->tcb,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_vector(io, k->value);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsQuatKey*
+lib3ds_quat_key_new()
+{
+ Lib3dsQuatKey* k;
+ k=(Lib3dsQuatKey*)calloc(sizeof(Lib3dsQuatKey), 1);
+ return(k);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_quat_key_free(Lib3dsQuatKey *key)
+{
+ ASSERT(key);
+ free(key);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_quat_track_free_keys(Lib3dsQuatTrack *track)
+{
+ Lib3dsQuatKey *p,*q;
+
+ ASSERT(track);
+ for (p=track->keyL; p; p=q) {
+ q=p->next;
+ lib3ds_quat_key_free(p);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_quat_key_setup(Lib3dsQuatKey *p, Lib3dsQuatKey *cp, Lib3dsQuatKey *c,
+ Lib3dsQuatKey *cn, Lib3dsQuatKey *n)
+{
+ Lib3dsFloat ksm,ksp,kdm,kdp;
+ Lib3dsQuat q,qp,qn,qa,qb;
+ int i;
+
+ ASSERT(c);
+ if (!cp) {
+ cp=c;
+ }
+ if (!cn) {
+ cn=c;
+ }
+ if (!p || !n) {
+ lib3ds_quat_copy(c->ds, c->q);
+ lib3ds_quat_copy(c->dd, c->q);
+ return;
+ }
+
+ if (p) {
+ if (p->angle>LIB3DS_TWOPI-LIB3DS_EPSILON) {
+ lib3ds_quat_axis_angle(qp, p->axis, 0.0f);
+ lib3ds_quat_ln(qp);
+ }
+ else {
+ lib3ds_quat_copy(q, p->q);
+ if (lib3ds_quat_dot(q,c->q)<0) lib3ds_quat_neg(q);
+
+ lib3ds_quat_ln_dif(qp, q, c->q);
+ }
+ }
+ if (n) {
+ if (n->angle>LIB3DS_TWOPI-LIB3DS_EPSILON) {
+ lib3ds_quat_axis_angle(qn, n->axis, 0.0f);
+ lib3ds_quat_ln(qn);
+ }
+ else {
+ lib3ds_quat_copy(q, n->q);
+ if (lib3ds_quat_dot(q,c->q)<0) lib3ds_quat_neg(q);
+ lib3ds_quat_ln_dif(qn, c->q, q);
+ }
+ }
+
+ if (n && p) {
+ lib3ds_tcb(&p->tcb, &cp->tcb, &c->tcb, &cn->tcb, &n->tcb, &ksm, &ksp, &kdm, &kdp);
+ for (i=0; i<4; i++) {
+ qa[i]=0.5f*(kdm*qp[i]+(kdp-1.f)*qn[i]);
+ qb[i]=0.5f*((1.f-ksm)*qp[i]-ksp*qn[i]);
+ }
+ lib3ds_quat_exp(qa);
+ lib3ds_quat_exp(qb);
+
+ lib3ds_quat_mul(c->ds, c->q, qb);
+ lib3ds_quat_mul(c->dd, c->q, qa);
+ }
+ else {
+ if (p) {
+ lib3ds_quat_exp(qp);
+ lib3ds_quat_mul(c->ds, c->q, qp);
+ lib3ds_quat_mul(c->dd, c->q, qp);
+ }
+ if (n) {
+ lib3ds_quat_exp(qn);
+ lib3ds_quat_mul(c->ds, c->q, qn);
+ lib3ds_quat_mul(c->dd, c->q, qn);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_quat_track_setup(Lib3dsQuatTrack *track)
+{
+ Lib3dsQuatKey *pp,*pc,*pn,*pl;
+ Lib3dsQuat q;
+
+ ASSERT(track);
+ for (pp=0,pc=track->keyL; pc; pp=pc,pc=pc->next) {
+ lib3ds_quat_axis_angle(q, pc->axis, pc->angle);
+ if (pp) {
+ lib3ds_quat_mul(pc->q, q, pp->q);
+ }
+ else {
+ lib3ds_quat_copy(pc->q, q);
+ }
+ }
+
+ pc=track->keyL;
+ if (!pc) {
+ return;
+ }
+ if (!pc->next) {
+ lib3ds_quat_copy(pc->ds, pc->q);
+ lib3ds_quat_copy(pc->dd, pc->q);
+ return;
+ }
+
+ if (track->flags&LIB3DS_SMOOTH) {
+ for (pl=track->keyL; pl->next->next; pl=pl->next);
+ lib3ds_quat_key_setup(pl, pl->next, pc, 0, pc->next);
+ }
+ else {
+ lib3ds_quat_key_setup(0, 0, pc, 0, pc->next);
+ }
+ for (;;) {
+ pp=pc;
+ pc=pc->next;
+ pn=pc->next;
+ if (!pn) {
+ break;
+ }
+ lib3ds_quat_key_setup(pp, 0, pc, 0, pn);
+ }
+
+ if (track->flags&LIB3DS_SMOOTH) {
+ lib3ds_quat_key_setup(pp, 0, pc, track->keyL, track->keyL->next);
+ }
+ else {
+ lib3ds_quat_key_setup(pp, 0, pc, 0, 0);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_quat_track_insert(Lib3dsQuatTrack *track, Lib3dsQuatKey *key)
+{
+ ASSERT(track);
+ ASSERT(key);
+ ASSERT(!key->next);
+
+ if (!track->keyL) {
+ track->keyL=key;
+ key->next=0;
+ }
+ else {
+ Lib3dsQuatKey *k,*p;
+
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame>key->tcb.frame) {
+ break;
+ }
+ }
+ if (!p) {
+ key->next=track->keyL;
+ track->keyL=key;
+ }
+ else {
+ key->next=k;
+ p->next=key;
+ }
+
+ if (k && (key->tcb.frame==k->tcb.frame)) {
+ key->next=k->next;
+ lib3ds_quat_key_free(k);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_quat_track_remove(Lib3dsQuatTrack *track, Lib3dsIntd frame)
+{
+ Lib3dsQuatKey *k,*p;
+
+ ASSERT(track);
+ if (!track->keyL) {
+ return;
+ }
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame==frame) {
+ if (!p) {
+ track->keyL=track->keyL->next;
+ }
+ else {
+ p->next=k->next;
+ }
+ lib3ds_quat_key_free(k);
+ break;
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_quat_track_eval(Lib3dsQuatTrack *track, Lib3dsQuat q, Lib3dsFloat t)
+{
+ Lib3dsQuatKey *k;
+ Lib3dsFloat nt;
+ Lib3dsFloat u;
+
+ if (!track->keyL) {
+ lib3ds_quat_identity(q);
+ return;
+ }
+ if (!track->keyL->next || ((t<track->keyL->tcb.frame) && ((track->flags&LIB3DS_REPEAT) != 0))) {
+ lib3ds_quat_copy(q, track->keyL->q);
+ return;
+ }
+
+ for (k=track->keyL; k->next!=0; k=k->next) {
+ if ((t>=k->tcb.frame) && (t<k->next->tcb.frame)) {
+ break;
+ }
+ }
+ if (!k->next) {
+ if (track->flags&LIB3DS_REPEAT) {
+ nt=(Lib3dsFloat)fmod(t - track->keyL->tcb.frame, k->tcb.frame - track->keyL->tcb.frame) + track->keyL->tcb.frame;
+ for (k=track->keyL; k->next!=0; k=k->next) {
+ if ((nt>=k->tcb.frame) && (nt<k->next->tcb.frame)) {
+ break;
+ }
+ }
+ ASSERT(k->next);
+ }
+ else {
+ lib3ds_quat_copy(q, k->q);
+ return;
+ }
+ }
+ else {
+ nt=t;
+ }
+ u=nt - k->tcb.frame;
+ u/=(k->next->tcb.frame - k->tcb.frame);
+
+ lib3ds_quat_squad(
+ q,
+ k->q,
+ k->dd,
+ k->next->ds,
+ k->next->q,
+ u
+ );
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_quat_track_read(Lib3dsQuatTrack *track, Lib3dsIo *io)
+{
+ int keys;
+ int i,j;
+ Lib3dsQuatKey *p,*k;
+
+ track->flags=lib3ds_io_read_word(io);
+ lib3ds_io_read_dword(io);
+ lib3ds_io_read_dword(io);
+ keys=lib3ds_io_read_intd(io);
+
+ for (p=0,i=0; i<keys; p=k,++i) {
+ k=lib3ds_quat_key_new();
+ if (!lib3ds_tcb_read(&k->tcb, io)) {
+ return(LIB3DS_FALSE);
+ }
+ k->angle=lib3ds_io_read_float(io);
+ for (j=0; j<3; ++j) {
+ k->axis[j]=lib3ds_io_read_float(io);
+ }
+ lib3ds_quat_track_insert(track, k);
+ }
+ lib3ds_quat_track_setup(track);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_quat_track_write(Lib3dsQuatTrack *track, Lib3dsIo *io)
+{
+ Lib3dsQuatKey *k;
+ Lib3dsDword num=0;
+ for (k=track->keyL; k; k=k->next) {
+ ++num;
+ }
+ lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, 0);
+ lib3ds_io_write_dword(io, num);
+
+ for (k=track->keyL; k; k=k->next) {
+ if (!lib3ds_tcb_write(&k->tcb,io)) {
+ return(LIB3DS_FALSE);
+ }
+ lib3ds_io_write_float(io, k->angle);
+ lib3ds_io_write_vector(io, k->axis);
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsMorphKey*
+lib3ds_morph_key_new()
+{
+ Lib3dsMorphKey* k;
+ k=(Lib3dsMorphKey*)calloc(sizeof(Lib3dsMorphKey), 1);
+ return(k);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_morph_key_free(Lib3dsMorphKey *key)
+{
+ ASSERT(key);
+ free(key);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_morph_track_free_keys(Lib3dsMorphTrack *track)
+{
+ Lib3dsMorphKey *p,*q;
+
+ ASSERT(track);
+ for (p=track->keyL; p; p=q) {
+ q=p->next;
+ lib3ds_morph_key_free(p);
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_morph_track_insert(Lib3dsMorphTrack *track, Lib3dsMorphKey *key)
+{
+ ASSERT(track);
+ ASSERT(key);
+ ASSERT(!key->next);
+
+ if (!track->keyL) {
+ track->keyL=key;
+ key->next=0;
+ }
+ else {
+ Lib3dsMorphKey *k,*p;
+
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame>key->tcb.frame) {
+ break;
+ }
+ }
+ if (!p) {
+ key->next=track->keyL;
+ track->keyL=key;
+ }
+ else {
+ key->next=k;
+ p->next=key;
+ }
+
+ if (k && (key->tcb.frame==k->tcb.frame)) {
+ key->next=k->next;
+ lib3ds_morph_key_free(k);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_morph_track_remove(Lib3dsMorphTrack *track, Lib3dsIntd frame)
+{
+ Lib3dsMorphKey *k,*p;
+
+ ASSERT(track);
+ if (!track->keyL) {
+ return;
+ }
+ for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
+ if (k->tcb.frame==frame) {
+ if (!p) {
+ track->keyL=track->keyL->next;
+ }
+ else {
+ p->next=k->next;
+ }
+ lib3ds_morph_key_free(k);
+ break;
+ }
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+void
+lib3ds_morph_track_eval(Lib3dsMorphTrack *track, char *p, Lib3dsFloat t)
+{
+ Lib3dsMorphKey *k;
+ char* result;
+
+ ASSERT(p);
+ if (!track->keyL) {
+ strcpy(p,"");
+ return;
+ }
+ if (!track->keyL->next) {
+ strcpy(p,track->keyL->name);
+ return;
+ }
+
+
+ /* TODO: this function finds the mesh frame that corresponds to this
+ * timeframe. It would be better to actually interpolate the mesh.
+ */
+
+ result=0;
+
+ for (k = track->keyL;
+ k->next != NULL && t >= k->next->tcb.frame;
+ k = k->next);
+
+ result=k->name;
+
+ if (result) {
+ strcpy(p,result);
+ }
+ else {
+ strcpy(p,"");
+ }
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_morph_track_read(Lib3dsMorphTrack *track, Lib3dsIo *io)
+{
+ /* This function was written by Stephane Denis on 5-18-04 */
+ int i;
+ Lib3dsMorphKey *k, *pk = 0;
+ int keys;
+ track->flags=lib3ds_io_read_word(io);
+ lib3ds_io_read_dword(io);
+ lib3ds_io_read_dword(io);
+ keys=lib3ds_io_read_intd(io);
+
+ for (i=0; i<keys; ++i) {
+ k=lib3ds_morph_key_new();
+ if (!lib3ds_tcb_read(&k->tcb, io)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!lib3ds_io_read_string(io, k->name, 11)) {
+ return(LIB3DS_FALSE);
+ }
+ if (!track->keyL)
+ track->keyL = k;
+ else
+ pk->next = k;
+ pk = k;
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup tracks
+ */
+Lib3dsBool
+lib3ds_morph_track_write(Lib3dsMorphTrack *track, Lib3dsIo *io)
+{
+ /* FIXME: */
+ ASSERT(0);
+ LIB3DS_UNUSED(track);
+ LIB3DS_UNUSED(io);
+ return(LIB3DS_FALSE);
+}
+
+
+
+void
+tcb_dump(Lib3dsTcb *tcb)
+{
+ printf(" tcb: frame=%d, flags=%04x, tens=%g, cont=%g, ",
+ tcb->frame, tcb->flags, tcb->tens, tcb->cont);
+ printf("bias=%g, ease_to=%g, ease_from=%g\n",
+ tcb->bias, tcb->ease_to, tcb->ease_from);
+}
+
+
+void
+lib3ds_boolTrack_dump(Lib3dsBoolTrack *track)
+{
+ Lib3dsBoolKey *key;
+ printf("flags: %08x, keys:\n", track->flags);
+ for ( key = track->keyL; key != NULL; key = key->next)
+ {
+ tcb_dump(&key->tcb);
+ }
+}
+
+
+void
+lib3ds_lin1Track_dump(Lib3dsLin1Track *track)
+{
+ Lib3dsLin1Key *key;
+ printf("flags: %08x, keys:\n", track->flags);
+ for ( key = track->keyL; key != NULL; key = key->next)
+ {
+ tcb_dump(&key->tcb);
+ printf(" value = %g, dd=%g, ds=%g\n",
+ key->value, key->dd, key->ds);
+ }
+}
+
+
+void
+lib3ds_lin3Track_dump(Lib3dsLin3Track *track)
+{
+ Lib3dsLin3Key *key;
+ printf("flags: %08x, keys:\n", track->flags);
+ for ( key = track->keyL; key != NULL; key = key->next)
+ {
+ tcb_dump(&key->tcb);
+ printf(" value = %g,%g,%g, dd=%g,%g,%g, ds=%g,%g,%g\n",
+ key->value[0], key->value[1], key->value[2],
+ key->dd[0], key->dd[1], key->dd[2],
+ key->ds[0], key->ds[1], key->ds[2]);
+ }
+}
+
+
+void
+lib3ds_quatTrack_dump(Lib3dsQuatTrack *track)
+{
+ Lib3dsQuatKey *key;
+ printf("flags: %08x, keys:\n", track->flags);
+ for ( key = track->keyL; key != NULL; key = key->next)
+ {
+ tcb_dump(&key->tcb);
+ printf(" axis = %g,%g,%g, angle=%g, q=%g,%g,%g,%g\n",
+ key->axis[0], key->axis[1], key->axis[2], key->angle,
+ key->q[0], key->q[1], key->q[2], key->q[3]);
+ printf(" dd = %g,%g,%g,%g, ds=%g,%g,%g,%g\n",
+ key->dd[0], key->dd[1], key->dd[2], key->dd[3],
+ key->ds[0], key->ds[1], key->ds[2], key->ds[3]);
+ }
+}
+
+
+void
+lib3ds_morphTrack_dump(Lib3dsMorphTrack *track)
+{
+ Lib3dsMorphKey *key;
+ printf("flags: %08x, keys:\n", track->flags);
+ for ( key = track->keyL; key != NULL; key = key->next)
+ {
+ tcb_dump(&key->tcb);
+ printf(" name = %s\n", key->name);
+ }
+}
+
+
+
+void
+lib3ds_dump_tracks(Lib3dsNode *node)
+{
+ switch( node->type ) {
+ case LIB3DS_AMBIENT_NODE:
+ printf("ambient: ");
+ lib3ds_lin3Track_dump(&node->data.ambient.col_track);
+ break;
+ case LIB3DS_OBJECT_NODE:
+ printf("pos: ");
+ lib3ds_lin3Track_dump(&node->data.object.pos_track);
+ printf("rot: ");
+ lib3ds_quatTrack_dump(&node->data.object.rot_track);
+ printf("scl: ");
+ lib3ds_lin3Track_dump(&node->data.object.scl_track);
+ printf("morph: ");
+ lib3ds_morphTrack_dump(&node->data.object.morph_track);
+ printf("hide: ");
+ lib3ds_boolTrack_dump(&node->data.object.hide_track);
+ break;
+ case LIB3DS_CAMERA_NODE:
+ printf("pos: ");
+ lib3ds_lin3Track_dump(&node->data.camera.pos_track);
+ printf("fov: ");
+ lib3ds_lin1Track_dump(&node->data.camera.fov_track);
+ printf("roll: ");
+ lib3ds_lin1Track_dump(&node->data.camera.roll_track);
+ break;
+ case LIB3DS_TARGET_NODE:
+ printf("pos: ");
+ lib3ds_lin3Track_dump(&node->data.target.pos_track);
+ break;
+ case LIB3DS_LIGHT_NODE:
+ printf("pos: ");
+ lib3ds_lin3Track_dump(&node->data.light.pos_track);
+ printf("col: ");
+ lib3ds_lin3Track_dump(&node->data.light.col_track);
+ printf("hotspot: ");
+ lib3ds_lin1Track_dump(&node->data.light.hotspot_track);
+ printf("falloff: ");
+ lib3ds_lin1Track_dump(&node->data.light.falloff_track);
+ printf("roll: ");
+ lib3ds_lin1Track_dump(&node->data.light.roll_track);
+ break;
+ case LIB3DS_SPOT_NODE:
+ printf("pos: ");
+ lib3ds_lin3Track_dump(&node->data.spot.pos_track);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/3rdparty/lib3ds/tracks.h b/3rdparty/lib3ds/tracks.h
new file mode 100644
index 000000000..7783e51c5
--- /dev/null
+++ b/3rdparty/lib3ds/tracks.h
@@ -0,0 +1,209 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_TRACKS_H
+#define INCLUDED_LIB3DS_TRACKS_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: tracks.h,v 1.11 2007/06/20 17:04:09 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TCB_H
+#include <lib3ds/tcb.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Track flags
+ * \ingroup tracks
+ */
+typedef enum {
+ LIB3DS_REPEAT =0x0001,
+ LIB3DS_SMOOTH =0x0002,
+ LIB3DS_LOCK_X =0x0008,
+ LIB3DS_LOCK_Y =0x0010,
+ LIB3DS_LOCK_Z =0x0020,
+ LIB3DS_UNLINK_X =0x0100,
+ LIB3DS_UNLINK_Y =0x0200,
+ LIB3DS_UNLINK_Z =0x0400
+} Lib3dsTrackFlags;
+
+/**
+ * Boolean track key
+ * \ingroup tracks
+ */
+struct Lib3dsBoolKey {
+ Lib3dsTcb tcb;
+ Lib3dsBoolKey *next;
+};
+
+/**
+ * Boolean track
+ * \ingroup tracks
+ */
+struct Lib3dsBoolTrack {
+ Lib3dsDword flags;
+ Lib3dsBoolKey *keyL;
+};
+
+/**
+ * Floating-point track key
+ * \ingroup tracks
+ */
+struct Lib3dsLin1Key {
+ Lib3dsTcb tcb;
+ Lib3dsLin1Key *next;
+ Lib3dsFloat value;
+ Lib3dsFloat dd;
+ Lib3dsFloat ds;
+};
+
+/**
+ * Floating-point track
+ * \ingroup tracks
+ */
+struct Lib3dsLin1Track {
+ Lib3dsDword flags;
+ Lib3dsLin1Key *keyL;
+};
+
+/**
+ * Vector track key
+ * \ingroup tracks
+ */
+struct Lib3dsLin3Key {
+ Lib3dsTcb tcb;
+ Lib3dsLin3Key *next;
+ Lib3dsVector value;
+ Lib3dsVector dd;
+ Lib3dsVector ds;
+};
+
+/**
+ * Vector track
+ * \ingroup tracks
+ */
+struct Lib3dsLin3Track {
+ Lib3dsDword flags;
+ Lib3dsLin3Key *keyL;
+};
+
+/**
+ * Rotation track key
+ * \ingroup tracks
+ */
+struct Lib3dsQuatKey {
+ Lib3dsTcb tcb;
+ Lib3dsQuatKey *next;
+ Lib3dsVector axis;
+ Lib3dsFloat angle;
+ Lib3dsQuat q;
+ Lib3dsQuat dd;
+ Lib3dsQuat ds;
+};
+
+/**
+ * Rotation track
+ * \ingroup tracks
+ */
+struct Lib3dsQuatTrack {
+ Lib3dsDword flags;
+ Lib3dsQuatKey *keyL;
+};
+
+/**
+ * Morph track key
+ * \ingroup tracks
+ */
+struct Lib3dsMorphKey {
+ Lib3dsTcb tcb;
+ Lib3dsMorphKey *next;
+ char name[64];
+};
+
+/**
+ * Morph track
+ * \ingroup tracks
+ */
+struct Lib3dsMorphTrack {
+ Lib3dsDword flags;
+ Lib3dsMorphKey *keyL;
+};
+
+extern LIB3DSAPI Lib3dsBoolKey* lib3ds_bool_key_new();
+extern LIB3DSAPI void lib3ds_bool_key_free(Lib3dsBoolKey* key);
+extern LIB3DSAPI void lib3ds_bool_track_free_keys(Lib3dsBoolTrack *track);
+extern LIB3DSAPI void lib3ds_bool_track_insert(Lib3dsBoolTrack *track, Lib3dsBoolKey* key);
+extern LIB3DSAPI void lib3ds_bool_track_remove(Lib3dsBoolTrack *track, Lib3dsIntd frame);
+extern LIB3DSAPI void lib3ds_bool_track_eval(Lib3dsBoolTrack *track, Lib3dsBool *p, Lib3dsFloat t);
+extern LIB3DSAPI Lib3dsBool lib3ds_bool_track_read(Lib3dsBoolTrack *track, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_bool_track_write(Lib3dsBoolTrack *track, Lib3dsIo *io);
+
+extern LIB3DSAPI Lib3dsLin1Key* lib3ds_lin1_key_new();
+extern LIB3DSAPI void lib3ds_lin1_key_free(Lib3dsLin1Key* key);
+extern LIB3DSAPI void lib3ds_lin1_track_free_keys(Lib3dsLin1Track *track);
+extern LIB3DSAPI void lib3ds_lin1_key_setup(Lib3dsLin1Key *p, Lib3dsLin1Key *cp, Lib3dsLin1Key *c,
+ Lib3dsLin1Key *cn, Lib3dsLin1Key *n);
+extern LIB3DSAPI void lib3ds_lin1_track_setup(Lib3dsLin1Track *track);
+extern LIB3DSAPI void lib3ds_lin1_track_insert(Lib3dsLin1Track *track, Lib3dsLin1Key *key);
+extern LIB3DSAPI void lib3ds_lin1_track_remove(Lib3dsLin1Track *track, Lib3dsIntd frame);
+extern LIB3DSAPI void lib3ds_lin1_track_eval(Lib3dsLin1Track *track, Lib3dsFloat *p, Lib3dsFloat t);
+extern LIB3DSAPI Lib3dsBool lib3ds_lin1_track_read(Lib3dsLin1Track *track, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_lin1_track_write(Lib3dsLin1Track *track, Lib3dsIo *io);
+
+extern LIB3DSAPI Lib3dsLin3Key* lib3ds_lin3_key_new();
+extern LIB3DSAPI void lib3ds_lin3_key_free(Lib3dsLin3Key* key);
+extern LIB3DSAPI void lib3ds_lin3_track_free_keys(Lib3dsLin3Track *track);
+extern LIB3DSAPI void lib3ds_lin3_key_setup(Lib3dsLin3Key *p, Lib3dsLin3Key *cp, Lib3dsLin3Key *c,
+ Lib3dsLin3Key *cn, Lib3dsLin3Key *n);
+extern LIB3DSAPI void lib3ds_lin3_track_setup(Lib3dsLin3Track *track);
+extern LIB3DSAPI void lib3ds_lin3_track_insert(Lib3dsLin3Track *track, Lib3dsLin3Key *key);
+extern LIB3DSAPI void lib3ds_lin3_track_remove(Lib3dsLin3Track *track, Lib3dsIntd frame);
+extern LIB3DSAPI void lib3ds_lin3_track_eval(Lib3dsLin3Track *track, Lib3dsVector p, Lib3dsFloat t);
+extern LIB3DSAPI Lib3dsBool lib3ds_lin3_track_read(Lib3dsLin3Track *track, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_lin3_track_write(Lib3dsLin3Track *track, Lib3dsIo *io);
+
+extern LIB3DSAPI Lib3dsQuatKey* lib3ds_quat_key_new();
+extern LIB3DSAPI void lib3ds_quat_key_free(Lib3dsQuatKey* key);
+extern LIB3DSAPI void lib3ds_quat_track_free_keys(Lib3dsQuatTrack *track);
+extern LIB3DSAPI void lib3ds_quat_key_setup(Lib3dsQuatKey *p, Lib3dsQuatKey *cp, Lib3dsQuatKey *c,
+ Lib3dsQuatKey *cn, Lib3dsQuatKey *n);
+extern LIB3DSAPI void lib3ds_quat_track_setup(Lib3dsQuatTrack *track);
+extern LIB3DSAPI void lib3ds_quat_track_insert(Lib3dsQuatTrack *track, Lib3dsQuatKey *key);
+extern LIB3DSAPI void lib3ds_quat_track_remove(Lib3dsQuatTrack *track, Lib3dsIntd frame);
+extern LIB3DSAPI void lib3ds_quat_track_eval(Lib3dsQuatTrack *track, Lib3dsQuat p, Lib3dsFloat t);
+extern LIB3DSAPI Lib3dsBool lib3ds_quat_track_read(Lib3dsQuatTrack *track, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_quat_track_write(Lib3dsQuatTrack *track, Lib3dsIo *io);
+
+extern LIB3DSAPI Lib3dsMorphKey* lib3ds_morph_key_new();
+extern LIB3DSAPI void lib3ds_morph_key_free(Lib3dsMorphKey* key);
+extern LIB3DSAPI void lib3ds_morph_track_free_keys(Lib3dsMorphTrack *track);
+extern LIB3DSAPI void lib3ds_morph_track_insert(Lib3dsMorphTrack *track, Lib3dsMorphKey *key);
+extern LIB3DSAPI void lib3ds_morph_track_remove(Lib3dsMorphTrack *track, Lib3dsIntd frame);
+extern LIB3DSAPI void lib3ds_morph_track_eval(Lib3dsMorphTrack *track, char *p, Lib3dsFloat t);
+extern LIB3DSAPI Lib3dsBool lib3ds_morph_track_read(Lib3dsMorphTrack *track, Lib3dsIo *io);
+extern LIB3DSAPI Lib3dsBool lib3ds_morph_track_write(Lib3dsMorphTrack *track, Lib3dsIo *io);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/types.h b/3rdparty/lib3ds/types.h
new file mode 100644
index 000000000..77fe00c72
--- /dev/null
+++ b/3rdparty/lib3ds/types.h
@@ -0,0 +1,159 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#define INCLUDED_LIB3DS_TYPES_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: types.h,v 1.25 2007/06/21 08:36:41 jeh Exp $
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+#ifdef _MSC_VER
+#ifdef LIB3DS_EXPORTS
+#define LIB3DSAPI __declspec(dllexport)
+#else
+#define LIB3DSAPI __declspec(dllimport)
+#endif
+#else
+#define LIB3DSAPI
+#endif
+*/
+#define LIB3DSAPI
+#define LIB3DS_UNUSED(x) (void)x
+
+#define LIB3DS_TRUE 1
+#define LIB3DS_FALSE 0
+
+#ifdef _MSC_VER
+typedef __int32 Lib3dsBool;
+typedef unsigned __int8 Lib3dsByte;
+typedef unsigned __int16 Lib3dsWord;
+typedef unsigned __int32 Lib3dsDword;
+typedef signed __int8 Lib3dsIntb;
+typedef signed __int16 Lib3dsIntw;
+typedef signed __int16 Lib3dsIntd;
+#else
+#include <stdint.h>
+typedef int32_t Lib3dsBool;
+typedef uint8_t Lib3dsByte;
+typedef uint16_t Lib3dsWord;
+typedef uint32_t Lib3dsDword;
+typedef int8_t Lib3dsIntb;
+typedef int16_t Lib3dsIntw;
+typedef int32_t Lib3dsIntd;
+#endif
+
+typedef float Lib3dsFloat;
+typedef double Lib3dsDouble;
+
+typedef float Lib3dsVector[3];
+typedef float Lib3dsTexel[2];
+typedef float Lib3dsQuat[4];
+typedef float Lib3dsMatrix[4][4];
+typedef float Lib3dsRgb[3];
+typedef float Lib3dsRgba[4];
+
+#define LIB3DS_EPSILON (1e-8)
+#define LIB3DS_PI 3.14159265358979323846
+#define LIB3DS_TWOPI (2.0*LIB3DS_PI)
+#define LIB3DS_HALFPI (LIB3DS_PI/2.0)
+#define LIB3DS_RAD_TO_DEG(x) ((180.0/LIB3DS_PI)*(x))
+#define LIB3DS_DEG_TO_RAD(x) ((LIB3DS_PI/180.0)*(x))
+
+#include <stdio.h>
+
+#ifdef _DEBUG
+ #ifndef ASSERT
+ #include <assert.h>
+ #define ASSERT(__expr) assert(__expr)
+ #endif
+ #define LIB3DS_ERROR_LOG \
+ {printf("\t***LIB3DS_ERROR_LOG*** %s : %d\n", __FILE__, __LINE__);}
+#else
+ #ifndef ASSERT
+ #define ASSERT(__expr)
+ #endif
+ #define LIB3DS_ERROR_LOG
+#endif
+
+typedef struct Lib3dsIo Lib3dsIo;
+typedef struct Lib3dsFile Lib3dsFile;
+typedef struct Lib3dsBackground Lib3dsBackground;
+typedef struct Lib3dsAtmosphere Lib3dsAtmosphere;
+typedef struct Lib3dsShadow Lib3dsShadow;
+typedef struct Lib3dsViewport Lib3dsViewport;
+typedef struct Lib3dsMaterial Lib3dsMaterial;
+typedef struct Lib3dsFace Lib3dsFace;
+typedef struct Lib3dsBoxMap Lib3dsBoxMap;
+typedef struct Lib3dsMapData Lib3dsMapData;
+typedef struct Lib3dsMesh Lib3dsMesh;
+typedef struct Lib3dsCamera Lib3dsCamera;
+typedef struct Lib3dsLight Lib3dsLight;
+typedef struct Lib3dsBoolKey Lib3dsBoolKey;
+typedef struct Lib3dsBoolTrack Lib3dsBoolTrack;
+typedef struct Lib3dsLin1Key Lib3dsLin1Key;
+typedef struct Lib3dsLin1Track Lib3dsLin1Track;
+typedef struct Lib3dsLin3Key Lib3dsLin3Key;
+typedef struct Lib3dsLin3Track Lib3dsLin3Track;
+typedef struct Lib3dsQuatKey Lib3dsQuatKey;
+typedef struct Lib3dsQuatTrack Lib3dsQuatTrack;
+typedef struct Lib3dsMorphKey Lib3dsMorphKey;
+typedef struct Lib3dsMorphTrack Lib3dsMorphTrack;
+
+typedef enum Lib3dsNodeTypes {
+ LIB3DS_UNKNOWN_NODE =0,
+ LIB3DS_AMBIENT_NODE =1,
+ LIB3DS_OBJECT_NODE =2,
+ LIB3DS_CAMERA_NODE =3,
+ LIB3DS_TARGET_NODE =4,
+ LIB3DS_LIGHT_NODE =5,
+ LIB3DS_SPOT_NODE =6
+} Lib3dsNodeTypes;
+
+typedef struct Lib3dsNode Lib3dsNode;
+
+typedef enum Lib3dsObjectFlags {
+ LIB3DS_OBJECT_HIDDEN =0x01,
+ LIB3DS_OBJECT_VIS_LOFTER =0x02,
+ LIB3DS_OBJECT_DOESNT_CAST =0x04,
+ LIB3DS_OBJECT_MATTE =0x08,
+ LIB3DS_OBJECT_DONT_RCVSHADOW =0x10,
+ LIB3DS_OBJECT_FAST =0x20,
+ LIB3DS_OBJECT_FROZEN =0x40
+} Lib3dsObjectFlags;
+
+typedef union Lib3dsUserData {
+ void *p;
+ Lib3dsIntd i;
+ Lib3dsDword d;
+ Lib3dsFloat f;
+ Lib3dsMaterial *material;
+ Lib3dsMesh *mesh;
+ Lib3dsCamera *camera;
+ Lib3dsLight *light;
+ Lib3dsNode *node;
+} Lib3dsUserData;
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/3rdparty/lib3ds/types.txt b/3rdparty/lib3ds/types.txt
new file mode 100644
index 000000000..08d654410
--- /dev/null
+++ b/3rdparty/lib3ds/types.txt
@@ -0,0 +1,96 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: types.txt,v 1.3 2007/06/20 17:04:09 jeh Exp $
+ */
+/*!
+
+\defgroup types General Types
+
+*/
+/*!
+
+\typedef Lib3dsBool
+ \ingroup types
+ Bool Typedef
+
+*/
+/*!
+
+\typedef Lib3dsByte
+ \ingroup types
+ Byte (== 8bit unsigned int) Typedef
+
+*/
+/*!
+
+\typedef Lib3dsWord
+ \ingroup types
+ Word (== 16bit unsigned int) Typedef
+
+*/
+/*!
+
+\typedef Lib3dsDword
+ \ingroup types
+ Double-Word (== 32bit unsigned int) Typedef
+
+*/
+/*!
+
+\typedef Lib3dsIntb
+ \ingroup types
+ Signed Byte (== 8bit signed int) Typedef
+
+*/
+/*!
+
+\typedef Lib3dsIntw
+ \ingroup types
+ Signed Word (== 16bit signed int) Typedef
+
+*/
+/*!
+
+\typedef Lib3dsIntd
+ \ingroup types
+ Signed Double-Word (== 32bit signed int) Typedef
+
+*/
+/*!
+
+\typedef Lib3dsRgb
+ \ingroup types
+ Red, Green, Blue color Typedef
+
+*/
+/*!
+
+\typedef Lib3dsRgba
+ \ingroup types
+ Red, Green, Blue, Alpha color Typedef
+
+*/
+/*!
+
+\typedef Lib3dsTexel
+ \ingroup types
+ UV texture coordinates
+
+*/
diff --git a/3rdparty/lib3ds/vector.c b/3rdparty/lib3ds/vector.c
new file mode 100644
index 000000000..46f48f205
--- /dev/null
+++ b/3rdparty/lib3ds/vector.c
@@ -0,0 +1,376 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: vector.c,v 1.12 2007/06/20 17:04:09 jeh Exp $
+ */
+#include <lib3ds/vector.h>
+#include <math.h>
+
+
+/*!
+ * \defgroup vector Vector Mathematics
+ */
+
+
+/*!
+ * \typedef Lib3dsVector
+ * \ingroup vector
+ */
+
+
+/*!
+ * Clear a vector to zero.
+ *
+ * \param c Vector to clear.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_zero(Lib3dsVector c)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]=0.0f;
+ }
+}
+
+
+/*!
+ * Copy a vector.
+ *
+ * \param dest Destination vector.
+ * \param src Source vector.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_copy(Lib3dsVector dest, Lib3dsVector src)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ dest[i]=src[i];
+ }
+}
+
+
+/*!
+ * Negate a vector.
+ *
+ * \param c Vector to negate.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_neg(Lib3dsVector c)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]=-c[i];
+ }
+}
+
+
+/*!
+ * Add two vectors.
+ *
+ * \param c Result.
+ * \param a First addend.
+ * \param b Second addend.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_add(Lib3dsVector c, Lib3dsVector a, Lib3dsVector b)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]=a[i]+b[i];
+ }
+}
+
+
+/*!
+ * Subtract two vectors.
+ *
+ * \param c Result.
+ * \param a Addend.
+ * \param b Minuend.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_sub(Lib3dsVector c, Lib3dsVector a, Lib3dsVector b)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]=a[i]-b[i];
+ }
+}
+
+
+/*!
+ * Multiply a vector by a scalar.
+ *
+ * \param c Vector to be multiplied.
+ * \param k Scalar.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_scalar(Lib3dsVector c, Lib3dsFloat k)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ c[i]*=k;
+ }
+}
+
+
+/*!
+ * Compute cross product.
+ *
+ * \param c Result.
+ * \param a First vector.
+ * \param b Second vector.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_cross(Lib3dsVector c, Lib3dsVector a, Lib3dsVector b)
+{
+ c[0]=a[1]*b[2] - a[2]*b[1];
+ c[1]=a[2]*b[0] - a[0]*b[2];
+ c[2]=a[0]*b[1] - a[1]*b[0];
+}
+
+
+/*!
+ * Compute dot product.
+ *
+ * \param a First vector.
+ * \param b Second vector.
+ *
+ * \return Dot product.
+ *
+ * \ingroup vector
+ */
+Lib3dsFloat
+lib3ds_vector_dot(Lib3dsVector a, Lib3dsVector b)
+{
+ return(a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
+}
+
+
+/*!
+ * Compute square of vector.
+ *
+ * Computes x*x + y*y + z*z.
+ *
+ * \param c Vector to square.
+ *
+ * \return Square of vector.
+ *
+ * \ingroup vector
+ */
+Lib3dsFloat
+lib3ds_vector_squared(Lib3dsVector c)
+{
+ return(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]);
+}
+
+
+/*!
+ * Compute length of vector.
+ *
+ * Computes |c| = sqrt(x*x + y*y + z*z)
+ *
+ * \param c Vector to compute.
+ *
+ * \return Length of vector.
+ *
+ * \ingroup vector
+ */
+Lib3dsFloat
+lib3ds_vector_length(Lib3dsVector c)
+{
+ return((Lib3dsFloat)sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]));
+}
+
+
+/*!
+ * Normalize a vector.
+ *
+ * Scales a vector so that its length is 1.0.
+ *
+ * \param c Vector to normalize.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_normalize(Lib3dsVector c)
+{
+ Lib3dsFloat l,m;
+
+ l=(Lib3dsFloat)sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]);
+ if (fabs(l)<LIB3DS_EPSILON) {
+ if ((c[0]>=c[1]) && (c[0]>=c[2])) {
+ c[0]=1.0f;
+ c[1]=c[2]=0.0f;
+ }
+ else
+ if (c[1]>=c[2]) {
+ c[1]=1.0f;
+ c[0]=c[2]=0.0f;
+ }
+ else {
+ c[2]=1.0f;
+ c[0]=c[1]=0.0f;
+ }
+ }
+ else {
+ m=1.0f/l;
+ c[0]*=m;
+ c[1]*=m;
+ c[2]*=m;
+ }
+}
+
+
+/*!
+ * Compute a vector normal to two line segments.
+ *
+ * Computes the normal vector to the lines b-a and b-c.
+ *
+ * \param n Returned normal vector.
+ * \param a Endpoint of first line.
+ * \param b Base point of both lines.
+ * \param c Endpoint of second line.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_normal(Lib3dsVector n, Lib3dsVector a, Lib3dsVector b, Lib3dsVector c)
+{
+ Lib3dsVector p,q;
+
+ lib3ds_vector_sub(p,c,b);
+ lib3ds_vector_sub(q,a,b);
+ lib3ds_vector_cross(n,p,q);
+ lib3ds_vector_normalize(n);
+}
+
+
+/*!
+ * Multiply a point by a transformation matrix.
+ *
+ * Applies the given transformation matrix to the given point. With some
+ * transformation matrices, a vector may also be transformed.
+ *
+ * \param c Result.
+ * \param m Transformation matrix.
+ * \param a Input point.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_transform(Lib3dsVector c, Lib3dsMatrix m, Lib3dsVector a)
+{
+ c[0]= m[0][0]*a[0] + m[1][0]*a[1] + m[2][0]*a[2] + m[3][0];
+ c[1]= m[0][1]*a[0] + m[1][1]*a[1] + m[2][1]*a[2] + m[3][1];
+ c[2]= m[0][2]*a[0] + m[1][2]*a[1] + m[2][2]*a[2] + m[3][2];
+}
+
+
+/*!
+ * Compute a point on a cubic spline.
+ *
+ * Computes a point on a parametric Bezier spline.
+ *
+ * \param c Result.
+ * \param a First endpoint of the spline.
+ * \param p First tangent vector of the spline.
+ * \param q Second tangent vector of the spline.
+ * \param b Second endpoint of the spline.
+ * \param t Spline parameter [0. 1.]
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_cubic(Lib3dsVector c, Lib3dsVector a, Lib3dsVector p, Lib3dsVector q,
+ Lib3dsVector b, Lib3dsFloat t)
+{
+ Lib3dsDouble x,y,z,w;
+
+ x=2*t*t*t - 3*t*t + 1;
+ y=-2*t*t*t + 3*t*t;
+ z=t*t*t - 2*t*t + t;
+ w=t*t*t - t*t;
+ c[0]=(Lib3dsFloat)(x*a[0] + y*b[0] + z*p[0] + w*q[0]);
+ c[1]=(Lib3dsFloat)(x*a[1] + y*b[1] + z*p[1] + w*q[1]);
+ c[2]=(Lib3dsFloat)(x*a[2] + y*b[2] + z*p[2] + w*q[2]);
+}
+
+
+/*!
+ * c[i] = min(c[i], a[i]);
+ *
+ * Computes minimum values of x,y,z independently.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_min(Lib3dsVector c, Lib3dsVector a)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ if (a[i]<c[i]) {
+ c[i] = a[i];
+ }
+ }
+}
+
+
+/*!
+ * c[i] = max(c[i], a[i]);
+ *
+ * Computes maximum values of x,y,z independently.
+ *
+ * \ingroup vector
+ */
+void
+lib3ds_vector_max(Lib3dsVector c, Lib3dsVector a)
+{
+ int i;
+ for (i=0; i<3; ++i) {
+ if (a[i]>c[i]) {
+ c[i] = a[i];
+ }
+ }
+}
+
+
+/*!
+ * \ingroup vector
+ */
+void
+lib3ds_vector_dump(Lib3dsVector c)
+{
+ fprintf(stderr, "%f %f %f\n", c[0], c[1], c[2]);
+}
+
diff --git a/3rdparty/lib3ds/vector.h b/3rdparty/lib3ds/vector.h
new file mode 100644
index 000000000..00f273b23
--- /dev/null
+++ b/3rdparty/lib3ds/vector.h
@@ -0,0 +1,58 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_VECTOR_H
+#define INCLUDED_LIB3DS_VECTOR_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: vector.h,v 1.7 2007/06/14 09:59:10 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern LIB3DSAPI void lib3ds_vector_zero(Lib3dsVector c);
+extern LIB3DSAPI void lib3ds_vector_copy(Lib3dsVector dest, Lib3dsVector src);
+extern LIB3DSAPI void lib3ds_vector_neg(Lib3dsVector c);
+extern LIB3DSAPI void lib3ds_vector_add(Lib3dsVector c, Lib3dsVector a, Lib3dsVector b);
+extern LIB3DSAPI void lib3ds_vector_sub(Lib3dsVector c, Lib3dsVector a, Lib3dsVector b);
+extern LIB3DSAPI void lib3ds_vector_scalar(Lib3dsVector c, Lib3dsFloat k);
+extern LIB3DSAPI void lib3ds_vector_cross(Lib3dsVector c, Lib3dsVector a, Lib3dsVector b);
+extern LIB3DSAPI Lib3dsFloat lib3ds_vector_dot(Lib3dsVector a, Lib3dsVector b);
+extern LIB3DSAPI Lib3dsFloat lib3ds_vector_squared(Lib3dsVector c);
+extern LIB3DSAPI Lib3dsFloat lib3ds_vector_length(Lib3dsVector c);
+extern LIB3DSAPI void lib3ds_vector_normalize(Lib3dsVector c);
+extern LIB3DSAPI void lib3ds_vector_normal(Lib3dsVector n, Lib3dsVector a,
+ Lib3dsVector b, Lib3dsVector c);
+extern LIB3DSAPI void lib3ds_vector_transform(Lib3dsVector c, Lib3dsMatrix m, Lib3dsVector a);
+extern LIB3DSAPI void lib3ds_vector_cubic(Lib3dsVector c, Lib3dsVector a, Lib3dsVector p,
+ Lib3dsVector q, Lib3dsVector b, Lib3dsFloat t);
+extern LIB3DSAPI void lib3ds_vector_min(Lib3dsVector c, Lib3dsVector a);
+extern LIB3DSAPI void lib3ds_vector_max(Lib3dsVector c, Lib3dsVector a);
+extern LIB3DSAPI void lib3ds_vector_dump(Lib3dsVector c);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/3rdparty/lib3ds/viewport.c b/3rdparty/lib3ds/viewport.c
new file mode 100644
index 000000000..270caf8fd
--- /dev/null
+++ b/3rdparty/lib3ds/viewport.c
@@ -0,0 +1,413 @@
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: viewport.c,v 1.11 2007/06/20 17:04:09 jeh Exp $
+ */
+#include <lib3ds/viewport.h>
+#include <lib3ds/chunk.h>
+#include <lib3ds/io.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*!
+ * \defgroup viewport Viewport and default view settings
+ */
+
+
+/*!
+ * \ingroup viewport
+ */
+Lib3dsBool
+lib3ds_viewport_read(Lib3dsViewport *viewport, Lib3dsIo *io)
+{
+ Lib3dsChunk c;
+ Lib3dsWord chunk;
+
+ if (!lib3ds_chunk_read_start(&c, 0, io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ switch (c.chunk) {
+ case LIB3DS_VIEWPORT_LAYOUT:
+ {
+ int cur=0;
+ viewport->layout.style=lib3ds_io_read_word(io);
+ viewport->layout.active=lib3ds_io_read_intw(io);
+ lib3ds_io_read_intw(io);
+ viewport->layout.swap=lib3ds_io_read_intw(io);
+ lib3ds_io_read_intw(io);
+ viewport->layout.swap_prior=lib3ds_io_read_intw(io);
+ viewport->layout.swap_view=lib3ds_io_read_intw(io);
+ lib3ds_chunk_read_tell(&c, io);
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_VIEWPORT_SIZE:
+ {
+ viewport->layout.position[0]=lib3ds_io_read_word(io);
+ viewport->layout.position[1]=lib3ds_io_read_word(io);
+ viewport->layout.size[0]=lib3ds_io_read_word(io);
+ viewport->layout.size[1]=lib3ds_io_read_word(io);
+ }
+ break;
+ case LIB3DS_VIEWPORT_DATA_3:
+ {
+ lib3ds_viewport_set_views(viewport,cur+1);
+ lib3ds_io_read_intw(io);
+ viewport->layout.viewL[cur].axis_lock=lib3ds_io_read_word(io);
+ viewport->layout.viewL[cur].position[0]=lib3ds_io_read_intw(io);
+ viewport->layout.viewL[cur].position[1]=lib3ds_io_read_intw(io);
+ viewport->layout.viewL[cur].size[0]=lib3ds_io_read_intw(io);
+ viewport->layout.viewL[cur].size[1]=lib3ds_io_read_intw(io);
+ viewport->layout.viewL[cur].type=lib3ds_io_read_word(io);
+ viewport->layout.viewL[cur].zoom=lib3ds_io_read_float(io);
+ lib3ds_io_read_vector(io, viewport->layout.viewL[cur].center);
+ viewport->layout.viewL[cur].horiz_angle=lib3ds_io_read_float(io);
+ viewport->layout.viewL[cur].vert_angle=lib3ds_io_read_float(io);
+ lib3ds_io_read(io, viewport->layout.viewL[cur].camera, 11);
+ ++cur;
+ }
+ break;
+ case LIB3DS_VIEWPORT_DATA:
+ /* 3DS R2 & R3 chunk
+ unsupported */
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ }
+ break;
+ case LIB3DS_DEFAULT_VIEW:
+ {
+ memset(&viewport->default_view,0,sizeof(Lib3dsDefaultView));
+ while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
+ switch (chunk) {
+ case LIB3DS_VIEW_TOP:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_TOP;
+ lib3ds_io_read_vector(io, viewport->default_view.position);
+ viewport->default_view.width=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_VIEW_BOTTOM:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_BOTTOM;
+ lib3ds_io_read_vector(io, viewport->default_view.position);
+ viewport->default_view.width=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_VIEW_LEFT:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_LEFT;
+ lib3ds_io_read_vector(io, viewport->default_view.position);
+ viewport->default_view.width=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_VIEW_RIGHT:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_RIGHT;
+ lib3ds_io_read_vector(io, viewport->default_view.position);
+ viewport->default_view.width=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_VIEW_FRONT:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_FRONT;
+ lib3ds_io_read_vector(io, viewport->default_view.position);
+ viewport->default_view.width=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_VIEW_BACK:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_BACK;
+ lib3ds_io_read_vector(io, viewport->default_view.position);
+ viewport->default_view.width=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_VIEW_USER:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_USER;
+ lib3ds_io_read_vector(io, viewport->default_view.position);
+ viewport->default_view.width=lib3ds_io_read_float(io);
+ viewport->default_view.horiz_angle=lib3ds_io_read_float(io);
+ viewport->default_view.vert_angle=lib3ds_io_read_float(io);
+ viewport->default_view.roll_angle=lib3ds_io_read_float(io);
+ }
+ break;
+ case LIB3DS_VIEW_CAMERA:
+ {
+ viewport->default_view.type=LIB3DS_VIEW_TYPE_CAMERA;
+ lib3ds_io_read(io, viewport->default_view.camera, 11);
+ }
+ break;
+ default:
+ lib3ds_chunk_unknown(chunk);
+ }
+ }
+ }
+ break;
+ }
+
+ lib3ds_chunk_read_end(&c, io);
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * \ingroup viewport
+ */
+void
+lib3ds_viewport_set_views(Lib3dsViewport *viewport, Lib3dsDword views)
+{
+ ASSERT(viewport);
+ if (viewport->layout.views) {
+ if (views) {
+ viewport->layout.views=views;
+ viewport->layout.viewL=(Lib3dsView*)realloc(viewport->layout.viewL, sizeof(Lib3dsView)*views);
+ }
+ else {
+ free(viewport->layout.viewL);
+ viewport->layout.views=0;
+ viewport->layout.viewL=0;
+ }
+ }
+ else {
+ if (views) {
+ viewport->layout.views=views;
+ viewport->layout.viewL=(Lib3dsView*)calloc(sizeof(Lib3dsView),views);
+ }
+ }
+}
+
+
+/*!
+ * \ingroup viewport
+ */
+Lib3dsBool
+lib3ds_viewport_write(Lib3dsViewport *viewport, Lib3dsIo *io)
+{
+ if (viewport->layout.views) {
+ Lib3dsChunk c;
+ unsigned i;
+
+ c.chunk=LIB3DS_VIEWPORT_LAYOUT;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ lib3ds_io_write_word(io, viewport->layout.style);
+ lib3ds_io_write_intw(io, viewport->layout.active);
+ lib3ds_io_write_intw(io, 0);
+ lib3ds_io_write_intw(io, viewport->layout.swap);
+ lib3ds_io_write_intw(io, 0);
+ lib3ds_io_write_intw(io, viewport->layout.swap_prior);
+ lib3ds_io_write_intw(io, viewport->layout.swap_view);
+
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEWPORT_SIZE;
+ c.size=14;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_intw(io, viewport->layout.position[0]);
+ lib3ds_io_write_intw(io, viewport->layout.position[1]);
+ lib3ds_io_write_intw(io, viewport->layout.size[0]);
+ lib3ds_io_write_intw(io, viewport->layout.size[1]);
+ }
+
+ for (i=0; i<viewport->layout.views; ++i) {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEWPORT_DATA_3;
+ c.size=55;
+ lib3ds_chunk_write(&c,io);
+
+ lib3ds_io_write_intw(io, 0);
+ lib3ds_io_write_word(io, viewport->layout.viewL[i].axis_lock);
+ lib3ds_io_write_intw(io, viewport->layout.viewL[i].position[0]);
+ lib3ds_io_write_intw(io, viewport->layout.viewL[i].position[1]);
+ lib3ds_io_write_intw(io, viewport->layout.viewL[i].size[0]);
+ lib3ds_io_write_intw(io, viewport->layout.viewL[i].size[1]);
+ lib3ds_io_write_word(io, viewport->layout.viewL[i].type);
+ lib3ds_io_write_float(io, viewport->layout.viewL[i].zoom);
+ lib3ds_io_write_vector(io, viewport->layout.viewL[i].center);
+ lib3ds_io_write_float(io, viewport->layout.viewL[i].horiz_angle);
+ lib3ds_io_write_float(io, viewport->layout.viewL[i].vert_angle);
+ lib3ds_io_write(io, viewport->layout.viewL[i].camera,11);
+ }
+
+ if (!lib3ds_chunk_write_end(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+
+ if (viewport->default_view.type) {
+ Lib3dsChunk c;
+
+ c.chunk=LIB3DS_DEFAULT_VIEW;
+ if (!lib3ds_chunk_write_start(&c,io)) {
+ return(LIB3DS_FALSE);
+ }
+
+ switch (viewport->default_view.type) {
+ case LIB3DS_VIEW_TYPE_TOP:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_TOP;
+ c.size=22;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, viewport->default_view.position);
+ lib3ds_io_write_float(io, viewport->default_view.width);
+ }
+ break;
+ case LIB3DS_VIEW_TYPE_BOTTOM:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_BOTTOM;
+ c.size=22;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, viewport->default_view.position);
+ lib3ds_io_write_float(io, viewport->default_view.width);
+ }
+ break;
+ case LIB3DS_VIEW_TYPE_LEFT:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_LEFT;
+ c.size=22;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, viewport->default_view.position);
+ lib3ds_io_write_float(io, viewport->default_view.width);
+ }
+ break;
+ case LIB3DS_VIEW_TYPE_RIGHT:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_RIGHT;
+ c.size=22;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, viewport->default_view.position);
+ lib3ds_io_write_float(io, viewport->default_view.width);
+ }
+ break;
+ case LIB3DS_VIEW_TYPE_FRONT:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_FRONT;
+ c.size=22;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, viewport->default_view.position);
+ lib3ds_io_write_float(io, viewport->default_view.width);
+ }
+ break;
+ case LIB3DS_VIEW_TYPE_BACK:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_BACK;
+ c.size=22;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, viewport->default_view.position);
+ lib3ds_io_write_float(io, viewport->default_view.width);
+ }
+ break;
+ case LIB3DS_VIEW_TYPE_USER:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_USER;
+ c.size=34;
+ lib3ds_chunk_write(&c,io);
+ lib3ds_io_write_vector(io, viewport->default_view.position);
+ lib3ds_io_write_float(io, viewport->default_view.width);
+ lib3ds_io_write_float(io, viewport->default_view.horiz_angle);
+ lib3ds_io_write_float(io, viewport->default_view.vert_angle);
+ lib3ds_io_write_float(io, viewport->default_view.roll_angle);
+ }
+ break;
+ case LIB3DS_VIEW_TYPE_CAMERA:
+ {
+ Lib3dsChunk c;
+ c.chunk=LIB3DS_VIEW_CAMERA;
+ c.size=17;
+ lib3ds_chunk_write(&c, io);
+ lib3ds_io_write(io, viewport->default_view.camera, 11);
+ }
+ break;
+ }
+
+ if (!lib3ds_chunk_write_end(&c, io)) {
+ return(LIB3DS_FALSE);
+ }
+ }
+ return(LIB3DS_TRUE);
+}
+
+
+/*!
+ * Dump viewport.
+ *
+ * \param vp The viewport to be dumped.
+ *
+ * \ingroup node
+ */
+void
+lib3ds_viewport_dump(Lib3dsViewport *vp)
+{
+ Lib3dsView *view;
+ unsigned i;
+ ASSERT(vp);
+
+ printf(" viewport:\n");
+ printf(" layout:\n");
+ printf(" style: %d\n", vp->layout.style);
+ printf(" active: %d\n", vp->layout.active);
+ printf(" swap: %d\n", vp->layout.swap);
+ printf(" swap_prior: %d\n", vp->layout.swap_prior);
+ printf(" position: %d,%d\n",
+ vp->layout.position[0], vp->layout.position[1]);
+ printf(" size: %d,%d\n", vp->layout.size[0], vp->layout.size[1]);
+ printf(" views: %ld\n", (long)(vp->layout.views));
+ if (vp->layout.views > 0 && vp->layout.viewL != NULL) {
+ for (i=0, view=vp->layout.viewL; i < vp->layout.views; ++i, ++view) {
+ printf(" view %d:\n", i);
+ printf(" type: %d\n", view->type);
+ printf(" axis_lock: %d\n", view->axis_lock);
+ printf(" position: (%d,%d)\n",
+ view->position[0], view->position[1]);
+ printf(" size: (%d,%d)\n", view->size[0], view->size[1]);
+ printf(" zoom: %g\n", view->zoom);
+ printf(" center: (%g,%g,%g)\n",
+ view->center[0], view->center[1], view->center[2]);
+ printf(" horiz_angle: %g\n", view->horiz_angle);
+ printf(" vert_angle: %g\n", view->vert_angle);
+ printf(" camera: %s\n", view->camera);
+ }
+ }
+
+ printf(" default_view:\n");
+ printf(" type: %d\n", vp->default_view.type);
+ printf(" position: (%g,%g,%g)\n",
+ vp->default_view.position[0],
+ vp->default_view.position[1],
+ vp->default_view.position[2]);
+ printf(" width: %g\n", vp->default_view.width);
+ printf(" horiz_angle: %g\n", vp->default_view.horiz_angle);
+ printf(" vert_angle: %g\n", vp->default_view.vert_angle);
+ printf(" roll_angle: %g\n", vp->default_view.roll_angle);
+ printf(" camera: %s\n", vp->default_view.camera);
+}
+
diff --git a/3rdparty/lib3ds/viewport.h b/3rdparty/lib3ds/viewport.h
new file mode 100644
index 000000000..03faa1844
--- /dev/null
+++ b/3rdparty/lib3ds/viewport.h
@@ -0,0 +1,137 @@
+/* -*- c -*- */
+#ifndef INCLUDED_LIB3DS_VIEWPORT_H
+#define INCLUDED_LIB3DS_VIEWPORT_H
+/*
+ * The 3D Studio File Format Library
+ * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: viewport.h,v 1.8 2007/06/20 17:04:09 jeh Exp $
+ */
+
+#ifndef INCLUDED_LIB3DS_TYPES_H
+#include <lib3ds/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Layout view types
+ * \ingroup viewport
+ */
+typedef enum Lib3dsViewType {
+ LIB3DS_VIEW_TYPE_NOT_USED =0,
+ LIB3DS_VIEW_TYPE_TOP =1,
+ LIB3DS_VIEW_TYPE_BOTTOM =2,
+ LIB3DS_VIEW_TYPE_LEFT =3,
+ LIB3DS_VIEW_TYPE_RIGHT =4,
+ LIB3DS_VIEW_TYPE_FRONT =5,
+ LIB3DS_VIEW_TYPE_BACK =6,
+ LIB3DS_VIEW_TYPE_USER =7,
+ LIB3DS_VIEW_TYPE_SPOTLIGHT =18,
+ LIB3DS_VIEW_TYPE_CAMERA =65535
+} Lib3dsViewType;
+
+/**
+ * Layout view settings
+ * \ingroup viewport
+ */
+typedef struct Lib3dsView {
+ Lib3dsWord type;
+ Lib3dsWord axis_lock;
+ Lib3dsIntw position[2];
+ Lib3dsIntw size[2];
+ Lib3dsFloat zoom;
+ Lib3dsVector center;
+ Lib3dsFloat horiz_angle;
+ Lib3dsFloat vert_angle;
+ char camera[11];
+} Lib3dsView;
+
+/**
+ * Layout styles
+ * \ingroup viewport
+ */
+typedef enum Lib3dsLayoutStyle {
+ LIB3DS_LAYOUT_SINGLE =0,
+ LIB3DS_LAYOUT_TWO_PANE_VERT_SPLIT =1,
+ LIB3DS_LAYOUT_TWO_PANE_HORIZ_SPLIT =2,
+ LIB3DS_LAYOUT_FOUR_PANE =3,
+ LIB3DS_LAYOUT_THREE_PANE_LEFT_SPLIT =4,
+ LIB3DS_LAYOUT_THREE_PANE_BOTTOM_SPLIT =5,
+ LIB3DS_LAYOUT_THREE_PANE_RIGHT_SPLIT =6,
+ LIB3DS_LAYOUT_THREE_PANE_TOP_SPLIT =7,
+ LIB3DS_LAYOUT_THREE_PANE_VERT_SPLIT =8,
+ LIB3DS_LAYOUT_THREE_PANE_HORIZ_SPLIT =9,
+ LIB3DS_LAYOUT_FOUR_PANE_LEFT_SPLIT =10,
+ LIB3DS_LAYOUT_FOUR_PANE_RIGHT_SPLIT =11
+} Lib3dsLayoutStyle;
+
+/**
+ * Viewport layout settings
+ * \ingroup viewport
+ */
+typedef struct Lib3dsLayout {
+ Lib3dsWord style;
+ Lib3dsIntw active;
+ Lib3dsIntw swap;
+ Lib3dsIntw swap_prior;
+ Lib3dsIntw swap_view;
+ Lib3dsWord position[2];
+ Lib3dsWord size[2];
+ Lib3dsDword views;
+ Lib3dsView *viewL;
+} Lib3dsLayout;
+
+/**
+ * Default view settings
+ * \ingroup viewport
+ */
+typedef struct Lib3dsDefaultView {
+ Lib3dsWord type;
+ Lib3dsVector position;
+ Lib3dsFloat width;
+ Lib3dsFloat horiz_angle;
+ Lib3dsFloat vert_angle;
+ Lib3dsFloat roll_angle;
+ char camera[64];
+} Lib3dsDefaultView;
+
+/**
+ * Viewport and default view settings
+ * \ingroup viewport
+ */
+struct Lib3dsViewport {
+ Lib3dsLayout layout;
+ Lib3dsDefaultView default_view;
+};
+
+extern LIB3DSAPI Lib3dsBool lib3ds_viewport_read(Lib3dsViewport *viewport, Lib3dsIo *io);
+extern LIB3DSAPI void lib3ds_viewport_set_views(Lib3dsViewport *viewport, Lib3dsDword views);
+extern LIB3DSAPI Lib3dsBool lib3ds_viewport_write(Lib3dsViewport *viewport, Lib3dsIo *io);
+extern LIB3DSAPI void lib3ds_viewport_dump(Lib3dsViewport *viewport);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
+