forked from bartvdbraak/blender
f5c3c624f8
This was the last item in KX_ConvertPhysicsObject. Therefore, KX_ConvertPhysicsObject.h and KX_ConvertPhysicsObjects.cpp have been removed.
2610 lines
81 KiB
C++
2610 lines
81 KiB
C++
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
* Convert blender data to ketsji
|
|
*/
|
|
|
|
/** \file gameengine/Converter/BL_BlenderDataConversion.cpp
|
|
* \ingroup bgeconv
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
# pragma warning (disable:4786)
|
|
#endif
|
|
|
|
/* Since threaded object update we've disabled in-place
|
|
* curve evaluation (in cases when applying curve modifier
|
|
* with target curve non-evaluated yet).
|
|
*
|
|
* This requires game engine to take care of DAG and object
|
|
* evaluation (currently it's designed to export only objects
|
|
* it able to render).
|
|
*
|
|
* This workaround will make sure that curve_cache for curves
|
|
* is up-to-date.
|
|
*/
|
|
#define THREADED_DAG_WORKAROUND
|
|
|
|
#include <math.h>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
#include "BL_BlenderDataConversion.h"
|
|
#include "KX_BlenderScalarInterpolator.h"
|
|
|
|
#include "RAS_IPolygonMaterial.h"
|
|
|
|
// Expressions
|
|
#include "ListValue.h"
|
|
#include "IntValue.h"
|
|
// Collision & Fuzzics LTD
|
|
|
|
#include "PHY_Pro.h"
|
|
|
|
|
|
#include "KX_Scene.h"
|
|
#include "KX_GameObject.h"
|
|
#include "RAS_FramingManager.h"
|
|
#include "RAS_MeshObject.h"
|
|
#include "RAS_IRasterizer.h"
|
|
#include "RAS_ILightObject.h"
|
|
|
|
#include "KX_ConvertActuators.h"
|
|
#include "KX_ConvertControllers.h"
|
|
#include "KX_ConvertSensors.h"
|
|
|
|
#include "SCA_LogicManager.h"
|
|
#include "SCA_EventManager.h"
|
|
#include "SCA_TimeEventManager.h"
|
|
#include "KX_Light.h"
|
|
#include "KX_Camera.h"
|
|
#include "KX_ClientObjectInfo.h"
|
|
#include "KX_EmptyObject.h"
|
|
#include "KX_FontObject.h"
|
|
#include "MT_Point3.h"
|
|
#include "MT_Transform.h"
|
|
#include "MT_MinMax.h"
|
|
#include "SCA_IInputDevice.h"
|
|
#include "RAS_TexMatrix.h"
|
|
#include "RAS_ICanvas.h"
|
|
#include "RAS_MaterialBucket.h"
|
|
//#include "KX_BlenderPolyMaterial.h"
|
|
#include "RAS_Polygon.h"
|
|
#include "RAS_TexVert.h"
|
|
#include "RAS_BucketManager.h"
|
|
#include "BL_Material.h"
|
|
#include "KX_BlenderMaterial.h"
|
|
#include "BL_Texture.h"
|
|
|
|
#include "DNA_action_types.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_object.h"
|
|
#include "BL_ModifierDeformer.h"
|
|
#include "BL_ShapeDeformer.h"
|
|
#include "BL_SkinDeformer.h"
|
|
#include "BL_MeshDeformer.h"
|
|
#include "KX_SoftBodyDeformer.h"
|
|
//#include "BL_ArmatureController.h"
|
|
#include "BLI_utildefines.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BlenderWorldInfo.h"
|
|
|
|
#include "KX_KetsjiEngine.h"
|
|
#include "KX_BlenderSceneConverter.h"
|
|
|
|
/* This little block needed for linking to Blender... */
|
|
#ifdef WIN32
|
|
#include "BLI_winstuff.h"
|
|
#endif
|
|
|
|
/* This list includes only data type definitions */
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_material_types.h"
|
|
#include "DNA_texture_types.h"
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_lamp_types.h"
|
|
#include "DNA_group_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_camera_types.h"
|
|
#include "DNA_property_types.h"
|
|
#include "DNA_text_types.h"
|
|
#include "DNA_sensor_types.h"
|
|
#include "DNA_controller_types.h"
|
|
#include "DNA_actuator_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
#include "DNA_world_types.h"
|
|
#include "DNA_sound_types.h"
|
|
#include "DNA_key_types.h"
|
|
#include "DNA_armature_types.h"
|
|
#include "DNA_object_force.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BKE_key.h"
|
|
#include "BKE_mesh.h"
|
|
#include "MT_Point3.h"
|
|
|
|
#include "BLI_math.h"
|
|
|
|
extern "C" {
|
|
#include "BKE_scene.h"
|
|
#include "BKE_customdata.h"
|
|
#include "BKE_cdderivedmesh.h"
|
|
#include "BKE_DerivedMesh.h"
|
|
#include "BKE_material.h" /* give_current_material */
|
|
#include "BKE_image.h"
|
|
#include "IMB_imbuf_types.h"
|
|
#include "BKE_displist.h"
|
|
|
|
extern Material defmaterial; /* material.c */
|
|
}
|
|
|
|
/* end of blender include block */
|
|
|
|
#include "KX_BlenderInputDevice.h"
|
|
#include "KX_ConvertProperties.h"
|
|
#include "KX_HashedPtr.h"
|
|
|
|
|
|
#include "KX_ScalarInterpolator.h"
|
|
|
|
#include "KX_IpoConvert.h"
|
|
#include "BL_System.h"
|
|
|
|
#include "SG_Node.h"
|
|
#include "SG_BBox.h"
|
|
#include "SG_Tree.h"
|
|
|
|
#ifdef WITH_BULLET
|
|
#include "CcdPhysicsEnvironment.h"
|
|
#include "CcdGraphicController.h"
|
|
#endif
|
|
#include "KX_MotionState.h"
|
|
|
|
// This file defines relationships between parents and children
|
|
// in the game engine.
|
|
|
|
#include "KX_SG_NodeRelationships.h"
|
|
#include "KX_SG_BoneParentNodeRelationship.h"
|
|
|
|
#include "BL_ArmatureObject.h"
|
|
#include "BL_DeformableGameObject.h"
|
|
|
|
#include "KX_NavMeshObject.h"
|
|
#include "KX_ObstacleSimulation.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
//XXX void update_for_newframe();
|
|
//void BKE_scene_update_for_newframe(struct Scene *sce, unsigned int lay);
|
|
//void do_all_data_ipos(void);
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#include "BLI_threads.h"
|
|
|
|
static bool default_light_mode = 0;
|
|
|
|
static std::map<int, SCA_IInputDevice::KX_EnumInputs> create_translate_table()
|
|
{
|
|
std::map<int, SCA_IInputDevice::KX_EnumInputs> m;
|
|
|
|
/* The reverse table. In order to not confuse ourselves, we */
|
|
/* immediately convert all events that come in to KX codes. */
|
|
m[LEFTMOUSE ] = SCA_IInputDevice::KX_LEFTMOUSE;
|
|
m[MIDDLEMOUSE ] = SCA_IInputDevice::KX_MIDDLEMOUSE;
|
|
m[RIGHTMOUSE ] = SCA_IInputDevice::KX_RIGHTMOUSE;
|
|
m[WHEELUPMOUSE ] = SCA_IInputDevice::KX_WHEELUPMOUSE;
|
|
m[WHEELDOWNMOUSE ] = SCA_IInputDevice::KX_WHEELDOWNMOUSE;
|
|
m[MOUSEX ] = SCA_IInputDevice::KX_MOUSEX;
|
|
m[MOUSEY ] = SCA_IInputDevice::KX_MOUSEY;
|
|
|
|
// TIMERS
|
|
|
|
m[TIMER0 ] = SCA_IInputDevice::KX_TIMER0;
|
|
m[TIMER1 ] = SCA_IInputDevice::KX_TIMER1;
|
|
m[TIMER2 ] = SCA_IInputDevice::KX_TIMER2;
|
|
|
|
// SYSTEM
|
|
|
|
#if 0
|
|
/* **** XXX **** */
|
|
m[KEYBD ] = SCA_IInputDevice::KX_KEYBD;
|
|
m[RAWKEYBD ] = SCA_IInputDevice::KX_RAWKEYBD;
|
|
m[REDRAW ] = SCA_IInputDevice::KX_REDRAW;
|
|
m[INPUTCHANGE ] = SCA_IInputDevice::KX_INPUTCHANGE;
|
|
m[QFULL ] = SCA_IInputDevice::KX_QFULL;
|
|
m[WINFREEZE ] = SCA_IInputDevice::KX_WINFREEZE;
|
|
m[WINTHAW ] = SCA_IInputDevice::KX_WINTHAW;
|
|
m[WINCLOSE ] = SCA_IInputDevice::KX_WINCLOSE;
|
|
m[WINQUIT ] = SCA_IInputDevice::KX_WINQUIT;
|
|
m[Q_FIRSTTIME ] = SCA_IInputDevice::KX_Q_FIRSTTIME;
|
|
/* **** XXX **** */
|
|
#endif
|
|
|
|
// standard keyboard
|
|
|
|
m[AKEY ] = SCA_IInputDevice::KX_AKEY;
|
|
m[BKEY ] = SCA_IInputDevice::KX_BKEY;
|
|
m[CKEY ] = SCA_IInputDevice::KX_CKEY;
|
|
m[DKEY ] = SCA_IInputDevice::KX_DKEY;
|
|
m[EKEY ] = SCA_IInputDevice::KX_EKEY;
|
|
m[FKEY ] = SCA_IInputDevice::KX_FKEY;
|
|
m[GKEY ] = SCA_IInputDevice::KX_GKEY;
|
|
|
|
//XXX clean up
|
|
#ifdef WIN32
|
|
#define HKEY 'h'
|
|
#endif
|
|
m[HKEY ] = SCA_IInputDevice::KX_HKEY;
|
|
//XXX clean up
|
|
#ifdef WIN32
|
|
#undef HKEY
|
|
#endif
|
|
|
|
m[IKEY ] = SCA_IInputDevice::KX_IKEY;
|
|
m[JKEY ] = SCA_IInputDevice::KX_JKEY;
|
|
m[KKEY ] = SCA_IInputDevice::KX_KKEY;
|
|
m[LKEY ] = SCA_IInputDevice::KX_LKEY;
|
|
m[MKEY ] = SCA_IInputDevice::KX_MKEY;
|
|
m[NKEY ] = SCA_IInputDevice::KX_NKEY;
|
|
m[OKEY ] = SCA_IInputDevice::KX_OKEY;
|
|
m[PKEY ] = SCA_IInputDevice::KX_PKEY;
|
|
m[QKEY ] = SCA_IInputDevice::KX_QKEY;
|
|
m[RKEY ] = SCA_IInputDevice::KX_RKEY;
|
|
m[SKEY ] = SCA_IInputDevice::KX_SKEY;
|
|
m[TKEY ] = SCA_IInputDevice::KX_TKEY;
|
|
m[UKEY ] = SCA_IInputDevice::KX_UKEY;
|
|
m[VKEY ] = SCA_IInputDevice::KX_VKEY;
|
|
m[WKEY ] = SCA_IInputDevice::KX_WKEY;
|
|
m[XKEY ] = SCA_IInputDevice::KX_XKEY;
|
|
m[YKEY ] = SCA_IInputDevice::KX_YKEY;
|
|
m[ZKEY ] = SCA_IInputDevice::KX_ZKEY;
|
|
|
|
m[ZEROKEY ] = SCA_IInputDevice::KX_ZEROKEY;
|
|
m[ONEKEY ] = SCA_IInputDevice::KX_ONEKEY;
|
|
m[TWOKEY ] = SCA_IInputDevice::KX_TWOKEY;
|
|
m[THREEKEY ] = SCA_IInputDevice::KX_THREEKEY;
|
|
m[FOURKEY ] = SCA_IInputDevice::KX_FOURKEY;
|
|
m[FIVEKEY ] = SCA_IInputDevice::KX_FIVEKEY;
|
|
m[SIXKEY ] = SCA_IInputDevice::KX_SIXKEY;
|
|
m[SEVENKEY ] = SCA_IInputDevice::KX_SEVENKEY;
|
|
m[EIGHTKEY ] = SCA_IInputDevice::KX_EIGHTKEY;
|
|
m[NINEKEY ] = SCA_IInputDevice::KX_NINEKEY;
|
|
|
|
m[CAPSLOCKKEY ] = SCA_IInputDevice::KX_CAPSLOCKKEY;
|
|
|
|
m[LEFTCTRLKEY ] = SCA_IInputDevice::KX_LEFTCTRLKEY;
|
|
m[LEFTALTKEY ] = SCA_IInputDevice::KX_LEFTALTKEY;
|
|
m[RIGHTALTKEY ] = SCA_IInputDevice::KX_RIGHTALTKEY;
|
|
m[RIGHTCTRLKEY ] = SCA_IInputDevice::KX_RIGHTCTRLKEY;
|
|
m[RIGHTSHIFTKEY ] = SCA_IInputDevice::KX_RIGHTSHIFTKEY;
|
|
m[LEFTSHIFTKEY ] = SCA_IInputDevice::KX_LEFTSHIFTKEY;
|
|
|
|
m[ESCKEY ] = SCA_IInputDevice::KX_ESCKEY;
|
|
m[TABKEY ] = SCA_IInputDevice::KX_TABKEY;
|
|
m[RETKEY ] = SCA_IInputDevice::KX_RETKEY;
|
|
m[SPACEKEY ] = SCA_IInputDevice::KX_SPACEKEY;
|
|
m[LINEFEEDKEY ] = SCA_IInputDevice::KX_LINEFEEDKEY;
|
|
m[BACKSPACEKEY ] = SCA_IInputDevice::KX_BACKSPACEKEY;
|
|
m[DELKEY ] = SCA_IInputDevice::KX_DELKEY;
|
|
m[SEMICOLONKEY ] = SCA_IInputDevice::KX_SEMICOLONKEY;
|
|
m[PERIODKEY ] = SCA_IInputDevice::KX_PERIODKEY;
|
|
m[COMMAKEY ] = SCA_IInputDevice::KX_COMMAKEY;
|
|
m[QUOTEKEY ] = SCA_IInputDevice::KX_QUOTEKEY;
|
|
m[ACCENTGRAVEKEY ] = SCA_IInputDevice::KX_ACCENTGRAVEKEY;
|
|
m[MINUSKEY ] = SCA_IInputDevice::KX_MINUSKEY;
|
|
m[SLASHKEY ] = SCA_IInputDevice::KX_SLASHKEY;
|
|
m[BACKSLASHKEY ] = SCA_IInputDevice::KX_BACKSLASHKEY;
|
|
m[EQUALKEY ] = SCA_IInputDevice::KX_EQUALKEY;
|
|
m[LEFTBRACKETKEY ] = SCA_IInputDevice::KX_LEFTBRACKETKEY;
|
|
m[RIGHTBRACKETKEY ] = SCA_IInputDevice::KX_RIGHTBRACKETKEY;
|
|
|
|
m[LEFTARROWKEY ] = SCA_IInputDevice::KX_LEFTARROWKEY;
|
|
m[DOWNARROWKEY ] = SCA_IInputDevice::KX_DOWNARROWKEY;
|
|
m[RIGHTARROWKEY ] = SCA_IInputDevice::KX_RIGHTARROWKEY;
|
|
m[UPARROWKEY ] = SCA_IInputDevice::KX_UPARROWKEY;
|
|
|
|
m[PAD2 ] = SCA_IInputDevice::KX_PAD2;
|
|
m[PAD4 ] = SCA_IInputDevice::KX_PAD4;
|
|
m[PAD6 ] = SCA_IInputDevice::KX_PAD6;
|
|
m[PAD8 ] = SCA_IInputDevice::KX_PAD8;
|
|
|
|
m[PAD1 ] = SCA_IInputDevice::KX_PAD1;
|
|
m[PAD3 ] = SCA_IInputDevice::KX_PAD3;
|
|
m[PAD5 ] = SCA_IInputDevice::KX_PAD5;
|
|
m[PAD7 ] = SCA_IInputDevice::KX_PAD7;
|
|
m[PAD9 ] = SCA_IInputDevice::KX_PAD9;
|
|
|
|
m[PADPERIOD ] = SCA_IInputDevice::KX_PADPERIOD;
|
|
m[PADSLASHKEY ] = SCA_IInputDevice::KX_PADSLASHKEY;
|
|
m[PADASTERKEY ] = SCA_IInputDevice::KX_PADASTERKEY;
|
|
|
|
m[PAD0 ] = SCA_IInputDevice::KX_PAD0;
|
|
m[PADMINUS ] = SCA_IInputDevice::KX_PADMINUS;
|
|
m[PADENTER ] = SCA_IInputDevice::KX_PADENTER;
|
|
m[PADPLUSKEY ] = SCA_IInputDevice::KX_PADPLUSKEY;
|
|
|
|
|
|
m[F1KEY ] = SCA_IInputDevice::KX_F1KEY;
|
|
m[F2KEY ] = SCA_IInputDevice::KX_F2KEY;
|
|
m[F3KEY ] = SCA_IInputDevice::KX_F3KEY;
|
|
m[F4KEY ] = SCA_IInputDevice::KX_F4KEY;
|
|
m[F5KEY ] = SCA_IInputDevice::KX_F5KEY;
|
|
m[F6KEY ] = SCA_IInputDevice::KX_F6KEY;
|
|
m[F7KEY ] = SCA_IInputDevice::KX_F7KEY;
|
|
m[F8KEY ] = SCA_IInputDevice::KX_F8KEY;
|
|
m[F9KEY ] = SCA_IInputDevice::KX_F9KEY;
|
|
m[F10KEY ] = SCA_IInputDevice::KX_F10KEY;
|
|
m[F11KEY ] = SCA_IInputDevice::KX_F11KEY;
|
|
m[F12KEY ] = SCA_IInputDevice::KX_F12KEY;
|
|
m[F13KEY ] = SCA_IInputDevice::KX_F13KEY;
|
|
m[F14KEY ] = SCA_IInputDevice::KX_F14KEY;
|
|
m[F15KEY ] = SCA_IInputDevice::KX_F15KEY;
|
|
m[F16KEY ] = SCA_IInputDevice::KX_F16KEY;
|
|
m[F17KEY ] = SCA_IInputDevice::KX_F17KEY;
|
|
m[F18KEY ] = SCA_IInputDevice::KX_F18KEY;
|
|
m[F19KEY ] = SCA_IInputDevice::KX_F19KEY;
|
|
|
|
m[OSKEY ] = SCA_IInputDevice::KX_OSKEY;
|
|
|
|
m[PAUSEKEY ] = SCA_IInputDevice::KX_PAUSEKEY;
|
|
m[INSERTKEY ] = SCA_IInputDevice::KX_INSERTKEY;
|
|
m[HOMEKEY ] = SCA_IInputDevice::KX_HOMEKEY;
|
|
m[PAGEUPKEY ] = SCA_IInputDevice::KX_PAGEUPKEY;
|
|
m[PAGEDOWNKEY ] = SCA_IInputDevice::KX_PAGEDOWNKEY;
|
|
m[ENDKEY ] = SCA_IInputDevice::KX_ENDKEY;
|
|
|
|
return m;
|
|
}
|
|
|
|
static std::map<int, SCA_IInputDevice::KX_EnumInputs> gReverseKeyTranslateTable = create_translate_table();
|
|
|
|
static unsigned int KX_rgbaint2uint_new(unsigned int icol)
|
|
{
|
|
union
|
|
{
|
|
unsigned int integer;
|
|
unsigned char cp[4];
|
|
} out_color, in_color;
|
|
|
|
in_color.integer = icol;
|
|
out_color.cp[0] = in_color.cp[3]; // red
|
|
out_color.cp[1] = in_color.cp[2]; // green
|
|
out_color.cp[2] = in_color.cp[1]; // blue
|
|
out_color.cp[3] = in_color.cp[0]; // alpha
|
|
|
|
return out_color.integer;
|
|
}
|
|
|
|
/* Now the real converting starts... */
|
|
static unsigned int KX_Mcol2uint_new(MCol col)
|
|
{
|
|
/* color has to be converted without endian sensitivity. So no shifting! */
|
|
union
|
|
{
|
|
MCol col;
|
|
unsigned int integer;
|
|
unsigned char cp[4];
|
|
} out_color, in_color;
|
|
|
|
in_color.col = col;
|
|
out_color.cp[0] = in_color.cp[3]; // red
|
|
out_color.cp[1] = in_color.cp[2]; // green
|
|
out_color.cp[2] = in_color.cp[1]; // blue
|
|
out_color.cp[3] = in_color.cp[0]; // alpha
|
|
|
|
return out_color.integer;
|
|
}
|
|
|
|
static void SetDefaultLightMode(Scene* scene)
|
|
{
|
|
default_light_mode = false;
|
|
Scene *sce_iter;
|
|
Base *base;
|
|
|
|
for (SETLOOPER(scene, sce_iter, base))
|
|
{
|
|
if (base->object->type == OB_LAMP)
|
|
{
|
|
default_light_mode = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static bool GetMaterialUseVColor(Material *ma, const bool glslmat)
|
|
{
|
|
if (ma) {
|
|
/* glsl uses vertex colors, otherwise use material setting
|
|
* defmaterial doesn't have VERTEXCOLP as default [#34505] */
|
|
return (glslmat || ma == &defmaterial || (ma->mode & MA_VERTEXCOLP) != 0);
|
|
}
|
|
else {
|
|
/* no material, use vertex colors */
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// --
|
|
static void GetRGB(
|
|
const bool use_vcol,
|
|
MFace* mface,
|
|
MCol* mmcol,
|
|
Material *mat,
|
|
unsigned int c[4])
|
|
{
|
|
unsigned int color = 0xFFFFFFFFL;
|
|
if (use_vcol == true) {
|
|
if (mmcol) {
|
|
c[0] = KX_Mcol2uint_new(mmcol[0]);
|
|
c[1] = KX_Mcol2uint_new(mmcol[1]);
|
|
c[2] = KX_Mcol2uint_new(mmcol[2]);
|
|
if (mface->v4)
|
|
c[3] = KX_Mcol2uint_new(mmcol[3]);
|
|
}
|
|
else { // backup white
|
|
c[0] = KX_rgbaint2uint_new(color);
|
|
c[1] = KX_rgbaint2uint_new(color);
|
|
c[2] = KX_rgbaint2uint_new(color);
|
|
if (mface->v4)
|
|
c[3] = KX_rgbaint2uint_new( color );
|
|
}
|
|
}
|
|
else {
|
|
/* material rgba */
|
|
if (mat) {
|
|
union {
|
|
unsigned char cp[4];
|
|
unsigned int integer;
|
|
} col_converter;
|
|
col_converter.cp[3] = (unsigned char) (mat->r * 255.0f);
|
|
col_converter.cp[2] = (unsigned char) (mat->g * 255.0f);
|
|
col_converter.cp[1] = (unsigned char) (mat->b * 255.0f);
|
|
col_converter.cp[0] = (unsigned char) (mat->alpha * 255.0f);
|
|
color = col_converter.integer;
|
|
}
|
|
c[0] = KX_rgbaint2uint_new(color);
|
|
c[1] = KX_rgbaint2uint_new(color);
|
|
c[2] = KX_rgbaint2uint_new(color);
|
|
if (mface->v4) {
|
|
c[3] = KX_rgbaint2uint_new(color);
|
|
}
|
|
}
|
|
|
|
#if 0 /* white, unused */
|
|
{
|
|
c[0] = KX_rgbaint2uint_new(color);
|
|
c[1] = KX_rgbaint2uint_new(color);
|
|
c[2] = KX_rgbaint2uint_new(color);
|
|
if (mface->v4)
|
|
c[3] = KX_rgbaint2uint_new(color);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
typedef struct MTF_localLayer {
|
|
MTFace *face;
|
|
const char *name;
|
|
} MTF_localLayer;
|
|
|
|
static void GetUVs(BL_Material *material, MTF_localLayer *layers, MFace *mface, MTFace *tface, MT_Point2 uvs[4][MAXTEX])
|
|
{
|
|
int unit = 0;
|
|
if (tface)
|
|
{
|
|
|
|
uvs[0][0].setValue(tface->uv[0]);
|
|
uvs[1][0].setValue(tface->uv[1]);
|
|
uvs[2][0].setValue(tface->uv[2]);
|
|
|
|
if (mface->v4)
|
|
uvs[3][0].setValue(tface->uv[3]);
|
|
}
|
|
else
|
|
{
|
|
uvs[0][0] = uvs[1][0] = uvs[2][0] = uvs[3][0] = MT_Point2(0.f, 0.f);
|
|
}
|
|
|
|
vector<STR_String> found_layers;
|
|
|
|
for (int vind = 0; vind<MAXTEX; vind++)
|
|
{
|
|
BL_Mapping &map = material->mapping[vind];
|
|
|
|
if (!(map.mapping & USEUV)) continue;
|
|
|
|
if (std::find(found_layers.begin(), found_layers.end(), map.uvCoName) != found_layers.end())
|
|
continue;
|
|
|
|
//If no UVSet is specified, try grabbing one from the UV/Image editor
|
|
if (map.uvCoName.IsEmpty() && tface)
|
|
{
|
|
uvs[0][unit].setValue(tface->uv[0]);
|
|
uvs[1][unit].setValue(tface->uv[1]);
|
|
uvs[2][unit].setValue(tface->uv[2]);
|
|
|
|
if (mface->v4)
|
|
uvs[3][unit].setValue(tface->uv[3]);
|
|
|
|
++unit;
|
|
continue;
|
|
}
|
|
|
|
|
|
for (int lay=0; lay<MAX_MTFACE; lay++)
|
|
{
|
|
MTF_localLayer& layer = layers[lay];
|
|
if (layer.face == 0) break;
|
|
|
|
if (map.uvCoName.IsEmpty() || strcmp(map.uvCoName.ReadPtr(), layer.name)==0)
|
|
{
|
|
uvs[0][unit].setValue(layer.face->uv[0]);
|
|
uvs[1][unit].setValue(layer.face->uv[1]);
|
|
uvs[2][unit].setValue(layer.face->uv[2]);
|
|
|
|
if (mface->v4)
|
|
uvs[3][unit].setValue(layer.face->uv[3]);
|
|
else
|
|
uvs[3][unit].setValue(0.0f, 0.0f);
|
|
|
|
++unit;
|
|
found_layers.push_back(map.uvCoName);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------
|
|
static bool ConvertMaterial(
|
|
BL_Material *material,
|
|
Material *mat,
|
|
MTFace* tface,
|
|
const char *tfaceName,
|
|
MFace* mface,
|
|
MCol* mmcol,
|
|
bool glslmat)
|
|
{
|
|
material->Initialize();
|
|
int texalpha = 0;
|
|
const bool validmat = (mat != NULL);
|
|
const bool validface = (tface != NULL);
|
|
const bool use_vcol = GetMaterialUseVColor(mat, glslmat);
|
|
|
|
material->IdMode = DEFAULT_BLENDER;
|
|
material->glslmat = (validmat) ? glslmat: false;
|
|
material->materialindex = mface->mat_nr;
|
|
|
|
// --------------------------------
|
|
if (validmat) {
|
|
|
|
// use lighting?
|
|
material->ras_mode |= ( mat->mode & MA_SHLESS )?0:USE_LIGHT;
|
|
material->ras_mode |= ( mat->game.flag & GEMAT_BACKCULL )?0:TWOSIDED;
|
|
|
|
// cast shadows?
|
|
material->ras_mode |= ( (mat->mode2 & MA_CASTSHADOW) && (mat->mode & MA_SHADBUF) )?CAST_SHADOW:0;
|
|
|
|
// only shadows?
|
|
material->ras_mode |= ( mat->mode & MA_ONLYCAST )?ONLY_SHADOW:0;
|
|
|
|
MTex *mttmp = 0;
|
|
int valid_index = 0;
|
|
|
|
/* In Multitexture use the face texture if and only if
|
|
* it is set in the buttons
|
|
* In GLSL is not working yet :/ 3.2011 */
|
|
bool facetex = false;
|
|
if (validface && mat->mode &MA_FACETEXTURE)
|
|
facetex = true;
|
|
|
|
// foreach MTex
|
|
for (int i=0; i<MAXTEX; i++) {
|
|
// use face tex
|
|
|
|
if (i==0 && facetex ) {
|
|
facetex = false;
|
|
Image*tmp = (Image*)(tface->tpage);
|
|
|
|
if (tmp) {
|
|
material->img[i] = tmp;
|
|
material->texname[i] = material->img[i]->id.name;
|
|
material->flag[i] |= MIPMAP;
|
|
|
|
material->flag[i] |= ( mat->game.alpha_blend & GEMAT_ALPHA_SORT )?USEALPHA:0;
|
|
material->flag[i] |= ( mat->game.alpha_blend & GEMAT_ALPHA )?USEALPHA:0;
|
|
material->flag[i] |= ( mat->game.alpha_blend & GEMAT_ADD )?CALCALPHA:0;
|
|
|
|
if (material->img[i]->flag & IMA_REFLECT) {
|
|
material->mapping[i].mapping |= USEREFL;
|
|
}
|
|
else {
|
|
mttmp = getMTexFromMaterial(mat, i);
|
|
if (mttmp && (mttmp->texco & TEXCO_UV)) {
|
|
/* string may be "" but thats detected as empty after */
|
|
material->mapping[i].uvCoName = mttmp->uvname;
|
|
}
|
|
material->mapping[i].mapping |= USEUV;
|
|
}
|
|
|
|
valid_index++;
|
|
}
|
|
else {
|
|
material->img[i] = 0;
|
|
material->texname[i] = "";
|
|
}
|
|
continue;
|
|
}
|
|
|
|
mttmp = getMTexFromMaterial(mat, i);
|
|
if (mttmp) {
|
|
if (mttmp->tex) {
|
|
if ( mttmp->tex->type == TEX_IMAGE ) {
|
|
material->mtexname[i] = mttmp->tex->id.name;
|
|
material->img[i] = mttmp->tex->ima;
|
|
if ( material->img[i] ) {
|
|
|
|
material->texname[i] = material->img[i]->id.name;
|
|
material->flag[i] |= ( mttmp->tex->imaflag &TEX_MIPMAP )?MIPMAP:0;
|
|
// -----------------------
|
|
if (material->img[i] && (material->img[i]->flag & IMA_IGNORE_ALPHA) == 0)
|
|
material->flag[i] |= USEALPHA;
|
|
// -----------------------
|
|
if ( mttmp->tex->imaflag &TEX_CALCALPHA ) {
|
|
material->flag[i] |= CALCALPHA;
|
|
}
|
|
else if (mttmp->tex->flag &TEX_NEGALPHA) {
|
|
material->flag[i] |= USENEGALPHA;
|
|
}
|
|
|
|
material->color_blend[i] = mttmp->colfac;
|
|
material->flag[i] |= ( mttmp->mapto & MAP_ALPHA )?TEXALPHA:0;
|
|
material->flag[i] |= ( mttmp->texflag& MTEX_NEGATIVE )?TEXNEG:0;
|
|
|
|
if (!glslmat && (material->flag[i] & TEXALPHA))
|
|
texalpha = 1;
|
|
}
|
|
}
|
|
else if (mttmp->tex->type == TEX_ENVMAP) {
|
|
if ( mttmp->tex->env->stype == ENV_LOAD ) {
|
|
|
|
material->mtexname[i] = mttmp->tex->id.name;
|
|
EnvMap *env = mttmp->tex->env;
|
|
env->ima = mttmp->tex->ima;
|
|
material->cubemap[i] = env;
|
|
|
|
if (material->cubemap[i])
|
|
{
|
|
if (!material->cubemap[i]->cube[0])
|
|
BL_Texture::SplitEnvMap(material->cubemap[i]);
|
|
|
|
material->texname[i] = material->cubemap[i]->ima->id.name;
|
|
material->mapping[i].mapping |= USEENV;
|
|
}
|
|
}
|
|
}
|
|
#if 0 /* this flag isn't used anymore */
|
|
material->flag[i] |= (BKE_animdata_from_id(mat->id) != NULL) ? HASIPO : 0;
|
|
#endif
|
|
/// --------------------------------
|
|
// mapping methods
|
|
if (mat->septex & (1 << i)) {
|
|
// If this texture slot isn't in use, set it to disabled to prevent multi-uv problems
|
|
material->mapping[i].mapping = DISABLE;
|
|
} else {
|
|
material->mapping[i].mapping |= ( mttmp->texco & TEXCO_REFL )?USEREFL:0;
|
|
|
|
if (mttmp->texco & TEXCO_OBJECT) {
|
|
material->mapping[i].mapping |= USEOBJ;
|
|
if (mttmp->object)
|
|
material->mapping[i].objconame = mttmp->object->id.name;
|
|
}
|
|
else if (mttmp->texco &TEXCO_REFL)
|
|
material->mapping[i].mapping |= USEREFL;
|
|
else if (mttmp->texco &(TEXCO_ORCO|TEXCO_GLOB))
|
|
material->mapping[i].mapping |= USEORCO;
|
|
else if (mttmp->texco & TEXCO_UV) {
|
|
/* string may be "" but thats detected as empty after */
|
|
material->mapping[i].uvCoName = mttmp->uvname;
|
|
material->mapping[i].mapping |= USEUV;
|
|
}
|
|
else if (mttmp->texco &TEXCO_NORM)
|
|
material->mapping[i].mapping |= USENORM;
|
|
else if (mttmp->texco &TEXCO_TANGENT)
|
|
material->mapping[i].mapping |= USETANG;
|
|
else
|
|
material->mapping[i].mapping |= DISABLE;
|
|
|
|
material->mapping[i].scale[0] = mttmp->size[0];
|
|
material->mapping[i].scale[1] = mttmp->size[1];
|
|
material->mapping[i].scale[2] = mttmp->size[2];
|
|
material->mapping[i].offsets[0] = mttmp->ofs[0];
|
|
material->mapping[i].offsets[1] = mttmp->ofs[1];
|
|
material->mapping[i].offsets[2] = mttmp->ofs[2];
|
|
|
|
material->mapping[i].projplane[0] = mttmp->projx;
|
|
material->mapping[i].projplane[1] = mttmp->projy;
|
|
material->mapping[i].projplane[2] = mttmp->projz;
|
|
}
|
|
/// --------------------------------
|
|
|
|
switch (mttmp->blendtype) {
|
|
case MTEX_BLEND:
|
|
material->blend_mode[i] = BLEND_MIX;
|
|
break;
|
|
case MTEX_MUL:
|
|
material->blend_mode[i] = BLEND_MUL;
|
|
break;
|
|
case MTEX_ADD:
|
|
material->blend_mode[i] = BLEND_ADD;
|
|
break;
|
|
case MTEX_SUB:
|
|
material->blend_mode[i] = BLEND_SUB;
|
|
break;
|
|
case MTEX_SCREEN:
|
|
material->blend_mode[i] = BLEND_SCR;
|
|
break;
|
|
}
|
|
valid_index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// above one tex the switches here
|
|
// are not used
|
|
switch (valid_index) {
|
|
case 0:
|
|
material->IdMode = DEFAULT_BLENDER;
|
|
break;
|
|
case 1:
|
|
material->IdMode = ONETEX;
|
|
break;
|
|
default:
|
|
material->IdMode = GREATERTHAN2;
|
|
break;
|
|
}
|
|
material->SetUsers(mat->id.us);
|
|
|
|
material->num_enabled = valid_index;
|
|
|
|
material->speccolor[0] = mat->specr;
|
|
material->speccolor[1] = mat->specg;
|
|
material->speccolor[2] = mat->specb;
|
|
material->hard = (float)mat->har/4.0f;
|
|
material->matcolor[0] = mat->r;
|
|
material->matcolor[1] = mat->g;
|
|
material->matcolor[2] = mat->b;
|
|
material->matcolor[3] = mat->alpha;
|
|
material->alpha = mat->alpha;
|
|
material->emit = mat->emit;
|
|
material->spec_f = mat->spec;
|
|
material->ref = mat->ref;
|
|
material->amb = mat->amb;
|
|
|
|
material->ras_mode |= (mat->material_type == MA_TYPE_WIRE)? WIRE: 0;
|
|
}
|
|
else { // No Material
|
|
int valid = 0;
|
|
|
|
// check for tface tex to fallback on
|
|
if ( validface ) {
|
|
material->img[0] = (Image*)(tface->tpage);
|
|
// ------------------------
|
|
if (material->img[0]) {
|
|
material->texname[0] = material->img[0]->id.name;
|
|
material->mapping[0].mapping |= ( (material->img[0]->flag & IMA_REFLECT)!=0 )?USEREFL:0;
|
|
|
|
/* see if depth of the image is 32bits */
|
|
if (BKE_image_has_alpha(material->img[0])) {
|
|
material->flag[0] |= USEALPHA;
|
|
material->alphablend = GEMAT_ALPHA;
|
|
}
|
|
else
|
|
material->alphablend = GEMAT_SOLID;
|
|
|
|
valid++;
|
|
}
|
|
}
|
|
else
|
|
material->alphablend = GEMAT_SOLID;
|
|
|
|
material->SetUsers(-1);
|
|
material->num_enabled = valid;
|
|
material->IdMode = TEXFACE;
|
|
material->speccolor[0] = 1.f;
|
|
material->speccolor[1] = 1.f;
|
|
material->speccolor[2] = 1.f;
|
|
material->hard = 35.f;
|
|
material->matcolor[0] = 0.5f;
|
|
material->matcolor[1] = 0.5f;
|
|
material->matcolor[2] = 0.5f;
|
|
material->spec_f = 0.5f;
|
|
material->ref = 0.8f;
|
|
|
|
// No material - old default TexFace properties
|
|
material->ras_mode |= USE_LIGHT;
|
|
}
|
|
|
|
/* No material, what to do? let's see what is in the UV and set the material accordingly
|
|
* light and visible is always on */
|
|
if ( validface ) {
|
|
material->tile = tface->tile;
|
|
}
|
|
else {
|
|
// nothing at all
|
|
material->alphablend = GEMAT_SOLID;
|
|
material->tile = 0;
|
|
}
|
|
|
|
if (validmat && validface) {
|
|
material->alphablend = mat->game.alpha_blend;
|
|
}
|
|
|
|
// with ztransp enabled, enforce alpha blending mode
|
|
if (validmat && (mat->mode & MA_TRANSP) && (mat->mode & MA_ZTRANSP) && (material->alphablend == GEMAT_SOLID))
|
|
material->alphablend = GEMAT_ALPHA;
|
|
|
|
// always zsort alpha + add
|
|
if ((ELEM3(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) {
|
|
material->ras_mode |= ALPHA;
|
|
material->ras_mode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT))? ZSORT: 0;
|
|
}
|
|
|
|
// XXX The RGB values here were meant to be temporary storage for the conversion process,
|
|
// but fonts now make use of them too, so we leave them in for now.
|
|
unsigned int rgb[4];
|
|
GetRGB(use_vcol, mface, mmcol, mat, rgb);
|
|
|
|
// swap the material color, so MCol on bitmap font works
|
|
if (validmat && (use_vcol == false) && (mat->game.flag & GEMAT_TEXT))
|
|
{
|
|
rgb[0] = KX_rgbaint2uint_new(rgb[0]);
|
|
rgb[1] = KX_rgbaint2uint_new(rgb[1]);
|
|
rgb[2] = KX_rgbaint2uint_new(rgb[2]);
|
|
rgb[3] = KX_rgbaint2uint_new(rgb[3]);
|
|
}
|
|
|
|
if (validmat)
|
|
material->matname =(mat->id.name);
|
|
|
|
if (tface) {
|
|
material->tface = *tface;
|
|
}
|
|
else {
|
|
memset(&material->tface, 0, sizeof(material->tface));
|
|
}
|
|
material->material = mat;
|
|
return true;
|
|
}
|
|
|
|
static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace *tface, MCol *mcol, MTF_localLayer *layers, int lightlayer, unsigned int *rgb, MT_Point2 uvs[4][RAS_TexVert::MAX_UNIT], const char *tfaceName, KX_Scene* scene, KX_BlenderSceneConverter *converter)
|
|
{
|
|
RAS_IPolyMaterial* polymat = converter->FindCachedPolyMaterial(scene, ma);
|
|
BL_Material* bl_mat = converter->FindCachedBlenderMaterial(scene, ma);
|
|
KX_BlenderMaterial* kx_blmat = NULL;
|
|
|
|
/* first is the BL_Material */
|
|
if (!bl_mat)
|
|
{
|
|
bl_mat = new BL_Material();
|
|
|
|
ConvertMaterial(bl_mat, ma, tface, tfaceName, mface, mcol,
|
|
converter->GetGLSLMaterials());
|
|
|
|
if (ma && (ma->mode & MA_FACETEXTURE) == 0)
|
|
converter->CacheBlenderMaterial(scene, ma, bl_mat);
|
|
}
|
|
|
|
const bool use_vcol = GetMaterialUseVColor(ma, bl_mat->glslmat);
|
|
GetRGB(use_vcol, mface, mcol, ma, rgb);
|
|
|
|
GetUVs(bl_mat, layers, mface, tface, uvs);
|
|
|
|
/* then the KX_BlenderMaterial */
|
|
if (polymat == NULL)
|
|
{
|
|
kx_blmat = new KX_BlenderMaterial();
|
|
|
|
kx_blmat->Initialize(scene, bl_mat, (ma?&ma->game:NULL), lightlayer);
|
|
polymat = static_cast<RAS_IPolyMaterial*>(kx_blmat);
|
|
if (ma && (ma->mode & MA_FACETEXTURE) == 0)
|
|
converter->CachePolyMaterial(scene, ma, polymat);
|
|
}
|
|
|
|
// see if a bucket was reused or a new one was created
|
|
// this way only one KX_BlenderMaterial object has to exist per bucket
|
|
bool bucketCreated;
|
|
RAS_MaterialBucket* bucket = scene->FindBucket(polymat, bucketCreated);
|
|
|
|
// this is needed to free up memory afterwards.
|
|
// the converter will also prevent duplicates from being registered,
|
|
// so just register everything.
|
|
converter->RegisterPolyMaterial(polymat);
|
|
converter->RegisterBlenderMaterial(bl_mat);
|
|
|
|
return bucket;
|
|
}
|
|
|
|
/* blenderobj can be NULL, make sure its checked for */
|
|
RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene, KX_BlenderSceneConverter *converter, bool libloading)
|
|
{
|
|
RAS_MeshObject *meshobj;
|
|
int lightlayer = blenderobj ? blenderobj->lay:(1<<20)-1; // all layers if no object.
|
|
|
|
// Without checking names, we get some reuse we don't want that can cause
|
|
// problems with material LoDs.
|
|
if (blenderobj && ((meshobj = converter->FindGameMesh(mesh/*, ob->lay*/)) != NULL)) {
|
|
const char *bge_name = meshobj->GetName().ReadPtr();
|
|
const char *blender_name = ((ID *)blenderobj->data)->name + 2;
|
|
if (STREQ(bge_name, blender_name)) {
|
|
return meshobj;
|
|
}
|
|
}
|
|
|
|
// Get DerivedMesh data
|
|
DerivedMesh *dm = CDDM_from_mesh(mesh);
|
|
DM_ensure_tessface(dm);
|
|
|
|
MVert *mvert = dm->getVertArray(dm);
|
|
int totvert = dm->getNumVerts(dm);
|
|
|
|
MFace *mface = dm->getTessFaceArray(dm);
|
|
MTFace *tface = static_cast<MTFace*>(dm->getTessFaceDataArray(dm, CD_MTFACE));
|
|
MCol *mcol = static_cast<MCol*>(dm->getTessFaceDataArray(dm, CD_MCOL));
|
|
float (*tangent)[4] = NULL;
|
|
int totface = dm->getNumTessFaces(dm);
|
|
const char *tfaceName = "";
|
|
|
|
if (tface) {
|
|
DM_add_tangent_layer(dm);
|
|
tangent = (float(*)[4])dm->getTessFaceDataArray(dm, CD_TANGENT);
|
|
}
|
|
|
|
meshobj = new RAS_MeshObject(mesh);
|
|
|
|
// Extract avaiable layers
|
|
MTF_localLayer *layers = new MTF_localLayer[MAX_MTFACE];
|
|
for (int lay=0; lay<MAX_MTFACE; lay++) {
|
|
layers[lay].face = 0;
|
|
layers[lay].name = "";
|
|
}
|
|
|
|
int validLayers = 0;
|
|
for (int i=0; i<dm->faceData.totlayer; i++)
|
|
{
|
|
if (dm->faceData.layers[i].type == CD_MTFACE)
|
|
{
|
|
if (validLayers >= MAX_MTFACE) {
|
|
printf("%s: corrupted mesh %s - too many CD_MTFACE layers\n", __func__, mesh->id.name);
|
|
break;
|
|
}
|
|
|
|
layers[validLayers].face = (MTFace*)(dm->faceData.layers[i].data);
|
|
layers[validLayers].name = dm->faceData.layers[i].name;
|
|
if (tface == layers[validLayers].face)
|
|
tfaceName = layers[validLayers].name;
|
|
validLayers++;
|
|
}
|
|
}
|
|
|
|
meshobj->SetName(mesh->id.name + 2);
|
|
meshobj->m_sharedvertex_map.resize(totvert);
|
|
|
|
Material* ma = 0;
|
|
bool collider = true;
|
|
MT_Point2 uvs[4][RAS_TexVert::MAX_UNIT];
|
|
unsigned int rgb[4] = {0};
|
|
|
|
MT_Point3 pt[4];
|
|
MT_Vector3 no[4];
|
|
MT_Vector4 tan[4];
|
|
|
|
/* ugh, if there is a less annoying way to do this please use that.
|
|
* since these are converted from floats to floats, theres no real
|
|
* advantage to use MT_ types - campbell */
|
|
for (unsigned int i = 0; i < 4; i++) {
|
|
const float zero_vec[4] = {0.0f};
|
|
pt[i].setValue(zero_vec);
|
|
no[i].setValue(zero_vec);
|
|
tan[i].setValue(zero_vec);
|
|
}
|
|
|
|
/* we need to manually initialize the uvs (MoTo doesn't do that) [#34550] */
|
|
for (unsigned int i = 0; i < RAS_TexVert::MAX_UNIT; i++) {
|
|
uvs[0][i] = uvs[1][i] = uvs[2][i] = uvs[3][i] = MT_Point2(0.f, 0.f);
|
|
}
|
|
|
|
for (int f=0;f<totface;f++,mface++)
|
|
{
|
|
/* get coordinates, normals and tangents */
|
|
pt[0].setValue(mvert[mface->v1].co);
|
|
pt[1].setValue(mvert[mface->v2].co);
|
|
pt[2].setValue(mvert[mface->v3].co);
|
|
if (mface->v4) pt[3].setValue(mvert[mface->v4].co);
|
|
|
|
if (mface->flag & ME_SMOOTH) {
|
|
float n0[3], n1[3], n2[3], n3[3];
|
|
|
|
normal_short_to_float_v3(n0, mvert[mface->v1].no);
|
|
normal_short_to_float_v3(n1, mvert[mface->v2].no);
|
|
normal_short_to_float_v3(n2, mvert[mface->v3].no);
|
|
no[0] = n0;
|
|
no[1] = n1;
|
|
no[2] = n2;
|
|
|
|
if (mface->v4) {
|
|
normal_short_to_float_v3(n3, mvert[mface->v4].no);
|
|
no[3] = n3;
|
|
}
|
|
}
|
|
else {
|
|
float fno[3];
|
|
|
|
if (mface->v4)
|
|
normal_quad_v3(fno,mvert[mface->v1].co, mvert[mface->v2].co, mvert[mface->v3].co, mvert[mface->v4].co);
|
|
else
|
|
normal_tri_v3(fno,mvert[mface->v1].co, mvert[mface->v2].co, mvert[mface->v3].co);
|
|
|
|
no[0] = no[1] = no[2] = no[3] = MT_Vector3(fno);
|
|
}
|
|
|
|
if (tangent) {
|
|
tan[0] = tangent[f*4 + 0];
|
|
tan[1] = tangent[f*4 + 1];
|
|
tan[2] = tangent[f*4 + 2];
|
|
|
|
if (mface->v4)
|
|
tan[3] = tangent[f*4 + 3];
|
|
}
|
|
if (blenderobj)
|
|
ma = give_current_material(blenderobj, mface->mat_nr+1);
|
|
else
|
|
ma = mesh->mat ? mesh->mat[mface->mat_nr]:NULL;
|
|
|
|
/* ckeck for texface since texface _only_ is used as a fallback */
|
|
if (ma == NULL && tface == NULL) {
|
|
ma= &defmaterial;
|
|
}
|
|
|
|
{
|
|
bool visible = true;
|
|
bool twoside = false;
|
|
|
|
RAS_MaterialBucket* bucket = material_from_mesh(ma, mface, tface, mcol, layers, lightlayer, rgb, uvs, tfaceName, scene, converter);
|
|
|
|
// set render flags
|
|
if (ma)
|
|
{
|
|
visible = ((ma->game.flag & GEMAT_INVISIBLE)==0);
|
|
twoside = ((ma->game.flag & GEMAT_BACKCULL)==0);
|
|
collider = ((ma->game.flag & GEMAT_NOPHYSICS)==0);
|
|
}
|
|
else {
|
|
visible = true;
|
|
twoside = false;
|
|
collider = true;
|
|
}
|
|
|
|
/* mark face as flat, so vertices are split */
|
|
bool flat = (mface->flag & ME_SMOOTH) == 0;
|
|
|
|
int nverts = (mface->v4)? 4: 3;
|
|
|
|
RAS_Polygon *poly = meshobj->AddPolygon(bucket, nverts);
|
|
|
|
poly->SetVisible(visible);
|
|
poly->SetCollider(collider);
|
|
poly->SetTwoside(twoside);
|
|
//poly->SetEdgeCode(mface->edcode);
|
|
|
|
meshobj->AddVertex(poly,0,pt[0],uvs[0],tan[0],rgb[0],no[0],flat,mface->v1);
|
|
meshobj->AddVertex(poly,1,pt[1],uvs[1],tan[1],rgb[1],no[1],flat,mface->v2);
|
|
meshobj->AddVertex(poly,2,pt[2],uvs[2],tan[2],rgb[2],no[2],flat,mface->v3);
|
|
|
|
if (nverts==4)
|
|
meshobj->AddVertex(poly,3,pt[3],uvs[3],tan[3],rgb[3],no[3],flat,mface->v4);
|
|
}
|
|
|
|
if (tface)
|
|
tface++;
|
|
if (mcol)
|
|
mcol+=4;
|
|
|
|
for (int lay=0; lay<MAX_MTFACE; lay++)
|
|
{
|
|
MTF_localLayer &layer = layers[lay];
|
|
if (layer.face == 0) break;
|
|
|
|
layer.face++;
|
|
}
|
|
}
|
|
// keep meshobj->m_sharedvertex_map for reinstance phys mesh.
|
|
// 2.49a and before it did: meshobj->m_sharedvertex_map.clear();
|
|
// but this didnt save much ram. - Campbell
|
|
meshobj->EndConversion();
|
|
|
|
// pre calculate texture generation
|
|
// However, we want to delay this if we're libloading so we can make sure we have the right scene.
|
|
if (!libloading) {
|
|
for (list<RAS_MeshMaterial>::iterator mit = meshobj->GetFirstMaterial();
|
|
mit != meshobj->GetLastMaterial(); ++ mit) {
|
|
mit->m_bucket->GetPolyMaterial()->OnConstruction();
|
|
}
|
|
}
|
|
|
|
if (layers)
|
|
delete []layers;
|
|
|
|
dm->release(dm);
|
|
|
|
converter->RegisterGameMesh(meshobj, mesh);
|
|
return meshobj;
|
|
}
|
|
|
|
|
|
|
|
static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blenderobject)
|
|
{
|
|
PHY_MaterialProps *materialProps = new PHY_MaterialProps;
|
|
|
|
MT_assert(materialProps && "Create physics material properties failed");
|
|
|
|
Material* blendermat = give_current_material(blenderobject, 1);
|
|
|
|
if (blendermat)
|
|
{
|
|
MT_assert(0.0f <= blendermat->reflect && blendermat->reflect <= 1.0f);
|
|
|
|
materialProps->m_restitution = blendermat->reflect;
|
|
materialProps->m_friction = blendermat->friction;
|
|
materialProps->m_fh_spring = blendermat->fh;
|
|
materialProps->m_fh_damping = blendermat->xyfrict;
|
|
materialProps->m_fh_distance = blendermat->fhdist;
|
|
materialProps->m_fh_normal = (blendermat->dynamode & MA_FH_NOR) != 0;
|
|
}
|
|
else {
|
|
//give some defaults
|
|
materialProps->m_restitution = 0.f;
|
|
materialProps->m_friction = 0.5;
|
|
materialProps->m_fh_spring = 0.f;
|
|
materialProps->m_fh_damping = 0.f;
|
|
materialProps->m_fh_distance = 0.f;
|
|
materialProps->m_fh_normal = false;
|
|
|
|
}
|
|
|
|
return materialProps;
|
|
}
|
|
|
|
static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blenderobject)
|
|
{
|
|
PHY_ShapeProps *shapeProps = new PHY_ShapeProps;
|
|
|
|
MT_assert(shapeProps);
|
|
|
|
shapeProps->m_mass = blenderobject->mass;
|
|
|
|
// This needs to be fixed in blender. For now, we use:
|
|
|
|
// in Blender, inertia stands for the size value which is equivalent to
|
|
// the sphere radius
|
|
shapeProps->m_inertia = blenderobject->formfactor;
|
|
|
|
MT_assert(0.0f <= blenderobject->damping && blenderobject->damping <= 1.0f);
|
|
MT_assert(0.0f <= blenderobject->rdamping && blenderobject->rdamping <= 1.0f);
|
|
|
|
shapeProps->m_lin_drag = 1.0f - blenderobject->damping;
|
|
shapeProps->m_ang_drag = 1.0f - blenderobject->rdamping;
|
|
|
|
shapeProps->m_friction_scaling[0] = blenderobject->anisotropicFriction[0];
|
|
shapeProps->m_friction_scaling[1] = blenderobject->anisotropicFriction[1];
|
|
shapeProps->m_friction_scaling[2] = blenderobject->anisotropicFriction[2];
|
|
shapeProps->m_do_anisotropic = ((blenderobject->gameflag & OB_ANISOTROPIC_FRICTION) != 0);
|
|
|
|
shapeProps->m_do_fh = (blenderobject->gameflag & OB_DO_FH) != 0;
|
|
shapeProps->m_do_rot_fh = (blenderobject->gameflag & OB_ROT_FH) != 0;
|
|
|
|
// velocity clamping XXX
|
|
shapeProps->m_clamp_vel_min = blenderobject->min_vel;
|
|
shapeProps->m_clamp_vel_max = blenderobject->max_vel;
|
|
|
|
// Character physics properties
|
|
shapeProps->m_step_height = blenderobject->step_height;
|
|
shapeProps->m_jump_speed = blenderobject->jump_speed;
|
|
shapeProps->m_fall_speed = blenderobject->fall_speed;
|
|
|
|
return shapeProps;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
static float my_boundbox_mesh(Mesh *me, float *loc, float *size)
|
|
{
|
|
MVert *mvert;
|
|
BoundBox *bb;
|
|
float min[3], max[3];
|
|
float mloc[3], msize[3];
|
|
float radius_sq=0.0f, vert_radius_sq, *co;
|
|
int a;
|
|
|
|
if (me->bb==0) {
|
|
me->bb = BKE_boundbox_alloc_unit();
|
|
}
|
|
bb= me->bb;
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
if (!loc) loc= mloc;
|
|
if (!size) size= msize;
|
|
|
|
mvert= me->mvert;
|
|
for (a = 0; a<me->totvert; a++, mvert++) {
|
|
co = mvert->co;
|
|
|
|
/* bounds */
|
|
minmax_v3v3_v3(min, max, co);
|
|
|
|
/* radius */
|
|
|
|
vert_radius_sq = len_squared_v3(co);
|
|
if (vert_radius_sq > radius_sq)
|
|
radius_sq = vert_radius_sq;
|
|
}
|
|
|
|
if (me->totvert) {
|
|
loc[0] = (min[0] + max[0]) / 2.0f;
|
|
loc[1] = (min[1] + max[1]) / 2.0f;
|
|
loc[2] = (min[2] + max[2]) / 2.0f;
|
|
|
|
size[0] = (max[0] - min[0]) / 2.0f;
|
|
size[1] = (max[1] - min[1]) / 2.0f;
|
|
size[2] = (max[2] - min[2]) / 2.0f;
|
|
}
|
|
else {
|
|
loc[0] = loc[1] = loc[2] = 0.0f;
|
|
size[0] = size[1] = size[2] = 0.0f;
|
|
}
|
|
|
|
bb->vec[0][0] = bb->vec[1][0] = bb->vec[2][0] = bb->vec[3][0] = loc[0]-size[0];
|
|
bb->vec[4][0] = bb->vec[5][0] = bb->vec[6][0] = bb->vec[7][0] = loc[0]+size[0];
|
|
|
|
bb->vec[0][1] = bb->vec[1][1] = bb->vec[4][1] = bb->vec[5][1] = loc[1]-size[1];
|
|
bb->vec[2][1] = bb->vec[3][1] = bb->vec[6][1] = bb->vec[7][1] = loc[1]+size[1];
|
|
|
|
bb->vec[0][2] = bb->vec[3][2] = bb->vec[4][2] = bb->vec[7][2] = loc[2]-size[2];
|
|
bb->vec[1][2] = bb->vec[2][2] = bb->vec[5][2] = bb->vec[6][2] = loc[2]+size[2];
|
|
|
|
return sqrtf_signed(radius_sq);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////
|
|
|
|
|
|
static void BL_CreateGraphicObjectNew(KX_GameObject* gameobj,
|
|
const MT_Point3& localAabbMin,
|
|
const MT_Point3& localAabbMax,
|
|
KX_Scene* kxscene,
|
|
bool isActive,
|
|
e_PhysicsEngine physics_engine)
|
|
{
|
|
if (gameobj->GetMeshCount() > 0)
|
|
{
|
|
switch (physics_engine)
|
|
{
|
|
#ifdef WITH_BULLET
|
|
case UseBullet:
|
|
{
|
|
CcdPhysicsEnvironment* env = (CcdPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
|
|
assert(env);
|
|
PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
|
|
CcdGraphicController* ctrl = new CcdGraphicController(env, motionstate);
|
|
gameobj->SetGraphicController(ctrl);
|
|
ctrl->SetNewClientInfo(gameobj->getClientInfo());
|
|
ctrl->SetLocalAabb(localAabbMin, localAabbMax);
|
|
if (isActive) {
|
|
// add first, this will create the proxy handle, only if the object is visible
|
|
if (gameobj->GetVisible())
|
|
env->AddCcdGraphicController(ctrl);
|
|
// update the mesh if there is a deformer, this will also update the bounding box for modifiers
|
|
RAS_Deformer* deformer = gameobj->GetDeformer();
|
|
if (deformer)
|
|
deformer->UpdateBuckets();
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
|
|
struct Object* blenderobject,
|
|
RAS_MeshObject* meshobj,
|
|
KX_Scene* kxscene,
|
|
int activeLayerBitInfo,
|
|
KX_BlenderSceneConverter *converter,
|
|
bool processCompoundChildren
|
|
)
|
|
|
|
{
|
|
//SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
|
|
//int userigidbody = SYS_GetCommandLineInt(syshandle,"norigidbody",0);
|
|
//bool bRigidBody = (userigidbody == 0);
|
|
|
|
// object has physics representation?
|
|
if (!(blenderobject->gameflag & OB_COLLISION)) {
|
|
// Respond to all collisions so that Near sensors work on No Collision
|
|
// objects.
|
|
gameobj->SetUserCollisionGroup(0xff);
|
|
gameobj->SetUserCollisionMask(0xff);
|
|
return;
|
|
}
|
|
|
|
gameobj->SetUserCollisionGroup(blenderobject->col_group);
|
|
gameobj->SetUserCollisionMask(blenderobject->col_mask);
|
|
|
|
// get Root Parent of blenderobject
|
|
struct Object* parent= blenderobject->parent;
|
|
while (parent && parent->parent) {
|
|
parent= parent->parent;
|
|
}
|
|
|
|
bool isCompoundChild = false;
|
|
bool hasCompoundChildren = !parent && (blenderobject->gameflag & OB_CHILD);
|
|
|
|
/* When the parent is not OB_DYNAMIC and has no OB_COLLISION then it gets no bullet controller
|
|
* and cant be apart of the parents compound shape */
|
|
if (parent && (parent->gameflag & (OB_DYNAMIC | OB_COLLISION))) {
|
|
|
|
if ((parent->gameflag & OB_CHILD) != 0 && (blenderobject->gameflag & OB_CHILD))
|
|
{
|
|
isCompoundChild = true;
|
|
}
|
|
}
|
|
if (processCompoundChildren != isCompoundChild)
|
|
return;
|
|
|
|
|
|
PHY_ShapeProps* shapeprops =
|
|
CreateShapePropsFromBlenderObject(blenderobject);
|
|
|
|
|
|
PHY_MaterialProps* smmaterial =
|
|
CreateMaterialFromBlenderObject(blenderobject);
|
|
|
|
DerivedMesh* dm = NULL;
|
|
if (gameobj->GetDeformer())
|
|
dm = gameobj->GetDeformer()->GetPhysicsMesh();
|
|
|
|
class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
|
|
|
|
kxscene->GetPhysicsEnvironment()->ConvertObject(gameobj, meshobj, dm, kxscene, shapeprops, smmaterial, motionstate, activeLayerBitInfo, isCompoundChild, hasCompoundChildren);
|
|
|
|
bool isActor = (blenderobject->gameflag & OB_ACTOR)!=0;
|
|
bool isSensor = (blenderobject->gameflag & OB_SENSOR) != 0;
|
|
gameobj->getClientInfo()->m_type =
|
|
(isSensor) ? ((isActor) ? KX_ClientObjectInfo::OBACTORSENSOR : KX_ClientObjectInfo::OBSENSOR) :
|
|
(isActor) ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC;
|
|
|
|
// should we record animation for this object?
|
|
if ((blenderobject->gameflag & OB_RECORD_ANIMATION) != 0)
|
|
gameobj->SetRecordAnimation(true);
|
|
|
|
// store materialname in auxinfo, needed for touchsensors
|
|
if (meshobj)
|
|
{
|
|
const STR_String& matname=meshobj->GetMaterialName(0);
|
|
gameobj->getClientInfo()->m_auxilary_info = (matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL);
|
|
} else
|
|
{
|
|
gameobj->getClientInfo()->m_auxilary_info = 0;
|
|
}
|
|
|
|
delete shapeprops;
|
|
delete smmaterial;
|
|
if (dm) {
|
|
dm->needsFree = 1;
|
|
dm->release(dm);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int layerflag, KX_Scene *kxscene, RAS_IRasterizer *rasterizer, KX_BlenderSceneConverter *converter)
|
|
{
|
|
RAS_ILightObject *lightobj = rasterizer->CreateLight();
|
|
KX_LightObject *gamelight;
|
|
|
|
lightobj->m_att1 = la->att1;
|
|
lightobj->m_att2 = (la->mode & LA_QUAD) ? la->att2 : 0.0f;
|
|
lightobj->m_color[0] = la->r;
|
|
lightobj->m_color[1] = la->g;
|
|
lightobj->m_color[2] = la->b;
|
|
lightobj->m_distance = la->dist;
|
|
lightobj->m_energy = la->energy;
|
|
lightobj->m_layer = layerflag;
|
|
lightobj->m_spotblend = la->spotblend;
|
|
lightobj->m_spotsize = la->spotsize;
|
|
|
|
lightobj->m_nodiffuse = (la->mode & LA_NO_DIFF) != 0;
|
|
lightobj->m_nospecular = (la->mode & LA_NO_SPEC) != 0;
|
|
|
|
bool glslmat = converter->GetGLSLMaterials();
|
|
|
|
// in GLSL NEGATIVE LAMP is handled inside the lamp update function
|
|
if (glslmat==0) {
|
|
if (la->mode & LA_NEG)
|
|
{
|
|
lightobj->m_color[0] = -lightobj->m_color[0];
|
|
lightobj->m_color[1] = -lightobj->m_color[1];
|
|
lightobj->m_color[2] = -lightobj->m_color[2];
|
|
}
|
|
}
|
|
|
|
if (la->type==LA_SUN) {
|
|
lightobj->m_type = RAS_ILightObject::LIGHT_SUN;
|
|
} else if (la->type==LA_SPOT) {
|
|
lightobj->m_type = RAS_ILightObject::LIGHT_SPOT;
|
|
} else {
|
|
lightobj->m_type = RAS_ILightObject::LIGHT_NORMAL;
|
|
}
|
|
|
|
gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rasterizer,
|
|
lightobj, glslmat);
|
|
|
|
return gamelight;
|
|
}
|
|
|
|
static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter)
|
|
{
|
|
Camera* ca = static_cast<Camera*>(ob->data);
|
|
RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->sensor_x, ca->sensor_y, ca->sensor_fit, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, ca->YF_dofdist);
|
|
KX_Camera *gamecamera;
|
|
|
|
gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata);
|
|
gamecamera->SetName(ca->id.name + 2);
|
|
|
|
return gamecamera;
|
|
}
|
|
|
|
static KX_GameObject *gameobject_from_blenderobject(
|
|
Object *ob,
|
|
KX_Scene *kxscene,
|
|
RAS_IRasterizer *rendertools,
|
|
KX_BlenderSceneConverter *converter,
|
|
bool libloading)
|
|
{
|
|
KX_GameObject *gameobj = NULL;
|
|
Scene *blenderscene = kxscene->GetBlenderScene();
|
|
|
|
switch (ob->type) {
|
|
case OB_LAMP:
|
|
{
|
|
KX_LightObject* gamelight = gamelight_from_blamp(ob, static_cast<Lamp*>(ob->data), ob->lay, kxscene, rendertools, converter);
|
|
gameobj = gamelight;
|
|
|
|
if (blenderscene->lay & ob->lay)
|
|
{
|
|
gamelight->AddRef();
|
|
kxscene->GetLightList()->Add(gamelight);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OB_CAMERA:
|
|
{
|
|
KX_Camera* gamecamera = gamecamera_from_bcamera(ob, kxscene, converter);
|
|
gameobj = gamecamera;
|
|
|
|
//don't add a reference: the camera list in kxscene->m_cameras is not released at the end
|
|
//gamecamera->AddRef();
|
|
kxscene->AddCamera(gamecamera);
|
|
|
|
break;
|
|
}
|
|
|
|
case OB_MESH:
|
|
{
|
|
Mesh* mesh = static_cast<Mesh*>(ob->data);
|
|
float center[3], extents[3];
|
|
float radius = my_boundbox_mesh((Mesh*) ob->data, center, extents);
|
|
RAS_MeshObject* meshobj = BL_ConvertMesh(mesh,ob,kxscene,converter, libloading);
|
|
|
|
// needed for python scripting
|
|
kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
|
|
|
|
if (ob->gameflag & OB_NAVMESH)
|
|
{
|
|
gameobj = new KX_NavMeshObject(kxscene,KX_Scene::m_callbacks);
|
|
gameobj->AddMesh(meshobj);
|
|
break;
|
|
}
|
|
|
|
gameobj = new BL_DeformableGameObject(ob,kxscene,KX_Scene::m_callbacks);
|
|
|
|
// set transformation
|
|
gameobj->AddMesh(meshobj);
|
|
|
|
// gather levels of detail
|
|
if (BLI_countlist(&ob->lodlevels) > 1) {
|
|
LodLevel *lod = ((LodLevel*)ob->lodlevels.first)->next;
|
|
Mesh* lodmesh = mesh;
|
|
Object* lodmatob = ob;
|
|
gameobj->AddLodMesh(meshobj);
|
|
for (; lod; lod = lod->next) {
|
|
if (!lod->source || lod->source->type != OB_MESH) continue;
|
|
if (lod->flags & OB_LOD_USE_MESH) {
|
|
lodmesh = static_cast<Mesh*>(lod->source->data);
|
|
}
|
|
if (lod->flags & OB_LOD_USE_MAT) {
|
|
lodmatob = lod->source;
|
|
}
|
|
gameobj->AddLodMesh(BL_ConvertMesh(lodmesh, lodmatob, kxscene, converter, libloading));
|
|
}
|
|
}
|
|
|
|
// for all objects: check whether they want to
|
|
// respond to updates
|
|
bool ignoreActivityCulling =
|
|
((ob->gameflag2 & OB_NEVER_DO_ACTIVITY_CULLING)!=0);
|
|
gameobj->SetIgnoreActivityCulling(ignoreActivityCulling);
|
|
gameobj->SetOccluder((ob->gameflag & OB_OCCLUDER) != 0, false);
|
|
|
|
// we only want obcolor used if there is a material in the mesh
|
|
// that requires it
|
|
Material *mat= NULL;
|
|
bool bUseObjectColor=false;
|
|
|
|
for (int i=0;i<mesh->totcol;i++) {
|
|
mat=mesh->mat[i];
|
|
if (!mat) break;
|
|
if ((mat->shade_flag & MA_OBCOLOR)) {
|
|
bUseObjectColor = true;
|
|
break;
|
|
}
|
|
}
|
|
if (bUseObjectColor)
|
|
gameobj->SetObjectColor(ob->col);
|
|
|
|
// two options exists for deform: shape keys and armature
|
|
// only support relative shape key
|
|
bool bHasShapeKey = mesh->key != NULL && mesh->key->type==KEY_RELATIVE;
|
|
bool bHasDvert = mesh->dvert != NULL && ob->defbase.first;
|
|
bool bHasArmature = (BL_ModifierDeformer::HasArmatureDeformer(ob) && ob->parent && ob->parent->type == OB_ARMATURE && bHasDvert);
|
|
bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(ob);
|
|
#ifdef WITH_BULLET
|
|
bool bHasSoftBody = (!ob->parent && (ob->gameflag & OB_SOFT_BODY));
|
|
#endif
|
|
if (bHasModifier) {
|
|
BL_ModifierDeformer *dcont = new BL_ModifierDeformer((BL_DeformableGameObject *)gameobj,
|
|
kxscene->GetBlenderScene(), ob, meshobj);
|
|
((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
|
|
} else if (bHasShapeKey) {
|
|
// not that we can have shape keys without dvert!
|
|
BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj,
|
|
ob, meshobj);
|
|
((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
|
|
} else if (bHasArmature) {
|
|
BL_SkinDeformer *dcont = new BL_SkinDeformer((BL_DeformableGameObject*)gameobj,
|
|
ob, meshobj);
|
|
((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
|
|
} else if (bHasDvert) {
|
|
// this case correspond to a mesh that can potentially deform but not with the
|
|
// object to which it is attached for the moment. A skin mesh was created in
|
|
// BL_ConvertMesh() so must create a deformer too!
|
|
BL_MeshDeformer *dcont = new BL_MeshDeformer((BL_DeformableGameObject*)gameobj,
|
|
ob, meshobj);
|
|
((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
|
|
#ifdef WITH_BULLET
|
|
} else if (bHasSoftBody) {
|
|
KX_SoftBodyDeformer *dcont = new KX_SoftBodyDeformer(meshobj, (BL_DeformableGameObject*)gameobj);
|
|
((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
|
|
#endif
|
|
}
|
|
|
|
MT_Point3 min = MT_Point3(center) - MT_Vector3(extents);
|
|
MT_Point3 max = MT_Point3(center) + MT_Vector3(extents);
|
|
SG_BBox bbox = SG_BBox(min, max);
|
|
gameobj->GetSGNode()->SetBBox(bbox);
|
|
gameobj->GetSGNode()->SetRadius(radius);
|
|
|
|
break;
|
|
}
|
|
|
|
case OB_ARMATURE:
|
|
{
|
|
bArmature *arm = (bArmature*)ob->data;
|
|
gameobj = new BL_ArmatureObject(
|
|
kxscene,
|
|
KX_Scene::m_callbacks,
|
|
ob,
|
|
kxscene->GetBlenderScene(), // handle
|
|
arm->gevertdeformer
|
|
);
|
|
/* Get the current pose from the armature object and apply it as the rest pose */
|
|
break;
|
|
}
|
|
|
|
case OB_EMPTY:
|
|
{
|
|
gameobj = new KX_EmptyObject(kxscene,KX_Scene::m_callbacks);
|
|
// set transformation
|
|
break;
|
|
}
|
|
|
|
case OB_FONT:
|
|
{
|
|
bool do_color_management = !(blenderscene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT);
|
|
/* font objects have no bounding box */
|
|
gameobj = new KX_FontObject(kxscene,KX_Scene::m_callbacks, rendertools, ob, do_color_management);
|
|
|
|
/* add to the list only the visible fonts */
|
|
if ((ob->lay & kxscene->GetBlenderScene()->lay) != 0)
|
|
kxscene->AddFont(static_cast<KX_FontObject*>(gameobj));
|
|
break;
|
|
}
|
|
|
|
#ifdef THREADED_DAG_WORKAROUND
|
|
case OB_CURVE:
|
|
{
|
|
if (ob->curve_cache == NULL) {
|
|
BKE_displist_make_curveTypes(blenderscene, ob, false);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
if (gameobj)
|
|
{
|
|
gameobj->SetLayer(ob->lay);
|
|
gameobj->SetBlenderObject(ob);
|
|
/* set the visibility state based on the objects render option in the outliner */
|
|
if (ob->restrictflag & OB_RESTRICT_RENDER) gameobj->SetVisible(0, 0);
|
|
}
|
|
return gameobj;
|
|
}
|
|
|
|
struct parentChildLink {
|
|
struct Object* m_blenderchild;
|
|
SG_Node* m_gamechildnode;
|
|
};
|
|
|
|
#include "DNA_constraint_types.h"
|
|
//XXX #include "BIF_editconstraint.h"
|
|
|
|
static bPoseChannel *get_active_posechannel2(Object *ob)
|
|
{
|
|
bArmature *arm= (bArmature*)ob->data;
|
|
bPoseChannel *pchan;
|
|
|
|
/* find active */
|
|
for (pchan= (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
|
if (pchan->bone && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer))
|
|
return pchan;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static ListBase *get_active_constraints2(Object *ob)
|
|
{
|
|
if (!ob)
|
|
return NULL;
|
|
|
|
// XXX - shouldnt we care about the pose data and not the mode???
|
|
if (ob->mode & OB_MODE_POSE) {
|
|
bPoseChannel *pchan;
|
|
|
|
pchan = get_active_posechannel2(ob);
|
|
if (pchan)
|
|
return &pchan->constraints;
|
|
}
|
|
else
|
|
return &ob->constraints;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void UNUSED_FUNCTION(RBJconstraints)(Object *ob)//not used
|
|
{
|
|
ListBase *conlist;
|
|
bConstraint *curcon;
|
|
|
|
conlist = get_active_constraints2(ob);
|
|
|
|
if (conlist) {
|
|
for (curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) {
|
|
|
|
printf("%i\n",curcon->type);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
#include "PHY_IPhysicsEnvironment.h"
|
|
#include "PHY_DynamicTypes.h"
|
|
|
|
|
|
static KX_GameObject* getGameOb(STR_String busc,CListValue* sumolist)
|
|
{
|
|
|
|
for (int j=0;j<sumolist->GetCount();j++)
|
|
{
|
|
KX_GameObject* gameobje = (KX_GameObject*) sumolist->GetValue(j);
|
|
if (gameobje->GetName()==busc)
|
|
return gameobje;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* helper for BL_ConvertBlenderObjects, avoids code duplication
|
|
* note: all var names match args are passed from the caller */
|
|
static void bl_ConvertBlenderObject_Single(
|
|
KX_BlenderSceneConverter *converter,
|
|
Scene *blenderscene, Object *blenderobject,
|
|
vector<MT_Vector3> &inivel, vector<MT_Vector3> &iniang,
|
|
vector<parentChildLink> &vec_parent_child,
|
|
CListValue* logicbrick_conversionlist,
|
|
CListValue* objectlist, CListValue* inactivelist, CListValue* sumolist,
|
|
KX_Scene* kxscene, KX_GameObject* gameobj,
|
|
SCA_LogicManager* logicmgr, SCA_TimeEventManager* timemgr,
|
|
bool isInActiveLayer
|
|
)
|
|
{
|
|
MT_Point3 posPrev;
|
|
MT_Matrix3x3 angor;
|
|
if (converter->addInitFromFrame) blenderscene->r.cfra=blenderscene->r.sfra;
|
|
|
|
MT_Point3 pos(
|
|
blenderobject->loc[0]+blenderobject->dloc[0],
|
|
blenderobject->loc[1]+blenderobject->dloc[1],
|
|
blenderobject->loc[2]+blenderobject->dloc[2]
|
|
);
|
|
|
|
MT_Matrix3x3 rotation;
|
|
float rotmat[3][3];
|
|
BKE_object_rot_to_mat3(blenderobject, rotmat, false);
|
|
rotation.setValue3x3((float*)rotmat);
|
|
|
|
MT_Vector3 scale(blenderobject->size);
|
|
|
|
if (converter->addInitFromFrame) {//rcruiz
|
|
blenderscene->r.cfra=blenderscene->r.sfra-1;
|
|
//XXX update_for_newframe();
|
|
MT_Vector3 tmp=pos-MT_Point3(blenderobject->loc[0]+blenderobject->dloc[0],
|
|
blenderobject->loc[1]+blenderobject->dloc[1],
|
|
blenderobject->loc[2]+blenderobject->dloc[2]
|
|
);
|
|
|
|
float rotmatPrev[3][3];
|
|
BKE_object_rot_to_mat3(blenderobject, rotmatPrev, false);
|
|
|
|
float eulxyz[3], eulxyzPrev[3];
|
|
mat3_to_eul(eulxyz, rotmat);
|
|
mat3_to_eul(eulxyzPrev, rotmatPrev);
|
|
|
|
double fps = (double) blenderscene->r.frs_sec/
|
|
(double) blenderscene->r.frs_sec_base;
|
|
|
|
tmp.scale(fps, fps, fps);
|
|
inivel.push_back(tmp);
|
|
tmp[0]=eulxyz[0]-eulxyzPrev[0];
|
|
tmp[1]=eulxyz[1]-eulxyzPrev[1];
|
|
tmp[2]=eulxyz[2]-eulxyzPrev[2];
|
|
tmp.scale(fps, fps, fps);
|
|
iniang.push_back(tmp);
|
|
blenderscene->r.cfra=blenderscene->r.sfra;
|
|
//XXX update_for_newframe();
|
|
}
|
|
|
|
gameobj->NodeSetLocalPosition(pos);
|
|
gameobj->NodeSetLocalOrientation(rotation);
|
|
gameobj->NodeSetLocalScale(scale);
|
|
gameobj->NodeUpdateGS(0);
|
|
|
|
sumolist->Add(gameobj->AddRef());
|
|
|
|
BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer);
|
|
|
|
gameobj->SetName(blenderobject->id.name + 2);
|
|
|
|
// update children/parent hierarchy
|
|
if ((blenderobject->parent != 0)&&(!converter->addInitFromFrame))
|
|
{
|
|
// blender has an additional 'parentinverse' offset in each object
|
|
SG_Callbacks callback(NULL,NULL,NULL,KX_Scene::KX_ScenegraphUpdateFunc,KX_Scene::KX_ScenegraphRescheduleFunc);
|
|
SG_Node* parentinversenode = new SG_Node(NULL,kxscene,callback);
|
|
|
|
// define a normal parent relationship for this node.
|
|
KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New();
|
|
parentinversenode->SetParentRelation(parent_relation);
|
|
|
|
parentChildLink pclink;
|
|
pclink.m_blenderchild = blenderobject;
|
|
pclink.m_gamechildnode = parentinversenode;
|
|
vec_parent_child.push_back(pclink);
|
|
|
|
float* fl = (float*) blenderobject->parentinv;
|
|
MT_Transform parinvtrans(fl);
|
|
parentinversenode->SetLocalPosition(parinvtrans.getOrigin());
|
|
// problem here: the parent inverse transform combines scaling and rotation
|
|
// in the basis but the scenegraph needs separate rotation and scaling.
|
|
// This is not important for OpenGL (it uses 4x4 matrix) but it is important
|
|
// for the physic engine that needs a separate scaling
|
|
//parentinversenode->SetLocalOrientation(parinvtrans.getBasis());
|
|
|
|
// Extract the rotation and the scaling from the basis
|
|
MT_Matrix3x3 ori(parinvtrans.getBasis());
|
|
MT_Vector3 x(ori.getColumn(0));
|
|
MT_Vector3 y(ori.getColumn(1));
|
|
MT_Vector3 z(ori.getColumn(2));
|
|
MT_Vector3 parscale(x.length(), y.length(), z.length());
|
|
if (!MT_fuzzyZero(parscale[0]))
|
|
x /= parscale[0];
|
|
if (!MT_fuzzyZero(parscale[1]))
|
|
y /= parscale[1];
|
|
if (!MT_fuzzyZero(parscale[2]))
|
|
z /= parscale[2];
|
|
ori.setColumn(0, x);
|
|
ori.setColumn(1, y);
|
|
ori.setColumn(2, z);
|
|
parentinversenode->SetLocalOrientation(ori);
|
|
parentinversenode->SetLocalScale(parscale);
|
|
|
|
parentinversenode->AddChild(gameobj->GetSGNode());
|
|
}
|
|
|
|
// needed for python scripting
|
|
logicmgr->RegisterGameObjectName(gameobj->GetName(),gameobj);
|
|
|
|
// needed for group duplication
|
|
logicmgr->RegisterGameObj(blenderobject, gameobj);
|
|
for (int i = 0; i < gameobj->GetMeshCount(); i++)
|
|
logicmgr->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), blenderobject);
|
|
|
|
converter->RegisterGameObject(gameobj, blenderobject);
|
|
// this was put in rapidly, needs to be looked at more closely
|
|
// only draw/use objects in active 'blender' layers
|
|
|
|
logicbrick_conversionlist->Add(gameobj->AddRef());
|
|
|
|
if (converter->addInitFromFrame) {
|
|
posPrev=gameobj->NodeGetWorldPosition();
|
|
angor=gameobj->NodeGetWorldOrientation();
|
|
}
|
|
if (isInActiveLayer)
|
|
{
|
|
objectlist->Add(gameobj->AddRef());
|
|
//tf.Add(gameobj->GetSGNode());
|
|
|
|
gameobj->NodeUpdateGS(0);
|
|
gameobj->AddMeshUser();
|
|
|
|
}
|
|
else
|
|
{
|
|
//we must store this object otherwise it will be deleted
|
|
//at the end of this function if it is not a root object
|
|
inactivelist->Add(gameobj->AddRef());
|
|
}
|
|
|
|
if (converter->addInitFromFrame) {
|
|
gameobj->NodeSetLocalPosition(posPrev);
|
|
gameobj->NodeSetLocalOrientation(angor);
|
|
}
|
|
}
|
|
|
|
|
|
// convert blender objects into ketsji gameobjects
|
|
void BL_ConvertBlenderObjects(struct Main* maggie,
|
|
KX_Scene* kxscene,
|
|
KX_KetsjiEngine* ketsjiEngine,
|
|
e_PhysicsEngine physics_engine,
|
|
RAS_IRasterizer* rendertools,
|
|
RAS_ICanvas* canvas,
|
|
KX_BlenderSceneConverter* converter,
|
|
bool alwaysUseExpandFraming,
|
|
bool libloading
|
|
)
|
|
{
|
|
|
|
#define BL_CONVERTBLENDEROBJECT_SINGLE \
|
|
bl_ConvertBlenderObject_Single(converter, \
|
|
blenderscene, blenderobject, \
|
|
inivel, iniang, \
|
|
vec_parent_child, \
|
|
logicbrick_conversionlist, \
|
|
objectlist, inactivelist, sumolist, \
|
|
kxscene, gameobj, \
|
|
logicmgr, timemgr, \
|
|
isInActiveLayer \
|
|
)
|
|
|
|
|
|
|
|
Scene *blenderscene = kxscene->GetBlenderScene();
|
|
// for SETLOOPER
|
|
Scene *sce_iter;
|
|
Base *base;
|
|
|
|
// Get the frame settings of the canvas.
|
|
// Get the aspect ratio of the canvas as designed by the user.
|
|
|
|
RAS_FrameSettings::RAS_FrameType frame_type;
|
|
int aspect_width;
|
|
int aspect_height;
|
|
vector<MT_Vector3> inivel,iniang;
|
|
set<Group*> grouplist; // list of groups to be converted
|
|
set<Object*> allblobj; // all objects converted
|
|
set<Object*> groupobj; // objects from groups (never in active layer)
|
|
|
|
// This is bad, but we use this to make sure the first time this is called
|
|
// is not in a separate thread.
|
|
BL_Texture::GetMaxUnits();
|
|
|
|
if (alwaysUseExpandFraming) {
|
|
frame_type = RAS_FrameSettings::e_frame_extend;
|
|
aspect_width = canvas->GetWidth();
|
|
aspect_height = canvas->GetHeight();
|
|
} else {
|
|
if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_BARS) {
|
|
frame_type = RAS_FrameSettings::e_frame_bars;
|
|
} else if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_EXTEND) {
|
|
frame_type = RAS_FrameSettings::e_frame_extend;
|
|
} else {
|
|
frame_type = RAS_FrameSettings::e_frame_scale;
|
|
}
|
|
|
|
aspect_width = (int)(blenderscene->r.xsch * blenderscene->r.xasp);
|
|
aspect_height = (int)(blenderscene->r.ysch * blenderscene->r.yasp);
|
|
}
|
|
|
|
RAS_FrameSettings frame_settings(
|
|
frame_type,
|
|
blenderscene->gm.framing.col[0],
|
|
blenderscene->gm.framing.col[1],
|
|
blenderscene->gm.framing.col[2],
|
|
aspect_width,
|
|
aspect_height
|
|
);
|
|
kxscene->SetFramingType(frame_settings);
|
|
|
|
kxscene->SetGravity(MT_Vector3(0,0, -blenderscene->gm.gravity));
|
|
|
|
/* set activity culling parameters */
|
|
kxscene->SetActivityCulling( (blenderscene->gm.mode & WO_ACTIVITY_CULLING) != 0);
|
|
kxscene->SetActivityCullingRadius(blenderscene->gm.activityBoxRadius);
|
|
kxscene->SetDbvtCulling((blenderscene->gm.mode & WO_DBVT_CULLING) != 0);
|
|
|
|
// no occlusion culling by default
|
|
kxscene->SetDbvtOcclusionRes(0);
|
|
|
|
int activeLayerBitInfo = blenderscene->lay;
|
|
|
|
// list of all object converted, active and inactive
|
|
CListValue* sumolist = new CListValue();
|
|
|
|
vector<parentChildLink> vec_parent_child;
|
|
|
|
CListValue* objectlist = kxscene->GetObjectList();
|
|
CListValue* inactivelist = kxscene->GetInactiveList();
|
|
CListValue* parentlist = kxscene->GetRootParentList();
|
|
|
|
SCA_LogicManager* logicmgr = kxscene->GetLogicManager();
|
|
SCA_TimeEventManager* timemgr = kxscene->GetTimeEventManager();
|
|
|
|
CListValue* logicbrick_conversionlist = new CListValue();
|
|
|
|
//SG_TreeFactory tf;
|
|
|
|
// Convert actions to actionmap
|
|
bAction *curAct;
|
|
for (curAct = (bAction*)maggie->action.first; curAct; curAct=(bAction*)curAct->id.next)
|
|
{
|
|
logicmgr->RegisterActionName(curAct->id.name + 2, curAct);
|
|
}
|
|
|
|
SetDefaultLightMode(blenderscene);
|
|
// Let's support scene set.
|
|
// Beware of name conflict in linked data, it will not crash but will create confusion
|
|
// in Python scripting and in certain actuators (replace mesh). Linked scene *should* have
|
|
// no conflicting name for Object, Object data and Action.
|
|
for (SETLOOPER(blenderscene, sce_iter, base))
|
|
{
|
|
Object* blenderobject = base->object;
|
|
allblobj.insert(blenderobject);
|
|
|
|
KX_GameObject* gameobj = gameobject_from_blenderobject(
|
|
base->object,
|
|
kxscene,
|
|
rendertools,
|
|
converter,
|
|
libloading);
|
|
|
|
bool isInActiveLayer = (blenderobject->lay & activeLayerBitInfo) !=0;
|
|
bool addobj=true;
|
|
|
|
if (converter->addInitFromFrame)
|
|
if (!isInActiveLayer)
|
|
addobj=false;
|
|
|
|
if (gameobj)
|
|
{
|
|
if (addobj)
|
|
{ /* macro calls object conversion funcs */
|
|
BL_CONVERTBLENDEROBJECT_SINGLE;
|
|
|
|
if (gameobj->IsDupliGroup()) {
|
|
grouplist.insert(blenderobject->dup_group);
|
|
}
|
|
}
|
|
|
|
/* Note about memory leak issues:
|
|
* When a CValue derived class is created, m_refcount is initialized to 1
|
|
* so the class must be released after being used to make sure that it won't
|
|
* hang in memory. If the object needs to be stored for a long time,
|
|
* use AddRef() so that this Release() does not free the object.
|
|
* Make sure that for any AddRef() there is a Release()!!!!
|
|
* Do the same for any object derived from CValue, CExpression and NG_NetworkMessage
|
|
*/
|
|
gameobj->Release();
|
|
}
|
|
}
|
|
|
|
if (!grouplist.empty())
|
|
{
|
|
// now convert the group referenced by dupli group object
|
|
// keep track of all groups already converted
|
|
set<Group*> allgrouplist = grouplist;
|
|
set<Group*> tempglist;
|
|
// recurse
|
|
while (!grouplist.empty())
|
|
{
|
|
set<Group*>::iterator git;
|
|
tempglist.clear();
|
|
tempglist.swap(grouplist);
|
|
for (git=tempglist.begin(); git!=tempglist.end(); git++)
|
|
{
|
|
Group* group = *git;
|
|
GroupObject* go;
|
|
for (go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next)
|
|
{
|
|
Object* blenderobject = go->ob;
|
|
if (converter->FindGameObject(blenderobject) == NULL)
|
|
{
|
|
allblobj.insert(blenderobject);
|
|
groupobj.insert(blenderobject);
|
|
KX_GameObject* gameobj = gameobject_from_blenderobject(
|
|
blenderobject,
|
|
kxscene,
|
|
rendertools,
|
|
converter,
|
|
libloading);
|
|
|
|
// this code is copied from above except that
|
|
// object from groups are never in active layer
|
|
bool isInActiveLayer = false;
|
|
bool addobj=true;
|
|
|
|
if (converter->addInitFromFrame)
|
|
if (!isInActiveLayer)
|
|
addobj=false;
|
|
|
|
if (gameobj)
|
|
{
|
|
if (addobj)
|
|
{ /* macro calls object conversion funcs */
|
|
BL_CONVERTBLENDEROBJECT_SINGLE;
|
|
}
|
|
|
|
if (gameobj->IsDupliGroup())
|
|
{
|
|
if (allgrouplist.insert(blenderobject->dup_group).second)
|
|
{
|
|
grouplist.insert(blenderobject->dup_group);
|
|
}
|
|
}
|
|
|
|
|
|
/* see comment above re: mem leaks */
|
|
gameobj->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// non-camera objects not supported as camera currently
|
|
if (blenderscene->camera && blenderscene->camera->type == OB_CAMERA) {
|
|
KX_Camera *gamecamera= (KX_Camera*) converter->FindGameObject(blenderscene->camera);
|
|
|
|
if (gamecamera)
|
|
kxscene->SetActiveCamera(gamecamera);
|
|
}
|
|
|
|
// Set up armatures
|
|
set<Object*>::iterator oit;
|
|
for (oit=allblobj.begin(); oit!=allblobj.end(); oit++)
|
|
{
|
|
Object* blenderobj = *oit;
|
|
if (blenderobj->type==OB_MESH) {
|
|
Mesh *me = (Mesh*)blenderobj->data;
|
|
|
|
if (me->dvert) {
|
|
BL_DeformableGameObject *obj = (BL_DeformableGameObject*)converter->FindGameObject(blenderobj);
|
|
|
|
if (obj && BL_ModifierDeformer::HasArmatureDeformer(blenderobj) && blenderobj->parent && blenderobj->parent->type==OB_ARMATURE) {
|
|
KX_GameObject *par = converter->FindGameObject(blenderobj->parent);
|
|
if (par && obj->GetDeformer())
|
|
((BL_SkinDeformer*)obj->GetDeformer())->SetArmature((BL_ArmatureObject*) par);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// create hierarchy information
|
|
int i;
|
|
vector<parentChildLink>::iterator pcit;
|
|
|
|
for (pcit = vec_parent_child.begin();!(pcit==vec_parent_child.end());++pcit)
|
|
{
|
|
|
|
struct Object* blenderchild = pcit->m_blenderchild;
|
|
struct Object* blenderparent = blenderchild->parent;
|
|
KX_GameObject* parentobj = converter->FindGameObject(blenderparent);
|
|
KX_GameObject* childobj = converter->FindGameObject(blenderchild);
|
|
|
|
assert(childobj);
|
|
|
|
if (!parentobj || objectlist->SearchValue(childobj) != objectlist->SearchValue(parentobj))
|
|
{
|
|
// special case: the parent and child object are not in the same layer.
|
|
// This weird situation is used in Apricot for test purposes.
|
|
// Resolve it by not converting the child
|
|
childobj->GetSGNode()->DisconnectFromParent();
|
|
delete pcit->m_gamechildnode;
|
|
// Now destroy the child object but also all its descendent that may already be linked
|
|
// Remove the child reference in the local list!
|
|
// Note: there may be descendents already if the children of the child were processed
|
|
// by this loop before the child. In that case, we must remove the children also
|
|
CListValue* childrenlist = childobj->GetChildrenRecursive();
|
|
childrenlist->Add(childobj->AddRef());
|
|
for ( i=0;i<childrenlist->GetCount();i++)
|
|
{
|
|
KX_GameObject* obj = static_cast<KX_GameObject*>(childrenlist->GetValue(i));
|
|
if (sumolist->RemoveValue(obj))
|
|
obj->Release();
|
|
if (logicbrick_conversionlist->RemoveValue(obj))
|
|
obj->Release();
|
|
}
|
|
childrenlist->Release();
|
|
|
|
// now destroy recursively
|
|
converter->UnregisterGameObject(childobj); // removing objects during conversion make sure this runs too
|
|
kxscene->RemoveObject(childobj);
|
|
|
|
continue;
|
|
}
|
|
|
|
switch (blenderchild->partype)
|
|
{
|
|
case PARVERT1:
|
|
{
|
|
// creat a new vertex parent relationship for this node.
|
|
KX_VertexParentRelation * vertex_parent_relation = KX_VertexParentRelation::New();
|
|
pcit->m_gamechildnode->SetParentRelation(vertex_parent_relation);
|
|
break;
|
|
}
|
|
case PARSLOW:
|
|
{
|
|
// creat a new slow parent relationship for this node.
|
|
KX_SlowParentRelation * slow_parent_relation = KX_SlowParentRelation::New(blenderchild->sf);
|
|
pcit->m_gamechildnode->SetParentRelation(slow_parent_relation);
|
|
break;
|
|
}
|
|
case PARBONE:
|
|
{
|
|
// parent this to a bone
|
|
Bone *parent_bone = BKE_armature_find_bone_name(BKE_armature_from_object(blenderchild->parent),
|
|
blenderchild->parsubstr);
|
|
|
|
if (parent_bone) {
|
|
KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone);
|
|
pcit->m_gamechildnode->SetParentRelation(bone_parent_relation);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case PARSKEL: // skinned - ignore
|
|
break;
|
|
case PAROBJECT:
|
|
case PARCURVE:
|
|
case PARKEY:
|
|
case PARVERT3:
|
|
default:
|
|
// unhandled
|
|
break;
|
|
}
|
|
|
|
parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode);
|
|
}
|
|
vec_parent_child.clear();
|
|
|
|
// find 'root' parents (object that has not parents in SceneGraph)
|
|
for (i=0;i<sumolist->GetCount();++i)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
if (gameobj->GetSGNode()->GetSGParent() == 0)
|
|
{
|
|
parentlist->Add(gameobj->AddRef());
|
|
gameobj->NodeUpdateGS(0);
|
|
}
|
|
}
|
|
|
|
// create graphic controller for culling
|
|
if (kxscene->GetDbvtCulling())
|
|
{
|
|
bool occlusion = false;
|
|
for (i=0; i<sumolist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
if (gameobj->GetMeshCount() > 0)
|
|
{
|
|
MT_Point3 box[2];
|
|
gameobj->GetSGNode()->BBox().getmm(box, MT_Transform::Identity());
|
|
// box[0] is the min, box[1] is the max
|
|
bool isactive = objectlist->SearchValue(gameobj);
|
|
BL_CreateGraphicObjectNew(gameobj,box[0],box[1],kxscene,isactive,physics_engine);
|
|
if (gameobj->GetOccluder())
|
|
occlusion = true;
|
|
}
|
|
}
|
|
if (occlusion)
|
|
kxscene->SetDbvtOcclusionRes(blenderscene->gm.occlusionRes);
|
|
}
|
|
if (blenderscene->world)
|
|
kxscene->GetPhysicsEnvironment()->SetNumTimeSubSteps(blenderscene->gm.physubstep);
|
|
|
|
// now that the scenegraph is complete, let's instantiate the deformers.
|
|
// We need that to create reusable derived mesh and physic shapes
|
|
for (i=0;i<sumolist->GetCount();++i)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
if (gameobj->GetDeformer())
|
|
gameobj->GetDeformer()->UpdateBuckets();
|
|
}
|
|
|
|
// Set up armature constraints and shapekey drivers
|
|
for (i=0;i<sumolist->GetCount();++i)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
|
|
{
|
|
BL_ArmatureObject *armobj = (BL_ArmatureObject*)gameobj;
|
|
armobj->LoadConstraints(converter);
|
|
|
|
CListValue *children = armobj->GetChildren();
|
|
for (int j=0; j<children->GetCount();++j)
|
|
{
|
|
BL_ShapeDeformer *deform = dynamic_cast<BL_ShapeDeformer*>(((KX_GameObject*)children->GetValue(j))->GetDeformer());
|
|
if (deform)
|
|
deform->LoadShapeDrivers(armobj);
|
|
}
|
|
|
|
children->Release();
|
|
}
|
|
}
|
|
|
|
bool processCompoundChildren = false;
|
|
|
|
// create physics information
|
|
for (i=0;i<sumolist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
struct Object* blenderobject = gameobj->GetBlenderObject();
|
|
int nummeshes = gameobj->GetMeshCount();
|
|
RAS_MeshObject* meshobj = 0;
|
|
if (nummeshes > 0)
|
|
{
|
|
meshobj = gameobj->GetMesh(0);
|
|
}
|
|
int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0;
|
|
BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,converter,processCompoundChildren);
|
|
}
|
|
|
|
processCompoundChildren = true;
|
|
// create physics information
|
|
for (i=0;i<sumolist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
struct Object* blenderobject = gameobj->GetBlenderObject();
|
|
int nummeshes = gameobj->GetMeshCount();
|
|
RAS_MeshObject* meshobj = 0;
|
|
if (nummeshes > 0)
|
|
{
|
|
meshobj = gameobj->GetMesh(0);
|
|
}
|
|
int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0;
|
|
BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,converter,processCompoundChildren);
|
|
}
|
|
|
|
//set ini linearVel and int angularVel //rcruiz
|
|
if (converter->addInitFromFrame)
|
|
for (i=0;i<sumolist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
if (gameobj->IsDynamic()) {
|
|
gameobj->setLinearVelocity(inivel[i],false);
|
|
gameobj->setAngularVelocity(iniang[i],false);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// create physics joints
|
|
for (i=0;i<sumolist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
|
|
struct Object* blenderobject = gameobj->GetBlenderObject();
|
|
ListBase *conlist;
|
|
bConstraint *curcon;
|
|
conlist = get_active_constraints2(blenderobject);
|
|
|
|
if ((gameobj->GetLayer()&activeLayerBitInfo)==0)
|
|
continue;
|
|
|
|
if (conlist) {
|
|
for (curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) {
|
|
if (curcon->type==CONSTRAINT_TYPE_RIGIDBODYJOINT) {
|
|
|
|
bRigidBodyJointConstraint *dat=(bRigidBodyJointConstraint *)curcon->data;
|
|
|
|
if (!dat->child && !(curcon->flag & CONSTRAINT_OFF)) {
|
|
|
|
PHY_IPhysicsController* physctr2 = 0;
|
|
|
|
if (dat->tar)
|
|
{
|
|
KX_GameObject *gotar=getGameOb(dat->tar->id.name+2,sumolist);
|
|
if (gotar && ((gotar->GetLayer()&activeLayerBitInfo)!=0) && gotar->GetPhysicsController())
|
|
physctr2 = gotar->GetPhysicsController();
|
|
}
|
|
|
|
if (gameobj->GetPhysicsController())
|
|
{
|
|
PHY_IPhysicsController* physctrl = gameobj->GetPhysicsController();
|
|
//we need to pass a full constraint frame, not just axis
|
|
|
|
//localConstraintFrameBasis
|
|
MT_Matrix3x3 localCFrame(MT_Vector3(dat->axX,dat->axY,dat->axZ));
|
|
MT_Vector3 axis0 = localCFrame.getColumn(0);
|
|
MT_Vector3 axis1 = localCFrame.getColumn(1);
|
|
MT_Vector3 axis2 = localCFrame.getColumn(2);
|
|
|
|
int constraintId = kxscene->GetPhysicsEnvironment()->CreateConstraint(physctrl,physctr2,(PHY_ConstraintType)dat->type,(float)dat->pivX,
|
|
(float)dat->pivY,(float)dat->pivZ,
|
|
(float)axis0.x(),(float)axis0.y(),(float)axis0.z(),
|
|
(float)axis1.x(),(float)axis1.y(),(float)axis1.z(),
|
|
(float)axis2.x(),(float)axis2.y(),(float)axis2.z(),dat->flag);
|
|
if (constraintId)
|
|
{
|
|
//if it is a generic 6DOF constraint, set all the limits accordingly
|
|
if (dat->type == PHY_GENERIC_6DOF_CONSTRAINT)
|
|
{
|
|
int dof;
|
|
int dofbit=1;
|
|
for (dof=0;dof<6;dof++)
|
|
{
|
|
if (dat->flag & dofbit)
|
|
{
|
|
kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]);
|
|
} else
|
|
{
|
|
//minLimit > maxLimit means free(disabled limit) for this degree of freedom
|
|
kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,1,-1);
|
|
}
|
|
dofbit<<=1;
|
|
}
|
|
}
|
|
else if (dat->type == PHY_CONE_TWIST_CONSTRAINT)
|
|
{
|
|
int dof;
|
|
int dofbit = 1<<3; // bitflag use_angular_limit_x
|
|
|
|
for (dof=3;dof<6;dof++)
|
|
{
|
|
if (dat->flag & dofbit)
|
|
{
|
|
kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]);
|
|
}
|
|
else
|
|
{
|
|
//maxLimit < 0 means free(disabled limit) for this degree of freedom
|
|
kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,1,-1);
|
|
}
|
|
dofbit<<=1;
|
|
}
|
|
}
|
|
else if (dat->type == PHY_LINEHINGE_CONSTRAINT)
|
|
{
|
|
int dof = 3; // dof for angular x
|
|
int dofbit = 1<<3; // bitflag use_angular_limit_x
|
|
|
|
if (dat->flag & dofbit)
|
|
{
|
|
kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,
|
|
dat->minLimit[dof],dat->maxLimit[dof]);
|
|
} else
|
|
{
|
|
//minLimit > maxLimit means free(disabled limit) for this degree of freedom
|
|
kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,1,-1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sumolist->Release();
|
|
|
|
// convert world
|
|
KX_WorldInfo* worldinfo = new BlenderWorldInfo(blenderscene, blenderscene->world);
|
|
converter->RegisterWorldInfo(worldinfo);
|
|
kxscene->SetWorldInfo(worldinfo);
|
|
|
|
//create object representations for obstacle simulation
|
|
KX_ObstacleSimulation* obssimulation = kxscene->GetObstacleSimulation();
|
|
if (obssimulation)
|
|
{
|
|
for ( i=0;i<objectlist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i));
|
|
struct Object* blenderobject = gameobj->GetBlenderObject();
|
|
if (blenderobject->gameflag & OB_HASOBSTACLE)
|
|
{
|
|
obssimulation->AddObstacleForObj(gameobj);
|
|
}
|
|
}
|
|
}
|
|
|
|
//process navigation mesh objects
|
|
for ( i=0; i<objectlist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i));
|
|
struct Object* blenderobject = gameobj->GetBlenderObject();
|
|
if (blenderobject->type==OB_MESH && (blenderobject->gameflag & OB_NAVMESH))
|
|
{
|
|
KX_NavMeshObject* navmesh = static_cast<KX_NavMeshObject*>(gameobj);
|
|
navmesh->SetVisible(0, true);
|
|
navmesh->BuildNavMesh();
|
|
if (obssimulation)
|
|
obssimulation->AddObstaclesForNavMesh(navmesh);
|
|
}
|
|
}
|
|
for ( i=0; i<inactivelist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(inactivelist->GetValue(i));
|
|
struct Object* blenderobject = gameobj->GetBlenderObject();
|
|
if (blenderobject->type==OB_MESH && (blenderobject->gameflag & OB_NAVMESH))
|
|
{
|
|
KX_NavMeshObject* navmesh = static_cast<KX_NavMeshObject*>(gameobj);
|
|
navmesh->SetVisible(0, true);
|
|
}
|
|
}
|
|
|
|
#define CONVERT_LOGIC
|
|
#ifdef CONVERT_LOGIC
|
|
// convert logic bricks, sensors, controllers and actuators
|
|
for (i=0;i<logicbrick_conversionlist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
|
|
struct Object* blenderobj = gameobj->GetBlenderObject();
|
|
int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0;
|
|
bool isInActiveLayer = (blenderobj->lay & layerMask)!=0;
|
|
BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,converter);
|
|
}
|
|
for ( i=0;i<logicbrick_conversionlist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
|
|
struct Object* blenderobj = gameobj->GetBlenderObject();
|
|
int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0;
|
|
bool isInActiveLayer = (blenderobj->lay & layerMask)!=0;
|
|
BL_ConvertControllers(blenderobj,gameobj,logicmgr, layerMask,isInActiveLayer,converter, libloading);
|
|
}
|
|
for ( i=0;i<logicbrick_conversionlist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
|
|
struct Object* blenderobj = gameobj->GetBlenderObject();
|
|
int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0;
|
|
bool isInActiveLayer = (blenderobj->lay & layerMask)!=0;
|
|
BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,canvas,converter);
|
|
// set the init state to all objects
|
|
gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state);
|
|
}
|
|
// apply the initial state to controllers, only on the active objects as this registers the sensors
|
|
for ( i=0;i<objectlist->GetCount();i++)
|
|
{
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i));
|
|
gameobj->ResetState();
|
|
}
|
|
|
|
#endif //CONVERT_LOGIC
|
|
|
|
logicbrick_conversionlist->Release();
|
|
|
|
// Calculate the scene btree -
|
|
// too slow - commented out.
|
|
//kxscene->SetNodeTree(tf.MakeTree());
|
|
|
|
// instantiate dupli group, we will loop trough the object
|
|
// that are in active layers. Note that duplicating group
|
|
// has the effect of adding objects at the end of objectlist.
|
|
// Only loop through the first part of the list.
|
|
int objcount = objectlist->GetCount();
|
|
for (i=0;i<objcount;i++)
|
|
{
|
|
KX_GameObject* gameobj = (KX_GameObject*) objectlist->GetValue(i);
|
|
if (gameobj->IsDupliGroup())
|
|
{
|
|
kxscene->DupliGroupRecurse(gameobj, 0);
|
|
}
|
|
}
|
|
|
|
KX_Camera *activecam = kxscene->GetActiveCamera();
|
|
MT_Scalar distance = (activecam)? activecam->GetCameraFar() - activecam->GetCameraNear(): 100.0f;
|
|
RAS_BucketManager *bucketmanager = kxscene->GetBucketManager();
|
|
bucketmanager->OptimizeBuckets(distance);
|
|
}
|
|
|
|
SCA_IInputDevice::KX_EnumInputs ConvertKeyCode(int key_code)
|
|
{
|
|
return gReverseKeyTranslateTable[key_code];
|
|
}
|