2014-07-08 182 views
1

在大多数情况下,我很高兴通过SWIG处理数据的方式,但是我遇到问题并且无法在文档中找到答案。SWIG扩展变量

的所有IM使用痛饮和Lua的第一和具有以下结构包裹:

typedef struct 
{ 
    %mutable; 
     float x,y,z; 
    ... 
    ... 

} Vector3; 


typedef struct 
{ 
    ... 
    ... 

    %immutable; 
     Vector3 gravity; 

    ... 
    ... 

    %extend 
    { 
     void SetGravity(Vector3 gravity) 
     { 
      WorldSetGravity($self,gravity); 
     } 
    }; 
} World; 

正如你所看到的严重性XYZ可以通过调用SetGravity功能受到影响,它的工作很大。

然而,为了更直观,更易于使用,我想给的机会,用户设置组件(XY或Z)独立,如:

world.gravity.x=-10; 

但我需要调用在后台SetGravity中,以便能够将适当的值发送给物理引擎(未暴露给Lua)。

我想知道是否有方法%extend变量,这将允许我调用world.gravity.xy or z调用SetGravity

或者能够为每个组件实现我自己的wrap功能版本,如:_wrap_World_gravity_set_x这将分配我在后台调用SetGravity

+1

如果你想'world.gravity.x'是可变的,那么为什么'world.gravity'标记为不可变?如果一个对象被标记为不可变,那么你不应该设计使它的一部分变为可变的黑客。有些事情是不对的,也许描述你想如何使用重力和约束。 – Schollii

+0

需要注意的一点是:如果您展示说明问题所需的最少但仍然完整的代码量,则可以更轻松地回答这样的问题。当我开始回答时,我不得不重新发明你已经得到的东西。一般来说,如果你坚持这一点,你会得到更多更好的答案。 – Flexo

回答

1

首先值得注意的是,这个问题比使用%extend制作一个“虚拟”成员变量更难,当有人修改它时会自动调用一个额外的函数。这是因为你想要它是另一个类的成员来改变行为。

我可以看到几个基本的方法,你可以拿得到这个行为:

  1. 注入目标脚本语言的一些额外的代码勾集
  2. 注入一些额外的东西在痛饮接口透明地将World中的Vector3转换为仍然看起来和感觉相同的东西,但具有您想要的行为。
  3. Vector3的memberin类型映射注入一些额外的代码,该代码检查从中调用的上下文并相应地修改行为。

这些#2是我首选的解决方案,因为#1是特定语言(我不知道Lua的不够好做!)和#3从软件工程的角度看感觉很脏。

为了实现#2我做了以下内容:

%module test 

%{ 
#include "test.h" 
%} 

typedef struct 
{ 
    %mutable; 
    float x,y,z; 
} Vector3; 

%nodefaultctor Vector3Gravity; 

%{ 
// Inside C this is just a typedef! 
typedef Vector3 Vector3Gravity; 
// But we have magic for sets/gets now: 
#define MEMBER_VAR(ct,vt,rt,n)          \ 
    SWIGINTERN void ct##_##n##_set(ct *self, const vt val) {   \ 
    self->n = val;             \ 
    /* Need to find a way to lookup world here */     \ 
    WorldSetGravity(world, self);         \ 
    }                 \ 
    SWIGINTERN vt ct##_##n##_get(const ct *self) { return self->n; } 

MEMBER_VAR(Vector3Gravity, float, Vector3, x) 
MEMBER_VAR(Vector3Gravity, float, Vector3, y) 
MEMBER_VAR(Vector3Gravity, float, Vector3, z) 
%} 

// Inside SWIG Vector3Gravity is a distinct type: 
typedef struct 
{ 
    %mutable; 
    %extend { 
     float x,y,z; 
    } 
} Vector3Gravity; 


%typemap(memberin,noblock=1) Vector3Gravity gravity %{ 
    $1 = *((const Vector3*)$input); 
    WorldSetGravity($self, $1); // This gets expanded to automatically make this call 
%} 

typedef struct 
{ 
    // This is a blatant lie! 
    Vector3Gravity gravity; 
} World; 

本质上讲,我们是在撒谎,并声称世界gravity成员是一个“特殊”的类型,而实际上它只是一个Vector3。我们特殊的类型有两个明显的特点。首先设置/获取其成员由我们实现一个C代码。其次,当我们设置这个成员时,我们会自动进行额外的调用,而不仅仅是传递值。

有两件事情可能是从这个例子里缺了,你可能想:

  1. 透明转换从Vector3GravityVector3。 (因为它的立场除了重力集以外的任何东西都会拒绝接受Vector3Gravity实例)。如果需要,可以通过使用SWIG/Lua的重载解析机制来实现透明。
  2. 对于Vector3Gravity的设置者,我们不知道这个引力属于哪个世界。

    我们可以通过几种方式解决这个问题,最简单的就是每次创建一个Vector3Gravity就隐式设置一个静态指针。如果只有一个世界,这是有道理的。

    另一种方法是将Vector3Gravity实例的全局地图用于自动维护的世界。

    最后,而是采用了typedefVector3Gravity类型,我们可以做一个真正独特的类型,与兼容的布局,但添加到World它来自一个指针。虽然这是更多的工作。

+0

Humm ...在某些时候,我正在玩类似的东西,通过创建一个“假的”Gravity结构来保存XYZ,并在每个组件被调用时扩展它以便SetGravity是触发器。它可以工作,但问题是重力不再是Vector3,不能使用任何Vector3功能。有没有一种方法来保持Vector3的重力,并且只有%扩展了XYZ set方法才能触发SetGravity?当然,在引力的情况下,它不会有多大意义,但在ie:Object.location.xyz的情况下,它会调用ie:ObjectSetTransform它会... – user3192607

+1

因此,您需要一种机制,通过这种机制,所有矢量可以关联一些其他功能的变化。我将不得不多想一想。我会做的是让矢量不可变(然后通过总是创建新的来改变),然后使用我的示例的成员部分将修改修改到正确位置的变量。 – Flexo

+0

@Flexo:Im与这个用户有几乎相同的问题。你介意发表一个最后一种方法的例子(你必须考虑更多的方法) – McBob