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;
}