ux-dx 0.2.1

3D Graphics Primitives for Angular Rust
Documentation
use super::Matrix;
use std::mem;

// typedef enum _MatrixOp
// {
//   MATRIX_OP_LOAD_IDENTITY,
//   MATRIX_OP_TRANSLATE,
//   MATRIX_OP_ROTATE,
//   MATRIX_OP_ROTATE_QUATERNION,
//   MATRIX_OP_ROTATE_EULER,
//   MATRIX_OP_SCALE,
//   MATRIX_OP_MULTIPLY,
//   MATRIX_OP_LOAD,
//   MATRIX_OP_SAVE,
// } MatrixOp;

// typedef struct _MatrixEntryTranslate
// {
//   MatrixEntry _parent_data;

//   float x;
//   float y;
//   float z;

// } MatrixEntryTranslate;

// typedef struct _MatrixEntryRotate
// {
//   MatrixEntry _parent_data;

//   float angle;
//   float x;
//   float y;
//   float z;

// } MatrixEntryRotate;

// typedef struct _MatrixEntryRotateEuler
// {
//   MatrixEntry _parent_data;

//   /* This doesn't store an actual Euler in order to avoid the
//    * padding */
//   float heading;
//   float pitch;
//   float roll;
// } MatrixEntryRotateEuler;

// typedef struct _MatrixEntryRotateQuaternion
// {
//   MatrixEntry _parent_data;

//   /* This doesn't store an actual Quaternion in order to avoid the
//    * padding */
//   float values[4];
// } MatrixEntryRotateQuaternion;

// typedef struct _MatrixEntryScale
// {
//   MatrixEntry _parent_data;

//   float x;
//   float y;
//   float z;

// } MatrixEntryScale;

// typedef struct _MatrixEntryMultiply
// {
//   MatrixEntry _parent_data;

//   Matrix *matrix;

// } MatrixEntryMultiply;

// typedef struct _MatrixEntryLoad
// {
//   MatrixEntry _parent_data;

//   Matrix *matrix;

// } MatrixEntryLoad;

// typedef struct _MatrixEntrySave
// {
//   MatrixEntry _parent_data;

//   Matrix *cache;
//   Bool cache_valid;

// } MatrixEntrySave;

// typedef union _MatrixEntryFull
// {
//   MatrixEntry any;
//   MatrixEntryTranslate translate;
//   MatrixEntryRotate rotate;
//   MatrixEntryRotateEuler rotate_euler;
//   MatrixEntryRotateQuaternion rotate_quaternion;
//   MatrixEntryScale scale;
//   MatrixEntryMultiply multiply;
//   MatrixEntryLoad load;
//   MatrixEntrySave save;
// } MatrixEntryFull;

// typedef struct _MatrixEntryCache
// {
//   MatrixEntry *entry;
//   Bool flushed_identity;
//   Bool flipped;
// } MatrixEntryCache;

// void
// _matrix_entry_identity_init (MatrixEntry *entry);

// typedef enum {
//   MATRIX_MODELVIEW,
//   MATRIX_PROJECTION,
//   MATRIX_TEXTURE
// } MatrixMode;

// MatrixEntry:
//
// Represents a single immutable transformation that was retrieved
// from a #MatrixStack using matrix_stack_get_entry().
//
// Internally a #MatrixEntry represents a single matrix
// operation (such as "rotate", "scale", "translate") which is applied
// to the transform of a single parent entry.
//
// Using the #MatrixStack api effectively builds up a graph of
// these immutable #MatrixEntry structures whereby operations
// that can be shared between multiple transformations will result
// in shared #MatrixEntry nodes in the graph.
//
// When a #MatrixStack is first created it references one
// #MatrixEntry that represents a single "load identity"
// operation. This serves as the root entry and all operations
// that are then applied to the stack will extend the graph
// starting from this root "load identity" entry.
//
// Given the typical usage model for a #MatrixStack and the way
// the entries are built up while traversing a scenegraph then in most
// cases where an application is interested in comparing two
// transformations for equality then it is enough to simply compare
// two #MatrixEntry pointers directly. Technically this can lead
// to false negatives that could be identified with a deeper
// comparison but often these false negatives are unlikely and
// don't matter anyway so this enables extremely cheap comparisons.
//
// #MatrixEntrys are reference counted using
// matrix_entry_ref() and matrix_entry_unref() not with
// object_ref() and object_unref().
#[derive(Debug, PartialOrd, Ord)] // Hash
pub struct MatrixEntry {
    //     MatrixEntry *parent;
    //     MatrixOp op;
    //     unsigned int ref_count;

    //   #ifdef DEBUG_ENABLED
    //     /* used for performance tracing */
    //     int composite_gets;
    //   #endif
}

impl MatrixEntry {
    /// Determines if the only difference between two transforms is a
    /// translation and if so returns what the `x`, `y`, and `z` components of
    /// the translation are.
    ///
    /// If the difference between the two translations involves anything
    /// other than a translation then the fn returns `false`.
    /// ## `other`
    /// A second reference transform
    /// ## `x`
    /// The destination for the x-component of the translation
    /// ## `y`
    /// The destination for the y-component of the translation
    /// ## `z`
    /// The destination for the z-component of the translation
    ///
    /// # Returns
    ///
    /// `true` if the only difference between the transform of
    ///  `self` and the transform of `other` is a translation,
    ///  otherwise `false`.
    pub fn calculate_translation(&self, other: &MatrixEntry) -> (bool, f32, f32, f32) {
        // GSList *head0 = NULL;
        // GSList *head1 = NULL;
        // MatrixEntry *node0;
        // MatrixEntry *node1;
        // int len0 = 0;
        // int len1 = 0;
        // int count;
        // GSList *common_ancestor0;
        // GSList *common_ancestor1;

        // Algorithm:
        //
        // 1) Ignoring _OP_SAVE entries walk the ancestors of each entry to
        //    the root node or any non-translation node, adding a pointer to
        //    each ancestor node to two linked lists.
        //
        // 2) Compare the lists to find the nodes where they start to
        //    differ marking the common_ancestor node for each list.
        //
        // 3) For the list corresponding to entry0, start iterating after
        //    the common ancestor applying the negative of all translations
        //    to x, y and z.
        //
        // 4) For the list corresponding to entry1, start iterating after
        //    the common ancestor applying the positive of all translations
        //    to x, y and z.
        //
        // If we come across any non-translation operations during 3) or 4)
        // then bail out returning false.

        // for (node0 = entry0; node0; node0 = node0->parent) {
        //     GSList *link;

        //     if (node0->op == MATRIX_OP_SAVE)
        //         continue;

        //     link = alloca (sizeof (GSList));
        //     link->next = head0;
        //     link->data = node0;
        //     head0 = link;
        //     len0++;

        //     if (node0->op != MATRIX_OP_TRANSLATE)
        //         break;
        //     }
        // for (node1 = entry1; node1; node1 = node1->parent)
        //     {
        //     GSList *link;

        //     if (node1->op == MATRIX_OP_SAVE)
        //         continue;

        //     link = alloca (sizeof (GSList));
        //     link->next = head1;
        //     link->data = node1;
        //     head1 = link;
        //     len1++;

        //     if (node1->op != MATRIX_OP_TRANSLATE)
        //         break;
        //     }

        // if (head0->data != head1->data)
        //     return false;

        // common_ancestor0 = head0;
        // common_ancestor1 = head1;
        // head0 = head0->next;
        // head1 = head1->next;
        // count = MIN (len0, len1) - 1;
        // while (count--)
        //     {
        //     if (head0->data != head1->data)
        //         break;
        //     common_ancestor0 = head0;
        //     common_ancestor1 = head1;
        //     head0 = head0->next;
        //     head1 = head1->next;
        //     }

        //x = 0;
        //y = 0;
        //z = 0;

        // for (head0 = common_ancestor0->next; head0; head0 = head0->next)
        //     {
        //     MatrixEntryTranslate *translate;

        //     node0 = head0->data;

        //     if (node0->op != MATRIX_OP_TRANSLATE)
        //         return false;

        //     translate = (MatrixEntryTranslate *)node0;

        //     *x = *x - translate->x;
        //     *y = *y - translate->y;
        //     *z = *z - translate->z;
        //     }
        // for (head1 = common_ancestor1->next; head1; head1 = head1->next)
        //     {
        //     MatrixEntryTranslate *translate;

        //     node1 = head1->data;

        //     if (node1->op != MATRIX_OP_TRANSLATE)
        //         return false;

        //     translate = (MatrixEntryTranslate *)node1;

        //     *x = *x + translate->x;
        //     *y = *y + translate->y;
        //     *z = *z + translate->z;
        //     }

        // return true;
        unimplemented!()
    }

    /// Compares two arbitrary `MatrixEntry` transforms for equality
    /// returning `true` if they are equal or `false` otherwise.
    ///
    /// In many cases it is unnecessary to use this api and instead
    /// direct pointer comparisons of entries are good enough and much
    /// cheaper too.
    /// ## `other`
    /// A second `MatrixEntry` to compare
    ///
    /// # Returns
    ///
    /// `true` if `self` represents the same transform as
    ///  `other`, otherwise `false`.
    fn equal(&self, other: &Self) -> bool {
        // for (; entry0 && entry1; entry0 = entry0->parent, entry1 = entry1->parent)
        //  {
        //    entry0 = _matrix_entry_skip_saves (entry0);
        //    entry1 = _matrix_entry_skip_saves (entry1);

        //    if (entry0 == entry1)
        //      return true;

        //    if (entry0->op != entry1->op)
        //      return false;

        //    switch (entry0->op)
        //      {
        //      case MATRIX_OP_LOAD_IDENTITY:
        //        return true;
        //      case MATRIX_OP_TRANSLATE:
        //        {
        //          MatrixEntryTranslate *translate0 =
        //            (MatrixEntryTranslate *)entry0;
        //          MatrixEntryTranslate *translate1 =
        //            (MatrixEntryTranslate *)entry1;
        //          /* We could perhaps use an epsilon to compare here?
        //           * I expect the false negatives are probaly never going to
        //           * be a problem and this is a bit cheaper. */
        //          if (translate0->x != translate1->x ||
        //              translate0->y != translate1->y ||
        //              translate0->z != translate1->z)
        //            return false;
        //        }
        //        break;
        //      case MATRIX_OP_ROTATE:
        //        {
        //          MatrixEntryRotate *rotate0 =
        //            (MatrixEntryRotate *)entry0;
        //          MatrixEntryRotate *rotate1 =
        //            (MatrixEntryRotate *)entry1;
        //          if (rotate0->angle != rotate1->angle ||
        //              rotate0->x != rotate1->x ||
        //              rotate0->y != rotate1->y ||
        //              rotate0->z != rotate1->z)
        //            return false;
        //        }
        //        break;
        //      case MATRIX_OP_ROTATE_QUATERNION:
        //        {
        //          MatrixEntryRotateQuaternion *rotate0 =
        //            (MatrixEntryRotateQuaternion *)entry0;
        //          MatrixEntryRotateQuaternion *rotate1 =
        //            (MatrixEntryRotateQuaternion *)entry1;
        //          int i;
        //          for (i = 0; i < 4; i++)
        //            if (rotate0->values[i] != rotate1->values[i])
        //              return false;
        //        }
        //        break;
        //      case MATRIX_OP_ROTATE_EULER:
        //        {
        //          MatrixEntryRotateEuler *rotate0 =
        //            (MatrixEntryRotateEuler *)entry0;
        //          MatrixEntryRotateEuler *rotate1 =
        //            (MatrixEntryRotateEuler *)entry1;

        //          if (rotate0->heading != rotate1->heading ||
        //              rotate0->pitch != rotate1->pitch ||
        //              rotate0->roll != rotate1->roll)
        //            return false;
        //        }
        //        break;
        //      case MATRIX_OP_SCALE:
        //        {
        //          MatrixEntryScale *scale0 = (MatrixEntryScale *)entry0;
        //          MatrixEntryScale *scale1 = (MatrixEntryScale *)entry1;
        //          if (scale0->x != scale1->x ||
        //              scale0->y != scale1->y ||
        //              scale0->z != scale1->z)
        //            return false;
        //        }
        //        break;
        //      case MATRIX_OP_MULTIPLY:
        //        {
        //          MatrixEntryMultiply *mult0 = (MatrixEntryMultiply *)entry0;
        //          MatrixEntryMultiply *mult1 = (MatrixEntryMultiply *)entry1;
        //          if (!matrix_equal (mult0->matrix, mult1->matrix))
        //            return false;
        //        }
        //        break;
        //      case MATRIX_OP_LOAD:
        //        {
        //          MatrixEntryLoad *load0 = (MatrixEntryLoad *)entry0;
        //          MatrixEntryLoad *load1 = (MatrixEntryLoad *)entry1;
        //          /* There's no need to check any further since an
        //           * _OP_LOAD makes all the ancestors redundant as far as
        //           * the final matrix value is concerned. */
        //          return matrix_equal (load0->matrix, load1->matrix);
        //        }
        //      case MATRIX_OP_SAVE:
        //        /* We skip over saves above so we shouldn't see save entries */
        //        g_warn_if_reached ();
        //      }
        //  }

        // return false;
        unimplemented!()
    }

    /// Resolves the current `self` transform into a `Matrix` by
    /// combining the sequence of operations that have been applied to
    /// build up the current transform.
    ///
    /// There are two possible ways that this fn may return its
    /// result depending on whether it's possible to directly point
    /// to an internal `Matrix` or whether the result needs to be
    /// composed of multiple operations.
    ///
    /// If an internal matrix contains the required result then this
    /// fn will directly return a pointer to that matrix, otherwise
    /// if the fn returns `None` then `matrix` will be initialized
    /// to match the transform of `self`.
    ///
    /// `matrix` will be left untouched if a direct pointer is
    /// returned.
    /// ## `matrix`
    /// The potential destination for the transform as
    ///  a matrix
    ///
    /// # Returns
    ///
    /// A direct pointer to a `Matrix` transform or `None`
    ///  and in that case `matrix` will be initialized with
    ///  the effective transform represented by `self`.
    pub fn get(&self) -> (Matrix, Matrix) {
        // int depth;
        // MatrixEntry *current;
        // MatrixEntry **children;
        // int i;

        // for (depth = 0, current = entry;
        //     current;
        //     current = current->parent, depth++)
        //     {
        //     switch (current->op)
        //         {
        //         case MATRIX_OP_LOAD_IDENTITY:
        //         matrix_init_identity (matrix);
        //         goto initialized;
        //         case MATRIX_OP_LOAD:
        //         {
        //             MatrixEntryLoad *load = (MatrixEntryLoad *)current;
        //             _matrix_init_from_matrix_without_inverse (matrix,
        //                                                         load->matrix);
        //             goto initialized;
        //         }
        //         case MATRIX_OP_SAVE:
        //         {
        //             MatrixEntrySave *save = (MatrixEntrySave *)current;
        //             if (!save->cache_valid)
        //             {
        //                 Magazine *matrices_magazine =
        //                 matrix_stack_matrices_magazine;
        //                 save->cache = _magazine_chunk_alloc (matrices_magazine);
        //                 matrix_entry_get (current->parent, save->cache);
        //                 save->cache_valid = true;
        //             }
        //             _matrix_init_from_matrix_without_inverse (matrix, save->cache);
        //             goto initialized;
        //         }
        //         default:
        //         continue;
        //         }
        //     }

        // initialized:

        // if (depth == 0)
        //     {
        //     switch (entry->op)
        //         {
        //         case MATRIX_OP_LOAD_IDENTITY:
        //         case MATRIX_OP_TRANSLATE:
        //         case MATRIX_OP_ROTATE:
        //         case MATRIX_OP_ROTATE_QUATERNION:
        //         case MATRIX_OP_ROTATE_EULER:
        //         case MATRIX_OP_SCALE:
        //         case MATRIX_OP_MULTIPLY:
        //         return NULL;

        //         case MATRIX_OP_LOAD:
        //         {
        //             MatrixEntryLoad *load = (MatrixEntryLoad *)entry;
        //             return load->matrix;
        //         }
        //         case MATRIX_OP_SAVE:
        //         {
        //             MatrixEntrySave *save = (MatrixEntrySave *)entry;
        //             return save->cache;
        //         }
        //         }
        //     g_warn_if_reached ();
        //     return NULL;
        //     }

        // #ifdef ENABLE_DEBUG
        // if (!current)
        //     {
        //     g_warning ("Inconsistent matrix stack");
        //     return NULL;
        //     }

        // entry->composite_gets++;
        // #endif

        // children = g_alloca (sizeof (MatrixEntry) * depth);

        // We need walk the list of entries from the init/load/save entry
        // back towards the leaf node but the nodes don't link to their
        // children so we need to re-walk them here to add to a separate
        // array. */
        // for (i = depth - 1, current = entry;
        //     i >= 0 && current;
        //     i--, current = current->parent)
        //     {
        //     children[i] = current;
        //     }

        // #ifdef ENABLE_DEBUG
        // if (DEBUG_ENABLED (DEBUG_PERFORMANCE) &&
        //     entry->composite_gets >= 2)
        //     {
        //     NOTE (PERFORMANCE,
        //                 "Re-composing a matrix stack entry multiple times");
        //     }
        // #endif

        // for (i = 0; i < depth; i++)
        //     {
        //     switch (children[i]->op)
        //         {
        //         case MATRIX_OP_TRANSLATE:
        //         {
        //             MatrixEntryTranslate *translate =
        //             (MatrixEntryTranslate *)children[i];
        //             matrix_translate (matrix,
        //                                 translate->x,
        //                                 translate->y,
        //                                 translate->z);
        //             continue;
        //         }
        //         case MATRIX_OP_ROTATE:
        //         {
        //             MatrixEntryRotate *rotate=
        //             (MatrixEntryRotate *)children[i];
        //             matrix_rotate (matrix,
        //                                 rotate->angle,
        //                                 rotate->x,
        //                                 rotate->y,
        //                                 rotate->z);
        //             continue;
        //         }
        //         case MATRIX_OP_ROTATE_EULER:
        //         {
        //             MatrixEntryRotateEuler *rotate =
        //             (MatrixEntryRotateEuler *)children[i];
        //             Euler euler;
        //             euler_init (&euler,
        //                             rotate->heading,
        //                             rotate->pitch,
        //                             rotate->roll);
        //             matrix_rotate_euler (matrix,
        //                                     &euler);
        //             continue;
        //         }
        //         case MATRIX_OP_ROTATE_QUATERNION:
        //         {
        //             MatrixEntryRotateQuaternion *rotate =
        //             (MatrixEntryRotateQuaternion *)children[i];
        //             Quaternion quaternion;
        //             quaternion_init_from_array (&quaternion, rotate->values);
        //             matrix_rotate_quaternion (matrix, &quaternion);
        //             continue;
        //         }
        //         case MATRIX_OP_SCALE:
        //         {
        //             MatrixEntryScale *scale =
        //             (MatrixEntryScale *)children[i];
        //             matrix_scale (matrix,
        //                             scale->x,
        //                             scale->y,
        //                             scale->z);
        //             continue;
        //         }
        //         case MATRIX_OP_MULTIPLY:
        //         {
        //             MatrixEntryMultiply *multiply =
        //             (MatrixEntryMultiply *)children[i];
        //             matrix_multiply (matrix, matrix, multiply->matrix);
        //             continue;
        //         }

        //         case MATRIX_OP_LOAD_IDENTITY:
        //         case MATRIX_OP_LOAD:
        //         case MATRIX_OP_SAVE:
        //         g_warn_if_reached ();
        //         continue;
        //         }
        //     }

        // return NULL;
        unimplemented!()
    }

    /// Determines whether `self` is known to represent an identity
    /// transform.
    ///
    /// If this returns `true` then the entry is definitely the identity
    /// matrix. If it returns `false` it may or may not be the identity
    /// matrix but no expensive comparison is performed to verify it.
    ///
    /// # Returns
    ///
    /// `true` if `self` is definitely an identity transform,
    ///  otherwise `false`.
    pub fn is_identity(&self) -> bool {
        // return entry ? entry->op == MATRIX_OP_LOAD_IDENTITY : false;
        unimplemented!()
    }
}

impl PartialEq for MatrixEntry {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        MatrixEntry::equal(self, other)
    }
}

impl Eq for MatrixEntry {}