static void draw_zebra_float(ImBuf *src, ImBuf *ibuf, float perc) { float limit = perc / 100.0f; const float *p = src->rect_float; unsigned char *o = (unsigned char *) ibuf->rect; int x; int y; for (y = 0; y < ibuf->y; y++) { for (x = 0; x < ibuf->x; x++) { float r = *p++; float g = *p++; float b = *p++; float a = *p++; if (r >= limit || g >= limit || b >= limit) { if (((x + y) & 0x08) != 0) { r = -r; g = -g; b = -b; } } *o++ = FTOCHAR(r); *o++ = FTOCHAR(g); *o++ = FTOCHAR(b); *o++ = FTOCHAR(a); } } }
/* MultiresBake callback for normals' baking general idea: - find coord and normal of point with specified UV in hi-res mesh - multiply it by tangmat - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *UNUSED(bake_data), const int face_index, const int lvl, const float st[2], float tangmat[3][3], const int x, const int y) { MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; Image *ima= mtface[face_index].tpage; ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); float uv[2], *st0, *st1, *st2, *st3; int pixel= ibuf->x*y + x; float n[3], vec[3], tmp[3]= {0.5, 0.5, 0.5}; lores_dm->getFace(lores_dm, face_index, &mface); st0= mtface[face_index].uv[0]; st1= mtface[face_index].uv[1]; st2= mtface[face_index].uv[2]; if(mface.v4) { st3= mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], NULL, n); mul_v3_m3v3(vec, tangmat, n); normalize_v3(vec); mul_v3_fl(vec, 0.5); add_v3_v3(vec, tmp); if(ibuf->rect_float) { float *rrgbf= ibuf->rect_float + pixel*4; rrgbf[0]= vec[0]; rrgbf[1]= vec[1]; rrgbf[2]= vec[2]; rrgbf[3]= 1.0f; ibuf->userflags= IB_RECT_INVALID; } else { char *rrgb= (char*)ibuf->rect + pixel*4; rrgb[0]= FTOCHAR(vec[0]); rrgb[1]= FTOCHAR(vec[1]); rrgb[2]= FTOCHAR(vec[2]); rrgb[3]= 255; } }
/* same as above, byte version */ void curvemapping_evaluate_premulRGB(const CurveMapping *cumap, unsigned char vecout_byte[3], const unsigned char vecin_byte[3]) { float vecin[3], vecout[3]; vecin[0] = (float) vecin_byte[0] / 255.0f; vecin[1] = (float) vecin_byte[1] / 255.0f; vecin[2] = (float) vecin_byte[2] / 255.0f; curvemapping_evaluate_premulRGBF(cumap, vecout, vecin); vecout_byte[0] = FTOCHAR(vecout[0]); vecout_byte[1] = FTOCHAR(vecout[1]); vecout_byte[2] = FTOCHAR(vecout[2]); }
void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int UNUSED(w)) { int x, y; float *rf= rectf; unsigned char *rc= rectc; for(y=y1; y<y2; y++) { for(x=x1; x<x2; x++, rf+=4, rc+=4) { rc[0]= FTOCHAR(rf[0]); rc[1]= FTOCHAR(rf[1]); rc[2]= FTOCHAR(rf[2]); rc[3]= FTOCHAR(rf[3]); } } }
static void apply_heights_data(void *bake_data) { MHeightBakeData *height_data= (MHeightBakeData*)bake_data; ImBuf *ibuf= BKE_image_get_ibuf(height_data->ima, NULL); int x, y, i; float height, *heights= height_data->heights; float min= height_data->height_min, max= height_data->height_max; for(x= 0; x<ibuf->x; x++) { for(y =0; y<ibuf->y; y++) { i= ibuf->x*y + x; if(((char*)ibuf->userdata)[i] != FILTER_MASK_USED) continue; if(ibuf->rect_float) { float *rrgbf= ibuf->rect_float + i*4; if(max-min > 1e-5f) height= (heights[i]-min)/(max-min); else height= 0; rrgbf[0]=rrgbf[1]=rrgbf[2]= height; } else { char *rrgb= (char*)ibuf->rect + i*4; if(max-min > 1e-5f) height= (heights[i]-min)/(max-min); else height= 0; rrgb[0]=rrgb[1]=rrgb[2]= FTOCHAR(height); } } } ibuf->userflags= IB_RECT_INVALID; }
static void rna_Image_pixels_set(PointerRNA *ptr, const float *values) { Image *ima = ptr->id.data; ImBuf *ibuf; void *lock; int i, size; ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); if (ibuf) { size = ibuf->x * ibuf->y * ibuf->channels; if (ibuf->rect_float) { memcpy(ibuf->rect_float, values, sizeof(float) * size); } else { for (i = 0; i < size; i++) ((unsigned char *)ibuf->rect)[i] = FTOCHAR(values[i]); } ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID; } BKE_image_release_ibuf(ima, ibuf, lock); }
void TextMarker_color_set(PointerRNA *ptr, const float values[4]) { TextMarker *data= (TextMarker*)(ptr->data); int i; for(i=0; i<4; i++) { data->color[i]= FTOCHAR(values[i]); } }
MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di, float s, float t) { float dither_value = dither_random_value(s, t) * 0.005f * di->dither; b[0] = ftochar(dither_value + f[0]); b[1] = ftochar(dither_value + f[1]); b[2] = ftochar(dither_value + f[2]); b[3] = FTOCHAR(f[3]); }
/* Byte equivalent of IMB_colormanagement_get_luminance(). */ unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3]) { float rgbf[3]; float val; rgb_uchar_to_float(rgbf, rgb); val = dot_v3v3(imbuf_luma_coefficients, rgbf); return FTOCHAR(val); }
void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol) { int stride = mVData->getStride(0); if (stride == 0) stride = 3; switch (mVData->getType()) { case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: { COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues(); if (values->empty() || values->getCount() <= (v_index * stride + 2)) return; // xxx need to create an eror instead mloopcol->r = FTOCHAR((*values)[v_index * stride]); mloopcol->g = FTOCHAR((*values)[v_index * stride + 1]); mloopcol->b = FTOCHAR((*values)[v_index * stride + 2]); } break; case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: { COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues(); if (values->empty() || values->getCount() <= (v_index * stride + 2)) return; // xxx need to create an eror instead mloopcol->r = FTOCHAR((*values)[v_index * stride]); mloopcol->g = FTOCHAR((*values)[v_index * stride + 1]); mloopcol->b = FTOCHAR((*values)[v_index * stride + 2]); } break; default: fprintf(stderr, "VCOLDataWrapper.getvcol(): unknown data type\n"); } }
static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) { unsigned char *pixels, *p; const float *fp = fpixels; const int len = 4 * length; p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); for (int a = 0; a < len; a++, p++, fp++) *p = FTOCHAR((*fp)); return pixels; }
static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, int x, int y) { BakeShade *bs = handle; float disp; if (R.r.bake_flag & R_BAKE_NORMALIZE) { if (R.r.bake_maxdist) disp = (dist + R.r.bake_maxdist) / (R.r.bake_maxdist * 2); /* alter the range from [-bake_maxdist, bake_maxdist] to [0, 1]*/ else disp = dist; } else { disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/ } if (bs->displacement_buffer) { float *displacement = bs->displacement_buffer + (bs->rectx * y + x); *displacement = disp; bs->displacement_min = min_ff(bs->displacement_min, disp); bs->displacement_max = max_ff(bs->displacement_max, disp); } if (bs->rect_float && !bs->vcol) { float *col = bs->rect_float + 4 * (bs->rectx * y + x); col[0] = col[1] = col[2] = disp; col[3] = 1.0f; } else { /* Target is char (LDR). */ unsigned char col[4]; col[0] = col[1] = col[2] = FTOCHAR(disp); col[3] = 255; if (bs->vcol) { /* Vertex color baking. Vcol has no useful alpha channel (it exists * but is used only for vertex painting). */ bs->vcol->r = col[0]; bs->vcol->g = col[1]; bs->vcol->b = col[2]; } else { char *imcol = (char *)(bs->rect + bs->rectx * y + x); copy_v4_v4_char((char *)imcol, (char *)col); } } if (bs->rect_mask) { bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; } }
void *AntiAliasOperation::initializeTileData(rcti *rect) { if (this->m_buffer) { return this->m_buffer; } lockMutex(); if (this->m_buffer == NULL) { MemoryBuffer *tile = (MemoryBuffer *)this->m_valueReader->initializeTileData(rect); int size = tile->getHeight() * tile->getWidth(); float *input = tile->getBuffer(); char *valuebuffer = (char *)MEM_mallocN(sizeof(char) * size, __func__); for (int i = 0; i < size; i++) { float in = input[i * COM_NUMBER_OF_CHANNELS]; valuebuffer[i] = FTOCHAR(in); } antialias_tagbuf(tile->getWidth(), tile->getHeight(), valuebuffer); this->m_buffer = valuebuffer; } unlockMutex(); return this->m_buffer; }
static void rna_ImagePreview_pixels_float_set(PointerRNA *ptr, const float *values, enum eIconSizes size) { ID *id = ptr->id.data; PreviewImage *prv_img = (PreviewImage *)ptr->data; unsigned char *data = (unsigned char *)prv_img->rect[size]; const size_t len = prv_img->w[size] * prv_img->h[size] * 4; size_t i; BLI_assert(sizeof(unsigned int) == 4); if (id != NULL) { BLI_assert(prv_img == BKE_previewimg_id_ensure(id)); } for (i = 0; i < len; i++) { data[i] = FTOCHAR(values[i]); } prv_img->flag[size] |= PRV_USER_EDITED; }
void RE_bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max) { int i; float *current_displacement = displacement; char *current_mask = mask; float max_distance; max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max)); for (i = 0; i < ibuf->x * ibuf->y; i++) { if (*current_mask == FILTER_MASK_USED) { float normalized_displacement; if (max_distance > 1e-5f) normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2); else normalized_displacement = 0.5f; if (ibuf->rect_float) { /* currently baking happens to RGBA only */ float *fp = ibuf->rect_float + i * 4; fp[0] = fp[1] = fp[2] = normalized_displacement; fp[3] = 1.0f; } if (ibuf->rect) { unsigned char *cp = (unsigned char *) (ibuf->rect + i); cp[0] = cp[1] = cp[2] = FTOCHAR(normalized_displacement); cp[3] = 255; } } current_displacement++; current_mask++; } }
/* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance) { Scene *scene = painter->scene; Brush *brush = painter->brush; const char *display_device = scene->display_settings.display_device; struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; struct ImagePool *pool = painter->pool; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; int x, y, thread = 0; float brush_rgb[3]; /* allocate image buffer */ ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect); /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display); } else { brush_rgb[0] = 1.0f; brush_rgb[1] = 1.0f; brush_rgb[2] = 1.0f; } /* fill image buffer */ for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { /* sample texture and multiply with brush color */ float texco[3], rgba[4]; if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); } mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } if (use_float) { /* write to float pixel */ float *dstf = ibuf->rect_float + (y * size + x) * 4; mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */ dstf[3] = rgba[3]; } else { /* write to byte pixel */ unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4; rgb_float_to_uchar(dst, rgba); dst[3] = FTOCHAR(rgba[3]); } } } return ibuf; }
/* float to byte pixels, output 4-channel RGBA */ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, int channels_from, float dither, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from) { float tmp[4]; int x, y; DitherContext *di = NULL; float inv_width = 1.0f / width, inv_height = 1.0f / height; /* we need valid profiles */ BLI_assert(profile_to != IB_PROFILE_NONE); BLI_assert(profile_from != IB_PROFILE_NONE); if (dither) di = create_dither_context(dither); for (y = 0; y < height; y++) { float t = y * inv_height; if (channels_from == 1) { /* single channel input */ const float *from = rect_from + stride_from * y; uchar *to = rect_to + stride_to * y * 4; for (x = 0; x < width; x++, from++, to += 4) to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]); } else if (channels_from == 3) { /* RGB input */ const float *from = rect_from + stride_from * y * 3; uchar *to = rect_to + stride_to * y * 4; if (profile_to == profile_from) { /* no color space conversion */ for (x = 0; x < width; x++, from += 3, to += 4) { rgb_float_to_uchar(to, from); to[3] = 255; } } else if (profile_to == IB_PROFILE_SRGB) { /* convert from linear to sRGB */ for (x = 0; x < width; x++, from += 3, to += 4) { linearrgb_to_srgb_v3_v3(tmp, from); rgb_float_to_uchar(to, tmp); to[3] = 255; } } else if (profile_to == IB_PROFILE_LINEAR_RGB) { /* convert from sRGB to linear */ for (x = 0; x < width; x++, from += 3, to += 4) { srgb_to_linearrgb_v3_v3(tmp, from); rgb_float_to_uchar(to, tmp); to[3] = 255; } } } else if (channels_from == 4) { /* RGBA input */ const float *from = rect_from + stride_from * y * 4; uchar *to = rect_to + stride_to * y * 4; if (profile_to == profile_from) { float straight[4]; /* no color space conversion */ if (dither && predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { premul_to_straight_v4_v4(straight, from); float_to_byte_dither_v4(to, straight, di, (float) x * inv_width, t); } } else if (dither) { for (x = 0; x < width; x++, from += 4, to += 4) float_to_byte_dither_v4(to, from, di, (float) x * inv_width, t); } else if (predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { premul_to_straight_v4_v4(straight, from); rgba_float_to_uchar(to, straight); } } else { for (x = 0; x < width; x++, from += 4, to += 4) rgba_float_to_uchar(to, from); } } else if (profile_to == IB_PROFILE_SRGB) { /* convert from linear to sRGB */ unsigned short us[4]; float straight[4]; if (dither && predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { premul_to_straight_v4_v4(straight, from); linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_dither_v4(to, us, di, (float) x * inv_width, t); } } else if (dither) { for (x = 0; x < width; x++, from += 4, to += 4) { linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_dither_v4(to, us, di, (float) x * inv_width, t); } } else if (predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { premul_to_straight_v4_v4(straight, from); linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_v4(to, us); } } else { for (x = 0; x < width; x++, from += 4, to += 4) { linearrgb_to_srgb_ushort4(us, from); ushort_to_byte_v4(to, us); } } } else if (profile_to == IB_PROFILE_LINEAR_RGB) { /* convert from sRGB to linear */ if (dither && predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { srgb_to_linearrgb_predivide_v4(tmp, from); float_to_byte_dither_v4(to, tmp, di, (float) x * inv_width, t); } } else if (dither) { for (x = 0; x < width; x++, from += 4, to += 4) { srgb_to_linearrgb_v4(tmp, from); float_to_byte_dither_v4(to, tmp, di, (float) x * inv_width, t); } } else if (predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { srgb_to_linearrgb_predivide_v4(tmp, from); rgba_float_to_uchar(to, tmp); } } else { for (x = 0; x < width; x++, from += 4, to += 4) { srgb_to_linearrgb_v4(tmp, from); rgba_float_to_uchar(to, tmp); } } } } } if (dither) clear_dither_context(di); }
static void update_tface_color_layer(DerivedMesh *dm) { MTFace *tface = DM_get_tessface_data_layer(dm, CD_MTFACE); MFace *mface = dm->getTessFaceArray(dm); MCol *finalCol; int i, j; MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL); if (!mcol) mcol = dm->getTessFaceDataArray(dm, CD_MCOL); if (CustomData_has_layer(&dm->faceData, CD_TEXTURE_MCOL)) { finalCol = CustomData_get_layer(&dm->faceData, CD_TEXTURE_MCOL); } else { finalCol = MEM_mallocN(sizeof(MCol) * 4 * dm->getNumTessFaces(dm), "add_tface_color_layer"); CustomData_add_layer(&dm->faceData, CD_TEXTURE_MCOL, CD_ASSIGN, finalCol, dm->numTessFaceData); } for (i = 0; i < dm->getNumTessFaces(dm); i++) { Material *ma = give_current_material(Gtexdraw.ob, mface[i].mat_nr + 1); if (ma && (ma->game.flag & GEMAT_INVISIBLE)) { if (mcol) memcpy(&finalCol[i * 4], &mcol[i * 4], sizeof(MCol) * 4); else for (j = 0; j < 4; j++) { finalCol[i * 4 + j].b = 255; finalCol[i * 4 + j].g = 255; finalCol[i * 4 + j].r = 255; } } else if (tface && set_draw_settings_cached(0, tface, ma, Gtexdraw)) { for (j = 0; j < 4; j++) { finalCol[i * 4 + j].b = 255; finalCol[i * 4 + j].g = 0; finalCol[i * 4 + j].r = 255; } } else if (ma && (ma->shade_flag & MA_OBCOLOR)) { for (j = 0; j < 4; j++) { finalCol[i * 4 + j].b = Gtexdraw.obcol[0]; finalCol[i * 4 + j].g = Gtexdraw.obcol[1]; finalCol[i * 4 + j].r = Gtexdraw.obcol[2]; } } else if (!mcol) { if (tface) { for (j = 0; j < 4; j++) { finalCol[i * 4 + j].b = 255; finalCol[i * 4 + j].g = 255; finalCol[i * 4 + j].r = 255; } } else { float col[3]; if (ma) { if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r); else copy_v3_v3(col, &ma->r); for (j = 0; j < 4; j++) { finalCol[i * 4 + j].b = FTOCHAR(col[0]); finalCol[i * 4 + j].g = FTOCHAR(col[1]); finalCol[i * 4 + j].r = FTOCHAR(col[2]); } } else for (j = 0; j < 4; j++) { finalCol[i * 4 + j].b = 255; finalCol[i * 4 + j].g = 255; finalCol[i * 4 + j].r = 255; } } } else { for (j = 0; j < 4; j++) { finalCol[i * 4 + j].r = mcol[i * 4 + j].r; finalCol[i * 4 + j].g = mcol[i * 4 + j].g; finalCol[i * 4 + j].b = mcol[i * 4 + j].b; } } } }
/* called inside thread! */ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect) { float x1, y1, *rectf= NULL; int ymin, ymax, xmin, xmax; int rymin, rxmin, do_color_management; 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 composit... 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= (char *)(ibuf->rect + ibuf->x*rymin + rxmin); do_color_management = (scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)); /* XXX make nice consistent functions for this */ for(y1= 0; y1<ymax; y1++) { float *rf= rectf; float srgb[3]; char *rc= rectc; const float dither = ibuf->dither / 255.0f; /* XXX temp. because crop offset */ if(rectc >= (char *)(ibuf->rect)) { for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) { /* color management */ if(do_color_management) { srgb[0]= linearrgb_to_srgb(rf[0]); srgb[1]= linearrgb_to_srgb(rf[1]); srgb[2]= linearrgb_to_srgb(rf[2]); } else { copy_v3_v3(srgb, rf); } /* dither */ if(dither != 0.0f) { const float d = (BLI_frand()-0.5f)*dither; srgb[0] += d; srgb[1] += d; srgb[2] += d; } /* write */ rc[0]= FTOCHAR(srgb[0]); rc[1]= FTOCHAR(srgb[1]); rc[2]= FTOCHAR(srgb[2]); rc[3]= FTOCHAR(rf[3]); } } rectf += 4*rr->rectx; rectc += 4*ibuf->x; } }
/* float to byte pixels, output 4-channel RGBA */ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from, int channels_from, float dither, bool predivide, int width, int height, int stride_to, int stride_from, char *mask) { int x, y; DitherContext *di = NULL; float inv_width = 1.0f / width, inv_height = 1.0f / height; if (dither) di = create_dither_context(dither); for (y = 0; y < height; y++) { float t = y * inv_height; if (channels_from == 1) { /* single channel input */ const float *from = rect_from + stride_from * y; uchar *to = rect_to + stride_to * y * 4; for (x = 0; x < width; x++, from++, to += 4) if (*mask++ == FILTER_MASK_USED) to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]); } else if (channels_from == 3) { /* RGB input */ const float *from = rect_from + stride_from * y * 3; uchar *to = rect_to + stride_to * y * 4; for (x = 0; x < width; x++, from += 3, to += 4) { if (*mask++ == FILTER_MASK_USED) { rgb_float_to_uchar(to, from); to[3] = 255; } } } else if (channels_from == 4) { /* RGBA input */ const float *from = rect_from + stride_from * y * 4; uchar *to = rect_to + stride_to * y * 4; float straight[4]; if (dither && predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { if (*mask++ == FILTER_MASK_USED) { premul_to_straight_v4_v4(straight, from); float_to_byte_dither_v4(to, straight, di, (float) x * inv_width, t); } } } else if (dither) { for (x = 0; x < width; x++, from += 4, to += 4) if (*mask++ == FILTER_MASK_USED) float_to_byte_dither_v4(to, from, di, (float) x * inv_width, t); } else if (predivide) { for (x = 0; x < width; x++, from += 4, to += 4) { if (*mask++ == FILTER_MASK_USED) { premul_to_straight_v4_v4(straight, from); rgba_float_to_uchar(to, straight); } } } else { for (x = 0; x < width; x++, from += 4, to += 4) if (*mask++ == FILTER_MASK_USED) rgba_float_to_uchar(to, from); } } } if (dither) clear_dither_context(di); }
void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction) { ImBuf *ibuf; float xy[2], dist, rgba[4], *dstf; int x, y, rowbytes, xoff, yoff, imbflag; const int radius= brush_size(brush); char *dst, crgb[3]; const float alpha= brush_alpha(brush); float brush_rgb[3]; imbflag= (flt)? IB_rectfloat: IB_rect; xoff = -bufsize/2.0f + 0.5f; yoff = -bufsize/2.0f + 0.5f; rowbytes= bufsize*4; if (*outbuf) ibuf= *outbuf; else ibuf= IMB_allocImBuf(bufsize, bufsize, 32, imbflag); if (flt) { copy_v3_v3(brush_rgb, brush->rgb); if(use_color_correction){ srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb); } for (y=0; y < ibuf->y; y++) { dstf = ibuf->rect_float + y*rowbytes; for (x=0; x < ibuf->x; x++, dstf+=4) { xy[0] = x + xoff; xy[1] = y + yoff; if (texfall == 0) { dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); copy_v3_v3(dstf, brush_rgb); dstf[3]= alpha*brush_curve_strength_clamp(brush, dist, radius); } else if (texfall == 1) { brush_sample_tex(brush, xy, dstf, 0); } else { dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); brush_sample_tex(brush, xy, rgba, 0); mul_v3_v3v3(dstf, rgba, brush_rgb); dstf[3] = rgba[3]*alpha*brush_curve_strength_clamp(brush, dist, radius); } } } } else { crgb[0]= FTOCHAR(brush->rgb[0]); crgb[1]= FTOCHAR(brush->rgb[1]); crgb[2]= FTOCHAR(brush->rgb[2]); for (y=0; y < ibuf->y; y++) { dst = (char*)ibuf->rect + y*rowbytes; for (x=0; x < ibuf->x; x++, dst+=4) { xy[0] = x + xoff; xy[1] = y + yoff; if (texfall == 0) { dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); dst[0]= crgb[0]; dst[1]= crgb[1]; dst[2]= crgb[2]; dst[3]= FTOCHAR(alpha*brush_curve_strength(brush, dist, radius)); } else if (texfall == 1) { brush_sample_tex(brush, xy, rgba, 0); dst[0]= FTOCHAR(rgba[0]); dst[1]= FTOCHAR(rgba[1]); dst[2]= FTOCHAR(rgba[2]); dst[3]= FTOCHAR(rgba[3]); } else if (texfall == 2) { dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); brush_sample_tex(brush, xy, rgba, 0); dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]); dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]); dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]); dst[3] = FTOCHAR(rgba[3]*alpha*brush_curve_strength_clamp(brush, dist, radius)); } else { dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); brush_sample_tex(brush, xy, rgba, 0); dst[0]= crgb[0]; dst[1]= crgb[1]; dst[2]= crgb[2]; dst[3] = FTOCHAR(rgba[3]*alpha*brush_curve_strength_clamp(brush, dist, radius)); } } } } *outbuf= ibuf; }
static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang) { BakeShade *bs = handle; ShadeSample *ssamp = &bs->ssamp; ShadeResult shr; VlakRen *vlr = shi->vlr; shade_input_init_material(shi); if (bs->type == RE_BAKE_AO) { ambient_occlusion(shi); if (R.r.bake_flag & R_BAKE_NORMALIZE) { copy_v3_v3(shr.combined, shi->ao); } else { zero_v3(shr.combined); environment_lighting_apply(shi, &shr); } } else { if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ shi->r = shi->g = shi->b = 1.0f; shade_input_set_shade_texco(shi); /* only do AO for a full bake (and obviously AO bakes) * AO for light bakes is a leftover and might not be needed */ if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) shade_samples_do_AO(ssamp); if (shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, &shr); shi->mat = vlr->mat; /* shi->mat is being set in nodetree */ } else shade_material_loop(shi, &shr); if (bs->type == RE_BAKE_NORMALS) { float nor[3]; copy_v3_v3(nor, shi->vn); if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) { /* pass */ } else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { float mat[3][3], imat[3][3]; /* bitangent */ if (tvn && ttang) { copy_v3_v3(mat[0], ttang); cross_v3_v3v3(mat[1], tvn, ttang); mul_v3_fl(mat[1], ttang[3]); copy_v3_v3(mat[2], tvn); } else { copy_v3_v3(mat[0], shi->nmaptang); cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang); mul_v3_fl(mat[1], shi->nmaptang[3]); copy_v3_v3(mat[2], shi->nmapnorm); } invert_m3_m3(imat, mat); mul_m3_v3(imat, nor); } else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT) mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */ else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD) mul_mat3_m4_v3(R.viewinv, nor); normalize_v3(nor); /* in case object has scaling */ /* The invert of the red channel is to make * the normal map compliant with the outside world. * It needs to be done because in Blender * the normal used in the renderer points inward. It is generated * this way in calc_vertexnormals(). Should this ever change * this negate must be removed. */ shr.combined[0] = (-nor[0]) / 2.0f + 0.5f; shr.combined[1] = nor[1] / 2.0f + 0.5f; shr.combined[2] = nor[2] / 2.0f + 0.5f; } else if (bs->type == RE_BAKE_TEXTURE) { copy_v3_v3(shr.combined, &shi->r); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SHADOW) { copy_v3_v3(shr.combined, shr.shad); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SPEC_COLOR) { copy_v3_v3(shr.combined, &shi->specr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_SPEC_INTENSITY) { copy_v3_fl(shr.combined, shi->spec); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_COLOR) { copy_v3_v3(shr.combined, &shi->mirr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_INTENSITY) { copy_v3_fl(shr.combined, shi->ray_mirror); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_ALPHA) { copy_v3_fl(shr.combined, shi->alpha); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_EMIT) { copy_v3_fl(shr.combined, shi->emit); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_VERTEX_COLORS) { copy_v3_v3(shr.combined, shi->vcol); shr.alpha = shi->vcol[3]; } } if (bs->rect_float && !bs->vcol) { float *col = bs->rect_float + 4 * (bs->rectx * y + x); copy_v3_v3(col, shr.combined); if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) { col[3] = shr.alpha; } else { col[3] = 1.0; } } else { /* Target is char (LDR). */ unsigned char col[4]; if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { float rgb[3]; copy_v3_v3(rgb, shr.combined); if (R.scene_color_manage) { /* Vertex colors have no way to specify color space, so they * default to sRGB. */ if (!bs->vcol) IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace); else linearrgb_to_srgb_v3_v3(rgb, rgb); } rgb_float_to_uchar(col, rgb); } else { rgb_float_to_uchar(col, shr.combined); } if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { col[3] = FTOCHAR(shr.alpha); } else { col[3] = 255; } if (bs->vcol) { /* Vertex color baking. Vcol has no useful alpha channel (it exists * but is used only for vertex painting). */ bs->vcol->r = col[0]; bs->vcol->g = col[1]; bs->vcol->b = col[2]; } else { unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); copy_v4_v4_char((char *)imcol, (char *)col); } } if (bs->rect_mask) { bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; } if (bs->do_update) { *bs->do_update = true; } }
/* returns user-scale */ float RE_bake_make_derivative(ImBuf *ibuf, float *heights_buffer, const char *mask, const float height_min, const float height_max, const float fmult) { const float delta_height = height_max - height_min; const float denom = delta_height > 0.0f ? (8 * delta_height) : 1.0f; bool auto_range_fit = fmult <= 0.0f; float max_num_deriv = -1.0f; int x, y, index; /* Need a single margin to calculate good derivatives. */ add_single_heights_margin(ibuf, mask, heights_buffer); if (auto_range_fit) { /* If automatic range fitting is enabled. */ for (y = 0; y < ibuf->y; y++) { const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1); const int Yc = y; const int Yd = y == 0 ? 0 : (y - 1); for (x = 0; x < ibuf->x; x++) { const int Xl = x == 0 ? 0 : (x - 1); const int Xc = x; const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1); const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl]; const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl]; const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl]; const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl]; const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc]; const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr]; /* This corresponds to using the sobel kernel on the heights buffer * to obtain the derivative multiplied by 8. */ const float deriv_x = Hu + 2 * Hcy + Hd; const float deriv_y = Hr + 2 * Hcx + Hl; /* early out */ index = ibuf->x * y + x; if (mask[index] != FILTER_MASK_USED) { continue; } /* Widen bound. */ if (fabsf(deriv_x) > max_num_deriv) { max_num_deriv = fabsf(deriv_x); } if (fabsf(deriv_y) > max_num_deriv) { max_num_deriv = fabsf(deriv_y); } } } } /* Output derivatives. */ auto_range_fit &= (max_num_deriv > 0); for (y = 0; y < ibuf->y; y++) { const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1); const int Yc = y; const int Yd = y == 0 ? 0 : (y - 1); for (x = 0; x < ibuf->x; x++) { const int Xl = x == 0 ? 0 : (x - 1); const int Xc = x; const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1); const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl]; const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl]; const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl]; const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl]; const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc]; const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr]; /* This corresponds to using the sobel kernel on the heights buffer * to obtain the derivative multiplied by 8. */ float deriv_x = Hu + 2 * Hcy + Hd; float deriv_y = Hr + 2 * Hcx + Hl; /* Early out. */ index = ibuf->x * y + x; if (mask[index] != FILTER_MASK_USED) { continue; } if (auto_range_fit) { deriv_x /= max_num_deriv; deriv_y /= max_num_deriv; } else { deriv_x *= (fmult / denom); deriv_y *= (fmult / denom); } deriv_x = deriv_x * 0.5f + 0.5f; deriv_y = deriv_y * 0.5f + 0.5f; /* Clamp. */ CLAMP(deriv_x, 0.0f, 1.0f); CLAMP(deriv_y, 0.0f, 1.0f); /* Write out derivatives. */ if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + index * 4; rrgbf[0] = deriv_x; rrgbf[1] = deriv_y; rrgbf[2] = 0.0f; rrgbf[3] = 1.0f; } else { char *rrgb = (char *)ibuf->rect + index * 4; rrgb[0] = FTOCHAR(deriv_x); rrgb[1] = FTOCHAR(deriv_y); rrgb[2] = 0; rrgb[3] = 255; } } } /* Eeturn user-scale (for rendering). */ return auto_range_fit ? (max_num_deriv / denom) : (fmult > 0.0f ? (1.0f / fmult) : 0.0f); }
/* TODO, use define for 'texfall' arg */ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction) { ImBuf *ibuf; float xy[2], rgba[4], *dstf; int x, y, rowbytes, xoff, yoff, imbflag; const int radius = BKE_brush_size_get(scene, brush); unsigned char *dst, crgb[3]; const float alpha = BKE_brush_alpha_get(scene, brush); float brush_rgb[3]; imbflag = (flt) ? IB_rectfloat : IB_rect; xoff = -bufsize / 2.0f + 0.5f; yoff = -bufsize / 2.0f + 0.5f; rowbytes = bufsize * 4; if (*outbuf) ibuf = *outbuf; else ibuf = IMB_allocImBuf(bufsize, bufsize, 32, imbflag); if (flt) { copy_v3_v3(brush_rgb, brush->rgb); if (use_color_correction) { srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb); } for (y = 0; y < ibuf->y; y++) { dstf = ibuf->rect_float + y * rowbytes; for (x = 0; x < ibuf->x; x++, dstf += 4) { xy[0] = x + xoff; xy[1] = y + yoff; if (texfall == 0) { copy_v3_v3(dstf, brush_rgb); dstf[3] = alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); } else if (texfall == 1) { BKE_brush_sample_tex(scene, brush, xy, dstf, 0); } else { BKE_brush_sample_tex(scene, brush, xy, rgba, 0); mul_v3_v3v3(dstf, rgba, brush_rgb); dstf[3] = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); } } } } else { float alpha_f; /* final float alpha to convert to char */ rgb_float_to_uchar(crgb, brush->rgb); for (y = 0; y < ibuf->y; y++) { dst = (unsigned char *)ibuf->rect + y * rowbytes; for (x = 0; x < ibuf->x; x++, dst += 4) { xy[0] = x + xoff; xy[1] = y + yoff; if (texfall == 0) { alpha_f = alpha * BKE_brush_curve_strength(brush, len_v2(xy), radius); dst[0] = crgb[0]; dst[1] = crgb[1]; dst[2] = crgb[2]; dst[3] = FTOCHAR(alpha_f); } else if (texfall == 1) { BKE_brush_sample_tex(scene, brush, xy, rgba, 0); rgba_float_to_uchar(dst, rgba); } else if (texfall == 2) { BKE_brush_sample_tex(scene, brush, xy, rgba, 0); mul_v3_v3(rgba, brush->rgb); alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); rgb_float_to_uchar(dst, rgba); dst[3] = FTOCHAR(alpha_f); } else { BKE_brush_sample_tex(scene, brush, xy, rgba, 0); alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); dst[0] = crgb[0]; dst[1] = crgb[1]; dst[2] = crgb[2]; dst[3] = FTOCHAR(alpha_f); } } } } *outbuf = ibuf; }
/* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) { Scene *scene = painter->scene; Brush *brush = painter->brush; rctf tex_mapping = painter->tex_mapping; rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; bool is_maskbrush = painter->cache.is_maskbrush; float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush); int radius = BKE_brush_size_get(scene, brush); int xoff = -size * 0.5f + 0.5f; int yoff = -size * 0.5f + 0.5f; int x, y, thread = 0; float brush_rgb[3]; /* allocate image buffer */ ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect); /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { copy_v3_v3(brush_rgb, brush->rgb); if (use_color_correction) srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb); } else { brush_rgb[0] = 1.0f; brush_rgb[1] = 1.0f; brush_rgb[2] = 1.0f; } /* fill image buffer */ for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { /* sample texture and multiply with brush color */ float texco[3], rgba[4]; if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { linearrgb_to_srgb_v3_v3(rgba, rgba); } mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } if (is_maskbrush) { brush_imbuf_tex_co(&mask_mapping, x, y, texco); rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); } /* when not using masking, multiply in falloff and strength */ if (!use_masking) { float xy[2] = {x + xoff, y + yoff}; float len = len_v2(xy); rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius); } if (use_float) { /* write to float pixel */ float *dstf = ibuf->rect_float + (y * size + x) * 4; mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */ dstf[3] = rgba[3]; } else { /* write to byte pixel */ unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4; rgb_float_to_uchar(dst, rgba); dst[3] = FTOCHAR(rgba[3]); } } } return ibuf; }
static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, int x, int y, int w, int h, int xt, int yt, float *pos) { Brush *brush= painter->brush; ImBuf *ibuf, *maskibuf, *texibuf; float *bf, *mf, *tf, *otf=NULL, xoff, yoff, xy[2], rgba[4]; char *b, *m, *t, *ot= NULL; int dotexold, origx= x, origy= y; const int radius= brush_size(brush); xoff = -radius + 0.5f; yoff = -radius + 0.5f; xoff += (int)pos[0] - (int)painter->startpaintpos[0]; yoff += (int)pos[1] - (int)painter->startpaintpos[1]; ibuf = painter->cache.ibuf; texibuf = painter->cache.texibuf; maskibuf = painter->cache.maskibuf; dotexold = (oldtexibuf != NULL); /* not sure if it's actually needed or it's a mistake in coords/sizes calculation in brush_painter_fixed_tex_partial_update(), but without this limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */ w = MIN2(w, ibuf->x); h = MIN2(h, ibuf->y); if (painter->cache.flt) { for (; y < h; y++) { bf = ibuf->rect_float + (y*ibuf->x + origx)*4; tf = texibuf->rect_float + (y*texibuf->x + origx)*4; mf = maskibuf->rect_float + (y*maskibuf->x + origx)*4; if (dotexold) otf = oldtexibuf->rect_float + ((y - origy + yt)*oldtexibuf->x + xt)*4; for (x=origx; x < w; x++, bf+=4, mf+=4, tf+=4) { if (dotexold) { copy_v3_v3(tf, otf); tf[3] = otf[3]; otf += 4; } else { xy[0] = x + xoff; xy[1] = y + yoff; brush_sample_tex(brush, xy, tf, 0); } bf[0] = tf[0]*mf[0]; bf[1] = tf[1]*mf[1]; bf[2] = tf[2]*mf[2]; bf[3] = tf[3]*mf[3]; } } } else { for (; y < h; y++) { b = (char*)ibuf->rect + (y*ibuf->x + origx)*4; t = (char*)texibuf->rect + (y*texibuf->x + origx)*4; m = (char*)maskibuf->rect + (y*maskibuf->x + origx)*4; if (dotexold) ot = (char*)oldtexibuf->rect + ((y - origy + yt)*oldtexibuf->x + xt)*4; for (x=origx; x < w; x++, b+=4, m+=4, t+=4) { if (dotexold) { t[0] = ot[0]; t[1] = ot[1]; t[2] = ot[2]; t[3] = ot[3]; ot += 4; } else { xy[0] = x + xoff; xy[1] = y + yoff; brush_sample_tex(brush, xy, rgba, 0); t[0]= FTOCHAR(rgba[0]); t[1]= FTOCHAR(rgba[1]); t[2]= FTOCHAR(rgba[2]); t[3]= FTOCHAR(rgba[3]); } b[0] = t[0]*m[0]/255; b[1] = t[1]*m[1]/255; b[2] = t[2]*m[2]/255; b[3] = t[3]*m[3]/255; } } } }
static void brightcontrast_apply_threaded(int width, int height, unsigned char *rect, float *rect_float, unsigned char *mask_rect, float *mask_rect_float, void *data_v) { BrightContrastThreadData *data = (BrightContrastThreadData *) data_v; int x, y; float i; int c; float a, b, v; float brightness = data->bright / 100.0f; float contrast = data->contrast; float delta = contrast / 200.0f; a = 1.0f - delta * 2.0f; /* * The algorithm is by Werner D. Streidt * (http://visca.com/ffactory/archives/5-99/msg00021.html) * Extracted of OpenCV demhist.c */ if (contrast > 0) { a = 1.0f / a; b = a * (brightness - delta); } else { delta *= -1; b = a * (brightness + delta); } for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { int pixel_index = (y * width + x) * 4; if (rect) { unsigned char *pixel = rect + pixel_index; for (c = 0; c < 3; c++) { i = (float) pixel[c] / 255.0f; v = a * i + b; if (mask_rect) { unsigned char *m = mask_rect + pixel_index; float t = (float) m[c] / 255.0f; v = (float) pixel[c] / 255.0f * (1.0f - t) + v * t; } pixel[c] = FTOCHAR(v); } } else if (rect_float) { float *pixel = rect_float + pixel_index; for (c = 0; c < 3; c++) { i = pixel[c]; v = a * i + b; if (mask_rect_float) { const float *m = mask_rect_float + pixel_index; pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c]; } else pixel[c] = v; } } } } }
/* MultiresBake callback for heights baking * general idea: * - find coord of point with specified UV in hi-res mesh (let's call it p1) * - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res * mesh to make texture smoother) let's call this point p0 and n. * - height wound be dot(n, p1-p0) */ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data_v, void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; MHeightBakeData *height_data = (MHeightBakeData *)bake_data; MultiresBakeThread *thread_data = (MultiresBakeThread *) thread_data_v; float uv[2], *st0, *st1, *st2, *st3; int pixel = ibuf->x * y + x; float vec[3], p0[3], p1[3], n[3], len; lores_dm->getTessFace(lores_dm, face_index, &mface); st0 = mtface[face_index].uv[0]; st1 = mtface[face_index].uv[1]; st2 = mtface[face_index].uv[2]; if (mface.v4) { st3 = mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, lvl, face_index, uv[0], uv[1], p1, NULL); if (height_data->ssdm) { get_ccgdm_data(lores_dm, height_data->ssdm, height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, 0, face_index, uv[0], uv[1], p0, n); } else { lores_dm->getTessFace(lores_dm, face_index, &mface); if (mface.v4) { interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } else { interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n); } } sub_v3_v3v3(vec, p1, p0); len = dot_v3v3(n, vec); height_data->heights[pixel] = len; thread_data->height_min = min_ff(thread_data->height_min, len); thread_data->height_max = max_ff(thread_data->height_max, len); if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + pixel * 4; rrgbf[0] = rrgbf[1] = rrgbf[2] = len; rrgbf[3] = 1.0f; } else { char *rrgb = (char *)ibuf->rect + pixel * 4; rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(len); rrgb[3] = 255; } }
static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MAOBakeData *ao_data = (MAOBakeData *) bake_data; MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; int i, k, perm_offs; float pos[3], nrm[3]; float cen[3]; float axisX[3], axisY[3], axisZ[3]; float shadow = 0; float value; int pixel = ibuf->x * y + x; float uv[2], *st0, *st1, *st2, *st3; lores_dm->getTessFace(lores_dm, face_index, &mface); st0 = mtface[face_index].uv[0]; st1 = mtface[face_index].uv[1]; st2 = mtface[face_index].uv[2]; if (mface.v4) { st3 = mtface[face_index].uv[3]; resolve_quad_uv(uv, st, st0, st1, st2, st3); } else resolve_tri_uv(uv, st, st0, st1, st2); CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, ao_data->orig_index_mf_to_mpoly, ao_data->orig_index_mp_to_orig, lvl, face_index, uv[0], uv[1], pos, nrm); /* offset ray origin by user bias along normal */ for (i = 0; i < 3; i++) cen[i] = pos[i] + ao_data->bias * nrm[i]; /* build tangent frame */ for (i = 0; i < 3; i++) axisZ[i] = nrm[i]; build_coordinate_frame(axisX, axisY, axisZ); /* static noise */ perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1); /* importance sample shadow rays (cosine weighted) */ for (i = 0; i < ao_data->number_of_rays; i++) { int hit_something; /* use N-Rooks to distribute our N ray samples across * a multi-dimensional domain (2D) */ const unsigned short I = ao_data->permutation_table_1[(i + perm_offs) % ao_data->number_of_rays]; const unsigned short J = ao_data->permutation_table_2[i]; const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS); const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS); const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays; const float Theta = (float)(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays); /* this gives results identical to the so-called cosine * weighted distribution relative to the north pole. */ float SiPhi = sqrt(SiSqPhi); float CoPhi = SiSqPhi < 1.0f ? sqrtf(1.0f - SiSqPhi) : 0; float CoThe = cos(Theta); float SiThe = sin(Theta); const float dx = CoThe * CoPhi; const float dy = SiThe * CoPhi; const float dz = SiPhi; /* transform ray direction out of tangent frame */ float dv[3]; for (k = 0; k < 3; k++) dv[k] = axisX[k] * dx + axisY[k] * dy + axisZ[k] * dz; hit_something = trace_ao_ray(ao_data, cen, dv); if (hit_something != 0) shadow += 1; } value = 1.0f - (shadow / ao_data->number_of_rays); if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + pixel * 4; rrgbf[0] = rrgbf[1] = rrgbf[2] = value; rrgbf[3] = 1.0f; } else { unsigned char *rrgb = (unsigned char *) ibuf->rect + pixel * 4; rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(value); rrgb[3] = 255; } }
void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2) { int i, j; float a; /* alpha */ float ai; /* alpha inverted */ float aich; /* alpha, inverted, ai/255.0 - Convert char to float at the same time */ if ((!rect && !rectf) || (!col) || col[3]==0.0f) return; /* sanity checks for coords */ CLAMP(x1, 0, width); CLAMP(x2, 0, width); CLAMP(y1, 0, height); CLAMP(y2, 0, height); if (x1>x2) SWAP(int,x1,x2); if (y1>y2) SWAP(int,y1,y2); if (x1==x2 || y1==y2) return; a = col[3]; ai = 1-a; aich = ai/255.0f; if (rect) { unsigned char *pixel; unsigned char chr=0, chg=0, chb=0; float fr=0, fg=0, fb=0; if (a == 1.0f) { chr = FTOCHAR(col[0]); chg = FTOCHAR(col[1]); chb = FTOCHAR(col[2]); } else { fr = col[0]*a; fg = col[1]*a; fb = col[2]*a; } for (j = 0; j < y2-y1; j++) { for (i = 0; i < x2-x1; i++) { pixel = rect + 4 * (((y1 + j) * width) + (x1 + i)); if (pixel >= rect && pixel < rect+ (4 * (width * height))) { if (a == 1.0f) { pixel[0] = chr; pixel[1] = chg; pixel[2] = chb; } else { pixel[0] = (char)((fr + ((float)pixel[0]*aich))*255.0f); pixel[1] = (char)((fg + ((float)pixel[1]*aich))*255.0f); pixel[2] = (char)((fb + ((float)pixel[2]*aich))*255.0f); } } } } } if (rectf) { float *pixel; for (j = 0; j < y2-y1; j++) { for (i = 0; i < x2-x1; i++) { pixel = rectf + 4 * (((y1 + j) * width) + (x1 + i)); if (a == 1.0f) { pixel[0] = col[0]; pixel[1] = col[1]; pixel[2] = col[2]; } else { pixel[0] = (col[0]*a) + (pixel[0]*ai); pixel[1] = (col[1]*a) + (pixel[1]*ai); pixel[2] = (col[2]*a) + (pixel[2]*ai); } } } } }