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 :)
817 lines
22 KiB
C
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);
|
|
}
|