Two in one:
[blender.git] / source / blender / src / verse_image.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * Contributor(s): Jiri Hnidek.
24  *
25  * ***** END GPL/BL DUAL LICENSE BLOCK *****
26  */
27
28 #ifdef WITH_VERSE
29
30 #include <string.h>
31
32 #include "mydevice.h"
33
34 #include "BKE_verse.h"
35 #include "BKE_image.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_image_types.h"
40
41 #include "IMB_imbuf_types.h"
42 #include "IMB_imbuf.h"
43
44 #include "BDR_drawmesh.h"
45
46 #include "BIF_verse.h"
47 #include "BIF_space.h"
48
49 /*
50  * unsubscribe from verse bitmap
51  */
52 void unsubscribe_from_bitmap_node(VNode *vnode)
53 {
54         if(vnode->type != V_NT_BITMAP) return;
55         
56         /* TODO */
57 }
58
59 /*
60  * upload image to verse server
61  */
62 void push_image_to_verse_server(VerseSession *session, Image *image)
63 {
64         ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
65         struct VNode *vnode;
66
67         if(!session) return;
68
69         if(!(session->flag & VERSE_CONNECTED)) return;
70
71         /* create "my" new object VerseNode */
72         vnode= create_verse_node(session, -1 , V_NT_BITMAP, VN_OWNER_MINE);
73         /* create object data */
74         vnode->data = create_bitmap_data();
75
76         /* set up name of VerseNode */
77         vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(image->id.name)-1), "object node name");
78         vnode->name[0] = '\0';
79         strcat(vnode->name, image->id.name+2);
80
81         /* set up dimension of image */
82         if(ibuf) {
83                 ((VBitmapData*)vnode->data)->width = ibuf->x;
84                 ((VBitmapData*)vnode->data)->height = ibuf->y;
85         }
86         else {
87                 ((VBitmapData*)vnode->data)->width = 0;
88                 ((VBitmapData*)vnode->data)->height = 0;
89         }
90         ((VBitmapData*)(vnode->data))->height = 1;
91
92         /* set up pointers between Object and VerseNode */
93         ((VBitmapData*)vnode->data)->image = (void*)image;
94         image->vnode = (void*)vnode;
95
96         /* add node to sending queue */
97         add_item_to_send_queue(&(session->queue), vnode, VERSE_NODE);
98 }
99
100 /*
101  * synchronize blender image channel (R,G,B,A) with verse bitmap layer
102  */
103 void sync_blender_image_channel_with_verse_layer(VNode *vnode, VBitmapLayer *vblayer)
104 {
105         struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
106         struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
107         unsigned char *rect;
108         int x, y, height, t_width, i, channel=0;
109
110         if(!image) return;
111
112         if(!ibuf) return;
113
114         rect = (unsigned char*)ibuf->rect;
115
116         /* select channel due to verse layer name */
117         if(strcmp(vblayer->name,"col_r")==0)
118                 channel = 0;
119         else if(strcmp(vblayer->name,"col_g")==0)
120                 channel = 1;
121         else if(strcmp(vblayer->name, "col_b")==0)
122                 channel = 2;
123         else if(strcmp(vblayer->name,"alpha")==0)
124                 channel = 3;
125
126 #ifdef VERSE_DEBUG_PRINT
127         printf(" %s:%d\n", vblayer->name, channel);
128 #endif
129
130         height = ((VBitmapData*)(vnode->data))->height;
131         t_width = ((VBitmapData*)(vnode->data))->t_width;
132
133         i = (height-1)*t_width;
134
135 #ifdef VERSE_DEBUG_PRINT
136         printf("\ti:%d\n", i);
137 #endif
138
139         if(vblayer->type==VN_B_LAYER_UINT8) {
140                 unsigned char *vuint8 = (unsigned char*)vblayer->data;
141                 for(y=height-1; y>=0; y--, i=y*t_width)
142                         for(x=0; x<ibuf->x; x++, rect+=4, i++)
143                                 rect[channel] = (char)vuint8[i];
144         }
145
146         allqueue(REDRAWIMAGE, 0);
147         allqueue(REDRAWVIEW3D, 0);
148 }
149
150 /*
151  * synchronize blender image with verse image
152  */
153 void sync_blender_image_with_verse_bitmap_node(VNode *vnode)
154 {
155         struct VBitmapLayer *vblayer;
156
157         vblayer = ((VBitmapData*)(vnode->data))->layers.lb.first;
158
159         while(vblayer) {
160 #ifdef VERSE_DEBUG_PRINT
161                 printf("\tsyncing layer:");
162 #endif
163                 sync_blender_image_channel_with_verse_layer(vnode, vblayer);
164                 vblayer = vblayer->next;
165         }
166 }
167
168 /*
169  * This function is called, when some other verse client change dimension of image.
170  * It is neccesary to reallocate blender image too, when dimension of verse image
171  * is different from blender image.
172  */
173 void post_bitmap_dimension_set(VNode *vnode)
174 {
175         struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
176         struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
177
178         if(!image) return;
179
180         if(!ibuf) return;
181
182         if(vnode->owner_id == VN_OWNER_MINE) {
183                 if( ((VBitmapData*)vnode->data)->layers.lb.first == NULL ) {
184                         /* send all verse bitmap layers (RGBA) to verse server */
185                         printf("\tsending all bitmap layers to verse server\n");
186                         verse_send_b_layer_create(vnode->id, -1, "col_r", VN_B_LAYER_UINT8);
187                         verse_send_b_layer_create(vnode->id, -1, "col_g", VN_B_LAYER_UINT8);
188                         verse_send_b_layer_create(vnode->id, -1, "col_b", VN_B_LAYER_UINT8);
189                         verse_send_b_layer_create(vnode->id, -1, "alpha", VN_B_LAYER_UINT8);
190
191                         return;
192                 }
193         }
194
195         if((ibuf->x!=((VBitmapData*)vnode->data)->width) || (ibuf->y!=((VBitmapData*)vnode->data)->height)) {
196                 struct VBitmapLayer *vblayer;
197                 struct ImBuf *new_ibuf;
198
199                 /* allocate new ibuf */
200                 new_ibuf= IMB_allocImBuf(((VBitmapData*)vnode->data)->width,
201                                 ((VBitmapData*)vnode->data)->height, 24, IB_rect, 0);
202                 /* free old ibuf */
203                 BKE_image_signal(image, NULL, IMA_SIGNAL_FREE);
204                 /* set up pointer at new ibuf */
205                 BKE_image_assign_ibuf(image, ibuf);
206                 
207                 /* sync blender image with all verse layers */
208                 vblayer = ((VBitmapData*)(vnode->data))->layers.lb.first;
209                 while(vblayer) {
210                         sync_blender_image_channel_with_verse_layer(vnode, vblayer);
211                         vblayer = vblayer->next;
212                 }
213         }
214 }
215
216 /*
217  * when blender tries to upload image to verse server, then it is neccessary
218  * to push coresponding channel data to verse server, when verse bitmap layer
219  * was created
220  */
221 void post_bitmap_layer_create(VBitmapLayer *vblayer)
222 {
223         struct VNode *vnode = vblayer->vnode;
224         struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
225         struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
226         unsigned char *rect;
227         short channel;
228 /*      VNBTile tile[VN_B_TILE_SIZE*VN_B_TILE_SIZE];
229         unsigned int width, t_width, height, t_height, x, y, i, j; */
230
231         /* if this application doesn't try to upload this image to verse
232          * server then do nothing */
233         if(vnode->owner_id != VN_OWNER_MINE) return;
234         
235         if(!image) return;
236
237         if(!ibuf) return;
238
239         rect = (unsigned char*)ibuf->rect;
240
241         if(strncmp(vblayer->name, "col_r", 5))
242                 channel = 0;
243         else if(strncmp(vblayer->name, "col_g", 5))
244                 channel = 1;
245         else if(strncmp(vblayer->name, "col_b", 5))
246                 channel = 2;
247         else if(strncmp(vblayer->name, "alpha", 5))
248                 channel = 3;
249
250         /* TODO: send all data of channel to verse server */
251 }
252
253 /*
254  * dummy function now
255  */
256 void post_bitmap_layer_destroy(VBitmapLayer *vblayer)
257 {
258 }
259
260 /*
261  * this function is executed, when some image changed tile comes from verse server,
262  * it is neccessary to do some crazy transformation here, because blender uses
263  * different (very unstandard) image coordinate system (begining of coordinate
264  * system is in bottom left corner) ... all other programs (including verse) has
265  * begining of image coordinate system in left top corner
266  */
267 void post_bitmap_tile_set(VBitmapLayer *vblayer, unsigned int xs, unsigned int ys)
268 {
269         struct VNode *vnode = vblayer->vnode;
270         struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
271         struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
272         unsigned char *rect, *i_rect;
273         unsigned int x, y, t_width, t_height, height, m_ys, m_y, d, i, j, channel=0;
274
275         if(!image) return;
276
277         if(!ibuf) return;
278
279         /* select channel due to verse layer name */
280         if(strcmp(vblayer->name,"color_r")==0)
281                 channel = 0;
282         else if(strcmp(vblayer->name,"color_g")==0)
283                 channel = 1;
284         else if(strcmp(vblayer->name, "color_b")==0)
285                 channel = 2;
286         else if(strcmp(vblayer->name,"transparency")==0)
287                 channel = 3;
288
289         i_rect = rect = (unsigned char*)ibuf->rect;
290
291         /* width of verse image including all tiles */
292         t_width =((VBitmapData*)vnode->data)->t_width;
293         /* height of verse image including all tiles */
294         t_height =((VBitmapData*)vnode->data)->t_height;
295         /* height of blender image */
296         height = ((VBitmapData*)vnode->data)->height;
297
298         /* if the bitmap's dimensions are not integer multiples of the tile
299          * side length, eight, then d will not be zero (height of "uncomplete
300          * tile") */
301         d = VN_B_TILE_SIZE - (t_height - height);
302         /* mirrored coordination of received tile */
303         m_ys = t_height - ys - VN_B_TILE_SIZE;
304
305         /* ys and m_ys are y axis, where we will do some changes */
306         if(ys + VN_B_TILE_SIZE > height) {
307                 m_ys = 0;
308                 ys = ys + d - 1;
309         }
310         else {
311                 m_ys = m_ys - VN_B_TILE_SIZE + d;
312                 ys = ys + VN_B_TILE_SIZE - 1;
313         }
314
315         /* "index" of blender image */
316         j = m_ys*ibuf->x + xs;
317         /* index of verse image */
318         i = ys*t_width + xs;
319
320         /* pointer at image data, that will be changed in following loop */
321         rect = i_rect + 4*j;
322
323         /* it seems hackish, but I didn't find better solution :-/ */
324         if(vblayer->type==VN_B_LAYER_UINT8) {
325                 unsigned char *vuint8 = (unsigned char*)vblayer->data;
326                 for(y=ys, m_y = m_ys;
327                         (m_y<m_ys+VN_B_TILE_SIZE) && (m_y<ibuf->y);
328                         y--, m_y++, i=y*t_width+xs, j=m_y*ibuf->x+xs, rect=i_rect+4*j)
329                         for(x=xs; (x<xs+VN_B_TILE_SIZE) && (x<ibuf->x); x++, rect+=4, i++, j++)
330                                 rect[channel] = (char)vuint8[i];
331         }
332
333         free_realtime_image(image);
334
335         /* redraw preview of image ... uncommented, because rendering
336          * was computed too often */
337 /*      BIF_preview_changed(ID_TE); */
338         allqueue(REDRAWIMAGE, 0);
339         allqueue(REDRAWVIEW3D, 0);
340 }
341
342 #endif
343