599 lines
16 KiB
C
599 lines
16 KiB
C
/**
|
|
* $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* Contributor(s): Jiri Hnidek.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#ifdef WITH_VERSE
|
|
|
|
#include <string.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "mydevice.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_listBase.h"
|
|
|
|
#include "BLI_dynamiclist.h"
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_editVert.h"
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "BIF_verse.h"
|
|
#include "BIF_space.h"
|
|
#include "BIF_editmesh.h"
|
|
#include "BIF_drawimage.h"
|
|
#include "BIF_editmode_undo.h"
|
|
#include "BIF_toolbox.h"
|
|
|
|
#include "BKE_verse.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_utildefines.h"
|
|
#include "BKE_depsgraph.h"
|
|
#include "BKE_image.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_DerivedMesh.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_displist.h"
|
|
|
|
#include "BDR_editobject.h"
|
|
|
|
#include "verse.h"
|
|
|
|
/* button callback function, it test object name and send new name to verse server */
|
|
void test_and_send_idbutton_cb(void *obj, void *ob_name)
|
|
{
|
|
struct Object *ob = (Object*)obj;
|
|
char *name= (char*)ob_name;
|
|
|
|
test_idbutton(name+2);
|
|
|
|
if(ob->vnode) verse_send_node_name_set(((VNode*)ob->vnode)->id, name+2);
|
|
}
|
|
|
|
/*
|
|
* duplicate verse object nodes
|
|
*/
|
|
void b_verse_duplicate_object(VerseSession *session, Object *ob, Object *n_ob)
|
|
{
|
|
struct VNode *obj_vnode;
|
|
|
|
if(!session) return;
|
|
|
|
if(!(session->flag & VERSE_CONNECTED)) return;
|
|
|
|
/* create "my" new object VerseNode */
|
|
obj_vnode= create_verse_node(session, -1 , V_NT_OBJECT, VN_OWNER_MINE);
|
|
/* create object data */
|
|
obj_vnode->data = create_object_data();
|
|
|
|
/* set up name of VerseNode */
|
|
obj_vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(n_ob->id.name)-1), "object node name");
|
|
obj_vnode->name[0] = '\0';
|
|
strcat(obj_vnode->name, n_ob->id.name+2);
|
|
|
|
/* set up object node transformation */
|
|
VECCOPY(((VObjectData*)obj_vnode->data)->pos, n_ob->loc);
|
|
EulToQuat(n_ob->rot, ((VObjectData*)obj_vnode->data)->quat);
|
|
VECCOPY(((VObjectData*)obj_vnode->data)->scale, n_ob->size);
|
|
|
|
/* set up pointers between Object and VerseNode */
|
|
((VObjectData*)obj_vnode->data)->object = (void*)n_ob;
|
|
n_ob->vnode = (void*)obj_vnode;
|
|
|
|
/* add node to sending queue */
|
|
add_item_to_send_queue(&(session->queue), obj_vnode, VERSE_NODE);
|
|
|
|
if(ob->type==OB_MESH) {
|
|
struct Mesh *me;
|
|
struct VNode *geom_vnode;
|
|
struct VLink *vlink;
|
|
|
|
/* when current mesh already shared at verse server, then only set up link
|
|
* between object node and geometry node */
|
|
if(ob->data == n_ob->data) {
|
|
geom_vnode = (VNode*)((Mesh*)ob->data)->vnode;
|
|
}
|
|
else {
|
|
geom_vnode = create_geom_vnode_from_geom_vnode((VNode*)((Mesh*)ob->data)->vnode);
|
|
me = (Mesh*)n_ob->data;
|
|
me->vnode = (void*)geom_vnode;
|
|
((VGeomData*)geom_vnode->data)->mesh = (void*)me;
|
|
|
|
}
|
|
/* create new link between VereseNodes */
|
|
vlink = create_verse_link(session, obj_vnode, geom_vnode, -1, -1, "geometry");
|
|
/* "send" link to verse server */
|
|
add_item_to_send_queue(&(((VObjectData*)obj_vnode->data)->queue), vlink, VERSE_LINK);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* temp hack: this function push mesh objects (edit mode only) to verse server
|
|
*/
|
|
void b_verse_push_object(VerseSession *session, Object *ob)
|
|
{
|
|
struct VNode *obj_vnode;
|
|
|
|
if(!session) return;
|
|
|
|
if(!(session->flag & VERSE_CONNECTED)) return;
|
|
|
|
/* create "my" new object VerseNode */
|
|
obj_vnode= create_verse_node(session, -1 , V_NT_OBJECT, VN_OWNER_MINE);
|
|
/* create object data */
|
|
obj_vnode->data = create_object_data();
|
|
|
|
/* set up name of VerseNode */
|
|
obj_vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(ob->id.name)-1), "object node name");
|
|
obj_vnode->name[0] = '\0';
|
|
strcat(obj_vnode->name, ob->id.name+2);
|
|
|
|
/* set up object node transformation */
|
|
VECCOPY(((VObjectData*)obj_vnode->data)->pos, ob->loc);
|
|
EulToQuat(ob->rot, ((VObjectData*)obj_vnode->data)->quat);
|
|
VECCOPY(((VObjectData*)obj_vnode->data)->scale, ob->size);
|
|
|
|
/* set up pointers between Object and VerseNode */
|
|
((VObjectData*)obj_vnode->data)->object = (void*)ob;
|
|
ob->vnode = (void*)obj_vnode;
|
|
|
|
/* add node to sending queue */
|
|
add_item_to_send_queue(&(session->queue), obj_vnode, VERSE_NODE);
|
|
|
|
if(ob->type==OB_MESH) {
|
|
struct VNode *geom_vnode;
|
|
struct VLink *vlink;
|
|
|
|
if(G.obedit)
|
|
geom_vnode = create_geom_vnode_data_from_editmesh(session, G.editMesh);
|
|
else
|
|
geom_vnode = create_geom_vnode_data_from_mesh(session, get_mesh(ob));
|
|
|
|
if(geom_vnode) {
|
|
/* create new link between VereseNodes */
|
|
vlink = create_verse_link(session, obj_vnode, geom_vnode, -1, -1, "geometry");
|
|
/* send link to verse server */
|
|
add_item_to_send_queue(&(((VObjectData*)obj_vnode->data)->queue), vlink, VERSE_LINK);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* creates blender object from verse object node and it
|
|
* will create links between them
|
|
*/
|
|
Object *create_object_from_verse_node(VNode *vnode)
|
|
{
|
|
struct Object *ob;
|
|
|
|
if(vnode->type != V_NT_OBJECT) return NULL;
|
|
|
|
/* create new object*/
|
|
ob = add_object(OB_MESH);
|
|
/* set up bindings between verse node and blender object */
|
|
ob->vnode = (void*)vnode;
|
|
((VObjectData*)vnode->data)->object = (void*)ob;
|
|
/* set up flags */
|
|
((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY;
|
|
((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY;
|
|
((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY;
|
|
/* copy name from verse node to object */
|
|
if(vnode->name) {
|
|
char *str;
|
|
str = (char*)MEM_mallocN(sizeof(char)*(strlen(vnode->name)+3), "temp object name");
|
|
str[0] = '\0';
|
|
strcat(str, "OB");
|
|
strcat(str, vnode->name);
|
|
strncpy(ob->id.name, str, 23);
|
|
MEM_freeN(str);
|
|
}
|
|
/* subscribe for object transformation */
|
|
verse_send_o_transform_subscribe(vnode->id, 0);
|
|
|
|
return ob;
|
|
}
|
|
|
|
/*
|
|
* Create blender object-mesh from verse object node, verse geometry node,
|
|
*/
|
|
void b_verse_pop_node(VNode *vnode)
|
|
{
|
|
if((!vnode) || (!(vnode->data))) return;
|
|
|
|
if(vnode->type==V_NT_OBJECT) {
|
|
struct VNode *geom_node=NULL;
|
|
struct VLink *vlink;
|
|
struct VLayer *vlayer;
|
|
struct Object *ob;
|
|
struct Mesh *me;
|
|
|
|
if(((VObjectData*)vnode->data)->object) {
|
|
printf("\tError: already subscribed to object node.\n");
|
|
return;
|
|
}
|
|
|
|
vlink = ((VObjectData*)vnode->data)->links.lb.first;
|
|
|
|
/* try to find geometry node */
|
|
while(vlink) {
|
|
if(vlink->target && vlink->target->type==V_NT_GEOMETRY){
|
|
geom_node = vlink->target;
|
|
break;
|
|
}
|
|
vlink = vlink->next;
|
|
}
|
|
|
|
/* we are not interested now in avatars node, etc. (vnodes without
|
|
* links at geometry node) */
|
|
if(!geom_node) return;
|
|
|
|
/* subscribe to all verse geometry layer */
|
|
vlayer = ((VGeomData*)geom_node->data)->layers.lb.first;
|
|
while(vlayer) {
|
|
verse_send_g_layer_subscribe(geom_node->id, vlayer->id, 0);
|
|
vlayer = vlayer->next;
|
|
}
|
|
|
|
ob = create_object_from_verse_node(vnode);
|
|
|
|
me = create_mesh_from_geom_node(geom_node);
|
|
|
|
/* set up bindings between object and mesh */
|
|
if(ob && me) ob->data = me;
|
|
}
|
|
else if(vnode->type==V_NT_BITMAP) {
|
|
struct VBitmapData *vbitmap;
|
|
struct VBitmapLayer *vblayer;
|
|
float color[] = {0, 0, 0, 1};
|
|
|
|
vbitmap = (VBitmapData*)vnode->data;
|
|
|
|
vblayer = vbitmap->layers.lb.first;
|
|
|
|
while(vblayer) {
|
|
if(!(vblayer->flag & VBLAYER_SUBSCRIBED)) {
|
|
/* 0 means level of subscription (full resolution) */
|
|
verse_send_b_layer_subscribe(vnode->id, vblayer->id, 0);
|
|
vblayer->flag |= VBLAYER_SUBSCRIBED;
|
|
}
|
|
vblayer = vblayer->next;
|
|
}
|
|
|
|
if(vbitmap->image) {
|
|
printf("\tError: already subscribed to image node.\n");
|
|
return;
|
|
}
|
|
|
|
vbitmap->image = (void*)BKE_add_image_size(
|
|
vbitmap->width,
|
|
vbitmap->height,
|
|
vnode->name,
|
|
0,
|
|
0,
|
|
color);
|
|
((Image*)vbitmap->image)->vnode = (void*)vnode;
|
|
sync_blender_image_with_verse_bitmap_node(vnode);
|
|
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* this function will unsubscribe object node from transformation, but it will
|
|
* keep all tags and links at other nodes ... user could subscribe to this node
|
|
* again in future
|
|
*/
|
|
void unsubscribe_from_obj_node(VNode *vnode)
|
|
{
|
|
struct VerseSession *session = vnode->session;
|
|
struct VLink *vlink;
|
|
|
|
if(vnode->type != V_NT_OBJECT) return;
|
|
|
|
/* unsubscribe from receiving changes of transformation matrix */
|
|
if(session->flag & VERSE_CONNECTED)
|
|
verse_send_o_transform_unsubscribe(vnode->id, 0);
|
|
|
|
/* we have to reinitialize object node transformation */
|
|
((VObjectData*)vnode->data)->pos[0] = 0.0f;
|
|
((VObjectData*)vnode->data)->pos[1] = 0.0f;
|
|
((VObjectData*)vnode->data)->pos[2] = 0.0f;
|
|
|
|
((VObjectData*)vnode->data)->quat[0] = 0.0f;
|
|
((VObjectData*)vnode->data)->quat[1] = 0.0f;
|
|
((VObjectData*)vnode->data)->quat[2] = 0.0f;
|
|
((VObjectData*)vnode->data)->quat[3] = 0.0f;
|
|
|
|
((VObjectData*)vnode->data)->scale[0] = 0.0f;
|
|
((VObjectData*)vnode->data)->scale[1] = 0.0f;
|
|
((VObjectData*)vnode->data)->scale[2] = 0.0f;
|
|
|
|
/* clear bindings between object and object node */
|
|
if(((VObjectData*)vnode->data)->object) {
|
|
((Object*)((VObjectData*)vnode->data)->object)->vnode = NULL;
|
|
((VObjectData*)vnode->data)->object = NULL;
|
|
}
|
|
|
|
/* unsubscribe from all supported verse nodes */
|
|
vlink = ((VObjectData*)vnode->data)->links.lb.first;
|
|
while(vlink) {
|
|
if(vlink->target->counter==1) {
|
|
switch(vlink->target->type) {
|
|
case V_NT_OBJECT:
|
|
unsubscribe_from_obj_node(vlink->target);
|
|
break;
|
|
case V_NT_GEOMETRY:
|
|
unsubscribe_from_geom_node(vlink->target);
|
|
break;
|
|
case V_NT_BITMAP:
|
|
unsubscribe_from_bitmap_node(vlink->target);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
vlink = vlink->next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* when blender Object is deleted, then we have to unsubscribe and free all
|
|
* VerseNode dependent on this object
|
|
*/
|
|
void b_verse_delete_object(Object *object)
|
|
{
|
|
struct VNode *vnode;
|
|
|
|
vnode = (VNode*)object->vnode;
|
|
|
|
if(vnode) unsubscribe_from_obj_node(vnode);
|
|
}
|
|
|
|
/*
|
|
* "fake" unsubscribing from object node and all child nodes
|
|
*/
|
|
void b_verse_unsubscribe(VNode *vnode)
|
|
{
|
|
struct VLink *vlink = ((VObjectData*)vnode->data)->links.lb.first;
|
|
struct Object *ob = (Object*)((VObjectData*)vnode->data)->object;
|
|
|
|
if(vnode->type==V_NT_OBJECT) {
|
|
/* exit edit mode */
|
|
if(G.obedit && G.obedit->vnode == (void*)vnode)
|
|
exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
|
|
|
|
/* when some geometry node is child of this object node, then create mesh data */
|
|
while(vlink){
|
|
if(vlink->target->type == V_NT_GEOMETRY) {
|
|
struct Mesh *me;
|
|
me = ((VGeomData*)vlink->target->data)->mesh;
|
|
create_meshdata_from_geom_node(me, vlink->target);
|
|
break;
|
|
}
|
|
vlink = vlink->next;
|
|
}
|
|
|
|
/* unsubscribe from object transformation and clear bindings between
|
|
* verse object node and object */
|
|
unsubscribe_from_obj_node(vnode);
|
|
|
|
/* when geometry node was shared with more object nodes, then make
|
|
* data single user */
|
|
if(ob->type == OB_MESH) {
|
|
struct ID *id = ob->data;
|
|
if(id && id->us>1 && id->lib==0) {
|
|
ob->recalc= OB_RECALC_DATA;
|
|
ob->data = copy_mesh(ob->data);
|
|
id->us--;
|
|
id->newid= ob->data;
|
|
}
|
|
}
|
|
|
|
/* reinitialize object derived mesh */
|
|
makeDerivedMesh(ob, get_viewedit_datamask());
|
|
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
|
|
}
|
|
else if(vnode->type==V_NT_BITMAP) {
|
|
/* fake ... it isn't impelemented yet ... poke jiri, when needed */
|
|
unsubscribe_from_bitmap_node(vnode);
|
|
}
|
|
|
|
allqueue(REDRAWVIEW3D, 1);
|
|
}
|
|
|
|
/*
|
|
* whe VerseLink is created between two nodes, the Object start to point at
|
|
* coresponding data
|
|
*/
|
|
void post_link_set(VLink *vlink)
|
|
{
|
|
struct VNode *target, *source;
|
|
struct Object *ob=NULL;
|
|
struct Mesh *me=NULL;
|
|
|
|
source = vlink->source;
|
|
target = vlink->target;
|
|
|
|
if(source->type==V_NT_OBJECT && target->type==V_NT_GEOMETRY){
|
|
if(((VObjectData*)source->data)->object)
|
|
ob = (Object*)((VObjectData*)source->data)->object;
|
|
if(((VGeomData*)target->data)->mesh)
|
|
me = (Mesh*)((VGeomData*)target->data)->mesh;
|
|
if(ob && me && ob->data!=me) {
|
|
ob->data = me;
|
|
makeDerivedMesh(ob, get_viewedit_datamask());
|
|
}
|
|
}
|
|
|
|
allqueue(REDRAWALL, 1);
|
|
}
|
|
|
|
/*
|
|
* when VerseLink is deleted, then bindings between Object and data should be removed
|
|
*/
|
|
void post_link_destroy(VLink *vlink)
|
|
{
|
|
struct VNode *source, *target;
|
|
struct Object *ob;
|
|
|
|
source = vlink->source;
|
|
target = vlink->target;
|
|
|
|
if(source->type==V_NT_OBJECT && target->type==V_NT_GEOMETRY) {
|
|
if(((VObjectData*)source->data)->object) {
|
|
ob = (Object*)((VObjectData*)source->data)->object;
|
|
ob->data=NULL;
|
|
}
|
|
}
|
|
|
|
allqueue(REDRAWALL, 1);
|
|
}
|
|
|
|
/*
|
|
* update position of blender object
|
|
*/
|
|
void post_transform_pos(VNode *vnode)
|
|
{
|
|
struct VObjectData *obj_data = (VObjectData*)vnode->data;
|
|
struct Object *ob = (Object*)obj_data->object;
|
|
|
|
VECCOPY(ob->loc, obj_data->pos);
|
|
|
|
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
|
|
|
|
allqueue(REDRAWVIEW3D, 1);
|
|
}
|
|
|
|
/*
|
|
* update rotation of blender object
|
|
*/
|
|
void post_transform_rot(VNode *vnode)
|
|
{
|
|
struct VObjectData *obj_data = (VObjectData*)vnode->data;
|
|
struct Object *ob = (Object*)obj_data->object;
|
|
|
|
/* convert quaternion to euler rotation */
|
|
QuatToEul(obj_data->quat, ob->rot);
|
|
|
|
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
|
|
|
|
allqueue(REDRAWVIEW3D, 1);
|
|
}
|
|
|
|
/*
|
|
* update scale of blender object
|
|
*/
|
|
void post_transform_scale(VNode *vnode)
|
|
{
|
|
struct VObjectData *obj_data = (VObjectData*)vnode->data;
|
|
struct Object *ob = (Object*)obj_data->object;
|
|
|
|
VECCOPY(ob->size, obj_data->scale);
|
|
|
|
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
|
|
|
|
allqueue(REDRAWVIEW3D, 1);
|
|
}
|
|
|
|
/*
|
|
* send transformation of Object to verse server
|
|
*/
|
|
void b_verse_send_transformation(Object *ob)
|
|
{
|
|
struct VNode *vnode= ob->vnode;
|
|
float quat[4];
|
|
|
|
if(!vnode) return;
|
|
|
|
/* if last sent position wasn't received yet, then next change of position
|
|
* can't be send until last send change is received */
|
|
if( ((VObjectData*)vnode->data)->flag & POS_SEND_READY ) {
|
|
if((((VObjectData*)vnode->data)->pos[0]!=ob->loc[0]) ||
|
|
(((VObjectData*)vnode->data)->pos[1]!=ob->loc[1]) ||
|
|
(((VObjectData*)vnode->data)->pos[2]!=ob->loc[2])) {
|
|
VECCOPY(((VObjectData*)vnode->data)->pos, ob->loc);
|
|
send_verse_object_position(vnode);
|
|
}
|
|
}
|
|
|
|
/* if last sent rotation wasn't received yet, then next change of rotation
|
|
* can't be send until last send change is received */
|
|
if( ((VObjectData*)vnode->data)->flag & ROT_SEND_READY ) {
|
|
EulToQuat(ob->rot, quat);
|
|
|
|
if((((VObjectData*)vnode->data)->quat[0] != quat[0]) ||
|
|
(((VObjectData*)vnode->data)->quat[1] != quat[1]) ||
|
|
(((VObjectData*)vnode->data)->quat[2] != quat[2]) ||
|
|
(((VObjectData*)vnode->data)->quat[3] != quat[3])) {
|
|
QUATCOPY(((VObjectData*)vnode->data)->quat, quat);
|
|
send_verse_object_rotation(vnode);
|
|
}
|
|
}
|
|
|
|
/* if last sent object size wasn't received yet, then next change of object size
|
|
* can't be send until last send change is received */
|
|
if( ((VObjectData*)vnode->data)->flag & SCALE_SEND_READY ) {
|
|
if((((VObjectData*)vnode->data)->scale[0]!=ob->size[0]) ||
|
|
(((VObjectData*)vnode->data)->scale[1]!=ob->size[1]) ||
|
|
(((VObjectData*)vnode->data)->scale[2]!=ob->size[2])) {
|
|
VECCOPY(((VObjectData*)vnode->data)->scale, ob->size);
|
|
send_verse_object_scale(vnode);
|
|
}
|
|
}
|
|
|
|
verse_callback_update(0);
|
|
}
|
|
|
|
/*
|
|
* free constraint between object VerseNode and blender Object
|
|
*/
|
|
void post_object_free_constraint(VNode *vnode)
|
|
{
|
|
if(((VObjectData*)vnode->data)->object) {
|
|
/* free pointer at verse derived mesh */
|
|
struct Object *ob = (Object*)((VObjectData*)vnode->data)->object;
|
|
if(ob) {
|
|
if(ob->derivedFinal) {
|
|
ob->derivedFinal->needsFree = 1;
|
|
ob->derivedFinal->release((DerivedMesh*)ob->derivedFinal);
|
|
ob->derivedFinal = NULL;
|
|
}
|
|
if(ob->derivedDeform) {
|
|
ob->derivedDeform->needsFree = 1;
|
|
ob->derivedDeform->release((DerivedMesh*)ob->derivedDeform);
|
|
ob->derivedDeform = NULL;
|
|
}
|
|
}
|
|
/* free constraint */
|
|
((Object*)((VObjectData*)vnode->data)->object)->vnode = NULL;
|
|
((VObjectData*)vnode->data)->object = NULL;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|