blender/source/gameengine/Converter/BL_BlenderDataConversion.cpp

2706 lines
81 KiB
C++
Raw Normal View History

2002-10-12 11:37:38 +00:00
/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
2002-10-12 11:37:38 +00:00
*
* 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.
2002-10-12 11:37:38 +00:00
*
* 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,
2010-02-12 13:34:04 +00:00
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2002-10-12 11:37:38 +00:00
*
* 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 *****
2002-10-12 11:37:38 +00:00
* Convert blender data to ketsji
*/
#if defined(WIN32) && !defined(FREE_WINDOWS)
2002-10-12 11:37:38 +00:00
#pragma warning (disable : 4786)
#endif
#include <math.h>
2002-10-12 11:37:38 +00:00
#include "BL_BlenderDataConversion.h"
#include "KX_BlenderGL.h"
#include "KX_BlenderScalarInterpolator.h"
#include "RAS_IPolygonMaterial.h"
#include "KX_PolygonMaterial.h"
2002-10-12 11:37:38 +00:00
// 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 "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_EmptyObject.h"
#include "MT_Point3.h"
#include "MT_Transform.h"
#include "MT_MinMax.h"
2002-10-12 11:37:38 +00:00
#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 "RAS_IRenderTools.h"
#include "BL_Material.h"
#include "KX_BlenderMaterial.h"
#include "BL_Texture.h"
2002-10-12 11:37:38 +00:00
#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"
2002-10-12 11:37:38 +00:00
#include "BL_SkinDeformer.h"
#include "BL_MeshDeformer.h"
#include "KX_SoftBodyDeformer.h"
2002-10-12 11:37:38 +00:00
//#include "BL_ArmatureController.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"
2002-10-12 11:37:38 +00:00
#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"
2002-10-12 11:37:38 +00:00
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
#include "DNA_sound_types.h"
#include "DNA_key_types.h"
2005-04-23 11:36:44 +00:00
#include "DNA_armature_types.h"
#include "DNA_object_force.h"
2002-10-12 11:37:38 +00:00
#include "MEM_guardedalloc.h"
#include "BKE_utildefines.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"
}
2002-10-12 11:37:38 +00:00
#include "BKE_material.h" /* give_current_material */
/* 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 "SYS_System.h"
#include "SG_Node.h"
#include "SG_BBox.h"
#include "SG_Tree.h"
2002-10-12 11:37:38 +00:00
#include "KX_ConvertPhysicsObject.h"
#ifdef USE_BULLET
#include "CcdPhysicsEnvironment.h"
#include "CcdGraphicController.h"
#endif
#include "KX_MotionState.h"
2002-10-12 11:37:38 +00:00
// This file defines relationships between parents and children
// in the game engine.
#include "KX_SG_NodeRelationships.h"
2005-04-23 11:36:44 +00:00
#include "KX_SG_BoneParentNodeRelationship.h"
2002-10-12 11:37:38 +00:00
#include "BL_ArmatureObject.h"
#include "BL_DeformableGameObject.h"
#ifdef __cplusplus
extern "C" {
#endif
//XXX #include "BSE_headerbuttons.h"
//XXX void update_for_newframe();
//void scene_update_for_newframe(struct Scene *sce, unsigned int lay);
//#include "BKE_ipo.h"
//void do_all_data_ipos(void);
#ifdef __cplusplus
}
#endif
static int default_face_mode = TF_DYNAMIC;
2002-10-12 11:37:38 +00:00
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;
2002-10-12 11:37:38 +00:00
}
/* 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;
2002-10-12 11:37:38 +00:00
}
static void SetDefaultFaceType(Scene* scene)
{
default_face_mode = TF_DYNAMIC;
Scene *sce;
Base *base;
for(SETLOOPER(scene,base))
{
if (base->object->type == OB_LAMP)
{
default_face_mode = TF_DYNAMIC|TF_LIGHT;
return;
}
}
}
// --
static void GetRGB(short type,
MFace* mface,
MCol* mmcol,
Material *mat,
unsigned int &c0,
unsigned int &c1,
unsigned int &c2,
unsigned int &c3)
{
unsigned int color = 0xFFFFFFFFL;
switch(type)
{
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 04:28:02 +00:00
case 0: // vertex colors
{
if(mmcol) {
c0 = KX_Mcol2uint_new(mmcol[0]);
c1 = KX_Mcol2uint_new(mmcol[1]);
c2 = KX_Mcol2uint_new(mmcol[2]);
if (mface->v4)
c3 = KX_Mcol2uint_new(mmcol[3]);
}else // backup white
{
c0 = KX_rgbaint2uint_new(color);
c1 = KX_rgbaint2uint_new(color);
c2 = KX_rgbaint2uint_new(color);
if (mface->v4)
c3 = KX_rgbaint2uint_new( color );
}
} break;
case 1: // material rgba
{
if (mat) {
union {
unsigned char cp[4];
unsigned int integer;
} col_converter;
col_converter.cp[3] = (unsigned char) (mat->r*255.0);
col_converter.cp[2] = (unsigned char) (mat->g*255.0);
col_converter.cp[1] = (unsigned char) (mat->b*255.0);
col_converter.cp[0] = (unsigned char) (mat->alpha*255.0);
color = col_converter.integer;
}
c0 = KX_rgbaint2uint_new(color);
c1 = KX_rgbaint2uint_new(color);
c2 = KX_rgbaint2uint_new(color);
if (mface->v4)
c3 = KX_rgbaint2uint_new(color);
} break;
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 04:28:02 +00:00
default: // white
{
c0 = KX_rgbaint2uint_new(color);
c1 = KX_rgbaint2uint_new(color);
c2 = KX_rgbaint2uint_new(color);
if (mface->v4)
c3 = KX_rgbaint2uint_new(color);
} break;
}
}
typedef struct MTF_localLayer
{
MTFace *face;
const char *name;
}MTF_localLayer;
// ------------------------------------
bool ConvertMaterial(
BL_Material *material,
Material *mat,
MTFace* tface,
const char *tfaceName,
MFace* mface,
MCol* mmcol,
MTF_localLayer *layers,
bool glslmat)
{
material->Initialize();
int numchan = -1, texalpha = 0;
bool validmat = (mat!=0);
bool validface = (tface!=0);
short type = 0;
if( validmat )
type = 1; // material color
material->IdMode = DEFAULT_BLENDER;
material->glslmat = (validmat)? glslmat: false;
material->materialindex = mface->mat_nr;
// --------------------------------
if(validmat) {
// use vertex colors by explicitly setting
if(mat->mode &MA_VERTEXCOLP || glslmat)
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 04:28:02 +00:00
type = 0;
// use lighting?
material->ras_mode |= ( mat->mode & MA_SHLESS )?0:USE_LIGHT;
MTex *mttmp = 0;
numchan = getNumTexChannels(mat);
int valid_index = 0;
// use the face texture if
// 1) it is set in the buttons
// 2) we have a face texture and a material but no valid texture in slot 1
bool facetex = false;
if(validface && mat->mode &MA_FACETEXTURE)
facetex = true;
if(validface && !mat->mtex[0])
facetex = true;
if(validface && mat->mtex[0]) {
MTex *tmp = mat->mtex[0];
if(!tmp->tex || (tmp->tex && !tmp->tex->ima))
facetex = true;
}
numchan = numchan>MAXTEX?MAXTEX:numchan;
// foreach MTex
for(int i=0; i<numchan; i++) {
// use face tex
if(i==0 && facetex ) {
Image*tmp = (Image*)(tface->tpage);
if(tmp) {
material->img[i] = tmp;
material->texname[i] = material->img[i]->id.name;
material->flag[i] |= ( tface->transp &TF_ALPHA )?USEALPHA:0;
material->flag[i] |= ( tface->transp &TF_ADD )?CALCALPHA:0;
material->flag[i] |= MIPMAP;
if(material->img[i]->flag & IMA_REFLECT)
material->mapping[i].mapping |= USEREFL;
else
{
mttmp = getImageFromMaterial( mat, i );
if(mttmp && mttmp->texco &TEXCO_UV)
{
STR_String uvName = mttmp->uvname;
if (!uvName.IsEmpty())
material->mapping[i].uvCoName = mttmp->uvname;
else
material->mapping[i].uvCoName = "";
}
material->mapping[i].mapping |= USEUV;
}
if(material->ras_mode & USE_LIGHT)
material->ras_mode &= ~USE_LIGHT;
if(tface->mode & TF_LIGHT)
material->ras_mode |= USE_LIGHT;
valid_index++;
}
else {
material->img[i] = 0;
material->texname[i] = "";
}
continue;
}
mttmp = getImageFromMaterial( 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( mttmp->tex->imaflag &TEX_USEALPHA ) {
material->flag[i] |= USEALPHA;
}
// -----------------------
else 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;
}
}
}
material->flag[i] |= (mat->ipo!=0)?HASIPO:0;
/// --------------------------------
// mapping methods
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)
{
STR_String uvName = mttmp->uvname;
if (!uvName.IsEmpty())
material->mapping[i].uvCoName = mttmp->uvname;
else
material->mapping[i].uvCoName = "";
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++;
}
}
}
Merge of apricot branch game engine changes into trunk, excluding GLSL. GLEW ==== Added the GLEW opengl extension library into extern/, always compiled into Blender now. This is much nicer than doing this kind of extension management manually, and will be used in the game engine, for GLSL, and other opengl extensions. * According to the GLEW website it works on Windows, Linux, Mac OS X, FreeBSD, Irix, and Solaris. There might still be platform specific issues due to this commit, so let me know and I'll look into it. * This means also that all extensions will now always be compiled in, regardless of the glext.h on the platform where compilation happens. Game Engine =========== Refactoring of the use of opengl extensions and other drawing code in the game engine, and cleaning up some hacks related to GLSL integration. These changes will be merged into trunk too after this. The game engine graphics demos & apricot level survived my tests, but this could use some good testing of course. For users: please test with the options "Generate Display Lists" and "Vertex Arrays" enabled, these should be the fastest and are supposed to be "unreliable", but if that's the case that's probably due to bugs that can be fixed. * The game engine now also uses GLEW for extensions, replacing the custom opengl extensions code that was there. Removes a lot of #ifdef's, but the runtime checks stay of course. * Removed the WITHOUT_GLEXT environment variable. This was added to work around a specific bug and only disabled multitexturing anyway. It might also have caused a slowdown since it was retrieving the environment variable for every vertex in immediate mode (bug #13680). * Refactored the code to allow drawing skinned meshes with vertex arrays too, removing some specific immediate mode drawing functions for this that only did extra normal calculation. Now it always splits vertices of flat faces instead. * Refactored normal recalculation with some minor optimizations, required for the above change. * Removed some outdated code behind the __NLA_OLDDEFORM #ifdef. * Fixed various bugs in setting of multitexture coordinates and vertex attributes for vertex arrays. These were not being enabled/disabled correct according to the opengl spec, leading to crashes. Also tangent attributes used an immediate mode call for vertex arrays, which can't work. * Fixed use of uninitialized variable in RAS_TexVert. * Exporting skinned meshes was doing O(n^2) lookups for vertices and deform weights, now uses same trick as regular meshes.
2008-06-17 10:27:34 +00:00
// 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 {
int valid = 0;
// check for tface tex to fallback on
if( validface ){
// no light bugfix
if(tface->mode) material->ras_mode |= USE_LIGHT;
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;
material->flag[0] |= ( tface->transp &TF_ALPHA )?USEALPHA:0;
material->flag[0] |= ( tface->transp &TF_ADD )?CALCALPHA:0;
valid++;
}
}
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;
}
MT_Point2 uv[4];
MT_Point2 uv2[4];
const char *uvName = "", *uv2Name = "";
Merge of apricot branch game engine changes into trunk, excluding GLSL. GLEW ==== Added the GLEW opengl extension library into extern/, always compiled into Blender now. This is much nicer than doing this kind of extension management manually, and will be used in the game engine, for GLSL, and other opengl extensions. * According to the GLEW website it works on Windows, Linux, Mac OS X, FreeBSD, Irix, and Solaris. There might still be platform specific issues due to this commit, so let me know and I'll look into it. * This means also that all extensions will now always be compiled in, regardless of the glext.h on the platform where compilation happens. Game Engine =========== Refactoring of the use of opengl extensions and other drawing code in the game engine, and cleaning up some hacks related to GLSL integration. These changes will be merged into trunk too after this. The game engine graphics demos & apricot level survived my tests, but this could use some good testing of course. For users: please test with the options "Generate Display Lists" and "Vertex Arrays" enabled, these should be the fastest and are supposed to be "unreliable", but if that's the case that's probably due to bugs that can be fixed. * The game engine now also uses GLEW for extensions, replacing the custom opengl extensions code that was there. Removes a lot of #ifdef's, but the runtime checks stay of course. * Removed the WITHOUT_GLEXT environment variable. This was added to work around a specific bug and only disabled multitexturing anyway. It might also have caused a slowdown since it was retrieving the environment variable for every vertex in immediate mode (bug #13680). * Refactored the code to allow drawing skinned meshes with vertex arrays too, removing some specific immediate mode drawing functions for this that only did extra normal calculation. Now it always splits vertices of flat faces instead. * Refactored normal recalculation with some minor optimizations, required for the above change. * Removed some outdated code behind the __NLA_OLDDEFORM #ifdef. * Fixed various bugs in setting of multitexture coordinates and vertex attributes for vertex arrays. These were not being enabled/disabled correct according to the opengl spec, leading to crashes. Also tangent attributes used an immediate mode call for vertex arrays, which can't work. * Fixed use of uninitialized variable in RAS_TexVert. * Exporting skinned meshes was doing O(n^2) lookups for vertices and deform weights, now uses same trick as regular meshes.
2008-06-17 10:27:34 +00:00
uv2[0]= uv2[1]= uv2[2]= uv2[3]= MT_Point2(0.0f, 0.0f);
if( validface ) {
material->ras_mode |= (tface->mode & TF_INVISIBLE)?0:POLY_VIS;
material->transp = tface->transp;
material->tile = tface->tile;
material->mode = tface->mode;
uv[0].setValue(tface->uv[0]);
uv[1].setValue(tface->uv[1]);
uv[2].setValue(tface->uv[2]);
if (mface->v4)
uv[3].setValue(tface->uv[3]);
uvName = tfaceName;
}
else {
// nothing at all
material->ras_mode |= (POLY_VIS| (validmat?0:USE_LIGHT));
material->mode = default_face_mode;
material->transp = TF_SOLID;
material->tile = 0;
uv[0]= uv[1]= uv[2]= uv[3]= MT_Point2(0.0f, 0.0f);
}
// with ztransp enabled, enforce alpha blending mode
if(validmat && (mat->mode & MA_TRANSP) && (mat->mode & MA_ZTRANSP) && (material->transp == TF_SOLID))
material->transp = TF_ALPHA;
// always zsort alpha + add
if((material->transp == TF_ALPHA || material->transp == TF_ADD || texalpha) && (material->transp != TF_CLIP)) {
material->ras_mode |= ALPHA;
material->ras_mode |= (material->mode & TF_ALPHASORT)? ZSORT: 0;
}
// collider or not?
material->ras_mode |= (material->mode & TF_DYNAMIC)? COLLIDER: 0;
// these flags are irrelevant at this point, remove so they
// don't hurt material bucketing
material->mode &= ~(TF_DYNAMIC|TF_ALPHASORT|TF_TEX);
// get uv sets
if(validmat)
{
bool isFirstSet = true;
// only two sets implemented, but any of the eight
// sets can make up the two layers
for (int vind = 0; vind<material->num_enabled; vind++)
{
BL_Mapping &map = material->mapping[vind];
if (map.uvCoName.IsEmpty())
isFirstSet = false;
else
{
for (int lay=0; lay<MAX_MTFACE; lay++)
{
MTF_localLayer& layer = layers[lay];
if (layer.face == 0) break;
if (strcmp(map.uvCoName.ReadPtr(), layer.name)==0)
{
MT_Point2 uvSet[4];
uvSet[0].setValue(layer.face->uv[0]);
uvSet[1].setValue(layer.face->uv[1]);
uvSet[2].setValue(layer.face->uv[2]);
if (mface->v4)
uvSet[3].setValue(layer.face->uv[3]);
else
uvSet[3].setValue(0.0f, 0.0f);
if (isFirstSet)
{
uv[0] = uvSet[0]; uv[1] = uvSet[1];
uv[2] = uvSet[2]; uv[3] = uvSet[3];
isFirstSet = false;
uvName = layer.name;
}
else if(strcmp(layer.name, uvName) != 0)
{
uv2[0] = uvSet[0]; uv2[1] = uvSet[1];
uv2[2] = uvSet[2]; uv2[3] = uvSet[3];
map.mapping |= USECUSTOMUV;
uv2Name = layer.name;
}
}
}
}
}
}
unsigned int rgb[4];
Added custom vertex/edge/face data for meshes: All data layers, including MVert/MEdge/MFace, are now managed as custom data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are still used of course, but allocating, copying or freeing these arrays should be done through the CustomData API. Work in progress documentation on this is here: http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData Replaced TFace by MTFace: This is the same struct, except that it does not contain color, that now always stays separated in MCol. This was not a good design decision to begin with, and it is needed for adding multiple color layers later. Note that this does mean older Blender versions will not be able to read UV coordinates from the next release, due to an SDNA limitation. Removed DispListMesh: This now fully replaced by DerivedMesh. To provide access to arrays of vertices, edges and faces, like DispListMesh does. The semantics of the DerivedMesh.getVertArray() and similar functions were changed to return a pointer to an array if one exists, or otherwise allocate a temporary one. On releasing the DerivedMesh, this temporary array will be removed automatically. Removed ssDM and meshDM DerivedMesh backends: The ssDM backend was for DispListMesh, so that became obsolete automatically. The meshDM backend was replaced by the custom data backend, that now figures out which layers need to be modified, and only duplicates those. This changes code in many places, and overall removes 2514 lines of code. So, there's a good chance this might break some stuff, although I've been testing it for a few days now. The good news is, adding multiple color and uv layers should now become easy.
2006-11-20 04:28:02 +00:00
GetRGB(type,mface,mmcol,mat,rgb[0],rgb[1],rgb[2], rgb[3]);
// swap the material color, so MCol on TF_BMFONT works
if (validmat && type==1 && (tface && tface->mode & TF_BMFONT))
{
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]);
}
material->SetConversionRGB(rgb);
material->SetConversionUV(uvName, uv);
material->SetConversionUV2(uv2Name, uv2);
if(validmat)
material->matname =(mat->id.name);
material->tface = tface;
material->material = mat;
return true;
}
/* blenderobj can be NULL, make sure its checked for */
RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene, KX_BlenderSceneConverter *converter)
2002-10-12 11:37:38 +00:00
{
RAS_MeshObject *meshobj;
int lightlayer = blenderobj ? blenderobj->lay:(1<<20)-1; // all layers if no object.
if ((meshobj = converter->FindGameMesh(mesh/*, ob->lay*/)) != NULL)
return meshobj;
// Get DerivedMesh data
DerivedMesh *dm = CDDM_from_mesh(mesh, blenderobj);
MVert *mvert = dm->getVertArray(dm);
int totvert = dm->getNumVerts(dm);
MFace *mface = dm->getFaceArray(dm);
MTFace *tface = static_cast<MTFace*>(dm->getFaceDataArray(dm, CD_MTFACE));
MCol *mcol = static_cast<MCol*>(dm->getFaceDataArray(dm, CD_MCOL));
float (*tangent)[3] = NULL;
int totface = dm->getNumFaces(dm);
const char *tfaceName = "";
if(tface) {
DM_add_tangent_layer(dm);
tangent = (float(*)[3])dm->getFaceDataArray(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)
{
assert(validLayers <= 8);
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);
RAS_IPolyMaterial* polymat = NULL;
STR_String imastr;
// These pointers will hold persistent material structure during the conversion
// to avoid countless allocation/deallocation of memory.
BL_Material* bl_mat = NULL;
KX_BlenderMaterial* kx_blmat = NULL;
KX_PolygonMaterial* kx_polymat = NULL;
for (int f=0;f<totface;f++,mface++)
2002-10-12 11:37:38 +00:00
{
Material* ma = 0;
2002-10-12 11:37:38 +00:00
bool collider = true;
MT_Point2 uv0(0.0,0.0),uv1(0.0,0.0),uv2(0.0,0.0),uv3(0.0,0.0);
MT_Point2 uv20(0.0,0.0),uv21(0.0,0.0),uv22(0.0,0.0),uv23(0.0,0.0);
unsigned int rgb0,rgb1,rgb2,rgb3 = 0;
MT_Point3 pt0, pt1, pt2, pt3;
MT_Vector3 no0(0,0,0), no1(0,0,0), no2(0,0,0), no3(0,0,0);
MT_Vector4 tan0(0,0,0,0), tan1(0,0,0,0), tan2(0,0,0,0), tan3(0,0,0,0);
/* get coordinates, normals and tangents */
pt0.setValue(mvert[mface->v1].co);
pt1.setValue(mvert[mface->v2].co);
pt2.setValue(mvert[mface->v3].co);
if (mface->v4) pt3.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);
no0 = n0;
no1 = n1;
no2 = n2;
if(mface->v4) {
normal_short_to_float_v3(n3, mvert[mface->v4].no);
no3 = n3;
2002-10-12 11:37:38 +00:00
}
}
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);
no0 = no1 = no2 = no3 = MT_Vector3(fno);
}
if(tangent) {
tan0 = tangent[f*4 + 0];
tan1 = tangent[f*4 + 1];
tan2 = tangent[f*4 + 2];
if (mface->v4)
tan3 = 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;
{
bool visible = true;
bool twoside = false;
if(converter->GetMaterials()) {
/* do Blender Multitexture and Blender GLSL materials */
unsigned int rgb[4];
MT_Point2 uv[4];
/* first is the BL_Material */
if (!bl_mat)
bl_mat = new BL_Material();
ConvertMaterial(bl_mat, ma, tface, tfaceName, mface, mcol,
layers, converter->GetGLSLMaterials());
visible = ((bl_mat->ras_mode & POLY_VIS)!=0);
collider = ((bl_mat->ras_mode & COLLIDER)!=0);
twoside = ((bl_mat->mode & TF_TWOSIDE)!=0);
/* vertex colors and uv's were stored in bl_mat temporarily */
bl_mat->GetConversionRGB(rgb);
rgb0 = rgb[0]; rgb1 = rgb[1];
rgb2 = rgb[2]; rgb3 = rgb[3];
bl_mat->GetConversionUV(uv);
uv0 = uv[0]; uv1 = uv[1];
uv2 = uv[2]; uv3 = uv[3];
bl_mat->GetConversionUV2(uv);
uv20 = uv[0]; uv21 = uv[1];
uv22 = uv[2]; uv23 = uv[3];
/* then the KX_BlenderMaterial */
if (kx_blmat == NULL)
kx_blmat = new KX_BlenderMaterial();
kx_blmat->Initialize(scene, bl_mat);
polymat = static_cast<RAS_IPolyMaterial*>(kx_blmat);
2002-10-12 11:37:38 +00:00
}
else {
/* do Texture Face materials */
Image* bima = (tface)? (Image*)tface->tpage: NULL;
imastr = (tface)? (bima? (bima)->id.name : "" ) : "";
2002-10-12 11:37:38 +00:00
char transp=0;
short mode=0, tile=0;
int tilexrep=4,tileyrep = 4;
if (bima) {
tilexrep = bima->xrep;
tileyrep = bima->yrep;
}
/* get tface properties if available */
if(tface) {
/* TF_DYNAMIC means the polygon is a collision face */
collider = ((tface->mode & TF_DYNAMIC) != 0);
transp = tface->transp;
tile = tface->tile;
mode = tface->mode;
2002-10-12 11:37:38 +00:00
visible = !(tface->mode & TF_INVISIBLE);
twoside = ((tface->mode & TF_TWOSIDE)!=0);
2002-10-12 11:37:38 +00:00
uv0.setValue(tface->uv[0]);
uv1.setValue(tface->uv[1]);
uv2.setValue(tface->uv[2]);
if (mface->v4)
uv3.setValue(tface->uv[3]);
}
else {
/* no texfaces, set COLLSION true and everything else FALSE */
mode = default_face_mode;
transp = TF_SOLID;
tile = 0;
}
/* get vertex colors */
if (mcol) {
/* we have vertex colors */
rgb0 = KX_Mcol2uint_new(mcol[0]);
rgb1 = KX_Mcol2uint_new(mcol[1]);
rgb2 = KX_Mcol2uint_new(mcol[2]);
if (mface->v4)
rgb3 = KX_Mcol2uint_new(mcol[3]);
}
else {
/* no vertex colors, take from material, otherwise white */
unsigned int color = 0xFFFFFFFFL;
if (ma)
2002-10-12 11:37:38 +00:00
{
union
{
unsigned char cp[4];
unsigned int integer;
} col_converter;
2002-10-12 11:37:38 +00:00
col_converter.cp[3] = (unsigned char) (ma->r*255.0);
col_converter.cp[2] = (unsigned char) (ma->g*255.0);
col_converter.cp[1] = (unsigned char) (ma->b*255.0);
col_converter.cp[0] = (unsigned char) (ma->alpha*255.0);
color = col_converter.integer;
}
rgb0 = KX_rgbaint2uint_new(color);
rgb1 = KX_rgbaint2uint_new(color);
rgb2 = KX_rgbaint2uint_new(color);
2002-10-12 11:37:38 +00:00
if (mface->v4)
rgb3 = KX_rgbaint2uint_new(color);
}
// only zsort alpha + add
bool alpha = (transp == TF_ALPHA || transp == TF_ADD);
bool zsort = (mode & TF_ALPHASORT)? alpha: 0;
if (kx_polymat == NULL)
kx_polymat = new KX_PolygonMaterial();
kx_polymat->Initialize(imastr, ma, (int)mface->mat_nr,
tile, tilexrep, tileyrep,
mode, transp, alpha, zsort, lightlayer, tface, (unsigned int*)mcol);
polymat = static_cast<RAS_IPolyMaterial*>(kx_polymat);
if (ma) {
polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec;
polymat->m_shininess = (float)ma->har/4.0; // 0 < ma->har <= 512
polymat->m_diffuse = MT_Vector3(ma->r, ma->g, ma->b)*(ma->emit + ma->ref);
2002-10-12 11:37:38 +00:00
}
else {
polymat->m_specular.setValue(0.0f,0.0f,0.0f);
polymat->m_shininess = 35.0;
2002-10-12 11:37:38 +00:00
}
}
2002-10-12 11:37:38 +00:00
/* mark face as flat, so vertices are split */
bool flat = (mface->flag & ME_SMOOTH) == 0;
// 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);
if (bucketCreated) {
// this is needed to free up memory afterwards
converter->RegisterPolyMaterial(polymat);
if(converter->GetMaterials()) {
converter->RegisterBlenderMaterial(bl_mat);
// the poly material has been stored in the bucket, next time we must create a new one
bl_mat = NULL;
kx_blmat = NULL;
} else {
// the poly material has been stored in the bucket, next time we must create a new one
kx_polymat = NULL;
2002-10-12 11:37:38 +00:00
}
} else {
// from now on, use the polygon material from the material bucket
polymat = bucket->GetPolyMaterial();
// keep the material pointers, they will be reused for next face
2002-10-12 11:37:38 +00:00
}
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,pt0,uv0,uv20,tan0,rgb0,no0,flat,mface->v1);
meshobj->AddVertex(poly,1,pt1,uv1,uv21,tan1,rgb1,no1,flat,mface->v2);
meshobj->AddVertex(poly,2,pt2,uv2,uv22,tan2,rgb2,no2,flat,mface->v3);
if (nverts==4)
meshobj->AddVertex(poly,3,pt3,uv3,uv23,tan3,rgb3,no3,flat,mface->v4);
2002-10-12 11:37:38 +00:00
}
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++;
}
2002-10-12 11:37:38 +00:00
}
// 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
for(list<RAS_MeshMaterial>::iterator mit = meshobj->GetFirstMaterial();
mit != meshobj->GetLastMaterial(); ++ mit) {
mit->m_bucket->GetPolyMaterial()->OnConstruction(lightlayer);
}
if (layers)
delete []layers;
dm->release(dm);
// cleanup material
if (bl_mat)
delete bl_mat;
if (kx_blmat)
delete kx_blmat;
if (kx_polymat)
delete kx_polymat;
converter->RegisterGameMesh(meshobj, mesh);
2002-10-12 11:37:38 +00:00
return meshobj;
}
static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blenderobject)
2002-10-12 11:37:38 +00:00
{
PHY_MaterialProps *materialProps = new PHY_MaterialProps;
MT_assert(materialProps && "Create physics material properties failed");
2002-10-12 11:37:38 +00:00
Material* blendermat = give_current_material(blenderobject, 0);
if (blendermat)
{
MT_assert(0.0f <= blendermat->reflect && blendermat->reflect <= 1.0f);
2002-10-12 11:37:38 +00:00
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;
2002-10-12 11:37:38 +00:00
}
return materialProps;
}
static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blenderobject)
2002-10-12 11:37:38 +00:00
{
PHY_ShapeProps *shapeProps = new PHY_ShapeProps;
MT_assert(shapeProps);
2002-10-12 11:37:38 +00:00
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;
2002-10-12 11:37:38 +00:00
MT_assert(0.0f <= blenderobject->damping && blenderobject->damping <= 1.0f);
MT_assert(0.0f <= blenderobject->rdamping && blenderobject->rdamping <= 1.0f);
2002-10-12 11:37:38 +00:00
shapeProps->m_lin_drag = 1.0 - blenderobject->damping;
shapeProps->m_ang_drag = 1.0 - 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;
2002-10-12 11:37:38 +00:00
return shapeProps;
}
//////////////////////////////////////////////////////////
static float my_boundbox_mesh(Mesh *me, float *loc, float *size)
{
2002-10-12 11:37:38 +00:00
MVert *mvert;
BoundBox *bb;
MT_Point3 min, max;
2002-10-12 11:37:38 +00:00
float mloc[3], msize[3];
float radius=0.0f, vert_radius, *co;
2002-10-12 11:37:38 +00:00
int a;
if(me->bb==0) me->bb= (struct BoundBox *)MEM_callocN(sizeof(BoundBox), "boundbox");
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 */
DO_MINMAX(co, min, max);
/* radius */
vert_radius= co[0]*co[0] + co[1]*co[1] + co[2]*co[2];
if (vert_radius > radius)
radius= vert_radius;
}
2002-10-12 11:37:38 +00:00
if(me->totvert) {
loc[0]= (min[0]+max[0])/2.0;
loc[1]= (min[1]+max[1])/2.0;
loc[2]= (min[2]+max[2])/2.0;
size[0]= (max[0]-min[0])/2.0;
size[1]= (max[1]-min[1])/2.0;
size[2]= (max[2]-min[2])/2.0;
}
else {
loc[0]= loc[1]= loc[2]= 0.0;
size[0]= size[1]= size[2]= 0.0;
}
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 sqrt(radius);
}
2002-10-12 11:37:38 +00:00
static void my_tex_space_mesh(Mesh *me)
2002-10-12 11:37:38 +00:00
{
KeyBlock *kb;
float *fp, loc[3], size[3], min[3], max[3];
int a;
my_boundbox_mesh(me, loc, size);
if(me->texflag & AUTOSPACE) {
2002-10-12 11:37:38 +00:00
if(me->key) {
kb= me->key->refkey;
if (kb) {
INIT_MINMAX(min, max);
fp= (float *)kb->data;
for(a=0; a<kb->totelem; a++, fp+=3) {
DO_MINMAX(fp, min, max);
}
if(kb->totelem) {
loc[0]= (min[0]+max[0])/2.0; loc[1]= (min[1]+max[1])/2.0; loc[2]= (min[2]+max[2])/2.0;
size[0]= (max[0]-min[0])/2.0; size[1]= (max[1]-min[1])/2.0; size[2]= (max[2]-min[2])/2.0;
}
else {
loc[0]= loc[1]= loc[2]= 0.0;
size[0]= size[1]= size[2]= 0.0;
}
}
}
VECCOPY(me->loc, loc);
VECCOPY(me->size, size);
me->rot[0]= me->rot[1]= me->rot[2]= 0.0;
if(me->size[0]==0.0) me->size[0]= 1.0;
else if(me->size[0]>0.0 && me->size[0]<0.00001) me->size[0]= 0.00001;
else if(me->size[0]<0.0 && me->size[0]> -0.00001) me->size[0]= -0.00001;
if(me->size[1]==0.0) me->size[1]= 1.0;
else if(me->size[1]>0.0 && me->size[1]<0.00001) me->size[1]= 0.00001;
else if(me->size[1]<0.0 && me->size[1]> -0.00001) me->size[1]= -0.00001;
if(me->size[2]==0.0) me->size[2]= 1.0;
else if(me->size[2]>0.0 && me->size[2]<0.00001) me->size[2]= 0.00001;
else if(me->size[2]<0.0 && me->size[2]> -0.00001) me->size[2]= -0.00001;
}
}
static void my_get_local_bounds(Object *ob, DerivedMesh *dm, float *center, float *size)
{
2002-10-12 11:37:38 +00:00
BoundBox *bb= NULL;
/* uses boundbox, function used by Ketsji */
switch (ob->type)
{
case OB_MESH:
if (dm)
{
float min_r[3], max_r[3];
INIT_MINMAX(min_r, max_r);
dm->getMinMax(dm, min_r, max_r);
size[0]= 0.5*fabs(max_r[0] - min_r[0]);
size[1]= 0.5*fabs(max_r[1] - min_r[1]);
size[2]= 0.5*fabs(max_r[2] - min_r[2]);
center[0]= 0.5*(max_r[0] + min_r[0]);
center[1]= 0.5*(max_r[1] + min_r[1]);
center[2]= 0.5*(max_r[2] + min_r[2]);
return;
} else
{
bb= ( (Mesh *)ob->data )->bb;
if(bb==0)
{
my_tex_space_mesh((struct Mesh *)ob->data);
bb= ( (Mesh *)ob->data )->bb;
}
}
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
center[0]= center[1]= center[2]= 0.0;
size[0] = size[1]=size[2]=0.0;
break;
case OB_MBALL:
bb= ob->bb;
break;
2002-10-12 11:37:38 +00:00
}
if(bb==NULL)
{
center[0]= center[1]= center[2]= 0.0;
size[0] = size[1]=size[2]=1.0;
2002-10-12 11:37:38 +00:00
}
else
{
2002-10-12 11:37:38 +00:00
size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]);
size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]);
size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]);
center[0]= 0.5*(bb->vec[0][0] + bb->vec[4][0]);
center[1]= 0.5*(bb->vec[0][1] + bb->vec[2][1]);
center[2]= 0.5*(bb->vec[0][2] + bb->vec[1][2]);
}
2002-10-12 11:37:38 +00:00
}
//////////////////////////////////////////////////////
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 USE_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;
}
}
}
2002-10-12 11:37:38 +00:00
void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
struct Object* blenderobject,
RAS_MeshObject* meshobj,
KX_Scene* kxscene,
int activeLayerBitInfo,
e_PhysicsEngine physics_engine,
KX_BlenderSceneConverter *converter,
bool processCompoundChildren
2002-10-12 11:37:38 +00:00
)
{
//SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
2002-10-12 11:37:38 +00:00
//int userigidbody = SYS_GetCommandLineInt(syshandle,"norigidbody",0);
//bool bRigidBody = (userigidbody == 0);
BGE patch: new Physics button and margin parameter in Logic panel. Change subversion. The Physics button controls the creation of a physics representation of the object when starting the game. If the button is not selected, the object is a pure graphical object with no physics representation and all the other physics buttons are hidden. Selecting this button gives access to the usual physics buttons. The physics button is enabled by default to match previous Blender behavior. The margin parameter allows to control the collision margin from the UI. Previously, this parameter was only accessible through Python. By default, the collision margin is set to 0.0 on static objects and 0.06 on dynamic objects. To maintain compatibility with older games, the collision margin is set to 0.06 on all objects when loading older blend file. Note about the collision algorithms in Bullet 2.71 -------------------------------------------------- Bullet 2.71 handles the collision margin differently than Bullet 2.53 (the previous Bullet version in Blender). The collision margin is now kept "inside" the object for box, sphere and cylinder bound shapes. This means that two objects bound to any of these shape will come in close contact when colliding. The static mesh, convex hull and cone shapes still have their collision margin "outside" the object, which leaves a space of 1 or 2 times the collision margin between objects. The situation with Bullet 2.53 was more complicated, generally leading to more space between objects, except for box-box collisions. This means that running a old game under Bullet 2.71 may cause visual problems, especially if the objects are small. You can fix these problems by changing some visual aspect of the objects: center, shape, size, position of children, etc.
2008-09-14 19:34:06 +00:00
// object has physics representation?
if (!(blenderobject->gameflag & OB_COLLISION))
BGE patch: new Physics button and margin parameter in Logic panel. Change subversion. The Physics button controls the creation of a physics representation of the object when starting the game. If the button is not selected, the object is a pure graphical object with no physics representation and all the other physics buttons are hidden. Selecting this button gives access to the usual physics buttons. The physics button is enabled by default to match previous Blender behavior. The margin parameter allows to control the collision margin from the UI. Previously, this parameter was only accessible through Python. By default, the collision margin is set to 0.0 on static objects and 0.06 on dynamic objects. To maintain compatibility with older games, the collision margin is set to 0.06 on all objects when loading older blend file. Note about the collision algorithms in Bullet 2.71 -------------------------------------------------- Bullet 2.71 handles the collision margin differently than Bullet 2.53 (the previous Bullet version in Blender). The collision margin is now kept "inside" the object for box, sphere and cylinder bound shapes. This means that two objects bound to any of these shape will come in close contact when colliding. The static mesh, convex hull and cone shapes still have their collision margin "outside" the object, which leaves a space of 1 or 2 times the collision margin between objects. The situation with Bullet 2.53 was more complicated, generally leading to more space between objects, except for box-box collisions. This means that running a old game under Bullet 2.71 may cause visual problems, especially if the objects are small. You can fix these problems by changing some visual aspect of the objects: center, shape, size, position of children, etc.
2008-09-14 19:34:06 +00:00
return;
// 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;
2002-10-12 11:37:38 +00:00
PHY_ShapeProps* shapeprops =
CreateShapePropsFromBlenderObject(blenderobject);
2002-10-12 11:37:38 +00:00
PHY_MaterialProps* smmaterial =
CreateMaterialFromBlenderObject(blenderobject);
2002-10-12 11:37:38 +00:00
KX_ObjectProperties objprop;
objprop.m_lockXaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_AXIS) !=0;
objprop.m_lockYaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_AXIS) !=0;
objprop.m_lockZaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_AXIS) !=0;
objprop.m_lockXRotaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_ROT_AXIS) !=0;
objprop.m_lockYRotaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_ROT_AXIS) !=0;
objprop.m_lockZRotaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_ROT_AXIS) !=0;
objprop.m_isCompoundChild = isCompoundChild;
objprop.m_hasCompoundChildren = hasCompoundChildren;
BGE patch: new Physics button and margin parameter in Logic panel. Change subversion. The Physics button controls the creation of a physics representation of the object when starting the game. If the button is not selected, the object is a pure graphical object with no physics representation and all the other physics buttons are hidden. Selecting this button gives access to the usual physics buttons. The physics button is enabled by default to match previous Blender behavior. The margin parameter allows to control the collision margin from the UI. Previously, this parameter was only accessible through Python. By default, the collision margin is set to 0.0 on static objects and 0.06 on dynamic objects. To maintain compatibility with older games, the collision margin is set to 0.06 on all objects when loading older blend file. Note about the collision algorithms in Bullet 2.71 -------------------------------------------------- Bullet 2.71 handles the collision margin differently than Bullet 2.53 (the previous Bullet version in Blender). The collision margin is now kept "inside" the object for box, sphere and cylinder bound shapes. This means that two objects bound to any of these shape will come in close contact when colliding. The static mesh, convex hull and cone shapes still have their collision margin "outside" the object, which leaves a space of 1 or 2 times the collision margin between objects. The situation with Bullet 2.53 was more complicated, generally leading to more space between objects, except for box-box collisions. This means that running a old game under Bullet 2.71 may cause visual problems, especially if the objects are small. You can fix these problems by changing some visual aspect of the objects: center, shape, size, position of children, etc.
2008-09-14 19:34:06 +00:00
objprop.m_margin = blenderobject->margin;
// ACTOR is now a separate feature
objprop.m_isactor = (blenderobject->gameflag & OB_ACTOR)!=0;
objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0;
objprop.m_softbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0;
objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0;
///contact processing threshold is only for rigid bodies and static geometry, not 'dynamic'
if (objprop.m_angular_rigidbody || !objprop.m_dyna )
{
objprop.m_contactProcessingThreshold = blenderobject->m_contactProcessingThreshold;
} else
{
objprop.m_contactProcessingThreshold = 0.f;
}
objprop.m_sensor = (blenderobject->gameflag & OB_SENSOR) != 0;
if (objprop.m_softbody)
{
///for game soft bodies
if (blenderobject->bsoft)
{
objprop.m_gamesoftFlag = blenderobject->bsoft->flag;
///////////////////
objprop.m_soft_linStiff = blenderobject->bsoft->linStiff;
objprop.m_soft_angStiff = blenderobject->bsoft->angStiff; /* angular stiffness 0..1 */
objprop.m_soft_volume= blenderobject->bsoft->volume; /* volume preservation 0..1 */
objprop.m_soft_viterations= blenderobject->bsoft->viterations; /* Velocities solver iterations */
objprop.m_soft_piterations= blenderobject->bsoft->piterations; /* Positions solver iterations */
objprop.m_soft_diterations= blenderobject->bsoft->diterations; /* Drift solver iterations */
objprop.m_soft_citerations= blenderobject->bsoft->citerations; /* Cluster solver iterations */
objprop.m_soft_kSRHR_CL= blenderobject->bsoft->kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */
objprop.m_soft_kSKHR_CL= blenderobject->bsoft->kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */
objprop.m_soft_kSSHR_CL= blenderobject->bsoft->kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */
objprop.m_soft_kSR_SPLT_CL= blenderobject->bsoft->kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
objprop.m_soft_kSK_SPLT_CL= blenderobject->bsoft->kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
objprop.m_soft_kSS_SPLT_CL= blenderobject->bsoft->kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
objprop.m_soft_kVCF= blenderobject->bsoft->kVCF; /* Velocities correction factor (Baumgarte) */
objprop.m_soft_kDP= blenderobject->bsoft->kDP; /* Damping coefficient [0,1] */
objprop.m_soft_kDG= blenderobject->bsoft->kDG; /* Drag coefficient [0,+inf] */
objprop.m_soft_kLF= blenderobject->bsoft->kLF; /* Lift coefficient [0,+inf] */
objprop.m_soft_kPR= blenderobject->bsoft->kPR; /* Pressure coefficient [-inf,+inf] */
objprop.m_soft_kVC= blenderobject->bsoft->kVC; /* Volume conversation coefficient [0,+inf] */
objprop.m_soft_kDF= blenderobject->bsoft->kDF; /* Dynamic friction coefficient [0,1] */
objprop.m_soft_kMT= blenderobject->bsoft->kMT; /* Pose matching coefficient [0,1] */
objprop.m_soft_kCHR= blenderobject->bsoft->kCHR; /* Rigid contacts hardness [0,1] */
objprop.m_soft_kKHR= blenderobject->bsoft->kKHR; /* Kinetic contacts hardness [0,1] */
objprop.m_soft_kSHR= blenderobject->bsoft->kSHR; /* Soft contacts hardness [0,1] */
objprop.m_soft_kAHR= blenderobject->bsoft->kAHR; /* Anchors hardness [0,1] */
objprop.m_soft_collisionflags= blenderobject->bsoft->collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */
objprop.m_soft_numclusteriterations= blenderobject->bsoft->numclusteriterations; /* number of iterations to refine collision clusters*/
//objprop.m_soft_welding = blenderobject->bsoft->welding; /* welding */
/* disable welding: it doesn't bring any additional stability and it breaks the relation between soft body collision shape and graphic mesh */
objprop.m_soft_welding = 0.f;
objprop.m_margin = blenderobject->bsoft->margin;
objprop.m_contactProcessingThreshold = 0.f;
} else
{
objprop.m_gamesoftFlag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
objprop.m_soft_linStiff = 0.5;;
objprop.m_soft_angStiff = 1.f; /* angular stiffness 0..1 */
objprop.m_soft_volume= 1.f; /* volume preservation 0..1 */
objprop.m_soft_viterations= 0;
objprop.m_soft_piterations= 1;
objprop.m_soft_diterations= 0;
objprop.m_soft_citerations= 4;
objprop.m_soft_kSRHR_CL= 0.1f;
objprop.m_soft_kSKHR_CL= 1.f;
objprop.m_soft_kSSHR_CL= 0.5;
objprop.m_soft_kSR_SPLT_CL= 0.5f;
objprop.m_soft_kSK_SPLT_CL= 0.5f;
objprop.m_soft_kSS_SPLT_CL= 0.5f;
objprop.m_soft_kVCF= 1;
objprop.m_soft_kDP= 0;
objprop.m_soft_kDG= 0;
objprop.m_soft_kLF= 0;
objprop.m_soft_kPR= 0;
objprop.m_soft_kVC= 0;
objprop.m_soft_kDF= 0.2f;
objprop.m_soft_kMT= 0.05f;
objprop.m_soft_kCHR= 1.0f;
objprop.m_soft_kKHR= 0.1f;
objprop.m_soft_kSHR= 1.f;
objprop.m_soft_kAHR= 0.7f;
objprop.m_soft_collisionflags= OB_BSB_COL_SDF_RS + OB_BSB_COL_VF_SS;
objprop.m_soft_numclusteriterations= 16;
objprop.m_soft_welding = 0.f;
objprop.m_margin = 0.f;
objprop.m_contactProcessingThreshold = 0.f;
}
}
objprop.m_ghost = (blenderobject->gameflag & OB_GHOST) != 0;
objprop.m_disableSleeping = (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0;//abuse the OB_COLLISION_RESPONSE flag
2002-10-12 11:37:38 +00:00
//mmm, for now, taks this for the size of the dynamicobject
// Blender uses inertia for radius of dynamic object
objprop.m_radius = blenderobject->inertia;
objprop.m_in_active_layer = (blenderobject->lay & activeLayerBitInfo) != 0;
objprop.m_dynamic_parent=NULL;
objprop.m_isdeformable = ((blenderobject->gameflag2 & 2)) != 0;
objprop.m_boundclass = objprop.m_dyna?KX_BOUNDSPHERE:KX_BOUNDMESH;
if ((blenderobject->gameflag & OB_SOFT_BODY) && !(blenderobject->gameflag & OB_BOUNDS))
{
objprop.m_boundclass = KX_BOUNDMESH;
}
KX_BoxBounds bb;
DerivedMesh* dm = NULL;
if (gameobj->GetDeformer())
dm = gameobj->GetDeformer()->GetFinalMesh();
my_get_local_bounds(blenderobject,dm,objprop.m_boundobject.box.m_center,bb.m_extends);
if (blenderobject->gameflag & OB_BOUNDS)
2002-10-12 11:37:38 +00:00
{
switch (blenderobject->boundtype)
{
case OB_BOUND_BOX:
objprop.m_boundclass = KX_BOUNDBOX;
//mmm, has to be divided by 2 to be proper extends
objprop.m_boundobject.box.m_extends[0]=2.f*bb.m_extends[0];
objprop.m_boundobject.box.m_extends[1]=2.f*bb.m_extends[1];
objprop.m_boundobject.box.m_extends[2]=2.f*bb.m_extends[2];
break;
case OB_BOUND_POLYT:
if (blenderobject->type == OB_MESH)
{
objprop.m_boundclass = KX_BOUNDPOLYTOPE;
break;
}
// Object is not a mesh... fall through OB_BOUND_POLYH to
// OB_BOUND_SPHERE
case OB_BOUND_POLYH:
if (blenderobject->type == OB_MESH)
{
objprop.m_boundclass = KX_BOUNDMESH;
break;
}
2010-07-09 23:14:07 +00:00
// Object is not a mesh... can't use polyhedron.
// Fall through and become a sphere.
case OB_BOUND_SPHERE:
{
objprop.m_boundclass = KX_BOUNDSPHERE;
objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], MT_max(bb.m_extends[1], bb.m_extends[2]));
break;
}
case OB_BOUND_CYLINDER:
{
objprop.m_boundclass = KX_BOUNDCYLINDER;
objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], bb.m_extends[1]);
objprop.m_boundobject.c.m_height = 2.f*bb.m_extends[2];
break;
}
case OB_BOUND_CONE:
{
objprop.m_boundclass = KX_BOUNDCONE;
objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], bb.m_extends[1]);
objprop.m_boundobject.c.m_height = 2.f*bb.m_extends[2];
break;
}
case OB_BOUND_CAPSULE:
{
objprop.m_boundclass = KX_BOUNDCAPSULE;
objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], bb.m_extends[1]);
objprop.m_boundobject.c.m_height = 2.f*(bb.m_extends[2]-objprop.m_boundobject.c.m_radius);
if (objprop.m_boundobject.c.m_height < 0.f)
objprop.m_boundobject.c.m_height = 0.f;
break;
}
}
2002-10-12 11:37:38 +00:00
}
if (parent/* && (parent->gameflag & OB_DYNAMIC)*/) {
// parented object cannot be dynamic
2002-10-12 11:37:38 +00:00
KX_GameObject *parentgameobject = converter->FindGameObject(parent);
objprop.m_dynamic_parent = parentgameobject;
//cannot be dynamic:
objprop.m_dyna = false;
objprop.m_softbody = false;
shapeprops->m_mass = 0.f;
2002-10-12 11:37:38 +00:00
}
2002-10-12 11:37:38 +00:00
objprop.m_concave = (blenderobject->boundtype & 4) != 0;
switch (physics_engine)
{
2005-07-16 21:47:54 +00:00
#ifdef USE_BULLET
case UseBullet:
KX_ConvertBulletObject(gameobj, meshobj, dm, kxscene, shapeprops, smmaterial, &objprop);
2005-07-16 21:47:54 +00:00
break;
#endif
case UseDynamo:
//KX_ConvertDynamoObject(gameobj,meshobj,kxscene,shapeprops, smmaterial, &objprop);
break;
case UseNone:
default:
break;
2002-10-12 11:37:38 +00:00
}
delete shapeprops;
delete smmaterial;
2002-10-12 11:37:38 +00:00
}
static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int layerflag, KX_Scene *kxscene, RAS_IRenderTools *rendertools, KX_BlenderSceneConverter *converter) {
2002-10-12 11:37:38 +00:00
RAS_LightObject lightobj;
KX_LightObject *gamelight;
lightobj.m_att1 = la->att1;
lightobj.m_att2 = (la->mode & LA_QUAD)?la->att2:0.0;
2002-10-12 11:37:38 +00:00
lightobj.m_red = la->r;
lightobj.m_green = la->g;
lightobj.m_blue = 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_red = -lightobj.m_red;
lightobj.m_green = -lightobj.m_green;
lightobj.m_blue = -lightobj.m_blue;
}
}
2002-10-12 11:37:38 +00:00
if (la->type==LA_SUN) {
lightobj.m_type = RAS_LightObject::LIGHT_SUN;
} else if (la->type==LA_SPOT) {
lightobj.m_type = RAS_LightObject::LIGHT_SPOT;
} else {
lightobj.m_type = RAS_LightObject::LIGHT_NORMAL;
}
gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools,
lightobj, glslmat);
2002-10-12 11:37:38 +00:00
BL_ConvertLampIpos(la, gamelight, converter);
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->clipsta, ca->clipend, ca->type == CAM_PERSP, ca->YF_dofdist);
2002-10-12 11:37:38 +00:00
KX_Camera *gamecamera;
gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata);
gamecamera->SetName(ca->id.name + 2);
BL_ConvertCameraIpos(ca, gamecamera, converter);
return gamecamera;
}
static KX_GameObject *gameobject_from_blenderobject(
Object *ob,
KX_Scene *kxscene,
RAS_IRenderTools *rendertools,
2009-07-30 21:42:29 +00:00
KX_BlenderSceneConverter *converter)
2002-10-12 11:37:38 +00:00
{
KX_GameObject *gameobj = NULL;
switch(ob->type)
{
case OB_LAMP:
{
KX_LightObject* gamelight= gamelight_from_blamp(ob, static_cast<Lamp*>(ob->data), ob->lay, kxscene, rendertools, converter);
2002-10-12 11:37:38 +00:00
gameobj = gamelight;
gamelight->AddRef();
kxscene->GetLightList()->Add(gamelight);
2002-10-12 11:37:38 +00:00
break;
}
case OB_CAMERA:
{
KX_Camera* gamecamera = gamecamera_from_bcamera(ob, kxscene, converter);
2002-10-12 11:37:38 +00:00
gameobj = gamecamera;
//don't add a reference: the camera list in kxscene->m_cameras is not released at the end
//gamecamera->AddRef();
2002-10-12 11:37:38 +00:00
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);
2002-10-12 11:37:38 +00:00
// needed for python scripting
kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
gameobj = new BL_DeformableGameObject(ob,kxscene,KX_Scene::m_callbacks);
2002-10-12 11:37:38 +00:00
// set transformation
gameobj->AddMesh(meshobj);
// 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);
2002-10-12 11:37:38 +00:00
// 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);
bool bHasSoftBody = (!ob->parent && (ob->gameflag & OB_SOFT_BODY));
if (bHasModifier) {
BL_ModifierDeformer *dcont = new BL_ModifierDeformer((BL_DeformableGameObject *)gameobj,
kxscene->GetBlenderScene(), ob, meshobj);
((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
if (bHasShapeKey && bHasArmature)
dcont->LoadShapeDrivers(ob->parent);
} 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);
if (bHasArmature)
dcont->LoadShapeDrivers(ob->parent);
} 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 USE_BULLET
} else if (bHasSoftBody) {
KX_SoftBodyDeformer *dcont = new KX_SoftBodyDeformer(meshobj, (BL_DeformableGameObject*)gameobj);
((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont);
#endif
2002-10-12 11:37:38 +00:00
}
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);
2002-10-12 11:37:38 +00:00
break;
}
case OB_ARMATURE:
{
gameobj = new BL_ArmatureObject(
kxscene,
KX_Scene::m_callbacks,
ob,
kxscene->GetBlenderScene() // handle
);
2002-10-12 11:37:38 +00:00
/* 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;
}
}
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);
}
2002-10-12 11:37:38 +00:00
return gameobj;
}
struct parentChildLink {
struct Object* m_blenderchild;
SG_Node* m_gamechildnode;
};
#include "DNA_constraint_types.h"
//XXX #include "BIF_editconstraint.h"
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;
}
ListBase *get_active_constraints2(Object *ob)
{
if (!ob)
return NULL;
2009-08-16 03:51:25 +00:00
// 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;
}
void 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 "KX_IPhysicsController.h"
#include "PHY_DynamicTypes.h"
KX_IPhysicsController* getPhId(CListValue* sumolist,STR_String busc){//not used
for (int j=0;j<sumolist->GetCount();j++)
{
KX_GameObject* gameobje = (KX_GameObject*) sumolist->GetValue(j);
if (gameobje->GetName()==busc)
return gameobje->GetPhysicsController();
}
return 0;
}
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;
}
2002-10-12 11:37:38 +00:00
// convert blender objects into ketsji gameobjects
void BL_ConvertBlenderObjects(struct Main* maggie,
KX_Scene* kxscene,
KX_KetsjiEngine* ketsjiEngine,
e_PhysicsEngine physics_engine,
RAS_IRenderTools* rendertools,
RAS_ICanvas* canvas,
KX_BlenderSceneConverter* converter,
bool alwaysUseExpandFraming
)
{
2009-07-30 21:42:29 +00:00
Scene *blenderscene = kxscene->GetBlenderScene();
// for SETLOOPER
Scene *sce;
Base *base;
2002-10-12 11:37:38 +00:00
// 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;
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
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)
2002-10-12 11:37:38 +00:00
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) {
2002-10-12 11:37:38 +00:00
frame_type = RAS_FrameSettings::e_frame_bars;
} else if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_EXTEND) {
2002-10-12 11:37:38 +00:00
frame_type = RAS_FrameSettings::e_frame_extend;
} else {
frame_type = RAS_FrameSettings::e_frame_scale;
}
aspect_width = blenderscene->gm.xsch;
aspect_height = blenderscene->gm.ysch;
2002-10-12 11:37:38 +00:00
}
RAS_FrameSettings frame_settings(
frame_type,
blenderscene->gm.framing.col[0],
blenderscene->gm.framing.col[1],
blenderscene->gm.framing.col[2],
2002-10-12 11:37:38 +00:00
aspect_width,
aspect_height
);
kxscene->SetFramingType(frame_settings);
kxscene->SetGravity(MT_Vector3(0,0, -blenderscene->gm.gravity));
2002-10-12 11:37:38 +00:00
/* 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);
2002-10-12 11:37:38 +00:00
int activeLayerBitInfo = blenderscene->lay;
// list of all object converted, active and inactive
2002-10-12 11:37:38 +00:00
CListValue* sumolist = new CListValue();
vector<parentChildLink> vec_parent_child;
CListValue* objectlist = kxscene->GetObjectList();
CListValue* inactivelist = kxscene->GetInactiveList();
2002-10-12 11:37:38 +00:00
CListValue* parentlist = kxscene->GetRootParentList();
SCA_LogicManager* logicmgr = kxscene->GetLogicManager();
SCA_TimeEventManager* timemgr = kxscene->GetTimeEventManager();
CListValue* logicbrick_conversionlist = new CListValue();
//SG_TreeFactory tf;
2002-10-12 11:37:38 +00:00
// 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);
2002-10-12 11:37:38 +00:00
}
SetDefaultFaceType(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, base))
2002-10-12 11:37:38 +00:00
{
Object* blenderobject = base->object;
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
allblobj.insert(blenderobject);
2002-10-12 11:37:38 +00:00
KX_GameObject* gameobj = gameobject_from_blenderobject(
base->object,
kxscene,
rendertools,
2009-07-30 21:42:29 +00:00
converter);
bool isInActiveLayer = (blenderobject->lay & activeLayerBitInfo) !=0;
bool addobj=true;
if (converter->addInitFromFrame)
if (!isInActiveLayer)
addobj=false;
if (gameobj&&addobj)
2002-10-12 11:37:38 +00:00
{
MT_Point3 posPrev;
MT_Matrix3x3 angor;
if (converter->addInitFromFrame) blenderscene->r.cfra=blenderscene->r.sfra;
MT_Point3 pos;
pos.setValue(
2002-10-12 11:37:38 +00:00
blenderobject->loc[0]+blenderobject->dloc[0],
blenderobject->loc[1]+blenderobject->dloc[1],
blenderobject->loc[2]+blenderobject->dloc[2]
);
MT_Vector3 eulxyz(blenderobject->rot);
MT_Vector3 scale(blenderobject->size);
if (converter->addInitFromFrame){//rcruiz
float eulxyzPrev[3];
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]
);
eulxyzPrev[0]=blenderobject->rot[0];
eulxyzPrev[1]=blenderobject->rot[1];
eulxyzPrev[2]=blenderobject->rot[2];
double fps = (double) blenderscene->r.frs_sec/
(double) blenderscene->r.frs_sec_base;
tmp.scale(fps, fps, fps);
inivel.push_back(tmp);
tmp=eulxyz-eulxyzPrev;
tmp.scale(fps, fps, fps);
iniang.push_back(tmp);
blenderscene->r.cfra=blenderscene->r.sfra;
//XXX update_for_newframe();
}
2002-10-12 11:37:38 +00:00
gameobj->NodeSetLocalPosition(pos);
gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
gameobj->NodeSetLocalScale(scale);
gameobj->NodeUpdateGS(0);
2002-10-12 11:37:38 +00:00
BL_ConvertIpos(blenderobject,gameobj,converter);
BL_ConvertMaterialIpos(blenderobject, gameobj, converter);
2002-10-12 11:37:38 +00:00
sumolist->Add(gameobj->AddRef());
BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer);
gameobj->SetName(blenderobject->id.name + 2);
2002-10-12 11:37:38 +00:00
// update children/parent hierarchy
if ((blenderobject->parent != 0)&&(!converter->addInitFromFrame))
2002-10-12 11:37:38 +00:00
{
// 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);
2002-10-12 11:37:38 +00:00
// 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);
2005-04-23 11:36:44 +00:00
2002-10-12 11:37:38 +00:00
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);
2005-04-23 11:36:44 +00:00
2002-10-12 11:37:38 +00:00
parentinversenode->AddChild(gameobj->GetSGNode());
}
// needed for python scripting
logicmgr->RegisterGameObjectName(gameobj->GetName(),gameobj);
Patch: [ #2439 ] Makes objects react properly to deformations after a mesh replacement call. from brian hayward (bthayward) Detailed description: Currently, when an armature deformed object's mesh is replaced by the ReplaceMesh actuator, the new mesh fails to deform to the armature's movement. My patch fixes this by properly replacing the deform controller along with the mesh (when appropriete). For instance, if one had an animated character using any of the standard deformation techniques (armature, ipo, RVK, or AVK), that character's mesh would currently be prevented from changing mid-game. It could be replaced, but the new mesh would lack the controller which tells it how to deform. If one wanted to dynamiclly add a hat on top of the character's head, it would require storing a secondary prebuilt character (mesh, armature, logic, ect...) on another layer FOR EACH HAT the character could possibly wear, then swapping out the whole character when the hat change was desired. So if you had 4 possible hat/character combos, you would have 4 character meshes, 4 armatures, 4 sets of logic, and so on. I find this lack of flexibility to be unresonable. With my patch, one could accomplish the same thing mearly by making one version of the character in the main layer, and adding an invisible object atop the character's head (which is parented to the head bone). Then whenever it becomes desirable, one can replace the invisible object's mesh with the desirable hat's mesh, then make it visible. With my patch, the hat object would then continue to deform to the character's head regardless of which hat was currently being worn. *note 1* for armature/mesh deformations, the new mesh must have properly assigned vertex groups which match one or more of the bones of the target armature before the replaceMesh call is made. Otherwise the vertices won't react to the armature because they won't know how. (not sure if vertices can be scripted to change groups after the game has started) *note 2* The added processing time involved with replacing the object's deform controller is negligible.
2005-04-18 11:44:21 +00:00
// needed for group duplication
logicmgr->RegisterGameObj(blenderobject, gameobj);
Patch: [ #2439 ] Makes objects react properly to deformations after a mesh replacement call. from brian hayward (bthayward) Detailed description: Currently, when an armature deformed object's mesh is replaced by the ReplaceMesh actuator, the new mesh fails to deform to the armature's movement. My patch fixes this by properly replacing the deform controller along with the mesh (when appropriete). For instance, if one had an animated character using any of the standard deformation techniques (armature, ipo, RVK, or AVK), that character's mesh would currently be prevented from changing mid-game. It could be replaced, but the new mesh would lack the controller which tells it how to deform. If one wanted to dynamiclly add a hat on top of the character's head, it would require storing a secondary prebuilt character (mesh, armature, logic, ect...) on another layer FOR EACH HAT the character could possibly wear, then swapping out the whole character when the hat change was desired. So if you had 4 possible hat/character combos, you would have 4 character meshes, 4 armatures, 4 sets of logic, and so on. I find this lack of flexibility to be unresonable. With my patch, one could accomplish the same thing mearly by making one version of the character in the main layer, and adding an invisible object atop the character's head (which is parented to the head bone). Then whenever it becomes desirable, one can replace the invisible object's mesh with the desirable hat's mesh, then make it visible. With my patch, the hat object would then continue to deform to the character's head regardless of which hat was currently being worn. *note 1* for armature/mesh deformations, the new mesh must have properly assigned vertex groups which match one or more of the bones of the target armature before the replaceMesh call is made. Otherwise the vertices won't react to the armature because they won't know how. (not sure if vertices can be scripted to change groups after the game has started) *note 2* The added processing time involved with replacing the object's deform controller is negligible.
2005-04-18 11:44:21 +00:00
for (int i = 0; i < gameobj->GetMeshCount(); i++)
logicmgr->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), blenderobject);
2002-10-12 11:37:38 +00:00
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();
}
2002-10-12 11:37:38 +00:00
if (isInActiveLayer)
{
objectlist->Add(gameobj->AddRef());
//tf.Add(gameobj->GetSGNode());
2002-10-12 11:37:38 +00:00
gameobj->NodeUpdateGS(0);
gameobj->AddMeshUser();
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
}
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 (gameobj->IsDupliGroup())
grouplist.insert(blenderobject->dup_group);
if (converter->addInitFromFrame){
gameobj->NodeSetLocalPosition(posPrev);
gameobj->NodeSetLocalOrientation(angor);
}
2002-10-12 11:37:38 +00:00
}
/* 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
*/
if (gameobj)
gameobj->Release();
2002-10-12 11:37:38 +00:00
}
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
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,
2009-07-30 21:42:29 +00:00
converter);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
// this code is copied from above except that
// object from groups are never in active layer
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
bool isInActiveLayer = false;
bool addobj=true;
if (converter->addInitFromFrame)
if (!isInActiveLayer)
addobj=false;
if (gameobj&&addobj)
{
MT_Point3 posPrev;
MT_Matrix3x3 angor;
if (converter->addInitFromFrame)
blenderscene->r.cfra=blenderscene->r.sfra;
MT_Point3 pos(
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
blenderobject->loc[0]+blenderobject->dloc[0],
blenderobject->loc[1]+blenderobject->dloc[1],
blenderobject->loc[2]+blenderobject->dloc[2]
);
MT_Vector3 eulxyz(blenderobject->rot);
MT_Vector3 scale(blenderobject->size);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
if (converter->addInitFromFrame){//rcruiz
float eulxyzPrev[3];
blenderscene->r.cfra=blenderscene->r.sfra-1;
//XXX update_for_newframe();
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
MT_Vector3 tmp=pos-MT_Point3(blenderobject->loc[0]+blenderobject->dloc[0],
blenderobject->loc[1]+blenderobject->dloc[1],
blenderobject->loc[2]+blenderobject->dloc[2]
);
eulxyzPrev[0]=blenderobject->rot[0];
eulxyzPrev[1]=blenderobject->rot[1];
eulxyzPrev[2]=blenderobject->rot[2];
double fps = (double) blenderscene->r.frs_sec/
(double) blenderscene->r.frs_sec_base;
tmp.scale(fps, fps, fps);
inivel.push_back(tmp);
tmp=eulxyz-eulxyzPrev;
tmp.scale(fps, fps, fps);
iniang.push_back(tmp);
blenderscene->r.cfra=blenderscene->r.sfra;
//XXX update_for_newframe();
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
}
gameobj->NodeSetLocalPosition(pos);
gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
gameobj->NodeSetLocalScale(scale);
gameobj->NodeUpdateGS(0);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
BL_ConvertIpos(blenderobject,gameobj,converter);
BL_ConvertMaterialIpos(blenderobject,gameobj, converter);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
sumolist->Add(gameobj->AddRef());
BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer);
gameobj->SetName(blenderobject->id.name + 2);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
// 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);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
// 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());
// 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 localscale(x.length(), y.length(), z.length());
if (!MT_fuzzyZero(localscale[0]))
x /= localscale[0];
if (!MT_fuzzyZero(localscale[1]))
y /= localscale[1];
if (!MT_fuzzyZero(localscale[2]))
z /= localscale[2];
ori.setColumn(0, x);
ori.setColumn(1, y);
ori.setColumn(2, z);
parentinversenode->SetLocalOrientation(ori);
parentinversenode->SetLocalScale(localscale);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
parentinversenode->AddChild(gameobj->GetSGNode());
}
// needed for python scripting
logicmgr->RegisterGameObjectName(gameobj->GetName(),gameobj);
// needed for group duplication
logicmgr->RegisterGameObj(blenderobject, gameobj);
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
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();
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
}
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 (gameobj->IsDupliGroup())
{
// check that the group is not already converted
if (allgrouplist.insert(blenderobject->dup_group).second)
grouplist.insert(blenderobject->dup_group);
}
if (converter->addInitFromFrame){
gameobj->NodeSetLocalPosition(posPrev);
gameobj->NodeSetLocalOrientation(angor);
}
}
if (gameobj)
gameobj->Release();
}
}
}
}
2002-10-12 11:37:38 +00:00
}
// non-camera objects not supported as camera currently
if (blenderscene->camera && blenderscene->camera->type == OB_CAMERA) {
2002-10-12 11:37:38 +00:00
KX_Camera *gamecamera= (KX_Camera*) converter->FindGameObject(blenderscene->camera);
if(gamecamera)
kxscene->SetActiveCamera(gamecamera);
2002-10-12 11:37:38 +00:00
}
// Set up armatures
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
set<Object*>::iterator oit;
for(oit=allblobj.begin(); oit!=allblobj.end(); oit++)
{
Object* blenderobj = *oit;
if (blenderobj->type==OB_MESH) {
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
Mesh *me = (Mesh*)blenderobj->data;
2002-10-12 11:37:38 +00:00
if (me->dvert){
BL_DeformableGameObject *obj = (BL_DeformableGameObject*)converter->FindGameObject(blenderobj);
if (obj && BL_ModifierDeformer::HasArmatureDeformer(blenderobj) && blenderobj->parent && blenderobj->parent->type==OB_ARMATURE){
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
KX_GameObject *par = converter->FindGameObject(blenderobj->parent);
if (par && obj->GetDeformer())
((BL_SkinDeformer*)obj->GetDeformer())->SetArmature((BL_ArmatureObject*) par);
2002-10-12 11:37:38 +00:00
}
}
}
}
// 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;
}
2005-04-23 11:36:44 +00:00
switch (blenderchild->partype)
2002-10-12 11:37:38 +00:00
{
2005-04-23 11:36:44 +00:00
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
2009-01-05 15:48:24 +00:00
Bone *parent_bone = get_named_bone( (bArmature *)(blenderchild->parent)->data, blenderchild->parsubstr);
if(parent_bone) {
KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone);
pcit->m_gamechildnode->SetParentRelation(bone_parent_relation);
}
2005-04-23 11:36:44 +00:00
break;
}
case PARSKEL: // skinned - ignore
break;
case PAROBJECT:
case PARCURVE:
case PARKEY:
case PARVERT3:
default:
// unhandled
break;
}
2002-10-12 11:37:38 +00:00
parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode);
2002-10-12 11:37:38 +00:00
}
vec_parent_child.clear();
// find 'root' parents (object that has not parents in SceneGraph)
for (i=0;i<sumolist->GetCount();++i)
2002-10-12 11:37:38 +00:00
{
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
2002-10-12 11:37:38 +00:00
if (gameobj->GetSGNode()->GetSGParent() == 0)
{
parentlist->Add(gameobj->AddRef());
gameobj->NodeUpdateGS(0);
2002-10-12 11:37:38 +00:00
}
}
// 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
for (i=0;i<sumolist->GetCount();++i)
{
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
((BL_ArmatureObject*)gameobj)->LoadConstraints(converter);
}
bool processCompoundChildren = false;
2002-10-12 11:37:38 +00:00
// create physics information
for (i=0;i<sumolist->GetCount();i++)
{
KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
struct Object* blenderobject = gameobj->GetBlenderObject();
2002-10-12 11:37:38 +00:00
int nummeshes = gameobj->GetMeshCount();
RAS_MeshObject* meshobj = 0;
if (nummeshes > 0)
{
meshobj = gameobj->GetMesh(0);
}
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0;
BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,physics_engine,converter,processCompoundChildren);
}
2002-10-12 11:37:38 +00:00
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);
}
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0;
BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,physics_engine,converter,processCompoundChildren);
2002-10-12 11:37:38 +00:00
}
//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 (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){
PHY_IPhysicsController* physctr2 = 0;
if (dat->tar)
{
KX_GameObject *gotar=getGameOb(dat->tar->id.name+2,sumolist);
if (gotar && gotar->GetPhysicsController())
physctr2 = (PHY_IPhysicsController*) gotar->GetPhysicsController()->GetUserData();
}
if (gameobj->GetPhysicsController())
{
PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) gameobj->GetPhysicsController()->GetUserData();
//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;
}
}
}
}
}
}
}
}
}
sumolist->Release();
2002-10-12 11:37:38 +00:00
// convert world
KX_WorldInfo* worldinfo = new BlenderWorldInfo(blenderscene, blenderscene->world);
2002-10-12 11:37:38 +00:00
converter->RegisterWorldInfo(worldinfo);
kxscene->SetWorldInfo(worldinfo);
2005-07-16 21:47:54 +00:00
#define CONVERT_LOGIC
#ifdef CONVERT_LOGIC
2002-10-12 11:37:38 +00:00
// 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();
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
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,rendertools,converter);
2002-10-12 11:37:38 +00:00
}
for ( i=0;i<logicbrick_conversionlist->GetCount();i++)
{
KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
struct Object* blenderobj = gameobj->GetBlenderObject();
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0;
bool isInActiveLayer = (blenderobj->lay & layerMask)!=0;
BL_ConvertControllers(blenderobj,gameobj,logicmgr, layerMask,isInActiveLayer,converter);
2002-10-12 11:37:38 +00:00
}
for ( i=0;i<logicbrick_conversionlist->GetCount();i++)
{
KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
struct Object* blenderobj = gameobj->GetBlenderObject();
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
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);
2002-10-12 11:37:38 +00:00
}
// apply the initial state to controllers, only on the active objects as this registers the sensors
for ( i=0;i<objectlist->GetCount();i++)
BGE patch: add state engine support in the logic bricks. This patch introduces a simple state engine system with the logic bricks. This system features full backward compatibility, multiple active states, multiple state transitions, automatic disabling of sensor and actuators, full GUI support and selective display of sensors and actuators. Note: Python API is available but not documented yet. It will be added asap. State internals =============== The state system is object based. The current state mask is stored in the object as a 32 bit value; each bit set in the mask is an active state. The controllers have a state mask too but only one bit can be set: a controller belongs to a single state. The game engine will only execute controllers that belong to active states. Sensors and actuators don't have a state mask but are effectively attached to states via their links to the controllers. Sensors and actuators can be connected to more than one state. When a controller becomes inactive because of a state change, its links to sensors and actuators are temporarily broken (until the state becomes active again). If an actuator gets isolated, i.e all the links to controllers are broken, it is automatically disabled. If a sensor gets isolated, the game engine will stop calling it to save CPU. It will also reset the sensor internal state so that it can react as if the game just started when it gets reconnected to an active controller. For example, an Always sensor in no pulse mode that is connected to a single state (i.e connected to one or more controllers of a single state) will generate a pulse each time the state becomes active. This feature is not available on all sensors, see the notes below. GUI === This system system is fully configurable through the GUI: the object state mask is visible under the object bar in the controller's colum as an array of buttons just like the 3D view layer mask. Click on a state bit to only display the controllers of that state. You can select more than one state with SHIFT-click. The All button sets all the bits so that you can see all the controllers of the object. The Ini button sets the state mask back to the object default state. You can change the default state of object by first selecting the desired state mask and storing using the menu under the State button. If you define a default state mask, it will be loaded into the object state make when you load the blend file or when you run the game under the blenderplayer. However, when you run the game under Blender, the current selected state mask will be used as the startup state for the object. This allows you to test specific state during the game design. The controller display the state they belong to with a new button in the controller header. When you add a new controller, it is added by default in the lowest enabled state. You can change the controller state by clicking on the button and selecting another state. If more than one state is enabled in the object state mask, controllers are grouped by state for more readibility. The new Sta button in the sensor and actuator column header allows you to display only the sensors and actuators that are linked to visible controllers. A new state actuator is available to modify the state during the game. It defines a bit mask and the operation to apply on the current object state mask: Cpy: the bit mask is copied to the object state mask. Add: the bits that set in the bit mask will be turned on in the object state mask. Sub: the bits that set in the bit mask will be turned off in the object state mask. Inv: the bits that set in the bit mask will be inverted in the objecyy state mask. Notes ===== - Although states have no name, a simply convention consists in using the name of the first controller of the state as the state name. The GUI will support that convention by displaying as a hint the name of the first controller of the state when you move the mouse over a state bit of the object state mask or of the state actuator bit mask. - Each object has a state mask and each object can have a state engine but if several objects are part of a logical group, it is recommended to put the state engine only in the main object and to link the controllers of that object to the sensors and actuators of the different objects. - When loading an old blend file, the state mask of all objects and controllers are initialized to 1 so that all the controllers belong to this single state. This ensures backward compatibility with existing game. - When the state actuator is activated at the same time as other actuators, these actuators are guaranteed to execute before being eventually disabled due to the state change. This is useful for example to send a message or update a property at the time of changing the state. - Sensors that depend on underlying resource won't reset fully when they are isolated. By the time they are acticated again, they will behave as follow: * keyboard sensor: keys already pressed won't be detected. The keyboard sensor is only sensitive to new key press. * collision sensor: objects already colliding won't be detected. Only new collisions are detected. * near and radar sensor: same as collision sensor.
2008-06-22 14:23:57 +00:00
{
KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i));
BGE logic patch: new "Add" mode for Ipo actuator, several corrections in state system. New Add mode for Ipo actuator ============================= A new Add button, mutually exclusive with Force button, is available in the Ipo actuator. When selected, it activates the Add mode that consists in adding the Ipo curve to the current object situation in world coordinates, or parent coordinates if the object has a parent. Scale Ipo curves are multiplied instead of added to the object current scale. If the local flag is selected, the Ipo curve is added (multiplied) in the object's local coordinates. Delta Ipo curves are handled identically to normal Ipo curve and there is no need to work with Delta Ipo curves provided that you make sure that the Ipo curve starts from origin. Origin means location 0 for Location Ipo curve, rotation 0 for Rotation Ipo curve and scale 1 for Scale Ipo curve. The "current object situation" means the object's location, rotation and scale at the start of the Ipo curve. For Loop Stop and Loop End Ipo actuators, this means at the start of each loop. This initial state is used as a base during the execution of the Ipo Curve but when the Ipo curve is restarted (later or immediately in case of Loop mode), the object current situation at that time is used as the new base. For reference, here is the exact operation of the Add mode for each type of Ipo curve (oLoc, oRot, oScale, oMat: object's loc/rot/scale and orientation matrix at the start of the curve; iLoc, iRot, iScale, iMat: Ipo curve loc/rot/scale and orientation matrix resulting from the rotation). Location Local=false: newLoc = oLoc+iLoc Local=true : newLoc = oLoc+oScale*(oMat*iLoc) Rotation Local=false: newMat = iMat*oMat Local=true : newMat = oMat*iMat Scale Local=false: newScale = oScale*iScale Local=true : newScale = oScale*iScale Add+Local mode is very useful to have dynamic object executing complex movement relative to their current location/orientation. Of cource, dynamics should be disabled during the execution of the curve. Several corrections in state system =================================== - Object initial state is taken into account when adding object dynamically - Fix bug with link count when adding object dynamically - Fix false on-off detection for Actuator sensor when actuator is trigged on negative event. - Fix Parent actuator false activation on negative event - Loop Ipo curve not restarting at correct frame when start frame is different from one.
2008-07-08 12:18:43 +00:00
gameobj->ResetState();
BGE patch: add state engine support in the logic bricks. This patch introduces a simple state engine system with the logic bricks. This system features full backward compatibility, multiple active states, multiple state transitions, automatic disabling of sensor and actuators, full GUI support and selective display of sensors and actuators. Note: Python API is available but not documented yet. It will be added asap. State internals =============== The state system is object based. The current state mask is stored in the object as a 32 bit value; each bit set in the mask is an active state. The controllers have a state mask too but only one bit can be set: a controller belongs to a single state. The game engine will only execute controllers that belong to active states. Sensors and actuators don't have a state mask but are effectively attached to states via their links to the controllers. Sensors and actuators can be connected to more than one state. When a controller becomes inactive because of a state change, its links to sensors and actuators are temporarily broken (until the state becomes active again). If an actuator gets isolated, i.e all the links to controllers are broken, it is automatically disabled. If a sensor gets isolated, the game engine will stop calling it to save CPU. It will also reset the sensor internal state so that it can react as if the game just started when it gets reconnected to an active controller. For example, an Always sensor in no pulse mode that is connected to a single state (i.e connected to one or more controllers of a single state) will generate a pulse each time the state becomes active. This feature is not available on all sensors, see the notes below. GUI === This system system is fully configurable through the GUI: the object state mask is visible under the object bar in the controller's colum as an array of buttons just like the 3D view layer mask. Click on a state bit to only display the controllers of that state. You can select more than one state with SHIFT-click. The All button sets all the bits so that you can see all the controllers of the object. The Ini button sets the state mask back to the object default state. You can change the default state of object by first selecting the desired state mask and storing using the menu under the State button. If you define a default state mask, it will be loaded into the object state make when you load the blend file or when you run the game under the blenderplayer. However, when you run the game under Blender, the current selected state mask will be used as the startup state for the object. This allows you to test specific state during the game design. The controller display the state they belong to with a new button in the controller header. When you add a new controller, it is added by default in the lowest enabled state. You can change the controller state by clicking on the button and selecting another state. If more than one state is enabled in the object state mask, controllers are grouped by state for more readibility. The new Sta button in the sensor and actuator column header allows you to display only the sensors and actuators that are linked to visible controllers. A new state actuator is available to modify the state during the game. It defines a bit mask and the operation to apply on the current object state mask: Cpy: the bit mask is copied to the object state mask. Add: the bits that set in the bit mask will be turned on in the object state mask. Sub: the bits that set in the bit mask will be turned off in the object state mask. Inv: the bits that set in the bit mask will be inverted in the objecyy state mask. Notes ===== - Although states have no name, a simply convention consists in using the name of the first controller of the state as the state name. The GUI will support that convention by displaying as a hint the name of the first controller of the state when you move the mouse over a state bit of the object state mask or of the state actuator bit mask. - Each object has a state mask and each object can have a state engine but if several objects are part of a logical group, it is recommended to put the state engine only in the main object and to link the controllers of that object to the sensors and actuators of the different objects. - When loading an old blend file, the state mask of all objects and controllers are initialized to 1 so that all the controllers belong to this single state. This ensures backward compatibility with existing game. - When the state actuator is activated at the same time as other actuators, these actuators are guaranteed to execute before being eventually disabled due to the state change. This is useful for example to send a message or update a property at the time of changing the state. - Sensors that depend on underlying resource won't reset fully when they are isolated. By the time they are acticated again, they will behave as follow: * keyboard sensor: keys already pressed won't be detected. The keyboard sensor is only sensitive to new key press. * collision sensor: objects already colliding won't be detected. Only new collisions are detected. * near and radar sensor: same as collision sensor.
2008-06-22 14:23:57 +00:00
}
2005-07-16 21:47:54 +00:00
#endif //CONVERT_LOGIC
2002-10-12 11:37:38 +00:00
logicbrick_conversionlist->Release();
// Calculate the scene btree -
// too slow - commented out.
//kxscene->SetNodeTree(tf.MakeTree());
BGE patch: DUPLIGROUP option supported in BGE. Blender duplicates groups in the 3D view at the location of objects having the DUPLIGROUP option set. This feature is now supported in the BGE: the groups will be instantiated as in the 3D view when the scene is converted. This is useful to populate a scene with multiple enemies without having to actually duplicate the objects in the blend file. Notes: * The BGE applies the same criteria to instantiate the group as Blender to display them: if you see the group in the 3D view, it will be instantiated in the BGE. * Groups are instantiated as if the object having the DUPLIGROUP option (usually an empty) executed an AddObject actuator on the top objects of the group (objects without parent). * As a result, only intra-group parent relationship is supported: the BGE will not instantiate objects that have parents outside the group. * Intra-group logic bricks connections are preserved between the duplicated objects, even between the top objects of the group. * For best result, the state engine of the objects in the group should be self-contained: logic bricks should only have intra-group connections. Use messages to communicate with state engines outside the group. * Nested groups are supported: if one or more objects in the group have the DUPLIGROUP option set, the corresponding groups will be instantiated at the corresponding position and orientation. * Nested groups are instantiated as separate groups, not as one big group. * Linked groups are supported as well as groups containing objects from the active layers. * There is a difference in the way Blender displays the groups in the 3D view and how BGE instantiates them: Blender does not take into account the parent relationship in the group and displays the objects as if they were all children of the object having the DUPLIGROUP option. That's correct for the top objects of the group but not for the children. Hence the orientation of the children objects may be different in the BGE. * An AddGroup actuator will be added in a future release.
2008-07-15 20:05:23 +00:00
// 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);
}