void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode) { switch (mode) { case IMB_BLEND_MIX: blend_color_mix_float(dst, src1, src2); break; case IMB_BLEND_ADD: blend_color_add_float(dst, src1, src2); break; case IMB_BLEND_SUB: blend_color_sub_float(dst, src1, src2); break; case IMB_BLEND_MUL: blend_color_mul_float(dst, src1, src2); break; case IMB_BLEND_LIGHTEN: blend_color_lighten_float(dst, src1, src2); break; case IMB_BLEND_DARKEN: blend_color_darken_float(dst, src1, src2); break; case IMB_BLEND_ERASE_ALPHA: blend_color_erase_alpha_float(dst, src1, src2); break; case IMB_BLEND_ADD_ALPHA: blend_color_add_alpha_float(dst, src1, src2); break; default: dst[0] = src1[0]; dst[1] = src1[1]; dst[2] = src1[2]; dst[3] = src1[3]; break; } }
void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode) { switch (mode) { case IMB_BLEND_MIX: blend_color_mix_float(dst, src1, src2); break; case IMB_BLEND_ADD: blend_color_add_float(dst, src1, src2); break; case IMB_BLEND_SUB: blend_color_sub_float(dst, src1, src2); break; case IMB_BLEND_MUL: blend_color_mul_float(dst, src1, src2); break; case IMB_BLEND_LIGHTEN: blend_color_lighten_float(dst, src1, src2); break; case IMB_BLEND_DARKEN: blend_color_darken_float(dst, src1, src2); break; case IMB_BLEND_ERASE_ALPHA: blend_color_erase_alpha_float(dst, src1, src2); break; case IMB_BLEND_ADD_ALPHA: blend_color_add_alpha_float(dst, src1, src2); break; case IMB_BLEND_OVERLAY: blend_color_overlay_float(dst, src1, src2); break; case IMB_BLEND_HARDLIGHT: blend_color_hardlight_float(dst, src1, src2); break; case IMB_BLEND_COLORBURN: blend_color_burn_float(dst, src1, src2); break; case IMB_BLEND_LINEARBURN: blend_color_linearburn_float(dst, src1, src2); break; case IMB_BLEND_COLORDODGE: blend_color_dodge_float(dst, src1, src2); break; case IMB_BLEND_SCREEN: blend_color_screen_float(dst, src1, src2); break; case IMB_BLEND_SOFTLIGHT: blend_color_softlight_float(dst, src1, src2); break; case IMB_BLEND_PINLIGHT: blend_color_pinlight_float(dst, src1, src2); break; case IMB_BLEND_LINEARLIGHT: blend_color_linearlight_float(dst, src1, src2); break; case IMB_BLEND_VIVIDLIGHT: blend_color_vividlight_float(dst, src1, src2); break; case IMB_BLEND_DIFFERENCE: blend_color_difference_float(dst, src1, src2); break; case IMB_BLEND_EXCLUSION: blend_color_exclusion_float(dst, src1, src2); break; case IMB_BLEND_COLOR: blend_color_color_float(dst, src1, src2); break; case IMB_BLEND_HUE: blend_color_hue_float(dst, src1, src2); break; case IMB_BLEND_SATURATION: blend_color_saturation_float(dst, src1, src2); break; case IMB_BLEND_LUMINOSITY: blend_color_luminosity_float(dst, src1, src2); break; default: dst[0] = src1[0]; dst[1] = src1[1]; dst[2] = src1[2]; dst[3] = src1[3]; break; } }
static void blend_color_darken_float(float *cp, float *cp1, float *cp2, float fac) { /* See if were darker, if so mix, else dont do anything. if the pafloat col is brighter then the original, then ignore */ if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) { cp[0]= cp1[0]; cp[1]= cp1[1]; cp[2]= cp1[2]; } else blend_color_mix_float(cp, cp1, cp2, fac); }
void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode) { if (fac==0) { dst[0]= src1[0]; dst[1]= src1[1]; dst[2]= src1[2]; dst[3]= src1[3]; return; } switch (mode) { case IMB_BLEND_MIX: blend_color_mix_float(dst, src1, src2, fac); break; case IMB_BLEND_ADD: blend_color_add_float(dst, src1, src2, fac); break; case IMB_BLEND_SUB: blend_color_sub_float(dst, src1, src2, fac); break; case IMB_BLEND_MUL: blend_color_mul_float(dst, src1, src2, fac); break; case IMB_BLEND_LIGHTEN: blend_color_lighten_float(dst, src1, src2, fac); break; case IMB_BLEND_DARKEN: blend_color_darken_float(dst, src1, src2, fac); break; default: dst[0]= src1[0]; dst[1]= src1[1]; dst[2]= src1[2]; } if (mode == IMB_BLEND_ERASE_ALPHA) { dst[3]= (src1[3] - fac*src2[3]); if (dst[3] < 0.0f) dst[3] = 0.0f; } else { /* this does ADD_ALPHA also */ dst[3]= (src1[3] + fac*src2[3]); if (dst[3] > 1.0f) dst[3] = 1.0f; } }
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) { Scene *scene = oglrender->scene; ARegion *ar = oglrender->ar; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; Object *camera = NULL; ImBuf *ibuf; float winmat[4][4]; int sizex = oglrender->sizex; int sizey = oglrender->sizey; const short view_context = (v3d != NULL); bool draw_bgpic = true; bool draw_sky = (scene->r.alphamode == R_ADDSKY); unsigned char *rect = NULL; const char *viewname = RE_GetActiveRenderView(oglrender->re); if (oglrender->is_sequencer) { SeqRenderData context; SpaceSeq *sseq = oglrender->sseq; int chanshown = sseq ? sseq->chanshown : 0; struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL; BKE_sequencer_new_render_data( oglrender->bmain->eval_ctx, oglrender->bmain, scene, oglrender->sizex, oglrender->sizey, 100.0f, &context); context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); if (ibuf) { float *rectf; ImBuf *linear_ibuf; BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y)); linear_ibuf = IMB_dupImBuf(ibuf); IMB_freeImBuf(ibuf); if (linear_ibuf->rect_float == NULL) { /* internally sequencer working in display space and stores both bytes and float buffers in that space. * It is possible that byte->float onversion didn't happen in sequencer (e.g. when adding image sequence/movie * into sequencer) there'll be only byte buffer. Create float buffer from existing byte buffer, making it linear */ IMB_float_from_rect(linear_ibuf); } else { /* ensure float buffer is in linear space, not in display space */ BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf); } rectf = RE_RenderViewGetRectf(rr, oglrender->view_id); memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey); IMB_freeImBuf(linear_ibuf); } if (gpd) { int i; unsigned char *gp_rect; GPU_offscreen_bind(oglrender->ofs, true); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); wmOrtho2(0, sizex, 0, sizey); glTranslatef(sizex / 2, sizey / 2, 0.0f); G.f |= G_RENDER_OGL; ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); G.f &= ~G_RENDER_OGL; gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect); for (i = 0; i < sizex * sizey * 4; i += 4) { float col_src[4]; rgba_uchar_to_float(col_src, &gp_rect[i]); blend_color_mix_float(&rr->rectf[i], &rr->rectf[i], col_src); } GPU_offscreen_unbind(oglrender->ofs, true); MEM_freeN(gp_rect); } } else if (view_context) { bool is_persp; /* full copy */ GPUFXSettings fx_settings = v3d->fx_settings; ED_view3d_draw_offscreen_init(scene, v3d); GPU_offscreen_bind(oglrender->ofs, true); /* bind */ /* render 3d view */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { /*int is_ortho = scene->r.mode & R_ORTHO;*/ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname); RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat); if (camera->type == OB_CAMERA) { Camera *cam = camera->data; is_persp = cam->type == CAM_PERSP; } else is_persp = true; BKE_camera_to_gpu_dof(camera, &fx_settings); } else { rctf viewplane; float clipsta, clipend; bool is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); is_persp = !is_ortho; } rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); if ((scene->r.mode & R_OSA) == 0) { ED_view3d_draw_offscreen( scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky, is_persp, oglrender->ofs, oglrender->fx, &fx_settings, viewname); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); } else { /* simple accumulation, less hassle then FSAA FBO's */ static float jit_ofs[32][2]; float winmat_jitter[4][4]; int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int) * 4, "accum1"); int i, j; BLI_jitter_init(jit_ofs, scene->r.osa); /* first sample buffer, also initializes 'rv3d->persmat' */ ED_view3d_draw_offscreen( scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky, is_persp, oglrender->ofs, oglrender->fx, &fx_settings, viewname); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); for (i = 0; i < sizex * sizey * 4; i++) accum_buffer[i] = rect[i]; /* skip the first sample */ for (j = 1; j < scene->r.osa; j++) { copy_m4_m4(winmat_jitter, winmat); window_translate_m4(winmat_jitter, rv3d->persmat, (jit_ofs[j][0] * 2.0f) / sizex, (jit_ofs[j][1] * 2.0f) / sizey); ED_view3d_draw_offscreen( scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_bgpic, draw_sky, is_persp, oglrender->ofs, oglrender->fx, &fx_settings, viewname); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); for (i = 0; i < sizex * sizey * 4; i++) accum_buffer[i] += rect[i]; } for (i = 0; i < sizex * sizey * 4; i++) rect[i] = accum_buffer[i] / scene->r.osa; MEM_freeN(accum_buffer); } GPU_offscreen_unbind(oglrender->ofs, true); /* unbind */ } else { /* shouldnt suddenly give errors mid-render but possible */ char err_out[256] = "unknown"; ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey, IB_rect, OB_SOLID, false, true, true, (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out); camera = scene->camera; if (ibuf_view) { /* steal rect reference from ibuf */ rect = (unsigned char *)ibuf_view->rect; ibuf_view->mall &= ~IB_rect; IMB_freeImBuf(ibuf_view); } else { fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); } } /* note on color management: * * OpenGL renders into sRGB colors, but render buffers are expected to be * linear So we convert to linear here, so the conversion back to bytes can make it * sRGB (or other display space) again, and so that e.g. openexr saving also saves the * correct linear float buffer. */ if (rect) { int profile_to; float *rectf = RE_RenderViewGetRectf(rr, oglrender->view_id); if (BKE_scene_check_color_management_enabled(scene)) profile_to = IB_PROFILE_LINEAR_RGB; else profile_to = IB_PROFILE_SRGB; /* sequencer has got trickier conversion happened above * also assume opengl's space matches byte buffer color space */ IMB_buffer_float_from_byte(rectf, rect, profile_to, IB_PROFILE_SRGB, true, oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex); /* rr->rectf is now filled with image data */ if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4); MEM_freeN(rect); } }