void IMB_rect_from_float(ImBuf *ibuf) { float *buffer; const char *from_colorspace; /* verify we have a float buffer */ if (ibuf->rect_float == NULL) { return; } /* create byte rect if it didn't exist yet */ if (ibuf->rect == NULL) { if (imb_addrectImBuf(ibuf) == 0) { return; } } if (ibuf->float_colorspace == NULL) { from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); } else { from_colorspace = ibuf->float_colorspace->name; } buffer = MEM_dupallocN(ibuf->rect_float); /* first make float buffer in byte space */ const bool predivide = IMB_alpha_affects_rgb(ibuf); IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, predivide); /* convert from float's premul alpha to byte's straight alpha */ if (IMB_alpha_affects_rgb(ibuf)) { IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y); } /* convert float to byte */ IMB_buffer_byte_from_float((unsigned char *)ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, ibuf->x, ibuf->y, ibuf->x, ibuf->x); MEM_freeN(buffer); /* ensure user flag is reset */ ibuf->userflags &= ~IB_RECT_INVALID; }
/* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data) { const float *rect_float; uchar *rect_byte; int profile_from = IB_PROFILE_LINEAR_RGB; /* verify we have a float buffer */ if (ibuf->rect_float == NULL || buffer == NULL) return; /* create byte rect if it didn't exist yet */ if (ibuf->rect == NULL) imb_addrectImBuf(ibuf); /* do conversion */ rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels; rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4; if (is_data) { /* exception for non-color data, just copy float */ IMB_buffer_float_from_float(buffer, rect_float, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, 0, w, h, w, ibuf->x); /* and do color space conversion to byte */ IMB_buffer_byte_from_float(rect_byte, rect_float, 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, true, w, h, ibuf->x, w); } else { IMB_buffer_float_from_float(buffer, rect_float, ibuf->channels, IB_PROFILE_SRGB, profile_from, true, w, h, w, ibuf->x); IMB_buffer_float_unpremultiply(buffer, w, h); /* XXX: need to convert to image buffer's rect space */ IMB_buffer_byte_from_float(rect_byte, buffer, 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, w, h, ibuf->x, w); } /* ensure user flag is reset */ ibuf->userflags &= ~IB_RECT_INVALID; }
static bool write_external_bake_pixels( const char *filepath, BakePixel pixel_array[], float *buffer, const int width, const int height, const int margin, ImageFormatData *im_format, const bool is_noncolor) { ImBuf *ibuf = NULL; bool ok = false; bool is_float; is_float = im_format->depth > 8; /* create a new ImBuf */ ibuf = IMB_allocImBuf(width, height, im_format->planes, (is_float ? IB_rectfloat : IB_rect)); if (!ibuf) return false; /* populates the ImBuf */ if (is_float) { IMB_buffer_float_from_float( ibuf->rect_float, buffer, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } else { if (!is_noncolor) { const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); const char *to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false); } IMB_buffer_byte_from_float( (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } /* margins */ if (margin > 0) { char *mask_buffer = NULL; const size_t num_pixels = (size_t)width * (size_t)height; mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); RE_bake_margin(ibuf, mask_buffer, margin); if (mask_buffer) MEM_freeN(mask_buffer); } if ((ok = BKE_imbuf_write(ibuf, filepath, im_format))) { #ifndef WIN32 chmod(filepath, S_IRUSR | S_IWUSR); #endif //printf("%s saving bake map: '%s'\n", __func__, filepath); } /* garbage collection */ IMB_freeImBuf(ibuf); return ok; }
static bool write_internal_bake_pixels( Image *image, BakePixel pixel_array[], float *buffer, const int width, const int height, const int margin, const bool is_clear, const bool is_noncolor) { ImBuf *ibuf; void *lock; bool is_float; char *mask_buffer = NULL; const size_t num_pixels = (size_t)width * (size_t)height; ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); if (!ibuf) return false; if (margin > 0 || !is_clear) { mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); } is_float = (ibuf->flags & IB_rectfloat); /* colormanagement conversions */ if (!is_noncolor) { const char *from_colorspace; const char *to_colorspace; from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); if (is_float) to_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); else to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); if (from_colorspace != to_colorspace) IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false); } /* populates the ImBuf */ if (is_clear) { if (is_float) { IMB_buffer_float_from_float( ibuf->rect_float, buffer, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } else { IMB_buffer_byte_from_float( (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } } else { if (is_float) { IMB_buffer_float_from_float_mask( ibuf->rect_float, buffer, ibuf->channels, ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer); } else { IMB_buffer_byte_from_float_mask( (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, false, ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer); } } /* margins */ if (margin > 0) RE_bake_margin(ibuf, mask_buffer, margin); ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_BITMAPDIRTY; if (ibuf->rect_float) ibuf->userflags |= IB_RECT_INVALID; /* force mipmap recalc */ if (ibuf->mipmap[0]) { ibuf->userflags |= IB_MIPMAP_INVALID; imb_freemipmapImBuf(ibuf); } BKE_image_release_ibuf(image, ibuf, NULL); if (mask_buffer) MEM_freeN(mask_buffer); return true; }
/* called inside thread! */ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect) { float *rectf = NULL; int ymin, ymax, xmin, xmax; int rymin, rxmin, predivide, profile_from; unsigned char *rectc; /* if renrect argument, we only refresh scanlines */ if (renrect) { /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */ if (rr->renlay == NULL || renrect->ymax >= rr->recty) return; /* xmin here is first subrect x coord, xmax defines subrect width */ xmin = renrect->xmin + rr->crop; xmax = renrect->xmax - xmin + rr->crop; if (xmax < 2) return; ymin = renrect->ymin + rr->crop; ymax = renrect->ymax - ymin + rr->crop; if (ymax < 2) return; renrect->ymin = renrect->ymax; } else { xmin = ymin = rr->crop; xmax = rr->rectx - 2 * rr->crop; ymax = rr->recty - 2 * rr->crop; } /* xmin ymin is in tile coords. transform to ibuf */ rxmin = rr->tilerect.xmin + xmin; if (rxmin >= ibuf->x) return; rymin = rr->tilerect.ymin + ymin; if (rymin >= ibuf->y) return; if (rxmin + xmax > ibuf->x) xmax = ibuf->x - rxmin; if (rymin + ymax > ibuf->y) ymax = ibuf->y - rymin; if (xmax < 1 || ymax < 1) return; /* find current float rect for display, first case is after composite... still weak */ if (rr->rectf) rectf = rr->rectf; else { if (rr->rect32) return; else { if (rr->renlay == NULL || rr->renlay->rectf == NULL) return; rectf = rr->renlay->rectf; } } if (rectf == NULL) return; if (ibuf->rect == NULL) imb_addrectImBuf(ibuf); rectf += 4 * (rr->rectx * ymin + xmin); rectc = (unsigned char *)(ibuf->rect + ibuf->x * rymin + rxmin); if (scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)) { profile_from = IB_PROFILE_LINEAR_RGB; predivide = (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); } else { profile_from = IB_PROFILE_SRGB; predivide = 0; } IMB_buffer_byte_from_float(rectc, rectf, 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide, xmax, ymax, ibuf->x, rr->rectx); }
/* uses ROUNDBOX button in block to get the rect */ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int first, rcti *rect, rcti *newrect) { Render *re; RenderResult rres; char name[32]; int do_gamma_correct = 0, do_predivide = 0; int offx = 0, newx = rect->xmax - rect->xmin, newy = rect->ymax - rect->ymin; if (id && GS(id->name) != ID_TE) { /* exception: don't color manage texture previews - show the raw values */ if (sce) { do_gamma_correct = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT; do_predivide = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE; } } if (!split || first) sprintf(name, "Preview %p", (void *)sa); else sprintf(name, "SecondPreview %p", (void *)sa); if (split) { if (first) { offx = 0; newx = newx / 2; } else { offx = newx / 2; newx = newx - newx / 2; } } re = RE_GetRender(name); RE_AcquireResultImage(re, &rres); if (rres.rectf) { if (ABS(rres.rectx - newx) < 2 && ABS(rres.recty - newy) < 2) { newrect->xmax = MAX2(newrect->xmax, rect->xmin + rres.rectx + offx); newrect->ymax = MAX2(newrect->ymax, rect->ymin + rres.recty); if (rres.rectx && rres.recty) { /* temporary conversion to byte for drawing */ float fx = rect->xmin + offx; float fy = rect->ymin; int profile_from = (do_gamma_correct) ? IB_PROFILE_LINEAR_RGB : IB_PROFILE_SRGB; int dither = 0; unsigned char *rect_byte; rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); IMB_buffer_byte_from_float(rect_byte, rres.rectf, 4, dither, IB_PROFILE_SRGB, profile_from, do_predivide, rres.rectx, rres.recty, rres.rectx, rres.rectx); glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte); MEM_freeN(rect_byte); } RE_ReleaseResultImage(re); return 1; } } RE_ReleaseResultImage(re); return 0; }