1
1

Compare commits

...

9 Commits

36 changed files with 1832 additions and 7 deletions

View File

@@ -0,0 +1,72 @@
import bge
from collections import OrderedDict
class ThirdPerson(bge.types.KX_PythonComponent):
"""A component for a third person camera"""
args = OrderedDict([
("Pivot Name", "pivot"),
("Time Offset", 35),
("Lens", 30),
("Scale Max", 4.0),
("Scale Min", 0.6),
])
def start(self, args):
# Make sure we have a camera
if not isinstance(self.object, bge.types.KX_Camera):
raise TypeError("This component must be attached to a camera")
# Apply settings
self.object.parent.timeOffset = args['Time Offset']
self.object.lens = args['Lens']
# Save scale settings
self.scale_max = args['Scale Max']
self.scale_min = args['Scale Min']
# Find the pivot
pivot = self.object.parent
while pivot:
if pivot.name == args['Pivot Name']:
break
pivot = pivot.parent
if not pivot:
raise ValueError("Could not find the pivot object")
self.pivot = pivot
self._target_distance = (self.object.worldPosition - pivot.worldPosition).length
def update(self):
ob = self.object
pivot = self.pivot
# Cast a ray and see if we hit something
hit_pos = self.object.rayCast(
ob.worldPosition,
pivot.worldPosition,
ob.localPosition[2])[1]
if hit_pos:
scale = ob.getDistanceTo(hit_pos)/self._target_distance
if scale > self.scale_max:
scale = self.scale_max
elif scale < self.scale_min:
scale = self.scale_min
else:
scale = self.scale_max
# Apply the scaling
pivot.scaling = [scale, scale, scale]
# Undo the scaling on the camera
# inv_scale = 1/scale
# ob.scaling = [inv_scale, inv_scale, inv_scale]
# Update the "look at"
vec = ob.getVectTo(pivot)[1]
ob.alignAxisToVect(vec, 1)

View File

@@ -0,0 +1,39 @@
import bge
class ThirdPerson(bge.types.KX_PythonComponent):
"""Basic third person controls
W: move forward
A: turn left
S: move backward
D: turn right
"""
args = {
"Move Speed": 10,
"Turn Speed": 0.04
}
def start(self, args):
self.move_speed = args['Move Speed']
self.turn_speed = args['Turn Speed']
def update(self):
keyboard = bge.logic.keyboard.events
move = 0
rotate = 0
if keyboard[bge.events.WKEY]:
move += self.move_speed
if keyboard[bge.events.SKEY]:
move -= self.move_speed
if keyboard[bge.events.AKEY]:
rotate += self.turn_speed
if keyboard[bge.events.DKEY]:
rotate -= self.turn_speed
self.object.setLinearVelocity((0, move, 0), True)
self.object.applyRotation((0, 0, rotate), True)

View File

@@ -0,0 +1,116 @@
import bge
import mathutils
import math
import random
from collections import OrderedDict
X_AXIS = mathutils.Vector((1, 0, 0))
Y_AXIS = mathutils.Vector((0, 1, 0))
Z_AXIS = mathutils.Vector((0, 0, 1))
class ParticleSystem(bge.types.KX_PythonComponent):
"""Simple particles System"""
args = OrderedDict([
("Particle Name", ""),
("Particles Per Frame", 1),
("X Angle", 30.0),
("Y Angle", 30.0),
("X Size", 0.0),
("Y Size", 0.0),
("Starting Velocity", 500.0),
("Velocity Variance", 0.0),
("Particle Life", 30),
("Life Variance", 0.0),
("Gravity", -9.8),
])
def start(self, args):
self.valid = True
self.particle = args['Particle Name']
self.part_life = args['Particle Life']
self.ppf_inv = 1/(args['Particles Per Frame'] if args['Particles Per Frame'] else 1)
# Save directional variance as radians
self.x_var = math.radians(args['X Angle'])
self.y_var = math.radians(args['Y Angle'])
# Save the offests
self.x_off = args['X Size']
self.y_off = args['Y Size']
# Save variances
self.velocity_var = args['Velocity Variance']
self.life_variance = args['Life Variance']
# Store a time step
self.dt = 1/bge.logic.getLogicTicRate()
# Precalculate gravity*dt
self.gravity_dt = args['Gravity']*self.dt
# Precalculate velocity*dt
self.start_velocity_dt = args['Starting Velocity'] * self.dt
# Add the first particle into the list
self.particle_list = [self.create_particle()]
def update(self):
frame_position = self.ppf_inv
while frame_position <= 1:
self.particle_list.append(self.create_particle(frame_position))
frame_position += self.ppf_inv
[self.update_particle(particle) for particle in self.particle_list]
def create_particle(self, frame_position=0):
# Add the particle
scene = bge.logic.getCurrentScene()
particle = scene.addObject(self.particle, self.object, 0)
# Determine particle heading
x_tilt = random.uniform(-self.x_var, self.x_var)
y_tilt = random.uniform(-self.y_var, self.y_var)
# Apply x offset
x_dir = self.object.getAxisVect(X_AXIS)
particle.worldPosition = particle.worldPosition.copy() + x_dir * random.uniform(-self.x_off, self.x_off)
# Apply y offset
y_dir = self.object.getAxisVect(Y_AXIS)
particle.worldPosition = particle.worldPosition.copy() + y_dir * random.uniform(-self.y_off, self.y_off)
# Determine the particle velocity vector
velocity = self.object.getAxisVect(Z_AXIS)
velocity.rotate(mathutils.Euler((x_tilt, 0, 0)))
velocity.rotate(mathutils.Euler((0, y_tilt, 0)))
# Assign the particle properties
particle['life'] = self.part_life
if self.life_variance > .0001:
particle['life'] *= 1+random.uniform(-self.life_variance, self.life_variance)
particle['velocity'] = velocity * self.start_velocity_dt
if self.velocity_var > .0001:
particle['velocity'] *= 1+random.uniform(-self.velocity_var, self.velocity_var)
# Deal with subframe positioning
if frame_position < 1:
particle.worldPosition = particle.worldPosition.copy() + particle['velocity']*self.dt*frame_position
# Return the particle
return particle
def update_particle(self, particle):
# Update particle life
if particle['life'] == 0:
self.particle_list.remove(particle)
particle.endObject()
return
else:
particle['life'] -= 1
# Apply gravity to the particle's velocity
particle['velocity'][2] += self.gravity_dt
# Update particle position
particle.worldPosition = particle.worldPosition.copy() + particle['velocity']*self.dt

View File

@@ -0,0 +1,128 @@
import bge
from collections import OrderedDict
class Vehicle(bge.types.KX_PythonComponent):
"""A component making use of the vehicle wrapper
Controls:
W: Move forward
S: Move backward
A: Turn left
D: Turn right
SPACE: Brake
"""
args = OrderedDict([
("Gas Power", 15.0),
("Reverse Power", 10.0),
("Brake Power", 10.0),
("Turn Power", 0.3),
("Drive Type", {"Front Wheel", "Rear Wheel"}),
("Tire Prefix", "tire_"),
("Front Tire Radius", 0.3),
("Rear Tire Radius", 0.3),
("Tire Friction", 10.0),
("Suspension Height", 0.2),
("Suspension Compression", 6.0),
("Suspension Damping", 1.0),
("Suspension Stiffness", 20.0),
("Roll Influence", 0.06),
])
def start(self, args):
# Save power settings
self.gas = args['Gas Power']
self.reverse = args['Reverse Power']
self.brake = args['Brake Power']
self.turn = args['Turn Power']
# Save steering settings
self.fwd = args['Drive Type'] == "Front Wheel"
self.rwd = args['Drive Type'] == "Rear Wheel"
# Create the vehicle constraint
constraint = bge.constraints.createConstraint(self.object.getPhysicsId(), 0, 11)
cid = constraint.getConstraintId()
vid = bge.constraints.getVehicleConstraint(cid)
self.vid = vid
# Find the tires (they should be parented)
tpx = args['Tire Prefix']
tires = [None]*4
for child in self.object.childrenRecursive:
for i in range(4):
if child.name.startswith(tpx+str(i+1)):
tires[i] = child
# Unparent the tire so it doesn't cause the vehicle wrapper grief
child.removeParent()
# Verify that we have all of the tires
for idx, tire in enumerate(tires):
if tire is None:
raise ValueError("Tire "+str(idx+1)+" not found")
# Now setup the tires
for i in range(4):
# Add the wheel
vid.addWheel(
# Object
tires[i],
# Position
tires[i].worldPosition - self.object.worldPosition,
# Suspension angle
(0, 0, -1),
# Suspension axis
(-1, 0, 0),
# Suspension height
args['Suspension Height'],
# Tire radius
args['Front Tire Radius'] if i in (0, 1) else args['Rear Tire Radius'],
# Steerability
self.fwd if i in (2, 3) else self.rwd)
# Advanced settings
vid.setTyreFriction(args['Tire Friction'], i)
vid.setSuspensionCompression(args['Suspension Compression'], i)
vid.setSuspensionDamping(args['Suspension Damping'], i)
vid.setSuspensionStiffness(args['Suspension Stiffness'], i)
vid.setRollInfluence(args['Roll Influence'], i)
def update(self):
keyboard = bge.logic.keyboard.events
# Engine force
engine_force = 0
if keyboard[bge.events.WKEY] == bge.logic.KX_INPUT_ACTIVE:
engine_force -= self.gas
if keyboard[bge.events.SKEY] == bge.logic.KX_INPUT_ACTIVE:
engine_force += self.gas
# Steering
steering = 0
if keyboard[bge.events.AKEY] == bge.logic.KX_INPUT_ACTIVE:
steering += self.turn
if keyboard[bge.events.DKEY] == bge.logic.KX_INPUT_ACTIVE:
steering -= self.turn
# Braking
braking = 0
if keyboard[bge.events.SPACEKEY] == bge.logic.KX_INPUT_ACTIVE:
braking += self.brake
# Apply settings
for i in range(4):
self.vid.applyEngineForce(engine_force, i)
if (i in (0, 1) and self.fwd) or (i in (2, 3) and self.rwd):
self.vid.applyBraking(braking, i)
self.vid.setSteeringValue(steering, i)

View File

@@ -33,7 +33,7 @@ import sys as _sys
import addon_utils as _addon_utils
_script_module_dirs = "startup", "modules"
_script_module_dirs = "startup", "modules", "bge_components"
def _test_import(module_name, loaded_modules):
@@ -190,8 +190,8 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
if _os.path.isdir(path):
_sys_path_ensure(path)
# only add this to sys.modules, dont run
if path_subdir == "modules":
# only add these to sys.modules, dont run
if path_subdir in ("modules", "bge_components"):
continue
for mod in modules_from_path(path, loaded_modules):

View File

@@ -19,6 +19,40 @@
# <pep8 compliant>
import bpy
class LOGIC_PT_components(bpy.types.Panel):
bl_space_type = 'LOGIC_EDITOR'
bl_region_type = 'UI'
bl_label = 'Components'
@classmethod
def poll(cls, context):
ob = context.active_object
return ob and ob.name
def draw(self, context):
layout = self.layout
ob = context.active_object
game = ob.game
st = context.space_data
row = layout.row()
row.prop(st, "import_string", text="")
row.operator("logic.component_add", text="Add Component")
for i, c in enumerate(game.components):
box = layout.box()
row = box.row()
row.prop(c, "name", text="")
row.operator("logic.component_reload", text="", icon='RECOVER_LAST').index = i
row.operator("logic.component_remove", text="", icon='X').index = i
for prop in c.properties:
row = box.row()
row.label(text=prop.name)
row.prop(prop, "value", text="")
class LOGIC_PT_properties(bpy.types.Panel):
bl_space_type = 'LOGIC_EDITOR'

View File

@@ -0,0 +1,15 @@
#ifndef BKE_PYCOMPONENT_H
#define BKE_PYCOMPONENT_H
#ifdef __cplusplus
extern "C" {
#endif
struct PythonComponent *new_component_from_import(char *import);
void free_component(struct PythonComponent *pc);
void free_components(struct ListBase *base);
#ifdef __cplusplus
}
#endif
#endif /*BKE_PYCOMPONENT_H*/

View File

@@ -75,6 +75,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_animsys.h"
#include "BKE_anim.h"
#include "BKE_pycomponent.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -308,6 +309,7 @@ void free_object(Object *ob)
free_sensors(&ob->sensors);
free_controllers(&ob->controllers);
free_actuators(&ob->actuators);
free_components(&ob->components);
free_constraints(&ob->constraints);
@@ -1337,6 +1339,7 @@ Object *copy_object(Object *ob)
copy_sensors(&obn->sensors, &ob->sensors);
copy_controllers(&obn->controllers, &ob->controllers);
copy_actuators(&obn->actuators, &ob->actuators);
// XXX todo copy_components(&obn->components, &ob->components);
if(ob->pose) {
copy_object_pose(obn, ob);

View File

@@ -0,0 +1,367 @@
#include <stdlib.h>
#include "DNA_component_types.h"
#include "DNA_property_types.h" /* For MAX_PROPSTRING */
#include "DNA_listBase.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_pycomponent.h"
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "MEM_guardedalloc.h"
#include "RNA_types.h"
#ifdef WITH_PYTHON
#include "Python.h"
#endif
#ifndef WITH_PYTHON
struct PyObject;
#endif
int verify_class(PyObject *cls)
{
#ifdef WITH_PYTHON
PyObject *list, *item;
char *name;
int i;
int comp;
list = PyObject_GetAttrString(cls, "__bases__");
for (i=0; i<PyTuple_Size(list); ++i)
{
item = PyObject_GetAttrString(PyTuple_GetItem(list, i), "__name__");
name = _PyUnicode_AsString(item);
// We don't want to decref until after the comprison
comp = strcmp("KX_PythonComponent", name);
Py_DECREF(item);
if (comp == 0)
{
Py_DECREF(list);
return 1;
}
}
Py_DECREF(list);
#endif
return 0;
}
ComponentProperty *create_property(char *name, short type, int data, void *poin)
{
ComponentProperty *cprop;
cprop = MEM_mallocN(sizeof(ComponentProperty), "ComponentProperty");
if (cprop)
{
BLI_strncpy(cprop->name, name, sizeof(cprop->name));
cprop->type = type;
cprop->data = 0;
cprop->poin = NULL;
cprop->poin2 = NULL;
if (type == CPROP_TYPE_INT)
cprop->data = data;
else if (type == CPROP_TYPE_FLOAT)
*((float *)&cprop->data) = *(float*)(&data);
else if (type == CPROP_TYPE_BOOLEAN)
cprop->data = data;
else if (type == CPROP_TYPE_STRING)
cprop->poin = poin;
else if (type == CPROP_TYPE_SET)
{
cprop->poin = poin;
cprop->poin2 = ((EnumPropertyItem*)poin)->identifier;
cprop->data = 0;
}
}
return cprop;
}
void free_component_property(ComponentProperty *cprop)
{
if (cprop->poin) MEM_freeN(cprop->poin);
if (cprop->poin2) MEM_freeN(cprop->poin2);
MEM_freeN(cprop);
}
void free_component_properties(ListBase *lb)
{
ComponentProperty *cprop;
while (cprop= lb->first) {
BLI_remlink(lb, cprop);
free_component_property(cprop);
}
}
void create_properties(PythonComponent *pycomp, PyObject *cls)
{
#ifdef WITH_PYTHON
PyObject *args_dict, *key, *value, *items, *item;
ComponentProperty *cprop;
char name[64];
int i=0, data;
short type;
void *poin=NULL;
args_dict = PyObject_GetAttrString(cls, "args");
// If there is no args dict, then we are already done
if (args_dict == NULL || !PyDict_Check(args_dict))
{
Py_XDECREF(args_dict);
return;
}
// Otherwise, parse the dict:
// key => value
// key = property name
// value = default value
// type(value) = property type
items = PyMapping_Items(args_dict);
for (i=0; i<PyList_Size(items); ++i)
{
item = PyList_GetItem(items, i);
key = PyTuple_GetItem(item, 0);
value = PyTuple_GetItem(item, 1);
// Make sure type(key) == string
if (!PyUnicode_Check(key))
{
printf("Non-string key found in the args dictionary, skipping\n");
continue;
}
BLI_strncpy(name, _PyUnicode_AsString(key), sizeof(name));
// Determine the type and default value
if (PyBool_Check(value))
{
type = CPROP_TYPE_BOOLEAN;
data = PyLong_AsLong(value) != 0;
}
else if (PyLong_Check(value))
{
type = CPROP_TYPE_INT;
data = PyLong_AsLong(value);
}
else if (PyFloat_Check(value))
{
type = CPROP_TYPE_FLOAT;
*((float*)&data) = (float)PyFloat_AsDouble(value);
}
else if (PyUnicode_Check(value))
{
type = CPROP_TYPE_STRING;
poin = MEM_callocN(MAX_PROPSTRING, "ComponentProperty string");
BLI_strncpy((char*)poin, _PyUnicode_AsString(value), MAX_PROPSTRING);
}
else if (PySet_Check(value))
{
int len = PySet_Size(value), i=0;
EnumPropertyItem *items;
PyObject *iterator = PyObject_GetIter(value), *v=NULL;
char *str;
type = CPROP_TYPE_SET;
// Create an EnumPropertyItem array
poin = MEM_callocN(sizeof(EnumPropertyItem)*(len+1), "ComponentProperty set");
items = (EnumPropertyItem*)poin;
while (v = PyIter_Next(iterator))
{
str = MEM_callocN(MAX_PROPSTRING, "ComponentProperty set string");
BLI_strncpy(str, _PyUnicode_AsString(v), MAX_PROPSTRING);
printf("SET: %s\n", str);
items[i].value = i;
items[i].identifier = str;
items[i].icon = 0;
items[i].name = str;
items[i].description = "";
i++;
}
data = 0;
}
else
{
// Unsupported type
printf("Unsupported type found for args[%s], skipping\n", name);
continue;
}
cprop = create_property(name, type, data, poin);
if (cprop)
BLI_addtail(&pycomp->properties, cprop);
else
// Cleanup poin if it's set
if (poin) MEM_freeN(poin);
}
#endif /* WITH_PYTHON */
}
PyObject *arg_dict_from_component(PythonComponent *pc)
{
ComponentProperty *cprop;
PyObject *args= NULL, *value=NULL;
#ifdef WITH_PYTHON
args = PyDict_New();
cprop = pc->properties.first;
while (cprop)
{
if (cprop->type == CPROP_TYPE_INT)
value = PyLong_FromLong(cprop->data);
else if (cprop->type == CPROP_TYPE_FLOAT)
value = PyFloat_FromDouble(*(float*)(&cprop->data));
else if (cprop->type == CPROP_TYPE_BOOLEAN)
value = PyBool_FromLong(cprop->data);
else if (cprop->type == CPROP_TYPE_STRING)
value = PyUnicode_FromString((char*)cprop->poin);
else
continue;
PyDict_SetItemString(args, cprop->name, value);
cprop= cprop->next;
}
#endif /* WITH_PYTHON */
return args;
}
PythonComponent *new_component_from_import(char *import)
{
PythonComponent *pc = NULL;
#ifdef WITH_PYTHON
PyObject *mod, *mod_list, *item, *py_name;
PyGILState_STATE state;
char *last_dot_str, *name;
char cls[64], path[64];
int i, last_dot;
// Don't bother with an empty string
if (strcmp(import, "") == 0)
return NULL;
// Split the class and module
last_dot_str = strrchr(import, '.');
last_dot = (int)(last_dot_str-import) + 1;
if(last_dot > 0)
{
BLI_strncpy(path, import, last_dot);
strcpy(cls, import+last_dot);
}
else
{
printf("No component class was specified, only the module was.\n");
return NULL;
}
state = PyGILState_Ensure();
// Try to load up the module
mod = PyImport_ImportModule(path);
if (mod)
{
// Get the list of objects in the module
mod_list = PyDict_Values(PyModule_GetDict(mod));
// Now iterate the list
for (i=0; i<PyList_Size(mod_list); ++i)
{
item = PyList_GetItem(mod_list, i);
// We only want to bother checking type objects
if (!PyType_Check(item))
continue;
// Make sure the name matches
py_name = PyObject_GetAttrString(item, "__name__");
name = _PyUnicode_AsString(py_name);
Py_DECREF(py_name);
if (strcmp(name, cls) != 0)
continue;
// Check the subclass with our own function since we don't have access to the KX_PythonComponent type object
if (!verify_class(item))
{
printf("A %s type was found, but it was not a valid subclass of KX_PythonComponent\n", cls);
}
else
{
// We have a valid class, make a component
pc = MEM_callocN(sizeof(PythonComponent), "PythonComponent");
strcpy(pc->module, path);
strcpy(pc->name, cls);
// Setup the properties
create_properties(pc, item);
break;
}
}
// If we still have a NULL component, then we didn't find a suitable class
if (pc == NULL)
printf("No suitable class was found for a component at %s\n", import);
// Take the module out of the module list so it's not cached by Python (this allows for simpler reloading of components)
PyDict_DelItemString(PyImport_GetModuleDict(), path);
// Cleanup our Python objects
Py_DECREF(mod);
Py_DECREF(mod_list);
}
else
{
PyErr_Print();
printf("Unable to load component from %s\n", import);
}
PyGILState_Release(state);
#endif /* WITH_PYTHON */
return pc;
}
void free_component(PythonComponent *pc)
{
free_component_properties(&pc->properties);
MEM_freeN(pc);
}
void free_components(ListBase *lb)
{
PythonComponent *pc;
while (pc= lb->first) {
BLI_remlink(lb, pc);
free_component(pc);
}
}

View File

@@ -56,6 +56,7 @@
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_component_types.h"
#include "DNA_controller_types.h"
#include "DNA_constraint_types.h"
#include "DNA_effect_types.h"
@@ -4164,6 +4165,8 @@ static void direct_link_object(FileData *fd, Object *ob)
bSensor *sens;
bController *cont;
bActuator *act;
PythonComponent *pc;
ComponentProperty *cprop;
/* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */
ob->flag &= ~OB_FROMGROUP;
@@ -4324,6 +4327,20 @@ static void direct_link_object(FileData *fd, Object *ob)
act= act->next;
}
link_glob_list(fd, &ob->components);
pc= ob->components.first;
while(pc) {
link_glob_list(fd, &pc->properties);
cprop= pc->properties.first;
while(cprop) {
cprop->poin= newdataadr(fd, cprop->poin);
cprop= cprop->next;
}
pc= pc->next;
}
link_list(fd, &ob->hooks);
while (ob->hooks.first) {
ObHook *hook = ob->hooks.first;

View File

@@ -97,6 +97,7 @@ Any case: direct data is ALWAYS after the lib block
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_component_types.h"
#include "DNA_constraint_types.h"
#include "DNA_controller_types.h"
#include "DNA_genfile.h"
@@ -1096,6 +1097,36 @@ static void write_actuators(WriteData *wd, ListBase *lb)
}
}
static void write_component_properties(WriteData *wd, ListBase *lb)
{
ComponentProperty *cprop;
cprop= lb->first;
while(cprop) {
writestruct(wd, DATA, "ComponentProperty", 1, cprop);
if(cprop->poin)
writedata(wd, DATA, MEM_allocN_len(cprop->poin), cprop->poin);
cprop= cprop->next;
}
}
static void write_components(WriteData *wd, ListBase *lb)
{
PythonComponent *pc;
pc= lb->first;
while(pc) {
writestruct(wd, DATA, "PythonComponent", 1, pc);
write_component_properties(wd, &pc->properties);
pc= pc->next;
}
}
static void write_motionpath(WriteData *wd, bMotionPath *mpath)
{
/* sanity checks */
@@ -1321,6 +1352,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
write_sensors(wd, &ob->sensors);
write_controllers(wd, &ob->controllers);
write_actuators(wd, &ob->actuators);
write_components(wd, &ob->components);
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;

View File

@@ -36,6 +36,7 @@
#include "DNA_sensor_types.h"
#include "DNA_controller_types.h"
#include "DNA_actuator_types.h"
#include "DNA_component_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -43,6 +44,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_sca.h"
#include "BKE_pycomponent.h"
#include "ED_logic.h"
#include "ED_object.h"
@@ -57,6 +59,8 @@
#include "logic_intern.h"
#include <stdio.h> /* sprintf */
/* ************* Generic Operator Helpers ************* */
static int edit_sensor_poll(bContext *C)
{
@@ -687,6 +691,149 @@ static void LOGIC_OT_actuator_move(wmOperatorType *ot)
RNA_def_enum(ot->srna, "direction", logicbricks_move_direction, 1, "Direction", "Move Up or Down");
}
/* Component operators */
static int component_add_exec(bContext *C, wmOperator *op)
{
SpaceLogic *slogic= CTX_wm_space_logic(C);
PythonComponent *pycomp;
Object *ob = CTX_data_active_object(C);
char import[sizeof(slogic->import_string)];
if (!ob)
return OPERATOR_CANCELLED;
/* We always want to clear the import_string after this operator is called */
BLI_strncpy(import, slogic->import_string, sizeof(import));
BLI_strncpy(slogic->import_string, "", sizeof(slogic->import_string));
pycomp = new_component_from_import(import);
if(!pycomp)
return OPERATOR_CANCELLED;
BLI_addtail(&ob->components, pycomp);
WM_event_add_notifier(C, NC_LOGIC, NULL);
return OPERATOR_FINISHED;
}
void LOGIC_OT_component_add(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Add Component";
ot->description= "Add Component";
ot->idname= "LOGIC_OT_component_add";
/* api callbacks */
ot->exec= component_add_exec;
ot->poll= ED_operator_object_active_editable;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
static int component_remove_exec(bContext *C, wmOperator *op)
{
Object *ob= CTX_data_active_object(C);
PythonComponent *pc= NULL;
int index= RNA_int_get(op->ptr, "index");
if(!ob)
return OPERATOR_CANCELLED;
pc= BLI_findlink(&ob->components, index);
if(!pc)
return OPERATOR_CANCELLED;
BLI_remlink(&ob->components, pc);
free_component(pc);
WM_event_add_notifier(C,NC_LOGIC, NULL);
return OPERATOR_FINISHED;
}
void LOGIC_OT_component_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Remove Component";
ot->description= "Remove Component";
ot->idname= "LOGIC_OT_component_remove";
/* api callbacks */
ot->exec= component_remove_exec;
ot->poll= ED_operator_object_active_editable;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Component index to remove", 0, INT_MAX);
}
static int component_reload_exec(bContext *C, wmOperator *op)
{
Object *ob= CTX_data_active_object(C);
PythonComponent *pc= NULL, *new_pc=NULL, *prev_pc=NULL;
int index= RNA_int_get(op->ptr, "index");
char import[64];
if(!ob)
return OPERATOR_CANCELLED;
if (index > 0)
{
prev_pc= BLI_findlink(&ob->components, index-1);
pc = prev_pc->next;
}
else
{
/* pc is at the head */
pc = BLI_findlink(&ob->components, index);
}
if(!pc)
return OPERATOR_CANCELLED;
/* Try to create a new component */
sprintf(import, "%s.%s", pc->module, pc->name);
new_pc = new_component_from_import(import);
/* If creation failed, leave the old one along */
if(!new_pc)
return OPERATOR_CANCELLED;
/* Otherwise swap and destroy the old one */
BLI_remlink(&ob->components, pc);
free_component(pc);
if (prev_pc)
BLI_insertlink(&ob->components, prev_pc, new_pc);
else
BLI_addhead(&ob->components, new_pc);
return OPERATOR_FINISHED;
}
void LOGIC_OT_component_reload(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Reload Component";
ot->description= "Reload Component";
ot->idname= "LOGIC_OT_component_reload";
/* api callbacks */
ot->exec= component_reload_exec;
ot->poll= ED_operator_object_active_editable;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Component index to remove", 0, INT_MAX);
}
void ED_operatortypes_logic(void)
{
@@ -699,4 +846,8 @@ void ED_operatortypes_logic(void)
WM_operatortype_append(LOGIC_OT_actuator_remove);
WM_operatortype_append(LOGIC_OT_actuator_add);
WM_operatortype_append(LOGIC_OT_actuator_move);
WM_operatortype_append(LOGIC_OT_component_add);
WM_operatortype_append(LOGIC_OT_component_remove);
WM_operatortype_append(LOGIC_OT_component_reload);
}

View File

@@ -0,0 +1,28 @@
#ifndef DNA_COMPONENT_TYPES_H
#define DNA_COMPONENT_TYPES_H
#include "DNA_listBase.h"
typedef struct ComponentProperty {
struct ComponentProperty *next, *prev;
char name[32];
short type, pad;
int data;
void *poin, *poin2;
} ComponentProperty;
typedef struct PythonComponent {
struct PythonComponent *next, *prev;
ListBase properties;
char name[64];
char module[64];
} PythonComponent;
/* ComponentProperty.type */
#define CPROP_TYPE_INT 0
#define CPROP_TYPE_FLOAT 1
#define CPROP_TYPE_STRING 2
#define CPROP_TYPE_BOOLEAN 3
#define CPROP_TYPE_SET 4
#endif /*DNA_COMPONENT_TYPES_H*/

View File

@@ -201,6 +201,7 @@ typedef struct Object {
ListBase sensors;
ListBase controllers;
ListBase actuators;
ListBase components;
float bbsize[3];
short index; /* custom index, for renderpasses */

View File

@@ -430,6 +430,8 @@ typedef struct SpaceLogic {
short flag, scaflag;
int pad;
char import_string[64];
struct bGPdata *gpd; /* grease-pencil data */
} SpaceLogic;

View File

@@ -132,6 +132,7 @@ const char *includefiles[] = {
"DNA_anim_types.h",
"DNA_boid_types.h",
"DNA_smoke_types.h",
"DNA_component_types.h",
// empty string to indicate end of includefiles
""
@@ -1196,4 +1197,5 @@ int main(int argc, char ** argv)
#include "DNA_anim_types.h"
#include "DNA_boid_types.h"
#include "DNA_smoke_types.h"
#include "DNA_component_types.h"
/* end of list */

View File

@@ -376,6 +376,7 @@ extern StructRNA RNA_PropertyGroupItem;
extern StructRNA RNA_PropertySensor;
extern StructRNA RNA_PythonConstraint;
extern StructRNA RNA_PythonController;
extern StructRNA RNA_PythonComponent;
extern StructRNA RNA_RGBANodeSocket;
extern StructRNA RNA_RadarSensor;
extern StructRNA RNA_RandomSensor;

View File

@@ -68,6 +68,7 @@ set(DEFSRC
rna_particle.c
rna_pose.c
rna_property.c
rna_pycomponent.c
rna_render.c
rna_rna.c
rna_scene.c

View File

@@ -2453,6 +2453,7 @@ static RNAProcessItem PROCESS_ITEMS[]= {
{"rna_particle.c", NULL, RNA_def_particle},
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose},
{"rna_property.c", NULL, RNA_def_gameproperty},
{"rna_pycomponent.c", NULL, RNA_def_py_component},
{"rna_render.c", NULL, RNA_def_render},
{"rna_scene.c", "rna_scene_api.c", RNA_def_scene},
{"rna_screen.c", NULL, RNA_def_screen},

View File

@@ -159,6 +159,7 @@ void RNA_def_object_force(struct BlenderRNA *brna);
void RNA_def_packedfile(struct BlenderRNA *brna);
void RNA_def_particle(struct BlenderRNA *brna);
void RNA_def_pose(struct BlenderRNA *brna);
void RNA_def_py_component(struct BlenderRNA *brna);
void RNA_def_render(struct BlenderRNA *brna);
void RNA_def_rna(struct BlenderRNA *brna);
void RNA_def_scene(struct BlenderRNA *brna);

View File

@@ -38,6 +38,7 @@
#include "DNA_action_types.h"
#include "DNA_customdata_types.h"
#include "DNA_component_types.h"
#include "DNA_controller_types.h"
#include "DNA_group_types.h"
#include "DNA_material_types.h"
@@ -134,6 +135,7 @@ EnumPropertyItem object_type_curve_items[] = {
#include "BKE_armature.h"
#include "BKE_bullet.h"
#include "BKE_pycomponent.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -922,6 +924,16 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
}
}
static PythonComponent *rna_py_components_add(Object *ob, ReportList *reports, const char *path)
{
return NULL;
}
static void rna_py_components_remove(Object *ob, ReportList *reports, PythonComponent *pycomp)
{
}
static PointerRNA rna_Object_active_particle_system_get(PointerRNA *ptr)
{
Object *ob= (Object*)ptr->id.data;
@@ -1327,6 +1339,35 @@ static void rna_def_material_slot(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
}
/* object.components */
static void rna_def_py_components(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "Components");
srna= RNA_def_struct(brna, "Components", NULL);
RNA_def_struct_sdna(srna, "Object");
RNA_def_struct_ui_text(srna, "Components", "Collection of components");
func= RNA_def_function(srna, "add", "rna_py_components_add");
RNA_def_function_ui_description(func, "Add a component to an object");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm= RNA_def_string(func, "pypath", "", 64, "", "The import string for the component");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm= RNA_def_pointer(func, "component", "PythonComponent", "", "The newly created component");
RNA_def_function_return(func, parm);
func= RNA_def_function(srna, "remove", "rna_py_components_remove");
RNA_def_function_ui_description(func, "Remove a component from an object");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm= RNA_def_pointer(func, "component", "PythonComponent", "", "The component to remove");
RNA_def_property_flag(parm, PROP_REQUIRED|PROP_NEVER_NULL);
}
static void rna_def_object_game_settings(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1367,6 +1408,12 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "GameProperty"); /* rna_property.c */
RNA_def_property_ui_text(prop, "Properties", "Game engine properties");
prop= RNA_def_property(srna, "components", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "components", NULL);
RNA_def_property_struct_type(prop, "PythonComponent"); /* rna_pycomponent.c */
RNA_def_property_ui_text(prop, "Components", "Game engine components");
rna_def_py_components(brna, prop);
prop= RNA_def_property(srna, "show_sensors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_SHOWSENS);
RNA_def_property_ui_text(prop, "Show Sensors", "Shows sensors for this object in the user interface");

View File

@@ -0,0 +1,202 @@
/**
* $Id: rna_controller.c 32883 2010-11-05 07:35:21Z campbellbarton $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Blender Foundation (2008).
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdlib.h>
#include "RNA_define.h"
#include "rna_internal.h"
#include "DNA_component_types.h"
#include "DNA_property_types.h"
#include "WM_types.h"
#ifdef RNA_RUNTIME
//#include "BKE_pycomponent.h"
static StructRNA* rna_ComponentProperty_refine(struct PointerRNA *ptr)
{
ComponentProperty *cprop= (ComponentProperty*)ptr->data;
switch(cprop->type) {
case CPROP_TYPE_BOOLEAN:
return &RNA_ComponentBooleanProperty;
case CPROP_TYPE_INT:
return &RNA_ComponentIntProperty;
case CPROP_TYPE_FLOAT:
return &RNA_ComponentFloatProperty;
case CPROP_TYPE_STRING:
return &RNA_ComponentStringProperty;
case CPROP_TYPE_SET:
return &RNA_ComponentSetProperty;
default:
return &RNA_ComponentProperty;
}
}
static float rna_ComponentFloatProperty_value_get(PointerRNA *ptr)
{
ComponentProperty *cprop= (ComponentProperty*)(ptr->data);
return *(float*)(&cprop->data);
}
static void rna_ComponentFloatProperty_value_set(PointerRNA *ptr, float value)
{
ComponentProperty *cprop= (ComponentProperty*)(ptr->data);
*(float*)(&cprop->data)= value;
}
static int rna_ComponentSetProperty_get(struct PointerRNA *ptr)
{
ComponentProperty *cprop= (ComponentProperty*)(ptr->data);
return cprop->data;
}
static void rna_ComponentSetProperty_set(struct PointerRNA *ptr, int value)
{
ComponentProperty *cprop= (ComponentProperty*)(ptr->data);
cprop->data = value;
cprop->poin2 = (((EnumPropertyItem*)cprop->poin)+value)->identifier;
}
EnumPropertyItem *rna_ComponentSetProperty_itemf(bContext *C, PointerRNA *ptr, int *free)
{
ComponentProperty *cprop= (ComponentProperty*)(ptr->data);
*free = 0;
return (EnumPropertyItem*)cprop->poin;
}
#else
void rna_def_py_component(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
/* Python Component */
srna= RNA_def_struct(brna, "PythonComponent", NULL);
RNA_def_struct_sdna(srna, "PythonComponent");
RNA_def_struct_ui_text(srna, "Python Component", "");
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop= RNA_def_property(srna, "properties", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "properties", NULL);
RNA_def_property_struct_type(prop, "ComponentProperty");
RNA_def_property_ui_text(prop, "Properties", "Component properties");
}
void rna_def_py_component_property(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem empty_items[] = {
{0, "EMPTY", 0, "Empty", ""},
{0, NULL, 0, NULL, NULL}};
/* Base Python Component Property */
srna= RNA_def_struct(brna, "ComponentProperty", NULL);
RNA_def_struct_sdna(srna, "ComponentProperty");
RNA_def_struct_ui_text(srna, "Python Component Property", "A property of a Python Component");
RNA_def_struct_refine_func(srna, "rna_ComponentProperty_refine");
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, NC_LOGIC, NULL);
/* Boolean */
srna= RNA_def_struct(brna, "ComponentBooleanProperty", "ComponentProperty");
RNA_def_struct_sdna(srna, "ComponentProperty");
RNA_def_struct_ui_text(srna, "Python Component Boolean Property", "A boolean property of a Python Component");
prop= RNA_def_property(srna, "value", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "data", 1);
RNA_def_property_ui_text(prop, "Value", "Property value");
RNA_def_property_update(prop, NC_LOGIC, NULL);
/* Int */
srna= RNA_def_struct(brna, "ComponentIntProperty", "ComponentProperty");
RNA_def_struct_sdna(srna, "ComponentProperty");
RNA_def_struct_ui_text(srna, "Python Component Integer Property", "An integer property of a Python Component");
prop= RNA_def_property(srna, "value", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "data");
RNA_def_property_ui_text(prop, "Value", "Property value");
RNA_def_property_update(prop, NC_LOGIC, NULL);
/* Float */
srna= RNA_def_struct(brna, "ComponentFloatProperty", "ComponentProperty");
RNA_def_struct_sdna(srna, "ComponentProperty");
RNA_def_struct_ui_text(srna, "Python Component Float Property", "A float property of a Python Component");
prop= RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Value", "Property value");
RNA_def_property_float_funcs(prop, "rna_ComponentFloatProperty_value_get", "rna_ComponentFloatProperty_value_set", NULL);
RNA_def_property_update(prop, NC_LOGIC, NULL);
/* String */
srna= RNA_def_struct(brna, "ComponentStringProperty", "ComponentProperty");
RNA_def_struct_sdna(srna, "ComponentProperty");
RNA_def_struct_ui_text(srna, "Python Component String Property", "A string property of a Python Component");
prop= RNA_def_property(srna, "value", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "poin");
RNA_def_property_string_maxlength(prop, MAX_PROPSTRING);
RNA_def_property_ui_text(prop, "Value", "Property value");
RNA_def_property_update(prop, NC_LOGIC, NULL);
/* Set */
//#if 0
srna= RNA_def_struct(brna, "ComponentSetProperty", "ComponentProperty");
RNA_def_struct_sdna(srna, "ComponentProperty");
RNA_def_struct_ui_text(srna, "Python Component Set Property", "A set property of a Python Component");
prop= RNA_def_property(srna, "value", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, empty_items);
RNA_def_property_enum_funcs(prop, "rna_ComponentSetProperty_get", "rna_ComponentSetProperty_set", "rna_ComponentSetProperty_itemf");
RNA_def_property_enum_default(prop, 0);
//RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ComponentSetProperty_itemf");
RNA_def_property_ui_text(prop, "Value", "Property value");
RNA_def_property_update(prop, NC_LOGIC, NULL);
//#endif
}
void RNA_def_py_component(BlenderRNA *brna)
{
rna_def_py_component(brna);
rna_def_py_component_property(brna);
}
#endif /* RNA_RUNTIME */

View File

@@ -2506,6 +2506,12 @@ static void rna_def_space_logic(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SpaceLogic");
RNA_def_struct_ui_text(srna, "Space Logic Editor", "Logic editor space data");
/* Properties */
prop= RNA_def_property(srna, "import_string", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "import_string");
RNA_def_property_ui_text(prop, "Import String", "Import string used to find the component when adding a new component");
/* sensors */
prop= RNA_def_property(srna, "show_sensors_selected_objects", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_SEL);

View File

@@ -60,6 +60,8 @@
#include "../generic/blf_py_api.h"
#include "../mathutils/mathutils.h"
#include "../../../gameengine/Ketsji/KX_PythonInitTypes.h"
PyObject *bpy_package_py= NULL;
PyDoc_STRVAR(bpy_script_paths_doc,
@@ -251,6 +253,9 @@ void BPy_init_modules(void)
/* stand alone utility modules not related to blender directly */
IDProp_Init_Types(); /* not actually a submodule, just types */
/* Setup a dummy BGE module so we can import BGE classes for introspection */
initPyTypes();
PyRun_SimpleString("sys = __import__('sys');mod = sys.modules['bge'] = type(sys)('bge');mod.__dict__.update({'logic':'', 'render':'', 'events':'', 'constraints':'', 'types':__import__('GameTypes'), 'texture':''});");
mod= PyModule_New("_bpy");
/* add the module so we can import it */

View File

@@ -102,6 +102,8 @@
#include "KX_KetsjiEngine.h"
#include "KX_BlenderSceneConverter.h"
#include "KX_PyConstraintBinding.h"
/* This little block needed for linking to Blender... */
#ifdef WIN32
#include "BLI_winstuff.h"
@@ -2712,6 +2714,9 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
converter->RegisterWorldInfo(worldinfo);
kxscene->SetWorldInfo(worldinfo);
// Set the physics environment so KX_PythonComponent.start() can use bge.constraints
PHY_SetActiveEnvironment(kxscene->GetPhysicsEnvironment());
#define CONVERT_LOGIC
#ifdef CONVERT_LOGIC
// convert logic bricks, sensors, controllers and actuators
@@ -2742,12 +2747,13 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state);
}
// apply the initial state to controllers, only on the active objects as this registers the sensors
// also, to avoid another loop, we initialze components here
for ( i=0;i<objectlist->GetCount();i++)
{
KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i));
gameobj->ResetState();
gameobj->InitComponents();
}
#endif //CONVERT_LOGIC
logicbrick_conversionlist->Release();

View File

@@ -98,6 +98,7 @@ set(SRC
KX_PositionInterpolator.cpp
KX_PyConstraintBinding.cpp
KX_PyMath.cpp
KX_PythonComponent.cpp
KX_PythonInit.cpp
KX_PythonInitTypes.cpp
KX_PythonSeq.cpp
@@ -175,6 +176,7 @@ set(SRC
KX_PositionInterpolator.h
KX_PyConstraintBinding.h
KX_PyMath.h
KX_PythonComponent.h
KX_PythonInit.h
KX_PythonInitTypes.h
KX_PythonSeq.h

View File

@@ -45,11 +45,11 @@ typedef unsigned long uint_ptr;
#pragma warning( disable : 4786 )
#endif
#define KX_INERTIA_INFINITE 10000
#include "RAS_IPolygonMaterial.h"
#include "KX_BlenderMaterial.h"
#include "KX_GameObject.h"
#include "KX_PythonComponent.h"
#include "KX_Camera.h" // only for their ::Type
#include "KX_Light.h" // only for their ::Type
#include "KX_FontObject.h" // only for their ::Type
@@ -83,6 +83,9 @@ typedef unsigned long uint_ptr;
#include "BLI_math.h"
/* Component stuff */
#include "DNA_component_types.h"
static MT_Point3 dummy_point= MT_Point3(0.0, 0.0, 0.0);
static MT_Vector3 dummy_scaling = MT_Vector3(1.0, 1.0, 1.0);
static MT_Matrix3x3 dummy_orientation = MT_Matrix3x3( 1.0, 0.0, 0.0,
@@ -160,6 +163,15 @@ KX_GameObject::~KX_GameObject()
/* Py_CLEAR: Py_DECREF's and NULL's */
Py_CLEAR(m_attr_dict);
}
ComponentList::iterator it;
for (it=m_components.begin(); it != m_components.end(); ++it)
{
Py_DECREF(*it);
}
m_components.clear();
#endif // WITH_PYTHON
}
@@ -360,6 +372,8 @@ void KX_GameObject::ProcessReplica()
m_attr_dict= PyDict_Copy(m_attr_dict);
#endif
// Reinitialize any components
InitComponents();
}
static void setGraphicController_recursive(SG_Node* node)
@@ -1221,6 +1235,137 @@ CListValue* KX_GameObject::GetChildrenRecursive()
return list;
}
ComponentList &KX_GameObject::GetComponents()
{
return m_components;
}
#ifdef WITH_PYTHON
PyObject *arg_dict_from_component(PythonComponent *pc)
{
ComponentProperty *cprop;
PyObject *args= NULL, *value=NULL;
args = PyDict_New();
cprop = (ComponentProperty*)pc->properties.first;
while (cprop)
{
if (cprop->type == CPROP_TYPE_INT)
value = PyLong_FromLong(cprop->data);
else if (cprop->type == CPROP_TYPE_FLOAT)
value = PyFloat_FromDouble(*(float*)(&cprop->data));
else if (cprop->type == CPROP_TYPE_BOOLEAN)
value = PyBool_FromLong(cprop->data);
else if (cprop->type == CPROP_TYPE_STRING)
value = PyUnicode_FromString((char*)cprop->poin);
else if (cprop->type == CPROP_TYPE_SET)
value = PyUnicode_FromString((char*)cprop->poin2);
else
{
cprop= cprop->next;
continue;
}
PyDict_SetItemString(args, cprop->name, value);
cprop= cprop->next;
}
return args;
}
#endif /* WITH_PYTHON */
void KX_GameObject::InitComponents()
{
#ifdef WITH_PYTHON
PythonComponent *pc = (PythonComponent*)GetBlenderObject()->components.first;
PyObject *arg_dict=NULL, *args=NULL, *mod=NULL, *cls=NULL, *pycomp;
while (pc)
{
// Make sure to clean out anything from previous loops
Py_XDECREF(args);
Py_XDECREF(arg_dict);
Py_XDECREF(mod);
Py_XDECREF(cls);
args = mod = cls = NULL;
// Grab the module
mod = PyImport_ImportModule(pc->module);
if (mod == NULL)
{
if (PyErr_Occurred()) PyErr_Print();
printf("Coulding import the module '%s'\n", pc->module);
pc = pc->next;
continue;
}
// Clear the module from sys.modules
//PyDict_DelItemString(PyImport_GetModuleDict(), pc->module);
// Grab the class object
cls = PyObject_GetAttrString(mod, pc->name);
if (cls == NULL)
{
if (PyErr_Occurred()) PyErr_Print();
printf("Python module found, but failed to find the compoent '%s'\n", pc->name);
pc = pc->next;
continue;
}
// Lastly make sure we have a class and it's an appropriate sub type
if (!PyType_Check(cls) || !PyObject_IsSubclass(cls, (PyObject*)&KX_PythonComponent::Type))
{
printf("%s.%s is not a KX_PythonComponent subclass\n", pc->module, pc->name);
pc = pc->next;
continue;
}
// Every thing checks out, now generate the args dictionary and init the component
arg_dict = arg_dict_from_component(pc);
args = PyTuple_New(1);
PyTuple_SetItem(args, 0, GetProxy());
pycomp = PyObject_Call(cls, args, NULL);
PyObject_CallMethod(pycomp, "start", "O", arg_dict);
if (PyErr_Occurred())
{
// The component is invalid, drop it
PyErr_Print();
Py_XDECREF(pycomp);
}
else
m_components.push_back(pycomp);
pc = pc->next;
}
Py_XDECREF(args);
Py_XDECREF(arg_dict);
Py_XDECREF(mod);
Py_XDECREF(cls);
#endif // WITH_PYTHON
}
void KX_GameObject::UpdateComponents()
{
#ifdef WITH_PYTHON
for (size_t i=0; i<m_components.size(); ++i)
{
if (!PyObject_CallMethod(m_components[i], "update", ""))
PyErr_Print();
}
#endif // WITH_PYTHON
}
/* ---------------------------------------------------------------------
* Some stuff taken from the header
* --------------------------------------------------------------------- */
@@ -1536,6 +1681,7 @@ PyAttributeDef KX_GameObject::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive),
KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict),
KX_PYATTRIBUTE_RW_FUNCTION("color", KX_GameObject, pyattr_get_obcolor, pyattr_set_obcolor),
KX_PYATTRIBUTE_RO_FUNCTION("components", KX_GameObject, pyattr_get_components),
/* Experemental, dont rely on these yet */
KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors),
@@ -2220,6 +2366,11 @@ int KX_GameObject::pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *at
return PY_SET_ATTR_SUCCESS;
}
PyObject* KX_GameObject::pyattr_get_components(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_COMPONENTS);
}
/* These are experimental! */
PyObject* KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
@@ -3029,7 +3180,7 @@ bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py
}
if (PyUnicode_Check(value)) {
*object = (KX_GameObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) ));
*object = (KX_GameObject*)KX_GetActiveScene()->GetLogicManager()->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) ));
if (*object) {
return true;

View File

@@ -74,6 +74,8 @@ bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py
void KX_GameObject_Mathutils_Callback_Init(void);
#endif
typedef std::vector<PyObject*> ComponentList;
/**
* KX_GameObject is the main class for dynamic objects.
*/
@@ -112,6 +114,10 @@ protected:
SG_Node* m_pSGNode;
MT_CmMatrix4x4 m_OpenGL_4x4Matrix;
#ifdef WITH_PYTHON
ComponentList m_components;
#endif
public:
bool m_isDeformable;
@@ -801,6 +807,21 @@ public:
CListValue* GetChildren();
CListValue* GetChildrenRecursive();
/**
* Returns the component list
*/
ComponentList &GetComponents();
/**
* Initializes the components
*/
void InitComponents();
/**
* Updates the components
*/
void UpdateComponents();
#ifdef WITH_PYTHON
/**
* @section Python interface functions.
@@ -901,6 +922,7 @@ public:
static PyObject* pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_obcolor(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_components(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
/* Experemental! */
static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);

View File

@@ -0,0 +1,162 @@
/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef DISABLE_PYTHON
#include "KX_PythonComponent.h"
#include "KX_GameObject.h"
#include "BLI_string.h"
/* ------------------------------------------------------------------------- */
/* Native functions */
/* ------------------------------------------------------------------------- */
KX_PythonComponent::KX_PythonComponent(char *name)
: PyObjectPlus(),
m_gameobj(NULL),
m_name(name)
{
}
KX_PythonComponent::~KX_PythonComponent()
{
}
STR_String& KX_PythonComponent::GetName()
{
return m_name;
}
KX_GameObject* KX_PythonComponent::GetGameobject()
{
return m_gameobj;
}
void KX_PythonComponent::SetGameobject(KX_GameObject *gameobj)
{
m_gameobj = gameobj;
}
/* ------------------------------------------------------------------------- */
/* Python functions */
/* ------------------------------------------------------------------------- */
PyObject *KX_PythonComponent::py_component_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObjectPlus_Proxy *self;
char name[64];
self = (PyObjectPlus_Proxy*)type->tp_alloc(type, 0);
if (self)
{
BLI_strncpy(name, Py_TYPE(self)->tp_name, sizeof(name));
self->ptr = NULL;
self->ref = new KX_PythonComponent(name);
self->py_owns = true;
self->py_ref = true;
}
return (PyObject*)self;
}
int KX_PythonComponent::py_component_init(PyObjectPlus_Proxy *self, PyObject *args, PyObject *kwds)
{
KX_GameObject *gameobj;
KX_PythonComponent *kxpycomp;
PyObject *pyobj;
if (!PyArg_ParseTuple(args, "O", &pyobj))
return -1;
if (!PyObject_IsInstance(pyobj, (PyObject*)&KX_GameObject::Type))
{
PyErr_SetString(PyExc_TypeError, "expected a KX_GameObject for first argument");
return -1;
}
gameobj = static_cast<KX_GameObject*>(BGE_PROXY_REF(pyobj));
kxpycomp = static_cast<KX_PythonComponent*>(BGE_PROXY_REF(self));
kxpycomp->SetGameobject(gameobj);
return 0;
}
/* Integration hooks ------------------------------------------------------- */
PyTypeObject KX_PythonComponent::Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"KX_PythonComponent",
sizeof(PyObjectPlus_Proxy),
0,
py_base_dealloc,
0,
0,
0,
0,
py_base_repr,
0,0,0,0,0,0,0,0,0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0,0,0,0,0,0,0,
Methods,
0,
0,
&PyObjectPlus::Type,
0,0,0,0,
(initproc)py_component_init,
0,
py_component_new
};
PyMethodDef KX_PythonComponent::Methods[] = {
KX_PYMETHODTABLE_O(KX_PythonComponent, start),
{NULL,NULL} //Sentinel
};
PyAttributeDef KX_PythonComponent::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("object", KX_PythonComponent, pyattr_get_object),
{ NULL } //Sentinel
};
PyObject* KX_PythonComponent::pyattr_get_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_PythonComponent* self= static_cast<KX_PythonComponent*>(self_v);
KX_GameObject *gameobj = self->GetGameobject();
if (gameobj)
return gameobj->GetProxy();
else
Py_RETURN_NONE;
}
KX_PYMETHODDEF_DOC_O(KX_PythonComponent, start,
"start(args)\n"
"initializes the component")
{
printf("base start\n");
// We leave this empty, derived classes should define their own if they need it
Py_RETURN_NONE;
}
#endif

View File

@@ -0,0 +1,60 @@
/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __KX_PYCOMPONENT
#define __KX_PYCOMPONENT
#ifndef DISABLE_PYTHON
#include "PyObjectPlus.h"
class KX_PythonComponent : public PyObjectPlus
{
Py_Header;
private:
// member vars
class KX_GameObject *m_gameobj;
STR_String m_name;
public:
KX_PythonComponent(char *name);
virtual ~KX_PythonComponent();
STR_String& GetName();
class KX_GameObject *GetGameobject();
void SetGameobject(class KX_GameObject*);
static PyObject *py_component_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static int py_component_init(PyObjectPlus_Proxy *self, PyObject *args, PyObject *kwds);
// Methods
KX_PYMETHOD_DOC_O(KX_PythonComponent, start);
// Attributes
static PyObject* pyattr_get_object(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
};
#endif //ndef DISABLE_PYTHON
#endif //__KX_PYCOMPONENT

View File

@@ -63,6 +63,7 @@
#include "KX_PolyProxy.h"
#include "KX_PolygonMaterial.h"
#include "KX_PythonSeq.h"
#include "KX_PythonComponent.h"
#include "KX_SCA_AddObjectActuator.h"
#include "KX_SCA_EndObjectActuator.h"
#include "KX_SCA_ReplaceMeshActuator.h"
@@ -164,7 +165,7 @@ static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *a
#define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, NULL, i)
#define PyType_Ready_AttrPtr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, n::AttributesPtr, i)
void initPyTypes(void)
extern "C" void initPyTypes(void)
{
/*
@@ -210,6 +211,7 @@ void initPyTypes(void)
PyType_Ready_Attr(dict, KX_PhysicsObjectWrapper, init_getset);
PyType_Ready_Attr(dict, KX_PolyProxy, init_getset);
PyType_Ready_Attr(dict, KX_PolygonMaterial, init_getset);
PyType_Ready_Attr(dict, KX_PythonComponent, init_getset);
PyType_Ready_Attr(dict, KX_RadarSensor, init_getset);
PyType_Ready_Attr(dict, KX_RaySensor, init_getset);
PyType_Ready_Attr(dict, KX_SCA_AddObjectActuator, init_getset);

View File

@@ -35,7 +35,18 @@
#define _adr_py_init_types_h_ // even if multiply included
#ifdef WITH_PYTHON
#ifdef __cplusplus
extern "C"
{
#endif
void initPyTypes(void);
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@@ -41,6 +41,7 @@
#include "SCA_ISensor.h"
#include "SCA_IController.h"
#include "SCA_IActuator.h"
#include "KX_PythonComponent.h"
PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
@@ -91,6 +92,8 @@ static Py_ssize_t KX_PythonSeq_len( PyObject * self )
return ((KX_GameObject *)self_plus)->GetControllers().size();
case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
return ((KX_GameObject *)self_plus)->GetActuators().size();
case KX_PYGENSEQ_OB_TYPE_COMPONENTS:
return ((KX_GameObject *)self_plus)->GetComponents().size();
case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
return ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
case KX_PYGENSEQ_OB_TYPE_CHANNELS:
@@ -162,6 +165,17 @@ static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index)
}
return linkedactuators[index]->GetProxy();
}
case KX_PYGENSEQ_OB_TYPE_COMPONENTS:
{
ComponentList& components= ((KX_GameObject *)self_plus)->GetComponents();
if(index<0) index += components.size();
if(index<0 || index>= components.size()) {
PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
return NULL;
}
Py_INCREF(components[index]);
return components[index];
}
case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
{
int nb_constraint = ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
@@ -252,6 +266,17 @@ static PyObjectPlus * KX_PythonSeq_subscript__internal(PyObject *self, char *key
}
break;
}
case KX_PYGENSEQ_OB_TYPE_COMPONENTS:
{
ComponentList& components= ((KX_GameObject *)self_plus)->GetComponents();
PyObject *comp;
for (unsigned int index=0;index<components.size();index++) {
comp = components[index];
if (strcmp(Py_TYPE(comp)->tp_name, key) == 0)
return (PyObjectPlus*)comp;
}
break;
}
case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
{
return ((BL_ArmatureObject*)self_plus)->GetConstraint(key);
@@ -283,6 +308,11 @@ static PyObject * KX_PythonSeq_subscript(PyObject * self, PyObject *key)
PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name);
if(ret) {
if (((KX_PythonSeq *)self)->type == KX_PYGENSEQ_OB_TYPE_COMPONENTS)
{
Py_INCREF((PyObject*)ret);
return (PyObject*)ret;
}
return ret->GetProxy();
} else {
PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
@@ -326,7 +356,14 @@ PyObject* KX_PythonSeq_get(PyObject * self, PyObject *args)
return NULL;
if((ret_plus = KX_PythonSeq_subscript__internal(self, key)))
{
if (((KX_PythonSeq*)self)->type == KX_PYGENSEQ_OB_TYPE_COMPONENTS)
{
Py_INCREF((PyObject*)ret_plus);
return (PyObject*)ret_plus;
}
return ret_plus->GetProxy();
}
Py_INCREF(def);
return def;

View File

@@ -46,6 +46,7 @@ enum KX_PYGENSEQ_TYPE {
KX_PYGENSEQ_OB_TYPE_SENSORS,
KX_PYGENSEQ_OB_TYPE_CONTROLLERS,
KX_PYGENSEQ_OB_TYPE_ACTUATORS,
KX_PYGENSEQ_OB_TYPE_COMPONENTS,
KX_PYGENSEQ_OB_TYPE_CONSTRAINTS,
KX_PYGENSEQ_OB_TYPE_CHANNELS,
};

View File

@@ -1506,6 +1506,9 @@ void KX_Scene::LogicBeginFrame(double curtime)
void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
{
// Update object components
for (int i=0; i<m_objectlist->GetCount(); ++i)
((KX_GameObject*)m_objectlist->GetValue(i))->UpdateComponents();
m_logicmgr->UpdateFrame(curtime, frame);
}

View File

@@ -1,3 +1,99 @@
<<<<<<< .working
# $Id$
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Jacques Beaurain.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
../../../source/gameengine/Ketsji
../../../source/gameengine/Expressions
../../../source/gameengine/GameLogic
../../../source/gameengine/SceneGraph
../../../source/gameengine/Rasterizer
../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
../../../source/gameengine/BlenderRoutines
../../../source/blender/blenlib
../../../source/blender/blenkernel
../../../source/blender/makesdna
../../../source/blender/editors/include
../../../source/blender/imbuf
../../../source/blender/python
../../../source/blender/python/generic
../../../source/blender/gpu
../../../intern/container
../../../intern/string
../../../intern/moto/include
../../../intern/guardedalloc
${GLEW_INCLUDE_PATH}
)
set(SRC
Exception.cpp
FilterBase.cpp
FilterBlueScreen.cpp
FilterColor.cpp
FilterNormal.cpp
FilterSource.cpp
ImageBase.cpp
ImageBuff.cpp
ImageMix.cpp
ImageRender.cpp
ImageViewport.cpp
PyTypeList.cpp
Texture.cpp
VideoBase.cpp
VideoFFmpeg.cpp
blendVideoTex.cpp
BlendType.h
Common.h
Exception.h
FilterBase.h
FilterBlueScreen.h
FilterColor.h
FilterNormal.h
FilterSource.h
ImageBase.h
ImageBuff.h
ImageMix.h
ImageRender.h
ImageViewport.h
PyTypeList.h
Texture.h
VideoBase.h
VideoFFmpeg.h
)
if(WITH_CODEC_FFMPEG)
set(INC ${INC} ${FFMPEG_INC} ${PTHREADS_INC})
add_definitions(-DWITH_FFMPEG)
add_definitions(-D__STDC_CONSTANT_MACROS)
endif()
blender_add_lib(ge_videotex "${SRC}" "${INC}")
=======
# $Id$
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -99,3 +195,4 @@ if(WITH_CODEC_FFMPEG)
endif()
blender_add_lib(ge_videotex "${SRC}" "${INC}" "${INC_SYS}")
>>>>>>> .merge-right.r38806