diff options
author | Jiri Hnidek <jiri.hnidek@tul.cz> | 2006-08-20 19:22:56 +0400 |
---|---|---|
committer | Jiri Hnidek <jiri.hnidek@tul.cz> | 2006-08-20 19:22:56 +0400 |
commit | 2ee42ac01e6f4b154ac68976024af0615f7acb26 (patch) | |
tree | 9a2400a99bf7880a2f146c7a89bd2d8c0108374c /source/blender | |
parent | ffe630b452f4abb28c105fca2b8eb9fdb6e72370 (diff) |
Huge commit: VERSE
- All code is in #ifdef ... #endif
- Only make build system is supported and you have to add:
export WITH_VERSE=true
to user-def.mk file
- Blender can share only mesh objects and bitmaps now
- More informations can be found at wiki:
http://mediawiki.blender.org/index.php/BlenderDev/VerseIntegrationToBlender
http://mediawiki.blender.org/index.php/BlenderDev/VerseIntegrationToBlenderUserDoc
I hope, that I didn't forget at anything
Diffstat (limited to 'source/blender')
50 files changed, 9153 insertions, 56 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index e239d4de3c0..8f6aa8c3f54 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -184,6 +184,11 @@ typedef struct Global { #define G_RECORDKEYS (1 << 25) +/*#ifdef WITH_VERSE*/ +#define G_VERSE_CONNECTED (1 << 26) +#define G_DRAW_VERSE_DEBUG (1 << 27) +/*#endif*/ + /* G.fileflags */ #define G_AUTOPACK (1 << 0) diff --git a/source/blender/blenkernel/BKE_verse.h b/source/blender/blenkernel/BKE_verse.h new file mode 100644 index 00000000000..00a6bdd4e60 --- /dev/null +++ b/source/blender/blenkernel/BKE_verse.h @@ -0,0 +1,503 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +/* #define WITH_VERSE */ + +#ifndef BKE_VERSE_H +#define BKE_VERSE_H + +#include "DNA_listBase.h" +#include "BLI_dynamiclist.h" + +#include "verse.h" + +struct VNode; + +/* + * virtual data type (used only for retype) + */ +typedef struct verse_parent { + struct verse_parent *next, *prev; + VLayerID layer_id; + uint32 id; +} verse_parent; + +/* + * verse data: 4 float value + */ +typedef struct quat_real32_item { + struct quat_real32_item *next, *prev; + VLayerID layer_id; + void *parent; + real32 value[4]; +} quat_real32_item; + +/* + * verse data: 4 uint32 values + */ +typedef struct quat_uint32_item { + struct quat_uint32_item *next, *prev; + VLayerID layer_id; + void *parent; + uint32 value[4]; +} quat_uint32_item; + +/* + * verse data: 3 float values + */ +typedef struct vec_real32_item { + struct vec_real32_item *next, *prev; + VLayerID layer_id; + void *parent; + real32 value[3]; +} vec_real32_item; + +/* + * verse data: float value (weight) + */ +typedef struct real32_item { + struct real32_item *next, *prev; + VLayerID layer_id; + void *parent; + real32 value; +} real32_item; + +/* + * verse data: uint32 value + */ +typedef struct uint32_item { + struct uint32_item *next, *prev; + VLayerID layer_id; + void *parent; + uint32 value; +} uint32_item; + +/* + * verse data: uint8 value + */ +typedef struct uint8_item { + struct uint8_item *next, *prev; + VLayerID layer_id; + void *parent; + uint8 value; +} uint8_item; + +/* + * verse data: vertex + */ +typedef struct VerseVert { + struct VerseVert *next, *prev; + /* verse data */ + struct VLayer *vlayer; /* pointer at VerseLayer */ + uint32 id; /* id of vertex */ + real32 co[3]; /* x,y,z-coordinates of vertex */ + real32 no[3]; /* normal of vertex */ + /* blender internals */ + short flag; /* flags: VERT_DELETED, VERT_RECEIVED */ + void *vertex; /* pointer at EditVert or MVert */ + int counter; /* counter of VerseFaces using this VerseVert */ + union { + unsigned int index; /* counter need during transformation to mesh */ + struct VerseVert *vvert; + } tmp; /* pointer at new created verse vert, it is + * used during duplicating geometry node */ + float *cos; /* modified coordinates of vertex */ +} VerseVert; + +/* + * verse data: polygon + */ +typedef struct VerseFace { + struct VerseFace *next, *prev; + /* verse data */ + struct VLayer *vlayer; /* pointer at VerseLayer */ + uint32 id; /* id of face */ + struct VerseVert *vvert0; /* pointer at 1st VerseVert */ + struct VerseVert *vvert1; /* pointer at 2nd VerseVert */ + struct VerseVert *vvert2; /* pointer at 3th VerseVert */ + struct VerseVert *vvert3; /* pointer at 4th VerseVert */ + unsigned int v0, v1, v2, v3; /* indexes of VerseVerts ... needed during receiving */ + /* blender internals */ + char flag; /* flags: FACE_SEND_READY, FACE_SENT, FACE_RECEIVED, FACE_CHANGED*/ + short counter; /* counter of missed VerseVertexes */ + void *face; /* pointer at EditFace */ + float no[3]; /* normal vector */ +} VerseFace; + +/* + * verse data: layer + */ +typedef struct VLayer { + struct VLayer *next, *prev; + /* verse data*/ + struct VNode *vnode; /* pointer at VerseNode */ + uint16 id; /* id of layer */ + char *name; /* name of layer */ + VNGLayerType type; /* type of layer (VN_G_LAYER_VERTEX_XYZ, VN_G_LAYER_POLYGON_CORNER_UINT32) */ + uint32 def_int; /* default integer value */ + real64 def_real; /* default float value */ + /* blender internals */ + char flag; /* flags: LAYER_SENT, LAYER_RECEIVED, LAYER_DELETED, LAYER_OBSOLETE */ + short content; /* type of content (VERTEX_LAYER, POLYGON_LAYER) */ + struct DynamicList dl; /* vertexes, polygons, etc. */ + struct ListBase queue; /* queue of vertexes, polygons, etc. waiting for sending to verse server */ + struct ListBase orphans; /* list of versedata (polygons, etc.), that can be added to the DynamicList + * due to not received VerseVerts */ + unsigned int counter; /* counter of sent items */ + /* client dependent methods */ + void (*post_layer_create)(struct VLayer *vlayer); + void (*post_layer_destroy)(struct VLayer *vlayer); +} VLayer; + +/* + * verse data: link + */ +typedef struct VLink{ + struct VLink *next, *prev; + /* verse data */ + struct VerseSession *session; /* session pointer */ + struct VNode *source; /* object VerseNode "pointing" at some other VerseNode */ + struct VNode *target; /* VerseNode linked with some object node */ + unsigned int id; /* id of VerseLink */ + unsigned int target_id; /* some unknow id */ + char *label; /* name/label of VerseLink */ + /* blender internals */ + char flag; /* flags: LINK_SEND_READY */ + /* client dependent methods */ + void (*post_link_set)(struct VLink *vlink); + void (*post_link_destroy)(struct VLink *vlink); +} VLink; + +/* + * bitmap layer + */ +typedef struct VBitmapLayer { + struct VBitmapLayer *next, *prev; + /* verse data */ + struct VNode *vnode; /* pointer at Verse Node */ + VLayerID id; /* id of layer */ + char *name; /* name of layer */ + VNBLayerType type; /* type of layer (bits per channel) 1, 8, 16, 32, 64 */ + void *data; /* dynamic allocated data */ + /* blender internals */ + char flag; +} VBitmapLayer; + +/* + * data of bitmap node + */ +typedef struct VBitmapData { + struct DynamicList layers; /* dynamic list with access array of bitmap layers */ + struct ListBase queue; /* queue of layers waiting for receiving from verse server */ + uint16 width; /* width of all verse layers */ + uint16 height; /* height of all verse layers */ + uint16 depth; /* depth of bitmap 1 is 2D bitmap, >1 is 3D bitmap */ + /* blender internals */ + uint16 t_width; /* = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */ + uint16 t_height; /* = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */ + void *image; /* pointer at image */ + /* client dependent methods */ + void (*post_bitmap_dimension_set)(struct VNode *vnode); + void (*post_bitmap_layer_create)(struct VBitmapLayer *vblayer); + void (*post_bitmap_layer_destroy)(struct VBitmapLayer *vblayer); + void (*post_bitmap_tile_set)(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys); +}VBitmapData; + +/* + * data of geometry node + */ +typedef struct VGeomData { + struct DynamicList layers; /* dynamic list with access array of Layers */ + struct VLink *vlink; /* pointer at VerseLink connecting object node and geom node */ + struct ListBase queue; /* queue of our layers waiting for receiving from verse server */ + void *mesh; /* pointer at Mesh (object node) */ + void *editmesh; /* pointer at EditMesh (edit mode) */ + /* client dependent methods */ + void (*post_vertex_create)(struct VerseVert *vvert); + void (*post_vertex_set_xyz)(struct VerseVert *vvert); + void (*post_vertex_delete)(struct VerseVert *vvert); + void (*post_vertex_free_constraint)(struct VerseVert *vvert); + void (*post_polygon_create)(struct VerseFace *vface); + void (*post_polygon_set_corner)(struct VerseFace *vface); + void (*post_polygon_delete)(struct VerseFace *vface); + void (*post_polygon_free_constraint)(struct VerseFace *vface); + void (*post_geometry_free_constraint)(struct VNode *vnode); + void (*post_polygon_set_uint8)(struct VerseFace *vface); +} VGeomData; + +/* + * data of object node + */ +typedef struct VObjectData { + struct DynamicList links; /* dynamic list with access array of links between other nodes */ + struct ListBase queue; /* queue of links waiting for sending and receiving from verse server */ + float pos[3]; /* position of object VerseNode */ + float rot[4]; /* rotation of object VerseNode stored in quat */ + float scale[3]; /* scale of object VerseNode */ + void *object; /* pointer at object */ + short flag; /* flag: POS_RECEIVE_READY, ROT_RECEIVE_READY. SCALE_RECEIVE_READY */ + /* client dependent methods */ + void (*post_transform)(struct VNode *vnode); + void (*post_object_free_constraint)(struct VNode *vnode); +} VObjectData; + +/* + * Verse Tag + */ +typedef struct VTag { + struct VTag *next, *prev; + /* verse data*/ + struct VTagGroup *vtaggroup; /* pointer at Verse Tag Group */ + uint16 id; /* id of this tag */ + char *name; /* name of this tag*/ + VNTagType type; /* type: VN_TAG_BOOLEAN, VN_TAG_UINT32, VN_TAG_REAL64, VN_TAG_REAL64_VEC3, + VN_TAG_LINK, VN_TAG_ANIMATION, VN_TAG_BLOB */ + VNTag *tag; /* pointer at value (enum: vboolean, vuint32, vreal64, vstring, + vreal64_vec3, vlink, vanimation, vblob)*/ + /* blender internals */ + void *value; /* pointer at blender value */ +} VTag; + +/* + * Verse Tag Group (verse tags are grouped in tag groups) + */ +typedef struct VTagGroup { + struct VTagGroup *next, *prev; + /* verse data*/ + struct VNode *vnode; /* pointer at Verse Node */ + uint16 id; /* id of this tag group */ + char *name; /* name of this tag group */ + /* blender internals */ + struct DynamicList tags; /* dynamic list with access array containing tags */ + struct ListBase queue; /* list of tags waiting for receiving from verse server */ + /* client dependent methods */ + void (*post_tag_change)(struct VTag *vatg); + void (*post_taggroup_create)(struct VTagGroup *vtaggroup); +} VTagGroup; + +/* + * Verse Node + */ +typedef struct VNode { + struct VNode *next, *prev; + /* verse data*/ + struct VerseSession *session; /* session pointer */ + VNodeID id; /* node id */ + VNodeID owner_id; /* owner's id of this node */ + char *name; /* name of this node */ + uint32 type; /* type of node (V_NT_OBJECT, V_NT_GEOMETRY, V_NT_BITMAP) */ + /* blender internals */ + char flag; /* flags: NODE_SENT, NODE_RECEIVED, NODE_DELTED, NODE_OBSOLETE */ + struct DynamicList taggroups; /* dynamic list with access array of taggroups */ + struct ListBase queue; /* list of taggroups waiting for receiving from verse server */ + void *data; /* generic pointer at some data (VObjectData, VGeomData, ...) */ + int counter; /* counter of verse link pointing at this vnode (vlink->target) */ + /* client dependent methods */ + void (*post_node_create)(struct VNode *vnode); + void (*post_node_destroy)(struct VNode *vnode); + void (*post_node_name_set)(struct VNode *vnode); +} VNode; + +/* + * Verse Session: verse client can be connected to several verse servers + * it is neccessary to store some information about each session + */ +typedef struct VerseSession { + struct VerseSession *next, *prev; + /* verse data */ + VSession *vsession; /* pointer at VSeesion (verse.h) */ + uint32 avatar; /* id of avatar */ + char *address; /* string containg IP/domain name of verse server and number of port */ + void *connection; /* no clue */ + uint8 *host_id; /* no clue */ + /* blender internals */ + short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */ + DynamicList nodes; /* list of verse nodes */ + ListBase queue; /* list of nodes waiting for sending to verse server */ + unsigned int counter; /* count of events, when connection wasn't accepted */ + /* client dependent methods */ + void (*post_connect_accept)(struct VerseSession *session); + void (*post_connect_terminated)(struct VerseSession *session); + void (*post_connect_update)(struct VerseSession *session); +} VerseSession; + +/* + * list of post callback functions + */ +typedef struct PostCallbackFunction { + void (*function)(void *arg); + void *param; +} PostCallbackFunction; + +/* VerseSession->flag */ +#define VERSE_CONNECTING 1 +#define VERSE_CONNECTED 2 +#define VERSE_AUTOSUBSCRIBE 4 + +/* max VerseSession->counter value */ +#define MAX_UNCONNECTED_EVENTS 100 + +/* VNode flags */ +#define NODE_SENT 1 +#define NODE_RECEIVED 2 +#define NODE_DELTED 4 +#define NODE_OBSOLETE 8 + +/* VLayer flags */ +#define LAYER_SENT 1 +#define LAYER_RECEIVED 2 +#define LAYER_DELETED 4 +#define LAYER_OBSOLETE 8 + +/* VLink->flag */ +#define LINK_SEND_READY 1 + +/* VObjectData->flag */ +#define POS_RECEIVE_READY 1 +#define ROT_RECEIVE_READY 2 +#define SCALE_RECEIVE_READY 4 +#define POS_SEND_READY 8 +#define ROT_SEND_READY 16 +#define SCALE_SEND_READY 32 + +/* VLayer->content */ +#define VERTEX_LAYER 0 +#define POLYGON_LAYER 1 + +/* VerseVert->flag */ +#define VERT_DELETED 1 /* vertex delete command was received from verse server */ +#define VERT_RECEIVED 2 /* VerseVert was received from verse server (is not in sending queue) */ +#define VERT_LOCKED 4 /* VerseVert is ready to send local position to verse server */ +#define VERT_POS_OBSOLETE 8 /* position of vertex was changed during sending to verse server */ +#define VERT_OBSOLETE 16 /* vertex delete command was sent to verse server; it means, that + * no information related to this vertex shoudln't be sent to verse + * until verse vertex is completely deleted ... then this vertex id + * can be reused again for new vertex */ + +/* VerseFace->flag */ +#define FACE_SEND_READY 1 /* VerseFace is ready for sending to verse server */ +#define FACE_RECEIVED 2 /* VerseFace was received from verse server */ +#define FACE_SENT 4 /* VerseFace was sent to verse server and we expect receiving from verse server */ +#define FACE_DELETED 8 /* delete command was sent to verse server */ +#define FACE_CHANGED 16 /* VerseFace was only changed not created */ +#define FACE_OBSOLETE 32 /* VerseFace was changed during sending to verse server */ + +/* Queue type */ +#define VERSE_NODE 1 +#define VERSE_LINK 2 +#define VERSE_LAYER 3 +#define VERSE_VERT 4 +#define VERSE_FACE 5 + +#define VERSE_TAG 6 +#define VERSE_TAG_GROUP 7 + +#define VERSE_VERT_UINT32 8 +#define VERSE_VERT_REAL32 9 +#define VERSE_VERT_VEC_REAL32 10 + +#define VERSE_FACE_UINT8 11 +#define VERSE_FACE_UINT32 12 +#define VERSE_FACE_REAL32 13 +#define VERSE_FACE_QUAT_UINT32 14 +#define VERSE_FACE_QUAT_REAL32 15 + +/* Verse Bitmap Layer flags */ +#define VBLAYER_SUBSCRIBED 1 + +/* function prototypes */ + +/* functions from verse_session.c */ +void set_verse_session_callbacks(void); +struct VerseSession *versesession_from_vsession(VSession *vsession); +struct VerseSession *current_verse_session(void); +struct VerseSession *create_verse_session(const char *name, const char *pass, const char *address, uint8 *expected_key); +void free_verse_session(struct VerseSession *session); +void b_verse_update(void); +void b_verse_connect(char *address); +void end_verse_session(struct VerseSession *session, char free); +void end_all_verse_sessions(void); + +/* functions from verse_node.c */ +void send_verse_tag(struct VTag *vtag); +void send_verse_taggroup(struct VTagGroup *vtaggroup); +void send_verse_node(struct VNode *vnode); +void free_verse_node_data(struct VNode *vnode); +void free_verse_node(struct VNode *vnode); +struct VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id); +void set_node_callbacks(void); + +/* functions from verse_object_node.c */ +struct VLink *find_unsent_parent_vlink(struct VerseSession *session, struct VNode *vnode); +struct VLink *find_unsent_child_vlink(struct VerseSession *session, struct VNode *vnode); +struct VLink *create_verse_link(VerseSession *session, struct VNode *source, struct VNode *target, uint16 link_id, uint32 target_id, const char *label); +void send_verse_object_position(struct VNode *vnode); +void send_verse_object_rotation(struct VNode *vnode); +void send_verse_object_scale(struct VNode *vnode); +void send_verse_link(struct VLink *vlink); + +void free_object_data(struct VNode *vnode); +void set_object_callbacks(void); +struct VObjectData *create_object_data(void); + +/* functions from verse_geometry_node.c */ +struct VerseFace* create_verse_face(struct VLayer *vlayer, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); +struct VerseVert* create_verse_vertex(struct VLayer *vlayer, uint32 vertex_id, real32 x, real32 y, real32 z); +struct VLayer *create_verse_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real); +struct VGeomData *create_geometry_data(void); + +void send_verse_layer(struct VLayer *vlayer); + +void send_verse_face_corner_quat_real32(struct quat_real32_item *item, short type); +void send_verse_face_corner_quat_uint32(struct quat_uint32_item *item, short type); +void send_verse_face_real32(struct real32_item *item, short type); +void send_verse_face_uint32(struct uint32_item *item, short type); +void send_verse_face_uint8(struct uint8_item *item, short type); + +void send_verse_vert_vec_real32(struct vec_real32_item *item, short type); +void send_verse_vert_real32(struct real32_item *item, short type); +void send_verse_vert_uint32(struct uint32_item *item, short type); + +void send_verse_vertex_delete(struct VerseVert *vvert); +void send_verse_vertex(struct VerseVert *vvert); +void send_verse_face_delete(struct VerseFace *vface); + +void destroy_geometry(struct VNode *vnode); + +struct VLayer* find_verse_layer_type(struct VGeomData *geom, short content); +void add_item_to_send_queue(struct ListBase *lb, void *item, short type); +void free_geom_data(struct VNode *vnode); +void set_geometry_callbacks(void); + +/* functions prototypes from verse_bitmap.c */ +void set_bitmap_callbacks(void); +void free_bitmap_layer_data(struct VBitmapLayer *vblayer); +struct VBitmapLayer *create_bitmap_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNBLayerType type); +void free_bitmap_node_data(struct VNode *vnode); +struct VBitmapData *create_bitmap_data(void); + +#endif diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 063185f456a..f0c1ef7f890 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -68,6 +68,10 @@ #include "BKE_modifier.h" #include "BKE_key.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_gl.h" #include "BIF_glutil.h" @@ -1490,6 +1494,454 @@ DerivedMesh *derivedmesh_from_displistmesh(DispListMesh *dlm, float (*vertexCos) return (DerivedMesh*) ssdm; } +#ifdef WITH_VERSE + +/* verse derived mesh */ +typedef struct { + struct DerivedMesh dm; + struct VNode *vnode; + struct VLayer *vertex_layer; + struct VLayer *polygon_layer; + float (*verts)[3]; +} VDerivedMesh; + +/* this function set up border points of verse mesh bounding box */ +static void vDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + + if(!vdm->vertex_layer) return; + + vvert = (VerseVert*)vdm->vertex_layer->dl.lb.first; + + if(vdm->vertex_layer->dl.da.count > 0) { + while(vvert) { + DO_MINMAX(vdm->verts ? vvert->cos : vvert->co, min_r, max_r); + vvert = vvert->next; + } + } + else { + min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; + } +} + +/* this function return number of vertexes in vertex layer */ +static int vDM_getNumVerts(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + if(!vdm->vertex_layer) return 0; + else return vdm->vertex_layer->dl.da.count; +} + +/* this function returns number of polygons in polygon layer */ +static int vDM_getNumFaces(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + if(!vdm->polygon_layer) return 0; + else return vdm->polygon_layer->dl.da.count; +} + +/* create diplist mesh from verse mesh */ +static DispListMesh* vDM_convertToDispListMesh(DerivedMesh *dm, int allowShared) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + DispListMesh *dlm = MEM_callocN(sizeof(*dlm), "dlm"); + struct VerseVert *vvert; + struct VerseFace *vface; + struct MVert *mvert=NULL; + struct MFace *mface=NULL; + float *norms; + unsigned int i; + + if(!vdm->vertex_layer || !vdm->polygon_layer) { + dlm->totvert = 0; + dlm->totedge = 0; + dlm->totface = 0; + dlm->dontFreeVerts = dlm->dontFreeOther = dlm->dontFreeNors = 0; + + return dlm; + }; + + /* number of vertexes, edges and faces */ + dlm->totvert = vdm->vertex_layer->dl.da.count; + dlm->totedge = 0; + dlm->totface = vdm->polygon_layer->dl.da.count; + + /* create dynamic array of mverts */ + mvert = (MVert*)MEM_mallocN(sizeof(MVert)*dlm->totvert, "dlm verts"); + dlm->mvert = mvert; + vvert = (VerseVert*)vdm->vertex_layer->dl.lb.first; + i = 0; + while(vvert) { + VECCOPY(mvert->co, vdm->verts ? vvert->cos : vvert->co); + VECCOPY(mvert->no, vvert->no); + mvert->mat_nr = 0; + mvert->flag = 0; + + vvert->tmp.index = i++; + mvert++; + vvert = vvert->next; + } + + /* verse doesn't support edges */ + dlm->medge = NULL; + + /* create dynamic array of faces */ + mface = (MFace*)MEM_mallocN(sizeof(MFace)*dlm->totface, "dlm faces"); + dlm->mface = mface; + vface = (VerseFace*)vdm->polygon_layer->dl.lb.first; + i = 0; + while(vface) { + mface->v1 = vface->vvert0->tmp.index; + mface->v2 = vface->vvert1->tmp.index; + mface->v3 = vface->vvert2->tmp.index; + if(vface->vvert3) mface->v4 = vface->vvert3->tmp.index; + else mface->v4 = 0; + + mface->pad = 0; + mface->mat_nr = 0; + mface->flag = 0; + mface->edcode = 0; + + test_index_face(mface, NULL, NULL, vface->vvert3?4:3); + + mface++; + vface = vface->next; + } + + /* textures and verex colors aren't supported yet */ + dlm->tface = NULL; + dlm->mcol = NULL; + + /* faces normals */ + norms = (float*)MEM_mallocN(sizeof(float)*3*dlm->totface, "dlm norms"); + dlm->nors = norms; + + vface = (VerseFace*)vdm->polygon_layer->dl.lb.first; + while(vface){ + VECCOPY(norms, vface->no); + norms += 3; + vface = vface->next; + } + + /* free everything, nothing is shared */ + dlm->dontFreeVerts = dlm->dontFreeOther = dlm->dontFreeNors = 0; + + return dlm; +} + +/* return coordination of vertex with index ... I suppose, that it will + * be very hard to do, becuase there can be holes in access array */ +static void vDM_getVertCo(DerivedMesh *dm, int index, float co_r[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert = NULL; + + if(!vdm->vertex_layer) return; + + vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index); + if(vvert) { + VECCOPY(co_r, vdm->verts ? vvert->cos : vvert->co); + } + else { + co_r[0] = co_r[1] = co_r[2] = 0.0; + } +} + +/* return array of vertex coordiantions */ +static void vDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + int i = 0; + + if(!vdm->vertex_layer) return; + + vvert = vdm->vertex_layer->dl.lb.first; + while(vvert) { + VECCOPY(cos_r[i], vdm->verts ? vvert->cos : vvert->co); + i++; + vvert = vvert->next; + } +} + +/* return normal of vertex with index ... again, it will be hard to + * implemente, because access array */ +static void vDM_getVertNo(DerivedMesh *dm, int index, float no_r[3]) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert = NULL; + + if(!vdm->vertex_layer) return; + + vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index); + if(vvert) { + VECCOPY(no_r, vvert->no); + } + else { + no_r[0] = no_r[1] = no_r[2] = 0.0; + } +} + +/* draw all VerseVertexes */ +static void vDM_drawVerts(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseVert *vvert; + + if(!vdm->vertex_layer) return; + + vvert = vdm->vertex_layer->dl.lb.first; + + bglBegin(GL_POINTS); + while(vvert) { + bglVertex3fv(vdm->verts ? vvert->cos : vvert->co); + vvert = vvert->next; + } + bglEnd(); +} + +/* draw all edges of VerseFaces ... it isn't optimal, because verse + * specification doesn't support edges :-( ... bother eskil ;-) + * ... some edges (most of edges) are drawn twice */ +static void vDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + + if(!vdm->polygon_layer) return; + + vface = vdm->polygon_layer->dl.lb.first; + + while(vface) { + glBegin(GL_LINE_LOOP); + glVertex3fv(vdm->verts ? vface->vvert0->cos : vface->vvert0->co); + glVertex3fv(vdm->verts ? vface->vvert1->cos : vface->vvert1->co); + glVertex3fv(vdm->verts ? vface->vvert2->cos : vface->vvert2->co); + if(vface->vvert3) glVertex3fv(vdm->verts ? vface->vvert3->cos : vface->vvert3->co); + glEnd(); + + vface = vface->next; + } +} + +/* verse spec doesn't support edges ... loose edges can't exist */ +void vDM_drawLooseEdges(DerivedMesh *dm) +{ +} + +/* draw uv edges, not supported yet */ +static void vDM_drawUVEdges(DerivedMesh *dm) +{ +} + +/* draw all VerseFaces */ +static void vDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int)) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + + if(!vdm->polygon_layer) return; + + vface = vdm->polygon_layer->dl.lb.first; + + while(vface) { +/* if((vface->smooth) && (vface->smooth->value)){ + glShadeModel(GL_SMOOTH); + glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); + glNormal3fv(vface->vvert0->no); + glVertex3fv(vdm->verts ? vface->vvert0->cos : vface->vvert0->co); + glNormal3fv(vface->vvert1->no); + glVertex3fv(vdm->verts ? vface->vvert1->cos : vface->vvert1->co); + glNormal3fv(vface->vvert2->no); + glVertex3fv(vdm->verts ? vface->vvert2->cos : vface->vvert2->co); + if(vface->vvert3){ + glNormal3fv(vface->vvert3->no); + glVertex3fv(vdm->verts ? vface->vvert3->cos : vface->vvert3->co); + } + glEnd(); + } + else { */ + glShadeModel(GL_FLAT); + glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); + glNormal3fv(vface->no); + glVertex3fv(vdm->verts ? vface->vvert0->cos : vface->vvert0->co); + glVertex3fv(vdm->verts ? vface->vvert1->cos : vface->vvert1->co); + glVertex3fv(vdm->verts ? vface->vvert2->cos : vface->vvert2->co); + if(vface->vvert3) + glVertex3fv(vdm->verts ? vface->vvert3->cos : vface->vvert3->co); + glEnd(); +/* } */ + + vface = vface->next; + } + glShadeModel(GL_FLAT); +} + +/* this function should draw mesh with colored faces (weight paint, vertex + * colors, etc.), but it isn't supported yet */ +static void vDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + struct VerseFace *vface; + + if(!vdm->polygon_layer) return; + + vface = vdm->polygon_layer->dl.lb.first; + + while(vface) { + glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); + glVertex3fv(vdm->verts ? vface->vvert0->cos : vface->vvert0->co); + glVertex3fv(vdm->verts ? vface->vvert1->cos : vface->vvert1->co); + glVertex3fv(vdm->verts ? vface->vvert2->cos : vface->vvert2->co); + if(vface->vvert3) + glVertex3fv(vdm->verts ? vface->vvert3->cos : vface->vvert3->co); + glEnd(); + + vface = vface->next; + } +} + +/**/ +static void vDM_foreachMappedVert( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), + void *userData) +{ +} + +/**/ +static void vDM_foreachMappedEdge( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *v0co, float *v1co), + void *userData) +{ +} + +/**/ +static void vDM_foreachMappedFaceCenter( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *cent, float *no), + void *userData) +{ +} + +/**/ +static void vDM_drawMappedFacesTex( + DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index, int matnr), + void *userData) +{ +} + +/**/ +static void vDM_drawMappedFaces( + DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), + void *userData, + int useColors) +{ +} + +/**/ +static void vDM_drawMappedEdges( + DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index), + void *userData) +{ +} + +/**/ +static void vDM_drawMappedEdgesInterp( + DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index), + void (*setDrawInterpOptions)(void *userData, int index, float t), + void *userData) +{ +} + +/* free all DerivedMesh data */ +static void vDM_release(DerivedMesh *dm) +{ + VDerivedMesh *vdm = (VDerivedMesh*)dm; + + if(vdm->verts) MEM_freeN(vdm->verts); + MEM_freeN(vdm); +} + +/* create derived mesh from verse mesh ... it is used in object mode, when some other client can + * change shared data and want to see this changes in real time too */ +DerivedMesh *derivedmesh_from_versemesh(VNode *vnode, float (*vertexCos)[3]) +{ + VDerivedMesh *vdm = MEM_callocN(sizeof(*vdm), "vdm"); + struct VerseVert *vvert; + + vdm->vnode = vnode; + vdm->vertex_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + vdm->polygon_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + vdm->dm.getMinMax = vDM_getMinMax; + + vdm->dm.getNumVerts = vDM_getNumVerts; + vdm->dm.getNumFaces = vDM_getNumFaces; + + vdm->dm.foreachMappedVert = vDM_foreachMappedVert; + vdm->dm.foreachMappedEdge = vDM_foreachMappedEdge; + vdm->dm.foreachMappedFaceCenter = vDM_foreachMappedFaceCenter; + + vdm->dm.convertToDispListMesh = vDM_convertToDispListMesh; + + vdm->dm.getVertCos = vDM_getVertCos; + vdm->dm.getVertCo = vDM_getVertCo; + vdm->dm.getVertNo = vDM_getVertNo; + + vdm->dm.drawVerts = vDM_drawVerts; + + vdm->dm.drawEdges = vDM_drawEdges; + vdm->dm.drawLooseEdges = vDM_drawLooseEdges; + vdm->dm.drawUVEdges = vDM_drawUVEdges; + + vdm->dm.drawFacesSolid = vDM_drawFacesSolid; + vdm->dm.drawFacesColored = vDM_drawFacesColored; + + vdm->dm.drawMappedFacesTex = vDM_drawMappedFacesTex; + vdm->dm.drawMappedFaces = vDM_drawMappedFaces; + vdm->dm.drawMappedEdges = vDM_drawMappedEdges; + vdm->dm.drawMappedEdgesInterp = vDM_drawMappedEdgesInterp; + + vdm->dm.release = vDM_release; + + if(vdm->vertex_layer) { + if(vertexCos) { + int i; + + vdm->verts = MEM_mallocN(sizeof(float)*3*vdm->vertex_layer->dl.da.count, "verse mod vertexes"); + vvert = vdm->vertex_layer->dl.lb.first; + + for(i=0; i<vdm->vertex_layer->dl.da.count && vvert; i++, vvert = vvert->next) { + VECCOPY(vdm->verts[i], vertexCos[i]); + vvert->cos = vdm->verts[i]; + } + } + else { + vdm->verts = NULL; + vvert = vdm->vertex_layer->dl.lb.first; + + while(vvert) { + vvert->cos = NULL; + vvert = vvert->next; + } + } + } + + return (DerivedMesh*) vdm; +} + +#endif + /***/ DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md) @@ -1506,8 +1958,13 @@ DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md) float (*deformedVerts)[3] = mesh_getVertexCos(me, &numVerts); mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); - +#ifdef WITH_VERSE + if(me->vnode) dm = derivedmesh_from_versemesh(me->vnode, deformedVerts); + else dm = getMeshDerivedMesh(me, ob, deformedVerts); +#else dm = getMeshDerivedMesh(me, ob, deformedVerts); +#endif + MEM_freeN(deformedVerts); } else { dm = mti->applyModifier(md, ob, NULL, NULL, 0, 0); @@ -1566,7 +2023,13 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM * places that wish to use the original mesh but with deformed * coordinates (vpaint, etc.) */ - if (deform_r) *deform_r = getMeshDerivedMesh(me, ob, deformedVerts); + if (deform_r) +#ifdef WITH_VERSE + if(me->vnode) *deform_r = derivedmesh_from_versemesh(me->vnode, deformedVerts); + else *deform_r = getMeshDerivedMesh(me, ob, deformedVerts); +#else + *deform_r = getMeshDerivedMesh(me, ob, deformedVerts); +#endif } else { if(!fluidsimMeshUsed) { // default behaviour for meshes @@ -1651,7 +2114,12 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM } else if (dm) { *final_r = dm; } else { +#ifdef WITH_VERSE + if(me->vnode) *final_r = derivedmesh_from_versemesh(me->vnode, deformedVerts); + else *final_r = getMeshDerivedMesh(me, ob, deformedVerts); +#else *final_r = getMeshDerivedMesh(me, ob, deformedVerts); +#endif } if (deformedVerts && deformedVerts!=inputVertexCos) { diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile index fdfcef53954..28d4151154c 100644 --- a/source/blender/blenkernel/intern/Makefile +++ b/source/blender/blenkernel/intern/Makefile @@ -84,6 +84,11 @@ ifeq ($(WITH_FREETYPE2), true) CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 endif +ifeq ($(WITH_VERSE), true) + CPPFLAGS += -DWITH_VERSE + CPPFLAGS += -I$(NAN_VERSE)/include +endif + ifeq ($(WITH_FFMPEG),true) CPPFLAGS += -DWITH_FFMPEG CPPFLAGS += $(NAN_FFMPEGCFLAGS) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 098f6adb33c..2b0c936edd9 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -71,6 +71,10 @@ #include "BKE_utildefines.h" #include "BKE_bad_level_calls.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_arithb.h" @@ -199,7 +203,11 @@ Mesh *add_mesh() me->texflag= AUTOSPACE; me->flag= ME_TWOSIDED; me->bb= unit_boundbox(); - + +#ifdef WITH_VERSE + me->vnode = NULL; +#endif + return me; } @@ -234,7 +242,11 @@ Mesh *copy_mesh(Mesh *me) men->key= copy_key(me->key); if(men->key) men->key->from= (ID *)men; - + +#ifdef WITH_VERSE + men->vnode = NULL; +#endif + return men; } @@ -1073,15 +1085,39 @@ void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3] { - int i, numVerts = me->totvert; - float (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos1"); +#ifdef WITH_VERSE + if(me->vnode) { + struct VLayer *vlayer; + struct VerseVert *vvert; + unsigned int i, numVerts; + float (*cos)[3]; - if (numVerts_r) *numVerts_r = numVerts; - for (i=0; i<numVerts; i++) { - VECCOPY(cos[i], me->mvert[i].co); - } + vlayer = find_verse_layer_type((VGeomData*)((VNode*)me->vnode)->data, VERTEX_LAYER); + + vvert = vlayer->dl.lb.first; + numVerts = vlayer->dl.da.count; + cos = MEM_mallocN(sizeof(*cos)*numVerts, "verse_vertexcos"); - return cos; + for(i=0; i<numVerts && vvert; vvert = vvert->next, i++) { + VECCOPY(cos[i], vvert->co); + } + + return cos; + } + else { +#endif + int i, numVerts = me->totvert; + float (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos1"); + + if (numVerts_r) *numVerts_r = numVerts; + for (i=0; i<numVerts; i++) { + VECCOPY(cos[i], me->mvert[i].co); + } + + return cos; +#ifdef WITH_VERSE + } +#endif } /* UvVertMap */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 1a96b41d9bb..5ce83c19033 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -910,6 +910,11 @@ Object *copy_object(Object *ob) obn->derivedDeform = NULL; obn->derivedFinal = NULL; +#ifdef WITH_VERSE + obn->vnode = NULL; +#endif + + return obn; } diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c new file mode 100644 index 00000000000..f9b18c38dc8 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_bitmap_node.c @@ -0,0 +1,449 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" + +#include "BIF_verse.h" + +#include "BKE_verse.h" + +#include "verse.h" + +/* function prototypes of static functions */ +static void cb_b_dimension_set(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth); +static void cb_b_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type); +static void cb_b_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id); +static void cb_b_tile_set(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile); + +static void change_layer_dimension( + VBitmapLayer *vblayer, + unsigned int old_width, + unsigned int old_height, + unsigned int t_old_width, + unsigned int t_old_height); +static void *alloc_verse_bitmap_layer_data(struct VBitmapLayer *vblayer); + +/* + * resize/crop verse bitmap layer + */ +static void change_layer_dimension( + VBitmapLayer *vblayer, + unsigned int old_width, + unsigned int old_height, + unsigned int t_old_width, + unsigned int t_old_height) +{ + struct VNode *vnode = vblayer->vnode; + unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width; + unsigned int t_height = ((VBitmapData*)(vnode->data))->t_height; + unsigned int width = ((VBitmapData*)(vnode->data))->width; + unsigned int height = ((VBitmapData*)(vnode->data))->height; + unsigned int x, y, i, j; + + i = j = 0; + + /* "copy" old data to new data */ + if(vblayer->type==VN_B_LAYER_UINT8) { + unsigned char *data = (unsigned char*)vblayer->data; + /* allocate new verse bitmap layer data */ + unsigned char *new_data = (unsigned char*)alloc_verse_bitmap_layer_data(vblayer); + for(y=0; y<old_height && y<height; y++, i=y*t_width, j=y*t_old_width) { + for(x=0; x<old_width && y<width; x++, i++, j++) { + new_data[i] = data[j]; + } + } + MEM_freeN(vblayer->data); + vblayer->data = new_data; + } +} + +/* + * free data stored in verse bitmap layer + */ +void free_bitmap_layer_data(VBitmapLayer *vblayer) +{ + struct VerseSession *session = vblayer->vnode->session; + + /* free name of bitmap layer */ + MEM_freeN(vblayer->name); + + /* unsubscribe from verse bitmap layer */ + if(session->flag & VERSE_CONNECTED) + verse_send_b_layer_unsubscribe(vblayer->vnode->id, vblayer->id); + + /* free image data of bitmap layer */ + if(vblayer->data) MEM_freeN(vblayer->data); +} + +/* + * allocate data of verse bitmap layer + */ +static void *alloc_verse_bitmap_layer_data(VBitmapLayer *vblayer) +{ + struct VNode *vnode = vblayer->vnode; + unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width; + unsigned int t_height = ((VBitmapData*)(vnode->data))->t_height; + unsigned int size; + void *data; + + size = t_width*t_height; + + /* allocation of own data stored in verse bitmap layer */ + switch (vblayer->type) { + case VN_B_LAYER_UINT1: + data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint1"); + break; + case VN_B_LAYER_UINT8: + data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint8"); + break; + case VN_B_LAYER_UINT16: + data = (void*)MEM_mallocN(sizeof(unsigned int)*size, "VBLayer data uint16"); + break; + case VN_B_LAYER_REAL32: + data = (void*)MEM_mallocN(sizeof(float)*size, "VBLayer data float16"); + break; + case VN_B_LAYER_REAL64: + data = (void*)MEM_mallocN(sizeof(double)*size, "VBLayer data float32"); + break; + } + + return data; +} + +/* + * create verse bitmap layer + */ +VBitmapLayer *create_bitmap_layer( + VNode *vnode, + VLayerID layer_id, + const char *name, + VNBLayerType type) +{ + struct VBitmapLayer *vblayer; + unsigned int width = ((VBitmapData*)(vnode->data))->width; + unsigned int height = ((VBitmapData*)(vnode->data))->height; + + /* allocate memory for own verse bitmap layer */ + vblayer = (VBitmapLayer*)MEM_mallocN(sizeof(VBitmapLayer), "Verse Bitmap Layer"); + + /* verse bitmap layer will include pointer at parent verse node and own id */ + vblayer->vnode = vnode; + vblayer->id = layer_id; + + /* name of verse layer */ + vblayer->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "Verse Bitmap Layer name"); + vblayer->name[0] = '\0'; + strcpy(vblayer->name, name); + + /* type of data stored in verse bitmap layer */ + vblayer->type = type; + + /* we can allocate memory for layer data, when we know dimmension of layers; when + * we don't know it, then we will allocate this data when we will receive dimmension */ + if(width==0 || height==0) + vblayer->data = NULL; + else + vblayer->data = alloc_verse_bitmap_layer_data(vblayer); + + vblayer->flag = 0; + + return vblayer; +} + +/* + * free data of bitmap node + */ +void free_bitmap_node_data(VNode *vnode) +{ + if(vnode->data) { + struct VBitmapLayer *vblayer = (VBitmapLayer*)((VBitmapData*)(vnode->data))->layers.lb.first; + + /* free all VerseLayer data */ + while(vblayer) { + free_bitmap_layer_data(vblayer); + vblayer = vblayer->next; + } + + /* free all VerseLayers */ + BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers)); + } +} + +/* + * create data of bitmap node + */ +VBitmapData *create_bitmap_data() +{ + struct VBitmapData *vbitmap; + + vbitmap = (VBitmapData*)MEM_mallocN(sizeof(VBitmapData), "Verse Bitmap Data"); + + BLI_dlist_init(&(vbitmap->layers)); + vbitmap->queue.first = vbitmap->queue.last = NULL; + + vbitmap->width = 0; + vbitmap->height = 0; + vbitmap->depth = 0; + + vbitmap->image = NULL; + + vbitmap->post_bitmap_dimension_set = post_bitmap_dimension_set; + vbitmap->post_bitmap_layer_create = post_bitmap_layer_create; + vbitmap->post_bitmap_layer_destroy = post_bitmap_layer_destroy; + vbitmap->post_bitmap_tile_set = post_bitmap_tile_set; + + return vbitmap; +} + +/* + * callback function, dimension of image was changed, it is neccessary to + * crop all layers + */ +static void cb_b_dimension_set( + void *user_data, + VNodeID node_id, + uint16 width, + uint16 height, + uint16 depth) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + unsigned int old_width, old_height, t_old_width, t_old_height; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_dimension_set()\n"); +#endif + + /* backup old width and height */ + old_width = ((VBitmapData*)(vnode->data))->width; + old_height = ((VBitmapData*)(vnode->data))->height; + t_old_width = ((VBitmapData*)(vnode->data))->t_width; + t_old_height = ((VBitmapData*)(vnode->data))->t_height; + + /* set up new dimension of layers */ + ((VBitmapData*)(vnode->data))->width = width; + ((VBitmapData*)(vnode->data))->height = height; + ((VBitmapData*)(vnode->data))->depth = depth; + + /* we cache t_width because tiles aren't one pixel width */ + if((width % VN_B_TILE_SIZE)!=0) + ((VBitmapData*)(vnode->data))->t_width = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE; + else + ((VBitmapData*)(vnode->data))->t_width = width; + + /* we cache t_height because tiles aren't one pixel height */ + if((height % VN_B_TILE_SIZE)!=0) + ((VBitmapData*)(vnode->data))->t_height = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE; + else + ((VBitmapData*)(vnode->data))->t_height = height; + + /* crop resize all layers */ + vblayer = ((VBitmapData*)vnode->data)->layers.lb.first; + + while(vblayer) { + /* when this callback function received after cb_b_layer_create, + * then we have to allocate memory for verse bitmap layer data */ + if(!vblayer->data) vblayer->data = alloc_verse_bitmap_layer_data(vblayer); + /* crop/resize all verse bitmap layers */ + else change_layer_dimension(vblayer, old_width, old_height, t_old_width, t_old_height); + + vblayer = vblayer->next; + } + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_dimension_set(vnode); +} + +/* + * callback function, new layer channel of image was created + */ +static void cb_b_layer_create( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + const char *name, + VNBLayerType type) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_layer_create()\n"); +#endif + + /* when no layer exists, then new layer will be created */ + vblayer = create_bitmap_layer(vnode, layer_id, name, type); + + /* add verse bitmap layer to list of layers */ + BLI_dlist_add_item_index(&((VBitmapData*)vnode->data)->layers, vblayer, layer_id); + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_layer_create(vblayer); + +} + +/* + * callback function, existing layer of image was destroyed + */ +static void cb_b_layer_destroy( + void *user_data, + VNodeID node_id, + VLayerID layer_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + + if(!session) return; + + /* find node of this layer*/ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id); + if(!vblayer) return; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_layer_destroy()\n"); +#endif + + /* remove verse bitmap layer from list of layers */ + BLI_dlist_rem_item(&(((VBitmapData*)vnode->data)->layers), layer_id); + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_layer_destroy(vblayer); + + /* free data of verse bitmap layer */ + free_bitmap_layer_data(vblayer); + + /* free verse bitmap layer */ + MEM_freeN(vblayer); +} + +/* + * callback function, small part (8x8 pixels) was changed + */ +static void cb_b_tile_set( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + uint16 tile_x, + uint16 tile_y, + uint16 z, + VNBLayerType type, + const VNBTile *tile) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VBitmapLayer *vblayer; + unsigned int x, y, xs, ys, width, height, t_height, t_width, i, j; + + if(!session) return; + + /* try to find verse node in dynamic list nodes */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find verse bitmap layer in list of layers */ + vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id); + if(!vblayer) return; + + /* we have to have allocated memory for bitmap layer */ + if(!vblayer->data) return; + + width = ((VBitmapData*)vnode->data)->width; + height = ((VBitmapData*)vnode->data)->height; + + /* width of verse image including all tiles */ + t_height = ((VBitmapData*)vnode->data)->t_height; + /* height of verse image including all tiles */ + t_width = ((VBitmapData*)vnode->data)->t_width; + +#ifdef VERSE_DEBUG_PRINT + printf("\t cb_b_tile_set()\n"); +#endif + + xs = tile_x*VN_B_TILE_SIZE; + ys = tile_y*VN_B_TILE_SIZE; + + /* initial position in one dimension vblayer->data (y_start*width + x_start) */ + i = ys*t_width + xs; + /* intial position in one dimension tile array */ + j = 0; + + if(type==VN_B_LAYER_UINT8) { + unsigned char *data = (unsigned char*)vblayer->data; + for(y=ys; y<ys+VN_B_TILE_SIZE && y<height; y++, i=y*t_width+xs) + for(x=xs; x<xs+VN_B_TILE_SIZE && x<width; x++, i++, j++) + data[i] = (unsigned char)tile->vuint8[j]; + } + + /* post callback function */ + ((VBitmapData*)(vnode->data))->post_bitmap_tile_set(vblayer, xs, ys); +} + +/* + * set up all callbacks functions for image nodes + */ +void set_bitmap_callbacks(void) +{ + /* dimension (size) of bitmap was set up or changes (image will be croped) */ + verse_callback_set(verse_send_b_dimensions_set, cb_b_dimension_set, NULL); + + /* new layer (chanell) of image was added or created */ + verse_callback_set(verse_send_b_layer_create, cb_b_layer_create, NULL); + + /* existing layer was destroyed */ + verse_callback_set(verse_send_b_layer_destroy, cb_b_layer_destroy, NULL); + + /* some tile (small part 8x8 pixels of image was changed) */ + verse_callback_set(verse_send_b_tile_set, cb_b_tile_set, NULL); +} + +#endif + diff --git a/source/blender/blenkernel/intern/verse_geometry_node.c b/source/blender/blenkernel/intern/verse_geometry_node.c new file mode 100644 index 00000000000..bb3234d04fd --- /dev/null +++ b/source/blender/blenkernel/intern/verse_geometry_node.c @@ -0,0 +1,1665 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_verse.h" +#include "BKE_utildefines.h" + +#include "BIF_verse.h" + +#include "verse.h" + +/* function prototypes of static functions */ + +/* test functions for callback functions */ +static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3); + +/* callback functions */ +static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real); +static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id); +static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z); +static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); +static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id); +static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id); +static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); +static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); + +/* other static functions */ + +static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface); +static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert); +static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface); +static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer); + +static void send_verse_face(struct VerseFace *vface); + +static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z); +static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); + +static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface); +static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert); +static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert); +static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface); +static void increase_verse_verts_references(struct VerseFace *vface); +static void recalculate_verseface_normals(struct VNode *vnode); + +/* + * recalcute normals of all VerseFaces + */ +static void recalculate_verseface_normals(VNode *vnode) +{ + struct VLayer *vert_layer, *face_layer; + struct VerseFace *vface; + struct VerseVert *vvert; + + if(vnode->type != V_NT_GEOMETRY) return; + + vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + vvert = vert_layer->dl.lb.first; + while(vvert) { + vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0; + vvert = vvert->next; + } + + vface = face_layer->dl.lb.first; + while(vface) { + /* calculate face normals */ + if(vface->vvert3) { + CalcNormFloat4(vface->vvert0->co, vface->vvert1->co, + vface->vvert2->co, vface->vvert3->co, vface->no); + VecAddf(vface->vvert3->no, vface->vvert3->no, vface->no); + } + else + CalcNormFloat(vface->vvert0->co, vface->vvert1->co, + vface->vvert2->co, vface->no); + + /* calculate vertex normals ... it is averadge of all face normals using the vertex */ + VecAddf(vface->vvert0->no, vface->vvert0->no, vface->no); + VecAddf(vface->vvert1->no, vface->vvert1->no, vface->no); + VecAddf(vface->vvert2->no, vface->vvert2->no, vface->no); + + vface = vface->next; + } + + /* we have to normalise all vertex normals */ + vvert = vert_layer->dl.lb.first; + while(vvert) { + Normalise(vvert->no); + vvert = vvert->next; + } +} + +/* + * add created item to the queue and send it if possible + */ +void add_item_to_send_queue(ListBase *lb, void *item, short type) +{ + /* this prevent from adding duplicated faces */ + if(type==VERSE_FACE) { + struct Link *link = (Link*)lb->first; + while(link) { + if(link==item) { + if(((VerseFace*)item)->flag & FACE_SENT) { +/* printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/ + ((VerseFace*)item)->flag |= FACE_OBSOLETE; + } + return; + } + link = link->next; + } + } + + /* add item to sending queue (two way dynamic list) */ + BLI_addtail(lb, item); + + /* send item, when it is possible */ + switch (type) { + case VERSE_NODE: /* only first node in queue can be sent */ + if(lb->first==lb->last) + send_verse_node((VNode*)item); + break; + case VERSE_LINK: /* both object between have to exist */ + if(((VLink*)item)->flag & LINK_SEND_READY) + send_verse_link((VLink*)item); + break; + case VERSE_LAYER: + if(((VLayer*)item)->vnode->flag & NODE_RECEIVED) + send_verse_layer((VLayer*)item); + break; + case VERSE_VERT: + if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED) + send_verse_vertex((VerseVert*)item); + break; + case VERSE_FACE: /* all vertexes of face have to be received */ + if(((VerseFace*)item)->flag & FACE_SEND_READY) + send_verse_face((VerseFace*)item); + break; + case VERSE_TAG: + send_verse_tag((VTag*)item); + break; + case VERSE_TAG_GROUP: + send_verse_taggroup((VTagGroup*)item); + break; + case VERSE_VERT_UINT32: /* parent item has to exist */ + if( ((verse_parent*)((uint32_item*)item)->parent)->id != -1) + send_verse_vert_uint32((uint32_item*)item, type); + break; + case VERSE_VERT_REAL32: /* parent item has to exist */ + if( ((verse_parent*)((real32_item*)item)->parent)->id != -1) + send_verse_vert_real32((real32_item*)item, type); + break; + case VERSE_VERT_VEC_REAL32: /* parent item has to exist */ + if( ((verse_parent*)((vec_real32_item*)item)->parent)->id != -1) + send_verse_vert_vec_real32((vec_real32_item*)item, type); + break; + case VERSE_FACE_UINT8: /* parent item has to exist */ + if( ((verse_parent*)((uint8_item*)item)->parent)->id != -1) + send_verse_face_uint8((uint8_item*)item, type); + break; + case VERSE_FACE_UINT32: /* parent item has to exist */ + if( ((verse_parent*)((uint32_item*)item)->parent)->id != -1) + send_verse_face_uint32((uint32_item*)item, type); + break; + case VERSE_FACE_REAL32: /* parent item has to exist */ + if( ((verse_parent*)((real32_item*)item)->parent)->id != -1) + send_verse_face_real32((real32_item*)item, type); + break; + case VERSE_FACE_QUAT_UINT32: /* parent item has to exist */ + if( ((verse_parent*)((quat_uint32_item*)item)->parent)->id != -1) + send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type); + break; + case VERSE_FACE_QUAT_REAL32: /* parent item has to exist */ + if( ((verse_parent*)((quat_real32_item*)item)->parent)->id != -1) + send_verse_face_corner_quat_real32((quat_real32_item*)item, type); + break; + } +} + +/* + * return VerseLayer with certain content (vertexes, polygons, in the + * future: weight, red color, etc.) + */ +VLayer* find_verse_layer_type(VGeomData *geom, short content) +{ + struct VLayer *vlayer = NULL; + + switch(content) { + case VERTEX_LAYER: + /* VERTEX_LAYER equals 0 and vertex layer is + * always in 1st layer */ + vlayer = geom->layers.da.items[VERTEX_LAYER]; + break; + case POLYGON_LAYER: + /* POLYGON_LAYER equals 1 and vertex layer is + * always in 2nd layer */ + vlayer = geom->layers.da.items[POLYGON_LAYER]; + break; + } + + return vlayer; +} + +/* + * increase references of VerseVerts of new VerseFace + */ +static void increase_verse_verts_references(VerseFace *vface) +{ + if(vface->vvert0) vface->vvert0->counter++; + if(vface->vvert1) vface->vvert1->counter++; + if(vface->vvert2) vface->vvert2->counter++; + if(vface->vvert3) vface->vvert3->counter++; +} + +/* + * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed + * then this VerseFace is only removed from list of orphans) + */ +static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface) +{ + /* remove vface from list of orphans */ + BLI_remlink(&(vlayer->orphans), vface); + /* increase references of all vertexes beying part of this face*/ + increase_verse_verts_references(vface); + + if(vface->flag & FACE_RECEIVED) { + /* set up vface flag */ + vface->flag &= ~FACE_RECEIVED; + /* move vface to dynamic list of faces */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id); + /* recalculate all vertex and faces normals */ + recalculate_verseface_normals(vnode); + /* post create action (change local data) */ + ((VGeomData*)vnode->data)->post_polygon_create(vface); + } + else if(vface->flag & FACE_CHANGED) { + /* set up vface flag */ + vface->flag &= ~FACE_CHANGED; + /* move vface to dynamic list of faces */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id); + /* recalculate all vertex and faces normals */ + recalculate_verseface_normals(vnode); + /* post create action (change local data) */ + ((VGeomData*)vnode->data)->post_polygon_set_corner(vface); + } +} + +/* + * find all VerseFaces waiting in queue, which needs id of new VerseVert + */ +static void find_unsent_faces(VNode *vnode, VerseVert *vvert) +{ + VLayer *vlayer; + VerseFace *vface, *next_vface; + + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + if(vlayer) { + vface = vlayer->queue.first; + while(vface) { + next_vface = vface->next; + if(vface->vvert0==vvert) { + vface->v0 = vvert->id; + vface->counter--; + } + else if(vface->vvert1==vvert) { + vface->v1 = vvert->id; + vface->counter--; + } + else if(vface->vvert2==vvert) { + vface->v2 = vvert->id; + vface->counter--; + } + else if(vface->vvert3==vvert){ + vface->v3 = vvert->id; + vface->counter--; + } + + if(vface->counter<1 && !(vface->flag & FACE_SENT)) + send_verse_face(vface); + + vface = next_vface; + } + } +} + +/* + * find all VerseFace orphans, which needs incoming VerseVert + */ +static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert) +{ + VLayer *vlayer; + VerseFace *vface, *next_vface; + unsigned int vertex_id = vvert->id; + + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + if(vlayer) { + vface = vlayer->orphans.first; + while(vface){ + next_vface = vface->next; + if(vface->v0 == vertex_id) { + vface->vvert0 = vvert; + vface->counter--; + } + else if(vface->v1 == vertex_id) { + vface->vvert1 = vvert; + vface->counter--; + } + else if(vface->v2 == vertex_id) { + vface->vvert2 = vvert; + vface->counter--; + } + else if(vface->v3 == vertex_id) { + vface->vvert3 = vvert; + vface->counter--; + } + if(vface->counter<1) { + /* moving VerseFace orphan to dlist */ + move_face_orphan_to_dlist(vnode, vlayer, vface); + } + vface = next_vface; + } + } +} + +/* + * return number of VerseVerts missing to incoming VerseFace, set up pointers + * at VerseVerts + */ +static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface) +{ + struct VLayer *vert_layer; + struct VerseVert *vvert; + int counter=0; + + vert_layer = find_verse_layer_type(geom, VERTEX_LAYER); + + if(vface->v0 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0); + if(vvert==NULL) counter++; + else vface->vvert0 = vvert; + } + if(vface->v1 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1); + if(vvert==NULL) counter++; + else vface->vvert1 = vvert; + } + if(vface->v2 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2); + if(vvert==NULL) counter++; + else vface->vvert2 = vvert; + } + if(vface->v3 != -1){ + vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3); + if(vvert==NULL) counter++; + else vface->vvert3 = vvert; + } + + return counter; +} + +/* + * try to find changed VerseFace in sending queue + */ +static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id) +{ + struct VerseFace *vface = vlayer->queue.first; + + while(vface){ + if(vface->id == polygon_id && vface->flag & FACE_CHANGED) { + return vface; + } + vface = vface->next; + } + return NULL; +} + +/* + * try to find VerseFace in queue + */ +static VerseFace* find_verse_face_in_queue( + VLayer *vlayer, + VNodeID node_id, + uint32 polygon_id, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + struct VerseFace *vface = vlayer->queue.first; + + while(vface){ + if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){ + vface->id = polygon_id; + vface->vlayer = vlayer; + return vface; + } + vface = vface->next; + } + return NULL; +} + +/* + * try to find VerseVert in queue + */ +static VerseVert* find_verse_vert_in_queue( + VLayer *vlayer, + VNodeID node_id, + uint32 vertex_id, + real32 x, + real32 y, + real32 z) +{ + struct VerseVert *vvert = vlayer->queue.first; + + while(vvert){ + if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z)) + { + vvert->id = vertex_id; + vvert->vlayer = vlayer; + + return vvert; + } + vvert = vvert->next; + } + + return NULL; +} + + +/* + * send quat of float values to verse server (4x32 bits) + */ +void send_verse_face_corner_quat_real32(quat_real32_item *item, short type) +{ + struct VerseFace *vface = (VerseFace*)item->parent; + + verse_send_g_polygon_set_corner_real32( + vface->vlayer->vnode->id, + item->layer_id, + vface->id, + item->value[0], + item->value[1], + item->value[2], + item->value[3]); +} + +/* + * send quat of unsigned int values to verse server (4x32 bits) + */ +void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type) +{ + struct VerseFace *vface = (VerseFace*)item->parent; + + verse_send_g_polygon_set_corner_uint32( + vface->vlayer->vnode->id, + item->layer_id, + vface->id, + item->value[0], + item->value[1], + item->value[2], + item->value[3]); +} + +/* + * send float value (32 bits) to verse server + */ +void send_verse_face_real32(real32_item *item, short type) +{ + struct VerseFace *vface = (VerseFace*)item->parent; + + verse_send_g_polygon_set_face_real32( + vface->vlayer->vnode->id, + item->layer_id, + vface->id, + item->value); +} + +/* + * send unsigned integer (32 bits) to verse server + */ +void send_verse_face_uint32(uint32_item *item, short type) +{ + struct VerseFace *vface = (VerseFace*)item->parent; + + verse_send_g_polygon_set_face_uint32( + vface->vlayer->vnode->id, + item->layer_id, + vface->id, + item->value); +} + +/* + * send unsigned char (8 bits) to verse server + */ +void send_verse_face_uint8(uint8_item *item, short type) +{ + struct VerseFace *vface = (VerseFace*)item->parent; + + verse_send_g_polygon_set_face_uint8( + vface->vlayer->vnode->id, + item->layer_id, + vface->id, + item->value); +} + +/* + * send vector of float values to verse server (3x32 bits) + */ +void send_verse_vert_vec_real32(vec_real32_item *item, short type) +{ + struct VerseVert *vvert = (VerseVert*)item->parent; + + verse_send_g_vertex_set_xyz_real32( + vvert->vlayer->vnode->id, + item->layer_id, + vvert->id, + item->value[0], + item->value[1], + item->value[2]); +} + +/* + * send float value (32 bits) to verse server + */ +void send_verse_vert_real32(real32_item *item, short type) +{ + struct VerseVert *vvert = (VerseVert*)item->parent; + + verse_send_g_vertex_set_real32( + vvert->vlayer->vnode->id, + item->layer_id, + vvert->id, + item->value); +} + +/* + * send unsigned integer (32 bits) to verse server + */ +void send_verse_vert_uint32(uint32_item *item, short type) +{ + struct VerseVert *vvert = (VerseVert*)item->parent; + + verse_send_g_vertex_set_uint32( + vvert->vlayer->vnode->id, + item->layer_id, + vvert->id, + item->value); +} + +/* + * send delete command to verse server + */ +void send_verse_vertex_delete(VerseVert *vvert) +{ + verse_session_set(vvert->vlayer->vnode->session->vsession); + + vvert->flag |= VERT_OBSOLETE; + + verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id); +} + +/* + * send VerseLayer to verse server + */ +void send_verse_layer(VLayer *vlayer) +{ + verse_session_set(vlayer->vnode->session->vsession); + + verse_send_g_layer_create( + vlayer->vnode->id, + vlayer->id, + vlayer->name, + vlayer->type, + vlayer->def_int, + vlayer->def_real); +} + +/* + * send VerseVert to verse server + */ +void send_verse_vertex(VerseVert *vvert) +{ + /* new vertex position will not be sent, when vertex was deleted */ + if(vvert->flag & VERT_OBSOLETE) return; + + verse_session_set(vvert->vlayer->vnode->session->vsession); + + verse_send_g_vertex_set_xyz_real32( + vvert->vlayer->vnode->id, + vvert->vlayer->id, + vvert->id, + vvert->co[0], + -vvert->co[2], + vvert->co[1]); +} + +/* + * send delete command to verse server + */ +void send_verse_face_delete(VerseFace *vface) +{ + verse_session_set(vface->vlayer->vnode->session->vsession); + + vface->flag |= FACE_DELETED; + + verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id); +} + +/* + * send VerseFace to verse server + */ +static void send_verse_face(VerseFace *vface) +{ + verse_session_set(vface->vlayer->vnode->session->vsession); + + vface->flag |= FACE_SENT; + + if(vface->v3 != -1) { +/* printf("\tSEND: VerseFace: %d, %d, %d, %d, %d\n", vface->id, vface->v0, vface->v3, vface->v2, vface->v1);*/ + verse_send_g_polygon_set_corner_uint32( + vface->vlayer->vnode->id, + vface->vlayer->id, + vface->id, + vface->v0, + vface->v3, /* verse use clock-wise winding */ + vface->v2, + vface->v1); /* verse use clock-wise winding */ + } + else { +/* printf("\tSEND: VerseFace: %d, %d, %d, %d, %d\n", vface->id, vface->v0, vface->v2, vface->v1, vface->v3);*/ + verse_send_g_polygon_set_corner_uint32( + vface->vlayer->vnode->id, + vface->vlayer->id, + vface->id, + vface->v0, + vface->v2, /* verse use clock-wise winding */ + vface->v1, /* verse use clock-wise winding */ + vface->v3); + } +} + +/* + * free VerseVert + */ +static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert) +{ + /* free VerseVert */ + BLI_freelinkN(&(vlayer->orphans), vvert); +} + +/* + * free VerseFace (and blender face) + */ +static void free_verse_face(VLayer *vlayer, VerseFace *vface) +{ + /* free VerseFace */ + BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id); +} + +/* + * free VerseLayer data + */ +static void free_verse_layer_data(VNode *vnode, VLayer *vlayer) +{ + struct VerseFace *vface; + struct VerseVert *vvert; + + /* set up EditVert->vvert and EditFace->vface pointers to NULL */ + switch(vlayer->content) { + case VERTEX_LAYER: + vvert = (VerseVert*)vlayer->dl.lb.first; + while(vvert) { + ((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert); + vvert = vvert->next; + } + break; + case POLYGON_LAYER: + vface = (VerseFace*)vlayer->dl.lb.first; + while(vface) { + ((VGeomData*)vnode->data)->post_polygon_free_constraint(vface); + vface = vface->next; + } + break; + default: + break; + } + /* free Verse Layer name */ + MEM_freeN(vlayer->name); + /* destroy VerseLayer data (vertexes, polygons, etc.) */ + BLI_dlist_destroy(&(vlayer->dl)); + /* free unsent data */ + BLI_freelistN(&(vlayer->queue)); + /* free orphans */ + BLI_freelistN(&(vlayer->orphans)); +} + +/* + * free all unneeded VerseVerts waiting for deleting + */ +static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface) +{ + struct VLayer *vert_vlayer; + + /* find layer containing vertexes */ + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + + /* free all "deleted" VerseVert waiting for deleting this VerseFace */ + + if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0); + free_verse_vertex(vert_vlayer, vface->vvert0); + vface->vvert0 = NULL; + } + if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1); + free_verse_vertex(vert_vlayer, vface->vvert1); + vface->vvert1 = NULL; + } + if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2); + free_verse_vertex(vert_vlayer, vface->vvert2); + vface->vvert2 = NULL; + } + if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3); + free_verse_vertex(vert_vlayer, vface->vvert3); + vface->vvert3 = NULL; + } +} + +/* + * This function create VerseVert and returns pointer on this vertex + */ +VerseVert* create_verse_vertex( + VLayer *vlayer, + uint32 vertex_id, + real32 x, + real32 y, + real32 z) +{ + struct VerseVert *vvert; + + vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert"); + + /* set up pointer on parent node */ + vvert->vlayer = vlayer; + vvert->id = vertex_id; + /* position */ + vvert->co[0] = x; + vvert->co[1] = y; + vvert->co[2] = z; + /* normal */ + vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0; + /* blender internals */ + vvert->flag = 0; + vvert->counter = 0; + vvert->vertex = NULL; + + /* increase layer counter of vertexes */ + vlayer->counter++; + + return vvert; +} + +/* + * this function will create new VerseFace and will return pointer on such Face + */ +VerseFace* create_verse_face( + VLayer *vlayer, + uint32 polygon_id, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + struct VerseFace *vface; + + vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace"); + + /* verse data */ + vface->vlayer = vlayer; + vface->id = polygon_id; + + vface->vvert0 = NULL; + vface->vvert1 = NULL; + vface->vvert2 = NULL; + vface->vvert3 = NULL; + + vface->v0 = v0; + vface->v1 = v1; + vface->v2 = v2; + vface->v3 = v3; + + /* blender data */ + vface->face = NULL; + vface->flag = 0; + vface->counter = 4; + + /* increase layer counter of faces */ + vlayer->counter++; + + return vface; +} + +/* + * create and return VerseLayer + */ +VLayer *create_verse_layer( + VNode *vnode, + VLayerID layer_id, + const char *name, + VNGLayerType type, + uint32 def_integer, + real64 def_real) +{ + struct VLayer *vlayer; + + /* add layer to the DynamicList */ + vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer"); + + /* store all relevant info to the vlayer and set up vlayer */ + vlayer->vnode = vnode; + vlayer->id = layer_id; + vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name"); + strcpy(vlayer->name, name); + vlayer->type = type; + vlayer->def_int = def_integer; + vlayer->def_real = def_real; + + if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0)) + vlayer->content = VERTEX_LAYER; + else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1)) + vlayer->content = POLYGON_LAYER; + else + vlayer->content = -1; + + /* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/ + BLI_dlist_init(&(vlayer->dl)); + /* initialization of queue of layer */ + vlayer->queue.first = vlayer->queue.last = NULL; + /* initialization of list of orphans */ + vlayer->orphans.first = vlayer->orphans.last = NULL; + /* initialize number of sent items (vertexes, faces, etc) */ + vlayer->counter = 0; + /* initialize flag */ + vlayer->flag = 0; + + /* set up methods */ + vlayer->post_layer_create = post_layer_create; + vlayer->post_layer_destroy = post_layer_destroy; + + return vlayer; +} + +/* + * create geometry data + */ +VGeomData *create_geometry_data(void) +{ + struct VGeomData *geom; + + geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData"); + BLI_dlist_init(&(geom->layers)); + geom->vlink = NULL; + geom->queue.first = geom->queue.last = NULL; + geom->mesh = NULL; + geom->editmesh = NULL; + + /* set up methods */ + geom->post_vertex_create = post_vertex_create; + geom->post_vertex_set_xyz = post_vertex_set_xyz; + geom->post_vertex_delete = post_vertex_delete; + geom->post_vertex_free_constraint = post_vertex_free_constraint; + geom->post_polygon_create = post_polygon_create; + geom->post_polygon_set_corner = post_polygon_set_corner; + geom->post_polygon_delete = post_polygon_delete; + geom->post_polygon_free_constraint = post_polygon_free_constraint; + geom->post_geometry_free_constraint = post_geometry_free_constraint; + geom->post_polygon_set_uint8 = post_polygon_set_uint8; + + return geom; +} + +/* + * callback function: vertex crease was set + */ +static void cb_g_crease_set_vertex( + void *user_data, + VNodeID node_id, + const char *layer, + uint32 def_crease) +{ +/* struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode;*/ +} + +/* + * callback function: edge crease was set + */ +static void cb_g_crease_set_edge( + void *user_data, + VNodeID node_id, + const char *layer, + uint32 def_crease) +{ +/* struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode;*/ +} + +/* + * callback function: float value for polygon was set up + */ +static void cb_g_polygon_set_face_real32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + real32 value) +{ +/* struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode;*/ +} + +/* + * callback function: int values for polygon was set up + */ +static void cb_g_polygon_set_face_uint32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + uint32 value) +{ +/* struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode;*/ +} + +static uint8_item *create_uint8_item(void) +{ + struct uint8_item *item; + + item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item"); + item->value = 0; + + return item; +} + +/* + * callback function: uint8 value for polygon was set up + */ +static void cb_g_polygon_set_face_uint8( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + uint8 value) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct uint8_item *item; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + /* find layer containing uint_8 data */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + + /* try to find item*/ + item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); + + if(item) { + item->value = value; + } + else { + item = create_uint8_item(); + BLI_dlist_add_item_index(&(vlayer->dl), item, polygon_id); + item->value = value; + } +} + +/* + * callback function: float value for polygon corner was set up + */ +static void cb_g_polygon_set_corner_real32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + real32 v0, + real32 v1, + real32 v2, + real32 v3) +{ +} + +/* + * callback function: polygon is deleted + */ +static void cb_g_polygon_delete( + void *user_data, + VNodeID node_id, + uint32 polygon_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + VNode *vnode; + VLayer *vlayer; + VerseFace *vface; + + if(!session) return; + + /* find needed node (we can be sure, that it is geometry node) */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + + /* find layer containing faces */ + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + /* find wanted VerseFace */ + vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id); + + if(!vface) return; + + ((VGeomData*)vnode->data)->post_polygon_delete(vface); + + /* decrease references at coresponding VerseVertexes */ + vface->vvert0->counter--; + vface->vvert1->counter--; + vface->vvert2->counter--; + if(vface->vvert3) vface->vvert3->counter--; + + /* delete unneeded VerseVertexes */ + free_unneeded_verseverts_of_verseface(vnode, vface); + + free_verse_face(vlayer, vface); +} + +/* + * we have to test corretness of incoming data from verse server + * no two vertexes can have the same index + */ +static char test_polygon_set_corner_uint32( + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3)) + return 0; + else + return 1; +} + +/* + * try to find verse layer in sending queue of verse geometry node + */ +static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id) +{ + struct VLayer *vlayer; + + /* try to find verse layyer in sending queue */ + vlayer = ((VGeomData*)vnode->data)->queue.first; + while(vlayer) { + if(vlayer->id==layer_id) return vlayer; + vlayer = vlayer->next; + } + + return NULL; +} + +/* + * callback function: new polygon (face) created or existing polygon was changed + */ +static void cb_g_polygon_set_corner_uint32( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + uint32 polygon_id, + uint32 v0, + uint32 v1, + uint32 v2, + uint32 v3) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + struct VerseFace *vface=NULL; + + if(!session) return; + + /* try to find VerseNode */ + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find VerseLayer */ + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + if(!vlayer) return; + + /* we have to test coretness of incoming data */ + if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return; + +/* printf("\tRECEIVE VerseFace: %d, %d, %d, %d, %d\n", polygon_id, v0, v1, v2, v3);*/ + + /* Blender uses different order of vertexes */ + if(v3!=-1) { /* quat swap */ + unsigned int v; v = v1; v1 = v3; v3 = v; + } + else { /* triangle swap */ + unsigned int v; v = v1; v1 = v2; v2 = v; + } + + /* try to find VerseFace */ + vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id); + + /* try to find modified VerseFace */ + if(!vface) { + vface = find_changed_verse_face_in_queue(vlayer, polygon_id); + if(vface) { + BLI_remlink(&(vlayer->queue), (void*)vface); + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id); +/* printf("\treceived changed face (changed by this app)\n");*/ + } + } + + if(!vface) { +/* printf("\tno vface\n");*/ + /* try to find VerseFace in list of VerseVaces created by me and set up polygon and + * layer ids */ + vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3); + + if(vface){ +/* printf("\tremove from vface queue\n");*/ + /* I creeated this face ... remove VerseFace from queue */ + BLI_remlink(&(vlayer->queue), (void*)vface); + } + else { +/* printf("\tcreate vface\n");*/ + /* some other client created this face*/ + vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3); + } + + vface->flag &= ~FACE_SENT; + + /* return number of missing verse vertexes */ + vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface); + + if(vface->counter < 1) { + /* when VerseFace received all needed VerseFaces, then it is moved + * to list of VerseFaces */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id); + increase_verse_verts_references(vface); + recalculate_verseface_normals(vnode); + ((VGeomData*)vnode->data)->post_polygon_create(vface); + } + else { +/* printf("\torphan vface\n");*/ + /* when all needed VerseVertexes weren't received, then VerseFace is moved to + * the list of orphans waiting on needed vertexes */ + vface->flag |= FACE_RECEIVED; + BLI_addtail(&(vlayer->orphans), (void*)vface); + } + } + else { + VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); +/* printf("\tvface changed\n");*/ + /* VerseVertexes of existing VerseFace were changed (VerseFace will use some different + * VerseVertexes or it will use them in different order) */ + + /* initialize count of unreceived vertexes needed for this face */ + vface->counter = 4; + + /* 1st corner */ + if(vface->vvert0->id != v0) { + /* decrease references of obsolete vertexes*/ + vface->vvert0->counter--; + /* delete this vertex, when it isn't used by any face and it was marked as deleted */ + if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0); + free_verse_vertex(vert_vlayer, vface->vvert0); + } + /* try to set up new pointer at verse vertex */ + vface->v0 = v0; + vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0); + if(vface->vvert0) { + /* increase references at new vertex */ + vface->vvert0->counter++; + /* decrease count of needed vertex to receive */ + vface->counter--; + } + + } + else + /* this corner wasn't changed */ + vface->counter--; + + /* 2nd corner */ + if(vface->vvert1->id != v1) { + vface->vvert1->counter--; + if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1); + free_verse_vertex(vert_vlayer, vface->vvert1); + } + vface->v1 = v1; + vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1); + if(vface->vvert1) { + vface->vvert1->counter++; + vface->counter--; + } + } + else + vface->counter--; + + /* 3rd corner */ + if(vface->vvert2->id != v2) { + vface->vvert2->counter--; + if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2); + free_verse_vertex(vert_vlayer, vface->vvert2); + } + vface->v2 = v2; + vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2); + if(vface->vvert2) { + vface->vvert2->counter++; + vface->counter--; + } + } + else + vface->counter--; + + /* 4th corner */ + if(vface->vvert3) { + if(vface->vvert3->id != v3) { + vface->vvert3->counter--; + if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) { + ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3); + free_verse_vertex(vert_vlayer, vface->vvert3); + } + vface->v3 = v3; + if(v3 != -1) { + vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3); + if(vface->vvert3) { + vface->vvert3->counter++; + vface->counter--; + } + } + else { + /* this is some special case, this face hase now only 3 corners + * quat -> triangle */ + vface->vvert3 = NULL; + vface->counter--; + } + } + } + else if(v3 != -1) + /* this is some special case, 4th corner of this polygon was created + * triangle -> quat */ + vface->v3 = v3; + vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3); + if(vface->vvert3) { + vface->vvert3->counter++; + vface->counter--; + } + else { + vface->v3 = -1; + vface->counter--; + } + + vface->flag &= ~FACE_SENT; + vface->flag |= FACE_CHANGED; + + if(vface->counter<1) { + vface->flag &= ~FACE_CHANGED; + recalculate_verseface_normals(vnode); + ((VGeomData*)vnode->data)->post_polygon_set_corner(vface); + } + else { + /* when all needed VerseVertexes weren't received, then VerseFace is added to + * the list of orphans waiting on needed vertexes */ + BLI_dlist_rem_item(&(vlayer->dl), vface->id); + BLI_addtail(&(vlayer->orphans), (void*)vface); + } + } +} + +/* + * callback function: float value was set up for VerseVert with vertex_id + */ +static void cb_g_vertex_set_real32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 vertex_id, + real32 value) +{ +/* struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode;*/ +} + +/* + * callback function: int value was set up for VerseVert with vertex_id + */ +static void cb_g_vertex_set_uint32( + void *user_def, + VNodeID node_id, + VLayerID layer_id, + uint32 vertex_id, + uint32 value) +{ +/* struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode;*/ +} + +/* + * callback function: polygon was deleted + */ +static void cb_g_vertex_delete_real32( + void *user_data, + VNodeID node_id, + uint32 vertex_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + VNode *vnode=NULL; + VLayer *vert_vlayer=NULL; + VerseVert *vvert=NULL; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + + vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id); + + if(!vvert) return; + + if(vvert->counter < 1) { + ((VGeomData*)vnode->data)->post_vertex_delete(vvert); + BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id); + } + else { + /* some VerseFace(s) still need VerseVert, remove verse vert from + * list verse vertexes and put it to list of orphans */ + vvert->flag |= VERT_DELETED; + BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id); + BLI_addtail(&(vert_vlayer->orphans), vvert); + } +} + +/* + * callback function: position of one vertex was changed or new vertex was created + */ +static void cb_g_vertex_set_xyz_real32( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + uint32 vertex_id, + real32 x, + real32 y, + real32 z) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode = NULL; + struct VLayer *vlayer = NULL; + struct VerseVert *vvert = NULL; + real32 tmp; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode)return; + + vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); + if(!vlayer) return; + + /* switch axis orientation */ + tmp = -y; + y = z; + z = tmp; + + if(vlayer->id == 0) { + /* try to pick up verse vert from DynamicList */ + vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id); + + if(vvert) { + if(vvert->flag & VERT_OBSOLETE) return; + + if (vvert->flag & VERT_LOCKED) { + if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) { + if (!(vvert->flag & VERT_POS_OBSOLETE)) + vvert->flag &= ~VERT_LOCKED; + recalculate_verseface_normals(vnode); + ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert); + } + } + else { + if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) { + vvert->co[0] = x; + vvert->co[1] = y; + vvert->co[2] = z; + + recalculate_verseface_normals(vnode); + ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert); + } + } + } + else { + /* create new verse vert */ + + /* test if we are authors of this vertex :-) */ + vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z); + + if(vvert) { + /* remove vert from queue */ + BLI_remlink(&(vlayer->queue), (void*)vvert); + /* add vvert to the dynamic list */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id); + /* set VerseVert flags */ + vvert->flag |= VERT_RECEIVED; + if(!(vvert->flag & VERT_POS_OBSOLETE)) + vvert->flag &= ~VERT_LOCKED; + /* find VerseFaces orphans */ + find_vlayer_orphans(vnode, vvert); + /* find unsent VerseFaces */ + find_unsent_faces(vnode, vvert); + } + else { + /* create new VerseVert */ + vvert = create_verse_vertex(vlayer, vertex_id, x, y, z); + /* add VerseVert to list of VerseVerts */ + BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id); + /* set VerseVert flags */ + vvert->flag |= VERT_RECEIVED; + /* find VerseFaces orphans */ + find_vlayer_orphans(vnode, vvert); + } + + ((VGeomData*)vnode->data)->post_vertex_create(vvert); + } + } +} + +/* + * callback function for destroyng of verse layer + */ +static void cb_g_layer_destroy( + void *user_data, + VNodeID node_id, + VLayerID layer_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLayer *vlayer; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id); + if(!vnode) return; + + vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id); + + if(vlayer){ + /* free VerseLayer data */ + free_verse_layer_data(vnode, vlayer); + /* remove VerseLayer from list of verse layers */ + BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id); + /* do client dependent actions */ + vlayer->post_layer_destroy(vlayer); + /* free vlayer itself */ + MEM_freeN(vlayer); + } + +} + +/* + * callback function: new layer was created + */ +static void cb_g_layer_create( + void *user_data, + VNodeID node_id, + VLayerID layer_id, + const char *name, + VNGLayerType type, + uint32 def_integer, + real64 def_real) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode=NULL; + struct VLayer *vlayer=NULL; + + if(!session) return; + + /* find node of this layer*/ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + if(!vnode) return; + + /* when we created this layer, then subscribe to this layer */ + if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE) + verse_send_g_layer_subscribe(node_id, layer_id, 0); + + /* try to find */ + if(vnode->owner_id == VN_OWNER_MINE) + vlayer = find_vlayer_in_sending_queue(vnode, layer_id); + + if(vlayer) { + /* remove vlayer form sending queue add verse layer to list of verse layers */ + BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer); + BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id); + /* send all not sent vertexes to verse server + * other items waiting in sending queue will be automaticaly sent to verse server, + * when verse vertexes will be received from verse server */ + if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) { + struct VerseVert *vvert = (VerseVert*)vlayer->queue.first; + while(vvert) { + send_verse_vertex(vvert); + vvert = vvert->next; + } + } + } + else { + /* create new VerseLayer */ + vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real); + /* add layer to the list of VerseLayers */ + BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id); + } + + vlayer->flag |= LAYER_RECEIVED; + + /* post callback function */ + vlayer->post_layer_create(vlayer); +} + +/* + * this function will send destroy commands for all VerseVertexes and + * VerseFaces to verse server, but it will not send destroy commands + * for VerseLayers or geometry node, it can be used in other functions + * (undo, destroy geom node, some edit mesh commands, ... ), parameter of + * this function has to be geometry verse node + */ +void destroy_geometry(VNode *vnode) +{ + struct VLayer *vert_vlayer, *face_vlayer; + struct VerseFace *vface; + struct VerseVert *vvert; + + if(vnode->type != V_NT_GEOMETRY) return; + + face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + vface = face_vlayer->dl.lb.first; + + while(vface) { + send_verse_face_delete(vface); + vface = vface->next; + } + + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + vvert = vert_vlayer->dl.lb.first; + + while(vvert) { + send_verse_vertex_delete(vvert); + vvert = vvert->next; + } + + /* own destruction of local verse date will be executed, when client will + * receive apropriate callback commands from verse server */ +} + +/* + * free VGeomData + */ +void free_geom_data(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + struct VLayer *vlayer; + + if(vnode->data){ + vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first; + while(vlayer){ + /* unsubscribe from layer */ + if(session->flag & VERSE_CONNECTED) + verse_send_g_layer_unsubscribe(vnode->id, vlayer->id); + /* free VerseLayer data */ + free_verse_layer_data(vnode, vlayer); + /* next layer */ + vlayer = vlayer->next; + } + /* free constraint between vnode and mesh */ + ((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode); + /* free all VerseLayers */ + BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers)); + } +} + +void set_geometry_callbacks(void) +{ + /* new layer created */ + verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL); + /* layer was destroyed */ + verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL); + + /* position of vertex was changed */ + verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL); + /* vertex was deleted */ + verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL); + + /* callback functions for values being associated with vertexes */ + verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL); + verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL); + + /* new polygon was created / vertex(es) of polygon was set */ + verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL); + /* polygon was deleted */ + verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL); + + /* callback functions for values being associated with polygon corners */ + verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL); + /* callback functions for values being associated with faces */ + verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL); + verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL); + verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL); + + /* crease of vertex was set */ + verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL); + /* crease of edge was set */ + verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL); +} + +#endif diff --git a/source/blender/blenkernel/intern/verse_node.c b/source/blender/blenkernel/intern/verse_node.c new file mode 100644 index 00000000000..570d3a2df5c --- /dev/null +++ b/source/blender/blenkernel/intern/verse_node.c @@ -0,0 +1,735 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" + +#include "BIF_verse.h" + +#include "BKE_verse.h" + +#include "verse.h" + +/* function prototypes of static functions */ + /* for tags */ +static void free_verse_tag_data(struct VTag *vtag); +static struct VTag *find_tag_in_queue(struct VTagGroup *vtaggroup, const char *name); +static struct VTag *create_verse_tag(struct VTagGroup *vtaggroup, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); + /* for verse tag groups */ +static void free_verse_taggroup_data(struct VTagGroup *taggroup); +static struct VTagGroup *find_taggroup_in_queue(struct VNode *vnode, const char *name); +static struct VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name); + /* for verse nodes */ +static void move_verse_node_to_dlist(struct VerseSession *session, VNodeID vnode_id); + /* function prototypes of node callback functions */ +static void cb_tag_destroy(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id); +static void cb_tag_create(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); +static void cb_tag_group_destroy(void *user_data, VNodeID node_id, uint16 group_id); +static void cb_tag_group_create(void *user_data, VNodeID node_id, uint16 group_id, const char *name); +static void cb_node_name_set(void *user_data, VNodeID node_id, const char *name); +static void cb_node_destroy(void *user_data, VNodeID node_id); +static void cb_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeID owner_id); + +/* + * send new tag to verse server + */ +void send_verse_tag(VTag *vtag) +{ + verse_send_tag_create(vtag->vtaggroup->vnode->id, + vtag->vtaggroup->id, + vtag->id, + vtag->name, + vtag->type, + vtag->tag); +} + +/* + * free tag data + */ +static void free_verse_tag_data(VTag *vtag) +{ + /* free name of verse tag */ + MEM_freeN(vtag->name); + /* free value of tag */ + MEM_freeN(vtag->tag); +} + +/* + * try to find tag in sending queue ... if tag will be found, then + * this function will removed tag from queue and will return pointer + * at this tag + */ +static VTag *find_tag_in_queue(VTagGroup *vtaggroup, const char *name) +{ + struct VTag *vtag; + + vtag = vtaggroup->queue.first; + + while(vtag) { + if(strcmp(vtag->name, name)==0) { + BLI_remlink(&(vtaggroup->queue), vtag); + break; + } + vtag = vtag->next; + } + + return vtag; +} + +/* + * create new verse tag + */ +static VTag *create_verse_tag( + VTagGroup *vtaggroup, + uint16 tag_id, + const char *name, + VNTagType type, + const VNTag *tag) +{ + struct VTag *vtag; + + vtag = (VTag*)MEM_mallocN(sizeof(VTag), "VTag"); + + vtag->vtaggroup = vtaggroup; + vtag->id = tag_id; + vtag->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTag name"); + strcpy(vtag->name, name); + vtag->type = type; + + vtag->tag = (VNTag*)MEM_mallocN(sizeof(VNTag), "VNTag"); + *vtag->tag = *tag; + + vtag->value = NULL; + + return vtag; +} + +/* + * send taggroup to verse server + */ +void send_verse_taggroup(VTagGroup *vtaggroup) +{ + verse_send_tag_group_create( + vtaggroup->vnode->id, + vtaggroup->id, + vtaggroup->name); +} + +/* + * free taggroup data + */ +static void free_verse_taggroup_data(VTagGroup *taggroup) +{ + struct VerseSession *session = taggroup->vnode->session; + struct VTag *vtag; + + vtag = taggroup->tags.lb.first; + + while(vtag) { + free_verse_tag_data(vtag); + vtag = vtag->next; + } + + /* unsubscribe from taggroup */ + if(session->flag & VERSE_CONNECTED) + verse_send_tag_group_unsubscribe(taggroup->vnode->id, taggroup->id); + + BLI_dlist_destroy(&(taggroup->tags)); + MEM_freeN(taggroup->name); +} + +/* + * move taggroup from queue to dynamic list with access array, + * set up taggroup id and return pointer at this taggroup + */ +static VTagGroup *find_taggroup_in_queue(VNode *vnode, const char *name) +{ + struct VTagGroup *vtaggroup; + + vtaggroup = vnode->queue.first; + + while(vtaggroup) { + if(strcmp(vtaggroup->name, name)==0) { + BLI_remlink(&(vnode->queue), vtaggroup); + break; + } + vtaggroup = vtaggroup->next; + } + + return vtaggroup; +} + +/* + * create new verse group of tags + */ +static VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name) +{ + struct VTagGroup *taggroup; + + taggroup = (VTagGroup*)MEM_mallocN(sizeof(VTagGroup), "VTagGroup"); + + taggroup->vnode = vnode; + taggroup->id = group_id; + taggroup->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTagGroup name"); + strcpy(taggroup->name, name); + + BLI_dlist_init(&(taggroup->tags)); + taggroup->queue.first = taggroup->queue.last = NULL; + + taggroup->post_tag_change = post_tag_change; + taggroup->post_taggroup_create = post_taggroup_create; + + return taggroup; +} + +/* + * move first VerseNode waiting in sending queue to dynamic list of VerseNodes + * (it usually happens, when "our" VerseNode was received from verse server) + */ +static void move_verse_node_to_dlist(VerseSession *session, VNodeID vnode_id) +{ + VNode *vnode; + + vnode = session->queue.first; + + if(vnode) { + BLI_remlink(&(session->queue), vnode); + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, vnode_id); + } +} + +/* + * send VerseNode to verse server + */ +void send_verse_node(VNode *vnode) +{ + verse_send_node_create( + vnode->id, + vnode->type, + vnode->session->avatar); +} + +/* + * free Verse Node data + */ +void free_verse_node_data(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + struct VTagGroup *vtaggroup; + + /* free node data (object, geometry, etc.) */ + switch(vnode->type){ + case V_NT_OBJECT: + free_object_data(vnode); + break; + case V_NT_GEOMETRY: + free_geom_data(vnode); + break; + case V_NT_BITMAP: + free_bitmap_node_data(vnode); + break; + default: + break; + } + + /* free all tag groups in dynamic list with access array */ + vtaggroup = vnode->taggroups.lb.first; + while(vtaggroup) { + free_verse_taggroup_data(vtaggroup); + vtaggroup = vtaggroup->next; + } + BLI_dlist_destroy(&(vnode->taggroups)); + + /* free all tag groups still waiting in queue */ + vtaggroup = vnode->queue.first; + while(vtaggroup) { + free_verse_taggroup_data(vtaggroup); + vtaggroup = vtaggroup->next; + } + BLI_freelistN(&(vnode->queue)); + + /* unsubscribe from node */ + if(session->flag & VERSE_CONNECTED) + verse_send_node_unsubscribe(vnode->id); + + /* free node name */ + MEM_freeN(vnode->name); + vnode->name = NULL; + + /* free node data */ + MEM_freeN(vnode->data); + vnode->data = NULL; + +} + +/* + * free VerseNode + */ +void free_verse_node(VNode *vnode) +{ + free_verse_node_data(vnode); + + BLI_dlist_free_item(&(vnode->session->nodes), vnode->id); +} + +/* + * create new Verse Node + */ +VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id) +{ + struct VNode *vnode; + + vnode = (VNode*)MEM_mallocN(sizeof(VNode), "VerseNode"); + + vnode->session = session; + vnode->id = node_id; + vnode->owner_id = owner_id; + vnode->name = NULL; + vnode->type = type; + + BLI_dlist_init(&(vnode->taggroups)); + vnode->queue.first = vnode->queue.last = NULL; + + vnode->data = NULL; + + vnode->counter = 0; + + vnode->flag = 0; + + vnode->post_node_create = post_node_create; + vnode->post_node_destroy = post_node_destroy; + vnode->post_node_name_set = post_node_name_set; + + return vnode; +} + +/* + * callback function: tag was destroyed + */ +static void cb_tag_destroy( + void *user_data, + VNodeID node_id, + uint16 group_id, + uint16 tag_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + struct VTag *vtag; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find tag group in list of tag groups */ + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(!vtaggroup) return; + + /* try to find verse tag in dynamic list of tags in tag group */ + vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id); + + if(vtag) { + free_verse_tag_data(vtag); + BLI_dlist_free_item(&(vtaggroup->tags), vtag->id); + } +} + +/* + * callback function: new tag was created + */ +static void cb_tag_create( + void *user_data, + VNodeID node_id, + uint16 group_id, + uint16 tag_id, + const char *name, + VNTagType type, + const VNTag *tag) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + struct VTag *vtag; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* try to find tag group in list of tag groups */ + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(!vtaggroup) return; + + /* try to find verse tag in dynamic list of tags in tag group */ + vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id); + + if(!vtag) { + /* we will try to find vtag in sending queue */ + vtag = find_tag_in_queue(vtaggroup, name); + + /* when we didn't create this tag, then we will have to create one */ + if(!vtag) vtag = create_verse_tag(vtaggroup, tag_id, name, type, tag); + else vtag->id = tag_id; + + /* add tag to the list of tags in tag group */ + BLI_dlist_add_item_index(&(vtaggroup->tags), vtag, tag_id); + + /* post change/create method */ + vtaggroup->post_tag_change(vtag); + } + else { + /* this tag exists, then we will propably change value of this tag */ + if((vtag->type != type) || (strcmp(vtag->name, name)!=0)) { + /* changes of type or name are not allowed and such + * stupid changes will be returned back */ + send_verse_tag(vtag); + } + else { + /* post change/create method */ + vtaggroup->post_tag_change(vtag); + } + } +} + +/* + * callback function: tag group was destroyed + */ +static void cb_tag_group_destroy( + void *user_data, + VNodeID node_id, + uint16 group_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(vtaggroup) { + free_verse_taggroup_data(vtaggroup); + BLI_dlist_free_item(&(vnode->taggroups), vtaggroup->id); + } +} + +/* + * callback function: new tag group was created + */ +static void cb_tag_group_create( + void *user_data, + VNodeID node_id, + uint16 group_id, + const char *name) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VTagGroup *vtaggroup; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(!vnode) return; + + /* name of taggroup has to begin with string "blender:" */ + if(strncmp("blender:", name, 8)) return; + + /* try to find tag group in list of tag groups */ + vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); + + if(!vtaggroup) { + /* subscribe to tag group (when new tag will be created, then blender will + * receive command about it) */ + verse_send_tag_group_subscribe(vnode->id, group_id); + verse_callback_update(0); + + /* try to find taggroup in waiting queue */ + vtaggroup = find_taggroup_in_queue(vnode, name); + + /* if no taggroup exist, then new has to be created */ + if(!vtaggroup) vtaggroup = create_verse_taggroup(vnode, group_id, name); + else vtaggroup->id = group_id; + + /* add tag group to dynamic list with access array */ + BLI_dlist_add_item_index(&(vnode->taggroups), (void*)vtaggroup, (unsigned int)group_id); + + /* post create method */ + vtaggroup->post_taggroup_create(vtaggroup); + } + else { + /* this taggroup exist and somebody try to change its name */ + if(strcmp(vtaggroup->name, name)!=0) { + /* blender doesn't allow such stupid and dangerous things */ + send_verse_taggroup(vtaggroup); + } + } +} + +/* + * callback function: change name of node + */ +static void cb_node_name_set( + void *user_data, + VNodeID node_id, + const char *name) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + + if(!session) return; + + vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + if(vnode && name) { + if(!vnode->name) { + vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name"); + } + else if(strlen(name) > strlen(vnode->name)) { + MEM_freeN(vnode->name); + vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name"); + } + strcpy(vnode->name, name); + + vnode->post_node_name_set(vnode); + } +} + +/* + * callback function for deleting node + */ +static void cb_node_destroy( + void *user_data, + VNodeID node_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + if(vnode) { + /* remove VerseNode from dynamic list */ + BLI_dlist_rem_item(&(session->nodes), (unsigned int)node_id); + /* do post destroy operations */ + vnode->post_node_destroy(vnode); + /* free verse data */ + free_verse_node_data(vnode); + /* free VerseNode */ + MEM_freeN(vnode); + }; +} + + +/* + * callback function for new created node + */ +static void cb_node_create( + void *user_data, + VNodeID node_id, + uint8 type, + VNodeID owner_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + + if(!session) return; + + /* subscribe to node */ + if((type==V_NT_OBJECT) || (type==V_NT_GEOMETRY) || (type==V_NT_BITMAP)) + verse_send_node_subscribe(node_id); + else + return; + + switch(type){ + case V_NT_OBJECT : + if(owner_id==VN_OWNER_MINE) { + struct VLink *vlink; + /* collect VerseNode from VerseNode queue */ + move_verse_node_to_dlist(session, node_id); + /* send next VerseNode waiting in queue */ + if(session->queue.first) send_verse_node(session->queue.first); + /* get received VerseNode from list of VerseNodes */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + /* set up ID */ + vnode->id = node_id; + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* find unsent link pointing at this VerseNode */ + vlink = find_unsent_child_vlink(session, vnode); + /* send VerseLink */ + if(vlink) send_verse_link(vlink); + /* send name of object node */ + verse_send_node_name_set(node_id, vnode->name); + /* subscribe to changes of object node transformations */ + verse_send_o_transform_subscribe(node_id, 0); + /* send object transformation matrix */ + send_verse_object_position(vnode); + send_verse_object_rotation(vnode); + send_verse_object_scale(vnode); + } + else { + /* create new VerseNode */ + vnode = create_verse_node(session, node_id, type, owner_id); + /* add VerseNode to list of nodes */ + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* create object data */ + vnode->data = create_object_data(); + /* set up avatar's name */ + if(node_id == session->avatar) { + char *client_name; + client_name = verse_client_name(); + verse_send_node_name_set(node_id, client_name); + MEM_freeN(client_name); + } + else if(session->flag & VERSE_AUTOSUBSCRIBE) { + /* subscribe to changes of object node transformations */ + verse_send_o_transform_subscribe(node_id, 0); + } + } + break; + case V_NT_GEOMETRY : + if(owner_id==VN_OWNER_MINE){ + struct VLink *vlink; + struct VLayer *vlayer; + /* collect VerseNode from VerseNode queue */ + move_verse_node_to_dlist(session, node_id); + /* send next VerseNode waiting in queue */ + if(session->queue.first) send_verse_node(session->queue.first); + /* get received VerseNode from list of VerseNodes */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + /* set up ID */ + vnode->id = node_id; + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* find unsent link pointing at this VerseNode */ + vlink = find_unsent_parent_vlink(session, vnode); + /* send VerseLink */ + if(vlink) send_verse_link(vlink); + /* send name of geometry node */ + verse_send_node_name_set(node_id, vnode->name); + /* send all not sent layer to verse server */ + vlayer = (VLayer*)((VGeomData*)vnode->data)->queue.first; + if(vlayer) { + while(vlayer) { + send_verse_layer(vlayer); + vlayer = vlayer->next; + } + } + else { + /* send two verse layers to verse server */ +/* verse_send_g_layer_create(node_id, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0); + verse_send_g_layer_create(node_id, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);*/ + } + } + else { + /* create new VerseNode*/ + vnode = create_verse_node(session, node_id, type, owner_id); + /* add VerseNode to dlist of nodes */ + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* create geometry data */ + vnode->data = (void*)create_geometry_data(); + } + break; + case V_NT_BITMAP : + if(owner_id==VN_OWNER_MINE) { + /* collect VerseNode from VerseNode queue */ + move_verse_node_to_dlist(session, node_id); + /* send next VerseNode waiting in queue */ + if(session->queue.first) send_verse_node(session->queue.first); + /* get received VerseNode from list of VerseNodes */ + vnode = BLI_dlist_find_link(&(session->nodes), node_id); + /* set up ID */ + vnode->id = node_id; + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* send name of object node */ + verse_send_node_name_set(node_id, vnode->name); + /* send dimension of image to verse server */ + verse_send_b_dimensions_set(node_id, + ((VBitmapData*)vnode->data)->width, + ((VBitmapData*)vnode->data)->height, + ((VBitmapData*)vnode->data)->depth); + } + else { + /* create new VerseNode*/ + vnode = create_verse_node(session, node_id, type, owner_id); + /* add VerseNode to dlist of nodes */ + BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); + /* set up flags */ + vnode->flag |= NODE_RECEIVED; + /* create bitmap data */ + vnode->data = (void*)create_bitmap_data(); + } + default: + break; + } + + vnode->post_node_create(vnode); +} + +/* + * set up all callbacks for verse nodes + */ +void set_node_callbacks(void) +{ + /* new node created */ + verse_callback_set(verse_send_node_create, cb_node_create, NULL); + /* node was deleted */ + verse_callback_set(verse_send_node_destroy, cb_node_destroy, NULL); + /* name of node was set */ + verse_callback_set(verse_send_node_name_set, cb_node_name_set, NULL); + + /* new tag group was created */ + verse_callback_set(verse_send_tag_group_create, cb_tag_group_create, NULL); + /* tag group was destroy */ + verse_callback_set(verse_send_tag_group_destroy, cb_tag_group_destroy, NULL); + + /* new tag was created */ + verse_callback_set(verse_send_tag_create, cb_tag_create, NULL); + /* tag was destroy */ + verse_callback_set(verse_send_tag_destroy, cb_tag_destroy, NULL); +} + +#endif diff --git a/source/blender/blenkernel/intern/verse_object_node.c b/source/blender/blenkernel/intern/verse_object_node.c new file mode 100644 index 00000000000..9e6de928ef0 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_object_node.c @@ -0,0 +1,605 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BIF_verse.h" + +#include "BKE_verse.h" + +#include "verse.h" + +/* function prototypes of static functions */ + +/* callback functions */ +static void cb_o_transform_pos_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag); +static void cb_o_transform_rot_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag); +static void cb_o_transform_scale_real32(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z); +static void cb_o_link_set(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id); +static void cb_o_link_destroy(void *user_data, VNodeID node_id,uint16 link_id); + +/* other functions */ +static void set_target_node_link_pointer(struct VNode *vnode, struct VLink *vlink); +static void free_verse_link_data(struct VLink *vlink); + +/* + * find noy sent VerseLink in queue + */ +VLink *find_unsent_child_vlink(VerseSession *session, VNode *vnode) +{ + struct VLink *vlink; + + if(vnode->type!=V_NT_OBJECT) return NULL; + + vlink = ((VObjectData*)vnode->data)->queue.first; + while(vlink) { + if(vlink->target->id != -1) { + printf("\t vlink found, vnode target id %d\n", vlink->target->id); + return vlink; + } + vlink = vlink->next; + } + return NULL; +} + +/* + * find unsent VerseLink "pointing at this VerseNode" + */ +VLink *find_unsent_parent_vlink(VerseSession *session, VNode *vnode) +{ + struct VNode *tmp; + struct VLink *vlink; + + tmp = session->nodes.lb.first; + + while(tmp) { + if(tmp->type==V_NT_OBJECT) { + vlink = ((VObjectData*)tmp->data)->queue.first; + while(vlink) { + if(vlink->target == vnode) + return vlink; + vlink = vlink->next; + } + } + tmp = tmp->next; + } + return NULL; +} + +/* + * send object position to verse server + */ +void send_verse_object_position(VNode *vnode) +{ + float tmp; + + ((VObjectData*)vnode->data)->flag &= ~POS_SEND_READY; + + tmp = -((VObjectData*)vnode->data)->pos[1]; + ((VObjectData*)vnode->data)->pos[1] = ((VObjectData*)vnode->data)->pos[2]; + ((VObjectData*)vnode->data)->pos[2] = tmp; + + verse_send_o_transform_pos_real32( + vnode->id, /* node id */ + 0, /* time_s ... no interpolation */ + 0, /* time_f ... no interpolation */ + ((VObjectData*)vnode->data)->pos, + NULL, /* speed ... no interpolation */ + NULL, /* accelerate ... no interpolation */ + NULL, /* drag normal ... no interpolation */ + 0.0); /* drag ... no interpolation */ +} + +/* + * send object rotation to verse server + */ +void send_verse_object_rotation(VNode *vnode) +{ + float quat[4]; +/* float bvec[3], vvec[3];*/ + VNQuat32 rot; + + rot.x = ((VObjectData*)vnode->data)->rot[0]; + rot.y = ((VObjectData*)vnode->data)->rot[1]; + rot.z = ((VObjectData*)vnode->data)->rot[2]; + rot.w = ((VObjectData*)vnode->data)->rot[3]; + +/* + quat[0] = ((VObjectData*)vnode->data)->rot[0]; + quat[1] = ((VObjectData*)vnode->data)->rot[1]; + quat[2] = ((VObjectData*)vnode->data)->rot[2]; + quat[3] = ((VObjectData*)vnode->data)->rot[3]; + + QuatToEul(quat, bvec); + vvec[0] = bvec[0]; + vvec[1] = bvec[1]; + vvec[2] = bvec[2]; + EulToQuat(vvec, quat); + + rot.x = quat[0]; + rot.y = quat[1]; + rot.z = quat[2]; + rot.w = quat[3]; +*/ + + ((VObjectData*)vnode->data)->flag &= ~ROT_SEND_READY; + + verse_send_o_transform_rot_real32( + vnode->id, /* node id */ + 0, /* time_s ... no interpolation */ + 0, /* time_f ... no interpolation */ + &rot, + NULL, /* speed ... no interpolation */ + NULL, /* accelerate ... no interpolation */ + NULL, /* drag normal ... no interpolation */ + 0.0); /* drag ... no interpolation */ +} + +/* + * send object rotation to verse server + */ +void send_verse_object_scale(VNode *vnode) +{ + ((VObjectData*)vnode->data)->flag &= ~SCALE_SEND_READY; + + verse_send_o_transform_scale_real32( + vnode->id, + ((VObjectData*)vnode->data)->scale[0], + ((VObjectData*)vnode->data)->scale[2], + ((VObjectData*)vnode->data)->scale[1]); +} + +/* + * send VerseLink to verse server + */ +void send_verse_link(VLink *vlink) +{ + verse_session_set(vlink->session->vsession); + + verse_send_o_link_set( + vlink->source->id, + vlink->id, + vlink->target->id, + vlink->label, + vlink->target_id); +} + +/* + * set up pointer at VerseLink of target node (geometry node, material node, etc.) + */ +static void set_target_node_link_pointer(VNode *vnode, VLink *vlink) +{ + switch (vnode->type) { + case V_NT_GEOMETRY: + ((VGeomData*)vnode->data)->vlink = vlink; + break; + default: + break; + } +} + +/* + * free VerseLink and it's label + */ +static void free_verse_link_data(VLink *vlink) +{ + MEM_freeN(vlink->label); +} + +/* + * create new VerseLink + */ +VLink *create_verse_link( + VerseSession *session, + VNode *source, + VNode *target, + uint16 link_id, + uint32 target_id, + const char *label) +{ + struct VLink *vlink; + + vlink = (VLink*)MEM_mallocN(sizeof(VLink), "VerseLink"); + vlink->session = session; + vlink->source = source; + vlink->target = target; + vlink->id = link_id; + vlink->target_id = target_id; + + set_target_node_link_pointer(target, vlink); + + vlink->label = (char*)MEM_mallocN(sizeof(char)*(strlen(label)+1), "VerseLink label"); + vlink->label[0] = '\0'; + strcat(vlink->label, label); + + vlink->flag = 0; + + vlink->post_link_set = post_link_set; + vlink->post_link_destroy = post_link_destroy; + + return vlink; +} + +/* + * free ObjectData (links, links in queue and lables of links) + */ +void free_object_data(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + struct VObjectData *obj = (VObjectData*)vnode->data; + struct VLink *vlink; + + if(!obj) return; + + /* free all labels of links in dlist */ + vlink = obj->links.lb.first; + while(vlink){ + free_verse_link_data(vlink); + vlink = vlink->next; + } + + /* free all labels of links waiting in queue */ + vlink = obj->queue.first; + while(vlink){ + free_verse_link_data(vlink); + vlink = vlink->next; + } + /* free dynamic list and sendig queue of links */ + BLI_dlist_destroy(&(obj->links)); + BLI_freelistN(&(obj->queue)); + + /* free constraint between VerseNode and Object */ + obj->post_object_free_constraint(vnode); + + /* unsubscribe from receiving changes of transformation matrix */ + if(session->flag & VERSE_CONNECTED) + verse_send_o_transform_unsubscribe(vnode->id, 0); +} + +/* + * create new object data + */ +VObjectData *create_object_data(void) +{ + VObjectData *obj; + + obj = (VObjectData*)MEM_mallocN(sizeof(VObjectData), "VerseObjectData"); + obj->object = NULL; + BLI_dlist_init(&(obj->links)); + obj->queue.first = obj->queue.last = NULL; + obj->flag = 0; + + /* transformation matrix */ + obj->pos[0] = obj->pos[1] = obj->pos[2] = 0.0; + obj->rot[0] = obj->rot[1] = obj->rot[2] = 0.0; obj->rot[3] = 1; + obj->scale[0] = obj->scale[1] = obj->scale[2] = 1.0; + + /* transformation flags */ + obj->flag |= POS_SEND_READY; + obj->flag |= ROT_SEND_READY; + obj->flag |= SCALE_SEND_READY; + + /* set up pointers at post callback functions */ + obj->post_transform = post_transform; + obj->post_object_free_constraint = post_object_free_constraint; + + return obj; +} + +/* + * callback function: + */ +static void cb_o_transform_pos_real32( + void *user_data, + VNodeID node_id, + uint32 time_s, + uint32 time_f, + const real32 *pos, + const real32 *speed, + const real32 *accelerate, + const real32 *drag_normal, + real32 drag) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + float vec[3], dt, tmp; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + ((VObjectData*)vnode->data)->flag |= POS_SEND_READY; + + /* verse server sends automaticaly some stupid default values ... + * we have to ignore these values, when we created this object node */ + if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & POS_RECEIVE_READY) ) { + ((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY; + return; + } + + dt = time_s + time_f/(0xffff); + + /* we have to flip z and y coordinates, because verse and blender use different axis + * orientation */ + if(pos) { + vec[0] = pos[0]; + vec[1] = pos[1]; + vec[2] = pos[2]; + } + + if(speed) { + vec[0] += speed[0]*dt; + vec[1] += speed[1]*dt; + vec[2] += speed[2]*dt; + } + + if(accelerate) { + vec[0] += accelerate[0]*dt*dt/2; + vec[1] += accelerate[1]*dt*dt/2; + vec[2] += accelerate[2]*dt*dt/2; + } + + /* flip axis (due to verse spec) */ + tmp = vec[1]; + vec[1] = -vec[2]; + vec[2] = tmp; + + if( (((VObjectData*)vnode->data)->pos[0] != vec[0]) || + (((VObjectData*)vnode->data)->pos[1] != vec[1]) || + (((VObjectData*)vnode->data)->pos[2] != vec[2])) + { + ((VObjectData*)vnode->data)->pos[0] = vec[0]; + ((VObjectData*)vnode->data)->pos[1] = vec[1]; + ((VObjectData*)vnode->data)->pos[2] = vec[2]; + + ((VObjectData*)vnode->data)->post_transform(vnode); + } +} + +/* + * callback function: + */ +static void cb_o_transform_rot_real32( + void *user_data, + VNodeID node_id, + uint32 time_s, + uint32 time_f, + const VNQuat32 *rot, + const VNQuat32 *speed, + const VNQuat32 *accelerate, + const VNQuat32 *drag_normal, + real32 drag) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + float quat[4]={0, 0, 0, 0}, dt; +/* float vvec[3], bvec[3];*/ + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY; + + /* verse server sends automaticaly some stupid default values ... + * we have to ignore these values, when we created this object node */ + if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & ROT_RECEIVE_READY) ) { + ((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY; + return; + } + + dt = time_s + time_f/(0xffff); + + if(rot) { + quat[0] = rot->x; + quat[1] = rot->y; + quat[2] = rot->z; + quat[3] = rot->w; + } + + if(speed) { + quat[0] += speed->x*dt; + quat[1] += speed->y*dt; + quat[2] += speed->z*dt; + quat[3] += speed->w*dt; + } + + if(accelerate) { + quat[0] += accelerate->x*dt*dt/2; + quat[1] += accelerate->y*dt*dt/2; + quat[2] += accelerate->z*dt*dt/2; + quat[3] += accelerate->w*dt*dt/2; + } + +/* QuatToEul(quat, vvec); + bvec[0] = vvec[0]; + bvec[1] = vvec[1]; + bvec[2] = vvec[2]; + EulToQuat(bvec, quat);*/ + + if( (((VObjectData*)vnode->data)->rot[0] != quat[0]) || + (((VObjectData*)vnode->data)->rot[1] != quat[1]) || + (((VObjectData*)vnode->data)->rot[2] != quat[2]) || + (((VObjectData*)vnode->data)->rot[3] != quat[3])) + { + ((VObjectData*)vnode->data)->rot[0] = quat[0]; + ((VObjectData*)vnode->data)->rot[1] = quat[1]; + ((VObjectData*)vnode->data)->rot[2] = quat[2]; + ((VObjectData*)vnode->data)->rot[3] = quat[3]; + + ((VObjectData*)vnode->data)->post_transform(vnode); + } +} + +/* + * callback function: + */ +static void cb_o_transform_scale_real32( + void *user_data, + VNodeID node_id, + real32 scale_x, + real32 scale_y, + real32 scale_z) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + real32 tmp; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY; + + /* verse server sends automaticaly some stupid default values ... + * we have to ignore these values, when we created this object node */ + if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & SCALE_RECEIVE_READY) ) { + ((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY; + return; + } + + /* flip axis (verse spec) */ + tmp = scale_y; + scale_y = scale_z; + scale_z = tmp; + + /* z and y axis are flipped here too */ + if( (((VObjectData*)vnode->data)->scale[0] != scale_x) || + (((VObjectData*)vnode->data)->scale[1] != scale_y) || + (((VObjectData*)vnode->data)->scale[2] != scale_z)) + { + ((VObjectData*)vnode->data)->scale[0] = scale_x; + ((VObjectData*)vnode->data)->scale[1] = scale_y; + ((VObjectData*)vnode->data)->scale[2] = scale_z; + + ((VObjectData*)vnode->data)->post_transform(vnode); + } +} + +/* + * callback function: link between object node and some other node was created + */ +static void cb_o_link_set( + void *user_data, + VNodeID node_id, + uint16 link_id, + VNodeID link, + const char *label, + uint32 target_id) +{ + struct VLink *vlink; + struct VNode *source; + struct VNode *target; + + struct VerseSession *session = (VerseSession*)current_verse_session(); + + if(!session) return; + + source = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + target = BLI_dlist_find_link(&(session->nodes), (unsigned int)link); + + if(!(source && target)) return; + + vlink = ((VObjectData*)source->data)->queue.first; + + if(vlink && (vlink->source==source) && (vlink->target==target)) { + /* remove VerseLink from sending queue */ + BLI_remlink(&(((VObjectData*)source->data)->queue), vlink); + /* add VerseLink to dynamic list of VerseLinks */ + BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id); + /* send next link from sending queue */ + if(((VObjectData*)source->data)->queue.first) + send_verse_link(((VObjectData*)source->data)->queue.first); + /* set up VerseLink variables */ + vlink->flag = 0; + vlink->id = link_id; + vlink->target_id = target_id; + } + else { + /* create new VerseLink */ + vlink = create_verse_link(session, source, target, link_id, target_id, label); + /* add VerseLink to dynamic list of VerseLinks */ + BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id); + } + + target->counter++; + + vlink->post_link_set(vlink); +} + +/* + * callback function: destroy link between two VerseNodes + */ +static void cb_o_link_destroy( + void *user_data, + VNodeID node_id, + uint16 link_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + struct VNode *vnode; + struct VLink *vlink; + + if(!session) return; + + vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); + + vlink = BLI_dlist_find_link(&(((VObjectData*)vnode->data)->links), link_id); + + if(vlink) { + vlink->target->counter--; + free_verse_link_data(vlink); + BLI_dlist_free_item(&(((VObjectData*)vnode->data)->links), link_id); + } + + vlink->post_link_destroy(vlink); +} + +void set_object_callbacks(void) +{ + /* position of object was changed */ + verse_callback_set(verse_send_o_transform_pos_real32, cb_o_transform_pos_real32, NULL); + /* rotation of object was changed */ + verse_callback_set(verse_send_o_transform_rot_real32, cb_o_transform_rot_real32, NULL); + /* size of object was changed */ + verse_callback_set(verse_send_o_transform_scale_real32, cb_o_transform_scale_real32, NULL); + /* new link between nodes was created */ + verse_callback_set(verse_send_o_link_set, cb_o_link_set, NULL); + /* link between nodes was destroyed */ + verse_callback_set(verse_send_o_link_destroy, cb_o_link_destroy, NULL); +} + +#endif diff --git a/source/blender/blenkernel/intern/verse_session.c b/source/blender/blenkernel/intern/verse_session.c new file mode 100644 index 00000000000..e6f16a93239 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_session.c @@ -0,0 +1,345 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" /* temp */ +#include "DNA_listBase.h" +#include "DNA_screen_types.h" + +#include "BLI_dynamiclist.h" +#include "BLI_blenlib.h" + +#include "BIF_verse.h" + +#include "BKE_global.h" +#include "BKE_verse.h" + +#include "verse.h" + +struct ListBase session_list={NULL, NULL}; + +/* list of static function prototypes */ +static void cb_connect_terminate(const char *address, const char *bye); +static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id); +static void set_all_callbacks(void); +static void free_verse_session_data(struct VerseSession *session); + +/* + * callback function for connection terminated + */ +static void cb_connect_terminate(const char *address, const char *bye) +{ + VerseSession *session = (VerseSession*)current_verse_session(); + + if(!session) return; + + /* remove session from list of session */ + BLI_remlink(&session_list, session); + /* do post connect operations */ + session->post_connect_terminated(session); + /* free session data */ + free_verse_session_data(session); + /* free session */ + MEM_freeN(session); +} + +/* + * callback function for accepted connection to verse server + */ +static void cb_connect_accept( + void *user_data, + uint32 avatar, + void *address, + void *connection, + const uint8 *host_id) +{ + struct VerseSession *session = (VerseSession*)current_verse_session(); + uint32 i, mask=0; + + if(!session) return; + + session->flag |= VERSE_CONNECTED; + session->flag &= ~VERSE_CONNECTING; + + printf("\tBlender was connected to verse server: %s\n", (char*)address); + printf("\tVerseSession->counter: %d\n", session->counter); + + session->avatar = avatar; + + session->post_connect_accept(session); + + for(i = 0; i < V_NT_NUM_TYPES; i++) + mask = mask | (1 << i); + verse_send_node_index_subscribe(mask); +} + +/* + * set up all callbacks for sessions + */ +void set_verse_session_callbacks(void) +{ + /* connection */ + verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL); + /* connection was terminated */ + verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL); +} + +/* + * set all callbacks used in Blender + */ +static void set_all_callbacks(void) +{ + /* set up all callbacks for sessions */ + set_verse_session_callbacks(); + + /* set up callbacks for nodes */ + set_node_callbacks(); + + /* set up all callbacks for object nodes */ + set_object_callbacks(); + + /* set up all callbacks for geometry nodes */ + set_geometry_callbacks(); + + /* set up all callbacks for bitmap nodes */ + set_bitmap_callbacks(); +} + +/* + * this function sends and receive all packets for all sessions + */ +void b_verse_update(void) +{ + VerseSession *session, *next_session; + + session = session_list.first; + while(session){ + next_session = session->next; + verse_session_set(session->vsession); + if((session->flag & VERSE_CONNECTED) || (session->flag & VERSE_CONNECTING)) { + verse_callback_update(10); + session->post_connect_update(session); + } + session = next_session; + } +} + +/* + * returns VerseSession coresponding to vsession pointer + */ +VerseSession *versesession_from_vsession(VSession *vsession) +{ + struct VerseSession *session; + + session = session_list.first; + + while(session) { + if(session->vsession==vsession) return session; + session = session->next; + } + + return session; +} + +/* + * returns pointer at current VerseSession + */ +VerseSession *current_verse_session(void) +{ + struct VerseSession *session; + VSession vsession = verse_session_get(); + + session = session_list.first; + + while(session){ + if(session->vsession == vsession) + return session; + session = session->next; + } + + printf("error: non-existing SESSION occured!\n"); + return NULL; +} + +/* + * free VerseSession + */ +static void free_verse_session_data(VerseSession *session) +{ + struct VNode *vnode; + + /* free data of all nodes */ + vnode = session->nodes.lb.first; + while(vnode){ + free_verse_node_data(vnode); + vnode = vnode->next; + } + + /* free data of nodes waiting in queue */ + vnode = session->queue.first; + while(vnode){ + free_verse_node_data(vnode); + vnode = vnode->next; + } + + /* free all VerseNodes */ + BLI_dlist_destroy(&(session->nodes)); + /* free all VerseNodes waiting in queque */ + BLI_freelistN(&(session->queue)); + + /* free name of verse host for this session */ + MEM_freeN(session->address); +} + +/* + * free VerseSession + */ +void free_verse_session(VerseSession *session) +{ + /* remove session from session list*/ + BLI_remlink(&session_list, session); + /* do post terminated operations */ + session->post_connect_terminated(session); + /* free session data (nodes, layers) */ + free_verse_session_data(session); + /* free session */ + MEM_freeN(session); +} + +/* + * create new verse session and return coresponding data structure + */ +VerseSession *create_verse_session( + const char *name, + const char *pass, + const char *address, + uint8 *expected_key) +{ + struct VerseSession *session; + VSession *vsession; + + vsession = verse_send_connect(name, pass, address, expected_key); + + if(!vsession) return NULL; + + session = (VerseSession*)MEM_mallocN(sizeof(VerseSession), "VerseSession"); + + session->flag = VERSE_CONNECTING; + + session->vsession = vsession; + session->avatar = -1; + + session->address = (char*)MEM_mallocN(sizeof(char)*(strlen(address)+1),"session adress name"); + strcpy(session->address, address); + + session->connection = NULL; + session->host_id = NULL; + session->counter = 0; + + /* initialize dynamic list of nodes and node queue */ + BLI_dlist_init(&(session->nodes)); + session->queue.first = session->queue.last = NULL; + + /* set up all client dependent functions */ + session->post_connect_accept = post_connect_accept; + session->post_connect_terminated = post_connect_terminated; + session->post_connect_update = post_connect_update; + + return session; +} + +/* + * end verse session and free all session data + */ +void end_verse_session(VerseSession *session, char free) +{ + /* send terminate command to verse server */ + verse_send_connect_terminate(session->address, "blender: bye bye"); + /* update callbacks */ + verse_callback_update(1000); + /* send destroy session command to verse server */ + verse_session_destroy(session->vsession); + /* set up flag of verse session */ + session->flag &= ~VERSE_CONNECTED; + /* do post connect operations */ + session->post_connect_terminated(session); + /* free session data */ + free_verse_session_data(session); + /* free structure of verse session */ + if(free) free_verse_session(session); +} + +/* + * end connection to all verse hosts (servers) ... free all VerseSessions + */ +void end_all_verse_sessions(void) +{ + VerseSession *session; + + session = session_list.first; + + while(session) { + end_verse_session(session, 0); + /* end next session */ + session = session->next; + } + + BLI_freelistN(&session_list); +} + +/* + * connect to verse host, set up all callbacks, create session + */ +void b_verse_connect(char *address) +{ + VerseSession *session; + + /* if no session was created before, then set up all callbacks */ + if((session_list.first==NULL) && (session_list.last==NULL)) + set_all_callbacks(); + + /* create new session */ + if(address) + session = create_verse_session("Blender", "pass", address, NULL); + + if(session) { + /* add new session to the list of sessions */ + BLI_addtail(&session_list, session); + + /* add verse handler if this is first session */ + if(session_list.first == session_list.last) + add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1); + + } +} + +#endif diff --git a/source/blender/blenlib/BLI_blenlib.h b/source/blender/blenlib/BLI_blenlib.h index d26afbc350c..564b250da81 100644 --- a/source/blender/blenlib/BLI_blenlib.h +++ b/source/blender/blenlib/BLI_blenlib.h @@ -84,6 +84,7 @@ struct rcti; struct EditVert; struct PackedFile; struct LinkNode; +struct DynamicList; #ifdef __cplusplus extern "C" { @@ -112,6 +113,17 @@ int BLI_countlist(struct ListBase *listbase); void BLI_freelinkN(ListBase *listbase, void *vlink); void BLI_splitdirstring(char *di,char *fi); +struct DynamicList *BLI_dlist_from_listbase(struct ListBase *lb); +struct ListBase *BLI_listbase_from_dlist(struct DynamicList *dlist, struct ListBase *lb); +void * BLI_dlist_find_link(struct DynamicList *dlist, unsigned int index); +unsigned int BLI_count_items(struct DynamicList *dlist); +void BLI_dlist_free_item(struct DynamicList *dlist, unsigned int index); +void BLI_dlist_rem_item(struct DynamicList *dlist, unsigned int index); +void * BLI_dlist_add_item_index(struct DynamicList *dlist, void *item, unsigned int index); +void BLI_dlist_destroy(struct DynamicList *dlist); +void BLI_dlist_init(struct DynamicList *dlist); +void BLI_dlist_reinit(struct DynamicList *dlist); + /** * dir can be any input, like from buttons, and this function * converts it to a regular full path. diff --git a/source/blender/blenlib/BLI_dynamiclist.h b/source/blender/blenlib/BLI_dynamiclist.h new file mode 100644 index 00000000000..89e27743054 --- /dev/null +++ b/source/blender/blenlib/BLI_dynamiclist.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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. + * + * Documentation of Two way dynamic list with access array can be found at: + * + * http://wiki.blender.org/bin/view.pl/Blenderwiki/DynamicListWithAccessArray + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef B_DYNAMIC_LIST_H +#define B_DYNAMIC_LIST_H + +#define PAGE_SIZE 4 + +struct ListBase; + +/* + * Access array using realloc + */ +typedef struct DynamicArray{ + unsigned int count; /* count of items in list */ + unsigned int max_item_index; /* max available index */ + unsigned int last_item_index; /* max used index */ + void **items; /* dynamicaly allocated array of pointers + pointing at items in list */ +} DynamicArray; + +/* + * Two way dynamic list with access array + */ +typedef struct DynamicList { + struct DynamicArray da; /* access array */ + struct ListBase lb; /* two way linked dynamic list */ +} DynamicList; + +#endif diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h index 3dc6ebadb71..2c8df6efd43 100644 --- a/source/blender/blenlib/BLI_editVert.h +++ b/source/blender/blenlib/BLI_editVert.h @@ -68,6 +68,9 @@ typedef struct EditVert int hash; struct MDeformWeight *dw; /* __NLA a pointer to an array of defirm weights */ int keyindex; /* original index #, for restoring key information */ +/*#ifdef WITH_VERSE*/ + void *vvert; +/*#endif*/ } EditVert; struct EditEdge; @@ -124,6 +127,9 @@ typedef struct EditFace unsigned char f, f1, h; unsigned char fast; /* only 0 or 1, for editmesh_fastmalloc */ unsigned char fgonf; /* flag for fgon options */ +/*#ifdef WITH_VERSE*/ + void *vface; +/*#endif*/ } EditFace; @@ -154,6 +160,10 @@ typedef struct EditMesh * to derived final, care should be taken on release. */ struct DerivedMesh *derivedCage, *derivedFinal; + +#ifdef WITH_VERSE + void *vnode; +#endif } EditMesh; #endif diff --git a/source/blender/blenlib/intern/util.c b/source/blender/blenlib/intern/util.c index c559761fb32..1ef9c5c8cda 100644 --- a/source/blender/blenlib/intern/util.c +++ b/source/blender/blenlib/intern/util.c @@ -47,6 +47,7 @@ #include "DNA_listBase.h" #include "BLI_storage.h" #include "BLI_storage_types.h" +#include "BLI_dynamiclist.h" #include "BLI_util.h" @@ -403,6 +404,228 @@ void * BLI_findlink(ListBase *listbase, int number) return (link); } +/*=====================================================================================*/ +/* Methods for access array (realloc) */ +/*=====================================================================================*/ + +/* remove item with index */ +static void rem_array_item(struct DynamicArray *da, unsigned int index) +{ + da->items[index]=NULL; + da->count--; + if(index==da->last_item_index){ + while((!da->items[da->last_item_index]) && (da->last_item_index>0)){ + da->last_item_index--; + } + } +} + +/* add array (if needed, then realloc) */ +static void add_array_item(struct DynamicArray *da, void *item, unsigned int index) +{ + /* realloc of access array */ + if(da->max_item_index < index){ + unsigned int i, max = da->max_item_index; + void **nitems; + + do { + da->max_item_index += PAGE_SIZE; /* OS can allocate only PAGE_SIZE Bytes */ + } while(da->max_item_index<=index); + + nitems = (void**)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array"); + for(i=0;i<=max;i++) + nitems[i] = da->items[i]; + + /* set rest pointers to the NULL */ + for(i=max+1; i<=da->max_item_index; i++) + nitems[i]=NULL; + + MEM_freeN(da->items); /* free old access array */ + da->items = nitems; + } + + da->items[index] = item; + da->count++; + if(index > da->last_item_index) da->last_item_index = index; +} + +/* free access array */ +static void destroy_array(DynamicArray *da) +{ + da->count=0; + da->last_item_index=0; + da->max_item_index=0; + MEM_freeN(da->items); + da->items = NULL; +} + +/* initialize dynamic array */ +static void init_array(DynamicArray *da) +{ + unsigned int i; + + da->count=0; + da->last_item_index=0; + da->max_item_index = PAGE_SIZE-1; + da->items = (void*)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array"); + for(i=0; i<=da->max_item_index; i++) da->items[i]=NULL; +} + +/* reinitialize dynamic array */ +static void reinit_array(DynamicArray *da) +{ + destroy_array(da); + init_array(da); +} + +/*=====================================================================================*/ +/* Methods for two way dynamic list with access array */ +/*=====================================================================================*/ + +/* create new two way dynamic list with access array from two way dynamic list + * it doesn't copy any items to new array or something like this It is strongly + * recomended to use BLI_dlist_ methods for adding/removing items from dynamic list + * unless you can end with inconsistence system !!! */ +DynamicList *BLI_dlist_from_listbase(ListBase *lb) +{ + DynamicList *dlist; + Link *item; + int i=0, count; + + if(!lb) return NULL; + + count = BLI_countlist(lb); + + dlist = MEM_mallocN(sizeof(DynamicList), "temp dynamic list"); + /* ListBase stuff */ + dlist->lb.first = lb->first; + dlist->lb.last = lb->last; + /* access array stuff */ + dlist->da.count=count; + dlist->da.max_item_index = count-1; + dlist->da.last_item_index = count -1; + dlist->da.items = (void*)MEM_mallocN(sizeof(void*)*count, "temp dlist access array"); + + item = (Link*)lb->first; + while(item){ + dlist->da.items[i] = (void*)item; + item = item->next; + i++; + } + + /* to prevent you of using original ListBase :-) */ + lb->first = lb->last = NULL; + + return dlist; +} + +/* take out ListBase from DynamicList and destroy all temporary structures of DynamicList */ +ListBase *BLI_listbase_from_dlist(DynamicList *dlist, ListBase *lb) +{ + if(!dlist) return NULL; + + if(!lb) lb = (ListBase*)MEM_mallocN(sizeof(ListBase), "ListBase"); + + lb->first = dlist->lb.first; + lb->last = dlist->lb.last; + + /* free all items of access array */ + MEM_freeN(dlist->da.items); + /* free DynamicList*/ + MEM_freeN(dlist); + + return lb; +} + +/* return pointer at item from th dynamic list with access array */ +void *BLI_dlist_find_link(DynamicList *dlist, unsigned int index) +{ + if(!dlist || !dlist->da.items) return NULL; + + if((index <= dlist->da.last_item_index) && (index >= 0) && (dlist->da.count>0)){ + return dlist->da.items[index]; + } + else { + return NULL; + } +} + +/* return count of items in the dynamic list with access array */ +unsigned int BLI_count_items(DynamicList *dlist) +{ + if(!dlist) return 0; + + return dlist->da.count; +} + +/* free item from the dynamic list with access array */ +void BLI_dlist_free_item(DynamicList *dlist, unsigned int index) +{ + if(!dlist || !dlist->da.items) return; + + if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){ + BLI_freelinkN(&(dlist->lb), dlist->da.items[index]); + rem_array_item(&(dlist->da), index); + } +} + +/* remove item from the dynamic list with access array */ +void BLI_dlist_rem_item(DynamicList *dlist, unsigned int index) +{ + if(!dlist || !dlist->da.items) return; + + if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){ + BLI_remlink(&(dlist->lb), dlist->da.items[index]); + rem_array_item(&(dlist->da), index); + } +} + +/* add item to the dynamic list with access array (index) */ +void* BLI_dlist_add_item_index(DynamicList *dlist, void *item, unsigned int index) +{ + if(!dlist || !dlist->da.items) return NULL; + + if((index <= dlist->da.max_item_index) && (dlist->da.items[index])) { + /* you can't place item at used index */ + return NULL; + } + else { + add_array_item(&(dlist->da), item, index); + BLI_addtail(&(dlist->lb), item); + return item; + } +} + +/* destroy dynamic list with access array */ +void BLI_dlist_destroy(DynamicList *dlist) +{ + if(!dlist) return; + + BLI_freelistN(&(dlist->lb)); + destroy_array(&(dlist->da)); +} + +/* initialize dynamic list with access array */ +void BLI_dlist_init(DynamicList *dlist) +{ + if(!dlist) return; + + dlist->lb.first = NULL; + dlist->lb.last = NULL; + + init_array(&(dlist->da)); +} + +/* reinitialize dynamic list with acces array */ +void BLI_dlist_reinit(DynamicList *dlist) +{ + if(!dlist) return; + + BLI_freelistN(&(dlist->lb)); + reinit_array(&(dlist->da)); +} + +/*=====================================================================================*/ char *BLI_strdupn(char *str, int len) { char *n= MEM_mallocN(len+1, "strdup"); diff --git a/source/blender/blenloader/intern/Makefile b/source/blender/blenloader/intern/Makefile index 9faeb42879f..86ccd607d63 100644 --- a/source/blender/blenloader/intern/Makefile +++ b/source/blender/blenloader/intern/Makefile @@ -51,6 +51,11 @@ ifeq ($(OS),$(findstring $(OS), "solaris windows")) CPPFLAGS += -I$(NAN_ZLIB)/include endif +ifeq ($(WITH_VERSE), true) + CPPFLAGS += -DWITH_VERSE + CPPFLAGS += -I$(NAN_VERSE)/include +endif + # streaming write function CPPFLAGS += -I../../writestreamglue CPPFLAGS += -I../../readstreamglue diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 557c553d0fd..7156b6ffcab 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -164,6 +164,10 @@ Important to know is that 'streaming' has been added to files, for Blender Publi #include "BKE_sound.h" /* ... and for samples */ #include "BKE_utildefines.h" // for defines #include "BKE_modifier.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#include "BIF_verse.h" +#endif #include "GEN_messaging.h" @@ -745,7 +749,15 @@ static void write_objects(WriteData *wd, ListBase *idbase) while(ob) { if(ob->id.us>0 || wd->current) { /* write LibData */ +#ifdef WITH_VERSE + /* pointer at vnode stored in file have to be NULL */ + struct VNode *vnode = (VNode*)ob->vnode; + if(vnode) ob->vnode = NULL; +#endif writestruct(wd, ID_OB, "Object", 1, ob); +#ifdef WITH_VERSE + if(vnode) ob->vnode = (void*)vnode; +#endif /* direct data */ writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat); @@ -987,7 +999,19 @@ static void write_meshs(WriteData *wd, ListBase *idbase) while(mesh) { if(mesh->id.us>0 || wd->current) { /* write LibData */ +#ifdef WITH_VERSE + struct VNode *vnode = (VNode*)mesh->vnode; + if(vnode) { + /* mesh has to be created from verse geometry node*/ + create_meshdata_from_geom_node(mesh, vnode); + /* pointer at verse node can't be stored in file */ + mesh->vnode = NULL; + } +#endif writestruct(wd, ID_ME, "Mesh", 1, mesh); +#ifdef WITH_VERSE + if(vnode) mesh->vnode = (void*)vnode; +#endif /* direct data */ writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat); diff --git a/source/blender/include/BIF_outliner.h b/source/blender/include/BIF_outliner.h index 442247864b5..539ee055dba 100644 --- a/source/blender/include/BIF_outliner.h +++ b/source/blender/include/BIF_outliner.h @@ -66,6 +66,11 @@ typedef struct TreeElement { #define TSE_SCRIPT_BASE 12 #define TSE_POSE_BASE 13 #define TSE_POSE_CHANNEL 14 +/*#ifdef WITH_VERSE*/ +#define TSE_VERSE_SESSION 15 +#define TSE_VERSE_OBJ_NODE 16 +#define TSE_VERSE_GEOM_NODE 17 +/*#endif*/ /* button events */ #define OL_NAMEBUTTON 1 diff --git a/source/blender/include/BIF_verse.h b/source/blender/include/BIF_verse.h new file mode 100644 index 00000000000..7dada3f3986 --- /dev/null +++ b/source/blender/include/BIF_verse.h @@ -0,0 +1,134 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#ifndef BIF_VERSE_H +#define BIF_VERSE_H + +#include "BKE_verse.h" +#include "DNA_meshdata_types.h" + +struct Object; + +struct EditVert; +struct EditFace; +struct MVert; +struct Mface; + +/* verse_object.c */ +void unsubscribe_from_obj_node(struct VNode *vnode); +void unsubscribe_from_geom_node(struct VNode *vnode); +void unsubscribe_from_bitmap_node(struct VNode *vnode); + +void test_and_send_idbutton_cb(void *obj, void *ob_name); + +struct Object *create_object_from_verse_node(struct VNode *vnode); + +void b_verse_pop_node(struct VNode *vnode); +void b_verse_unsubscribe(VNode *vnode); +void b_verse_push_object(struct VerseSession *session, struct Object *ob); +void b_verse_delete_object(struct Object *ob); + +void post_transform(struct VNode *vnode); +void post_link_set(struct VLink *vlink); +void post_link_destroy(struct VLink *vlink); +void post_object_free_constraint(struct VNode *vnode); + +void b_verse_send_transformation(struct Object *ob); + +/* verse_mesh.c */ +void b_verse_send_vertex_delete(struct EditVert *eve); +void send_versevert_pos(struct VerseVert *vvert); + +void b_verse_send_face_delete(struct EditFace *efa); + +void sync_all_versefaces_with_editfaces(struct VNode *vnode); +void sync_all_verseverts_with_editverts(struct VNode *vnode); + +void createVerseVert(struct EditVert *ev); +void createVerseFace(struct EditFace *efa); + +void b_verse_duplicate_object(struct VerseSession *session, struct Object *ob, struct Object *n_ob); +struct VNode *create_geom_vnode_from_geom_vnode(struct VNode *vnode); +struct VNode *create_geom_vnode_data_from_editmesh(struct VerseSession *session, struct EditMesh *em); +struct VNode *create_geom_vnode_data_from_mesh(struct VerseSession *session, struct Mesh *me); + +void destroy_unused_geometry(struct VNode *vnode); +void destroy_binding_between_versemesh_and_editmesh(struct VNode *vnode); + +void destroy_verse_mesh(struct VNode *vnode); + +void unsubscribe_from_geom_node(struct VNode *vnode); + +void create_edit_mesh_from_geom_node(struct VNode *vnode); +struct Mesh *create_mesh_from_geom_node(struct VNode *vnode); +void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode); + +/* geometry post callback functions */ +void post_layer_create(struct VLayer *vlayer); +void post_layer_destroy(struct VLayer *vlayer); + +void post_vertex_create(struct VerseVert *vvert); +void post_vertex_set_xyz(struct VerseVert *vvert); +void post_vertex_delete(struct VerseVert *vvert); +void post_vertex_free_constraint(struct VerseVert *vvert); + +void post_polygon_set_uint8(struct VerseFace *vface); +void post_polygon_create(struct VerseFace *vface); +void post_polygon_set_corner(struct VerseFace *vface); +void post_polygon_delete(struct VerseFace *vface); +void post_polygon_free_constraint(struct VerseFace *vface); + +void post_geometry_free_constraint(struct VNode *vnode); + +/* verse_common.c */ +struct VerseSession *session_menu(void); +char *verse_client_name(void); + +void post_tag_change(struct VTag *vtag); +void post_taggroup_create(struct VTagGroup *vtaggroup); + +void post_node_create(struct VNode *vnode); +void post_node_destroy(struct VNode *vnode); +void post_node_name_set(struct VNode *vnode); + +void post_connect_accept(struct VerseSession *session); +void post_connect_terminated(struct VerseSession *session); +void post_connect_update(struct VerseSession *session); + +/* verse_image.c */ + +void sync_blender_image_with_verse_bitmap_node(struct VNode *vnode); +void post_bitmap_dimension_set(struct VNode *vnode); +void post_bitmap_layer_create(struct VBitmapLayer *vblayer); +void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer); +void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys); + +#endif + +#endif diff --git a/source/blender/include/blendef.h b/source/blender/include/blendef.h index c7cc268de19..ddbbfbd802f 100644 --- a/source/blender/include/blendef.h +++ b/source/blender/include/blendef.h @@ -89,6 +89,9 @@ #define SELECT 1 #define ACTIVE 2 +/*#ifdef WITH_VERSE*/ +#define VERSE 3 +/*#endif*/ #define DESELECT 0 #define NOT_YET 0 diff --git a/source/blender/include/transform.h b/source/blender/include/transform.h index c17d920693f..ec55b768381 100755 --- a/source/blender/include/transform.h +++ b/source/blender/include/transform.h @@ -128,6 +128,9 @@ typedef struct TransData { void *tdmir; /* mirrored element pointer, in editmode mesh to EditVert */ short flag; /* Various flags */ short protectflag; /* If set, copy of Object or PoseChannel protection */ +/*#ifdef WITH_VERSE*/ + void *verse; /* pointer at verse data struct (VerseVert, etc.) */ +/*#endif*/ } TransData; typedef struct TransInfo { @@ -232,6 +235,10 @@ typedef struct TransInfo { #define TD_USEQUAT 4 #define TD_NOTCONNECTED 8 #define TD_SINGLESIZE 16 /* used for scaling of MetaElem->rad */ +#ifdef WITH_VERSE +#define TD_VERSE_OBJECT 32 +#define TD_VERSE_VERT 64 +#endif void checkFirstTime(void); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index f9a824eec27..847f7123150 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -140,6 +140,11 @@ typedef struct Library { /* used in outliner... */ #define ID_NLA MAKE_ID2('N', 'L') +/*#ifdef WITH_VERSE*/ +#define ID_VS MAKE_ID2('V', 'S') /* fake id for VerseSession, needed for outliner */ +#define ID_VN MAKE_ID2('V', 'N') /* fake id for VerseNode, needed for outliner */ +/*#endif*/ + /* id->flag: set frist 8 bits always at zero while reading */ #define LIB_LOCAL 0 diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index da8787d05ab..ad8b3daf657 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -73,6 +73,9 @@ typedef struct Image { short animspeed; short reserved1; int reserved2; +/*#ifdef WITH_VERSE*/ + void *vnode; /* pointer at verse bitmap node */ +/*#endif*/ } Image; /* in Image struct */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 6f477e963c6..a57791be06d 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -99,6 +99,10 @@ typedef struct Mesh { short totcol; short subsurftype; +/*ifdef WITH_VERSE*/ + /* not written in file, pointer at geometry VerseNode */ + void *vnode; +/*#endif*/ } Mesh; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index e8573f3da4a..9cdb5054493 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -201,6 +201,10 @@ typedef struct Object { struct FluidsimSettings *fluidsimSettings; /* if fluidsim enabled, store additional settings */ struct DerivedMesh *derivedDeform, *derivedFinal; + +/*#ifdef WITH_VERSE*/ + void *vnode; /* pointer at object VerseNode */ +/*#endif*/ } Object; typedef struct ObHook { diff --git a/source/blender/src/Makefile b/source/blender/src/Makefile index 3bfb17dc586..fd92c412736 100644 --- a/source/blender/src/Makefile +++ b/source/blender/src/Makefile @@ -123,6 +123,15 @@ ifeq ($(INTERNATIONAL), true) CPPFLAGS += -DINTERNATIONAL endif +ifeq ($(WITH_VERSE), true) + CPPFLAGS += -DWITH_VERSE + CPPFLAGS += -I$(NAN_VERSE)/include + # print some other debug information + ifeq ($(VERSE_DEBUG_PRINT), true) + CPPFLAGS += -DVERSE_DEBUG_PRINT + endif +endif + ifeq ($(NAN_TWEAK_MODE), true) CPPFLAGS += -DTWEAK_MODE endif diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 36280938da9..baa3d27be90 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -117,6 +117,10 @@ #include "BIF_previewrender.h" #include "BIF_butspace.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "mydevice.h" #include "blendef.h" @@ -3499,6 +3503,10 @@ static void editing_panel_mesh_tools1(Object *ob, Mesh *me) /* Measurement drawing options */ uiBlockBeginAlign(block); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + uiDefButBitI(block, TOG, G_DRAW_VERSE_DEBUG, REDRAWVIEW3D, "Draw VDebug",1125,132,150,19, &G.f, 0, 0, 0, 0, "Displays verse debug information"); +#endif uiDefButBitI(block, TOG, G_DRAW_VNORMALS, REDRAWVIEW3D, "Draw VNormals",1125,110,150,19, &G.f, 0, 0, 0, 0, "Displays vertex normals as lines"); uiDefButBitI(block, TOG, G_DRAW_EDGELEN, REDRAWVIEW3D, "Edge Length", 1125,88,150,19, &G.f, 0, 0, 0, 0, "Displays selected edge lengths"); uiDefButBitI(block, TOG, G_DRAW_EDGEANG, REDRAWVIEW3D, "Edge Angles", 1125,66,150,19, &G.f, 0, 0, 0, 0, "Displays the angles in the selected edges in degrees"); @@ -3608,7 +3616,13 @@ static void editing_panel_links(Object *ob) } if(ob) { but = uiDefBut(block, TEX, B_IDNAME, "OB:", xco, 180, 454-xco, YIC, ob->id.name+2, 0.0, 19.0, 0, 0, "Displays Active Object name. Click to change."); +#ifdef WITH_VERSE + if(ob->vnode) uiButSetFunc(but, test_and_send_idbutton_cb, ob, ob->id.name); + else uiButSetFunc(but, test_idbutton_cb, ob->id.name, NULL); +#else uiButSetFunc(but, test_idbutton_cb, ob->id.name, NULL); +#endif + } diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index c4f11a577c0..6bb70a42b96 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -92,6 +92,9 @@ #include "BKE_mball.h" #include "BKE_object.h" #include "BKE_anim.h" //for the where_on_path function +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif #include "BIF_gl.h" #include "BIF_glutil.h" @@ -325,7 +328,13 @@ static void drawcentercircle(float *vec, int selstate, int special_color) glEnable(GL_BLEND); if(special_color) { +#ifdef WITH_VERSE + if (selstate==VERSE) glColor4ub(0x00, 0xFF, 0x00, 155); + else if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155); +#else if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155); +#endif + else glColor4ub(0x55, 0xCC, 0xCC, 155); } else { @@ -1506,6 +1515,71 @@ static void draw_em_fancy_edges(DerivedMesh *cageDM) } } +#ifdef WITH_VERSE +/* + * draw some debug info about verse mesh (vertex indexes, + * face indexes, status of ) + */ +static draw_verse_debug(Object *ob, EditMesh *em) +{ + struct EditVert *eve=NULL; + struct EditFace *efa=NULL; + float v1[3], v2[3], v3[3], v4[3], fvec[3], col[3]; + char val[32]; + + if(G.vd->zbuf && (G.vd->flag & V3D_ZBUF_SELECT)==0) + glDisable(GL_DEPTH_TEST); + + if(G.vd->zbuf) bglPolygonOffset(5.0); + + BIF_GetThemeColor3fv(TH_TEXT, col); + /* make color a bit more red */ + if(col[0]> 0.5) {col[1]*=0.7; col[2]*= 0.7;} + else col[0]= col[0]*0.7 + 0.3; + glColor3fv(col); + + /* draw IDs of verse vertexes */ + for(eve = em->verts.first; eve; eve = eve->next) { + if(eve->vvert) { + VecLerpf(fvec, ob->loc, eve->co, 1.1); + glRasterPos3f(fvec[0], fvec[1], fvec[2]); + + sprintf(val, "%d", ((VerseVert*)eve->vvert)->id); + BMF_DrawString(G.fonts, val); + } + } + + /* draw IDs of verse faces */ + for(efa = em->faces.first; efa; efa = efa->next) { + if(efa->vface) { + VECCOPY(v1, efa->v1->co); + VECCOPY(v2, efa->v2->co); + VECCOPY(v3, efa->v3->co); + if(efa->v4) { + VECCOPY(v4, efa->v4->co); + glRasterPos3f(0.25*(v1[0]+v2[0]+v3[0]+v4[0]), + 0.25*(v1[1]+v2[1]+v3[1]+v4[1]), + 0.25*(v1[2]+v2[2]+v3[2]+v4[2])); + } + else { + glRasterPos3f((v1[0]+v2[0]+v3[0])/3, + (v1[1]+v2[1]+v3[1])/3, + (v1[2]+v2[2]+v3[2])/3); + } + + sprintf(val, "%d", ((VerseFace*)efa->vface)->id); + BMF_DrawString(G.fonts, val); + + } + } + + if(G.vd->zbuf) { + glEnable(GL_DEPTH_TEST); + bglPolygonOffset(0.0); + } +} +#endif + static void draw_em_measure_stats(Object *ob, EditMesh *em) { EditEdge *eed; @@ -1760,6 +1834,10 @@ static void draw_em_fancy(Object *ob, EditMesh *em, DerivedMesh *cageDM, Derived if(G.f & (G_DRAW_EDGELEN|G_DRAW_FACEAREA|G_DRAW_EDGEANG)) draw_em_measure_stats(ob, em); +#ifdef WITH_VERSE + if(em->vnode && (G.f & G_DRAW_VERSE_DEBUG)) + draw_verse_debug(ob, em); +#endif } if(dt>OB_WIRE) { @@ -1808,8 +1886,31 @@ static void draw_mesh_fancy(Base *base, DerivedMesh *baseDM, DerivedMesh *dm, in Material *ma= give_current_material(ob, 1); int hasHaloMat = (ma && (ma->mode&MA_HALO)); int draw_wire = ob->dtx&OB_DRAWWIRE; + int totvert, totedge, totface; DispList *dl; +#ifdef WITH_VERSE + if(me->vnode) { + struct VNode *vnode = (VNode*)me->vnode; + struct VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + struct VLayer *face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + if(vert_vlayer) totvert = vert_vlayer->dl.da.count; + else totvert = 0; + totedge = 0; /* total count of edge needn't to be zero, but verse doesn't know edges */ + if(face_vlayer) totface = face_vlayer->dl.da.count; + else totface = 0; + } + else { + totvert = me->totvert; + totedge = me->totedge; + totface = me->totface; + } +#else + totvert = me->totvert; + totedge = me->totedge; + totface = me->totface; +#endif glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); // Unwanted combination. @@ -1818,12 +1919,12 @@ static void draw_mesh_fancy(Base *base, DerivedMesh *baseDM, DerivedMesh *dm, in if(dt==OB_BOUNDBOX) { draw_bounding_volume(ob); } - else if(hasHaloMat || (me->totface==0 && me->totedge==0)) { + else if(hasHaloMat || (totface==0 && totedge==0)) { glPointSize(1.5); dm->drawVerts(dm); glPointSize(1.0); } - else if(dt==OB_WIRE || me->totface==0) { + else if(dt==OB_WIRE || totface==0) { draw_wire = 1; } else if( (ob==OBACT && (G.f & G_FACESELECT)) || (G.vd->drawtype==OB_TEXTURE && dt>OB_SOLID)) { @@ -1946,7 +2047,7 @@ static void draw_mesh_fancy(Base *base, DerivedMesh *baseDM, DerivedMesh *dm, in // if (G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT)) { // baseDM->drawEdges(baseDM, dt==OB_WIRE); // } else { - dm->drawEdges(dm, (dt==OB_WIRE || me->totface==0)); + dm->drawEdges(dm, (dt==OB_WIRE || totface==0)); // } if (dt!=OB_WIRE) { @@ -3999,7 +4100,12 @@ void draw_object(Base *base, int flag) } else if((flag & DRAW_CONSTCOLOR)==0) { /* we don't draw centers for duplicators and sets */ - drawcentercircle(ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us>1); +#ifdef WITH_VERSE + if(ob->vnode) + drawcentercircle(ob->obmat[3], VERSE, 1); + else +#endif + drawcentercircle(ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us>1); } } } diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c index 8368d69d30e..773ad3cfb8f 100644 --- a/source/blender/src/drawview.c +++ b/source/blender/src/drawview.c @@ -112,6 +112,10 @@ #include "BIF_screen.h" #include "BIF_space.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BDR_drawmesh.h" #include "BDR_drawobject.h" #include "BDR_editobject.h" @@ -2228,7 +2232,13 @@ static void view3d_panel_object(short cntrl) // VIEW3D_HANDLER_OBJECT } else { bt= uiDefBut(block, TEX, B_IDNAME, "OB: ", 10,180,140,20, ob->id.name+2, 0.0, 19.0, 0, 0, ""); +#ifdef WITH_VERSE + if(ob->vnode) uiButSetFunc(bt, test_and_send_idbutton_cb, ob, ob->id.name); + else uiButSetFunc(bt, test_idbutton_cb, ob->id.name, NULL); +#else uiButSetFunc(bt, test_idbutton_cb, ob->id.name, NULL); +#endif + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_OBJECTPANELPARENT, "Par:", 160, 180, 140, 20, &ob->parent, "Parent Object"); } diff --git a/source/blender/src/edit.c b/source/blender/src/edit.c index bad89da633f..914ddffb528 100644 --- a/source/blender/src/edit.c +++ b/source/blender/src/edit.c @@ -82,6 +82,10 @@ #include "BKE_object.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_editmesh.h" #include "BIF_editview.h" #include "BIF_editarmature.h" @@ -94,6 +98,10 @@ #include "BIF_screen.h" #include "BIF_toolbox.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BSE_edit.h" #include "BSE_drawipo.h" #include "BSE_drawview.h" @@ -759,6 +767,10 @@ static void special_transvert_update(void) DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); if(G.obedit->type==OB_MESH) { +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); +#endif recalc_editnormals(); // does face centers too } else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) { @@ -1114,6 +1126,9 @@ void snap_sel_to_grid() ob->loc[1]+= vec[1]; ob->loc[2]+= vec[2]; } +#ifdef WITH_VERSE + if(ob->vnode) b_verse_send_transformation(ob); +#endif } } @@ -1212,6 +1227,9 @@ void snap_sel_to_curs() ob->loc[1]+= vec[1]; ob->loc[2]+= vec[2]; } +#ifdef WITH_VERSE + if(ob->vnode) b_verse_send_transformation(ob); +#endif } } @@ -1519,6 +1537,9 @@ void snap_to_center() ob->loc[1]+= vec[1]; ob->loc[2]+= vec[2]; } +#ifdef WITH_VERSE + if(ob->vnode) b_verse_send_transformation(ob); +#endif } } diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c index 3bba88003d1..6c351a09dc4 100644 --- a/source/blender/src/editmesh.c +++ b/source/blender/src/editmesh.c @@ -74,6 +74,10 @@ #include "BKE_texture.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_editkey.h" #include "BIF_editmesh.h" #include "BIF_editmode_undo.h" @@ -84,6 +88,10 @@ #include "BIF_screen.h" #include "BIF_toolbox.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BSE_view.h" #include "BSE_edit.h" #include "BSE_trans_types.h" @@ -141,11 +149,27 @@ EditVert *addvertlist(float *vec) * have a pre-editmode vertex order */ eve->keyindex = -1; + +#ifdef WITH_VERSE + createVerseVert(eve); +#endif + return eve; } void free_editvert (EditVert *eve) { +#ifdef WITH_VERSE + if(eve->vvert) { + /* it prevents from removing all verse vertexes + * during entering edit mode ... messy solution */ + if(G.editMesh->vnode) + b_verse_send_vertex_delete(eve); + else + ((VerseVert*)eve->vvert)->vertex = NULL; + } +#endif + if(eve->dw) MEM_freeN(eve->dw); EM_remove_selection(eve, EDITVERT); if(eve->fast==0){ @@ -288,6 +312,16 @@ void free_editedge(EditEdge *eed) void free_editface(EditFace *efa) { +#ifdef WITH_VERSE + if(efa->vface) { + /* it prevents from removing all verse faces + * during entering edit mode ... messy solution */ + if(G.editMesh->vnode) + b_verse_send_face_delete(efa); + else + ((VerseFace*)efa->vface)->face = NULL; + } +#endif EM_remove_selection(efa, EDITFACE); if(efa->fast==0){ free(efa); @@ -397,6 +431,10 @@ EditFace *addfacelist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed CalcCent3f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co); } +#ifdef WITH_VERSE + createVerseFace(efa); +#endif + return efa; } @@ -500,8 +538,18 @@ static void end_editmesh_fastmalloc(void) void free_editMesh(EditMesh *em) { +#ifdef WITH_VERSE + struct VNode *vnode=NULL; +#endif if(em==NULL) return; - + +#ifdef WITH_VERSE + if(em->vnode) { + vnode = (VNode*)em->vnode; + em->vnode = NULL; + } +#endif + if(em->verts.first) free_vertlist(&em->verts); if(em->edges.first) free_edgelist(&em->edges); if(em->faces.first) free_facelist(&em->faces); @@ -517,6 +565,12 @@ void free_editMesh(EditMesh *em) em->derivedCage= NULL; } +#ifdef WITH_VERSE + if(vnode) { + em->vnode = (void*)vnode; + } +#endif + /* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */ #if 0 if(em->hashedgetab) { @@ -727,6 +781,13 @@ void make_editMesh() EditSelection *ese; int tot, a, eekadoodle= 0; +#ifdef WITH_VERSE + if(me->vnode){ + create_edit_mesh_from_geom_node(me->vnode); + return; + } +#endif + /* because of reload */ free_editMesh(G.editMesh); @@ -907,6 +968,15 @@ void load_editMesh(void) MDeformVert *dvert; waitcursor(1); + +#ifdef WITH_VERSE + if(em->vnode) { + struct VNode *vnode = (VNode*)em->vnode; + ((VGeomData*)vnode->data)->editmesh = NULL; + em->vnode = NULL; + } +#endif + countall(); /* this one also tests of edges are not in faces: */ @@ -989,7 +1059,13 @@ void load_editMesh(void) if(eve->f1==1) mvert->flag |= ME_SPHERETEST; mvert->flag |= (eve->f & SELECT); if (eve->h) mvert->flag |= ME_HIDE; - + +#ifdef WITH_VERSE + if(eve->vvert) { + ((VerseVert*)eve->vvert)->vertex = NULL; + eve->vvert = NULL; + } +#endif eve= eve->next; mvert++; if(dvert) dvert++; @@ -1069,7 +1145,13 @@ void load_editMesh(void) /* no index '0' at location 3 or 4 */ test_index_face(mface, NULL, &efa->tf, efa->v4?4:3); - + +#ifdef WITH_VERSE + if(efa->vface) { + ((VerseFace*)efa->vface)->face = NULL; + efa->vface = NULL; + } +#endif efa->tmp.l = a++; i++; efa= efa->next; @@ -1326,6 +1408,9 @@ void separate_mesh(void) Mesh *me, *men; Base *base, *oldbase; ListBase edve, eded, edvl; +#ifdef WITH_VERSE + struct VNode *vnode = NULL; +#endif TEST_EDITMESH @@ -1359,9 +1444,21 @@ void separate_mesh(void) base= base->next; } +#ifdef WITH_VERSE + if(G.editMesh->vnode) { + vnode = G.editMesh->vnode; + G.editMesh->vnode = NULL; + } +#endif /* no test for split, split doesn't split when a loose part is selected */ /* SPLIT: first make duplicate */ adduplicateflag(SELECT); + +#ifdef WITH_VERSE + if(vnode) { + G.editMesh->vnode = vnode; + } +#endif /* SPLIT: old faces have 3x flag 128 set, delete these ones */ delfaceflag(128); @@ -1376,7 +1473,14 @@ void separate_mesh(void) if((eve->f & SELECT)==0) { BLI_remlink(&em->verts, eve); BLI_addtail(&edve, eve); +#ifdef WITH_VERSE + if(eve->vvert) { + ((VerseVert*)eve->vvert)->vertex = NULL; + eve->vvert = NULL; + } +#endif } + eve= v1; } eed= em->edges.first; @@ -1394,6 +1498,12 @@ void separate_mesh(void) if((efa->f & SELECT)==0) { BLI_remlink(&em->faces, efa); BLI_addtail(&edvl, efa); +#ifdef WITH_VERSE + if(efa->vface) { + ((VerseFace*)efa->vface)->face = NULL; + efa->vface = NULL; + } +#endif } efa= vl1; } @@ -1401,7 +1511,18 @@ void separate_mesh(void) oldob= G.obedit; oldbase= BASACT; +#ifdef WITH_VERSE + if(G.obedit->vnode) { + vnode = G.obedit->vnode; + G.obedit->vnode = NULL; + } +#endif adduplicate(1, 0); /* notrans and a linked duplicate*/ +#ifdef WITH_VERSE + if(vnode) { + G.obedit->vnode = vnode; + } +#endif G.obedit= BASACT->object; /* basact was set in adduplicate() */ @@ -1428,7 +1549,7 @@ void separate_mesh(void) /* hashedges are freed now, make new! */ editMesh_set_hash(); - + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); G.obedit= oldob; BASACT= oldbase; @@ -1449,13 +1570,28 @@ void separate_mesh_loose(void) EditVert *eve, *v1; EditEdge *eed, *e1; EditFace *efa, *vl1; - Object *oldob; + Object *oldob=NULL; Mesh *me, *men; Base *base, *oldbase; ListBase edve, eded, edvl; int vertsep=0; short done=0, check=1; - +#ifdef WITH_VERSE + struct VNode *vnode = NULL; +#endif + + me= get_mesh(G.obedit); +#ifdef WITH_VERSE + if(me->vnode) { + error("Can't separate a mesh shared at verse server"); + return; + } +#endif + if(me->key) { + error("Can't separate a mesh with vertex keys"); + return; + } + TEST_EDITMESH waitcursor(1); @@ -1467,19 +1603,11 @@ void separate_mesh_loose(void) * 5. freelist and get back old verts, edges, facs */ - - while(!done){ vertsep=check=1; countall(); - me= get_mesh(G.obedit); - if(me->key) { - error("Can't separate a mesh with vertex keys"); - return; - } - /* make only obedit selected */ base= FIRSTBASE; while(base) { @@ -1541,6 +1669,11 @@ void separate_mesh_loose(void) if((eve->f & SELECT)==0) { BLI_remlink(&em->verts, eve); BLI_addtail(&edve, eve); +#ifdef WITH_VERSE + if(eve->vvert) { + b_verse_send_vertex_delete(eve); + } +#endif } eve= v1; } @@ -1559,6 +1692,11 @@ void separate_mesh_loose(void) if( (efa->f & SELECT)==0 ) { BLI_remlink(&em->faces, efa); BLI_addtail(&edvl, efa); +#ifdef WITH_VERSE + if(efa->vface) { + b_verse_send_face_delete(efa); + } +#endif } efa= vl1; } @@ -1566,10 +1704,21 @@ void separate_mesh_loose(void) oldob= G.obedit; oldbase= BASACT; - adduplicate(1, 0); /* notrans and 0 for linked duplicate */ +#ifdef WITH_VERSE + if(G.obedit->vnode) { + vnode = G.obedit->vnode; + G.obedit->vnode = NULL; + } +#endif + adduplicate(1, 0); /* notrans and a linked duplicate*/ +#ifdef WITH_VERSE + if(vnode) { + G.obedit->vnode = vnode; + } +#endif G.obedit= BASACT->object; /* basact was set in adduplicate() */ - + men= copy_mesh(me); set_mesh(G.obedit, men); /* because new mesh is a copy: reduce user count */ @@ -1627,7 +1776,7 @@ typedef struct EditVertC unsigned char f, h; short totweight; struct MDeformWeight *dw; - int keyindex; + int keyindex; } EditVertC; typedef struct EditEdgeC @@ -1791,18 +1940,28 @@ static void undoMesh_to_editMesh(void *umv) EditSelectionC *esec; TFace *tface; int a=0; - + +#ifdef WITH_VERSE + struct VNode *vnode = G.editMesh->vnode; + if(vnode) { + /* send delete command to all verse vertexes and verse face ... + * verse mesh will be recreated from new edit mesh */ + destroy_versemesh(vnode); + } +#endif G.scene->selectmode = um->selectmode; free_editMesh(G.editMesh); /* malloc blocks */ memset(em, 0, sizeof(EditMesh)); - - init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface); +#ifdef WITH_VERSE + G.editMesh->vnode = vnode; +#endif + /* now copy vertices */ if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar"); for(a=0, evec= um->verts; a<um->totvert; a++, evec++) { @@ -1867,6 +2026,7 @@ static void undoMesh_to_editMesh(void *umv) } EM_free_index_arrays(); } + } diff --git a/source/blender/src/editmesh_add.c b/source/blender/src/editmesh_add.c index b10d855d12e..18f8fbd20dc 100644 --- a/source/blender/src/editmesh_add.c +++ b/source/blender/src/editmesh_add.c @@ -60,6 +60,11 @@ #include "BKE_object.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + + #include "BIF_editmesh.h" #include "BIF_graphics.h" #include "BIF_interface.h" @@ -69,6 +74,10 @@ #include "BIF_toolbox.h" #include "BIF_transform.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BDR_editobject.h" #include "BSE_view.h" @@ -233,6 +242,12 @@ void add_click_mesh(void) countall(); +#ifdef WITH_VERSE + if(G.editMesh->vnode) { + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); + } +#endif + BIF_undo_push("Add vertex/edge/face"); allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); @@ -561,7 +576,18 @@ static void fix_new_face(EditFace *eface) eface->flag &= ~ME_SMOOTH; /* flip face, when too much "face normals" in neighbourhood is different */ - if(count > 0) flipface(eface); + if(count > 0) { + flipface(eface); +#ifdef WITH_VERSE + if(eface->vface) { + struct VNode *vnode; + struct VLayer *vlayer; + vnode = (VNode*)((Mesh*)G.obedit->data)->vnode; + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + add_item_to_send_queue(&(vlayer->queue), (void*)eface->vface, VERSE_FACE); + } +#endif + } } void addedgeface_mesh(void) diff --git a/source/blender/src/editmesh_lib.c b/source/blender/src/editmesh_lib.c index fce6141e5a9..2d729cf94d9 100644 --- a/source/blender/src/editmesh_lib.c +++ b/source/blender/src/editmesh_lib.c @@ -63,6 +63,10 @@ editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data #include "BIF_editmesh.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BSE_edit.h" #include "editmesh.h" @@ -1711,6 +1715,10 @@ void flip_editnormals(void) } efa= efa->next; } +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif } /* does face centers too */ diff --git a/source/blender/src/editmesh_loop.c b/source/blender/src/editmesh_loop.c index a5b41d8291e..06da8711028 100644 --- a/source/blender/src/editmesh_loop.c +++ b/source/blender/src/editmesh_loop.c @@ -63,6 +63,10 @@ editmesh_loop: tools with own drawing subloops, select, knife, subdiv #include "BKE_object.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_cursors.h" #include "BIF_editmesh.h" #include "BIF_gl.h" @@ -74,6 +78,10 @@ editmesh_loop: tools with own drawing subloops, select, knife, subdiv #include "BIF_space.h" #include "BIF_toolbox.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BSE_view.h" #include "BSE_edit.h" #include "BSE_drawview.h" @@ -402,8 +410,12 @@ void CutEdgeloop(int numcuts) } DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); +#endif scrarea_queue_headredraw(curarea); - scrarea_queue_winredraw(curarea); + scrarea_queue_winredraw(curarea); return; } @@ -754,6 +766,12 @@ void KnifeSubdivide(char mode) window_set_cursor(win, oldcursor); BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); if (curve) MEM_freeN(curve); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Knife"); } diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c index ab105a0cd4a..cf24bbd05a9 100644 --- a/source/blender/src/editmesh_mods.c +++ b/source/blender/src/editmesh_mods.c @@ -68,6 +68,10 @@ editmesh_mods.c, UI level access, no geometry changes #include "BKE_texture.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_editmesh.h" #include "BIF_resources.h" #include "BIF_gl.h" @@ -81,6 +85,10 @@ editmesh_mods.c, UI level access, no geometry changes #include "BIF_space.h" #include "BIF_toolbox.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BDR_drawobject.h" #include "BDR_editobject.h" @@ -2792,6 +2800,11 @@ void righthandfaces(int select) /* makes faces righthand turning */ recalc_editnormals(); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif waitcursor(0); } @@ -3081,6 +3094,11 @@ void vertexsmooth(void) allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_verseverts_with_editverts(G.editMesh->vnode); +#endif BIF_undo_push("Vertex Smooth"); } @@ -3128,6 +3146,10 @@ void vertexnoise(void) recalc_editnormals(); allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_verseverts_with_editverts(G.editMesh->vnode); +#endif BIF_undo_push("Vertex Noise"); } @@ -3192,6 +3214,10 @@ void vertices_to_sphere(void) recalc_editnormals(); allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_verseverts_with_editverts(G.editMesh->vnode); +#endif BIF_undo_push("To Sphere"); } diff --git a/source/blender/src/editmesh_tools.c b/source/blender/src/editmesh_tools.c index de8cc5b7a9b..f1e5b555009 100644 --- a/source/blender/src/editmesh_tools.c +++ b/source/blender/src/editmesh_tools.c @@ -72,6 +72,10 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise #include "BKE_object.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_cursors.h" #include "BIF_editmesh.h" #include "BIF_gl.h" @@ -85,6 +89,10 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise #include "BIF_toolbox.h" #include "BIF_transform.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BDR_drawobject.h" #include "BDR_editobject.h" @@ -200,6 +208,11 @@ void convert_to_triface(int direction) } EM_fgon_flags(); // redo flags and indices for fgons + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif BIF_undo_push("Convert Quads to Triangles"); } @@ -509,6 +522,13 @@ int removedoublesflag(short flag, float limit) /* return amount */ eve= nextve; } +#ifdef WITH_VERSE + if((a>0) && (G.editMesh->vnode)) { + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); + } +#endif + return a; /* amount */ } @@ -549,6 +569,12 @@ void xsortvert_flag(int flag) addlisttolist(&em->verts, &tbase); MEM_freeN(sortblock); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Xsort"); } @@ -609,6 +635,10 @@ void hashvert_flag(int flag) addlisttolist(&em->verts, &tbase); MEM_freeN(sortblock); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif BIF_undo_push("Hash"); } @@ -710,6 +740,12 @@ void split_mesh(void) countall(); allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Split"); } @@ -747,7 +783,7 @@ void extrude_repeat_mesh(int steps, float offs) allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - + BIF_undo_push("Extrude Repeat"); } @@ -833,6 +869,7 @@ void spin_mesh(int steps, int degr, float *dvec, int mode) countall(); allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + if(dvec==NULL) BIF_undo_push("Spin"); } @@ -1180,6 +1217,12 @@ void fill_mesh(void) countall(); allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Fill"); } /*GB*/ @@ -3310,6 +3353,10 @@ void beauty_fill(void) allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif BIF_undo_push("Beauty Fill"); } @@ -3404,6 +3451,10 @@ void join_triangles(void) allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif BIF_undo_push("Convert Triangles to Quads"); } @@ -3515,6 +3566,10 @@ void edge_flip(void) allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif BIF_undo_push("Flip Triangle Edges"); } @@ -3974,7 +4029,12 @@ void edge_rotate_selected(int dir) allqueue(REDRAWVIEW3D, 0); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Rotate Edge"); } @@ -5377,10 +5437,18 @@ int EdgeSlide(short immediate, float imperc) BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); BLI_linklist_free(vertlist,NULL); BLI_linklist_free(edgelist,NULL); - + if(cancel == 1) { return -1; } + else { +#ifdef WITH_VERSE + if(G.editMesh->vnode) { + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); + } +#endif + } return 1; } @@ -5638,7 +5706,14 @@ void mesh_rip(void) } countall(); // apparently always needed when adding stuff, derived mesh - + +#ifdef WITH_VERSE + if(G.editMesh->vnode) { + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); + } +#endif + BIF_TransformSetUndo("Rip"); initTransform(TFM_TRANSLATION, 0); Transform(); diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 4ab9005e875..5dd7bab5176 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -143,6 +143,10 @@ #include "BIF_toolbox.h" #include "BIF_toets.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BSE_edit.h" #include "BSE_editipo.h" #include "BSE_filesel.h" /* For activate_databrowse() */ @@ -255,7 +259,9 @@ void delete_obj(int ok) if TESTBASE(base) { if(ok==0 && (ok=okee("Erase selected Object(s)"))==0) return; if(base->object->type==OB_LAMP) islamp= 1; - +#ifdef WITH_VERSE + if(base->object->vnode) b_verse_delete_object(base->object); +#endif free_and_unlink_base(base); } @@ -961,16 +967,40 @@ void clear_object(char mode) memset(ob->drot, 0, 3*sizeof(float)); QuatOne(ob->quat); QuatOne(ob->dquat); +#ifdef WITH_VERSE + if(ob->vnode) { + struct VNode *vnode = (VNode*)ob->vnode; + ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY; + b_verse_send_transformation(ob); + } +#endif + } else if(mode=='g') { memset(ob->loc, 0, 3*sizeof(float)); memset(ob->dloc, 0, 3*sizeof(float)); +#ifdef WITH_VERSE + if(ob->vnode) { + struct VNode *vnode = (VNode*)ob->vnode; + ((VObjectData*)vnode->data)->flag |= POS_SEND_READY; + b_verse_send_transformation(ob); + } +#endif + } else if(mode=='s') { memset(ob->dsize, 0, 3*sizeof(float)); ob->size[0]= 1.0; ob->size[1]= 1.0; ob->size[2]= 1.0; +#ifdef WITH_VERSE + if(ob->vnode) { + struct VNode *vnode = (VNode*)ob->vnode; + ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY; + b_verse_send_transformation(ob); + } +#endif + } else if(mode=='o') { if(ob->parent) { @@ -1661,7 +1691,6 @@ void docentre(int centremode) Mat4MulVecfl(base->object->imat, cent); } else { INIT_MINMAX(min, max); - mvert= me->mvert; for(a=0; a<me->totvert; a++, mvert++) { DO_MINMAX(mvert->co, min, max); @@ -1671,7 +1700,7 @@ void docentre(int centremode) cent[1]= (min[1]+max[1])/2.0f; cent[2]= (min[2]+max[2])/2.0f; } - + mvert= me->mvert; for(a=0; a<me->totvert; a++, mvert++) { VecSubf(mvert->co, mvert->co, cent); @@ -3770,7 +3799,19 @@ void single_obdata_users(int flag) Mesh *me; ID *id; int a; - + +#ifdef WITH_VERSE + base= FIRSTBASE; + while(base) { + ob= base->object; + if(ob->vnode) { + error("Can't make data single user, when data are shared at verse server"); + return; + } + base = base->next; + } +#endif + base= FIRSTBASE; while(base) { ob= base->object; @@ -4478,6 +4519,13 @@ void adduplicate(int mode, int dupflag) } } } +#ifdef WITH_VERSE + /* send new created object to verse server, + * when original object was linked with object node */ + if(ob->vnode) { + b_verse_duplicate_object(((VNode*)ob->vnode)->session, ob, obn); + } +#endif } } diff --git a/source/blender/src/editscreen.c b/source/blender/src/editscreen.c index 47476bd76f6..4085cb353f5 100644 --- a/source/blender/src/editscreen.c +++ b/source/blender/src/editscreen.c @@ -76,6 +76,10 @@ #include "BKE_blender.h" #include "BKE_screen.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_cursors.h" #include "BIF_drawscene.h" #include "BIF_editsound.h" @@ -1118,6 +1122,10 @@ int do_screenhandlers(bScreen *sc) done= 1; break; case SCREEN_HANDLER_VERSE: +#ifdef WITH_VERSE + b_verse_update(); +#endif + done= 1; break; } diff --git a/source/blender/src/header_info.c b/source/blender/src/header_info.c index 55a4ad49d93..bfbd9d1b265 100644 --- a/source/blender/src/header_info.c +++ b/source/blender/src/header_info.c @@ -79,6 +79,10 @@ #include "BIF_writeimage.h" #include "BIF_drawscene.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BKE_blender.h" #include "BKE_depsgraph.h" #include "BKE_exotic.h" @@ -91,6 +95,10 @@ #include "BKE_scene.h" #include "BKE_world.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLO_writefile.h" @@ -720,6 +728,82 @@ static uiBlock *info_file_exportmenu(void *arg_unused) return block; } +#ifdef WITH_VERSE + +extern ListBase session_list; + +static void do_verse_filemenu(void *arg, int event) +{ + char address[64]; /* lenght of domain name is 63 characters or less */ + VerseSession *session = NULL; + ScrArea *sa; + + if(curarea->spacetype==SPACE_INFO) { + sa= closest_bigger_area(); + areawinset(sa->win); + } + + switch(event) { + case 0: + waitcursor(1); + printf("Connecting to localhost!\n"); + b_verse_connect("localhost"); + waitcursor(0); + break; + case 1: + address[0] = '\0'; + if(sbutton(address, 0, 63, "Server:")) { + waitcursor(1); + printf("Connecting to %s\n", address); + b_verse_connect(address); + waitcursor(0); + } + break; + case 2: + session = session_menu(); + if(session) { + printf("Disconnecting session: %s!\n", session->address); + end_verse_session(session, 1); + } + break; + case 3: + printf("Disconnecting all sessions!\n"); + end_all_verse_sessions(); + break; + } +} + +static uiBlock *verse_filemenu(void *unusedargs) +{ + uiBlock *block; + short yco = 20, menuwidth = 120; + + block= uiNewBlock(&curarea->uiblocks, "verse_filemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); + uiBlockSetButmFunc(block, do_verse_filemenu, NULL); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Connect to localhost", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Connect ...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); + if(session_list.first != NULL) { + if(session_list.first != session_list.last) { + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Disconnect ...", + 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Disconnect all", + 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); + } + else { + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Disconnect", + 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); + } + + } + + uiBlockSetDirection(block, UI_RIGHT); + uiTextBoundsBlock(block, 60); + + return block; +} +#endif + static void do_info_filemenu(void *arg, int event) { ScrArea *sa; @@ -871,6 +955,9 @@ static uiBlock *info_filemenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "New|Ctrl X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Open...|F1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); +#ifdef WITH_VERSE + uiDefIconTextBlockBut(block, verse_filemenu, NULL, ICON_RIGHTARROW_THIN, "Verse", 0, yco-=20, menuwidth, 19, ""); +#endif uiDefIconTextBlockBut(block, info_openrecentmenu, NULL, ICON_RIGHTARROW_THIN, "Open Recent",0, yco-=20, 120, 19, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Recover Last Session", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, ""); diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index ade1b001efc..a0aa801b55a 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -1,4 +1,4 @@ -/** +/* * header_view3d.c oct-2003 * * Functions to draw the "3D Viewport" window header @@ -69,6 +69,10 @@ #include "BKE_main.h" #include "BKE_mesh.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -106,6 +110,10 @@ #include "BIF_toolbox.h" #include "BIF_transform.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BPY_extern.h" #include "BPY_menus.h" @@ -2074,11 +2082,18 @@ static uiBlock *view3d_edit_object_scriptsmenu(void *arg_unused) return block; } +#ifdef WITH_VERSE +extern ListBase session_list; +#endif + static void do_view3d_edit_objectmenu(void *arg, int event) { /* needed to check for valid selected objects */ Base *base=NULL; Object *ob=NULL; +#ifdef WITH_VERSE + struct VerseSession *session=NULL; +#endif base= BASACT; if (base) ob= base->object; @@ -2118,6 +2133,13 @@ static void do_view3d_edit_objectmenu(void *arg, int event) case 15: /* Object Panel */ add_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, UI_PNL_UNSTOW); break; +#ifdef WITH_VERSE + case 16: /* Share Object at Verse server */ + if(session_list.first != session_list.last) session = session_menu(); + else session = session_list.first; + if(session) b_verse_push_object(session, ob); + break; +#endif } allqueue(REDRAWVIEW3D, 0); } @@ -2130,6 +2152,19 @@ static uiBlock *view3d_edit_objectmenu(void *arg_unused) block= uiNewBlock(&curarea->uiblocks, "view3d_edit_objectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); uiBlockSetButmFunc(block, do_view3d_edit_objectmenu, NULL); +#ifdef WITH_VERSE + if(session_list.first != NULL) { + Base *base = BASACT; + Object *ob = NULL; + if (base) ob= base->object; + + if((ob->type == OB_MESH) && (!ob->vnode)) { + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Share at Verse Server", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, ""); + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + } + } +#endif + uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 15, ""); uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, ""); uiDefIconTextBlockBut(block, view3d_object_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, ""); @@ -2610,6 +2645,10 @@ static uiBlock *view3d_edit_mesh_scriptsmenu(void *arg_unused) static void do_view3d_edit_meshmenu(void *arg, int event) { +#ifdef WITH_VERSE + struct VerseSession *session; +#endif + switch(event) { case 0: /* Undo Editing */ @@ -2652,6 +2691,13 @@ static void do_view3d_edit_meshmenu(void *arg, int event) if(G.scene->proportional) G.scene->proportional= 0; else G.scene->proportional= 1; break; +#ifdef WITH_VERSE + case 13: + if(session_list.first != session_list.last) session = session_menu(); + else session = session_list.first; + if(session) b_verse_push_object(session, G.obedit); + break; +#endif } allqueue(REDRAWVIEW3D, 0); } @@ -2664,7 +2710,15 @@ static uiBlock *view3d_edit_meshmenu(void *arg_unused) block= uiNewBlock(&curarea->uiblocks, "view3d_edit_meshmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); uiBlockSetButmFunc(block, do_view3d_edit_meshmenu, NULL); - + +#ifdef WITH_VERSE + if((session_list.first != NULL) && (!G.obedit->vnode)) { + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Share at Verse Server", + 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, ""); + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + } +#endif + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Editing|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Redo Editing|Shift U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); uiDefIconTextBlockBut(block, editmode_undohistorymenu, NULL, ICON_RIGHTARROW_THIN, "Undo History", 0, yco-=20, 120, 19, ""); diff --git a/source/blender/src/meshtools.c b/source/blender/src/meshtools.c index 4dd3825c134..03771e3df93 100644 --- a/source/blender/src/meshtools.c +++ b/source/blender/src/meshtools.c @@ -138,7 +138,28 @@ int join_mesh(void) ob= OBACT; if(!ob || ob->type!=OB_MESH) return 0; - + +#ifdef WITH_VERSE + /* it isn't allowed to join shared object at verse server + * this function will be implemented as soon as possible */ + base= FIRSTBASE; + while(base) { + if TESTBASELIB(base) { + if(base->object->type==OB_MESH) { + if(base->object->vnode) { + haskey= 1; + break; + } + } + } + base= base->next; + } + if(haskey) { + error("Can't join meshes shared at verse server"); + return 0; + } +#endif + /* count */ base= FIRSTBASE; while(base) { diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c index d7d89f991d7..187106e79d6 100644 --- a/source/blender/src/outliner.c +++ b/source/blender/src/outliner.c @@ -70,6 +70,10 @@ #include "BKE_scene.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BIF_butspace.h" #include "BIF_drawscene.h" #include "BIF_drawtext.h" @@ -94,6 +98,10 @@ #include "BIF_space.h" #include "BIF_toolbox.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #ifdef INTERNATIONAL #include "FTF_Api.h" #endif @@ -114,6 +122,10 @@ #define TREESTORE(a) ((a)?soops->treestore->data+(a)->store_index:NULL) +#ifdef WITH_VERSE +extern ListBase session_list; +#endif + /* ******************** PERSISTANT DATA ***************** */ static void outliner_storage_cleanup(SpaceOops *soops) @@ -702,6 +714,34 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i break; } } +#ifdef WITH_VERSE + else if(type==ID_VS) { + struct VerseSession *session = (VerseSession*)idv; + te->name = session->address; + te->directdata = (void*)session; + te->idcode = ID_VS; + } + else if(type==ID_VN) { + struct VNode *vnode = (VNode*)idv; + te->name = vnode->name; + te->idcode = ID_VN; + if(vnode->type==V_NT_OBJECT) { + struct TreeElement *ten; + struct VNode *child_node; + struct VLink *vlink; + + vlink = ((VObjectData*)vnode->data)->links.lb.first; + while(vlink) { + child_node = vlink->target; + if(child_node && child_node->type==V_NT_GEOMETRY) { + ten = outliner_add_element(soops, &te->subtree, child_node, te, ID_VN, 0); + ten->directdata = child_node; + } + vlink = vlink->next; + } + } + } +#endif return te; } @@ -754,6 +794,9 @@ static void outliner_build_tree(SpaceOops *soops) TreeElement *te, *ten; TreeStoreElem *tselem; int show_opened= soops->treestore==NULL; /* on first view, we open scenes */ +#ifdef WITH_VERSE + struct VerseSession *session; +#endif outliner_free_tree(&soops->tree); outliner_storage_cleanup(soops); @@ -840,7 +883,28 @@ static void outliner_build_tree(SpaceOops *soops) ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0); if(ten) ten->directdata= BASACT; } - + +#ifdef WITH_VERSE + /* add all session to the "root" of hierarchy */ + for(session=session_list.first; session; session = session->next) { + struct VNode *vnode; + if(session->flag & VERSE_CONNECTED) { + te= outliner_add_element(soops, &soops->tree, session, NULL, ID_VS, 0); + /* add all object nodes as childreen of session */ + for(vnode=session->nodes.lb.first; vnode; vnode=vnode->next) { + if(vnode->type==V_NT_OBJECT) { + ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0); + ten->directdata= vnode; + } + else if(vnode->type==V_NT_BITMAP) { + ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0); + ten->directdata= vnode; + } + } + } + } +#endif + outliner_sort(soops, &soops->tree); } @@ -1509,6 +1573,59 @@ static int do_outliner_mouse_event(SpaceOops *soops, TreeElement *te, short even } } else { +#ifdef WITH_VERSE + if(event==RIGHTMOUSE) { + short event; + if(te->idcode==ID_VS) { + struct VerseSession *session = (VerseSession*)te->directdata; + struct VNode *vnode; + if(!(session->flag & VERSE_AUTOSUBSCRIBE)) { + event = pupmenu("VerseSession %t| End Session %x1| Subscribe to All Nodes %x2| Start Autosubscribe %x3"); + } + else { + event = pupmenu("VerseSession %t| End Session %x1| Subscribe to All Nodes %x2| Stop Autosubscribe %x4"); + } + switch(event) { + case 1: + end_verse_session(session, 1); + break; + case 2: + vnode = session->nodes.lb.first; + while(vnode) { + b_verse_pop_node(vnode); + vnode = vnode->next; + } + break; + case 3: + vnode = session->nodes.lb.first; + while(vnode) { + b_verse_pop_node(vnode); + vnode = vnode->next; + } + session->flag |= VERSE_AUTOSUBSCRIBE; + break; + case 4: + session->flag &= ~VERSE_AUTOSUBSCRIBE; + break; + } + } + else if(te->idcode==ID_VN) { + struct VNode *vnode = (VNode*)te->directdata; + event = pupmenu("VerseNode %t| Subscribe %x1| Unsubscribe %x2"); + switch(event) { + case 1: + b_verse_pop_node(vnode); + break; + case 2: + /* Global */ + b_verse_unsubscribe(vnode); + break; + } + } + } + else { +#endif + /* always makes active object */ tree_element_active_object(soops, te); @@ -1533,6 +1650,9 @@ static int do_outliner_mouse_event(SpaceOops *soops, TreeElement *te, short even } else tree_element_type_active(soops, te, tselem, 1); +#ifdef WITH_VERSE + } +#endif } return 1; } @@ -1722,7 +1842,13 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb) tselem= TREESTORE(te); if(tselem->flag & TSE_SELECTED) { if(tselem->type) { +#ifdef WITH_VERSE + if(te->idcode==ID_VS) datalevel= TSE_VERSE_SESSION; + else if(te->idcode==ID_VN) datalevel= TSE_VERSE_OBJ_NODE; + else if(datalevel==0) datalevel= tselem->type; +#else if(datalevel==0) datalevel= tselem->type; +#endif else if(datalevel!=tselem->type) datalevel= -1; } else { @@ -1973,6 +2099,17 @@ static void ebone_cb(int event, TreeElement *te, TreeStoreElem *tselem) ebone->flag &= ~BONE_HIDDEN_A; } +#ifdef WITH_VERSE +static void vsession_cb(int event, TreeElement *te, TreeStoreElem *tselem) +{ +/* struct VerseSession *vsession =(VerseSession*)te->directdata;*/ + + if(event==1) { + printf("\tending verse session\n"); + } +} +#endif + static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, void (*operation_cb)(int, TreeElement *, TreeStoreElem *)) { @@ -2095,6 +2232,14 @@ void outliner_operation_menu(ScrArea *sa) BIF_undo_push("EditBone operation"); } } +#ifdef WITH_VERSE + else if(datalevel==TSE_VERSE_SESSION) { + short event= pupmenu("VerseSession %t| End %x1"); + if(event>0) { + outliner_do_data_operation(soops, datalevel, event, &soops->tree, vsession_cb); + } + } +#endif allqueue(REDRAWOOPS, 0); allqueue(REDRAWBUTSALL, 0); @@ -2163,6 +2308,12 @@ static void tselem_draw_icon(float x, float y, TreeStoreElem *tselem, TreeElemen BIF_icon_draw(x, y, ICON_ARMATURE_DEHLT); break; case TSE_POSE_CHANNEL: BIF_icon_draw(x, y, ICON_WPAINT_DEHLT); break; +#ifdef WITH_VERSE + case ID_VS: + BIF_icon_draw(x, y, ICON_VERSE); break; + case ID_VN: + BIF_icon_draw(x, y, ICON_VERSE); break; +#endif default: BIF_icon_draw(x, y, ICON_DOT); break; } @@ -2354,9 +2505,14 @@ static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int st else BIF_ThemeColor(TH_TEXT); glRasterPos2i(startx+offsx, *starty+5); BIF_RasterPos(startx+offsx, *starty+5); - BIF_DrawString(G.font, te->name, 0); - - offsx+= OL_X + BIF_GetStringWidth(G.font, te->name, 0); +#ifdef WITH_VERSE + if(te->name) { +#endif + BIF_DrawString(G.font, te->name, 0); + offsx+= OL_X + BIF_GetStringWidth(G.font, te->name, 0); +#ifdef WITH_VERSE + } +#endif /* closed item, we draw the icons, not when it's a scene though */ if(tselem->flag & TSE_CLOSED) { diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 8ce07779d84..6f05605cb30 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -4327,7 +4327,12 @@ static void winqreadoopsspace(ScrArea *sa, void *spacedata, BWinEvent *evt) view2dmove(event); /* in drawipo.c */ break; case RIGHTMOUSE: +#ifdef WITH_VERSE + /* evil hack due to verse */ + outliner_mouse_event(sa, event); +#else outliner_operation_menu(sa); +#endif break; case AKEY: diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c index 572bde118d5..30ab9fdb17e 100755 --- a/source/blender/src/transform_conversions.c +++ b/source/blender/src/transform_conversions.c @@ -1428,6 +1428,15 @@ static void VertsToTransData(TransData *td, EditVert *eve) td->tdi = NULL; td->val = NULL; td->tdmir= NULL; + +#ifdef WITH_VERSE + if(eve->vvert) { + td->verse = (void*)eve->vvert; + td->flag |= TD_VERSE_VERT; + } + else + td->flag &= ~TD_VERSE_VERT; +#endif } /* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */ @@ -2051,6 +2060,14 @@ static void ObjectToTransData(TransData *td, Object *ob) Mat3One(td->smtx); Mat3One(td->mtx); } +#ifdef WITH_VERSE + if(ob->vnode) { + td->verse = (void*)ob; + td->flag |= TD_VERSE_OBJECT; + } + else + td->flag &= ~TD_VERSE_OBJECT; +#endif } diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c index 52b2c823cc8..71ce2ff7f84 100755 --- a/source/blender/src/transform_generics.c +++ b/source/blender/src/transform_generics.c @@ -59,6 +59,10 @@ #include "BIF_editsima.h" #include "BIF_meshtools.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + #include "BKE_action.h" #include "BKE_anim.h" #include "BKE_armature.h" @@ -74,6 +78,10 @@ #include "BKE_object.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BSE_view.h" #include "BDR_unwrapper.h" @@ -202,6 +210,9 @@ static void editmesh_apply_to_mirror(TransInfo *t) void recalcData(TransInfo *t) { Base *base; +#ifdef WITH_VERSE + struct TransData *td; +#endif if (G.obedit) { if (G.obedit->type == OB_MESH) { @@ -334,6 +345,17 @@ void recalcData(TransInfo *t) } } } + +#ifdef WITH_VERSE + for (td = t->data; td < t->data + t->total; td++) { + if(td->flag & TD_VERSE_VERT) { + if(td->verse) + send_versevert_pos((VerseVert*)td->verse); + } + else if(td->flag & TD_VERSE_OBJECT) + if(td->verse) b_verse_send_transformation((Object*)td->verse); + } +#endif /* update shaded drawmode while transform */ if(t->spacetype==SPACE_VIEW3D && G.vd->drawtype == OB_SHADED) @@ -463,6 +485,25 @@ void initTrans (TransInfo *t) void postTrans (TransInfo *t) { G.moving = 0; // Set moving flag off (display as usual) +#ifdef WITH_VERSE + struct TransData *td; + + for (td = t->data; td < t->data + t->total; td++) { + if(td->flag & TD_VERSE_VERT) { + if(td->verse) send_versevert_pos((VerseVert*)td->verse); + } + else if(td->flag & TD_VERSE_OBJECT) { + if(td->verse) { + struct VNode *vnode; + vnode = (VNode*)((Object*)td->verse)->vnode; + ((VObjectData*)vnode->data)->flag |= POS_SEND_READY; + ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY; + ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY; + b_verse_send_transformation((Object*)td->verse); + } + } + } +#endif stopConstraint(t); @@ -619,6 +660,25 @@ void restoreTransObjects(TransInfo *t) for (td = t->data; td < t->data + t->total; td++) { restoreElement(td); +#ifdef WITH_VERSE + /* position of vertexes and object transformation matrix is sent + * extra, becuase blender uses synchronous sending of vertexes + * position as well object trans. matrix and it isn't possible to + * send it in recalcData sometimes */ + if(td->flag & TD_VERSE_VERT) { + if(td->verse) { + ((VerseVert*)td->verse)->flag |= VERT_POS_OBSOLETE; + } + } + else if(td->flag & TD_VERSE_OBJECT) + if(td->verse) { + struct VNode *vnode; + vnode = (VNode*)((Object*)td->verse)->vnode; + ((VObjectData*)vnode->data)->flag |= POS_SEND_READY; + ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY; + ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY; + } +#endif } recalcData(t); } diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index 27f2248d985..10dd2a29024 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -82,6 +82,10 @@ #include "BKE_packedFile.h" #include "BKE_utildefines.h" +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + #include "BLI_vfontdata.h" #include "BIF_fsmenu.h" @@ -104,6 +108,11 @@ #include "BIF_toolbox.h" #include "BIF_cursors.h" +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + + #include "BSE_drawview.h" #include "BSE_edit.h" #include "BSE_editipo.h" @@ -344,13 +353,38 @@ static void init_userdef_file(void) } +#ifdef WITH_VERSE +extern ListBase session_list; +#endif + void BIF_read_file(char *name) { extern short winqueue_break; /* editscreen.c */ int retval; - - //NOT here! - //sound_end_all_sounds(); +#ifdef WITH_VERSE + struct VerseSession *session; + struct VNode *vnode; + + session = session_list.first; + while(session) { + vnode = session->nodes.lb.first; + while(vnode) { + switch(vnode->type) { + case V_NT_OBJECT: + unsubscribe_from_obj_node(vnode); + break; + case V_NT_GEOMETRY: + unsubscribe_from_geom_node(vnode); + break; + case V_NT_BITMAP: + unsubscribe_from_bitmap_node(vnode); + break; + } + vnode = vnode->next; + } + session = session->next; + } +#endif /* first try to read exotic file formats... */ /* it throws error box when file doesnt exist and returns -1 */ @@ -568,7 +602,6 @@ static void readBlog(void) BLI_free_file_lines(lines); } - static void writeBlog(void) { struct RecentFile *recent, *next_recent; @@ -859,6 +892,10 @@ void exit_usiblender(void) sound_exit_audio(); if(G.listener) MEM_freeN(G.listener); +#ifdef WITH_VERSE + end_all_verse_sessions(); +#endif + libtiff_exit(); #ifdef WITH_QUICKTIME diff --git a/source/blender/src/verse_common.c b/source/blender/src/verse_common.c new file mode 100644 index 00000000000..ec1ee8cf024 --- /dev/null +++ b/source/blender/src/verse_common.c @@ -0,0 +1,270 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include <string.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "mydevice.h" + +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_global.h" +#include "BKE_blender.h" + +#include "BIF_verse.h" +#include "BIF_space.h" +#include "BIF_interface.h" + +extern ListBase session_list; + +/* + * this function creates popup menu with all active VerseSessions + * it return pointer at selected VerseSession, if no VerseSession + * is selected, then NULL is returned + */ +VerseSession *session_menu(void) +{ + struct VerseSession *session; + char session_number[10]; + short i=1, num=1; + char session_address_list[1024]; /* pupmenu business */ + + session_number[0] = '\0'; + session_address_list[0] = '\0'; + + strcat(session_address_list, "Session list %t"); + + session = session_list.first; + + while(session){ + strcat(session_address_list, "| "); + strcat(session_address_list, session->address); + strcat(session_address_list, " %x"); + sprintf(session_number, "%d", num); + strcat(session_address_list, session_number); + num++; + session = session->next; + } + + printf("session list: %s\n", session_address_list); + num = pupmenu(session_address_list); + + if(num==-1) return NULL; + + session = session_list.first; + + while(session) { + if(i==num) return session; + i++; + session = session->next; + } + + return NULL; +} + +/* + * returns name of verse client (it is used as avatar's name) + */ +char *verse_client_name(void) +{ + char *client_name; + char blender_version[5]; + short name_lenght = 14; + +#ifndef WIN32 + char *hostname; + hostname = getenv("HOSTNAME"); + if(hostname) name_lenght += strlen(hostname); +#endif + + client_name = (char*)MEM_mallocN(sizeof(char)*name_lenght, "verse client name"); + client_name[0] = '\0'; + + strcat(client_name, "blender_"); + blender_version[0] = '\0'; + sprintf(blender_version, "%d", BLENDER_VERSION); + strcat(client_name, blender_version); + +#ifndef WIN32 + /* add at the end of the client name hostname */ + if(hostname) { + strcat(client_name, ":"); + strcat(client_name, hostname); + } +#endif + + return client_name; +} + +/*=========================================================== + * + * functions executed after calling callback functions + * + ============================================================*/ + +/* + * this function is called, when some tag was changed or new tag was created + */ +void post_tag_change(VTag *vtag) +{ + printf("\tnew tag %s was created or changed\n", vtag->name); +} + +/* + * this function is called, when verse taggroup was created + */ +void post_taggroup_create(VTagGroup *vtaggroup) +{ + printf("\tnew taggroup %s was created\n", vtaggroup->name); +} + +/* + * this function is called after creating of new VerseNode + */ +void post_node_create(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + + if((session->flag & VERSE_AUTOSUBSCRIBE) && (vnode->owner_id != VN_OWNER_MINE)) { + if(vnode->type == V_NT_OBJECT) { + create_object_from_verse_node(vnode); + } + else if(vnode->type == V_NT_GEOMETRY) { + create_mesh_from_geom_node(vnode);; + } + } + + allqueue(REDRAWOOPS, 0); +} + +/* + * this function is called after destroying of VerseNode + */ +void post_node_destroy(VNode *vnode) +{ + allqueue(REDRAWOOPS, 0); + + /* TODO: destroy bindings between vnode and blender data structures */ +} + +/* + * this function is calles after renaming of VerseNode by verse_server + */ +void post_node_name_set(VNode *vnode) +{ + /* if VerseNode has coresponding blender data structure, then + * change ID name of data structure */ + if(vnode->type==V_NT_OBJECT) { + struct Object *ob; + ob = (Object*)((VObjectData*)vnode->data)->object; + if(ob) { + char *str; + str = (char*)malloc(sizeof(char)*(strlen(vnode->name)+3)); + str[0] = '\0'; + strcat(str, "OB"); + strcat(str, vnode->name); + strncpy(ob->id.name, str, 23); + printf("\tob->id.name: %s\n", ob->id.name); + free(str); + } + } + else if(vnode->type==V_NT_GEOMETRY) { + struct Mesh *me; + + me = (Mesh*)((VGeomData*)vnode->data)->mesh; + if(me) { + char *str; + str = (char*)malloc(sizeof(char)*(strlen(vnode->name)+3)); + str[0] = '\0'; + strcat(str, "ME"); + strcat(str, vnode->name); + strncpy(me->id.name, str, 23); + printf("\tme->id.name: %s\n", me->id.name); + free(str); + } + } + + allqueue(REDRAWALL, 0); +} + +/* + * this function is called after acception connection with verse server + */ +void post_connect_accept(VerseSession *session) +{ + G.f |= G_VERSE_CONNECTED; + + session->counter = 0; + + allqueue(REDRAWOOPS, 0); +} + +/* + * this function is called, when connestion with verse server is ended/terminated/etc. + */ +void post_connect_terminated(VerseSession *session) +{ + /* if it is last session, then no other will exist ... set Global flag */ + if((session->prev==NULL) && (session->next==NULL)) + G.f &= ~G_VERSE_CONNECTED; + + allqueue(REDRAWOOPS, 0); +} + +/* + * if connection wasn't accepted, then free VerseSession + * and print warning message with popupmenu + */ +void post_connect_update(VerseSession *session) +{ + if(session->flag & VERSE_CONNECTING) { + session->counter++; + if(session->counter > MAX_UNCONNECTED_EVENTS) { + char *str; + /* popup menu*/ + str = malloc(sizeof(char)*(strlen(session->address)+35)); + str[0]='\0'; + strcat(str, "Error%t|No response from server: "); + strcat(str, session->address); + pupmenu(str); + free(str); + + session->flag = 0; + session->counter = 0; + session->post_connect_terminated(session); + free_verse_session(session); + } + } +} + +#endif + diff --git a/source/blender/src/verse_image.c b/source/blender/src/verse_image.c new file mode 100644 index 00000000000..78da14220e8 --- /dev/null +++ b/source/blender/src/verse_image.c @@ -0,0 +1,345 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WITH_VERSE + +#include <string.h> + +#include "mydevice.h" + +#include "BKE_verse.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_image_types.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BDR_drawmesh.h" + +#include "BIF_verse.h" +#include "BIF_space.h" + +/* + * unsubscribe from verse bitmap + */ +void unsubscribe_from_bitmap_node(VNode *vnode) +{ + if(vnode->type != V_NT_BITMAP) return; + + /* TODO */ +} + +/* + * upload image to verse server + */ +void push_image_to_verse_server(VerseSession *session, Image *image) +{ + struct VNode *vnode; + + if(!session) return; + + if(!(session->flag & VERSE_CONNECTED)) return; + + /* create "my" new object VerseNode */ + vnode= create_verse_node(session->vsession, -1 , V_NT_BITMAP, VN_OWNER_MINE); + /* create object data */ + vnode->data = create_bitmap_data(); + + /* set up name of VerseNode */ + vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(image->id.name)-1), "object node name"); + vnode->name[0] = '\0'; + strcat(vnode->name, image->id.name+2); + + /* set up dimension of image */ + if(image->ibuf) { + ((VBitmapData*)vnode->data)->width = image->ibuf->x; + ((VBitmapData*)vnode->data)->height = image->ibuf->y; + } + else { + ((VBitmapData*)vnode->data)->width = 0; + ((VBitmapData*)vnode->data)->height = 0; + } + ((VBitmapData*)(vnode->data))->height = 1; + + /* set up pointers between Object and VerseNode */ + ((VBitmapData*)vnode->data)->image = (void*)image; + image->vnode = (void*)vnode; + + /* add node to sending queue */ + add_item_to_send_queue(&(session->queue), vnode, VERSE_NODE); +} + +/* + * synchronize blender image channel (R,G,B,A) with verse bitmap layer + */ +void sync_blender_image_channel_with_verse_layer(VNode *vnode, VBitmapLayer *vblayer) +{ + struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image; + struct ImBuf *ibuf; + unsigned char *rect; + int x, y, height, t_width, i, channel=0; + + if(!image) return; + + ibuf = image->ibuf; + if(!ibuf) return; + + rect = (unsigned char*)ibuf->rect; + + /* select channel due to verse layer name */ + if(strcmp(vblayer->name,"col_r")==0) + channel = 0; + else if(strcmp(vblayer->name,"col_g")==0) + channel = 1; + else if(strcmp(vblayer->name, "col_b")==0) + channel = 2; + else if(strcmp(vblayer->name,"alpha")==0) + channel = 3; + +#ifdef VERSE_DEBUG_PRINT + printf(" %s:%d\n", vblayer->name, channel); +#endif + + height = ((VBitmapData*)(vnode->data))->height; + t_width = ((VBitmapData*)(vnode->data))->t_width; + + i = (height-1)*t_width; + +#ifdef VERSE_DEBUG_PRINT + printf("\ti:%d\n", i); +#endif + + if(vblayer->type==VN_B_LAYER_UINT8) { + unsigned char *vuint8 = (unsigned char*)vblayer->data; + for(y=height-1; y>=0; y--, i=y*t_width) + for(x=0; x<ibuf->x; x++, rect+=4, i++) + rect[channel] = (char)vuint8[i]; + } + + allqueue(REDRAWIMAGE, 0); + allqueue(REDRAWVIEW3D, 0); +} + +/* + * synchronize blender image with verse image + */ +void sync_blender_image_with_verse_bitmap_node(VNode *vnode) +{ + struct VBitmapLayer *vblayer; + + vblayer = ((VBitmapData*)(vnode->data))->layers.lb.first; + + while(vblayer) { +#ifdef VERSE_DEBUG_PRINT + printf("\tsyncing layer:"); +#endif + sync_blender_image_channel_with_verse_layer(vnode, vblayer); + vblayer = vblayer->next; + } +} + +/* + * This function is called, when some other verse client change dimension of image. + * It is neccesary to reallocate blender image too, when dimension of verse image + * is different from blender image. + */ +void post_bitmap_dimension_set(VNode *vnode) +{ + struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image; + struct ImBuf *ibuf; + + if(!image) return; + + ibuf = image->ibuf; + if(!ibuf) return; + + if(vnode->owner_id == VN_OWNER_MINE) { + if( ((VBitmapData*)vnode->data)->layers.lb.first == NULL ) { + /* send all verse bitmap layers (RGBA) to verse server */ + printf("\tsending all bitmap layers to verse server\n"); + verse_send_b_layer_create(vnode->id, -1, "col_r", VN_B_LAYER_UINT8); + verse_send_b_layer_create(vnode->id, -1, "col_g", VN_B_LAYER_UINT8); + verse_send_b_layer_create(vnode->id, -1, "col_b", VN_B_LAYER_UINT8); + verse_send_b_layer_create(vnode->id, -1, "alpha", VN_B_LAYER_UINT8); + + return; + } + } + + if((ibuf->x!=((VBitmapData*)vnode->data)->width) || (ibuf->y!=((VBitmapData*)vnode->data)->height)) { + struct VBitmapLayer *vblayer; + struct ImBuf *new_ibuf; + + /* allocate new ibuf */ + new_ibuf= IMB_allocImBuf(((VBitmapData*)vnode->data)->width, + ((VBitmapData*)vnode->data)->height, 24, IB_rect, 0); + /* free old ibuf */ + IMB_freeImBuf(ibuf); + /* set up pointer at new ibuf */ + image->ibuf = new_ibuf; + + /* sync blender image with all verse layers */ + vblayer = ((VBitmapData*)(vnode->data))->layers.lb.first; + while(vblayer) { + sync_blender_image_channel_with_verse_layer(vnode, vblayer); + vblayer = vblayer->next; + } + } +} + +/* + * when blender tries to upload image to verse server, then it is neccessary + * to push coresponding channel data to verse server, when verse bitmap layer + * was created + */ +void post_bitmap_layer_create(VBitmapLayer *vblayer) +{ + struct VNode *vnode = vblayer->vnode; + struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image; + struct ImBuf *ibuf; + unsigned char *rect; + short channel; +/* VNBTile tile[VN_B_TILE_SIZE*VN_B_TILE_SIZE]; + unsigned int width, t_width, height, t_height, x, y, i, j; */ + + /* if this application doesn't try to upload this image to verse + * server then do nothing */ + if(vnode->owner_id != VN_OWNER_MINE) return; + + if(!image) return; + + ibuf = image->ibuf; + if(!ibuf) return; + + rect = (unsigned char*)ibuf->rect; + + if(strncmp(vblayer->name, "col_r", 5)) + channel = 0; + else if(strncmp(vblayer->name, "col_g", 5)) + channel = 1; + else if(strncmp(vblayer->name, "col_b", 5)) + channel = 2; + else if(strncmp(vblayer->name, "alpha", 5)) + channel = 3; + + /* TODO: send all data of channel to verse server */ +} + +/* + * dummy function now + */ +void post_bitmap_layer_destroy(VBitmapLayer *vblayer) +{ +} + +/* + * this function is executed, when some image changed tile comes from verse server, + * it is neccessary to do some crazy transformation here, because blender uses + * different (very unstandard) image coordinate system (begining of coordinate + * system is in bottom left corner) ... all other programs (including verse) has + * begining of image coordinate system in left top corner + */ +void post_bitmap_tile_set(VBitmapLayer *vblayer, unsigned int xs, unsigned int ys) +{ + struct VNode *vnode = vblayer->vnode; + struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image; + struct ImBuf *ibuf; + unsigned char *rect, *i_rect; + unsigned int x, y, t_width, t_height, height, m_ys, m_y, d, i, j, channel=0; + + if(!image) return; + + ibuf = image->ibuf; + if(!ibuf) return; + + /* select channel due to verse layer name */ + if(strcmp(vblayer->name,"col_r")==0) + channel = 0; + else if(strcmp(vblayer->name,"col_g")==0) + channel = 1; + else if(strcmp(vblayer->name, "col_b")==0) + channel = 2; + else if(strcmp(vblayer->name,"alpha")==0) + channel = 3; + + i_rect = rect = (unsigned char*)ibuf->rect; + + /* width of verse image including all tiles */ + t_width =((VBitmapData*)vnode->data)->t_width; + /* height of verse image including all tiles */ + t_height =((VBitmapData*)vnode->data)->t_height; + /* height of blender image */ + height = ((VBitmapData*)vnode->data)->height; + + /* if the bitmap's dimensions are not integer multiples of the tile + * side length, eight, then d will not be zero (height of "uncomplete + * tile") */ + d = VN_B_TILE_SIZE - (t_height - height); + /* mirrored coordination of received tile */ + m_ys = t_height - ys - VN_B_TILE_SIZE; + + /* ys and m_ys are y axis, where we will do some changes */ + if(ys + VN_B_TILE_SIZE > height) { + m_ys = 0; + ys = ys + d - 1; + } + else { + m_ys = m_ys - VN_B_TILE_SIZE + d; + ys = ys + VN_B_TILE_SIZE - 1; + } + + /* "index" of blender image */ + j = m_ys*ibuf->x + xs; + /* index of verse image */ + i = ys*t_width + xs; + + /* pointer at image data, that will be changed in following loop */ + rect = i_rect + 4*j; + + /* it seems hackish, but I didn't find better solution :-/ */ + if(vblayer->type==VN_B_LAYER_UINT8) { + unsigned char *vuint8 = (unsigned char*)vblayer->data; + for(y=ys, m_y = m_ys; + (m_y<m_ys+VN_B_TILE_SIZE) && (m_y<ibuf->y); + y--, m_y++, i=y*t_width+xs, j=m_y*ibuf->x+xs, rect=i_rect+4*j) + for(x=xs; (x<xs+VN_B_TILE_SIZE) && (x<ibuf->x); x++, rect+=4, i++, j++) + rect[channel] = (char)vuint8[i]; + } + + free_realtime_image(image); + + /* redraw preview of image ... uncommented, because rendering + * was computed too often */ +/* BIF_preview_changed(ID_TE); */ + allqueue(REDRAWIMAGE, 0); + allqueue(REDRAWVIEW3D, 0); +} + +#endif + diff --git a/source/blender/src/verse_mesh.c b/source/blender/src/verse_mesh.c new file mode 100644 index 00000000000..7e3479e3144 --- /dev/null +++ b/source/blender/src/verse_mesh.c @@ -0,0 +1,1611 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL 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 "BLI_dynamiclist.h" +#include "BLI_blenlib.h" +#include "BLI_editVert.h" + +#include "BKE_global.h" +#include "BKE_verse.h" +#include "BKE_mesh.h" +#include "BKE_depsgraph.h" +#include "BKE_utildefines.h" + +#include "BIF_verse.h" +#include "BIF_editmesh.h" +#include "BIF_space.h" +#include "BIF_screen.h" + +#include "BSE_edit.h" + +#include "editmesh.h" + +#include "verse.h" + +/* prototypes of static functions */ + +static void mark_changed_face_obsolete(struct VerseFace *vface); +static void sync_verseface_with_editface(struct VLayer *vlayer, struct VerseFace *vface); + +void createVerseVertNL(struct EditVert *ev, struct VNode *vnode, struct VLayer *vlayer); +static void createAllVerseVerts(struct VNode *vnode, struct VLayer *vlayer); +void createVerseFaceNL(struct EditFace *efa, struct VNode *vnode, struct VLayer *vlayer); +static void createAllVerseFaces(struct VNode *vnode, struct VLayer *vlayer); + +/*============================================================================= + * + * functions handling verse/blender FACES + * + *===========================================================================*/ + +/* + * create new VerseFace (polygon), due to information about EditFace + * put VerseFace to queue ... send to verse host (server) + */ +void createVerseFace(EditFace *efa) +{ + if(G.editMesh->vnode) { + struct VLayer *vlayer = find_verse_layer_type((VGeomData*)((VNode*)G.editMesh->vnode)->data, POLYGON_LAYER); + createVerseFaceNL(efa, (VNode*)G.editMesh->vnode, vlayer); + } + else efa->vface = NULL; +} + +/* + * create new VerseFace (polygon), due to information about EditFace + * put VerseFace to queue ... send to verse host (server) + * NL version of function (infomration about verse node and + * layer is known ... optimalisation) + */ +void createVerseFaceNL(EditFace *efa, VNode *vnode, VLayer *vlayer) +{ + struct VerseFace *vface; + + vface = (VerseFace*)create_verse_face(vlayer, vlayer->counter, -1, -1, -1, -1); + + vface->face = (void*)efa; + efa->vface = (void*)vface; + + vface->flag |= FACE_SEND_READY; + + /* EditVert #1 */ + if(efa->v1) { + if(efa->v1->vvert) { + vface->vvert0 = (VerseVert*)efa->v1->vvert; + if(((VerseVert*)efa->v1->vvert)->flag & VERT_RECEIVED) { + vface->v0 = ((VerseVert*)efa->v1->vvert)->id; + vface->counter--; + } + else + vface->flag &= ~FACE_SEND_READY; + } + } + else + vface->counter--; + + /* EditVert #2 */ + if(efa->v2) { + if(efa->v2->vvert) { + vface->vvert1 = (VerseVert*)efa->v2->vvert; + if(((VerseVert*)efa->v2->vvert)->flag & VERT_RECEIVED) { + vface->v1 = ((VerseVert*)efa->v2->vvert)->id; + vface->counter--; + } + else + vface->flag &= ~FACE_SEND_READY; + } + } + else + vface->counter--; + /* EditVert #3 */ + if(efa->v3) { + if(efa->v3->vvert) { + vface->vvert2 = (VerseVert*)efa->v3->vvert; + if(((VerseVert*)efa->v3->vvert)->flag & VERT_RECEIVED) { + vface->v2 = ((VerseVert*)efa->v3->vvert)->id; + vface->counter--; + } + else + vface->flag &= ~FACE_SEND_READY; + } + } + else + vface->counter--; + /* EditVert #4 */ + if(efa->v4) { + if(efa->v4->vvert) { + vface->vvert3 = (VerseVert*)efa->v4->vvert; + if(((VerseVert*)efa->v4->vvert)->flag & VERT_RECEIVED) { + vface->v3 = ((VerseVert*)efa->v4->vvert)->id; + vface->counter--; + } + else + vface->flag &= ~FACE_SEND_READY; + } + } + else + vface->counter--; + + add_item_to_send_queue(&(vlayer->queue), (void*)vface, VERSE_FACE); +} + +/* + * creates new verse faces, add all of then to queue ... send to verse server + */ +static void createAllVerseFaces(VNode *vnode, VLayer *vlayer) +{ + if(G.obedit) { + struct EditMesh *em; + struct EditFace *efa; + + em = G.editMesh; + + efa = em->faces.first; + /* push all EditFaces to the verse server */ + while(efa){ + createVerseFaceNL(efa, vnode, vlayer); + efa = efa->next; + } + } +} + +/* + * When verse face is changed during sending/receiving from verse server, then + * this verse face is marked as obsolete and it will be send again, when it + * will be received from verse server + */ +static void mark_changed_face_obsolete(VerseFace *vface) +{ + struct EditFace *efa = (EditFace*)vface->face; + + if(efa) { + if(vface->vvert0->vertex != efa->v1) vface->flag |= FACE_OBSOLETE; + if(vface->vvert1->vertex != efa->v2) vface->flag |= FACE_OBSOLETE; + if(vface->vvert2->vertex != efa->v3) vface->flag |= FACE_OBSOLETE; + if(vface->vvert3 && (vface->vvert3->vertex != efa->v4)) vface->flag |= FACE_OBSOLETE; + } +} + +/* + * this function will sync EditFace and VerseFace and it will send changes to + * verse server too + */ +static void sync_verseface_with_editface(VLayer *vlayer, VerseFace *vface) +{ + struct EditFace *efa = (EditFace*)vface->face; + int dosend = 0; + + /* edit face and probably verse face was deleted */ + if(!efa || (vface->flag & FACE_DELETED)) return; + + /* blender nor verse don't support such crazy things */ + if(!(vface->vvert0) || !(vface->vvert1) || !(vface->vvert2)) { + printf("\tERROR: vface->vvert0: %p, vface->vvert1: %p, vface->vvert2: %p\n", vface->vvert0, vface->vvert1, vface->vvert2); + return; + } + + /* initialize verse face flag */ + vface->flag |= FACE_SEND_READY; + + /* debug print */ +#if 0 + printf("\n"); + if(efa->v4) { + printf("\tefa->v1,v2,v3,v4->vvert->id: %d, %d, %d, %d\n", + ((VerseVert*)efa->v1->vvert)->id, + ((VerseVert*)efa->v2->vvert)->id, + ((VerseVert*)efa->v3->vvert)->id, + ((VerseVert*)efa->v4->vvert)->id); + printf("\tefa->v1,v2,v3,v4->vvert: %p, %p, %p, %p\n", + efa->v1->vvert, + efa->v2->vvert, + efa->v3->vvert, + efa->v4->vvert); + } + else { + printf("\tefa->v1,v2,v3->vvert->id: %d, %d, %d, NULL\n", + ((VerseVert*)efa->v1->vvert)->id, + ((VerseVert*)efa->v2->vvert)->id, + ((VerseVert*)efa->v3->vvert)->id); + printf("\tefa->v1,v2,v3,v4->vvert: %p, %p, %p, NULL\n", + efa->v1->vvert, + efa->v2->vvert, + efa->v3->vvert); + } + printf("\tvface->vvert0, vvvert1, vvvert2, vvvert3: %p, %p, %p, %p\n", + vface->vvert0, + vface->vvert1, + vface->vvert2, + vface->vvert3); + + printf("\tefa->v1, v2, v3, v4: %p, %p, %p, %p\n", + efa->v1, + efa->v2, + efa->v3, + efa->v4); + if(vface->vvert3) { + printf("\tvface->v0,v1,v2,v3: %d, %d, %d, %d\n", + vface->v0, + vface->v1, + vface->v2, + vface->v3); + printf("\tvface->vvert0,vvvert1,vvvert2,vvvert3->vertex: %p, %p, %p, %p\n", + vface->vvert0->vertex, + vface->vvert1->vertex, + vface->vvert2->vertex, + vface->vvert3->vertex); + } + else { + printf("\tvface->v0,v1,v2,v3: %d, %d, %d, NULL\n", + vface->v0, + vface->v1, + vface->v2); + printf("\tvface->vvert0,vvvert1,vvvert2->vertex: %p, %p, %p, NULL\n", + vface->vvert0->vertex, + vface->vvert1->vertex, + vface->vvert2->vertex); + } +#endif + + /* initialize counter of unreceived vertexes */ + vface->counter = 4; + + /* 1st vertex */ + if(vface->vvert0->vertex != efa->v1) { + dosend = 1; + vface->vvert0->counter--; + vface->vvert0 = (VerseVert*)efa->v1->vvert; + vface->v0 = vface->vvert0->id; + if(vface->vvert0->flag & VERT_RECEIVED) + vface->counter--; + else + vface->flag &= ~FACE_SEND_READY; + } + else + vface->counter--; + + /* 2nd vertex */ + if(vface->vvert1->vertex != efa->v2) { + dosend = 1; + vface->vvert1->counter--; + vface->vvert1 = (VerseVert*)efa->v2->vvert; + vface->v1 = vface->vvert1->id; + if(vface->vvert1->flag & VERT_RECEIVED) + vface->counter--; + else + vface->flag &= ~FACE_SEND_READY; + } + else + vface->counter--; + + /* 3th vertex */ + if(vface->vvert2->vertex != efa->v3) { + dosend = 1; + vface->vvert2->counter--; + vface->vvert2 = (VerseVert*)efa->v3->vvert; + vface->v2 = vface->vvert2->id; + if(vface->vvert2->flag & VERT_RECEIVED) + vface->counter--; + else + vface->flag &= ~FACE_SEND_READY; + } + else + vface->counter--; + + /* 4th vertex */ + if(vface->vvert3 && ((vface->vvert3->vertex != efa->v4) || (vface->vvert3 && !efa->v4) || (vface->v3 != vface->vvert3->id))) { + dosend = 1; + if(efa->v4) { + vface->vvert3->counter--; + vface->vvert3 = (VerseVert*)efa->v4->vvert; + vface->v3 = vface->vvert3->id; + if(vface->vvert3->flag & VERT_RECEIVED) + vface->counter--; + else + vface->flag &= ~FACE_SEND_READY; + } + else { + vface->vvert3->counter--; + vface->vvert3 = NULL; + vface->v3 = -1; + vface->counter--; + } + } + /* verse face has 4 vertexes now, not 3 vertexes as in past */ + else if(!(vface->vvert3) && efa->v4) { + dosend = 1; + vface->vvert3 = (VerseVert*)efa->v4->vvert; + vface->v3 = vface->vvert3->id; + if(vface->vvert3->flag & VERT_RECEIVED) + vface->counter--; + else + vface->flag &= ~FACE_SEND_READY; + } + else + vface->counter--; + + if(dosend) { + /* printf("\tsending CHANGED FACE\n"); + printf("\t\tnew: %d %d %d %d\n", vface->v0, vface->v1, vface->v2, vface->v3);*/ + vface->flag |= FACE_CHANGED; + /* remove verse face from list of received faces */ + BLI_dlist_rem_item(&(vlayer->dl), vface->id); + /* and add verse face again to sending queue */ + add_item_to_send_queue(&(vlayer->queue), (void*)vface, VERSE_FACE); + } +} + +/* + * this function will sync all VerseFaces with coresponding EditFaces, + * this is useful, when some editmesh tool has changed editface pointers at + * vertexes (edges), parameter of this function is geometry node + */ +void sync_all_versefaces_with_editfaces(VNode *vnode) +{ + struct VLayer *vlayer; + struct VerseFace *vface, *nvface; + + if(vnode->type != V_NT_GEOMETRY) return; + + vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + /* mark changed verse faces in sending queue as obsolete at the first time */ + vface = vlayer->queue.first; + while(vface) { + mark_changed_face_obsolete(vface); + vface = vface->next; + } + + /* send all received and changed verse face again to verse server */ + vface = vlayer->dl.lb.first; + while(vface) { + nvface = vface->next; + sync_verseface_with_editface(vlayer, vface); + vface = nvface; + } +} + +/* + * send delete polygon command to verse server + */ +void b_verse_send_face_delete(EditFace *efa) +{ + ((VerseFace*)efa->vface)->face = NULL; + send_verse_face_delete((VerseFace*)efa->vface); + efa->vface = NULL; +} + +/*============================================================================= + * + * functions handling verse/blender VERTEXES + * + *===========================================================================*/ + +/* + * this function will sync position of all VerseVerts with EditVerts + * this function is called after actions: Smooth, Noise and To Sphere, + * because position of vertexes isn't managed by transform system + */ +void sync_all_verseverts_with_editverts(VNode *vnode) +{ + struct VLayer *vlayer; + struct VerseVert *vvert; + + if(vnode->type != V_NT_GEOMETRY) return; + + vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + + vvert = vlayer->dl.lb.first; + + /* sync all received vertexes */ + while(vvert) { + send_versevert_pos(vvert); + vvert = vvert->next; + } + + vvert = vlayer->queue.first; + + /* sync all unreceived vertexes (mar pos as obsolete, when + * actual position was changed) */ + while(vvert) { + send_versevert_pos(vvert); + vvert = vvert->next; + } + + verse_callback_update(0); +} + +/* + * send delete vertex command to verse server + */ +void b_verse_send_vertex_delete(EditVert *eve) +{ + ((VerseVert*)eve->vvert)->vertex = NULL; + send_verse_vertex_delete((VerseVert*)eve->vvert); + eve->vvert = NULL; +} + +/* + * send position of verse vertex to verse server + */ +void send_versevert_pos(VerseVert *vvert) +{ + /* don't send position of verse vertex to verse server, because it could create + * new vertex */ + if(vvert->flag & VERT_RECEIVED && !(vvert->flag & VERT_DELETED)) { + if(vvert->flag & VERT_LOCKED) { + /* when position of verse vert was sent to verse server + * and it wasn't received yet, then mark sent position + * as obsolete ... blender will automaticaly send actual + * position, when old will be received */ + vvert->flag |= VERT_POS_OBSOLETE; +/* printf("\tsend_versevert_pos: %d mark OBSOLETE\n", vvert->id);*/ + } + else { + struct EditVert *eve = (EditVert*)vvert->vertex; + /* send position to verse server, when it is different from actual position */ + if(eve && (eve->co[0]!=vvert->co[0] || eve->co[1]!=vvert->co[1] || eve->co[2]!=vvert->co[2])) { + /* lock vertex and send its position to verse server */ + vvert->flag |= VERT_LOCKED; + VECCOPY(vvert->co, eve->co); +/* printf("\tsend_versevert_pos: %d send and LOCK \n", vvert->id);*/ + send_verse_vertex(vvert); + } + } + } + + if(!(vvert->flag & VERT_RECEIVED) && (vvert->flag & VERT_LOCKED)) { + struct EditVert *eve = (EditVert*)vvert->vertex; + if(eve && (eve->co[0]!=vvert->co[0] || eve->co[1]!=vvert->co[1] || eve->co[2]!=vvert->co[2])) { +/* printf("\tsend_versevert_pos: %d mark VERT_POS_OBSOLETE\n", vvert->id); */ + vvert->flag |= VERT_POS_OBSOLETE; + } + } + + verse_callback_update(0); +} + +/* + * create new VerseVert due to information about EditVert, + * put VerseVert to queue ... send to verse host (server) + */ +void createVerseVert(EditVert *eve) +{ + if(G.editMesh->vnode) { + struct VLayer *vlayer = find_verse_layer_type((VGeomData*)((VNode*)G.editMesh->vnode)->data, VERTEX_LAYER); + createVerseVertNL(eve, (VNode*)G.editMesh->vnode, vlayer); + } + else eve->vvert = NULL; +} + +/* + * create new VerseVert due to information about EditVert, + * put VerseVert to queue ... send to verse host (server) + * NL version of function (infomration about verse node and + * layer is known ... optimalisation) + */ +void createVerseVertNL(EditVert *eve, VNode *vnode, VLayer *vlayer) +{ + struct VerseVert *vvert; + + vvert = create_verse_vertex(vlayer, vlayer->counter, eve->co[0], eve->co[1], eve->co[2]); + + vvert->vertex = (void*)eve; + eve->vvert = (void*)vvert; + + vvert->flag |= VERT_LOCKED; + +/* printf("\tsend_versevert_pos: %d create and LOCK \n", vvert->id);*/ + + /* add vvert to sending queue */ + add_item_to_send_queue(&(vlayer->queue), (void*)vvert, VERSE_VERT); +} + +/* + * create new verse vertexes due to all vertexes and send all of them to verse server + */ +static void createAllVerseVerts(VNode *vnode, VLayer *vlayer) +{ + if(G.obedit) { + struct EditMesh *em; + struct EditVert *eve; + + em = G.editMesh; + eve = em->verts.first; + + /* push all EditVertexes to the verse server */ + while(eve){ + createVerseVertNL(eve, vnode, vlayer); + eve = eve->next; + } + } +} + +/* + * unsubscribe from verse geometry layers of verse geometry node + * and clear bindings between verse node and mesh + */ +void unsubscribe_from_geom_node(VNode *vnode) +{ + struct VerseSession *session = vnode->session; + + struct VLayer *vlayer = ((VGeomData*)vnode->data)->layers.lb.first; + + if(vnode->type != V_NT_GEOMETRY) return; + + if(((VGeomData*)vnode->data)->mesh) { + ((Mesh*)((VGeomData*)vnode->data)->mesh)->vnode = NULL; + ((VGeomData*)vnode->data)->mesh = NULL; + } + + if(((VGeomData*)vnode->data)->editmesh) { + ((EditMesh*)((VGeomData*)vnode->data)->editmesh)->vnode = NULL; + ((VGeomData*)vnode->data)->editmesh = NULL; + } + + while(vlayer) { + BLI_dlist_reinit(&(vlayer->dl)); + BLI_freelistN(&(vlayer->queue)); + BLI_freelistN(&(vlayer->orphans)); + + if(session->flag & VERSE_CONNECTED) + verse_send_g_layer_unsubscribe(vnode->id, vlayer->id); + + vlayer = vlayer->next; + } + +} + +/* =================================================================================== + * + * Function executed after execution of callback functions + * + * ===================================================================================*/ + +/* + * Actions executed after new VerseLayer is created + */ +void post_layer_create(struct VLayer *vlayer) +{ + /* if we are owners of VerseNode, then push geometry to verse server */ + if(vlayer->vnode->owner_id == VN_OWNER_MINE) { + switch(vlayer->type){ + case VN_G_LAYER_VERTEX_XYZ: +/* if(vlayer->id==0) createAllVerseVerts(vlayer->vnode, vlayer); + break;*/ + case VN_G_LAYER_POLYGON_CORNER_UINT32: +/* if(vlayer->id==1) createAllVerseFaces(vlayer->vnode, vlayer); + break;*/ + case VN_G_LAYER_VERTEX_UINT32: + case VN_G_LAYER_VERTEX_REAL: + case VN_G_LAYER_POLYGON_CORNER_REAL: + case VN_G_LAYER_POLYGON_FACE_UINT8: + case VN_G_LAYER_POLYGON_FACE_UINT32: + case VN_G_LAYER_POLYGON_FACE_REAL: + break; + } + } + else { + switch(vlayer->type) { + case VN_G_LAYER_VERTEX_XYZ: + case VN_G_LAYER_POLYGON_CORNER_UINT32: + case VN_G_LAYER_VERTEX_UINT32: + case VN_G_LAYER_VERTEX_REAL: + case VN_G_LAYER_POLYGON_CORNER_REAL: + case VN_G_LAYER_POLYGON_FACE_UINT8: + case VN_G_LAYER_POLYGON_FACE_UINT32: + case VN_G_LAYER_POLYGON_FACE_REAL: + break; + } + } +} + +/* + * Actions after destroying of VerseLayer + */ +void post_layer_destroy(struct VLayer *vlayer) +{ +} + +/* + * Actions executed after creating of new VerseVert, when object is in edit + * mode, and this client didn't create this VerseVert (vvert->vertex is NULL), + * then new editvert is created + */ +void post_vertex_create(VerseVert *vvert) +{ + struct VNode *obj_vnode; + struct VNode *geom_vnode = vvert->vlayer->vnode; + struct EditMesh *em=NULL; + + if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) { + em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh; + } + + /* when vert was changed during sending to verse server, then + * we have to send it to verse server again */ + if(vvert->flag & VERT_POS_OBSOLETE) { + vvert->flag &= ~VERT_POS_OBSOLETE; + + if(em && (vvert->vertex)) { + struct EditVert *eve = (EditVert*)vvert->vertex; + VECCOPY(vvert->co, eve->co); +/* printf("\tpost_vertex_create: %d send and NOT_OBSOLETE\n", vvert->id);*/ + send_verse_vertex(vvert); + verse_callback_update(0); + + return; + } + } + + if(em && !(vvert->vertex)) { + struct EditVert *eve; + + /* to prevent never ending loop of sending and receiving + * vertexes, because addvertlist() sends new vertex to verse + * server if em->vnode isn't NULL */ + em->vnode = NULL; + eve = addvertlist(vvert->co); + em->vnode = (void*)geom_vnode; + + eve->vvert = (void*)vvert; + vvert->vertex = (void*)eve; + + countall(); + + recalc_editnormals(); + } + + if(((VGeomData*)geom_vnode->data)->vlink) { + obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source; + DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA); + + allqueue(REDRAWVIEW3D, 1); + } +} + +/* + * Actions executed, when position of VerseVert was changed + * position of EditVert is changed in edit mode + */ +void post_vertex_set_xyz(VerseVert *vvert) +{ + struct VNode *obj_vnode; + struct VNode *geom_vnode = vvert->vlayer->vnode; + struct EditVert *eve = NULL; + + /* when vert was changed during sending to verse server, then + * we have to send it to verse server again */ + if(vvert->flag & VERT_POS_OBSOLETE) { + if(vvert->vertex) { + vvert->flag &= ~VERT_POS_OBSOLETE; + vvert->flag |= VERT_LOCKED; + + eve = (EditVert*)vvert->vertex; + VECCOPY(vvert->co, eve->co); +/* printf("\tpost_vertex_set_xyz: %d send and NOT_OBSOLETE\n", vvert->id); */ + send_verse_vertex(vvert); + verse_callback_update(0); + } + else { + printf("\terror: vvert->vertex shouldn't be NULL\n"); + } + + return; + } + + /* when shared object is in edit mode, then update editmesh */ + if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) { + if(vvert->vertex) { + eve = (EditVert*)vvert->vertex; +/* printf("\tupdate pos of edit vert %d\n", vvert->id); */ + VECCOPY(eve->co, vvert->co); + recalc_editnormals(); + } + else { + printf("\terror: vvert->vertex shouldn't be NULL\n"); + } + } + + if(((VGeomData*)geom_vnode->data)->vlink) { + obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source; + DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA); + + allqueue(REDRAWVIEW3D, 1); + } +} + +/* + * Actions executed after deleting of VerseVert + */ +void post_vertex_delete(VerseVert *vvert) +{ + struct VNode *obj_vnode; + struct VNode *geom_vnode = vvert->vlayer->vnode; + struct EditMesh *em = NULL; + struct EditEdge *ed, *edn; + struct EditVert *eve = NULL; + + if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) { + em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh; + eve = (EditVert*)vvert->vertex; + } + + if(em && eve) { + /*printf("\tPOST_VERTEX_DELETE()\n");*/ + + /* delete all edges needing eve vertex */ + ed = em->edges.first; + while(ed) { + edn = ed->next; + if(ed->v1==eve || ed->v2==eve) { + remedge(ed); + free_editedge(ed); + } + ed = edn; + } + + eve->vvert = NULL; + BLI_remlink(&em->verts, eve); + free_editvert(eve); + vvert->vertex = NULL; + + countall(); + + recalc_editnormals(); + } + + if(((VGeomData*)geom_vnode->data)->vlink) { + obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source; + DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA); + + allqueue(REDRAWVIEW3D, 1); + } +} + +/* + * free constraint between VerseVert and EditVert + */ +void post_vertex_free_constraint(VerseVert *vvert) +{ + if(vvert->vertex) { + ((EditVert*)vvert->vertex)->vvert=NULL; + vvert->vertex=NULL; + } +} + +/* + * Action executed after setting up uint8 value of polygon + */ +void post_polygon_set_uint8(VerseFace *vface) +{ +} + +/* + * Action executed after creating of new VerseFace + */ +void post_polygon_create(VerseFace *vface) +{ + struct VNode *obj_vnode; + struct VNode *geom_vnode = vface->vlayer->vnode; + struct EditMesh *em = NULL; + + /* if verse face was set as deleted during sending to verse server, then send + * delete command to verse server now ... we know verse face id */ +/* if(vface->flag & FACE_DELETED) { + send_verse_face_delete(vface); + return; + }*/ + + if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) { + em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh; + } + + /* when face was changed during sending to verse server, then + * we have to send it to verse server again */ + if(vface->flag & FACE_OBSOLETE) { + vface->flag &= ~FACE_OBSOLETE; + sync_verseface_with_editface(vface->vlayer, vface); + return; + } + + if(em && !(vface->face) && (vface->counter==0)) { + struct VLayer *vlayer; + struct VerseVert *vvert; + struct EditFace *efa; + struct EditVert *eves[4]={NULL, NULL, NULL, NULL}; + uint32 vert_ids[4]={vface->v0, vface->v1, vface->v2, vface->v3}; + int i; + + /*printf("\tPOST_POLYGON_CREATE()\n");*/ + + vlayer = find_verse_layer_type((VGeomData*)geom_vnode->data, VERTEX_LAYER); + + for(i=0; i<4; i++) { + if(vert_ids[i] != -1) { + vvert = BLI_dlist_find_link(&(vlayer->dl), vert_ids[i]); + if(vvert) eves[i] = (EditVert*)vvert->vertex; + } + } + + /* to prevent never ending loop of sending and receiving + * faces, because addfacelist() sends new face to verse + * server if em->vnode isn't NULL */ + em->vnode = NULL; + efa = addfacelist(eves[0], eves[1], eves[2], eves[3], NULL, NULL); + em->vnode = geom_vnode; + + if(efa) { + efa->vface = vface; + vface->face = efa; + } + + countall(); + + recalc_editnormals(); + } + + if(((VGeomData*)geom_vnode->data)->vlink) { + obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source; + DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA); + + allqueue(REDRAWVIEW3D, 1); + } +} + +/* + * Action executed after changes of VerseFace + * ... order of vertexes was fliped, etc. + */ +void post_polygon_set_corner(VerseFace *vface) +{ + struct VNode *obj_vnode; + struct VNode *geom_vnode = vface->vlayer->vnode; + struct EditMesh *em = NULL; + struct EditFace *efa = NULL; + struct EditEdge *eed, *eedn; + + if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) { + em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh; + efa = (EditFace*)vface->face; + } + + if(em && efa) { + + /* when face was changed during sending to verse server, then + * we have to send it to verse server again */ + if(vface->flag & FACE_OBSOLETE) { + vface->flag &= ~FACE_OBSOLETE; + sync_verseface_with_editface(vface->vlayer, vface); + return; + } + + /* mark all edges, which are part of face efa */ + efa->e1->f2 = 1; + efa->e2->f2 = 1; + efa->e3->f2 = 1; + if(efa->e4) efa->e4->f2 = 1; + + /* change pointers at EdtitVerts and decrease counters of "old" + * VerseVertexes reference ... less VerseFaces will need them */ + if(vface->vvert0 != efa->v1->vvert) + efa->v1 = (EditVert*)vface->vvert0->vertex; + if(vface->vvert1 != efa->v2->vvert) + efa->v2 = (EditVert*)vface->vvert1->vertex; + if(vface->vvert2 != efa->v3->vvert) + efa->v3 = (EditVert*)vface->vvert2->vertex; + if(efa->v4) { + if(!vface->vvert3) + efa->v4 = NULL; + else if(vface->vvert3 != efa->v4->vvert) + efa->v4 = (EditVert*)vface->vvert3->vertex; + } + + /* change pointers at EditEdges */ + + /* 1st edge */ + eed = findedgelist(efa->v1, efa->v2); + if(eed) efa->e1 = eed; + else efa->e1 = addedgelist(efa->v1, efa->v2, NULL); + + /* 2nd edge */ + eed = findedgelist(efa->v2, efa->v3); + if(eed) efa->e2 = eed; + else efa->e2 = addedgelist(efa->v2, efa->v3, NULL); + + if(efa->v4) { + /* 3th edge */ + eed = findedgelist(efa->v2, efa->v3); + if(eed) efa->e3 = eed; + else efa->e3 = addedgelist(efa->v2, efa->v3, NULL); + /* 4th edge */ + eed = findedgelist(efa->v4, efa->v1); + if(eed) efa->e4 = eed; + else efa->e4 = addedgelist(efa->v4, efa->v1, NULL); + } + else { + /* 3th edge */ + eed = findedgelist(efa->v3, efa->v1); + if(eed) efa->e3 = eed; + else efa->e3 = addedgelist(efa->v3, efa->v1, NULL); + /* 4th edge */ + efa->e4 = NULL; + } + + /* unmark needed edges */ + efa = em->faces.first; + while(efa) { + efa->e1->f2 = 0; + efa->e2->f2 = 0; + efa->e3->f2 = 0; + if(efa->e4) efa->e4->f2 = 0; + efa = efa->next; + } + + /* delete all unneeded edges */ + eed = em->edges.first; + while(eed) { + eedn = eed->next; + if(eed->f2) { + remedge(eed); + free_editedge(eed); + } + eed = eedn; + } + + countall(); + + recalc_editnormals(); + } + + if(((VGeomData*)geom_vnode->data)->vlink) { + obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source; + DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA); + + allqueue(REDRAWVIEW3D, 1); + } +} + +/* + * Action executed after deleting of VerseFace + */ +void post_polygon_delete(VerseFace *vface) +{ + struct VNode *obj_vnode; + struct VNode *geom_vnode = vface->vlayer->vnode; + struct EditMesh *em = NULL; + struct EditFace *efa = NULL; + struct EditEdge *eed, *eedn; + + if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) { + em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh; + efa = (EditFace*)vface->face; + } + + if(em && efa) { + /*printf("\tPOST_POLYGON_DELETE()\n");*/ + + /* mark all edges, which are part of face efa */ + efa->e1->f2 = 1; + efa->e2->f2 = 1; + efa->e3->f2 = 1; + if(efa->e4) efa->e4->f2 = 1; + + efa->vface = NULL; + BLI_remlink(&em->faces, efa); + free_editface(efa); + vface->face = NULL; + + /* following two crazy loops wouldn't be neccessary if verse spec + * would support edges */ + + /* unmark needed edges */ + efa = em->faces.first; + while(efa) { + efa->e1->f2 = 0; + efa->e2->f2 = 0; + efa->e3->f2 = 0; + if(efa->e4) efa->e4->f2 = 0; + efa = efa->next; + } + + /* delete all unneeded edges */ + eed = em->edges.first; + while(eed) { + eedn = eed->next; + if(eed->f2) { + remedge(eed); + free_editedge(eed); + } + eed = eedn; + } + + countall(); + } + + if(((VGeomData*)geom_vnode->data)->vlink) { + obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source; + DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA); + + allqueue(REDRAWVIEW3D, 1); + } +} + +/* + * free constraint between VerseFace and EditFace + */ +void post_polygon_free_constraint(VerseFace *vface) +{ + if(vface->face) { + ((EditFace*)vface->face)->vface = NULL; + vface->face = NULL; + } +} + +/* + * free constraint between VGeomData, EditMesh and Mesh + */ +void post_geometry_free_constraint(VNode *vnode) +{ + if(((VGeomData*)vnode->data)->editmesh) { + G.editMesh->vnode = NULL; + ((VGeomData*)vnode->data)->editmesh = NULL; + } + if(((VGeomData*)vnode->data)->mesh) { + ((Mesh*)((VGeomData*)vnode->data)->mesh)->vnode = NULL; + ((VGeomData*)vnode->data)->mesh = NULL; + } +} + +/* ========================================================================= + * + * Functions influencing whole EditMesh or VerseMesh + * + * ========================================================================= */ + +/* + * free all bindings between EditMesh and "verse mesh" ... it is called between + * restorng editmesh from undo stack + */ +void destroy_versemesh(VNode *vnode) +{ + struct VLayer *vert_vlayer, *face_vlayer; + struct VerseVert *vvert; + struct VerseFace *vface; + + if(vnode->type != V_NT_GEOMETRY) return; + + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + + /* send delete command to all received verse faces */ + vface = face_vlayer->dl.lb.first; + while(vface) { + if(vface->face) ((EditFace*)vface->face)->vface = NULL; + vface->face = NULL; + send_verse_face_delete(vface); + vface = vface->next; + } + /* send delete command to all verse faces waiting in orphan list */ + vface = face_vlayer->orphans.first; + while(vface) { + if(vface->face) ((EditFace*)vface->face)->vface = NULL; + vface->face = NULL; + send_verse_face_delete(vface); + vface = vface->next; + } + /* mark all verse faces waiting in sending queue as deleted, + * send delete command, when this verse face was changed */ + vface = face_vlayer->queue.first; + while(vface) { + if(vface->face) ((EditFace*)vface->face)->vface = NULL; + vface->face = NULL; + if(vface->flag & FACE_CHANGED) + send_verse_face_delete(vface); + else { + vface->flag |= FACE_DELETED; + } + vface = vface->next; + } + + /* send delete command to all received verse vertexes */ + vvert = vert_vlayer->dl.lb.first; + while(vvert) { + if(vvert->vertex) ((EditVert*)vvert->vertex)->vvert = NULL; + vvert->vertex = NULL; + send_verse_vertex_delete(vvert); + vvert = vvert->next; + } + /* mark all verse vertexes waiting in sending queue as deleted + * ... verse vertexes will be deleted, when received */ + vvert = vert_vlayer->queue.first; + while(vvert) { + if(vvert->vertex) ((EditVert*)vvert->vertex)->vvert = NULL; + vvert->vertex = NULL; + vvert = vvert->next; + } +} + +/* + * duplicate geometry verse node, this can be handy, when you duplicate some + * object or make object single user + */ +VNode *create_geom_vnode_from_geom_vnode(VNode *vnode) +{ + struct VNode *n_vnode; /* new verse geometry node */ + struct VGeomData *geom_data; /* new geometry data */ + struct VLayer *n_vert_vlayer, *n_face_vlayer; /* new vertex and polygon layer */ + struct VLayer *vert_vlayer, *face_vlayer; + struct VerseVert *n_vvert, *vvert; + struct VerseFace *n_vface, *vface; + int i; + + if(!vnode) return NULL; + + if(vnode->type != V_NT_GEOMETRY) return NULL; + + /* create new verse node, when no one exist */ + n_vnode= create_verse_node(vnode->session, -1 , V_NT_GEOMETRY, VN_OWNER_MINE); + /* create new geometry data */ + geom_data = create_geometry_data(); + n_vnode->data = (void*)geom_data; + + /* set up name of VerseNode */ + n_vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(vnode->name)-1), "new geom node name"); + n_vnode->name[0] = '\0'; + strcat(n_vnode->name, vnode->name); + + /* add node to sending queue */ + add_item_to_send_queue(&(vnode->session->queue), n_vnode, VERSE_NODE); + + /* create vertex verse layer */ + n_vert_vlayer = create_verse_layer(n_vnode, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0); + add_item_to_send_queue(&(geom_data->queue), n_vert_vlayer, VERSE_LAYER); + + /* create polygon verse layer */ + n_face_vlayer = create_verse_layer(n_vnode, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0); + add_item_to_send_queue(&(geom_data->queue), n_face_vlayer, VERSE_LAYER); + + /* find vertex layer of old verse node */ + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + /* find polygon layer of old verse node */ + face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + /* duplicate verse vertexes */ + for(i=0, vvert = (VerseVert*)vert_vlayer->dl.lb.first; vvert; vvert = vvert->next, i++) { + n_vvert = create_verse_vertex(n_vert_vlayer, i, vvert->co[0], vvert->co[1], vvert->co[2]); + vvert->tmp.vvert = n_vvert; + add_item_to_send_queue(&(n_vert_vlayer->queue), n_vvert, VERSE_VERT); + } + + /* duplicate verse faces (polyons) */ + for(i=0, vface = (VerseFace*)face_vlayer->dl.lb.first; vface; vface = vface->next, i++) { + n_vface = create_verse_face(n_face_vlayer, i, -1, -1, -1, -1); + n_vface->vvert0 = vface->vvert0->tmp.vvert; + n_vface->vvert1 = vface->vvert1->tmp.vvert; + n_vface->vvert2 = vface->vvert2->tmp.vvert; + if(vface->vvert3) + n_vface->vvert3 = vface->vvert3->tmp.vvert; + else + n_vface->vvert3 = NULL; + add_item_to_send_queue(&(n_face_vlayer->queue), n_vface, VERSE_FACE); + } + + return n_vnode; +} + +/* + * create new geometry node, make bindings between geometry node and editmesh, + * make bindings between editverts and verseverts, make bindings between editfaces + * and versefaces + */ +VNode *create_geom_vnode_data_from_editmesh(VerseSession *session, EditMesh *em) +{ + struct VNode *vnode; + struct Mesh *me; + struct VGeomData *geom_data; + struct VLayer *vert_vlayer, *face_vlayer; + + if(!session) return NULL; + + if(!em) return NULL; + + /* some verse geometry node already exists */ + if(em->vnode) return NULL; + + /* we will need mesh too (mesh name, creating bindings between verse node, etc.) */ + me = get_mesh(G.obedit); + + /* create new verse node, when no one exist */ + vnode = create_verse_node(session, -1 , V_NT_GEOMETRY, VN_OWNER_MINE); + /* create new geometry data */ + geom_data = create_geometry_data(); + vnode->data = (void*)geom_data; + + /* set up name of VerseNode */ + vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(me->id.name)-1), "geom node name"); + vnode->name[0] = '\0'; + strcat(vnode->name, me->id.name+2); + + /* set up bindings */ + me->vnode = (void*)vnode; + em->vnode = (void*)vnode; + geom_data->mesh = (void*)me; + geom_data->editmesh = (void*)em; + + /* add node to sending queue */ + add_item_to_send_queue(&(session->queue), vnode, VERSE_NODE); + + /* create vertex verse layer */ + vert_vlayer = create_verse_layer(vnode, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0); + add_item_to_send_queue(&(geom_data->queue), vert_vlayer, VERSE_LAYER); + + /* create polygon verse layer */ + face_vlayer = create_verse_layer(vnode, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0); + add_item_to_send_queue(&(geom_data->queue), face_vlayer, VERSE_LAYER); + + /* create all verse verts and add them to sending queue */ + createAllVerseVerts(vnode, vert_vlayer); + + /* create all verse faces and add tehm to sending queue */ + createAllVerseFaces(vnode, face_vlayer); + + return vnode; +} + +/* + * create new geometry node, make bindings between geometry node and mesh and + * fill geometry node with new data based at mesh data + */ +VNode *create_geom_vnode_data_from_mesh(VerseSession *session, Mesh *me) +{ + struct VNode *vnode; + struct VGeomData *geom_data; + struct VLayer *vert_vlayer, *face_vlayer; + struct VerseVert *vvert, **vverts; + struct VerseFace *vface; + struct MVert *mvert; + struct MFace *mface; + int i; + + if(!session) return NULL; + + if(!me) return NULL; + + /* some verse geometry node already exists */ + if(me->vnode) return NULL; + + /* create new verse node, when no one exist */ + vnode = create_verse_node(session, -1 , V_NT_GEOMETRY, VN_OWNER_MINE); + /* create new geometry data */ + geom_data = create_geometry_data(); + vnode->data = (void*)geom_data; + + /* set up name of VerseNode */ + vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(me->id.name)-1), "geom node name"); + vnode->name[0] = '\0'; + strcat(vnode->name, me->id.name+2); + + /* set up bindings */ + me->vnode = (void*)vnode; + geom_data->mesh = (void*)me; + + /* add node to sending queue */ + add_item_to_send_queue(&(session->queue), vnode, VERSE_NODE); + + /* create vertex verse layer */ + vert_vlayer = create_verse_layer(vnode, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0); + add_item_to_send_queue(&(geom_data->queue), vert_vlayer, VERSE_LAYER); + + /* create polygon verse layer */ + face_vlayer = create_verse_layer(vnode, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0); + add_item_to_send_queue(&(geom_data->queue), face_vlayer, VERSE_LAYER); + + /* temporary array of VerseVerts */ + vverts = (VerseVert**)MEM_mallocN(sizeof(VerseVert*)*me->totvert,"temp array of vverts"); + + /* "fill vertex layer with vertexes" and add them to sending queue (send them to verse server) */ + for(i=0, mvert=me->mvert; i<me->totvert; i++, mvert++) { + vverts[i] = vvert = create_verse_vertex(vert_vlayer, i, mvert->co[0], mvert->co[1], mvert->co[2]); + add_item_to_send_queue(&(vert_vlayer->queue), vvert, VERSE_VERT); + } + + /* "fill face/polygon layer with faces" and them to sending queue */ + for(i=0, mface = me->mface; i<me->totface; i++, mface++) { + if(mface->v4) { + vface = create_verse_face(face_vlayer, i, mface->v1, mface->v2, mface->v3, mface->v4); + vface->vvert0 = vverts[mface->v1]; + vface->vvert1 = vverts[mface->v2]; + vface->vvert2 = vverts[mface->v3]; + vface->vvert3 = vverts[mface->v4]; + vface->counter = 4; + } + else { + vface = create_verse_face(face_vlayer, i, mface->v1, mface->v2, mface->v3, -1); + vface->vvert0 = vverts[mface->v1]; + vface->vvert1 = vverts[mface->v2]; + vface->vvert2 = vverts[mface->v3]; + vface->counter = 3; + } + add_item_to_send_queue(&(face_vlayer->queue), vface, VERSE_FACE); + } + + MEM_freeN(vverts); + + return vnode; +} + +/* + * creates Mesh from verse geometry node and create bindings + * between them + */ +Mesh *create_mesh_from_geom_node(VNode *vnode) +{ + struct Mesh *me; + + if(vnode->type != V_NT_GEOMETRY) return NULL; + + /* add new empty mesh*/ + me = add_mesh(); + /* set up bindings between mesh and verse node */ + me->vnode = (void*)vnode; + ((VGeomData*)vnode->data)->mesh = (void*)me; + + return me; +} + +/* + * create mesh from verse mesh + */ +void create_meshdata_from_geom_node(Mesh *me, VNode *vnode) +{ + struct VLayer *vert_vlayer, *face_vlayer; + struct VerseVert *vvert; + struct VerseFace *vface; + struct MVert *mvert; + struct MFace *mface; + int index; + + if(!me || !vnode) return; + + if(vnode->type != V_NT_GEOMETRY) return; + + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + if(me->mvert) { + MEM_freeN(me->mvert); + me->mvert = NULL; + } + if(me->mface) { + MEM_freeN(me->mface); + me->mface = NULL; + } + if(me->tface) { + MEM_freeN(me->tface); + me->tface = NULL; + } + if(me->medge) { + MEM_freeN(me->medge); + me->medge = NULL; + } + if(me->dvert) { + MEM_freeN(me->dvert); + me->dvert = NULL; + } + if(me->mcol) { + MEM_freeN(me->mcol); + me->mcol = NULL; + } + if(me->msticky) { + MEM_freeN(me->msticky); + me->msticky = NULL; + } + if(me->mselect) { + MEM_freeN(me->mselect); + me->mselect = NULL; + } + + me->totvert = vert_vlayer->dl.da.count; + me->totface = face_vlayer->dl.da.count; + me->totedge = 0; + me->totselect = 0; + + mvert = me->mvert = (MVert*)MEM_mallocN(sizeof(MVert)*me->totvert, "mesh_from_verse vert"); + mface = me->mface = (MFace*)MEM_mallocN(sizeof(MFace)*me->totface, "mesh_from_verse face"); + + index = 0; + vvert = vert_vlayer->dl.lb.first; + while(vvert) { + VECCOPY(mvert->co, vvert->co); + VECCOPY(mvert->no, vvert->no); + mvert->flag = 0; + mvert->mat_nr = 0; + vvert->tmp.index = index++; + vvert = vvert->next; + mvert++; + } + + vface = face_vlayer->dl.lb.first; + while(vface) { + mface->v1 = vface->vvert0->tmp.index; + mface->v2 = vface->vvert1->tmp.index; + mface->v3 = vface->vvert2->tmp.index; + if(vface->vvert3) + mface->v4 = vface->vvert3->tmp.index; + else + mface->v4 = 0; + + mface->flag = 0; + mface->pad = 0; + mface->mat_nr = 0; + mface->edcode = 0; + + /* index 0 isn't allowed at location 3 or 4 */ + test_index_face(mface, NULL, NULL, vface->vvert3?4:3); +/* printf("\t mface: %d, %d, %d, %d\n", mface->v1, mface->v2, mface->v3, mface->v4);*/ + + vface = vface->next; + mface++; + } + + mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); +} + +/* + * Create EditMesh from VerseMesh and keep system in consitant state, this + * function is called, when edit mode is entered ... edit mesh is generated + * from verse mesh (not from Mesh: (Mesh*)ob->data) + */ +void create_edit_mesh_from_geom_node(VNode *vnode) +{ + struct VLayer *vert_layer, *face_layer; + struct VerseVert *vvert; + struct VerseFace *vface; + struct Mesh *me; + struct EditVert *eve, *eve0, *eve1, *eve2, *eve3; + struct EditFace *efa; + unsigned int keyindex; + + if(!(G.obedit && G.obedit->type==OB_MESH)) return; + me = (Mesh*)G.obedit->data; + if(vnode!=(VNode*)me->vnode || vnode->type!=V_NT_GEOMETRY) return; + + vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + + if(!(vert_layer && face_layer)) return; + + waitcursor(1); + + /* free old editMesh */ + free_editMesh(G.editMesh); + + G.editMesh->vnode = NULL; + + vvert = vert_layer->dl.lb.first; + + keyindex = 0; + + /* create all EditVerts */ + while(vvert) { + eve = addvertlist(vvert->co); + + eve->f = 0; + eve->h = 0; + eve->dw = NULL; + eve->keyindex = keyindex; + eve->vvert = (void*)vvert; + + vvert->vertex = (void*)eve; + + keyindex++; + vvert = vvert->next; + } + + vface = face_layer->dl.lb.first; + + /* create all EditFaces and EditEdges */ + while(vface) { + if(vface->vvert0) eve0= vface->vvert0->vertex; + else eve0 = NULL; + if(vface->vvert1) eve1= vface->vvert1->vertex; + else eve1 = NULL; + if(vface->vvert2) eve2= vface->vvert2->vertex; + else eve2 = NULL; + if(vface->vvert3) eve3= vface->vvert3->vertex; + else eve3 = NULL; + + efa= addfacelist(eve0, eve1, eve2, eve3, NULL, NULL); + if(efa) { + efa->f = 0; + efa->h = 0; + efa->vface = (void*)vface; + vface->face = (void*)efa; + } + vface = vface->next; + } + + countall(); + + recalc_editnormals(); + + G.editMesh->vnode = (void*)vnode; + ((VGeomData*)vnode->data)->editmesh = (void*)G.editMesh; + + waitcursor(0); +} + +/* + * destroy bindings between EditMesh and VerseMesh and send delete commands + * for all VerseVerts and VerseFaces to verse server, Verse Node has to be + * geometry node + */ + +void destroy_verse_mesh(VNode *vnode) +{ + struct VLayer *vert_vlayer, *face_vlayer; + struct VerseFace *vface; + struct VerseVert *vvert; + + if(vnode->type != V_NT_GEOMETRY) return; + + face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); + vface = face_vlayer->dl.lb.first; + + while(vface) { + ((EditFace*)vface->face)->vface = NULL; + vface->face = NULL; + vface = vface->next; + } + + vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); + vvert = vert_vlayer->dl.lb.first; + + while(vvert) { + ((EditVert*)vvert->vertex)->vvert = NULL; + vvert->vertex = NULL; + vvert = vvert->next; + } + + destroy_geometry(vnode); +} + +#endif + diff --git a/source/blender/src/verse_object.c b/source/blender/src/verse_object.c new file mode 100644 index 00000000000..3327ac4e5de --- /dev/null +++ b/source/blender/src/verse_object.c @@ -0,0 +1,587 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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/BL DUAL 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)->rot); + 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)->rot); + 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; + + 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*)new_image( + vbitmap->width, + vbitmap->height, + vnode->name, + 0); + ((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)->rot[0] = 0.0f; + ((VObjectData*)vnode->data)->rot[1] = 0.0f; + ((VObjectData*)vnode->data)->rot[2] = 0.0f; + ((VObjectData*)vnode->data)->rot[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) return; + + if(G.obedit && G.obedit->vnode == (void*)vnode) + exit_editmode(2); + + /* create mesh data */ + while(vlink){ + if(vlink->target->type == V_NT_GEOMETRY) { + struct Mesh *me; + me = ((VGeomData*)vnode->data)->mesh; + create_meshdata_from_geom_node(me, vnode); + 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 */ + makeDispListMesh(ob); + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + 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; + makeDispListMesh(ob); + } + } + + 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); +} + +/* + * recalculate transformation matrix of object + */ +void post_transform(VNode *vnode) +{ + struct VObjectData *obj_data = (VObjectData*)vnode->data; + struct Object *ob = (Object*)obj_data->object; + float mat_s[4][4]; + float mat_r[4][4]; + float mat_p[4][4]; + float mat[4][4]; + + if(!obj_data->object) return; + + Mat4One(mat_s); + Mat4One(mat_r); + Mat4One(mat_p); + + /* scale */ + mat_s[0][0] = ob->size[0] = obj_data->scale[0]; + mat_s[1][1] = ob->size[1] = obj_data->scale[1]; + mat_s[2][2] = ob->size[2] = obj_data->scale[2]; + + /* rotate */ + QuatToEul(obj_data->rot, ob->rot); + QuatToMat4(obj_data->rot, mat_r); + + /* position */ + mat_p[3][0] = ob->loc[0] = obj_data->pos[0]; + mat_p[3][1] = ob->loc[1] = obj_data->pos[1]; + mat_p[3][2] = ob->loc[2] = obj_data->pos[2]; + + /* matrix multiplication */ + Mat4MulMat4(mat, mat_r, mat_p); + Mat4MulMat4(ob->obmat, mat_s, mat); + + 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)->rot[0] != quat[0]) || + (((VObjectData*)vnode->data)->rot[1] != quat[1]) || + (((VObjectData*)vnode->data)->rot[2] != quat[2]) || + (((VObjectData*)vnode->data)->rot[3] != quat[3])) { + QUATCOPY(((VObjectData*)vnode->data)->rot, 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) { + ((DerivedMesh*)ob->derivedFinal)->release((DerivedMesh*)ob->derivedFinal); + ob->derivedFinal = NULL; + } + if(ob->derivedDeform) { + ((DerivedMesh*)ob->derivedDeform)->release((DerivedMesh*)ob->derivedDeform); + ob->derivedDeform = NULL; + } + } + /* free constraint */ + ((Object*)((VObjectData*)vnode->data)->object)->vnode = NULL; + ((VObjectData*)vnode->data)->object = NULL; + } +} + +#endif + |