/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Tomas Frydrych * * Copyright (C) 2006, 2007 OpenedHand * * 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. */ #define G_IMPLEMENT_INLINES #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "clutter-fixed.h" #include "clutter-private.h" /** * SECTION:clutter-fixed * @short_description: Fixed Point API * * Clutter has a fixed point API targeted at platforms without a * floating point unit, such as embedded devices. On such platforms * this API should be preferred to the floating point one as it does * not trigger the slow path of software emulation, relying on integer * math for fixed-to-floating and floating-to-fixed conversion. * * It is no recommened for use on platforms with a floating point unit * (eg desktop systems) nor for use in bindings. * * Basic rules of Fixed Point arithmethic: * * * * Two fixed point numbers can be directly added, * subtracted and have their modulus taken. * * * To add other numerical type to a fixed point number it has to * be first converted to fixed point. * * * A fixed point number can be directly multiplied or divided by * an integer. * * * Two fixed point numbers can only be multiplied and divided by the * provided %CLUTTER_FIXED_MUL and %CLUTTER_FIXED_DIV macros. * * */ static GTypeInfo _info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, }; static GTypeFundamentalInfo _finfo = { 0, }; static void clutter_value_init_fixed (GValue *value) { value->data[0].v_int = 0; } static void clutter_value_copy_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = src->data[0].v_int; } static gchar * clutter_value_collect_fixed (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { value->data[0].v_int = collect_values[0].v_int; return NULL; } static gchar * clutter_value_lcopy_fixed (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint32 *fixed_p = collect_values[0].v_pointer; if (!fixed_p) return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); *fixed_p = value->data[0].v_int; return NULL; } static void clutter_value_transform_fixed_int (const GValue *src, GValue *dest) { dest->data[0].v_int = COGL_FIXED_TO_INT (src->data[0].v_int); } static void clutter_value_transform_fixed_double (const GValue *src, GValue *dest) { dest->data[0].v_double = COGL_FIXED_TO_DOUBLE (src->data[0].v_int); } static void clutter_value_transform_fixed_float (const GValue *src, GValue *dest) { dest->data[0].v_float = COGL_FIXED_TO_FLOAT (src->data[0].v_int); } static void clutter_value_transform_int_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = COGL_FIXED_FROM_INT (src->data[0].v_int); } static void clutter_value_transform_double_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = COGL_FIXED_FROM_FLOAT (src->data[0].v_double); } static void clutter_value_transform_float_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = COGL_FIXED_FROM_FLOAT (src->data[0].v_float); } static const GTypeValueTable _clutter_fixed_value_table = { clutter_value_init_fixed, NULL, clutter_value_copy_fixed, NULL, "i", clutter_value_collect_fixed, "p", clutter_value_lcopy_fixed }; GType clutter_fixed_get_type (void) { static GType _clutter_fixed_type = 0; if (G_UNLIKELY (_clutter_fixed_type == 0)) { _info.value_table = & _clutter_fixed_value_table; _clutter_fixed_type = g_type_register_fundamental (g_type_fundamental_next (), I_("ClutterFixed"), &_info, &_finfo, 0); g_value_register_transform_func (_clutter_fixed_type, G_TYPE_INT, clutter_value_transform_fixed_int); g_value_register_transform_func (G_TYPE_INT, _clutter_fixed_type, clutter_value_transform_int_fixed); g_value_register_transform_func (_clutter_fixed_type, G_TYPE_FLOAT, clutter_value_transform_fixed_float); g_value_register_transform_func (G_TYPE_FLOAT, _clutter_fixed_type, clutter_value_transform_float_fixed); g_value_register_transform_func (_clutter_fixed_type, G_TYPE_DOUBLE, clutter_value_transform_fixed_double); g_value_register_transform_func (G_TYPE_DOUBLE, _clutter_fixed_type, clutter_value_transform_double_fixed); } return _clutter_fixed_type; } /** * clutter_value_set_fixed: * @value: a #GValue initialized to #CLUTTER_TYPE_FIXED * @fixed_: the fixed point value to set * * Sets @value to @fixed_. * * Since: 0.8 */ void clutter_value_set_fixed (GValue *value, ClutterFixed fixed_) { g_return_if_fail (CLUTTER_VALUE_HOLDS_FIXED (value)); value->data[0].v_int = fixed_; } /** * clutter_value_get_fixed: * @value: a #GValue initialized to #CLUTTER_TYPE_FIXED * * Gets the fixed point value stored inside @value. * * Return value: the value inside the passed #GValue * * Since: 0.8 */ ClutterFixed clutter_value_get_fixed (const GValue *value) { g_return_val_if_fail (CLUTTER_VALUE_HOLDS_FIXED (value), 0); return value->data[0].v_int; } static void param_fixed_init (GParamSpec *pspec) { ClutterParamSpecFixed *fspec = CLUTTER_PARAM_SPEC_FIXED (pspec); fspec->minimum = COGL_FIXED_MIN; fspec->maximum = COGL_FIXED_MAX; fspec->default_value = 0; } static void param_fixed_set_default (GParamSpec *pspec, GValue *value) { value->data[0].v_int = CLUTTER_PARAM_SPEC_FIXED (pspec)->default_value; } static gboolean param_fixed_validate (GParamSpec *pspec, GValue *value) { ClutterParamSpecFixed *fspec = CLUTTER_PARAM_SPEC_FIXED (pspec); gint oval = COGL_FIXED_TO_INT (value->data[0].v_int); gint min, max, val; g_assert (CLUTTER_IS_PARAM_SPEC_FIXED (pspec)); /* we compare the integer part of the value because the minimum * and maximum values cover just that part of the representation */ min = fspec->minimum; max = fspec->maximum; val = COGL_FIXED_TO_INT (value->data[0].v_int); val = CLAMP (val, min, max); if (val != oval) { value->data[0].v_int = val; return TRUE; } return FALSE; } static gint param_fixed_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { if (value1->data[0].v_int < value2->data[0].v_int) return -1; else return value1->data[0].v_int > value2->data[0].v_int; } GType clutter_param_fixed_get_type (void) { static GType pspec_type = 0; if (G_UNLIKELY (pspec_type == 0)) { const GParamSpecTypeInfo pspec_info = { sizeof (ClutterParamSpecFixed), 16, param_fixed_init, CLUTTER_TYPE_FIXED, NULL, param_fixed_set_default, param_fixed_validate, param_fixed_values_cmp, }; pspec_type = g_param_type_register_static (I_("ClutterParamSpecFixed"), &pspec_info); } return pspec_type; } /** * clutter_param_spec_fixed: * @name: name of the property * @nick: short name * @blurb: description (can be translatable) * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * @flags: flags for the param spec * * Creates a #GParamSpec for properties using #ClutterFixed values * * Return value: the newly created #GParamSpec * * Since: 0.8 */ GParamSpec * clutter_param_spec_fixed (const gchar *name, const gchar *nick, const gchar *blurb, ClutterFixed minimum, ClutterFixed maximum, ClutterFixed default_value, GParamFlags flags) { ClutterParamSpecFixed *fspec; g_return_val_if_fail (default_value >= minimum && default_value <= maximum, NULL); fspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_FIXED, name, nick, blurb, flags); fspec->minimum = minimum; fspec->maximum = maximum; fspec->default_value = default_value; return G_PARAM_SPEC (fspec); }