Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
commitbdfe7d89e2f1292644577972c716931b4ce3c6c3 (patch)
treed00eb50b749cb001e2b08272c91791e66740b05d /source/blender/imbuf/intern/scaling.c
parent78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (diff)
parent7e4db234cee71ead34ee81a12e27da4bd548eb4b (diff)
Merge of trunk into blender 2.5:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416 Issues: * GHOST/X11 had conflicting changes. Some code was added in 2.5, which was later added in trunk also, but reverted partially, specifically revision 16683. I have left out this reversion in the 2.5 branch since I think it is needed there. http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683 * Scons had various conflicting changes, I decided to go with trunk version for everything except priorities and some library renaming. * In creator.c, there were various fixes and fixes for fixes related to the -w -W and -p options. In 2.5 -w and -W is not coded yet, and -p is done differently. Since this is changed so much, and I don't think those fixes would be needed in 2.5, I've left them out. * Also in creator.c: there was code for a python bugfix where the screen was not initialized when running with -P. The code that initializes the screen there I had to disable, that can't work in 2.5 anymore but left it commented as a reminder. Further I had to disable some new function calls. using src/ and python/, as was done already in this branch, disabled function calls: * bpath.c: error reporting * BME_conversions.c: editmesh conversion functions. * SHD_dynamic: disabled almost completely, there is no python/. * KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled. * text.c: clipboard copy call. * object.c: OB_SUPPORT_MATERIAL. * DerivedMesh.c and subsurf_ccg, stipple_quarttone. Still to be done: * Go over files and functions that were moved to a different location but could still use changes that were done in trunk.
Diffstat (limited to 'source/blender/imbuf/intern/scaling.c')
-rw-r--r--source/blender/imbuf/intern/scaling.c475
1 files changed, 473 insertions, 2 deletions
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index c46a4bf1e93..8257eb4643e 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -39,6 +39,8 @@
#include "IMB_allocimbuf.h"
#include "IMB_filter.h"
+#include "BLO_sys_types.h" // for intptr_t support
+
/************************************************************************/
/* SCALING */
/************************************************************************/
@@ -480,6 +482,468 @@ struct ImBuf *IMB_halflace(struct ImBuf *ibuf1)
return (ibuf2);
}
+/* q_scale_linear_interpolation helper functions */
+
+static void enlarge_picture_byte(
+ unsigned char* src, unsigned char* dst, int src_width,
+ int src_height, int dst_width, int dst_height)
+{
+ double ratiox = (double) (dst_width - 1.0)
+ / (double) (src_width - 1.001);
+ double ratioy = (double) (dst_height - 1.0)
+ / (double) (src_height - 1.001);
+ uintptr_t x_src, dx_src, x_dst;
+ uintptr_t y_src, dy_src, y_dst;
+
+ dx_src = 65536.0 / ratiox;
+ dy_src = 65536.0 / ratioy;
+
+ y_src = 0;
+ for (y_dst = 0; y_dst < dst_height; y_dst++) {
+ unsigned char* line1 = src + (y_src >> 16) * 4 * src_width;
+ unsigned char* line2 = line1 + 4 * src_width;
+ uintptr_t weight1y = 65536 - (y_src & 0xffff);
+ uintptr_t weight2y = 65536 - weight1y;
+
+ if ((y_src >> 16) == src_height - 1) {
+ line2 = line1;
+ }
+
+ x_src = 0;
+ for (x_dst = 0; x_dst < dst_width; x_dst++) {
+ uintptr_t weight1x = 65536 - (x_src & 0xffff);
+ uintptr_t weight2x = 65536 - weight1x;
+
+ unsigned long x = (x_src >> 16) * 4;
+
+ *dst++ = ((((line1[x] * weight1y) >> 16)
+ * weight1x) >> 16)
+ + ((((line2[x] * weight2y) >> 16)
+ * weight1x) >> 16)
+ + ((((line1[4 + x] * weight1y) >> 16)
+ * weight2x) >> 16)
+ + ((((line2[4 + x] * weight2y) >> 16)
+ * weight2x) >> 16);
+
+ *dst++ = ((((line1[x + 1] * weight1y) >> 16)
+ * weight1x) >> 16)
+ + ((((line2[x + 1] * weight2y) >> 16)
+ * weight1x) >> 16)
+ + ((((line1[4 + x + 1] * weight1y) >> 16)
+ * weight2x) >> 16)
+ + ((((line2[4 + x + 1] * weight2y) >> 16)
+ * weight2x) >> 16);
+
+ *dst++ = ((((line1[x + 2] * weight1y) >> 16)
+ * weight1x) >> 16)
+ + ((((line2[x + 2] * weight2y) >> 16)
+ * weight1x) >> 16)
+ + ((((line1[4 + x + 2] * weight1y) >> 16)
+ * weight2x) >> 16)
+ + ((((line2[4 + x + 2] * weight2y) >> 16)
+ * weight2x) >> 16);
+
+ *dst++ = ((((line1[x + 3] * weight1y) >> 16)
+ * weight1x) >> 16)
+ + ((((line2[x + 3] * weight2y) >> 16)
+ * weight1x) >> 16)
+ + ((((line1[4 + x + 3] * weight1y) >> 16)
+ * weight2x) >> 16)
+ + ((((line2[4 + x + 3] * weight2y) >> 16)
+ * weight2x) >> 16);
+
+ x_src += dx_src;
+ }
+ y_src += dy_src;
+ }
+}
+
+struct scale_outpix_byte {
+ uintptr_t r;
+ uintptr_t g;
+ uintptr_t b;
+ uintptr_t a;
+
+ uintptr_t weight;
+};
+
+static void shrink_picture_byte(
+ unsigned char* src, unsigned char* dst, int src_width,
+ int src_height, int dst_width, int dst_height)
+{
+ double ratiox = (double) (dst_width) / (double) (src_width);
+ double ratioy = (double) (dst_height) / (double) (src_height);
+ uintptr_t x_src, dx_dst, x_dst;
+ uintptr_t y_src, dy_dst, y_dst;
+ intptr_t y_counter;
+ unsigned char * dst_begin = dst;
+
+ struct scale_outpix_byte * dst_line1 = NULL;
+ struct scale_outpix_byte * dst_line2 = NULL;
+
+ dst_line1 = (struct scale_outpix_byte*) MEM_callocN(
+ (dst_width + 1) * sizeof(struct scale_outpix_byte),
+ "shrink_picture_byte 1");
+ dst_line2 = (struct scale_outpix_byte*) MEM_callocN(
+ (dst_width + 1) * sizeof(struct scale_outpix_byte),
+ "shrink_picture_byte 2");
+
+ dx_dst = 65536.0 * ratiox;
+ dy_dst = 65536.0 * ratioy;
+
+ y_dst = 0;
+ y_counter = 65536;
+ for (y_src = 0; y_src < src_height; y_src++) {
+ unsigned char* line = src + y_src * 4 * src_width;
+ uintptr_t weight1y = 65536 - (y_dst & 0xffff);
+ uintptr_t weight2y = 65536 - weight1y;
+ x_dst = 0;
+ for (x_src = 0; x_src < src_width; x_src++) {
+ uintptr_t weight1x = 65536 - (x_dst & 0xffff);
+ uintptr_t weight2x = 65536 - weight1x;
+
+ uintptr_t x = x_dst >> 16;
+
+ uintptr_t w;
+
+ w = (weight1y * weight1x) >> 16;
+
+ dst_line1[x].r += (line[0] * w) >> 16;
+ dst_line1[x].g += (line[1] * w) >> 16;
+ dst_line1[x].b += (line[2] * w) >> 16;
+ dst_line1[x].a += (line[3] * w) >> 16;
+ dst_line1[x].weight += w;
+
+ w = (weight2y * weight1x) >> 16;
+
+ dst_line2[x].r += (line[0] * w) >> 16;
+ dst_line2[x].g += (line[1] * w) >> 16;
+ dst_line2[x].b += (line[2] * w) >> 16;
+ dst_line2[x].a += (line[3] * w) >> 16;
+ dst_line2[x].weight += w;
+
+ w = (weight1y * weight2x) >> 16;
+
+ dst_line1[x+1].r += (line[0] * w) >> 16;
+ dst_line1[x+1].g += (line[1] * w) >> 16;
+ dst_line1[x+1].b += (line[2] * w) >> 16;
+ dst_line1[x+1].a += (line[3] * w) >> 16;
+ dst_line1[x+1].weight += w;
+
+ w = (weight2y * weight2x) >> 16;
+
+ dst_line2[x+1].r += (line[0] * w) >> 16;
+ dst_line2[x+1].g += (line[1] * w) >> 16;
+ dst_line2[x+1].b += (line[2] * w) >> 16;
+ dst_line2[x+1].a += (line[3] * w) >> 16;
+ dst_line2[x+1].weight += w;
+
+ x_dst += dx_dst;
+ line += 4;
+ }
+
+ y_dst += dy_dst;
+ y_counter -= dy_dst;
+ if (y_counter < 0) {
+ uintptr_t x;
+ struct scale_outpix_byte * temp;
+
+ y_counter += 65536;
+
+ for (x=0; x < dst_width; x++) {
+ uintptr_t f = 0x80000000UL
+ / dst_line1[x].weight;
+ *dst++ = (dst_line1[x].r * f) >> 15;
+ *dst++ = (dst_line1[x].g * f) >> 15;
+ *dst++ = (dst_line1[x].b * f) >> 15;
+ *dst++ = (dst_line1[x].a * f) >> 15;
+ }
+ memset(dst_line1, 0, dst_width *
+ sizeof(struct scale_outpix_byte));
+ temp = dst_line1;
+ dst_line1 = dst_line2;
+ dst_line2 = temp;
+ }
+ }
+ if (dst - dst_begin < dst_width * dst_height * 4) {
+ uintptr_t x;
+ for (x = 0; x < dst_width; x++) {
+ uintptr_t f = 0x80000000UL / dst_line1[x].weight;
+ *dst++ = (dst_line1[x].r * f) >> 15;
+ *dst++ = (dst_line1[x].g * f) >> 15;
+ *dst++ = (dst_line1[x].b * f) >> 15;
+ *dst++ = (dst_line1[x].a * f) >> 15;
+ }
+ }
+ MEM_freeN(dst_line1);
+ MEM_freeN(dst_line2);
+}
+
+
+static void q_scale_byte(unsigned char* in, unsigned char* out, int in_width,
+ int in_height, int dst_width, int dst_height)
+{
+ if (dst_width > in_width && dst_height > in_height) {
+ enlarge_picture_byte(in, out, in_width, in_height,
+ dst_width, dst_height);
+ } else if (dst_width < in_width && dst_height < in_height) {
+ shrink_picture_byte(in, out, in_width, in_height,
+ dst_width, dst_height);
+ }
+}
+
+static void enlarge_picture_float(
+ float* src, float* dst, int src_width,
+ int src_height, int dst_width, int dst_height)
+{
+ double ratiox = (double) (dst_width - 1.0)
+ / (double) (src_width - 1.001);
+ double ratioy = (double) (dst_height - 1.0)
+ / (double) (src_height - 1.001);
+ uintptr_t x_dst;
+ uintptr_t y_dst;
+ double x_src, dx_src;
+ double y_src, dy_src;
+
+ dx_src = 1.0 / ratiox;
+ dy_src = 1.0 / ratioy;
+
+ y_src = 0;
+ for (y_dst = 0; y_dst < dst_height; y_dst++) {
+ float* line1 = src + ((int) y_src) * 4 * src_width;
+ float* line2 = line1 + 4 * src_width;
+ float weight1y = 1.0 - (y_src - (int) y_src);
+ float weight2y = 1.0 - weight1y;
+
+ if ((int) y_src == src_height - 1) {
+ line2 = line1;
+ }
+
+ x_src = 0;
+ for (x_dst = 0; x_dst < dst_width; x_dst++) {
+ float weight1x = 1.0 - (x_src - (int) x_src);
+ float weight2x = 1.0 - weight1x;
+
+ float w11 = weight1y * weight1x;
+ float w21 = weight2y * weight1x;
+ float w12 = weight1y * weight2x;
+ float w22 = weight2y * weight2x;
+
+ uintptr_t x = ((int) x_src) * 4;
+
+ *dst++ = line1[x] * w11
+ + line2[x] * w21
+ + line1[4 + x] * w12
+ + line2[4 + x] * w22;
+
+ *dst++ = line1[x + 1] * w11
+ + line2[x + 1] * w21
+ + line1[4 + x + 1] * w12
+ + line2[4 + x + 1] * w22;
+
+ *dst++ = line1[x + 2] * w11
+ + line2[x + 2] * w21
+ + line1[4 + x + 2] * w12
+ + line2[4 + x + 2] * w22;
+
+ *dst++ = line1[x + 3] * w11
+ + line2[x + 3] * w21
+ + line1[4 + x + 3] * w12
+ + line2[4 + x + 3] * w22;
+
+ x_src += dx_src;
+ }
+ y_src += dy_src;
+ }
+}
+
+struct scale_outpix_float {
+ float r;
+ float g;
+ float b;
+ float a;
+
+ float weight;
+};
+
+static void shrink_picture_float(
+ float* src, float* dst, int src_width,
+ int src_height, int dst_width, int dst_height)
+{
+ double ratiox = (double) (dst_width) / (double) (src_width);
+ double ratioy = (double) (dst_height) / (double) (src_height);
+ uintptr_t x_src;
+ uintptr_t y_src;
+ float dx_dst, x_dst;
+ float dy_dst, y_dst;
+ float y_counter;
+ float * dst_begin = dst;
+
+ struct scale_outpix_float * dst_line1;
+ struct scale_outpix_float * dst_line2;
+
+ dst_line1 = (struct scale_outpix_float*) MEM_callocN(
+ (dst_width + 1) * sizeof(struct scale_outpix_float),
+ "shrink_picture_float 1");
+ dst_line2 = (struct scale_outpix_float*) MEM_callocN(
+ (dst_width + 1) * sizeof(struct scale_outpix_float),
+ "shrink_picture_float 2");
+
+ dx_dst = ratiox;
+ dy_dst = ratioy;
+
+ y_dst = 0;
+ y_counter = 1.0;
+ for (y_src = 0; y_src < src_height; y_src++) {
+ float* line = src + y_src * 4 * src_width;
+ uintptr_t weight1y = 1.0 - (y_dst - (int) y_dst);
+ uintptr_t weight2y = 1.0 - weight1y;
+ x_dst = 0;
+ for (x_src = 0; x_src < src_width; x_src++) {
+ uintptr_t weight1x = 1.0 - (x_dst - (int) x_dst);
+ uintptr_t weight2x = 1.0 - weight1x;
+
+ uintptr_t x = (int) x_dst;
+
+ float w;
+
+ w = weight1y * weight1x;
+
+ dst_line1[x].r += line[0] * w;
+ dst_line1[x].g += line[1] * w;
+ dst_line1[x].b += line[2] * w;
+ dst_line1[x].a += line[3] * w;
+ dst_line1[x].weight += w;
+
+ w = weight2y * weight1x;
+
+ dst_line2[x].r += line[0] * w;
+ dst_line2[x].g += line[1] * w;
+ dst_line2[x].b += line[2] * w;
+ dst_line2[x].a += line[3] * w;
+ dst_line2[x].weight += w;
+
+ w = weight1y * weight2x;
+
+ dst_line1[x+1].r += line[0] * w;
+ dst_line1[x+1].g += line[1] * w;
+ dst_line1[x+1].b += line[2] * w;
+ dst_line1[x+1].a += line[3] * w;
+ dst_line1[x+1].weight += w;
+
+ w = weight2y * weight2x;
+
+ dst_line2[x+1].r += line[0] * w;
+ dst_line2[x+1].g += line[1] * w;
+ dst_line2[x+1].b += line[2] * w;
+ dst_line2[x+1].a += line[3] * w;
+ dst_line2[x+1].weight += w;
+
+ x_dst += dx_dst;
+ line += 4;
+ }
+
+ y_dst += dy_dst;
+ y_counter -= dy_dst;
+ if (y_counter < 0) {
+ uintptr_t x;
+ struct scale_outpix_float * temp;
+
+ y_counter += 1.0;
+
+ for (x=0; x < dst_width; x++) {
+ float f = 1.0 / dst_line1[x].weight;
+ *dst++ = dst_line1[x].r * f;
+ *dst++ = dst_line1[x].g * f;
+ *dst++ = dst_line1[x].b * f;
+ *dst++ = dst_line1[x].a * f;
+ }
+ memset(dst_line1, 0, dst_width *
+ sizeof(struct scale_outpix_float));
+ temp = dst_line1;
+ dst_line1 = dst_line2;
+ dst_line2 = temp;
+ }
+ }
+ if (dst - dst_begin < dst_width * dst_height * 4) {
+ uintptr_t x;
+ for (x = 0; x < dst_width; x++) {
+ float f = 1.0 / dst_line1[x].weight;
+ *dst++ = dst_line1[x].r * f;
+ *dst++ = dst_line1[x].g * f;
+ *dst++ = dst_line1[x].b * f;
+ *dst++ = dst_line1[x].a * f;
+ }
+ }
+ MEM_freeN(dst_line1);
+ MEM_freeN(dst_line2);
+}
+
+
+static void q_scale_float(float* in, float* out, int in_width,
+ int in_height, int dst_width, int dst_height)
+{
+ if (dst_width > in_width && dst_height > in_height) {
+ enlarge_picture_float(in, out, in_width, in_height,
+ dst_width, dst_height);
+ } else if (dst_width < in_width && dst_height < in_height) {
+ shrink_picture_float(in, out, in_width, in_height,
+ dst_width, dst_height);
+ }
+}
+
+/* q_scale_linear_interpolation (derived from ppmqscale, http://libdv.sf.net)
+
+ q stands for quick _and_ quality :)
+
+ only handles common cases when we either
+
+ scale both, x and y or
+ shrink both, x and y
+
+ but that is pretty fast:
+ * does only blit once instead of two passes like the old code
+ (fewer cache misses)
+ * uses fixed point integer arithmetic for byte buffers
+ * doesn't branch in tight loops
+
+ Should be comparable in speed to the ImBuf ..._fast functions at least
+ for byte-buffers.
+
+*/
+static int q_scale_linear_interpolation(
+ struct ImBuf *ibuf, int newx, int newy)
+{
+ if ((newx >= ibuf->x && newy <= ibuf->y) ||
+ (newx <= ibuf->x && newy >= ibuf->y)) {
+ return FALSE;
+ }
+
+ if (ibuf->rect) {
+ unsigned char * newrect =
+ MEM_mallocN(newx * newy * sizeof(int), "q_scale rect");
+ q_scale_byte((unsigned char *)ibuf->rect, newrect, ibuf->x, ibuf->y,
+ newx, newy);
+
+ imb_freerectImBuf(ibuf);
+ ibuf->mall |= IB_rect;
+ ibuf->rect = (unsigned int *) newrect;
+ }
+ if (ibuf->rect_float) {
+ float * newrect =
+ MEM_mallocN(newx * newy * 4 *sizeof(float),
+ "q_scale rectfloat");
+ q_scale_float(ibuf->rect_float, newrect, ibuf->x, ibuf->y,
+ newx, newy);
+ imb_freerectfloatImBuf(ibuf);
+ ibuf->mall |= IB_rectfloat;
+ ibuf->rect_float = newrect;
+ }
+ ibuf->x = newx;
+ ibuf->y = newy;
+
+ return TRUE;
+}
static struct ImBuf *scaledownx(struct ImBuf *ibuf, int newx)
{
@@ -1110,11 +1574,18 @@ struct ImBuf *IMB_scaleImBuf(struct ImBuf * ibuf, short newx, short newy)
{
if (ibuf==NULL) return (0);
if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf);
+
+ if (newx == ibuf->x && newy == ibuf->y) { return ibuf; }
- // scaleup / scaledown functions below change ibuf->x and ibuf->y
- // so we first scale the Z-buffer (if any)
+ /* scaleup / scaledown functions below change ibuf->x and ibuf->y
+ so we first scale the Z-buffer (if any) */
scalefast_Z_ImBuf(ibuf, newx, newy);
+ /* try to scale common cases in a fast way */
+ if (q_scale_linear_interpolation(ibuf, newx, newy)) {
+ return ibuf;
+ }
+
if (newx < ibuf->x) if (newx) scaledownx(ibuf,newx);
if (newy < ibuf->y) if (newy) scaledowny(ibuf,newy);
if (newx > ibuf->x) if (newx) scaleupx(ibuf,newx);