Files
test/source/blender/src/verse_image.c

344 lines
9.5 KiB
C

/**
* $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 "BKE_image.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)
{
ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
struct VNode *vnode;
if(!session) return;
if(!(session->flag & VERSE_CONNECTED)) return;
/* create "my" new object VerseNode */
vnode= create_verse_node(session, -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(ibuf) {
((VBitmapData*)vnode->data)->width = ibuf->x;
((VBitmapData*)vnode->data)->height = 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= BKE_image_get_ibuf(image, NULL);
unsigned char *rect;
int x, y, height, t_width, i, channel=0;
if(!image) return;
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= BKE_image_get_ibuf(image, NULL);
if(!image) return;
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 */
BKE_image_signal(image, NULL, IMA_SIGNAL_FREE);
/* set up pointer at new ibuf */
BKE_image_assign_ibuf(image, 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= BKE_image_get_ibuf(image, NULL);
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;
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= BKE_image_get_ibuf(image, NULL);
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;
if(!ibuf) return;
/* select channel due to verse layer name */
if(strcmp(vblayer->name,"color_r")==0)
channel = 0;
else if(strcmp(vblayer->name,"color_g")==0)
channel = 1;
else if(strcmp(vblayer->name, "color_b")==0)
channel = 2;
else if(strcmp(vblayer->name,"transparency")==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