Files
test/source/blender/editors/space_image/image_draw.c
Sergey Sharybin 5c6f6301b0 Image thread safe improvements
This commit makes BKE_image_acquire_ibuf referencing result, which means once
some area requested for image buffer, it'll be guaranteed this buffer wouldn't
be freed by image signal.

To de-reference buffer BKE_image_release_ibuf should now always be used.

To make referencing working correct we can not rely on result of
image_get_ibuf_threadsafe called outside from thread lock. This is so because
we need to guarantee getting image buffer from list of loaded buffers and it's
referencing happens atomic. Without lock here it is possible that between call
of image_get_ibuf_threadsafe and referencing the buffer IMA_SIGNAL_FREE would
be called. Image signal handling too is blocking now to prevent such a
situation.

Threads are locking by spinlock, which are faster than mutexes. There were some
slowdown reports in the past about render slowdown when using OSX on Xeon CPU.
It shouldn't happen with spin locks, but more tests on different hardware would
be really welcome. So far can not see speed regressions on own computers.

This commit also removes BKE_image_get_ibuf, because it was not so intuitive
when get_ibuf and acquire_ibuf should be used.

Thanks to Ton and Brecht for discussion/review :)
2012-11-15 15:59:58 +00:00

817 lines
22 KiB
C

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* Contributor(s): Blender Foundation, 2002-2009
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/space_image/image_draw.c
* \ingroup spimage
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_brush_types.h"
#include "PIL_time.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_threads.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_colormanagement.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BLF_api.h"
#include "ED_gpencil.h"
#include "ED_image.h"
#include "ED_screen.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RE_pipeline.h"
#include "image_intern.h"
static void draw_render_info(Scene *scene, Image *ima, ARegion *ar)
{
RenderResult *rr;
rr = BKE_image_acquire_renderresult(scene, ima);
if (rr && rr->text) {
ED_region_info_draw(ar, rr->text, 1, 0.25);
}
BKE_image_release_renderresult(scene, ima);
}
/* used by node view too */
void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_default_view, int channels, int x, int y,
const unsigned char cp[4], const float fp[4], int *zp, float *zpf)
{
char str[256];
float dx = 6;
/* text colors */
/* XXX colored text not allowed in Blender UI */
#if 0
unsigned char red[3] = {255, 50, 50};
unsigned char green[3] = {0, 255, 0};
unsigned char blue[3] = {100, 100, 255};
#else
unsigned char red[3] = {255, 255, 255};
unsigned char green[3] = {255, 255, 255};
unsigned char blue[3] = {255, 255, 255};
#endif
float hue = 0, sat = 0, val = 0, lum = 0, u = 0, v = 0;
float col[4], finalcol[4];
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
/* noisy, high contrast make impossible to read if lower alpha is used. */
glColor4ub(0, 0, 0, 190);
glRecti(0.0, 0.0, BLI_rcti_size_x(&ar->winrct) + 1, 20);
glDisable(GL_BLEND);
BLF_size(blf_mono_font, 11, 72);
glColor3ub(255, 255, 255);
BLI_snprintf(str, sizeof(str), "X:%-4d Y:%-4d |", x, y);
// UI_DrawString(6, 6, str); // works ok but fixed width is nicer.
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
if (zp) {
glColor3ub(255, 255, 255);
BLI_snprintf(str, sizeof(str), " Z:%-.4f |", 0.5f + 0.5f * (((float)*zp) / (float)0x7fffffff));
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
}
if (zpf) {
glColor3ub(255, 255, 255);
BLI_snprintf(str, sizeof(str), " Z:%-.3f |", *zpf);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
}
if (channels >= 3) {
glColor3ubv(red);
if (fp)
BLI_snprintf(str, sizeof(str), " R:%-.4f", fp[0]);
else if (cp)
BLI_snprintf(str, sizeof(str), " R:%-3d", cp[0]);
else
BLI_snprintf(str, sizeof(str), " R:-");
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
glColor3ubv(green);
if (fp)
BLI_snprintf(str, sizeof(str), " G:%-.4f", fp[1]);
else if (cp)
BLI_snprintf(str, sizeof(str), " G:%-3d", cp[1]);
else
BLI_snprintf(str, sizeof(str), " G:-");
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
glColor3ubv(blue);
if (fp)
BLI_snprintf(str, sizeof(str), " B:%-.4f", fp[2]);
else if (cp)
BLI_snprintf(str, sizeof(str), " B:%-3d", cp[2]);
else
BLI_snprintf(str, sizeof(str), " B:-");
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
if (channels == 4) {
glColor3ub(255, 255, 255);
if (fp)
BLI_snprintf(str, sizeof(str), " A:%-.4f", fp[3]);
else if (cp)
BLI_snprintf(str, sizeof(str), " A:%-3d", cp[3]);
else
BLI_snprintf(str, sizeof(str), "- ");
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
}
if (color_manage && channels == 4) {
float pixel[4];
if (use_default_view)
IMB_colormanagement_pixel_to_display_space_v4(pixel, fp, NULL, &scene->display_settings);
else
IMB_colormanagement_pixel_to_display_space_v4(pixel, fp, &scene->view_settings, &scene->display_settings);
BLI_snprintf(str, sizeof(str), " | CM R:%-.4f G:%-.4f B:%-.4f", pixel[0], pixel[1], pixel[2]);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
}
}
/* color rectangle */
if (channels == 1) {
if (fp) {
col[0] = col[1] = col[2] = fp[0];
}
else if (cp) {
col[0] = col[1] = col[2] = (float)cp[0] / 255.0f;
}
else {
col[0] = col[1] = col[2] = 0.0f;
}
col[3] = 1.0f;
}
else if (channels == 3) {
if (fp) {
copy_v3_v3(col, fp);
}
else if (cp) {
rgb_uchar_to_float(col, cp);
}
else {
zero_v3(col);
}
col[3] = 1.0f;
}
else if (channels == 4) {
if (fp)
copy_v4_v4(col, fp);
else if (cp) {
rgba_uchar_to_float(col, cp);
}
else {
zero_v4(col);
}
}
else {
BLI_assert(0);
zero_v4(col);
}
if (color_manage) {
if (use_default_view)
IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, NULL, &scene->display_settings);
else
IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, &scene->view_settings, &scene->display_settings);
}
else {
copy_v4_v4(finalcol, col);
}
glDisable(GL_BLEND);
glColor3fv(finalcol);
dx += 5;
glBegin(GL_QUADS);
glVertex2f(dx, 3);
glVertex2f(dx, 17);
glVertex2f(dx + 30, 17);
glVertex2f(dx + 30, 3);
glEnd();
/* draw outline */
glColor3ub(128, 128, 128);
glBegin(GL_LINE_LOOP);
glVertex2f(dx, 3);
glVertex2f(dx, 17);
glVertex2f(dx + 30, 17);
glVertex2f(dx + 30, 3);
glEnd();
dx += 35;
glColor3ub(255, 255, 255);
if (channels == 1) {
if (fp) {
rgb_to_hsv(fp[0], fp[0], fp[0], &hue, &sat, &val);
rgb_to_yuv(fp[0], fp[0], fp[0], &lum, &u, &v);
}
else if (cp) {
rgb_to_hsv((float)cp[0] / 255.0f, (float)cp[0] / 255.0f, (float)cp[0] / 255.0f, &hue, &sat, &val);
rgb_to_yuv((float)cp[0] / 255.0f, (float)cp[0] / 255.0f, (float)cp[0] / 255.0f, &lum, &u, &v);
}
BLI_snprintf(str, sizeof(str), "V:%-.4f", val);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
BLI_snprintf(str, sizeof(str), " L:%-.4f", lum);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
}
else if (channels >= 3) {
if (fp) {
rgb_to_hsv(fp[0], fp[1], fp[2], &hue, &sat, &val);
rgb_to_yuv(fp[0], fp[1], fp[2], &lum, &u, &v);
}
else if (cp) {
rgb_to_hsv((float)cp[0] / 255.0f, (float)cp[1] / 255.0f, (float)cp[2] / 255.0f, &hue, &sat, &val);
rgb_to_yuv((float)cp[0] / 255.0f, (float)cp[1] / 255.0f, (float)cp[2] / 255.0f, &lum, &u, &v);
}
BLI_snprintf(str, sizeof(str), "H:%-.4f", hue);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
BLI_snprintf(str, sizeof(str), " S:%-.4f", sat);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
BLI_snprintf(str, sizeof(str), " V:%-.4f", val);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
BLI_snprintf(str, sizeof(str), " L:%-.4f", lum);
BLF_position(blf_mono_font, dx, 6, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str);
}
(void)dx;
}
/* image drawing */
static void sima_draw_alpha_pixels(float x1, float y1, int rectx, int recty, unsigned int *recti)
{
/* swap bytes, so alpha is most significant one, then just draw it as luminance int */
if (ENDIAN_ORDER == B_ENDIAN)
glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_UNSIGNED_INT, recti);
glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
}
static void sima_draw_alpha_pixelsf(float x1, float y1, int rectx, int recty, float *rectf)
{
float *trectf = MEM_mallocN(rectx * recty * 4, "temp");
int a, b;
for (a = rectx * recty - 1, b = 4 * a + 3; a >= 0; a--, b -= 4)
trectf[a] = rectf[b];
glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_FLOAT, trectf);
MEM_freeN(trectf);
/* ogl trick below is slower... (on ATI 9600) */
// glColorMask(1, 0, 0, 0);
// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf+3);
// glColorMask(0, 1, 0, 0);
// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf+2);
// glColorMask(0, 0, 1, 0);
// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf+1);
// glColorMask(1, 1, 1, 1);
}
static void sima_draw_zbuf_pixels(float x1, float y1, int rectx, int recty, int *recti)
{
/* zbuffer values are signed, so we need to shift color range */
glPixelTransferf(GL_RED_SCALE, 0.5f);
glPixelTransferf(GL_GREEN_SCALE, 0.5f);
glPixelTransferf(GL_BLUE_SCALE, 0.5f);
glPixelTransferf(GL_RED_BIAS, 0.5f);
glPixelTransferf(GL_GREEN_BIAS, 0.5f);
glPixelTransferf(GL_BLUE_BIAS, 0.5f);
glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_INT, recti);
glPixelTransferf(GL_RED_SCALE, 1.0f);
glPixelTransferf(GL_GREEN_SCALE, 1.0f);
glPixelTransferf(GL_BLUE_SCALE, 1.0f);
glPixelTransferf(GL_RED_BIAS, 0.0f);
glPixelTransferf(GL_GREEN_BIAS, 0.0f);
glPixelTransferf(GL_BLUE_BIAS, 0.0f);
}
static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rectx, int recty, float *rect_float)
{
float bias, scale, *rectf, clipend;
int a;
if (scene->camera && scene->camera->type == OB_CAMERA) {
bias = ((Camera *)scene->camera->data)->clipsta;
clipend = ((Camera *)scene->camera->data)->clipend;
scale = 1.0f / (clipend - bias);
}
else {
bias = 0.1f;
scale = 0.01f;
clipend = 100.0f;
}
rectf = MEM_mallocN(rectx * recty * 4, "temp");
for (a = rectx * recty - 1; a >= 0; a--) {
if (rect_float[a] > clipend)
rectf[a] = 0.0f;
else if (rect_float[a] < bias)
rectf[a] = 1.0f;
else {
rectf[a] = 1.0f - (rect_float[a] - bias) * scale;
rectf[a] *= rectf[a];
}
}
glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_FLOAT, rectf);
MEM_freeN(rectf);
}
static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, Scene *scene, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy)
{
int x, y;
/* set zoom */
glPixelZoom(zoomx, zoomy);
/* find window pixel coordinates of origin */
UI_view2d_to_region_no_clip(&ar->v2d, fx, fy, &x, &y);
/* this part is generic image display */
if (sima->flag & SI_SHOW_ALPHA) {
if (ibuf->rect)
sima_draw_alpha_pixels(x, y, ibuf->x, ibuf->y, ibuf->rect);
else if (ibuf->rect_float && ibuf->channels == 4)
sima_draw_alpha_pixelsf(x, y, ibuf->x, ibuf->y, ibuf->rect_float);
}
else if (sima->flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) {
if (ibuf->zbuf)
sima_draw_zbuf_pixels(x, y, ibuf->x, ibuf->y, ibuf->zbuf);
else if (ibuf->zbuf_float)
sima_draw_zbuffloat_pixels(scene, x, y, ibuf->x, ibuf->y, ibuf->zbuf_float);
else if (ibuf->channels == 1)
sima_draw_zbuffloat_pixels(scene, x, y, ibuf->x, ibuf->y, ibuf->rect_float);
}
else {
unsigned char *display_buffer;
void *cache_handle;
if (sima->flag & SI_USE_ALPHA) {
fdrawcheckerboard(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
if (display_buffer)
glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer);
#if 0
else
glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_FLOAT, ibuf->rect_float);
#endif
IMB_display_buffer_release(cache_handle);
if (sima->flag & SI_USE_ALPHA)
glDisable(GL_BLEND);
}
/* reset zoom */
glPixelZoom(1.0f, 1.0f);
}
static unsigned int *get_part_from_buffer(unsigned int *buffer, int width, short startx, short starty, short endx, short endy)
{
unsigned int *rt, *rp, *rectmain;
short y, heigth, len;
/* the right offset in rectot */
rt = buffer + (starty * width + startx);
len = (endx - startx);
heigth = (endy - starty);
rp = rectmain = MEM_mallocN(heigth * len * sizeof(int), "rect");
for (y = 0; y < heigth; y++) {
memcpy(rp, rt, len * 4);
rt += width;
rp += len;
}
return rectmain;
}
static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy)
{
unsigned char *display_buffer;
unsigned int *rect;
int dx, dy, sx, sy, x, y;
void *cache_handle;
/* verify valid values, just leave this a while */
if (ima->xrep < 1) return;
if (ima->yrep < 1) return;
if (ima->flag & IMA_VIEW_AS_RENDER)
display_buffer = IMB_display_buffer_acquire(ibuf, &scene->view_settings, &scene->display_settings, &cache_handle);
else
display_buffer = IMB_display_buffer_acquire(ibuf, NULL, &scene->display_settings, &cache_handle);
if (!display_buffer)
return;
glPixelZoom(zoomx, zoomy);
if (sima->curtile >= ima->xrep * ima->yrep)
sima->curtile = ima->xrep * ima->yrep - 1;
/* retrieve part of image buffer */
dx = ibuf->x / ima->xrep;
dy = ibuf->y / ima->yrep;
sx = (sima->curtile % ima->xrep) * dx;
sy = (sima->curtile / ima->xrep) * dy;
rect = get_part_from_buffer((unsigned int *)display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy);
/* draw repeated */
for (sy = 0; sy + dy <= ibuf->y; sy += dy) {
for (sx = 0; sx + dx <= ibuf->x; sx += dx) {
UI_view2d_to_region_no_clip(&ar->v2d, fx + (float)sx / (float)ibuf->x, fy + (float)sy / (float)ibuf->y, &x, &y);
glaDrawPixelsSafe(x, y, dx, dy, dx, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
}
glPixelZoom(1.0f, 1.0f);
IMB_display_buffer_release(cache_handle);
MEM_freeN(rect);
}
static void draw_image_buffer_repeated(const bContext *C, SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float zoomx, float zoomy)
{
const double time_current = PIL_check_seconds_timer();
const int xmax = ceil(ar->v2d.cur.xmax);
const int ymax = ceil(ar->v2d.cur.ymax);
const int xmin = floor(ar->v2d.cur.xmin);
const int ymin = floor(ar->v2d.cur.ymin);
int x;
for (x = xmin; x < xmax; x++) {
int y;
for (y = ymin; y < ymax; y++) {
if (ima && (ima->tpageflag & IMA_TILES))
draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, x, y, zoomx, zoomy);
else
draw_image_buffer(C, sima, ar, scene, ibuf, x, y, zoomx, zoomy);
/* only draw until running out of time */
if ((PIL_check_seconds_timer() - time_current) > 0.25)
return;
}
}
}
/* draw uv edit */
/* draw grease pencil */
void draw_image_grease_pencil(bContext *C, short onlyv2d)
{
/* draw in View2D space? */
if (onlyv2d) {
/* draw grease-pencil ('image' strokes) */
draw_gpencil_2dimage(C);
}
else {
/* assume that UI_view2d_restore(C) has been called... */
//SpaceImage *sima = (SpaceImage *)CTX_wm_space_data(C);
/* draw grease-pencil ('screen' strokes) */
draw_gpencil_view2d(C, 0);
}
}
void draw_image_sample_line(SpaceImage *sima)
{
if (sima->sample_line_hist.flag & HISTO_FLAG_SAMPLELINE) {
Histogram *hist = &sima->sample_line_hist;
glBegin(GL_LINES);
glColor3ub(0, 0, 0);
glVertex2fv(hist->co[0]);
glVertex2fv(hist->co[1]);
glEnd();
setlinestyle(1);
glBegin(GL_LINES);
glColor3ub(255, 255, 255);
glVertex2fv(hist->co[0]);
glVertex2fv(hist->co[1]);
glEnd();
setlinestyle(0);
}
}
/* XXX becomes WM paint cursor */
#if 0
static void draw_image_view_tool(Scene *scene)
{
ToolSettings *settings = scene->toolsettings;
Brush *brush = settings->imapaint.brush;
int mval[2];
float radius;
int draw = 0;
if (brush) {
if (settings->imapaint.flag & IMAGEPAINT_DRAWING) {
if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
draw = 1;
}
else if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL)
draw = 1;
if (draw) {
getmouseco_areawin(mval);
radius = BKE_brush_size_get(brush) * G.sima->zoom;
fdrawXORcirc(mval[0], mval[1], radius);
if (brush->innerradius != 1.0) {
radius *= brush->innerradius;
fdrawXORcirc(mval[0], mval[1], radius);
}
}
}
}
#endif
static unsigned char *get_alpha_clone_image(const bContext *C, Scene *scene, int *width, int *height)
{
Brush *brush = paint_brush(&scene->toolsettings->imapaint.paint);
ImBuf *ibuf;
unsigned int size, alpha;
unsigned char *display_buffer;
unsigned char *rect, *cp;
void *cache_handle;
if (!brush || !brush->clone.image)
return NULL;
ibuf = BKE_image_acquire_ibuf(brush->clone.image, NULL, NULL);
if (!ibuf)
return NULL;
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
if (!display_buffer) {
BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
IMB_display_buffer_release(cache_handle);
return NULL;
}
rect = MEM_dupallocN(display_buffer);
IMB_display_buffer_release(cache_handle);
if (!rect) {
BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
return NULL;
}
*width = ibuf->x;
*height = ibuf->y;
size = (*width) * (*height);
alpha = (unsigned char)255 * brush->clone.alpha;
cp = rect;
while (size-- > 0) {
cp[3] = alpha;
cp += 4;
}
BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
return rect;
}
static void draw_image_paint_helpers(const bContext *C, ARegion *ar, Scene *scene, float zoomx, float zoomy)
{
Brush *brush;
int x, y, w, h;
unsigned char *clonerect;
brush = paint_brush(&scene->toolsettings->imapaint.paint);
if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) {
/* this is not very efficient, but glDrawPixels doesn't allow
* drawing with alpha */
clonerect = get_alpha_clone_image(C, scene, &w, &h);
if (clonerect) {
UI_view2d_to_region_no_clip(&ar->v2d, brush->clone.offset[0], brush->clone.offset[1], &x, &y);
glPixelZoom(zoomx, zoomy);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, clonerect);
glDisable(GL_BLEND);
glPixelZoom(1.0, 1.0);
MEM_freeN(clonerect);
}
}
}
/* draw main image area */
void draw_image_main(const bContext *C, ARegion *ar)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
Image *ima;
ImBuf *ibuf;
float zoomx, zoomy;
int show_viewer, show_render;
void *lock;
/* XXX can we do this in refresh? */
#if 0
what_image(sima);
if (sima->image) {
ED_image_get_aspect(sima->image, &xuser_asp, &yuser_asp);
/* UGLY hack? until now iusers worked fine... but for flipbook viewer we need this */
if (sima->image->type == IMA_TYPE_COMPOSITE) {
ImageUser *iuser = ntree_get_active_iuser(scene->nodetree);
if (iuser) {
BKE_image_user_calc_imanr(iuser, scene->r.cfra, 0);
sima->iuser = *iuser;
}
}
/* and we check for spare */
ibuf = ED_space_image_buffer(sima);
}
#endif
/* retrieve the image and information about it */
ima = ED_space_image(sima);
ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
show_viewer = (ima && ima->source == IMA_SRC_VIEWER);
show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT);
if (show_viewer) {
/* use locked draw for drawing viewer image buffer since the conpositor
* is running in separated thread and compositor could free this buffers.
* other images are not modifying in such a way so they does not require
* lock (sergey)
*/
BLI_lock_thread(LOCK_DRAW_IMAGE);
}
ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* draw the image or grid */
if (ibuf == NULL)
ED_region_grid_draw(ar, zoomx, zoomy);
else if (sima->flag & SI_DRAW_TILE)
draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
else if (ima && (ima->tpageflag & IMA_TILES))
draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
else
draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
/* paint helpers */
if (sima->mode == SI_MODE_PAINT)
draw_image_paint_helpers(C, ar, scene, zoomx, zoomy);
/* XXX integrate this code */
#if 0
if (ibuf) {
float xoffs = 0.0f, yoffs = 0.0f;
if (image_preview_active(sa, &xim, &yim)) {
xoffs = scene->r.disprect.xmin;
yoffs = scene->r.disprect.ymin;
glColor3ub(0, 0, 0);
calc_image_view(sima, 'f');
myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
glRectf(0.0f, 0.0f, 1.0f, 1.0f);
glLoadIdentity();
}
}
#endif
ED_space_image_release_buffer(sima, ibuf, lock);
if (show_viewer) {
BLI_unlock_thread(LOCK_DRAW_IMAGE);
}
/* render info */
if (ima && show_render)
draw_render_info(scene, ima, ar);
}