1
0
Fork 0

Merge branch '1.0-integration'

* 1.0-integration: (138 commits)
  [x11] Disable XInput by default
  [xinput] Invert the XI extension version check
  [cogl-primitives] Fix an unused variable warning when building GLES
  [clutter-stage-egl] Pass -1,-1 to clutter_stage_x11_fix_window_size
  Update the GLES backend to have the layer filters in the material
  [gles/cogl-shader] Add a missing semicolon
  [cogl] Move the texture filters to be a property of the material layer
  [text] Fix Pango unit to pixels conversion
  [actor] Force unrealization on destroy only for non-toplevels
  [x11] Rework map/unmap and resizing
  [xinput] Check for the XInput entry points
  [units] Validate units against the ParamSpec
  [actor] Add the ::allocation-changed signal
  [actor] Use flags to control allocations
  [units] Rework Units into logical distance value
  Remove a stray g_value_get_int()
  Remove usage of Units and macros
  [cogl-material] Allow setting a layer with an invalid texture handle
  [timeline] Remove the concept of frames from timelines
  [gles/cogl-shader] Fix parameter spec for cogl_shader_get_info_log
  ...

Conflicts:
	configure.ac
This commit is contained in:
Emmanuele Bassi 2009-06-05 12:41:42 +01:00
commit 7e33fe3175
174 changed files with 12479 additions and 7608 deletions

18
.gitignore vendored
View file

@ -19,8 +19,11 @@ clutter/stamp-*
/clutter/clutter-json.h
/clutter/cogl/cogl-defines-gl.h
/clutter/cogl/cogl-defines-gles.h
/clutter/cogl/cogl-enum-types.h
/clutter/cogl/cogl.h
/clutter/cogl/*.pc
/clutter/cogl/common/cogl-enum-types.[ch]
/clutter/cogl/common/stamp-cogl-enum-types.h
/clutter/cogl/gles/cogl-fixed-vertex-shader.[ch]
/clutter/cogl/gles/cogl-fixed-fragment-shader.[ch]
*.gir
@ -36,12 +39,12 @@ doc/reference/clutter/clutter-*.txt
doc/reference/clutter/html
doc/reference/clutter/tmpl
doc/reference/clutter/xml
doc/reference/clutter/version.xml
doc/reference/clutter/clutter.args
doc/reference/clutter/clutter.hierarchy
doc/reference/clutter/clutter.interfaces
doc/reference/clutter/clutter.prerequisites
doc/reference/clutter/clutter.signals
doc/reference/clutter/clutter-docs.xml
doc/reference/clutter/*.stamp
doc/reference/clutter/*.bak
doc/reference/cogl/cogl-*.txt
@ -49,12 +52,12 @@ doc/reference/cogl/cogl-*.txt
doc/reference/cogl/html
doc/reference/cogl/tmpl
doc/reference/cogl/xml
doc/reference/cogl/version.xml
doc/reference/cogl/cogl.args
doc/reference/cogl/cogl.hierarchy
doc/reference/cogl/cogl.interfaces
doc/reference/cogl/cogl.prerequisites
doc/reference/cogl/cogl.signals
doc/reference/cogl/cogl-docs.xml
doc/reference/cogl/*.stamp
doc/reference/cogl/*.bak
doltcompile
@ -193,7 +196,16 @@ stamp-h1
/tests/conform/test-list-model-filter
/tests/conform/test-npot-texture
/tests/conform/redhand.png
/tests/micro-bench/test-glyph-perf
/tests/conform/test-map-recursive
/tests/conform/test-realize-not-recursive
/tests/conform/test-shown-not-parented
/tests/conform/test-blend-strings
/tests/conform/test-color-from-string
/tests/conform/test-color-to-string
/tests/conform/test-units-constructors
/tests/conform/test-units-string
/tests/conform/test-conformance-result.xml
/tests/micro-bench/test-text-perf
/tests/micro-bench/test-text
/tests/micro-bench/test-picking
/tests/tools/disable-npots.sh

3
README
View file

@ -333,6 +333,9 @@ Release Notes for Clutter 1.0
* cogl_shader_get_parameteriv has been replaced by cogl_shader_get_type and
cogl_shader_is_compiled. More getters can be added later if desired.
* cogl_enable_depth_test has been renamed to cogl_set_depth_test_enabled and
a corresponding cogl_get_depth_test_enabled function has been added.
Release Notes for Clutter 0.8
-------------------------------

View file

@ -1,29 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:gnome="http://api.gnome.org/doap-extensions#"
xmlns="http://usefulinc.com/ns/doap#">
<name>Clutter</name>
<shortname>clutter</shortname>
<created>2006-11-18</created>
<shortdesc xml:lang="en">
Clutter is an OpenGL based interface library
</shortdesc>
<shortdesc xml:lang="en">Clutter is an OpenGL based interface library</shortdesc>
<description xml:lang="en">
Clutter is an open source software library for creating fast, visually
rich and animated graphical user interfaces. Clutter uses OpenGL (and
optionally OpenGL ES for use on Mobile and embedded platforms) for
rendering, but with an API which hides the underlying GL complexity
from the developer. The Clutter API is intended to be easy to use,
efficient and flexible.
</description>
<description xml:lang="en">Clutter is an open source software library for creating
fast, visually rich, portable and animated graphical user interfaces. Clutter uses
OpenGL (and optionally OpenGL|ES for use on Mobile and embedded platforms) for
rendering, but with an API which hides the underlying GL complexity from the
developer. The Clutter API is intended to be easy to use, efficient and
flexible.</description>
<homepage rdf:resource="http://www.clutter-project.org" />
<download-page rdf:resource="http://www.clutter-project.org/sources" />
<license rdf:resource="http://usefulinc.com/doap/licenses/lgpl" />
<bug-database rdf:resource="http://bugzilla.o-hand.com/enter_bug.cgi?product=Clutter"/>
<download-page rdf:resource="http://www.clutter-project.org/sources" />
<mailing-list rdf:resource="mailto:clutter+subscribe@o-hand.com" />
<programming-language>C</programming-language>
@ -32,6 +30,7 @@
<category rdf:resource="http://labs.o-hand.com/doap/category/graphics"/>
<category rdf:resource="http://labs.o-hand.com/doap/category/embedded"/>
<category rdf:resource="http://labs.o-hand.com/doap/category/clutter"/>
<maintainer>
<foaf:Person>
<foaf:name>Matthew Allum</foaf:name>
@ -39,6 +38,13 @@
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Emmanuele Bassi</foaf:name>
<foaf:mbox rdf:resource="mailto:ebassi@linux.intel.com"/>
</foaf:Person>
</maintainer>
<author>
<foaf:Person>
<foaf:name>Matthew Allum</foaf:name>
@ -49,15 +55,36 @@
<author>
<foaf:Person>
<foaf:name>Emmanuele Bassi</foaf:name>
<foaf:mbox rdf:resource="mailto:ebassi@o-hand.com"/>
<foaf:mbox rdf:resource="mailto:ebassi@linux.intel.com"/>
</foaf:Person>
</author>
<author>
<foaf:Person>
<foaf:name>Neil Roberts</foaf:name>
<foaf:mbox rdf:resource="mailto:neil@linux.intel.com"/>
</foaf:Person>
</author>
<author>
<foaf:Person>
<foaf:name>Robert Bragg</foaf:name>
<foaf:mbox rdf:resource="mailto:robert@linux.intel.com"/>
</foaf:Person>
</author>
<author>
<foaf:Person>
<foaf:name>Øyvind Kolås</foaf:name>
<foaf:mbox rdf:resource="mailto:pippin@linux.intel.com"/>
</foaf:Person>
</author>
<repository>
<SVNRepository>
<browse rdf:resource="http://svn.o-hand.com/view/clutter"/>
<location rdf:resource="https://svn.o-hand.com/repos/clutter"/>
</SVNRepository>
<GitRepository>
<browse rdf:resource="http://git.clutter-project.org/?r=clutter"/>
<location rdf:resource="git://git.clutter-project.org/clutter"/>
</GitRepository>
</repository>
<release>

View file

@ -169,6 +169,7 @@ source_c = \
$(srcdir)/clutter-list-model.c \
$(srcdir)/clutter-main.c \
clutter-marshal.c \
$(srcdir)/clutter-master-clock.c \
$(srcdir)/clutter-media.c \
$(srcdir)/clutter-model.c \
$(srcdir)/clutter-path.c \
@ -195,6 +196,7 @@ source_h_priv = \
$(srcdir)/clutter-bezier.h \
$(srcdir)/clutter-debug.h \
$(srcdir)/clutter-keysyms-table.h \
$(srcdir)/clutter-master-clock.h \
$(srcdir)/clutter-model-private.h \
$(srcdir)/clutter-private.h \
$(srcdir)/clutter-id-pool.h \
@ -234,7 +236,6 @@ clutter_HEADERS = \
$(source_h) \
$(top_builddir)/clutter/clutter-json.h \
$(top_builddir)/clutter/clutter-enum-types.h \
$(top_builddir)/clutter/clutter-version.h \
$(top_srcdir)/clutter/clutter.h
if HAVE_INTROSPECTION
@ -248,11 +249,6 @@ endif
# subdir Makefile.am, so just extract them from cogl.h instead. The doc
# comments for COGL are in the headers, so we don't need the source files.
Clutter-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_API_VERSION@.la
headers=`sed -n "s/#include <cogl\/\([^>]*\)>/\1/p" < $(top_srcdir)/clutter/cogl/cogl.h` ; \
cogl_headers="" ; \
for header in $$headers; do \
cogl_headers="$$cogl_headers $(top_srcdir)/clutter/cogl/$$header " ; \
done ; \
$(INTROSPECTION_SCANNER) -v --namespace Clutter --nsversion=@CLUTTER_API_VERSION@ \
$(INCLUDES) \
$(json_gir_include_path) \
@ -260,6 +256,7 @@ Clutter-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-@CLUTTER_
--include=GObject-2.0 \
--include=Pango-1.0 \
--include=PangoCairo-1.0 \
--include=Cogl-@CLUTTER_API_VERSION@ \
--include=ClutterJson-@CLUTTER_API_VERSION@ \
--library=clutter-@CLUTTER_FLAVOUR@-@CLUTTER_API_VERSION@ \
--libtool="$(top_builddir)/doltlibtool" \
@ -268,8 +265,6 @@ Clutter-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-@CLUTTER_
--pkg pangocairo \
--output $@ \
$(clutter_HEADERS) \
$$cogl_headers \
$(top_builddir)/clutter/cogl/cogl-defines-$(CLUTTER_COGL).h \
$(source_c)
BUILT_GIRSOURCES += Clutter-@CLUTTER_API_VERSION@.gir

File diff suppressed because it is too large Load diff

View file

@ -74,10 +74,10 @@ G_BEGIN_DECLS
*/
#define CLUTTER_ACTOR_UNSET_FLAGS(a,f) (((ClutterActor*)(a))->flags &= ~(f))
#define CLUTTER_ACTOR_IS_MAPPED(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_MAPPED) != FALSE)
#define CLUTTER_ACTOR_IS_REALIZED(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_REALIZED) != FALSE)
#define CLUTTER_ACTOR_IS_VISIBLE(e) (CLUTTER_ACTOR_IS_MAPPED (e) && CLUTTER_ACTOR_IS_REALIZED (e))
#define CLUTTER_ACTOR_IS_REACTIVE(e) ((((ClutterActor*)(e))->flags & CLUTTER_ACTOR_REACTIVE) != FALSE)
#define CLUTTER_ACTOR_IS_MAPPED(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_MAPPED) != FALSE)
#define CLUTTER_ACTOR_IS_REALIZED(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_REALIZED) != FALSE)
#define CLUTTER_ACTOR_IS_VISIBLE(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_VISIBLE) != FALSE)
#define CLUTTER_ACTOR_IS_REACTIVE(a) ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_REACTIVE) != FALSE)
typedef struct _ClutterActorClass ClutterActorClass;
typedef struct _ClutterActorBox ClutterActorBox;
@ -90,7 +90,8 @@ typedef struct _ClutterActorPrivate ClutterActorPrivate;
*
* Generic callback
*/
typedef void (*ClutterCallback) (ClutterActor *actor, gpointer data);
typedef void (*ClutterCallback) (ClutterActor *actor,
gpointer data);
/**
* CLUTTER_CALLBACK
@ -102,11 +103,12 @@ typedef void (*ClutterCallback) (ClutterActor *actor, gpointer data);
/**
* ClutterActorFlags:
* @CLUTTER_ACTOR_MAPPED: the actor has been painted
* @CLUTTER_ACTOR_MAPPED: the actor will be painted (is visible, and inside a toplevel, and all parents visible)
* @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been
* allocated
* @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emmitting event
* signals
* @CLUTTER_ACTOR_VISIBLE: the actor has been shown by the application program
*
* Flags used to signal the state of an actor.
*/
@ -114,9 +116,28 @@ typedef enum
{
CLUTTER_ACTOR_MAPPED = 1 << 1,
CLUTTER_ACTOR_REALIZED = 1 << 2,
CLUTTER_ACTOR_REACTIVE = 1 << 3
CLUTTER_ACTOR_REACTIVE = 1 << 3,
CLUTTER_ACTOR_VISIBLE = 1 << 4
} ClutterActorFlags;
/**
* ClutterAllocationFlags:
* @CLUTTER_ALLOCATION_NONE: No flag set
* @CLUTTER_ABSOLUTE_ORIGIN_CHANGED: Whether the absolute origin of the
* actor has changed; this implies that any ancestor of the actor has
* been moved
*
* Flags passed to the #ClutterActor::allocate() virtual function and
* to the clutter_actor_allocate() function
*
* Since: 1.0
*/
typedef enum
{
CLUTTER_ALLOCATION_NONE = 0,
CLUTTER_ABSOLUTE_ORIGIN_CHANGED = 1 << 1
} ClutterAllocationFlags;
/**
* ClutterActorBox:
* @x1: X coordinate of the top left corner
@ -126,15 +147,15 @@ typedef enum
*
* Bounding box of an actor. The coordinates of the top left and right bottom
* corners of an actor. The coordinates of the two points are expressed in
* #ClutterUnit<!-- -->s, that is are device-independent. If you want to obtain
* the box dimensions in pixels, use clutter_actor_get_geometry().
* pixels with sub-pixel precision
*/
struct _ClutterActorBox
{
ClutterUnit x1;
ClutterUnit y1;
ClutterUnit x2;
ClutterUnit y2;
gfloat x1;
gfloat y1;
gfloat x2;
gfloat y2;
};
GType clutter_actor_box_get_type (void) G_GNUC_CONST;
@ -177,6 +198,10 @@ struct _ClutterActor
* it should chain up to the parent's implementation
* @unrealize: virtual function, used to deallocate resources allocated
* in ::realize; it should chain up to the parent's implementation
* @map: virtual function for containers and composite actors, to
* map their children; it must chain up to the parent's implementation
* @unmap: virtual function for containers and composite actors, to
* unmap their children; it must chain up to the parent's implementation
* @paint: virtual function, used to paint the actor
* @get_preferred_width: virtual function, used when querying the minimum
* and natural widths of an actor for a given height; it is used by
@ -203,8 +228,8 @@ struct _ClutterActor
* @enter_event: signal class closure for #ClutterActor::enter-event
* @leave_event: signal class closure for #ClutterActor::leave-event
* @captured_event: signal class closure for #ClutterActor::captured-event
* @focus_in: signal class closure for #ClutterActor::focus-in
* @focus_out: signal class closure for #ClutterActor::focus-out
* @key_focus_in: signal class closure for #ClutterActor::focus-in
* @key_focus_out: signal class closure for #ClutterActor::focus-out
*
* Base class for actors.
*/
@ -220,6 +245,8 @@ struct _ClutterActorClass
void (* hide_all) (ClutterActor *actor);
void (* realize) (ClutterActor *actor);
void (* unrealize) (ClutterActor *actor);
void (* map) (ClutterActor *actor);
void (* unmap) (ClutterActor *actor);
void (* paint) (ClutterActor *actor);
void (* parent_set) (ClutterActor *actor,
ClutterActor *old_parent);
@ -232,17 +259,17 @@ struct _ClutterActorClass
ClutterActor *leaf_that_queued);
/* size negotiation */
void (* get_preferred_width) (ClutterActor *actor,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p);
void (* get_preferred_height) (ClutterActor *actor,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p);
void (* allocate) (ClutterActor *actor,
const ClutterActorBox *box,
gboolean absolute_origin_changed);
void (* get_preferred_width) (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p);
void (* get_preferred_height) (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p);
void (* allocate) (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags);
/* event signals */
gboolean (* event) (ClutterActor *actor,
ClutterEvent *event);
@ -264,8 +291,8 @@ struct _ClutterActorClass
ClutterCrossingEvent *event);
gboolean (* captured_event) (ClutterActor *actor,
ClutterEvent *event);
void (* focus_in) (ClutterActor *actor);
void (* focus_out) (ClutterActor *actor);
void (* key_focus_in) (ClutterActor *actor);
void (* key_focus_out) (ClutterActor *actor);
/*< private >*/
/* padding for future expansion */
@ -274,12 +301,20 @@ struct _ClutterActorClass
GType clutter_actor_get_type (void) G_GNUC_CONST;
void clutter_actor_set_flags (ClutterActor *self,
ClutterActorFlags flags);
void clutter_actor_unset_flags (ClutterActor *self,
ClutterActorFlags flags);
ClutterActorFlags clutter_actor_get_flags (ClutterActor *self);
void clutter_actor_show (ClutterActor *self);
void clutter_actor_show_all (ClutterActor *self);
void clutter_actor_hide (ClutterActor *self);
void clutter_actor_hide_all (ClutterActor *self);
void clutter_actor_realize (ClutterActor *self);
void clutter_actor_unrealize (ClutterActor *self);
void clutter_actor_map (ClutterActor *self);
void clutter_actor_unmap (ClutterActor *self);
void clutter_actor_paint (ClutterActor *self);
void clutter_actor_pick (ClutterActor *self,
const ClutterColor *color);
@ -289,23 +324,29 @@ void clutter_actor_destroy (ClutterActor
/* size negotiation */
void clutter_actor_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p);
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p);
void clutter_actor_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p);
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p);
void clutter_actor_get_preferred_size (ClutterActor *self,
ClutterUnit *min_width_p,
ClutterUnit *min_height_p,
ClutterUnit *natural_width_p,
ClutterUnit *natural_height_p);
gfloat *min_width_p,
gfloat *min_height_p,
gfloat *natural_width_p,
gfloat *natural_height_p);
void clutter_actor_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean absolute_origin_changed);
ClutterAllocationFlags flags);
void clutter_actor_allocate_preferred_size (ClutterActor *self,
gboolean absolute_origin_changed);
ClutterAllocationFlags flags);
void clutter_actor_allocate_available_size (ClutterActor *self,
gfloat x,
gfloat y,
gfloat available_width,
gfloat available_height,
ClutterAllocationFlags flags);
void clutter_actor_get_allocation_coords (ClutterActor *self,
gint *x_1,
gint *y_1,
@ -324,100 +365,60 @@ void clutter_actor_set_geometry (ClutterActor
void clutter_actor_get_geometry (ClutterActor *self,
ClutterGeometry *geometry);
void clutter_actor_set_size (ClutterActor *self,
gint width,
gint height);
void clutter_actor_set_sizeu (ClutterActor *self,
ClutterUnit width,
ClutterUnit height);
gfloat width,
gfloat height);
void clutter_actor_get_size (ClutterActor *self,
guint *width,
guint *height);
void clutter_actor_get_sizeu (ClutterActor *self,
ClutterUnit *width,
ClutterUnit *height);
gfloat *width,
gfloat *height);
void clutter_actor_get_transformed_size (ClutterActor *self,
guint *width,
guint *height);
void clutter_actor_get_transformed_sizeu (ClutterActor *self,
ClutterUnit *width,
ClutterUnit *height);
gfloat *width,
gfloat *height);
void clutter_actor_set_position (ClutterActor *self,
gint x,
gint y);
void clutter_actor_set_positionu (ClutterActor *self,
ClutterUnit x,
ClutterUnit y);
gfloat x,
gfloat y);
void clutter_actor_get_position (ClutterActor *self,
gint *x,
gint *y);
void clutter_actor_get_positionu (ClutterActor *self,
ClutterUnit *x,
ClutterUnit *y);
gfloat *x,
gfloat *y);
void clutter_actor_get_transformed_position (ClutterActor *self,
gint *x,
gint *y);
void clutter_actor_get_transformed_positionu (ClutterActor *self,
ClutterUnit *x,
ClutterUnit *y);
gfloat *x,
gfloat *y);
gboolean clutter_actor_get_fixed_position_set (ClutterActor *self);
void clutter_actor_set_fixed_position_set (ClutterActor *self,
gboolean is_set);
guint clutter_actor_get_width (ClutterActor *self);
ClutterUnit clutter_actor_get_widthu (ClutterActor *self);
guint clutter_actor_get_height (ClutterActor *self);
ClutterUnit clutter_actor_get_heightu (ClutterActor *self);
gfloat clutter_actor_get_width (ClutterActor *self);
gfloat clutter_actor_get_height (ClutterActor *self);
void clutter_actor_set_width (ClutterActor *self,
guint width);
void clutter_actor_set_widthu (ClutterActor *self,
ClutterUnit width);
gfloat width);
void clutter_actor_set_height (ClutterActor *self,
guint height);
void clutter_actor_set_heightu (ClutterActor *self,
ClutterUnit height);
gint clutter_actor_get_x (ClutterActor *self);
ClutterUnit clutter_actor_get_xu (ClutterActor *self);
gint clutter_actor_get_y (ClutterActor *self);
ClutterUnit clutter_actor_get_yu (ClutterActor *self);
gfloat height);
gfloat clutter_actor_get_x (ClutterActor *self);
gfloat clutter_actor_get_y (ClutterActor *self);
void clutter_actor_set_x (ClutterActor *self,
gint x);
void clutter_actor_set_xu (ClutterActor *self,
ClutterUnit x);
gfloat x);
void clutter_actor_set_y (ClutterActor *self,
gint y);
void clutter_actor_set_yu (ClutterActor *self,
ClutterUnit y);
gfloat y);
void clutter_actor_set_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
gint x,
gint y,
gint z);
void clutter_actor_set_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
ClutterUnit x,
ClutterUnit y,
ClutterUnit z);
gfloat x,
gfloat y,
gfloat z);
void clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
gdouble angle,
ClutterGravity gravity);
gdouble clutter_actor_get_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gint *x,
gint *y,
gint *z);
gdouble clutter_actor_get_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
ClutterUnit *x,
ClutterUnit *y,
ClutterUnit *z);
gfloat *x,
gfloat *y,
gfloat *z);
ClutterGravity clutter_actor_get_z_rotation_gravity (ClutterActor *self);
void clutter_actor_set_opacity (ClutterActor *self,
guint8 opacity);
guint8 clutter_actor_get_opacity (ClutterActor *self);
guint8 clutter_actor_get_paint_opacity (ClutterActor *self);
gboolean clutter_actor_get_paint_visibility (ClutterActor *self);
@ -428,27 +429,17 @@ G_CONST_RETURN gchar *clutter_actor_get_name (ClutterActor
guint32 clutter_actor_get_gid (ClutterActor *self);
void clutter_actor_set_clip (ClutterActor *self,
gint xoff,
gint yoff,
gint width,
gint height);
void clutter_actor_set_clipu (ClutterActor *self,
ClutterUnit xoff,
ClutterUnit yoff,
ClutterUnit width,
ClutterUnit height);
gfloat xoff,
gfloat yoff,
gfloat width,
gfloat height);
void clutter_actor_remove_clip (ClutterActor *self);
gboolean clutter_actor_has_clip (ClutterActor *self);
void clutter_actor_get_clip (ClutterActor *self,
gint *xoff,
gint *yoff,
gint *width,
gint *height);
void clutter_actor_get_clipu (ClutterActor *self,
ClutterUnit *xoff,
ClutterUnit *yoff,
ClutterUnit *width,
ClutterUnit *height);
gfloat *xoff,
gfloat *yoff,
gfloat *width,
gfloat *height);
void clutter_actor_set_parent (ClutterActor *self,
ClutterActor *parent);
@ -465,11 +456,8 @@ void clutter_actor_lower (ClutterActor
void clutter_actor_raise_top (ClutterActor *self);
void clutter_actor_lower_bottom (ClutterActor *self);
void clutter_actor_set_depth (ClutterActor *self,
gint depth);
gint clutter_actor_get_depth (ClutterActor *self);
void clutter_actor_set_depthu (ClutterActor *self,
ClutterUnit depth);
ClutterUnit clutter_actor_get_depthu (ClutterActor *self);
gfloat depth);
gfloat clutter_actor_get_depth (ClutterActor *self);
void clutter_actor_set_scale (ClutterActor *self,
gdouble scale_x,
@ -477,13 +465,8 @@ void clutter_actor_set_scale (ClutterActor
void clutter_actor_set_scale_full (ClutterActor *self,
gdouble scale_x,
gdouble scale_y,
int center_x,
int center_y);
void clutter_actor_set_scale_fullu (ClutterActor *self,
gdouble scale_x,
gdouble scale_y,
ClutterUnit center_x,
ClutterUnit center_y);
gfloat center_x,
gfloat center_y);
void clutter_actor_set_scale_with_gravity (ClutterActor *self,
gdouble scale_x,
gdouble scale_y,
@ -492,19 +475,13 @@ void clutter_actor_get_scale (ClutterActor
gdouble *scale_x,
gdouble *scale_y);
void clutter_actor_get_scale_center (ClutterActor *self,
gint *center_x,
gint *center_y);
void clutter_actor_get_scale_centeru (ClutterActor *self,
ClutterUnit *center_x,
ClutterUnit *center_y);
gfloat *center_x,
gfloat *center_y);
ClutterGravity clutter_actor_get_scale_gravity (ClutterActor *self);
void clutter_actor_move_by (ClutterActor *self,
gint dx,
gint dy);
void clutter_actor_move_byu (ClutterActor *self,
ClutterUnit dx,
ClutterUnit dy);
gfloat dx,
gfloat dy);
void clutter_actor_set_reactive (ClutterActor *actor,
gboolean reactive);
@ -530,34 +507,25 @@ void clutter_actor_set_shader_param_float (ClutterActor
gfloat value);
void clutter_actor_set_anchor_point (ClutterActor *self,
gint anchor_x,
gint anchor_y);
gfloat anchor_x,
gfloat anchor_y);
void clutter_actor_move_anchor_point (ClutterActor *self,
gint anchor_x,
gint anchor_y);
gfloat anchor_x,
gfloat anchor_y);
void clutter_actor_get_anchor_point (ClutterActor *self,
gint *anchor_x,
gint *anchor_y);
gfloat *anchor_x,
gfloat *anchor_y);
ClutterGravity clutter_actor_get_anchor_point_gravity (ClutterActor *self);
void clutter_actor_set_anchor_pointu (ClutterActor *self,
ClutterUnit anchor_x,
ClutterUnit anchor_y);
void clutter_actor_move_anchor_pointu (ClutterActor *self,
ClutterUnit anchor_x,
ClutterUnit anchor_y);
void clutter_actor_get_anchor_pointu (ClutterActor *self,
ClutterUnit *anchor_x,
ClutterUnit *anchor_y);
void clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
ClutterGravity gravity);
void clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
ClutterGravity gravity);
gboolean clutter_actor_transform_stage_point (ClutterActor *self,
ClutterUnit x,
ClutterUnit y,
ClutterUnit *x_out,
ClutterUnit *y_out);
gfloat x,
gfloat y,
gfloat *x_out,
gfloat *y_out);
gboolean clutter_actor_is_rotated (ClutterActor *self);
gboolean clutter_actor_is_scaled (ClutterActor *self);
gboolean clutter_actor_should_pick_paint (ClutterActor *self);

View file

@ -603,9 +603,7 @@ clutter_ease_out_quad (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble p = t / d;
gdouble p = clutter_timeline_get_progress (timeline);
return -1.0 * p * (p - 2);
}
@ -615,8 +613,8 @@ clutter_ease_in_out_quad (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / (d / 2);
if (p < 1)
@ -632,9 +630,7 @@ clutter_ease_in_cubic (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble p = t / d;
gdouble p = clutter_timeline_get_progress (timeline);
return p * p * p;
}
@ -644,8 +640,8 @@ clutter_ease_out_cubic (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / d - 1;
return p * p * p + 1;
@ -656,8 +652,8 @@ clutter_ease_in_out_cubic (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / (d / 2);
if (p < 1)
@ -673,9 +669,7 @@ clutter_ease_in_quart (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble p = t / d;
gdouble p = clutter_timeline_get_progress (timeline);
return p * p * p * p;
}
@ -685,8 +679,8 @@ clutter_ease_out_quart (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / d - 1;
return -1.0 * (p * p * p * p - 1);
@ -697,8 +691,8 @@ clutter_ease_in_out_quart (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / (d / 2);
if (p < 1)
@ -714,9 +708,7 @@ clutter_ease_in_quint (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble p = t / d;
gdouble p = clutter_timeline_get_progress (timeline);
return p * p * p * p * p;
}
@ -726,8 +718,8 @@ clutter_ease_out_quint (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / d - 1;
return p * p * p * p * p + 1;
@ -738,8 +730,8 @@ clutter_ease_in_out_quint (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / (d / 2);
if (p < 1)
@ -755,8 +747,8 @@ clutter_ease_in_sine (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
return -1.0 * cos (t / d * G_PI_2) + 1.0;
}
@ -766,8 +758,8 @@ clutter_ease_out_sine (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
return sin (t / d * G_PI_2);
}
@ -777,8 +769,8 @@ clutter_ease_in_out_sine (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
return -0.5 * (cos (G_PI * t / d) - 1);
}
@ -788,8 +780,8 @@ clutter_ease_in_expo (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
return (t == 0) ? 0.0 : pow (2, 10 * (t / d - 1));
}
@ -799,8 +791,8 @@ clutter_ease_out_expo (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
return (t == d) ? 1.0 : -pow (2, -10 * t / d) + 1;
}
@ -810,8 +802,8 @@ clutter_ease_in_out_expo (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p;
if (t == 0)
@ -835,9 +827,7 @@ clutter_ease_in_circ (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble p = t / d;
gdouble p = clutter_timeline_get_progress (timeline);
return -1.0 * (sqrt (1 - p * p) - 1);
}
@ -847,8 +837,8 @@ clutter_ease_out_circ (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / d - 1;
return sqrt (1 - p * p);
@ -859,8 +849,8 @@ clutter_ease_in_out_circ (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / (d / 2);
if (p < 1)
@ -876,8 +866,8 @@ clutter_ease_in_elastic (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = d * .3;
gdouble s = p / 4;
gdouble q = t / d;
@ -895,8 +885,8 @@ clutter_ease_out_elastic (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = d * .3;
gdouble s = p / 4;
gdouble q = t / d;
@ -912,8 +902,8 @@ clutter_ease_in_out_elastic (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = d * (.3 * 1.5);
gdouble s = p / 4;
gdouble q = t / (d / 2);
@ -942,9 +932,7 @@ clutter_ease_in_back (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble p = t / d;
gdouble p = clutter_timeline_get_progress (timeline);
return p * p * ((1.70158 + 1) * p - 1.70158);
}
@ -954,8 +942,8 @@ clutter_ease_out_back (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / d - 1;
return p * p * ((1.70158 + 1) * p + 1.70158) + 1;
@ -966,8 +954,8 @@ clutter_ease_in_out_back (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
gdouble p = t / (d / 2);
gdouble s = 1.70158 * 1.525;
@ -1019,8 +1007,8 @@ clutter_ease_in_bounce (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
return ease_in_bounce_internal (t, d);
}
@ -1030,8 +1018,8 @@ clutter_ease_out_bounce (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
return ease_out_bounce_internal (t, d);
}
@ -1041,8 +1029,8 @@ clutter_ease_in_out_bounce (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = alpha->priv->timeline;
gdouble t = clutter_timeline_get_current_frame (timeline);
gdouble d = clutter_timeline_get_n_frames (timeline);
gdouble t = clutter_timeline_get_elapsed_time (timeline);
gdouble d = clutter_timeline_get_duration (timeline);
if (t < d / 2)
return ease_in_bounce_internal (t * 2, d) * 0.5;

View file

@ -86,9 +86,12 @@ clutter_animatable_get_type (void)
* All implementation of the #ClutterAnimatable interface must
* implement this function.
*
* Return value: %TRUE if the value has been validated and can
* be applied to the #ClutterAnimatable, and %FALSE otherwise
*
* Since: 1.0
*/
void
gboolean
clutter_animatable_animate_property (ClutterAnimatable *animatable,
ClutterAnimation *animation,
const gchar *property_name,
@ -97,21 +100,27 @@ clutter_animatable_animate_property (ClutterAnimatable *animatable,
gdouble progress,
GValue *value)
{
g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable));
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
g_return_if_fail (property_name != NULL);
g_return_if_fail (initial_value != NULL && final_value != NULL);
g_return_if_fail (G_VALUE_TYPE (initial_value) != G_TYPE_INVALID);
g_return_if_fail (G_VALUE_TYPE (final_value) != G_TYPE_INVALID);
g_return_if_fail (value != NULL);
g_return_if_fail (G_VALUE_TYPE (value) == G_VALUE_TYPE (initial_value) &&
G_VALUE_TYPE (value) == G_VALUE_TYPE (final_value));
gboolean res;
CLUTTER_ANIMATABLE_GET_IFACE (animatable)->animate_property (animatable,
animation,
property_name,
initial_value,
final_value,
progress,
value);
g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), FALSE);
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE);
g_return_val_if_fail (property_name != NULL, FALSE);
g_return_val_if_fail (initial_value != NULL && final_value != NULL, FALSE);
g_return_val_if_fail (G_VALUE_TYPE (initial_value) != G_TYPE_INVALID, FALSE);
g_return_val_if_fail (G_VALUE_TYPE (final_value) != G_TYPE_INVALID, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (G_VALUE_TYPE (value) == G_VALUE_TYPE (initial_value) &&
G_VALUE_TYPE (value) == G_VALUE_TYPE (final_value),
FALSE);
res =
CLUTTER_ANIMATABLE_GET_IFACE (animatable)->animate_property (animatable,
animation,
property_name,
initial_value,
final_value,
progress,
value);
return res;
}

View file

@ -56,24 +56,24 @@ struct _ClutterAnimatableIface
GTypeInterface parent_iface;
/*< public >*/
void (* animate_property) (ClutterAnimatable *animatable,
ClutterAnimation *animation,
const gchar *property_name,
const GValue *initial_value,
const GValue *final_value,
gdouble progress,
GValue *value);
gboolean (* animate_property) (ClutterAnimatable *animatable,
ClutterAnimation *animation,
const gchar *property_name,
const GValue *initial_value,
const GValue *final_value,
gdouble progress,
GValue *value);
};
GType clutter_animatable_get_type (void) G_GNUC_CONST;
void clutter_animatable_animate_property (ClutterAnimatable *animatable,
ClutterAnimation *animation,
const gchar *property_name,
const GValue *initial_value,
const GValue *final_value,
gdouble progress,
GValue *value);
gboolean clutter_animatable_animate_property (ClutterAnimatable *animatable,
ClutterAnimation *animation,
const gchar *property_name,
const GValue *initial_value,
const GValue *final_value,
gdouble progress,
GValue *value);
G_END_DECLS

View file

@ -25,14 +25,43 @@
/**
* SECTION:clutter-animation
* @short_description: Simple implicit animations
* @See_Also: #ClutterAnimatable, #ClutterInterval, #ClutterAlpha,
* #ClutterTimeline
*
* #ClutterAnimation is an object providing simple, implicit animations
* for #GObject<!-- -->s.
*
* #ClutterAnimation instances will bind a #GObject property belonging
* to a #GObject to a #ClutterInterval, and will then use a #ClutterTimeline
* to interpolate the property between the initial and final values of the
* interval.
* #ClutterAnimation instances will bind one or more #GObject properties
* belonging to a #GObject to a #ClutterInterval, and will then use a
* #ClutterAlpha to interpolate the property between the initial and final
* values of the interval.
*
* The duration of the animation is set using clutter_animation_set_duration().
* The easing mode of the animation is set using clutter_animation_set_mode().
*
* If you want to control the animation you should retrieve the
* #ClutterTimeline using clutter_animation_get_timeline() and then
* use #ClutterTimeline functions like clutter_timeline_start(),
* clutter_timeline_pause() or clutter_timeline_stop().
*
* A #ClutterAnimation will emit the #ClutterAnimation::completed signal
* when the #ClutterTimeline used by the animation is completed; unlike
* #ClutterTimeline, though, the #ClutterAnimation::completed will not be
* emitted if #ClutterAnimation:loop is set to %TRUE - that is, a looping
* animation never completes.
*
* If your animation depends on user control you can force its completion
* using clutter_animation_completed().
*
* If the #GObject instance bound to a #ClutterAnimation implements the
* #ClutterAnimatable interface it is possible for that instance to
* control the way the initial and final states are interpolated.
*
* #ClutterAnimation<!-- -->s are distinguished from #ClutterBehaviour<!-- -->s
* because the former can only control #GObject properties of a single
* #GObject instance, while the latter can control multiple properties
* using accessor functions inside the #ClutterBehaviour::alpha_notify
* virtual function, and can control multiple #ClutterActor<!-- -->s as well.
*
* For convenience, it is possible to use the clutter_actor_animate()
* function call which will take care of setting up and tearing down
@ -85,16 +114,10 @@ struct _ClutterAnimationPrivate
GHashTable *properties;
gulong mode;
ClutterAlpha *alpha;
guint loop : 1;
guint duration;
ClutterTimeline *timeline;
guint timeline_started_id;
guint timeline_completed_id;
ClutterAlpha *alpha;
guint alpha_notify_id;
};
@ -122,48 +145,43 @@ static void
clutter_animation_dispose (GObject *gobject)
{
ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv;
ClutterTimeline *timeline;
if (priv->object)
if (priv->alpha != NULL)
timeline = clutter_alpha_get_timeline (priv->alpha);
else
timeline = NULL;
if (timeline != NULL && priv->timeline_started_id != 0)
g_signal_handler_disconnect (timeline, priv->timeline_started_id);
if (timeline != NULL && priv->timeline_completed_id != 0)
g_signal_handler_disconnect (timeline, priv->timeline_completed_id);
priv->timeline_started_id = 0;
priv->timeline_completed_id = 0;
if (priv->alpha != NULL)
{
if (priv->alpha_notify_id != 0)
g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id);
g_object_unref (priv->alpha);
}
priv->alpha_notify_id = 0;
priv->alpha = NULL;
if (priv->object != NULL)
{
g_object_weak_unref (G_OBJECT (gobject),
on_animation_weak_notify,
priv->object);
g_object_set_qdata (priv->object, quark_object_animation, NULL);
g_object_unref (priv->object);
priv->object = NULL;
}
if (priv->timeline)
{
if (priv->timeline_started_id)
{
g_signal_handler_disconnect (priv->timeline,
priv->timeline_started_id);
priv->timeline_started_id = 0;
}
if (priv->timeline_completed_id)
{
g_signal_handler_disconnect (priv->timeline,
priv->timeline_completed_id);
priv->timeline_completed_id = 0;
}
g_object_unref (priv->timeline);
priv->timeline = NULL;
}
if (priv->alpha)
{
if (priv->alpha_notify_id)
{
g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id);
priv->alpha_notify_id = 0;
}
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
priv->object = NULL;
G_OBJECT_CLASS (clutter_animation_parent_class)->dispose (gobject);
}
@ -214,7 +232,8 @@ clutter_animation_get_property (GObject *gobject,
GValue *value,
GParamSpec *pspec)
{
ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv;
ClutterAnimation *animation = CLUTTER_ANIMATION (gobject);
ClutterAnimationPrivate *priv = animation->priv;
switch (prop_id)
{
@ -223,23 +242,23 @@ clutter_animation_get_property (GObject *gobject,
break;
case PROP_MODE:
g_value_set_ulong (value, priv->mode);
g_value_set_ulong (value, clutter_animation_get_mode (animation));
break;
case PROP_DURATION:
g_value_set_uint (value, priv->duration);
g_value_set_uint (value, clutter_animation_get_duration (animation));
break;
case PROP_LOOP:
g_value_set_boolean (value, priv->loop);
g_value_set_boolean (value, clutter_animation_get_loop (animation));
break;
case PROP_TIMELINE:
g_value_set_object (value, priv->timeline);
g_value_set_object (value, clutter_animation_get_timeline (animation));
break;
case PROP_ALPHA:
g_value_set_object (value, priv->alpha);
g_value_set_object (value, clutter_animation_get_alpha (animation));
break;
default:
@ -370,7 +389,7 @@ clutter_animation_class_init (ClutterAnimationClass *klass)
G_TYPE_NONE, 0);
/**
* ClutterAniamtion::completed:
* ClutterAnimation::completed:
* @animation: the animation that emitted the signal
*
* The ::completed signal is emitted once the animation has
@ -396,7 +415,6 @@ clutter_animation_init (ClutterAnimation *self)
{
self->priv = CLUTTER_ANIMATION_GET_PRIVATE (self);
self->priv->mode = CLUTTER_LINEAR;
self->priv->properties =
g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
@ -750,7 +768,7 @@ on_timeline_completed (ClutterTimeline *timeline,
{
CLUTTER_NOTE (ANIMATION, "Timeline [%p] complete", timeline);
if (!animation->priv->loop)
if (!clutter_animation_get_loop (animation))
g_signal_emit (animation, animation_signals[COMPLETED], 0);
}
@ -781,6 +799,7 @@ on_alpha_notify (GObject *gobject,
const gchar *p_name = p->data;
ClutterInterval *interval;
GValue value = { 0, };
gboolean apply;
interval = g_hash_table_lookup (priv->properties, p_name);
g_assert (CLUTTER_IS_INTERVAL (interval));
@ -794,23 +813,22 @@ on_alpha_notify (GObject *gobject,
initial = clutter_interval_peek_initial_value (interval);
final = clutter_interval_peek_final_value (interval);
CLUTTER_NOTE (ANIMATION, "Animatable property '%s'", p_name);
clutter_animatable_animate_property (animatable, animation,
p_name,
initial, final,
alpha_value,
&value);
g_object_set_property (priv->object, p_name, &value);
apply = clutter_animatable_animate_property (animatable, animation,
p_name,
initial, final,
alpha_value,
&value);
}
else
{
CLUTTER_NOTE (ANIMATION, "Standard property '%s'", p_name);
if (clutter_interval_compute_value (interval, alpha_value, &value))
g_object_set_property (priv->object, p_name, &value);
apply = clutter_interval_compute_value (interval,
alpha_value,
&value);
}
if (apply)
g_object_set_property (priv->object, p_name, &value);
g_value_unset (&value);
}
@ -819,6 +837,65 @@ on_alpha_notify (GObject *gobject,
g_object_thaw_notify (priv->object);
}
static ClutterAlpha *
clutter_animation_get_alpha_internal (ClutterAnimation *animation)
{
ClutterAnimationPrivate *priv = animation->priv;
if (priv->alpha == NULL)
{
ClutterAlpha *alpha;
alpha = clutter_alpha_new ();
clutter_alpha_set_mode (alpha, CLUTTER_LINEAR);
priv->alpha_notify_id =
g_signal_connect (alpha, "notify::alpha",
G_CALLBACK (on_alpha_notify),
animation);
priv->alpha = g_object_ref_sink (alpha);
g_object_notify (G_OBJECT (animation), "alpha");
}
return priv->alpha;
}
static ClutterTimeline *
clutter_animation_get_timeline_internal (ClutterAnimation *animation)
{
ClutterAnimationPrivate *priv = animation->priv;
ClutterTimeline *timeline;
ClutterAlpha *alpha;
alpha = clutter_animation_get_alpha_internal (animation);
timeline = clutter_alpha_get_timeline (alpha);
if (timeline != NULL)
return timeline;
timeline = g_object_new (CLUTTER_TYPE_TIMELINE, NULL);
priv->timeline_started_id =
g_signal_connect (timeline, "started",
G_CALLBACK (on_timeline_started),
animation);
priv->timeline_completed_id =
g_signal_connect (timeline, "completed",
G_CALLBACK (on_timeline_completed),
animation);
clutter_alpha_set_timeline (alpha, timeline);
/* the alpha owns the timeline now */
g_object_unref (timeline);
g_object_notify (G_OBJECT (animation), "timeline");
return timeline;
}
/*
* Removes the animation pointer from the qdata section of the
* actor attached to the animation
@ -924,16 +1001,6 @@ clutter_animation_get_object (ClutterAnimation *animation)
return animation->priv->object;
}
static inline void
clutter_animation_set_mode_internal (ClutterAnimation *animation,
ClutterAlpha *alpha)
{
ClutterAnimationPrivate *priv = animation->priv;
if (alpha)
clutter_alpha_set_mode (alpha, priv->mode);
}
/**
* clutter_animation_set_mode:
* @animation: a #ClutterAnimation
@ -943,22 +1010,26 @@ clutter_animation_set_mode_internal (ClutterAnimation *animation,
* a logical id, either coming from the #ClutterAnimationMode enumeration
* or the return value of clutter_alpha_register_func().
*
* This function will also set #ClutterAnimation:alpha if needed.
*
* Since: 1.0
*/
void
clutter_animation_set_mode (ClutterAnimation *animation,
gulong mode)
{
ClutterAnimationPrivate *priv;
ClutterAlpha *alpha;
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
priv = animation->priv;
g_object_freeze_notify (G_OBJECT (animation));
priv->mode = mode;
clutter_animation_set_mode_internal (animation, priv->alpha);
alpha = clutter_animation_get_alpha_internal (animation);
clutter_alpha_set_mode (alpha, mode);
g_object_notify (G_OBJECT (animation), "mode");
g_object_thaw_notify (G_OBJECT (animation));
}
/**
@ -975,9 +1046,13 @@ clutter_animation_set_mode (ClutterAnimation *animation,
gulong
clutter_animation_get_mode (ClutterAnimation *animation)
{
ClutterAlpha *alpha;
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), CLUTTER_LINEAR);
return animation->priv->mode;
alpha = clutter_animation_get_alpha_internal (animation);
return clutter_alpha_get_mode (alpha);
}
/**
@ -987,35 +1062,28 @@ clutter_animation_get_mode (ClutterAnimation *animation)
*
* Sets the duration of @animation in milliseconds.
*
* This function will set #ClutterAnimation:alpha and
* #ClutterAnimation:timeline if needed.
*
* Since: 1.0
*/
void
clutter_animation_set_duration (ClutterAnimation *animation,
gint msecs)
{
ClutterAnimationPrivate *priv;
ClutterTimeline *timeline;
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
priv = animation->priv;
g_object_freeze_notify (G_OBJECT (animation));
priv->duration = msecs;
if (priv->timeline)
{
gboolean was_playing;
was_playing = clutter_timeline_is_playing (priv->timeline);
if (was_playing)
clutter_timeline_stop (priv->timeline);
clutter_timeline_set_duration (priv->timeline, msecs);
if (was_playing)
clutter_timeline_start (priv->timeline);
}
timeline = clutter_animation_get_timeline_internal (animation);
clutter_timeline_set_duration (timeline, msecs);
clutter_timeline_rewind (timeline);
g_object_notify (G_OBJECT (animation), "duration");
g_object_thaw_notify (G_OBJECT (animation));
}
/**
@ -1028,27 +1096,27 @@ clutter_animation_set_duration (ClutterAnimation *animation,
* A looping #ClutterAnimation will not emit the #ClutterAnimation::completed
* signal when finished.
*
* This function will set #ClutterAnimation:alpha and
* #ClutterAnimation:timeline if needed.
*
* Since: 1.0
*/
void
clutter_animation_set_loop (ClutterAnimation *animation,
gboolean loop)
{
ClutterAnimationPrivate *priv;
ClutterTimeline *timeline;
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
priv = animation->priv;
g_object_freeze_notify (G_OBJECT (animation));
if (priv->loop != loop)
{
priv->loop = loop;
timeline = clutter_animation_get_timeline_internal (animation);
clutter_timeline_set_loop (timeline, loop);
if (priv->timeline)
clutter_timeline_set_loop (priv->timeline, priv->loop);
g_object_notify (G_OBJECT (animation), "loop");
g_object_notify (G_OBJECT (animation), "loop");
}
g_object_thaw_notify (G_OBJECT (animation));
}
/**
@ -1064,9 +1132,13 @@ clutter_animation_set_loop (ClutterAnimation *animation,
gboolean
clutter_animation_get_loop (ClutterAnimation *animation)
{
ClutterTimeline *timeline;
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE);
return animation->priv->loop;
timeline = clutter_animation_get_timeline_internal (animation);
return clutter_timeline_get_loop (timeline);
}
/**
@ -1082,26 +1154,23 @@ clutter_animation_get_loop (ClutterAnimation *animation)
guint
clutter_animation_get_duration (ClutterAnimation *animation)
{
ClutterTimeline *timeline;
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), 0);
return animation->priv->duration;
timeline = clutter_animation_get_timeline_internal (animation);
return clutter_timeline_get_duration (timeline);
}
/**
* clutter_animation_set_timeline:
* @animation: a #ClutterAnimation
* @timeline: a #ClutterTimeline or %NULL
* @timeline: a #ClutterTimeline, or %NULL to unset the
* current #ClutterTimeline
*
* Sets the #ClutterTimeline used by @animation.
*
* The #ClutterAnimation:duration and #ClutterAnimation:loop properties
* will be set using the corresponding #ClutterTimeline properties as a
* side effect.
*
* If @timeline is %NULL a new #ClutterTimeline will be constructed
* using the current values of the #ClutterAnimation:duration and
* #ClutterAnimation:loop properties.
*
* Since: 1.0
*/
void
@ -1109,62 +1178,50 @@ clutter_animation_set_timeline (ClutterAnimation *animation,
ClutterTimeline *timeline)
{
ClutterAnimationPrivate *priv;
ClutterTimeline *cur_timeline;
ClutterAlpha *alpha;
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
g_return_if_fail (timeline == NULL || CLUTTER_IS_TIMELINE (timeline));
priv = animation->priv;
if (timeline != NULL && priv->timeline == timeline)
if (priv->alpha != NULL)
cur_timeline = clutter_alpha_get_timeline (priv->alpha);
else
cur_timeline = NULL;
if (cur_timeline == timeline)
return;
g_object_freeze_notify (G_OBJECT (animation));
if (priv->timeline != NULL)
{
if (priv->timeline_started_id)
g_signal_handler_disconnect (priv->timeline,
priv->timeline_started_id);
if (cur_timeline != NULL && priv->timeline_started_id != 0)
g_signal_handler_disconnect (cur_timeline, priv->timeline_started_id);
if (priv->timeline_completed_id)
g_signal_handler_disconnect (priv->timeline,
priv->timeline_completed_id);
if (cur_timeline != NULL && priv->timeline_completed_id != 0)
g_signal_handler_disconnect (cur_timeline, priv->timeline_completed_id);
g_object_unref (priv->timeline);
priv->timeline_started_id = 0;
priv->timeline_completed_id = 0;
priv->timeline = 0;
}
priv->timeline_started_id = 0;
priv->timeline_completed_id = 0;
if (timeline == NULL)
{
timeline = g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", priv->duration,
"loop", priv->loop,
NULL);
}
else
{
g_object_ref (timeline);
priv->duration = clutter_timeline_get_duration (timeline);
g_object_notify (G_OBJECT (animation), "duration");
priv->loop = clutter_timeline_get_loop (timeline);
g_object_notify (G_OBJECT (animation), "loop");
}
priv->timeline = timeline;
alpha = clutter_animation_get_alpha_internal (animation);
clutter_alpha_set_timeline (alpha, timeline);
g_object_notify (G_OBJECT (animation), "timeline");
g_object_notify (G_OBJECT (animation), "duration");
g_object_notify (G_OBJECT (animation), "loop");
priv->timeline_started_id =
g_signal_connect (timeline, "started",
G_CALLBACK (on_timeline_started),
animation);
priv->timeline_completed_id =
g_signal_connect (timeline, "completed",
G_CALLBACK (on_timeline_completed),
animation);
if (timeline)
{
priv->timeline_started_id =
g_signal_connect (timeline, "started",
G_CALLBACK (on_timeline_started),
animation);
priv->timeline_completed_id =
g_signal_connect (timeline, "completed",
G_CALLBACK (on_timeline_completed),
animation);
}
g_object_thaw_notify (G_OBJECT (animation));
}
@ -1184,19 +1241,18 @@ clutter_animation_get_timeline (ClutterAnimation *animation)
{
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL);
return animation->priv->timeline;
return clutter_animation_get_timeline_internal (animation);
}
/**
* clutter_animation_set_alpha:
* @animation: a #ClutterAnimation
* @alpha: a #ClutterAlpha, or %NULL
* @alpha: a #ClutterAlpha, or %NULL to unset the current #ClutterAlpha
*
* Sets @alpha as the #ClutterAlpha used by @animation.
*
* If @alpha is %NULL, a new #ClutterAlpha will be constructed from
* the current values of the #ClutterAnimation:mode and
* #ClutterAnimation:timeline properties.
* If @alpha is not %NULL, the #ClutterAnimation will take ownership
* of the #ClutterAlpha instance.
*
* Since: 1.0
*/
@ -1205,41 +1261,84 @@ clutter_animation_set_alpha (ClutterAnimation *animation,
ClutterAlpha *alpha)
{
ClutterAnimationPrivate *priv;
ClutterTimeline *timeline;
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
g_return_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha));
priv = animation->priv;
if (!alpha)
if (priv->alpha == alpha)
return;
g_object_freeze_notify (G_OBJECT (animation));
if (priv->alpha != NULL)
timeline = clutter_alpha_get_timeline (priv->alpha);
else
timeline = NULL;
/* disconnect the old timeline first */
if (timeline != NULL && priv->timeline_started_id != 0)
{
ClutterTimeline *timeline;
timeline = clutter_animation_get_timeline (animation);
alpha = clutter_alpha_new ();
clutter_alpha_set_timeline (alpha, timeline);
clutter_animation_set_mode_internal (animation, alpha);
g_signal_handler_disconnect (timeline, priv->timeline_started_id);
priv->timeline_started_id = 0;
}
g_object_ref_sink (alpha);
if (priv->alpha)
if (timeline != NULL && priv->timeline_completed_id != 0)
{
if (priv->alpha_notify_id)
g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id);
g_signal_handler_disconnect (timeline, priv->timeline_completed_id);
priv->timeline_completed_id = 0;
}
g_object_unref (priv->alpha);
/* then we need to disconnect the signal handler from the old alpha */
if (priv->alpha_notify_id != 0)
{
g_signal_handler_disconnect (priv->alpha, priv->alpha_notify_id);
priv->alpha_notify_id = 0;
}
if (priv->alpha != NULL)
{
/* this will take care of any reference we hold on the timeline */
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
priv->alpha = alpha;
if (alpha == NULL)
goto out;
priv->alpha = g_object_ref_sink (alpha);
priv->alpha_notify_id =
g_signal_connect (alpha, "notify::alpha",
g_signal_connect (priv->alpha, "notify::value",
G_CALLBACK (on_alpha_notify),
animation);
/* if the alpha has a timeline then we use it, otherwise we create one */
timeline = clutter_alpha_get_timeline (priv->alpha);
if (timeline != NULL)
{
priv->timeline_started_id =
g_signal_connect (timeline, "started",
G_CALLBACK (on_timeline_started),
animation);
priv->timeline_completed_id =
g_signal_connect (timeline, "completed",
G_CALLBACK (on_timeline_completed),
animation);
}
else
timeline = clutter_animation_get_timeline_internal (animation);
out:
/* emit all relevant notifications */
g_object_notify (G_OBJECT (animation), "mode");
g_object_notify (G_OBJECT (animation), "duration");
g_object_notify (G_OBJECT (animation), "loop");
g_object_notify (G_OBJECT (animation), "alpha");
g_object_notify (G_OBJECT (animation), "timeline");
g_object_thaw_notify (G_OBJECT (animation));
}
/**
@ -1257,7 +1356,7 @@ clutter_animation_get_alpha (ClutterAnimation *animation)
{
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL);
return animation->priv->alpha;
return clutter_animation_get_alpha_internal (animation);
}
/**
@ -1298,8 +1397,12 @@ on_animation_completed (ClutterAnimation *animation)
static void
clutter_animation_start (ClutterAnimation *animation)
{
if (G_LIKELY (animation->priv->timeline))
clutter_timeline_start (animation->priv->timeline);
ClutterTimeline *timeline;
timeline = clutter_animation_get_timeline_internal (animation);
if (G_LIKELY (timeline != NULL))
clutter_timeline_start (timeline);
else
{
/* sanity check */
@ -1545,7 +1648,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor,
g_return_val_if_fail (first_property_name != NULL, NULL);
timeline = clutter_alpha_get_timeline (alpha);
if (G_UNLIKELY (!timeline))
if (timeline == NULL)
{
g_warning ("The passed ClutterAlpha does not have an "
"associated ClutterTimeline.");
@ -1553,9 +1656,10 @@ clutter_actor_animate_with_alpha (ClutterActor *actor,
}
animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
if (animation == NULL)
{
animation = clutter_animation_new ();
clutter_animation_set_object (animation, G_OBJECT (actor));
g_signal_connect (animation, "completed",
G_CALLBACK (on_animation_completed),
@ -1566,9 +1670,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor,
else
CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation);
clutter_animation_set_timeline (animation, timeline);
clutter_animation_set_alpha (animation, alpha);
clutter_animation_set_object (animation, G_OBJECT (actor));
va_start (args, first_property_name);
clutter_animation_setup_valist (animation, first_property_name, args);
@ -1618,9 +1720,10 @@ clutter_actor_animate_with_timeline (ClutterActor *actor,
g_return_val_if_fail (first_property_name != NULL, NULL);
animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
if (animation == NULL)
{
animation = clutter_animation_new ();
clutter_animation_set_object (animation, G_OBJECT (actor));
g_signal_connect (animation, "completed",
G_CALLBACK (on_animation_completed),
@ -1631,10 +1734,8 @@ clutter_actor_animate_with_timeline (ClutterActor *actor,
else
CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation);
clutter_animation_set_timeline (animation, timeline);
clutter_animation_set_alpha (animation, NULL);
clutter_animation_set_mode (animation, mode);
clutter_animation_set_object (animation, G_OBJECT (actor));
clutter_animation_set_timeline (animation, timeline);
va_start (args, first_property_name);
clutter_animation_setup_valist (animation, first_property_name, args);
@ -1809,15 +1910,13 @@ clutter_actor_animate (ClutterActor *actor,
g_return_val_if_fail (first_property_name != NULL, NULL);
animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
if (animation == NULL)
{
/* if there is no animation already attached to the actor,
* create one and set up the timeline and alpha using the
* current values for duration, mode and loop
*/
animation = clutter_animation_new ();
clutter_animation_set_timeline (animation, NULL);
clutter_animation_set_alpha (animation, NULL);
clutter_animation_set_object (animation, G_OBJECT (actor));
g_signal_connect (animation, "completed",
@ -1832,8 +1931,8 @@ clutter_actor_animate (ClutterActor *actor,
/* force the update of duration and mode using the new
* values coming from the parameters of this function
*/
clutter_animation_set_duration (animation, duration);
clutter_animation_set_mode (animation, mode);
clutter_animation_set_duration (animation, duration);
va_start (args, first_property_name);
clutter_animation_setup_valist (animation, first_property_name, args);
@ -1888,15 +1987,13 @@ clutter_actor_animatev (ClutterActor *actor,
g_return_val_if_fail (values != NULL, NULL);
animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
if (animation == NULL)
{
/* if there is no animation already attached to the actor,
* create one and set up the timeline and alpha using the
* current values for duration, mode and loop
*/
animation = clutter_animation_new ();
clutter_animation_set_timeline (animation, NULL);
clutter_animation_set_alpha (animation, NULL);
clutter_animation_set_object (animation, G_OBJECT (actor));
g_signal_connect (animation, "completed",
@ -1911,8 +2008,8 @@ clutter_actor_animatev (ClutterActor *actor,
/* force the update of duration and mode using the new
* values coming from the parameters of this function
*/
clutter_animation_set_duration (animation, duration);
clutter_animation_set_mode (animation, mode);
clutter_animation_set_duration (animation, duration);
clutter_animation_setupv (animation, n_properties, properties, values);
clutter_animation_start (animation);
@ -1967,9 +2064,10 @@ clutter_actor_animate_with_timelinev (ClutterActor *actor,
g_return_val_if_fail (values != NULL, NULL);
animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
if (animation == NULL)
{
animation = clutter_animation_new ();
clutter_animation_set_object (animation, G_OBJECT (actor));
g_signal_connect (animation, "completed",
G_CALLBACK (on_animation_completed),
@ -1980,10 +2078,8 @@ clutter_actor_animate_with_timelinev (ClutterActor *actor,
else
CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation);
clutter_animation_set_timeline (animation, timeline);
clutter_animation_set_alpha (animation, NULL);
clutter_animation_set_mode (animation, mode);
clutter_animation_set_object (animation, G_OBJECT (actor));
clutter_animation_set_timeline (animation, timeline);
clutter_animation_setupv (animation, n_properties, properties, values);
clutter_animation_start (animation);
@ -2036,7 +2132,7 @@ clutter_actor_animate_with_alphav (ClutterActor *actor,
g_return_val_if_fail (values != NULL, NULL);
timeline = clutter_alpha_get_timeline (alpha);
if (G_UNLIKELY (!timeline))
if (timeline == NULL)
{
g_warning ("The passed ClutterAlpha does not have an "
"associated ClutterTimeline.");
@ -2044,9 +2140,10 @@ clutter_actor_animate_with_alphav (ClutterActor *actor,
}
animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
if (animation == NULL)
{
animation = clutter_animation_new ();
clutter_animation_set_object (animation, G_OBJECT (actor));
g_signal_connect (animation, "completed",
G_CALLBACK (on_animation_completed),
@ -2057,9 +2154,7 @@ clutter_actor_animate_with_alphav (ClutterActor *actor,
else
CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p]", animation);
clutter_animation_set_timeline (animation, timeline);
clutter_animation_set_alpha (animation, alpha);
clutter_animation_set_object (animation, G_OBJECT (actor));
clutter_animation_setupv (animation, n_properties, properties, values);
clutter_animation_start (animation);

View file

@ -61,7 +61,8 @@ struct _ClutterBackendPrivate
guint double_click_distance;
gdouble resolution;
gdouble units_per_em;
gfloat units_per_em;
cairo_font_options_t *font_options;
@ -102,55 +103,74 @@ clutter_backend_dispose (GObject *gobject)
G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
}
static inline void
update_units_per_em (ClutterBackend *backend)
static gfloat
get_units_per_em (ClutterBackend *backend,
PangoFontDescription *font_desc)
{
ClutterBackendPrivate *priv = backend->priv;
const gchar *font_name;
gfloat units_per_em = -1.0;
gboolean free_font_desc = FALSE;
gdouble dpi;
font_name = clutter_backend_get_font_name (backend);
dpi = clutter_backend_get_resolution (backend);
if (G_LIKELY (font_name != NULL && *font_name != '\0'))
if (font_desc == NULL)
{
PangoFontDescription *font_desc;
gdouble font_size = 0;
const gchar *font_name = clutter_backend_get_font_name (backend);
font_desc = pango_font_description_from_string (font_name);
if (G_LIKELY (font_desc != NULL))
if (G_LIKELY (font_name != NULL && *font_name != '\0'))
{
gint pango_size;
gboolean is_absolute;
pango_size = pango_font_description_get_size (font_desc);
is_absolute =
pango_font_description_get_size_is_absolute (font_desc);
if (!is_absolute)
font_size = ((gdouble) font_size) / PANGO_SCALE;
pango_font_description_free (font_desc);
font_desc = pango_font_description_from_string (font_name);
free_font_desc = TRUE;
}
}
/* 10 points at 96 DPI is 12 pixels */
priv->units_per_em = 1.2 * font_size
* dpi
/ 96.0;
if (font_desc != NULL)
{
gdouble font_size = 0;
gint pango_size;
gboolean is_absolute;
pango_size = pango_font_description_get_size (font_desc);
is_absolute = pango_font_description_get_size_is_absolute (font_desc);
/* "absolute" means "device units" (usually, pixels); otherwise,
* it means logical units (points)
*/
if (is_absolute)
font_size = (gdouble) pango_size / PANGO_SCALE;
else
font_size = (gdouble) pango_size / PANGO_SCALE
* dpi
/ 96.0f;
/* 10 points at 96 DPI is 13.3 pixels */
units_per_em = (1.2f * font_size)
* dpi
/ 96.0f;
}
else
priv->units_per_em = -1.0;
units_per_em = -1.0f;
if (free_font_desc)
pango_font_description_free (font_desc);
return units_per_em;
}
static void
clutter_backend_real_resolution_changed (ClutterBackend *backend)
{
update_units_per_em (backend);
backend->priv->units_per_em = get_units_per_em (backend, NULL);
CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->priv->units_per_em);
}
static void
clutter_backend_real_font_changed (ClutterBackend *backend)
{
update_units_per_em (backend);
backend->priv->units_per_em = get_units_per_em (backend, NULL);
CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->priv->units_per_em);
}
static void
@ -280,36 +300,63 @@ _clutter_backend_redraw (ClutterBackend *backend,
klass->redraw (backend, stage);
}
gboolean
_clutter_backend_create_context (ClutterBackend *backend,
gboolean is_offscreen,
GError **error)
{
ClutterBackendClass *klass;
g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE);
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (klass->create_context)
return klass->create_context (backend, is_offscreen, error);
return TRUE;
}
void
_clutter_backend_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendClass *klass;
static ClutterStage *current_context_stage = NULL;
ClutterBackendClass *klass;
g_return_if_fail (CLUTTER_IS_BACKEND (backend));
g_return_if_fail (CLUTTER_IS_STAGE (stage));
if (current_context_stage != stage || !CLUTTER_ACTOR_IS_REALIZED (stage))
{
ClutterStage *new_stage = NULL;
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
CLUTTER_NOTE (MULTISTAGE, "Stage is not realized, unsetting");
stage = NULL;
new_stage = NULL;
CLUTTER_NOTE (MULTISTAGE,
"Stage [%p] is not realized, unsetting the stage",
stage);
}
else
CLUTTER_NOTE (MULTISTAGE, "Setting the new stage [%p]", stage);
{
new_stage = stage;
CLUTTER_NOTE (MULTISTAGE,
"Setting the new stage [%p]",
new_stage);
}
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (G_LIKELY (klass->ensure_context))
klass->ensure_context (backend, stage);
klass->ensure_context (backend, new_stage);
/* FIXME: With a NULL stage and thus no active context it may make more
* sense to clean the context but then re call with the default stage
* so at least there is some kind of context in place (as to avoid
* potential issue of GL calls with no context)
*/
current_context_stage = stage;
current_context_stage = new_stage;
/* if the new stage has a different size than the previous one
* we need to update the viewport; we do it by simply setting the
@ -359,8 +406,9 @@ _clutter_backend_init_events (ClutterBackend *backend)
klass->init_events (backend);
}
ClutterUnit
_clutter_backend_get_units_per_em (ClutterBackend *backend)
gfloat
_clutter_backend_get_units_per_em (ClutterBackend *backend,
PangoFontDescription *font_desc)
{
ClutterBackendPrivate *priv;
@ -368,8 +416,12 @@ _clutter_backend_get_units_per_em (ClutterBackend *backend)
priv = backend->priv;
if (G_UNLIKELY (priv->units_per_em < 0))
update_units_per_em (backend);
/* recompute for the font description, but do not cache the result */
if (font_desc != NULL)
return get_units_per_em (backend, font_desc);
if (priv->units_per_em < 0)
priv->units_per_em = get_units_per_em (backend, NULL);
return priv->units_per_em;
}
@ -602,6 +654,8 @@ clutter_backend_get_font_options (ClutterBackend *backend)
cairo_font_options_set_antialias (priv->font_options,
CAIRO_ANTIALIAS_DEFAULT);
g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
return priv->font_options;
}
@ -661,7 +715,12 @@ clutter_backend_get_font_name (ClutterBackend *backend)
if (G_LIKELY (priv->font_name))
return priv->font_name;
/* if we have never been called then we need to set the
* default font and update everything that relies on the
* ::font-changed signal
*/
priv->font_name = g_strdup (DEFAULT_FONT_NAME);
g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
return priv->font_name;
}

View file

@ -77,6 +77,9 @@ struct _ClutterBackendClass
ClutterFeatureFlags (* get_features) (ClutterBackend *backend);
void (* redraw) (ClutterBackend *backend,
ClutterStage *stage);
gboolean (* create_context) (ClutterBackend *backend,
gboolean is_offscreen,
GError **error);
void (* ensure_context) (ClutterBackend *backend,
ClutterStage *stage);

View file

@ -552,13 +552,16 @@ notify_cb (GObject *object,
* @behave: a #ClutterBehaviour
* @alpha: a #ClutterAlpha or %NULL to unset a previously set alpha
*
* Binds @alpha to a #ClutterBehaviour. The #ClutterAlpha object
* Binds @alpha to a #ClutterBehaviour. The #ClutterAlpha object
* is what makes a behaviour work: for each tick of the timeline
* used by #ClutterAlpha a new value of the alpha parameter is
* computed by the alpha function; the value should be used by
* the #ClutterBehaviour to update one or more properties of the
* actors to which the behaviour applies.
*
* If @alpha is not %NULL, the #ClutterBehaviour will take ownership
* of the #ClutterAlpha instance.
*
* Since: 0.2
*/
void

View file

@ -325,9 +325,9 @@ clutter_cairo_texture_notify (GObject *object,
static void
clutter_cairo_texture_get_preferred_width (ClutterActor *actor,
ClutterUnit for_height,
ClutterUnit *min_width,
ClutterUnit *natural_width)
gfloat for_height,
gfloat *min_width,
gfloat *natural_width)
{
ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (actor)->priv;
@ -335,14 +335,14 @@ clutter_cairo_texture_get_preferred_width (ClutterActor *actor,
*min_width = 0;
if (natural_width)
*natural_width = CLUTTER_UNITS_FROM_DEVICE (priv->width);
*natural_width = (gfloat) priv->width;
}
static void
clutter_cairo_texture_get_preferred_height (ClutterActor *actor,
ClutterUnit for_width,
ClutterUnit *min_height,
ClutterUnit *natural_height)
gfloat for_width,
gfloat *min_height,
gfloat *natural_height)
{
ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (actor)->priv;
@ -350,7 +350,7 @@ clutter_cairo_texture_get_preferred_height (ClutterActor *actor,
*min_height = 0;
if (natural_height)
*natural_height = CLUTTER_UNITS_FROM_DEVICE (priv->height);
*natural_height = (gfloat) priv->height;
}
static void

View file

@ -65,16 +65,18 @@ struct _ClutterClonePrivate
ClutterActor *clone_source;
};
static void clutter_clone_set_source_internal (ClutterClone *clone,
ClutterActor *source);
static void
clutter_clone_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActor *clone_source = priv->clone_source;
if (G_UNLIKELY (clone_source == NULL))
if (clone_source == NULL)
{
if (min_width_p)
*min_width_p = 0;
@ -91,14 +93,14 @@ clutter_clone_get_preferred_width (ClutterActor *self,
static void
clutter_clone_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActor *clone_source = priv->clone_source;
if (G_UNLIKELY (clone_source == NULL))
if (clone_source == NULL)
{
if (min_height_p)
*min_height_p = 0;
@ -120,6 +122,7 @@ clutter_clone_paint (ClutterActor *self)
ClutterClonePrivate *priv = clone->priv;
ClutterGeometry geom, clone_geom;
gfloat x_scale, y_scale;
gboolean was_unmapped = FALSE;
if (G_UNLIKELY (priv->clone_source == NULL))
return;
@ -153,23 +156,32 @@ clutter_clone_paint (ClutterActor *self)
_clutter_actor_set_opacity_parent (priv->clone_source, self);
_clutter_actor_set_enable_model_view_transform (priv->clone_source, FALSE);
if (!CLUTTER_ACTOR_IS_MAPPED (priv->clone_source))
{
_clutter_actor_set_enable_paint_unmapped (priv->clone_source, TRUE);
was_unmapped = TRUE;
}
clutter_actor_paint (priv->clone_source);
if (was_unmapped)
_clutter_actor_set_enable_paint_unmapped (priv->clone_source, FALSE);
_clutter_actor_set_enable_model_view_transform (priv->clone_source, TRUE);
_clutter_actor_set_opacity_parent (priv->clone_source, NULL);
}
static void
clutter_clone_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
clutter_clone_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorClass *parent_class;
/* chain up */
parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class);
parent_class->allocate (self, box, origin_changed);
parent_class->allocate (self, box, flags);
if (G_UNLIKELY (priv->clone_source == NULL))
return;
@ -182,10 +194,7 @@ clutter_clone_allocate (ClutterActor *self,
* paint cycle, we can safely give it as much size as it requires
*/
if (clutter_actor_get_parent (priv->clone_source) == NULL)
{
clutter_actor_allocate_preferred_size (priv->clone_source,
origin_changed);
}
clutter_actor_allocate_preferred_size (priv->clone_source, flags);
}
static void
@ -231,13 +240,7 @@ clutter_clone_get_property (GObject *gobject,
static void
clutter_clone_dispose (GObject *gobject)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (gobject)->priv;
if (priv->clone_source)
{
g_object_unref (priv->clone_source);
priv->clone_source = NULL;
}
clutter_clone_set_source_internal (CLUTTER_CLONE (gobject), NULL);
G_OBJECT_CLASS (clutter_clone_parent_class)->dispose (gobject);
}
@ -302,6 +305,46 @@ clutter_clone_new (ClutterActor *source)
return g_object_new (CLUTTER_TYPE_CLONE, "source", source, NULL);
}
static void
clone_source_queue_redraw_cb (ClutterActor *source,
ClutterActor *origin,
ClutterClone *clone)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (clone));
}
static void
clutter_clone_set_source_internal (ClutterClone *clone,
ClutterActor *source)
{
ClutterClonePrivate *priv;
g_return_if_fail (CLUTTER_IS_CLONE (clone));
g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source));
priv = clone->priv;
if (priv->clone_source)
{
g_signal_handlers_disconnect_by_func (priv->clone_source,
(void *) clone_source_queue_redraw_cb,
clone);
g_object_unref (priv->clone_source);
priv->clone_source = NULL;
}
if (source)
{
priv->clone_source = g_object_ref (source);
g_signal_connect (priv->clone_source, "queue-redraw",
G_CALLBACK (clone_source_queue_redraw_cb), clone);
}
g_object_notify (G_OBJECT (clone), "source");
clutter_actor_queue_relayout (CLUTTER_ACTOR (clone));
}
/**
* clutter_clone_set_source:
* @clone: a #ClutterClone
@ -315,24 +358,10 @@ void
clutter_clone_set_source (ClutterClone *clone,
ClutterActor *source)
{
ClutterClonePrivate *priv;
g_return_if_fail (CLUTTER_IS_CLONE (clone));
g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source));
priv = clone->priv;
if (priv->clone_source)
{
g_object_unref (priv->clone_source);
priv->clone_source = NULL;
}
if (source)
priv->clone_source = g_object_ref (source);
g_object_notify (G_OBJECT (clone), "source");
clutter_clone_set_source_internal (clone, source);
clutter_actor_queue_relayout (CLUTTER_ACTOR (clone));
}

View file

@ -398,7 +398,7 @@ clutter_color_from_string (ClutterColor *color,
g_return_val_if_fail (str != NULL, FALSE);
/* if the string contains a color encoded using the hexadecimal
* notations (#rrggbbaa or #rrggbb) we attempt a rough pass at
* notations (#rrggbbaa or #rgba) we attempt a rough pass at
* parsing the color ourselves, as we need the alpha channel that
* Pango can't retrieve.
*/
@ -407,36 +407,34 @@ clutter_color_from_string (ClutterColor *color,
gint32 result;
if (sscanf (str + 1, "%x", &result))
{
if (strlen (str) == 9)
{
{
if (strlen (str) == 9)
{
/* #rrggbbaa */
color->red = (result >> 24) & 0xff;
color->green = (result >> 16) & 0xff;
color->blue = (result >> 8) & 0xff;
color->red = (result >> 24) & 0xff;
color->green = (result >> 16) & 0xff;
color->blue = (result >> 8) & 0xff;
color->alpha = result & 0xff;
color->alpha = result & 0xff;
return TRUE;
}
else if (strlen (str) == 7)
{
/* #rrggbb */
color->red = (result >> 16) & 0xff;
color->green = (result >> 8) & 0xff;
color->blue = result & 0xff;
return TRUE;
}
else if (strlen (str) == 5)
{
/* #rgba */
color->red = ((result >> 12) & 0xf);
color->green = ((result >> 8) & 0xf);
color->blue = ((result >> 4) & 0xf);
color->alpha = result & 0xf;
color->alpha = 0xff;
color->red = (color->red << 4) | color->red;
color->green = (color->green << 4) | color->green;
color->blue = (color->blue << 4) | color->blue;
color->alpha = (color->alpha << 4) | color->alpha;
return TRUE;
}
}
/* XXX - should we return FALSE here? it's not like
* Pango is endowed with mystical parsing powers and
* will be able to do better than the code above.
* still, it doesn't hurt
*/
return TRUE;
}
}
}
/* Fall back to pango for named colors */

View file

@ -449,7 +449,10 @@ clutter_container_get_children (ClutterContainer *container)
* @callback: a function to be called for each child
* @user_data: data to be passed to the function, or %NULL
*
* Calls @callback for each child of @container.
* Calls @callback for each child of @container that was added
* by the application (with clutter_container_add_actor()). Does
* not iterate over "internal" children that are part of the
* container's own implementation, if any.
*
* Since: 0.4
*/
@ -473,6 +476,41 @@ clutter_container_foreach (ClutterContainer *container,
iface->foreach (container, callback, user_data);
}
/**
* clutter_container_foreach_with_internals:
* @container: a #ClutterContainer
* @callback: a function to be called for each child
* @user_data: data to be passed to the function, or %NULL
*
* Calls @callback for each child of @container, including "internal"
* children built in to the container itself that were never added
* by the application.
*
* Since: 1.0
*/
void
clutter_container_foreach_with_internals (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data)
{
ClutterContainerIface *iface;
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (callback != NULL);
iface = CLUTTER_CONTAINER_GET_IFACE (container);
if (!iface->foreach)
{
CLUTTER_CONTAINER_WARN_NOT_IMPLEMENTED (container, "foreach");
return;
}
if (iface->foreach_with_internals != NULL)
iface->foreach_with_internals (container, callback, user_data);
else
iface->foreach (container, callback, user_data);
}
/**
* clutter_container_raise_child:
* @container: a #ClutterContainer

View file

@ -52,6 +52,11 @@ typedef struct _ClutterContainerIface ClutterContainerIface;
* implementation of this virtual function is required.
* @foreach: virtual function for iterating over the container's children.
* The implementation of this virtual function is required.
* @foreach_with_internals: virtual functions for iterating over the
* container's children, both added using the #ClutterContainer API
* and internal children. The implementation of this virtual function
* is required only if the #ClutterContainer implementation has
* internal children.
* @raise: virtual function for raising a child
* @lower: virtual function for lowering a child
* @sort_depth_order: virtual function for sorting the children of a
@ -90,6 +95,10 @@ struct _ClutterContainerIface
ClutterCallback callback,
gpointer user_data);
void (* foreach_with_internals) (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data);
/* child stacking */
void (* raise) (ClutterContainer *container,
ClutterActor *actor,
@ -137,20 +146,22 @@ void clutter_container_remove_actor (ClutterContainer *container,
void clutter_container_remove_valist (ClutterContainer *container,
ClutterActor *first_actor,
va_list var_args);
GList * clutter_container_get_children (ClutterContainer *container);
void clutter_container_foreach (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data);
ClutterActor *clutter_container_find_child_by_name (ClutterContainer *container,
const gchar *child_name);
void clutter_container_raise_child (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling);
void clutter_container_lower_child (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling);
void clutter_container_sort_depth_order (ClutterContainer *container);
GList * clutter_container_get_children (ClutterContainer *container);
void clutter_container_foreach (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data);
void clutter_container_foreach_with_internals (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data);
ClutterActor *clutter_container_find_child_by_name (ClutterContainer *container,
const gchar *child_name);
void clutter_container_raise_child (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling);
void clutter_container_lower_child (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling);
void clutter_container_sort_depth_order (ClutterContainer *container);
GParamSpec * clutter_container_class_find_child_property (GObjectClass *klass,

View file

@ -148,4 +148,24 @@
#define clutter_shader_set_uniform_1f clutter_shader_set_uniform_1f_REPLACED_BY_clutter_shader_set_uniform
#define clutter_actor_set_xu clutter_actor_set_xu_DEPRECATED_BY_clutter_actor_set_x
#define clutter_actor_set_yu clutter_actor_set_yu_DEPRECATED_BY_clutter_actor_set_y
#define clutter_actor_set_widthu clutter_actor_set_widthu_DEPRECATED_BY_clutter_actor_set_width
#define clutter_actor_set_heightu clutter_actor_set_heightu_DEPRECATED_BY_clutter_actor_set_height
#define clutter_actor_set_depthu clutter_actor_set_depthu_DEPRECATED_BY_clutter_actor_set_depth
#define clutter_actor_set_positionu clutter_actor_set_positionu_DEPRECATED_BY_clutter_actor_set_position
#define clutter_actor_set_sizeu clutter_actor_set_sizeu_DEPRECATED_BY_clutter_actor_set_size
#define clutter_actor_set_anchor_pointu clutter_actor_set_anchor_pointu_DEPRECATED_BY_clutter_actor_set_anchor_point
#define clutter_actor_get_anchor_pointu clutter_actor_get_anchor_pointu_DEPRECATED_BY_clutter_actor_get_anchor_point
#define clutter_actor_move_byu clutter_actor_move_byu_DEPRECATED_BY_clutter_actor_move_by
#define clutter_actor_get_xu clutter_actor_get_xu_DEPRECATED_BY_clutter_actor_get_x
#define clutter_actor_get_yu clutter_actor_get_yu_DEPRECATED_BY_clutter_actor_get_y
#define clutter_actor_get_widthu clutter_actor_get_widthu_DEPRECATED_BY_clutter_actor_get_width
#define clutter_actor_get_heightu clutter_actor_get_heightu_DEPRECATED_BY_clutter_actor_get_height
#define clutter_actor_get_depthu clutter_actor_get_depthu_DEPRECATED_BY_clutter_actor_get_depth
#define clutter_actor_get_positionu clutter_actor_get_positionu_DEPRECATED_BY_clutter_actor_get_position
#define clutter_actor_get_sizeu clutter_actor_get_sizeu_DEPRECATED_BY_clutter_actor_get_size
#endif /* CLUTTER_DEPRECATED_H */

View file

@ -3,15 +3,19 @@
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
#include "@filename@"
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type(void) {
static GType etype = 0;
if (G_UNLIKELY (!etype))
@enum_name@_get_type (void)
{
static volatile gsize g_enum_type_id__volatile = 0;
if (g_once_init_enter (&g_enum_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
@ -23,8 +27,14 @@ GType
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
GType g_enum_type_id;
g_enum_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
}
return etype;
return g_enum_type_id__volatile;
}
/*** END value-tail ***/

View file

@ -120,10 +120,10 @@ clutter_event_get_state (ClutterEvent *event)
*/
void
clutter_event_get_coords (ClutterEvent *event,
gint *x,
gint *y)
gfloat *x,
gfloat *y)
{
gint event_x, event_y;
gfloat event_x, event_y;
g_return_if_fail (event != NULL);
@ -141,15 +141,18 @@ clutter_event_get_coords (ClutterEvent *event,
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
event_x = event->button.x;
event_y = event->button.y;
break;
case CLUTTER_MOTION:
event_x = event->motion.x;
event_y = event->motion.y;
break;
case CLUTTER_SCROLL:
event_x = event->scroll.x;
event_y = event->scroll.y;

View file

@ -221,8 +221,8 @@ typedef struct _ClutterInputDevice ClutterInputDevice;
*/
struct _ClutterAnyEvent
{
ClutterEventType type;
guint32 time;
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
@ -290,8 +290,8 @@ struct _ClutterButtonEvent
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
gfloat x;
gfloat y;
ClutterModifierType modifier_state;
guint32 button;
guint click_count;
@ -322,8 +322,8 @@ struct _ClutterCrossingEvent
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
gfloat x;
gfloat y;
ClutterInputDevice *device; /* future use */
ClutterActor *related;
};
@ -352,8 +352,8 @@ struct _ClutterMotionEvent
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
gfloat x;
gfloat y;
ClutterModifierType modifier_state;
gdouble *axes; /* Future use */
ClutterInputDevice *device; /* Future use */
@ -384,8 +384,8 @@ struct _ClutterScrollEvent
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
gfloat x;
gfloat y;
ClutterScrollDirection direction;
ClutterModifierType modifier_state;
gdouble *axes; /* future use */
@ -451,8 +451,8 @@ ClutterEventType clutter_event_type (ClutterEvent *event);
guint32 clutter_event_get_time (ClutterEvent *event);
ClutterModifierType clutter_event_get_state (ClutterEvent *event);
void clutter_event_get_coords (ClutterEvent *event,
gint *x,
gint *y);
gfloat *x,
gfloat *y);
gint clutter_event_get_device_id (ClutterEvent *event);
ClutterActor* clutter_event_get_source (ClutterEvent *event);

View file

@ -96,8 +96,7 @@ clutter_group_paint (ClutterActor *actor)
g_assert (child != NULL);
if (CLUTTER_ACTOR_IS_VISIBLE (child))
clutter_actor_paint (child);
clutter_actor_paint (child);
}
CLUTTER_NOTE (PAINT, "ClutterGroup paint leave '%s'",
@ -105,44 +104,36 @@ clutter_group_paint (ClutterActor *actor)
: "unknown");
}
static void
clutter_group_realize (ClutterActor *actor)
{
clutter_container_foreach (CLUTTER_CONTAINER (actor),
CLUTTER_CALLBACK (clutter_actor_realize),
NULL);
}
static void
clutter_group_unrealize (ClutterActor *actor)
{
clutter_container_foreach (CLUTTER_CONTAINER (actor),
CLUTTER_CALLBACK (clutter_actor_unrealize),
NULL);
}
static void
clutter_group_pick (ClutterActor *actor,
const ClutterColor *color)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
GList *child_item;
/* Chain up so we get a bounding box pained (if we are reactive) */
CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->pick (actor, color);
/* Just forward to the paint call which in turn will trigger
* the child actors also getting 'picked'.
*/
if (CLUTTER_ACTOR_IS_VISIBLE (actor))
clutter_group_paint (actor);
for (child_item = priv->children;
child_item != NULL;
child_item = child_item->next)
{
ClutterActor *child = child_item->data;
g_assert (child != NULL);
clutter_actor_paint (child);
}
}
static void
clutter_fixed_layout_get_preferred_width (GList *children,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
clutter_fixed_layout_get_preferred_width (GList *children,
gfloat *min_width_p,
gfloat *natural_width_p)
{
GList *l;
ClutterUnit min_left, min_right;
ClutterUnit natural_left, natural_right;
gfloat min_left, min_right;
gfloat natural_left, natural_right;
min_left = 0;
min_right = 0;
@ -152,9 +143,9 @@ clutter_fixed_layout_get_preferred_width (GList *children,
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
ClutterUnit child_x, child_min, child_natural;
gfloat child_x, child_min, child_natural;
child_x = clutter_actor_get_xu (child);
child_x = clutter_actor_get_x (child);
clutter_actor_get_preferred_size (child,
&child_min, NULL,
@ -212,13 +203,13 @@ clutter_fixed_layout_get_preferred_width (GList *children,
}
static void
clutter_fixed_layout_get_preferred_height (GList *children,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
clutter_fixed_layout_get_preferred_height (GList *children,
gfloat *min_height_p,
gfloat *natural_height_p)
{
GList *l;
ClutterUnit min_top, min_bottom;
ClutterUnit natural_top, natural_bottom;
gfloat min_top, min_bottom;
gfloat natural_top, natural_bottom;
min_top = 0;
min_bottom = 0;
@ -228,9 +219,9 @@ clutter_fixed_layout_get_preferred_height (GList *children,
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
ClutterUnit child_y, child_min, child_natural;
gfloat child_y, child_min, child_natural;
child_y = clutter_actor_get_yu (child);
child_y = clutter_actor_get_y (child);
clutter_actor_get_preferred_size (child,
NULL, &child_min,
@ -288,23 +279,23 @@ clutter_fixed_layout_get_preferred_height (GList *children,
}
static void
clutter_fixed_layout_allocate (GList *children,
gboolean absolute_origin_changed)
clutter_fixed_layout_allocate (GList *children,
ClutterAllocationFlags flags)
{
GList *l;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
clutter_actor_allocate_preferred_size (child, absolute_origin_changed);
clutter_actor_allocate_preferred_size (child, flags);
}
}
static void
clutter_group_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
@ -316,9 +307,9 @@ clutter_group_get_preferred_width (ClutterActor *self,
static void
clutter_group_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
@ -329,22 +320,21 @@ clutter_group_get_preferred_height (ClutterActor *self,
}
static void
clutter_group_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
clutter_group_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* chain up to set actor->allocation */
CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->allocate (self, box,
origin_changed);
CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->allocate (self, box, flags);
/* Note that fixed-layout allocation of children does not care what
* allocation the container received, so "box" is not passed in
* here. We do not require that children's allocations are completely
* contained by our own.
*/
clutter_fixed_layout_allocate (priv->children, origin_changed);
clutter_fixed_layout_allocate (priv->children, flags);
}
static void
@ -587,8 +577,6 @@ clutter_group_class_init (ClutterGroupClass *klass)
actor_class->pick = clutter_group_pick;
actor_class->show_all = clutter_group_real_show_all;
actor_class->hide_all = clutter_group_real_hide_all;
actor_class->realize = clutter_group_realize;
actor_class->unrealize = clutter_group_unrealize;
actor_class->get_preferred_width = clutter_group_get_preferred_width;
actor_class->get_preferred_height = clutter_group_get_preferred_height;

View file

@ -95,20 +95,7 @@ clutter_interval_real_validate (ClutterInterval *interval,
GType pspec_gtype = G_PARAM_SPEC_VALUE_TYPE (pspec);
/* check the GTypes we provide first */
if (pspec_gtype == CLUTTER_TYPE_UNIT)
{
ClutterParamSpecUnit *pspec_unit = CLUTTER_PARAM_SPEC_UNIT (pspec);
ClutterUnit a, b;
a = b = 0;
clutter_interval_get_interval (interval, &a, &b);
if ((a >= pspec_unit->minimum && a <= pspec_unit->maximum) &&
(b >= pspec_unit->minimum && b <= pspec_unit->maximum))
return TRUE;
else
return FALSE;
}
else if (pspec_gtype == COGL_TYPE_FIXED)
if (pspec_gtype == COGL_TYPE_FIXED)
{
ClutterParamSpecFixed *pspec_fixed = CLUTTER_PARAM_SPEC_FIXED (pspec);
CoglFixed a, b;
@ -265,8 +252,16 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
{
gdouble ia, ib, res;
ia = g_value_get_double (initial);
ib = g_value_get_double (final);
if (value_type == G_TYPE_DOUBLE)
{
ia = g_value_get_double (initial);
ib = g_value_get_double (final);
}
else
{
ia = g_value_get_float (initial);
ib = g_value_get_float (final);
}
res = (factor * (ib - ia)) + ia;

View file

@ -41,6 +41,7 @@
#include "clutter-event.h"
#include "clutter-backend.h"
#include "clutter-main.h"
#include "clutter-master-clock.h"
#include "clutter-feature.h"
#include "clutter-actor.h"
#include "clutter-stage.h"
@ -118,7 +119,7 @@ clutter_get_show_fps (void)
void
_clutter_stage_maybe_relayout (ClutterActor *stage)
{
ClutterUnit natural_width, natural_height;
gfloat natural_width, natural_height;
ClutterActorBox box = { 0, };
/* avoid reentrancy */
@ -139,10 +140,10 @@ _clutter_stage_maybe_relayout (ClutterActor *stage)
box.y2 = natural_height;
CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
CLUTTER_UNITS_TO_DEVICE (natural_width),
CLUTTER_UNITS_TO_DEVICE (natural_height));
(int) natural_width,
(int) natural_height);
clutter_actor_allocate (stage, &box, FALSE);
clutter_actor_allocate (stage, &box, CLUTTER_ALLOCATION_NONE);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
}
@ -154,18 +155,20 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
{
ClutterPerspective perspective;
guint width, height;
gfloat width, height;
clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
clutter_stage_get_perspective (stage, &perspective);
CLUTTER_NOTE (PAINT, "Setting up the viewport");
CLUTTER_NOTE (PAINT,
"Setting up the viewport { w:%.2f, h:%.2f }",
width, height);
cogl_setup_viewport (width, height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
_cogl_setup_viewport (width, height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
@ -181,14 +184,12 @@ void
clutter_redraw (ClutterStage *stage)
{
ClutterMainContext *ctx;
static GTimer *timer = NULL;
static guint timer_n_frames = 0;
ClutterMasterClock *master_clock;
static GTimer *timer = NULL;
static guint timer_n_frames = 0;
ctx = clutter_context_get_default ();
CLUTTER_TIMESTAMP (SCHEDULER, "Redraw start for stage:%p", stage);
CLUTTER_NOTE (PAINT, " Redraw enter for stage:%p", stage);
CLUTTER_NOTE (MULTISTAGE, "Redraw called for stage:%p", stage);
master_clock = _clutter_master_clock_get_default ();
/* Before we can paint, we have to be sure we have the latest layout */
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
@ -209,10 +210,15 @@ clutter_redraw (ClutterStage *stage)
/* Call through to the actual backend to do the painting down from
* the stage. It will likely need to swap buffers, vblank sync etc
* which will be windowing system dependant.
* which will be windowing system dependent
*/
_clutter_backend_redraw (ctx->backend, stage);
/* prepare for the next frame; if anything queues a redraw as the
* result of a timeline, this will end up redrawing the scene
*/
_clutter_master_clock_advance (master_clock);
/* Complete FPS info */
if (G_UNLIKELY (clutter_get_show_fps ()))
{
@ -226,7 +232,6 @@ clutter_redraw (ClutterStage *stage)
}
}
CLUTTER_NOTE (PAINT, " Redraw leave for stage:%p", stage);
CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish for stage:%p", stage);
}
@ -1053,6 +1058,8 @@ clutter_context_get_default (void)
ctx->is_initialized = FALSE;
ctx->motion_events_per_actor = TRUE;
ctx->master_clock = _clutter_master_clock_get_default ();
#ifdef CLUTTER_ENABLE_DEBUG
ctx->timer = g_timer_new ();
g_timer_start (ctx->timer);
@ -1932,8 +1939,8 @@ generate_enter_leave_events (ClutterEvent *event)
{
if (motion_current_actor)
{
gint x, y;
ClutterEvent cev;
gfloat x, y;
cev.crossing.device = device;
clutter_event_get_coords (event, &x, &y);
@ -2154,7 +2161,7 @@ clutter_do_event (ClutterEvent *event)
case CLUTTER_SCROLL:
{
ClutterActor *actor;
gint x,y;
gfloat x, y;
clutter_event_get_coords (event, &x, &y);
@ -2171,7 +2178,7 @@ clutter_do_event (ClutterEvent *event)
if (event->type == CLUTTER_BUTTON_RELEASE)
{
CLUTTER_NOTE (EVENT,
"Release off stage received at %i, %i",
"Release off stage received at %.2f, %.2f",
x, y);
event->button.source = stage;
@ -2197,12 +2204,14 @@ clutter_do_event (ClutterEvent *event)
/* FIXME: for an optimisation should check if there are
* actually any reactive actors and avoid the pick all togeather
* actually any reactive actors and avoid the pick all together
* (signalling just the stage). Should be big help for gles.
*/
CLUTTER_NOTE (EVENT, "Reactive event received at %i, %i - actor: %p",
x, y, actor);
CLUTTER_NOTE (EVENT,
"Reactive event received at %.2f, %.2f - actor: %p",
x, y,
actor);
/* Create, enter/leave events if needed */
generate_enter_leave_events (event);
@ -2809,3 +2818,162 @@ clutter_get_font_map (void)
return NULL;
}
typedef struct _ClutterRepaintFunction
{
guint id;
GSourceFunc func;
gpointer data;
GDestroyNotify notify;
} ClutterRepaintFunction;
/**
* clutter_threads_remove_repaint_func:
* @handle_id: an unsigned integer greater than zero
*
* Removes the repaint function with @handle_id as its id
*
* Since: 1.0
*/
void
clutter_threads_remove_repaint_func (guint handle_id)
{
ClutterRepaintFunction *repaint_func;
ClutterMainContext *context;
GList *l;
g_return_if_fail (handle_id > 0);
context = CLUTTER_CONTEXT ();
l = context->repaint_funcs;
while (l != NULL)
{
repaint_func = l->data;
if (repaint_func->id == handle_id)
{
context->repaint_funcs =
g_list_remove_link (context->repaint_funcs, l);
g_list_free (l);
if (repaint_func->notify)
repaint_func->notify (repaint_func->data);
g_slice_free (ClutterRepaintFunction, repaint_func);
return;
}
l = l->next;
}
}
/**
* clutter_threads_add_repaint_func:
* @func: the function to be called within the paint cycle
* @data: data to be passed to the function, or %NULL
* @notify: function to be called when removing the repaint
* function, or %NULL
*
* Adds a function to be called whenever Clutter is repainting a Stage.
* If the function returns %FALSE it is automatically removed from the
* list of repaint functions and will not be called again.
*
* This function is guaranteed to be called from within the same thread
* that called clutter_main(), and while the Clutter lock is being held.
*
* A repaint function is useful to ensure that an update of the scenegraph
* is performed before the scenegraph is repainted; for instance, uploading
* a frame from a video into a #ClutterTexture.
*
* When the repaint function is removed (either because it returned %FALSE
* or because clutter_threads_remove_repaint_func() has been called) the
* @notify function will be called, if any is set.
*
* Return value: the ID (greater than 0) of the repaint function. You
* can use the returned integer to remove the repaint function by
* calling clutter_threads_remove_repaint_func().
*
* Since: 1.0
*/
guint
clutter_threads_add_repaint_func (GSourceFunc func,
gpointer data,
GDestroyNotify notify)
{
static guint repaint_id = 1;
ClutterMainContext *context;
ClutterRepaintFunction *repaint_func;
g_return_val_if_fail (func != NULL, 0);
context = CLUTTER_CONTEXT ();
/* XXX lock the context */
repaint_func = g_slice_new (ClutterRepaintFunction);
repaint_func->id = repaint_id++;
repaint_func->func = func;
repaint_func->data = data;
repaint_func->notify = notify;
context->repaint_funcs = g_list_prepend (context->repaint_funcs,
repaint_func);
/* XXX unlock the context */
return repaint_func->id;
}
/*
* _clutter_run_repaint_functions:
*
* Executes the repaint functions added using the
* clutter_threads_add_repaint_func() function.
*
* Must be called before calling clutter_redraw() and
* with the Clutter thread lock held.
*/
void
_clutter_run_repaint_functions (void)
{
ClutterMainContext *context = CLUTTER_CONTEXT ();
ClutterRepaintFunction *repaint_func;
GList *reinvoke_list, *l;
if (context->repaint_funcs == NULL)
return;
reinvoke_list = NULL;
/* consume the whole list while we execute the functions */
while (context->repaint_funcs)
{
gboolean res = FALSE;
repaint_func = context->repaint_funcs->data;
l = context->repaint_funcs;
context->repaint_funcs =
g_list_remove_link (context->repaint_funcs, context->repaint_funcs);
g_list_free (l);
res = repaint_func->func (repaint_func->data);
if (res)
reinvoke_list = g_list_prepend (reinvoke_list, repaint_func);
else
{
if (repaint_func->notify)
repaint_func->notify (repaint_func->data);
g_slice_free (ClutterRepaintFunction, repaint_func);
}
}
if (reinvoke_list)
context->repaint_funcs = reinvoke_list;
}

View file

@ -70,7 +70,7 @@ GQuark clutter_init_error_quark (void);
*
* Since: 0.8
*/
#define CLUTTER_PRIORITY_REDRAW (G_PRIORITY_DEFAULT + 10)
#define CLUTTER_PRIORITY_REDRAW (G_PRIORITY_HIGH_IDLE + 20)
/**
* CLUTTER_PRIORITY_TIMELINE:
@ -109,34 +109,38 @@ gboolean clutter_get_show_fps (void);
gulong clutter_get_timestamp (void);
/* Threading functions */
void clutter_threads_init (void);
void clutter_threads_enter (void);
void clutter_threads_leave (void);
void clutter_threads_set_lock_functions (GCallback enter_fn,
GCallback leave_fn);
guint clutter_threads_add_idle (GSourceFunc func,
gpointer data);
guint clutter_threads_add_idle_full (gint priority,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
guint clutter_threads_add_timeout (guint interval,
GSourceFunc func,
gpointer data);
guint clutter_threads_add_timeout_full (gint priority,
guint interval,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
guint clutter_threads_add_frame_source (guint fps,
GSourceFunc func,
gpointer data);
guint clutter_threads_add_frame_source_full
(gint priority,
guint fps,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
void clutter_threads_init (void);
void clutter_threads_enter (void);
void clutter_threads_leave (void);
void clutter_threads_set_lock_functions (GCallback enter_fn,
GCallback leave_fn);
guint clutter_threads_add_idle (GSourceFunc func,
gpointer data);
guint clutter_threads_add_idle_full (gint priority,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
guint clutter_threads_add_timeout (guint interval,
GSourceFunc func,
gpointer data);
guint clutter_threads_add_timeout_full (gint priority,
guint interval,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
guint clutter_threads_add_frame_source (guint fps,
GSourceFunc func,
gpointer data);
guint clutter_threads_add_frame_source_full (gint priority,
guint fps,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
guint clutter_threads_add_repaint_func (GSourceFunc func,
gpointer data,
GDestroyNotify notify);
void clutter_threads_remove_repaint_func (guint handle_id);
void clutter_set_motion_events_enabled (gboolean enable);
gboolean clutter_get_motion_events_enabled (void);
@ -158,7 +162,7 @@ void clutter_clear_glyph_cache (void);
void clutter_set_font_flags (ClutterFontFlags flags);
ClutterFontFlags clutter_get_font_flags (void);
ClutterInputDevice* clutter_get_input_device_for_id (gint id);
ClutterInputDevice *clutter_get_input_device_for_id (gint id);
void clutter_grab_pointer_for_device (ClutterActor *actor,
gint id);

View file

@ -3,9 +3,11 @@ BOOLEAN:STRING,UINT,ENUM
DOUBLE:VOID
UINT:VOID
VOID:BOXED
VOID:BOXED,FLAGS
VOID:INT
VOID:INT64,INT64,FLOAT,BOOLEAN
VOID:INT,INT
VOID:FLOAT,FLOAT
VOID:INT,INT,INT,INT
VOID:OBJECT
VOID:OBJECT,OBJECT,PARAM

View file

@ -0,0 +1,477 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
/*
* SECTION:clutter-master-clock
* @short_description: The master clock for all animations
*
* The #ClutterMasterClock class is responsible for advancing all
* #ClutterTimelines when a stage is being redrawn. The master clock
* makes sure that the scenegraph is always integrally updated before
* painting it.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-master-clock.h"
#include "clutter-debug.h"
#include "clutter-private.h"
#define CLUTTER_MASTER_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClockClass))
#define CLUTTER_IS_MASTER_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_MASTER_CLOCK))
#define CLUTTER_MASTER_CLASS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClockClass))
typedef struct _ClutterClockSource ClutterClockSource;
typedef struct _ClutterMasterClockClass ClutterMasterClockClass;
struct _ClutterMasterClock
{
GObject parent_instance;
/* the list of timelines handled by the clock */
GSList *timelines;
/* the previous state of the clock, used to compute
* the delta
*/
GTimeVal prev_tick;
gulong msecs_delta;
/* an idle source, used by the Master Clock to queue
* a redraw on the stage and drive the animations
*/
GSource *source;
/* a guard, so that we dispatch the last redraw even
* after the last timeline has been completed
*/
guint last_advance : 1;
};
struct _ClutterMasterClockClass
{
GObjectClass parent_class;
};
struct _ClutterClockSource
{
GSource source;
ClutterMasterClock *master_clock;
};
static void on_timeline_started (ClutterTimeline *timeline,
ClutterMasterClock *master_clock);
static void on_timeline_completed (ClutterTimeline *timeline,
ClutterMasterClock *master_clock);
static void on_timeline_paused (ClutterTimeline *timeline,
ClutterMasterClock *master_clock);
static gboolean clutter_clock_prepare (GSource *source,
gint *timeout);
static gboolean clutter_clock_check (GSource *source);
static gboolean clutter_clock_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static ClutterMasterClock *default_clock = NULL;
static GSourceFuncs clock_funcs = {
clutter_clock_prepare,
clutter_clock_check,
clutter_clock_dispatch,
NULL
};
G_DEFINE_TYPE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT);
/*
* has_running_timeline:
* @master_clock: a #ClutterMasterClock
* @filter: a #ClutterTimeline or %NULL
*
* Checks if @master_clock has any running timeline; if @filter
* is not %NULL then the timeline will be filtered from the
* list of timelines held by @master_clock
*
* Return value: %TRUE if the #ClutterMasterClock has at least
* one running timeline
*/
static gboolean
has_running_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *filter)
{
GSList *l;
if (master_clock->last_advance)
return TRUE;
if (master_clock->timelines == NULL)
return FALSE;
for (l = master_clock->timelines; l != NULL; l = l->next)
{
/* if we get a timeline then we should filter it
* from the list of timelines we want to check
*/
if (filter != NULL && filter == l->data)
continue;
if (clutter_timeline_is_playing (l->data))
return TRUE;
}
return FALSE;
}
/*
* clutter_clock_source_new:
* @master_clock: a #ClutterMasterClock for the source
*
* The #ClutterClockSource is an idle GSource that will queue a redraw
* if @master_clock has at least a running #ClutterTimeline. The redraw
* will cause @master_clock to advance all timelines, thus advancing all
* animations as well.
*
* Return value: the newly created #GSource
*/
static GSource *
clutter_clock_source_new (ClutterMasterClock *master_clock)
{
GSource *source = g_source_new (&clock_funcs, sizeof (ClutterClockSource));
ClutterClockSource *clock_source = (ClutterClockSource *) source;
clock_source->master_clock = master_clock;
return source;
}
static gboolean
clutter_clock_prepare (GSource *source,
gint *timeout)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClock *master_clock = clock_source->master_clock;
gboolean retval;
/* just like an idle source, we are ready if nothing else is */
*timeout = -1;
retval = has_running_timeline (master_clock, NULL);
return retval;
}
static gboolean
clutter_clock_check (GSource *source)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClock *master_clock = clock_source->master_clock;
gboolean retval;
retval = has_running_timeline (master_clock, NULL);
return retval;
}
static gboolean
clutter_clock_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClock *master_clock = clock_source->master_clock;
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
CLUTTER_NOTE (SCHEDULER, "Master clock [tick]");
stages = clutter_stage_manager_peek_stages (stage_manager);
/* queue a redraw for each stage; this will advance each timeline
* held by the master clock of the amount of milliseconds elapsed
* since the last redraw
*/
for (l = stages; l != NULL; l = l->next)
clutter_actor_queue_redraw (l->data);
/* if this is the remainder of an advancement, needed for the last
* timeline to finish its run, then we need to reset the prev_tick
*/
if (master_clock->last_advance)
{
master_clock->prev_tick.tv_sec = 0;
master_clock->last_advance = FALSE;
}
return TRUE;
}
static void
timeline_weak_ref (gpointer data,
GObject *object_pointer)
{
ClutterMasterClock *master_clock = data;
master_clock->timelines =
g_slist_remove (master_clock->timelines, object_pointer);
if (master_clock->timelines == NULL)
master_clock->prev_tick.tv_sec = 0;
}
static void
clutter_master_clock_finalize (GObject *gobject)
{
ClutterMasterClock *master_clock = CLUTTER_MASTER_CLOCK (gobject);
GSList *l;
for (l = master_clock->timelines; l != NULL; l = l->next)
{
ClutterTimeline *timeline = l->data;
g_object_weak_unref (G_OBJECT (timeline),
timeline_weak_ref,
master_clock);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (on_timeline_started),
master_clock);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (on_timeline_completed),
master_clock);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (on_timeline_paused),
master_clock);
}
g_slist_free (master_clock->timelines);
G_OBJECT_CLASS (clutter_master_clock_parent_class)->finalize (gobject);
}
static void
clutter_master_clock_class_init (ClutterMasterClockClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = clutter_master_clock_finalize;
}
static void
clutter_master_clock_init (ClutterMasterClock *self)
{
GSource *source;
source = clutter_clock_source_new (self);
self->source = source;
g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
g_source_set_can_recurse (source, FALSE);
g_source_attach (source, NULL);
}
/*
* _clutter_master_clock_get_default:
*
* Retrieves the default master clock. If this function has never
* been called before, the default master clock is created.
*
* Return value: the default master clock. The returned object is
* owned by Clutter and should not be modified or freed
*/
ClutterMasterClock *
_clutter_master_clock_get_default (void)
{
if (G_LIKELY (default_clock != NULL))
return default_clock;
default_clock = g_object_new (CLUTTER_TYPE_MASTER_CLOCK, NULL);
return default_clock;
}
static void
on_timeline_started (ClutterTimeline *timeline,
ClutterMasterClock *master_clock)
{
/* we want to reset the prev_tick if this is the first
* timeline; since timeline is playing we need to filter
* it out, otherwise has_running_timeline() will return
* TRUE and prev_tick will not be unset
*/
if (!has_running_timeline (master_clock, timeline))
master_clock->prev_tick.tv_sec = 0;
}
static void
on_timeline_completed (ClutterTimeline *timeline,
ClutterMasterClock *master_clock)
{
/* if this is the last timeline we need to turn :last-advance
* on in order to queue the redraw of the scene for the last
* frame; otherwise the ClockSource will fail the prepare and
* check phases and the last frame will not be painted
*/
if (!has_running_timeline (master_clock, NULL))
master_clock->last_advance = TRUE;
}
static void
on_timeline_paused (ClutterTimeline *timeline,
ClutterMasterClock *master_clock)
{
/* see the comment in on_timeline_completed */
if (!has_running_timeline (master_clock, NULL))
master_clock->last_advance = TRUE;
}
/*
* _clutter_master_clock_add_timeline:
* @master_clock: a #ClutterMasterClock
* @timeline: a #ClutterTimeline
*
* Adds @timeline to the list of timelines held by the master
* clock. This function should be called during the instance
* creation phase of the timeline.
*/
void
_clutter_master_clock_add_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline)
{
gboolean is_first = FALSE;
if (g_slist_find (master_clock->timelines, timeline))
return;
is_first = (master_clock->timelines == NULL) ? TRUE : FALSE;
master_clock->timelines = g_slist_prepend (master_clock->timelines,
timeline);
g_object_weak_ref (G_OBJECT (timeline),
timeline_weak_ref,
master_clock);
g_signal_connect (timeline, "started",
G_CALLBACK (on_timeline_started),
master_clock);
g_signal_connect (timeline, "completed",
G_CALLBACK (on_timeline_completed),
master_clock);
g_signal_connect (timeline, "paused",
G_CALLBACK (on_timeline_paused),
master_clock);
}
/*
* _clutter_master_clock_remove_timeline:
* @master_clock: a #ClutterMasterClock
* @timeline: a #ClutterTimeline
*
* Removes @timeline from the list of timelines held by the
* master clock. This function should be called during the
* #ClutterTimeline finalization.
*/
void
_clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline)
{
if (!g_slist_find (master_clock->timelines, timeline))
return;
master_clock->timelines = g_slist_remove (master_clock->timelines,
timeline);
g_object_weak_unref (G_OBJECT (timeline),
timeline_weak_ref,
master_clock);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (on_timeline_started),
master_clock);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (on_timeline_completed),
master_clock);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (on_timeline_paused),
master_clock);
/* last timeline: unset the prev_tick so that we can start
* from scratch when we add a new timeline
*/
if (master_clock->timelines == NULL)
master_clock->prev_tick.tv_sec = 0;
}
/*
* _clutter_master_clock_advance:
* @master_clock: a #ClutterMasterClock
*
* Advances all the timelines held by the master clock. This function
* should be called before calling clutter_redraw() to make sure that
* all the timelines are advanced and the scene is updated.
*/
void
_clutter_master_clock_advance (ClutterMasterClock *master_clock)
{
GTimeVal cur_tick = { 0, };
gulong msecs;
GSList *l;
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
if (master_clock->timelines == NULL)
return;
g_get_current_time (&cur_tick);
if (master_clock->prev_tick.tv_sec == 0)
master_clock->prev_tick = cur_tick;
msecs = (cur_tick.tv_sec - master_clock->prev_tick.tv_sec) * 1000
+ (cur_tick.tv_usec - master_clock->prev_tick.tv_usec) / 1000;
if (msecs == 0)
return;
CLUTTER_NOTE (SCHEDULER, "Advancing %d timelines by %lu milliseconds",
g_slist_length (master_clock->timelines),
msecs);
for (l = master_clock->timelines; l != NULL; l = l->next)
{
ClutterTimeline *timeline = l->data;
if (clutter_timeline_is_playing (timeline))
clutter_timeline_advance_delta (timeline, msecs);
}
/* store the previous state so that we can use
* it for the next advancement
*/
master_clock->msecs_delta = msecs;
master_clock->prev_tick = cur_tick;
}

View file

@ -0,0 +1,48 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CLUTTER_MASTER_CLOCK_H__
#define __CLUTTER_MASTER_CLOCK_H__
#include <clutter/clutter-timeline.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_MASTER_CLOCK (clutter_master_clock_get_type ())
#define CLUTTER_MASTER_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClock))
#define CLUTTER_IS_MASTER_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MASTER_CLOCK))
typedef struct _ClutterMasterClock ClutterMasterClock;
GType clutter_master_clock_get_type (void) G_GNUC_CONST;
ClutterMasterClock *_clutter_master_clock_get_default (void);
void _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void _clutter_master_clock_advance (ClutterMasterClock *master_clock);
G_END_DECLS
#endif /* __CLUTTER_MASTER_CLOCK_H__ */

View file

@ -44,9 +44,11 @@
#include "clutter-event.h"
#include "clutter-feature.h"
#include "clutter-id-pool.h"
#include "clutter-master-clock.h"
#include "clutter-stage-manager.h"
#include "clutter-stage-window.h"
#include "clutter-stage.h"
#include "clutter-timeline.h"
G_BEGIN_DECLS
@ -65,12 +67,6 @@ typedef enum {
CLUTTER_TEXTURE_IN_CLONE_PAINT = 1 << 6 /* Used for safety in clones */
} ClutterPrivateFlags;
typedef enum {
CLUTTER_PICK_NONE = 0,
CLUTTER_PICK_REACTIVE,
CLUTTER_PICK_ALL
} ClutterPickMode;
struct _ClutterInputDevice
{
gint id;
@ -133,6 +129,11 @@ struct _ClutterMainContext
MultiTouch */
guint32 last_event_time;
ClutterMasterClock *master_clock;
gulong redraw_count;
GList *repaint_funcs;
};
#define CLUTTER_CONTEXT() (clutter_context_get_default ())
@ -185,6 +186,9 @@ ClutterActor *_clutter_backend_create_stage (ClutterBackend *backend,
GError **error);
void _clutter_backend_ensure_context (ClutterBackend *backend,
ClutterStage *stage);
gboolean _clutter_backend_create_context (ClutterBackend *backend,
gboolean is_offscreen,
GError **error);
void _clutter_backend_add_options (ClutterBackend *backend,
GOptionGroup *group);
@ -196,21 +200,21 @@ void _clutter_backend_init_events (ClutterBackend *backend);
ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend);
ClutterUnit _clutter_backend_get_units_per_em (ClutterBackend *backend);
gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend,
PangoFontDescription *font_desc);
void _clutter_feature_init (void);
/* Picking code */
ClutterActor *_clutter_do_pick (ClutterStage *stage,
gint x,
gint y,
ClutterPickMode mode);
ClutterActor *_clutter_do_pick (ClutterStage *stage,
gint x,
gint y,
ClutterPickMode mode);
guint _clutter_pixel_to_id (guchar pixel[4]);
void _clutter_id_to_color (guint id, ClutterColor *col);
/* use this function as the accumulator if you have a signal with
* a G_TYPE_BOOLEAN return value; this will stop the emission as
* soon as one handler returns TRUE
@ -223,12 +227,21 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
ClutterActor *ancestor);
void _clutter_actor_rerealize (ClutterActor *self,
ClutterCallback callback,
void *data);
void _clutter_actor_set_opacity_parent (ClutterActor *self,
ClutterActor *parent);
void _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
gboolean enable);
void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
gboolean enable);
void _clutter_run_repaint_functions (void);
G_END_DECLS
#endif /* _HAVE_CLUTTER_PRIVATE_H */

View file

@ -451,16 +451,22 @@ clutter_shader_glsl_bind (ClutterShader *self,
cogl_shader_compile (shader);
if (!cogl_shader_is_compiled (shader))
{
gchar error_buf[512];
gchar *log_buf;
cogl_shader_get_info_log (shader, 512, error_buf);
log_buf = cogl_shader_get_info_log (shader);
/* translators: the first %s is the type of the shader, either
* Vertex shader or Fragment shader; the second %s is the actual
* error as reported by COGL
*/
g_set_error (error, CLUTTER_SHADER_ERROR,
CLUTTER_SHADER_ERROR_COMPILE,
_("%s compilation failed: %s"),
shader_type == CLUTTER_VERTEX_SHADER ? _("Vertex shader")
: _("Fragment shader"),
error_buf);
log_buf);
g_free (log_buf);
return FALSE;
}

View file

@ -224,8 +224,9 @@ clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager)
*
* Lists all currently used stages.
*
* Return value: (transfer container) (element-type ClutterStage): a newly allocated list
* of #ClutterStage objects. Use g_slist_free() to deallocate it when done.
* Return value: (transfer container) (element-type ClutterStage): a newly
* allocated list of #ClutterStage objects. Use g_slist_free() to
* deallocate it when done.
*
* Since: 0.8
*/
@ -235,6 +236,25 @@ clutter_stage_manager_list_stages (ClutterStageManager *stage_manager)
return g_slist_copy (stage_manager->stages);
}
/**
* clutter_stage_manager_list_stage:
* @stage_manager: a #ClutterStageManager
*
* Lists all currently used stages.
*
* Return value: (transfer none) (element-type ClutterStage): a pointer
* to the internal list of #ClutterStage objects. The returned list
* is owned by the #ClutterStageManager and should never be modified
* or freed
*
* Since: 1.0
*/
const GSList *
clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager)
{
return stage_manager->stages;
}
void
_clutter_stage_manager_add_stage (ClutterStageManager *stage_manager,
ClutterStage *stage)

View file

@ -61,6 +61,7 @@ void clutter_stage_manager_set_default_stage (ClutterStageManage
ClutterStage *stage);
ClutterStage * clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager);
GSList * clutter_stage_manager_list_stages (ClutterStageManager *stage_manager);
const GSList * clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager);
G_END_DECLS

View file

@ -27,6 +27,10 @@ struct _ClutterStageWindowIface
gboolean cursor_visible);
void (* set_user_resizable) (ClutterStageWindow *stage_window,
gboolean is_resizable);
void (* show) (ClutterStageWindow *stage_window,
gboolean do_raise);
void (* hide) (ClutterStageWindow *stage_window);
};
GType clutter_stage_window_get_type (void) G_GNUC_CONST;

View file

@ -59,6 +59,7 @@
#include "clutter-color.h"
#include "clutter-util.h"
#include "clutter-marshal.h"
#include "clutter-master-clock.h"
#include "clutter-enum-types.h"
#include "clutter-private.h"
#include "clutter-debug.h"
@ -86,7 +87,7 @@ struct _ClutterStagePrivate
gchar *title;
ClutterActor *key_focused_actor;
guint update_idle; /* repaint idler id */
guint update_idle; /* repaint idler id */
guint is_fullscreen : 1;
guint is_offscreen : 1;
@ -126,9 +127,9 @@ static const ClutterColor default_stage_color = { 255, 255, 255, 255 };
static void
clutter_stage_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
@ -142,9 +143,9 @@ clutter_stage_get_preferred_width (ClutterActor *self,
static void
clutter_stage_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
@ -156,11 +157,14 @@ clutter_stage_get_preferred_height (ClutterActor *self,
natural_height_p);
}
static void
clutter_stage_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
clutter_stage_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
gboolean origin_changed;
origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? TRUE : FALSE;
g_assert (priv->impl != NULL);
@ -168,30 +172,31 @@ clutter_stage_allocate (ClutterActor *self,
* then we simply ignore any allocation request and override the
* allocation chain.
*/
if (G_LIKELY (!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)))
if ((!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)))
{
ClutterActorClass *klass;
CLUTTER_NOTE (ACTOR, "Following allocation to %dx%d (origin %s)",
CLUTTER_UNITS_TO_DEVICE (box->x2 - box->x1),
CLUTTER_UNITS_TO_DEVICE (box->y2 - box->y1),
CLUTTER_NOTE (LAYOUT,
"Following allocation to %dx%d (origin %s)",
(int) (box->x2 - box->x1),
(int) (box->y2 - box->y1),
origin_changed ? "changed" : "not changed");
klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
klass->allocate (self, box, origin_changed);
klass->allocate (self, box, flags);
klass = CLUTTER_ACTOR_GET_CLASS (priv->impl);
klass->allocate (priv->impl, box, origin_changed);
klass->allocate (priv->impl, box, flags);
}
else
{
ClutterActorBox override = { 0, };
ClutterActorClass *klass;
ClutterUnit natural_width, natural_height;
gfloat natural_width, natural_height;
/* propagate the allocation */
klass = CLUTTER_ACTOR_GET_CLASS (priv->impl);
klass->allocate (self, box, origin_changed);
klass->allocate (self, box, flags);
/* get the preferred size from the backend */
clutter_actor_get_preferred_size (priv->impl,
@ -203,9 +208,18 @@ clutter_stage_allocate (ClutterActor *self,
override.x2 = natural_width;
override.y2 = natural_height;
CLUTTER_NOTE (LAYOUT,
"Overrigin original allocation of %dx%d "
"with %dx%d (origin %s)",
(int) (box->x2 - box->x1),
(int) (box->y2 - box->y1),
(int) (override.x2),
(int) (override.y2),
origin_changed ? "changed" : "not changed");
/* and store the overridden allocation */
klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
klass->allocate (self, &override, origin_changed);
klass->allocate (self, &override, flags);
}
}
@ -257,7 +271,7 @@ clutter_stage_pick (ClutterActor *self,
* Chain up to the groups paint howerer so our children get picked
* - clutter_group_pick
*/
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->pick (self, color);
}
static void
@ -265,21 +279,23 @@ clutter_stage_realize (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
/* Make sure the viewport and projection matrix are valid for the
first paint (which will likely occur before the ConfigureNotify
is received) */
* first paint (which will likely occur before the ConfigureNotify
* is received)
*/
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES);
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->realize (priv->impl);
clutter_actor_realize (priv->impl);
/* ensure that the stage is using the context if the
* realization sequence was successful
*/
if (CLUTTER_ACTOR_IS_REALIZED (priv->impl))
clutter_stage_ensure_current (CLUTTER_STAGE (self));
{
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (CLUTTER_STAGE (self));
}
else
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
@ -289,12 +305,9 @@ clutter_stage_unrealize (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
/* unset the flag */
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
/* and then unrealize the implementation */
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->unrealize (priv->impl);
clutter_actor_unrealize (priv->impl);
clutter_stage_ensure_current (CLUTTER_STAGE (self));
}
@ -303,33 +316,60 @@ static void
clutter_stage_show (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
if (!CLUTTER_ACTOR_IS_REALIZED (priv->impl))
clutter_actor_realize (priv->impl);
clutter_actor_show (priv->impl);
ClutterStageWindow *impl;
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);
g_assert (priv->impl != NULL);
impl = CLUTTER_STAGE_WINDOW (priv->impl);
CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->show (impl, TRUE);
}
static void
clutter_stage_hide (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
ClutterStageWindow *impl;
g_assert (priv->impl != NULL);
clutter_actor_hide (priv->impl);
impl = CLUTTER_STAGE_WINDOW (priv->impl);
CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->hide (impl);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
}
static void
clutter_stage_emit_key_focus_event (ClutterStage *stage,
gboolean focus_in)
{
ClutterStagePrivate *priv = stage->priv;
if (priv->key_focused_actor == NULL)
return;
if (focus_in)
g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in");
else
g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out");
}
static void
clutter_stage_real_activate (ClutterStage *stage)
{
clutter_stage_emit_key_focus_event (stage, TRUE);
}
static void
clutter_stage_real_deactivate (ClutterStage *stage)
{
clutter_stage_emit_key_focus_event (stage, FALSE);
}
static void
clutter_stage_real_fullscreen (ClutterStage *stage)
{
ClutterStagePrivate *priv = stage->priv;
ClutterUnit natural_width, natural_height;
gfloat natural_width, natural_height;
ClutterActorBox box;
/* we need to force an allocation here because the size
@ -348,7 +388,9 @@ clutter_stage_real_fullscreen (ClutterStage *stage)
box.x2 = natural_width;
box.y2 = natural_height;
clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, FALSE);
clutter_actor_allocate (CLUTTER_ACTOR (stage),
&box,
CLUTTER_ALLOCATION_NONE);
}
static gboolean
@ -356,23 +398,48 @@ redraw_update_idle (gpointer user_data)
{
ClutterStage *stage = user_data;
ClutterStagePrivate *priv = stage->priv;
ClutterMasterClock *master_clock;
/* clutter_redraw() will also call maybe_relayout(), but since a relayout can
* queue a redraw, we want to do the relayout before we clear the update_idle
* to avoid painting the stage twice. Calling maybe_relayout() twice in a row
* is cheap because of caching of requested and allocated size.
/* before we redraw we advance the master clock of one tick; this means
* that all the timelines that need advancing will be advanced by one
* frame. this will cause multiple redraw requests, so we do this before
* we ask for a relayout and before we do the actual redraw. this ensures
* that we paint the most updated scenegraph state and that all animations
* are in sync with the paint process.
*/
CLUTTER_NOTE (PAINT, "Avdancing master clock");
master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_advance (master_clock);
/* run the (eventual) repaint functions; since those might end up queuing
* a relayout or a redraw we need to execute them before maybe_relayout()
*/
CLUTTER_NOTE (PAINT, "Repaint functions");
_clutter_run_repaint_functions ();
/* clutter_redraw() will also call maybe_relayout(), but since a relayout
* can queue a redraw, we want to do the relayout before we clear the
* update_idle to avoid painting the stage twice. Calling maybe_relayout()
* twice in a row is cheap because of caching of requested and allocated
* size.
*/
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
if (priv->update_idle)
{
g_source_remove (priv->update_idle);
priv->update_idle = 0;
}
CLUTTER_NOTE (MULTISTAGE, "redrawing via idle for stage:%p", stage);
/* redrawing will advance the master clock */
CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage);
clutter_redraw (stage);
/* reset the guard, so that new redraws are possible */
priv->update_idle = 0;
if (CLUTTER_CONTEXT ()->redraw_count > 0)
{
CLUTTER_NOTE (SCHEDULER, "Queued %lu redraws during the last cycle",
CLUTTER_CONTEXT ()->redraw_count);
CLUTTER_CONTEXT ()->redraw_count = 0;
}
return FALSE;
}
@ -383,17 +450,28 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
ClutterStage *stage = CLUTTER_STAGE (actor);
ClutterStagePrivate *priv = stage->priv;
CLUTTER_NOTE (PAINT, "Redraw request number %lu",
CLUTTER_CONTEXT ()->redraw_count + 1);
if (priv->update_idle == 0)
{
CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for stage: %p", stage);
CLUTTER_NOTE (PAINT, "Adding idle source for stage: %p", stage);
/* FIXME: weak_ref self in case we dissapear before paint? */
priv->update_idle =
clutter_threads_add_idle_full (CLUTTER_PRIORITY_REDRAW,
redraw_update_idle,
stage,
NULL);
}
else
CLUTTER_CONTEXT ()->redraw_count += 1;
}
static void
set_offscreen_while_unrealized (ClutterActor *actor,
void *data)
{
CLUTTER_STAGE (actor)->priv->is_offscreen = GPOINTER_TO_INT (data);
}
static void
@ -417,24 +495,26 @@ clutter_stage_set_property (GObject *object,
break;
case PROP_OFFSCREEN:
if (priv->is_offscreen == g_value_get_boolean (value))
return;
{
gboolean was_showing;
if (CLUTTER_ACTOR_IS_REALIZED (actor))
{
/* Backend needs to check this prop and handle accordingly
* in realise.
* FIXME: More 'obvious' implementation needed?
*/
clutter_actor_unrealize (actor);
priv->is_offscreen = g_value_get_boolean (value);
clutter_actor_realize (actor);
if (priv->is_offscreen == g_value_get_boolean (value))
return;
if (!CLUTTER_ACTOR_IS_REALIZED (actor))
priv->is_offscreen = ~g_value_get_boolean (value);
}
else
priv->is_offscreen = g_value_get_boolean (value);
was_showing = CLUTTER_ACTOR_IS_VISIBLE (actor);
/* Backend needs to check this prop and handle accordingly
* in realise.
* FIXME: More 'obvious' implementation needed?
*/
_clutter_actor_rerealize (actor,
set_offscreen_while_unrealized,
GINT_TO_POINTER (g_value_get_boolean (value)));
if (was_showing &&
!CLUTTER_ACTOR_IS_REALIZED (actor))
priv->is_offscreen = ~g_value_get_boolean (value);
}
break;
case PROP_FULLSCREEN:
@ -536,7 +616,7 @@ clutter_stage_dispose (GObject *object)
ClutterStagePrivate *priv = stage->priv;
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
clutter_actor_unrealize (CLUTTER_ACTOR (object));
clutter_actor_hide (CLUTTER_ACTOR (object));
if (priv->update_idle)
{
@ -548,8 +628,9 @@ clutter_stage_dispose (GObject *object)
if (priv->impl)
{
CLUTTER_NOTE (MISC, "Disposing of the stage implementation");
g_object_unref (priv->impl);
CLUTTER_NOTE (BACKEND, "Disposing of the stage implementation");
clutter_actor_hide (priv->impl);
clutter_actor_destroy (priv->impl);
priv->impl = NULL;
}
@ -783,6 +864,8 @@ clutter_stage_class_init (ClutterStageClass *klass)
G_TYPE_NONE, 0);
klass->fullscreen = clutter_stage_real_fullscreen;
klass->activate = clutter_stage_real_activate;
klass->deactivate = clutter_stage_real_deactivate;
g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate));
}
@ -813,6 +896,9 @@ clutter_stage_init (ClutterStage *self)
else
g_object_ref_sink (priv->impl);
/* make sure that the implementation is considered a top level */
CLUTTER_SET_PRIVATE_FLAGS (priv->impl, CLUTTER_ACTOR_IS_TOPLEVEL);
priv->is_offscreen = FALSE;
priv->is_fullscreen = FALSE;
priv->is_user_resizable = FALSE;
@ -1244,20 +1330,26 @@ clutter_stage_read_pixels (ClutterStage *stage,
/**
* clutter_stage_get_actor_at_pos:
* @stage: a #ClutterStage
* @pick_mode: how the scene graph should be painted
* @x: X coordinate to check
* @y: Y coordinate to check
*
* Checks the scene at the coordinates @x and @y and returns a pointer
* to the #ClutterActor at those coordinates.
*
* Return value: (transfer none): the actor at the specified coordinates, if any
* By using @pick_mode it is possible to control which actors will be
* painted and thus available.
*
* Return value: (transfer none): the actor at the specified coordinates,
* if any
*/
ClutterActor *
clutter_stage_get_actor_at_pos (ClutterStage *stage,
gint x,
gint y)
clutter_stage_get_actor_at_pos (ClutterStage *stage,
ClutterPickMode pick_mode,
gint x,
gint y)
{
return _clutter_do_pick (stage, x, y, CLUTTER_PICK_ALL);
return _clutter_do_pick (stage, x, y, pick_mode);
}
/**
@ -1428,12 +1520,12 @@ clutter_stage_set_key_focus (ClutterStage *stage,
g_object_weak_unref (G_OBJECT (priv->key_focused_actor),
on_key_focused_weak_notify,
stage);
g_signal_emit_by_name (priv->key_focused_actor, "focus-out");
g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out");
priv->key_focused_actor = NULL;
}
else
g_signal_emit_by_name (stage, "focus-out");
g_signal_emit_by_name (stage, "key-focus-out");
if (actor)
{
@ -1442,10 +1534,10 @@ clutter_stage_set_key_focus (ClutterStage *stage,
g_object_weak_ref (G_OBJECT (actor),
on_key_focused_weak_notify,
stage);
g_signal_emit_by_name (priv->key_focused_actor, "focus-in");
g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in");
}
else
g_signal_emit_by_name (stage, "focus-in");
g_signal_emit_by_name (stage, "key-focus-in");
}
/**

View file

@ -79,6 +79,22 @@ G_BEGIN_DECLS
#define CLUTTER_STAGE_HEIGHT() \
(clutter_actor_get_height (clutter_stage_get_default ()))
/**
* ClutterPickMode:
* @CLUTTER_PICK_NONE: Do not paint any actor
* @CLUTTER_PICK_REACTIVE: Paint only the reactive actors
* @CLUTTER_PICK_ALL: Paint all actors
*
* Controls the paint cycle of the scene graph when in pick mode
*
* Since: 1.0
*/
typedef enum {
CLUTTER_PICK_NONE = 0,
CLUTTER_PICK_REACTIVE,
CLUTTER_PICK_ALL
} ClutterPickMode;
typedef struct _ClutterPerspective ClutterPerspective;
typedef struct _ClutterFog ClutterFog;
@ -192,6 +208,7 @@ void clutter_stage_show_cursor (ClutterStage *stage);
void clutter_stage_hide_cursor (ClutterStage *stage);
ClutterActor *clutter_stage_get_actor_at_pos (ClutterStage *stage,
ClutterPickMode pick_mode,
gint x,
gint y);
guchar * clutter_stage_read_pixels (ClutterStage *stage,

View file

@ -87,10 +87,10 @@ struct _LayoutCache
PangoLayout *layout;
/* The width that was used to generate this layout */
ClutterUnit width;
gfloat width;
/* The height that was used to generate this layout */
ClutterUnit height;
gfloat height;
/* A number representing the age of this cache (so that when a
* new layout is needed the last used cache is replaced)
@ -240,8 +240,8 @@ clutter_text_clear_selection (ClutterText *self)
static PangoLayout *
clutter_text_create_layout_no_cache (ClutterText *text,
ClutterUnit allocation_width,
ClutterUnit allocation_height)
gfloat allocation_width,
gfloat allocation_height)
{
ClutterTextPrivate *priv = text->priv;
PangoLayout *layout;
@ -322,7 +322,7 @@ clutter_text_create_layout_no_cache (ClutterText *text,
gint width;
width = allocation_width > 0
? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
? (allocation_width * 1024)
: -1;
pango_layout_set_width (layout, width);
@ -345,7 +345,7 @@ clutter_text_create_layout_no_cache (ClutterText *text,
gint height;
height = allocation_height > 0
? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_height)
? (allocation_height * 1024)
: -1;
pango_layout_set_height (layout, height);
@ -390,8 +390,8 @@ clutter_text_font_changed_cb (ClutterText *text)
*/
static PangoLayout *
clutter_text_create_layout (ClutterText *text,
ClutterUnit allocation_width,
ClutterUnit allocation_height)
gfloat allocation_width,
gfloat allocation_height)
{
ClutterTextPrivate *priv = text->priv;
LayoutCache *oldest_cache = priv->cached_layouts;
@ -456,16 +456,17 @@ clutter_text_create_layout (ClutterText *text,
static gint
clutter_text_coords_to_position (ClutterText *text,
gint x,
gint y)
gfloat x,
gfloat y)
{
ClutterTextPrivate *priv = text->priv;
gint index_;
gint px, py;
gint trailing;
/* Take any offset due to scrolling into account */
if (text->priv->single_line_mode)
x += text->priv->text_x * -1;
if (priv->single_line_mode)
x += priv->text_x * -1;
px = x * PANGO_SCALE;
py = y * PANGO_SCALE;
@ -494,9 +495,9 @@ clutter_text_coords_to_position (ClutterText *text,
gboolean
clutter_text_position_to_coords (ClutterText *self,
gint position,
ClutterUnit *x,
ClutterUnit *y,
ClutterUnit *line_height)
gfloat *x,
gfloat *y,
gfloat *line_height)
{
ClutterTextPrivate *priv;
PangoRectangle rect;
@ -537,7 +538,7 @@ clutter_text_position_to_coords (ClutterText *self,
if (x)
{
*x = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.x);
*x = (gfloat) rect.x / 1024.0f;
/* Take any offset due to scrolling into account */
if (priv->single_line_mode)
@ -545,10 +546,10 @@ clutter_text_position_to_coords (ClutterText *self,
}
if (y)
*y = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.y);
*y = (gfloat) rect.y / 1024.0f;
if (line_height)
*line_height = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.height);
*line_height = (gfloat) rect.height / 1024.0f;
return TRUE;
}
@ -557,7 +558,7 @@ static inline void
clutter_text_ensure_cursor_position (ClutterText *self)
{
ClutterTextPrivate *priv = self->priv;
ClutterUnit x, y, cursor_height;
gfloat x, y, cursor_height;
ClutterGeometry cursor_pos = { 0, };
gboolean x_changed, y_changed;
gboolean width_changed, height_changed;
@ -961,7 +962,7 @@ cursor_paint (ClutterText *self)
gint i;
gint index_;
gint maxindex;
ClutterUnit y, height;
gfloat y, height;
line = pango_layout_get_line_readonly (layout, line_no);
pango_layout_line_x_to_index (line, G_MAXINT, &maxindex, NULL);
@ -982,22 +983,20 @@ cursor_paint (ClutterText *self)
gint range_x;
gint range_width;
range_x = ranges[i * 2]
/ PANGO_SCALE;
range_x = ranges[i * 2] / PANGO_SCALE;
/* Account for any scrolling in single line mode */
if (priv->single_line_mode)
range_x += priv->text_x;
range_x += priv->text_x;
range_width = (ranges[i * 2 + 1] - ranges[i * 2])
/ PANGO_SCALE;
cogl_rectangle (range_x,
CLUTTER_UNITS_TO_DEVICE (y),
y,
range_x + range_width,
CLUTTER_UNITS_TO_DEVICE (y)
+ CLUTTER_UNITS_TO_DEVICE (height));
y + height);
}
g_free (ranges);
@ -1164,7 +1163,7 @@ clutter_text_button_press (ClutterActor *actor,
ClutterText *self = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = self->priv;
gboolean res = FALSE;
ClutterUnit x, y;
gfloat x, y;
gint index_;
/* we'll steal keyfocus if we do not have it */
@ -1182,18 +1181,15 @@ clutter_text_button_press (ClutterActor *actor,
return TRUE;
}
x = CLUTTER_UNITS_FROM_INT (event->x);
y = CLUTTER_UNITS_FROM_INT (event->y);
res = clutter_actor_transform_stage_point (actor, x, y, &x, &y);
res = clutter_actor_transform_stage_point (actor,
event->x,
event->y,
&x, &y);
if (res)
{
gint offset;
index_ = clutter_text_coords_to_position (self,
CLUTTER_UNITS_TO_INT (x),
CLUTTER_UNITS_TO_INT (y));
index_ = clutter_text_coords_to_position (self, x, y);
offset = bytes_to_offset (priv->text, index_);
/* what we select depends on the number of button clicks we
@ -1229,32 +1225,30 @@ static gboolean
clutter_text_motion (ClutterActor *actor,
ClutterMotionEvent *mev)
{
ClutterText *ttext = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = ttext->priv;
ClutterUnit x, y;
gint index_;
const gchar *text;
ClutterText *self = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = self->priv;
gfloat x, y;
gint index_, offset;
gboolean res;
if (!priv->in_select_drag)
return FALSE;
text = clutter_text_get_text (ttext);
res = clutter_actor_transform_stage_point (actor,
mev->x, mev->y,
&x, &y);
if (!res)
return FALSE;
x = CLUTTER_UNITS_FROM_INT (mev->x);
y = CLUTTER_UNITS_FROM_INT (mev->y);
clutter_actor_transform_stage_point (actor, x, y, &x, &y);
index_ = clutter_text_coords_to_position (ttext,
CLUTTER_UNITS_TO_INT (x),
CLUTTER_UNITS_TO_INT (y));
index_ = clutter_text_coords_to_position (self, x, y);
offset = bytes_to_offset (priv->text, index_);
if (priv->selectable)
clutter_text_set_cursor_position (ttext, bytes_to_offset (text, index_));
clutter_text_set_cursor_position (self, offset);
else
{
clutter_text_set_cursor_position (ttext, bytes_to_offset (text, index_));
clutter_text_set_selection_bound (ttext, bytes_to_offset (text, index_));
clutter_text_set_cursor_position (self, offset);
clutter_text_set_selection_bound (self, offset);
}
return TRUE;
@ -1264,8 +1258,8 @@ static gboolean
clutter_text_button_release (ClutterActor *actor,
ClutterButtonEvent *bev)
{
ClutterText *ttext = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = ttext->priv;
ClutterText *self = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = self->priv;
if (priv->in_select_drag)
{
@ -1380,11 +1374,11 @@ clutter_text_paint (ClutterActor *self)
pango_layout_get_extents (layout, NULL, &logical_rect);
cogl_clip_push (0, 0,
CLUTTER_UNITS_TO_FLOAT (alloc.x2 - alloc.x1),
CLUTTER_UNITS_TO_FLOAT (alloc.y2 - alloc.y1));
(alloc.x2 - alloc.x1),
(alloc.y2 - alloc.y1));
clip_set = TRUE;
actor_width = (CLUTTER_UNITS_TO_DEVICE (alloc.x2 - alloc.x1))
actor_width = (alloc.x2 - alloc.x1)
- 2 * TEXT_PADDING;
text_width = logical_rect.width / PANGO_SCALE;
@ -1449,16 +1443,16 @@ clutter_text_paint (ClutterActor *self)
static void
clutter_text_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterText *text = CLUTTER_TEXT (self);
ClutterTextPrivate *priv = text->priv;
PangoRectangle logical_rect = { 0, };
PangoLayout *layout;
gint logical_width;
ClutterUnit layout_width;
gfloat layout_width;
layout = clutter_text_create_layout (text, -1, -1);
@ -1471,7 +1465,7 @@ clutter_text_get_preferred_width (ClutterActor *self,
logical_width = logical_rect.x + logical_rect.width;
layout_width = logical_width > 0
? CLUTTER_UNITS_FROM_PANGO_UNIT (logical_width)
? (logical_width / 1024.0f)
: 1;
if (min_width_p)
@ -1493,9 +1487,9 @@ clutter_text_get_preferred_width (ClutterActor *self,
static void
clutter_text_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
@ -1512,7 +1506,7 @@ clutter_text_get_preferred_height (ClutterActor *self,
PangoLayout *layout;
PangoRectangle logical_rect = { 0, };
gint logical_height;
ClutterUnit layout_height;
gfloat layout_height;
layout = clutter_text_create_layout (CLUTTER_TEXT (self),
for_width, -1);
@ -1524,7 +1518,7 @@ clutter_text_get_preferred_height (ClutterActor *self,
* the height accordingly
*/
logical_height = logical_rect.y + logical_rect.height;
layout_height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_height);
layout_height = (gfloat) logical_height / 1024.0f;
if (min_height_p)
{
@ -1534,13 +1528,13 @@ clutter_text_get_preferred_height (ClutterActor *self,
if (priv->ellipsize && priv->wrap)
{
PangoLayoutLine *line;
ClutterUnit line_height;
gfloat line_height;
line = pango_layout_get_line_readonly (layout, 0);
pango_layout_line_get_extents (line, NULL, &logical_rect);
logical_height = logical_rect.y + logical_rect.height;
line_height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_height);
line_height = (gfloat) logical_height / 1024.0f;
*min_height_p = line_height;
}
@ -1554,9 +1548,9 @@ clutter_text_get_preferred_height (ClutterActor *self,
}
static void
clutter_text_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
clutter_text_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterText *text = CLUTTER_TEXT (self);
ClutterActorClass *parent_class;
@ -1569,7 +1563,7 @@ clutter_text_allocate (ClutterActor *self,
box->y2 - box->y1);
parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
parent_class->allocate (self, box, origin_changed);
parent_class->allocate (self, box, flags);
}
static gboolean
@ -3362,11 +3356,11 @@ clutter_text_set_markup (ClutterText *self,
PangoLayout *
clutter_text_get_layout (ClutterText *self)
{
ClutterUnit width, height;
gfloat width, height;
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
clutter_actor_get_sizeu (CLUTTER_ACTOR (self), &width, &height);
clutter_actor_get_size (CLUTTER_ACTOR (self), &width, &height);
return clutter_text_create_layout (self, width, height);
}

View file

@ -77,10 +77,8 @@ typedef struct _ClutterTextureAsyncData ClutterTextureAsyncData;
struct _ClutterTexturePrivate
{
gint width;
gint height;
gint max_tile_waste;
ClutterTextureQuality filter_quality;
gfloat width;
gfloat height;
CoglHandle material;
gboolean no_slice;
@ -136,7 +134,7 @@ enum
PROP_0,
PROP_NO_SLICE,
PROP_MAX_TILE_WASTE,
PROP_PIXEL_FORMAT, /* Texture format */
PROP_PIXEL_FORMAT,
PROP_SYNC_SIZE,
PROP_REPEAT_Y,
PROP_REPEAT_X,
@ -177,36 +175,35 @@ clutter_texture_error_quark (void)
return g_quark_from_static_string ("clutter-texture-error-quark");
}
static const struct
{
gint min_filter;
gint mag_filter;
}
clutter_texture_quality_filters[] =
{
/* CLUTTER_TEXTURE_QUALITY_LOW */
{ COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST },
/* CLUTTER_TEXTURE_QUALITY_MEDIUM */
{ COGL_MATERIAL_FILTER_LINEAR, COGL_MATERIAL_FILTER_LINEAR },
/* CLUTTER_TEXTURE_QUALITY_HIGH */
{ COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR, COGL_MATERIAL_FILTER_LINEAR }
};
static inline void
clutter_texture_quality_to_filters (ClutterTextureQuality quality,
gint *min_filter_p,
gint *mag_filter_p)
{
gint min_filter, mag_filter;
switch (quality)
{
case CLUTTER_TEXTURE_QUALITY_LOW:
min_filter = COGL_TEXTURE_FILTER_NEAREST;
mag_filter = COGL_TEXTURE_FILTER_NEAREST;
break;
case CLUTTER_TEXTURE_QUALITY_MEDIUM:
min_filter = COGL_TEXTURE_FILTER_LINEAR;
mag_filter = COGL_TEXTURE_FILTER_LINEAR;
break;
case CLUTTER_TEXTURE_QUALITY_HIGH:
min_filter = COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR;
mag_filter = COGL_TEXTURE_FILTER_LINEAR;
break;
}
g_return_if_fail (quality < G_N_ELEMENTS (clutter_texture_quality_filters));
if (min_filter_p)
*min_filter_p = min_filter;
*min_filter_p = clutter_texture_quality_filters[quality].min_filter;
if (mag_filter_p)
*mag_filter_p = mag_filter;
*mag_filter_p = clutter_texture_quality_filters[quality].mag_filter;
}
static void
@ -217,7 +214,10 @@ texture_free_gl_resources (ClutterTexture *texture)
CLUTTER_MARK();
if (priv->material != COGL_INVALID_HANDLE)
cogl_material_remove_layer (priv->material, 0);
/* We want to keep the layer so that the filter settings will
remain but we want to free its resources so we clear the
texture handle */
cogl_material_set_layer (priv->material, 0, COGL_INVALID_HANDLE);
}
static void
@ -286,31 +286,20 @@ clutter_texture_realize (ClutterActor *actor)
if (priv->fbo_source)
{
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
gint max_waste = -1;
CoglHandle tex;
/* Handle FBO's */
if (!priv->no_slice)
max_waste = priv->max_tile_waste;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING;
tex = cogl_texture_new_with_size (priv->width,
priv->height,
max_waste, flags,
flags,
COGL_PIXEL_FORMAT_RGBA_8888);
cogl_material_set_layer (priv->material, 0, tex);
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (tex, min_filter, mag_filter);
priv->fbo_handle = cogl_offscreen_new_to_texture (tex);
/* The material now has a reference to the texture so it will
@ -337,19 +326,15 @@ clutter_texture_realize (ClutterActor *actor)
}
else
{
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_READ_PIXELS))
{
/* Dont allow realization with no data - note set_data
* will set realize flags.
*/
CLUTTER_NOTE (TEXTURE,
"Texture has no image data cannot realize");
CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
CLUTTER_NOTE (TEXTURE, "flags %i", actor->flags);
return;
}
/* If we have no data, then realization is a no-op but
* we still want to be in REALIZED state to maintain
* invariants. We may have already created the texture
* if someone set some data earlier, or we may create it
* later if someone sets some data later. The fact that
* we may have created it earlier is really a bug, since
* it means ClutterTexture can have GL resources without
* being realized.
*/
}
CLUTTER_NOTE (TEXTURE, "Texture realized");
@ -357,9 +342,9 @@ clutter_texture_realize (ClutterActor *actor)
static void
clutter_texture_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
@ -376,19 +361,14 @@ clutter_texture_get_preferred_width (ClutterActor *self,
for_height < 0 ||
priv->height <= 0)
{
*natural_width_p = CLUTTER_UNITS_FROM_DEVICE (priv->width);
*natural_width_p = priv->width;
}
else
{
/* Set the natural width so as to preserve the aspect ratio */
gfloat ratio, height;
gfloat ratio = priv->width / priv->height;
ratio = (float)(priv->width) / (float)(priv->height);
height = CLUTTER_UNITS_TO_FLOAT (for_height);
*natural_width_p =
CLUTTER_UNITS_FROM_FLOAT (ratio * height);
*natural_width_p = ratio * for_height;
}
}
}
@ -401,9 +381,9 @@ clutter_texture_get_preferred_width (ClutterActor *self,
static void
clutter_texture_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
@ -420,19 +400,14 @@ clutter_texture_get_preferred_height (ClutterActor *self,
for_width < 0 ||
priv->width <= 0)
{
*natural_height_p = CLUTTER_UNITS_FROM_DEVICE (priv->height);
*natural_height_p = priv->height;
}
else
{
/* Set the natural height so as to preserve the aspect ratio */
gfloat ratio, width;
gfloat ratio = priv->height / priv->width;
ratio = (float)(priv->height) / (float)(priv->width);
width = CLUTTER_UNITS_TO_FLOAT (for_width);
*natural_height_p =
CLUTTER_UNITS_FROM_FLOAT (ratio * width);
*natural_height_p = ratio * for_width;
}
}
}
@ -444,20 +419,21 @@ clutter_texture_get_preferred_height (ClutterActor *self,
}
static void
clutter_texture_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
clutter_texture_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv;
/* chain up to set actor->allocation */
CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->allocate (self, box,
origin_changed);
CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->allocate (self,
box,
flags);
/* If we adopted the source fbo then allocate that at its preferred
size */
if (priv->fbo_source && clutter_actor_get_parent (priv->fbo_source) == self)
clutter_actor_allocate_preferred_size (priv->fbo_source, origin_changed);
clutter_actor_allocate_preferred_size (priv->fbo_source, flags);
}
static void
@ -466,7 +442,7 @@ clutter_texture_set_fbo_projection (ClutterActor *self)
ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv;
ClutterVertex verts[4];
gfloat viewport[4];
ClutterUnit x_min, x_max, y_min, y_max;
gfloat x_min, x_max, y_min, y_max;
gfloat tx_min, tx_max, ty_min, ty_max;
gfloat tan_angle, near_size;
ClutterPerspective perspective;
@ -501,13 +477,13 @@ clutter_texture_set_fbo_projection (ClutterActor *self)
/* Convert the coordinates back to [-1,1] range */
cogl_get_viewport (viewport);
tx_min = (CLUTTER_UNITS_TO_FLOAT (x_min) / viewport[2])
tx_min = (x_min / viewport[2])
* 2 - 1.0;
tx_max = (CLUTTER_UNITS_TO_FLOAT (x_max) / viewport[2])
tx_max = (x_max / viewport[2])
* 2 - 1.0;
ty_min = (CLUTTER_UNITS_TO_FLOAT (y_min) / viewport[3])
ty_min = (y_min / viewport[3])
* 2 - 1.0;
ty_max = (CLUTTER_UNITS_TO_FLOAT (y_max) / viewport[3])
ty_max = (y_max / viewport[3])
* 2 - 1.0;
/* Set up a projection matrix so that the actor will be projected as
@ -528,7 +504,7 @@ clutter_texture_paint (ClutterActor *self)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
gint x_1, y_1, x_2, y_2;
ClutterActorBox box = { 0, };
CoglColor transparent_col;
gfloat t_w, t_h;
guint8 paint_opacity = clutter_actor_get_paint_opacity (self);
@ -541,9 +517,6 @@ clutter_texture_paint (ClutterActor *self)
return;
}
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR(texture)))
clutter_actor_realize (CLUTTER_ACTOR(texture));
if (priv->fbo_handle != COGL_INVALID_HANDLE)
{
ClutterMainContext *context;
@ -567,19 +540,20 @@ clutter_texture_paint (ClutterActor *self)
if ((stage = clutter_actor_get_stage (self)))
{
guint stage_width, stage_height;
ClutterActor *source_parent;
gfloat stage_width, stage_height;
ClutterActor *source_parent;
clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
clutter_actor_get_size (stage, &stage_width, &stage_height);
/* Use below to set the modelview matrix as if the viewport
was still the same size as the stage */
cogl_setup_viewport (stage_width, stage_height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
_cogl_setup_viewport (stage_width, stage_height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
/* Use a projection matrix that makes the actor appear as it
would if it was rendered at its normal screen location */
clutter_texture_set_fbo_projection (self);
@ -636,28 +610,28 @@ clutter_texture_paint (ClutterActor *self)
cogl_material_set_color4ub (priv->material, 0xff, 0xff, 0xff, paint_opacity);
clutter_actor_get_allocation_coords (self, &x_1, &y_1, &x_2, &y_2);
clutter_actor_get_allocation_box (self, &box);
CLUTTER_NOTE (PAINT, "paint to x1: %i, y1: %i x2: %i, y2: %i "
CLUTTER_NOTE (PAINT, "paint to x1: %f, y1: %f x2: %f, y2: %f "
"opacity: %i",
x_1, y_1, x_2, y_2,
box.x1, box.y1, box.x2, box.y2,
clutter_actor_get_opacity (self));
if (priv->repeat_x && priv->width > 0)
t_w = (float) (x_2 - x_1) / (float) (priv->width);
t_w = (box.x2 - box.x1) / priv->width;
else
t_w = 1.0;
if (priv->repeat_y && priv->height > 0)
t_h = (float) (y_2 - y_1) / (float) (priv->height);
t_h = (box.y2 - box.y1) / priv->height;
else
t_h = 1.0;
/* Paint will have translated us */
cogl_set_source (priv->material);
cogl_rectangle_with_texture_coords (0, 0,
(float) (x_2 - x_1),
(float) (y_2 - y_1),
box.x2 - box.x1,
box.y2 - box.y1,
0, 0, t_w, t_h);
}
@ -791,10 +765,6 @@ clutter_texture_set_property (GObject *object,
switch (prop_id)
{
case PROP_MAX_TILE_WASTE:
clutter_texture_set_max_tile_waste (texture, g_value_get_int (value));
break;
case PROP_SYNC_SIZE:
clutter_texture_set_sync_size (texture, g_value_get_boolean (value));
break;
@ -876,14 +846,14 @@ clutter_texture_get_property (GObject *object,
switch (prop_id)
{
case PROP_MAX_TILE_WASTE:
g_value_set_int (value, clutter_texture_get_max_tile_waste (texture));
break;
case PROP_PIXEL_FORMAT:
g_value_set_enum (value, clutter_texture_get_pixel_format (texture));
break;
case PROP_MAX_TILE_WASTE:
g_value_set_int (value, clutter_texture_get_max_tile_waste (texture));
break;
case PROP_SYNC_SIZE:
g_value_set_boolean (value, priv->sync_actor_size);
break;
@ -962,6 +932,14 @@ clutter_texture_class_init (ClutterTextureClass *klass)
FALSE,
G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE));
g_object_class_install_property
(gobject_class, PROP_MAX_TILE_WASTE,
g_param_spec_int ("tile-waste",
"Tile Waste",
"Maximum waste area of a sliced texture",
-1, G_MAXINT,
COGL_TEXTURE_MAX_WASTE,
CLUTTER_PARAM_READABLE));
g_object_class_install_property
(gobject_class, PROP_REPEAT_X,
@ -990,19 +968,6 @@ clutter_texture_class_init (ClutterTextureClass *klass)
CLUTTER_TEXTURE_QUALITY_MEDIUM,
G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE));
g_object_class_install_property
(gobject_class, PROP_MAX_TILE_WASTE,
g_param_spec_int ("tile-waste",
"Tile dimension to waste",
"Max wastage dimension of a texture when using "
"sliced textures or -1 to disable slicing. "
"Bigger values use less textures, "
"smaller values less texture memory.",
-1,
G_MAXINT,
63,
G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE));
g_object_class_install_property
(gobject_class, PROP_PIXEL_FORMAT,
g_param_spec_enum ("pixel-format",
@ -1112,9 +1077,9 @@ clutter_texture_class_init (ClutterTextureClass *klass)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterTextureClass, size_change),
NULL, NULL,
clutter_marshal_VOID__INT_INT,
clutter_marshal_VOID__FLOAT_FLOAT,
G_TYPE_NONE,
2, G_TYPE_INT, G_TYPE_INT);
2, G_TYPE_FLOAT, G_TYPE_FLOAT);
/**
* ClutterTexture::pixbuf-change:
* @texture: the texture which received the signal
@ -1215,8 +1180,6 @@ clutter_texture_init (ClutterTexture *self)
self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self);
priv->max_tile_waste = 63;
priv->filter_quality = CLUTTER_TEXTURE_QUALITY_MEDIUM;
priv->repeat_x = FALSE;
priv->repeat_y = FALSE;
priv->sync_actor_size = TRUE;
@ -1256,12 +1219,6 @@ clutter_texture_save_to_local_data (ClutterTexture *texture)
/* Align to 4 bytes */
priv->local_data_rowstride = (priv->local_data_width * bpp + 3) & ~3;
/* Store the filter quality and max_tile_waste from the texture
properties so that they will be restored the data is loaded
again */
priv->max_tile_waste = clutter_texture_get_max_tile_waste (texture);
priv->filter_quality = clutter_texture_get_filter_quality (texture);
priv->local_data = g_malloc (priv->local_data_rowstride
* priv->local_data_height);
@ -1396,6 +1353,12 @@ clutter_texture_get_cogl_texture (ClutterTexture *texture)
* @cogl_tex. A reference to the texture is taken so if the handle is
* no longer needed it should be deref'd with cogl_handle_unref.
*
* This should not be called on an unrealizable texture (one that
* isn't inside a stage). (Currently the ClutterTexture
* implementation relies on being able to have a GL texture while
* unrealized, which means you can get away with it, but it's
* not correct and may change in the future.)
*
* Since: 0.8
*/
void
@ -1409,6 +1372,12 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
g_return_if_fail (cogl_is_texture (cogl_tex));
/* FIXME this implementation should realize the actor if it's in a
* stage, and warn and return if not in a stage yet. However, right
* now everything would break if we did that, so we just fudge it
* and we're broken: we can have a texture without being realized.
*/
priv = texture->priv;
width = cogl_texture_get_width (cogl_tex);
@ -1424,6 +1393,14 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
/* Remove old texture */
texture_free_gl_resources (texture);
/* Free any saved data so realization doesn't resend it to GL */
if (priv->local_data)
{
g_free (priv->local_data);
priv->local_data = NULL;
}
/* Use the new texture */
cogl_material_set_layer (priv->material, 0, cogl_tex);
@ -1436,12 +1413,10 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
priv->width = width;
priv->height = height;
CLUTTER_NOTE (TEXTURE, "set size %ix%i\n",
CLUTTER_NOTE (TEXTURE, "set size %.2fx%.2f\n",
priv->width,
priv->height);
CLUTTER_ACTOR_SET_FLAGS (CLUTTER_ACTOR (texture), CLUTTER_ACTOR_REALIZED);
if (size_change)
{
g_signal_emit (texture, texture_signals[SIZE_CHANGE], 0,
@ -1475,17 +1450,16 @@ clutter_texture_set_from_data (ClutterTexture *texture,
ClutterTexturePrivate *priv = texture->priv;
CoglHandle new_texture = COGL_INVALID_HANDLE;
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
gint max_waste = -1;
if (!priv->no_slice)
max_waste = priv->max_tile_waste;
if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
/* FIXME if we are not realized, we should store the data
* for future use, instead of creating the texture.
*/
new_texture = cogl_texture_new_from_data (width, height,
max_waste, flags,
flags,
source_format,
COGL_PIXEL_FORMAT_ANY,
rowstride,
@ -1500,12 +1474,6 @@ clutter_texture_set_from_data (ClutterTexture *texture,
return FALSE;
}
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (new_texture, min_filter, mag_filter);
clutter_texture_set_cogl_texture (texture, new_texture);
cogl_handle_unref (new_texture);
@ -1530,25 +1498,23 @@ clutter_texture_set_from_data (ClutterTexture *texture,
*
* Sets #ClutterTexture image data.
*
* Note: This function is likely to change in future versions.
*
* Return value: %TRUE on success, %FALSE on failure.
*
* Since: 0.4.
**/
*/
gboolean
clutter_texture_set_from_rgb_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint width,
gint height,
gint rowstride,
gint bpp,
ClutterTextureFlags flags,
GError **error)
clutter_texture_set_from_rgb_data (ClutterTexture *texture,
const guchar *data,
gboolean has_alpha,
gint width,
gint height,
gint rowstride,
gint bpp,
ClutterTextureFlags flags,
GError **error)
{
ClutterTexturePrivate *priv;
CoglPixelFormat source_format;
CoglPixelFormat source_format;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE);
@ -1561,9 +1527,13 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Unsupported BPP");
"Unsupported bits per pixel value '%d': "
"Clutter supports only a BPP value of 4 "
"for RGBA data",
bpp);
return FALSE;
}
source_format = COGL_PIXEL_FORMAT_RGBA_8888;
}
else
@ -1572,11 +1542,16 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"Unsupported BPP");
"Unsupported bits per pixel value '%d': "
"Clutter supports only a BPP value of 3 "
"for RGB data",
bpp);
return FALSE;
}
source_format = COGL_PIXEL_FORMAT_RGB_888;
}
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_BGR))
source_format |= COGL_BGR_BIT;
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT))
@ -1601,8 +1576,6 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
* Sets a #ClutterTexture from YUV image data. If an error occurred,
* %FALSE is returned and @error is set.
*
* This function is likely to change in future versions.
*
* Return value: %TRUE if the texture was successfully updated
*
* Since: 0.4
@ -1634,7 +1607,7 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture,
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
"YUV2 not supported");
"YUV2 textues are not supported");
return FALSE;
}
@ -1663,20 +1636,16 @@ clutter_texture_async_load_complete (ClutterTexture *self,
ClutterTexturePrivate *priv = self->priv;
CoglHandle handle;
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint waste = -1;
priv->async_data = NULL;
if (error == NULL)
{
if (!priv->no_slice)
waste = priv->max_tile_waste;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING;
handle = cogl_texture_new_from_bitmap (bitmap,
waste, flags,
flags,
COGL_PIXEL_FORMAT_ANY);
clutter_texture_set_cogl_texture (self, handle);
if (priv->load_size_async)
@ -1908,8 +1877,6 @@ clutter_texture_set_from_file (ClutterTexture *texture,
CoglHandle new_texture = COGL_INVALID_HANDLE;
GError *internal_error = NULL;
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
gint max_waste = -1;
priv = texture->priv;
@ -1918,14 +1885,11 @@ clutter_texture_set_from_file (ClutterTexture *texture,
if (priv->load_data_async)
return clutter_texture_async_load (texture, filename, error);
if (!priv->no_slice)
max_waste = priv->max_tile_waste;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
if (priv->no_slice)
flags |= COGL_TEXTURE_NO_SLICING;
new_texture = cogl_texture_new_from_file (filename,
max_waste, flags,
flags,
COGL_PIXEL_FORMAT_ANY,
&internal_error);
if (new_texture == COGL_INVALID_HANDLE)
@ -1945,12 +1909,6 @@ clutter_texture_set_from_file (ClutterTexture *texture,
return FALSE;
}
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (new_texture, min_filter, mag_filter);
clutter_texture_set_cogl_texture (texture, new_texture);
cogl_handle_unref (new_texture);
@ -1991,33 +1949,14 @@ clutter_texture_set_filter_quality (ClutterTexture *texture,
if (filter_quality != old_quality)
{
CoglHandle cogl_texture = clutter_texture_get_cogl_texture (texture);
gint min_filter, mag_filter;
priv->filter_quality = filter_quality;
clutter_texture_quality_to_filters (priv->filter_quality,
clutter_texture_quality_to_filters (filter_quality,
&min_filter,
&mag_filter);
/* Is this actually needed - causes problems with TFP mipmaps */
if (cogl_texture != COGL_INVALID_HANDLE)
cogl_texture_set_filters (cogl_texture, min_filter, mag_filter);
if ((old_quality == CLUTTER_TEXTURE_QUALITY_HIGH ||
filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) &&
CLUTTER_ACTOR_IS_REALIZED (texture))
{
gboolean was_visible;
was_visible = CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (texture));
clutter_actor_unrealize (CLUTTER_ACTOR (texture));
clutter_actor_realize (CLUTTER_ACTOR (texture));
if (was_visible)
clutter_actor_show (CLUTTER_ACTOR (texture));
}
cogl_material_set_layer_filters (priv->material, 0,
min_filter, mag_filter);
g_object_notify (G_OBJECT (texture), "filter-quality");
@ -2040,46 +1979,28 @@ ClutterTextureQuality
clutter_texture_get_filter_quality (ClutterTexture *texture)
{
ClutterTexturePrivate *priv;
const GList *layers;
CoglMaterialFilter min_filter, mag_filter;
int i;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0);
priv = texture->priv;
return priv->filter_quality;
}
layers = cogl_material_get_layers (priv->material);
if (layers == NULL)
return CLUTTER_TEXTURE_QUALITY_MEDIUM;
/**
* clutter_texture_set_max_tile_waste
* @texture: A #ClutterTexture
* @max_tile_waste: Maximum amount of waste in pixels or -1
*
* Sets the maximum number of pixels in either axis that can be wasted
* for an individual texture slice. If -1 is specified then the
* texture is forced not to be sliced and the texture creation will
* fail if the hardware can't create a texture large enough.
*
* The value is only used when first creating a texture so changing it
* after the texture data has been set has no effect.
*
* Since: 0.8
*/
void
clutter_texture_set_max_tile_waste (ClutterTexture *texture,
gint max_tile_waste)
{
ClutterTexturePrivate *priv;
CoglHandle cogl_texture;
min_filter = cogl_material_layer_get_min_filter (layers->data);
mag_filter = cogl_material_layer_get_mag_filter (layers->data);
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
for (i = 0; i < G_N_ELEMENTS (clutter_texture_quality_filters); i++)
if (clutter_texture_quality_filters[i].min_filter == min_filter
&& clutter_texture_quality_filters[i].mag_filter == mag_filter)
return i;
priv = texture->priv;
cogl_texture = clutter_texture_get_cogl_texture (texture);
/* There's no point in changing the max_tile_waste if the texture
has already been created because it will be overridden with the
value from the texture handle */
if (cogl_texture == COGL_INVALID_HANDLE)
priv->max_tile_waste = max_tile_waste;
/* Unknown filter combination */
return CLUTTER_TEXTURE_QUALITY_LOW;
}
/**
@ -2090,7 +2011,7 @@ clutter_texture_set_max_tile_waste (ClutterTexture *texture,
* -1 if slicing is disabled.
*
* Return value: The maximum waste or -1 if the texture waste is
* unlimited.
* unlimited.
*
* Since: 0.8
*/
@ -2103,13 +2024,12 @@ clutter_texture_get_max_tile_waste (ClutterTexture *texture)
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0);
priv = texture->priv;
cogl_texture = clutter_texture_get_cogl_texture (texture);
if (cogl_texture == COGL_INVALID_HANDLE)
return texture->priv->max_tile_waste;
return priv->no_slice ? -1 : COGL_TEXTURE_MAX_WASTE;
else
/* If we have a valid texture handle then use the value from that
instead */
return cogl_texture_get_max_waste (cogl_texture);
}
@ -2247,8 +2167,15 @@ clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT))
source_format |= COGL_PREMULT_BIT;
clutter_actor_realize (CLUTTER_ACTOR (texture));
/* attempt to realize ... */
if (!CLUTTER_ACTOR_IS_REALIZED (texture) &&
clutter_actor_get_stage (CLUTTER_ACTOR (texture)) != NULL)
clutter_actor_realize (CLUTTER_ACTOR (texture));
/* due to the fudging of clutter_texture_set_cogl_texture()
* which allows setting a texture pre-realize, we may end
* up having a texture even if we couldn't realize yet.
*/
cogl_texture = clutter_texture_get_cogl_texture (texture);
if (cogl_texture == COGL_INVALID_HANDLE)
{
@ -2287,14 +2214,13 @@ on_fbo_source_size_change (GObject *object,
ClutterTexture *texture)
{
ClutterTexturePrivate *priv = texture->priv;
guint w, h;
gfloat w, h;
clutter_actor_get_transformed_size (priv->fbo_source, &w, &h);
if (w != priv->width || h != priv->height)
{
CoglTextureFlags flags = COGL_TEXTURE_NONE;
gint min_filter, mag_filter;
CoglHandle tex;
/* tear down the FBO */
@ -2306,23 +2232,15 @@ on_fbo_source_size_change (GObject *object,
priv->width = w;
priv->height = h;
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
flags |= COGL_TEXTURE_AUTO_MIPMAP;
flags |= COGL_TEXTURE_NO_SLICING;
tex = cogl_texture_new_with_size (MAX (priv->width, 1),
MAX (priv->height, 1),
-1,
flags,
COGL_PIXEL_FORMAT_RGBA_8888);
cogl_material_set_layer (priv->material, 0, tex);
clutter_texture_quality_to_filters (priv->filter_quality,
&min_filter,
&mag_filter);
cogl_texture_set_filters (tex, min_filter, mag_filter);
priv->fbo_handle = cogl_offscreen_new_to_texture (tex);
/* The material now has a reference to the texture so it will
@ -2332,8 +2250,6 @@ on_fbo_source_size_change (GObject *object,
if (priv->fbo_handle == COGL_INVALID_HANDLE)
{
g_warning ("%s: Offscreen texture creation failed", G_STRLOC);
CLUTTER_ACTOR_UNSET_FLAGS (CLUTTER_ACTOR (texture),
CLUTTER_ACTOR_REALIZED);
return;
}
@ -2439,7 +2355,7 @@ clutter_texture_new_from_actor (ClutterActor *actor)
{
ClutterTexture *texture;
ClutterTexturePrivate *priv;
guint w, h;
gfloat w, h;
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
@ -2509,8 +2425,8 @@ clutter_texture_new_from_actor (ClutterActor *actor)
G_CALLBACK(on_fbo_parent_change),
texture);
priv->width = w;
priv->height = h;
priv->width = w;
priv->height = h;
clutter_actor_set_size (CLUTTER_ACTOR (texture), priv->width, priv->height);
@ -2764,7 +2680,7 @@ clutter_texture_get_keep_aspect_ratio (ClutterTexture *texture)
/**
* clutter_texture_set_load_async:
* @texture: a #ClutterTexture
* @load_sync: %TRUE if the texture should asynchronously load data
* @load_async: %TRUE if the texture should asynchronously load data
* from a filename
*
* Sets whether @texture should use a worker thread to load the data

View file

@ -202,9 +202,6 @@ void clutter_texture_get_base_size (ClutterTexture
void clutter_texture_set_filter_quality (ClutterTexture *texture,
ClutterTextureQuality filter_quality);
ClutterTextureQuality clutter_texture_get_filter_quality (ClutterTexture *texture);
void clutter_texture_set_max_tile_waste (ClutterTexture *texture,
gint max_tile_waste);
gint clutter_texture_get_max_tile_waste (ClutterTexture *texture);
CoglHandle clutter_texture_get_cogl_texture (ClutterTexture *texture);
void clutter_texture_set_cogl_texture (ClutterTexture *texture,
CoglHandle cogl_tex);
@ -221,6 +218,7 @@ void clutter_texture_get_repeat (ClutterTexture
gboolean *repeat_x,
gboolean *repeat_y);
CoglPixelFormat clutter_texture_get_pixel_format (ClutterTexture *texture);
gint clutter_texture_get_max_tile_waste (ClutterTexture *texture);
void clutter_texture_set_keep_aspect_ratio (ClutterTexture *texture,
gboolean keep_aspect);
gboolean clutter_texture_get_keep_aspect_ratio (ClutterTexture *texture);

File diff suppressed because it is too large Load diff

View file

@ -112,17 +112,12 @@ struct _ClutterTimelineClass
GType clutter_timeline_get_type (void) G_GNUC_CONST;
ClutterTimeline *clutter_timeline_new (guint n_frames,
guint fps);
ClutterTimeline *clutter_timeline_new_for_duration (guint msecs);
ClutterTimeline *clutter_timeline_new (guint msecs);
ClutterTimeline *clutter_timeline_clone (ClutterTimeline *timeline);
guint clutter_timeline_get_duration (ClutterTimeline *timeline);
void clutter_timeline_set_duration (ClutterTimeline *timeline,
guint msecs);
guint clutter_timeline_get_speed (ClutterTimeline *timeline);
void clutter_timeline_set_speed (ClutterTimeline *timeline,
guint fps);
ClutterTimelineDirection clutter_timeline_get_direction (ClutterTimeline *timeline);
void clutter_timeline_set_direction (ClutterTimeline *timeline,
ClutterTimelineDirection direction);
@ -134,38 +129,35 @@ void clutter_timeline_set_loop (ClutterTimeline *timeli
gboolean clutter_timeline_get_loop (ClutterTimeline *timeline);
void clutter_timeline_rewind (ClutterTimeline *timeline);
void clutter_timeline_skip (ClutterTimeline *timeline,
guint n_frames);
guint msecs);
void clutter_timeline_advance (ClutterTimeline *timeline,
guint frame_num);
gint clutter_timeline_get_current_frame (ClutterTimeline *timeline);
guint msecs);
guint clutter_timeline_get_elapsed_time (ClutterTimeline *timeline);
gdouble clutter_timeline_get_progress (ClutterTimeline *timeline);
CoglFixed clutter_timeline_get_progressx (ClutterTimeline *timeline);
void clutter_timeline_set_n_frames (ClutterTimeline *timeline,
guint n_frames);
guint clutter_timeline_get_n_frames (ClutterTimeline *timeline);
gboolean clutter_timeline_is_playing (ClutterTimeline *timeline);
void clutter_timeline_set_delay (ClutterTimeline *timeline,
guint msecs);
guint clutter_timeline_get_delay (ClutterTimeline *timeline);
guint clutter_timeline_get_delta (ClutterTimeline *timeline,
guint *msecs);
guint clutter_timeline_get_delta (ClutterTimeline *timeline);
void clutter_timeline_add_marker_at_frame (ClutterTimeline *timeline,
const gchar *marker_name,
guint frame_num);
void clutter_timeline_add_marker_at_time (ClutterTimeline *timeline,
const gchar *marker_name,
guint msecs);
void clutter_timeline_remove_marker (ClutterTimeline *timeline,
const gchar *marker_name);
gchar ** clutter_timeline_list_markers (ClutterTimeline *timeline,
gint frame_num,
gint msecs,
gsize *n_markers) G_GNUC_MALLOC;
gboolean clutter_timeline_has_marker (ClutterTimeline *timeline,
const gchar *marker_name);
void clutter_timeline_advance_to_marker (ClutterTimeline *timeline,
const gchar *marker_name);
/*< private >*/
void clutter_timeline_advance_delta (ClutterTimeline *timeline,
guint msecs);
G_END_DECLS
#endif /* _CLUTTER_TIMELINE_H__ */

View file

@ -106,15 +106,15 @@ GType clutter_geometry_get_type (void) G_GNUC_CONST;
* @y: Y coordinate of the vertex
* @z: Z coordinate of the vertex
*
* Vertex of an actor in 3D space, expressed in device independent units.
* Vertex of an actor in 3D space, expressed in pixels
*
* Since: 0.4
*/
struct _ClutterVertex
{
ClutterUnit x;
ClutterUnit y;
ClutterUnit z;
gfloat x;
gfloat y;
gfloat z;
};
GType clutter_vertex_get_type (void) G_GNUC_CONST;

View file

@ -27,68 +27,39 @@
/**
* SECTION:clutter-units
* @short_description: A logical distance unit.
* @short_description: A logical distance unit
*
* Clutter units are logical units with granularity greater than that of the
* device units; they are used by #ClutterActorBox and the units-based family
* of #ClutterActor functions. To convert between Clutter units and device
* units, use %CLUTTER_UNITS_FROM_DEVICE and %CLUTTER_UNITS_TO_DEVICE macros.
* #ClutterUnits is a structure holding a logical distance value along with
* its type, expressed as a value of the #ClutterUnitType enumeration. It is
* possible to use #ClutterUnits to store a position or a size in units
* different than pixels, and convert them whenever needed (for instance
* inside the #ClutterActor::allocate() virtual function, or inside the
* #ClutterActor::get_preferred_width() and #ClutterActor::get_preferred_height()
* virtual functions.
*
* #ClutterUnit<!-- -->s can be converted from other units like millimeters,
* typographic points (at the current resolution) and percentages. It is
* also possible to convert fixed point values to and from #ClutterUnit
* values.
*
* In order to register a #ClutterUnit property, the #ClutterParamSpecUnit
* In order to register a #ClutterUnits property, the #ClutterParamSpecUnits
* #GParamSpec sub-class should be used:
*
* |[
* GParamSpec *pspec;
*
* pspec = clutter_param_spec_unit ("width",
* "Width",
* "Width of the actor, in units",
* 0, CLUTTER_MAXUNIT,
* 0,
* G_PARAM_READWRITE);
* pspec = clutter_param_spec_units ("active-width",
* "Width",
* "Width of the active area, in millimeters",
* CLUTTER_UNIT_MM,
* 0.0, 12.0,
* 12.0,
* G_PARAM_READWRITE);
* g_object_class_install_property (gobject_class, PROP_WIDTH, pspec);
* ]|
*
* A #GValue holding units can be manipulated using clutter_value_set_unit()
* and clutter_value_get_unit(). #GValue<!-- -->s containing a #ClutterUnit
* value can also be transformed to #GValue<!-- -->s containing integer
* values - with a loss of precision:
* A #GValue holding units can be manipulated using clutter_value_set_units()
* and clutter_value_get_units(). #GValue<!-- -->s containing a #ClutterUnits
* value can also be transformed to #GValue<!-- -->s initialized with
* %G_TYPE_INT, %G_TYPE_FLOAT and %G_TYPE_STRING through implicit conversion
* and using g_value_transform().
*
* |[
* static gboolean
* units_to_int (const GValue *src,
* GValue *dest)
* {
* g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (src), FALSE);
*
* g_value_init (dest, G_TYPE_INT);
* return g_value_transform (src, &dest);
* }
* ]|
*
* The code above is equivalent to:
*
* |[
* static gboolean
* units_to_int (const GValue *src,
* GValue *dest)
* {
* g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (src), FALSE);
*
* g_value_init (dest, G_TYPE_INT);
* g_value_set_int (dest,
* CLUTTER_UNITS_TO_INT (clutter_value_get_unit (src)));
*
* return TRUE;
* }
* ]|
*
* #ClutterUnit is available since Clutter 0.4
* #ClutterUnits is available since Clutter 1.0
*/
#ifdef HAVE_CONFIG_H
@ -105,19 +76,8 @@
#define FLOAT_EPSILON (1e-30)
/**
* clutter_units_mm:
* @mm: millimeters to convert
*
* Converts a value in millimeters to #ClutterUnit<!-- -->s at
* the current DPI.
*
* Return value: the value in units
*
* Since: 1.0
*/
ClutterUnit
clutter_units_mm (gdouble mm)
static gfloat
units_mm_to_pixels (gfloat mm)
{
ClutterBackend *backend;
gdouble dpi;
@ -130,19 +90,8 @@ clutter_units_mm (gdouble mm)
return mm * dpi / 25.4;
}
/**
* clutter_units_pt:
* @pt: typographic points to convert
*
* Converts a value in typographic points to #ClutterUnit<!-- -->s
* at the current DPI.
*
* Return value: the value in units
*
* Since: 1.0
*/
ClutterUnit
clutter_units_pt (gdouble pt)
static gfloat
units_pt_to_pixels (gfloat pt)
{
ClutterBackend *backend;
gdouble dpi;
@ -155,41 +104,213 @@ clutter_units_pt (gdouble pt)
return pt * dpi / 72.0;
}
static gfloat
units_em_to_pixels (const gchar *font_name,
gfloat em)
{
ClutterBackend *backend = clutter_get_default_backend ();
if (font_name == NULL || *font_name == '\0')
return em * _clutter_backend_get_units_per_em (backend, NULL);
else
{
PangoFontDescription *font_desc;
gfloat res;
font_desc = pango_font_description_from_string (font_name);
if (font_desc == NULL)
res = -1.0;
else
{
res = em * _clutter_backend_get_units_per_em (backend, font_desc);
pango_font_description_free (font_desc);
}
return res;
}
}
/**
* clutter_units_em:
* @em: em to convert
* clutter_units_mm:
* @units: a #ClutterUnits
* @mm: millimeters
*
* Converts a value in em to #ClutterUnit<!-- -->s at the
* current DPI
*
* Return value: the value in units
* Stores a value in millimiters inside @units
*
* Since: 1.0
*/
ClutterUnit
clutter_units_em (gdouble em)
void
clutter_units_mm (ClutterUnits *units,
gfloat mm)
{
ClutterBackend *backend;
g_return_if_fail (units != NULL);
backend = clutter_get_default_backend ();
units->unit_type = CLUTTER_UNIT_MM;
units->value = mm;
units->pixels = units_mm_to_pixels (mm);
units->pixels_set = TRUE;
}
return em * _clutter_backend_get_units_per_em (backend);
/**
* clutter_units_pt:
* @units: a #ClutterUnits
* @pt: typographic points
*
* Stores a value in typographic points inside @units
*
* Since: 1.0
*/
void
clutter_units_pt (ClutterUnits *units,
gfloat pt)
{
g_return_if_fail (units != NULL);
units->unit_type = CLUTTER_UNIT_POINT;
units->value = pt;
units->pixels = units_pt_to_pixels (pt);
units->pixels_set = TRUE;
}
/**
* clutter_units_em:
* @units: a #ClutterUnits
* @em: em
*
* Stores a value in em inside @units, using the default font
* name as returned by clutter_backend_get_font_name()
*
* Since: 1.0
*/
void
clutter_units_em (ClutterUnits *units,
gfloat em)
{
g_return_if_fail (units != NULL);
units->unit_type = CLUTTER_UNIT_EM;
units->value = em;
units->pixels = units_em_to_pixels (NULL, em);
units->pixels_set = TRUE;
}
/**
* clutter_units_em_for_font:
* @units: a #ClutterUnits
* @font_name: the font name and size
* @em: em
*
* Stores a value in em inside @units using @font_name
*
* Since: 1.0
*/
void
clutter_units_em_for_font (ClutterUnits *units,
const gchar *font_name,
gfloat em)
{
g_return_if_fail (units != NULL);
units->unit_type = CLUTTER_UNIT_EM;
units->value = em;
units->pixels = units_em_to_pixels (font_name, em);
units->pixels_set = TRUE;
}
/**
* clutter_units_pixels:
* @px: pixels to convert
* @units: a #ClutterUnits
* @px: pixels
*
* Converts a value in pixels to #ClutterUnit<!-- -->s
*
* Return value: the value in units
* Stores a value in pixels inside @units
*
* Since: 1.0
*/
ClutterUnit
clutter_units_pixels (gint px)
void
clutter_units_pixels (ClutterUnits *units,
gint px)
{
return CLUTTER_UNITS_FROM_INT (px);
g_return_if_fail (units != NULL);
units->unit_type = CLUTTER_UNIT_PIXEL;
units->value = px;
units->pixels = px;
units->pixels_set = TRUE;
}
/**
* clutter_units_get_unit_type:
* @units: a #ClutterUnits
*
* Retrieves the unit type of the value stored inside @units
*
* Return value: a unit type
*
* Since: 1.0
*/
ClutterUnitType
clutter_units_get_unit_type (const ClutterUnits *units)
{
g_return_val_if_fail (units != NULL, CLUTTER_UNIT_PIXEL);
return units->unit_type;
}
/**
* clutter_units_get_unit_value:
* @units: a #ClutterUnits
*
* Retrieves the value stored inside @units
*
* Return value: the value stored inside a #ClutterUnits
*
* Since: 1.0
*/
gfloat
clutter_units_get_unit_value (const ClutterUnits *units)
{
g_return_val_if_fail (units != NULL, 0.0);
return units->value;
}
/**
* clutter_units_copy:
* @units: the #ClutterUnits to copy
*
* Copies @units
*
* Return value: the newly created copy of a #ClutterUnits structure.
* Use clutter_units_free() to free the allocated resources
*
* Since: 1.0
*/
ClutterUnits *
clutter_units_copy (const ClutterUnits *units)
{
if (units != NULL)
return g_slice_dup (ClutterUnits, units);
return NULL;
}
/**
* clutter_units_free:
* @units: the #ClutterUnits to free
*
* Frees the resources allocated by @units
*
* You should only call this function on a #ClutterUnits
* created using clutter_units_copy()
*
* Since: 1.0
*/
void
clutter_units_free (ClutterUnits *units)
{
if (units != NULL)
g_slice_free (ClutterUnits, units);
}
/**
@ -202,156 +323,294 @@ clutter_units_pixels (gint px)
*
* Since: 1.0
*/
gint
clutter_units_to_pixels (ClutterUnit units)
gfloat
clutter_units_to_pixels (ClutterUnits *units)
{
return CLUTTER_UNITS_TO_INT (units);
g_return_val_if_fail (units != NULL, 0.0);
if (units->pixels_set)
return units->pixels;
switch (units->unit_type)
{
case CLUTTER_UNIT_MM:
units->pixels = units_mm_to_pixels (units->value);
break;
case CLUTTER_UNIT_POINT:
units->pixels = units_pt_to_pixels (units->value);
break;
case CLUTTER_UNIT_EM:
units->pixels = units_em_to_pixels (NULL, units->value);
break;
case CLUTTER_UNIT_PIXEL:
units->pixels = units->value;
break;
}
units->pixels_set = TRUE;
return units->pixels;
}
/**
* clutter_units_from_string:
* @units: a #ClutterUnits
* @str: the string to convert
*
* Parses a value and updates @units with it
*
* A #ClutterUnits expressed in string should match:
*
* |[
* number: [0-9]
* unit_value: <numbers>+
* unit_name: px|pt|mm|em
* units: <unit_value> <unit_name>
* ]|
*
* For instance, these are valid strings:
*
* |[
* 10 px
* 5 em
* 24 pt
* 12.6 mm
* ]|
*
* Return value: %TRUE if the string was successfully parsed
*
* Since: 1.0
*/
gboolean
clutter_units_from_string (ClutterUnits *units,
const gchar *str)
{
ClutterUnitType unit_type;
gfloat value;
g_return_val_if_fail (units != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
/* Ensure that the first character is a digit */
while (g_ascii_isspace (*str))
str++;
if (*str == '\0')
return FALSE;
if (!g_ascii_isdigit (*str))
return FALSE;
/* integer part */
value = (gfloat) strtoul (str, (char **) &str, 10);
if (*str == '.' || *str == ',')
{
glong frac = 100000;
while (g_ascii_isdigit (*++str))
{
frac += (*str - '0') * frac;
frac /= 10;
}
value += (1.0f / (gfloat) frac);
}
/* assume pixels by default, if no unit is specified */
if (str == '\0')
unit_type = CLUTTER_UNIT_PIXEL;
else
{
while (g_ascii_isspace (*str))
str++;
if (strncmp (str, "em", 2) == 0)
unit_type = CLUTTER_UNIT_EM;
else if (strncmp (str, "mm", 2) == 0)
unit_type = CLUTTER_UNIT_MM;
else if (strncmp (str, "pt", 2) == 0)
unit_type = CLUTTER_UNIT_POINT;
else if (strncmp (str, "px", 2) == 0)
unit_type = CLUTTER_UNIT_PIXEL;
else
return FALSE;
}
units->unit_type = unit_type;
units->value = value;
units->pixels_set = FALSE;
return TRUE;
}
static const gchar *
clutter_unit_type_name (ClutterUnitType unit_type)
{
switch (unit_type)
{
case CLUTTER_UNIT_MM:
return "mm";
case CLUTTER_UNIT_POINT:
return "pt";
case CLUTTER_UNIT_EM:
return "em";
case CLUTTER_UNIT_PIXEL:
return "px";
}
g_warning ("Invalid unit type %d", (int) unit_type);
return "<invalid>";
}
/**
* clutter_units_to_string:
* @units: a #ClutterUnits
*
* Converts @units into a string
*
* See clutter_units_from_string() for the units syntax and for
* examples of outputs
*
* Return value: a newly allocated string containing the encoded
* #ClutterUnits value. Use g_free() to free the string
*
* Since: 1.0
*/
gchar *
clutter_units_to_string (const ClutterUnits *units)
{
const gchar *unit_name;
gchar *fmt;
g_return_val_if_fail (units != NULL, NULL);
switch (units->unit_type)
{
case CLUTTER_UNIT_MM:
unit_name = "mm";
fmt = g_strdup_printf ("%.2f", units->value);
break;
case CLUTTER_UNIT_POINT:
unit_name = "pt";
fmt = g_strdup_printf ("%.1f", units->value);
break;
case CLUTTER_UNIT_EM:
unit_name = "em";
fmt = g_strdup_printf ("%.2f", units->value);
break;
case CLUTTER_UNIT_PIXEL:
unit_name = "px";
fmt = g_strdup_printf ("%d", (int) units->value);
break;
}
return g_strconcat (fmt, " ", unit_name, NULL);
}
/*
* GValue and GParamSpec integration
*/
static GTypeInfo _info = {
0,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
NULL,
};
static GTypeFundamentalInfo _finfo = { 0, };
/* units to integer */
static void
clutter_value_init_unit (GValue *value)
clutter_value_transform_units_int (const GValue *src,
GValue *dest)
{
value->data[0].v_float = 0.0;
dest->data[0].v_int = clutter_units_to_pixels (src->data[0].v_pointer);
}
/* integer to units */
static void
clutter_value_copy_unit (const GValue *src,
GValue *dest)
clutter_value_transform_int_units (const GValue *src,
GValue *dest)
{
dest->data[0].v_float = src->data[0].v_float;
}
static gchar *
clutter_value_collect_unit (GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags)
{
value->data[0].v_float = collect_values[0].v_double;
return NULL;
}
static gchar *
clutter_value_lcopy_unit (const GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags)
{
gfloat *units_p = collect_values[0].v_pointer;
if (!units_p)
return g_strdup_printf ("value location for '%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
*units_p = value->data[0].v_float;
return NULL;
clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_int);
}
/* units to float */
static void
clutter_value_transform_unit_int (const GValue *src,
GValue *dest)
clutter_value_transform_units_float (const GValue *src,
GValue *dest)
{
dest->data[0].v_int = CLUTTER_UNITS_TO_INT (src->data[0].v_float);
dest->data[0].v_float = clutter_units_to_pixels (src->data[0].v_pointer);
}
/* float to units */
static void
clutter_value_transform_int_unit (const GValue *src,
GValue *dest)
clutter_value_transform_float_units (const GValue *src,
GValue *dest)
{
dest->data[0].v_float = CLUTTER_UNITS_FROM_INT (src->data[0].v_int);
clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_float);
}
/* units to string */
static void
clutter_value_transform_unit_float (const GValue *src,
GValue *dest)
clutter_value_transform_units_string (const GValue *src,
GValue *dest)
{
dest->data[0].v_float = CLUTTER_UNITS_TO_FLOAT (src->data[0].v_float);
gchar *string = clutter_units_to_string (src->data[0].v_pointer);
g_value_take_string (dest, string);
}
/* string to units */
static void
clutter_value_transform_float_unit (const GValue *src,
GValue *dest)
clutter_value_transform_string_units (const GValue *src,
GValue *dest)
{
dest->data[0].v_float = CLUTTER_UNITS_FROM_FLOAT (src->data[0].v_float);
}
ClutterUnits units = { CLUTTER_UNIT_PIXEL, 0.0f };
#if 0
static void
clutter_value_transform_unit_fixed (const GValue *src,
GValue *dest)
{
dest->data[0].v_int = CLUTTER_UNITS_TO_FIXED (src->data[0].v_float);
}
clutter_units_from_string (&units, g_value_get_string (src));
static void
clutter_value_transform_fixed_unit (const GValue *src,
GValue *dest)
{
dest->data[0].v_float = CLUTTER_UNITS_FROM_FIXED (src->data[0].v_int);
clutter_value_set_units (dest, &units);
}
#endif
static const GTypeValueTable _clutter_unit_value_table = {
clutter_value_init_unit,
NULL,
clutter_value_copy_unit,
NULL,
"d",
clutter_value_collect_unit,
"p",
clutter_value_lcopy_unit
};
GType
clutter_unit_get_type (void)
clutter_units_get_type (void)
{
static GType _clutter_unit_type = 0;
static volatile gsize clutter_units_type__volatile = 0;
if (G_UNLIKELY (_clutter_unit_type == 0))
if (g_once_init_enter (&clutter_units_type__volatile))
{
_info.value_table = & _clutter_unit_value_table;
_clutter_unit_type =
g_type_register_fundamental (g_type_fundamental_next (),
I_("ClutterUnit"),
&_info, &_finfo, 0);
GType clutter_units_type =
g_boxed_type_register_static (I_("ClutterUnits"),
(GBoxedCopyFunc) clutter_units_copy,
(GBoxedFreeFunc) clutter_units_free);
g_value_register_transform_func (_clutter_unit_type, G_TYPE_INT,
clutter_value_transform_unit_int);
g_value_register_transform_func (G_TYPE_INT, _clutter_unit_type,
clutter_value_transform_int_unit);
g_value_register_transform_func (clutter_units_type, G_TYPE_INT,
clutter_value_transform_units_int);
g_value_register_transform_func (G_TYPE_INT, clutter_units_type,
clutter_value_transform_int_units);
g_value_register_transform_func (_clutter_unit_type, G_TYPE_FLOAT,
clutter_value_transform_unit_float);
g_value_register_transform_func (G_TYPE_FLOAT, _clutter_unit_type,
clutter_value_transform_float_unit);
g_value_register_transform_func (clutter_units_type, G_TYPE_FLOAT,
clutter_value_transform_units_float);
g_value_register_transform_func (G_TYPE_FLOAT, clutter_units_type,
clutter_value_transform_float_units);
g_value_register_transform_func (clutter_units_type, G_TYPE_STRING,
clutter_value_transform_units_string);
g_value_register_transform_func (G_TYPE_STRING, clutter_units_type,
clutter_value_transform_string_units);
g_once_init_leave (&clutter_units_type__volatile, clutter_units_type);
}
return _clutter_unit_type;
return clutter_units_type__volatile;
}
/**
* clutter_value_set_unit:
* clutter_value_set_units:
* @value: a #GValue initialized to #CLUTTER_TYPE_UNIT
* @units: the units to set
*
@ -360,16 +619,16 @@ clutter_unit_get_type (void)
* Since: 0.8
*/
void
clutter_value_set_unit (GValue *value,
ClutterUnit units)
clutter_value_set_units (GValue *value,
const ClutterUnits *units)
{
g_return_if_fail (CLUTTER_VALUE_HOLDS_UNIT (value));
g_return_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value));
value->data[0].v_float = units;
value->data[0].v_pointer = clutter_units_copy (units);
}
/**
* clutter_value_get_unit:
* clutter_value_get_units:
* @value: a #GValue initialized to #CLUTTER_TYPE_UNIT
*
* Gets the #ClutterUnit<!-- -->s contained in @value.
@ -378,76 +637,113 @@ clutter_value_set_unit (GValue *value,
*
* Since: 0.8
*/
ClutterUnit
G_CONST_RETURN ClutterUnits *
clutter_value_get_unit (const GValue *value)
{
g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (value), 0);
g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value), NULL);
return value->data[0].v_float;
return value->data[0].v_pointer;
}
static void
param_unit_init (GParamSpec *pspec)
param_units_init (GParamSpec *pspec)
{
ClutterParamSpecUnit *uspec = CLUTTER_PARAM_SPEC_UNIT (pspec);
ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec);
uspec->minimum = CLUTTER_MINUNIT;
uspec->maximum = CLUTTER_MAXUNIT;
uspec->default_value = 0;
uspec->minimum = -G_MAXFLOAT;
uspec->maximum = G_MAXFLOAT;
uspec->default_value = 0.0f;
uspec->default_type = CLUTTER_UNIT_PIXEL;
}
static void
param_unit_set_default (GParamSpec *pspec,
GValue *value)
param_units_set_default (GParamSpec *pspec,
GValue *value)
{
value->data[0].v_float = CLUTTER_PARAM_SPEC_UNIT (pspec)->default_value;
ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec);
ClutterUnits units;
units.unit_type = uspec->default_type;
units.value = uspec->default_value;
units.pixels_set = FALSE;
clutter_value_set_units (value, &units);
}
static gboolean
param_unit_validate (GParamSpec *pspec,
GValue *value)
param_units_validate (GParamSpec *pspec,
GValue *value)
{
ClutterParamSpecUnit *uspec = CLUTTER_PARAM_SPEC_UNIT (pspec);
gfloat oval = value->data[0].v_float;
ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec);
ClutterUnits *units = value->data[0].v_pointer;
ClutterUnitType otype = units->unit_type;
gfloat oval = units->value;
g_assert (CLUTTER_IS_PARAM_SPEC_UNIT (pspec));
g_assert (CLUTTER_IS_PARAM_SPEC_UNITS (pspec));
value->data[0].v_float = CLAMP (value->data[0].v_float,
uspec->minimum,
uspec->maximum);
if (otype != uspec->default_type)
{
gchar *str = clutter_units_to_string (units);
return value->data[0].v_float != oval;
g_warning ("The units value of '%s' does not have the same unit "
"type as declared by the ClutterParamSpecUnits of '%s'",
str,
clutter_unit_type_name (otype));
g_free (str);
return FALSE;
}
units->value = CLAMP (units->value,
uspec->minimum,
uspec->maximum);
return units->value != oval;
}
static gint
param_unit_values_cmp (GParamSpec *pspec,
const GValue *value1,
const GValue *value2)
param_units_values_cmp (GParamSpec *pspec,
const GValue *value1,
const GValue *value2)
{
gfloat epsilon = FLOAT_EPSILON;
ClutterUnits *units1 = value1->data[0].v_pointer;
ClutterUnits *units2 = value2->data[0].v_pointer;
gfloat v1, v2;
if (value1->data[0].v_float < value2->data[0].v_float)
return - (value2->data[0].v_float - value1->data[0].v_float > epsilon);
if (units1->unit_type == units2->unit_type)
{
v1 = units1->value;
v2 = units2->value;
}
else
return value1->data[0].v_float - value2->data[0].v_float > epsilon;
{
v1 = clutter_units_to_pixels (units1);
v2 = clutter_units_to_pixels (units2);
}
if (v1 < v2)
return - (v2 - v1 > FLOAT_EPSILON);
else
return v1 - v2 > FLOAT_EPSILON;
}
GType
clutter_param_unit_get_type (void)
clutter_param_units_get_type (void)
{
static GType pspec_type = 0;
if (G_UNLIKELY (pspec_type == 0))
{
const GParamSpecTypeInfo pspec_info = {
sizeof (ClutterParamSpecUnit),
sizeof (ClutterParamSpecUnits),
16,
param_unit_init,
CLUTTER_TYPE_UNIT,
param_units_init,
CLUTTER_TYPE_UNITS,
NULL,
param_unit_set_default,
param_unit_validate,
param_unit_values_cmp,
param_units_set_default,
param_units_validate,
param_units_values_cmp,
};
pspec_type = g_param_type_register_static (I_("ClutterParamSpecUnit"),
@ -458,38 +754,42 @@ clutter_param_unit_get_type (void)
}
/**
* clutter_param_spec_unit:
* clutter_param_spec_units:
* @name: name of the property
* @nick: short name
* @blurb: description (can be translatable)
* @default_type: the default type for the #ClutterUnits
* @minimum: lower boundary
* @maximum: higher boundary
* @default_value: default value
* @flags: flags for the param spec
*
* Creates a #GParamSpec for properties using #ClutterUnit<!-- -->s.
* Creates a #GParamSpec for properties using #ClutterUnits.
*
* Return value: the newly created #GParamSpec
*
* Since: 0.8
* Since: 1.0
*/
GParamSpec *
clutter_param_spec_unit (const gchar *name,
const gchar *nick,
const gchar *blurb,
ClutterUnit minimum,
ClutterUnit maximum,
ClutterUnit default_value,
GParamFlags flags)
clutter_param_spec_units (const gchar *name,
const gchar *nick,
const gchar *blurb,
ClutterUnitType default_type,
gfloat minimum,
gfloat maximum,
gfloat default_value,
GParamFlags flags)
{
ClutterParamSpecUnit *uspec;
ClutterParamSpecUnits *uspec;
g_return_val_if_fail (default_value >= minimum && default_value <= maximum,
NULL);
uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNIT,
uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNITS,
name, nick, blurb,
flags);
uspec->default_type = default_type;
uspec->minimum = minimum;
uspec->maximum = maximum;
uspec->default_value = default_value;

View file

@ -25,250 +25,144 @@
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly.h"
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_UNITS_H__
#define __CLUTTER_UNITS_H__
#include <glib-object.h>
#include <clutter/clutter-fixed.h>
#include <cogl/cogl.h>
G_BEGIN_DECLS
/**
* ClutterUnit:
* ClutterUnitType:
* @CLUTTER_UNIT_PIXEL: Unit expressed in pixels (with subpixel precision)
* @CLUTTER_UNIT_EM: Unit expressed in em
* @CLUTTER_UNIT_MM: Unit expressed in millimeters
* @CLUTTER_UNIT_POINT: Unit expressed in points
*
* Device independent unit used by Clutter. The value held can be
* transformed into other units, likes pixels
* The type of unit in which a value is expressed
*
* Since: 0.4
*/
typedef float ClutterUnit;
/**
* CLUTTER_UNITS_FROM_INT:
* @x: integer value
*
* Converts @x from an integer value to #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_INT(x) ((float)(x))
/**
* CLUTTER_UNITS_TO_INT:
* @x: value in #ClutterUnit<!-- -->s
*
* Converts @x from a #ClutterUnit value into an integer
*
* Since: 0.6
*/
#define CLUTTER_UNITS_TO_INT(x) ((int)(x))
/**
* CLUTTER_UNITS_FROM_FLOAT:
* @x: float value
*
* Converts @x from a floating point value to #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_FLOAT(x) (x)
/**
* CLUTTER_UNITS_TO_FLOAT:
* @x: value in #ClutterUnit<!-- -->s
*
* Converts @x from a #ClutterUnit value into a float
*
* Since: 0.6
*/
#define CLUTTER_UNITS_TO_FLOAT(x) (x)
/**
* CLUTTER_UNITS_FROM_FIXED:
* @x: #CoglFixed value
*
* Converts @x from a fixed point value to #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_FIXED(x) (COGL_FIXED_TO_FLOAT (x))
/**
* CLUTTER_UNITS_TO_FIXED:
* @x: value in #ClutterUnit<!-- -->s
*
* Converts @x from a #ClutterUnit value into a #CoglFixed
*
* Since: 0.6
*/
#define CLUTTER_UNITS_TO_FIXED(x) (COGL_FIXED_FROM_FLOAT (x))
/**
* CLUTTER_UNITS_FORMAT:
*
* Format string that should be used for scanning and printing units.
* It is a string literal, but it does not include the percent sign to
* allow precision and length modifiers between the percent sign and
* the format:
*
* |[
* g_print ("%" CLUTTER_UNITS_FORMAT, units);
* ]|
* This enumeration might be expanded at later date
*
* Since: 1.0
*/
#define CLUTTER_UNITS_FORMAT "f"
typedef enum {
CLUTTER_UNIT_PIXEL,
CLUTTER_UNIT_EM,
CLUTTER_UNIT_MM,
CLUTTER_UNIT_POINT
} ClutterUnitType;
/**
* CLUTTER_UNITS_FROM_DEVICE:
* @x: value in pixels
* ClutterUnits:
*
* Converts @x from pixels to #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_DEVICE(x) (clutter_units_pixels ((x)))
/**
* CLUTTER_UNITS_TO_DEVICE:
* @x: value in #ClutterUnit<!-- -->s
*
* Converts @x from #ClutterUnit<!-- -->s to pixels
*
* Since: 0.6
*/
#define CLUTTER_UNITS_TO_DEVICE(x) (clutter_units_to_pixels ((x)))
/**
* CLUTTER_UNITS_FROM_PANGO_UNIT:
* @x: value in Pango units
*
* Converts a value in Pango units to #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_PANGO_UNIT(x) ((float)((x) / 1024.0))
/**
* CLUTTER_UNITS_TO_PANGO_UNIT:
* @x: value in #ClutterUnit<!-- -->s
*
* Converts a value in #ClutterUnit<!-- -->s to Pango units
*
* Since: 0.6
*/
#define CLUTTER_UNITS_TO_PANGO_UNIT(x) ((int)((x) * 1024))
/**
* CLUTTER_UNITS_FROM_MM:
* @x: a value in millimeters
*
* Converts a value in millimeters into #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_MM(x) (clutter_units_mm (x))
/**
* CLUTTER_UNITS_FROM_POINTS:
* @x: a value in typographic points
*
* Converts a value in typographic points into #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_POINTS(x) (clutter_units_pt (x))
/**
* CLUTTER_UNITS_FROM_EM:
* @x: a value in em
*
* Converts a value in em into #ClutterUnit<!-- -->s
* An opaque structure, to be used to store sizing and positioning
* values along with their unit.
*
* Since: 1.0
*/
#define CLUTTER_UNITS_FROM_EM(x) (clutter_units_em (x))
typedef struct _ClutterUnits ClutterUnits;
ClutterUnit clutter_units_mm (gdouble mm);
ClutterUnit clutter_units_pt (gdouble pt);
ClutterUnit clutter_units_em (gdouble em);
ClutterUnit clutter_units_pixels (gint px);
struct _ClutterUnits
{
/*< private >*/
ClutterUnitType unit_type;
gint clutter_units_to_pixels (ClutterUnit units);
gfloat value;
#define CLUTTER_TYPE_UNIT (clutter_unit_get_type ())
#define CLUTTER_TYPE_PARAM_UNIT (clutter_param_unit_get_type ())
#define CLUTTER_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNIT, ClutterParamSpecUnit))
#define CLUTTER_IS_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNIT))
/* pre-filled by the provided constructors */
gfloat pixels;
guint pixels_set;
/**
* CLUTTER_MAXUNIT:
*
* Higher boundary for a #ClutterUnit
*
* Since: 0.8
*/
#define CLUTTER_MAXUNIT (G_MAXFLOAT)
/* padding for eventual expansion */
gint64 __padding_1;
gint64 __padding_2;
};
/**
* CLUTTER_MINUNIT:
*
* Lower boundary for a #ClutterUnit
*
* Since: 0.8
*/
#define CLUTTER_MINUNIT (-G_MAXFLOAT)
GType clutter_units_get_type (void) G_GNUC_CONST;
ClutterUnitType clutter_units_get_unit_type (const ClutterUnits *units);
gfloat clutter_units_get_unit_value (const ClutterUnits *units);
ClutterUnits * clutter_units_copy (const ClutterUnits *units);
void clutter_units_free (ClutterUnits *units);
void clutter_units_pixels (ClutterUnits *units,
gint px);
void clutter_units_em (ClutterUnits *units,
gfloat em);
void clutter_units_em_for_font (ClutterUnits *units,
const gchar *font_name,
gfloat em);
void clutter_units_mm (ClutterUnits *units,
gfloat mm);
void clutter_units_pt (ClutterUnits *units,
gfloat pt);
gfloat clutter_units_to_pixels (ClutterUnits *units);
gchar * clutter_units_to_string (const ClutterUnits *units);
gboolean clutter_units_from_string (ClutterUnits *units,
const gchar *str);
#define CLUTTER_TYPE_UNITS (clutter_units_get_type ())
#define CLUTTER_TYPE_PARAM_UNITS (clutter_param_units_get_type ())
#define CLUTTER_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNITS, ClutterParamSpecUnits))
#define CLUTTER_IS_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNITS))
/**
* CLUTTER_VALUE_HOLDS_UNIT:
* @x: a #GValue
*
* Evaluates to %TRUE if @x holds #ClutterUnit<!-- -->s.
* Evaluates to %TRUE if @x holds a #ClutterUnits value
*
* Since: 0.8
*/
#define CLUTTER_VALUE_HOLDS_UNIT(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_UNIT))
#define CLUTTER_VALUE_HOLDS_UNITS(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_UNITS))
typedef struct _ClutterParamSpecUnit ClutterParamSpecUnit;
typedef struct _ClutterParamSpecUnits ClutterParamSpecUnits;
/**
* ClutterParamSpecUnit:
* ClutterParamSpecUnits:
* @default_type: default type
* @default_value: default value
* @minimum: lower boundary
* @maximum: higher boundary
* @default_value: default value
*
* #GParamSpec subclass for unit based properties.
*
* Since: 0.8
* Since: 1.0
*/
struct _ClutterParamSpecUnit
struct _ClutterParamSpecUnits
{
/*< private >*/
GParamSpec parent_instance;
GParamSpec parent_instance;
/*< public >*/
ClutterUnit minimum;
ClutterUnit maximum;
ClutterUnit default_value;
ClutterUnitType default_type;
gfloat default_value;
gfloat minimum;
gfloat maximum;
};
GType clutter_unit_get_type (void) G_GNUC_CONST;
GType clutter_param_unit_get_type (void) G_GNUC_CONST;
GType clutter_param_units_get_type (void) G_GNUC_CONST;
void clutter_value_set_unit (GValue *value,
ClutterUnit units);
ClutterUnit clutter_value_get_unit (const GValue *value);
GParamSpec * clutter_param_spec_units (const gchar *name,
const gchar *nick,
const gchar *blurb,
ClutterUnitType default_type,
gfloat minimum,
gfloat maximum,
gfloat default_value,
GParamFlags flags);
GParamSpec *clutter_param_spec_unit (const gchar *name,
const gchar *nick,
const gchar *blurb,
ClutterUnit minimum,
ClutterUnit maximum,
ClutterUnit default_value,
GParamFlags flags);
void clutter_value_set_units (GValue *value,
const ClutterUnits *units);
G_CONST_RETURN ClutterUnits *clutter_value_get_units (const GValue *value);
G_END_DECLS

View file

@ -1,3 +1,9 @@
NULL =
V = @
Q = $(V:1=)
QUIET_GEN = $(Q:@=@echo ' GEN '$@;)
SUBDIRS = common $(CLUTTER_COGL)
BUILT_SOURCES = cogl.h
@ -23,29 +29,42 @@ CLEANFILES = $(pc_files)
AM_CPPFLAGS = $(CLUTTER_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS)
# COGL installed headers
cogl_headers = \
$(top_srcdir)/clutter/cogl/cogl-bitmap.h \
$(top_srcdir)/clutter/cogl/cogl-color.h \
$(top_srcdir)/clutter/cogl/cogl-debug.h \
$(top_srcdir)/clutter/cogl/cogl-fixed.h \
$(top_srcdir)/clutter/cogl/cogl-material.h \
$(top_srcdir)/clutter/cogl/cogl-matrix.h \
$(top_srcdir)/clutter/cogl/cogl-offscreen.h \
$(top_srcdir)/clutter/cogl/cogl-path.h \
$(top_srcdir)/clutter/cogl/cogl-shader.h \
$(top_srcdir)/clutter/cogl/cogl-texture.h \
$(top_srcdir)/clutter/cogl/cogl-types.h \
$(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h
$(top_srcdir)/clutter/cogl/cogl-bitmap.h \
$(top_srcdir)/clutter/cogl/cogl-color.h \
$(top_srcdir)/clutter/cogl/cogl-debug.h \
$(top_srcdir)/clutter/cogl/cogl-deprecated.h \
$(top_srcdir)/clutter/cogl/cogl-fixed.h \
$(top_srcdir)/clutter/cogl/cogl-material.h \
$(top_srcdir)/clutter/cogl/cogl-matrix.h \
$(top_srcdir)/clutter/cogl/cogl-offscreen.h \
$(top_srcdir)/clutter/cogl/cogl-path.h \
$(top_srcdir)/clutter/cogl/cogl-shader.h \
$(top_srcdir)/clutter/cogl/cogl-texture.h \
$(top_srcdir)/clutter/cogl/cogl-types.h \
$(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h \
$(top_builddir)/clutter/cogl/cogl-defines-@CLUTTER_COGL@.h \
$(top_builddir)/clutter/cogl/cogl-enum-types.h \
$(top_builddir)/clutter/cogl/cogl.h \
$(NULL)
# this is copied in from common/ to make cogl.h work, but we
# need to clean it up ourselves once we're done
DISTCLEANFILES = cogl-enum-types.h
# HACK - gobject-introspection can't scan a library in another directory
# so we create a libclutter-cogl.la that's just identical to the one
# in the subdir
noinst_LTLIBRARIES = libclutter-cogl.la
libclutter_cogl_la_LIBADD = $(CLUTTER_COGL)/libclutter-cogl.la
libclutter_cogl_la_LIBADD = $(CLUTTER_COGL)/libclutter-cogl-$(CLUTTER_COGL).la
libclutter_cogl_la_SOURCES = $(cogl_headers)
coglincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/cogl
coglinclude_HEADERS = $(cogl_headers)
if HAVE_INTROSPECTION
Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) $(CLUTTER_COGL)/libclutter-cogl.la
Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-cogl.la
$(QUIET_GEN)$(INTROSPECTION_SCANNER) -v \
--namespace Cogl --nsversion=@CLUTTER_API_VERSION@ \
-I$(top_srcdir)/clutter/cogl \
@ -59,8 +78,6 @@ Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) $(CLUTTER_COGL)/libclut
--libtool="$(top_builddir)/doltlibtool" \
--pkg gobject-2.0 \
--output $@ \
$(top_builddir)/clutter/cogl/cogl-defines-@CLUTTER_COGL@.h \
$(top_builddir)/clutter/cogl/cogl.h \
$(cogl_headers)
BUILT_GIRSOURCES = Cogl-@CLUTTER_API_VERSION@.gir

View file

@ -29,15 +29,16 @@
G_BEGIN_DECLS
typedef enum {
COGL_DEBUG_MISC = 1 << 0,
COGL_DEBUG_TEXTURE = 1 << 1,
COGL_DEBUG_MATERIAL = 1 << 2,
COGL_DEBUG_SHADER = 1 << 3,
COGL_DEBUG_OFFSCREEN = 1 << 4,
COGL_DEBUG_DRAW = 1 << 5,
COGL_DEBUG_PANGO = 1 << 6,
COGL_DEBUG_RECTANGLES = 1 << 7,
COGL_DEBUG_HANDLE = 1 << 8
COGL_DEBUG_MISC = 1 << 0,
COGL_DEBUG_TEXTURE = 1 << 1,
COGL_DEBUG_MATERIAL = 1 << 2,
COGL_DEBUG_SHADER = 1 << 3,
COGL_DEBUG_OFFSCREEN = 1 << 4,
COGL_DEBUG_DRAW = 1 << 5,
COGL_DEBUG_PANGO = 1 << 6,
COGL_DEBUG_RECTANGLES = 1 << 7,
COGL_DEBUG_HANDLE = 1 << 8,
COGL_DEBUG_BLEND_STRINGS = 1 << 9
} CoglDebugFlags;
#ifdef COGL_ENABLE_DEBUG
@ -69,3 +70,4 @@ extern guint cogl_debug_flags;
G_END_DECLS
#endif /* __COGL_DEBUG_H__ */

View file

@ -23,6 +23,14 @@
#ifndef COGL_DEPRECATED_H
#define cogl_color cogl_color_REPLACED_BY_cogl_set_source_color
#define cogl_color cogl_color_REPLACED_BY_cogl_set_source_color
#define cogl_enable_depth_test cogl_enable_depth_test_RENAMED_TO_cogl_set_depth_test_enabled
#define cogl_enable_backface_culling cogl_enable_backface_culling_RENAMED_TO_cogl_set_backface_culling_enabled
#define cogl_texture_rectangle cogl_texture_rectangle_REPLACE_BY_cogl_set_source_texture_AND_cogl_rectangle_with_texture_coords
#define cogl_texture_multiple_rectangles cogl_texture_multiple_rectangles_REPLACED_BY_cogl_set_source_texture_AND_cogl_rectangles_with_texture_coords
#define cogl_texture_polygon cogl_texture_polygon_REPLACED_BY_cogl_set_source_texture_AND_cogl_polygon
#endif

View file

@ -43,6 +43,51 @@ G_BEGIN_DECLS
* blended together.
*/
/**
* CoglMaterialFilter:
* @COGL_MATERIAL_FILTER_NEAREST: Measuring in manhatten distance from the,
* current pixel center, use the nearest texture
* texel.
* @COGL_MATERIAL_FILTER_LINEAR: Use the weighted average of the 4 texels
* nearest the current pixel center.
* @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose
* texel size most closely matches
* the current pixel, and use the
* COGL_MATERIAL_FILTER_NEAREST
* criterion.
* @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose
* texel size most closely matches
* the current pixel, and use the
* COGL_MATERIAL_FILTER_LINEAR
* criterion.
* @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels
* whose texel size most closely
* matches the current pixel, use
* the COGL_MATERIAL_FILTER_NEAREST
* criterion on each one and take
* their weighted average.
* @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels
* whose texel size most closely
* matches the current pixel, use
* the COGL_MATERIAL_FILTER_LINEAR
* criterion on each one and take
* their weighted average.
*
* Texture filtering is used whenever the current pixel maps either to more
* than one texture element (texel) or less than one. These filter enums
* correspond to different strategies used to come up with a pixel color, by
* possibly referring to multiple neighbouring texels and taking a weighted
* average or simply using the nearest texel.
*/
typedef enum _CoglMaterialFilter
{
COGL_MATERIAL_FILTER_NEAREST = GL_NEAREST,
COGL_MATERIAL_FILTER_LINEAR = GL_LINEAR,
COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST,
COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST,
COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR,
COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR
} CoglMaterialFilter;
/**
* cogl_material_new:
@ -367,80 +412,90 @@ void cogl_material_set_alpha_test_function (CoglHandle material,
float alpha_reference);
/**
* CoglMaterialBlendFactor:
* @COGL_MATERIAL_BLEND_FACTOR_ZERO: (0, 0, 0, 0)
* @COGL_MATERIAL_BLEND_FACTOR_ONE: (1, 1, 1, 1)
* @COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR: (Rs, Gs, Bs, As)
* @COGL_MATERIAL_BLEND_FACTOR_DST_COLOR: (Rd, Gd, Bd, Ad)
* @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: (1-Rs, 1-Gs, 1-Bs, 1-As)
* @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: (1-Rd, 1-Gd, 1-Bd, 1-Ad)
* @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA: (As, As, As, As)
* @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: (1-As, 1-As, 1-As, 1-As)
* @COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA: (Ad, Ad, Ad, Ad)
* @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: (1-Ad, 1-Ad, 1-Ad, 1-Ad)
* @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: (f,f,f,1) where f=MIN(As,1-Ad)
* cogl_material_set_blend:
* @material: A CoglMaterial object
* @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
* describing the desired blend function.
* @error: A GError that may report lack of driver support if you give
* separate blend string statements for the alpha channel and RGB
* channels since some drivers or backends such as GLES 1.1 dont
* support this.
*
* If not already familiar; please refer
* <link linkend="cogl-Blend-Strings">here</link> for an overview of what blend
* strings are and there syntax.
*
* Blending occurs after the alpha test function, and combines fragments with
* the framebuffer.
* <para>
* A fixed function is used to determine the blended color, which is based on
* the incoming source color of your fragment (Rs, Gs, Bs, As), a source
* factor (Sr, Sg, Sb, Sa), a destination color (Rd, Rg, Rb, Ra) and
* a destination factor (Dr, Dg, Db, Da), and is given by these equations:
* </para>
* Currently the only blend function Cogl exposes is ADD(). So any valid
* blend statements will be of the form:
*
* <programlisting>
* R = Rs*Sr + Rd*Dr
* G = Gs*Sg + Gd*Dg
* B = Bs*Sb + Bd*Db
* A = As*Sa + Ad*Da
* &lt;channel-mask&gt;=ADD(SRC_COLOR*(&lt;factor&gt;), DST_COLOR*(&lt;factor&gt;))
* </programlisting>
*
* All factors have a range [0, 1]
* <b>NOTE: The brackets around blend factors are currently not optional!</b>
*
* The factors are selected with the following constants:
* This is the list of source-names usable as blend factors:
* <itemizedlist>
* <listitem>SRC_COLOR: The color of the in comming fragment</listitem>
* <listitem>DST_COLOR: The color of the framebuffer</listitem>
* <listitem>
* CONSTANT: The constant set via cogl_material_set_blend_constant()</listitem>
* </itemizedlist>
* The source names can be used according to the
* <link linkend="cogl-Blend-String-syntax">color-source and factor syntax</link>,
* so for example "(1-SRC_COLOR[A])" would be a valid factor, as would
* "(CONSTANT[RGB])"
*
* These can also be used as factors:
* <itemizedlist>
* <listitem>0: (0, 0, 0, 0)</listitem>
* <listitem>1: (1, 1, 1, 1)</listitem>
* <listitem>SRC_ALPHA_SATURATE_FACTOR: (f,f,f,1)
* where f=MIN(SRC_COLOR[A],1-DST_COLOR[A])</listitem>
* </itemizedlist>
* <para>
* Remember; all color components are normalized to the range [0, 1] before
* computing the result of blending.
* </para>
* <section>
* <title>Examples</title>
* Blend a non-premultiplied source over a destination with
* premultiplied alpha:
* <programlisting>
* "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))"
* "A = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))"
* </programlisting>
* Blend a premultiplied source over a destination with premultiplied alpha:
* <programlisting>
* "RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))"
* </programlisting>
* </section>
*
* Returns: TRUE if the blend string was successfully parsed, and the described
* blending is supported by the underlying driver/hardware. If there
* was an error, it returns FALSE.
*
* Since: 1.0
*/
typedef enum _CoglMaterialBlendFactor
{
COGL_MATERIAL_BLEND_FACTOR_ZERO = GL_ZERO,
COGL_MATERIAL_BLEND_FACTOR_ONE = GL_ONE,
COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR = GL_SRC_COLOR,
COGL_MATERIAL_BLEND_FACTOR_DST_COLOR = GL_DST_COLOR,
COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,
COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR,
COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA = GL_SRC_ALPHA,
COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA,
COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA = GL_DST_ALPHA,
COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA,
COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE,
} CoglMaterialBlendFactor;
gboolean cogl_material_set_blend (CoglHandle material,
const char *blend_string,
GError **error);
/**
* cogl_material_set_blend_factors:
* cogl_material_set_blend_constant:
* @material: A CoglMaterial object
* @src_factor: Chooses the @CoglMaterialBlendFactor you want plugged in to
* the blend equation.
* @dst_factor: Chooses the @CoglMaterialBlendFactor you want plugged in to
* the blend equation.
* @constant_color: The constant color you want
*
* This function lets you control how primitives using this material will get
* blended with the contents of your framebuffer. The blended RGBA components
* are calculated like this:
* When blending is setup to reference a CONSTANT blend factor then
* blending will depend on the constant set with this function.
*
* (RsSr+RdDr, GsSg+GdDg, BsSb+BsSb, AsSa+AdDa)
*
* Where (Rs,Gs,Bs,As) represents your source - material- color,
* (Rd,Gd,Bd,Ad) represents your destination - framebuffer - color,
* (Sr,Sg,Sb,Sa) represents your source blend factor and
* (Dr,Dg,Db,Da) represents you destination blend factor.
*
* All factors lie in the range [0,1] and incoming color components are also
* normalized to the range [0,1]
*
* Since 1.0
* Since: 1.0
*/
void cogl_material_set_blend_factors (CoglHandle material,
CoglMaterialBlendFactor src_factor,
CoglMaterialBlendFactor dst_factor);
void cogl_material_set_blend_constant (CoglHandle material,
CoglColor *constant_color);
/**
* cogl_material_set_layer:
@ -460,7 +515,7 @@ void cogl_material_set_blend_factors (CoglHandle material,
* Since 1.0
*/
void cogl_material_set_layer (CoglHandle material,
gint layer_index,
int layer_index,
CoglHandle texture);
/**
@ -473,233 +528,112 @@ void cogl_material_set_layer (CoglHandle material,
void cogl_material_remove_layer (CoglHandle material,
gint layer_index);
/**
* CoglMaterialLayerCombineFunc:
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: Arg0
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE: Arg0 x Arg1
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD: Arg0 + Arg1
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED: Arg0 + Arg1 - 0.5
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE: Arg0 x Arg + Arg1 x (1-Arg2)
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT: Arg0 - Arg1
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB: 4 x ((Arg0r - 0.5) x (Arg1r - 0.5)) +
* @COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA: ((Arg0b - 0.5) x (Arg1b - 0.5)) +
* cogl_material_set_layer_combine:
* @material: A CoglMaterial object
* @layer_index: Specifies the layer you want define a combine function for
* @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
* describing the desired texture combine function.
* @error: A GError that may report parse errors or lack of GPU/driver support.
*
* A material may comprise of 1 or more layers that can be combined using a
* number of different functions. By default layers are modulated, which is
* to say the components of the current source layer S are simply multipled
* together with the combined results of the previous layer P like this:
* If not already familiar; you can refer
* <link linkend="cogl-Blend-Strings">here</link> for an overview of what blend
* strings are and there syntax.
*
* These are all the functions available for texture combining:
* <itemizedlist>
* <listitem>REPLACE(arg0) = arg0</listitem>
* <listitem>MODULATE(arg0, arg1) = arg0 x arg1</listitem>
* <listitem>ADD(arg0, arg1) = arg0 + arg1</listitem>
* <listitem>ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5</listitem>
* <listitem>INTERPOLATE(arg0, arg1, arg2) =
* arg0 x arg2 + arg1 x (1 - arg2)</listitem>
* <listitem>SUBTRACT(arg0, arg1) = arg0 - arg1</listitem>
* <listitem>
* DOT3_RGB(arg0, arg1) =
* <programlisting>
* (Rs*Rp, Gs*Gp, Bs*Bp, As*Ap)
* 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) +
* (arg0[G] - 0.5)) * (arg1[G] - 0.5) +
* (arg0[B] - 0.5)) * (arg1[B] - 0.5))
* </programlisting>
*
* For more advanced techniques, Cogl exposes the fixed function texture
* combining capabilities of your GPU to give you greater control.
*/
typedef enum _CoglMaterialLayerCombineFunc
{
COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE = CGL_REPLACE,
COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE = CGL_MODULATE,
COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD = CGL_ADD,
COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED = CGL_ADD_SIGNED,
COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE = CGL_INTERPOLATE,
COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT = CGL_SUBTRACT,
COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB = CGL_DOT3_RGB,
COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA = CGL_DOT3_RGBA
} CoglMaterialLayerCombineFunc;
/**
* CoglMaterialLayerCombineChannels:
* @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB: Modify the function or argument
* src/op for the RGB components of a
* layer
* @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA: Modify the function or argument
* src/op for the Alpha component of a
* layer
* @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA: Modify the function or argument
* src/op for all the components of a
* layer
*
* Cogl optionally lets you describe 2 seperate combine modes for a single
* layer; 1 for the RGB components, and 1 for the Alpha component, so in this
* case you would repeat the 3 steps documented with the
* @cogl_material_set_layer_combine_function function for each channel
* selector.
*
* (Note: you can't have different modes for each channel, so if you need more
* control you will need to use a glsl fragment shader)
*/
typedef enum _CoglMaterialLayerCombineChannels
{
COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB,
COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA,
COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA
} CoglMaterialLayerCombineChannels;
/**
* cogl_material_set_layer_combine_function:
* @material: A CoglMaterial object
* @layer_index: Specifies the layer whos combine mode you want to modify
* @channels: Specifies which channels combine mode you want to modify
* (RGB, ALPHA, or RGBA)
* @func: Specifies the function you want to use for combining fragments
* of the specified layer with the results of previously combined
* layers.
*
* There are three basic steps to describing how a layer should be combined:
* <orderedlist>
* <listitem>
* Choose a function.
* </listitem>
* <listitem>
* Specify the source color for each argument of the chosen function. (Note
* the functions don't all take the same number of arguments)
* </listitem>
* <listitem>
* Specify an operator for each argument that can modify the corresponding
* source color before the function is applied.
* </listitem>
* </orderedlist>
*
* Cogl optionally lets you describe 2 seperate combine modes for a single
* layer; 1 for the RGB components, and 1 for the Alpha component, so in this
* case you would repeat the 3 steps for each channel selector.
*
* (Note: you can't have different modes for each channel, so if you need more
* control you will need to use a glsl fragment shader)
*
* For example here is how you could elect to use the ADD function for all
* components of layer 1 in your material:
* <listitem>DOT3_RGBA(arg0, arg1) =
* <programlisting>
* //Step 1: Choose a function. Note the ADD function takes 2 arguments...
* cogl_material_set_layer_combine_function (material,
* 1,
* COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA)
* COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD);
* //Step 2: Specify the source color for the 2 ADD function arguments...
* cogl_material_set_layer_combine_arg_src (material,
* 1,//layer index
* 0,//argument index
* COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS);
* cogl_material_set_layer_combine_arg_src (material,
* 1,//layer index
* 1,//argument index
* COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA)
* COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE);
* //Step 3: Specify the operators used to modify the arguments...
* cogl_material_set_layer_combine_arg_op (material,
* 1,//layer index
* 0,//argument index
* COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA,
* COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR);
* cogl_material_set_layer_combine_arg_op (material,
* 1,//layer index
* 1,//argument index
* COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA,
* COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR);
* 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) +
* (arg0[G] - 0.5)) * (arg1[G] - 0.5) +
* (arg0[B] - 0.5)) * (arg1[B] - 0.5))
* </programlisting>
*/
void cogl_material_set_layer_combine_function (CoglHandle material,
gint layer_index,
CoglMaterialLayerCombineChannels channels,
CoglMaterialLayerCombineFunc func);
/**
* CoglMaterialLayerCombineSrc:
* @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE: The fragment color of the current texture layer
* @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0: The fragment color of texture unit 0
* @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE1: The fragment color of texture unit 1
* @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE2: The fragment color of texture unit 2..7
* @COGL_MATERIAL_LAYER_COMBINE_SRC_CONSTANT: A fixed constant color (TODO: no API yet to specify the actual color!)
* @COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR: The basic color of the primitive ignoring texturing
* @COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS: The result of combining all previous layers
* </listitem>
* </itemizedlist>
*
* Note for the constants @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0..n the
* numbers may not correspond to the indices you choose for your layers since
* your layer indices don't need to be contiguous. If you need to use these
* it would probably be sensible to ensure the layer indices do infact
* correspond.
* Refer to the
* <link linkend="cogl-Blend-String-syntax">color-source syntax</link> for
* describing the arguments. The valid source names for texture combining
* are:
* <itemizedlist>
* <listitem>
* TEXTURE: Use the color from the current texture layer
* </listitem>
* <listitem>
* TEXTURE_0, TEXTURE_1, etc: Use the color from the specified texture layer
* </listitem>
* <listitem>
* CONSTANT: Use the color from the constant given with
* cogl_material_set_layer_constant()
* </listitem>
* <listitem>
* PRIMARY: Use the color of the material as set with cogl_material_set_color()
* </listitem>
* <listitem>
* PREVIOUS: Either use the texture color from the previous layer, or if this
* is layer 0, use the color of the material as set with
* cogl_material_set_color()
* </listitem>
* </itemizedlist>
* <section>
* <title>Example</title>
* This is effectively what the default blending is:
* <programlisting>
* "RGBA = MODULATE (PREVIOUS, TEXTURE)"
* </programlisting>
* This could be used to cross-fade between two images, using the alpha
* component of a constant as the interpolator. The constant color
* is given by calling cogl_material_set_layer_constant.
* <programlisting>
* RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A])
* </programlisting>
* </section>
* <b>Note: you can't give a multiplication factor for arguments as you can
* with blending.</b>
*
* Returns: TRUE if the blend string was successfully parsed, and the described
* texture combining is supported by the underlying driver/hardware.
* If there was an error, it returns FALSE.
*
* Since: 1.0
*/
typedef enum _CoglMaterialLayerCombineSrc
{
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE = GL_TEXTURE,
/* Can we find a nicer way... */
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0 = GL_TEXTURE0,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE1 = GL_TEXTURE1,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE2 = GL_TEXTURE2,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE3 = GL_TEXTURE3,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE4 = GL_TEXTURE4,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE5 = GL_TEXTURE5,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE6 = GL_TEXTURE6,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE7 = GL_TEXTURE7,
/* .. who would ever need more than 8 texture layers.. :-) */
COGL_MATERIAL_LAYER_COMBINE_SRC_CONSTANT = CGL_CONSTANT,
COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR = CGL_PRIMARY_COLOR,
COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS = CGL_PREVIOUS
} CoglMaterialLayerCombineSrc;
gboolean
cogl_material_set_layer_combine (CoglHandle material,
gint layer_index,
const char *blend_string,
GError **error);
/**
* cogl_material_set_layer_combine_arg_src:
* cogl_material_set_layer_combine_constant:
* @material: A CoglMaterial object
* @layer_index:
* @argument:
* @channels:
* @src:
* @layer_index: Specifies the layer you want to specify a constant used
* for texture combining
* @color_constant: The constant color you want
*
*/
void cogl_material_set_layer_combine_arg_src (CoglHandle material,
gint layer_index,
gint argument,
CoglMaterialLayerCombineChannels channels,
CoglMaterialLayerCombineSrc src);
typedef enum _CoglMaterialLayerCombineOp
{
COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR = GL_SRC_COLOR,
COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,
COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA = GL_SRC_ALPHA,
COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA
} CoglMaterialLayerCombineOp;
/**
* cogl_material_set_layer_combine_arg_op:
* @material: A CoglMaterial object
* @layer_index:
* @argument:
* @channels:
* @op:
* When you are using the 'CONSTANT' color source in a layer combine
* description then you can use this function to define its value.
*
* Since 1.0
*/
void cogl_material_set_layer_combine_arg_op (CoglHandle material,
gint layer_index,
gint argument,
CoglMaterialLayerCombineChannels channels,
CoglMaterialLayerCombineOp op);
/* TODO: */
#if 0
I think it would be be really neat to support a simple string description
of the fixed function texture combine modes exposed above. I think we can
consider this stuff to be set in stone from the POV that more advanced
texture combine functions are catered for with GLSL, so it seems reasonable
to find a concise string representation that can represent all the above
modes in a *much* more readable/useable fashion. I think somthing like
this would be quite nice:
"MODULATE(TEXTURE[RGB], PREVIOUS[A])"
"ADD(TEXTURE[A],PREVIOUS[RGB])"
"INTERPOLATE(TEXTURE[1-A], PREVIOUS[RGB])"
void cogl_material_set_layer_rgb_combine (CoglHandle material
gint layer_index,
const char *combine_description);
void cogl_material_set_layer_alpha_combine (CoglHandle material
gint layer_index,
const char *combine_description);
#endif
void cogl_material_set_layer_combine_constant (CoglHandle material,
int layer_index,
CoglColor *constant);
/**
* cogl_material_set_layer_matrix:
@ -709,38 +643,9 @@ void cogl_material_set_layer_alpha_combine (CoglHandle material
* and rotate a single layer of a material used to fill your geometry.
*/
void cogl_material_set_layer_matrix (CoglHandle material,
gint layer_index,
int layer_index,
CoglMatrix *matrix);
/**
* SECTION:cogl-material-internals
* @short_description: Functions for creating custom primitives that make use
* of Cogl materials for filling.
*
* Normally you shouldn't need to use this API directly, but if you need to
* developing a custom/specialised primitive - probably using raw OpenGL - then
* this API aims to expose enough of the material internals to support being
* able to fill your geometry according to a given Cogl material.
*/
/**
* cogl_material_get_cogl_enable_flags:
* @material: A CoglMaterial object
*
* This determines what flags need to be passed to cogl_enable before this
* material can be used. Normally you shouldn't need to use this function
* directly since Cogl will do this internally, but if you are developing
* custom primitives directly with OpenGL you may want to use this.
*
* Note: This API is hopfully just a stop-gap solution. Ideally cogl_enable
* will be replaced.
*/
/* TODO: find a nicer solution! */
gulong
cogl_material_get_cogl_enable_flags (CoglHandle handle);
/**
* cogl_material_get_layers:
* @material: A CoglMaterial object
@ -748,24 +653,20 @@ cogl_material_get_cogl_enable_flags (CoglHandle handle);
* This function lets you access a materials internal list of layers
* for iteration.
*
* Note: Normally you shouldn't need to use this function directly since
* Cogl will do this internally, but if you are developing custom primitives
* directly with OpenGL, you will need to iterate the layers that you want
* to texture with.
*
* Note: This function may return more layers than OpenGL can use at once
* so it's your responsability limit yourself to
* CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
*
* Note: It's a bit out of the ordinary to return a const GList *, but it
* was considered sensible to try and avoid list manipulation for every
* primitive emitted in a scene, every frame.
* Returns: A list of #CoglHandle<!-- -->'s that can be passed to the
* cogl_material_layer_* functions.
*/
const GList *cogl_material_get_layers (CoglHandle material_handle);
/**
* CoglMaterialLayerType:
* @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a CoglTexture
* @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a
* <link linkend="cogl-Textures">Cogl texture</link>
*
* Available types of layers for a #CoglMaterial. This enumeration
* might be expanded in later versions.
*
* Since: 1.0
*/
typedef enum _CoglMaterialLayerType
{
@ -774,17 +675,12 @@ typedef enum _CoglMaterialLayerType
/**
* cogl_material_layer_get_type:
* @layer_handle: A CoglMaterialLayer handle
* @layer_handle: A Cogl material layer handle
*
* Currently there is only one type of layer defined:
* COGL_MATERIAL_LAYER_TYPE_TEXTURE, but considering we may add purely GLSL
* based layers in the future, you should write code that checks the type
* first.
*
* Note: Normally you shouldn't need to use this function directly since
* Cogl will do this internally, but if you are developing custom primitives
* directly with OpenGL, you will need to iterate the layers that you want
* to texture with, and thus should be checking the layer types.
*/
CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle);
@ -792,75 +688,58 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle);
* cogl_material_layer_get_texture:
* @layer_handle: A CoglMaterialLayer handle
*
* This lets you extract a CoglTexture handle for a specific layer. Normally
* you shouldn't need to use this function directly since Cogl will do this
* internally, but if you are developing custom primitives directly with
* OpenGL you may need this.
* This lets you extract a CoglTexture handle for a specific layer.
*
* Note: In the future, we may support purely GLSL based layers which will
* likley return COGL_INVALID_HANDLE if you try to get the texture.
* Considering this, you should always call cogl_material_layer_get_type
* first, to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE.
* likely return COGL_INVALID_HANDLE if you try to get the texture.
* Considering this, you can call cogl_material_layer_get_type first,
* to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE.
*
* Note: It is possible for a layer object of type
* COGL_MATERIAL_LAYER_TYPE_TEXTURE to be realized before a texture
* object has been associated with the layer. For example this happens
* if you setup layer combining for a given layer index before calling
* cogl_material_set_layer for that index.
*
* Returns: A CoglHandle to the layers texture object or COGL_INVALID_HANDLE
* if a texture has not been set yet.
*/
CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle);
/**
* CoglMaterialLayerFlags:
* @COGL_MATERIAL_LAYER_FLAG_USER_MATRIX: Means the user has supplied a
* custom texture matrix.
* cogl_material_layer_get_min_filter:
* @layer_handle: a #CoglHandle for a material layer.
*
* Query the currently set downscaling filter for a cogl material layer.
*
* Returns: the current downscaling filter for a cogl material layer.
*/
typedef enum _CoglMaterialLayerFlags
{
COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX = 1L<<0
} CoglMaterialLayerFlags;
/* XXX: NB: if you add flags here you will need to update
* CoglMaterialLayerPrivFlags!!! */
CoglMaterialFilter cogl_material_layer_get_min_filter (CoglHandle layer_handle);
/**
* cogl_material_layer_get_flags:
* @layer_handle: A CoglMaterialLayer layer handle
* cogl_material_layer_get_mag_filter:
* @layer_handle: a #CoglHandle for a material layer.
*
* This lets you get a number of flag attributes about the layer. Normally
* you shouldn't need to use this function directly since Cogl will do this
* internally, but if you are developing custom primitives directly with
* OpenGL you may need this.
* Query the currently set downscaling filter for a cogl material layer.
*
* Returns: the current downscaling filter for a cogl material layer.
*/
gulong cogl_material_layer_get_flags (CoglHandle layer_handle);
CoglMaterialFilter cogl_material_layer_get_mag_filter (CoglHandle layer_handle);
/**
* CoglMaterialFlushOption:
* @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask
* of the layers that can't be supported with the user supplied texture
* and need to be replaced with fallback textures. (1 = fallback, and the
* least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask
* of the layers that you want to completly disable texturing for
* (1 = fallback, and the least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture
* name to override the texture used for layer 0 of the material. This is
* intended for dealing with sliced textures where you will need to point
* to each of the texture slices in turn when drawing your geometry.
* Passing a value of 0 is the same as not passing the option at all.
*/
typedef enum _CoglMaterialFlushOption
{
COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
} CoglMaterialFlushOption;
/**
* cogl_material_flush_gl_state:
* @material: A CoglMaterial object
* @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs
* cogl_material_set_layer_filters:
* @handle: a #CoglHandle to a material.
* @layer_index: the layer number to change.
* @min_filter: the filter used when scaling a texture down.
* @mag_filter: the filter used when magnifying a texture.
*
* This function commits the state of the specified CoglMaterial - including
* the texture state for all the layers - to the OpenGL[ES] driver.
*
* Since 1.0
* Changes the decimation and interpolation filters used when a texture is
* drawn at other scales than 100%.
*/
void cogl_material_flush_gl_state (CoglHandle material,
...) G_GNUC_NULL_TERMINATED;
void cogl_material_set_layer_filters (CoglHandle handle,
gint layer_index,
CoglMaterialFilter min_filter,
CoglMaterialFilter mag_filter);
G_END_DECLS

View file

@ -199,22 +199,50 @@ void cogl_matrix_frustum (CoglMatrix *matrix,
float z_far);
/**
* cogl_matrix_transform_point:
* cogl_matrix_perspective:
* @matrix: A 4x4 transformation matrix
* @x: The X component of your points position [in:out]
* @y: The Y component of your points position [in:out]
* @z: The Z component of your points position [in:out]
* @w: The W component of your points position [in:out]
* @fov_y: A field of view angle for the Y axis
* @aspect: The ratio of width to height determining the field of view angle
* for the x axis.
* @z_near: The distance to the near clip plane.
* Never pass 0 and always pass a positive number.
* @z_far: The distance to the far clip plane. (Should always be positive)
*
* This transforms a point whos position is given and returned
* as four float components.
* Multiplies the matrix by the described perspective matrix
*
* Note: you should be careful not to have to great a z_far / z_near ratio
* since that will reduce the effectiveness of depth testing since there wont
* be enough precision to identify the depth of objects near to each other.
*/
void
cogl_matrix_transform_point (const CoglMatrix *matrix,
float *x,
float *y,
float *z,
float *w);
cogl_matrix_perspective (CoglMatrix *matrix,
float fov_y,
float aspect,
float z_near,
float z_far);
/**
* cogl_matrix_ortho:
* @matrix: A 4x4 transformation matrix
* @left: The coordinate for the left clipping plane
* @right: The coordinate for the right clipping plane
* @bottom: The coordinate for the bottom clipping plane
* @top: The coordinate for the top clipping plane
* @z_near: The coordinate for the near clipping plane (may be negative if
* the plane is behind the viewer)
* @z_far: The coordinate for the far clipping plane (may be negative if
* the plane is behind the viewer)
*
* Multiples the matrix by a parallel projection matrix.
*/
void
cogl_matrix_ortho (CoglMatrix *matrix,
float left,
float right,
float bottom,
float top,
float z_near,
float z_far);
/**
* cogl_matrix_init_from_array:
@ -234,6 +262,24 @@ void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array);
*/
const float *cogl_matrix_get_array (const CoglMatrix *matrix);
/**
* cogl_matrix_transform_point:
* @matrix: A 4x4 transformation matrix
* @x: The X component of your points position [in:out]
* @y: The Y component of your points position [in:out]
* @z: The Z component of your points position [in:out]
* @w: The W component of your points position [in:out]
*
* This transforms a point whos position is given and returned
* as four float components.
*/
void
cogl_matrix_transform_point (const CoglMatrix *matrix,
float *x,
float *y,
float *z,
float *w);
G_END_DECLS
#endif /* __COGL_MATRIX_H */

View file

@ -46,9 +46,12 @@ G_BEGIN_DECLS
* CoglShaderType:
* @COGL_SHADER_TYPE_VERTEX: A program for proccessing vertices
* @COGL_SHADER_TYPE_FRAGMENT: A program for processing fragments
*
* Types of shaders
*
* Since: 1.0
*/
typedef enum _CoglShaderType
{
typedef enum {
COGL_SHADER_TYPE_VERTEX,
COGL_SHADER_TYPE_FRAGMENT
} CoglShaderType;
@ -103,7 +106,7 @@ gboolean cogl_is_shader (CoglHandle handle);
* one.
*/
void cogl_shader_source (CoglHandle shader,
const char *source);
const gchar *source);
/**
* cogl_shader_compile:
* @handle: #CoglHandle for a shader.
@ -111,29 +114,30 @@ void cogl_shader_source (CoglHandle shader,
* Compiles the shader, no return value, but the shader is now ready for
* linking into a program.
*/
void cogl_shader_compile (CoglHandle handle);
void cogl_shader_compile (CoglHandle handle);
/**
* cogl_shader_get_info_log:
* @handle: #CoglHandle for a shader.
* @size: maximum number of bytes to retrieve.
* @buffer: location for info log.
*
* Retrieves the information log for a coglobject, can be used in conjunction
* with #cogl_shader_get_parameteriv to retrieve the compiler warnings/error
* with cogl_shader_get_parameteriv() to retrieve the compiler warnings/error
* messages that caused a shader to not compile correctly, mainly useful for
* debugging purposes.
*
* Return value: a newly allocated string containing the info log. Use
* g_free() to free it
*/
void cogl_shader_get_info_log (CoglHandle handle,
size_t size,
char *buffer);
gchar * cogl_shader_get_info_log (CoglHandle handle);
/**
* cogl_shader_get_type:
* @handle: #CoglHandle for a shader.
*
* Returns: COGL_SHADER_TYPE_VERTEX if the shader is a vertex processor
* or COGL_SHADER_TYPE_FRAGMENT if the shader is a frament processor
* Retrieves the type of a shader #CoglHandle
*
* Return value: %COGL_SHADER_TYPE_VERTEX if the shader is a vertex processor
* or %COGL_SHADER_TYPE_FRAGMENT if the shader is a frament processor
*/
CoglShaderType cogl_shader_get_type (CoglHandle handle);
@ -141,7 +145,9 @@ CoglShaderType cogl_shader_get_type (CoglHandle handle);
* cogl_shader_is_compiled:
* @handle: #CoglHandle for a shader.
*
* Returns: TRUE if the shader object has sucessfully be compiled else FALSE
* Retrieves whether a shader #CoglHandle has been compiled
*
* Return value: %TRUE if the shader object has sucessfully be compiled
*/
gboolean cogl_shader_is_compiled (CoglHandle handle);

View file

@ -41,12 +41,12 @@ G_BEGIN_DECLS
* loading and manipulating textures.
*/
#define COGL_TEXTURE_MAX_WASTE 127
/**
* cogl_texture_new_with_size:
* @width: width of texture in pixels.
* @height: height of texture in pixels.
* @max_waste: maximum extra horizontal and|or vertical margin pixels
* to make the texture fit GPU limitations
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE
* @internal_format: the #CoglPixelFormat to use for the GPU storage of the
* texture.
@ -60,15 +60,12 @@ G_BEGIN_DECLS
*/
CoglHandle cogl_texture_new_with_size (guint width,
guint height,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format);
/**
* cogl_texture_new_from_file:
* @filename: the file to load
* @max_waste: maximum extra horizontal and|or vertical margin pixels
* to make the texture fit GPU limitations
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE
* @internal_format: the #CoglPixelFormat to use for the GPU storage of the
* texture
@ -82,7 +79,6 @@ CoglHandle cogl_texture_new_with_size (guint width,
* Since: 0.8
*/
CoglHandle cogl_texture_new_from_file (const gchar *filename,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error);
@ -91,8 +87,6 @@ CoglHandle cogl_texture_new_from_file (const gchar *filename,
* cogl_texture_new_from_data:
* @width: width of texture in pixels
* @height: height of texture in pixels
* @max_waste: maximum extra horizontal and|or vertical margin pixels
* to make the texture fit GPU limitations
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE
* @format: the #CoglPixelFormat the buffer is stored in in RAM
* @internal_format: the #CoglPixelFormat that will be used for storing
@ -110,7 +104,6 @@ CoglHandle cogl_texture_new_from_file (const gchar *filename,
*/
CoglHandle cogl_texture_new_from_data (guint width,
guint height,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat format,
CoglPixelFormat internal_format,
@ -136,19 +129,17 @@ CoglHandle cogl_texture_new_from_data (guint width,
*
* Since: 0.8
*/
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);
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);
/**
* cogl_texture_new_from_bitmap:
* @bmp_handle: A CoglBitmap handle
* @max_waste: maximum extra horizontal and|or vertical margin pixels
* to make the texture fit GPU limitations
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE
* @internal_format: the #CoglPixelFormat to use for the GPU storage of the
* texture
@ -160,10 +151,9 @@ CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle,
*
* Since: 1.0
*/
CoglHandle cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format);
CoglHandle cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
CoglTextureFlags flags,
CoglPixelFormat internal_format);
/**
* cogl_is_texture:
@ -228,72 +218,6 @@ guint cogl_texture_get_rowstride (CoglHandle handle);
*/
gint cogl_texture_get_max_waste (CoglHandle handle);
/**
* CoglTextureFilter:
* @COGL_TEXTURE_FILTER_NEAREST: Measuring in manhatten distance from the,
* current pixel center, use the nearest texture
* texel.
* @COGL_TEXTURE_FILTER_LINEAR: Use the weighted average of the 4 texels
* nearest the current pixel center.
* @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose
* texel size most closely matches
* the current pixel, and use the
* COGL_TEXTURE_FILTER_NEAREST
* criterion.
* @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose
* texel size most closely matches
* the current pixel, and use the
* COGL_TEXTURE_FILTER_LINEAR
* criterion.
* @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels
* whose texel size most closely
* matches the current pixel, use
* the COGL_TEXTURE_FILTER_NEAREST
* criterion on each one and take
* their weighted average.
* @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels
* whose texel size most closely
* matches the current pixel, use
* the COGL_TEXTURE_FILTER_LINEAR
* criterion on each one and take
* their weighted average.
*
* Texture filtering is used whenever the current pixel maps either to more
* than one texture element (texel) or less than one. These filter enums
* correspond to different strategies used to come up with a pixel color, by
* possibly referring to multiple neighbouring texels and taking a weighted
* average or simply using the nearest texel.
*/
typedef enum _CoglTextureFilter
{
COGL_TEXTURE_FILTER_NEAREST = GL_NEAREST,
COGL_TEXTURE_FILTER_LINEAR = GL_LINEAR,
COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST,
COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST,
COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR,
COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR
} CoglTextureFilter;
/**
* cogl_texture_get_min_filter:
* @handle: a #CoglHandle for a texture.
*
* Query the currently set downscaling filter for a cogl texture.
*
* Returns: the current downscaling filter for a cogl texture.
*/
CoglTextureFilter cogl_texture_get_min_filter (CoglHandle handle);
/**
* cogl_texture_get_mag_filter:
* @handle: a #CoglHandle for a texture.
*
* Query the currently set downscaling filter for a cogl texture.
*
* Returns: the current downscaling filter for a cogl texture.
*/
CoglTextureFilter cogl_texture_get_mag_filter (CoglHandle handle);
/**
* cogl_texture_is_sliced:
* @handle: a #CoglHandle for a texture.
@ -343,20 +267,6 @@ gint cogl_texture_get_data (CoglHandle handle,
guint rowstride,
guchar *data);
/**
* cogl_texture_set_filters:
* @handle: a #CoglHandle.
* @min_filter: the filter used when scaling the texture down.
* @mag_filter: the filter used when magnifying the texture.
*
* Changes the decimation and interpolation filters used when the texture is
* drawn at other scales than 100%.
*/
void cogl_texture_set_filters (CoglHandle handle,
CoglTextureFilter min_filter,
CoglTextureFilter mag_filter);
/**
* cogl_texture_set_region:
* @handle: a #CoglHandle.

View file

@ -123,8 +123,7 @@ typedef struct _CoglTextureVertex CoglTextureVertex;
*
* Since: 0.8
*/
typedef enum
{
typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
COGL_PIXEL_FORMAT_ANY = 0,
COGL_PIXEL_FORMAT_A_8 = 1 | COGL_A_BIT,
@ -135,60 +134,21 @@ typedef enum
COGL_PIXEL_FORMAT_G_8 = 8,
COGL_PIXEL_FORMAT_RGB_888 = COGL_PIXEL_FORMAT_24,
COGL_PIXEL_FORMAT_BGR_888 = (COGL_PIXEL_FORMAT_24 | COGL_BGR_BIT),
COGL_PIXEL_FORMAT_BGR_888 = (COGL_PIXEL_FORMAT_24 |
COGL_BGR_BIT),
COGL_PIXEL_FORMAT_RGBA_8888 = COGL_PIXEL_FORMAT_32 |
COGL_A_BIT,
COGL_PIXEL_FORMAT_BGRA_8888 = (COGL_PIXEL_FORMAT_32 |
COGL_A_BIT |
COGL_BGR_BIT),
COGL_PIXEL_FORMAT_ARGB_8888 = (COGL_PIXEL_FORMAT_32 |
COGL_A_BIT |
COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_ABGR_8888 = (COGL_PIXEL_FORMAT_32 |
COGL_A_BIT |
COGL_BGR_BIT |
COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_RGBA_8888_PRE = (COGL_PIXEL_FORMAT_32 |
COGL_A_BIT |
COGL_PREMULT_BIT),
COGL_PIXEL_FORMAT_BGRA_8888_PRE = (COGL_PIXEL_FORMAT_32 |
COGL_A_BIT |
COGL_PREMULT_BIT |
COGL_BGR_BIT),
COGL_PIXEL_FORMAT_ARGB_8888_PRE = (COGL_PIXEL_FORMAT_32 |
COGL_A_BIT |
COGL_PREMULT_BIT |
COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_ABGR_8888_PRE = (COGL_PIXEL_FORMAT_32 |
COGL_A_BIT |
COGL_PREMULT_BIT |
COGL_BGR_BIT |
COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_RGBA_4444_PRE = (COGL_PIXEL_FORMAT_RGBA_4444 |
COGL_A_BIT |
COGL_PREMULT_BIT),
COGL_PIXEL_FORMAT_RGBA_5551_PRE = (COGL_PIXEL_FORMAT_RGBA_5551 |
COGL_A_BIT |
COGL_PREMULT_BIT),
COGL_PIXEL_FORMAT_RGBA_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT),
COGL_PIXEL_FORMAT_BGRA_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_BGR_BIT),
COGL_PIXEL_FORMAT_ARGB_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_ABGR_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_RGBA_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT),
COGL_PIXEL_FORMAT_BGRA_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT),
COGL_PIXEL_FORMAT_ARGB_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_ABGR_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT),
COGL_PIXEL_FORMAT_RGBA_4444_PRE = (COGL_PIXEL_FORMAT_RGBA_4444 | COGL_A_BIT | COGL_PREMULT_BIT),
COGL_PIXEL_FORMAT_RGBA_5551_PRE = (COGL_PIXEL_FORMAT_RGBA_5551 | COGL_A_BIT | COGL_PREMULT_BIT),
} CoglPixelFormat;
#define COGL_TYPE_PIXEL_FORMAT (cogl_pixel_format_get_type ())
GType cogl_pixel_format_get_type (void) G_GNUC_CONST;
/**
* CoglFeatureFlags:
* @COGL_FEATURE_TEXTURE_RECTANGLE: ARB_texture_rectangle support
@ -222,9 +182,6 @@ typedef enum
COGL_FEATURE_VBOS = (1 << 11)
} CoglFeatureFlags;
#define COGL_TYPE_FEATURE_FLAGS (cogl_feature_flags_get_type ())
GType cogl_feature_flags_get_type (void) G_GNUC_CONST;
/**
* CoglBufferTarget:
* @COGL_WINDOW_BUFFER: FIXME
@ -240,9 +197,6 @@ typedef enum
COGL_OFFSCREEN_BUFFER = (1 << 2)
} CoglBufferTarget;
#define COGL_TYPE_BUFFER_TARGET (cogl_buffer_target_get_type ())
GType cogl_buffer_target_get_type (void) G_GNUC_CONST;
/**
* CoglColor:
*
@ -290,21 +244,23 @@ struct _CoglTextureVertex
/**
* CoglTextureFlags:
* @COGL_TEXTURE_NONE: No flags specified
* @COGL_TEXTURE_AUTO_MIPMAP: Enables the automatic generation of the
* mipmap pyramid from the base level image whenever it is updated
* @COGL_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of
* the mipmap pyramid from the base level image whenever it is
* updated. The mipmaps are only generated when the texture is
* rendered with a mipmap filter so it should be free to leave out
* this flag when using other filtering modes.
* @COGL_TEXTURE_NO_SLICING: Disables the slicing of the texture
*
* Flags to pass to the cogl_texture_new_* family of functions.
*
* Since: 1.0
*/
typedef enum {
COGL_TEXTURE_NONE = 0,
COGL_TEXTURE_AUTO_MIPMAP = 1 << 0
COGL_TEXTURE_NONE = 0,
COGL_TEXTURE_NO_AUTO_MIPMAP = 1 << 0,
COGL_TEXTURE_NO_SLICING = 1 << 1
} CoglTextureFlags;
#define COGL_TYPE_TEXTURE_FLAGS (cogl_texture_flags_get_type ())
GType cogl_texture_flags_get_type (void) G_GNUC_CONST;
/**
* CoglFogMode:
* @COGL_FOG_MODE_LINEAR: Calculates the fog blend factor as:
@ -333,16 +289,12 @@ GType cogl_texture_flags_get_type (void) G_GNUC_CONST;
*
* Since: 1.0
*/
typedef enum _CoglFogMode
{
typedef enum {
COGL_FOG_MODE_LINEAR,
COGL_FOG_MODE_EXPONENTIAL,
COGL_FOG_MODE_EXPONENTIAL_SQUARED
} CoglFogMode;
#define COGL_TYPE_FOG_MODE (cogl_fog_mode_get_type ())
GType cogl_fog_mode_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __COGL_TYPES_H__ */

View file

@ -94,6 +94,29 @@ cogl_vertex_buffer_new (guint n_vertices);
guint
cogl_vertex_buffer_get_n_vertices (CoglHandle handle);
/**
* CoglAttributeType:
* @COGL_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte
* @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an
* unsigned byte
* @COGL_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer
* @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of
* an unsigned short integer
* @COGL_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float
*
* Data types for the components of cogl_vertex_buffer_add()
*
* Since: 1.0
*/
typedef enum _CoglAttributeType
{
COGL_ATTRIBUTE_TYPE_BYTE = GL_BYTE,
COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE = GL_UNSIGNED_BYTE,
COGL_ATTRIBUTE_TYPE_SHORT = GL_SHORT,
COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT = GL_UNSIGNED_SHORT,
COGL_ATTRIBUTE_TYPE_FLOAT = GL_FLOAT
} CoglAttributeType;
/**
* cogl_vertex_buffer_add:
* @handle: A vertex buffer handle
@ -111,10 +134,9 @@ cogl_vertex_buffer_get_n_vertices (CoglHandle handle);
* the name can have a detail component, E.g.
* "gl_Color::active" or "gl_Color::inactive"
* @n_components: The number of components per attribute and must be 1,2,3 or 4
* @gl_type: Specifies the data type of each component (GL_BYTE, GL_UNSIGNED_BYTE,
* GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT or GL_FLOAT)
* @type: a #CoglAttributeType specifying the data type of each component.
* @normalized: If GL_TRUE, this specifies that values stored in an integer
* format should be mapped into the range [-1.0, 1.0] or [0.1, 1.0]
* format should be mapped into the range [-1.0, 1.0] or [0.0, 1.0]
* for unsigned values. If GL_FALSE they are converted to floats
* directly.
* @stride: This specifies the number of bytes from the start of one attribute
@ -156,13 +178,13 @@ cogl_vertex_buffer_get_n_vertices (CoglHandle handle);
* (Though you can have multiple groups of interleved attributes)
*/
void
cogl_vertex_buffer_add (CoglHandle handle,
const char *attribute_name,
guint8 n_components,
GLenum gl_type,
gboolean normalized,
guint16 stride,
const void *pointer);
cogl_vertex_buffer_add (CoglHandle handle,
const char *attribute_name,
guint8 n_components,
CoglAttributeType type,
gboolean normalized,
guint16 stride,
const void *pointer);
/**
* cogl_vertex_buffer_delete:
@ -226,21 +248,37 @@ void
cogl_vertex_buffer_enable (CoglHandle handle,
const char *attribute_name);
/**
* CoglVerticesMode:
* @COGL_VERTICES_MODE_POINTS: FIXME, equivalent to %GL_POINTS
* @COGL_VERTICES_MODE_LINE_STRIP: FIXME, equivalent to %GL_LINE_STRIP
* @COGL_VERTICES_MODE_LINE_LOOP: FIXME, equivalent to %GL_LINE_LOOP
* @COGL_VERTICES_MODE_LINES: FIXME, equivalent to %GL_LINES
* @COGL_VERTICES_MODE_TRIANGLE_STRIP: FIXME, equivalent to %GL_TRIANGLE_STRIP
* @COGL_VERTICES_MODE_TRIANGLE_FAN: FIXME, equivalent to %GL_TRIANGLE_FAN
* @COGL_VERTICES_MODE_TRIANGLES: FIXME, equivalent to %GL_TRIANGLES
*
* How vertices passed to cogl_vertex_buffer_draw() and
* cogl_vertex_buffer_draw_elements() should be interpreted
*
* Since: 1.0
*/
typedef enum _CoglVerticesMode
{
COGL_VERTICES_MODE_POINTS = GL_POINTS,
COGL_VERTICES_MODE_LINE_STRIP = GL_LINE_STRIP,
COGL_VERTICES_MODE_LINE_LOOP = GL_LINE_LOOP,
COGL_VERTICES_MODE_LINES = GL_LINES,
COGL_VERTICES_MODE_TRIANGLE_STRIP = GL_TRIANGLE_STRIP,
COGL_VERTICES_MODE_TRIANGLE_FAN = GL_TRIANGLE_FAN,
COGL_VERTICES_MODE_TRIANGLES = GL_TRIANGLES
} CoglVerticesMode;
/**
* cogl_vertex_buffer_draw:
* @handle: A vertex buffer handle
* @mode: Specifies how the vertices should be interpreted, and should be
* a valid GL primitive type:
* <itemizedlist>
* <listitem>GL_POINTS</listitem>
* <listitem>GL_LINE_STRIP</listitem>
* <listitem>GL_LINE_LOOP</listitem>
* <listitem>GL_LINES</listitem>
* <listitem>GL_TRIANGLE_STRIP</listitem>
* <listitem>GL_TRIANGLE_FAN</listitem>
* <listitem>GL_TRIANGLES</listitem>
* </itemizedlist>
* (Note: only types available in GLES are listed)
* @mode: A #CoglVerticesMode specifying how the vertices should be
* interpreted.
* @first: Specifies the index of the first vertex you want to draw with
* @count: Specifies the number of vertices you want to draw.
*
@ -251,52 +289,90 @@ cogl_vertex_buffer_enable (CoglHandle handle,
* drawing.
*/
void
cogl_vertex_buffer_draw (CoglHandle handle,
GLenum mode,
GLint first,
GLsizei count);
cogl_vertex_buffer_draw (CoglHandle handle,
CoglVerticesMode mode,
int first,
int count);
/**
* CoglIndicesType:
* @COGL_INDICES_TYPE_UNSIGNED_BYTE: Your indices are unsigned bytes
* @COGL_INDICES_TYPE_UNSIGNED_SHORT: Your indices are unsigned shorts
* @COGL_INDICES_TYPE_UNSIGNED_INT: You indices are unsigned integers
*
* You should aim to use the smallest data type that gives you enough
* range, since it reduces the size of your index array and can help
* reduce the demand on memory bandwidth.
*/
typedef enum _CoglIndicesType
{
COGL_INDICES_TYPE_UNSIGNED_BYTE,
COGL_INDICES_TYPE_UNSIGNED_SHORT,
COGL_INDICES_TYPE_UNSIGNED_INT
} CoglIndicesType;
/**
* cogl_vertex_buffer_indices_new:
* @indices_type: a #CoglIndicesType specifying the data type used for
* the indices.
* @indices_array: Specifies the address of your array of indices
* @indices_len: The number of indices in indices_array
*
* Depending on how much geometry you are submitting it can be worthwhile
* optimizing the number of redundant vertices you submit. Using an index
* array allows you to reference vertices multiple times, for example
* during triangle strips.
*
* Returns: A CoglHandle for the indices which you can pass to
* cogl_vertex_buffer_draw_elements().
*/
CoglHandle
cogl_vertex_buffer_indices_new (CoglIndicesType indices_type,
const void *indices_array,
int indices_len);
/**
* cogl_vertex_buffer_delete_indices:
* @handle: A vertex buffer handle
* @indices_id: The identifier for a an array of indices previously added to
* the given Cogl vertex buffer using
* cogl_vertex_buffer_add_indices().
*
* Frees the resources associated with a previously added array of vertex
* indices.
*/
void
cogl_vertex_buffer_delete_indices (CoglHandle handle,
int indices_id);
/**
* cogl_vertex_buffer_draw_elements:
* @handle: A vertex buffer handle
* @mode: Specifies how the vertices should be interpreted, and should be
* a valid GL primitive type:
* <itemizedlist>
* <listitem>GL_POINTS</listitem>
* <listitem>GL_LINE_STRIP</listitem>
* <listitem>GL_LINE_LOOP</listitem>
* <listitem>GL_LINES</listitem>
* <listitem>GL_TRIANGLE_STRIP</listitem>
* <listitem>GL_TRIANGLE_FAN</listitem>
* <listitem>GL_TRIANGLES</listitem>
* </itemizedlist>
* (Note: only types available in GLES are listed)
* @mode: A #CoglVerticesMode specifying how the vertices should be
* interpreted.
* @indices: A CoglHandle for a set of indices allocated via
* cogl_vertex_buffer_indices_new ()
* @min_index: Specifies the minimum vertex index contained in indices
* @max_index: Specifies the maximum vertex index contained in indices
* @indices_offset: An offset into named indices. The offset marks the first
* index to use for drawing.
* @count: Specifies the number of vertices you want to draw.
* @indices_type: Specifies the data type used for the indices, and must be
* one of:
* <itemizedlist>
* <listitem>GL_UNSIGNED_BYTE</listitem>
* <listitem>GL_UNSIGNED_SHORT</listitem>
* <listitem>GL_UNSIGNED_INT</listitem>
* </itemizedlist>
* @indices: Specifies the address of your array of indices
*
* This function lets you use an array of indices to specify the vertices
* within your vertex buffer that you want to draw.
* within your vertex buffer that you want to draw. The indices themselves
* are created by calling cogl_vertex_buffer_indices_new ()
*
* Any un-submitted attribute changes are automatically submitted before
* drawing.
*/
void
cogl_vertex_buffer_draw_elements (CoglHandle handle,
GLenum mode,
GLuint min_index,
GLuint max_index,
GLsizei count,
GLenum indices_type,
const GLvoid *indices);
cogl_vertex_buffer_draw_elements (CoglHandle handle,
CoglVerticesMode mode,
CoglHandle indices,
int min_index,
int max_index,
int indices_offset,
int count);
/**
* cogl_vertex_buffer_ref:
@ -318,6 +394,46 @@ cogl_vertex_buffer_ref (CoglHandle handle);
void
cogl_vertex_buffer_unref (CoglHandle handle);
/**
* cogl_vertex_buffer_indices_get_for_quads:
* @n_indices: the number of indices in the vertex buffer.
*
* Creates a vertex buffer containing the indices needed to draw pairs
* of triangles from a list of vertices grouped as quads. There will
* be at least @n_indices entries in the buffer (but there may be
* more).
*
* The indices will follow this pattern:
*
* 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7 ... etc
*
* For example, if you submit vertices for a quad like this:
*
* |[
* 0 3
* ########
* # #
* # #
* ########
* 1 2
* ]|
*
* Then you can request 6 indices to render two triangles like this:
*
* |[
* 0 0 3
* ## ########
* # ## ## #
* # ## ## #
* ######## ##
* 1 2 2
* ]|
*
* Returns: A %CoglHandle containing the indices. The handled is
* owned by Cogl and should not be modified or unref'd.
*/
CoglHandle
cogl_vertex_buffer_indices_get_for_quads (guint n_indices);
G_END_DECLS

View file

@ -45,6 +45,7 @@
#include <cogl/cogl-types.h>
#include <cogl/cogl-debug.h>
#include <cogl/cogl-deprecated.h>
#include <cogl/cogl-enum-types.h>
G_BEGIN_DECLS
@ -55,22 +56,6 @@ G_BEGIN_DECLS
* General utility functions for COGL.
*/
/* Context manipulation */
/**
* cogl_create_context:
*
* FIXME
*/
gboolean cogl_create_context (void);
/**
* cogl_destroy_context:
*
* FIXME
*/
void cogl_destroy_context (void);
/**
* cogl_get_option_group:
*
@ -187,7 +172,30 @@ void cogl_frustum (float left,
float z_far);
/**
* cogl_setup_viewport:
* cogl_ortho:
* @left: The coordinate for the left clipping plane
* @right: The coordinate for the right clipping plane
* @bottom: The coordinate for the bottom clipping plane
* @top: The coordinate for the top clipping plane
* @near: The coordinate for the near clipping plane (may be negative if
* the plane is behind the viewer)
* @far: The coordinate for the far clipping plane (may be negative if
* the plane is behind the viewer)
*
* Replaces the current projection matrix with a parallel projection
* matrix.
*
* Since: 1.0
*/
void cogl_ortho (float left,
float right,
float bottom,
float top,
float near,
float far);
/*
* _cogl_setup_viewport:
* @width: Width of the viewport
* @height: Height of the viewport
* @fovy: Field of view angle in degrees
@ -201,9 +209,11 @@ void cogl_frustum (float left,
* with one that has a viewing angle of @fovy along the y-axis and a
* view scaled according to @aspect along the x-axis. The view is
* clipped according to @z_near and @z_far on the z-axis.
*
* This function is used only by Clutter.
*/
void cogl_setup_viewport (guint width,
guint height,
void _cogl_setup_viewport (guint width,
guint height,
float fovy,
float aspect,
float z_near,
@ -288,6 +298,14 @@ void cogl_rotate (float angle,
*/
void cogl_get_modelview_matrix (CoglMatrix *matrix);
/**
* cogl_set_modelview_matrix:
* @matrix: pointer to a CoglMatrix to set as the new model-view matrix
*
* Loads matrix as the new model-view matrix.
*/
void cogl_set_modelview_matrix (CoglMatrix *matrix);
/**
* cogl_get_projection_matrix:
* @matrix: pointer to a CoglMatrix to recieve the matrix
@ -296,6 +314,14 @@ void cogl_get_modelview_matrix (CoglMatrix *matrix);
*/
void cogl_get_projection_matrix (CoglMatrix *matrix);
/**
* cogl_set_projection_matrix:
* @matrix: pointer to a CoglMatrix to set as the new projection matrix
*
* Loads matrix as the new projection matrix.
*/
void cogl_set_projection_matrix (CoglMatrix *matrix);
/**
* cogl_get_viewport:
* @v: pointer to a 4 element array of #float<!-- -->s to
@ -308,7 +334,7 @@ void cogl_get_projection_matrix (CoglMatrix *matrix);
void cogl_get_viewport (float v[4]);
/**
* cogl_enable_depth_test:
* cogl_set_depth_test_enable:
* @setting: %TRUE to enable depth testing or %FALSE to disable.
*
* Sets whether depth testing is enabled. If it is disabled then the
@ -317,10 +343,19 @@ void cogl_get_viewport (float v[4]);
* clutter_actor_lower(), otherwise it will also take into account the
* actor's depth. Depth testing is disabled by default.
*/
void cogl_enable_depth_test (gboolean setting);
void cogl_set_depth_test_enable (gboolean setting);
/**
* cogl_enable_backface_culling:
* cogl_get_depth_test_enable:
*
* Queries if depth testing has been enabled via cogl_set_depth_test_enable()
*
* Returns: TRUE if depth testing is enabled else FALSE
*/
gboolean cogl_get_depth_test_enable (void);
/**
* cogl_set_backface_culling_enabled:
* @setting: %TRUE to enable backface culling or %FALSE to disable.
*
* Sets whether textures positioned so that their backface is showing
@ -329,7 +364,17 @@ void cogl_enable_depth_test (gboolean setting);
* only affects calls to the cogl_rectangle* family of functions and
* cogl_vertex_buffer_draw*. Backface culling is disabled by default.
*/
void cogl_enable_backface_culling (gboolean setting);
void cogl_set_backface_culling_enabled (gboolean setting);
/**
* cogl_get_backface_culling_enabled:
*
* Queries if backface culling has been enabled via
* cogl_set_backface_culling_enabled()
*
* Returns: TRUE if backface culling is enabled else FALSE
*/
gboolean cogl_get_backface_culling_enabled (void);
/**
* cogl_set_fog:
@ -368,9 +413,12 @@ void cogl_disable_fog (void);
* @COGL_BUFFER_BIT_COLOR: Selects the primary color buffer
* @COGL_BUFFER_BIT_DEPTH: Selects the depth buffer
* @COGL_BUFFER_BIT_STENCIL: Selects the stencil buffer
*
* Types of auxiliary buffers
*
* Since: 1.0
*/
typedef enum _CoglBufferBit
{
typedef enum {
COGL_BUFFER_BIT_COLOR = 1L<<0,
COGL_BUFFER_BIT_DEPTH = 1L<<1,
COGL_BUFFER_BIT_STENCIL = 1L<<2
@ -379,13 +427,14 @@ typedef enum _CoglBufferBit
/**
* cogl_clear:
* @color: Background color to clear to
* @buffers: A mask of @CoglBufferBit<!-- -->'s identifying which auxiliary
* buffers to clear
* @buffers: A mask of #CoglBufferBit<!-- -->'s identifying which auxiliary
* buffers to clear
*
* Clears all the auxiliary buffers identified in the @buffers mask, and if
* that includes the color buffer then the specified @color is used.
*/
void cogl_clear (const CoglColor *color, gulong buffers);
void cogl_clear (const CoglColor *color,
gulong buffers);
/**
* cogl_set_source:
@ -628,7 +677,24 @@ void cogl_push_draw_buffer (void);
*/
void cogl_pop_draw_buffer (void);
/**
/*
* Internal API available only to Clutter.
*
* These are typically only to deal with the poor seperation of
* responsabilities that currently exists between Clutter and Cogl.
* Eventually a lot of the backend code currently in Clutter will
* move down into Cogl and these functions will be removed.
*/
void _cogl_destroy_context (void);
/* XXX: Removed before we release Clutter 1.0 since the implementation
* wasn't complete, and so we assume no one is using this yet. Util we
* have some one with a good usecase, we can't pretend to support breaking
* out into raw OpenGL. */
#if 0
/*
* cogl_flush_gl_state:
* @flags: flags controlling what is flushed; currently unused, pass in 0
*
@ -642,6 +708,7 @@ void cogl_pop_draw_buffer (void);
* Since: 1.0
*/
void cogl_flush_gl_state (int flags);
#endif
/* private */
void _cogl_set_indirect_context (gboolean indirect);

View file

@ -1,3 +1,10 @@
NULL =
V = @
Q = $(V:1=)
QUIET_GEN = $(Q:@=@echo ' GEN '$@;)
QUIET_CP = $(Q:@=@echo ' CP '$@;)
INCLUDES = \
-I$(top_srcdir) \
-I$(top_srcdir)/clutter \
@ -9,12 +16,49 @@ INCLUDES = \
-DG_LOG_DOMAIN=\"Cogl-Common\" \
-DCLUTTER_COMPILATION
cogl_public_h = \
$(top_srcdir)/clutter/cogl/cogl-bitmap.h \
$(top_srcdir)/clutter/cogl/cogl-color.h \
$(top_srcdir)/clutter/cogl/cogl-debug.h \
$(top_srcdir)/clutter/cogl/cogl-fixed.h \
$(top_srcdir)/clutter/cogl/cogl-material.h \
$(top_srcdir)/clutter/cogl/cogl-matrix.h \
$(top_srcdir)/clutter/cogl/cogl-offscreen.h \
$(top_srcdir)/clutter/cogl/cogl-path.h \
$(top_srcdir)/clutter/cogl/cogl-shader.h \
$(top_srcdir)/clutter/cogl/cogl-texture.h \
$(top_srcdir)/clutter/cogl/cogl-types.h \
$(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h \
$(top_builddir)/clutter/cogl/cogl.h \
$(NULL)
noinst_LTLIBRARIES = libclutter-cogl-common.la
EXTRA_DIST = stb_image.c
cogl-enum-types.h: stamp-cogl-enum-types.h
@true
stamp-cogl-enum-types.h: $(cogl_public_h) Makefile
$(QUIET_GEN)( $(GLIB_MKENUMS) \
--template $(srcdir)/cogl-enum-types.h.in \
$(cogl_public_h) ) > xgen-ceth \
&& (cmp -s xgen-ceth cogl-enum-types.h || cp -f xgen-ceth cogl-enum-types.h) \
&& cp -f cogl-enum-types.h $(top_builddir)/clutter/cogl/cogl-enum-types.h \
&& rm -f xgen-ceth \
&& echo timestamp > $(@F)
cogl-enum-types.c: cogl-enum-types.h
$(QUIET_GEN)( $(GLIB_MKENUMS) \
--template $(srcdir)/cogl-enum-types.c.in \
$(cogl_public_h) ) > xgen-cetc \
&& cp -f xgen-cetc cogl-enum-types.c \
&& rm -f xgen-cetc
BUILT_SOURCES = cogl-enum-types.h cogl-enum-types.c
libclutter_cogl_common_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS)
libclutter_cogl_common_la_LIBADD = -lm $(CLUTTER_LIBS)
libclutter_cogl_common_la_SOURCES = \
$(top_builddir)/clutter/cogl/common/cogl-enum-types.h \
$(top_builddir)/clutter/cogl/common/cogl-enum-types.c \
cogl-handle.h \
cogl-internal.h \
cogl.c \
@ -39,4 +83,11 @@ libclutter_cogl_common_la_SOURCES = \
cogl-matrix-stack.h \
cogl-material.c \
cogl-material-private.h \
cogl-debug.c
cogl-blend-string.c \
cogl-blend-string.h \
cogl-debug.c \
$(NULL)
EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.c.in
CLEANFILES = stamp-cogl-enum-types.h
DISTCLEANFILES = cogl-enum-types.h cogl-enum-types.c

View file

@ -0,0 +1,999 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2009 Intel Corporation.
*
* 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.
*
* Authors:
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "cogl.h"
#include "cogl-internal.h"
#include "cogl-context.h"
#include "cogl-debug.h"
#include "cogl-blend-string.h"
typedef enum _ParserState
{
PARSER_STATE_EXPECT_DEST_CHANNELS,
PARSER_STATE_SCRAPING_DEST_CHANNELS,
PARSER_STATE_EXPECT_FUNCTION_NAME,
PARSER_STATE_SCRAPING_FUNCTION_NAME,
PARSER_STATE_EXPECT_ARG_START,
PARSER_STATE_EXPECT_STATEMENT_END
} ParserState;
typedef enum _ParserArgState
{
PARSER_ARG_STATE_START,
PARSER_ARG_STATE_EXPECT_MINUS,
PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME,
PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME,
PARSER_ARG_STATE_MAYBE_COLOR_MASK,
PARSER_ARG_STATE_SCRAPING_MASK,
PARSER_ARG_STATE_MAYBE_MULT,
PARSER_ARG_STATE_EXPECT_OPEN_PAREN,
PARSER_ARG_STATE_EXPECT_FACTOR,
PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE,
PARSER_ARG_STATE_MAYBE_MINUS,
PARSER_ARG_STATE_EXPECT_CLOSE_PAREN,
PARSER_ARG_STATE_EXPECT_END
} ParserArgState;
#define DEFINE_COLOR_SOURCE(NAME, NAME_LEN) \
{.type = COGL_BLEND_STRING_COLOR_SOURCE_ ## NAME, \
.name = #NAME, \
.name_len = NAME_LEN}
static CoglBlendStringColorSourceInfo blending_color_sources[] = {
DEFINE_COLOR_SOURCE (SRC_COLOR, 9),
DEFINE_COLOR_SOURCE (DST_COLOR, 9),
DEFINE_COLOR_SOURCE (CONSTANT, 8)
};
static CoglBlendStringColorSourceInfo tex_combine_color_sources[] = {
DEFINE_COLOR_SOURCE (TEXTURE, 7),
/* DEFINE_COLOR_SOURCE (TEXTURE_N, *) - handled manually */
DEFINE_COLOR_SOURCE (PRIMARY, 7),
DEFINE_COLOR_SOURCE (CONSTANT, 8),
DEFINE_COLOR_SOURCE (PREVIOUS, 8)
};
static CoglBlendStringColorSourceInfo tex_combine_texture_n_color_source = {
.type = COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N,
.name = "TEXTURE_N",
.name_len = 0
};
#undef DEFINE_COLOR_SOURCE
#define DEFINE_FUNCTION(NAME, NAME_LEN, ARGC) \
{ .type = COGL_BLEND_STRING_FUNCTION_ ## NAME, \
.name = #NAME, \
.name_len = NAME_LEN, \
.argc = ARGC }
/* NB: These must be sorted so any name that's a subset of another
* comes later than the longer name. */
static CoglBlendStringFunctionInfo tex_combine_functions[] = {
DEFINE_FUNCTION (AUTO_COMPOSITE, 14, 0),
DEFINE_FUNCTION (REPLACE, 7, 1),
DEFINE_FUNCTION (MODULATE, 8, 2),
DEFINE_FUNCTION (ADD_SIGNED, 10, 2),
DEFINE_FUNCTION (ADD, 3, 2),
DEFINE_FUNCTION (INTERPOLATE, 11, 3),
DEFINE_FUNCTION (SUBTRACT, 8, 2),
DEFINE_FUNCTION (DOT3_RGBA, 9, 2),
DEFINE_FUNCTION (DOT3_RGB, 8, 2)
};
static CoglBlendStringFunctionInfo blend_functions[] = {
DEFINE_FUNCTION (AUTO_COMPOSITE, 14, 0),
DEFINE_FUNCTION (ADD, 3, 2)
};
#undef DEFINE_FUNCTION
GQuark
_cogl_blend_string_error_quark (void)
{
return g_quark_from_static_string ("cogl-blend-string-error-quark");
}
void
_cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement,
CoglBlendStringStatement *rgb,
CoglBlendStringStatement *a)
{
int i;
memcpy (rgb, statement, sizeof (CoglBlendStringStatement));
memcpy (a, statement, sizeof (CoglBlendStringStatement));
rgb->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
a->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
for (i = 0; i < statement->function->argc; i++)
{
CoglBlendStringArgument *arg = &statement->args[i];
CoglBlendStringArgument *rgb_arg = &rgb->args[i];
CoglBlendStringArgument *a_arg = &a->args[i];
if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
{
rgb_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
a_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
}
if (arg->factor.is_color &&
arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
{
rgb_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
a_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
}
}
}
static gboolean
validate_tex_combine_statements (CoglBlendStringStatement *statements,
int n_statements,
GError **error)
{
int i, j;
const char *error_string;
CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR;
for (i = 0; i < n_statements; i++)
{
#ifdef HAVE_COGL_GLES2
if (statements[i].function->type != COGL_BLEND_STRING_FUNCTION_MODULATE)
{
error_string = "Using anything but MODULATE() for texture combining"
" under GLES 2 is currently unsupported";
detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
goto error;
}
#endif
for (j = 0; j < statements[i].function->argc; j++)
{
CoglBlendStringArgument *arg = &statements[i].args[j];
if (arg->source.is_zero)
{
error_string = "You can't use the constant '0' as a texture "
"combine argument";
goto error;
}
if (!arg->factor.is_one)
{
error_string = "Argument factors are only relevant to blending "
"not texture combining";
goto error;
}
#ifdef HAVE_COGL_GLES2
if (arg->source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT)
{
error_string = "Using a constant for texture combining isn't "
"currently supported with GLES 2 "
"(TODO: glTexEnvf)";
detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
goto error;
}
#endif
}
}
return TRUE;
error:
g_set_error (error,
COGL_BLEND_STRING_ERROR,
detail,
"Invalid texture combine string: %s",
error_string);
if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
{
g_debug ("Invalid texture combine string: %s",
error_string);
}
return FALSE;
}
static gboolean
validate_blend_statements (CoglBlendStringStatement *statements,
int n_statements,
GError **error)
{
int i, j;
const char *error_string;
CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR;
#ifdef HAVE_COGL_GL
_COGL_GET_CONTEXT (ctx, 0);
#endif
#ifdef HAVE_COGL_GL
if (n_statements == 2)
{
/* glBlendEquationSeperate is GL 2.0 only */
if (!ctx->pf_glBlendEquationSeparate &&
statements[0].function->type != statements[1].function->type)
{
error_string = "Separate blend functions for the RGB an A "
"channels isn't supported by the driver";
detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
goto error;
}
}
#elif defined(HAVE_COGL_GLES)
if (n_statements != 1)
{
error_string = "Separate blend functions for the RGB an A "
"channels isn't supported by the GLES 1";
detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
goto error;
}
#endif
for (i = 0; i < n_statements; i++)
for (j = 0; j < statements[i].function->argc; j++)
{
CoglBlendStringArgument *arg = &statements[i].args[j];
if (arg->source.is_zero)
continue;
if ((j == 0 &&
arg->source.info->type !=
COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR)
|| (j == 1 &&
arg->source.info->type !=
COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR))
{
error_string = "For blending you must always use SRC_COLOR "
"for arg0 and DST_COLOR for arg1";
goto error;
}
#ifdef HAVE_COGL_GLES
if (arg->factor.is_color &&
arg->factor.source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT)
{
error_string = "GLES Doesn't support constant blend factors";
detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR;
goto error;
}
#endif
}
return TRUE;
error:
g_set_error (error,
COGL_BLEND_STRING_ERROR,
detail,
"Invalid blend string: %s",
error_string);
return FALSE;
}
static gboolean
validate_statements_for_context (CoglBlendStringStatement *statements,
int n_statements,
CoglBlendStringContext context,
GError **error)
{
const char *error_string;
if (n_statements == 1)
{
if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
{
error_string = "You need to also give a blend statement for the RGB"
"channels";
goto error;
}
else if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
{
error_string = "You need to also give a blend statement for the "
"Alpha channel";
goto error;
}
}
if (context == COGL_BLEND_STRING_CONTEXT_BLENDING)
return validate_blend_statements (statements, n_statements, error);
else
return validate_tex_combine_statements (statements, n_statements, error);
error:
g_set_error (error,
COGL_BLEND_STRING_ERROR,
COGL_BLEND_STRING_ERROR_INVALID_ERROR,
"Invalid %s string: %s",
context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
"blend" : "texture combine",
error_string);
if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
{
g_debug ("Invalid %s string: %s",
context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
"blend" : "texture combine",
error_string);
}
return FALSE;
}
static void
print_argument (CoglBlendStringArgument *arg)
{
const char *mask_names[] = {
"RGB",
"A",
"RGBA"
};
g_print (" Arg:\n");
g_print (" is zero = %s\n", arg->source.is_zero ? "yes" : "no");
if (!arg->source.is_zero)
{
g_print (" color source = %s\n", arg->source.info->name);
g_print (" one minus = %s\n", arg->source.one_minus ? "yes" : "no");
g_print (" mask = %s\n", mask_names[arg->source.mask]);
g_print (" texture = %d\n", arg->source.texture);
g_print ("\n");
g_print (" factor is_one = %s\n", arg->factor.is_one ? "yes" : "no");
g_print (" factor is_src_alpha_saturate = %s\n",
arg->factor.is_src_alpha_saturate ? "yes" : "no");
g_print (" factor is_color = %s\n", arg->factor.is_color ? "yes" : "no");
if (arg->factor.is_color)
{
g_print (" factor color:is zero = %s\n",
arg->factor.source.is_zero ? "yes" : "no");
g_print (" factor color:color source = %s\n",
arg->factor.source.info->name);
g_print (" factor color:one minus = %s\n",
arg->factor.source.one_minus ? "yes" : "no");
g_print (" factor color:mask = %s\n",
mask_names[arg->factor.source.mask]);
g_print (" factor color:texture = %d\n",
arg->factor.source.texture);
}
}
}
static void
print_statement (int num, CoglBlendStringStatement *statement)
{
const char *mask_names[] = {
"RGB",
"A",
"RGBA"
};
int i;
g_print ("Statement %d:\n", num);
g_print (" Destination channel mask = %s\n",
mask_names[statement->mask]);
g_print (" Function = %s\n", statement->function->name);
for (i = 0; i < statement->function->argc; i++)
print_argument (&statement->args[i]);
}
static const CoglBlendStringFunctionInfo *
get_function_info (const char *mark,
const char *p,
CoglBlendStringContext context)
{
size_t len = p - mark;
CoglBlendStringFunctionInfo *functions;
size_t array_len;
int i;
if (context == COGL_BLEND_STRING_CONTEXT_BLENDING)
{
functions = blend_functions;
array_len = G_N_ELEMENTS (blend_functions);
}
else
{
functions = tex_combine_functions;
array_len = G_N_ELEMENTS (tex_combine_functions);
}
for (i = 0; i < array_len; i++)
{
if (len >= functions[i].name_len
&& strncmp (mark, functions[i].name, functions[i].name_len) == 0)
return &functions[i];
}
return NULL;
}
static const CoglBlendStringColorSourceInfo *
get_color_src_info (const char *mark,
const char *p,
CoglBlendStringContext context)
{
size_t len = p - mark;
CoglBlendStringColorSourceInfo *sources;
size_t array_len;
int i;
if (context == COGL_BLEND_STRING_CONTEXT_BLENDING)
{
sources = blending_color_sources;
array_len = G_N_ELEMENTS (blending_color_sources);
}
else
{
sources = tex_combine_color_sources;
array_len = G_N_ELEMENTS (tex_combine_color_sources);
}
for (i = 0; i < array_len; i++)
{
if (len >= sources[i].name_len
&& strncmp (mark, sources[i].name, sources[i].name_len) == 0)
return &sources[i];
}
if (len >= 9 &&
strncmp (mark, "TEXTURE_", 8) == 0 &&
g_ascii_isdigit (mark[8]))
{
return &tex_combine_texture_n_color_source;
}
return NULL;
}
static gboolean
is_symbol_char (const char c)
{
return (g_ascii_isalpha (c) || c == '_') ? TRUE : FALSE;
}
static gboolean
parse_argument (const char *string, /* original user string */
const char **ret_p, /* start of argument IN:OUT */
const CoglBlendStringStatement *statement,
int current_arg,
CoglBlendStringArgument *arg, /* OUT */
CoglBlendStringContext context,
GError **error)
{
const char *p = *ret_p;
const char *mark;
const char *error_string;
ParserArgState state = PARSER_ARG_STATE_START;
gboolean parsing_factor = FALSE;
arg->source.is_zero = FALSE;
arg->source.info = NULL;
arg->source.texture = 0;
arg->source.one_minus = FALSE;
arg->source.mask = statement->mask;
arg->factor.is_one = FALSE;
arg->factor.is_color = FALSE;
arg->factor.is_src_alpha_saturate = FALSE;
arg->factor.source.is_zero = FALSE;
arg->factor.source.info = NULL;
arg->factor.source.texture = 0;
arg->factor.source.one_minus = FALSE;
arg->factor.source.mask = statement->mask;
do
{
if (g_ascii_isspace (*p))
continue;
if (*p == '\0')
{
error_string = "Unexpected end of string while parsing argument";
goto error;
}
switch (state)
{
case PARSER_ARG_STATE_START:
if (*p == '1')
state = PARSER_ARG_STATE_EXPECT_MINUS;
else if (*p == '0')
{
arg->source.is_zero = TRUE;
state = PARSER_ARG_STATE_EXPECT_END;
}
else
{
p--; /* backtrack */
state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
}
continue;
case PARSER_ARG_STATE_EXPECT_MINUS:
if (*p != '-')
{
error_string = "expected a '-' following the 1";
goto error;
}
arg->source.one_minus = TRUE;
state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
continue;
case PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME:
if (!is_symbol_char (*p))
{
error_string = "expected a color source name";
goto error;
}
state = PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME;
mark = p;
if (parsing_factor)
arg->factor.is_color = TRUE;
/* fall through */
case PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME:
if (!is_symbol_char (*p))
{
CoglBlendStringColorSource *source =
parsing_factor ? &arg->factor.source : &arg->source;
source->info = get_color_src_info (mark, p, context);
if (!source->info)
{
error_string = "Unknown color source name";
goto error;
}
if (source->info->type ==
COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N)
{
char *endp;
source->texture =
strtoul (&mark[strlen ("TEXTURE_")], &endp, 10);
if (mark == endp)
{
error_string = "invalid texture number given with "
"TEXTURE_N color source";
goto error;
}
p = endp;
}
state = PARSER_ARG_STATE_MAYBE_COLOR_MASK;
}
else
continue;
/* fall through */
case PARSER_ARG_STATE_MAYBE_COLOR_MASK:
if (*p != '[')
{
p--; /* backtrack */
if (!parsing_factor)
state = PARSER_ARG_STATE_MAYBE_MULT;
else
state = PARSER_ARG_STATE_EXPECT_END;
continue;
}
state = PARSER_ARG_STATE_SCRAPING_MASK;
mark = p;
/* fall through */
case PARSER_ARG_STATE_SCRAPING_MASK:
if (*p == ']')
{
size_t len = p - mark;
CoglBlendStringColorSource *source =
parsing_factor ? &arg->factor.source : &arg->source;
if (len == 5 && strncmp (mark, "[RGBA", len) == 0)
{
if (statement->mask != COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
{
error_string = "You can't use an RGBA color mask if the "
"statement hasn't also got an RGBA= mask";
goto error;
}
source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA;
}
else if (len == 4 && strncmp (mark, "[RGB", len) == 0)
source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
else if (len == 2 && strncmp (mark, "[A", len) == 0)
source->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
else
{
error_string = "Expected a channel mask of [RGBA]"
"[RGB] or [A]";
goto error;
}
if (parsing_factor)
state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
else
state = PARSER_ARG_STATE_MAYBE_MULT;
}
continue;
case PARSER_ARG_STATE_EXPECT_OPEN_PAREN:
if (*p != '(')
{
error_string = "Expected '(' before blend factor - the parser "
"currently requires that all blend factors "
"following a '*' be surrounded in brackets";
goto error;
}
parsing_factor = TRUE;
state = PARSER_ARG_STATE_EXPECT_FACTOR;
continue;
case PARSER_ARG_STATE_EXPECT_FACTOR:
if (*p == '1')
state = PARSER_ARG_STATE_MAYBE_MINUS;
else if (*p == '0')
{
arg->source.is_zero = TRUE;
state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
}
else
{
state = PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE;
mark = p;
}
continue;
case PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE:
if (!is_symbol_char (*p))
{
size_t len = p - mark;
if (len >= strlen ("SRC_ALPHA_SATURATE") &&
strncmp (mark, "SRC_ALPHA_SATURATE", len) == 0)
{
arg->factor.is_src_alpha_saturate = TRUE;
state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
}
else
{
state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
p = mark - 1; /* backtrack */
}
}
continue;
case PARSER_ARG_STATE_MAYBE_MINUS:
if (*p == '-')
{
arg->factor.source.one_minus = TRUE;
state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
}
else
{
arg->factor.is_one = TRUE;
state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
}
continue;
case PARSER_ARG_STATE_EXPECT_CLOSE_PAREN:
if (*p != ')')
{
error_string = "Expected closing parenthesis after blend factor";
goto error;
}
state = PARSER_ARG_STATE_EXPECT_END;
continue;
case PARSER_ARG_STATE_MAYBE_MULT:
if (*p == '*')
{
state = PARSER_ARG_STATE_EXPECT_OPEN_PAREN;
continue;
}
arg->factor.is_one = TRUE;
state = PARSER_ARG_STATE_EXPECT_END;
/* fall through */
case PARSER_ARG_STATE_EXPECT_END:
if (*p != ',' && *p != ')')
{
error_string = "expected , or )";
goto error;
}
*ret_p = p - 1;
return TRUE;
}
}
while (p++);
error:
{
int offset = p - string;
g_set_error (error,
COGL_BLEND_STRING_ERROR,
COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR,
"Syntax error for argument %d at offset %d: %s",
current_arg,
offset,
error_string);
if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
{
g_debug ("Syntax error for argument %d at offset %d: %s",
current_arg, offset, error_string);
}
return FALSE;
}
}
int
_cogl_blend_string_compile (const char *string,
CoglBlendStringContext context,
CoglBlendStringStatement *statements,
GError **error)
{
const char *p = string;
const char *mark;
const char *error_string;
ParserState state = PARSER_STATE_EXPECT_DEST_CHANNELS;
CoglBlendStringStatement *statement = statements;
int current_statement = 0;
int current_arg = 0;
int remaining_argc;
#if 0
cogl_debug_flags |= COGL_DEBUG_BLEND_STRINGS;
#endif
if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
{
COGL_NOTE (BLEND_STRINGS, "Compiling %s string:\n%s\n",
context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
"blend" : "texture combine",
string);
}
do
{
if (g_ascii_isspace (*p))
continue;
if (*p == '\0')
{
switch (state)
{
case PARSER_STATE_EXPECT_DEST_CHANNELS:
if (current_statement != 0)
goto finished;
error_string = "Empty statement";
goto error;
case PARSER_STATE_SCRAPING_DEST_CHANNELS:
error_string = "Expected an '=' following the destination "
"channel mask";
goto error;
case PARSER_STATE_EXPECT_FUNCTION_NAME:
error_string = "Expected a function name";
goto error;
case PARSER_STATE_SCRAPING_FUNCTION_NAME:
error_string = "Expected parenthesis after the function name";
goto error;
case PARSER_STATE_EXPECT_ARG_START:
error_string = "Expected to find the start of an argument";
goto error;
case PARSER_STATE_EXPECT_STATEMENT_END:
error_string = "Expected closing parenthesis for statement";
goto error;
}
}
switch (state)
{
case PARSER_STATE_EXPECT_DEST_CHANNELS:
mark = p;
state = PARSER_STATE_SCRAPING_DEST_CHANNELS;
/* fall through */
case PARSER_STATE_SCRAPING_DEST_CHANNELS:
if (*p != '=')
continue;
if (strncmp (mark, "RGBA", 4) == 0)
statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA;
else if (strncmp (mark, "RGB", 3) == 0)
statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
else if (strncmp (mark, "A", 1) == 0)
statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
else
{
error_string = "Unknown destination channel mask; "
"expected RGBA=, RGB= or A=";
goto error;
}
state = PARSER_STATE_EXPECT_FUNCTION_NAME;
continue;
case PARSER_STATE_EXPECT_FUNCTION_NAME:
mark = p;
state = PARSER_STATE_SCRAPING_FUNCTION_NAME;
/* fall through */
case PARSER_STATE_SCRAPING_FUNCTION_NAME:
if (*p != '(')
{
if (!is_symbol_char (*p))
{
error_string = "non alpha numeric character in function"
"name";
goto error;
}
continue;
}
statement->function = get_function_info (mark, p, context);
if (!statement->function)
{
error_string = "Unknown function name";
goto error;
}
remaining_argc = statement->function->argc;
current_arg = 0;
state = PARSER_STATE_EXPECT_ARG_START;
/* fall through */
case PARSER_STATE_EXPECT_ARG_START:
if (*p != '(' && *p != ',')
continue;
if (remaining_argc)
{
p++; /* parse_argument expects to see the first char of the arg */
if (!parse_argument (string, &p, statement,
current_arg, &statement->args[current_arg],
context, error))
return 0;
current_arg++;
remaining_argc--;
}
if (!remaining_argc)
state = PARSER_STATE_EXPECT_STATEMENT_END;
continue;
case PARSER_STATE_EXPECT_STATEMENT_END:
if (*p != ')')
{
error_string = "Expected end of statement";
goto error;
}
state = PARSER_STATE_EXPECT_DEST_CHANNELS;
if (current_statement++ == 1)
goto finished;
statement = &statements[current_statement];
}
}
while (p++);
finished:
if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
{
if (current_statement > 0)
print_statement (0, &statements[0]);
if (current_statement > 1)
print_statement (1, &statements[1]);
}
if (!validate_statements_for_context (statements,
current_statement,
context,
error))
return 0;
return current_statement;
error:
{
int offset = p - string;
g_set_error (error,
COGL_BLEND_STRING_ERROR,
COGL_BLEND_STRING_ERROR_PARSE_ERROR,
"Syntax error at offset %d: %s",
offset,
error_string);
if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
{
g_debug ("Syntax error at offset %d: %s",
offset, error_string);
}
return 0;
}
}
/*
* INTERNAL TESTING CODE ...
*/
struct _TestString
{
const char *string;
CoglBlendStringContext context;
};
int
_cogl_blend_string_test (void)
{
struct _TestString strings[] = {
{" A = MODULATE ( TEXTURE[RGB], PREVIOUS[A], PREVIOUS[A] ) ",
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE },
{" RGB = MODULATE ( TEXTURE[RGB], PREVIOUS[A] ) ",
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE },
{"A=ADD(TEXTURE[A],PREVIOUS[RGB])",
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE },
{"A=ADD(TEXTURE[A],PREVIOUS[RGB])",
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE },
{"RGBA = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))",
COGL_BLEND_STRING_CONTEXT_BLENDING },
{"RGB = ADD(SRC_COLOR, DST_COLOR*(0))",
COGL_BLEND_STRING_CONTEXT_BLENDING },
{"RGB = ADD(SRC_COLOR, 0)",
COGL_BLEND_STRING_CONTEXT_BLENDING },
{"RGB = ADD()",
COGL_BLEND_STRING_CONTEXT_BLENDING },
{"RGB = ADD(SRC_COLOR, 0, DST_COLOR)",
COGL_BLEND_STRING_CONTEXT_BLENDING },
{NULL}
};
int i;
GError *error = NULL;
for (i = 0; strings[i].string; i++)
{
CoglBlendStringStatement statements[2];
int count = _cogl_blend_string_compile (strings[i].string,
strings[i].context,
statements,
&error);
if (!count)
{
g_print ("Failed to parse string:\n%s\n%s\n",
strings[i].string,
error->message);
g_error_free (error);
error = NULL;
continue;
}
g_print ("Original:\n");
g_print ("%s\n", strings[i].string);
if (count > 0)
print_statement (0, &statements[0]);
if (count > 1)
print_statement (1, &statements[1]);
}
return 0;
}

View file

@ -0,0 +1,151 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2009 Intel Corporation.
*
* 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.
*
* Authors:
* Robert Bragg <robert@linux.intel.com>
*/
#ifndef COGL_BLEND_STRING_H
#define COGL_BLEND_STRING_H
#include <stdlib.h>
#include <glib.h>
typedef enum _CoglBlendStringContext
{
COGL_BLEND_STRING_CONTEXT_BLENDING,
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE
} CoglBlendStringContext;
#define COGL_BLEND_STRING_ERROR _cogl_blend_string_error_quark ()
typedef enum _CoglBlendStringError
{
COGL_BLEND_STRING_ERROR_PARSE_ERROR,
COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR,
COGL_BLEND_STRING_ERROR_INVALID_ERROR,
COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR
} CoglBlendStringError;
/* NB: debug stringify code will get upset if these
* are re-ordered */
typedef enum _CoglBlendStringChannelMask
{
COGL_BLEND_STRING_CHANNEL_MASK_RGB,
COGL_BLEND_STRING_CHANNEL_MASK_ALPHA,
COGL_BLEND_STRING_CHANNEL_MASK_RGBA
} CoglBlendStringChannelMask;
typedef enum _CoglBlendStringColorSourceType
{
/* blending */
COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR,
COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR,
/* shared */
COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT,
/* texture combining */
COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE,
COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N,
COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY,
COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS
} CoglBlendStringColorSourceType;
typedef struct _CoglBlendStringColorSourceInfo
{
CoglBlendStringColorSourceType type;
const char *name;
size_t name_len;
} CoglBlendStringColorSourceInfo;
typedef struct _CoglBlendStringColorSource
{
gboolean is_zero;
const CoglBlendStringColorSourceInfo *info;
int texture; /* for the TEXTURE_N color source */
gboolean one_minus;
CoglBlendStringChannelMask mask;
} CoglBlendStringColorSource;
typedef struct _CoglBlendStringFactor
{
gboolean is_one;
gboolean is_src_alpha_saturate;
gboolean is_color;
CoglBlendStringColorSource source;
} CoglBlendStringFactor;
typedef struct _CoglBlendStringArgument
{
CoglBlendStringColorSource source;
CoglBlendStringFactor factor;
} CoglBlendStringArgument;
typedef enum _CoglBlendStringFunctionType
{
/* shared */
COGL_BLEND_STRING_FUNCTION_AUTO_COMPOSITE,
COGL_BLEND_STRING_FUNCTION_ADD,
/* texture combine only */
COGL_BLEND_STRING_FUNCTION_REPLACE,
COGL_BLEND_STRING_FUNCTION_MODULATE,
COGL_BLEND_STRING_FUNCTION_ADD_SIGNED,
COGL_BLEND_STRING_FUNCTION_INTERPOLATE,
COGL_BLEND_STRING_FUNCTION_SUBTRACT,
COGL_BLEND_STRING_FUNCTION_DOT3_RGB,
COGL_BLEND_STRING_FUNCTION_DOT3_RGBA
} CoglBlendStringFunctionType;
typedef struct _CoglBlendStringFunctionInfo
{
enum _CoglBlendStringFunctionType type;
const char *name;
size_t name_len;
int argc;
} CoglBlendStringFunctionInfo;
typedef struct _CoglBlendStringStatement
{
CoglBlendStringChannelMask mask;
const CoglBlendStringFunctionInfo *function;
CoglBlendStringArgument args[3];
} CoglBlendStringStatement;
gboolean
_cogl_blend_string_compile (const char *string,
CoglBlendStringContext context,
CoglBlendStringStatement *statements,
GError **error);
void
_cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement,
CoglBlendStringStatement *rgb,
CoglBlendStringStatement *a);
GQuark
_cogl_blend_string_error_quark (void);
#endif /* COGL_BLEND_STRING_H */

View file

@ -45,6 +45,9 @@
#define glFrustum(L,R,B,T,N,F) \
glFrustumf((GLfloat)L, (GLfloat)R, (GLfloat)B, \
(GLfloat)T, (GLfloat)N, (GLfloat)F)
#define glOrtho glOrthof
#endif
#include <string.h>
@ -209,30 +212,57 @@ _cogl_current_matrix_frustum (float left,
}
void
_cogl_current_matrix_ortho (float left,
float right,
float bottom,
float top,
float near_val,
float far_val)
_cogl_current_matrix_perspective (float fov_y,
float aspect,
float z_near,
float z_far)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_perspective (current_stack,
fov_y, aspect, z_near, z_far);
else
{
/* NB: There is no glPerspective() (only gluPerspective()) so we use
* cogl_matrix_perspective: */
CoglMatrix matrix;
_cogl_get_matrix (ctx->matrix_mode, &matrix);
cogl_matrix_perspective (&matrix,
fov_y, aspect, z_near, z_far);
_cogl_current_matrix_load (&matrix);
}
}
void
_cogl_current_matrix_ortho (float left,
float right,
float bottom,
float top,
float near_val,
float far_val)
{
#if 0
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_ortho (current_stack,
left, right,
top, bottom,
bottom, top,
near_val,
far_val);
else
GE (glOrtho (left, right, bottom, top, near_val, far_val));
{
#ifdef HAVE_COGL_GLES2
/* NB: GLES 2 has no glOrtho(): */
CoglMatrix matrix;
_cogl_get_matrix (ctx->matrix_mode, &matrix);
cogl_matrix_ortho (&matrix,
left, right, bottom, top, near_val, far_val);
_cogl_current_matrix_load (&matrix);
#else
/* Nobody is using glOrtho right now anyway, so not bothering */
g_warning ("%s not implemented, need to code cogl_matrix_ortho() if you need"
" this function",
G_STRFUNC);
GE (glOrtho (left, right, bottom, top, near_val, far_val));
#endif
}
}
void
@ -276,6 +306,12 @@ _cogl_get_matrix (CoglMatrixMode mode,
}
}
void
_cogl_set_matrix (const CoglMatrix *matrix)
{
_cogl_current_matrix_load (matrix);
}
void
_cogl_current_matrix_state_init (void)
{
@ -354,85 +390,19 @@ cogl_rotate (float angle, float x, float y, float z)
}
void
_cogl_set_matrix (const CoglMatrix *matrix)
{
_cogl_current_matrix_load (matrix);
}
void
cogl_get_modelview_matrix (CoglMatrix *matrix)
{
_cogl_get_matrix (COGL_MATRIX_MODELVIEW,
matrix);
}
void
cogl_get_projection_matrix (CoglMatrix *matrix)
{
_cogl_get_matrix (COGL_MATRIX_PROJECTION,
matrix);
}
void
cogl_perspective (float fovy,
cogl_perspective (float fov_y,
float aspect,
float zNear,
float zFar)
float z_near,
float z_far)
{
float xmax, ymax;
float x, y, c, d;
float fovy_rad_half = (fovy * G_PI) / 360;
CoglMatrix perspective;
GLfloat m[16];
float ymax = z_near * tanf (fov_y * G_PI / 360.0);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
memset (&m[0], 0, sizeof (m));
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
_cogl_current_matrix_identity ();
/*
* Based on the original algorithm in perspective():
*
* 1) xmin = -xmax => xmax + xmin == 0 && xmax - xmin == 2 * xmax
* same true for y, hence: a == 0 && b == 0;
*
* 2) When working with small numbers, we are loosing significant
* precision
*/
ymax = (zNear * (sinf (fovy_rad_half) / cosf (fovy_rad_half)));
xmax = (ymax * aspect);
x = (zNear / xmax);
y = (zNear / ymax);
c = (-(zFar + zNear) / ( zFar - zNear));
d = (-(2 * zFar) * zNear) / (zFar - zNear);
#define M(row,col) m[col*4+row]
M(0,0) = x;
M(1,1) = y;
M(2,2) = c;
M(2,3) = d;
M(3,2) = -1.0;
cogl_matrix_init_from_array (&perspective, m);
_cogl_current_matrix_multiply (&perspective);
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (float) * 16);
#define m ctx->inverse_projection
M(0, 0) = (1.0 / x);
M(1, 1) = (1.0 / y);
M(2, 3) = -1.0;
M(3, 2) = (1.0 / d);
M(3, 3) = (c / d);
#undef m
#undef M
cogl_frustum (-ymax * aspect, /* left */
ymax * aspect, /* right */
-ymax, /* bottom */
ymax, /* top */
z_near,
z_far);
}
void
@ -474,4 +444,65 @@ cogl_frustum (float left,
M(3,2) = 1.0 / d;
M(3,3) = c / d;
#undef M
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
}
void
cogl_ortho (float left,
float right,
float bottom,
float top,
float z_near,
float z_far)
{
CoglMatrix ortho;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_matrix_init_identity (&ortho);
cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far);
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
_cogl_current_matrix_load (&ortho);
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (float) * 16);
#define M(row,col) ctx->inverse_projection[col*4+row]
M(0,0) = 1.0 / ortho.xx;
M(0,3) = -ortho.xw;
M(1,1) = 1.0 / ortho.yy;
M(1,3) = -ortho.yw;
M(2,2) = 1.0 / ortho.zz;
M(2,3) = -ortho.zw;
M(3,3) = 1.0;
#undef M
}
void
cogl_get_modelview_matrix (CoglMatrix *matrix)
{
_cogl_get_matrix (COGL_MATRIX_MODELVIEW,
matrix);
}
void
cogl_set_modelview_matrix (CoglMatrix *matrix)
{
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
_cogl_current_matrix_load (matrix);
}
void
cogl_get_projection_matrix (CoglMatrix *matrix)
{
_cogl_get_matrix (COGL_MATRIX_PROJECTION,
matrix);
}
void
cogl_set_projection_matrix (CoglMatrix *matrix)
{
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
_cogl_current_matrix_load (matrix);
}

View file

@ -39,7 +39,8 @@ static const GDebugKey cogl_debug_keys[] = {
{ "draw", COGL_DEBUG_DRAW },
{ "pango", COGL_DEBUG_PANGO },
{ "rectangles", COGL_DEBUG_RECTANGLES },
{ "handle", COGL_DEBUG_HANDLE }
{ "handle", COGL_DEBUG_HANDLE },
{ "blend-strings", COGL_DEBUG_BLEND_STRINGS }
};
static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys);

View file

@ -0,0 +1,41 @@
/*** BEGIN file-header ***/
#include "cogl-enum-types.h"
#include "cogl.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
#include "@filename@"
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
{
static volatile gsize g_enum_type_id__volatile = 0;
if (g_once_init_enter (&g_enum_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_enum_type_id;
g_enum_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
}
return g_enum_type_id__volatile;
}
/*** END value-tail ***/

View file

@ -0,0 +1,25 @@
/*** BEGIN file-header ***/
#ifndef __COGL_ENUM_TYPES_H__
#define __COGL_ENUM_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* !__CLUTTER_ENUM_TYPES_H__ */
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define COGL_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/

View file

@ -82,7 +82,7 @@ typedef struct _CoglHandleObject
static CoglHandleClass _cogl_##type_name##_class; \
\
static GQuark \
_cogl_##type_name##_get_type (void) \
_cogl_handle_##type_name##_get_type (void) \
{ \
static GQuark type = 0; \
if (!type) \
@ -99,13 +99,13 @@ _cogl_##type_name##_handle_new (Cogl##TypeName *new_obj) \
obj->klass = &_cogl_##type_name##_class; \
if (!obj->klass->type) \
{ \
obj->klass->type = _cogl_##type_name##_get_type (); \
obj->klass->virt_free = _cogl_##type_name##_free; \
} \
obj->klass->type = _cogl_handle_##type_name##_get_type ();\
obj->klass->virt_free = _cogl_##type_name##_free; \
} \
\
_COGL_HANDLE_DEBUG_NEW (TypeName, obj); \
return (CoglHandle) new_obj; \
} \
_COGL_HANDLE_DEBUG_NEW (TypeName, obj); \
return (CoglHandle) new_obj; \
} \
\
Cogl##TypeName * \
_cogl_##type_name##_pointer_from_handle (CoglHandle handle) \
@ -121,7 +121,8 @@ cogl_is_##type_name (CoglHandle handle) \
if (handle == COGL_INVALID_HANDLE) \
return FALSE; \
\
return (obj->klass->type == _cogl_##type_name##_get_type ()); \
return (obj->klass->type == \
_cogl_handle_##type_name##_get_type ()); \
} \
\
CoglHandle G_GNUC_DEPRECATED \

View file

@ -68,15 +68,20 @@ struct _CoglMaterialLayer
CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE
for an empty layer */
CoglMaterialFilter mag_filter;
CoglMaterialFilter min_filter;
/* Determines how the color of individual texture fragments
* are calculated. */
CoglMaterialLayerCombineFunc texture_combine_rgb_func;
CoglMaterialLayerCombineSrc texture_combine_rgb_src[3];
CoglMaterialLayerCombineOp texture_combine_rgb_op[3];
GLint texture_combine_rgb_func;
GLint texture_combine_rgb_src[3];
GLint texture_combine_rgb_op[3];
CoglMaterialLayerCombineFunc texture_combine_alpha_func;
CoglMaterialLayerCombineSrc texture_combine_alpha_src[3];
CoglMaterialLayerCombineOp texture_combine_alpha_op[3];
GLint texture_combine_alpha_func;
GLint texture_combine_alpha_src[3];
GLint texture_combine_alpha_op[3];
GLfloat texture_combine_constant[4];
/* TODO: Support purely GLSL based material layers */
@ -114,11 +119,104 @@ struct _CoglMaterial
GLfloat alpha_func_reference;
/* Determines how this material is blended with other primitives */
CoglMaterialBlendFactor blend_src_factor;
CoglMaterialBlendFactor blend_dst_factor;
#ifndef HAVE_COGL_GLES
GLenum blend_equation_rgb;
GLenum blend_equation_alpha;
GLint blend_src_factor_alpha;
GLint blend_dst_factor_alpha;
GLfloat blend_constant[4];
#endif
GLint blend_src_factor_rgb;
GLint blend_dst_factor_rgb;
GList *layers;
};
/*
* SECTION:cogl-material-internals
* @short_description: Functions for creating custom primitives that make use
* of Cogl materials for filling.
*
* Normally you shouldn't need to use this API directly, but if you need to
* developing a custom/specialised primitive - probably using raw OpenGL - then
* this API aims to expose enough of the material internals to support being
* able to fill your geometry according to a given Cogl material.
*/
/*
* cogl_material_get_cogl_enable_flags:
* @material: A CoglMaterial object
*
* This determines what flags need to be passed to cogl_enable before this
* material can be used. Normally you shouldn't need to use this function
* directly since Cogl will do this internally, but if you are developing
* custom primitives directly with OpenGL you may want to use this.
*
* Note: This API is hopfully just a stop-gap solution. Ideally cogl_enable
* will be replaced.
*/
/* TODO: find a nicer solution! */
gulong _cogl_material_get_cogl_enable_flags (CoglHandle handle);
/*
* CoglMaterialLayerFlags:
* @COGL_MATERIAL_LAYER_FLAG_USER_MATRIX: Means the user has supplied a
* custom texture matrix.
*/
typedef enum _CoglMaterialLayerFlags
{
COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX = 1L<<0
} CoglMaterialLayerFlags;
/* XXX: NB: if you add flags here you will need to update
* CoglMaterialLayerPrivFlags!!! */
/*
* cogl_material_layer_get_flags:
* @layer_handle: A CoglMaterialLayer layer handle
*
* This lets you get a number of flag attributes about the layer. Normally
* you shouldn't need to use this function directly since Cogl will do this
* internally, but if you are developing custom primitives directly with
* OpenGL you may need this.
*/
gulong _cogl_material_layer_get_flags (CoglHandle layer_handle);
/*
* CoglMaterialFlushOption:
* @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask
* of the layers that can't be supported with the user supplied texture
* and need to be replaced with fallback textures. (1 = fallback, and the
* least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask
* of the layers that you want to completly disable texturing for
* (1 = fallback, and the least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture
* name to override the texture used for layer 0 of the material. This is
* intended for dealing with sliced textures where you will need to point
* to each of the texture slices in turn when drawing your geometry.
* Passing a value of 0 is the same as not passing the option at all.
*/
typedef enum _CoglMaterialFlushOption
{
COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
} CoglMaterialFlushOption;
/*
* cogl_material_flush_gl_state:
* @material: A CoglMaterial object
* @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs
*
* This function commits the state of the specified CoglMaterial - including
* the texture state for all the layers - to the OpenGL[ES] driver.
*
* Since 1.0
*/
void _cogl_material_flush_gl_state (CoglHandle material,
...) G_GNUC_NULL_TERMINATED;
#endif /* __COGL_MATERIAL_PRIVATE_H */

View file

@ -35,6 +35,7 @@
#include "cogl-material-private.h"
#include "cogl-texture-private.h"
#include "cogl-blend-string.h"
#include <glib.h>
#include <string.h>
@ -50,6 +51,10 @@
#ifdef HAVE_COGL_GL
#define glActiveTexture ctx->pf_glActiveTexture
#define glClientActiveTexture ctx->pf_glClientActiveTexture
#define glBlendFuncSeparate ctx->pf_glBlendFuncSeparate
#define glBlendEquation ctx->pf_glBlendEquation
#define glBlendColor ctx->pf_glBlendColor
#define glBlendEquationSeparate ctx->pf_glBlendEquationSeparate
#endif
static void _cogl_material_free (CoglMaterial *tex);
@ -60,6 +65,12 @@ COGL_HANDLE_DEFINE (MaterialLayer, material_layer);
/* #define DISABLE_MATERIAL_CACHE 1 */
GQuark
_cogl_material_error_quark (void)
{
return g_quark_from_static_string ("cogl-material-error-quark");
}
CoglHandle
cogl_material_new (void)
{
@ -88,8 +99,18 @@ cogl_material_new (void)
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC;
/* Not the same as the GL default, but seems saner... */
material->blend_src_factor = COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA;
material->blend_dst_factor = COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
#ifndef HAVE_COGL_GLES
material->blend_equation_rgb = GL_FUNC_ADD;
material->blend_equation_alpha = GL_FUNC_ADD;
material->blend_src_factor_alpha = GL_SRC_ALPHA;
material->blend_dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA;
material->blend_constant[0] = 0;
material->blend_constant[1] = 0;
material->blend_constant[2] = 0;
material->blend_constant[3] = 0;
#endif
material->blend_src_factor_rgb = GL_SRC_ALPHA;
material->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA;
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
material->layers = NULL;
@ -408,20 +429,177 @@ cogl_material_set_alpha_test_function (CoglHandle handle,
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC;
}
GLenum
arg_to_gl_blend_factor (CoglBlendStringArgument *arg)
{
if (arg->source.is_zero)
return GL_ZERO;
if (arg->factor.is_one)
return GL_ONE;
else if (arg->factor.is_src_alpha_saturate)
return GL_SRC_ALPHA_SATURATE;
else if (arg->factor.source.info->type ==
COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR)
{
if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_SRC_COLOR;
else
return GL_SRC_COLOR;
}
else
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_SRC_ALPHA;
else
return GL_SRC_ALPHA;
}
}
else if (arg->factor.source.info->type ==
COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR)
{
if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_DST_COLOR;
else
return GL_DST_COLOR;
}
else
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_DST_ALPHA;
else
return GL_DST_ALPHA;
}
}
#ifndef HAVE_COGL_GLES
else if (arg->factor.source.info->type ==
COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT)
{
if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_CONSTANT_COLOR;
else
return GL_CONSTANT_COLOR;
}
else
{
if (arg->factor.source.one_minus)
return GL_ONE_MINUS_CONSTANT_ALPHA;
else
return GL_CONSTANT_ALPHA;
}
}
#endif
g_warning ("Unable to determine valid blend factor from blend string\n");
return GL_ONE;
}
void
cogl_material_set_blend_factors (CoglHandle handle,
CoglMaterialBlendFactor src_factor,
CoglMaterialBlendFactor dst_factor)
setup_blend_state (CoglBlendStringStatement *statement,
GLenum *blend_equation,
GLint *blend_src_factor,
GLint *blend_dst_factor)
{
#ifndef HAVE_COGL_GLES
switch (statement->function->type)
{
case COGL_BLEND_STRING_FUNCTION_ADD:
*blend_equation = GL_FUNC_ADD;
break;
/* TODO - add more */
default:
g_warning ("Unsupported blend function given");
*blend_equation = GL_FUNC_ADD;
}
#endif
*blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]);
*blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]);
}
gboolean
cogl_material_set_blend (CoglHandle handle,
const char *blend_description,
GError **error)
{
CoglMaterial *material;
CoglBlendStringStatement statements[2];
CoglBlendStringStatement split[2];
CoglBlendStringStatement *rgb;
CoglBlendStringStatement *a;
int count;
g_return_val_if_fail (cogl_is_material (handle), FALSE);
material = _cogl_material_pointer_from_handle (handle);
count =
_cogl_blend_string_compile (blend_description,
COGL_BLEND_STRING_CONTEXT_BLENDING,
statements,
error);
if (!count)
return FALSE;
if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
{
_cogl_blend_string_split_rgba_statement (statements,
&split[0], &split[1]);
rgb = &split[0];
a = &split[1];
}
else
{
rgb = &statements[0];
a = &statements[1];
}
#ifndef HAVE_COGL_GLES
setup_blend_state (rgb,
&material->blend_equation_rgb,
&material->blend_src_factor_rgb,
&material->blend_dst_factor_rgb);
setup_blend_state (a,
&material->blend_equation_alpha,
&material->blend_src_factor_alpha,
&material->blend_dst_factor_alpha);
#else
setup_blend_state (rgb,
NULL,
&material->blend_src_factor_rgb,
&material->blend_dst_factor_rgb);
#endif
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
return TRUE;
}
void
cogl_material_set_blend_constant (CoglHandle handle,
CoglColor *constant_color)
{
#ifndef HAVE_COGL_GLES
CoglMaterial *material;
GLfloat *constant;
g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle);
material->blend_src_factor = src_factor;
material->blend_dst_factor = dst_factor;
constant = material->blend_constant;
constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color);
constant[2] = cogl_color_get_blue_float (constant_color);
constant[3] = cogl_color_get_alpha_float (constant_color);
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
#endif
}
/* Asserts that a layer corresponding to the given index exists. If no
@ -459,25 +637,22 @@ _cogl_material_get_layer (CoglMaterial *material,
layer_handle = _cogl_material_layer_handle_new (layer);
layer->index = index_;
layer->flags = COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE;
layer->mag_filter = COGL_MATERIAL_FILTER_LINEAR;
layer->min_filter = COGL_MATERIAL_FILTER_LINEAR;
layer->texture = COGL_INVALID_HANDLE;
/* Choose the same default combine mode as OpenGL:
* MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */
layer->texture_combine_rgb_func = COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE;
layer->texture_combine_rgb_src[0] = COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS;
layer->texture_combine_rgb_src[1] = COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE;
layer->texture_combine_rgb_op[0] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR;
layer->texture_combine_rgb_op[1] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR;
layer->texture_combine_alpha_func =
COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE;
layer->texture_combine_alpha_src[0] =
COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS;
layer->texture_combine_alpha_src[1] =
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE;
layer->texture_combine_alpha_op[0] =
COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA;
layer->texture_combine_alpha_op[1] =
COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA;
layer->texture_combine_rgb_func = GL_MODULATE;
layer->texture_combine_rgb_src[0] = GL_PREVIOUS;
layer->texture_combine_rgb_src[1] = GL_TEXTURE;
layer->texture_combine_rgb_op[0] = GL_SRC_COLOR;
layer->texture_combine_rgb_op[1] = GL_SRC_COLOR;
layer->texture_combine_alpha_func = GL_MODULATE;
layer->texture_combine_alpha_src[0] = GL_PREVIOUS;
layer->texture_combine_alpha_src[1] = GL_TEXTURE;
layer->texture_combine_alpha_op[0] = GL_SRC_ALPHA;
layer->texture_combine_alpha_op[1] = GL_SRC_ALPHA;
cogl_matrix_init_identity (&layer->matrix);
@ -498,7 +673,8 @@ cogl_material_set_layer (CoglHandle material_handle,
int n_layers;
g_return_if_fail (cogl_is_material (material_handle));
g_return_if_fail (cogl_is_texture (texture_handle));
g_return_if_fail (texture_handle == COGL_INVALID_HANDLE
|| cogl_is_texture (texture_handle));
material = _cogl_material_pointer_from_handle (material_handle);
layer = _cogl_material_get_layer (material_handle, layer_index, TRUE);
@ -519,7 +695,8 @@ cogl_material_set_layer (CoglHandle material_handle,
* MAX_COMBINED_TEXTURE_IMAGE_UNITS layers. */
}
cogl_handle_ref (texture_handle);
if (texture_handle)
cogl_handle_ref (texture_handle);
if (layer->texture)
cogl_handle_unref (layer->texture);
@ -530,104 +707,164 @@ cogl_material_set_layer (CoglHandle material_handle,
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
}
void
cogl_material_set_layer_combine_function (
CoglHandle handle,
gint layer_index,
CoglMaterialLayerCombineChannels channels,
CoglMaterialLayerCombineFunc func)
static void
setup_texture_combine_state (CoglBlendStringStatement *statement,
GLint *texture_combine_func,
GLint *texture_combine_src,
GLint *texture_combine_op)
{
int i;
switch (statement->function->type)
{
case COGL_BLEND_STRING_FUNCTION_AUTO_COMPOSITE:
*texture_combine_func = GL_MODULATE; /* FIXME */
break;
case COGL_BLEND_STRING_FUNCTION_REPLACE:
*texture_combine_func = GL_REPLACE;
break;
case COGL_BLEND_STRING_FUNCTION_MODULATE:
*texture_combine_func = GL_MODULATE;
break;
case COGL_BLEND_STRING_FUNCTION_ADD:
*texture_combine_func = GL_ADD;
break;
case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED:
*texture_combine_func = GL_ADD_SIGNED;
break;
case COGL_BLEND_STRING_FUNCTION_INTERPOLATE:
*texture_combine_func = GL_INTERPOLATE;
break;
case COGL_BLEND_STRING_FUNCTION_SUBTRACT:
*texture_combine_func = GL_SUBTRACT;
break;
case COGL_BLEND_STRING_FUNCTION_DOT3_RGB:
*texture_combine_func = GL_DOT3_RGB;
break;
case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA:
*texture_combine_func = GL_DOT3_RGBA;
break;
}
for (i = 0; i < statement->function->argc; i++)
{
CoglBlendStringArgument *arg = &statement->args[i];
switch (arg->source.info->type)
{
case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT:
texture_combine_src[i] = GL_CONSTANT;
break;
case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE:
texture_combine_src[i] = GL_TEXTURE;
break;
case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N:
texture_combine_src[i] =
GL_TEXTURE0 + arg->source.texture;
break;
case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY:
texture_combine_src[i] = GL_PRIMARY_COLOR;
break;
case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS:
texture_combine_src[i] = GL_PREVIOUS;
break;
default:
g_warning ("Unexpected texture combine source");
texture_combine_src[i] = GL_TEXTURE;
}
if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
{
if (statement->args[i].source.one_minus)
texture_combine_op[i] = GL_ONE_MINUS_SRC_COLOR;
else
texture_combine_op[i] = GL_SRC_COLOR;
}
else
{
if (statement->args[i].source.one_minus)
texture_combine_op[i] = GL_ONE_MINUS_SRC_ALPHA;
else
texture_combine_op[i] = GL_SRC_ALPHA;
}
}
}
gboolean
cogl_material_set_layer_combine (CoglHandle handle,
gint layer_index,
const char *combine_description,
GError **error)
{
CoglMaterial *material;
CoglMaterialLayer *layer;
gboolean set_alpha_func = FALSE;
gboolean set_rgb_func = FALSE;
CoglBlendStringStatement statements[2];
CoglBlendStringStatement split[2];
CoglBlendStringStatement *rgb;
CoglBlendStringStatement *a;
int count;
g_return_val_if_fail (cogl_is_material (handle), FALSE);
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
count =
_cogl_blend_string_compile (combine_description,
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE,
statements,
error);
if (!count)
return FALSE;
if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
{
_cogl_blend_string_split_rgba_statement (statements,
&split[0], &split[1]);
rgb = &split[0];
a = &split[1];
}
else
{
rgb = &statements[0];
a = &statements[1];
}
setup_texture_combine_state (rgb,
&layer->texture_combine_rgb_func,
layer->texture_combine_rgb_src,
layer->texture_combine_rgb_op);
setup_texture_combine_state (a,
&layer->texture_combine_alpha_func,
layer->texture_combine_alpha_src,
layer->texture_combine_alpha_op);
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE;
return TRUE;
}
void
cogl_material_set_layer_combine_constant (CoglHandle handle,
gint layer_index,
CoglColor *constant_color)
{
CoglMaterial *material;
CoglMaterialLayer *layer;
GLfloat *constant;
g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA)
set_alpha_func = set_rgb_func = TRUE;
else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB)
set_rgb_func = TRUE;
else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA)
set_alpha_func = TRUE;
if (set_rgb_func)
layer->texture_combine_rgb_func = func;
if (set_alpha_func)
layer->texture_combine_alpha_func = func;
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE;
}
void
cogl_material_set_layer_combine_arg_src (
CoglHandle handle,
gint layer_index,
gint argument,
CoglMaterialLayerCombineChannels channels,
CoglMaterialLayerCombineSrc src)
{
CoglMaterial *material;
CoglMaterialLayer *layer;
gboolean set_arg_alpha_src = FALSE;
gboolean set_arg_rgb_src = FALSE;
g_return_if_fail (cogl_is_material (handle));
g_return_if_fail (argument >=0 && argument <= 3);
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA)
set_arg_alpha_src = set_arg_rgb_src = TRUE;
else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB)
set_arg_rgb_src = TRUE;
else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA)
set_arg_alpha_src = TRUE;
if (set_arg_rgb_src)
layer->texture_combine_rgb_src[argument] = src;
if (set_arg_alpha_src)
layer->texture_combine_alpha_src[argument] = src;
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE;
}
void
cogl_material_set_layer_combine_arg_op (
CoglHandle material_handle,
gint layer_index,
gint argument,
CoglMaterialLayerCombineChannels channels,
CoglMaterialLayerCombineOp op)
{
CoglMaterial *material;
CoglMaterialLayer *layer;
gboolean set_arg_alpha_op = FALSE;
gboolean set_arg_rgb_op = FALSE;
g_return_if_fail (cogl_is_material (material_handle));
g_return_if_fail (argument >=0 && argument <= 3);
material = _cogl_material_pointer_from_handle (material_handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA)
set_arg_alpha_op = set_arg_rgb_op = TRUE;
else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB)
set_arg_rgb_op = TRUE;
else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA)
set_arg_alpha_op = TRUE;
if (set_arg_rgb_op)
layer->texture_combine_rgb_op[argument] = op;
if (set_arg_alpha_op)
layer->texture_combine_alpha_op[argument] = op;
constant = layer->texture_combine_constant;
constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color);
constant[2] = cogl_color_get_blue_float (constant_color);
constant[3] = cogl_color_get_alpha_float (constant_color);
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE;
@ -690,7 +927,7 @@ cogl_material_remove_layer (CoglHandle material_handle,
/* XXX: This API is hopfully just a stop-gap solution. Ideally cogl_enable
* will be replaced. */
gulong
cogl_material_get_cogl_enable_flags (CoglHandle material_handle)
_cogl_material_get_cogl_enable_flags (CoglHandle material_handle)
{
CoglMaterial *material;
gulong enable_flags = 0;
@ -713,7 +950,7 @@ cogl_material_get_cogl_enable_flags (CoglHandle material_handle)
* probably sensible to try and avoid list manipulation for every
* primitive emitted in a scene, every frame.
*
* Alternativly; we could either add a _foreach function, or maybe
* Alternatively; we could either add a _foreach function, or maybe
* a function that gets a passed a buffer (that may be stack allocated)
* by the caller.
*/
@ -748,7 +985,7 @@ cogl_material_layer_get_texture (CoglHandle layer_handle)
}
gulong
cogl_material_layer_get_flags (CoglHandle layer_handle)
_cogl_material_layer_get_flags (CoglHandle layer_handle)
{
CoglMaterialLayer *layer;
@ -760,25 +997,34 @@ cogl_material_layer_get_flags (CoglHandle layer_handle)
}
static guint
get_n_args_for_combine_func (CoglMaterialLayerCombineFunc func)
get_n_args_for_combine_func (GLint func)
{
switch (func)
{
case COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE:
case GL_REPLACE:
return 1;
case COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE:
case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD:
case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED:
case COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT:
case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB:
case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA:
case GL_MODULATE:
case GL_ADD:
case GL_ADD_SIGNED:
case GL_SUBTRACT:
case GL_DOT3_RGB:
case GL_DOT3_RGBA:
return 2;
case COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE:
case GL_INTERPOLATE:
return 3;
}
return 0;
}
static gboolean
is_mipmap_filter (CoglMaterialFilter filter)
{
return (filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST
|| filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST
|| filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR
|| filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR);
}
static void
_cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer,
CoglLayerInfo *gl_layer_info)
@ -851,6 +1097,9 @@ _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer,
GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
layer->texture_combine_alpha_op[2]));
}
GE (glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
layer->texture_combine_constant));
}
#ifndef DISABLE_MATERIAL_CACHE
@ -976,6 +1225,13 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
GE (glActiveTexture (GL_TEXTURE0 + i));
_cogl_texture_set_filters (layer->texture,
layer->min_filter,
layer->mag_filter);
if (is_mipmap_filter (layer->min_filter)
|| is_mipmap_filter (layer->mag_filter))
_cogl_texture_ensure_mipmaps (layer->texture);
/* FIXME: We could be more clever here and only bind the texture
if it is different from gl_layer_info->gl_texture to avoid
redundant GL calls. However a few other places in Cogl and
@ -1122,12 +1378,44 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material)
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC
&& material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC))
{
GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor));
#if defined (HAVE_COGL_GLES2)
gboolean have_blend_equation_seperate = TRUE;
#elif defined (HAVE_COGL_GL)
gboolean have_blend_equation_seperate = FALSE;
if (ctx->pf_glBlendEquationSeparate) /* Only GL 2.0 + */
have_blend_equation_seperate = TRUE;
#endif
#ifndef HAVE_COGL_GLES /* GLES 1 only has glBlendFunc */
if (material->blend_src_factor_rgb != material->blend_src_factor_alpha
|| (material->blend_src_factor_rgb !=
material->blend_src_factor_alpha))
{
if (have_blend_equation_seperate &&
material->blend_equation_rgb != material->blend_equation_alpha)
GE (glBlendEquationSeparate (material->blend_equation_rgb,
material->blend_equation_alpha));
else
GE (glBlendEquation (material->blend_equation_rgb));
GE (glBlendFuncSeparate (material->blend_src_factor_rgb,
material->blend_dst_factor_rgb,
material->blend_src_factor_alpha,
material->blend_dst_factor_alpha));
GE (glBlendColor (material->blend_constant[0],
material->blend_constant[1],
material->blend_constant[2],
material->blend_constant[3]));
}
else
#endif
GE (glBlendFunc (material->blend_src_factor_rgb,
material->blend_dst_factor_rgb));
}
}
void
cogl_material_flush_gl_state (CoglHandle handle, ...)
_cogl_material_flush_gl_state (CoglHandle handle, ...)
{
CoglMaterial *material;
va_list ap;
@ -1204,3 +1492,44 @@ cogl_set_source_texture (CoglHandle texture_handle)
cogl_set_source (ctx->default_material);
}
CoglMaterialFilter
cogl_material_layer_get_min_filter (CoglHandle layer_handle)
{
CoglMaterialLayer *layer;
g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0);
layer = _cogl_material_layer_pointer_from_handle (layer_handle);
return layer->min_filter;
}
CoglMaterialFilter
cogl_material_layer_get_mag_filter (CoglHandle layer_handle)
{
CoglMaterialLayer *layer;
g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0);
layer = _cogl_material_layer_pointer_from_handle (layer_handle);
return layer->mag_filter;
}
void
cogl_material_set_layer_filters (CoglHandle handle,
gint layer_index,
CoglMaterialFilter min_filter,
CoglMaterialFilter mag_filter)
{
CoglMaterial *material;
CoglMaterialLayer *layer;
g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
layer->min_filter = min_filter;
layer->mag_filter = mag_filter;
}

View file

@ -257,6 +257,59 @@ _cogl_matrix_stack_multiply (CoglMatrixStack *stack,
stack->flushed_state = NULL;
}
void
_cogl_matrix_stack_frustum (CoglMatrixStack *stack,
float left,
float right,
float bottom,
float top,
float z_near,
float z_far)
{
CoglMatrixState *state;
state = _cogl_matrix_stack_top_mutable (stack);
cogl_matrix_frustum (&state->matrix,
left, right, bottom, top,
z_near, z_far);
/* mark dirty */
stack->flushed_state = NULL;
}
void
_cogl_matrix_stack_perspective (CoglMatrixStack *stack,
float fov_y,
float aspect,
float z_near,
float z_far)
{
CoglMatrixState *state;
state = _cogl_matrix_stack_top_mutable (stack);
cogl_matrix_perspective (&state->matrix,
fov_y, aspect, z_near, z_far);
/* mark dirty */
stack->flushed_state = NULL;
}
void
_cogl_matrix_stack_ortho (CoglMatrixStack *stack,
float left,
float right,
float bottom,
float top,
float z_near,
float z_far)
{
CoglMatrixState *state;
state = _cogl_matrix_stack_top_mutable (stack);
cogl_matrix_ortho (&state->matrix,
left, right, bottom, top, z_near, z_far);
/* mark dirty */
stack->flushed_state = NULL;
}
void
_cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix)
@ -280,25 +333,6 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack,
stack->flushed_state = NULL;
}
void
_cogl_matrix_stack_frustum (CoglMatrixStack *stack,
float left,
float right,
float bottom,
float top,
float z_near,
float z_far)
{
CoglMatrixState *state;
state = _cogl_matrix_stack_top_mutable (stack);
cogl_matrix_frustum (&state->matrix,
left, right, bottom, top,
z_near, z_far);
/* mark dirty */
stack->flushed_state = NULL;
}
void
_cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack,
GLenum gl_mode)

View file

@ -51,10 +51,6 @@ void _cogl_matrix_stack_rotate (CoglMatrixStack *stack,
float z);
void _cogl_matrix_stack_multiply (CoglMatrixStack *stack,
const CoglMatrix *matrix);
void _cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix);
void _cogl_matrix_stack_set (CoglMatrixStack *stack,
const CoglMatrix *matrix);
void _cogl_matrix_stack_frustum (CoglMatrixStack *stack,
float left,
float right,
@ -62,6 +58,22 @@ void _cogl_matrix_stack_frustum (CoglMatrixStack *stack,
float top,
float z_near,
float z_far);
void _cogl_matrix_stack_perspective (CoglMatrixStack *stack,
float fov_y,
float aspect,
float z_near,
float z_far);
void _cogl_matrix_stack_ortho (CoglMatrixStack *stack,
float left,
float right,
float bottom,
float top,
float z_near,
float z_far);
void _cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix);
void _cogl_matrix_stack_set (CoglMatrixStack *stack,
const CoglMatrix *matrix);
void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack,
GLenum gl_mode);

View file

@ -151,21 +151,6 @@ cogl_matrix_invert (CoglMatrix *matrix)
}
#endif
void
cogl_matrix_transform_point (const CoglMatrix *matrix,
float *x,
float *y,
float *z,
float *w)
{
float _x = *x, _y = *y, _z = *z, _w = *w;
*x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w;
*y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w;
*z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w;
*w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w;
}
void
cogl_matrix_frustum (CoglMatrix *matrix,
float left,
@ -208,6 +193,62 @@ cogl_matrix_frustum (CoglMatrix *matrix,
cogl_matrix_multiply (matrix, matrix, &frustum);
}
void
cogl_matrix_perspective (CoglMatrix *matrix,
float fov_y,
float aspect,
float z_near,
float z_far)
{
float ymax = z_near * tan (fov_y * G_PI / 360.0);
cogl_matrix_frustum (matrix,
-ymax * aspect, /* left */
ymax * aspect, /* right */
-ymax, /* bottom */
ymax, /* top */
z_near,
z_far);
}
void
cogl_matrix_ortho (CoglMatrix *matrix,
float left,
float right,
float bottom,
float top,
float near,
float far)
{
CoglMatrix ortho;
/* column 0 */
ortho.xx = 2.0 / (right - left);
ortho.yx = 0.0;
ortho.zx = 0.0;
ortho.wx = 0.0;
/* column 1 */
ortho.xy = 0.0;
ortho.yy = 2.0 / (top - bottom);
ortho.zy = 0.0;
ortho.wy = 0.0;
/* column 2 */
ortho.xz = 0.0;
ortho.yz = 0.0;
ortho.zz = -2.0 / (far - near);
ortho.wz = 0.0;
/* column 3 */
ortho.xw = -(right + left) / (right - left);
ortho.yw = -(top + bottom) / (top - bottom);
ortho.zw = -(far + near) / (far - near);
ortho.ww = 1.0;
cogl_matrix_multiply (matrix, matrix, &ortho);
}
void
cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
{
@ -220,3 +261,19 @@ cogl_matrix_get_array (const CoglMatrix *matrix)
return (float *)matrix;
}
void
cogl_matrix_transform_point (const CoglMatrix *matrix,
float *x,
float *y,
float *z,
float *w)
{
float _x = *x, _y = *y, _z = *z, _w = *w;
*x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w;
*y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w;
*z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w;
*w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w;
}

View file

@ -29,7 +29,8 @@
#include "cogl-internal.h"
#include "cogl-context.h"
#include "cogl-texture-private.h"
#include "cogl-material.h"
#include "cogl-material-private.h"
#include "cogl-vertex-buffer-private.h"
#include <string.h>
#include <gmodule.h>
@ -39,16 +40,8 @@
#ifdef HAVE_COGL_GL
#define glDrawRangeElements ctx->pf_glDrawRangeElements
#define glClientActiveTexture ctx->pf_glClientActiveTexture
#else
/* GLES doesn't have glDrawRangeElements, so we simply pretend it does
* but that it makes no use of the start, end constraints: */
#define glDrawRangeElements(mode, start, end, count, type, indices) \
glDrawElements (mode, count, type, indices)
#endif
/* these are defined in the particular backend */
@ -63,7 +56,6 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
gint batch_len,
GLfloat *vertex_pointer)
{
int needed_indices;
gsize stride;
int i;
gulong enable_flags = 0;
@ -72,35 +64,6 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* The indices are always the same sequence regardless of the vertices so we
* only need to change it if there are more vertices than ever before. */
needed_indices = batch_len * 6;
if (needed_indices > ctx->static_indices->len)
{
int old_len = ctx->static_indices->len;
int vert_num = old_len / 6 * 4;
GLushort *q;
/* Add two triangles for each quad to the list of
indices. That makes six new indices but two of the
vertices in the triangles are shared. */
g_array_set_size (ctx->static_indices, needed_indices);
q = &g_array_index (ctx->static_indices, GLushort, old_len);
for (i = old_len;
i < ctx->static_indices->len;
i += 6, vert_num += 4)
{
*(q++) = vert_num + 0;
*(q++) = vert_num + 1;
*(q++) = vert_num + 3;
*(q++) = vert_num + 1;
*(q++) = vert_num + 2;
*(q++) = vert_num + 3;
}
}
/* XXX NB:
* Our vertex data is arranged as follows:
* 4 vertices per quad: 2 GLfloats per position,
@ -112,16 +75,16 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
disable_mask = (1 << batch_start->n_layers) - 1;
disable_mask = ~disable_mask;
cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_FALLBACK_MASK,
batch_start->fallback_mask,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
disable_mask,
/* Redundant when dealing with unsliced
* textures but does no harm... */
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
batch_start->layer0_override_texture,
NULL);
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_FALLBACK_MASK,
batch_start->fallback_mask,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
disable_mask,
/* Redundant when dealing with unsliced
* textures but does no harm... */
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
batch_start->layer0_override_texture,
NULL);
for (i = 0; i < batch_start->n_layers; i++)
{
@ -140,7 +103,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
/* FIXME: This api is a bit yukky, ideally it will be removed if we
* re-work the cogl_enable mechanism */
enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
@ -150,12 +113,32 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer));
_cogl_current_matrix_state_flush ();
GE (glDrawRangeElements (GL_TRIANGLES,
0, ctx->static_indices->len - 1,
6 * batch_len,
GL_UNSIGNED_SHORT,
ctx->static_indices->data));
#ifdef HAVE_COGL_GL
GE( glDrawArrays (GL_QUADS, 0, batch_len * 4) );
#else /* HAVE_COGL_GL */
/* GLES doesn't support GL_QUADS so we will use GL_TRIANGLES and
indices */
{
int needed_indices = batch_len * 6;
CoglHandle indices_handle
= cogl_vertex_buffer_indices_get_for_quads (needed_indices);
CoglVertexBufferIndices *indices
= _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
GPOINTER_TO_UINT (indices->vbo_name)));
GE (glDrawElements (GL_TRIANGLES,
6 * batch_len,
indices->type,
NULL));
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
}
#endif /* HAVE_COGL_GL */
/* DEBUGGING CODE XXX:
* This path will cause all rectangles to be drawn with a red, green
@ -177,7 +160,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
color == 1 ? 0xff : 0x00,
color == 2 ? 0xff : 0x00,
0xff);
cogl_material_flush_gl_state (outline, NULL);
_cogl_material_flush_gl_state (outline, NULL);
_cogl_current_matrix_state_flush ();
GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) );
}
@ -791,7 +774,7 @@ _cogl_rectangles_with_multitexture_coords (
/* We don't support multi texturing using textures with any waste if the
* user has supplied a custom texture matrix, since we don't know if
* the result will end up trying to texture from the waste area. */
flags = cogl_material_layer_get_flags (layer);
flags = _cogl_material_layer_get_flags (layer);
if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX
&& _cogl_texture_span_has_waste (texture, 0, 0))
{
@ -1041,13 +1024,13 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
v += stride;
}
cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
(guint32)~1, /* disable all except the
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
(guint32)~1, /* disable all except the
first layer */
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
gl_handle,
NULL);
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
gl_handle,
NULL);
_cogl_current_matrix_state_flush ();
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
@ -1136,10 +1119,10 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
c[3] = cogl_color_get_alpha_float (&vertices[i].color);
}
cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_FALLBACK_MASK,
fallback_mask,
NULL);
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_FALLBACK_MASK,
fallback_mask,
NULL);
_cogl_current_matrix_state_flush ();
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
@ -1175,7 +1158,6 @@ cogl_polygon (CoglTextureVertex *vertices,
{
CoglHandle layer = (CoglHandle)tmp->data;
CoglHandle tex_handle = cogl_material_layer_get_texture (layer);
CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle);
if (i == 0 && cogl_texture_is_sliced (tex_handle))
{
@ -1203,7 +1185,8 @@ cogl_polygon (CoglTextureVertex *vertices,
use_sliced_polygon_fallback = TRUE;
n_layers = 1;
if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST)
if (cogl_material_layer_get_min_filter (layer) != GL_NEAREST
|| cogl_material_layer_get_mag_filter (layer) != GL_NEAREST)
{
static gboolean warning_seen = FALSE;
if (!warning_seen)
@ -1217,11 +1200,14 @@ cogl_polygon (CoglTextureVertex *vertices,
}
#ifdef HAVE_COGL_GL
/* Temporarily change the wrapping mode on all of the slices to use
* a transparent border
* XXX: it's doesn't look like we save/restore this, like the comment
* implies? */
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER);
{
CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle);
/* Temporarily change the wrapping mode on all of the slices to use
* a transparent border
* XXX: it's doesn't look like we save/restore this, like
* the comment implies? */
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER);
}
#endif
break;
}
@ -1254,7 +1240,7 @@ cogl_polygon (CoglTextureVertex *vertices,
/* Prepare GL state */
enable_flags = COGL_ENABLE_VERTEX_ARRAY;
enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;

View file

@ -103,159 +103,6 @@ cogl_handle_get_type (void)
return our_type;
}
GType
cogl_pixel_format_get_type (void)
{
static GType gtype = 0;
if (G_UNLIKELY (gtype == 0))
{
static const GEnumValue values[] = {
{ COGL_PIXEL_FORMAT_ANY, "COGL_PIXEL_FORMAT_ANY", "any" },
{ COGL_PIXEL_FORMAT_A_8, "COGL_PIXEL_FORMAT_A_8", "a-8" },
{ COGL_PIXEL_FORMAT_RGB_565, "COGL_PIXEL_FORMAT_RGB_565", "rgb-565" },
{ COGL_PIXEL_FORMAT_RGBA_4444, "COGL_PIXEL_FORMAT_RGBA_4444", "rgba-4444" },
{ COGL_PIXEL_FORMAT_RGBA_5551, "COGL_PIXEL_FORMAT_RGBA_5551", "rgba-5551" },
{ COGL_PIXEL_FORMAT_YUV, "COGL_PIXEL_FORMAT_YUV", "yuv" },
{ COGL_PIXEL_FORMAT_G_8, "COGL_PIXEL_FORMAT_G_8", "g-8" },
{ COGL_PIXEL_FORMAT_RGB_888, "COGL_PIXEL_FORMAT_RGB_888", "rgb-888" },
{ COGL_PIXEL_FORMAT_BGR_888, "COGL_PIXEL_FORMAT_BGR_888", "bgr-888" },
{ COGL_PIXEL_FORMAT_RGBA_8888, "COGL_PIXEL_FORMAT_RGBA_8888", "rgba-8888" },
{ COGL_PIXEL_FORMAT_BGRA_8888, "COGL_PIXEL_FORMAT_BGRA_8888", "bgra-8888" },
{ COGL_PIXEL_FORMAT_ARGB_8888, "COGL_PIXEL_FORMAT_ARGB_8888", "argb-8888" },
{ COGL_PIXEL_FORMAT_ABGR_8888, "COGL_PIXEL_FORMAT_ABGR_8888", "abgr-8888" },
{ COGL_PIXEL_FORMAT_RGBA_8888_PRE, "COGL_PIXEL_FORMAT_RGBA_8888_PRE", "rgba-8888-pre" },
{ COGL_PIXEL_FORMAT_BGRA_8888_PRE, "COGL_PIXEL_FORMAT_BGRA_8888_PRE", "bgra-8888-pre" },
{ COGL_PIXEL_FORMAT_ARGB_8888_PRE, "COGL_PIXEL_FORMAT_ARGB_8888_PRE", "argb-8888-pre" },
{ COGL_PIXEL_FORMAT_ABGR_8888_PRE, "COGL_PIXEL_FORMAT_ABGR_8888_PRE", "abgr-8888-pre" },
{ COGL_PIXEL_FORMAT_RGBA_4444_PRE, "COGL_PIXEL_FORMAT_RGBA_4444_PRE", "rgba-4444-pre" },
{ COGL_PIXEL_FORMAT_RGBA_5551_PRE, "COGL_PIXEL_FORMAT_RGBA_5551_PRE", "rgba-5551-pre" },
{ 0, NULL, NULL }
};
gtype =
g_enum_register_static (g_intern_static_string ("CoglPixelFormat"),
values);
}
return gtype;
}
GType
cogl_feature_flags_get_type (void)
{
static GType gtype = 0;
if (G_UNLIKELY (gtype == 0))
{
static const GFlagsValue values[] = {
{ COGL_FEATURE_TEXTURE_RECTANGLE, "COGL_FEATURE_TEXTURE_RECTANGLE", "texture-rectangle" },
{ COGL_FEATURE_TEXTURE_NPOT, "COGL_FEATURE_TEXTURE_NPOT", "texture-npot" },
{ COGL_FEATURE_TEXTURE_YUV, "COGL_FEATURE_TEXTURE_YUV", "yuv" },
{ COGL_FEATURE_TEXTURE_READ_PIXELS, "COGL_FEATURE_TEXTURE_READ_PIXELS", "read-pixels" },
{ COGL_FEATURE_SHADERS_GLSL, "COGL_FEATURE_SHADERS_GLSL", "shaders-glsl" },
{ COGL_FEATURE_OFFSCREEN, "COGL_FEATURE_OFFSCREEN", "offscreen" },
{ COGL_FEATURE_OFFSCREEN_MULTISAMPLE, "COGL_FEATURE_OFFSCREEN_MULTISAMPLE", "offscreen-multisample" },
{ COGL_FEATURE_OFFSCREEN_BLIT, "COGL_FEATURE_OFFSCREEN_BLIT", "offscreen-blit" },
{ COGL_FEATURE_FOUR_CLIP_PLANES, "COGL_FEATURE_FOUR_CLIP_PLANES", "four-clip-planes" },
{ COGL_FEATURE_STENCIL_BUFFER, "COGL_FEATURE_STENCIL_BUFFER", "stencil-buffer" },
{ 0, NULL, NULL }
};
gtype =
g_flags_register_static (g_intern_static_string ("CoglFeatureFlags"),
values);
}
return gtype;
}
GType
cogl_buffer_target_get_type (void)
{
static GType gtype = 0;
if (G_UNLIKELY (gtype == 0))
{
static const GFlagsValue values[] = {
{ COGL_WINDOW_BUFFER, "COGL_WINDOW_BUFFER", "window-buffer" },
{ COGL_OFFSCREEN_BUFFER, "COGL_OFFSCREEN_BUFFER", "offscreen-buffer" },
{ 0, NULL, NULL }
};
gtype =
g_flags_register_static (g_intern_static_string ("CoglBufferTarget"),
values);
}
return gtype;
}
GType
cogl_matrix_mode_get_type (void)
{
static GType gtype = 0;
if (G_UNLIKELY (gtype == 0))
{
static const GEnumValue values[] = {
{ COGL_MATRIX_MODELVIEW, "COGL_MATRIX_MODELVIEW", "modelview" },
{ COGL_MATRIX_PROJECTION, "COGL_MATRIX_PROJECTION", "projection" },
{ COGL_MATRIX_TEXTURE, "COGL_MATRIX_TEXTURE", "texture" },
{ 0, NULL, NULL }
};
gtype =
g_enum_register_static (g_intern_static_string ("CoglMatrixMode"),
values);
}
return gtype;
}
GType
cogl_texture_flags_get_type (void)
{
static GType gtype = 0;
if (G_UNLIKELY (gtype == 0))
{
static const GFlagsValue values[] = {
{ COGL_TEXTURE_NONE, "COGL_TEXTURE_NONE", "none" },
{ COGL_TEXTURE_AUTO_MIPMAP, "COGL_TEXTURE_AUTO_MIPMAP", "auto-mipmap" },
{ 0, NULL, NULL }
};
gtype =
g_flags_register_static (g_intern_static_string ("CoglTextureFlags"),
values);
}
return gtype;
}
GType
cogl_fog_mode_get_type (void)
{
static GType gtype = 0;
if (G_UNLIKELY (gtype == 0))
{
static const GEnumValue values[] = {
{ COGL_FOG_MODE_LINEAR, "COGL_FOG_MODE_LINEAR", "linear" },
{ COGL_FOG_MODE_EXPONENTIAL, "COGL_FOG_MODE_EXPONENTIAL", "exponential" },
{ COGL_FOG_MODE_EXPONENTIAL_SQUARED, "COGL_FOG_MODE_EXPONENTIAL_SQUARED", "exponential-squared" },
{ 0, NULL, NULL }
};
gtype =
g_enum_register_static (g_intern_static_string ("CoglFogMode"),
values);
}
return gtype;
}
/*
* CoglFixed
*/

View file

@ -99,9 +99,9 @@ typedef struct _CoglVertexBufferAttrib
union _u
{
const void *pointer;
gsize vbo_offset;
size_t vbo_offset;
} u;
gsize span_bytes;
size_t span_bytes;
guint16 stride;
guint8 n_components;
guint8 texture_unit;
@ -129,25 +129,41 @@ typedef struct _CoglVertexBufferVBO
{
CoglVertexBufferVBOFlags flags;
/* Note: this is a pointer to handle fallbacks, and normally holds
* a GLuint value */
gpointer vbo_name; /*!< The name of the corresponding buffer object */
gsize vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
/* Note: this is a pointer to handle fallbacks. It normally holds
* a GLuint VBO name, but when the driver doesn't support VBOs then
* this simply points to an malloc'd buffer. */
void *vbo_name; /*!< The name of the corresponding buffer object */
size_t vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
GList *attributes;
} CoglVertexBufferVBO;
typedef struct _CoglVertexBufferIndices
{
CoglHandleObject _parent;
/* Note: this is a pointer to handle fallbacks. It normally holds
* a GLuint VBO name, but when the driver doesn't support VBOs then
* this simply points to an malloc'd buffer. */
void *vbo_name;
GLenum type;
} CoglVertexBufferIndices;
typedef struct _CoglVertexBuffer
{
CoglHandleObject _parent;
guint n_vertices; /*!< The number of vertices in the buffer */
GList *submitted_vbos; /* The VBOs currently submitted to the GPU */
int n_vertices; /*!< The number of vertices in the buffer */
GList *submitted_vbos; /* The VBOs currently submitted to the GPU */
/* Note: new_attributes is normally NULL and only valid while
* modifying a buffer. */
GList *new_attributes; /*!< attributes pending submission */
GList *new_attributes; /*!< attributes pending submission */
} CoglVertexBuffer;
CoglVertexBuffer *_cogl_vertex_buffer_pointer_from_handle (CoglHandle handle);
CoglVertexBufferIndices *
_cogl_vertex_buffer_indices_pointer_from_handle (CoglHandle handle);
#endif /* __COGL_VERTEX_BUFFER_H */

View file

@ -136,6 +136,7 @@
#include "cogl-handle.h"
#include "cogl-vertex-buffer-private.h"
#include "cogl-texture-private.h"
#include "cogl-material-private.h"
#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
(VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1)))
@ -200,8 +201,10 @@
#endif /* HAVE_COGL_GL */
static void _cogl_vertex_buffer_free (CoglVertexBuffer *buffer);
static void _cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices);
COGL_HANDLE_DEFINE (VertexBuffer, vertex_buffer);
COGL_HANDLE_DEFINE (VertexBufferIndices, vertex_buffer_indices);
CoglHandle
cogl_vertex_buffer_new (guint n_vertices)
@ -411,13 +414,13 @@ get_gl_type_size (CoglVertexBufferAttribFlags flags)
}
void
cogl_vertex_buffer_add (CoglHandle handle,
const char *attribute_name,
guint8 n_components,
GLenum gl_type,
gboolean normalized,
guint16 stride,
const void *pointer)
cogl_vertex_buffer_add (CoglHandle handle,
const char *attribute_name,
guint8 n_components,
CoglAttributeType type,
gboolean normalized,
guint16 stride,
const void *pointer)
{
CoglVertexBuffer *buffer;
GQuark name_quark = g_quark_from_string (attribute_name);
@ -485,7 +488,7 @@ cogl_vertex_buffer_add (CoglHandle handle,
attribute->u.pointer = pointer;
attribute->texture_unit = texture_unit;
flags |= get_attribute_gl_type_flag_from_gl_type (gl_type);
flags |= get_attribute_gl_type_flag_from_gl_type (type);
flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
/* Note: We currently just assume, if an attribute is *ever* updated
@ -1638,14 +1641,14 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
}
}
cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_FALLBACK_MASK,
fallback_mask,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
disable_mask,
NULL);
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_FALLBACK_MASK,
fallback_mask,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
disable_mask,
NULL);
enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
@ -1716,23 +1719,21 @@ disable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
}
void
cogl_vertex_buffer_draw (CoglHandle handle,
GLenum mode,
GLint first,
GLsizei count)
cogl_vertex_buffer_draw (CoglHandle handle,
CoglVerticesMode mode,
int first,
int count)
{
CoglVertexBuffer *buffer;
if (!cogl_is_vertex_buffer (handle))
return;
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
enable_state_for_drawing_buffer (buffer);
cogl_clip_ensure ();
_cogl_current_matrix_state_flush ();
enable_state_for_drawing_buffer (buffer);
/* FIXME: flush cogl cache */
GE (glDrawArrays (mode, first, count));
@ -1740,35 +1741,127 @@ cogl_vertex_buffer_draw (CoglHandle handle,
disable_state_for_drawing_buffer (buffer);
}
static int
get_indices_type_size (GLuint indices_type)
{
if (indices_type == GL_UNSIGNED_BYTE)
return sizeof (GLubyte);
if (indices_type == GL_UNSIGNED_SHORT)
return sizeof (GLushort);
else
{
g_critical ("Unknown indices type %d\n", indices_type);
return 0;
}
}
CoglHandle
cogl_vertex_buffer_indices_new (CoglIndicesType indices_type,
const void *indices_array,
int indices_len)
{
gboolean fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
size_t indices_bytes;
CoglVertexBufferIndices *indices;
_COGL_GET_CONTEXT (ctx, 0);
indices = g_slice_alloc (sizeof (CoglVertexBufferIndices));
if (indices_type == COGL_INDICES_TYPE_UNSIGNED_BYTE)
indices->type = GL_UNSIGNED_BYTE;
else if (indices_type == COGL_INDICES_TYPE_UNSIGNED_SHORT)
indices->type = GL_UNSIGNED_SHORT;
else
{
g_critical ("unknown indices type %d", indices_type);
g_slice_free (CoglVertexBufferIndices, indices);
return 0;
}
indices_bytes = get_indices_type_size (indices->type) * indices_len;
if (fallback)
{
indices->vbo_name = g_malloc (indices_len);
memcpy (indices->vbo_name, indices_array, indices_bytes);
}
else
{
GE (glGenBuffers (1, (GLuint *)&indices->vbo_name));
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
GPOINTER_TO_UINT (indices->vbo_name)));
GE (glBufferData (GL_ELEMENT_ARRAY_BUFFER,
indices_bytes,
indices_array,
GL_STATIC_DRAW));
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
}
return _cogl_vertex_buffer_indices_handle_new (indices);
}
void
cogl_vertex_buffer_draw_elements (CoglHandle handle,
GLenum mode,
GLuint min_index,
GLuint max_index,
GLsizei count,
GLenum indices_type,
const GLvoid *indices)
_cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *indices)
{
gboolean fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (fallback)
g_free (indices->vbo_name);
else
GE (glDeleteBuffers (1, (GLuint *)&indices->vbo_name));
g_slice_free (CoglVertexBufferIndices, indices);
}
void
cogl_vertex_buffer_draw_elements (CoglHandle handle,
CoglVerticesMode mode,
CoglHandle indices_handle,
int min_index,
int max_index,
int indices_offset,
int count)
{
CoglVertexBuffer *buffer;
gboolean fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
size_t byte_offset;
CoglVertexBufferIndices *indices = NULL;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_vertex_buffer (handle))
return;
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
if (!cogl_is_vertex_buffer_indices (indices_handle))
return;
indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
cogl_clip_ensure ();
_cogl_current_matrix_state_flush ();
enable_state_for_drawing_buffer (buffer);
_cogl_current_matrix_state_flush ();
byte_offset = indices_offset * get_indices_type_size (indices->type);
if (fallback)
byte_offset = (size_t)(((char *)indices->vbo_name) + byte_offset);
else
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
GPOINTER_TO_UINT (indices->vbo_name)));
/* FIXME: flush cogl cache */
GE (glDrawRangeElements (mode, min_index, max_index,
count, indices_type, indices));
count, indices->type, (void *)byte_offset));
disable_state_for_drawing_buffer (buffer);
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
}
static void
@ -1778,8 +1871,92 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer)
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
cogl_vertex_buffer_vbo_free (tmp->data, TRUE);
g_list_free (buffer->submitted_vbos);
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
cogl_vertex_buffer_attribute_free (tmp->data);
g_list_free (buffer->new_attributes);
g_slice_free (CoglVertexBuffer, buffer);
}
CoglHandle
cogl_vertex_buffer_indices_get_for_quads (guint n_indices)
{
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
/* Check if the indices would fit in a byte array */
if (n_indices <= 256 / 4 * 6)
{
/* Generate the byte array if we haven't already */
if (ctx->quad_indices_byte == COGL_INVALID_HANDLE)
{
guint8 *byte_array = g_malloc (256 / 4 * 6 * sizeof (guint8));
guint8 *p = byte_array;
int i, vert_num = 0;
for (i = 0; i < 256 / 4; i++)
{
*(p++) = vert_num + 0;
*(p++) = vert_num + 1;
*(p++) = vert_num + 2;
*(p++) = vert_num + 0;
*(p++) = vert_num + 2;
*(p++) = vert_num + 3;
vert_num += 4;
}
ctx->quad_indices_byte
= cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_BYTE,
byte_array,
256 / 4 * 6);
g_free (byte_array);
}
return ctx->quad_indices_byte;
}
else
{
if (ctx->quad_indices_short_len < n_indices)
{
guint16 *short_array;
guint16 *p;
int i, vert_num = 0;
if (ctx->quad_indices_short != COGL_INVALID_HANDLE)
cogl_handle_unref (ctx->quad_indices_short);
/* Pick a power of two >= MAX (512, n_indices) */
if (ctx->quad_indices_short_len == 0)
ctx->quad_indices_short_len = 512;
while (ctx->quad_indices_short_len < n_indices)
ctx->quad_indices_short_len *= 2;
/* Over-allocate to generate a whole number of quads */
p = short_array = g_malloc ((ctx->quad_indices_short_len
+ 5) / 6 * 6
* sizeof (guint16));
/* Fill in the complete quads */
for (i = 0; i < ctx->quad_indices_short_len; i += 6)
{
*(p++) = vert_num + 0;
*(p++) = vert_num + 1;
*(p++) = vert_num + 2;
*(p++) = vert_num + 0;
*(p++) = vert_num + 2;
*(p++) = vert_num + 3;
vert_num += 4;
}
ctx->quad_indices_short
= cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
short_array,
ctx->quad_indices_short_len);
g_free (short_array);
}
return ctx->quad_indices_short;
}
}

View file

@ -42,6 +42,7 @@ typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
#include "cogl-internal.h"
#include "cogl-util.h"
#include "cogl-context.h"
#include "cogl-material-private.h"
#if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES)
#include "cogl-gles2-wrapper.h"
@ -213,30 +214,39 @@ cogl_get_enable ()
}
void
cogl_enable_depth_test (gboolean setting)
cogl_set_depth_test_enabled (gboolean setting)
{
if (setting)
{
glEnable (GL_DEPTH_TEST);
glEnable (GL_ALPHA_TEST);
glDepthFunc (GL_LEQUAL);
glAlphaFunc (GL_GREATER, 0.1);
}
else
{
glDisable (GL_DEPTH_TEST);
glDisable (GL_ALPHA_TEST);
}
glDisable (GL_DEPTH_TEST);
}
gboolean
cogl_get_depth_test_enabled (void)
{
return glIsEnabled (GL_DEPTH_TEST) == GL_TRUE ? TRUE : FALSE;
}
void
cogl_enable_backface_culling (gboolean setting)
cogl_set_backface_culling_enabled (gboolean setting)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
ctx->enable_backface_culling = setting;
}
gboolean
cogl_get_backface_culling_enabled (void)
{
_COGL_GET_CONTEXT (ctx, FALSE);
return ctx->enable_backface_culling;
}
void
cogl_set_source_color (const CoglColor *color)
{
@ -375,7 +385,7 @@ _cogl_add_stencil_clip (float x_offset,
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_material_flush_gl_state (ctx->stencil_material, NULL);
_cogl_material_flush_gl_state (ctx->stencil_material, NULL);
if (first)
{
@ -465,12 +475,12 @@ cogl_viewport (guint width,
}
void
cogl_setup_viewport (guint width,
guint height,
float fovy,
float aspect,
float z_near,
float z_far)
_cogl_setup_viewport (guint width,
guint height,
float fovy,
float aspect,
float z_near,
float z_far)
{
float z_camera;
CoglMatrix projection_matrix;
@ -478,7 +488,7 @@ cogl_setup_viewport (guint width,
GE( glViewport (0, 0, width, height) );
/* For Ortho projection.
* _cogl_current_matrix_ortho (0, width << 16, 0, height << 16, -1 << 16, 1 << 16);
* _cogl_current_matrix_ortho (0, width, 0, height, -1, 1);
*/
cogl_perspective (fovy, aspect, z_near, z_far);
@ -532,7 +542,7 @@ cogl_setup_viewport (guint width,
}
CoglFeatureFlags
cogl_get_features ()
cogl_get_features (void)
{
_COGL_GET_CONTEXT (ctx, 0);
@ -653,9 +663,11 @@ cogl_disable_fog (void)
glDisable (GL_FOG);
}
#if 0
void
cogl_flush_gl_state (int flags)
{
_cogl_current_matrix_state_flush ();
}
#endif

View file

@ -35,11 +35,6 @@ cogl_sources = \
cogl-context.c \
$(NULL)
coglincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/cogl
coglinclude_HEADERS = \
$(cogl_headers) \
$(top_builddir)/clutter/cogl/cogl.h
INCLUDES = \
-I$(top_srcdir)/clutter/cogl \
-I$(top_srcdir)/clutter/cogl/common \
@ -50,12 +45,12 @@ INCLUDES = \
-DG_LOG_DOMAIN=\"Cogl-GL\" \
-DCLUTTER_COMPILATION
noinst_LTLIBRARIES = libclutter-cogl.la
noinst_LTLIBRARIES = libclutter-cogl-gl.la
libclutter_cogl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS)
libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_la_SOURCES = \
libclutter_cogl_gl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS)
libclutter_cogl_gl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_gl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_gl_la_SOURCES = \
$(top_builddir)/clutter/cogl/cogl.h \
$(cogl_headers) \
$(cogl_priv_headers) \

View file

@ -37,7 +37,7 @@
static CoglContext *_context = NULL;
static gboolean gl_is_indirect = FALSE;
gboolean
static gboolean
cogl_create_context ()
{
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
@ -69,7 +69,6 @@ cogl_create_context ()
_context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
_context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat));
_context->static_indices = g_array_new (FALSE, FALSE, sizeof (GLushort));
_context->polygon_vertices = g_array_new (FALSE, FALSE,
sizeof (CoglTextureGLVertex));
@ -136,6 +135,9 @@ cogl_create_context ()
_context->pf_glActiveTexture = NULL;
_context->pf_glClientActiveTexture = NULL;
_context->pf_glBlendFuncSeparate = NULL;
_context->pf_glBlendEquationSeparate = NULL;
/* Initialise the clip stack */
_cogl_clip_stack_state_init ();
@ -146,8 +148,7 @@ cogl_create_context ()
_context->default_gl_texture_2d_tex =
cogl_texture_new_from_data (1, /* width */
1, /* height */
-1, /* max waste */
COGL_TEXTURE_NONE, /* flags */
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888, /* data format */
/* internal format */
COGL_PIXEL_FORMAT_RGBA_8888,
@ -156,8 +157,7 @@ cogl_create_context ()
_context->default_gl_texture_rect_tex =
cogl_texture_new_from_data (1, /* width */
1, /* height */
-1, /* max waste */
COGL_TEXTURE_NONE, /* flags */
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888, /* data format */
/* internal format */
COGL_PIXEL_FORMAT_RGBA_8888,
@ -165,16 +165,20 @@ cogl_create_context ()
default_texture_data);
cogl_set_source (_context->default_material);
cogl_material_flush_gl_state (_context->source_material, NULL);
_cogl_material_flush_gl_state (_context->source_material, NULL);
enable_flags =
cogl_material_get_cogl_enable_flags (_context->source_material);
_cogl_material_get_cogl_enable_flags (_context->source_material);
cogl_enable (enable_flags);
_context->quad_indices_byte = COGL_INVALID_HANDLE;
_context->quad_indices_short = COGL_INVALID_HANDLE;
_context->quad_indices_short_len = 0;
return TRUE;
}
void
cogl_destroy_context ()
_cogl_destroy_context ()
{
if (_context == NULL)
return;
@ -199,13 +203,16 @@ cogl_destroy_context ()
if (_context->logged_vertices)
g_array_free (_context->logged_vertices, TRUE);
if (_context->static_indices)
g_array_free (_context->static_indices, TRUE);
if (_context->polygon_vertices)
g_array_free (_context->polygon_vertices, TRUE);
if (_context->current_layers)
g_array_free (_context->current_layers, TRUE);
if (_context->quad_indices_byte)
cogl_handle_unref (_context->quad_indices_byte);
if (_context->quad_indices_short)
cogl_handle_unref (_context->quad_indices_short);
g_free (_context);
}

View file

@ -78,7 +78,6 @@ typedef struct
* can batch things together. */
GArray *journal;
GArray *logged_vertices;
GArray *static_indices;
GArray *polygon_vertices;
/* Some simple caching, to minimize state changes... */
@ -102,6 +101,12 @@ typedef struct
floatVec2 path_nodes_max;
CoglHandle stencil_material;
/* Pre-generated VBOs containing indices to generate GL_TRIANGLES
out of a vertex array of quads */
CoglHandle quad_indices_byte;
guint quad_indices_short_len;
CoglHandle quad_indices_short;
/* Relying on glext.h to define these */
COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT;
COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT;
@ -115,6 +120,7 @@ typedef struct
COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT;
COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT;
COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT;
COGL_PFNGLGENERATEMIPMAPEXTPROC pf_glGenerateMipmapEXT;
COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB;
COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB;
@ -164,6 +170,11 @@ typedef struct
COGL_PFNGLACTIVETEXTUREPROC pf_glActiveTexture;
COGL_PFNGLCLIENTACTIVETEXTUREPROC pf_glClientActiveTexture;
COGL_PFNGLBLENDEQUATIONPROC pf_glBlendEquation;
COGL_PFNGLBLENDCOLORPROC pf_glBlendColor;
COGL_PFNGLBLENDFUNCSEPARATEPROC pf_glBlendFuncSeparate;
COGL_PFNGLBLENDEQUATIONSEPARATEPROC pf_glBlendEquationSeparate;
} CoglContext;
CoglContext *

View file

@ -773,6 +773,10 @@ typedef void
GLsizei width,
GLsizei height);
typedef void
(APIENTRYP COGL_PFNGLGENERATEMIPMAPEXTPROC)
(GLenum target);
typedef GLhandleARB
(APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC)
(void);
@ -1020,6 +1024,29 @@ typedef void
(APIENTRYP COGL_PFNGLCLIENTACTIVETEXTUREPROC)
(GLenum texture);
typedef void
(APIENTRYP COGL_PFNGLBLENDFUNCSEPARATEPROC)
(GLenum srcRGB,
GLenum dstRGB,
GLenum srcAlpha,
GLenum dstAlpha);
typedef void
(APIENTRYP COGL_PFNGLBLENDEQUATIONSEPARATEPROC)
(GLenum modeRGB,
GLenum modeAlpha);
typedef void
(APIENTRYP COGL_PFNGLBLENDEQUATIONPROC)
(GLenum mode);
typedef void
(APIENTRYP COGL_PFNGLBLENDCOLORPROC)
(GLclampf red,
GLclampf green,
GLclampf blue,
GLclampf alpha);
G_END_DECLS
#endif

View file

@ -29,6 +29,7 @@
#include "cogl-internal.h"
#include "cogl-context.h"
#include "cogl-clip-stack.h"
#include "cogl-material-private.h"
#include <string.h>
#include <gmodule.h>
@ -78,13 +79,13 @@ _cogl_path_stroke_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
(guint32)~0, /* disable all texture layers */
NULL);
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
(guint32)~0, /* disable all texture layers */
NULL);
_cogl_current_matrix_state_flush ();
while (path_start < ctx->path_nodes->len)
@ -133,10 +134,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Just setup a simple material that doesn't use texturing... */
cogl_material_flush_gl_state (ctx->stencil_material, NULL);
_cogl_material_flush_gl_state (ctx->stencil_material, NULL);
enable_flags |=
cogl_material_get_cogl_enable_flags (ctx->source_material);
_cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
_cogl_path_get_bounds (nodes_min, nodes_max,

View file

@ -108,22 +108,23 @@ cogl_shader_compile (CoglHandle handle)
glCompileShaderARB (shader->gl_handle);
}
void
cogl_shader_get_info_log (CoglHandle handle,
size_t size,
char *buffer)
gchar *
cogl_shader_get_info_log (CoglHandle handle)
{
CoglShader *shader;
char buffer[512];
int len;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_COGL_GET_CONTEXT (ctx, NULL);
if (!cogl_is_shader (handle))
return;
return NULL;
shader = _cogl_shader_pointer_from_handle (handle);
glGetInfoLogARB (shader->gl_handle, size-1, &len, buffer);
glGetInfoLogARB (shader->gl_handle, 511, &len, buffer);
buffer[len]='\0';
return g_strdup (buffer);
}
CoglShaderType

View file

@ -30,6 +30,7 @@
typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
typedef struct _CoglSpanIter CoglSpanIter;
typedef struct _CoglTexturePixel CoglTexturePixel;
struct _CoglTexSliceSpan
{
@ -55,6 +56,18 @@ struct _CoglSpanIter
gboolean intersects;
};
/* This is used to store the first pixel of each slice. This is only
used when glGenerateMipmap is not available */
struct _CoglTexturePixel
{
/* We need to store the format of the pixel because we store the
data in the source format which might end up being different for
each slice if a subregion is updated with a different format */
GLenum gl_format;
GLenum gl_type;
guint8 data[4];
};
struct _CoglTexture
{
CoglHandleObject _parent;
@ -68,11 +81,17 @@ struct _CoglTexture
GArray *slice_y_spans;
GArray *slice_gl_handles;
gint max_waste;
CoglTextureFilter min_filter;
CoglTextureFilter mag_filter;
GLenum min_filter;
GLenum mag_filter;
gboolean is_foreign;
GLint wrap_mode;
gboolean auto_mipmap;
gboolean mipmaps_dirty;
/* This holds a copy of the first pixel in each slice. It is only
used to force an automatic update of the mipmaps when
glGenerateMipmap is not available. */
CoglTexturePixel *first_pixels;
};
/* To improve batching of geometry when submitting vertices to OpenGL we
@ -93,6 +112,14 @@ void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode);
void
_cogl_texture_set_filters (CoglHandle handle,
GLenum min_filter,
GLenum mag_filter);
void
_cogl_texture_ensure_mipmaps (CoglHandle handle);
gboolean
_cogl_texture_span_has_waste (CoglTexture *tex,
gint x_span_index,

View file

@ -49,6 +49,7 @@
#define glDrawRangeElements ctx->pf_glDrawRangeElements
#define glActiveTexture ctx->pf_glActiveTexture
#define glClientActiveTexture ctx->pf_glClientActiveTexture
#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT
#else
@ -247,11 +248,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
/* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x)
{
gint slice_num = y * tex->slice_x_spans->len + x;
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
/* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y * tex->slice_x_spans->len + x);
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
/* Setup gl alignment to match rowstride and top-left corner */
prep_for_gl_pixels_upload (tex->bitmap.rowstride,
@ -259,6 +261,17 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
y_span->start,
bpp);
/* Keep a copy of the first pixel if needed */
if (tex->first_pixels)
{
memcpy (tex->first_pixels[slice_num].data,
tex->bitmap.data + x_span->start * bpp
+ y_span->start * tex->bitmap.rowstride,
bpp);
tex->first_pixels[slice_num].gl_format = tex->gl_format;
tex->first_pixels[slice_num].gl_type = tex->gl_type;
}
/* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
@ -343,6 +356,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
if (waste_buf)
g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE;
}
@ -494,6 +509,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_next (&x_iter),
source_x += inter_w )
{
gint slice_num;
/* Discard slices out of the subregion early */
if (!x_iter.intersects)
{
@ -516,10 +533,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
local_y = (y_iter.intersect_start -
y_iter.pos);
slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index;
/* Pick slice GL handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y_iter.index * tex->slice_x_spans->len +
x_iter.index);
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
/* Setup gl alignment to match rowstride and top-left corner */
prep_for_gl_pixels_upload (source_bmp->rowstride,
@ -527,6 +544,17 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
source_y,
bpp);
/* Keep a copy of the first pixel if needed */
if (tex->first_pixels && local_x == 0 && local_y == 0)
{
memcpy (tex->first_pixels[slice_num].data,
source_bmp->data + source_x * bpp
+ source_y * source_bmp->rowstride,
bpp);
tex->first_pixels[slice_num].gl_format = source_gl_format;
tex->first_pixels[slice_num].gl_type = source_gl_type;
}
/* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
@ -640,14 +668,16 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
if (waste_buf)
g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE;
}
static gint
_cogl_rect_slices_for_size (gint size_to_fill,
gint max_span_size,
gint max_waste,
GArray *out_spans)
_cogl_rect_slices_for_size (gint size_to_fill,
gint max_span_size,
gint max_waste,
GArray *out_spans)
{
gint n_spans = 0;
CoglTexSliceSpan span;
@ -679,10 +709,10 @@ _cogl_rect_slices_for_size (gint size_to_fill,
}
static gint
_cogl_pot_slices_for_size (gint size_to_fill,
gint max_span_size,
gint max_waste,
GArray *out_spans)
_cogl_pot_slices_for_size (gint size_to_fill,
gint max_span_size,
gint max_waste,
GArray *out_spans)
{
gint n_spans = 0;
CoglTexSliceSpan span;
@ -693,7 +723,8 @@ _cogl_pot_slices_for_size (gint size_to_fill,
span.waste = 0;
/* Fix invalid max_waste */
if (max_waste < 0) max_waste = 0;
if (max_waste < 0)
max_waste = 0;
while (TRUE)
{
@ -826,10 +857,10 @@ _cogl_texture_slices_create (CoglTexture *tex)
/* Check if size supported else bail out */
if (!_cogl_texture_size_supported (tex->gl_target,
tex->gl_format,
tex->gl_type,
max_width,
max_height))
tex->gl_format,
tex->gl_type,
max_width,
max_height))
{
return FALSE;
}
@ -912,6 +943,14 @@ _cogl_texture_slices_create (CoglTexture *tex)
g_array_set_size (tex->slice_gl_handles, n_slices);
/* Allocate some space to store a copy of the first pixel of each
slice. This is only needed to glGenerateMipmap (which is part of
the FBO extension) is not available */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
tex->first_pixels = NULL;
else
tex->first_pixels = g_new (CoglTexturePixel, n_slices);
/* Wrap mode not yet set */
tex->wrap_mode = GL_FALSE;
@ -940,14 +979,6 @@ _cogl_texture_slices_create (CoglTexture *tex)
/* Setup texture parameters */
GE( glBindTexture (tex->gl_target,
gl_handles[y * n_x_slices + x]) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
tex->mag_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
tex->min_filter) );
if (tex->auto_mipmap)
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP,
GL_TRUE) );
/* Use a transparent border color so that we can leave the
color buffer alone when using texture co-ordinates
@ -984,6 +1015,9 @@ _cogl_texture_slices_free (CoglTexture *tex)
g_array_free (tex->slice_gl_handles, TRUE);
}
if (tex->first_pixels != NULL)
g_free (tex->first_pixels);
}
gboolean
@ -1199,11 +1233,10 @@ _cogl_texture_free (CoglTexture *tex)
}
CoglHandle
cogl_texture_new_with_size (guint width,
guint height,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
cogl_texture_new_with_size (guint width,
guint height,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
{
CoglTexture *tex;
gint bpp;
@ -1221,7 +1254,8 @@ cogl_texture_new_with_size (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0);
tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap.width = width;
tex->bitmap.height = height;
@ -1234,9 +1268,14 @@ cogl_texture_new_with_size (guint width,
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
tex->max_waste = max_waste;
tex->min_filter = COGL_TEXTURE_FILTER_NEAREST;
tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST;
if (flags & COGL_TEXTURE_NO_SLICING)
tex->max_waste = -1;
else
tex->max_waste = COGL_TEXTURE_MAX_WASTE;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* Find closest GL format match */
tex->bitmap.format =
@ -1258,7 +1297,6 @@ cogl_texture_new_with_size (guint width,
CoglHandle
cogl_texture_new_from_data (guint width,
guint height,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat format,
CoglPixelFormat internal_format,
@ -1282,7 +1320,8 @@ cogl_texture_new_from_data (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0);
tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap.width = width;
tex->bitmap.height = height;
@ -1295,9 +1334,14 @@ cogl_texture_new_from_data (guint width,
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
tex->max_waste = max_waste;
tex->min_filter = COGL_TEXTURE_FILTER_NEAREST;
tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST;
if (flags & COGL_TEXTURE_NO_SLICING)
tex->max_waste = -1;
else
tex->max_waste = COGL_TEXTURE_MAX_WASTE;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle (this
@ -1328,10 +1372,9 @@ cogl_texture_new_from_data (guint width,
}
CoglHandle
cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
{
CoglTexture *tex;
CoglBitmap *bmp = (CoglBitmap *)bmp_handle;
@ -1342,7 +1385,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0);
tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap = *bmp;
tex->bitmap_owner = FALSE;
@ -1351,9 +1395,14 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
tex->max_waste = max_waste;
tex->min_filter = COGL_TEXTURE_FILTER_NEAREST;
tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST;
if (flags & COGL_TEXTURE_NO_SLICING)
tex->max_waste = -1;
else
tex->max_waste = COGL_TEXTURE_MAX_WASTE;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle if the
@ -1388,13 +1437,12 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
CoglHandle
cogl_texture_new_from_file (const gchar *filename,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error)
{
CoglHandle bmp;
CoglHandle handle;
CoglHandle bmp;
CoglHandle handle;
g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
@ -1402,10 +1450,7 @@ cogl_texture_new_from_file (const gchar *filename,
if (bmp == COGL_INVALID_HANDLE)
return COGL_INVALID_HANDLE;
handle = cogl_texture_new_from_bitmap (bmp,
max_waste,
flags,
internal_format);
handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format);
cogl_handle_unref (bmp);
return handle;
@ -1433,8 +1478,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GLint gl_int_format = 0;
GLint gl_width = 0;
GLint gl_height = 0;
GLint gl_min_filter;
GLint gl_mag_filter;
GLint gl_gen_mipmap;
guint bpp;
CoglTexture *tex;
@ -1482,14 +1525,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GL_TEXTURE_HEIGHT,
&gl_height) );
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MIN_FILTER,
&gl_min_filter) );
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MAG_FILTER,
&gl_mag_filter) );
GE( glGetTexParameteriv (gl_target,
GL_GENERATE_MIPMAP,
&gl_gen_mipmap) );
@ -1508,18 +1543,16 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
return COGL_INVALID_HANDLE;
/* Try and match to a cogl format */
if (!_cogl_pixel_format_from_gl_internal (gl_int_format,
&format))
{
return COGL_INVALID_HANDLE;
}
if (!_cogl_pixel_format_from_gl_internal (gl_int_format, &format))
return COGL_INVALID_HANDLE;
/* Create new texture */
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
tex = (CoglTexture *) g_malloc (sizeof (CoglTexture));
/* Setup bitmap info */
tex->is_foreign = TRUE;
tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE;
tex->mipmaps_dirty = TRUE;
bpp = _cogl_get_format_bpp (format);
tex->bitmap.format = format;
@ -1533,8 +1566,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
tex->gl_format = gl_int_format;
tex->gl_type = GL_UNSIGNED_BYTE;
tex->min_filter = gl_min_filter;
tex->mag_filter = gl_mag_filter;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
tex->max_waste = 0;
/* Wrap mode not yet set */
@ -1680,36 +1714,10 @@ cogl_texture_get_gl_texture (CoglHandle handle,
return TRUE;
}
CoglTextureFilter
cogl_texture_get_min_filter (CoglHandle handle)
{
CoglTexture *tex;
if (!cogl_is_texture (handle))
return 0;
tex = _cogl_texture_pointer_from_handle (handle);
return tex->min_filter;
}
CoglTextureFilter
cogl_texture_get_mag_filter (CoglHandle handle)
{
CoglTexture *tex;
if (!cogl_is_texture (handle))
return 0;
tex = _cogl_texture_pointer_from_handle (handle);
return tex->mag_filter;
}
void
cogl_texture_set_filters (CoglHandle handle,
CoglTextureFilter min_filter,
CoglTextureFilter mag_filter)
_cogl_texture_set_filters (CoglHandle handle,
GLenum min_filter,
GLenum mag_filter)
{
CoglTexture *tex;
GLuint gl_handle;
@ -1720,14 +1728,18 @@ cogl_texture_set_filters (CoglHandle handle,
tex = _cogl_texture_pointer_from_handle (handle);
/* Store new values */
tex->min_filter = min_filter;
tex->mag_filter = mag_filter;
/* Make sure slices were created */
if (tex->slice_gl_handles == NULL)
return;
if (min_filter == tex->min_filter
&& mag_filter == tex->mag_filter)
return;
/* Store new values */
tex->min_filter = min_filter;
tex->mag_filter = mag_filter;
/* Apply new filters to every slice */
for (i=0; i<tex->slice_gl_handles->len; ++i)
{
@ -1740,6 +1752,52 @@ cogl_texture_set_filters (CoglHandle handle,
}
}
void
_cogl_texture_ensure_mipmaps (CoglHandle handle)
{
CoglTexture *tex;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_texture (handle))
return;
tex = _cogl_texture_pointer_from_handle (handle);
/* Only update if the mipmaps are dirty */
if (!tex->auto_mipmap || !tex->mipmaps_dirty)
return;
/* Make sure slices were created */
if (tex->slice_gl_handles == NULL)
return;
/* Regenerate the mipmaps on every slice */
for (i = 0; i < tex->slice_gl_handles->len; i++)
{
GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex->gl_target, gl_handle) );
/* glGenerateMipmap is defined in the FBO extension */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
GE( glGenerateMipmap (tex->gl_target) );
else
{
CoglTexturePixel *pixel = tex->first_pixels + i;
/* Temporarily enable automatic mipmap generation and
re-upload the first pixel to cause a regeneration */
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) );
GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1,
pixel->gl_format, pixel->gl_type,
pixel->data) );
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) );
}
}
tex->mipmaps_dirty = FALSE;
}
gboolean
cogl_texture_set_region (CoglHandle handle,
gint src_x,

View file

@ -399,6 +399,10 @@ _cogl_features_init (void)
(COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC)
cogl_get_proc_address ("glDeleteFramebuffersEXT");
ctx->pf_glGenerateMipmapEXT =
(COGL_PFNGLGENERATEMIPMAPEXTPROC)
cogl_get_proc_address ("glGenerateMipmapEXT");
if (ctx->pf_glGenRenderbuffersEXT &&
ctx->pf_glBindRenderbufferEXT &&
ctx->pf_glRenderbufferStorageEXT &&
@ -407,7 +411,8 @@ _cogl_features_init (void)
ctx->pf_glFramebufferTexture2DEXT &&
ctx->pf_glFramebufferRenderbufferEXT &&
ctx->pf_glCheckFramebufferStatusEXT &&
ctx->pf_glDeleteFramebuffersEXT)
ctx->pf_glDeleteFramebuffersEXT &&
ctx->pf_glGenerateMipmapEXT)
flags |= COGL_FEATURE_OFFSCREEN;
}
@ -486,6 +491,23 @@ _cogl_features_init (void)
(COGL_PFNGLCLIENTACTIVETEXTUREPROC)
cogl_get_proc_address ("glClientActiveTexture");
ctx->pf_glBlendEquation =
(COGL_PFNGLBLENDEQUATIONPROC)
cogl_get_proc_address ("glBlendEquation");
ctx->pf_glBlendColor =
(COGL_PFNGLBLENDCOLORPROC)
cogl_get_proc_address ("glBlendColor");
/* Available in 1.4 */
ctx->pf_glBlendFuncSeparate =
(COGL_PFNGLBLENDFUNCSEPARATEPROC)
cogl_get_proc_address ("glBlendFuncSeparate");
/* Available in 2.0 */
ctx->pf_glBlendEquationSeparate =
(COGL_PFNGLBLENDEQUATIONSEPARATEPROC)
cogl_get_proc_address ("glBlendEquationSeparate");
/* Cache features */
ctx->feature_flags = flags;
ctx->features_cached = TRUE;

View file

@ -27,12 +27,12 @@ INCLUDES = \
-DG_LOG_DOMAIN=\"Cogl-GLES\" \
-DCLUTTER_COMPILATION
noinst_LTLIBRARIES = libclutter-cogl.la
noinst_LTLIBRARIES = libclutter-cogl-gles.la
libclutter_cogl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS)
libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_la_SOURCES = \
libclutter_cogl_gles_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS)
libclutter_cogl_gles_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_gles_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la
libclutter_cogl_gles_la_SOURCES = \
$(top_builddir)/clutter/cogl/cogl.h \
$(top_builddir)/clutter/cogl/cogl-defines-gles.h \
$(top_builddir)/clutter/cogl/cogl-color.h \
@ -60,7 +60,7 @@ libclutter_cogl_la_SOURCES = \
cogl-shader.c
if USE_GLES2_WRAPPER
libclutter_cogl_la_SOURCES += \
libclutter_cogl_gles_la_SOURCES += \
cogl-gles2-wrapper.c \
cogl-fixed-vertex-shader.h \
cogl-fixed-vertex-shader.c \

View file

@ -39,7 +39,7 @@
static CoglContext *_context = NULL;
static gboolean gl_is_indirect = FALSE;
gboolean
static gboolean
cogl_create_context ()
{
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
@ -72,7 +72,6 @@ cogl_create_context ()
_context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
_context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat));
_context->static_indices = g_array_new (FALSE, FALSE, sizeof (GLushort));
_context->polygon_vertices = g_array_new (FALSE, FALSE,
sizeof (CoglTextureGLVertex));
@ -107,8 +106,7 @@ cogl_create_context ()
_context->default_gl_texture_2d_tex =
cogl_texture_new_from_data (1, /* width */
1, /* height */
-1, /* max waste */
COGL_TEXTURE_NONE, /* flags */
COGL_TEXTURE_NO_SLICING, /* flags */
COGL_PIXEL_FORMAT_RGBA_8888, /* data format */
/* internal format */
COGL_PIXEL_FORMAT_RGBA_8888,
@ -117,8 +115,7 @@ cogl_create_context ()
_context->default_gl_texture_rect_tex =
cogl_texture_new_from_data (1, /* width */
1, /* height */
-1, /* max waste */
COGL_TEXTURE_NONE, /* flags */
COGL_TEXTURE_NO_SLICING, /* flags */
COGL_PIXEL_FORMAT_RGBA_8888, /* data format */
/* internal format */
COGL_PIXEL_FORMAT_RGBA_8888,
@ -126,16 +123,20 @@ cogl_create_context ()
default_texture_data);
cogl_set_source (_context->default_material);
cogl_material_flush_gl_state (_context->source_material, NULL);
_cogl_material_flush_gl_state (_context->source_material, NULL);
enable_flags =
cogl_material_get_cogl_enable_flags (_context->source_material);
_cogl_material_get_cogl_enable_flags (_context->source_material);
cogl_enable (enable_flags);
_context->quad_indices_byte = COGL_INVALID_HANDLE;
_context->quad_indices_short = COGL_INVALID_HANDLE;
_context->quad_indices_short_len = 0;
return TRUE;
}
void
cogl_destroy_context ()
_cogl_destroy_context ()
{
if (_context == NULL)
return;
@ -160,13 +161,16 @@ cogl_destroy_context ()
if (_context->logged_vertices)
g_array_free (_context->logged_vertices, TRUE);
if (_context->static_indices)
g_array_free (_context->static_indices, TRUE);
if (_context->polygon_vertices)
g_array_free (_context->polygon_vertices, TRUE);
if (_context->current_layers)
g_array_free (_context->current_layers, TRUE);
if (_context->quad_indices_byte)
cogl_handle_unref (_context->quad_indices_byte);
if (_context->quad_indices_short)
cogl_handle_unref (_context->quad_indices_short);
g_free (_context);
}

View file

@ -80,7 +80,6 @@ typedef struct
* can batch things together. */
GArray *journal;
GArray *logged_vertices;
GArray *static_indices;
GArray *polygon_vertices;
/* Some simple caching, to minimize state changes... */
@ -104,6 +103,12 @@ typedef struct
floatVec2 path_nodes_max;
CoglHandle stencil_material;
/* Pre-generated VBOs containing indices to generate GL_TRIANGLES
out of a vertex array of quads */
CoglHandle quad_indices_byte;
guint quad_indices_short_len;
CoglHandle quad_indices_short;
#ifdef HAVE_COGL_GLES2
CoglGles2Wrapper gles2;
@ -111,7 +116,6 @@ typedef struct
supported */
GLint viewport_store[4];
#endif
} CoglContext;
CoglContext *

View file

@ -89,13 +89,13 @@ cogl_gles2_wrapper_create_shader (GLenum type, const char *source)
if (!status)
{
char log[1024];
char shader_log[1024];
GLint len;
glGetShaderInfoLog (shader, sizeof (log) - 1, &len, log);
log[len] = '\0';
glGetShaderInfoLog (shader, sizeof (shader_log) - 1, &len, shader_log);
shader_log[len] = '\0';
g_critical ("%s", log);
g_critical ("%s", shader_log);
glDeleteShader (shader);
@ -538,9 +538,9 @@ cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings)
CoglShader *shader
= _cogl_shader_pointer_from_handle ((CoglHandle) node->data);
if (shader->type == CGL_VERTEX_SHADER)
if (shader->type == COGL_SHADER_TYPE_VERTEX)
custom_vertex_shader = TRUE;
else if (shader->type == CGL_FRAGMENT_SHADER)
else if (shader->type == COGL_SHADER_TYPE_FRAGMENT)
custom_fragment_shader = TRUE;
}
}
@ -581,13 +581,13 @@ cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings)
if (!status)
{
char log[1024];
char shader_log[1024];
GLint len;
glGetProgramInfoLog (program->program, sizeof (log) - 1, &len, log);
log[len] = '\0';
glGetProgramInfoLog (program->program, sizeof (shader_log) - 1, &len, shader_log);
shader_log[len] = '\0';
g_critical ("%s", log);
g_critical ("%s", shader_log);
glDeleteProgram (program->program);
g_slice_free (CoglGles2WrapperProgram, program);
@ -1300,13 +1300,20 @@ cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture,
}
void
cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLfloat param)
cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param)
{
/* This function is only used to set the texture mode once to
GL_MODULATE. The shader is hard-coded to modulate the texture so
nothing needs to be done here. */
}
void
cogl_wrap_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params)
{
/* FIXME: Currently needed to support texture combining using
* COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT */
}
void
cogl_wrap_glClientActiveTexture (GLenum texture)
{

View file

@ -259,6 +259,7 @@ struct _CoglGles2WrapperShader
#define GL_TEXTURE_ENV 0x2300
#define GL_TEXTURE_ENV_MODE 0x2200
#define GL_TEXTURE_ENV_COLOR 0x2201
#define GL_MODULATE 0x2100
#define GL_EXP 0x8000
@ -327,7 +328,8 @@ void cogl_wrap_glColorPointer (GLint size, GLenum type, GLsizei stride,
void cogl_wrap_glNormalPointer (GLenum type, GLsizei stride,
const GLvoid *pointer);
void cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLfloat param);
void cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param);
void cogl_wrap_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);
void cogl_wrap_glClientActiveTexture (GLenum texture);
void cogl_wrap_glActiveTexture (GLenum texture);
@ -384,6 +386,7 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program);
#define glColorPointer cogl_wrap_glColorPointer
#define glNormalPointer cogl_wrap_glNormalPointer
#define glTexEnvi cogl_wrap_glTexEnvi
#define glTexEnvfv cogl_wrap_glTexEnvfv
#define glActiveTexture cogl_wrap_glActiveTexture
#define glClientActiveTexture cogl_wrap_glClientActiveTexture
#define glEnableClientState cogl_wrap_glEnableClientState

View file

@ -29,6 +29,7 @@
#include "cogl-internal.h"
#include "cogl-context.h"
#include "cogl-clip-stack.h"
#include "cogl-material-private.h"
#include <string.h>
#include <gmodule.h>
@ -78,13 +79,13 @@ _cogl_path_stroke_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
(guint32)~0, /* disable all texture layers */
NULL);
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
(guint32)~0, /* disable all texture layers */
NULL);
_cogl_current_matrix_state_flush ();
while (path_start < ctx->path_nodes->len)
@ -139,10 +140,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Just setup a simple material that doesn't use texturing... */
cogl_material_flush_gl_state (ctx->stencil_material, NULL);
_cogl_material_flush_gl_state (ctx->stencil_material, NULL);
enable_flags |=
cogl_material_get_cogl_enable_flags (ctx->source_material);
_cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
_cogl_path_get_bounds (nodes_min, nodes_max,
@ -361,30 +362,30 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
while (iter)
{
GSList *next = iter->next;
GLfloat x0, x1;
GLfloat y0, y1;
GLfloat x_0, x_1;
GLfloat y_0, y_1;
if (!next)
break;
x0 = GPOINTER_TO_INT (iter->data);
x1 = GPOINTER_TO_INT (next->data);
y0 = bounds_y + i;
y1 = bounds_y + i + 1.0625f;
x_0 = GPOINTER_TO_INT (iter->data);
x_1 = GPOINTER_TO_INT (next->data);
y_0 = bounds_y + i;
y_1 = bounds_y + i + 1.0625f;
/* render scanlines 1.0625 high to avoid gaps when
transformed */
coords[span_no * 12 + 0] = x0;
coords[span_no * 12 + 1] = y0;
coords[span_no * 12 + 2] = x1;
coords[span_no * 12 + 3] = y0;
coords[span_no * 12 + 4] = x1;
coords[span_no * 12 + 5] = y1;
coords[span_no * 12 + 6] = x0;
coords[span_no * 12 + 7] = y0;
coords[span_no * 12 + 8] = x0;
coords[span_no * 12 + 9] = y1;
coords[span_no * 12 + 10] = x1;
coords[span_no * 12 + 11] = y1;
coords[span_no * 12 + 0] = x_0;
coords[span_no * 12 + 1] = y_0;
coords[span_no * 12 + 2] = x_1;
coords[span_no * 12 + 3] = y_0;
coords[span_no * 12 + 4] = x_1;
coords[span_no * 12 + 5] = y_1;
coords[span_no * 12 + 6] = x_0;
coords[span_no * 12 + 7] = y_0;
coords[span_no * 12 + 8] = x_0;
coords[span_no * 12 + 9] = y_1;
coords[span_no * 12 + 10] = x_1;
coords[span_no * 12 + 11] = y_1;
span_no ++;
iter = next->next;
}

View file

@ -99,22 +99,23 @@ cogl_shader_compile (CoglHandle handle)
glCompileShader (shader->gl_handle);
}
void
cogl_shader_get_info_log (CoglHandle handle,
size_t size,
char *buffer)
gchar *
cogl_shader_get_info_log (CoglHandle handle)
{
CoglShader *shader;
char buffer[512];
int len = 0;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_COGL_GET_CONTEXT (ctx, NULL);
if (!cogl_is_shader (handle))
return;
return NULL;
shader = _cogl_shader_pointer_from_handle (handle);
glGetShaderInfoLog (shader->gl_handle, size - 1, &len, buffer);
glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer);
buffer[len] = '\0';
return g_strdup (buffer);
}
CoglShaderType
@ -199,11 +200,10 @@ cogl_shader_compile (CoglHandle shader_handle)
{
}
void
cogl_shader_get_info_log (CoglHandle handle,
size_t size,
char *buffer)
gchar *
cogl_shader_get_info_log (CoglHandle handle)
{
return NULL;
}
CoglShaderType

View file

@ -30,6 +30,7 @@
typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
typedef struct _CoglSpanIter CoglSpanIter;
typedef struct _CoglTexturePixel CoglTexturePixel;
struct _CoglTexSliceSpan
{
@ -55,6 +56,18 @@ struct _CoglSpanIter
gboolean intersects;
};
/* This is used to store the first pixel of each slice. This is only
used when glGenerateMipmap is not available */
struct _CoglTexturePixel
{
/* We need to store the format of the pixel because we store the
data in the source format which might end up being different for
each slice if a subregion is updated with a different format */
GLenum gl_format;
GLenum gl_type;
guint8 data[4];
};
struct _CoglTexture
{
CoglHandleObject _parent;
@ -68,11 +81,17 @@ struct _CoglTexture
GArray *slice_y_spans;
GArray *slice_gl_handles;
gint max_waste;
CoglTextureFilter min_filter;
CoglTextureFilter mag_filter;
GLenum min_filter;
GLenum mag_filter;
gboolean is_foreign;
GLint wrap_mode;
gboolean auto_mipmap;
gboolean mipmaps_dirty;
/* This holds a copy of the first pixel in each slice. It is only
used to force an automatic update of the mipmaps when
glGenerateMipmap is not available. */
CoglTexturePixel *first_pixels;
};
/* To improve batching of geometry when submitting vertices to OpenGL we
@ -93,6 +112,14 @@ void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode);
void
_cogl_texture_set_filters (CoglHandle handle,
GLenum min_filter,
GLenum mag_filter);
void
_cogl_texture_ensure_mipmaps (CoglHandle handle);
gboolean
_cogl_texture_span_has_waste (CoglTexture *tex,
gint x_span_index,

View file

@ -225,11 +225,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
/* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x)
{
gint slice_num = y * tex->slice_x_spans->len + x;
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
/* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y * tex->slice_x_spans->len + x);
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
/* FIXME: might optimize by not copying to intermediate slice
bitmap when source rowstride = bpp * width and the texture
@ -258,6 +259,16 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
slice_bmp.width,
slice_bmp.height);
/* Keep a copy of the first pixel if needed */
if (tex->first_pixels)
{
memcpy (tex->first_pixels[slice_num].data,
slice_bmp.data,
bpp);
tex->first_pixels[slice_num].gl_format = tex->gl_format;
tex->first_pixels[slice_num].gl_type = tex->gl_type;
}
/* Upload new image data */
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) );
@ -338,9 +349,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
waste_buf) );
}
if (tex->auto_mipmap)
cogl_wrap_glGenerateMipmap (tex->gl_target);
/* Free temp bitmap */
g_free (slice_bmp.data);
}
@ -349,6 +357,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
if (waste_buf)
g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE;
}
@ -442,6 +452,7 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
gint bpp;
GLint viewport[4];
CoglBitmap alpha_bmp;
CoglHandle prev_source;
_COGL_GET_CONTEXT (ctx, FALSE);
@ -477,31 +488,21 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
if (ctx->texture_download_material == COGL_INVALID_HANDLE)
{
ctx->texture_download_material = cogl_material_new ();
cogl_material_set_layer_combine_function (
ctx->texture_download_material,
0, /* layer */
COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB,
COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE);
cogl_material_set_layer_combine_arg_src (
ctx->texture_download_material,
0, /* layer */
0, /* arg */
COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB,
COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE);
cogl_material_set_blend_factors (ctx->texture_download_material,
COGL_MATERIAL_BLEND_FACTOR_ONE,
COGL_MATERIAL_BLEND_FACTOR_ZERO);
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);
cogl_material_set_layer (ctx->texture_download_material, 0, tex);
cogl_material_set_layer_combine_arg_op (
ctx->texture_download_material,
0, /* layer */
0, /* arg */
COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB,
COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR);
cogl_material_flush_gl_state (ctx->texture_download_material, NULL);
cogl_material_set_layer_combine (ctx->texture_download_material,
0, /* layer */
"RGBA = REPLACE (TEXTURE)",
NULL);
_cogl_texture_draw_and_read (tex, target_bmp, viewport);
/* Check whether texture has alpha and framebuffer not */
@ -534,13 +535,11 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
alpha_bmp.height);
/* Draw alpha values into RGB channels */
cogl_material_set_layer_combine_arg_op (
ctx->texture_download_material,
0, /* layer */
0, /* arg */
COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB,
COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA);
cogl_material_flush_gl_state (ctx->texture_download_material, NULL);
cogl_material_set_layer_combine (ctx->texture_download_material,
0, /* layer */
"RGBA = REPLACE (TEXTURE[A])",
NULL);
_cogl_texture_draw_and_read (tex, &alpha_bmp, viewport);
/* Copy temp R to target A */
@ -568,6 +567,10 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
_cogl_current_matrix_pop ();
/* restore the original material */
cogl_set_source (prev_source);
cogl_handle_unref (prev_source);
return TRUE;
}
@ -631,6 +634,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_next (&x_iter),
source_x += inter_w )
{
gint slice_num;
/* Discard slices out of the subregion early */
if (!x_iter.intersects)
{
@ -653,10 +658,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
local_y = (y_iter.intersect_start -
y_iter.pos);
slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index;
/* Pick slice GL handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y_iter.index * tex->slice_x_spans->len +
x_iter.index);
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
/* FIXME: might optimize by not copying to intermediate slice
bitmap when source rowstride = bpp * width and the texture
@ -685,6 +690,15 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
slice_bmp.width,
slice_bmp.height);
/* Keep a copy of the first pixel if needed */
if (tex->first_pixels && local_x == 0 && local_y == 0)
{
memcpy (tex->first_pixels[slice_num].data,
slice_bmp.data, bpp);
tex->first_pixels[slice_num].gl_format = source_gl_format;
tex->first_pixels[slice_num].gl_type = source_gl_type;
}
/* Upload new image data */
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) );
@ -794,9 +808,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
waste_buf) );
}
if (tex->auto_mipmap)
cogl_wrap_glGenerateMipmap (tex->gl_target);
/* Free temp bitmap */
g_free (slice_bmp.data);
}
@ -805,6 +816,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
if (waste_buf)
g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE;
}
@ -858,7 +871,8 @@ _cogl_pot_slices_for_size (gint size_to_fill,
span.waste = 0;
/* Fix invalid max_waste */
if (max_waste < 0) max_waste = 0;
if (max_waste < 0)
max_waste = 0;
while (TRUE)
{
@ -866,7 +880,9 @@ _cogl_pot_slices_for_size (gint size_to_fill,
if (size_to_fill > span.size)
{
/* Not yet - add a span of this size */
if (out_spans) g_array_append_val (out_spans, span);
if (out_spans)
g_array_append_val (out_spans, span);
span.start += span.size;
size_to_fill -= span.size;
n_spans++;
@ -875,7 +891,9 @@ _cogl_pot_slices_for_size (gint size_to_fill,
{
/* Yes and waste is small enough */
span.waste = span.size - size_to_fill;
if (out_spans) g_array_append_val (out_spans, span);
if (out_spans)
g_array_append_val (out_spans, span);
return ++n_spans;
}
else
@ -971,10 +989,10 @@ _cogl_texture_slices_create (CoglTexture *tex)
/* Check if size supported else bail out */
if (!_cogl_texture_size_supported (tex->gl_target,
tex->gl_format,
tex->gl_type,
max_width,
max_height))
tex->gl_format,
tex->gl_type,
max_width,
max_height))
{
return FALSE;
}
@ -1057,6 +1075,14 @@ _cogl_texture_slices_create (CoglTexture *tex)
g_array_set_size (tex->slice_gl_handles, n_slices);
/* Allocate some space to store a copy of the first pixel of each
slice. This is only needed to glGenerateMipmap (which is part of
the FBO extension) is not available */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
tex->first_pixels = NULL;
else
tex->first_pixels = g_new (CoglTexturePixel, n_slices);
/* Wrap mode not yet set */
tex->wrap_mode = GL_FALSE;
@ -1087,20 +1113,11 @@ _cogl_texture_slices_create (CoglTexture *tex)
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target,
gl_handles[y * n_x_slices + x],
tex->gl_intformat) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
tex->mag_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
tex->min_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S,
tex->wrap_mode) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T,
tex->wrap_mode) );
if (tex->auto_mipmap)
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP,
GL_TRUE) );
/* Pass NULL data to init size and internal format */
GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat,
x_span->size, y_span->size, 0,
@ -1130,6 +1147,9 @@ _cogl_texture_slices_free (CoglTexture *tex)
g_array_free (tex->slice_gl_handles, TRUE);
}
if (tex->first_pixels != NULL)
g_free (tex->first_pixels);
}
gboolean
@ -1288,11 +1308,10 @@ _cogl_texture_free (CoglTexture *tex)
}
CoglHandle
cogl_texture_new_with_size (guint width,
guint height,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
cogl_texture_new_with_size (guint width,
guint height,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
{
CoglTexture *tex;
gint bpp;
@ -1310,7 +1329,8 @@ cogl_texture_new_with_size (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0);
tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap.width = width;
tex->bitmap.height = height;
@ -1323,9 +1343,14 @@ cogl_texture_new_with_size (guint width,
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
tex->max_waste = max_waste;
tex->min_filter = CGL_NEAREST;
tex->mag_filter = CGL_NEAREST;
if (flags & COGL_TEXTURE_NO_SLICING)
tex->max_waste = -1;
else
tex->max_waste = COGL_TEXTURE_MAX_WASTE;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* Find closest GL format match */
tex->bitmap.format =
@ -1347,7 +1372,6 @@ cogl_texture_new_with_size (guint width,
CoglHandle
cogl_texture_new_from_data (guint width,
guint height,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat format,
CoglPixelFormat internal_format,
@ -1371,7 +1395,8 @@ cogl_texture_new_from_data (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0);
tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap.width = width;
tex->bitmap.height = height;
@ -1384,9 +1409,14 @@ cogl_texture_new_from_data (guint width,
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
tex->max_waste = max_waste;
tex->min_filter = CGL_NEAREST;
tex->mag_filter = CGL_NEAREST;
if (flags & COGL_TEXTURE_NO_SLICING)
tex->max_waste = -1;
else
tex->max_waste = COGL_TEXTURE_MAX_WASTE;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle (this
@ -1417,10 +1447,9 @@ cogl_texture_new_from_data (guint width,
}
CoglHandle
cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
CoglTextureFlags flags,
CoglPixelFormat internal_format)
{
CoglTexture *tex;
CoglBitmap *bmp = (CoglBitmap *)bmp_handle;
@ -1429,7 +1458,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0);
tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap = *bmp;
tex->bitmap_owner = TRUE;
@ -1439,9 +1469,14 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
tex->max_waste = max_waste;
tex->min_filter = CGL_NEAREST;
tex->mag_filter = CGL_NEAREST;
if (flags & COGL_TEXTURE_NO_SLICING)
tex->max_waste = -1;
else
tex->max_waste = COGL_TEXTURE_MAX_WASTE;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle if the
@ -1476,7 +1511,6 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
CoglHandle
cogl_texture_new_from_file (const gchar *filename,
gint max_waste,
CoglTextureFlags flags,
CoglPixelFormat internal_format,
GError **error)
@ -1490,10 +1524,7 @@ cogl_texture_new_from_file (const gchar *filename,
if (bmp == COGL_INVALID_HANDLE)
return COGL_INVALID_HANDLE;
handle = cogl_texture_new_from_bitmap (bmp,
max_waste,
flags,
internal_format);
handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format);
cogl_handle_unref (bmp);
return handle;
@ -1521,8 +1552,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GLint gl_int_format = 0;
GLint gl_width = 0;
GLint gl_height = 0;
GLint gl_min_filter;
GLint gl_mag_filter;
GLint gl_gen_mipmap;
guint bpp;
CoglTexture *tex;
@ -1569,14 +1598,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
gl_height = height + y_pot_waste;
#endif
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MIN_FILTER,
&gl_min_filter) );
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MAG_FILTER,
&gl_mag_filter) );
GE( glGetTexParameteriv (gl_target,
GL_GENERATE_MIPMAP,
&gl_gen_mipmap) );
@ -1607,6 +1628,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
/* Setup bitmap info */
tex->is_foreign = TRUE;
tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE;
tex->mipmaps_dirty = TRUE;
bpp = _cogl_get_format_bpp (format);
tex->bitmap.format = format;
@ -1620,8 +1642,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
tex->gl_format = gl_int_format;
tex->gl_type = GL_UNSIGNED_BYTE;
tex->min_filter = gl_min_filter;
tex->mag_filter = gl_mag_filter;
/* Unknown filter */
tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
tex->max_waste = 0;
/* Wrap mode not yet set */
@ -1767,36 +1790,10 @@ cogl_texture_get_gl_texture (CoglHandle handle,
return TRUE;
}
CoglTextureFilter
cogl_texture_get_min_filter (CoglHandle handle)
{
CoglTexture *tex;
if (!cogl_is_texture (handle))
return 0;
tex = _cogl_texture_pointer_from_handle (handle);
return tex->min_filter;
}
CoglTextureFilter
cogl_texture_get_mag_filter (CoglHandle handle)
{
CoglTexture *tex;
if (!cogl_is_texture (handle))
return 0;
tex = _cogl_texture_pointer_from_handle (handle);
return tex->mag_filter;
}
void
cogl_texture_set_filters (CoglHandle handle,
CoglTextureFilter min_filter,
CoglTextureFilter mag_filter)
_cogl_texture_set_filters (CoglHandle handle,
GLenum min_filter,
GLenum mag_filter)
{
CoglTexture *tex;
GLuint gl_handle;
@ -1807,14 +1804,18 @@ cogl_texture_set_filters (CoglHandle handle,
tex = _cogl_texture_pointer_from_handle (handle);
/* Store new values */
tex->min_filter = min_filter;
tex->mag_filter = mag_filter;
/* Make sure slices were created */
if (tex->slice_gl_handles == NULL)
return;
if (min_filter == tex->min_filter
&& mag_filter == tex->mag_filter)
return;
/* Store new values */
tex->min_filter = min_filter;
tex->mag_filter = mag_filter;
/* Apply new filters to every slice */
for (i=0; i<tex->slice_gl_handles->len; ++i)
{
@ -1827,6 +1828,52 @@ cogl_texture_set_filters (CoglHandle handle,
}
}
void
_cogl_texture_ensure_mipmaps (CoglHandle handle)
{
CoglTexture *tex;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_texture (handle))
return;
tex = _cogl_texture_pointer_from_handle (handle);
/* Only update if the mipmaps are dirty */
if (!tex->auto_mipmap || !tex->mipmaps_dirty)
return;
/* Make sure slices were created */
if (tex->slice_gl_handles == NULL)
return;
/* Regenerate the mipmaps on every slice */
for (i = 0; i < tex->slice_gl_handles->len; i++)
{
GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex->gl_target, gl_handle) );
/* glGenerateMipmap is defined in the FBO extension */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
GE( cogl_wrap_glGenerateMipmap (tex->gl_target) );
else
{
CoglTexturePixel *pixel = tex->first_pixels + i;
/* Temporarily enable automatic mipmap generation and
re-upload the first pixel to cause a regeneration */
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) );
GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1,
pixel->gl_format, pixel->gl_type,
pixel->data) );
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) );
}
}
tex->mipmaps_dirty = FALSE;
}
gboolean
cogl_texture_set_region (CoglHandle handle,
gint src_x,

View file

@ -49,7 +49,8 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
CLUTTER_MARK();
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor);
if (CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize != NULL)
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor);
if (stage_egl->egl_surface)
{
@ -220,9 +221,9 @@ clutter_stage_egl_realize (ClutterActor *actor)
static void
clutter_stage_egl_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self);
@ -235,9 +236,9 @@ clutter_stage_egl_get_preferred_width (ClutterActor *self,
static void
clutter_stage_egl_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self);
@ -253,8 +254,6 @@ clutter_stage_egl_dispose (GObject *gobject)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (gobject);
clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl));
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
}

View file

@ -38,7 +38,8 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL);
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor);
if (CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize != NULL)
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor);
clutter_x11_trap_x_errors ();
@ -204,7 +205,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
}
/* FIXME, do these in a clutterstage_x11_realise? */
clutter_stage_x11_fix_window_size (stage_x11);
clutter_stage_x11_fix_window_size (stage_x11, -1, -1);
clutter_stage_x11_set_wm_protocols (stage_x11);
if (stage_egl->egl_surface != EGL_NO_SURFACE)
@ -275,9 +276,6 @@ clutter_stage_egl_dispose (GObject *gobject)
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (gobject);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject);
if (stage_x11->xwin)
clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl));
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
}

View file

@ -393,6 +393,10 @@ typedef struct {
stage_fruity = CLUTTER_STAGE_EGL(backend_fruity->stage);
alive = FALSE;
/* FIXME why is this unrealize here? is the intent to destroy the stage?
* or hide it? Trying to clean up all manual unrealization so
* clutter_actor_unrealize() can be made private to clutter-actor.c
*/
clutter_actor_unrealize (CLUTTER_ACTOR (stage_fruity));
clutter_main_quit ();
}

View file

@ -45,7 +45,8 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
CLUTTER_MARK();
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor);
if (CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize != NULL)
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor);
if (stage_egl->egl_surface)
{
@ -189,9 +190,9 @@ clutter_stage_egl_realize (ClutterActor *actor)
static void
clutter_stage_egl_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self);
@ -204,9 +205,9 @@ clutter_stage_egl_get_preferred_width (ClutterActor *self,
static void
clutter_stage_egl_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (self);
@ -222,8 +223,6 @@ clutter_stage_egl_dispose (GObject *gobject)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (gobject);
clutter_actor_unrealize (CLUTTER_ACTOR (stage_egl));
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
}

View file

@ -219,7 +219,7 @@ clutter_backend_glx_constructor (GType gtype,
static gboolean
check_vblank_env (const char *name)
{
if (clutter_vblank_name && !strcasecmp(clutter_vblank_name, name))
if (clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name))
return TRUE;
return FALSE;
@ -354,6 +354,57 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
return flags;
}
static gboolean
clutter_backend_glx_create_context (ClutterBackend *backend,
gboolean is_offscreen,
GError **error)
{
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
if (backend_glx->gl_context == None)
{
XVisualInfo *xvisinfo;
xvisinfo =
clutter_backend_x11_get_visual_info (backend_x11, is_offscreen);
CLUTTER_NOTE (GL, "Creating GL Context (display: %p, %s)",
backend_x11->xdpy,
is_offscreen ? "offscreen" : "onscreen");
backend_glx->gl_context = glXCreateContext (backend_x11->xdpy,
xvisinfo,
0,
is_offscreen ? False : True);
XFree (xvisinfo);
if (backend_glx->gl_context == None)
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Unable to create suitable %s GL context",
is_offscreen ? "offscreen" : "onscreen");
return FALSE;
}
if (!is_offscreen)
{
gboolean is_direct;
is_direct = glXIsDirect (backend_x11->xdpy,
backend_glx->gl_context);
CLUTTER_NOTE (GL, "Setting %s context",
is_direct ? "direct" : "indirect");
_cogl_set_indirect_context (!is_direct);
}
}
return TRUE;
}
static void
clutter_backend_glx_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
@ -434,8 +485,11 @@ clutter_backend_glx_redraw (ClutterBackend *backend,
ClutterStageWindow *impl;
impl = _clutter_stage_get_window (stage);
if (!impl)
return;
if (G_UNLIKELY (impl == NULL))
{
CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage);
return;
}
g_assert (CLUTTER_IS_STAGE_GLX (impl));
@ -445,23 +499,28 @@ clutter_backend_glx_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage));
/* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers.
*/
if (stage_x11->xwin)
if (stage_x11->xwin != None)
{
/* wait for the next vblank */
CLUTTER_NOTE (BACKEND, "Waiting for vblank");
clutter_backend_glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
/* push on the screen */
CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
stage_x11->xdpy,
(unsigned long) stage_x11->xwin);
glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin);
}
else
{
/* offscreen */
glXWaitGL ();
CLUTTER_GLERR ();
}
}
static ClutterActor*
static ClutterActor *
clutter_backend_glx_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
@ -483,19 +542,67 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
stage_x11->backend = backend_x11;
stage_x11->wrapper = wrapper;
CLUTTER_NOTE (BACKEND, "GLX stage created (display:%p, screen:%d, root:%u)",
CLUTTER_NOTE (BACKEND,
"GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)",
stage,
stage_x11->xdpy,
stage_x11->xscreen,
(unsigned int) stage_x11->xwin_root);
(unsigned int) stage_x11->xwin_root,
wrapper);
return stage;
}
static XVisualInfo *
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11,
gboolean for_offscreen)
{
XVisualInfo *xvisinfo;
int onscreen_gl_attributes[] = {
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_STENCIL_SIZE, 1,
0
};
int offscreen_gl_attributes[] = {
GLX_RGBA,
GLX_USE_GL,
GLX_DEPTH_SIZE, 0,
GLX_ALPHA_SIZE, 0,
GLX_STENCIL_SIZE, 1,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
0
};
if (backend_x11->xdpy == None || backend_x11->xscreen == None)
return NULL;
CLUTTER_NOTE (BACKEND,
"Retrieving GL visual (for %s use), dpy: %p, xscreen; %p (%d)",
for_offscreen ? "offscreen" : "onscreen",
backend_x11->xdpy,
backend_x11->xscreen,
backend_x11->xscreen_num);
xvisinfo = glXChooseVisual (backend_x11->xdpy,
backend_x11->xscreen_num,
for_offscreen ? offscreen_gl_attributes
: onscreen_gl_attributes);
return xvisinfo;
}
static void
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
gobject_class->constructor = clutter_backend_glx_constructor;
gobject_class->dispose = clutter_backend_glx_dispose;
@ -507,7 +614,10 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
backend_class->add_options = clutter_backend_glx_add_options;
backend_class->get_features = clutter_backend_glx_get_features;
backend_class->redraw = clutter_backend_glx_redraw;
backend_class->create_context = clutter_backend_glx_create_context;
backend_class->ensure_context = clutter_backend_glx_ensure_context;
backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info;
}
static void

View file

@ -135,14 +135,6 @@ texture_bind (ClutterGLXTexturePixmap *tex)
/* FIXME: fire off an error here? */
glBindTexture (target, handle);
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (tex))
== CLUTTER_TEXTURE_QUALITY_HIGH && tex->priv->can_mipmap)
{
cogl_texture_set_filters (cogl_tex,
COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR,
COGL_TEXTURE_FILTER_LINEAR);
}
return TRUE;
}
@ -167,6 +159,18 @@ on_glx_texture_pixmap_pre_paint (ClutterGLXTexturePixmap *texture,
texture->priv->mipmap_generate_queued = 0;
}
/* Disable mipmaps if we can't support them */
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (texture))
== CLUTTER_TEXTURE_QUALITY_HIGH
&& !texture->priv->can_mipmap)
{
CoglHandle material
= clutter_texture_get_cogl_material (CLUTTER_TEXTURE (texture));
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_LINEAR,
COGL_MATERIAL_FILTER_LINEAR);
}
}
static void
@ -214,9 +218,9 @@ clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self)
if ((rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE")))
{
if (strcasecmp (rect_env, "force") == 0)
if (g_ascii_strcasecmp (rect_env, "force") == 0)
_rectangle_state = CLUTTER_GLX_RECTANGLE_FORCE;
else if (strcasecmp (rect_env, "disable") == 0)
else if (g_ascii_strcasecmp (rect_env, "disable") == 0)
_rectangle_state = CLUTTER_GLX_RECTANGLE_DISALLOW;
else if (rect_env[0])
g_warning ("Unknown value for CLUTTER_PIXMAP_TEXTURE_RECTANGLE, "
@ -360,7 +364,7 @@ create_cogl_texture (ClutterTexture *texture,
{
handle
= cogl_texture_new_with_size (width, height,
-1, FALSE,
COGL_TEXTURE_NO_SLICING,
cogl_format | COGL_BGR_BIT);
using_rectangle = FALSE;

View file

@ -67,10 +67,8 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL);
/* Chain up so all children get unrealized, needed to move texture data
* across contexts
*/
CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize (actor);
if (CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize != NULL)
CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize (actor);
clutter_x11_trap_x_errors ();
@ -99,6 +97,12 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
stage_x11->xwin = None;
}
if (stage_x11->xvisinfo != None)
{
XFree (stage_x11->xvisinfo);
stage_x11->xvisinfo = None;
}
XSync (stage_x11->xdpy, False);
clutter_x11_untrap_x_errors ();
@ -111,42 +115,29 @@ clutter_stage_glx_realize (ClutterActor *actor)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
ClutterBackend *backend;
ClutterBackendGLX *backend_glx;
ClutterBackendX11 *backend_x11;
gboolean is_offscreen;
CLUTTER_NOTE (MISC, "Realizing main stage");
CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
G_OBJECT_TYPE_NAME (actor),
actor);
g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL);
backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
backend = clutter_get_default_backend ();
backend_glx = CLUTTER_BACKEND_GLX (backend);
backend_x11 = CLUTTER_BACKEND_X11 (backend);
if (G_LIKELY (!is_offscreen))
{
int gl_attributes[] =
{
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_STENCIL_SIZE, 1,
0
};
GError *error;
if (stage_x11->xvisinfo)
{
XFree (stage_x11->xvisinfo);
stage_x11->xvisinfo = None;
}
stage_x11->xvisinfo =
clutter_backend_x11_get_visual_info (backend_x11, FALSE);
/* The following check seems strange */
if (stage_x11->xvisinfo == None)
stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
stage_x11->xscreen,
gl_attributes);
if (!stage_x11->xvisinfo)
{
g_critical ("Unable to find suitable GL visual.");
goto fail;
@ -208,25 +199,17 @@ clutter_stage_glx_realize (ClutterActor *actor)
}
/* no user resize.. */
clutter_stage_x11_fix_window_size (stage_x11);
clutter_stage_x11_fix_window_size (stage_x11, -1, -1);
clutter_stage_x11_set_wm_protocols (stage_x11);
if (G_UNLIKELY (backend_glx->gl_context == None))
/* ask for a context; a no-op, if a context already exists */
error = NULL;
_clutter_backend_create_context (backend, FALSE, &error);
if (error)
{
CLUTTER_NOTE (GL, "Creating GL Context");
backend_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_x11->xvisinfo,
0,
True);
if (backend_glx->gl_context == None)
{
g_critical ("Unable to create suitable GL context.");
goto fail;
}
_cogl_set_indirect_context (!glXIsDirect (stage_x11->xdpy,
backend_glx->gl_context));
g_critical ("Unable to realize stage: %s", error->message);
g_error_free (error);
goto fail;
}
CLUTTER_NOTE (BACKEND, "Marking stage as realized");
@ -234,33 +217,23 @@ clutter_stage_glx_realize (ClutterActor *actor)
}
else
{
int gl_attributes[] = {
GLX_DEPTH_SIZE, 0,
GLX_ALPHA_SIZE, 0,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_USE_GL,
GLX_RGBA,
0
};
GError *error;
if (stage_x11->xvisinfo)
XFree (stage_x11->xvisinfo);
if (stage_x11->xvisinfo != None)
{
XFree (stage_x11->xvisinfo);
stage_x11->xvisinfo = None;
}
stage_x11->xvisinfo = NULL;
stage_x11->xvisinfo =
clutter_backend_x11_get_visual_info (backend_x11, TRUE);
CLUTTER_NOTE (GL, "glXChooseVisual");
stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
stage_x11->xscreen,
gl_attributes);
if (!stage_x11->xvisinfo)
if (stage_x11->xvisinfo == None)
{
g_critical ("Unable to find suitable GL visual.");
goto fail;
}
stage_x11->xpixmap = XCreatePixmap (stage_x11->xdpy,
stage_x11->xwin_root,
stage_x11->xwin_width,
@ -272,25 +245,20 @@ clutter_stage_glx_realize (ClutterActor *actor)
stage_x11->xvisinfo,
stage_x11->xpixmap);
if (backend_glx->gl_context == None)
/* ask for a context; a no-op, if a context already exists
*
* FIXME: we probably need a seperate offscreen context here
* - though it likely makes most sense to drop offscreen stages
* and rely on FBO's instead and GLXPixmaps seems mostly broken
* anyway..
*/
error = NULL;
_clutter_backend_create_context (backend, TRUE, &error);
if (error)
{
CLUTTER_NOTE (GL, "Creating GL Context");
/* FIXME: we probably need a seperate offscreen context here
* - though it likely makes most sense to drop offscreen stages
* and rely on FBO's instead and GLXPixmaps seems mostly broken
* anyway..
*/
backend_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_x11->xvisinfo,
0,
False);
if (backend_glx->gl_context == None)
{
g_critical ("Unable to create suitable GL context.");
goto fail;
}
g_critical ("Unable to realize stage: %s", error->message);
g_error_free (error);
goto fail;
}
CLUTTER_NOTE (BACKEND, "Marking stage as realized");
@ -310,12 +278,6 @@ fail:
static void
clutter_stage_glx_dispose (GObject *gobject)
{
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (gobject);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject);
if (stage_x11->xwin)
clutter_actor_unrealize (CLUTTER_ACTOR (stage_glx));
G_OBJECT_CLASS (clutter_stage_glx_parent_class)->dispose (gobject);
}

View file

@ -367,9 +367,9 @@ clutter_stage_osx_hide (ClutterActor *actor)
static void
clutter_stage_osx_get_preferred_width (ClutterActor *actor,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
gboolean is_resizable;
@ -394,9 +394,9 @@ clutter_stage_osx_get_preferred_width (ClutterActor *actor,
static void
clutter_stage_osx_get_preferred_height (ClutterActor *actor,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
gboolean is_resizable;
@ -420,9 +420,9 @@ clutter_stage_osx_get_preferred_height (ClutterActor *actor,
}
static void
clutter_stage_osx_allocate (ClutterActor *actor,
const ClutterActorBox *box,
gboolean origin_changed)
clutter_stage_osx_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterStageOSX *self = CLUTTER_STAGE_OSX (actor);
ClutterActorClass *parent_class;
@ -452,7 +452,7 @@ clutter_stage_osx_allocate (ClutterActor *actor,
/* chain up */
parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class);
parent_class->allocate (actor, box, origin_changed);
parent_class->allocate (actor, box, flags);
}
/*************************************************************************/

View file

@ -1,4 +1,5 @@
source_c = \
cogl-pango-display-list.c \
cogl-pango-fontmap.c \
cogl-pango-render.c \
cogl-pango-glyph-cache.c
@ -6,26 +7,27 @@ source_c = \
source_h = cogl-pango.h
source_h_priv = \
cogl-pango-display-list.h \
cogl-pango-private.h \
cogl-pango-glyph-cache.h
noinst_LTLIBRARIES = libcoglpango.la
libcoglpango_la_SOURCES = \
$(source_c) \
$(source_h) \
$(source_h_priv)
libcoglpango_la_SOURCES = $(source_c) $(source_h) $(source_h_priv)
libcoglpango_la_CPPFLAGS = $(CLUTTER_CFLAGS)
libcoglpango_la_LIBADD = $(CLUTTER_LIBS)
INCLUDES = \
@GCC_FLAGS@ @CLUTTER_CFLAGS@ \
$(CLUTTER_DEBUG_CFLAGS) \
$(MAINTAINER_CFLAGS) \
-DCLUTTER_COMPILATION \
-I$(top_srcdir) \
-I$(top_srcdir)/clutter \
-I$(top_srcdir)/clutter/cogl \
-I$(top_builddir)/clutter \
-I$(top_builddir)/clutter/cogl
-DCLUTTER_COMPILATION \
-DG_LOG_DOMAIN=\"CoglPango\" \
-I$(top_srcdir) \
-I$(top_srcdir)/clutter \
-I$(top_srcdir)/clutter/cogl \
-I$(top_builddir)/clutter \
-I$(top_builddir)/clutter/cogl \
$(CLUTTER_DEBUG_CFLAGS) \
$(COGL_DEBUG_CFLAGS) \
$(MAINTAINER_CFLAGS)
coglpangoheadersdir = $(includedir)/clutter-@CLUTTER_MAJORMINOR@/cogl
coglpangoheaders_HEADERS = $(source_h)

View file

@ -0,0 +1,353 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib.h>
#include <cogl/cogl.h>
#include <string.h>
#include "cogl-pango-display-list.h"
typedef enum
{
COGL_PANGO_DISPLAY_LIST_TEXTURE,
COGL_PANGO_DISPLAY_LIST_RECTANGLE,
COGL_PANGO_DISPLAY_LIST_TRAPEZOID
} CoglPangoDisplayListNodeType;
typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode;
typedef struct _CoglPangoDisplayListVertex CoglPangoDisplayListVertex;
struct _CoglPangoDisplayList
{
CoglColor color;
GSList *nodes;
GSList *last_node;
};
struct _CoglPangoDisplayListNode
{
CoglPangoDisplayListNodeType type;
CoglColor color;
union
{
struct
{
/* The texture to render these coords from */
CoglHandle texture;
/* Array of vertex data to render out of this texture */
GArray *verts;
/* A VBO representing those vertices */
CoglHandle vertex_buffer;
} texture;
struct
{
float x_1, y_1;
float x_2, y_2;
} rectangle;
struct
{
float y_1;
float x_11;
float x_21;
float y_2;
float x_12;
float x_22;
} trapezoid;
} d;
};
struct _CoglPangoDisplayListVertex
{
float x, y, t_x, t_y;
};
CoglPangoDisplayList *
_cogl_pango_display_list_new (void)
{
return g_slice_new0 (CoglPangoDisplayList);
}
static void
_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl,
CoglPangoDisplayListNode *node)
{
if (dl->last_node)
dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node);
else
dl->last_node = dl->nodes = g_slist_prepend (NULL, node);
}
void
_cogl_pango_display_list_set_color (CoglPangoDisplayList *dl,
const CoglColor *color)
{
dl->color = *color;
}
void
_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
CoglHandle texture,
float x_1, float y_1,
float x_2, float y_2,
float tx_1, float ty_1,
float tx_2, float ty_2)
{
CoglPangoDisplayListNode *node;
CoglPangoDisplayListVertex *verts;
/* Add to the last node if it is a texture node with the same
target texture */
if (dl->last_node
&& (node = dl->last_node->data)->type == COGL_PANGO_DISPLAY_LIST_TEXTURE
&& node->d.texture.texture == texture
&& !memcmp (&dl->color, &node->color, sizeof (CoglColor)))
{
/* Get rid of the vertex buffer so that it will be recreated */
if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE)
{
cogl_vertex_buffer_unref (node->d.texture.vertex_buffer);
node->d.texture.vertex_buffer = COGL_INVALID_HANDLE;
}
}
else
{
/* Otherwise create a new node */
node = g_slice_new (CoglPangoDisplayListNode);
node->type = COGL_PANGO_DISPLAY_LIST_TEXTURE;
node->color = dl->color;
node->d.texture.texture = cogl_texture_ref (texture);
node->d.texture.verts
= g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListVertex));
node->d.texture.vertex_buffer = COGL_INVALID_HANDLE;
_cogl_pango_display_list_append_node (dl, node);
}
g_array_set_size (node->d.texture.verts,
node->d.texture.verts->len + 4);
verts = &g_array_index (node->d.texture.verts,
CoglPangoDisplayListVertex,
node->d.texture.verts->len - 4);
verts->x = x_1;
verts->y = y_1;
verts->t_x = tx_1;
verts->t_y = ty_1;
verts++;
verts->x = x_1;
verts->y = y_2;
verts->t_x = tx_1;
verts->t_y = ty_2;
verts++;
verts->x = x_2;
verts->y = y_2;
verts->t_x = tx_2;
verts->t_y = ty_2;
verts++;
verts->x = x_2;
verts->y = y_1;
verts->t_x = tx_2;
verts->t_y = ty_1;
}
void
_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl,
float x_1, float y_1,
float x_2, float y_2)
{
CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
node->type = COGL_PANGO_DISPLAY_LIST_RECTANGLE;
node->color = dl->color;
node->d.rectangle.x_1 = x_1;
node->d.rectangle.y_1 = y_1;
node->d.rectangle.x_2 = x_2;
node->d.rectangle.y_2 = y_2;
_cogl_pango_display_list_append_node (dl, node);
}
void
_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
float y_1,
float x_11,
float x_21,
float y_2,
float x_12,
float x_22)
{
CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
node->type = COGL_PANGO_DISPLAY_LIST_TRAPEZOID;
node->color = dl->color;
node->d.trapezoid.y_1 = y_1;
node->d.trapezoid.x_11 = x_11;
node->d.trapezoid.x_21 = x_21;
node->d.trapezoid.y_2 = y_2;
node->d.trapezoid.x_12 = x_12;
node->d.trapezoid.x_22 = x_22;
_cogl_pango_display_list_append_node (dl, node);
}
static void
_cogl_pango_display_list_render_texture (CoglHandle material,
CoglPangoDisplayListNode *node)
{
cogl_material_set_layer (material, 0, node->d.texture.texture);
cogl_material_set_color (material, &node->color);
cogl_set_source (material);
if (node->d.texture.vertex_buffer == COGL_INVALID_HANDLE)
{
CoglHandle vb = cogl_vertex_buffer_new (node->d.texture.verts->len);
cogl_vertex_buffer_add (vb, "gl_Vertex", 2,
COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
sizeof (CoglPangoDisplayListVertex),
&g_array_index (node->d.texture.verts,
CoglPangoDisplayListVertex, 0).x);
cogl_vertex_buffer_add (vb, "gl_MultiTexCoord0", 2,
COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
sizeof (CoglPangoDisplayListVertex),
&g_array_index (node->d.texture.verts,
CoglPangoDisplayListVertex,
0).t_x);
cogl_vertex_buffer_submit (vb);
node->d.texture.vertex_buffer = vb;
}
#ifdef CLUTTER_COGL_HAS_GL
cogl_vertex_buffer_draw (node->d.texture.vertex_buffer,
GL_QUADS,
0, node->d.texture.verts->len);
#else /* CLUTTER_COGL_HAS_GL */
{
/* GLES doesn't support GL_QUADS so instead we use a VBO with
indexed vertices to generate GL_TRIANGLES from the quads */
int n_indices = node->d.texture.verts->len / 4 * 6;
CoglHandle indices_vbo
= cogl_vertex_buffer_indices_get_for_quads (n_indices);
cogl_vertex_buffer_draw_elements (node->d.texture.vertex_buffer,
COGL_VERTICES_MODE_TRIANGLES,
indices_vbo,
0, node->d.texture.verts->len - 1,
0, n_indices);
}
#endif /* CLUTTER_COGL_HAS_GL */
}
void
_cogl_pango_display_list_render (CoglPangoDisplayList *dl,
CoglHandle glyph_material,
CoglHandle solid_material)
{
GSList *l;
for (l = dl->nodes; l; l = l->next)
{
CoglPangoDisplayListNode *node = l->data;
switch (node->type)
{
case COGL_PANGO_DISPLAY_LIST_TEXTURE:
_cogl_pango_display_list_render_texture (glyph_material, node);
break;
case COGL_PANGO_DISPLAY_LIST_RECTANGLE:
cogl_material_set_color (solid_material, &node->color);
cogl_set_source (solid_material);
cogl_rectangle (node->d.rectangle.x_1,
node->d.rectangle.y_1,
node->d.rectangle.x_2,
node->d.rectangle.y_2);
break;
case COGL_PANGO_DISPLAY_LIST_TRAPEZOID:
{
float points[8];
points[0] = node->d.trapezoid.x_11;
points[1] = node->d.trapezoid.y_1;
points[2] = node->d.trapezoid.x_12;
points[3] = node->d.trapezoid.y_2;
points[4] = node->d.trapezoid.x_22;
points[5] = node->d.trapezoid.y_2;
points[6] = node->d.trapezoid.x_21;
points[7] = node->d.trapezoid.y_1;
cogl_material_set_color (solid_material, &node->color);
cogl_set_source (solid_material);
cogl_path_polygon (points, 4);
cogl_path_fill ();
}
break;
}
}
}
static void
_cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node)
{
if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE)
{
g_array_free (node->d.texture.verts, TRUE);
if (node->d.texture.texture != COGL_INVALID_HANDLE)
cogl_texture_unref (node->d.texture.texture);
if (node->d.texture.vertex_buffer != COGL_INVALID_HANDLE)
cogl_vertex_buffer_unref (node->d.texture.vertex_buffer);
}
g_slice_free (CoglPangoDisplayListNode, node);
}
void
_cogl_pango_display_list_clear (CoglPangoDisplayList *dl)
{
g_slist_foreach (dl->nodes, (GFunc) _cogl_pango_display_list_node_free, NULL);
g_slist_free (dl->nodes);
dl->nodes = NULL;
dl->last_node = NULL;
}
void
_cogl_pango_display_list_free (CoglPangoDisplayList *dl)
{
_cogl_pango_display_list_clear (dl);
g_slice_free (CoglPangoDisplayList, dl);
}

Some files were not shown because too many files have changed in this diff Show more