Changes for opengl render to reflect new alpha premul pipeline
authorSergey Sharybin <sergey.vfx@gmail.com>
Sat, 5 Jan 2013 15:33:18 +0000 (15:33 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Sat, 5 Jan 2013 15:33:18 +0000 (15:33 +0000)
without hurting quick texture painting

- ED_view3d_draw_offscreen will now output buffer with
  transparent alpha, if sky needed it should be alpha-undered
  later.

- ED_view3d_draw_offscreen_imbuf now accepts alpha mode as an
  argument which could be either R_ADDSKY or R_PREMULALPHA

- OpenGL render and sequencer's opengl preview will now reflect
  scene's Alpha Mode

- Quick Edit will use OpenGL with transparent alpha mode

source/blender/blenkernel/intern/sequencer.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/render/render_opengl.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/imbuf/IMB_imbuf.h
source/blender/imbuf/intern/imageprocess.c
source/blender/windowmanager/intern/wm_files.c

index 8d010de408a37c981be9dce3c25eed1fdbac737b..2c1fd092fbbd56923490b28c696401ceec8f96ce 100644 (file)
@@ -2391,7 +2391,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float
                BKE_scene_update_for_newframe(context.bmain, scene, scene->lay);
                ibuf = sequencer_view3d_cb(scene, camera, context.rectx, context.recty, IB_rect,
                                           context.scene->r.seq_prev_type, context.scene->r.seq_flag & R_SEQ_SOLID_TEX,
-                                          TRUE, FALSE, err_out);
+                                          TRUE, scene->r.alphamode, err_out);
                if (ibuf == NULL) {
                        fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
                }
index 3d13938c20496673fbae2f92e30f54fa1a2f37b2..ac2c47216a6f67384d9806bd2b1c910da5ce25ac 100644 (file)
@@ -270,13 +270,13 @@ int ED_view3d_scene_layer_set(int lay, const int *values, int *active);
 int ED_view3d_context_activate(struct bContext *C);
 void ED_view3d_draw_offscreen_init(struct Scene *scene, struct View3D *v3d);
 void ED_view3d_draw_offscreen(struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
-                              int winx, int winy, float viewmat[4][4], float winmat[4][4], int do_bgpic, int colormanage_background);
+                              int winx, int winy, float viewmat[4][4], float winmat[4][4], int do_bgpic);
 
 struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
-                                             int draw_background, int colormanage_background, char err_out[256]);
+                                             int draw_background, int alpha_mode, char err_out[256]);
 struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
-                                                    int use_solid_tex, int draw_background, int colormanage_background, char err_out[256]);
-
+                                                    int use_solid_tex, int draw_background, int alpha_mode, char err_out[256]);
+void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]);
 
 struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
 void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, short do_clip);
index cbc076b33428a8d07c96782c940c0987d5946afb..7ba6a92e4be02665902b81abd3dd8069a52daf22 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
+#include "DNA_world_types.h"
 
 #include "BKE_context.h"
 #include "BKE_global.h"
@@ -192,7 +193,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
                }
 
                if ((scene->r.mode & R_OSA) == 0) {
-                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE, FALSE);
+                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE);
                        GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, rr->rectf);
                }
                else {
@@ -206,7 +207,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
                        BLI_jitter_init(jit_ofs[0], scene->r.osa);
 
                        /* first sample buffer, also initializes 'rv3d->persmat' */
-                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE, FALSE);
+                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE);
                        GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, accum_buffer);
 
                        /* skip the first sample */
@@ -216,7 +217,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
                                                    (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, TRUE, FALSE);
+                               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, TRUE);
                                GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, accum_tmp);
                                add_vn_vn(accum_buffer, accum_tmp, sizex * sizey * sizeof(float));
                        }
@@ -232,7 +233,8 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
        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_rectfloat, OB_SOLID, FALSE, TRUE, FALSE, err_out);
+               ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
+                                                                        IB_rectfloat, OB_SOLID, FALSE, TRUE, R_ALPHAPREMUL, err_out);
                camera = scene->camera;
 
                if (ibuf_view) {
@@ -243,7 +245,13 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
                        fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
                }
        }
-       
+
+       if (scene->r.alphamode == R_ADDSKY) {
+               float sky_color[3];
+               ED_view3d_offscreen_sky_color_get(scene, sky_color);
+               IMB_alpha_under_color_float(rr->rectf, sizex, sizey, sky_color);
+       }
+
        /* note on color management:
         *
         * OpenGL renders into sRGB colors, but render buffers are expected to be
index fa8252c824d0c118ec625eba4688deb027537f3d..d0f8e36e17d0f0a43eee041e8a216f298cae48df 100644 (file)
@@ -6038,7 +6038,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
        if (w > maxsize) w = maxsize;
        if (h > maxsize) h = maxsize;
 
-       ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, FALSE, err_out);
+       ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, R_ALPHAPREMUL, err_out);
        if (!ibuf) {
                /* Mostly happens when OpenGL offscreen buffer was failed to create, */
                /* but could be other reasons. Should be handled in the future. nazgul */
index 4ccf26e12b1f81a81cf7e6e54580198a7f640811..76f62db3c5bc3e58bdcb1af97f190958b0fd3c00 100644 (file)
@@ -2393,7 +2393,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
                invert_m4_m4(rv3d.persinv, rv3d.viewinv);
 
                /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */
-               ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, FALSE, FALSE);
+               ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, FALSE);
                GPU_lamp_shadow_buffer_unbind(shadow->lamp);
                
                v3d->drawtype = drawtype;
@@ -2540,13 +2540,11 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
 /* ED_view3d_draw_offscreen_init should be called before this to initialize
  * stuff like shadow buffers
  */
-void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
-                              int winx, int winy, float viewmat[4][4], float winmat[4][4],
-                              int do_bgpic, int colormanage_background)
+void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
+                              float viewmat[4][4], float winmat[4][4], int do_bgpic)
 {
        RegionView3D *rv3d = ar->regiondata;
        Base *base;
-       float backcol[3];
        int bwinx, bwiny;
        rcti brect;
 
@@ -2574,34 +2572,7 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
         * warning! can be slow so only free animated images - campbell */
        GPU_free_images_anim();
 
-       /* set background color, fallback on the view background color
-        * (if active clip is set but frame is failed to load fallback to horizon color as background) */
-       if (scene->world) {
-               /* NOTE: currently OpenGL is supposed to always work in sRGB space and do not
-                *       apply any tonemaps since it's really tricky to support for all features (GLSL, textures, etc)
-                *       but due to compatibility issues background is being affected display transform, so we can
-                *       emulate behavior of disabled color management
-                *       but this function is also used for sequencer's scene strips which shouldn't be affected by
-                *       tonemaps now and should be purely sRGB, that's why we've got this colormanage_background
-                *       we can drop this flag in cost of some compatibility loss -- background wouldn't be
-                *       color managed in 3d viewport
-                *       same goes to opengl rendering, where color profile should be applied as very final step
-                */
-
-               if (colormanage_background) {
-                       IMB_colormanagement_pixel_to_display_space_v3(backcol, &scene->world->horr, &scene->view_settings,
-                                                                     &scene->display_settings);
-               }
-               else {
-                       linearrgb_to_srgb_v3_v3(backcol, &scene->world->horr);
-               }
-
-               glClearColor(backcol[0], backcol[1], backcol[2], 0.0f);
-       }
-       else {
-                UI_ThemeClearColor(TH_BACK);
-       }
-
+       glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
@@ -2703,10 +2674,30 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
        G.f &= ~G_RENDER_OGL;
 }
 
+/* get a color used for offscreen sky, returns color in sRGB space */
+void ED_view3d_offscreen_sky_color_get(Scene *scene, float sky_color[3])
+{
+       if (scene->world)
+               linearrgb_to_srgb_v3_v3(sky_color, &scene->world->horr);
+       else
+               UI_GetThemeColor3fv(TH_BACK, sky_color);
+}
+
+static void offscreen_imbuf_add_sky(ImBuf *ibuf, Scene *scene)
+{
+       float sky_color[3];
+
+       ED_view3d_offscreen_sky_color_get(scene, sky_color);
+
+       if (ibuf->rect_float)
+               IMB_alpha_under_color_float(ibuf->rect_float, ibuf->x, ibuf->y, sky_color);
+       else
+               IMB_alpha_under_color_byte((unsigned char *) ibuf->rect, ibuf->x, ibuf->y, sky_color);
+}
+
 /* utility func for ED_view3d_draw_offscreen */
-ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar,
-                                      int sizex, int sizey, unsigned int flag, int draw_background,
-                                      int colormanage_background, char err_out[256])
+ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
+                                      int draw_background, int alpha_mode, char err_out[256])
 {
        RegionView3D *rv3d = ar->regiondata;
        ImBuf *ibuf;
@@ -2733,10 +2724,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar,
                BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
                BKE_camera_params_compute_matrix(&params);
 
-               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background, colormanage_background);
+               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background);
        }
        else {
-               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background, colormanage_background);
+               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background);
        }
 
        /* read in pixels & stamp */
@@ -2747,6 +2738,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar,
        else if (ibuf->rect)
                GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
 
+       if (alpha_mode == R_ADDSKY)
+               offscreen_imbuf_add_sky(ibuf, scene);
+
        /* unbind */
        GPU_offscreen_unbind(ofs);
        GPU_offscreen_free(ofs);
@@ -2760,9 +2754,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar,
 }
 
 /* creates own 3d views, used by the sequencer */
-ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height,
-                                             unsigned int flag, int drawtype, int use_solid_tex, int draw_background,
-                                             int colormanage_background, char err_out[256])
+ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height, unsigned int flag, int drawtype,
+                                             int use_solid_tex, int draw_background, int alpha_mode, char err_out[256])
 {
        View3D v3d = {NULL};
        ARegion ar = {NULL};
@@ -2805,7 +2798,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
        invert_m4_m4(rv3d.persinv, rv3d.viewinv);
 
        return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag,
-                                             draw_background, colormanage_background, err_out);
+                                             draw_background, alpha_mode, err_out);
 
        // seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty);
 }
index 850060ef4d54aac4ce15d559b197ead1b8f83980..8d60227377b57447c6a4104698f5f1eadb6f51ce 100644 (file)
@@ -416,6 +416,9 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char col[4], float c
 void bilinear_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
 void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
 
+void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
+void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3]);
+
 /**
  *
  * \attention defined in readimage.c
index 1eac6236829e0c5762660c89e976b44c980429bb..59282c9d207f6e757d95b5efa9c9aec28d368bcc 100644 (file)
@@ -327,3 +327,53 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
 
        MEM_freeN(handles);
 }
+
+/* Alpha-under */
+
+void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
+{
+       int a = x * y;
+       float *fp = rect_float;
+
+       while (a--) {
+               if (fp[3] == 0.0f) {
+                       copy_v3_v3(fp, backcol);
+               }
+               else {
+                       float mul = 1.0f - fp[3];
+
+                       fp[0] += mul * backcol[0];
+                       fp[1] += mul * backcol[1];
+                       fp[2] += mul * backcol[2];
+               }
+
+               fp[3] = 1.0f;
+
+               fp += 4;
+       }
+}
+
+void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3])
+{
+       int a = x * y;
+       unsigned char *cp = rect;
+
+       while (a--) {
+               if (cp[3] == 0) {
+                       cp[0] = backcol[0] * 255;
+                       cp[1] = backcol[1] * 255;
+                       cp[2] = backcol[2] * 255;
+               }
+               else {
+                       int mul = 255 - cp[3];
+
+                       cp[0] += mul * backcol[0] / 255;
+                       cp[1] += mul * backcol[1] / 255;
+                       cp[2] += mul * backcol[2] / 255;
+               }
+
+               cp[3] = 255;
+
+               cp += 4;
+       }
+}
index f31aff3d3f81296b163bc4c5e8968a281aea3e3d..a9b3e4272ce0c0fab4a62d2a1aae1859878c165c 100644 (file)
@@ -733,11 +733,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
        if (scene->camera) {
                ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
                                                             BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
-                                                            IB_rect, OB_SOLID, FALSE, FALSE, FALSE, err_out);
+                                                            IB_rect, OB_SOLID, FALSE, FALSE, R_ADDSKY, err_out);
        }
        else {
                ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
-                                                     IB_rect, FALSE, FALSE, err_out);
+                                                     IB_rect, FALSE, R_ADDSKY, err_out);
        }
 
        if (ibuf) {