2008-04-25 09:37:36 -04:00
|
|
|
/*
|
2009-04-27 10:48:12 -04:00
|
|
|
* Cogl
|
2008-04-25 09:37:36 -04:00
|
|
|
*
|
2009-04-27 10:48:12 -04:00
|
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
2008-04-25 09:37:36 -04:00
|
|
|
*
|
2009-04-27 10:48:12 -04:00
|
|
|
* Copyright (C) 2007,2008,2009 Intel Corporation.
|
2008-04-25 09:37:36 -04:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
2009-04-27 10:48:12 -04:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Matthew Allum <mallum@openedhand.com>
|
|
|
|
* Neil Roberts <neil@linux.intel.com>
|
|
|
|
* Robert Bragg <robert@linux.intel.com>
|
2008-04-25 09:37:36 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "cogl.h"
|
|
|
|
#include "cogl-internal.h"
|
|
|
|
#include "cogl-util.h"
|
|
|
|
#include "cogl-bitmap.h"
|
2009-04-30 13:00:22 -04:00
|
|
|
#include "cogl-bitmap-private.h"
|
2008-10-30 13:25:00 -04:00
|
|
|
#include "cogl-texture-private.h"
|
2009-07-27 19:37:11 -04:00
|
|
|
#include "cogl-texture-driver.h"
|
2009-08-30 06:36:11 -04:00
|
|
|
#include "cogl-texture-2d-sliced-private.h"
|
2009-11-27 13:45:36 -05:00
|
|
|
#include "cogl-texture-2d-private.h"
|
2009-11-27 11:39:16 -05:00
|
|
|
#include "cogl-sub-texture-private.h"
|
2009-12-04 08:06:32 -05:00
|
|
|
#include "cogl-atlas-texture-private.h"
|
Adds a CoglMaterial abstraction, which includes support for multi-texturing
My previous work to provide muti-texturing support has been extended into
a CoglMaterial abstraction that adds control over the texture combine
functions (controlling how multiple texture layers are blended together),
the gl blend function (used for blending the final primitive with the
framebuffer), the alpha function (used to discard fragments based on
their alpha channel), describing attributes such as a diffuse, ambient and
specular color (for use with the standard OpenGL lighting model), and
per layer rotations. (utilizing the new CoglMatrix utility API)
For now the only way this abstraction is exposed is via a new
cogl_material_rectangle function, that is similar to cogl_texture_rectangle
but doesn't take a texture handle (the source material is pulled from
the context), and the array of texture coordinates is extended to be able
to supply coordinates for each layer.
Note: this function doesn't support sliced textures; supporting sliced
textures is a non trivial problem, considering the ability to rotate layers.
Note: cogl_material_rectangle, has quite a few workarounds, for a number of
other limitations within Cogl a.t.m.
Note: The GLES1/2 multi-texturing support has yet to be updated to use
the material abstraction.
2008-12-11 15:11:30 -05:00
|
|
|
#include "cogl-material.h"
|
2008-04-25 09:37:36 -04:00
|
|
|
#include "cogl-context.h"
|
2008-04-29 12:10:37 -04:00
|
|
|
#include "cogl-handle.h"
|
[cogl] Improving Cogl journal to minimize driver overheads + GPU state changes
Previously the journal was always flushed at the end of
_cogl_rectangles_with_multitexture_coords, (i.e. the end of any
cogl_rectangle* calls) but now we have broadened the potential for batching
geometry. In ideal circumstances we will only flush once per scene.
In summary the journal works like this:
When you use any of the cogl_rectangle* APIs then nothing is emitted to the
GPU at this point, we just log one or more quads into the journal. A
journal entry consists of the quad coordinates, an associated material
reference, and a modelview matrix. Ideally the journal only gets flushed
once at the end of a scene, but in fact there are things to consider that
may cause unwanted flushing, including:
- modifying materials mid-scene
This is because each quad in the journal has an associated material
reference (i.e. not copy), so if you try and modify a material that is
already referenced in the journal we force a flush first)
NOTE: For now this means you should avoid using cogl_set_source_color()
since that currently uses a single shared material. Later we
should change it to use a pool of materials that is recycled
when the journal is flushed.
- modifying any state that isn't currently logged, such as depth, fog and
backface culling enables.
The first thing that happens when flushing, is to upload all the vertex data
associated with the journal into a single VBO.
We then go through a process of splitting up the journal into batches that
have compatible state so they can be emitted to the GPU together. This is
currently broken up into 3 levels so we can stagger the state changes:
1) we break the journal up according to changes in the number of material layers
associated with logged quads. The number of layers in a material determines
the stride of the associated vertices, so we have to update our vertex
array offsets at this level. (i.e. calling gl{Vertex,Color},Pointer etc)
2) we further split batches up according to material compatability. (e.g.
materials with different textures) We flush material state at this level.
3) Finally we split batches up according to modelview changes. At this level
we update the modelview matrix and actually emit the actual draw command.
This commit is largely about putting the initial design in-place; this will be
followed by other changes that take advantage of the extended batching.
2009-06-17 13:46:42 -04:00
|
|
|
#include "cogl-primitives.h"
|
2009-11-26 14:06:35 -05:00
|
|
|
#include "cogl-framebuffer-private.h"
|
2008-04-25 09:37:36 -04:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2009-01-20 11:20:54 -05:00
|
|
|
#include <math.h>
|
2008-04-25 09:37:36 -04:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* XXX:
|
|
|
|
* The CoglHandle macros don't support any form of inheritance, so for
|
|
|
|
* now we implement the CoglHandle support for the CoglTexture
|
|
|
|
* abstract class manually.
|
|
|
|
*/
|
2008-12-11 10:33:38 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
gboolean
|
|
|
|
cogl_is_texture (CoglHandle handle)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglHandleObject *obj = (CoglHandleObject *)handle;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
if (handle == COGL_INVALID_HANDLE)
|
|
|
|
return FALSE;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-27 13:45:36 -05:00
|
|
|
return (obj->klass->type == _cogl_handle_texture_2d_get_type () ||
|
2009-12-04 08:06:32 -05:00
|
|
|
obj->klass->type == _cogl_handle_atlas_texture_get_type () ||
|
2009-11-27 13:45:36 -05:00
|
|
|
obj->klass->type == _cogl_handle_texture_2d_sliced_get_type () ||
|
2009-11-27 11:39:16 -05:00
|
|
|
obj->klass->type == _cogl_handle_sub_texture_get_type ());
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglHandle
|
|
|
|
cogl_texture_ref (CoglHandle handle)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return COGL_INVALID_HANDLE;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
_COGL_HANDLE_DEBUG_REF (CoglTexture, handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
cogl_handle_ref (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
return handle;
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2009-03-23 08:29:15 -04:00
|
|
|
void
|
2009-08-30 06:36:11 -04:00
|
|
|
cogl_texture_unref (CoglHandle handle)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
2009-09-16 06:56:17 -04:00
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
g_warning (G_STRINGIFY (cogl_texture_unref)
|
|
|
|
": Ignoring unref of Cogl handle "
|
|
|
|
"due to type mismatch");
|
|
|
|
return;
|
2009-09-16 06:56:17 -04:00
|
|
|
}
|
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
_COGL_HANDLE_DEBUG_UNREF (CoglTexture, handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
cogl_handle_unref (handle);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2010-02-03 17:54:44 -05:00
|
|
|
static gboolean
|
|
|
|
_cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
|
|
|
|
CoglPixelFormat dst_format)
|
|
|
|
{
|
|
|
|
return ((src_format & COGL_A_BIT) &&
|
|
|
|
src_format != COGL_PIXEL_FORMAT_A_8 &&
|
|
|
|
(src_format & COGL_PREMULT_BIT) !=
|
|
|
|
(dst_format & COGL_PREMULT_BIT));
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglPixelFormat
|
|
|
|
_cogl_texture_determine_internal_format (CoglPixelFormat src_format,
|
|
|
|
CoglPixelFormat dst_format)
|
|
|
|
{
|
|
|
|
/* If the application hasn't specified a specific format then we'll
|
|
|
|
* pick the most appropriate. By default Cogl will use a
|
|
|
|
* premultiplied internal format. Later we will add control over
|
|
|
|
* this. */
|
|
|
|
if (dst_format == COGL_PIXEL_FORMAT_ANY)
|
|
|
|
{
|
|
|
|
if ((src_format & COGL_A_BIT) &&
|
|
|
|
src_format != COGL_PIXEL_FORMAT_A_8)
|
|
|
|
return src_format | COGL_PREMULT_BIT;
|
|
|
|
else
|
|
|
|
return src_format;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return dst_format;
|
|
|
|
}
|
|
|
|
|
2010-02-01 07:11:58 -05:00
|
|
|
gboolean
|
|
|
|
_cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
|
|
|
|
CoglPixelFormat dst_format,
|
|
|
|
CoglPixelFormat *dst_format_out,
|
|
|
|
CoglBitmap *dst_bmp,
|
|
|
|
gboolean *copied_bitmap,
|
|
|
|
GLenum *out_glintformat,
|
|
|
|
GLenum *out_glformat,
|
|
|
|
GLenum *out_gltype)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2010-02-03 17:54:44 -05:00
|
|
|
dst_format = _cogl_texture_determine_internal_format (src_bmp->format,
|
|
|
|
dst_format);
|
|
|
|
|
|
|
|
*copied_bitmap = FALSE;
|
|
|
|
*dst_bmp = *src_bmp;
|
2008-04-25 09:37:36 -04:00
|
|
|
|
2010-02-03 17:54:44 -05:00
|
|
|
/* If the source format does not have the same premult flag as the
|
|
|
|
dst format then we need to copy and convert it */
|
|
|
|
if (_cogl_texture_needs_premult_conversion (src_bmp->format,
|
|
|
|
dst_format))
|
2010-02-01 07:11:58 -05:00
|
|
|
{
|
2010-02-03 17:54:44 -05:00
|
|
|
dst_bmp->data = g_memdup (dst_bmp->data,
|
|
|
|
dst_bmp->height * dst_bmp->rowstride);
|
|
|
|
*copied_bitmap = TRUE;
|
|
|
|
|
|
|
|
if (!_cogl_bitmap_convert_premult_status (dst_bmp,
|
|
|
|
src_bmp->format ^
|
|
|
|
COGL_PREMULT_BIT))
|
2010-02-01 07:11:58 -05:00
|
|
|
{
|
2010-02-03 17:54:44 -05:00
|
|
|
g_free (dst_bmp->data);
|
|
|
|
return FALSE;
|
2010-02-01 07:11:58 -05:00
|
|
|
}
|
|
|
|
}
|
2008-04-25 09:37:36 -04:00
|
|
|
|
2010-02-01 07:11:58 -05:00
|
|
|
/* Use the source format from the src bitmap type and the internal
|
|
|
|
format from the dst format type so that GL can do the
|
|
|
|
conversion */
|
|
|
|
_cogl_pixel_format_to_gl (src_bmp->format,
|
|
|
|
NULL, /* internal format */
|
|
|
|
out_glformat,
|
|
|
|
out_gltype);
|
|
|
|
_cogl_pixel_format_to_gl (dst_format,
|
|
|
|
out_glintformat,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (dst_format_out)
|
|
|
|
*dst_format_out = dst_format;
|
2009-09-16 06:56:17 -04:00
|
|
|
|
2010-02-01 07:11:58 -05:00
|
|
|
return TRUE;
|
2009-09-16 06:56:17 -04:00
|
|
|
}
|
|
|
|
|
2009-07-27 19:37:11 -04:00
|
|
|
void
|
|
|
|
_cogl_texture_prep_gl_alignment_for_pixels_upload (int pixels_rowstride)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2008-11-18 11:24:09 -05:00
|
|
|
if (!(pixels_rowstride & 0x7))
|
|
|
|
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) );
|
|
|
|
else if (!(pixels_rowstride & 0x3))
|
|
|
|
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 4) );
|
|
|
|
else if (!(pixels_rowstride & 0x1))
|
|
|
|
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 2) );
|
|
|
|
else
|
|
|
|
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 1) );
|
|
|
|
}
|
2008-04-25 09:37:36 -04:00
|
|
|
|
2009-07-27 19:37:11 -04:00
|
|
|
void
|
|
|
|
_cogl_texture_prep_gl_alignment_for_pixels_download (int pixels_rowstride)
|
2008-11-18 11:24:09 -05:00
|
|
|
{
|
|
|
|
if (!(pixels_rowstride & 0x7))
|
|
|
|
GE( glPixelStorei (GL_PACK_ALIGNMENT, 8) );
|
|
|
|
else if (!(pixels_rowstride & 0x3))
|
|
|
|
GE( glPixelStorei (GL_PACK_ALIGNMENT, 4) );
|
|
|
|
else if (!(pixels_rowstride & 0x1))
|
|
|
|
GE( glPixelStorei (GL_PACK_ALIGNMENT, 2) );
|
2008-04-25 09:37:36 -04:00
|
|
|
else
|
2008-11-18 11:24:09 -05:00
|
|
|
GE( glPixelStorei (GL_PACK_ALIGNMENT, 1) );
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* FIXME: wrap modes should be set on materials not textures */
|
2009-03-23 08:29:15 -04:00
|
|
|
void
|
2009-09-16 06:56:17 -04:00
|
|
|
_cogl_texture_set_wrap_mode_parameter (CoglHandle handle,
|
2008-12-01 11:27:54 -05:00
|
|
|
GLenum wrap_mode)
|
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglTexture *tex = COGL_TEXTURE (handle);
|
2009-09-16 06:56:17 -04:00
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
tex->vtable->set_wrap_mode_parameter (tex, wrap_mode);
|
2008-12-01 11:27:54 -05:00
|
|
|
}
|
|
|
|
|
2009-12-02 08:41:49 -05:00
|
|
|
/* This is like CoglSpanIter except it deals with floats and it
|
|
|
|
effectively assumes there is only one span from 0.0 to 1.0 */
|
|
|
|
typedef struct _CoglTextureIter
|
|
|
|
{
|
|
|
|
gfloat pos, end, next_pos;
|
|
|
|
gboolean flipped;
|
|
|
|
gfloat t_1, t_2;
|
|
|
|
} CoglTextureIter;
|
|
|
|
|
|
|
|
static void
|
|
|
|
_cogl_texture_iter_update (CoglTextureIter *iter)
|
|
|
|
{
|
|
|
|
gfloat t_2;
|
2010-01-11 11:23:38 -05:00
|
|
|
float frac_part;
|
2009-12-02 08:41:49 -05:00
|
|
|
|
2010-01-11 11:23:38 -05:00
|
|
|
frac_part = modff (iter->pos, &iter->next_pos);
|
2009-12-02 08:41:49 -05:00
|
|
|
|
|
|
|
/* modff rounds the int part towards zero so we need to add one if
|
|
|
|
we're meant to be heading away from zero */
|
2010-01-11 11:23:38 -05:00
|
|
|
if (iter->pos >= 0.0f || frac_part == 0.0f)
|
2009-12-02 08:41:49 -05:00
|
|
|
iter->next_pos += 1.0f;
|
|
|
|
|
|
|
|
if (iter->next_pos > iter->end)
|
|
|
|
t_2 = iter->end;
|
|
|
|
else
|
|
|
|
t_2 = iter->next_pos;
|
|
|
|
|
|
|
|
if (iter->flipped)
|
|
|
|
{
|
|
|
|
iter->t_1 = t_2;
|
|
|
|
iter->t_2 = iter->pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iter->t_1 = iter->pos;
|
|
|
|
iter->t_2 = t_2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_cogl_texture_iter_begin (CoglTextureIter *iter,
|
|
|
|
gfloat t_1, gfloat t_2)
|
|
|
|
{
|
|
|
|
if (t_1 <= t_2)
|
|
|
|
{
|
|
|
|
iter->pos = t_1;
|
|
|
|
iter->end = t_2;
|
|
|
|
iter->flipped = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iter->pos = t_2;
|
|
|
|
iter->end = t_1;
|
|
|
|
iter->flipped = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
_cogl_texture_iter_update (iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_cogl_texture_iter_next (CoglTextureIter *iter)
|
|
|
|
{
|
|
|
|
iter->pos = iter->next_pos;
|
|
|
|
_cogl_texture_iter_update (iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
_cogl_texture_iter_end (CoglTextureIter *iter)
|
|
|
|
{
|
|
|
|
return iter->pos >= iter->end;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This invokes the callback with enough quads to cover the manually
|
|
|
|
repeated range specified by the virtual texture coordinates without
|
|
|
|
emitting coordinates outside the range [0,1] */
|
|
|
|
void
|
|
|
|
_cogl_texture_iterate_manual_repeats (CoglTextureManualRepeatCallback callback,
|
|
|
|
float tx_1, float ty_1,
|
|
|
|
float tx_2, float ty_2,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
CoglTextureIter x_iter, y_iter;
|
|
|
|
|
|
|
|
for (_cogl_texture_iter_begin (&y_iter, ty_1, ty_2);
|
|
|
|
!_cogl_texture_iter_end (&y_iter);
|
|
|
|
_cogl_texture_iter_next (&y_iter))
|
|
|
|
for (_cogl_texture_iter_begin (&x_iter, tx_1, tx_2);
|
|
|
|
!_cogl_texture_iter_end (&x_iter);
|
|
|
|
_cogl_texture_iter_next (&x_iter))
|
|
|
|
{
|
|
|
|
float coords[4] = { x_iter.t_1, y_iter.t_1, x_iter.t_2, y_iter.t_2 };
|
|
|
|
callback (coords, user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
CoglHandle
|
[cogl] Remove max_waste argument from Texture ctors
The CoglTexture constructors expose the "max-waste" argument for
controlling the maximum amount of wasted areas for slicing or,
if set to -1, disables slicing.
Slicing is really relevant only for large images that are never
repeated, so it's a useful feature only in controlled use cases.
Specifying the amount of wasted area is, on the other hand, just
a way to mess up this feature; 99% the times, you either pull this
number out of thin air, hoping it's right, or you try to do the
right thing and you choose the wrong number anyway.
Instead, we can use the CoglTextureFlags to control whether the
texture should not be sliced (useful for Clutter-GST and for the
texture-from-pixmap actors) and provide a reasonable value for
enabling the slicing ourself. At some point, we might even
provide a way to change the default at compile time or at run time,
for particular platforms.
Since max_waste is gone, the :tile-waste property of ClutterTexture
becomes read-only, and it proxies the cogl_texture_get_max_waste()
function.
Inside Clutter, the only cases where the max_waste argument was
not set to -1 are in the Pango glyph cache (which is a POT texture
anyway) and inside the test cases where we want to force slicing;
for the latter we can create larger textures that will be bigger than
the threshold we set.
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
Signed-off-by: Robert Bragg <robert@linux.intel.com>
Signed-off-by: Neil Roberts <neil@linux.intel.com>
2009-05-23 14:18:18 -04:00
|
|
|
cogl_texture_new_with_size (guint width,
|
|
|
|
guint height,
|
|
|
|
CoglTextureFlags flags,
|
|
|
|
CoglPixelFormat internal_format)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2009-11-27 13:45:36 -05:00
|
|
|
CoglHandle tex;
|
|
|
|
|
|
|
|
/* First try creating a fast-path non-sliced texture */
|
|
|
|
tex = _cogl_texture_2d_new_with_size (width, height, flags, internal_format);
|
|
|
|
|
|
|
|
/* If it fails resort to sliced textures */
|
|
|
|
if (tex == COGL_INVALID_HANDLE)
|
|
|
|
tex = _cogl_texture_2d_sliced_new_with_size (width,
|
|
|
|
height,
|
|
|
|
flags,
|
|
|
|
internal_format);
|
|
|
|
|
|
|
|
return tex;
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
CoglHandle
|
2009-01-18 09:51:19 -05:00
|
|
|
cogl_texture_new_from_data (guint width,
|
|
|
|
guint height,
|
|
|
|
CoglTextureFlags flags,
|
|
|
|
CoglPixelFormat format,
|
|
|
|
CoglPixelFormat internal_format,
|
|
|
|
guint rowstride,
|
|
|
|
const guchar *data)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2009-11-27 11:59:51 -05:00
|
|
|
CoglBitmap bitmap;
|
|
|
|
|
|
|
|
if (format == COGL_PIXEL_FORMAT_ANY)
|
|
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
|
|
|
|
if (data == NULL)
|
|
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
|
|
|
|
/* Rowstride from width if not given */
|
|
|
|
if (rowstride == 0)
|
|
|
|
rowstride = width * _cogl_get_format_bpp (format);
|
|
|
|
|
|
|
|
/* Wrap the data into a bitmap */
|
|
|
|
bitmap.width = width;
|
|
|
|
bitmap.height = height;
|
|
|
|
bitmap.data = (guchar *) data;
|
|
|
|
bitmap.format = format;
|
|
|
|
bitmap.rowstride = rowstride;
|
|
|
|
|
|
|
|
return cogl_texture_new_from_bitmap (&bitmap, flags, internal_format);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
CoglHandle
|
[cogl] Remove max_waste argument from Texture ctors
The CoglTexture constructors expose the "max-waste" argument for
controlling the maximum amount of wasted areas for slicing or,
if set to -1, disables slicing.
Slicing is really relevant only for large images that are never
repeated, so it's a useful feature only in controlled use cases.
Specifying the amount of wasted area is, on the other hand, just
a way to mess up this feature; 99% the times, you either pull this
number out of thin air, hoping it's right, or you try to do the
right thing and you choose the wrong number anyway.
Instead, we can use the CoglTextureFlags to control whether the
texture should not be sliced (useful for Clutter-GST and for the
texture-from-pixmap actors) and provide a reasonable value for
enabling the slicing ourself. At some point, we might even
provide a way to change the default at compile time or at run time,
for particular platforms.
Since max_waste is gone, the :tile-waste property of ClutterTexture
becomes read-only, and it proxies the cogl_texture_get_max_waste()
function.
Inside Clutter, the only cases where the max_waste argument was
not set to -1 are in the Pango glyph cache (which is a POT texture
anyway) and inside the test cases where we want to force slicing;
for the latter we can create larger textures that will be bigger than
the threshold we set.
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
Signed-off-by: Robert Bragg <robert@linux.intel.com>
Signed-off-by: Neil Roberts <neil@linux.intel.com>
2009-05-23 14:18:18 -04:00
|
|
|
cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
|
|
|
|
CoglTextureFlags flags,
|
|
|
|
CoglPixelFormat internal_format)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2009-11-27 13:45:36 -05:00
|
|
|
CoglHandle tex;
|
|
|
|
|
2009-12-04 08:06:32 -05:00
|
|
|
/* First try putting the texture in the atlas */
|
|
|
|
if ((tex = _cogl_atlas_texture_new_from_bitmap (bmp_handle,
|
|
|
|
flags,
|
|
|
|
internal_format)))
|
|
|
|
return tex;
|
|
|
|
|
|
|
|
/* If that doesn't work try a fast path 2D texture */
|
|
|
|
if ((tex = _cogl_texture_2d_new_from_bitmap (bmp_handle,
|
|
|
|
flags,
|
|
|
|
internal_format)))
|
|
|
|
return tex;
|
|
|
|
|
|
|
|
/* Otherwise create a sliced texture */
|
|
|
|
return _cogl_texture_2d_sliced_new_from_bitmap (bmp_handle,
|
|
|
|
flags,
|
|
|
|
internal_format);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2009-01-07 12:02:43 -05:00
|
|
|
CoglHandle
|
2009-01-18 09:51:19 -05:00
|
|
|
cogl_texture_new_from_file (const gchar *filename,
|
|
|
|
CoglTextureFlags flags,
|
|
|
|
CoglPixelFormat internal_format,
|
|
|
|
GError **error)
|
2009-01-07 12:02:43 -05:00
|
|
|
{
|
2010-02-03 18:08:30 -05:00
|
|
|
CoglHandle bmp_handle;
|
|
|
|
CoglBitmap *bmp;
|
|
|
|
CoglHandle handle = COGL_INVALID_HANDLE;
|
2009-11-27 11:59:51 -05:00
|
|
|
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
|
|
|
|
|
2010-02-03 18:08:30 -05:00
|
|
|
bmp_handle = cogl_bitmap_new_from_file (filename, error);
|
|
|
|
if (bmp_handle == COGL_INVALID_HANDLE)
|
2009-11-27 11:59:51 -05:00
|
|
|
return COGL_INVALID_HANDLE;
|
|
|
|
|
2010-02-03 18:08:30 -05:00
|
|
|
bmp = (CoglBitmap *) bmp_handle;
|
|
|
|
|
|
|
|
/* We know that the bitmap data is solely owned by this function so
|
|
|
|
we can do the premult conversion in place. This avoids having to
|
|
|
|
copy the bitmap which will otherwise happen in
|
|
|
|
_cogl_texture_prepare_for_upload */
|
|
|
|
internal_format = _cogl_texture_determine_internal_format (bmp->format,
|
|
|
|
internal_format);
|
|
|
|
if (!_cogl_texture_needs_premult_conversion (bmp->format, internal_format) ||
|
2010-02-05 19:12:10 -05:00
|
|
|
_cogl_bitmap_convert_premult_status (bmp, bmp->format ^ COGL_PREMULT_BIT))
|
2010-02-03 18:08:30 -05:00
|
|
|
handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format);
|
|
|
|
|
2009-11-27 11:59:51 -05:00
|
|
|
cogl_handle_unref (bmp);
|
|
|
|
|
|
|
|
return handle;
|
2009-01-07 12:02:43 -05:00
|
|
|
}
|
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
CoglHandle
|
|
|
|
cogl_texture_new_from_foreign (GLuint gl_handle,
|
|
|
|
GLenum gl_target,
|
|
|
|
GLuint width,
|
|
|
|
GLuint height,
|
|
|
|
GLuint x_pot_waste,
|
|
|
|
GLuint y_pot_waste,
|
|
|
|
CoglPixelFormat format)
|
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
return _cogl_texture_2d_sliced_new_from_foreign (gl_handle,
|
|
|
|
gl_target,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
x_pot_waste,
|
|
|
|
y_pot_waste,
|
|
|
|
format);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2009-11-27 11:39:16 -05:00
|
|
|
CoglHandle
|
|
|
|
cogl_texture_new_from_sub_texture (CoglHandle full_texture,
|
2010-01-18 04:22:04 -05:00
|
|
|
gint sub_x,
|
|
|
|
gint sub_y,
|
|
|
|
gint sub_width,
|
|
|
|
gint sub_height)
|
2009-11-27 11:39:16 -05:00
|
|
|
{
|
2010-01-18 04:22:04 -05:00
|
|
|
return _cogl_sub_texture_new (full_texture, sub_x, sub_y,
|
|
|
|
sub_width, sub_height);
|
2009-11-27 11:39:16 -05:00
|
|
|
}
|
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
guint
|
|
|
|
cogl_texture_get_width (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return 0;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-26 13:58:17 -05:00
|
|
|
return tex->vtable->get_width (tex);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
guint
|
|
|
|
cogl_texture_get_height (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return 0;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-26 13:58:17 -05:00
|
|
|
return tex->vtable->get_height (tex);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
CoglPixelFormat
|
|
|
|
cogl_texture_get_format (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return COGL_PIXEL_FORMAT_ANY;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-26 13:58:17 -05:00
|
|
|
return tex->vtable->get_format (tex);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
guint
|
|
|
|
cogl_texture_get_rowstride (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return 0;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-26 12:32:52 -05:00
|
|
|
/* FIXME: This function should go away. It previously just returned
|
|
|
|
the rowstride that was used to upload the data as far as I can
|
|
|
|
tell. This is not helpful */
|
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-26 12:32:52 -05:00
|
|
|
/* Just guess at a suitable rowstride */
|
2009-11-26 13:58:17 -05:00
|
|
|
return (_cogl_get_format_bpp (cogl_texture_get_format (tex))
|
|
|
|
* cogl_texture_get_width (tex));
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
cogl_texture_get_max_waste (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return 0;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
return tex->vtable->get_max_waste (tex);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
cogl_texture_is_sliced (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return FALSE;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
return tex->vtable->is_sliced (tex);
|
2009-08-30 06:36:11 -04:00
|
|
|
}
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* Some CoglTextures, notably sliced textures or atlas textures when repeating
|
|
|
|
* is used, will need to divide the coordinate space into multiple GL textures
|
|
|
|
* (or rather; in the case of atlases duplicate a single texture in multiple
|
|
|
|
* positions to handle repeating)
|
|
|
|
*
|
|
|
|
* This function helps you implement primitives using such textures by
|
|
|
|
* invoking a callback once for each sub texture that intersects a given
|
|
|
|
* region specified in texture coordinates.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
_cogl_texture_foreach_sub_texture_in_region (CoglHandle handle,
|
|
|
|
float virtual_tx_1,
|
|
|
|
float virtual_ty_1,
|
|
|
|
float virtual_tx_2,
|
|
|
|
float virtual_ty_2,
|
|
|
|
CoglTextureSliceCallback callback,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
CoglTexture *tex = COGL_TEXTURE (handle);
|
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
tex->vtable->foreach_sub_texture_in_region (tex,
|
|
|
|
virtual_tx_1,
|
|
|
|
virtual_ty_1,
|
|
|
|
virtual_tx_2,
|
|
|
|
virtual_ty_2,
|
|
|
|
callback,
|
|
|
|
user_data);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* If this returns FALSE, that implies _foreach_sub_texture_in_region
|
|
|
|
* will be needed to iterate over multiple sub textures for regions whos
|
|
|
|
* texture coordinates extend out of the range [0,1]
|
|
|
|
*/
|
2009-09-16 06:56:17 -04:00
|
|
|
gboolean
|
|
|
|
_cogl_texture_can_hardware_repeat (CoglHandle handle)
|
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglTexture *tex = (CoglTexture *)handle;
|
2009-09-16 06:56:17 -04:00
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
return tex->vtable->can_hardware_repeat (tex);
|
2009-09-16 06:56:17 -04:00
|
|
|
}
|
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* NB: You can't use this with textures comprised of multiple sub textures (use
|
|
|
|
* cogl_texture_is_sliced() to check) since coordinate transformation for such
|
|
|
|
* textures will be different for each slice. */
|
2009-09-16 06:56:17 -04:00
|
|
|
void
|
|
|
|
_cogl_texture_transform_coords_to_gl (CoglHandle handle,
|
|
|
|
float *s,
|
|
|
|
float *t)
|
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglTexture *tex = COGL_TEXTURE (handle);
|
2009-09-16 06:56:17 -04:00
|
|
|
|
2010-01-04 06:49:50 -05:00
|
|
|
tex->vtable->transform_coords_to_gl (tex, s, t);
|
2009-09-16 06:56:17 -04:00
|
|
|
}
|
|
|
|
|
2010-01-18 04:22:04 -05:00
|
|
|
gboolean
|
|
|
|
_cogl_texture_transform_quad_coords_to_gl (CoglHandle handle,
|
|
|
|
float *coords)
|
|
|
|
{
|
|
|
|
CoglTexture *tex = COGL_TEXTURE (handle);
|
|
|
|
|
|
|
|
return tex->vtable->transform_quad_coords_to_gl (tex, coords);
|
|
|
|
}
|
|
|
|
|
2009-09-16 06:56:17 -04:00
|
|
|
GLenum
|
2009-11-26 13:58:17 -05:00
|
|
|
_cogl_texture_get_gl_format (CoglHandle handle)
|
2009-09-16 06:56:17 -04:00
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglTexture *tex = COGL_TEXTURE (handle);
|
2009-09-16 06:56:17 -04:00
|
|
|
|
2009-11-26 13:58:17 -05:00
|
|
|
return tex->vtable->get_gl_format (tex);
|
2009-09-16 06:56:17 -04:00
|
|
|
}
|
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
gboolean
|
|
|
|
cogl_texture_get_gl_texture (CoglHandle handle,
|
|
|
|
GLuint *out_gl_handle,
|
|
|
|
GLenum *out_gl_target)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return FALSE;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
return tex->vtable->get_gl_texture (tex, out_gl_handle, out_gl_target);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2009-06-04 11:04:57 -04:00
|
|
|
void
|
|
|
|
_cogl_texture_set_filters (CoglHandle handle,
|
|
|
|
GLenum min_filter,
|
|
|
|
GLenum mag_filter)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
2009-06-04 11:04:57 -04:00
|
|
|
return;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2010-01-04 06:49:50 -05:00
|
|
|
tex->vtable->set_filters (tex, min_filter, mag_filter);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-06-04 11:04:57 -04:00
|
|
|
_cogl_texture_ensure_mipmaps (CoglHandle handle)
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
2009-06-04 11:04:57 -04:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2010-01-04 06:49:50 -05:00
|
|
|
tex->vtable->ensure_mipmaps (tex);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|
2010-01-18 04:22:04 -05:00
|
|
|
void
|
|
|
|
_cogl_texture_ensure_non_quad_rendering (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglTexture *tex;
|
|
|
|
|
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return;
|
|
|
|
|
|
|
|
tex = COGL_TEXTURE (handle);
|
|
|
|
|
|
|
|
return tex->vtable->ensure_non_quad_rendering (tex);
|
|
|
|
}
|
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
gboolean
|
|
|
|
cogl_texture_set_region (CoglHandle handle,
|
|
|
|
gint src_x,
|
|
|
|
gint src_y,
|
|
|
|
gint dst_x,
|
|
|
|
gint dst_y,
|
|
|
|
guint dst_width,
|
|
|
|
guint dst_height,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
CoglPixelFormat format,
|
|
|
|
guint rowstride,
|
|
|
|
const guchar *data)
|
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglTexture *tex;
|
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
|
|
|
return FALSE;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
return tex->vtable->set_region (tex,
|
|
|
|
src_x, src_y,
|
|
|
|
dst_x, dst_y,
|
|
|
|
dst_width, dst_height,
|
|
|
|
width, height,
|
|
|
|
format,
|
|
|
|
rowstride,
|
|
|
|
data);
|
2009-08-30 06:36:11 -04:00
|
|
|
}
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* Reads back the contents of a texture by rendering it to the framebuffer
|
|
|
|
* and reading back the resulting pixels.
|
|
|
|
*
|
|
|
|
* It will perform multiple renders if the texture is larger than the
|
|
|
|
* current glViewport.
|
|
|
|
*
|
|
|
|
* It assumes the projection and modelview have already been setup so
|
|
|
|
* that rendering to 0,0 with the same width and height of the viewport
|
|
|
|
* will exactly cover the viewport.
|
|
|
|
*
|
|
|
|
* NB: Normally this approach isn't normally used since we can just use
|
|
|
|
* glGetTexImage, but may be used as a fallback in some circumstances.
|
|
|
|
*/
|
|
|
|
static void
|
2009-11-26 12:32:52 -05:00
|
|
|
do_texture_draw_and_read (CoglHandle handle,
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglBitmap *target_bmp,
|
|
|
|
GLint *viewport)
|
|
|
|
{
|
|
|
|
gint bpp;
|
|
|
|
float rx1, ry1;
|
|
|
|
float rx2, ry2;
|
|
|
|
float tx1, ty1;
|
|
|
|
float tx2, ty2;
|
|
|
|
int bw, bh;
|
|
|
|
CoglBitmap rect_bmp;
|
2009-11-26 12:32:52 -05:00
|
|
|
guint tex_width, tex_height;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-26 12:32:52 -05:00
|
|
|
tex_width = cogl_texture_get_width (handle);
|
|
|
|
tex_height = cogl_texture_get_height (handle);
|
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
ry1 = 0; ry2 = 0;
|
|
|
|
ty1 = 0; ty2 = 0;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* Walk Y axis until whole bitmap height consumed */
|
2009-11-26 12:32:52 -05:00
|
|
|
for (bh = tex_height; bh > 0; bh -= viewport[3])
|
2008-04-25 09:37:36 -04:00
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
/* Rectangle Y coords */
|
|
|
|
ry1 = ry2;
|
|
|
|
ry2 += (bh < viewport[3]) ? bh : viewport[3];
|
|
|
|
|
|
|
|
/* Normalized texture Y coords */
|
|
|
|
ty1 = ty2;
|
2009-11-26 12:32:52 -05:00
|
|
|
ty2 = (ry2 / (float) tex_height);
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
rx1 = 0; rx2 = 0;
|
|
|
|
tx1 = 0; tx2 = 0;
|
|
|
|
|
|
|
|
/* Walk X axis until whole bitmap width consumed */
|
2009-11-26 12:32:52 -05:00
|
|
|
for (bw = tex_width; bw > 0; bw-=viewport[2])
|
2009-08-30 06:36:11 -04:00
|
|
|
{
|
|
|
|
/* Rectangle X coords */
|
|
|
|
rx1 = rx2;
|
|
|
|
rx2 += (bw < viewport[2]) ? bw : viewport[2];
|
|
|
|
|
|
|
|
/* Normalized texture X coords */
|
|
|
|
tx1 = tx2;
|
2009-11-26 12:32:52 -05:00
|
|
|
tx2 = (rx2 / (float) tex_width);
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
/* Draw a portion of texture */
|
|
|
|
cogl_rectangle_with_texture_coords (0, 0,
|
|
|
|
rx2 - rx1,
|
|
|
|
ry2 - ry1,
|
|
|
|
tx1, ty1,
|
|
|
|
tx2, ty2);
|
|
|
|
|
|
|
|
/* Read into a temporary bitmap */
|
|
|
|
rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888;
|
|
|
|
rect_bmp.width = rx2 - rx1;
|
|
|
|
rect_bmp.height = ry2 - ry1;
|
|
|
|
rect_bmp.rowstride = bpp * rect_bmp.width;
|
|
|
|
rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride *
|
|
|
|
rect_bmp.height);
|
|
|
|
|
|
|
|
_cogl_texture_driver_prep_gl_for_pixels_download (rect_bmp.rowstride,
|
|
|
|
bpp);
|
|
|
|
GE( glReadPixels (viewport[0], viewport[1],
|
|
|
|
rect_bmp.width,
|
|
|
|
rect_bmp.height,
|
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
|
rect_bmp.data) );
|
|
|
|
|
|
|
|
/* Copy to target bitmap */
|
|
|
|
_cogl_bitmap_copy_subregion (&rect_bmp,
|
|
|
|
target_bmp,
|
|
|
|
0,0,
|
|
|
|
rx1,ry1,
|
|
|
|
rect_bmp.width,
|
|
|
|
rect_bmp.height);
|
|
|
|
|
|
|
|
/* Free temp bitmap */
|
|
|
|
g_free (rect_bmp.data);
|
|
|
|
}
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
2009-08-30 06:36:11 -04:00
|
|
|
}
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
/* Reads back the contents of a texture by rendering it to the framebuffer
|
|
|
|
* and reading back the resulting pixels.
|
|
|
|
*
|
|
|
|
* NB: Normally this approach isn't normally used since we can just use
|
|
|
|
* glGetTexImage, but may be used as a fallback in some circumstances.
|
|
|
|
*/
|
|
|
|
gboolean
|
2009-11-26 12:32:52 -05:00
|
|
|
_cogl_texture_draw_and_read (CoglHandle handle,
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglBitmap *target_bmp,
|
|
|
|
GLuint target_gl_format,
|
|
|
|
GLuint target_gl_type)
|
|
|
|
{
|
|
|
|
gint bpp;
|
2009-11-26 14:06:35 -05:00
|
|
|
CoglHandle framebuffer;
|
2009-09-25 09:34:34 -04:00
|
|
|
int viewport[4];
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglBitmap alpha_bmp;
|
|
|
|
CoglHandle prev_source;
|
2009-10-13 18:09:42 -04:00
|
|
|
CoglMatrixStack *projection_stack;
|
|
|
|
CoglMatrixStack *modelview_stack;
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888);
|
|
|
|
|
2009-11-26 14:06:35 -05:00
|
|
|
framebuffer = _cogl_get_framebuffer ();
|
2009-08-30 06:36:11 -04:00
|
|
|
/* Viewport needs to have some size and be inside the window for this */
|
2009-11-26 14:06:35 -05:00
|
|
|
_cogl_framebuffer_get_viewport4fv (framebuffer, viewport);
|
2009-08-30 06:36:11 -04:00
|
|
|
if (viewport[0] < 0 || viewport[1] < 0 ||
|
|
|
|
viewport[2] <= 0 || viewport[3] <= 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Setup orthographic projection into current viewport (0,0 in bottom-left
|
|
|
|
* corner to draw the texture upside-down so we match the way glReadPixels
|
|
|
|
* works)
|
|
|
|
*/
|
|
|
|
|
2009-11-26 14:06:35 -05:00
|
|
|
projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer);
|
2009-09-25 09:34:34 -04:00
|
|
|
_cogl_matrix_stack_push (projection_stack);
|
|
|
|
_cogl_matrix_stack_load_identity (projection_stack);
|
|
|
|
_cogl_matrix_stack_ortho (projection_stack,
|
2009-10-13 18:09:42 -04:00
|
|
|
0, (float)(viewport[2]),
|
|
|
|
0, (float)(viewport[3]),
|
|
|
|
(float)(0),
|
|
|
|
(float)(100));
|
2009-08-30 06:36:11 -04:00
|
|
|
|
2009-11-26 14:06:35 -05:00
|
|
|
modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer);
|
2009-09-25 09:34:34 -04:00
|
|
|
_cogl_matrix_stack_push (modelview_stack);
|
|
|
|
_cogl_matrix_stack_load_identity (modelview_stack);
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
/* Direct copy operation */
|
|
|
|
|
|
|
|
if (ctx->texture_download_material == COGL_INVALID_HANDLE)
|
|
|
|
{
|
|
|
|
ctx->texture_download_material = cogl_material_new ();
|
|
|
|
cogl_material_set_blend (ctx->texture_download_material,
|
|
|
|
"RGBA = ADD (SRC_COLOR, 0)",
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
prev_source = cogl_handle_ref (ctx->source_material);
|
|
|
|
cogl_set_source (ctx->texture_download_material);
|
|
|
|
|
2009-11-26 12:32:52 -05:00
|
|
|
cogl_material_set_layer (ctx->texture_download_material, 0, handle);
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
cogl_material_set_layer_combine (ctx->texture_download_material,
|
|
|
|
0, /* layer */
|
|
|
|
"RGBA = REPLACE (TEXTURE)",
|
|
|
|
NULL);
|
|
|
|
|
2009-11-26 12:32:52 -05:00
|
|
|
do_texture_draw_and_read (handle, target_bmp, viewport);
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
/* Check whether texture has alpha and framebuffer not */
|
|
|
|
/* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer
|
|
|
|
still doesn't seem to have an alpha buffer. This might be just
|
|
|
|
a PowerVR issue.
|
|
|
|
GLint r_bits, g_bits, b_bits, a_bits;
|
|
|
|
GE( glGetIntegerv (GL_ALPHA_BITS, &a_bits) );
|
|
|
|
GE( glGetIntegerv (GL_RED_BITS, &r_bits) );
|
|
|
|
GE( glGetIntegerv (GL_GREEN_BITS, &g_bits) );
|
|
|
|
GE( glGetIntegerv (GL_BLUE_BITS, &b_bits) );
|
|
|
|
printf ("R bits: %d\n", r_bits);
|
|
|
|
printf ("G bits: %d\n", g_bits);
|
|
|
|
printf ("B bits: %d\n", b_bits);
|
|
|
|
printf ("A bits: %d\n", a_bits); */
|
2009-11-26 12:32:52 -05:00
|
|
|
if ((cogl_texture_get_format (handle) & COGL_A_BIT)/* && a_bits == 0*/)
|
2009-08-30 06:36:11 -04:00
|
|
|
{
|
|
|
|
guchar *srcdata;
|
|
|
|
guchar *dstdata;
|
|
|
|
guchar *srcpixel;
|
|
|
|
guchar *dstpixel;
|
|
|
|
gint x,y;
|
|
|
|
|
|
|
|
/* Create temp bitmap for alpha values */
|
|
|
|
alpha_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888;
|
|
|
|
alpha_bmp.width = target_bmp->width;
|
|
|
|
alpha_bmp.height = target_bmp->height;
|
|
|
|
alpha_bmp.rowstride = bpp * alpha_bmp.width;
|
|
|
|
alpha_bmp.data = (guchar*) g_malloc (alpha_bmp.rowstride *
|
|
|
|
alpha_bmp.height);
|
|
|
|
|
|
|
|
/* Draw alpha values into RGB channels */
|
|
|
|
cogl_material_set_layer_combine (ctx->texture_download_material,
|
|
|
|
0, /* layer */
|
|
|
|
"RGBA = REPLACE (TEXTURE[A])",
|
|
|
|
NULL);
|
|
|
|
|
2009-11-26 12:32:52 -05:00
|
|
|
do_texture_draw_and_read (handle, &alpha_bmp, viewport);
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
/* Copy temp R to target A */
|
|
|
|
srcdata = alpha_bmp.data;
|
|
|
|
dstdata = target_bmp->data;
|
|
|
|
|
|
|
|
for (y=0; y<target_bmp->height; ++y)
|
|
|
|
{
|
|
|
|
for (x=0; x<target_bmp->width; ++x)
|
|
|
|
{
|
|
|
|
srcpixel = srcdata + x*bpp;
|
|
|
|
dstpixel = dstdata + x*bpp;
|
|
|
|
dstpixel[3] = srcpixel[0];
|
|
|
|
}
|
|
|
|
srcdata += alpha_bmp.rowstride;
|
|
|
|
dstdata += target_bmp->rowstride;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (alpha_bmp.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore old state */
|
2009-10-13 18:09:42 -04:00
|
|
|
_cogl_matrix_stack_pop (modelview_stack);
|
|
|
|
_cogl_matrix_stack_pop (projection_stack);
|
2009-08-30 06:36:11 -04:00
|
|
|
|
|
|
|
/* restore the original material */
|
|
|
|
cogl_set_source (prev_source);
|
|
|
|
cogl_handle_unref (prev_source);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
cogl_texture_get_data (CoglHandle handle,
|
|
|
|
CoglPixelFormat format,
|
|
|
|
guint rowstride,
|
|
|
|
guchar *data)
|
|
|
|
{
|
2009-08-30 06:36:11 -04:00
|
|
|
CoglTexture *tex;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
if (!cogl_is_texture (handle))
|
2009-08-30 06:36:11 -04:00
|
|
|
return FALSE;
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-08-30 06:36:11 -04:00
|
|
|
tex = COGL_TEXTURE (handle);
|
2008-12-23 11:29:29 -05:00
|
|
|
|
2009-11-25 08:39:45 -05:00
|
|
|
return tex->vtable->get_data (handle, format, rowstride, data);
|
2008-04-25 09:37:36 -04:00
|
|
|
}
|
|
|
|
|