On ne 14. června 2009, Vladimir Nadvornik wrote:
> On Sunday 14 June 2009 13:08:25 Øyvind Kolås wrote:
> > On Sat, Jun 13, 2009 at 5:32 AM, Saul
> >
> > Lethbridge<[email protected]> wrote:
> > >> Is it possible to do something similar with clutter API?
> > >
> > > This sounds like it would be a useful addition.
> >
> > What would be the useful addition?
> >
> > I think it only makes sense to do such color correction in cases where
> > the software is part of a visual media production pipeline where both
> > source material and display devices have proper ICC profiles. (inputs
> > assumed to be in sRGB could be used).
>
> Yes. I am working on an image viewer for photos (geeqie.sf.net), where the
> color management is a must. Processing the image data with lcms is rather
> slow (around 10 MPix/s), the method with 3D lut in GPU is at least 30x
> faster. Clutter API would help a lot with image scaling, zooming, etc.
>
> > You can do similar lookup-tables with cogls API if you have a real
> > need for it, though I am not sure if you could used 3D-textures in the
> > manner required.
>
> I haven't found any possibility to use 3D textures with cogl. So the
> question is, if I can create it with opengl API and set it  up in the
> second texturing unit before the ClutterTexture is drawn with a 
> ClutterShader , or if there would be any conflict with clutter internals.
>
>

Hi,

I tried to port the original code to clutter, see the attachment. It seems to 
work with 0.9.8, but I am not sure if I can rely on it.

Vladimir
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#include <lcms.h>

#define GRIDPOINTS 64


static GLuint clut_texture;

static GLfloat clut_scale;
static GLfloat clut_offset;
static GLushort clut[GRIDPOINTS][GRIDPOINTS][GRIDPOINTS][3];

const char *cmm_shader_source =
    "uniform sampler2D image;					\n"
    "uniform sampler3D clut;					\n"
    "uniform float scale;					\n"
    "uniform float offset;					\n"
    "								\n"
    "void main()						\n"
    "{								\n"
    "    vec4 rgba = texture2D(image, gl_TexCoord[0].xy);	\n"
    "	 vec3 rgb = rgba.rgb;					\n"
    "								\n"
    "    // interpolate CLUT					\n"
    "    rgb = rgb * scale + offset;				\n"
    "    gl_FragColor = texture3D(clut, rgb);			\n"
    "	 gl_FragColor.a = rgba.a;				\n"
    "								\n"
    "    // w/o color management				\n"
    "    // gl_FragColor = rgba;				\n"
    "}								\n"
    ;

void
make_clut_texture (const char *profile_name)
{
    int r, g, b, n = GRIDPOINTS;
    cmsHPROFILE sRGB, monitor;
    cmsHTRANSFORM xform;

    sRGB = cmsCreate_sRGBProfile ();
    monitor = cmsOpenProfileFromFile (profile_name, "r");

    if (monitor == NULL) {
    	fprintf(stderr, "Cannot open display profile %s\n", profile_name);
	exit(1);
    }

    xform = cmsCreateTransform (sRGB, TYPE_RGB_16, monitor, TYPE_RGB_16,
				INTENT_PERCEPTUAL, cmsFLAGS_NOTPRECALC);

    if (xform == NULL) {
    	fprintf(stderr, "Failed to create transformation\n");
	exit(1);
    }

    clut_scale = (double) (n - 1) / n;
    clut_offset = 1.0 / (2 * n);

    for (r = 0; r < n; r++) {
	for (g = 0; g < n; g++) {
	    for (b = 0; b < n; b++) {
		unsigned short in[3];
		in[0] = floor ((double) r / (n - 1) * 65535.0 + 0.5);
		in[1] = floor ((double) g / (n - 1) * 65535.0 + 0.5);
		in[2] = floor ((double) b / (n - 1) * 65535.0 + 0.5);
//		memcpy(clut[b][g][r], in, sizeof(in));
		cmsDoTransform (xform, in, clut[b][g][r], 1);
	    }
	}
    }

    cmsDeleteTransform (xform);
    cmsCloseProfile (monitor);
    cmsCloseProfile (sRGB);

    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
    glPixelStorei (GL_UNPACK_IMAGE_HEIGHT, 0);
    glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); 
    glPixelStorei (GL_UNPACK_SKIP_IMAGES, 0); 
    glGenTextures (1, &clut_texture);
    /* texture 1 = clut */
    glActiveTextureARB (GL_TEXTURE0_ARB + 1);
    glBindTexture (GL_TEXTURE_3D, clut_texture);

    glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
    glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    /*
     * Don't use FP luts, but only 16-bit integer ones, since the ATI card
     * does not support GL_LINEAR for GL_RGB32F_ARB, but ony GL_NEAREST
     */
    glTexImage3D (GL_TEXTURE_3D, 0, GL_RGB16, n, n, n,
		  0, GL_RGB, GL_UNSIGNED_SHORT, clut);

    /* back to texture 0 */
    glActiveTextureARB (GL_TEXTURE0_ARB);
}


ClutterShader *init_shader()
{
      ClutterShader *shader;
      GError *error;
      
      shader = clutter_shader_new ();
      
      error = NULL;
      clutter_shader_set_fragment_source(shader, cmm_shader_source, strlen(cmm_shader_source));

      clutter_shader_compile (shader, &error);
      if (error)
        {
          g_print ("unable to set shader: %s", error->message);
          g_error_free (error);
          exit(1);
        }
    return shader;
}

	
static void
pre_paint (ClutterActor *actor,
                gpointer      user_data)
{
    /* texture 1 = clut */
    glActiveTextureARB (GL_TEXTURE0_ARB + 1);
    glBindTexture (GL_TEXTURE_3D, clut_texture);

    /* back to texture 0 (image) */
    glActiveTextureARB (GL_TEXTURE0_ARB);
}


gint
main (int argc, char *argv[])
{
  ClutterActor     *stage;
  ClutterActor     *image;
  GError           *error;

  clutter_init (&argc, &argv);
  

  stage = clutter_stage_get_default ();


  error = NULL;
  image = clutter_texture_new_from_file (argv[1]?argv[1]:"redhand.png", &error);
  if (error)
    g_error ("Unable to load image: %s", error->message);

  make_clut_texture("test.icc");

  clutter_actor_set_shader (image, init_shader());

  clutter_actor_set_shader_param_int (image, "image", 0);    /* texture 0 = image */
  clutter_actor_set_shader_param_int (image, "clut", 1);     /* texture 1 = clut */
  clutter_actor_set_shader_param_float (image, "scale", clut_scale);
  clutter_actor_set_shader_param_float (image, "offset", clut_offset);
  
  g_signal_connect (image,
                        "paint", G_CALLBACK (pre_paint),
                        NULL);

  /* center the image */
  clutter_actor_set_position (image, 
    (clutter_actor_get_width (stage) - clutter_actor_get_width (image))/2,
    (clutter_actor_get_height (stage) - clutter_actor_get_height (image))/2);
  clutter_container_add (CLUTTER_CONTAINER (stage), image, NULL);

  clutter_actor_show_all (stage);

  clutter_main ();

  return EXIT_SUCCESS;
}

Reply via email to