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