pax_global_header00006660000000000000000000000064132436526660014527gustar00rootroot0000000000000052 comment=0bd8ff0233024f40bcd11b7ce954d4ad7451e8f4 graphene-1.8.0/000077500000000000000000000000001324365266600133265ustar00rootroot00000000000000graphene-1.8.0/.editorconfig000066400000000000000000000006241324365266600160050ustar00rootroot00000000000000root = true [*] charset = utf-8 [*.{c,h}] indent_style = space indent_size = 2 end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true [configure.ac] indent_style = tab indent_size = 8 [Makefile.am] indent_style = tab indent_size = 8 [.travis.yml] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false [meson.build] indent_style = space indent_size = 8 graphene-1.8.0/.travis/000077500000000000000000000000001324365266600147145ustar00rootroot00000000000000graphene-1.8.0/.travis/Dockerfile000066400000000000000000000013121324365266600167030ustar00rootroot00000000000000FROM debian:stretch-slim MAINTAINER Emmanuele Bassi RUN apt-get update -qq \ && apt-get install --no-install-recommends -qq -y \ clang \ gcc \ gobject-introspection \ gir1.2-glib-2.0 \ libgirepository1.0-dev \ libglib2.0-dev \ locales \ ninja-build \ pkg-config \ python3 \ python3-pip \ python3-setuptools \ python3-wheel \ && rm -rf /usr/share/doc/* /usr/share/man/* RUN locale-gen C.UTF-8 && /usr/sbin/update-locale LANG=C.UTF-8 ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8 RUN pip3 install meson COPY graphene-run-tests.sh /root RUN chmod +x /root/graphene-run-tests.sh graphene-1.8.0/.travis/graphene-run-tests.sh000077500000000000000000000002221324365266600210020ustar00rootroot00000000000000#!/bin/bash mkdir _build meson --prefix /usr "$@" _build . || exit $? ninja -C _build || exit $? ninja -C _build test || exit $? rm -rf _build graphene-1.8.0/CONTRIBUTING.md000066400000000000000000000024651324365266600155660ustar00rootroot00000000000000# Contributing to Graphene If you found a bug (which I'm sure there will be plenty), or if you want to add your own pet feature, then follow these steps: 1. Fork the [ebassi/graphene](https://github.com/ebassi/graphene) repo 2. Fix bugs or add new features and push them to your clone 3. Open [a new issue](https://github.com/ebassi/graphene/issues/new) 4. Open [a pull request](https://github.com/ebassi/graphene/pulls) 5. Wait for me to give feedback on the pull request 6. Celebrate when your code gets merged That's pretty much it. Please, respect the coding style when writing patches for Graphene. The coding style can be immediately gleaned from the existing code, but here is a short version: * Indentation is made of spaces, and only spaces — **no tabs** * Each indentation level is 2 spaces * Curly braces for blocks go on a separate indentation level * Except for functions * Do not use curly braces for single-statement blocks * When declaring or defining a function, arguments go on separate lines * When calling a function never break a line between the function name and the opening parenthesis, and between the opening parenthesis and the first argument * Leave a space between functions and parenthesis A more comprehensive coding style document is available in the `docs` directory. graphene-1.8.0/LICENSE000066400000000000000000000020651324365266600143360ustar00rootroot00000000000000Copyright 2014 Emmanuele Bassi. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. graphene-1.8.0/README.md000066400000000000000000000202411324365266600146040ustar00rootroot00000000000000# Graphene ### A thin layer of types for graphic libraries [![Build Status](https://travis-ci.org/ebassi/graphene.svg?branch=master)](https://travis-ci.org/ebassi/graphene) [![Build status](https://ci.appveyor.com/api/projects/status/pw7o5grgko1l06hd/branch/master?svg=true)](https://ci.appveyor.com/project/ebassi/graphene/branch/master) When creating graphic libraries you most likely end up dealing with points and rectangles. If you're particularly unlucky, you may end up dealing with affine matrices and 2D transformations. If you're writing a graphic library with 3D transformations, though, you are going to hit the jackpot: 4x4 matrices, projections, transformations, vectors, and quaternions. Most of this stuff exists, in various forms, in other libraries, but it has the major drawback of coming along with the rest of those libraries, which may or may not be what you want. Those libraries are also available in various languages, as long as those languages are C++; again, it may or may not be something you want. For this reason, I decided to write the thinnest, smallest possible layer needed to write a canvas library; given its relative size, and the propensity for graphics libraries to have a pun in their name, I decided to call it Graphene. This library provides types and their relative API; it does not deal with windowing system surfaces, drawing, scene graphs, or input. You're supposed to do that yourself, in your own canvas implementation, which is the whole point of writing the library in the first place. ### Dependencies Graphene has little dependencies. Graphene contains optimizations for speeding up vector operations; those optimizations are optional, and used only if both Graphene was compiled with support for them *and* if the system you're running on has them. Currently, Graphene supports the following platform-specific fast paths: * Streaming SIMD Extensions (SSE) 2 * ARM NEON * GCC vector extensions In the remote case in which none of these optimizations are available, Graphene will fall back to a naive scalar implementation. Graphene can, optionally, provide types for integrating with GObject properties and signals, as well as introspection information for its use with other languages through introspection-based bindings. ### Installation In order to build and install Graphene you will need development tools and the headers of the dependencies. You will also need: * [meson](http://mesonbuild.com) * [ninja](https://ninja-build.org/) Alternatively, you can also use Autotools. First of all, clone the Git repository: $ git clone https://github.com/ebassi/graphene $ cd graphene Then run: $ meson _build # on Windows, it's "meson.py" $ cd _build $ ninja test # ninja install It is possible, when building Graphene, to disable specific optimizations by using configuration options: * `-Dsse2=false` - will disable the SSE2 fast paths * `-Darm_neon=false` - will disable the ARM NEON fast paths * `-Dgcc_vector=false` - will disable the GCC vector intrinsics If you don't plan on generating introspection data, use `-Dintrospection=false` when configuring Graphene; similarly, if you don't plan on using GObject with Graphene, use `-Dgobject_types=false`. Disabling GObject types will also automatically disable generating introspection data. You can also disable building the test suite and the benchmark suite, using the `-Dtests=false` and `-Dbenchmarks=false` configuration switches respectively. #### Building on Windows In order to build on Windows, it's recommended to use the [MSYS2](http://sourceforge.net/projects/msys2/) environment. First, [install MSYS2](https://msys2.github.io/) and update it fully as documented. Then use `pacman` to set up the build environment by installing the necessary prerequisites for your target. For all build systems, you will need a standard development environment and the appropriate native toolchain. You also need a Python interpreter for introspection builds, which are the default. $ pacman -S base-devel $ pacman -S python3 # for introspection $ pacman -S mingw-w64-x86_64-toolchain # only MINGW64 target $ pacman -S mingw-w64-i686-toolchain # only MINGW32 target If you're using GNU Autotools, you don't need to do anything more. Autotools is part of the `base-devel` group. If you want to try Meson, install the appropriate native package: $ pacman -S mingw-w64-x86_64-meson # only MINGW64 target $ pacman -S mingw-w64-i686-meson # only MINGW32 target There are a number of optional dependencies too: $ pacman -S gtk-doc # optional $ pacman -S mingw-w64-x86_64-glib2 # optional, MINGW64 target only $ pacman -S mingw-w64-i686-glib2 # optional, MINGW32 target only $ pacman -S glib2 glib2-devel # optional, MSYS target only Then clone the Graphene repository and build as usual by following the instructions in the section above. If you're using Meson, please note that the tool may be installed as "meson.py" on MSYS2. ### Contributing If you found a bug (which I'm sure there will be plenty), or if you want to add your own pet feature, then follow these steps: 1. Fork the [ebassi/graphene](https://github.com/ebassi/graphene) repo 2. Fix bugs or add new features and push them to your clone 3. Open [a new issue](https://github.com/ebassi/graphene/issues/new) 4. Open [a pull request](https://github.com/ebassi/graphene/pulls) 5. Wait for me to give feedback on the pull request 6. Celebrate when your code gets merged That's pretty much it. Please, respect the coding style when writing patches for Graphene. The coding style can be immediately gleaned from the existing code, but here is a short version: * Indentation is made of spaces, and only spaces — **no tabs** * Each indentation level is 2 spaces * Curly braces for blocks go on a separate indentation level * Except for functions * Do not use curly braces for single-statement blocks * When declaring or defining a function, arguments go on separate lines * When calling a function never break a line between the function name and the opening parenthesis, and between the opening parenthesis and the first argument * Leave a space between functions and parenthesis A more comprehensive coding style document is available in the `docs` directory. ## Documentation ### Release notes The release notes are available on the Graphene [wiki](https://github.com/ebassi/graphene/wiki/Release-Notes). ### Available types Graphene provides common types needed to handle 3D transformations: * [2D points](http://ebassi.github.io/graphene/docs/graphene-Point.html) * [3D points](http://ebassi.github.io/graphene/docs/graphene-Point3D.html) * [triangles](http://ebassi.github.io/graphene/docs/graphene-Triangle.html) * [rectangles](http://ebassi.github.io/graphene/docs/graphene-Rectangle.html) * [quads](http://ebassi.github.io/graphene/docs/graphene-Quad.html) * [quaternions](http://ebassi.github.io/graphene/docs/graphene-Quaternion.html) * [euler angles](http://ebassi.github.io/graphene/docs/graphene-Euler.html) * [vectors](http://ebassi.github.io/graphene/docs/graphene-Vectors.html) (2, 3, or 4-sized) * [matrices](http://ebassi.github.io/graphene/docs/graphene-Matrix.html) * [planes](http://ebassi.github.io/graphene/docs/graphene-Plane.html) * [axis aligned bounding boxes](http://ebassi.github.io/graphene/docs/graphene-Box.html) * [spheres](http://ebassi.github.io/graphene/docs/graphene-Sphere.html) * [frustums](http://ebassi.github.io/graphene/docs/graphene-Frustum.html) Graphene also provides its low-level SIMD [vector](http://ebassi.github.io/graphene/docs/graphene-SIMD-vector.html) and [matrix](http://ebassi.github.io/graphene/docs/graphene-SIMD-matrix.html) types, which are used to implement the API above. All types can be placed on the stack, but provide allocation/free functions for working on the heap as well. The contents of all structure types, unless noted otherwise, should be considered private, and should never be accessed directly. The full API reference for Graphene is [available online](http://ebassi.github.io/graphene/docs/). ### License Graphene is released under the terms of the MIT/X11 license. See the `LICENSE` file for more details. graphene-1.8.0/build-aux/000077500000000000000000000000001324365266600152205ustar00rootroot00000000000000graphene-1.8.0/build-aux/cross/000077500000000000000000000000001324365266600163515ustar00rootroot00000000000000graphene-1.8.0/build-aux/cross/fedora-mingw32.txt000066400000000000000000000011441324365266600216360ustar00rootroot00000000000000[binaries] c = '/usr/bin/i686-w64-mingw32-gcc' cpp = '/usr/bin/i686-w64-mingw32-cpp' ar = '/usr/bin/i686-w64-mingw32-ar' strip = '/usr/bin/i686-w64-mingw32-strip' pkgconfig = '/usr/bin/i686-w64-mingw32-pkg-config' exe_wrapper = 'wine' [properties] root = '/usr/i686-w64-mingw32/sys-root/mingw' c_args = [ '-O2', '-g', '-pipe', '-Wall', '-Wp', '-D_FORTIFY_SOURCE=2', '-fexceptions', '--param=ssp-buffer-size=4', '-I/usr/i686-w64-mingw32/sys-root/mingw/include' ] c_link_args = [ '-L/usr/i686-w64-mingw32/sys-root/mingw/lib' ] [host_machine] system = 'windows' cpu_family = 'i686' cpu = 'i686' endian = 'little' graphene-1.8.0/build-aux/cross/fedora-mingw64.txt000066400000000000000000000011371324365266600216450ustar00rootroot00000000000000[binaries] c = '/usr/bin/x86_64-w64-mingw32-gcc' cpp = '/usr/bin/x86_64-w64-mingw32-cpp' ar = '/usr/bin/x86_64-w64-mingw32-ar' strip = '/usr/bin/x86_64-w64-mingw32-strip' pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config' exe_wrapper = 'wine' [properties] root = '/usr/x86_64-w64-mingw32/sys-root/mingw' c_args = [ '-pipe', '-Wp,-D_FORTIFY_SOURCE=2', '-fexceptions', '--param=ssp-buffer-size=4', '-I/usr/x86_64-w64-mingw32/sys-root/mingw/include' ] c_link_args = [ '-L/usr/x86_64-w64-mingw32/sys-root/mingw/lib' ] [host_machine] system = 'windows' cpu_family = 'x86_64' cpu = 'x86_64' endian = 'little' graphene-1.8.0/build-aux/uncrustify.cfg000066400000000000000000000110211324365266600201070ustar00rootroot00000000000000newlines = lf input_tab_size = 8 output_tab_size = 8 string_escape_char = 100 string_escape_char2 = 0 # indenting indent_columns = 2 indent_with_tabs = 9 indent_align_string = true indent_brace = 2 indent_braces = false indent_braces_no_func = true indent_func_call_param = false indent_func_def_param = false indent_func_proto_param = false indent_switch_case = 0 indent_case_brace = 2 indent_paren_close = 1 indent_label = 0 indent_paren_open_brace = false # spacing sp_arith = add sp_assign = add sp_enum_assign = add sp_bool = add sp_compare = add sp_inside_paren = remove sp_inside_fparens = remove sp_func_def_paren = force sp_func_proto_paren = force sp_paren_paren = remove sp_balance_nested_parens = false sp_paren_brace = remove sp_before_square = remove sp_before_squares = remove sp_inside_square = remove sp_after_comma = add sp_before_comma = remove sp_after_cast = add sp_sizeof_paren = add sp_not = remove sp_inv = remove sp_addr = remove sp_member = remove sp_deref = remove sp_sign = remove sp_incdec = remove sp_attribute_paren = remove sp_macro = force sp_func_call_paren = force set func_call_user = _ N_ C_ sp_brace_typedef = add sp_cond_colon = add sp_cond_question = add sp_defined_paren = remove # alignment align_keep_tabs = false align_with_tabs = false align_on_tabstop = false align_number_left = true align_func_params = true align_var_def_span = 0 align_var_def_amp_style = 1 align_var_def_colon = true align_enum_equ_span = 0 align_var_struct_span = 2 align_var_def_star_style = 2 align_var_def_amp_style = 2 align_typedef_span = 2 align_typedef_func = 0 align_typedef_star_style = 2 align_typedef_amp_style = 2 # newlines nl_assign_leave_one_liners = true nl_enum_leave_one_liners = false nl_func_leave_one_liners = false nl_if_leave_one_liners = false nl_end_of_file = add nl_assign_brace = remove nl_func_var_def_blk = 1 nl_fcall_brace = add nl_enum_brace = remove nl_struct_brace = force nl_union_brace = force nl_if_brace = force nl_brace_else = force nl_elseif_brace = force nl_else_brace = add nl_for_brace = force nl_while_brace = force nl_do_brace = force nl_brace_while = force nl_switch_brace = force nl_before_case = true nl_after_case = false nl_func_type_name = force nl_func_proto_type_name = remove nl_func_paren = remove nl_func_decl_start = remove nl_func_decl_args = force nl_func_decl_end = remove nl_fdef_brace = force nl_after_return = false nl_define_macro = false nl_create_if_one_liner = false nl_create_for_one_liner = false nl_create_while_one_liner = false nl_after_semicolon = true nl_multi_line_cond = true # mod mod_full_brace_for = remove mod_full_brace_if = remove mod_full_brace_while = remove mod_full_brace_do = remove mod_full_brace_nl = 3 mod_paren_on_return = remove # line splitting #code_width = 78 ls_for_split_full = true ls_func_split_full = true # positioning pos_bool = trail pos_conditional = lead graphene-1.8.0/doc/000077500000000000000000000000001324365266600140735ustar00rootroot00000000000000graphene-1.8.0/doc/CODING_STYLE.md000066400000000000000000000347311324365266600163500ustar00rootroot00000000000000# Graphene Coding Style This document is intended to be a short description of the preferred coding style to be used for the Graphene source code. Coding style is a matter of consistency, readability and maintainance; coding style is also completely arbitrary and a matter of taste. This document will use examples at the very least to provide authoritative and consistent answers to common questions regarding the coding style, and will also try to identify the allowed exceptions. The examples will show the preferred coding style; the negative examples will be clearly identified. Please, don't submit code to Graphene that looks like any of these. Part of the rationales for these coding style rules are available either in the Linux kernel `CodingStyle` document or in Cairo's `CODING_STYLE` one. When in doubt, check the surrounding code and try to imitate it. ### Line width The maximum line width for source files is 100 characters, whenever possible. Longer lines are usually an indication that you either need a function or a pre-processor macro. ### Indentation Each new level is indented 2 or more spaces than the previous level: if (condition) single_statement (); This can only be achieved using space characters. It may not be achieved using tab characters alone, or using a combination of spaces and tabs. Do not change the editor's configuration to change the meaning of a tab character (see below); code using tabs to indent will not be accepted into Graphene. Even if two spaces for each indentation level allows deeper nesting than 8 spaces, Graphene favours self-documenting function names that can take quite some space. For this reason alone you should avoid deeply nested code. ### Tab characters The tab character must always be expanded to spaces. If a literal tab must be used inside the source, the tab must always be interpreted according to its traditional meaning: ``` Advance to the next column which is a multiple of 8. [ these two lines should be aligned ] ``` ### Braces Curly braces should not be used for single statement blocks: if (condition) single_statement (); else another_single_statement (arg1); In case of multiple statements, curly braces should be put on another indentation level: if (condition) { statement_1 (); statement_2 (); statement_3 (); } The "no block for single statements" rule has only three exceptions: 1. if the single statement covers multiple lines, e.g. for functions with many arguments, and it is followed by else or else if: ``` /* valid */ if (condition) { a_single_statement_with_many_arguments (some_lengthy_argument, another_lengthy_argument, and_another_one, plus_one); } else another_single_statement (arg1, arg2); ``` 2. if the condition is composed of many lines: ``` /* valid */ if (condition1 || (condition2 && condition3) || condition4 || (condition5 && (condition6 || condition7))) { a_single_statement (); } ``` 3. Nested if's, in which case the block should be placed on the outermost if: ``` /* valid */ if (condition) { if (another_condition) single_statement (); else another_single_statement (); } /* invalid */ if (condition) if (another_condition) single_statement (); else if (yet_another_condition) another_single_statement (); ``` In general, new blocks should be placed on a new indentation level, like: int retval = 0; statement_1 (); statement_2 (); { int var1 = 42; gboolean res = FALSE; res = statement_3 (var1); retval = res ? -1 : 1; } While curly braces for function definitions should rest on a new line they should not add an indentation level: /* valid */ static void my_function (int argument) { do_my_things (); } /* invalid */ static void my_function (int argument) { do_my_things (); } /* invalid */ static void my_function (int argument) { do_my_things (); } Curly braces must not be placed on the same line as a condition: /* invalid */ if (condition) { statement_1 (); statement_2 (); } ### Conditions Do not check boolean values for equality: /* invalid */ if (condition == TRUE) do_foo (); /* valid */ if (another_condition) do_bar (); Even if C handles NULL equality like a boolean, be explicit: /* valid */ if (some_pointer == NULL) do_blah (); /* invalid */ if (some_other_pointer) do_blurp (); In case of conditions split over multiple lines, the logical operators should always go at the end of the line: /* invalid */ if (condition1 || condition2 || condition3) { do_foo (); } /* valid */ if (condition1 && condition2 && (condition3 || (condition4 && condition5))) { do_blah (); } ### Types All public types in Graphene should conform to the `__t` pattern, e.g.: /* valid */ typedef struct _graphene_quaternion_t graphene_quaternion_t; /* valid */ typedef enum { ... } graphene_euler_order_t; /* invalid */ typedef struct _foo_bar_t foo_bar_t; /* invalid */ typedef enum { ... } GrapheneBlah; CamelCase is not allowed in the public API, and it's strongly discouraged for the internals as well. All public types should have public structure definitions, but if fields are to be considered private then you should add them at the end of the structure definition, and use the `GRAPHENE_PRIVATE_FIELD` macro to declare them, e.g.: /* valid */ struct _graphene_euler_t { GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, angles); GRAPHENE_PRIVATE_FIELD (graphene_euler_order_t, order); }; /* invalid */ struct _graphene_foo_t { graphene_vec4_t __some_private_field; graphene_vec4_t public_field; }; All public types should have the following functions: * a `graphene__alloc()` allocator; the contents of the structure returned by this function are undefined * a `graphene__free()` deallocator; this function should be NULL-safe * a `graphene__init()` initializer All initializer functions should take a pointer of the type they initialize as their first argument, and return the initialized structure, e.g.: /* valid */ graphene_rect_t * graphene_rect_init (graphene_rect_t *rect, float x, float y, float width, float height); All types should be usable on the stack, after being initialized; the behaviour of a type before initialization is undefined. ### Functions Functions should be declared by placing the returned value on a separate line from the function name: void my_function (void) { } The arguments list must be broken into a new line for each argument, with the argument names right aligned, taking into account pointers: void my_function (some_type_t type, another_type_t *a_pointer, final_type_t another_type) { } The alignment also holds when invoking a function without breaking the 80 characters limit: align_function_arguments (first_argument, second_argument, third_argument); To respect the 80 characters limit do not break the function name from the arguments: /* invalid */ a_very_long_function_name_with_long_parameters (argument_the_first, argument_the_second); /* invalid */ a_very_long_function_name_with_long_parameters ( argument_the_first, argument_the_second); /* valid */ first_a = argument_the_first; second_a = argument_the_second; a_very_long_function_name_with_long_parameters (first_a, second_a); All public functions must be annotated with the `GRAPHENE_AVAILABLE_IN_x_y` macro for the `x.y` stable release in which they appear. Functions private to a specific source file should always be marked as `static`; functions private to the whole project should be declared in a private header. ### Whitespace Always put a space before a parenthesis but never after: /* valid */ if (condition) do_my_things (); /* valid */ switch (condition) { } /* invalid */ if(condition) do_my_things(); /* invalid */ if ( condition ) do_my_things ( ); A `switch()` should open a block on a new indentation level, and each case should start on the same indentation level as the curly braces, with the case block on a new indentation level: /* valid */ switch (condition) { case FOO: do_foo (); break; case BAR: do_bar (); break; } /* invalid */ switch (condition) { case FOO: do_foo (); break; case BAR: do_bar (); break; } /* invalid */ switch (condition) { case FOO: do_foo (); break; case BAR: do_bar (); break; } /* invalid */ switch (condition) { case FOO: do_foo (); break; case BAR: do_bar (); break; } It is preferable, though not mandatory, to separate the various cases with a newline: switch (condition) { case FOO: do_foo (); break; case BAR: do_bar (); break; default: do_default (); } The `break` statement for the `default:` case is not mandatory, but it is appreciated. If a case block needs to declare new variables, the same rules as the inner blocks (see above) apply; the break statement should be placed outside of the inner block: switch (condition) { case FOO: { int foo; foo = do_foo (); } break; ... } Do not eliminate whitespace and newlines just because something would fit in the line character limit: /* invalid */ if (condition) foo (); else bar (); Please, eliminate all trailing or leading whitespace before submitting a patch for review. ### Headers Headers are special, for Graphene, in that they don't have to obey the 80 characters limit. The only major rule for headers is that the functions definition should be vertically aligned in three columns: return value function_name (type argument, type argument, type argument); The maximum width of each column is given by the longest element in the column: bool graphene_type_set_property (graphene_type_t *type, const char *value, char **out_value); const char *graphene_type_get_property (graphene_type_t *type); It is also possible to align the columns to the next tab: void graphene_type_set_property (graphene_type_t *type, float value); float graphene_type_get_property (graphene_type_t *type); int graphene_type_update_foobar (graphene_type_t *type); Public headers should have inclusion guards and C++ guards: #ifndef __GRAPHENE_HEADER_H__ #define __GRAPHENE_HEADER_H__ #if !defined(__GRAPHENE_H_INSIDE__) && !defined(GRAPHENE_COMPILATION) #error "Only can be included directly." #endif #include "graphene-types.h" GRAPHENE_BEGIN_DECLS ... GRAPHENE_END_DECLS #endif /* __GRAPHENE_HEADER_H__ */ Private headers do not need the single header inclusion guard, but they need every other guard. Private headers should also be clearly named with a `-private` suffix. Private headers should include the public header for the type they relate to, first: #ifndef __GRAPHENE_FOO_PRIVATE_H__ #define __GRAPHENE_FOO_PRIVATE_H__ #include "graphene-foo.h" GRAPHENE_BEGIN_DECLS ... GRAPHENE_END_DECLS #endif ### Includes Graphene source files should never include the global `graphene.h` header, but instead include the individual headers that are needed. Every file must include `graphene-private.h` first, then its own header, then other Graphene header in an alphabetical order, then system and third-party headers. /* valid */ #include "graphene-private.h" #include "graphene-foo.h" #include "graphene-box.h" #include "graphene-point3d.h" #include "graphene-vec3.h" ... #include ### Macros Try to avoid private macros unless strictly necessary. Remember to #undef them at the end of a block or a series of functions needing them. Inline functions are usually preferable to private macros. Public macros should not be used unless they evaluate to a constant. ### Documentation All public APIs must have gtk-doc comments. For functions, these should be placed in the source file, directly above the function. /* valid */ /** * graphene_type_get_property: * @type: a #graphene_type_t * * Gets the property of a #graphene_type_t. * * Returns: the value of the property */ float graphene_type_get_property (graphene_type_t *type) { ... } Doc comments for macros, function types, structures, etc should be placed next to the definitions, typically in headers. Section introductions should be placed in the source file they describe, after the license header: /* valid */ /** * SECTION:graphene-type * @Title: Type * @Short_description: A representation of a type * * [...] */ To properly document a new function, macro, function type or struct, it needs to be listed in the graphene-sections.txt file. To properly document a new type, it needs to be given its own section in `graphene-sections.txt`, and it needs to be included in `graphene-docs.xml`. ### Old code It is ok to update the style of a code block or function when you are touching it anyway, but sweeping whitespace changes obscure the revision control history and should be avoided at all costs. graphene-1.8.0/doc/graphene-docs.xml000066400000000000000000000062011324365266600173330ustar00rootroot00000000000000 ]> Graphene Reference Manual This document is the API reference for the Graphene library. The latest version of Graphene, as well as the latest version of this API reference, is available online. Graphene Graphene is a library of data types commonly used to implement 2D-in-3D or full 3D canvases. Graphene only contains math data types, like vectors and matrices; it does not deal with windowing system calls, event handling, drawing, or a full scene graph. Object Hierarchy API Index Index of deprecated API Index of new symbols in 1.0 Index of new symbols in 1.2 Index of new symbols in 1.4 Index of new symbols in 1.6 graphene-1.8.0/doc/graphene-overrides.txt000066400000000000000000000010651324365266600204270ustar00rootroot00000000000000 graphene_simd4f_t graphene_simd4x4f_t graphene_simd4x4f_init graphene_simd4x4f_t graphene_simd4f_t x, graphene_simd4f_t y, graphene_simd4f_t z, graphene_simd4f_t w GRAPHENE_MAJOR_VERSION #define GRAPHENE_MAJOR_VERSION GRAPHENE_MINOR_VERSION #define GRAPHENE_MINOR_VERSION GRAPHENE_MICRO_VERSION #define GRAPHENE_MICRO_VERSION graphene-1.8.0/doc/graphene-sections.txt000066400000000000000000000332741324365266600202630ustar00rootroot00000000000000graphene.h
graphene-box graphene_box_t graphene_box_alloc graphene_box_free graphene_box_init graphene_box_init_from_box graphene_box_init_from_points graphene_box_init_from_vec3 graphene_box_init_from_vectors graphene_box_equal graphene_box_expand graphene_box_expand_scalar graphene_box_expand_vec3 graphene_box_get_min graphene_box_get_max graphene_box_get_center graphene_box_get_depth graphene_box_get_height graphene_box_get_width graphene_box_get_size graphene_box_get_bounding_sphere graphene_box_get_vertices graphene_box_union graphene_box_intersection graphene_box_contains_box graphene_box_contains_point graphene_box_zero graphene_box_one graphene_box_minus_one graphene_box_one_minus_one graphene_box_empty graphene_box_infinite
graphene-euler graphene_euler_t graphene_euler_order_t graphene_euler_alloc graphene_euler_free graphene_euler_init graphene_euler_init_with_order graphene_euler_init_from_matrix graphene_euler_init_from_quaternion graphene_euler_init_from_vec3 graphene_euler_init_from_euler graphene_euler_equal graphene_euler_get_x graphene_euler_get_y graphene_euler_get_z graphene_euler_get_order graphene_euler_to_vec3 graphene_euler_to_matrix graphene_euler_reorder
graphene-frustum graphene_frustum_t graphene_frustum_alloc graphene_frustum_free graphene_frustum_init graphene_frustum_init_from_frustum graphene_frustum_init_from_matrix graphene_frustum_get_planes graphene_frustum_contains_point graphene_frustum_intersects_sphere graphene_frustum_intersects_box graphene_frustum_equal
graphene-gobject graphene-gobject.h GRAPHENE_TYPE_BOX GRAPHENE_TYPE_EULER GRAPHENE_TYPE_FRUSTUM GRAPHENE_TYPE_MATRIX GRAPHENE_TYPE_PLANE GRAPHENE_TYPE_POINT GRAPHENE_TYPE_POINT3D GRAPHENE_TYPE_QUAD GRAPHENE_TYPE_QUATERNION GRAPHENE_TYPE_RAY GRAPHENE_TYPE_RECT GRAPHENE_TYPE_SIZE GRAPHENE_TYPE_SPHERE GRAPHENE_TYPE_TRIANGLE GRAPHENE_TYPE_VEC2 GRAPHENE_TYPE_VEC3 GRAPHENE_TYPE_VEC4 graphene_box_get_type graphene_euler_get_type graphene_frustum_get_type graphene_matrix_get_type graphene_plane_get_type graphene_point3d_get_type graphene_point_get_type graphene_quad_get_type graphene_quaternion_get_type graphene_ray_get_type graphene_rect_get_type graphene_size_get_type graphene_sphere_get_type graphene_triangle_get_type graphene_vec2_get_type graphene_vec3_get_type graphene_vec4_get_type
graphene-matrix graphene_matrix_t graphene_matrix_alloc graphene_matrix_free graphene_matrix_init_identity graphene_matrix_init_from_float graphene_matrix_init_from_vec4 graphene_matrix_init_from_matrix graphene_matrix_init_from_2d graphene_matrix_init_perspective graphene_matrix_init_ortho graphene_matrix_init_look_at graphene_matrix_init_frustum graphene_matrix_init_scale graphene_matrix_init_translate graphene_matrix_init_rotate graphene_matrix_init_skew graphene_matrix_is_identity graphene_matrix_is_2d graphene_matrix_is_backface_visible graphene_matrix_is_singular graphene_matrix_to_float graphene_matrix_to_2d graphene_matrix_get_row graphene_matrix_get_value graphene_matrix_multiply graphene_matrix_determinant graphene_matrix_transform_vec4 graphene_matrix_transform_vec3 graphene_matrix_transform_point graphene_matrix_transform_point3d graphene_matrix_transform_rect graphene_matrix_transform_bounds graphene_matrix_transform_box graphene_matrix_transform_sphere graphene_matrix_transform_ray graphene_matrix_project_point graphene_matrix_project_rect_bounds graphene_matrix_project_rect graphene_matrix_untransform_point graphene_matrix_untransform_bounds graphene_matrix_unproject_point3d graphene_matrix_translate graphene_matrix_rotate graphene_matrix_rotate_x graphene_matrix_rotate_y graphene_matrix_rotate_z graphene_matrix_rotate_quaternion graphene_matrix_rotate_euler graphene_matrix_scale graphene_matrix_skew_xy graphene_matrix_skew_xz graphene_matrix_skew_yz graphene_matrix_transpose graphene_matrix_inverse graphene_matrix_perspective graphene_matrix_normalize graphene_matrix_get_x_scale graphene_matrix_get_y_scale graphene_matrix_get_z_scale graphene_matrix_interpolate graphene_matrix_print
graphene-plane graphene_plane_t graphene_plane_alloc graphene_plane_free graphene_plane_init graphene_plane_init_from_vec4 graphene_plane_init_from_plane graphene_plane_init_from_point graphene_plane_init_from_points graphene_plane_normalize graphene_plane_negate graphene_plane_equal graphene_plane_distance graphene_plane_get_normal graphene_plane_get_constant
graphene-point GRAPHENE_POINT_INIT GRAPHENE_POINT_INIT_ZERO graphene_point_t graphene_point_alloc graphene_point_free graphene_point_init graphene_point_init_from_point graphene_point_init_from_vec2 graphene_point_equal graphene_point_distance graphene_point_near graphene_point_interpolate graphene_point_to_vec2 graphene_point_zero
graphene-size GRAPHENE_SIZE_INIT GRAPHENE_SIZE_INIT_ZERO graphene_size_t graphene_size_alloc graphene_size_free graphene_size_init graphene_size_init_from_size graphene_size_equal graphene_size_scale graphene_size_interpolate graphene_size_zero
graphene-point3d GRAPHENE_POINT3D_INIT GRAPHENE_POINT3D_INIT_ZERO graphene_point3d_t graphene_point3d_alloc graphene_point3d_free graphene_point3d_init graphene_point3d_init_from_point graphene_point3d_init_from_vec3 graphene_point3d_to_vec3 graphene_point3d_equal graphene_point3d_near graphene_point3d_scale graphene_point3d_cross graphene_point3d_dot graphene_point3d_length graphene_point3d_normalize graphene_point3d_normalize_viewport graphene_point3d_distance graphene_point3d_interpolate graphene_point3d_zero
graphene-quad graphene_quad_t graphene_quad_alloc graphene_quad_free graphene_quad_init graphene_quad_init_from_rect graphene_quad_init_from_points graphene_quad_contains graphene_quad_bounds graphene_quad_get_point
graphene-quaternion graphene_quaternion_t graphene_quaternion_alloc graphene_quaternion_free graphene_quaternion_init graphene_quaternion_init_identity graphene_quaternion_init_from_quaternion graphene_quaternion_init_from_vec4 graphene_quaternion_init_from_matrix graphene_quaternion_init_from_angles graphene_quaternion_init_from_radians graphene_quaternion_init_from_angle_vec3 graphene_quaternion_init_from_euler graphene_quaternion_to_vec4 graphene_quaternion_to_matrix graphene_quaternion_to_angles graphene_quaternion_to_radians graphene_quaternion_to_angle_vec3 graphene_quaternion_equal graphene_quaternion_dot graphene_quaternion_invert graphene_quaternion_normalize graphene_quaternion_slerp
graphene-ray graphene_ray_t graphene_ray_alloc graphene_ray_free graphene_ray_init graphene_ray_init_from_ray graphene_ray_init_from_vec3 graphene_ray_get_origin graphene_ray_get_direction graphene_ray_get_position_at graphene_ray_get_distance_to_point graphene_ray_get_distance_to_plane graphene_ray_get_closest_point_to_point graphene_ray_equal
graphene-rect GRAPHENE_RECT_INIT graphene_rect_t graphene_rect_alloc graphene_rect_free graphene_rect_init graphene_rect_init_from_rect graphene_rect_equal graphene_rect_normalize graphene_rect_normalize_r graphene_rect_get_center graphene_rect_get_top_left graphene_rect_get_top_right graphene_rect_get_bottom_right graphene_rect_get_bottom_left graphene_rect_get_x graphene_rect_get_y graphene_rect_get_width graphene_rect_get_height graphene_rect_get_vertices graphene_rect_union graphene_rect_intersection graphene_rect_contains_point graphene_rect_contains_rect graphene_rect_offset graphene_rect_offset_r graphene_rect_inset graphene_rect_inset_r graphene_rect_round_to_pixel graphene_rect_round graphene_rect_expand graphene_rect_interpolate graphene_rect_zero
graphene-simd4f graphene_simd4f_t graphene_simd4f_init graphene_simd4f_init_zero graphene_simd4f_init_4f graphene_simd4f_init_3f graphene_simd4f_init_2f graphene_simd4f_dup_4f graphene_simd4f_dup_3f graphene_simd4f_dup_2f graphene_simd4f_get graphene_simd4f_get_x graphene_simd4f_get_y graphene_simd4f_get_z graphene_simd4f_get_w graphene_simd4f_splat graphene_simd4f_splat_x graphene_simd4f_splat_y graphene_simd4f_splat_z graphene_simd4f_splat_w graphene_simd4f_add graphene_simd4f_sub graphene_simd4f_mul graphene_simd4f_div graphene_simd4f_sqrt graphene_simd4f_reciprocal graphene_simd4f_rsqrt graphene_simd4f_cross3 graphene_simd4f_min graphene_simd4f_max graphene_simd4f_min_val graphene_simd4f_max_val graphene_simd4f_clamp graphene_simd4f_clamp_scalar graphene_simd4f_shuffle_wxyz graphene_simd4f_shuffle_zwxy graphene_simd4f_shuffle_yzwx graphene_simd4f_zero_w graphene_simd4f_zero_zw graphene_simd4f_merge_w graphene_simd4f_merge_high graphene_simd4f_merge_low graphene_simd4f_flip_sign_0101 graphene_simd4f_flip_sign_1010 graphene_simd4f_cmp_eq graphene_simd4f_cmp_neq graphene_simd4f_cmp_lt graphene_simd4f_cmp_le graphene_simd4f_cmp_ge graphene_simd4f_cmp_gt graphene_simd4f_neg graphene_simd4f_madd graphene_simd4f_sum graphene_simd4f_sum_scalar graphene_simd4f_dot4 graphene_simd4f_dot3 graphene_simd4f_dot3_scalar graphene_simd4f_dot2 graphene_simd4f_length4 graphene_simd4f_length3 graphene_simd4f_length2 graphene_simd4f_normalize4 graphene_simd4f_normalize3 graphene_simd4f_normalize2 graphene_simd4f_is_zero4 graphene_simd4f_is_zero3 graphene_simd4f_is_zero2 graphene_simd4f_interpolate graphene_simd4f_union_t graphene_simd4i_union_t graphene_simd2f_t
graphene-simd4x4f graphene_simd4x4f_t graphene_simd4x4f_init graphene_simd4x4f_init_identity graphene_simd4x4f_init_from_float graphene_simd4x4f_to_float graphene_simd4x4f_transpose_in_place graphene_simd4x4f_sum graphene_simd4x4f_vec4_mul graphene_simd4x4f_vec3_mul graphene_simd4x4f_point3_mul graphene_simd4x4f_transpose graphene_simd4x4f_inv_ortho_vec3_mul graphene_simd4x4f_inv_ortho_point3_mul graphene_simd4x4f_matrix_mul graphene_simd4x4f_init_perspective graphene_simd4x4f_init_ortho graphene_simd4x4f_init_look_at graphene_simd4x4f_init_frustum graphene_simd4x4f_perspective graphene_simd4x4f_translation graphene_simd4x4f_scale graphene_simd4x4f_rotation graphene_simd4x4f_add graphene_simd4x4f_sub graphene_simd4x4f_mul graphene_simd4x4f_div graphene_simd4x4f_inverse graphene_simd4x4f_determinant graphene_simd4x4f_is_identity graphene_simd4x4f_is_2d
graphene-sphere graphene_sphere_t graphene_sphere_alloc graphene_sphere_free graphene_sphere_init graphene_sphere_init_from_points graphene_sphere_init_from_vectors graphene_sphere_get_center graphene_sphere_get_radius graphene_sphere_get_bounding_box graphene_sphere_is_empty graphene_sphere_distance graphene_sphere_contains_point graphene_sphere_translate graphene_sphere_equal
graphene-triangle graphene_triangle_t graphene_triangle_alloc graphene_triangle_free graphene_triangle_init_from_point3d graphene_triangle_init_from_vec3 graphene_triangle_get_points graphene_triangle_get_vertices graphene_triangle_get_area graphene_triangle_get_midpoint graphene_triangle_get_normal graphene_triangle_get_plane graphene_triangle_get_bounding_box graphene_triangle_get_barycoords graphene_triangle_contains_point graphene_triangle_equal
graphene-vectors GRAPHENE_VEC2_LEN graphene_vec2_t graphene_vec2_alloc graphene_vec2_free graphene_vec2_init graphene_vec2_init_from_vec2 graphene_vec2_init_from_float graphene_vec2_to_float graphene_vec2_add graphene_vec2_subtract graphene_vec2_multiply graphene_vec2_divide graphene_vec2_dot graphene_vec2_scale graphene_vec2_length graphene_vec2_normalize graphene_vec2_negate graphene_vec2_equal graphene_vec2_near graphene_vec2_min graphene_vec2_max graphene_vec2_get_x graphene_vec2_get_y graphene_vec2_zero graphene_vec2_one graphene_vec2_x_axis graphene_vec2_y_axis GRAPHENE_VEC3_LEN graphene_vec3_t graphene_vec3_alloc graphene_vec3_free graphene_vec3_init graphene_vec3_init_from_vec3 graphene_vec3_init_from_float graphene_vec3_to_float graphene_vec3_add graphene_vec3_subtract graphene_vec3_multiply graphene_vec3_divide graphene_vec3_cross graphene_vec3_dot graphene_vec3_scale graphene_vec3_length graphene_vec3_normalize graphene_vec3_negate graphene_vec3_equal graphene_vec3_near graphene_vec3_min graphene_vec3_max graphene_vec3_get_x graphene_vec3_get_y graphene_vec3_get_z graphene_vec3_get_xy graphene_vec3_get_xy0 graphene_vec3_get_xyz0 graphene_vec3_get_xyz1 graphene_vec3_get_xyzw graphene_vec3_zero graphene_vec3_one graphene_vec3_x_axis graphene_vec3_y_axis graphene_vec3_z_axis GRAPHENE_VEC4_LEN graphene_vec4_t graphene_vec4_alloc graphene_vec4_free graphene_vec4_init graphene_vec4_init_from_vec4 graphene_vec4_init_from_vec3 graphene_vec4_init_from_vec2 graphene_vec4_init_from_float graphene_vec4_to_float graphene_vec4_add graphene_vec4_subtract graphene_vec4_multiply graphene_vec4_divide graphene_vec4_dot graphene_vec4_scale graphene_vec4_length graphene_vec4_normalize graphene_vec4_negate graphene_vec4_equal graphene_vec4_near graphene_vec4_min graphene_vec4_max graphene_vec4_get_x graphene_vec4_get_y graphene_vec4_get_z graphene_vec4_get_w graphene_vec4_get_xy graphene_vec4_get_xyz graphene_vec4_zero graphene_vec4_one graphene_vec4_x_axis graphene_vec4_y_axis graphene_vec4_z_axis graphene_vec4_w_axis
graphene-version GRAPHENE_MAJOR_VERSION GRAPHENE_MINOR_VERSION GRAPHENE_MICRO_VERSION GRAPHENE_HAS_GCC GRAPHENE_HAS_SCALAR GRAPHENE_HAS_SSE GRAPHENE_HAS_ARM_NEON GRAPHENE_USE_GCC GRAPHENE_USE_SCALAR GRAPHENE_USE_SSE GRAPHENE_USE_ARM_NEON GRAPHENE_SIMD_S
graphene-1.8.0/doc/meson.build000066400000000000000000000026151324365266600162410ustar00rootroot00000000000000subdir('xml') private_headers = [ 'config.h', 'graphene.h', 'graphene-alloc-private.h', 'graphene-bench-utils.h', 'graphene-config.h', 'graphene-line-segment-private.h', 'graphene-macros.h', 'graphene-private.h', 'graphene-test-compat.h', 'graphene-version-macros.h', 'graphene-vectors-private.h', ] html_images = [ 'rectangle-intersection.png', 'rectangle-union.png', 'rectangle.png', 'triangle-barycentric.png', ] glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix') glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html') docpath = join_paths(graphene_datadir, 'gtk-doc', 'html') gnome.gtkdoc('graphene', main_xml: 'graphene-docs.xml', src_dir: [ join_paths(meson.source_root(), 'src'), join_paths(meson.build_root(), 'src'), ], dependencies: graphene_dep, gobject_typesfile: 'graphene.types', scan_args: [ '--rebuild-types', '--ignore-decorators=_GRAPHENE_PUBLIC', '--ignore-headers=' + ' '.join(private_headers), ], fixxref_args: [ '--html-dir=@0@'.format(docpath), '--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')), '--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')), ], html_assets: html_images, install: true) graphene-1.8.0/doc/rectangle-intersection.png000066400000000000000000000041761324365266600212610ustar00rootroot00000000000000PNG  IHDR{XVe^sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxn\xuƢ- BA#q lCbE \k ,`S  p'gX8%HPXGs|V,ۯΙYn~4MhVGMvom}xޜyk-͇s8/= |ޚyg-\x@W|++뙹qg@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@fmeۇW<|7}A^{xx/㣃/o>>o/ n81j4ffwuz0glsOF̮Wo\?9z9|^]>rw7Ч|8{5::oN̼yɷ.Ϋ3saG_W柳͌y@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@'fyb@fWNgwK?sgvN3S1̓y }1#yaiIENDB`graphene-1.8.0/doc/rectangle-intersection.svg000066400000000000000000000051761324365266600212750ustar00rootroot00000000000000 image/svg+xml graphene-1.8.0/doc/rectangle-union.png000066400000000000000000000051541324365266600177000ustar00rootroot00000000000000PNG  IHDR;:sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATx=og۱c;&8An$.0 102X,,H @b@JA*EBrHb8Nl3A-i9Kё#ߒ<ݳI>7zµdQAw~r~o<oon$<_xRn4zt'Fo2O^ =oQ>pm\[y7Iqyk v;gda\F^cjCJrs8-8> :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t(07zGknN,<Lb򯓳#'x9__[# 7~/1Kw0e_.KIլ%ye(͏_x-_{k Qmp 8Sۙŧ'dJ8$9<3WX~nuk\ܺw nfe~\ٽ+$,ySISgֳAgl6 <=@I I>1z =[IwI6Np. :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :=CMrfgl#̌<\瓬QtSIf/);w$l̹vwV\\ک\$l8@<}彼{{I~5fP+ogwOO9vg:0I&3?_\W6bNo&If\ʧ$wa9[P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P@@A :t( P`nr#?;7d76_E)'=b;5G'w6~;Gpht>F;3;3z@ݝ!$A?wg{M Zyr͏Lnm$^<IENDB`graphene-1.8.0/doc/rectangle-union.svg000066400000000000000000000047441324365266600177170ustar00rootroot00000000000000 image/svg+xml graphene-1.8.0/doc/rectangle.png000066400000000000000000000306511324365266600165520ustar00rootroot00000000000000PNG  IHDR;:sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxyxϬ7'$@Dd)[ih[QlxJmkuĥpjE JS@PA =uf?&!$!$xk6߄ >s߿B%%KkΓ4KR^&w$%}ދ{5k̾.= 8 A%5H:KLlQI^&Q IEvHNY"%=#iÒ3G:pIo3`@'i߭F;mu咂%=ZOd lV!it"dֺ~]z[jPŒZW?)(v<#u6(Hګ֯ݒ6FvKzJu{[IJow^[KB'Z_; y%")k-%5!i<6Wn yGNlZm^%)s; nߢ=zVo:>՗:䘶yXұeo-A{Z_ŵ8c}:њ1[_*ooo@m'&:^ret"+xoוoT{ו<;r}mi1q`Od:@?~{%L/ ;[_%i2Н;9Oz}o}wu sB_?wHv< Ϣ3݋< ɤHTEE&^8~}<˩J)jig>S:MZY}n)6yLYaIYD_Y-nk|):]\DһxJ\ H. u$%rQ|jwzy۾Rw?.̒g7.t-JN/X[Chs#[=|z4788AGDDl6[CCCCii¯\.jIy3BO  .`bzzcEGGK***_7ؾ}?ItDnKٴI*(22򞬬ƍ6qDjju|ͮm۶}r~+Xѯ=ЯKKKѬYf|́3f̐zN6lؠK6]M`0g'872izoA=2gΜY~{ԩSe6hZ{Z|yqvv <-.,L:tCW_}짞zʞ_l5uTkyy"Ib0کU'&nI &IVUZ!Zݪcz[=ސ3+-Z4zhLd5~xƆ tݟɳD_@ |+ꩧ ; AAA7n)'''177ܼV wv-LR9rin}_QZ&Ye8ٳg_#D>[o8tPՅY $?}zCIG}ܹsC}Rllꪠ={ۜyn>/n[t3"I'IXrk:4 /L?~|kQvvvmfHZ I&I&)>>e> %&6]B FwiMǤG$&n0h1"lA{~ᯁړy8bC6@_ 'jfg#anS .//ޯZn'm3$D-v{uMAv]\-uXZ_fYp8$ѻE ҺˆQFBUW-gRJ>@os:֨ ;;!Y/JK?j=lssˏJƒyJO}*(hnT(>8YtۣɊ.ݞ0 3sf6FQ6(a/Cn<`nņ t͛%{篁}׮]3O> 33[';ss#亴V~猨cVXRyӰΫ+eAzC=$3=e˖5nݺuκ~y.]TZZ:|hzz-66rrr/VDJYmSpp(gR,<9ʵ:4lZ{ZSy.Ke.Qd;v] ڿ^xᅖUV=z+vp@2q( uuu ;頣Go9WDqa2UިmWojU5*ݨ95KT_hu[LaaafCKKrrr^;'p<k$ 6wdff^2xaCHRiqZkI.T~3ŕe"^++ݧ#*O>] (jvտZi9gBV7nUjzTE^7{]Dr&iZUax@aꃓ-%<uVWWr-w#9H2g rHr) j^'MvDž?n=<άmU;p!Ё30l.HaII[,2UV%?_ ~*o xu *,TM7ϻtRSS倢5~ 7OQ.t?Jc*WJA2.ZDIzAm| >Ґd&,,<4qB-Rժ>f'pbRRP[+My1騶^RwpIJIQƍJo"]|r۟"Fes:U=frI#6 ?w@ɾy2 R-;v^e0A! LQx\dKIQ""d %(䩥YY ZRqq9r햆Wc)y\EΜ}է5Id^E:EN ԫVw>o-%iOz"}^v"].wP]US*leKR|lqq;6L޿'ԕe޸QGVHQSa ZEge)tXpMV t@z?W܀~oIOLL,7ܠ\g̎ &M&ˊh!kX\lK{TTQ Tٖ/ J[il{V\|"Raoubd s8eK:ڶo#C;SS*_;~oPJowKRY]R{eJzBN]$uQoVLTTZse1B[fNMW̚i]ӶL&?¶0d@zwݥ[mfi >\A6[u{UW)RzKǝ Cڿ_M|#.%(;駞@>Ғt 3=ageRJ6+W(ג%'zڔӭvR:ez-*F@;C/oT+P[Ub[=J1Cṹw|rpI7++;nq&%yk@ٺ7QYC8xl'0@P⥗*T=abbd+(Pc^ީިQތGԾ7M^^NjDA:\1O?0 @z諯pEJ5KӦyJWýPwZޞ~Z (Ls*ϻ;MH7`U]-Ni&\yUi //W-e=!?λKKϾ˽ n;pU re : :Tァ.;;n5p"xB:uu8 k}򴰳v'gVXvj RG KNXYf?ѽ,՞&ѝ$&v7@B}ܟ~ڇVqZvje՝gT!w:6u{zO>񴶧MSܹ{k֜kUm64'MR%Zս@kOwz|졡3|[if*@/ii{v ~ .{iX`̿~,_Tvٿ3Li3e_yNf6|h:Ɯ6QUѣ=#?g3}"%_ իUzj}]Aq]/"{wu:5jξ^nYc(>{Q/tt/J/X7ܠ:97nTMQ4H1c|5|ʇ Q*4%EүB9kת?C{?UsJYZ? tJG]w)귿@V-ib%J7Y!5mKNQ |@R\ɓ44``@cGTG'Vɤ/b<vJK\@11*9S!C(siZl㫯x:CwLS;-adOJ6lCƏW`XX?A5]tyO> "ͦmܓ_GJ B5%)w۶<5ͧ_)͑#6ПxBGxBG]{ 08oܻ2|?bLQXLj:UmO&K::hC(4( ދ+PĕW*jF9BY˼y {Z2-YS_q2IE@J4e.6._jC rh{qkCδ4  [X,3g*"2R#GԴpZ*~Y\qB33%kYZmOUب;z'*+\LU|] C;@"wHIDAT CO޾}jܽ{ ЗvGя?Į\^~Y߯#Q]!нs/`I!5VUu87^}Tk::R[+k;V2C58W1ʽYX@9WàA u-UnPk'PA񆆎?T7ߨ`pv%JYPq1%? 0~*Vz-t @t ༽~ƌQw+FU|}]z+ IrsCr%$9f_Dؚ5=Z{|]]3Gg+46VZxĚ p:޷OM6z;+5$3SmTw/[!G+$5U;=ܽhDf?C7P,tMt/=d}MddhwS=sϧMShW V&t饊n*н<}rEޭ+U [p,=ɓr劲eZT6Bt/rΙӐ)m߯sO}R~ }W)'#Wӄ ʹzE̟#"KuZvT%*߸9Bw}WUᆱ*_@w0( нlܨUUdRV:;n@٪4؟Kh,\uJp.K``@"))Q6M7j!&N@oZ-^U5rlQƌ'@@esho4&FO?Ո x9EwY[nѡ'Ta@oa?8_@GկTrong?359e7TQTEiݦ1c8lMjRezլ[ݫɓwFUWW w@grӟ)-s4G=t-t @.%KpZZٴMv1ck_GJ:p޶oUުBmcjlBt @2`, ;PkJ%W{FOvZO<_йs5c\ɟ|a&"p нLR5jڶ_(G{W+[zhC2dssUto`Y֯W^ /I)W@o%*ӱcj~ UѶmfWW˙jkr ;y@ԩ +OtKRC\VMMr9+Km#'MR _~ʤz% O‘P>_.I.})鹳 {t]TԬWo_Q]n=S w RhU{~? m"2z7\m$@媓Cd]fЭ{tϏOymT9/=]v<=SjYp>7=:~Oon|J:v6=ߜr~m7{٭ofe' tIrkS[l Pf=Fρ޾۽0 kgj@LW$t5wÁq]f@hZW\fv1] `<Rg:t5A!л?}j@5 ט00t00czwj2F{t?g@$> Hy;g@jg@l#j3NKnXnqf0~xkRRl6wlXИJ2)ܯ]b̙n:o;55ٳg\paeXN9X>M+\g u0Ο_g;vlG744hzwnٲe%Sg;5ϟ٢Enj#qaaa2evرI\@M̙Q+ @7tiܸq$ԬSdddt$ɤ믿^Fك5}Xm JM'O,gwǍd2s#SRR'LӕeZs.ϔYCCMiX`=M&bcc[[UUClrrl%锟N_@oliiinll<\_+O6d?Gg655ȑ#M555G%5M}}_2??_YYY=:NEEGR>2"7&Ν;әOٲe \m}X :kihhpʕ+3g%&_^wϥ^rnBuu{m}WR3Лl6pݮ#GW_m^[I }[&?zڡAJO68p5I[>ு.IyGInhhHe /Z*eIR@onnUXX[TT{񈸸8EEE|P}֮]ŋ7~ǟڵke)wүVL2iӦeΛ7<~xzn8p@֭ի+֯_w6@iii1"cذa րUVVjϞ=EEE;vZSS|]@$bbb`=~x}IIIYaaa={>s\9O%MZZ֠ñ_ג6 _m"$M4JRIՒI!i$8? EIENDB`graphene-1.8.0/doc/rectangle.svg000066400000000000000000000164341324365266600165700ustar00rootroot00000000000000 image/svg+xml origin size.width size.height graphene-1.8.0/doc/triangle-barycentric.png000066400000000000000000000452101324365266600207130ustar00rootroot00000000000000PNG  IHDRXsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxy|\uי5k&miЍ K pE@vZB@R/?{WիlmAڒ"(UDPٻIڦm9Ǚ$YҬ$'9 """"""""""""""""""""""""""""""""""""""""""""""ʈw"" (]{*_F` 05QHI-X.×Z""2[{<7(NC/EDDB+.C^ ("""GЗn.vezOAw""C넷؏G 2( -!G% VED+@J""ovqBDDdϢC^)",""}I^gR"]p#(ײ|`:zM׃Dӟѯ@Q;˽}Tl~K 5DDf;@0{7K:@9r{1\kiA4:&tPd"4)NDd ڙqC%tZOK2l( Ocog %t1%޸D!Æ+NZ"""2>M؇H % SF  ]H pc'`"3jsۀZs?>ЧU""=sBJJ%sM,r8i`@"""YYYw:;Ϋs w#w\2kY]vYSVV֓DDDBՓA3ּyhH\fzҧj[߿ҪK[n?5--!==hĉDDuC@ oU|Yٌϧ=ײθ-|i_2{\sNkIXoEdhXJ,Nx};6{@8U`)1D$]]>>Ųt/\L0Y7*tI^;ցO`tPI̩Bӱ, w e9`l؞ZҜla~sNE$t;'H`h0<\ˈHrXʪou'a%1`ef'X: #1vp$k'G}N >v;`|>X\Rd8R]D WKdnb`dvk?|+ x#ÓZ".XF}NeW-1lGba+n"!𣖻$ex(~bkQDZrі$Í*tI=ݎV჆8WZ,ce-nKL2Bİ챹X9Jmb! auR%l\"S."վN v@U~8P&Z*$ÆVH\[>ʪ`9כI['s4 VK ."tÕ` dDnb/zIN'5?p:oa}Apu_rAdnaoG֖:Q]Z"2ʞNQ*,oL콑f=&~ ^;!Ч ]DW06j?m$sְŁõ8."cŋ.w L;-iIa6dXW>.rwc1kyQSoBEbVLy aiߎ}@2ԩBtÕw̻bղOa 8Ed`,[y>)-Д。y9{)/bCU"_5wlGk>im@hd`kXE}N}C;"vrXqI,Eop2~k-GE}!?T1amfZ xCI&U";+^tQUu3u3ΈmP73ya|O)xS.~d=t鹲uӨ~vBON^S]ԛiy;. ]Z"rD,p>zvM#[wmޙ5IytXHuİ9nGH2."Y0So.MB3aLhۥ2p/dQB, 9&%3{WzN XW~&V,ØWu'0eAp,pvFwp8wf{0%=*oNv ׍IGL0 dV/GF0aA pAP.Bl Q5jOb0"ϥ6oߝɝ#aN!x %t'E9tV}}V˽}D^a7+LhX|s>br_dPv*bIU"I}0?%sq~# {|sQsBe/sw<,ST2hHr$sp~W#sĨɼ*JRF/ ,FkhZ"IWX{d;>1KNR m%GEppN>  T$Z xX|ZƮGL-쪼-|_+ #T#C*t$c~vrլM6btENz1MS*^CzXÉXT$!@žx?sSF}]0=j2V:VjpzR%Rk{7(r#IO ]$P,^mZ(9%Qm_ѭ]t{<.= eXZ'}. hs{-}L{ D)a`1x#M ]$]TZ|m6;îʏqRJ0%({Q]zM]DU*7S?v\9zf|\~<UЯp:oaUpX;TJ؟>ۄMK&[`Y1nqIPBI47<㥵v,sV{Y?1[f.ࣆP}nzqk/fM8[8RХrI$׭;ь7nyKqAyٴUxv0psghr I4#PVg5ЖV.<%"T$`7_s~'TquOHV̼Pѻ۩tI ͜b`M|d.oe0?1g,}J?nGΧ_uЕjQ[G:~0KQB#PB 0+ιcFVv\:ஙTSbB48oKߨe0- ,__}w'(IJ"`oGaW|WqsΛ⯌^ľip7ˣ8L4 .i4Zb >rGqJ-kKן ][ǥf{"rbxfmM+prwAjAObւ/ZW.*wXC)xSV9ofǿ;|-,֙6{x< MF:H*tXXX,ё- '|;. v~W2Z-h4!-dtiJ*tAչꏼkF5wn!ۖǭ.pP=%HBI7؇YWm J*tRV>c#)Y+, ~3a?%Цd.!`-8~$) {;ڪyqƛ'^`/|!ȏԳBUD@*+봬˿\ Sq vAAJܡ_m>$qB(=~ ㍍L?Tqޕg\3NUC &,puR.V)*IPJ"؎fpw!%GŊ& *7$F X\gR%Z"؎\­oy՝gwY>&pf_UA&-,c2}$1Bv4*Sh<2k7U -x_XW)*I@Ez돕w<4q) "1aקZ4 ~PB靲 0Us~:rŦ'k9|eeCs05(Xy< 2._}({=%KF9jY|=J%tTu|ڪ;7mdrЙużUڎ&( Ea5AAI"QBhaoߴ5;.5qd,t4 ەz( j+ |~;\Ay;7{B,/gκ]upH%0>lOz"Z/!IP.X 6a<I8j`1o'@!pppC ՇܗkYmw\j?SΥʰ'věGE;ٴ%=%C*t }~U7ϛ~Ku7eqv-~{$,v ?(9(Kh1#4>I$eZ"`/$oes͇qD< F+%P|8+0Eq2XN`pOuW{?$g_;n;6mdZ3˳]>&ovZgě ^{hB?| 0;uD<{0N"̇= 63䮩/E }R]S9[؎ $pqZ֏Dzo=}śO0{g:,/oo IY8#$/- -x[MpndtÕXֻgUl9} tI˒/#Yє%ԙ~<8D# @-wL{ +ca_]>:.g N>δ,h,{#CFėZ2؂ < lf1X{6|NIm~vfmY U>Y.-(X9 +"D.U23_N0{ϿUJG^_ ecΧ Z&C@ xf,bĉ 7]]vu[{wlÝTf/S`Lmӕ!~%aG-w-*]mŋ.*;eO.≮Cݑg`$;Gy"\0fj;1GF \K㩬ZSp;6mdFЙ ~~ܗxrl6%sZ,h2!5tO:0 ]bmv |w[J=o3)Y1 jZ&C_ j Dz -&TK4 ruh<rZ_x[->ɯ}KmGaN0hc'] }P]_`;Zz[ xY#'/MQet=MXV/ZTKb[\k9M)nT͊ٗ]TY.XiW]ǥb%&)%tILh.k>|.nj͏poޅY$k'Xwo3vOǥT~<|y%K$B lGa3|*FPUa?NptrhTA.scZs|c#%,Ϝ }SY.g~ Y(E }R]bc++>~9euT8>MD/%a`[qrU5^"M ek<54 IDATԜǦPRǙs`W* z|,V%&TJ2xpax? 3[;.S­9 j;`0 ֠%!I-wxeOaNs$U}qIg`VQ\dФ0)l,8ӸᇱH*tXeO¨_['G: ʃO۴Md5[GJHf%&4J20}-w~g,%Z-v4CJȯz˸ `E6.WnشAgWdŬx3*E:";.Dt_$Be+ݥs7ބ̐_zRS} lGi7t:bgv|J?r!e7tsx$ }8Za:UYě6!1-s8\wDæ]wqIM }Xe47-ϧYn|☳ikA+,{9`)E =i>\,/orξO] 4v\Lm/㭴,R01nd<-TK_imY/F:qcO|ɴ{u,+NQI?(eh|˙=uE%w}f ?+QBOJjUKםXO_zfcpǬKהn6`JQ,V/z+IBjVq^aWlzym:,8^UȰf٧PBO2ЇGvno4_Kǥ-#uv9PD$` jXucYT k*!ގ|oT+qfԳ)"AjMy0z[^WT}|N2u-OGv4 eZmw%${2+۰ l][ωxfti&"MƅIo>T'vc,c.gx3s% \]j<ˀzns>xa|1lHg^Hm>k[i""GbaK kݕГZ"mBݾ[x1PEǥzW 8KWaǕ3'ׯh"&fu'rOT9b.g2"[,#w>T,WQXjɫ1GzEz"*۰ iw~z乻6w|{mݭCD5J% =g>-] ;,ߓ6/u l'zdp-^"AzX ^_#e|alG3/ >i; Z?BG<%=o_}(oʊjs!gż4zZ`; :]wUzBS=[wҏ6ctf+cpǬKߚ{WU."1ဒQmXV!?UqaoG+j||fyý|NjTU."1`3-f7_KLrDɞ m8kI+e0?|η=q62v:sVmGC~qzJ#|rdeԭiS#?rf/SYc>(H"\k{cQ$Kן7<[tɶ;~fO?:TMDK꾝|8+t TI }1]uEtW.pᘜ>u''lG;FR7g_+9av s~ -Q5t/qIJ 5}8mnn>3h={vz~~|ǍO?jkkW-p5t|30"=ڎ&"moc f+V/Z|h5Oe77HII|o.[̙˲xJ]2sͤFϔ!1u4~48+HED]Ɔ-(`^" '=> x8}KJJ=酅G|~[[K.k)5>&sǬKkf@>AD$4o(XZª%D ?®۽ |^ =+~7oU`_n?hn}'cC_D$!;6esD BAo~ς_{}e˖ &:6f̜͗ڲg3 vk;$4Lk|Ŭ.&J{n\_m-󻕙y]}In{_VMs֑𩒹$F3ҭB'8#, g{sA&i.\|?qdyrȽy7i!a>&z)vk< =Gr\nn<إw}i{a9d!"ڡsdNu:,~6@ @}nQɓ7>}R^9qa_T=cao1~{^,-jAi!帒$N)}Z'(mʁ^sss\ﱜm 4}A~..bs2ٴ{M&(ɋH9䇴aYKXPl\qL =tqۚ#<:zKdkuu5-Lxq2U3ߺ^֜j'*~O14d M}FHԙP`ѥJ/ ,8E%ɒSA+`Ox|p#p(?ǻ<0ɩ0vQ{$&Ѯ>*vq[M$uĂ߂&ifZF)Jq,JZ^^wpWhO̬~W=#-b 555'bk2c1 %*;!=t@h*|UTisdI1Ed0d:`\؞&,g#$%KB3pF.*k)ў.k֬ISO<^ڣ>l+s <,k>5 dW0v'[ ^؛YW5+b>nէvs F;׌?!z]ً:bĪ%?|tпHו܇]]8K=CL?~|sjkkyn6vZ>;mvPT v_ٲwuS`{Eq[[f炻0 ya>b⩑./z`Qޜ,A \܃ddd0M󪂂f̘رc}G{ϛ~Mtڋ$?C^Ug:I|!ժvELc.,z#.1 sгJ=`z't8WUx,` 1y^7kIup jٮދI[v@u! {\{o"2wCzzenV-1. sп1zvJ4?߀%F{?If]}0fYunxު׬zg 5pqa7{ne0$rB߄];x7+} 3,(w훆1ktl׻sCSݪo gՋHrS<I%.ݮS Xའ]=Z&ic0n[ mt;"eƄ< p g70{ v+z5 q[:[|;ZSv)w()w5+ժIl( ۊ{GHU&̠['=n3铰V1}[ ΥV՗|E 4N3++"nB҉a-cUqiJԄ.lyy>ߌVixܭ_9.3{K:+Vg綹&wAn(ؿjx3\)Klaid=r~?>t] oLh,U"1bQ`Sy`GhxRB֪Gܵ1>CzX{0YxE\%q\T&00yXᇜ{_rWUd+A& P.kogբU$hzo3UoVVՋˀu%tI.+^tQQ9NX8=宲uVHml]fgQBުäc]1rW5G$l'%Y6#D ]V=<`>.Sd-J~Z"ةQՋ6'C ]ȭe]Ov>xo"V} m2 J iV- . #J2|Zcxa)w)P96h8Kڪo0nȐUʇ˃K0IJC ]$5 qpX'Rp!s|oS V}z2dC|Ջ %ttaY1Y&;o|.Hk^[v V y.'}ωG8ÅHogaYspU(2:ύɔsSj3:[ w$GEؓnDZrі4<( Vl۱u.x]oU/eRN`+g|EC*7Ό1Z~|qz7宪v5[H>exI 9N(ۓ^g j PBV)@.@scw[ܭ߫{ N ikUđ ⍔ebbЧ.O?6i/ nՇnӔM<;фV%0"d#\ո3)$ȭ¦G[i߃oުoOM&tfO_F8UNg>->H[^7hOr8 {7(;.+ѝ }Z2 {حtUKCDCH2 o}B:d\K AE1L $y8'TUώG8CPP&TL ǬV}Uى~8wU0!nP.2T-pjFmPw[v@E׉sdxN`.$> MJ"7K d>oZ;MԪ^[<宪vYjKȣ`jgRBK<|wˀ%|3:[&tL+g)w;J`Jgo4A#ES"DV."2[^|خY_ۚY3ff[犷C8 ?? ]EPgKX{8ΤPB Eb'*k ؿW؋Ri)QVWw"Vi@tϞ5ڪ1#N¦>N5@@L jkN;d lG/%!F ]DzV=,jFcީ73 WFr >?څNQuIܪ='|̀*ӂz?Yg(Eb'9[}ESq8f5`LFK]=r|?~w>[Fc_w;t{3-<|x4BaڪL\ '`8fј1t&sE};iW:)wEvlp ~sT6{ታ௳⿖ \Y ^b%!d#P{Hzo=ʶS*BԹx|ǖa'OaPxb)Հak,QgiP]$1h6"oxt-1yx糫d.Jt5[ǻ"C.Z<g{aIŹ25Y.X|?NQ J"9{[0$sU][GxzU4.?0nLe;OKvS>-Ӫ=&58p‡|:iiCJX"Q]$vN'wyŁχW˽:[{HS"9co>uɲicqNp i}^((Xq /z- J" ` ~ADu}z_a>'a1z蔻#m;({EU+4xIrS=NCx7nǪE_K x{Ѓsv$i0iQ`p +&!%;%tػ|P2AYy5^şLBFo]o|.Hk~Snws"mj:2sB~D0 Ya IDAT߰j%')$j#= %ف 1JVlq=tݘ=n{[$ߓ[΁Dဒ{+U%R2SB鋲Unc:cY[A[}έsGғ$^fIcNj ⍰:@CٸfOr;o;)|o& {`vwBnXFUOG8L ]Dd0]DLb|./PTŷ_?d߻Ot^IJzn5H,5x.ͩzhw=d |v  }V-%$+%tX0ǁ]siMIٛN;6o:M3?j8q.TC~\~8+z`XSByZizh T}]}2Z7Ĺ`.q?i}glGJޖ&-M2ђfn'38:Mw#_-I>'&dwzB ngz<G\8s{}@V}Ɔ՘uX>N`(wjjZu~0]`Gh00dhS."2,ًW;]4_^71i^O4eWUU. xaF:%@ ]DdXL؁wc'm;qpB, cXS;p=UX= '֗X5%##}9GMMπ,$."2X,F˰mp qZPU?>F>|w)p۩~7|}~׉'uuun߻w'`WÒL\ '`8faX83`ob'*y. _Q湧ĉ+y7744| xuL"J""3֏$,N`.is̛Z|^sN3<… kf2 +u%t雎猓 L?b+yo=n&77mm V瀼"+Oς Md}Q)>-? 0̹UIL9u]N ㏳|8pZ/^6"̀hO? hsL ]DDbkAܶe{wbesg5tHcRkQm MA vB #.EW}InTHEAJW.*ԅY38s;Ψ3w~={=<<||{5u…,]R)HS~='8I.{0뼶+L+WOM~$je^%id&!b֞-hmmJr >6E#3EEgܛb$˓<$ߧ8xwŪY즕\}}S7)$4_^Oב$&Ydw͓2I`000pԩSӧRi^/splR_don}$%y!E`؋7nuرccƎT_N)e2 nт :;;k vojjd&9ꀾ{*oBTh۶m} 'O466^6:%Y2ucqT:{r\ioo-JoTϧ766^OP[`Nv4}Tԫ5R7[S?tPeMMM{3q$LѽL _Jw_ްa-[ڲptvvȑ#宮s===&}NG؆FG@`[dSKK˦Us9k\>3y2O״cCq6qim S``D{֥>h/QF:kDdt $Tך}F1C]IQ|ߍh??-jXeezM0R+IvKIkI^@?-Ie;As/ZIr(÷$''3,ԣ#W$ǓK1_-$kSTjSI~}Ҕ\?Su9ɧ)f4ZbF>@~1gIю#w(H:c)Ϋw%9IJr~z SkܽIENDB`graphene-1.8.0/doc/triangle-barycentric.svg000066400000000000000000000221601324365266600207250ustar00rootroot00000000000000 image/svg+xml A B C v u graphene-1.8.0/doc/xml/000077500000000000000000000000001324365266600146735ustar00rootroot00000000000000graphene-1.8.0/doc/xml/gtkdocentities.ent.in000066400000000000000000000005341324365266600210320ustar00rootroot00000000000000 graphene-1.8.0/doc/xml/meson.build000066400000000000000000000011071324365266600170340ustar00rootroot00000000000000ent_conf = configuration_data() ent_conf.set('PACKAGE', 'Graphene') ent_conf.set('PACKAGE_BUGREPORT', 'https://github.com/ebassi/graphene/issues') ent_conf.set('PACKAGE_NAME', 'Graphene') ent_conf.set('PACKAGE_STRING', 'graphene') ent_conf.set('PACKAGE_TARNAME', 'graphene-' + meson.project_version()) ent_conf.set('PACKAGE_URL', 'http://ebassi.github.io/graphene') ent_conf.set('PACKAGE_VERSION', meson.project_version()) ent_conf.set('PACKAGE_API_VERSION', graphene_api_version) configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf) graphene-1.8.0/meson.build000066400000000000000000000237231324365266600154770ustar00rootroot00000000000000project('graphene', 'c', version: '1.8.0', license: 'MIT', meson_version: '>= 0.43.1', default_options: [ 'buildtype=debugoptimized', 'c_std=c99', 'warning_level=1' ]) cc = meson.get_compiler('c') host_system = host_machine.system() add_project_arguments([ '-D_GNU_SOURCE' ], language: 'c') # Version graphene_version = meson.project_version() version_array = graphene_version.split('.') graphene_major_version = version_array[0].to_int() graphene_minor_version = version_array[1].to_int() graphene_micro_version = version_array[2].to_int() graphene_api_version = '@0@.0'.format(graphene_major_version) # The interface age is reset every time we add new API; this # should only happen during development cycles, otherwise the # interface age is the same as the micro version if graphene_minor_version.is_odd() graphene_interface_age = 0 else graphene_interface_age = graphene_micro_version endif graphene_binary_age = 100 * graphene_minor_version + graphene_micro_version # Maintain compatibility with the previous libtool versioning soversion = 0 libversion = '@0@.@1@.@2@'.format(soversion, graphene_binary_age - graphene_interface_age, graphene_interface_age) # Paths graphene_prefix = get_option('prefix') graphene_libdir = join_paths(graphene_prefix, get_option('libdir')) graphene_includedir = join_paths(graphene_prefix, get_option('includedir')) graphene_datadir = join_paths(graphene_prefix, get_option('datadir')) graphene_api_path = '@0@-@1@'.format(meson.project_name(), graphene_api_version) conf = configuration_data() # Compiler and linker flags common_cflags = [] common_ldflags = [] if cc.get_id() == 'msvc' # Make MSVC more pedantic, this is a recommended pragma list # from _Win32_Programming_ by Rector and Newcomer. Taken from # glib's msvc_recommended_pragmas.h--please see that file for # the meaning of the warning codes used here test_cflags = [ '-we4002', '-we4003', '-w14010', '-we4013', '-w14016', '-we4020', '-we4021', '-we4027', '-we4029', '-we4033', '-we4035', '-we4045', '-we4047', '-we4049', '-we4053', '-we4071', '-we4150', '-we4819' ] else test_cflags = [ '-ffast-math', '-fstrict-aliasing', '-Wpointer-arith', '-Wmissing-declarations', '-Wformat=2', '-Wstrict-prototypes', '-Wmissing-prototypes', '-Wnested-externs', '-Wold-style-definition', '-Wunused', '-Wuninitialized', '-Wshadow', '-Wmissing-noreturn', '-Wmissing-format-attribute', '-Wredundant-decls', '-Wlogical-op', '-Wcast-align', '-Wno-unused-local-typedefs', '-Werror=implicit', '-Werror=init-self', '-Werror=main', '-Werror=missing-braces', '-Werror=return-type', '-Werror=array-bounds', '-Werror=write-strings', ] endif common_cflags = cc.get_supported_arguments(test_cflags) if host_system == 'linux' and cc.get_id() == 'gcc' common_ldflags = [ '-Wl,-Bsymbolic-functions', '-Wl,-z,relro', '-Wl,-z,now', ] endif # Maintain compatibility with Autotools on macOS if host_system == 'darwin' common_ldflags += [ '-compatibility_version 1', '-current_version 1.0', ] endif # Required dependencies mathlib = cc.find_library('m', required: false) threadlib = dependency('threads') # Headers test_headers = [ 'stdlib.h', 'stdint.h', 'stdbool.h', 'memory.h', ] foreach h: test_headers conf.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h), description: 'Define if @0@ is available'.format(h)) endforeach conf.set('HAVE_PTHREAD_H', cc.has_header('pthread.h', dependencies: threadlib), description: 'Define if pthread.h is available') # Functions if cc.has_function('memalign', prefix: '#include \n#include ') conf.set10('HAVE_MEMALIGN', 1, description: 'Define if memalign() is available') elif cc.has_function('_aligned_malloc', prefix: '#include ') conf.set10('HAVE__ALIGNED_MALLOC', 1, description: 'Define if _aligned_malloc() is available') # Don't probe the ones below on Windows because when building with # MinGW-w64 on MSYS2, Meson<0.37.0 incorrectly detects those below as # being available even though they're not. elif cc.has_function('aligned_alloc', prefix: '#include ') and not (host_system == 'windows') conf.set10('HAVE_ALIGNED_ALLOC', 1, description: 'Define if aligned_malloc() is available') elif cc.has_function('posix_memalign', prefix: '#include ') and not (host_system == 'windows') conf.set10('HAVE_POSIX_MEMALIGN', 1, description: 'Define if posix_memalign() is available') else error('No aligned malloc function could be found.') endif # Look for sincosf(), a GNU libc extension conf.set('HAVE_SINCOSF', cc.has_function('sincosf', prefix: '#include ', args: [ '-D_GNU_SOURCE' ], dependencies: mathlib), description: 'Define if sincosf() is available') # Debugging debug_flags = [] buildtype = get_option('buildtype') if buildtype == 'release' debug_flags += [ '-DG_DISABLE_ASSERT' ] elif buildtype.startswith('debug') debug_flags += [ '-DGRAPHENE_ENABLE_DEBUG' ] endif extra_args = [] # Detect and set symbol visibility if get_option('default_library') != 'static' if host_system == 'windows' conf.set('DLL_EXPORT', true) conf.set('_GRAPHENE_PUBLIC', '__declspec(dllexport) extern') if cc.get_id() != 'msvc' extra_args += ['-fvisibility=hidden'] endif else conf.set('_GRAPHENE_PUBLIC', '__attribute__((visibility("default"))) extern') extra_args += ['-fvisibility=hidden'] endif endif # Optional dependency on GObject build_gobject = false gobject_req_version = '>= 2.30.0' if get_option('gobject_types') graphene_gobject_api_path = '@0@-gobject-@1@'.format(meson.project_name(), graphene_api_version) gobject = dependency('gobject-2.0', version: gobject_req_version, required: false) build_gobject = gobject.found() if build_gobject if cc.get_id() == 'msvc' extra_args += ['/FImsvc_recommended_pragmas.h'] endif endif endif # Optional dependency on GObject-Introspection; if GObject is disabled # then we don't build introspection data either build_gir = build_gobject and get_option('introspection') and get_option('default_library') == 'shared' # Check for InitOnce on Windows if host_system == 'windows' init_once_prog = ''' #define _WIN32_WINNT 0x0600 #include INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT; BOOL CALLBACK InitHandleFunc (PINIT_ONCE i, PVOID arg, PVOID *ctx) { return TRUE; } int main (void) { BOOL bInitStatus = InitOnceExecuteOnce (&g_InitOnce, InitHandleFunc, NULL, NULL); return 0; } ''' conf.set10( 'HAVE_INIT_ONCE', cc.compiles(init_once_prog, name: 'InitOnceExecuteOnce'), description: 'Define if InitOnceExecuteOnce is available', ) endif # Configuration for our installed config header graphene_conf = configuration_data() # Enabled SIMD implementations graphene_simd = [] # SSE intrinsics sse2_cflags = '' if get_option('sse2') sse_prog = ''' #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) # if !defined(__amd64__) && !defined(__x86_64__) # error "Need GCC >= 4.2 for SSE2 intrinsics on x86" # endif #elif defined (_MSC_VER) && (_MSC_VER < 1800) # if !defined (_M_X64) && !defined (_M_AMD64) # error "Need MSVC 2013 or later for SSE2 intrinsics on x86" # endif #endif #if defined(__SSE__) || (_M_IX86_FP > 0) || (_M_X64 > 0) || (_MSC_VER >= 1800) # include # include # include #else # error "No SSE intrinsics available" #endif int main () { __m128i a = _mm_set1_epi32 (0), b = _mm_set1_epi32 (0), c; c = _mm_xor_si128 (a, b); return 0; }''' if cc.compiles(sse_prog, name: 'SSE intrinsics') graphene_conf.set('GRAPHENE_HAS_SSE', 1) if cc.get_id() != 'msvc' extra_args += ['-mfpmath=sse', '-msse', '-msse2'] sse2_cflags = '-mfpmath=sse -msse -msse2' endif graphene_simd += [ 'sse2' ] endif endif # GCC vector intrinsics if get_option('gcc_vector') gcc_vector_prog = ''' #if defined(__GNUC__) # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9) # error "GCC vector intrinsics are disabled on GCC prior to 4.9" # elif defined(__arm__) # error "GCC vector intrinsics are disabled on ARM" # endif #else # error "Need GCC for GCC vectors intrinsics" #endif typedef float simd4f __attribute__((vector_size(16))); typedef int simd4i __attribute__((vector_size(16))); int main () { simd4f s = { 1.f, 2.f, 3.f, 4.f }; simd4i m = { 0, 1, 1, 3 }; simd4f r = __builtin_shuffle (s, m); return 0; }''' if cc.compiles(gcc_vector_prog, name: 'GCC vector intrinsics') graphene_conf.set('GRAPHENE_HAS_GCC', 1) graphene_simd += [ 'gcc' ] endif endif # ARM NEON intrinsics neon_cflags = '' if get_option('arm_neon') neon_prog = ''' #ifndef __ARM_EABI__ #error "EABI is required (to be sure that calling conventions are compatible)" #endif #ifndef __ARM_NEON__ #error "No ARM NEON instructions available" #endif #include int main () { const float32_t __v[4] = { 1, 2, 3, 4 }; \ const unsigned int __umask[4] = { \ 0x80000000, \ 0x80000000, \ 0x80000000, \ 0x80000000 \ }; \ const uint32x4_t __mask = vld1q_u32 (__umask); \ float32x4_t s = vld1q_f32 (__v); \ float32x4_t c = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (s), __mask)); \ return 0; }''' if cc.compiles(neon_prog, name: 'ARM NEON intrinsics') graphene_conf.set('GRAPHENE_HAS_ARM_NEON', 1) extra_args += ['-mfpu=neon'] if host_system == 'android' extra_args += ['-mfloat-abi=softfp'] neon_cflags = '-mfpu=neon -mfloat-abi=softfp' else neon_cflags = '-mfpu=neon' endif graphene_simd += [ 'neon' ] endif endif # Scalar is always available as a fallback graphene_simd += [ 'scalar' ] python3 = import('python3') gnome = import('gnome') subdir('src') if get_option('gtk_doc') subdir('doc') endif graphene-1.8.0/meson_options.txt000066400000000000000000000017601324365266600167670ustar00rootroot00000000000000option('gtk_doc', type: 'boolean', value: false, description: 'Enable generating the API reference (depends on GTK-Doc)') option('gobject_types', type: 'boolean', value: true, description: 'Enable GObject types (depends on GObject)') option('introspection', type: 'boolean', value: true, description: 'Enable GObject Introspection (depends on GObject)') option('gcc_vector', type: 'boolean', value: true, description: 'Enable GCC vector fast paths (requires GCC)') option('sse2', type: 'boolean', value: true, description: 'Enable SSE2 fast paths (requires SSE2 or later)') option('arm_neon', type: 'boolean', value: true, description: 'Enable ARM NEON fast paths (requires ARM)') option('tests', type: 'boolean', value: true, description: 'Build the test suite (requires GObject)') option('benchmarks', type: 'boolean', value: true, description: 'Build the benchmarks suite (requires GObject)') graphene-1.8.0/src/000077500000000000000000000000001324365266600141155ustar00rootroot00000000000000graphene-1.8.0/src/bench/000077500000000000000000000000001324365266600151745ustar00rootroot00000000000000graphene-1.8.0/src/bench/graphene-bench-utils.c000066400000000000000000000225521324365266600213520ustar00rootroot00000000000000/* graphene-bench-utils.c: Benchmarking suite * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "config.h" #include #include #include #include "graphene-bench-utils.h" enum { /* initial state */ BENCH_START, /* fixture set up */ BENCH_SETUP, /* run */ BENCH_WARM_UP, BENCH_RUNNING, BENCH_OUTPUT, /* fixture teardown */ BENCH_TEARDOWN, /* final state */ BENCH_STOP }; enum { BENCH_FORMAT_NONE, BENCH_FORMAT_CSV, BENCH_FORMAT_JSON }; static int bench_state; static int bench_exit_status; static const char *bench_argv0; static const char *bench_fast_path; static GrapheneBenchSetupFunc bench_fixture_setup; static GrapheneBenchTeardownFunc bench_fixture_teardown; static gpointer bench_fixture; static GHashTable *bench_units; static int bench_unit_rounds = 10000; static int bench_output; static gboolean bench_verbose = FALSE; static int bench_warm_up_runs = 50; static int bench_runs = 100; static char *bench_format = NULL; static GOptionEntry bench_options[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &bench_verbose, "Print extra information", NULL }, { "warm-up-runs", 0, 0, G_OPTION_ARG_INT, &bench_warm_up_runs, "Number of warm up cycles", "ITERATIONS" }, { "bench-runs", 0, 0, G_OPTION_ARG_INT, &bench_runs, "Number of bench cycles", "ITERATIONS" }, { "output-format", 'f', 0, G_OPTION_ARG_STRING, &bench_format, "Format of the output (csv,json)", "FORMAT" }, { NULL, } }; void graphene_bench_init (int *argc_p, char ***argv_p, ...) { GOptionContext *context; char **argv = argv_p != NULL ? *argv_p : NULL; int argc = argc_p != NULL ? *argc_p : 0; const char *opt = NULL; va_list opts; if (argc != 0) bench_argv0 = argv[0]; va_start (opts, argv_p); opt = va_arg (opts, const char *); while (opt != NULL) { if (g_strcmp0 (opt, "implementation") == 0) bench_fast_path = va_arg (opts, const char *); opt = va_arg (opts, const char *); } va_end (opts); context = g_option_context_new ("Graphene benchmark options"); g_option_context_add_main_entries (context, bench_options, NULL); g_option_context_set_help_enabled (context, TRUE); g_option_context_set_ignore_unknown_options (context, TRUE); g_option_context_parse (context, argc_p, argv_p, NULL); if (g_strcmp0 (bench_format, "csv") == 0) bench_output = BENCH_FORMAT_CSV; if (g_strcmp0 (bench_format, "json") == 0) bench_output = BENCH_FORMAT_JSON; } void graphene_bench_set_fixture_setup (GrapheneBenchSetupFunc func) { g_assert (bench_fixture_setup == NULL); bench_fixture_setup = func; } void graphene_bench_set_fixture_teardown (GrapheneBenchTeardownFunc func) { g_assert (bench_fixture_teardown == NULL); bench_fixture_teardown = func; } void graphene_bench_add_func (const char *path, GrapheneBenchFunc func) { if (bench_units == NULL) bench_units = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); g_hash_table_insert (bench_units, g_strdup (path), func); } static void graphene_bench_warm_up (const char *impl, const char *path, GrapheneBenchFunc func, int num_rounds) { int i; if (bench_verbose) g_printerr ("# warm up bench '[%s]:%s' (runs:%d)\n", bench_fast_path, path, bench_warm_up_runs); for (i = 0; i < num_rounds; i += 1) func (bench_fixture); } static double graphene_bench_run_test (const char *impl, const char *path, GrapheneBenchFunc func, gint64 num_rounds, double *round_min, double *round_max, double *round_avg) { GTimer *timer = g_timer_new (); double *round_elapsed = malloc (sizeof (double) * num_rounds); double elapsed = 0; int min_idx, max_idx; int i; g_timer_start (timer); for (i = 0; i < num_rounds; i += 1) { func (bench_fixture); round_elapsed[i] = g_timer_elapsed (timer, NULL) * 1000000000.0; g_timer_reset (timer); } g_timer_destroy (timer); *round_min = *round_max = 0; min_idx = max_idx = 0; for (i = 0; i < num_rounds; i += 1) { elapsed += round_elapsed[i]; if (round_elapsed[i] < *round_min) { *round_min = round_elapsed[i]; min_idx = i; } if (round_elapsed[i] > *round_max) { *round_max = round_elapsed[i]; max_idx = i; } } for (i = 0; i < num_rounds; i += 1) { if (i == min_idx || i == max_idx) continue; *round_avg += round_elapsed[i]; } if (min_idx != max_idx) *round_avg = *round_avg / (num_rounds - 2); else *round_avg = *round_avg / (num_rounds - 1); free (round_elapsed); if (bench_verbose) g_printerr ("# '[%s]:%s': %.6f usecs/round after %" G_GINT64_FORMAT " rounds\n", impl, path, elapsed, num_rounds); return elapsed; } static double format_time (double d, const char **unit) { if (d > 1000000000) { *unit = "s"; return d / 1000000000; } if (d > 1000000) { *unit = "ms"; return d / 1000000; } if (d > 1000) { *unit = "µs"; return d / 1000; } *unit = "ns"; return d; } static void graphene_bench_print_results (const char *impl, const char *path, double elapsed, int num_rounds, double min, double max, double avg) { const char *d_unit, *round_unit, *iter_unit; double d = format_time (elapsed, &d_unit); double round = format_time (avg, &round_unit); double iter = format_time (avg / bench_unit_rounds, &iter_unit); switch (bench_output) { case BENCH_FORMAT_NONE: g_print ("### '%s' (%" G_GINT64_FORMAT " iterations - using %s implementation) ###\n" " Total: %.6f %s (%d rounds)\n" " Per round: %.6f %s (%d iterations per round)\n" " Per iteration: %.6f %s\n", path, (gint64) (num_rounds * bench_unit_rounds), impl, d, d_unit, num_rounds, round, round_unit, bench_unit_rounds, iter, iter_unit); break; case BENCH_FORMAT_CSV: g_print ("%s,%s,%.6f,%.6f,%.6f\n", path, impl, elapsed, avg, avg / bench_unit_rounds); break; case BENCH_FORMAT_JSON: g_print ("{\"%s\":{\"impl\":\"%s\",\"total\":%.6f,\"iteration\":%.6f,\"round\":%.6f}}\n", path, impl, elapsed, avg, avg / bench_unit_rounds); break; default: break; } } static int graphene_bench_round_run (const char *impl) { bench_state = BENCH_START; if (bench_fixture_setup != NULL) { bench_state = BENCH_SETUP; bench_fixture = bench_fixture_setup (); } if (bench_units != NULL) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, bench_units); while (g_hash_table_iter_next (&iter, &key, &value)) { const char *path = key; GrapheneBenchFunc func = value; double elapsed, min, max, avg; elapsed = 0; min = max = avg = 0; bench_state = BENCH_WARM_UP; graphene_bench_warm_up (impl, path, func, bench_warm_up_runs); bench_state = BENCH_RUNNING; elapsed = graphene_bench_run_test (impl, path, func, bench_runs, &min, &max, &avg); bench_state = BENCH_OUTPUT; graphene_bench_print_results (impl, path, elapsed, bench_runs, min, max, avg); } } if (bench_fixture_teardown != NULL) { bench_state = BENCH_TEARDOWN; bench_fixture_teardown (bench_fixture); bench_fixture = NULL; } bench_state = BENCH_STOP; return bench_exit_status; } int graphene_bench_run (void) { return graphene_bench_round_run (bench_fast_path); } void graphene_bench_set_rounds_per_unit (int n_checks) { bench_unit_rounds = n_checks; } int graphene_bench_get_rounds_per_unit (void) { return MAX (bench_unit_rounds, 1); } graphene-1.8.0/src/bench/graphene-bench-utils.h000066400000000000000000000045711324365266600213600ustar00rootroot00000000000000/* graphene-bench-utils.h: Benchmarking suite * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_BENCH_UTILS_H__ #define __GRAPHENE_BENCH_UTILS_H__ #include #include G_BEGIN_DECLS typedef gpointer (* GrapheneBenchSetupFunc) (void); typedef void (* GrapheneBenchFunc) (gpointer fixture); typedef void (* GrapheneBenchTeardownFunc) (gpointer fixture); _GRAPHENE_PUBLIC void graphene_bench_init (int *argc, char ***argv, ...) G_GNUC_NULL_TERMINATED; _GRAPHENE_PUBLIC void graphene_bench_set_fixture_setup (GrapheneBenchSetupFunc func); _GRAPHENE_PUBLIC void graphene_bench_set_fixture_teardown (GrapheneBenchTeardownFunc func); _GRAPHENE_PUBLIC void graphene_bench_add_func (const char *path, GrapheneBenchFunc func); _GRAPHENE_PUBLIC int graphene_bench_run (void); _GRAPHENE_PUBLIC double graphene_bench_get_factor (void); _GRAPHENE_PUBLIC void graphene_bench_set_rounds_per_unit (int n_rounds); _GRAPHENE_PUBLIC int graphene_bench_get_rounds_per_unit (void); G_END_DECLS #endif /* __GRAPHENE_BENCH_UTILS_H__ */ graphene-1.8.0/src/bench/matrix.c000066400000000000000000000102341324365266600166440ustar00rootroot00000000000000#include "config.h" #if defined(HAVE_POSIX_MEMALIGN) && !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE 600 #endif #if defined(HAVE_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC) /* Required for _aligned_malloc() and _aligned_free() on Windows */ #include #endif #ifdef HAVE__ALIGNED_MALLOC /* On Windows, we have to use _aligned_malloc() which takes in parameters in * inverted order from aligned_alloc(), but things are more or less the same * there otherwise */ #define aligned_alloc(alignment,size) _aligned_malloc (size, alignment) /* if we _aligned_malloc()'ed, then we must do _align_free() on MSVC */ #define free_aligned(x) _aligned_free (x) #else #define free_aligned(x) free (x) #endif #include #include #include #include "graphene-simd4x4f.h" #include "graphene-bench-utils.h" #define N_ROUNDS 819200 typedef struct { graphene_simd4x4f_t *a; graphene_simd4x4f_t *b; graphene_simd4x4f_t *c; graphene_simd4f_t *pa; graphene_simd4f_t *qa; graphene_simd4f_t *ra; } MatrixBench; static gpointer alloc_align (gsize n, gsize size, gsize alignment) { gsize real_size = size * n; gpointer res; #if defined(HAVE_POSIX_MEMALIGN) if (posix_memalign (&res, alignment, real_size) != 0) g_assert_not_reached (); #elif defined(HAVE_ALIGNED_ALLOC) || defined (HAVE__ALIGNED_MALLOC) g_assert (real_size % alignment == 0); res = aligned_alloc (alignment, real_size); #elif defined(HAVE_MEMALIGN) res = memalign (alignment, real_size); #else #error "Need some type of aligned allocation function" #endif g_assert (res != NULL); return res; } #define alloc_n_matrix(n) alloc_align((n), sizeof (graphene_simd4x4f_t), 16) #define alloc_n_vec(n) alloc_align((n), sizeof (graphene_simd4f_t), 16) static gpointer matrix_setup (void) { MatrixBench *res = g_new0 (MatrixBench, 1); int i; res->a = alloc_n_matrix (N_ROUNDS); res->b = alloc_n_matrix (N_ROUNDS); res->c = alloc_n_matrix (N_ROUNDS); res->pa = alloc_n_vec (N_ROUNDS); res->qa = alloc_n_vec (N_ROUNDS); res->ra = alloc_n_vec (N_ROUNDS); for (i = 0; i < N_ROUNDS; i++) { graphene_simd4f_t p, q; p = graphene_simd4f_init (i, i, i, i); q = graphene_simd4f_init (N_ROUNDS - i, N_ROUNDS - i, N_ROUNDS - i, N_ROUNDS - i); res->a[i] = graphene_simd4x4f_init (p, p, p, p); res->b[i] = graphene_simd4x4f_init (q, q, q, q); res->pa[i] = graphene_simd4f_init (i, i, 0.f, 0.f); res->qa[i] = graphene_simd4f_init (N_ROUNDS - i, N_ROUNDS - 1, 1.f, 0.f); } return res; } static void matrix_multiply (gpointer data_) { MatrixBench *data = data_; int i; for (i = 0; i < N_ROUNDS; i++) graphene_simd4x4f_matrix_mul (&(data->a[i]), &(data->b[i]), &(data->c[i])); } static void matrix_project (gpointer data_) { MatrixBench *data = data_; int i; for (i = 0; i < N_ROUNDS; i++) { graphene_simd4f_t pback, qback, uback; float t, x, y; graphene_simd4x4f_vec3_mul (&(data->a[i]), &(data->pa[i]), &pback); graphene_simd4x4f_vec3_mul (&(data->a[i]), &(data->qa[i]), &qback); uback = graphene_simd4f_sub (data->pa[i], pback); t = -1.0f * graphene_simd4f_get_z (pback) / graphene_simd4f_get_z (uback); x = graphene_simd4f_get_x (pback) + t * graphene_simd4f_get_x (uback); y = graphene_simd4f_get_y (pback) + t * graphene_simd4f_get_y (uback); data->ra[i] = graphene_simd4f_init (x, y, 0.f, 0.f); } } static void matrix_teardown (gpointer data_) { MatrixBench *data = data_; free_aligned (data->a); free_aligned (data->b); free_aligned (data->c); free_aligned (data->pa); free_aligned (data->qa); free_aligned (data->ra); g_free (data); } int main (int argc, char *argv[]) { graphene_bench_init (&argc, &argv, "implementation", GRAPHENE_SIMD_S, NULL); graphene_bench_set_fixture_setup (matrix_setup); graphene_bench_set_fixture_teardown (matrix_teardown); graphene_bench_set_rounds_per_unit (N_ROUNDS); graphene_bench_add_func ("/simd/4x4f/multiply", matrix_multiply); graphene_bench_add_func ("/simd/4x4f/project", matrix_project); return graphene_bench_run (); } graphene-1.8.0/src/bench/meson.build000066400000000000000000000031241324365266600173360ustar00rootroot00000000000000graphene_bench_sources = [ 'graphene-bench-utils.h', 'graphene-bench-utils.c' ] graphene_bench = static_library('graphene-bench', graphene_bench_sources, c_args: common_cflags + [ '-DG_LOG_DOMAIN="Graphene-Bench"', '-DG_LOG_USE_STRUCTURED=1', '-DGLIB_DISABLE_DEPRECATION_WARNINGS', ], include_directories: [ graphene_inc ], install: false, dependencies: [ mathlib, graphene_dep ]) graphene_bench_dep = declare_dependency(link_with: [ graphene_bench ]) have_sse = graphene_simd.contains('sse2') have_gcc = graphene_simd.contains('gcc') have_neon = graphene_simd.contains('neon') all_simds = [ [ 'SSE', 'sse', have_sse ], [ 'GCC', 'gcc', have_gcc ], [ 'ARM_NEON', 'neon', have_neon ], [ 'SCALAR', 'scalar' ] ] bench_units = [ 'matrix' ] foreach simd: all_simds run_test = simd.get(2, true) if run_test foreach unit: bench_units exe = executable('@0@-@1@'.format(unit, simd[1]), unit + '.c', c_args: common_cflags + [ '-DGRAPHENE_COMPILATION', '-DGRAPHENE_SIMD_BENCHMARK', '-DGRAPHENE_HAS_' + simd[0], ], install: false, dependencies: [ graphene_bench_dep, graphene_dep ]) benchmark('@0@-@1@'.format(unit, simd[1]), exe) endforeach endif endforeach graphene-1.8.0/src/bench/vec2.c000066400000000000000000000030721324365266600162010ustar00rootroot00000000000000#include #include #include "graphene-bench-utils.h" typedef struct { graphene_vec2_t *vectors; int n_vectors; } Vec2Bench; static gpointer vec2_setup (void) { Vec2Bench *res = g_new0 (Vec2Bench, 1); res->n_vectors = 4; res->vectors = g_new0 (graphene_vec2_t, res->n_vectors); graphene_vec2_init_from_vec2 (&(res->vectors[0]), graphene_vec2_zero ()); graphene_vec2_init_from_vec2 (&(res->vectors[1]), graphene_vec2_one ()); graphene_vec2_init_from_vec2 (&(res->vectors[2]), graphene_vec2_x_axis ()); graphene_vec2_init_from_vec2 (&(res->vectors[3]), graphene_vec2_y_axis ()); return res; } static void vec2_dot (gpointer data_) { Vec2Bench *data = data_; int n_checks = graphene_bench_get_rounds_per_unit (); int i; for (i = 0; i < n_checks; i++) { int a = g_random_int_range (0, 3); int b = g_random_int_range (0, 3); graphene_vec2_t *op1 = &(data->vectors[a]); graphene_vec2_t *op2 = &(data->vectors[b]); float res; res = graphene_vec2_dot (op1, op2); } } static void vec2_teardown (gpointer data_) { Vec2Bench *data = data_; g_free (data->vectors); g_free (data); } int main (int argc, char *argv[]) { graphene_bench_init (&argc, &argv, GRAPHENE_BENCH_OPT_IMPLEMENTATION, GRAPHENE_BENCH, NULL); graphene_bench_set_fixture_setup (vec2_setup); graphene_bench_set_fixture_teardown (vec2_teardown); graphene_bench_set_rounds_per_unit (10000); graphene_bench_add_func ("/vec2/dot", vec2_dot); return graphene_bench_run (); } graphene-1.8.0/src/bench/vec4.c000066400000000000000000000042461324365266600162070ustar00rootroot00000000000000#include #include #include "graphene-bench-utils.h" typedef struct { graphene_vec4_t *vectors; int n_vectors; } Vec4Bench; static gpointer vec4_setup (void) { Vec4Bench *res = g_new0 (Vec4Bench, 1); res->n_vectors = 6; res->vectors = g_new0 (graphene_vec4_t, res->n_vectors); graphene_vec4_init_from_vec4 (&(res->vectors[0]), graphene_vec4_zero ()); graphene_vec4_init_from_vec4 (&(res->vectors[1]), graphene_vec4_one ()); graphene_vec4_init_from_vec4 (&(res->vectors[2]), graphene_vec4_x_axis ()); graphene_vec4_init_from_vec4 (&(res->vectors[3]), graphene_vec4_y_axis ()); graphene_vec4_init_from_vec4 (&(res->vectors[4]), graphene_vec4_z_axis ()); graphene_vec4_init_from_vec4 (&(res->vectors[5]), graphene_vec4_w_axis ()); return res; } static void vec4_dot (gpointer data_) { Vec4Bench *data = data_; int n_checks = graphene_bench_get_rounds_per_unit (); int i; for (i = 0; i < n_checks; i++) { int a = g_random_int_range (0, data->n_vectors - 1); int b = g_random_int_range (0, data->n_vectors - 1); graphene_vec4_t *op1 = &(data->vectors[a]); graphene_vec4_t *op2 = &(data->vectors[b]); float res; res = graphene_vec4_dot (op1, op2); } } static void vec4_normalize (gpointer data_) { Vec4Bench *data = data_; int n_checks = graphene_bench_get_rounds_per_unit (); int i; for (i = 0; i < n_checks; i++) { int a = g_random_int_range (0, data->n_vectors - 1); graphene_vec4_t *op = &(data->vectors[a]); graphene_vec4_t res; graphene_vec4_normalize (op, &res); } } static void vec4_teardown (gpointer data_) { Vec4Bench *data = data_; g_free (data->vectors); g_free (data); } int main (int argc, char *argv[]) { graphene_bench_init (&argc, &argv, GRAPHENE_BENCH_OPT_IMPLEMENTATION, GRAPHENE_BENCH, NULL); graphene_bench_set_fixture_setup (vec4_setup); graphene_bench_set_fixture_teardown (vec4_teardown); graphene_bench_set_rounds_per_unit (10000); graphene_bench_add_func ("/vec4/dot", vec4_dot); graphene_bench_add_func ("/vec4/normalize", vec4_normalize); return graphene_bench_run (); } graphene-1.8.0/src/graphene-alloc-private.h000066400000000000000000000033521324365266600206220ustar00rootroot00000000000000/* graphene-alloc-private.h: aligned allocator * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_ALLOC_PRIVATE_H__ #define __GRAPHENE_ALLOC_PRIVATE_H__ #include "graphene-types.h" #include GRAPHENE_BEGIN_DECLS void * graphene_aligned_alloc (size_t size, size_t number, size_t alignment); void * graphene_aligned_alloc0 (size_t size, size_t number, size_t alignment); void graphene_aligned_free (void *mem); GRAPHENE_END_DECLS #endif /* __GRAPHENE_ALLOC_PRIVATE_H__ */ graphene-1.8.0/src/graphene-alloc.c000066400000000000000000000107311324365266600171440ustar00rootroot00000000000000/* graphene-alloc.c: aligned allocator * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "graphene-private.h" #include "graphene-alloc-private.h" #if defined(HAVE_POSIX_MEMALIGN) && !defined(_XOPEN_SOURCE) # define _XOPEN_SOURCE 600 #endif #if defined(HAVE_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC) /* Required for _aligned_malloc() and _aligned_free() on Windows */ #include #endif #ifdef HAVE__ALIGNED_MALLOC /* _aligned_malloc() takes parameters of aligned_malloc() in reverse order */ # define aligned_alloc(alignment, size) _aligned_malloc (size, alignment) /* _aligned_malloc()'ed memory must be freed by _align_free() on MSVC */ # define aligned_free(x) _aligned_free (x) #else # define aligned_free(x) free (x) #endif #include #include #include #include /*< private > * graphene_aligned_alloc: * @size: the size of the memory to allocate * @number: the multiples of @size to allocate * @alignment: the alignment to be enforced, as a power of 2 * * Allocates @number times @size memory, with the given @alignment. * * If the total requested memory overflows %G_MAXSIZE, this function * will abort. * * If allocation fails, this function will abort, in line with * the behaviour of GLib. * * Returns: (transfer full): the allocated memory */ void * graphene_aligned_alloc (size_t size, size_t number, size_t alignment) { void *res = NULL; size_t max_size = (size_t) -1; size_t real_size; if (size == 0 || number == 0) return NULL; if (size > 0 && number > max_size / size) { #ifndef G_DISABLE_ASSERT fprintf (stderr, "Overflow in the allocation of (%lu x %lu) bytes\n", (unsigned long) size, (unsigned long) number); abort (); #else return NULL; #endif } real_size = size * number; #ifndef G_DISABLE_ASSERT errno = 0; #endif #if defined(HAVE_POSIX_MEMALIGN) errno = posix_memalign (&res, alignment, real_size); #elif defined(HAVE_ALIGNED_ALLOC) || defined(HAVE__ALIGNED_MALLOC) /* real_size must be a multiple of alignment */ if (real_size % alignment != 0) { size_t offset = real_size % alignment; real_size += (alignment - offset); } res = aligned_alloc (alignment, real_size); #elif defined(HAVE_MEMALIGN) res = memalign (alignment, real_size); #else res = malloc (real_size); #endif #ifndef G_DISABLE_ASSERT if (errno != 0 || res == NULL) { fprintf (stderr, "Allocation error: %s\n", strerror (errno)); abort (); } #endif return res; } /*< private > * graphene_aligned_alloc: * @size: the size of the memory to allocate * @number: the multiples of @size to allocate * @alignment: the alignment to be enforced, as a power of 2 * * Allocates @number times @size memory, with the given @alignment, * like graphene_aligned_alloc(), but it also clears the memory. * * Returns: (transfer full): the allocated, cleared memory */ void * graphene_aligned_alloc0 (size_t size, size_t number, size_t alignment) { void *res = graphene_aligned_alloc (size, number, alignment); if (res != NULL) memset (res, 0, size * number); return res; } /*< private > * graphene_aligned_free: * @mem: the memory to deallocate * * Frees the memory allocated by graphene_aligned_alloc(). */ void graphene_aligned_free (void *mem) { aligned_free (mem); } graphene-1.8.0/src/graphene-box.c000066400000000000000000000510311324365266600166400ustar00rootroot00000000000000/* graphene-box.c: A box * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-box * @Title: Box * @Short_Description: Axis-aligned bounding box * * #graphene_box_t provides a representation of an axis aligned minimum * bounding box using the coordinates of its minimum and maximum vertices. */ #include "graphene-private.h" #include "graphene-box.h" #include "graphene-alloc-private.h" #include "graphene-point3d.h" #include "graphene-simd4f.h" #include "graphene-sphere.h" #include #include #if HAVE_PTHREAD #include #include #include #include #endif #if HAVE_INIT_ONCE #define _WIN32_WINNT 0x0600 #include #endif /** * graphene_box_alloc: (constructor) * * Allocates a new #graphene_box_t. * * The contents of the returned structure are undefined. * * Returns: (transfer full): the newly allocated #graphene_box_t structure. * Use graphene_box_free() to free the resources allocated by this function * * Since: 1.2 */ graphene_box_t * graphene_box_alloc (void) { return graphene_aligned_alloc0 (sizeof (graphene_box_t), 1, 16); } /** * graphene_box_free: * @box: a #graphene_box_t * * Frees the resources allocated by graphene_box_alloc(). * * Since: 1.2 */ void graphene_box_free (graphene_box_t *box) { graphene_aligned_free (box); } /** * graphene_box_init: * @box: the #graphene_box_t to initialize * @min: (nullable): the coordinates of the minimum vertex * @max: (nullable): the coordinates of the maximum vertex * * Initializes the given #graphene_box_t with two vertices. * * Returns: (transfer none): the initialized #graphene_box_t * * Since: 1.2 */ graphene_box_t * graphene_box_init (graphene_box_t *box, const graphene_point3d_t *min, const graphene_point3d_t *max) { if (min != NULL) graphene_point3d_to_vec3 (min, &box->min); else graphene_vec3_init_from_vec3 (&box->min, graphene_vec3_zero ()); if (max != NULL) graphene_point3d_to_vec3 (max, &box->max); else graphene_vec3_init_from_vec3 (&box->max, graphene_vec3_zero ()); return box; } /** * graphene_box_init_from_points: * @box: the #graphene_box_t to initialize * @n_points: the number #graphene_point3d_t in the @points array * @points: (array length=n_points): an array of #graphene_point3d_t * * Initializes the given #graphene_box_t with the given array * of vertices. * * If @n_points is 0, the returned box is initialized with * graphene_box_empty(). * * Returns: (transfer none): the initialized #graphene_box_t * * Since: 1.2 */ graphene_box_t * graphene_box_init_from_points (graphene_box_t *box, unsigned int n_points, const graphene_point3d_t *points) { graphene_box_init_from_box (box, graphene_box_empty ()); for (unsigned int i = 0; i < n_points; i++) { graphene_vec3_t v; graphene_point3d_to_vec3 (&points[i], &v); graphene_box_expand_vec3 (box, &v, box); } return box; } /** * graphene_box_init_from_vectors: * @box: the #graphene_box_t to initialize * @n_vectors: the number #graphene_point3d_t in the @vectors array * @vectors: (array length=n_vectors): an array of #graphene_vec3_t * * Initializes the given #graphene_box_t with the given array * of vertices. * * If @n_vectors is 0, the returned box is initialized with * graphene_box_empty(). * * Returns: (transfer none): the initialized #graphene_box_t * * Since: 1.2 */ graphene_box_t * graphene_box_init_from_vectors (graphene_box_t *box, unsigned int n_vectors, const graphene_vec3_t *vectors) { graphene_box_init_from_box (box, graphene_box_empty ()); for (unsigned int i = 0; i < n_vectors; i++) graphene_box_expand_vec3 (box, &vectors[i], box); return box; } /** * graphene_box_init_from_box: * @box: the #graphene_box_t to initialize * @src: a #graphene_box_t * * Initializes the given #graphene_box_t with the vertices of * another #graphene_box_t. * * Returns: (transfer none): the initialized #graphene_box_t * * Since: 1.2 */ graphene_box_t * graphene_box_init_from_box (graphene_box_t *box, const graphene_box_t *src) { box->min = src->min; box->max = src->max; return box; } /** * graphene_box_init_from_vec3: * @box: the #graphene_box_t to initialize * @min: (nullable): the coordinates of the minimum vertex * @max: (nullable): the coordinates of the maximum vertex * * Initializes the given #graphene_box_t with two vertices * stored inside #graphene_vec3_t. * * Returns: (transfer none): the initialized #graphene_box_t * * Since: 1.2 */ graphene_box_t * graphene_box_init_from_vec3 (graphene_box_t *box, const graphene_vec3_t *min, const graphene_vec3_t *max) { if (min != NULL) box->min = *min; else graphene_vec3_init_from_vec3 (&box->min, graphene_vec3_zero ()); if (max != NULL) box->max = *max; else graphene_vec3_init_from_vec3 (&box->max, graphene_vec3_zero ()); return box; } static inline graphene_box_t * graphene_box_init_from_simd4f (graphene_box_t *box, const graphene_simd4f_t min, const graphene_simd4f_t max) { box->min.value = min; box->max.value = max; return box; } static inline void graphene_box_expand_simd4f (const graphene_box_t *box, const graphene_simd4f_t v, graphene_box_t *res) { res->min.value = graphene_simd4f_min (box->min.value, v); res->max.value = graphene_simd4f_max (box->max.value, v); } /** * graphene_box_expand_vec3: * @box: a #graphene_box_t * @vec: the coordinates of the point to include, as a #graphene_vec3_t * @res: (out caller-allocates): return location for the expanded box * * Expands the dimensions of @box to include the coordinates of the * given vector. * * Since: 1.2 */ void graphene_box_expand_vec3 (const graphene_box_t *box, const graphene_vec3_t *vec, graphene_box_t *res) { graphene_box_expand_simd4f (box, vec->value, res); } /** * graphene_box_expand: * @box: a #graphene_box_t * @point: the coordinates of the point to include * @res: (out caller-allocates): return location for the expanded box * * Expands the dimensions of @box to include the coordinates at @point. * * Since: 1.2 */ void graphene_box_expand (const graphene_box_t *box, const graphene_point3d_t *point, graphene_box_t *res) { graphene_simd4f_t v = graphene_simd4f_init (point->x, point->y, point->z, 0.f); graphene_box_expand_simd4f (box, v, res); } /** * graphene_box_expand_scalar: * @box: a #graphene_box_t * @scalar: a scalar value * @res: (out caller-allocates): return location for the expanded box * * Expands the dimensions of @box by the given @scalar value. * * If @scalar is positive, the #graphene_box_t will grow; if @scalar is * negative, the #graphene_box_t will shrink. * * Since: 1.2 */ void graphene_box_expand_scalar (const graphene_box_t *box, float scalar, graphene_box_t *res) { float min = scalar * -1.f; float max = scalar; res->min.value = graphene_simd4f_add (box->min.value, graphene_simd4f_splat (min)); res->max.value = graphene_simd4f_add (box->max.value, graphene_simd4f_splat (max)); } /** * graphene_box_union: * @a: a #graphene_box_t * @b: the box to union to @a * @res: (out caller-allocates): return location for the result * * Unions the two given #graphene_box_t. * * Since: 1.2 */ void graphene_box_union (const graphene_box_t *a, const graphene_box_t *b, graphene_box_t *res) { res->min.value = graphene_simd4f_min (a->min.value, b->min.value); res->max.value = graphene_simd4f_max (a->max.value, b->max.value); } /** * graphene_box_intersection: * @a: a #graphene_box_t * @b: a #graphene_box_t * @res: (out caller-allocates) (optional): return location for the result * * Intersects the two given #graphene_box_t. * * If the two boxes do not intersect, @res will contain a degenerate box * initialized with graphene_box_empty(). * * Returns: true if the two boxes intersect * * Since: 1.2 */ bool graphene_box_intersection (const graphene_box_t *a, const graphene_box_t *b, graphene_box_t *res) { graphene_simd4f_t min, max; min = graphene_simd4f_max (a->min.value, b->min.value); max = graphene_simd4f_min (a->max.value, b->max.value); if (graphene_simd4f_cmp_ge (min, max)) { if (res != NULL) graphene_box_init_from_box (res, graphene_box_empty ()); return false; } if (res != NULL) graphene_box_init_from_simd4f (res, min, max); return true; } /** * graphene_box_get_width: * @box: a #graphene_box_t * * Retrieves the size of the @box on the X axis. * * Returns: the width of the box * * Since: 1.2 */ float graphene_box_get_width (const graphene_box_t *box) { float res = graphene_simd4f_get_x (graphene_simd4f_sub (box->max.value, box->min.value)); return fabsf (res); } /** * graphene_box_get_height: * @box: a #graphene_box_t * * Retrieves the size of the @box on the Y axis. * * Returns: the height of the box * * Since: 1.2 */ float graphene_box_get_height (const graphene_box_t *box) { float res = graphene_simd4f_get_y (graphene_simd4f_sub (box->max.value, box->min.value)); return fabsf (res); } /** * graphene_box_get_depth: * @box: a #graphene_box_t * * Retrieves the size of the @box on the Z axis. * * Returns: the depth of the box * * Since: 1.2 */ float graphene_box_get_depth (const graphene_box_t *box) { float res = graphene_simd4f_get_z (graphene_simd4f_sub (box->max.value, box->min.value)); return fabsf (res); } /** * graphene_box_get_size: * @box: a #graphene_box_t * @size: (out caller-allocates): return location for the size * * Retrieves the size of the box on all three axes, and stores * it into the given @size vector. * * Since: 1.2 */ void graphene_box_get_size (const graphene_box_t *box, graphene_vec3_t *size) { size->value = graphene_simd4f_sub (box->max.value, box->min.value); } /** * graphene_box_get_center: * @box: a #graphene_box_t * @center: (out caller-allocates): return location for the coordinates of * the center * * Retrieves the coordinates of the center of a #graphene_box_t. * * Since: 1.2 */ void graphene_box_get_center (const graphene_box_t *box, graphene_point3d_t *center) { graphene_vec3_t res; graphene_vec3_subtract (&box->max, &box->min, &res); graphene_vec3_scale (&res, 0.5f, &res); graphene_point3d_init_from_vec3 (center, &res); } /** * graphene_box_get_min: * @box: a #graphene_box_t * @min: (out caller-allocates): return location for the minimum point * * Retrieves the coordinates of the minimum point of the given * #graphene_box_t. * * Since: 1.2 */ void graphene_box_get_min (const graphene_box_t *box, graphene_point3d_t *min) { graphene_point3d_init_from_vec3 (min, &box->min); } /** * graphene_box_get_max: * @box: a #graphene_box_t * @max: (out caller-allocates): return location for the maximum point * * Retrieves the coordinates of the maximum point of the given * #graphene_box_t. * * Since: 1.2 */ void graphene_box_get_max (const graphene_box_t *box, graphene_point3d_t *max) { graphene_point3d_init_from_vec3 (max, &box->max); } /** * graphene_box_get_vertices: * @box: a #graphene_box_t * @vertices: (out) (array fixed-size=8): return location for an array * of 8 #graphene_vec3_t * * Computes the vertices of the given #graphene_box_t. * * Since: 1.2 */ void graphene_box_get_vertices (const graphene_box_t *box, graphene_vec3_t vertices[]) { graphene_point3d_t min, max; graphene_box_get_min (box, &min); graphene_box_get_max (box, &max); graphene_vec3_init (&vertices[0], min.x, min.y, min.z); graphene_vec3_init (&vertices[1], min.x, min.y, max.z); graphene_vec3_init (&vertices[2], min.x, max.y, min.z); graphene_vec3_init (&vertices[3], min.x, max.y, max.z); graphene_vec3_init (&vertices[4], max.x, min.y, min.z); graphene_vec3_init (&vertices[5], max.x, min.y, max.z); graphene_vec3_init (&vertices[6], max.x, max.y, min.z); graphene_vec3_init (&vertices[7], max.x, max.y, max.z); } /** * graphene_box_contains_point: * @box: a #graphene_box_t * @point: the coordinates to check * * Checks whether @box contains the given @point. * * Returns: `true` if the point is contained in the given box * * Since: 1.2 */ bool graphene_box_contains_point (const graphene_box_t *box, const graphene_point3d_t *point) { graphene_simd4f_t p = graphene_simd4f_init (point->x, point->y, point->z, 0.f); if (graphene_simd4f_cmp_ge (p, box->min.value) && graphene_simd4f_cmp_le (p, box->max.value)) return true; return false; } /** * graphene_box_contains_box: * @a: a #graphene_box_t * @b: a #graphene_box_t * * Checks whether the #graphene_box_t @a contains the given * #graphene_box_t @b. * * Returns: `true` if the box is contained in the given box * * Since: 1.2 */ bool graphene_box_contains_box (const graphene_box_t *a, const graphene_box_t *b) { /* we cheat a bit and access the SIMD directly */ if (graphene_simd4f_cmp_ge (b->min.value, a->min.value) && graphene_simd4f_cmp_le (b->max.value, a->max.value)) return true; return false; } static bool box_equal (const void *p1, const void *p2) { const graphene_box_t *a = p1; const graphene_box_t *b = p2; return graphene_vec3_equal (&a->min, &b->min) && graphene_vec3_equal (&a->max, &b->max); } /** * graphene_box_equal: * @a: a #graphene_box_t * @b: a #graphene_box_t * * Checks whether the two given boxes are equal. * * Returns: `true` if the boxes are equal * * Since: 1.2 */ bool graphene_box_equal (const graphene_box_t *a, const graphene_box_t *b) { return graphene_pointer_equal (a, b, box_equal); } /** * graphene_box_get_bounding_sphere: * @box: a #graphene_box_t * @sphere: (out caller-allocates): return location for the bounding sphere * * Computes the bounding #graphene_sphere_t capable of containing the given * #graphene_box_t. * * Since: 1.2 */ void graphene_box_get_bounding_sphere (const graphene_box_t *box, graphene_sphere_t *sphere) { graphene_vec3_t size; graphene_vec3_subtract (&box->max, &box->min, &size); graphene_vec3_scale (&size, 0.5f, &sphere->center); sphere->radius = graphene_vec3_length (&size) * 0.5f; } enum { BOX_ZERO = 0, BOX_ONE, BOX_MINUS_ONE, BOX_ONE_MINUS_ONE, BOX_INFINITY, BOX_EMPTY, N_STATIC_BOX }; static graphene_box_t static_box[N_STATIC_BOX]; static void init_static_box_once (void) { static_box[BOX_ZERO].min.value = graphene_simd4f_init_zero (); static_box[BOX_ZERO].max.value = graphene_simd4f_init_zero (); static_box[BOX_ONE].min.value = graphene_simd4f_init_zero (); static_box[BOX_ONE].max.value = graphene_simd4f_init (1.f, 1.f, 1.f, 0.f); static_box[BOX_MINUS_ONE].min.value = graphene_simd4f_init (-1.f, -1.f, -1.f, 0.f); static_box[BOX_MINUS_ONE].max.value = graphene_simd4f_init_zero (); static_box[BOX_ONE_MINUS_ONE].min.value = graphene_simd4f_init (-1.f, -1.f, -1.f, 0.f); static_box[BOX_ONE_MINUS_ONE].max.value = graphene_simd4f_init (1.f, 1.f, 1.f, 0.f); static_box[BOX_INFINITY].min.value = graphene_simd4f_init (-INFINITY, -INFINITY, -INFINITY, 0.f); static_box[BOX_INFINITY].max.value = graphene_simd4f_init (INFINITY, INFINITY, INFINITY, 0.f); static_box[BOX_EMPTY].min.value = graphene_simd4f_init (INFINITY, INFINITY, INFINITY, 0.f); static_box[BOX_EMPTY].max.value = graphene_simd4f_init (-INFINITY, -INFINITY, -INFINITY, 0.f); } #if HAVE_PTHREAD static pthread_once_t static_box_once = PTHREAD_ONCE_INIT; static inline void init_static_box (void) { int status = pthread_once (&static_box_once, init_static_box_once); if (status < 0) { int saved_errno = errno; fprintf (stderr, "pthread_once failed: %s (errno:%d)\n", strerror (saved_errno), saved_errno); } } #elif HAVE_INIT_ONCE static INIT_ONCE static_box_once = INIT_ONCE_STATIC_INIT; BOOL CALLBACK InitBoxFunc (PINIT_ONCE InitOnce, PVOID param, PVOID *ctx) { init_static_box_once (); return TRUE; } static inline void init_static_box (void) { BOOL bStatus = InitOnceExecuteOnce (&static_box_once, InitBoxFunc, NULL, NULL); if (!bStatus) fprintf (stderr, "InitOnceExecuteOnce failed\n"); } #else /* !HAVE_PTHREAD */ static bool static_box_init = false; static inline void init_static_box (void) { if (static_box_init) return; init_static_box_once (); static_box_init = true; } #endif /* HAVE_PTHREAD */ /** * graphene_box_zero: * * A #graphene_box_t with both the minimum and maximum vertices set at (0, 0, 0). * * The returned value is owned by Graphene and should not be modified or freed. * * Returns: (transfer none): a #graphene_box_t * * Since: 1.2 */ const graphene_box_t * graphene_box_zero (void) { init_static_box (); return &(static_box[BOX_ZERO]); } /** * graphene_box_one: * * A #graphene_box_t with the minimum vertex set at (0, 0, 0) and the * maximum vertex set at (1, 1, 1). * * The returned value is owned by Graphene and should not be modified or freed. * * Returns: (transfer none): a #graphene_box_t * * Since: 1.2 */ const graphene_box_t * graphene_box_one (void) { init_static_box (); return &(static_box[BOX_ONE]); } /** * graphene_box_minus_one: * * A #graphene_box_t with the minimum vertex set at (-1, -1, -1) and the * maximum vertex set at (0, 0, 0). * * The returned value is owned by Graphene and should not be modified or freed. * * Returns: (transfer none): a #graphene_box_t * * Since: 1.2 */ const graphene_box_t * graphene_box_minus_one (void) { init_static_box (); return &(static_box[BOX_MINUS_ONE]); } /** * graphene_box_one_minus_one: * * A #graphene_box_t with the minimum vertex set at (-1, -1, -1) and the * maximum vertex set at (1, 1, 1). * * The returned value is owned by Graphene and should not be modified or freed. * * Returns: (transfer none): a #graphene_box_t * * Since: 1.2 */ const graphene_box_t * graphene_box_one_minus_one (void) { init_static_box (); return &(static_box[BOX_ONE_MINUS_ONE]); } /** * graphene_box_infinite: * * A degenerate #graphene_box_t that cannot be expanded. * * The returned value is owned by Graphene and should not be modified or freed. * * Returns: (transfer none): a #graphene_box_t * * Since: 1.2 */ const graphene_box_t * graphene_box_infinite (void) { init_static_box (); return &(static_box[BOX_INFINITY]); } /** * graphene_box_empty: * * A degenerate #graphene_box_t that can only be expanded. * * The returned value is owned by Graphene and should not be modified or freed. * * Returns: (transfer none): a #graphene_box_t * * Since: 1.2 */ const graphene_box_t * graphene_box_empty (void) { init_static_box (); return &(static_box[BOX_EMPTY]); } graphene-1.8.0/src/graphene-box.h000066400000000000000000000174301324365266600166520ustar00rootroot00000000000000/* graphene-box.h: A box * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_BOX_H__ #define __GRAPHENE_BOX_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-vec3.h" GRAPHENE_BEGIN_DECLS /** * graphene_box_t: * * A 3D box, described as the volume between a minimum and * a maximum vertices. * * Since: 1.2 */ struct _graphene_box_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, min); GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, max); }; GRAPHENE_AVAILABLE_IN_1_2 graphene_box_t * graphene_box_alloc (void); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_free (graphene_box_t *box); GRAPHENE_AVAILABLE_IN_1_2 graphene_box_t * graphene_box_init (graphene_box_t *box, const graphene_point3d_t *min, const graphene_point3d_t *max); GRAPHENE_AVAILABLE_IN_1_2 graphene_box_t * graphene_box_init_from_points (graphene_box_t *box, unsigned int n_points, const graphene_point3d_t *points); GRAPHENE_AVAILABLE_IN_1_2 graphene_box_t * graphene_box_init_from_vectors (graphene_box_t *box, unsigned int n_vectors, const graphene_vec3_t *vectors); GRAPHENE_AVAILABLE_IN_1_2 graphene_box_t * graphene_box_init_from_box (graphene_box_t *box, const graphene_box_t *src); GRAPHENE_AVAILABLE_IN_1_2 graphene_box_t * graphene_box_init_from_vec3 (graphene_box_t *box, const graphene_vec3_t *min, const graphene_vec3_t *max); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_expand (const graphene_box_t *box, const graphene_point3d_t *point, graphene_box_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_expand_vec3 (const graphene_box_t *box, const graphene_vec3_t *vec, graphene_box_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_expand_scalar (const graphene_box_t *box, float scalar, graphene_box_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_union (const graphene_box_t *a, const graphene_box_t *b, graphene_box_t *res); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_box_intersection (const graphene_box_t *a, const graphene_box_t *b, graphene_box_t *res); GRAPHENE_AVAILABLE_IN_1_2 float graphene_box_get_width (const graphene_box_t *box); GRAPHENE_AVAILABLE_IN_1_2 float graphene_box_get_height (const graphene_box_t *box); GRAPHENE_AVAILABLE_IN_1_2 float graphene_box_get_depth (const graphene_box_t *box); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_get_size (const graphene_box_t *box, graphene_vec3_t *size); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_get_center (const graphene_box_t *box, graphene_point3d_t *center); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_get_min (const graphene_box_t *box, graphene_point3d_t *min); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_get_max (const graphene_box_t *box, graphene_point3d_t *max); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_get_vertices (const graphene_box_t *box, graphene_vec3_t vertices[]); GRAPHENE_AVAILABLE_IN_1_2 void graphene_box_get_bounding_sphere (const graphene_box_t *box, graphene_sphere_t *sphere); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_box_contains_point (const graphene_box_t *box, const graphene_point3d_t *point); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_box_contains_box (const graphene_box_t *a, const graphene_box_t *b); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_box_equal (const graphene_box_t *a, const graphene_box_t *b); GRAPHENE_AVAILABLE_IN_1_2 const graphene_box_t * graphene_box_zero (void); GRAPHENE_AVAILABLE_IN_1_2 const graphene_box_t * graphene_box_one (void); GRAPHENE_AVAILABLE_IN_1_2 const graphene_box_t * graphene_box_minus_one (void); GRAPHENE_AVAILABLE_IN_1_2 const graphene_box_t * graphene_box_one_minus_one (void); GRAPHENE_AVAILABLE_IN_1_2 const graphene_box_t * graphene_box_infinite (void); GRAPHENE_AVAILABLE_IN_1_2 const graphene_box_t * graphene_box_empty (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_BOX_H__ */ graphene-1.8.0/src/graphene-config.h.meson000066400000000000000000000044451324365266600204510ustar00rootroot00000000000000/* graphene-config.h * * This is a generated file, DO NOT EDIT. */ #ifndef __GRAPHENE_CONFIG_H__ #define __GRAPHENE_CONFIG_H__ #ifdef __cplusplus extern "C" { #endif #ifndef GRAPHENE_SIMD_BENCHMARK # if defined(__SSE__) || (_M_IX86_FP > 0) || (_M_X64 > 0) || (_MSC_VER >= 1800) #mesondefine GRAPHENE_HAS_SSE # endif # if defined(__ARM_NEON__) #mesondefine GRAPHENE_HAS_ARM_NEON # endif # if defined(__GNUC__) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 9) && !defined(__arm__) #mesondefine GRAPHENE_HAS_GCC # endif # define GRAPHENE_HAS_SCALAR 1 #endif /* GRAPHENE_SIMD_BENCHMARK */ #if defined(GRAPHENE_HAS_SSE) # define GRAPHENE_USE_SSE # define GRAPHENE_SIMD_S "sse" #elif defined(GRAPHENE_HAS_ARM_NEON) # define GRAPHENE_USE_ARM_NEON # define GRAPHENE_SIMD_S "neon" #elif defined(GRAPHENE_HAS_GCC) # define GRAPHENE_USE_GCC # define GRAPHENE_SIMD_S "gcc" #elif defined(GRAPHENE_HAS_SCALAR) # define GRAPHENE_USE_SCALAR # define GRAPHENE_SIMD_S "scalar" #else # error "Unsupported platform." #endif #ifndef __GI_SCANNER__ # if defined(GRAPHENE_USE_SSE) # include # include # if defined(_M_IX86_FP) # if _M_IX86_FP >= 2 # define GRAPHENE_USE_SSE4_1 # endif # elif defined(__SSE4_1__) # define GRAPHENE_USE_SSE4_1 # elif defined(_MSC_VER) # define GRAPHENE_USE_SSE4_1 # endif # if defined(GRAPHENE_USE_SSE4_1) # include # endif typedef __m128 graphene_simd4f_t; # elif defined(GRAPHENE_USE_ARM_NEON) # include typedef float32x4_t graphene_simd4f_t; # elif defined(GRAPHENE_USE_GCC) typedef float graphene_simd4f_t __attribute__((vector_size(16))); # elif defined(GRAPHENE_USE_SCALAR) typedef struct { /*< private >*/ float x, y, z, w; } graphene_simd4f_t; # else # error "Unsupported platform." # endif #else /* __GI_SCANNER__ */ /* The gobject-introspection scanner has issues parsing the * system headers with SIMD built-ins, so we fall back to * scalars; it does not really matter, as we wrap them in * our public API, and introspection cannot use the SIMD API * directly anyway. */ typedef struct { /*< private >*/ float x, y, z, w; } graphene_simd4f_t; #endif /* __GI_SCANNER__ */ typedef struct { /*< private >*/ graphene_simd4f_t x, y, z, w; } graphene_simd4x4f_t; #ifdef __cplusplus } #endif #endif /* __GRAPHENE_CONFIG_H__ */ graphene-1.8.0/src/graphene-euler.c000066400000000000000000000526701324365266600171760ustar00rootroot00000000000000/* graphene-euler.c: Euler angles * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-euler * @Title: Euler * @Short_description: Euler angles * * The #graphene_euler_t structure defines a rotation along three axis using * three angles. It also optionally can describe the order of the rotations. * * Rotations described Euler angles are immediately understandable, compared * to rotations expressed using quaternions, but they are susceptible of * ["Gimbal lock"](http://en.wikipedia.org/wiki/Gimbal_lock) — the loss of * one degree of freedom caused by two axis on the same plane. You typically * should use #graphene_euler_t to expose rotation angles in your API, or to * store them, but use #graphene_quaternion_t to apply rotations to modelview * matrices, or interpolate between initial and final rotation transformations. * * See also: #graphene_quaternion_t. */ #include "graphene-private.h" #include "graphene-euler.h" #include "graphene-alloc-private.h" #include "graphene-matrix.h" #include "graphene-quaternion.h" #include "graphene-vectors-private.h" #define EULER_DEFAULT_ORDER GRAPHENE_EULER_ORDER_XYZ /** * graphene_euler_alloc: (constructor) * * Allocates a new #graphene_euler_t. * * The contents of the returned structure are undefined. * * Returns: (transfer full): the newly allocated #graphene_euler_t * * Since: 1.2 */ graphene_euler_t * graphene_euler_alloc (void) { return graphene_aligned_alloc0 (sizeof (graphene_euler_t), 1, 16); } /** * graphene_euler_free: * @e: a #graphene_euler_t * * Frees the resources allocated by graphene_euler_alloc(). * * Since: 1.2 */ void graphene_euler_free (graphene_euler_t *e) { graphene_aligned_free (e); } /*< private > * graphene_euler_init_internal: * @e: the #graphene_euler_t to initialize * @x: rotation angle on the X axis, in radians * @y: rotation angle on the Y axis, in radians * @z: rotation angle on the Z axis, in radians * @order: order of rotations * * Initializes a #graphene_euler_t using the given angles * and order of rotation. * * Returns: (transfer none): the initialized #graphene_euler_t */ static graphene_euler_t * graphene_euler_init_internal (graphene_euler_t *e, float rad_x, float rad_y, float rad_z, graphene_euler_order_t order) { graphene_vec3_init (&e->angles, rad_x, rad_y, rad_z); e->order = order; return e; } /** * graphene_euler_init: * @e: the #graphene_euler_t to initialize * @x: rotation angle on the X axis, in degrees * @y: rotation angle on the Y axis, in degrees * @z: rotation angle on the Z axis, in degrees * * Initializes a #graphene_euler_t using the given angles. * * The order of the rotations is %GRAPHENE_EULER_ORDER_DEFAULT. * * Returns: (transfer none): the initialized #graphene_euler_t * * Since: 1.2 */ graphene_euler_t * graphene_euler_init (graphene_euler_t *e, float x, float y, float z) { return graphene_euler_init_internal (e, GRAPHENE_DEG_TO_RAD (x), GRAPHENE_DEG_TO_RAD (y), GRAPHENE_DEG_TO_RAD (z), GRAPHENE_EULER_ORDER_DEFAULT); } /** * graphene_euler_init_with_order: * @e: the #graphene_euler_t to initialize * @x: rotation angle on the X axis, in degrees * @y: rotation angle on the Y axis, in degrees * @z: rotation angle on the Z axis, in degrees * @order: the order used to apply the rotations * * Initializes a #graphene_euler_t with the given angles and @order. * * Returns: (transfer none): the initialized #graphene_euler_t * * Since: 1.2 */ graphene_euler_t * graphene_euler_init_with_order (graphene_euler_t *e, float x, float y, float z, graphene_euler_order_t order) { return graphene_euler_init_internal (e, GRAPHENE_DEG_TO_RAD (x), GRAPHENE_DEG_TO_RAD (y), GRAPHENE_DEG_TO_RAD (z), order); } /** * graphene_euler_init_from_matrix: * @e: the #graphene_euler_t to initialize * @m: (nullable): a rotation matrix * @order: the order used to apply the rotations * * Initializes a #graphene_euler_t using the given rotation matrix. * * If the #graphene_matrix_t @m is %NULL, the #graphene_euler_t will * be initialized with all angles set to 0. * * Returns: (transfer none): the initialized #graphene_euler_t * * Since: 1.2 */ graphene_euler_t * graphene_euler_init_from_matrix (graphene_euler_t *e, const graphene_matrix_t *m, graphene_euler_order_t order) { float me[16]; float m11, m12, m13; float m21, m22, m23; float m31, m32, m33; float x, y, z; if (m == NULL) return graphene_euler_init_with_order (e, 0.f, 0.f, 0.f, order); graphene_matrix_to_float (m, me); /* isolate the rotation components */ m11 = me[0]; m21 = me[4]; m31 = me[8]; m12 = me[1]; m22 = me[5]; m32 = me[9]; m13 = me[2]; m23 = me[6]; m33 = me[10]; x = y = z = 0.f; e->order = order; switch (graphene_euler_get_order (e)) { case GRAPHENE_EULER_ORDER_XYZ: y = asinf (CLAMP (m13, -1.f, 1.f)); if (fabsf (m13) < 1.f) { x = atan2f (-1.f * m23, m33); z = atan2f (-1.f * m12, m11); } else { x = atan2f (m32, m22); z = 0.f; } break; case GRAPHENE_EULER_ORDER_YXZ: x = asinf (-1.f * CLAMP (m23, -1, 1)); if (fabsf (m23) < 1.f) { y = atan2f (m13, m33); z = atan2f (m21, m22); } else { y = atan2f (-1.f * m31, m11); z = 0.f; } break; case GRAPHENE_EULER_ORDER_ZXY: x = asinf (CLAMP (m32, -1.f, 1.f)); if (fabsf (m32) < 1.f) { y = atan2f (-1.f * m31, m33); z = atan2f (-1.f * m12, m22); } else { y = 0.f; z = atan2f (m21, m11); } break; case GRAPHENE_EULER_ORDER_ZYX: y = asinf (-1.f * CLAMP (m31, -1.f, 1.f)); if (fabsf (m31) < 1.f) { x = atan2f (m32, m33); z = atan2f (m21, m11); } else { x = 0.f; z = atan2f (-1.f * m12, m22); } break; case GRAPHENE_EULER_ORDER_YZX: z = asinf (CLAMP (m21, -1.f, 1.f)); if (fabsf (m21) < 1.f) { x = atan2f (-1.f * m23, m22); y = atan2f (-1.f * m31, m11); } else { x = 0.f; y = atan2f (m13, m33); } break; case GRAPHENE_EULER_ORDER_XZY: z = asinf (-1.f * CLAMP (m12, -1.f, 1.f)); if (fabsf (m12) < 1.f) { x = atan2f (m32, m22); y = atan2f (m13, m11); } else { x = atan2f (-1.f * m23, m33); y = 0.f; } break; case GRAPHENE_EULER_ORDER_DEFAULT: break; } graphene_vec3_init (&e->angles, x, y, z); return e; } /** * graphene_euler_init_from_quaternion: * @e: a #graphene_euler_t * @q: (nullable): a normalized #graphene_quaternion_t * @order: the order used to apply the rotations * * Initializes a #graphene_euler_t using the given normalized quaternion. * * If the #graphene_quaternion_t @q is %NULL, the #graphene_euler_t will * be initialized with all angles set to 0. * * Returns: (transfer none): the initialized #graphene_euler_t * * Since: 1.2 */ graphene_euler_t * graphene_euler_init_from_quaternion (graphene_euler_t *e, const graphene_quaternion_t *q, graphene_euler_order_t order) { if (q == NULL) return graphene_euler_init_with_order (e, 0.f, 0.f, 0.f, order); float sqx = q->x * q->x; float sqy = q->y * q->y; float sqz = q->z * q->z; float sqw = q->w * q->w; float x = 0.f; float y = 0.f; float z = 0.f; e->order = order; switch (graphene_euler_get_order (e)) { case GRAPHENE_EULER_ORDER_XYZ: x = atan2f (2.f * (q->x * q->w - q->y * q->z), (sqw - sqx - sqy + sqz)); y = asinf (CLAMP (2.f * (q->x * q->z + q->y * q->w), -1.f, 1.f)); z = atan2f (2.f * (q->z * q->w - q->x * q->y), (sqw + sqx - sqy - sqz)); break; case GRAPHENE_EULER_ORDER_YXZ: x = asinf (CLAMP (2.f * (q->x * q->w - q->y * q->z), -1.f, 1.f)); y = atan2f (2.f * (q->x * q->z + q->y * q->w), (sqw - sqx - sqy + sqz)); z = atan2f (2.f * (q->x * q->y + q->z * q->w), (sqw - sqx + sqy - sqz)); break; case GRAPHENE_EULER_ORDER_ZXY: x = asinf (CLAMP (2.f * (q->x * q->w + q->y * q->z), -1.f, 1.f)); y = atan2f (2.f * (q->y * q->w - q->z * q->x), (sqw - sqx - sqy + sqz)); z = atan2f (2.f * (q->z * q->w - q->x * q->y), (sqw - sqx + sqy - sqz)); break; case GRAPHENE_EULER_ORDER_ZYX: x = atan2f (2.f * (q->x * q->w + q->z * q->y), (sqw - sqx - sqy + sqz)); y = asinf (CLAMP (2.f * (q->y * q->w - q->x * q->z), -1.f, 1.f)); z = atan2f (2.f * (q->x * q->y + q->z * q->w), (sqw + sqx - sqy - sqz)); break; case GRAPHENE_EULER_ORDER_YZX: x = atan2f (2.f * (q->x * q->w - q->z * q->y), (sqw - sqx + sqy - sqz)); y = atan2f (2.f * (q->y * q->w - q->x * q->z), (sqw + sqx - sqy - sqz)); z = asinf (CLAMP (2.f * (q->x * q->y + q->z * q->w), -1.f, 1.f)); break; case GRAPHENE_EULER_ORDER_XZY: x = atan2f (2.f * (q->x * q->w + q->y * q->z), (sqw - sqx + sqy - sqz)); y = atan2f (2.f * (q->x * q->z + q->y * q->w), (sqw + sqx - sqy - sqz)); z = asinf (CLAMP (2.f * (q->z * q->w - q->x * q->y), -1.f, 1.f)); break; case GRAPHENE_EULER_ORDER_DEFAULT: break; } graphene_vec3_init (&e->angles, x, y, z); return e; } /** * graphene_euler_init_from_vec3: * @e: the #graphene_euler_t to initialize * @v: (nullable): a #graphene_vec3_t containing the rotation * angles in degrees * @order: the order used to apply the rotations * * Initializes a #graphene_euler_t using the angles contained in a * #graphene_vec3_t. * * If the #graphene_vec3_t @v is %NULL, the #graphene_euler_t will be * initialized with all angles set to 0. * * Returns: (transfer none): the initialized #graphene_euler_t * * Since: 1.2 */ graphene_euler_t * graphene_euler_init_from_vec3 (graphene_euler_t *e, const graphene_vec3_t *v, graphene_euler_order_t order) { if (v != NULL) graphene_vec3_scale (v, (GRAPHENE_PI / 180.f), &e->angles); else graphene_vec3_init_from_vec3 (&e->angles, graphene_vec3_zero ()); e->order = order; return e; } /** * graphene_euler_init_from_euler: * @e: the #graphene_euler_t to initialize * @src: (nullable): a #graphene_euler_t * * Initializes a #graphene_euler_t using the angles and order of * another #graphene_euler_t. * * If the #graphene_euler_t @src is %NULL, this function is equivalent * to calling graphene_euler_init() with all angles set to 0. * * Returns: (transfer none): the initialized #graphene_euler_t * * Since: 1.2 */ graphene_euler_t * graphene_euler_init_from_euler (graphene_euler_t *e, const graphene_euler_t *src) { if (src == NULL) return graphene_euler_init (e, 0.f, 0.f, 0.f); *e = *src; return e; } static bool euler_equal (const void *p1, const void *p2) { const graphene_euler_t *a = p1; const graphene_euler_t *b = p2; return graphene_vec3_equal (&a->angles, &b->angles) && a->order == b->order; } /** * graphene_euler_equal: * @a: a #graphene_euler_t * @b: a #graphene_euler_t * * Checks if two #graphene_euler_t are equal. * * Returns: `true` if the two #graphene_euler_t are equal * * Since: 1.2 */ bool graphene_euler_equal (const graphene_euler_t *a, const graphene_euler_t *b) { return graphene_pointer_equal (a, b, euler_equal); } /** * graphene_euler_get_x: * @e: a #graphene_euler_t * * Retrieves the rotation angle on the X axis, in degrees. * * Returns: the rotation angle * * Since: 1.2 */ float graphene_euler_get_x (const graphene_euler_t *e) { return GRAPHENE_RAD_TO_DEG (graphene_vec3_get_x (&e->angles)); } /** * graphene_euler_get_y: * @e: a #graphene_euler_t * * Retrieves the rotation angle on the Y axis, in degrees. * * Returns: the rotation angle * * Since: 1.2 */ float graphene_euler_get_y (const graphene_euler_t *e) { return GRAPHENE_RAD_TO_DEG (graphene_vec3_get_y (&e->angles)); } /** * graphene_euler_get_z: * @e: a #graphene_euler_t * * Retrieves the rotation angle on the Z axis, in degrees. * * Returns: the rotation angle * * Since: 1.2 */ float graphene_euler_get_z (const graphene_euler_t *e) { return GRAPHENE_RAD_TO_DEG (graphene_vec3_get_z (&e->angles)); } /** * graphene_euler_get_order: * @e: a #graphene_euler_t * * Retrieves the order used to apply the rotations described in the * #graphene_euler_t structure, when converting to and from other * structures, like #graphene_quaternion_t and #graphene_matrix_t. * * This function does not return the %GRAPHENE_EULER_ORDER_DEFAULT * enumeration value; it will return the effective order of rotation * instead. * * Returns: the order used to apply the rotations * * Since: 1.2 */ graphene_euler_order_t graphene_euler_get_order (const graphene_euler_t *e) { if (e->order == GRAPHENE_EULER_ORDER_DEFAULT) return EULER_DEFAULT_ORDER; return e->order; } /** * graphene_euler_to_vec3: * @e: a #graphene_euler_t * @res: (out caller-allocates): return location for a #graphene_vec3_t * * Retrieves the angles of a #graphene_euler_t and initializes a * #graphene_vec3_t with them. * * Since: 1.2 */ void graphene_euler_to_vec3 (const graphene_euler_t *e, graphene_vec3_t *res) { graphene_vec3_init_from_vec3 (res, &e->angles); graphene_vec3_scale (res, (180.f / GRAPHENE_PI), res); } /** * graphene_euler_to_matrix: * @e: a #graphene_euler_t * @res: (out caller-allocates): return location for a #graphene_matrix_t * * Converts a #graphene_euler_t into a transformation matrix expressing * the extrinsic composition of rotations described by the Euler angles. * * The rotations are applied over the reference frame axes in the order * associated with the #graphene_euler_t; for instance, if the order * used to initialize @e is %GRAPHENE_EULER_ORDER_XYZ: * * * the first rotation moves the body around the X axis with * an angle φ * * the second rotation moves the body around the Y axis with * an angle of ϑ * * the third rotation moves the body around the Z axis with * an angle of ψ * * The rotation sign convention is left-handed, to preserve compatibility * between Euler-based, quaternion-based, and angle-axis-based rotations. * * Since: 1.2 */ void graphene_euler_to_matrix (const graphene_euler_t *e, graphene_matrix_t *res) { graphene_euler_order_t order = graphene_euler_get_order (e); const float x = graphene_vec3_get_x (&e->angles); const float y = graphene_vec3_get_y (&e->angles); const float z = graphene_vec3_get_z (&e->angles); float c1, s1, c2, s2, c3, s3; float c3c2, s3c1, c3s2s1, s3s1; float c3s2c1, s3c2, c3c1, s3s2s1; float c3s1, s3s2c1, c2s1, c2c1; graphene_sincos (x, &c1, &s1); graphene_sincos (y, &c2, &s2); graphene_sincos (z, &c3, &s3); c3c2 = c3 * c2; s3c1 = s3 * c1; c3s2s1 = c3 * s2 * s1; s3s1 = s3 * s1; c3s2c1 = c3 * s2 * c1; s3c2 = s3 * c2; c3c1 = c3 * c1; s3s2s1 = s3 * s2 * s1; c3s1 = c3 * s1; s3s2c1 = s3 * s2 * c1; c2s1 = c2 * s1; c2c1 = c2 * c1; switch (order) { case GRAPHENE_EULER_ORDER_XYZ: { /* ⎡ c3 s3 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ 1 0 0 ⎤ * ⎢ -s3 c3 0 ⎥ ⎢ 0 1 0 ⎥ ⎢ 0 c1 s1 ⎥ * ⎣ 0 0 1 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 -s1 c1 ⎦ */ res->value.x = graphene_simd4f_init ( c3c2, s3c1 + c3s2s1, s3s1 - c3s2c1, 0.f); res->value.y = graphene_simd4f_init (-s3c2, c3c1 - s3s2s1, c3s1 + s3s2c1, 0.f); res->value.z = graphene_simd4f_init ( s2, -c2s1, c2c1, 0.f); res->value.w = graphene_simd4f_init ( 0.f, 0.f, 0.f, 1.f); } break; case GRAPHENE_EULER_ORDER_YXZ: { /* ⎡ c3 s3 0 ⎤ ⎡ 1 0 0 ⎤ ⎡ c1 0 -s1 ⎤ * ⎢ -s2 c3 0 ⎥ ⎢ 0 c2 s2 ⎥ ⎢ 0 1 0 ⎥ * ⎣ 0 0 1 ⎦ ⎣ 0 -s2 c2 ⎦ ⎣ s1 0 c1 ⎦ */ res->value.x = graphene_simd4f_init ( c3c1 + s3s2s1, s3c2, -c3s1 + s3s2c1, 0.f); res->value.y = graphene_simd4f_init (-s3c1 + c3s2s1, c3c2, s3s1 + c3s2c1, 0.f); res->value.z = graphene_simd4f_init ( c2s1, -s2, c2c1, 0.f); res->value.w = graphene_simd4f_init ( 0.f, 0.f, 0.f, 1.f); } break; case GRAPHENE_EULER_ORDER_ZXY: { /* ⎡ 1 0 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ c1 s1 0 ⎤ * ⎢ 0 c3 s3 ⎥ ⎢ 0 1 0 ⎥ ⎢ -s1 c1 0 ⎥ * ⎣ 0 -s3 c3 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 0 1 ⎦ */ res->value.x = graphene_simd4f_init (c3c1 - s3s2s1, c3s1 + s3s2c1, -s3c2, 0.f); res->value.y = graphene_simd4f_init ( -c2s1, c2c1, s2, 0.f); res->value.z = graphene_simd4f_init (s3c1 + c3s2s1, s3s1 - c3s2c1, c3c2, 0.f); res->value.w = graphene_simd4f_init ( 0.f, 0.f, 0.f, 1.f); } break; case GRAPHENE_EULER_ORDER_ZYX: { /* ⎡ 1 0 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ c1 s1 0 ⎤ * ⎢ 0 c3 s3 ⎥ ⎢ 0 1 0 ⎥ ⎢ -s1 c1 0 ⎥ * ⎣ 0 -s3 c3 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 0 1 ⎦ */ res->value.x = graphene_simd4f_init ( c2c1, c2s1, -s2, 0.f); res->value.y = graphene_simd4f_init (s3s2c1 - c3s1, s3s2s1 + c3c1, s3c2, 0.f); res->value.z = graphene_simd4f_init (c3s2c1 + s3s1, c3s2s1 - s3c1, c3c2, 0.f); res->value.w = graphene_simd4f_init ( 0.f, 0.f, 0.f, 1.f); } break; case GRAPHENE_EULER_ORDER_YZX: { /* ⎡ 1 0 0 ⎤ ⎡ c2 s2 0 ⎤ ⎡ c1 0 -s1 ⎤ * ⎢ 0 c3 s3 ⎥ ⎢ -s2 c2 0 ⎥ ⎢ 0 1 0 ⎥ * ⎣ 0 -s3 c3 ⎦ ⎣ 0 0 1 ⎦ ⎣ s1 0 c1 ⎦ */ res->value.x = graphene_simd4f_init ( c2c1, s2, -c2s1, 0.f); res->value.y = graphene_simd4f_init (-c3s2c1 + s3s1, c3c2, c3s2s1 + s3c1, 0.f); res->value.z = graphene_simd4f_init ( s3s2c1 + c3s1, -s3c2, -s3s2s1 + c3c1, 0.f); res->value.w = graphene_simd4f_init ( 0.f, 0.f, 0.f, 1.f); } break; case GRAPHENE_EULER_ORDER_XZY: { /* ⎡ c3 0 -s3 ⎤ ⎡ c2 s2 0 ⎤ ⎡ 1 0 0 ⎤ * ⎢ 0 1 0 ⎥ ⎢ -s2 c2 0 ⎥ ⎢ 0 c1 s1 ⎥ * ⎣ s3 0 c3 ⎦ ⎣ 0 0 1 ⎦ ⎣ 0 -s1 c1 ⎦ */ res->value.x = graphene_simd4f_init (c3c2, c3s2c1 + s3s1, c3s2s1 - s3c1, 0.f); res->value.y = graphene_simd4f_init ( -s2, c2c1, c2s1, 0.f); res->value.z = graphene_simd4f_init (s3c2, s3s2c1 - c3s1, s3s2s1 + c3c1, 0.f); res->value.w = graphene_simd4f_init ( 0.f, 0.f, 0.f, 1.f); } break; default: graphene_matrix_init_identity (res); break; } } /** * graphene_euler_reorder: * @e: a #graphene_euler_t * @order: the new order * @res: (out caller-allocates): return location for the reordered * #graphene_euler_t * * Reorders a #graphene_euler_t using @order. * * This function is equivalent to creating a #graphene_quaternion_t from the * given #graphene_euler_t, and then converting the quaternion into another * #graphene_euler_t. * * Since: 1.2 */ void graphene_euler_reorder (const graphene_euler_t *e, graphene_euler_order_t order, graphene_euler_t *res) { graphene_quaternion_t q; graphene_quaternion_init_from_euler (&q, e); graphene_euler_init_from_quaternion (res, &q, order); } graphene-1.8.0/src/graphene-euler.h000066400000000000000000000147521324365266600172020ustar00rootroot00000000000000/* graphene-euler.h: Euler angles * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_EULER_H__ #define __GRAPHENE_EULER_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-vec3.h" GRAPHENE_BEGIN_DECLS /** * graphene_euler_order_t: * @GRAPHENE_EULER_ORDER_DEFAULT: Rotate in the default order; the * default order is one of the following enumeration values * @GRAPHENE_EULER_ORDER_XYZ: Rotate in the X, Y, and Z order * @GRAPHENE_EULER_ORDER_YZX: Rotate in the Y, Z, and X order * @GRAPHENE_EULER_ORDER_ZXY: Rotate in the Z, X, and Y order * @GRAPHENE_EULER_ORDER_XZY: Rotate in the X, Z, and Y order * @GRAPHENE_EULER_ORDER_YXZ: Rotate in the Y, X, and Z order * @GRAPHENE_EULER_ORDER_ZYX: Rotate in the Z, Y, and X order * * Specify the order of the rotations on each axis. * * The %GRAPHENE_EULER_ORDER_DEFAULT value is special, and is used * as an alias for one of the other orders. * * Since: 1.2 */ typedef enum { GRAPHENE_EULER_ORDER_DEFAULT = -1, GRAPHENE_EULER_ORDER_XYZ = 0, GRAPHENE_EULER_ORDER_YZX, GRAPHENE_EULER_ORDER_ZXY, GRAPHENE_EULER_ORDER_XZY, GRAPHENE_EULER_ORDER_YXZ, GRAPHENE_EULER_ORDER_ZYX } graphene_euler_order_t; /** * graphene_euler_t: * * Describe a rotation using Euler angles. * * The contents of the #graphene_euler_t structure are private * and should never be accessed directly. * * Since: 1.2 */ struct _graphene_euler_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, angles); GRAPHENE_PRIVATE_FIELD (graphene_euler_order_t, order); }; GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_t * graphene_euler_alloc (void); GRAPHENE_AVAILABLE_IN_1_2 void graphene_euler_free (graphene_euler_t *e); GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_t * graphene_euler_init (graphene_euler_t *e, float x, float y, float z); GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_t * graphene_euler_init_with_order (graphene_euler_t *e, float x, float y, float z, graphene_euler_order_t order); GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_t * graphene_euler_init_from_matrix (graphene_euler_t *e, const graphene_matrix_t *m, graphene_euler_order_t order); GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_t * graphene_euler_init_from_quaternion (graphene_euler_t *e, const graphene_quaternion_t *q, graphene_euler_order_t order); GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_t * graphene_euler_init_from_vec3 (graphene_euler_t *e, const graphene_vec3_t *v, graphene_euler_order_t order); GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_t * graphene_euler_init_from_euler (graphene_euler_t *e, const graphene_euler_t *src); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_euler_equal (const graphene_euler_t *a, const graphene_euler_t *b); GRAPHENE_AVAILABLE_IN_1_2 float graphene_euler_get_x (const graphene_euler_t *e); GRAPHENE_AVAILABLE_IN_1_2 float graphene_euler_get_y (const graphene_euler_t *e); GRAPHENE_AVAILABLE_IN_1_2 float graphene_euler_get_z (const graphene_euler_t *e); GRAPHENE_AVAILABLE_IN_1_2 graphene_euler_order_t graphene_euler_get_order (const graphene_euler_t *e); GRAPHENE_AVAILABLE_IN_1_2 void graphene_euler_to_vec3 (const graphene_euler_t *e, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_euler_to_matrix (const graphene_euler_t *e, graphene_matrix_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_euler_reorder (const graphene_euler_t *e, graphene_euler_order_t order, graphene_euler_t *res); GRAPHENE_END_DECLS #endif /* __GRAPHENE_EULER_H__ */ graphene-1.8.0/src/graphene-frustum.c000066400000000000000000000226511324365266600175630ustar00rootroot00000000000000/* graphene-frustum.c: A 3D field of view * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-frustum * @Title: Frustum * @Short_Description: A 3D field of view * * A #graphene_frustum_t represents a volume of space delimited by planes. It * is usually employed to represent the field of view of a camera, and can be * used to determine whether an object falls within that view, to efficiently * remove invisible objects from the render process. */ #include "graphene-private.h" #include "graphene-frustum.h" #include "graphene-alloc-private.h" #include "graphene-box.h" #include "graphene-matrix.h" #include "graphene-sphere.h" #include "graphene-point3d.h" #include "graphene-vec4.h" #define N_CLIP_PLANES 6 /** * graphene_frustum_alloc: (constructor) * * Allocates a new #graphene_frustum_t structure. * * The contents of the returned structure are undefined. * * Returns: (transfer full): the newly allocated #graphene_frustum_t * structure. Use graphene_frustum_free() to free the resources * allocated by this function. * * Since: 1.2 */ graphene_frustum_t * graphene_frustum_alloc (void) { return graphene_aligned_alloc0 (sizeof (graphene_frustum_t), 1, 16); } /** * graphene_frustum_free: * @f: a #graphene_frustum_t * * Frees the resources allocated by graphene_frustum_alloc(). * * Since: 1.2 */ void graphene_frustum_free (graphene_frustum_t *f) { graphene_aligned_free (f); } /** * graphene_frustum_init: * @f: the #graphene_frustum_t to initialize * @p0: a clipping plane * @p1: a clipping plane * @p2: a clipping plane * @p3: a clipping plane * @p4: a clipping plane * @p5: a clipping plane * * Initializes the given #graphene_frustum_t using the provided * clipping planes. * * Returns: (transfer none): the initialized frustum * * Since: 1.2 */ graphene_frustum_t * graphene_frustum_init (graphene_frustum_t *f, const graphene_plane_t *p0, const graphene_plane_t *p1, const graphene_plane_t *p2, const graphene_plane_t *p3, const graphene_plane_t *p4, const graphene_plane_t *p5) { graphene_plane_init_from_plane (&f->planes[0], p0); graphene_plane_init_from_plane (&f->planes[1], p1); graphene_plane_init_from_plane (&f->planes[2], p2); graphene_plane_init_from_plane (&f->planes[3], p3); graphene_plane_init_from_plane (&f->planes[4], p4); graphene_plane_init_from_plane (&f->planes[5], p5); return f; } /** * graphene_frustum_init_from_frustum: * @f: the #graphene_frustum_t to initialize * @src: a #graphene_frustum_t * * Initializes the given #graphene_frustum_t using the clipping * planes of another #graphene_frustum_t. * * Returns: (transfer none): the initialized frustum * * Since: 1.2 */ graphene_frustum_t * graphene_frustum_init_from_frustum (graphene_frustum_t *f, const graphene_frustum_t *src) { for (int i = 0; i < N_CLIP_PLANES; i++) graphene_plane_init_from_plane (&f->planes[i], &src->planes[i]); return f; } /** * graphene_frustum_init_from_matrix: * @f: a #graphene_frustum_t * @matrix: a #graphene_matrix_t * * Initializes a #graphene_frustum_t using the given @matrix. * * Returns: (transfer none): the initialized frustum * * Since: 1.2 */ graphene_frustum_t * graphene_frustum_init_from_matrix (graphene_frustum_t *f, const graphene_matrix_t *matrix) { graphene_vec4_t r1, r2, r3, r4, t; graphene_plane_t p; graphene_matrix_t m; graphene_matrix_transpose (matrix, &m); graphene_matrix_get_row (&m, 0, &r1); graphene_matrix_get_row (&m, 1, &r2); graphene_matrix_get_row (&m, 2, &r3); graphene_matrix_get_row (&m, 3, &r4); graphene_vec4_subtract (&r4, &r1, &t); graphene_plane_init_from_vec4 (&p, &t); graphene_plane_normalize (&p, &f->planes[0]); graphene_vec4_add (&r4, &r1, &t); graphene_plane_init_from_vec4 (&p, &t); graphene_plane_normalize (&p, &f->planes[1]); graphene_vec4_subtract (&r4, &r2, &t); graphene_plane_init_from_vec4 (&p, &t); graphene_plane_normalize (&p, &f->planes[2]); graphene_vec4_add (&r4, &r2, &t); graphene_plane_init_from_vec4 (&p, &t); graphene_plane_normalize (&p, &f->planes[3]); graphene_vec4_subtract (&r4, &r3, &t); graphene_plane_init_from_vec4 (&p, &t); graphene_plane_normalize (&p, &f->planes[4]); graphene_vec4_add (&r4, &r3, &t); graphene_plane_init_from_vec4 (&p, &t); graphene_plane_normalize (&p, &f->planes[5]); return f; } /** * graphene_frustum_get_planes: * @f: a #graphene_frustum_t * @planes: (out) (array fixed-size=6): return location for an array * of 6 #graphene_plane_t * * Retrieves the planes that define the given #graphene_frustum_t. * * Since: 1.2 */ void graphene_frustum_get_planes (const graphene_frustum_t *f, graphene_plane_t planes[]) { for (int i = 0; i < N_CLIP_PLANES; i++) graphene_plane_init_from_plane (&planes[i], &f->planes[i]); } /** * graphene_frustum_contains_point: * @f: a #graphene_frustum_t * @point: a #graphene_point3d_t * * Checks whether a point is inside the volume defined by the given * #graphene_frustum_t. * * Returns: `true` if the point is inside the frustum * * Since: 1.2 */ bool graphene_frustum_contains_point (const graphene_frustum_t *f, const graphene_point3d_t *point) { if (point == NULL) return false; for (int i = 0; i < N_CLIP_PLANES; i++) { const graphene_plane_t *p = &f->planes[i]; if (graphene_plane_distance (p, point) < 0) return false; } return true; } /** * graphene_frustum_intersects_sphere: * @f: a #graphene_frustum_t * @sphere: a #graphene_sphere_t * * Checks whether the given @sphere intersects a plane of * a #graphene_frustum_t. * * Returns: `true` if the sphere intersects the frustum * * Since: 1.2 */ bool graphene_frustum_intersects_sphere (const graphene_frustum_t *f, const graphene_sphere_t *sphere) { graphene_point3d_t center; graphene_point3d_init_from_vec3 (¢er, &sphere->center); for (int i = 0; i < N_CLIP_PLANES; i++) { float distance = graphene_plane_distance (&f->planes[i], ¢er); if (distance < -sphere->radius) return false; } return true; } /** * graphene_frustum_intersects_box: * @f: a #graphene_frustum_t * @box: a #graphene_box_t * * Checks whether the given @box intersects a plane of * a #graphene_frustum_t. * * Returns: `true` if the box intersects the frustum * * Since: 1.2 */ bool graphene_frustum_intersects_box (const graphene_frustum_t *f, const graphene_box_t *box) { graphene_point3d_t min, max, normal; graphene_point3d_t p0, p1; const graphene_plane_t *plane; float d0, d1; graphene_box_get_min (box, &min); graphene_box_get_max (box, &max); for (int i = 0; i < N_CLIP_PLANES; i++) { plane = &f->planes[i]; graphene_point3d_init_from_vec3 (&normal, &(plane->normal)); p0.x = normal.x > 0 ? min.x : max.x; p1.x = normal.x > 0 ? max.x : min.x; p0.y = normal.y > 0 ? min.y : max.y; p1.y = normal.y > 0 ? max.y : min.y; p0.z = normal.z > 0 ? min.z : max.z; p1.z = normal.z > 0 ? max.z : min.z; d0 = graphene_plane_distance (plane, &p0); d1 = graphene_plane_distance (plane, &p1); if (d0 < 0 && d1 < 0) return false; } return true; } static bool frustum_equal (const void *p1, const void *p2) { const graphene_frustum_t *a = p1; const graphene_frustum_t *b = p2; return graphene_plane_equal (&a->planes[0], &b->planes[0]) && graphene_plane_equal (&a->planes[1], &b->planes[1]) && graphene_plane_equal (&a->planes[2], &b->planes[2]) && graphene_plane_equal (&a->planes[3], &b->planes[3]) && graphene_plane_equal (&a->planes[4], &b->planes[4]) && graphene_plane_equal (&a->planes[5], &b->planes[5]); } /** * graphene_frustum_equal: * @a: a #graphene_frustum_t * @b: a #graphene_frustum_t * * Checks whether the two given #graphene_frustum_t are equal. * * Returns: `true` if the given frustums are equal * * Since: 1.6 */ bool graphene_frustum_equal (const graphene_frustum_t *a, const graphene_frustum_t *b) { return graphene_pointer_equal (a, b, frustum_equal); } graphene-1.8.0/src/graphene-frustum.h000066400000000000000000000102011324365266600175540ustar00rootroot00000000000000/* graphene-frustum.h: A 3D field of view * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_FRUSTUM_H__ #define __GRAPHENE_FRUSTUM_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-plane.h" GRAPHENE_BEGIN_DECLS /** * graphene_frustum_t: * * A 3D volume delimited by 2D clip planes. * * The contents of the `graphene_frustum_t` are private, and should not be * modified directly. * * Since: 1.2 */ struct _graphene_frustum_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_plane_t, planes[6]); }; GRAPHENE_AVAILABLE_IN_1_2 graphene_frustum_t * graphene_frustum_alloc (void); GRAPHENE_AVAILABLE_IN_1_2 void graphene_frustum_free (graphene_frustum_t *f); GRAPHENE_AVAILABLE_IN_1_2 graphene_frustum_t * graphene_frustum_init (graphene_frustum_t *f, const graphene_plane_t *p0, const graphene_plane_t *p1, const graphene_plane_t *p2, const graphene_plane_t *p3, const graphene_plane_t *p4, const graphene_plane_t *p5); GRAPHENE_AVAILABLE_IN_1_2 graphene_frustum_t * graphene_frustum_init_from_frustum (graphene_frustum_t *f, const graphene_frustum_t *src); GRAPHENE_AVAILABLE_IN_1_2 graphene_frustum_t * graphene_frustum_init_from_matrix (graphene_frustum_t *f, const graphene_matrix_t *matrix); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_frustum_contains_point (const graphene_frustum_t *f, const graphene_point3d_t *point); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_frustum_intersects_sphere (const graphene_frustum_t *f, const graphene_sphere_t *sphere); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_frustum_intersects_box (const graphene_frustum_t *f, const graphene_box_t *box); GRAPHENE_AVAILABLE_IN_1_2 void graphene_frustum_get_planes (const graphene_frustum_t *f, graphene_plane_t planes[]); GRAPHENE_AVAILABLE_IN_1_6 bool graphene_frustum_equal (const graphene_frustum_t *a, const graphene_frustum_t *b); GRAPHENE_END_DECLS #endif /* __GRAPHENE_FRUSTUM_H__ */ graphene-1.8.0/src/graphene-gobject.c000066400000000000000000000143461324365266600174750ustar00rootroot00000000000000/* graphene-gobject.c: Shared GObject types * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-gobject * @Title: GObject integration * @short_description: Types for GObject properties and signals * * Graphene optionally provides information for using its own types with * GObject properties and signals. * * ## Using Graphene with GObject * * In order to discover at compile time if Graphene exposes type information * for the GType type system, you need to check if the `graphene-gobject-1.0` * pkg-config file exists. In build systems using autotools, you can use * the `PKG_CHECK_EXISTS` m4 macro, for instance: * * |[ * PKG_CHECK_EXISTS([graphene-gobject-1.0], * [action-if-found], * [action-if-not-found] * ]| * * All the types provided by Graphene are boxed types, which means you * will have to use the #GBoxed API when dealing with #GValue, #GParamSpec, * and signal marshallers. For instance, to install a property in a #GObject * class that uses #graphene_rect_t, you can use: * * |[ * g_object_class_install_property (object_class, PROP_BOUNDS, * g_param_spec_boxed ("bounds", "Bounds", "Bounds of an object", * GRAPHENE_TYPE_RECT, * G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); * ]| * * You'll then need to use g_value_set_boxed() and g_value_get_boxed() * in order to access the #graphene_rect_t pointer from the #GValue data * structure. * * Whereas for creating a new signal that has a #graphene_point_t parameter * you can use: * * |[ * signals[HIT_TEST] = * g_signal_new ("hit-test", * G_TYPE_FROM_CLASS (object_class), * G_SIGNAL_RUN_LAST, * 0, * g_signal_accumulator_true_handled, NULL, * marshal_BOOLEAN__BOXED, * G_TYPE_BOOLEAN, 1, * GRAPHENE_TYPE_POINT); * ]| * * ## Using Graphene via GObject introspection * * When using Graphene with another language than C, the GObject Introspection * bindings change the type names to the CamelCase version of the C name, minus * the `_t` suffix; for instance: * * * #graphene_point_t becomes `GraphenePoint` * * #graphene_point3d_t becomes `GraphenePoint3D` * * #graphene_rect_t becomes `GrapheneRect` * * #graphene_matrix_t becomes `GrapheneMatrix` * * There is no direct access for the low level #graphene_simd4f_t and * #graphene_simd4x4f_t SIMD types. */ #include "config.h" #include "graphene-gobject.h" #define GRAPHENE_ENUM_VALUE(EnumValue, EnumNick) { EnumValue, #EnumValue, EnumNick }, #define GRAPHENE_DEFINE_ENUM_TYPE(TypeName, type_name, values) \ GType \ type_name ## _get_type (void) \ { \ static volatile gsize graphene_define_id__volatile = 0; \ if (g_once_init_enter (&graphene_define_id__volatile)) \ { \ static const GEnumValue v[] = { \ values \ { 0, NULL, NULL }, \ }; \ GType graphene_define_id = \ g_enum_register_static (g_intern_static_string (#TypeName), v); \ g_once_init_leave (&graphene_define_id__volatile, graphene_define_id); \ } \ return graphene_define_id__volatile; \ } #define GRAPHENE_DEFINE_BOXED_TYPE(TypeName, type_name) \ static type_name ## _t * \ type_name ## _copy_internal (type_name ## _t * v) \ { \ type_name ## _t * res = NULL; \ if (G_LIKELY (v != NULL)) \ { \ res = type_name ## _alloc (); \ *res = *v; \ } \ return res; \ } \ \ GType \ type_name ## _get_type (void) \ { \ static volatile gsize graphene_define_id__volatile = 0; \ if (g_once_init_enter (&graphene_define_id__volatile)) \ { \ GType graphene_define_id = \ g_boxed_type_register_static (g_intern_static_string (#TypeName), \ (GBoxedCopyFunc) type_name ## _copy_internal, \ (GBoxedFreeFunc) type_name ## _free); \ g_once_init_leave (&graphene_define_id__volatile, graphene_define_id); \ } \ return graphene_define_id__volatile; \ } GRAPHENE_DEFINE_BOXED_TYPE (GraphenePoint, graphene_point) GRAPHENE_DEFINE_BOXED_TYPE (GraphenePoint3D, graphene_point3d) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneSize, graphene_size) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneRect, graphene_rect) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneVec2, graphene_vec2) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneVec3, graphene_vec3) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneVec4, graphene_vec4) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneQuad, graphene_quad) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneQuaternion, graphene_quaternion) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneMatrix, graphene_matrix) GRAPHENE_DEFINE_BOXED_TYPE (GraphenePlane, graphene_plane) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneFrustum, graphene_frustum) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneSphere, graphene_sphere) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneBox, graphene_box) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneTriangle, graphene_triangle) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneEuler, graphene_euler) GRAPHENE_DEFINE_BOXED_TYPE (GrapheneRay, graphene_ray) graphene-1.8.0/src/graphene-gobject.h000066400000000000000000000070701324365266600174760ustar00rootroot00000000000000/* graphene-gobject.h: Shared GObject types * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_GOBJECT_H__ #define __GRAPHENE_GOBJECT_H__ #include #include G_BEGIN_DECLS #define GRAPHENE_TYPE_POINT (graphene_point_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_point_get_type (void); #define GRAPHENE_TYPE_POINT3D (graphene_point3d_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_point3d_get_type (void); #define GRAPHENE_TYPE_SIZE (graphene_size_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_size_get_type (void); #define GRAPHENE_TYPE_RECT (graphene_rect_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_rect_get_type (void); #define GRAPHENE_TYPE_VEC2 (graphene_vec2_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_vec2_get_type (void); #define GRAPHENE_TYPE_VEC3 (graphene_vec3_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_vec3_get_type (void); #define GRAPHENE_TYPE_VEC4 (graphene_vec4_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_vec4_get_type (void); #define GRAPHENE_TYPE_QUAD (graphene_quad_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_quad_get_type (void); #define GRAPHENE_TYPE_QUATERNION (graphene_quaternion_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_quaternion_get_type (void); #define GRAPHENE_TYPE_MATRIX (graphene_matrix_get_type ()) GRAPHENE_AVAILABLE_IN_1_0 GType graphene_matrix_get_type (void); #define GRAPHENE_TYPE_PLANE (graphene_plane_get_type ()) GRAPHENE_AVAILABLE_IN_1_2 GType graphene_plane_get_type (void); #define GRAPHENE_TYPE_FRUSTUM (graphene_frustum_get_type ()) GRAPHENE_AVAILABLE_IN_1_2 GType graphene_frustum_get_type (void); #define GRAPHENE_TYPE_SPHERE (graphene_sphere_get_type ()) GRAPHENE_AVAILABLE_IN_1_2 GType graphene_sphere_get_type (void); #define GRAPHENE_TYPE_BOX (graphene_box_get_type ()) GRAPHENE_AVAILABLE_IN_1_2 GType graphene_box_get_type (void); #define GRAPHENE_TYPE_TRIANGLE (graphene_triangle_get_type ()) GRAPHENE_AVAILABLE_IN_1_2 GType graphene_triangle_get_type (void); #define GRAPHENE_TYPE_EULER (graphene_euler_get_type ()) GRAPHENE_AVAILABLE_IN_1_2 GType graphene_euler_get_type (void); #define GRAPHENE_TYPE_RAY (graphene_ray_get_type ()) GRAPHENE_AVAILABLE_IN_1_4 GType graphene_ray_get_type (void); G_END_DECLS #endif /* __GRAPHENE_GOBJECT_H__ */ graphene-1.8.0/src/graphene-line-segment-private.h000066400000000000000000000043171324365266600221210ustar00rootroot00000000000000/* graphene-line-segment-private.h: Segments * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_LINE_SEGMENT_PRIVATE_H__ #define __GRAPHENE_LINE_SEGMENT_PRIVATE_H__ #include "graphene-point.h" typedef struct { graphene_point_t start; graphene_point_t end; } graphene_line_segment_t; static inline graphene_line_segment_t graphene_line_segment_init (const graphene_point_t *start, const graphene_point_t *end) { graphene_line_segment_t l; l.start = *start; l.end = *end; return l; } static inline bool graphene_line_segment_points_on_same_side (graphene_line_segment_t s, const graphene_point_t *a, const graphene_point_t *b) { const float delta_x = (s.end.x - s.start.x); const float delta_y = (s.end.y - s.start.y); const float one = delta_x * (a->y - s.start.y) - delta_y * (a->x - s.start.x); const float two = delta_x * (b->y - s.start.y) - delta_y * (b->x - s.start.x); if ((one >= 0.f && two >= 0.f) || (one <= 0.f && two <= 0.f)) return true; return false; } #endif /* __GRAPHENE_LINE_SEGMENT_PRIVATE_H__ */ graphene-1.8.0/src/graphene-macros.h000066400000000000000000000072671324365266600173550ustar00rootroot00000000000000/* graphene-macros.h: Public macros * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_MACROS_H__ #define __GRAPHENE_MACROS_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #ifndef _GRAPHENE_PUBLIC #define _GRAPHENE_PUBLIC extern #endif #ifdef GRAPHENE_COMPILATION # define GRAPHENE_PRIVATE_FIELD(type,name) type name #else # define GRAPHENE_PRIVATE_FIELD(type,name) type __graphene_private_##name #endif #if defined(__GNUC__) # define GRAPHENE_ALIGN16 __attribute__((aligned(16))) #elif defined(_MSC_VER) # define GRAPHENE_ALIGN16 __declspec(align(16)) #else # define GRAPHENE_ALIGN16 #endif #if defined(_MSC_VER) && (_MSC_VER >= 1800) # ifdef _M_IX86 /* Use __vectorcall to enable SSE intrinsics on 32-bit builds on MSVC 2013 and later */ # define GRAPHENE_VECTORCALL __vectorcall # else # define GRAPHENE_VECTORCALL # endif #else # define GRAPHENE_VECTORCALL #endif #ifdef _MSC_VER # if !defined (__cplusplus) && defined (_MSC_VER) && (_MSC_VER < 1900) # define inline __inline # endif #endif #ifdef __cplusplus # define GRAPHENE_BEGIN_DECLS extern "C" { # define GRAPHENE_END_DECLS } #else # define GRAPHENE_BEGIN_DECLS # define GRAPHENE_END_DECLS #endif #ifndef __GI_SCANNER__ #if defined(_MSC_VER) && !defined(__bool_true_false_are_defined) && (_MSC_VER < 1800) typedef int bool; # define false 0 # define true 1 #else # include #endif #endif #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) #define _GRAPHENE_DEPRECATED __attribute__((__deprecated__)) #elif defined(_MSC_VER) && (_MSC_VER >= 1300) #define _GRAPHENE_DEPRECATED __declspec(deprecated) #else #define _GRAPHENE_DEPRECATED #endif #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define _GRAPHENE_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead"))) #elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320) #define _GRAPHENE_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead")) #else #define _GRAPHENE_DEPRECATED_FOR(f) _GRAPHENE_DEPRECATED #endif #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define _GRAPHENE_UNAVAILABLE(maj,min) __attribute__((deprecated("Not available before " #maj "." #min))) #elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320) #define _GRAPHENE_UNAVAILABLE(maj,min) __declspec(deprecated("is not available before " #maj "." #min)) #else #define _GRAPHENE_UNAVAILABLE(maj,min) _GRAPHENE_DEPRECATED #endif #define GRAPHENE_PI 3.1415926535897932384626434f #define GRAPHENE_PI_2 1.5707963267948966192313217f #endif /* __GRAPHENE_MACROS_H__ */ graphene-1.8.0/src/graphene-matrix.c000066400000000000000000001701631324365266600173640ustar00rootroot00000000000000/* graphene-matrix.h: 4x4 matrix * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-matrix * @title: Matrix * @short_description: 4x4 matrices * * #graphene_matrix_t is a type that provides a 4x4 square matrix, useful for * representing 3D transformations. * * The matrix is treated as row-major, i.e. it has four vectors (x, y, z, and * w) representing rows, and elements of each vector are a column: * * |[ * | x | | x.x x.y x.z x.w | * | y | -\ | y.x y.y y.z y.w | * | z | -/ | z.x z.y z.z z.w | * | w | | w.x w.y w.z w.w | * ]| * * It is possible to easily convert a #graphene_matrix_t to and from an array * of floating point values that can be used with other libraries. * * The contents of a #graphene_matrix_t are private, and direct access is not * possible. You can modify and read the contents of a #graphene_matrix_t * only through the provided API. */ #include "graphene-private.h" #include "graphene-matrix.h" #include "graphene-alloc-private.h" #include "graphene-box.h" #include "graphene-euler.h" #include "graphene-point.h" #include "graphene-point3d.h" #include "graphene-quad.h" #include "graphene-quaternion.h" #include "graphene-ray.h" #include "graphene-rect.h" #include "graphene-simd4x4f.h" #include "graphene-sphere.h" #include "graphene-vectors-private.h" #include /** * graphene_matrix_alloc: (constructor) * * Allocates a new #graphene_matrix_t. * * Returns: (transfer full): the newly allocated matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_alloc (void) { return graphene_aligned_alloc (sizeof (graphene_matrix_t), 1, 16); } /** * graphene_matrix_free: * @m: a #graphene_matrix_t * * Frees the resources allocated by graphene_matrix_alloc(). * * Since: 1.0 */ void graphene_matrix_free (graphene_matrix_t *m) { graphene_aligned_free (m); } /** * graphene_matrix_to_float: * @m: a #graphene_matrix_t * @v: (array fixed-size=16) (out caller-allocates): return location * for an array of floating point values. The array must be capable * of holding at least 16 values. * * Converts a #graphene_matrix_t to an array of floating point * values. * * Since: 1.0 */ void graphene_matrix_to_float (const graphene_matrix_t *m, float *v) { graphene_simd4x4f_to_float (&m->value, v); } static const float graphene_identity_matrix_floats[16] = { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, }; /** * graphene_matrix_init_identity: * @m: a #graphene_matrix_t * * Initializes a #graphene_matrix_t with the identity matrix. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_identity (graphene_matrix_t *m) { graphene_simd4x4f_init_from_float (&m->value, graphene_identity_matrix_floats); return m; } /** * graphene_matrix_init_from_float: * @m: a #graphene_matrix_t * @v: (array fixed-size=16): an array of at least 16 floating * point values * * Initializes a #graphene_matrix_t with the given array of floating * point values. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_from_float (graphene_matrix_t *m, const float *v) { graphene_simd4x4f_init_from_float (&m->value, v); return m; } /** * graphene_matrix_init_from_vec4: * @m: a #graphene_matrix_t * @v0: the first row vector * @v1: the second row vector * @v2: the third row vector * @v3: the fourth row vector * * Initializes a #graphene_matrix_t with the given four row * vectors. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_from_vec4 (graphene_matrix_t *m, const graphene_vec4_t *v0, const graphene_vec4_t *v1, const graphene_vec4_t *v2, const graphene_vec4_t *v3) { m->value = graphene_simd4x4f_init (v0->value, v1->value, v2->value, v3->value); return m; } /** * graphene_matrix_init_from_matrix: * @m: a #graphene_matrix_t * @src: a #graphene_matrix_t * * Initializes a #graphene_matrix_t using the values of the * given matrix. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_from_matrix (graphene_matrix_t *m, const graphene_matrix_t *src) { m->value = src->value; return m; } /** * graphene_matrix_init_perspective: * @m: a #graphene_matrix_t * @fovy: the field of view angle, in degrees * @aspect: the aspect value * @z_near: the near Z plane * @z_far: the far Z plane * * Initializes a #graphene_matrix_t with a perspective projection. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_perspective (graphene_matrix_t *m, float fovy, float aspect, float z_near, float z_far) { float fovy_rad = GRAPHENE_DEG_TO_RAD (fovy); graphene_simd4x4f_init_perspective (&m->value, fovy_rad, aspect, z_near, z_far); return m; } /** * graphene_matrix_init_ortho: * @m: a #graphene_matrix_t * @left: the left edge of the clipping plane * @right: the right edge of the clipping plane * @top: the top edge of the clipping plane * @bottom: the bottom edge of the clipping plane * @z_near: the distance of the near clipping plane * @z_far: the distance of the far clipping plane * * Initializes a #graphene_matrix_t with an orthographic projection. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_ortho (graphene_matrix_t *m, float left, float right, float top, float bottom, float z_near, float z_far) { graphene_simd4x4f_init_ortho (&m->value, left, right, top, bottom, z_near, z_far); return m; } /** * graphene_matrix_init_look_at: * @m: a #graphene_matrix_t * @eye: the vector describing the position to look from * @center: the vector describing the position to look at * @up: the vector describing the world's upward direction; usually, * this is the graphene_vec3_y_axis() vector * * Initializes a #graphene_matrix_t so that it positions the "camera" * at the given @eye coordinates towards an object at the @center * coordinates. The top of the camera is aligned to the direction * of the @up vector. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_look_at (graphene_matrix_t *m, const graphene_vec3_t *eye, const graphene_vec3_t *center, const graphene_vec3_t *up) { graphene_simd4x4f_init_look_at (&m->value, eye->value, center->value, up->value); return m; } /** * graphene_matrix_init_frustum: * @m: a #graphene_matrix_t * @left: distance of the left clipping plane * @right: distance of the right clipping plane * @bottom: distance of the bottom clipping plane * @top: distance of the top clipping plane * @z_near: distance of the near clipping plane * @z_far: distance of the far clipping plane * * Initializes a #graphene_matrix_t compatible with #graphene_frustum_t. * * See also: graphene_frustum_init_from_matrix() * * Returns: (transfer none): the initialized matrix * * Since: 1.2 */ graphene_matrix_t * graphene_matrix_init_frustum (graphene_matrix_t *m, float left, float right, float bottom, float top, float z_near, float z_far) { graphene_simd4x4f_init_frustum (&m->value, left, right, bottom, top, z_near, z_far); return m; } /** * graphene_matrix_init_scale: * @m: a #graphene_matrix_t * @x: the scale factor on the X axis * @y: the scale factor on the Y axis * @z: the scale factor on the Z axis * * Initializes a #graphene_matrix_t with the given scaling factors. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_scale (graphene_matrix_t *m, float x, float y, float z) { m->value = graphene_simd4x4f_init (graphene_simd4f_init ( x, 0.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, y, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, z, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 0.0f, 1.0f)); return m; } /** * graphene_matrix_init_translate: * @m: a #graphene_matrix_t * @p: the translation coordinates * * Initializes a #graphene_matrix_t with a translation to the * given coordinates. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_translate (graphene_matrix_t *m, const graphene_point3d_t *p) { m->value = graphene_simd4x4f_init (graphene_simd4f_init (1.0f, 0.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 1.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 1.0f, 0.0f), graphene_simd4f_init (p->x, p->y, p->z, 1.0f)); return m; } /** * graphene_matrix_init_skew: * @m: a #graphene_matrix_t * @x_skew: skew factor on the X axis * @y_skew: skew factor on the Y axis * * Initializes a #graphene_matrix_t with a skew transformation * with the given factors. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_skew (graphene_matrix_t *m, float x_skew, float y_skew) { float t_x, t_y; t_x = tanf (x_skew); t_y = tanf (y_skew); m->value = graphene_simd4x4f_init (graphene_simd4f_init (1.0f, t_y, 0.0f, 0.0f), graphene_simd4f_init ( t_x, 1.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 1.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 0.0f, 1.0f)); return m; } /** * graphene_matrix_init_rotate: * @m: a #graphene_matrix_t * @angle: the rotation angle, in degrees * @axis: the axis vector as a #graphene_vec3_t * * Initializes @m to represent a rotation of @angle degrees on * the axis represented by the @axis vector. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_rotate (graphene_matrix_t *m, float angle, const graphene_vec3_t *axis) { float rad = GRAPHENE_DEG_TO_RAD (angle); graphene_simd4x4f_rotation (&m->value, rad, axis->value); return m; } /** * graphene_matrix_is_identity: * @m: a #graphene_matrix_t * * Checks whether the given #graphene_matrix_t is the identity matrix. * * Returns: `true` if the matrix is the identity matrix * * Since: 1.0 */ bool graphene_matrix_is_identity (const graphene_matrix_t *m) { return graphene_simd4x4f_is_identity (&m->value); } /** * graphene_matrix_is_2d: * @m: a #graphene_matrix_t * * Checks whether the given #graphene_matrix_t is compatible with an * a 2D affine transformation matrix. * * Returns: `true` if the matrix is compatible with an affine * transformation matrix * * Since: 1.0 */ bool graphene_matrix_is_2d (const graphene_matrix_t *m) { #if 0 float res[4]; graphene_simd4f_dup_4f (m->value.x, res); if (!(graphene_fuzzy_equals (res[2], 0.f, 0.000001) && graphene_fuzzy_equals (res[3], 0.f, 0.000001))) return false; graphene_simd4f_dup_4f (m->value.y, res); if (!(graphene_fuzzy_equals (res[2], 0.f, 0.000001) && graphene_fuzzy_equals (res[3], 0.f, 0.000001))) return false; graphene_simd4f_dup_4f (m->value.z, res); if (!(graphene_fuzzy_equals (res[0], 0.f, 0.000001) && graphene_fuzzy_equals (res[1], 0.f, 0.000001) && graphene_fuzzy_equals (res[2], 1.f, 0.000001) && graphene_fuzzy_equals (res[3], 0.f, 0.000001))) return false; graphene_simd4f_dup_4f (m->value.w, res); if (!(graphene_fuzzy_equals (res[2], 0.f, 0.000001) && graphene_fuzzy_equals (res[3], 1.f, 0.000001))) return false; return true; #else return graphene_simd4x4f_is_2d (&m->value); #endif } /** * graphene_matrix_is_backface_visible: * @m: a #graphene_matrix_t * * Checks whether a #graphene_matrix_t has a visible back face. * * Returns: `true` if the back face of the matrix is visible * * Since: 1.0 */ bool graphene_matrix_is_backface_visible (const graphene_matrix_t *m) { graphene_simd4x4f_t tmp; if (!graphene_simd4x4f_inverse (&m->value, &tmp)) return false; /* inverse.zz < 0 */ return graphene_simd4f_get_z (tmp.z) < 0.f; } /** * graphene_matrix_is_singular: * @m: a #graphene_matrix_t * * Checks whether a matrix is singular. * * Returns: `true` if the matrix is singular * * Since: 1.0 */ bool graphene_matrix_is_singular (const graphene_matrix_t *m) { graphene_simd4f_t det; graphene_simd4x4f_determinant (&m->value, &det, NULL); return fabsf (graphene_simd4f_get_x (det)) <= GRAPHENE_FLOAT_EPSILON; } /** * graphene_matrix_init_from_2d: * @m: a #graphene_matrix_t * @xx: the xx member * @yx: the yx member * @xy: the xy member * @yy: the yy member * @x_0: the x0 member * @y_0: the y0 member * * Initializes a #graphene_matrix_t from the values of an affine * transformation matrix. * * The arguments map to the following matrix layout: * * |[ * | xx yx | | a b 0 | * | xy yy | = | c d 0 | * | x0 y0 | | tx ty 1 | * ]| * * This function can be used to convert between a matrix type from * other libraries and a #graphene_matrix_t. * * Returns: (transfer none): the initialized matrix * * Since: 1.0 */ graphene_matrix_t * graphene_matrix_init_from_2d (graphene_matrix_t *m, double xx, double yx, double xy, double yy, double x_0, double y_0) { m->value = graphene_simd4x4f_init (graphene_simd4f_init ( xx, yx, 0.f, 0.f), graphene_simd4f_init ( xy, yy, 0.f, 0.f), graphene_simd4f_init (0.f, 0.f, 1.f, 0.f), graphene_simd4f_init (x_0, y_0, 0.f, 1.f)); return m; } /** * graphene_matrix_to_2d: * @m: a #graphene_matrix_t * @xx: (out): return location for the xx member * @yx: (out): return location for the yx member * @xy: (out): return location for the xy member * @yy: (out): return location for the yy member * @x_0: (out): return location for the x0 member * @y_0: (out): return location for the y0 member * * Converts a #graphene_matrix_t to an affine transformation * matrix, if the given matrix is compatible. * * The returned values have the following layout: * * |[ * | xx yx | | a b 0 | * | xy yy | = | c d 0 | * | x0 y0 | | tx ty 1 | * ]| * * This function can be used to convert between a #graphene_matrix_t * and a matrix type from other libraries. * * Returns: `true` if the matrix is compatible with an affine * transformation matrix * * Since: 1.0 */ bool graphene_matrix_to_2d (const graphene_matrix_t *m, double *xx, double *yx, double *xy, double *yy, double *x_0, double *y_0) { float res[4]; graphene_simd4f_dup_4f (m->value.x, res); if (!graphene_approx_val (res[2], 0.f) && !graphene_approx_val (res[3], 0.f)) return false; if (xx != NULL) *xx = res[0]; if (yx != NULL) *yx = res[1]; graphene_simd4f_dup_4f (m->value.y, res); if (!graphene_approx_val (res[2], 0.f) && !graphene_approx_val (res[3], 0.f)) return false; if (xy != NULL) *xy = res[0]; if (yy != NULL) *yy = res[1]; graphene_simd4f_dup_4f (m->value.z, res); if (!graphene_approx_val (res[0], 0.f) && !graphene_approx_val (res[1], 0.f) && !graphene_approx_val (res[2], 1.f) && !graphene_approx_val (res[3], 0.f)) return false; graphene_simd4f_dup_4f (m->value.w, res); if (!graphene_approx_val (res[2], 0.f) && !graphene_approx_val (res[3], 1.f)) return false; if (x_0 != NULL) *x_0 = res[0]; if (y_0 != NULL) *y_0 = res[1]; return true; } /** * graphene_matrix_get_row: * @m: a #graphene_matrix_t * @index_: the index of the row vector, between 0 and 3 * @res: (out caller-allocates): return location for the #graphene_vec4_t * that is used to store the row vector * * Retrieves the given row vector at @index_ inside a matrix. * * Since: 1.0 */ void graphene_matrix_get_row (const graphene_matrix_t *m, unsigned int index_, graphene_vec4_t *res) { switch (index_) { case 0: res->value = m->value.x; break; case 1: res->value = m->value.y; break; case 2: res->value = m->value.z; break; case 3: res->value = m->value.w; break; default: res->value = graphene_simd4f_init_zero (); break; } } /** * graphene_matrix_get_value: * @m: a #graphene_matrix_t * @row: the row index * @col: the column index * * Retrieves the value at the given @row and @col index. * * Returns: the value at the given indices * * Since: 1.0 */ float graphene_matrix_get_value (const graphene_matrix_t *m, unsigned int row, unsigned int col) { graphene_simd4f_t r; if (row > 3 || col > 3) return 0.f; switch (row) { case 0: r = m->value.x; break; case 1: r = m->value.y; break; case 2: r = m->value.z; break; case 3: r = m->value.w; break; default: return 0.f; } switch (col) { case 0: return graphene_simd4f_get (r, 0); case 1: return graphene_simd4f_get (r, 1); case 2: return graphene_simd4f_get (r, 2); case 3: return graphene_simd4f_get (r, 3); default: return 0.f; } return 0.f; } /** * graphene_matrix_multiply: * @a: a #graphene_matrix_t * @b: a #graphene_matrix_t * @res: (out caller-allocates): return location for the matrix * result * * Multiplies two #graphene_matrix_t. * * Remember: matrix multiplication is not commutative, except for the * identity matrix; the product of this multiplication is (A * B). * * Since: 1.0 */ void graphene_matrix_multiply (const graphene_matrix_t *a, const graphene_matrix_t *b, graphene_matrix_t *res) { graphene_simd4x4f_matrix_mul (&a->value, &b->value, &res->value); } /** * graphene_matrix_determinant: * @m: a #graphene_matrix_t * * Computes the determinant of the given matrix. * * Returns: the value of the determinant * * Since: 1.0 */ float graphene_matrix_determinant (const graphene_matrix_t *m) { graphene_simd4f_t det; graphene_simd4x4f_determinant (&m->value, &det, NULL); return graphene_simd4f_get_x (det); } /** * graphene_matrix_transform_vec3: * @m: a #graphene_matrix_t * @v: a #graphene_vec3_t * @res: (out caller-allocates): return location for a #graphene_vec3_t * * Transforms the given #graphene_vec3_t using the matrix @m. * * Since: 1.0 */ void graphene_matrix_transform_vec3 (const graphene_matrix_t *m, const graphene_vec3_t *v, graphene_vec3_t *res) { graphene_simd4x4f_vec3_mul (&m->value, &v->value, &res->value); } /** * graphene_matrix_transform_vec4: * @m: a #graphene_matrix_t * @v: a #graphene_vec4_t * @res: (out caller-allocates): return location for a #graphene_vec4_t * * Transforms the given #graphene_vec4_t using the matrix @m. * * Since: 1.0 */ void graphene_matrix_transform_vec4 (const graphene_matrix_t *m, const graphene_vec4_t *v, graphene_vec4_t *res) { graphene_simd4x4f_vec4_mul (&m->value, &v->value, &res->value); } /** * graphene_matrix_transform_point: * @m: a #graphene_matrix_t * @p: a #graphene_point_t * @res: (out caller-allocates): return location for the * transformed #graphene_point_t * * Transforms the given #graphene_point_t using the matrix @m. * * Since: 1.0 */ void graphene_matrix_transform_point (const graphene_matrix_t *m, const graphene_point_t *p, graphene_point_t *res) { graphene_simd4f_t vec3; vec3 = graphene_simd4f_init (p->x, p->y, 0.0f, 0.0f); graphene_simd4x4f_vec3_mul (&m->value, &vec3, &vec3); res->x = graphene_simd4f_get_x (vec3); res->y = graphene_simd4f_get_y (vec3); } /** * graphene_matrix_transform_point3d: * @m: a #graphene_matrix_t * @p: a #graphene_point3d_t * @res: (out caller-allocates): return location for the result * * Transforms the given #graphene_point3d_t using the matrix @m. * * Unlike graphene_matrix_transform_vec3(), this function will take into * account the fourth row vector of the #graphene_matrix_t. * * Since: 1.2 */ void graphene_matrix_transform_point3d (const graphene_matrix_t *m, const graphene_point3d_t *p, graphene_point3d_t *res) { graphene_simd4f_t vec3; vec3 = graphene_simd4f_init (p->x, p->y, p->z, 0.f); graphene_simd4x4f_point3_mul (&m->value, &vec3, &vec3); res->x = graphene_simd4f_get_x (vec3); res->y = graphene_simd4f_get_y (vec3); res->z = graphene_simd4f_get_z (vec3); } /** * graphene_matrix_transform_rect: * @m: a #graphene_matrix_t * @r: a #graphene_rect_t * @res: (out caller-allocates): return location for the * transformed quad * * Transforms a #graphene_rect_t using the given matrix @m. The * result is a coplanar quad. * * Since: 1.0 */ void graphene_matrix_transform_rect (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_quad_t *res) { graphene_point_t ret[4]; #define TRANSFORM_POINT(matrix,rect,corner,out_p) do { \ graphene_simd4f_t __s; \ graphene_point_t __p; \ graphene_rect_get_ ## corner (rect, &__p); \ __s = graphene_simd4f_init (__p.x, __p.y, 0.f, 1.f); \ graphene_simd4x4f_vec4_mul (&matrix->value, &__s, &__s); \ out_p.x = graphene_simd4f_get_x (__s); \ out_p.y = graphene_simd4f_get_y (__s); } while (0) TRANSFORM_POINT (m, r, top_left, ret[0]); TRANSFORM_POINT (m, r, top_right, ret[1]); TRANSFORM_POINT (m, r, bottom_right, ret[2]); TRANSFORM_POINT (m, r, bottom_left, ret[3]); #undef TRANSFORM_POINT graphene_quad_init (res, &ret[0], &ret[1], &ret[2], &ret[3]); } /** * graphene_matrix_transform_bounds: * @m: a #graphene_matrix_t * @r: a #graphene_rect_t * @res: (out caller-allocates): return location for the bounds * of the transformed rectangle * * Transforms a #graphene_rect_t using the given matrix @m. The * result is the bounding box containing the coplanar quad. * * Since: 1.0 */ void graphene_matrix_transform_bounds (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_rect_t *res) { graphene_point_t ret[4]; float min_x, min_y; float max_x, max_y; #define TRANSFORM_POINT(matrix,rect,corner,out_p) do { \ graphene_simd4f_t __s; \ graphene_point_t __p; \ graphene_rect_get_ ## corner (rect, &__p); \ __s = graphene_simd4f_init (__p.x, __p.y, 0.f, 1.f); \ graphene_simd4x4f_vec4_mul (&matrix->value, &__s, &__s); \ out_p.x = graphene_simd4f_get_x (__s); \ out_p.y = graphene_simd4f_get_y (__s); } while (0) TRANSFORM_POINT (m, r, top_left, ret[0]); TRANSFORM_POINT (m, r, top_right, ret[1]); TRANSFORM_POINT (m, r, bottom_right, ret[2]); TRANSFORM_POINT (m, r, bottom_left, ret[3]); #undef TRANSFORM_POINT #if 0 { int i; min_x = max_x = ret[0].x; min_y = max_y = ret[0].y; for (i = 1; i < 4; i += 1) { min_x = MIN (ret[i].x, min_x); min_y = MIN (ret[i].y, min_y); max_x = MAX (ret[i].x, max_x); max_y = MAX (ret[i].y, max_y); } } #else { const graphene_simd4f_t vx = graphene_simd4f_init (ret[0].x, ret[1].x, ret[2].x, ret[3].x); const graphene_simd4f_t vy = graphene_simd4f_init (ret[0].y, ret[1].y, ret[2].y, ret[3].y); min_x = graphene_simd4f_get_x (graphene_simd4f_min_val (vx)); min_y = graphene_simd4f_get_x (graphene_simd4f_min_val (vy)); max_x = graphene_simd4f_get_x (graphene_simd4f_max_val (vx)); max_y = graphene_simd4f_get_x (graphene_simd4f_max_val (vy)); } #endif graphene_rect_init (res, min_x, min_y, max_x - min_x, max_y - min_y); } /** * graphene_matrix_transform_sphere: * @m: a #graphene_matrix_t * @s: a #graphene_sphere_t * @res: (out caller-allocates): return location for the bounds * of the transformed sphere * * Transforms a #graphene_sphere_t using the given matrix @m. The * result is the bounding sphere containing the transformed sphere. * * Since: 1.2 */ void graphene_matrix_transform_sphere (const graphene_matrix_t *m, const graphene_sphere_t *s, graphene_sphere_t *res) { float max_scale; graphene_simd4x4f_point3_mul (&m->value, &s->center.value, &res->center.value); max_scale = graphene_simd4f_dot3_scalar (m->value.x, m->value.x); max_scale = fmaxf (max_scale, graphene_simd4f_dot3_scalar (m->value.y, m->value.y)); max_scale = fmaxf (max_scale, graphene_simd4f_dot3_scalar (m->value.z, m->value.z)); res->radius = s->radius * sqrtf (max_scale); } /** * graphene_matrix_transform_box: * @m: a #graphene_matrix_t * @b: a #graphene_box_t * @res: (out caller-allocates): return location for the bounds * of the transformed box * * Transforms a #graphene_box_t using the given matrix @m. The * result is the bounding box containing the transformed box. * * Since: 1.2 */ void graphene_matrix_transform_box (const graphene_matrix_t *m, const graphene_box_t *b, graphene_box_t *res) { graphene_vec3_t points[8]; graphene_box_get_vertices (b, points); for (int i = 0; i < 8; i++) graphene_simd4x4f_point3_mul (&m->value, &(points[i].value), &(points[i].value)); graphene_box_init_from_vectors (res, 8, points); } /** * graphene_matrix_transform_ray: * @m: a #graphene_matrix_t * @r: a #graphene_ray_t * @res: (out caller-allocates): return location for the * transformed ray * * Transform a #graphene_ray_t using the given matrix @m. * * Since: 1.4 */ void graphene_matrix_transform_ray (const graphene_matrix_t *m, const graphene_ray_t *r, graphene_ray_t *res) { graphene_vec3_t origin, direction; graphene_vec3_add (&r->direction, &r->origin, &direction); graphene_matrix_transform_vec3 (m, &direction, &direction); graphene_matrix_transform_vec3 (m, &r->origin, &origin); graphene_vec3_subtract (&direction, &origin, &direction); graphene_ray_init_from_vec3 (res, &origin, &direction); } /** * graphene_matrix_project_point: * @m: a #graphene_matrix_t * @p: a #graphene_point_t * @res: (out caller-allocates): return location for the projected * point * * Projects a #graphene_point_t using the matrix @m. * * Since: 1.0 */ void graphene_matrix_project_point (const graphene_matrix_t *m, const graphene_point_t *p, graphene_point_t *res) { graphene_simd4f_t pa, pb, pc; float a[3], b[3]; float t; pa = graphene_simd4f_init (p->x, p->y, 0.f, 0.f); pb = graphene_simd4f_init (p->x, p->y, 1.f, 0.f); graphene_simd4x4f_vec3_mul (&m->value, &pa, &pa); graphene_simd4x4f_vec3_mul (&m->value, &pb, &pb); pc = graphene_simd4f_sub (pa, pb); graphene_simd4f_dup_3f (pa, a); graphene_simd4f_dup_3f (pc, b); t = -a[2] / b[2]; graphene_point_init (res, a[0] + t * b[0], a[1] + t * b[1]); } /** * graphene_matrix_project_rect_bounds: * @m: a #graphene_matrix_t * @r: a #graphene_rect_t * @res: (out caller-allocates): return location for the projected * rectangle * * Projects a #graphene_rect_t using the given matrix. * * The resulting rectangle is the bounding box capable of containing * fully the projected rectangle. * * Since: 1.0 */ void graphene_matrix_project_rect_bounds (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_rect_t *res) { graphene_point_t points[4]; graphene_point_t ret[4]; graphene_rect_get_top_left (r, &points[0]); graphene_rect_get_top_right (r, &points[1]); graphene_rect_get_bottom_left (r, &points[2]); graphene_rect_get_bottom_right (r, &points[3]); graphene_matrix_project_point (m, &points[0], &ret[0]); graphene_matrix_project_point (m, &points[1], &ret[1]); graphene_matrix_project_point (m, &points[2], &ret[2]); graphene_matrix_project_point (m, &points[3], &ret[3]); graphene_simd4f_t v_x = graphene_simd4f_init (ret[0].x, ret[1].x, ret[2].x, ret[3].x); graphene_simd4f_t v_y = graphene_simd4f_init (ret[0].y, ret[1].y, ret[2].y, ret[3].y); float min_x = graphene_simd4f_get_x (graphene_simd4f_min_val (v_x)); float max_x = graphene_simd4f_get_x (graphene_simd4f_max_val (v_x)); float min_y = graphene_simd4f_get_x (graphene_simd4f_min_val (v_y)); float max_y = graphene_simd4f_get_x (graphene_simd4f_max_val (v_y)); graphene_rect_init (res, min_x, min_y, max_x - min_x, max_y - min_y); } /** * graphene_matrix_project_rect: * @m: a #graphene_matrix_t * @r: a #graphene_rect_t * @res: (out caller-allocates): return location for the projected * rectangle * * Projects a #graphene_rect_t using the given matrix. * * Since: 1.2 */ void graphene_matrix_project_rect (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_quad_t *res) { graphene_point_t p[4]; graphene_rect_get_top_left (r, &p[0]); graphene_matrix_project_point (m, &p[0], &p[0]); graphene_rect_get_top_right (r, &p[1]); graphene_matrix_project_point (m, &p[1], &p[1]); graphene_rect_get_bottom_left (r, &p[2]); graphene_matrix_project_point (m, &p[2], &p[2]); graphene_rect_get_bottom_right (r, &p[3]); graphene_matrix_project_point (m, &p[3], &p[3]); graphene_quad_init_from_points (res, p); } /** * graphene_matrix_untransform_point: * @m: a #graphene_matrix_t * @p: a #graphene_point_t * @bounds: the bounds of the transformation * @res: (out caller-allocates): return location for the * untransformed point * * Undoes the transformation of a #graphene_point_t using the * given matrix, within the given rectangular @bounds. * * Returns: `true` if the point was successfully untransformed * * Since: 1.0 */ bool graphene_matrix_untransform_point (const graphene_matrix_t *m, const graphene_point_t *p, const graphene_rect_t *bounds, graphene_point_t *res) { graphene_matrix_t inverse; graphene_rect_t bounds_t; if (graphene_matrix_is_2d (m)) { if (!graphene_matrix_inverse (m, &inverse)) return false; graphene_matrix_transform_point (&inverse, p, res); return true; } graphene_matrix_transform_bounds (m, bounds, &bounds_t); if (!graphene_rect_contains_point (&bounds_t, p)) return false; if (!graphene_matrix_inverse (m, &inverse)) return false; graphene_matrix_project_point (&inverse, p, res); return true; } /** * graphene_matrix_untransform_bounds: * @m: a #graphene_matrix_t * @r: a #graphene_rect_t * @bounds: the bounds of the transformation * @res: (out caller-allocates): return location for the * untransformed rectangle * * Undoes the transformation on the points of a #graphene_rect_t * using the given matrix, within the given rectangular @bounds. * * Since: 1.0 */ void graphene_matrix_untransform_bounds (const graphene_matrix_t *m, const graphene_rect_t *r, const graphene_rect_t *bounds, graphene_rect_t *res) { graphene_matrix_t inverse; graphene_rect_t bounds_t; graphene_rect_t rect; if (graphene_matrix_is_2d (m)) { if (!graphene_matrix_inverse (m, &inverse)) return; graphene_matrix_transform_bounds (&inverse, r, res); return; } graphene_matrix_transform_bounds (m, bounds, &bounds_t); if (!graphene_rect_intersection (r, &bounds_t, &rect)) { graphene_rect_init (res, 0.f, 0.f, 0.f, 0.f); return; } if (!graphene_matrix_inverse (m, &inverse)) return; graphene_matrix_project_rect_bounds (&inverse, &rect, res); } /** * graphene_matrix_unproject_point3d: * @projection: a #graphene_matrix_t for the projection matrix * @modelview: a #graphene_matrix_t for the modelview matrix; this is * the inverse of the modelview used when projecting the point * @point: a #graphene_point3d_t with the coordinates of the point * @res: (out caller-allocates): return location for the unprojected * point * * Unprojects the given @point using the @projection matrix and * a @modelview matrix. * * Since: 1.2 */ void graphene_matrix_unproject_point3d (const graphene_matrix_t *projection, const graphene_matrix_t *modelview, const graphene_point3d_t *point, graphene_point3d_t *res) { graphene_simd4x4f_t tmp; graphene_simd4f_t v; float values[4]; float inv_w; if (!graphene_simd4x4f_inverse (&projection->value, &tmp)) return; graphene_simd4x4f_matrix_mul (&tmp, &modelview->value, &tmp); v = graphene_simd4f_init (point->x, point->y, point->z, 1.f); graphene_simd4x4f_vec4_mul (&tmp, &v, &v); inv_w = 1.f / graphene_simd4f_get_w (v); v = graphene_simd4f_mul (v, graphene_simd4f_splat (inv_w)); graphene_simd4f_dup_4f (v, values); graphene_point3d_init (res, values[0], values[1], values[2]); } /** * graphene_matrix_translate: * @m: a #graphene_matrix_t * @pos: a #graphene_point3d_t * * Adds a translation transformation to @m using the coordinates * of the given #graphene_point3d_t. * * Since: 1.0 */ void graphene_matrix_translate (graphene_matrix_t *m, const graphene_point3d_t *pos) { graphene_simd4x4f_t trans_m; graphene_simd4x4f_translation (&trans_m, pos->x, pos->y, pos->z); graphene_simd4x4f_matrix_mul (&m->value, &trans_m, &m->value); } /** * graphene_matrix_rotate_quaternion: * @m: a #graphene_matrix_t * @q: a rotation described by a #graphene_quaternion_t * * Adds a rotation transformation to @m, using the given * #graphene_quaternion_t. * * Since: 1.2 */ void graphene_matrix_rotate_quaternion (graphene_matrix_t *m, const graphene_quaternion_t *q) { graphene_matrix_t rot; graphene_quaternion_to_matrix (q, &rot); graphene_matrix_multiply (m, &rot, m); } /** * graphene_matrix_rotate_euler: * @m: a #graphene_matrix_t * @e: a rotation described by a #graphene_euler_t * * Adds a rotation transformation to @m, using the given * #graphene_euler_t. * * Since: 1.2 */ void graphene_matrix_rotate_euler (graphene_matrix_t *m, const graphene_euler_t *e) { graphene_quaternion_t q; graphene_quaternion_init_from_euler (&q, e); graphene_matrix_rotate_quaternion (m, &q); } static inline void graphene_matrix_rotate_internal (graphene_simd4x4f_t *m, float rad, const graphene_simd4f_t axis) { graphene_simd4x4f_t rot_m; graphene_simd4x4f_rotation (&rot_m, rad, axis); graphene_simd4x4f_matrix_mul (m, &rot_m, m); } /** * graphene_matrix_rotate: * @m: a #graphene_matrix_t * @angle: the rotation angle, in degrees * @axis: the rotation axis, as a #graphene_vec3_t * * Adds a rotation transformation to @m, using the given @angle * and @axis vector. * * Since: 1.0 */ void graphene_matrix_rotate (graphene_matrix_t *m, float angle, const graphene_vec3_t *axis) { graphene_matrix_rotate_internal (&m->value, GRAPHENE_DEG_TO_RAD (angle), axis->value); } /** * graphene_matrix_rotate_x: * @m: a #graphene_matrix_t * @angle: the rotation angle, in degrees * * Adds a rotation transformation around the X axis to @m, using * the given @angle. * * Since: 1.0 */ void graphene_matrix_rotate_x (graphene_matrix_t *m, float angle) { graphene_matrix_rotate_internal (&m->value, GRAPHENE_DEG_TO_RAD (angle), graphene_simd4f_init (1.f, 0.f, 0.f, 0.f)); } /** * graphene_matrix_rotate_y: * @m: a #graphene_matrix_t * @angle: the rotation angle, in degrees * * Adds a rotation transformation around the Y axis to @m, using * the given @angle. * * Since: 1.0 */ void graphene_matrix_rotate_y (graphene_matrix_t *m, float angle) { graphene_matrix_rotate_internal (&m->value, GRAPHENE_DEG_TO_RAD (angle), graphene_simd4f_init (0.f, 1.f, 0.f, 0.f)); } /** * graphene_matrix_rotate_z: * @m: a #graphene_matrix_t * @angle: the rotation angle, in degrees * * Adds a rotation transformation around the Z axis to @m, using * the given @angle. * * Since: 1.0 */ void graphene_matrix_rotate_z (graphene_matrix_t *m, float angle) { graphene_matrix_rotate_internal (&m->value, GRAPHENE_DEG_TO_RAD (angle), graphene_simd4f_init (0.f, 0.f, 1.f, 0.f)); } /** * graphene_matrix_scale: * @m: a #graphene_matrix_t * @factor_x: scaling factor on the X axis * @factor_y: scaling factor on the Y axis * @factor_z: scaling factor on the Z axis * * Adds a scaling transformation to @m, using the three * given factors. * * Since: 1.0 */ void graphene_matrix_scale (graphene_matrix_t *m, float factor_x, float factor_y, float factor_z) { graphene_simd4x4f_t scale_m; graphene_simd4x4f_scale (&scale_m, factor_x, factor_y, factor_z); graphene_simd4x4f_matrix_mul (&m->value, &scale_m, &m->value); } /** * graphene_matrix_skew_xy: * @m: a #graphene_matrix_t * @factor: skew factor * * Adds a skew of @factor on the X and Y axis to the given matrix. * * Since: 1.0 */ void graphene_matrix_skew_xy (graphene_matrix_t *m, float factor) { graphene_simd4f_t m_x, m_y; m_x = m->value.x; m_y = m->value.y; m->value.y = graphene_simd4f_madd (m_x, graphene_simd4f_splat (factor), m_y); } /** * graphene_matrix_skew_xz: * @m: a #graphene_matrix_t * @factor: skew factor * * Adds a skew of @factor on the X and Z axis to the given matrix. * * Since: 1.0 */ void graphene_matrix_skew_xz (graphene_matrix_t *m, float factor) { graphene_simd4f_t m_x, m_z; m_x = m->value.x; m_z = m->value.z; m->value.z = graphene_simd4f_madd (m_x, graphene_simd4f_splat (factor), m_z); } /** * graphene_matrix_skew_yz: * @m: a #graphene_matrix_t * @factor: skew factor * * Adds a skew of @factor on the Y and Z axis to the given matrix. * * Since: 1.0 */ void graphene_matrix_skew_yz (graphene_matrix_t *m, float factor) { graphene_simd4f_t m_y, m_z; m_y = m->value.y; m_z = m->value.z; m->value.z = graphene_simd4f_madd (m_y, graphene_simd4f_splat (factor), m_z); } static inline void graphene_matrix_transpose_transform_vec4 (const graphene_matrix_t *m, const graphene_vec4_t *v, graphene_vec4_t *res) { float x, y, z, w; x = graphene_simd4f_get_x (graphene_simd4f_dot4 (m->value.x, v->value)); y = graphene_simd4f_get_x (graphene_simd4f_dot4 (m->value.y, v->value)); z = graphene_simd4f_get_x (graphene_simd4f_dot4 (m->value.z, v->value)); w = graphene_simd4f_get_x (graphene_simd4f_dot4 (m->value.w, v->value)); graphene_vec4_init (res, x, y, z, w); } /** * graphene_matrix_transpose: * @m: a #graphene_matrix_t * @res: (out caller-allocates): return location for the * transposed matrix * * Transposes the given matrix. * * Since: 1.0 */ void graphene_matrix_transpose (const graphene_matrix_t *m, graphene_matrix_t *res) { graphene_simd4x4f_transpose (&m->value, &res->value); } /** * graphene_matrix_inverse: * @m: a #graphene_matrix_t * @res: (out caller-allocates): return location for the * inverse matrix * * Inverts the given matrix. * * Returns: `true` if the matrix is invertible * * Since: 1.0 */ bool graphene_matrix_inverse (const graphene_matrix_t *m, graphene_matrix_t *res) { return graphene_simd4x4f_inverse (&m->value, &res->value); } /** * graphene_matrix_perspective: * @m: a #graphene_matrix_t * @depth: the depth of the perspective * @res: (out caller-allocates): return location for the * perspective matrix * * Applies a perspective of @depth to the matrix. * * Since: 1.0 */ void graphene_matrix_perspective (const graphene_matrix_t *m, float depth, graphene_matrix_t *res) { res->value = m->value; graphene_simd4x4f_perspective (&res->value, depth); } /** * graphene_matrix_normalize: * @m: a #graphene_matrix_t * @res: (out caller-allocates): return location for the normalized matrix * * Normalizes the given #graphene_matrix_t. * * Since: 1.0 */ void graphene_matrix_normalize (const graphene_matrix_t *m, graphene_matrix_t *res) { float ww = graphene_simd4f_get_w (m->value.w); if (graphene_approx_val (ww, 0.f)) return; graphene_simd4f_t n = graphene_simd4f_splat (1.f / ww); res->value.x = graphene_simd4f_mul (m->value.x, n); res->value.y = graphene_simd4f_mul (m->value.y, n); res->value.z = graphene_simd4f_mul (m->value.z, n); res->value.w = graphene_simd4f_mul (m->value.w, n); } /** * graphene_matrix_get_x_scale: * @m: a #graphene_matrix_t * * Retrieves the scaling factor on the X axis in @m. * * Returns: the value of the scaling factor * * Since: 1.0 */ float graphene_matrix_get_x_scale (const graphene_matrix_t *m) { return graphene_simd4f_get_x (m->value.x); } /** * graphene_matrix_get_y_scale: * @m: a #graphene_matrix_t * * Retrieves the scaling factor on the Y axis in @m. * * Returns: the value of the scaling factor * * Since: 1.0 */ float graphene_matrix_get_y_scale (const graphene_matrix_t *m) { return graphene_simd4f_get_y (m->value.y); } /** * graphene_matrix_get_z_scale: * @m: a #graphene_matrix_t * * Retrieves the scaling factor on the Z axis in @m. * * Returns: the value of the scaling factor * * Since: 1.0 */ float graphene_matrix_get_z_scale (const graphene_matrix_t *m) { return graphene_simd4f_get_z (m->value.z); } /* the algorithm for decomposing two matrices and interpolating * between their components in order to reassemble a matrix that * is equivalent to a linear interpolation of the original two * matrices is taken from the CSS3 Transforms specification: * * http://dev.w3.org/csswg/css-transforms/ * * specifically, the 2D matrix decomposition is taken from: * * http://dev.w3.org/csswg/css-transforms/#decomposing-a-2d-matrix * * while the 3D matrix decomposition is taken from: * * http://dev.w3.org/csswg/css-transforms/#decomposing-a-3d-matrix * * both, in turn, refer to the `unmatrix` program published in * the book "Graphics Gems II" edited by Jim Arvo; the code is * available at: * * http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c */ #define XY_SHEAR 0 #define XZ_SHEAR 1 #define YZ_SHEAR 2 #define M_11 0 #define M_12 1 #define M_21 2 #define M_22 3 static bool matrix_decompose_2d (const graphene_matrix_t *m, graphene_point_t *translate_r, graphene_point_t *scale_r, double *angle_r, float m_r[4]) { float row0x = graphene_matrix_get_value (m, 0, 0); float row0y = graphene_matrix_get_value (m, 1, 0); float row1x = graphene_matrix_get_value (m, 0, 1); float row1y = graphene_matrix_get_value (m, 1, 1); float angle; float det; if (fabsf (row0x * row1y - row0y * row1x) < FLT_EPSILON) return false; graphene_point_init (translate_r, graphene_matrix_get_value (m, 3, 0), graphene_matrix_get_value (m, 3, 1)); scale_r->x = sqrtf (row0x * row0x + row0y * row0y); scale_r->y = sqrtf (row1x * row1x + row1y * row1y); det = row0x * row1y - row0y * row1x; if (det < 0) { if (row0x < row1y) scale_r->x = -scale_r->x; else scale_r->y = -scale_r->y; } if (!graphene_approx_val (scale_r->x, 0.f)) { row0x = row0x * (1.f / scale_r->x); row0y = row0y * (1.f / scale_r->y); } if (!graphene_approx_val (scale_r->y, 0.f)) { row1x = row1x * (1.f / scale_r->x); row1y = row1y * (1.f / scale_r->y); } angle = atan2 (row0y, row0x); if (angle) { double sn = -row0y, cs = row0x; double m11 = row0x, m12 = row0y; double m21 = row1x, m22 = row1y; row0x = cs * m11 + sn * m21; row0y = cs * m12 + sn * m22; row1x = -sn * m11 + cs * m21; row1y = -sn * m12 + cs * m22; } m_r[M_11] = row0x; m_r[M_12] = row0y; m_r[M_21] = row1x; m_r[M_22] = row1y; *angle_r = GRAPHENE_RAD_TO_DEG (angle); return true; } static bool matrix_decompose_3d (const graphene_matrix_t *m, graphene_point3d_t *scale_r, float shear_r[3], graphene_quaternion_t *rotate_r, graphene_point3d_t *translate_r, graphene_vec4_t *perspective_r) { graphene_matrix_t local, perspective; float shear_xy, shear_xz, shear_yz; float scale_x, scale_y, scale_z; graphene_simd4f_t perspective_v; graphene_simd4f_t cross; if (graphene_approx_val (graphene_simd4f_get_w (m->value.w), 0.f)) return false; local = *m; /* normalize the matrix */ graphene_matrix_normalize (&local, &local); /* perspective is used to solve for the perspective component, * but it also provides an easy way to test for singularity of * the upper 3x3 component */ perspective = local; perspective.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f); if (graphene_approx_val (graphene_matrix_determinant (&perspective), 0.f)) return false; perspective_v = graphene_simd4f_init (graphene_simd4f_get_w (local.value.x), graphene_simd4f_get_w (local.value.y), graphene_simd4f_get_w (local.value.z), graphene_simd4f_get_w (local.value.w)); /* isolate the perspective */ if (!graphene_simd4f_is_zero3 (perspective_v)) { graphene_matrix_t tmp; /* perspective_r is the right hand side of the equation */ perspective_r->value = perspective_v; /* solve the equation by inverting perspective and multiplying * the inverse with the perspective vector; we don't need to * check if the matrix is invertible here because we just checked * whether the determinant is not zero. */ graphene_matrix_inverse (&perspective, &tmp); graphene_matrix_transpose_transform_vec4 (&tmp, perspective_r, perspective_r); /* Clear the perspective component */ local.value.x = graphene_simd4f_merge_w (local.value.x, 0.f); local.value.y = graphene_simd4f_merge_w (local.value.y, 0.f); local.value.z = graphene_simd4f_merge_w (local.value.z, 0.f); local.value.w = graphene_simd4f_merge_w (local.value.w, 1.f); } else graphene_vec4_init (perspective_r, 0.f, 0.f, 0.f, 1.f); /* next, take care of the translation partition */ translate_r->x = graphene_simd4f_get_x (local.value.w); translate_r->y = graphene_simd4f_get_y (local.value.w); translate_r->z = graphene_simd4f_get_z (local.value.w); local.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, graphene_simd4f_get_w (local.value.w)); /* now get scale and shear */ /* compute the X scale factor and normalize the first row */ scale_x = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.x)); local.value.x = graphene_simd4f_normalize4 (local.value.x); /* compute XY shear factor and the second row orthogonal to the first */ shear_xy = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.x, local.value.y)); local.value.y = graphene_simd4f_sub (local.value.y, graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (shear_xy))); /* now, compute the Y scale factor and normalize the second row */ scale_y = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.y)); local.value.y = graphene_simd4f_normalize4 (local.value.y); shear_xy /= scale_y; /* compute XZ and YZ shears, make the third row orthogonal */ shear_xz = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.x, local.value.z)); local.value.z = graphene_simd4f_sub (local.value.z, graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (shear_xz))); shear_yz = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.y, local.value.z)); local.value.z = graphene_simd4f_sub (local.value.z, graphene_simd4f_mul (local.value.y, graphene_simd4f_splat (shear_yz))); /* next, get the Z scale and normalize the third row */ scale_z = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.z)); local.value.z = graphene_simd4f_normalize4 (local.value.z); shear_xz /= scale_z; shear_yz /= scale_z; shear_r[XY_SHEAR] = shear_xy; shear_r[XZ_SHEAR] = shear_xz; shear_r[YZ_SHEAR] = shear_yz; /* at this point, the matrix is orthonormal. we check for a * coordinate system flip. if the determinant is -1, then * negate the matrix and the scaling factors */ cross = graphene_simd4f_dot3 (local.value.x, graphene_simd4f_cross3 (local.value.y, local.value.z)); if (graphene_simd4f_get_x (cross) < 0.f) { scale_x *= -1.f; scale_y *= -1.f; scale_z *= -1.f; local.value.x = graphene_simd4f_neg (local.value.x); local.value.y = graphene_simd4f_neg (local.value.y); local.value.z = graphene_simd4f_neg (local.value.z); } graphene_point3d_init (scale_r, scale_x, scale_y, scale_z); /* get the rotations out */ graphene_quaternion_init_from_matrix (rotate_r, &local); return true; } /** * graphene_matrix_interpolate: * @a: a #graphene_matrix_t * @b: a #graphene_matrix_t * @factor: the linear interpolation factor * @res: (out caller-allocates): return location for the * interpolated matrix * * Linearly interpolates the two given #graphene_matrix_t by * interpolating the decomposed transformations separately. * * If either matrix cannot be reduced to their transformations * then the interpolation cannot be performed, and this function * will return an identity matrix. * * Since: 1.0 */ void graphene_matrix_interpolate (const graphene_matrix_t *a, const graphene_matrix_t *b, double factor, graphene_matrix_t *res) { bool success = false; graphene_matrix_init_identity (res); /* Special case the decomposition if we're interpolating between two * affine transformations. */ if (graphene_matrix_is_2d (a) && graphene_matrix_is_2d (b)) { graphene_point_t translate_a = GRAPHENE_POINT_INIT (0.f, 0.f); graphene_point_t translate_b = GRAPHENE_POINT_INIT (0.f, 0.f); graphene_point_t translate_res; graphene_point_t scale_a = GRAPHENE_POINT_INIT (1.f, 1.f); graphene_point_t scale_b = GRAPHENE_POINT_INIT (1.f, 1.f); graphene_point_t scale_res; double rotate_a, rotate_b, rotate_res; float m_a[4], m_b[4], m_res[4]; float rot_sin, rot_cos; graphene_simd4x4f_t tmp_m; success |= matrix_decompose_2d (a, &translate_a, &scale_a, &rotate_a, m_a); success |= matrix_decompose_2d (b, &translate_b, &scale_b, &rotate_b, m_b); /* If we cannot decompose either matrix we bail out with an identity */ if (!success) return; /* Flip the scaling factor and angle so they are consistent */ if ((scale_a.x < 0 && scale_b.y < 0) || (scale_a.y < 0 && scale_b.x < 0)) { scale_a.x = -scale_a.x; scale_a.y = -scale_a.y; rotate_a += (rotate_a < 0) ? 180 : -180; } /* Do not rotate "the long way around" */ if (!rotate_a) rotate_a = 360; if (!rotate_b) rotate_b = 360; if (fabs (rotate_a - rotate_b) > 180) { if (rotate_a > rotate_b) rotate_a -= 360; else rotate_b -= 360; } graphene_point_interpolate (&translate_a, &translate_b, factor, &translate_res); graphene_point_interpolate (&scale_a, &scale_b, factor, &scale_res); rotate_res = graphene_lerp (rotate_a, rotate_b, factor); /* Interpolate each component of the (2,2) matrices */ { graphene_simd4f_t tmp_va = graphene_simd4f_init_4f (m_a); graphene_simd4f_t tmp_vb = graphene_simd4f_init_4f (m_b); graphene_simd4f_t tmp_vres = graphene_simd4f_interpolate (tmp_va, tmp_vb, factor); graphene_simd4f_dup_4f (tmp_vres, m_res); } /* Initialize using the transposed (2,2) matrix */ res->value.x = graphene_simd4f_init (m_res[M_11], m_res[M_21], 0.f, 0.f); res->value.y = graphene_simd4f_init (m_res[M_12], m_res[M_22], 0.f, 0.f); res->value.z = graphene_simd4f_init ( 0.f, 0.f, 1.f, 0.f); /* Translate */ res->value.w = graphene_simd4f_init (translate_res.x * m_res[M_11] + translate_res.y * m_res[M_21], translate_res.x * m_res[M_12] + translate_res.y * m_res[M_22], 0.f, 1.f); /* Rotate using a (2,2) rotation matrix */ graphene_sincos (GRAPHENE_DEG_TO_RAD (rotate_res), &rot_sin, &rot_cos); tmp_m = graphene_simd4x4f_init (graphene_simd4f_init (rot_cos, -rot_sin, 0.f, 0.f), graphene_simd4f_init (rot_sin, rot_cos, 0.f, 0.f), graphene_simd4f_init ( 0.f, 0.f, 1.f, 0.f), graphene_simd4f_init ( 0.f, 0.f, 0.f, 1.f)); graphene_simd4x4f_matrix_mul (&res->value, &tmp_m, &res->value); /* Scale */ graphene_simd4x4f_scale (&tmp_m, scale_res.x, scale_res.y, 1.f); graphene_simd4x4f_matrix_mul (&res->value, &tmp_m, &res->value); } else { graphene_point3d_t scale_a = { 1.f, 1.f, 1.f }, translate_a; graphene_quaternion_t rotate_a; float shear_a[3] = { 0.f, 0.f, 0.f }; graphene_point3d_t scale_b = { 1.f, 1.f, 1.f }, translate_b; graphene_quaternion_t rotate_b; float shear_b[3] = { 0.f, 0.f, 0.f }; graphene_point3d_t scale_r = { 1.f, 1.f, 1.f }, translate_r; graphene_quaternion_t rotate_r; float shear; graphene_vec4_t perspective_a; graphene_vec4_t perspective_b; graphene_simd4f_t tmp; success |= matrix_decompose_3d (a, &scale_a, shear_a, &rotate_a, &translate_a, &perspective_a); success |= matrix_decompose_3d (b, &scale_b, shear_b, &rotate_b, &translate_b, &perspective_b); /* If we cannot decompose either matrix we bail out with an identity */ if (!success) return; /* Interpolate the perspective row */ tmp = graphene_simd4f_interpolate (perspective_a.value, perspective_b.value, factor); res->value.x = graphene_simd4f_init (1.f, 0.f, 0.f, graphene_simd4f_get_x (tmp)); res->value.y = graphene_simd4f_init (0.f, 1.f, 0.f, graphene_simd4f_get_y (tmp)); res->value.z = graphene_simd4f_init (0.f, 0.f, 1.f, graphene_simd4f_get_z (tmp)); res->value.w = graphene_simd4f_init (0.f, 0.f, 0.f, graphene_simd4f_get_w (tmp)); /* Translate */ graphene_point3d_interpolate (&translate_a, &translate_b, factor, &translate_r); graphene_matrix_translate (res, &translate_r); /* Rotate */ graphene_quaternion_slerp (&rotate_a, &rotate_b, factor, &rotate_r); graphene_matrix_rotate_quaternion (res, &rotate_r); /* Skew */ shear = graphene_lerp (shear_a[YZ_SHEAR], shear_b[YZ_SHEAR], factor); if (!graphene_approx_val (shear, 0.f)) graphene_matrix_skew_yz (res, shear); shear = graphene_lerp (shear_a[XZ_SHEAR], shear_b[XZ_SHEAR], factor); if (!graphene_approx_val (shear, 0.f)) graphene_matrix_skew_xz (res, shear); shear = graphene_lerp (shear_a[XY_SHEAR], shear_b[XY_SHEAR], factor); if (!graphene_approx_val (shear, 0.f)) graphene_matrix_skew_xy (res, shear); /* Scale */ graphene_point3d_interpolate (&scale_a, &scale_b, factor, &scale_r); if (!graphene_approx_val (scale_r.x, 1.f) || !graphene_approx_val (scale_r.y, 1.f) || !graphene_approx_val (scale_r.z, 1.f)) graphene_matrix_scale (res, scale_r.x, scale_r.y, scale_r.z); } } #undef M_11 #undef M_12 #undef M_21 #undef M_22 #undef XY_SHEAR #undef XZ_SHEAR #undef YZ_SHEAR /** * graphene_matrix_print: * @m: The matrix to print * * Prints the contents of a matrix. * * Since: 1.0 */ void graphene_matrix_print (const graphene_matrix_t *m) { for (int i = 0; i < 4; i++) { fprintf (stderr, "| %+.6f %+.6f %+.6f %+.6f |\n", graphene_matrix_get_value (m, i, 0), graphene_matrix_get_value (m, i, 1), graphene_matrix_get_value (m, i, 2), graphene_matrix_get_value (m, i, 3)); } } graphene-1.8.0/src/graphene-matrix.h000066400000000000000000000453611324365266600173720ustar00rootroot00000000000000/* graphene-matrix.h: 4x4 matrix * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_MATRIX_H__ #define __GRAPHENE_MATRIX_H__ #include "graphene-types.h" GRAPHENE_BEGIN_DECLS /** * graphene_matrix_t: * * A structure capable of holding a 4x4 matrix. * * The contents of the #graphene_matrix_t structure are private and * should never be accessed directly. */ struct _graphene_matrix_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_simd4x4f_t, value); }; GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_free (graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_identity (graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_from_float (graphene_matrix_t *m, const float *v); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_from_vec4 (graphene_matrix_t *m, const graphene_vec4_t *v0, const graphene_vec4_t *v1, const graphene_vec4_t *v2, const graphene_vec4_t *v3); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_from_matrix (graphene_matrix_t *m, const graphene_matrix_t *src); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_perspective (graphene_matrix_t *m, float fovy, float aspect, float z_near, float z_far); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_ortho (graphene_matrix_t *m, float left, float right, float top, float bottom, float z_near, float z_far); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_look_at (graphene_matrix_t *m, const graphene_vec3_t *eye, const graphene_vec3_t *center, const graphene_vec3_t *up); GRAPHENE_AVAILABLE_IN_1_2 graphene_matrix_t * graphene_matrix_init_frustum (graphene_matrix_t *m, float left, float right, float bottom, float top, float z_near, float z_far); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_scale (graphene_matrix_t *m, float x, float y, float z); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_translate (graphene_matrix_t *m, const graphene_point3d_t *p); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_rotate (graphene_matrix_t *m, float angle, const graphene_vec3_t *axis); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_skew (graphene_matrix_t *m, float x_skew, float y_skew); GRAPHENE_AVAILABLE_IN_1_0 graphene_matrix_t * graphene_matrix_init_from_2d (graphene_matrix_t *m, double xx, double yx, double xy, double yy, double x_0, double y_0); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_matrix_is_identity (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_matrix_is_2d (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_matrix_is_backface_visible (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_matrix_is_singular (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_to_float (const graphene_matrix_t *m, float *v); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_matrix_to_2d (const graphene_matrix_t *m, double *xx, double *yx, double *xy, double *yy, double *x_0, double *y_0); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_get_row (const graphene_matrix_t *m, unsigned int index_, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_matrix_get_value (const graphene_matrix_t *m, unsigned int row, unsigned int col); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_multiply (const graphene_matrix_t *a, const graphene_matrix_t *b, graphene_matrix_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_matrix_determinant (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_transform_vec4 (const graphene_matrix_t *m, const graphene_vec4_t *v, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_transform_vec3 (const graphene_matrix_t *m, const graphene_vec3_t *v, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_transform_point (const graphene_matrix_t *m, const graphene_point_t *p, graphene_point_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_matrix_transform_point3d (const graphene_matrix_t *m, const graphene_point3d_t *p, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_transform_rect (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_quad_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_transform_bounds (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_matrix_transform_sphere (const graphene_matrix_t *m, const graphene_sphere_t *s, graphene_sphere_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_matrix_transform_box (const graphene_matrix_t *m, const graphene_box_t *b, graphene_box_t *res); GRAPHENE_AVAILABLE_IN_1_4 void graphene_matrix_transform_ray (const graphene_matrix_t *m, const graphene_ray_t *r, graphene_ray_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_project_point (const graphene_matrix_t *m, const graphene_point_t *p, graphene_point_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_project_rect_bounds (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_matrix_project_rect (const graphene_matrix_t *m, const graphene_rect_t *r, graphene_quad_t *res); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_matrix_untransform_point (const graphene_matrix_t *m, const graphene_point_t *p, const graphene_rect_t *bounds, graphene_point_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_untransform_bounds (const graphene_matrix_t *m, const graphene_rect_t *r, const graphene_rect_t *bounds, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_matrix_unproject_point3d (const graphene_matrix_t *projection, const graphene_matrix_t *modelview, const graphene_point3d_t *point, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_translate (graphene_matrix_t *m, const graphene_point3d_t *pos); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_rotate (graphene_matrix_t *m, float angle, const graphene_vec3_t *axis); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_rotate_x (graphene_matrix_t *m, float angle); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_rotate_y (graphene_matrix_t *m, float angle); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_rotate_z (graphene_matrix_t *m, float angle); GRAPHENE_AVAILABLE_IN_1_2 void graphene_matrix_rotate_quaternion (graphene_matrix_t *m, const graphene_quaternion_t *q); GRAPHENE_AVAILABLE_IN_1_2 void graphene_matrix_rotate_euler (graphene_matrix_t *m, const graphene_euler_t *e); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_scale (graphene_matrix_t *m, float factor_x, float factor_y, float factor_z); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_skew_xy (graphene_matrix_t *m, float factor); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_skew_xz (graphene_matrix_t *m, float factor); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_skew_yz (graphene_matrix_t *m, float factor); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_transpose (const graphene_matrix_t *m, graphene_matrix_t *res); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_matrix_inverse (const graphene_matrix_t *m, graphene_matrix_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_perspective (const graphene_matrix_t *m, float depth, graphene_matrix_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_normalize (const graphene_matrix_t *m, graphene_matrix_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_matrix_get_x_scale (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 float graphene_matrix_get_y_scale (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 float graphene_matrix_get_z_scale (const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_interpolate (const graphene_matrix_t *a, const graphene_matrix_t *b, double factor, graphene_matrix_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_matrix_print (const graphene_matrix_t *m); GRAPHENE_END_DECLS #endif /* __GRAPHENE_MATRIX_H__ */ graphene-1.8.0/src/graphene-plane.c000066400000000000000000000216231324365266600171530ustar00rootroot00000000000000/* graphene-plane.c: A plane in 3D space * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-plane * @Title: Plane * @Short_Description: A plane in 3D space * * #graphene_plane_t is a structure representing a plane in 3D space, using * a normal vector pointing towards the origin, and a constant distance from * the origin along the normal vector. */ #include "graphene-private.h" #include "graphene-plane.h" #include "graphene-alloc-private.h" #include "graphene-point3d.h" #include "graphene-vec3.h" #include "graphene-vec4.h" #include /** * graphene_plane_alloc: (constructor) * * Allocates a new #graphene_plane_t structure. * * The contents of the returned structure are undefined. * * Returns: (transfer full): the newly allocated #graphene_plane_t. * Use graphene_plane_free() to free the resources allocated by * this function * * Since: 1.2 */ graphene_plane_t * graphene_plane_alloc (void) { return graphene_aligned_alloc0 (sizeof (graphene_plane_t), 1, 16); } /** * graphene_plane_free: * @p: a #graphene_plane_t * * Frees the resources allocated by graphene_plane_alloc(). * * Since: 1.2 */ void graphene_plane_free (graphene_plane_t *p) { graphene_aligned_free (p); } /** * graphene_plane_init: * @p: the #graphene_plane_t to initialize * @normal: (nullable): a normal vector defining the plane pointing towards the origin * @constant: the negative distance from the origin to the plane along the * normal vector * * Initializes the given #graphene_plane_t using the given @normal vector * and @constant values. * * Returns: (transfer none): the initialized plane * * Since: 1.2 */ graphene_plane_t * graphene_plane_init (graphene_plane_t *p, const graphene_vec3_t *normal, float constant) { if (normal != NULL) graphene_vec3_init_from_vec3 (&p->normal, normal); else graphene_vec3_init_from_vec3 (&p->normal, graphene_vec3_x_axis ()); p->constant = constant; return p; } /** * graphene_plane_init_from_vec4: * @p: the #graphene_plane_t to initialize * @src: a #graphene_vec4_t containing the normal vector in its first * three components, and the distance in its fourth component * * Initializes the given #graphene_plane_t using the components of * the given #graphene_vec4_t vector. * * Returns: (transfer none): the initialized plane * * Since: 1.2 */ graphene_plane_t * graphene_plane_init_from_vec4 (graphene_plane_t *p, const graphene_vec4_t *src) { graphene_vec4_get_xyz (src, &p->normal); p->constant = graphene_vec4_get_w (src); return p; } /** * graphene_plane_init_from_plane: * @p: the #graphene_plane_t to initialize * @src: a #graphene_plane_t * * Initializes the given #graphene_plane_t using the normal * vector and constant of another #graphene_plane_t. * * Returns: (transfer none): the initialized plane * * Since: 1.2 */ graphene_plane_t * graphene_plane_init_from_plane (graphene_plane_t *p, const graphene_plane_t *src) { graphene_vec3_init_from_vec3 (&p->normal, &src->normal); p->constant = src->constant; return p; } /** * graphene_plane_init_from_point: * @p: the #graphene_plane_t to initialize * @normal: a normal vector defining the plane pointing towards the origin * @point: a #graphene_point3d_t * * Initializes the given #graphene_plane_t using the given normal vector * and an arbitrary co-planar point. * * Returns: (transfer none): the initialized plane * * Since: 1.2 */ graphene_plane_t * graphene_plane_init_from_point (graphene_plane_t *p, const graphene_vec3_t *normal, const graphene_point3d_t *point) { graphene_vec3_t v_p; graphene_vec3_init_from_vec3 (&p->normal, normal); graphene_point3d_to_vec3 (point, &v_p); p->constant = graphene_vec3_dot (&v_p, &p->normal) * -1; return p; } /** * graphene_plane_init_from_points: * @p: the #graphene_plane_t to initialize * @a: a #graphene_point3d_t * @b: a #graphene_point3d_t * @c: a #graphene_point3d_t * * Initializes the given #graphene_plane_t using the 3 provided co-planar * points. * * The winding order is counter-clockwise, and determines which direction * the normal vector will point. * * Returns: (transfer none): the initialized plane * * Since: 1.2 */ graphene_plane_t * graphene_plane_init_from_points (graphene_plane_t *p, const graphene_point3d_t *a, const graphene_point3d_t *b, const graphene_point3d_t *c) { graphene_vec3_t v_a, v_b, v_c; graphene_vec3_t v1, v2; graphene_vec3_t normal; graphene_point3d_to_vec3 (a, &v_a); graphene_point3d_to_vec3 (b, &v_b); graphene_point3d_to_vec3 (c, &v_c); graphene_vec3_subtract (&v_c, &v_b, &v1); graphene_vec3_subtract (&v_a, &v_b, &v2); graphene_vec3_cross (&v1, &v2, &normal); graphene_vec3_normalize (&normal, &normal); return graphene_plane_init_from_point (p, &normal, a); } /** * graphene_plane_normalize: * @p: a #graphene_plane_t * @res: (out caller-allocates): return location for the normalized plane * * Normalizes the vector and constant of a #graphene_plane_t. * * Since: 1.2 */ void graphene_plane_normalize (const graphene_plane_t *p, graphene_plane_t *res) { float normal_length = graphene_vec3_length (&p->normal); graphene_vec3_normalize (&p->normal, &res->normal); res->constant = p->constant / normal_length; } /** * graphene_plane_negate: * @p: a #graphene_plane_t * @res: (out caller-allocates): return location for the negated plane * * Negates the normal vector and constant of a #graphene_plane_t, effectively * mirroring the plane across the origin. * * Since: 1.2 */ void graphene_plane_negate (const graphene_plane_t *p, graphene_plane_t *res) { graphene_vec3_negate (&p->normal, &res->normal); res->constant = p->constant * -1.f; } /** * graphene_plane_distance: * @p: a #graphene_plane_t * @point: a #graphene_point3d_t * * Computes the distance of @point from a #graphene_plane_t. * * Returns: the distance of the given #graphene_point3d_t from the plane * * Since: 1.2 */ float graphene_plane_distance (const graphene_plane_t *p, const graphene_point3d_t *point) { graphene_vec3_t v; graphene_point3d_to_vec3 (point, &v); return graphene_vec3_dot (&p->normal, &v) + p->constant; } /** * graphene_plane_get_normal: * @p: a #graphene_plane_t * @normal: (out caller-allocates): return location for the normal vector * * Retrieves the normal vector pointing towards the origin of the * given #graphene_plane_t. * * Since: 1.2 */ void graphene_plane_get_normal (const graphene_plane_t *p, graphene_vec3_t *normal) { graphene_vec3_init_from_vec3 (normal, &p->normal); } /** * graphene_plane_get_constant: * @p: a #graphene_plane_t * * Retrieves the distance along the normal vector of the * given #graphene_plane_t from the origin. * * Returns: the constant value of the plane * * Since: 1.2 */ float graphene_plane_get_constant (const graphene_plane_t *p) { return p->constant; } static bool plane_equal (const void *p1, const void *p2) { const graphene_plane_t *a = p1; const graphene_plane_t *b = p2; return graphene_vec3_equal (&a->normal, &b->normal) && graphene_approx_val (a->constant, b->constant); } /** * graphene_plane_equal: * @a: a #graphene_plane_t * @b: a #graphene_plane_t * * Checks whether the two given #graphene_plane_t are equal. * * Returns: `true` if the given planes are equal * * Since: 1.2 */ bool graphene_plane_equal (const graphene_plane_t *a, const graphene_plane_t *b) { return graphene_pointer_equal (a, b, plane_equal); } graphene-1.8.0/src/graphene-plane.h000066400000000000000000000111711324365266600171550ustar00rootroot00000000000000/* graphene-plane.h: A plane in 3D space * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_PLANE_H__ #define __GRAPHENE_PLANE_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-vec3.h" GRAPHENE_BEGIN_DECLS /** * graphene_plane_t: * * A 2D plane that extends infinitely in a 3D volume. * * The contents of the `graphene_plane_t` are private, and should not be * modified directly. * * Since: 1.2 */ struct _graphene_plane_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, normal); GRAPHENE_PRIVATE_FIELD (float, constant); }; GRAPHENE_AVAILABLE_IN_1_2 graphene_plane_t * graphene_plane_alloc (void); GRAPHENE_AVAILABLE_IN_1_2 void graphene_plane_free (graphene_plane_t *p); GRAPHENE_AVAILABLE_IN_1_2 graphene_plane_t * graphene_plane_init (graphene_plane_t *p, const graphene_vec3_t *normal, float constant); GRAPHENE_AVAILABLE_IN_1_2 graphene_plane_t * graphene_plane_init_from_vec4 (graphene_plane_t *p, const graphene_vec4_t *src); GRAPHENE_AVAILABLE_IN_1_2 graphene_plane_t * graphene_plane_init_from_plane (graphene_plane_t *p, const graphene_plane_t *src); GRAPHENE_AVAILABLE_IN_1_2 graphene_plane_t * graphene_plane_init_from_point (graphene_plane_t *p, const graphene_vec3_t *normal, const graphene_point3d_t *point); GRAPHENE_AVAILABLE_IN_1_2 graphene_plane_t * graphene_plane_init_from_points (graphene_plane_t *p, const graphene_point3d_t *a, const graphene_point3d_t *b, const graphene_point3d_t *c); GRAPHENE_AVAILABLE_IN_1_2 void graphene_plane_normalize (const graphene_plane_t *p, graphene_plane_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_plane_negate (const graphene_plane_t *p, graphene_plane_t *res); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_plane_equal (const graphene_plane_t *a, const graphene_plane_t *b); GRAPHENE_AVAILABLE_IN_1_2 float graphene_plane_distance (const graphene_plane_t *p, const graphene_point3d_t *point); GRAPHENE_AVAILABLE_IN_1_2 void graphene_plane_get_normal (const graphene_plane_t *p, graphene_vec3_t *normal); GRAPHENE_AVAILABLE_IN_1_2 float graphene_plane_get_constant (const graphene_plane_t *p); GRAPHENE_END_DECLS #endif /* __GRAPHENE_PLANE_H__ */ graphene-1.8.0/src/graphene-point.c000066400000000000000000000173241324365266600172100ustar00rootroot00000000000000/* graphene-point.c: Point * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-point * @Title: Point * @short_description: A point with 2 coordinates * * #graphene_point_t is a data structure capable of describing a point with * two coordinates: * * * @graphene_point_t.x * * @graphene_point_t.y */ #include "graphene-private.h" #include "graphene-point.h" #include "graphene-simd4f.h" #include "graphene-vec2.h" #include /** * graphene_point_alloc: (constructor) * * Allocates a new #graphene_point_t structure. * * The coordinates of the returned point are (0, 0). * * It's possible to chain this function with graphene_point_init() * or graphene_point_init_from_point(), e.g.: * * |[ * graphene_point_t * * point_new (float x, float y) * { * return graphene_point_init (graphene_point_alloc (), x, y); * } * * graphene_point_t * * point_copy (const graphene_point_t *p) * { * return graphene_point_init_from_point (graphene_point_alloc (), p); * } * ]| * * Returns: (transfer full): the newly allocated #graphene_point_t. * Use graphene_point_free() to free the resources allocated by * this function. * * Since: 1.0 */ graphene_point_t * graphene_point_alloc (void) { return calloc (1, sizeof (graphene_point_t)); } /** * graphene_point_free: * @p: a #graphene_point_t * * Frees the resources allocated by graphene_point_alloc(). * * Since: 1.0 */ void graphene_point_free (graphene_point_t *p) { free (p); } /** * graphene_point_init: * @p: a #graphene_point_t * @x: the X coordinate * @y: the Y coordinate * * Initializes @p to the given @x and @y coordinates. * * It's safe to call this function multiple times. * * Returns: (transfer none): the initialized point * * Since: 1.0 */ graphene_point_t * graphene_point_init (graphene_point_t *p, float x, float y) { p->x = x; p->y = y; return p; } /** * graphene_point_init_from_point: * @p: a #graphene_point_t * @src: the #graphene_point_t to use * * Initializes @p with the same coordinates of @src. * * Returns: (transfer none): the initialized point * * Since: 1.0 */ graphene_point_t * graphene_point_init_from_point (graphene_point_t *p, const graphene_point_t *src) { *p = *src; return p; } /** * graphene_point_init_from_vec2: * @p: the #graphene_point_t to initialize * @src: a #graphene_vec2_t * * Initializes @p with the coordinates inside the given #graphene_vec2_t. * * Returns: (transfer none): the initialized point * * Since: 1.4 */ graphene_point_t * graphene_point_init_from_vec2 (graphene_point_t *p, const graphene_vec2_t *src) { p->x = graphene_simd4f_get_x (src->value); p->y = graphene_simd4f_get_y (src->value); return p; } static bool point_equal (const void *p1, const void *p2) { const graphene_point_t *a = p1; const graphene_point_t *b = p2; return graphene_point_near (a, b, GRAPHENE_FLOAT_EPSILON); } /** * graphene_point_equal: * @a: a #graphene_point_t * @b: a #graphene_point_t * * Checks if the two points @a and @b point to the same * coordinates. * * This function accounts for floating point fluctuations; if * you want to control the fuzziness of the match, you can use * graphene_point_near() instead. * * Returns: `true` if the points have the same coordinates * * Since: 1.0 */ bool graphene_point_equal (const graphene_point_t *a, const graphene_point_t *b) { return graphene_pointer_equal (a, b, point_equal); } /** * graphene_point_distance: * @a: a #graphene_point_t * @b: a #graphene_point_t * @d_x: (out) (optional): distance component on the X axis * @d_y: (out) (optional): distance component on the Y axis * * Computes the distance between @a and @b. * * Returns: the distance between the two points * * Since: 1.0 */ float graphene_point_distance (const graphene_point_t *a, const graphene_point_t *b, float *d_x, float *d_y) { if (a == b) return 0.f; graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, 0.f, 0.f); graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, 0.f, 0.f); graphene_simd4f_t v_res = graphene_simd4f_sub (v_a, v_b); if (d_x != NULL) *d_x = fabsf (graphene_simd4f_get_x (v_res)); if (d_y != NULL) *d_y = fabsf (graphene_simd4f_get_y (v_res)); return graphene_simd4f_get_x (graphene_simd4f_length2 (v_res)); } /** * graphene_point_near: * @a: a #graphene_point_t * @b: a #graphene_point_t * @epsilon: threshold between the two points * * Checks whether the two points @a and @b are within * the threshold of @epsilon. * * Returns: `true` if the distance is within @epsilon * * Since: 1.0 */ bool graphene_point_near (const graphene_point_t *a, const graphene_point_t *b, float epsilon) { if (a == b) return true; graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, 0.f, 0.f); graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, 0.f, 0.f); graphene_simd4f_t v_res = graphene_simd4f_sub (v_a, v_b); return fabsf (graphene_simd4f_get_x (v_res)) < epsilon && fabsf (graphene_simd4f_get_y (v_res)) < epsilon; } /** * graphene_point_interpolate: * @a: a #graphene_point_t * @b: a #graphene_point_t * @factor: the linear interpolation factor * @res: (out caller-allocates): return location for the interpolated * point * * Linearly interpolates the coordinates of @a and @b using the * given @factor. * * Since: 1.0 */ void graphene_point_interpolate (const graphene_point_t *a, const graphene_point_t *b, double factor, graphene_point_t *res) { res->x = graphene_lerp (a->x, b->x, factor); res->y = graphene_lerp (a->y, b->y, factor); } /** * graphene_point_to_vec2: * @p: a #graphene_point_t * @v: (out caller-allocates): return location for the vertex * * Stores the coordinates of the given #graphene_point_t into a * #graphene_vec2_t. * * Since: 1.4 */ void graphene_point_to_vec2 (const graphene_point_t *p, graphene_vec2_t *v) { v->value = graphene_simd4f_init (p->x, p->y, 0.f, 0.f); } static const graphene_point_t _graphene_point_zero; /** * graphene_point_zero: * * Returns a point fixed at (0, 0). * * Returns: (transfer none): a fixed point * * Since: 1.0 */ const graphene_point_t * graphene_point_zero (void) { return &_graphene_point_zero; } graphene-1.8.0/src/graphene-point.h000066400000000000000000000113001324365266600172010ustar00rootroot00000000000000/* graphene-point.h: Point and Size * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_POINT_H__ #define __GRAPHENE_POINT_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" GRAPHENE_BEGIN_DECLS /** * GRAPHENE_POINT_INIT: * @_x: the X coordinate * @_y: the Y coordinate * * Initializes a #graphene_point_t with the given coordinates * when declaring it, e.g: * * |[ * graphene_point_t p = GRAPHENE_POINT_INIT (10.f, 10.f); * ]| * * Since: 1.0 */ #define GRAPHENE_POINT_INIT(_x,_y) (graphene_point_t) { .x = (_x), .y = (_y) } /** * GRAPHENE_POINT_INIT_ZERO: * * Initializes a #graphene_point_t to (0, 0) when declaring it. * * Since: 1.0 */ #define GRAPHENE_POINT_INIT_ZERO GRAPHENE_POINT_INIT (0.f, 0.f) /** * graphene_point_t: * @x: the X coordinate of the point * @y: the Y coordinate of the point * * A point with two coordinates. * * Since: 1.0 */ struct _graphene_point_t { float x; float y; }; GRAPHENE_AVAILABLE_IN_1_0 graphene_point_t * graphene_point_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point_free (graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_0 graphene_point_t * graphene_point_init (graphene_point_t *p, float x, float y); GRAPHENE_AVAILABLE_IN_1_0 graphene_point_t * graphene_point_init_from_point (graphene_point_t *p, const graphene_point_t *src); GRAPHENE_AVAILABLE_IN_1_4 graphene_point_t * graphene_point_init_from_vec2 (graphene_point_t *p, const graphene_vec2_t *src); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_point_equal (const graphene_point_t *a, const graphene_point_t *b); GRAPHENE_AVAILABLE_IN_1_0 float graphene_point_distance (const graphene_point_t *a, const graphene_point_t *b, float *d_x, float *d_y); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_point_near (const graphene_point_t *a, const graphene_point_t *b, float epsilon); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point_interpolate (const graphene_point_t *a, const graphene_point_t *b, double factor, graphene_point_t *res); GRAPHENE_AVAILABLE_IN_1_4 void graphene_point_to_vec2 (const graphene_point_t *p, graphene_vec2_t *v); GRAPHENE_AVAILABLE_IN_1_0 const graphene_point_t * graphene_point_zero (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_POINT_H__ */ graphene-1.8.0/src/graphene-point3d.c000066400000000000000000000305541324365266600174370ustar00rootroot00000000000000/* graphene-point3d.c: Point in 3D space * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-point3d * @Title: Point3D * @Short_Description: A point with 3 coordinates * * #graphene_point3d_t is a data structure capable of describing a point with * three coordinates: * * * @graphene_point3d_t.x * * @graphene_point3d_t.y * * @graphene_point3d_t.z */ #include "graphene-private.h" #include "graphene-point3d.h" #include "graphene-rect.h" #include "graphene-simd4f.h" #include "graphene-vec3.h" #include /** * graphene_point3d_alloc: (constructor) * * Allocates a #graphene_point3d_t structure. * * Returns: (transfer full): the newly allocated structure. * Use graphene_point3d_free() to free the resources * allocated by this function. * * Since: 1.0 */ graphene_point3d_t * graphene_point3d_alloc (void) { return calloc (1, sizeof (graphene_point3d_t)); } /** * graphene_point3d_free: * @p: a #graphene_point3d_t * * Frees the resources allocated via graphene_point3d_alloc(). * * Since: 1.0 */ void graphene_point3d_free (graphene_point3d_t *p) { free (p); } /** * graphene_point3d_init: * @p: the #graphene_point3d_t to initialize * @x: the X coordinate of the point * @y: the Y coordinate of the point * @z: the Z coordinate of the point * * Initializes a #graphene_point3d_t with the given coordinates. * * Returns: (transfer none): the initialized #graphene_point3d_t * * Since: 1.0 */ graphene_point3d_t * graphene_point3d_init (graphene_point3d_t *p, float x, float y, float z) { p->x = x; p->y = y; p->z = z; return p; } static inline graphene_point3d_t * graphene_point3d_init_from_simd4f (graphene_point3d_t *p, const graphene_simd4f_t v) { /* XXX: Apparently clang 3.4 does not allow vectorised partial reads * when using a pointer to a structure; this is possibly caused by some * of the optimization flags we use, which means we need this ugly * compiler check here. Clang 3.5 and GCC are perfectly happy with it, * but Travis-CI still uses Clang 3.4. */ #if defined(__clang__) && __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 5) p->x = graphene_simd4f_get (v, 0); p->y = graphene_simd4f_get (v, 1); p->z = graphene_simd4f_get (v, 2); #else graphene_simd4f_dup_3f (v, &(p->x)); #endif return p; } /** * graphene_point3d_init_from_point: * @p: a #graphene_point3d_t * @src: a #graphene_point3d_t * * Initializes a #graphene_point3d_t using the coordinates of * another #graphene_point3d_t. * * Returns: (transfer none): the initialized point * * Since: 1.0 */ graphene_point3d_t * graphene_point3d_init_from_point (graphene_point3d_t *p, const graphene_point3d_t *src) { *p = *src; return p; } /** * graphene_point3d_init_from_vec3: * @p: a #graphene_point3d_t * @v: a #graphene_vec3_t * * Initializes a #graphene_point3d_t using the components * of a #graphene_vec3_t. * * Returns: (transfer none): the initialized #graphene_point3d_t * * Since: 1.0 */ graphene_point3d_t * graphene_point3d_init_from_vec3 (graphene_point3d_t *p, const graphene_vec3_t *v) { return graphene_point3d_init_from_simd4f (p, v->value); } /** * graphene_point3d_to_vec3: * @p: a #graphene_point3d_t * @v: (out caller-allocates): return location for a #graphene_vec3_t * * Stores the coordinates of a #graphene_point3d_t into a * #graphene_vec3_t. * * Since: 1.0 */ void graphene_point3d_to_vec3 (const graphene_point3d_t *p, graphene_vec3_t *v) { v->value = graphene_simd4f_init (p->x, p->y, p->z, 0.f); } static bool point3d_equal (const void *p1, const void *p2) { const graphene_point3d_t *a = p1; const graphene_point3d_t *b = p2; return graphene_point3d_near (a, b, GRAPHENE_FLOAT_EPSILON); } /** * graphene_point3d_equal: * @a: a #graphene_point3d_t * @b: a #graphene_point3d_t * * Checks whether two given points are equal. * * Returns: `true` if the points are equal * * Since: 1.0 */ bool graphene_point3d_equal (const graphene_point3d_t *a, const graphene_point3d_t *b) { return graphene_pointer_equal (a, b, point3d_equal); } /** * graphene_point3d_near: * @a: a #graphene_point3d_t * @b: a #graphene_point3d_t * @epsilon: fuzzyness factor * * Checks whether the two points are near each other, within * an @epsilon factor. * * Returns: `true` if the points are near each other * * Since: 1.0 */ bool graphene_point3d_near (const graphene_point3d_t *a, const graphene_point3d_t *b, float epsilon) { if (a == b) return true; graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, a->z, 0.f); graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, b->z, 0.f); graphene_simd4f_t v_res = graphene_simd4f_sub (v_a, v_b); return fabsf (graphene_simd4f_get_x (v_res)) < epsilon && fabsf (graphene_simd4f_get_y (v_res)) < epsilon && fabsf (graphene_simd4f_get_z (v_res)) < epsilon; } /** * graphene_point3d_scale: * @p: a #graphene_point3d_t * @factor: the scaling factor * @res: (out caller-allocates): return location for the scaled point * * Scales the coordinates of the given #graphene_point3d_t by * the given @factor. * * Since: 1.0 */ void graphene_point3d_scale (const graphene_point3d_t *p, float factor, graphene_point3d_t *res) { graphene_simd4f_t v; v = graphene_simd4f_init (p->x, p->y, p->z, 0.f); v = graphene_simd4f_mul (v, graphene_simd4f_splat (factor)); graphene_point3d_init_from_simd4f (res, v); } /** * graphene_point3d_cross: * @a: a #graphene_point3d_t * @b: a #graphene_point3d_t * @res: (out caller-allocates): return location for the cross * product * * Computes the cross product of the two given #graphene_point3d_t. * * Since: 1.0 */ void graphene_point3d_cross (const graphene_point3d_t *a, const graphene_point3d_t *b, graphene_point3d_t *res) { graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, a->z, 0.f); graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, b->z, 0.f); graphene_simd4f_t v_res = graphene_simd4f_cross3 (v_a, v_b); graphene_point3d_init_from_simd4f (res, v_res); } /** * graphene_point3d_dot: * @a: a #graphene_point3d_t * @b: a #graphene_point3d_t * * Computes the dot product of the two given #graphene_point3d_t. * * Returns: the value of the dot product * * Since: 1.0 */ float graphene_point3d_dot (const graphene_point3d_t *a, const graphene_point3d_t *b) { graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, a->z, 0.f); graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, b->z, 0.f); return graphene_simd4f_dot3_scalar (v_a, v_b); } /** * graphene_point3d_length: * @p: a #graphene_point3d_t * * Computes the length of the vector represented by the * coordinates of the given #graphene_point3d_t. * * Returns: the length of the vector represented by the point * * Since: 1.0 */ float graphene_point3d_length (const graphene_point3d_t *p) { graphene_simd4f_t res = graphene_simd4f_init (p->x, p->y, p->z, 0.f); return graphene_simd4f_get_x (graphene_simd4f_length3 (res)); } /** * graphene_point3d_normalize: * @p: a #graphene_point3d_t * @res: (out caller-allocates): return location for the normalized * #graphene_point3d_t * * Computes the normalization of the vector represented by the * coordinates of the given #graphene_point3d_t. * * Since: 1.0 */ void graphene_point3d_normalize (const graphene_point3d_t *p, graphene_point3d_t *res) { graphene_simd4f_t v; v = graphene_simd4f_init (p->x, p->y, p->z, 0.f); v = graphene_simd4f_normalize3 (v); graphene_point3d_init_from_simd4f (res, v); } /** * graphene_point3d_distance: * @a: a #graphene_point3d_t * @b: a #graphene_point3d_t * @delta: (out caller-allocates) (optional): return location for the distance * components on the X, Y, and Z axis * * Computes the distance between the two given #graphene_point3d_t. * * Returns: the distance between two points * * Since: 1.4 */ float graphene_point3d_distance (const graphene_point3d_t *a, const graphene_point3d_t *b, graphene_vec3_t *delta) { graphene_vec3_t v_a, v_b, res; graphene_point3d_to_vec3 (a, &v_a); graphene_point3d_to_vec3 (b, &v_b); graphene_vec3_subtract (&v_a, &v_b, &res); if (delta != NULL) { graphene_vec3_init (delta, fabsf (graphene_vec3_get_x (&res)), fabsf (graphene_vec3_get_y (&res)), fabsf (graphene_vec3_get_z (&res))); } return graphene_vec3_length (&res); } /** * graphene_point3d_interpolate: * @a: a #graphene_point3d_t * @b: a #graphene_point3d_t * @factor: the interpolation factor * @res: (out caller-allocates): the return location for the * interpolated #graphene_point3d_t * * Linearly interpolates each component of @a and @b using the * provided @factor, and places the result in @res. * * Since: 1.0 */ void graphene_point3d_interpolate (const graphene_point3d_t *a, const graphene_point3d_t *b, double factor, graphene_point3d_t *res) { res->x = graphene_lerp (a->x, b->x, factor); res->y = graphene_lerp (a->y, b->y, factor); res->z = graphene_lerp (a->z, b->z, factor); } /** * graphene_point3d_normalize_viewport: * @p: a #graphene_point3d_t * @viewport: a #graphene_rect_t representing a viewport * @z_near: the coordinate of the near clipping plane, or 0 for * the default near clipping plane * @z_far: the coordinate of the far clipping plane, or 1 for the * default far clipping plane * @res: (out caller-allocates): the return location for the * normalized #graphene_point3d_t * * Normalizes the coordinates of a #graphene_point3d_t using the * given viewport and clipping planes. * * The coordinates of the resulting #graphene_point3d_t will be * in the [ -1, 1 ] range. * * Since: 1.4 */ void graphene_point3d_normalize_viewport (const graphene_point3d_t *p, const graphene_rect_t *viewport, float z_near, float z_far, graphene_point3d_t *res) { res->x = (p->x - viewport->origin.x) / viewport->size.width; res->y = (p->y - viewport->origin.y) / viewport->size.height; res->z = (p->z - z_near) / (z_far - z_near); res->x = CLAMP (res->x * 2.f - 1.f, -1.f, 1.f); res->y = CLAMP (res->y * 2.f - 1.f, -1.f, 1.f); res->z = CLAMP (res->z * 2.f - 1.f, -1.f, 1.f); } static const graphene_point3d_t _graphene_point3d_zero; /** * graphene_point3d_zero: * * Retrieves a constant point with all three coordinates set to 0. * * Returns: (transfer none): a zero point * * Since: 1.0 */ const graphene_point3d_t * graphene_point3d_zero (void) { return &_graphene_point3d_zero; } graphene-1.8.0/src/graphene-point3d.h000066400000000000000000000153071324365266600174430ustar00rootroot00000000000000/* graphene-point3d.h: Point in 3D space * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_POINT3D_H__ #define __GRAPHENE_POINT3D_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" GRAPHENE_BEGIN_DECLS /** * GRAPHENE_POINT3D_INIT: * @_x: the X coordinate * @_y: the Y coordinate * @_z: the Z coordinate * * Initializes a #graphene_point3d_t to the given coordinates when declaring it. * * Since: 1.0 */ #define GRAPHENE_POINT3D_INIT(_x,_y,_z) (graphene_point3d_t) { .x = (_x), .y = (_y), .z = (_z) } /** * GRAPHENE_POINT3D_INIT_ZERO: * * Initializes a #graphene_point3d_t to (0, 0, 0) when declaring it. * * Since: 1.0 */ #define GRAPHENE_POINT3D_INIT_ZERO GRAPHENE_POINT3D_INIT (0.f, 0.f, 0.f) /** * graphene_point3d_t: * @x: the X coordinate * @y: the Y coordinate * @z: the Z coordinate * * A point with three components: X, Y, and Z. * * Since: 1.0 */ struct _graphene_point3d_t { float x; float y; float z; }; GRAPHENE_AVAILABLE_IN_1_0 graphene_point3d_t * graphene_point3d_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point3d_free (graphene_point3d_t *p); GRAPHENE_AVAILABLE_IN_1_0 graphene_point3d_t * graphene_point3d_init (graphene_point3d_t *p, float x, float y, float z); GRAPHENE_AVAILABLE_IN_1_0 graphene_point3d_t * graphene_point3d_init_from_point (graphene_point3d_t *p, const graphene_point3d_t *src); GRAPHENE_AVAILABLE_IN_1_0 graphene_point3d_t * graphene_point3d_init_from_vec3 (graphene_point3d_t *p, const graphene_vec3_t *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point3d_to_vec3 (const graphene_point3d_t *p, graphene_vec3_t *v); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_point3d_equal (const graphene_point3d_t *a, const graphene_point3d_t *b); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_point3d_near (const graphene_point3d_t *a, const graphene_point3d_t *b, float epsilon); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point3d_scale (const graphene_point3d_t *p, float factor, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point3d_cross (const graphene_point3d_t *a, const graphene_point3d_t *b, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_point3d_dot (const graphene_point3d_t *a, const graphene_point3d_t *b); GRAPHENE_AVAILABLE_IN_1_0 float graphene_point3d_length (const graphene_point3d_t *p); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point3d_normalize (const graphene_point3d_t *p, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_4 float graphene_point3d_distance (const graphene_point3d_t *a, const graphene_point3d_t *b, graphene_vec3_t *delta); GRAPHENE_AVAILABLE_IN_1_0 void graphene_point3d_interpolate (const graphene_point3d_t *a, const graphene_point3d_t *b, double factor, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_4 void graphene_point3d_normalize_viewport (const graphene_point3d_t *p, const graphene_rect_t *viewport, float z_near, float z_far, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_0 const graphene_point3d_t * graphene_point3d_zero (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_POINT3D_H__ */ graphene-1.8.0/src/graphene-private.h000066400000000000000000000115261324365266600175340ustar00rootroot00000000000000/* graphene-private.h: Private header * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_PRIVATE_H__ #define __GRAPHENE_PRIVATE_H__ #include "config.h" #include "graphene-macros.h" #include #include #include #define GRAPHENE_FLOAT_EPSILON FLT_EPSILON #ifndef MIN # if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) # define MIN(a,b) \ __extension__({ \ __auto_type _a = (a); \ __auto_type _b = (b); \ _a < _b ? _a : _b; \ }) # else # define MIN(a,b) ((a) < (b) ? (a) : (b)) # endif #endif #ifndef MAX # if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) # define MAX(a,b) \ __extension__({ \ __auto_type _a = (a); \ __auto_type _b = (b); \ _a > _b ? _a : _b; \ }) # else # define MAX(a,b) ((a) > (b) ? (a) : (b)) # endif #endif #ifndef CLAMP # if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) # define CLAMP(v,min,max) \ __extension__({ \ __auto_type _v = (v); \ __auto_type _min = (min); \ __auto_type _max = (max); \ _v < _min ? _min : (_v > _max ? _max : _v); \ }) # else # define CLAMP(v,min,max) ((v) < (min) ? (min) : ((v) > (max) ? (max) : (v))) # endif #endif #if defined(__GNUC__) && __GNUC__ > 3 # define likely(x) (__builtin_expect((x) ? 1 : 0, 1)) # define unlikely(x) (__builtin_expect((x) ? 1 : 0, 0)) #else # define likely(x) (x) # define unlikely(x) (x) #endif #define GRAPHENE_DEG_TO_RAD(x) ((x) * (GRAPHENE_PI / 180.f)) #define GRAPHENE_RAD_TO_DEG(x) ((x) * (180.f / GRAPHENE_PI)) #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* Use typeof on GCC */ # define graphene_fuzzy_equals(n1,n2,epsilon) \ __extension__({ \ __auto_type _n1 = (n1); \ __auto_type _n2 = (n2); \ __auto_type _epsilon = (epsilon); \ (bool) ((_n1 > _n2 ? (_n1 - _n2) : (_n2 - _n1)) < _epsilon); \ }) #else /* fallback for Visual Studio, typeof not supported */ # define graphene_fuzzy_equals(n1,n2,epsilon) \ (((n1) > (n2) ? ((n1) - (n2)) : ((n2) - (n1))) < (epsilon)) #endif /* __GNUC__ */ static inline bool graphene_approx_val (float a, float b) { return graphene_fuzzy_equals (a, b, FLT_EPSILON); } static inline float graphene_flerpf (float a, float b, double factor) { return (float) ((1.0 - factor) * (double) a) + (factor * (double) b); } static inline double graphene_flerp (double a, double b, double factor) { return ((1.0 - factor) * a) + (factor * b); } static inline int graphene_ilerp (int a, int b, double factor) { return (int) (((1.0 - factor) * (double) a) + (factor * (double) b)); } #if defined(__GNUC__) && \ ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \ (__STDC_VERSION__ >= 201112L || !defined(__STRICT_ANSI__)) && \ !defined(__cplusplus) # define USE_C11_GENERIC 1 #endif #ifdef USE_C11_GENERIC # define graphene_lerp(a,b,f) \ _Generic((a), \ double: graphene_flerp, \ float: graphene_flerpf, \ int: graphene_ilerp, \ default: graphene_flerp) ((a), (b), (f)) #else # define graphene_lerp graphene_flerp #endif static inline void graphene_sincos (float angle, float *sin_out, float *cos_out) { #ifdef HAVE_SINCOSF sincosf (angle, sin_out, cos_out); #else if (sin_out != NULL) *sin_out = sinf (angle); if (cos_out != NULL) *cos_out = cosf (angle); #endif /* HAVE_SINCOSF */ } typedef bool (* graphene_compare_func_t) (const void *p1, const void *p2); static inline bool graphene_pointer_equal (const void *p1, const void *p2, graphene_compare_func_t func) { if (p1 == p2) return true; if (p1 == NULL || p2 == NULL) return false; if (func == NULL) return true; return func (p1, p2); } #endif /* __GRAPHENE_PRIVATE_H__ */ graphene-1.8.0/src/graphene-quad.c000066400000000000000000000142011324365266600170000ustar00rootroot00000000000000/* graphene-quad.c: Quad * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-quad * @title: Quad * @short_description: Four-vertex quadrilateral * * A #graphene_quad_t represents a coplanar, four vertex quadrilateral shape. */ #include "graphene-private.h" #include "graphene-quad.h" #include "graphene-line-segment-private.h" #include "graphene-rect.h" #include "graphene-simd4f.h" #include /** * graphene_quad_alloc: (constructor) * * Allocates a new #graphene_quad_t instance. * * The contents of the returned instance are undefined. * * Returns: (transfer full): the newly created #graphene_quad_t instance * * Since: 1.0 */ graphene_quad_t * graphene_quad_alloc (void) { return calloc (1, sizeof (graphene_quad_t)); } /** * graphene_quad_free: * @q: a #graphene_quad_t * * Frees the resources allocated by graphene_quad_alloc() * * Since: 1.0 */ void graphene_quad_free (graphene_quad_t *q) { free (q); } /** * graphene_quad_init: * @q: the #graphene_quad_t to initialize * @p1: the first point of the quadrilateral * @p2: the second point of the quadrilateral * @p3: the third point of the quadrilateral * @p4: the fourth point of the quadrilateral * * Initializes a #graphene_quad_t with the given points. * * Returns: (transfer none): the initialized #graphene_quad_t * * Since: 1.0 */ graphene_quad_t * graphene_quad_init (graphene_quad_t *q, const graphene_point_t *p1, const graphene_point_t *p2, const graphene_point_t *p3, const graphene_point_t *p4) { q->points[0] = *p1; q->points[1] = *p2; q->points[2] = *p3; q->points[3] = *p4; return q; } /** * graphene_quad_init_from_rect: * @q: the #graphene_quad_t to initialize * @r: a #graphene_rect_t * * Initializes a #graphene_quad_t using the four corners of the * given #graphene_rect_t. * * Returns: (transfer none): the initialized #graphene_quad_t * * Since: 1.0 */ graphene_quad_t * graphene_quad_init_from_rect (graphene_quad_t *q, const graphene_rect_t *r) { graphene_rect_get_top_left (r, &(q->points[0])); graphene_rect_get_top_right (r, &(q->points[1])); graphene_rect_get_bottom_right (r, &(q->points[2])); graphene_rect_get_bottom_left (r, &(q->points[3])); return q; } /** * graphene_quad_init_from_points: * @q: the #graphene_quad_t to initialize * @points: (array fixed-size=4): an array of 4 #graphene_point_t * * Initializes a #graphene_quad_t using an array of points. * * Returns: (transfer none): the initialized #graphene_quad_t * * Since: 1.2 */ graphene_quad_t * graphene_quad_init_from_points (graphene_quad_t *q, const graphene_point_t points[]) { memcpy (q->points, points, sizeof (graphene_point_t) * 4); return q; } /** * graphene_quad_contains: * @q: a #graphene_quad_t * @p: a #graphene_point_t * * Checks if the given #graphene_quad_t contains the given #graphene_point_t. * * Returns: `true` if the point is inside the #graphene_quad_t * * Since: 1.0 */ bool graphene_quad_contains (const graphene_quad_t *q, const graphene_point_t *p) { graphene_line_segment_t l1, l2, l3, l4; l1 = graphene_line_segment_init (&q->points[0], &q->points[1]); l2 = graphene_line_segment_init (&q->points[1], &q->points[2]); l3 = graphene_line_segment_init (&q->points[2], &q->points[3]); l4 = graphene_line_segment_init (&q->points[3], &q->points[0]); return graphene_line_segment_points_on_same_side (l1, p, &(q->points[2])) && graphene_line_segment_points_on_same_side (l2, p, &(q->points[3])) && graphene_line_segment_points_on_same_side (l3, p, &(q->points[0])) && graphene_line_segment_points_on_same_side (l4, p, &(q->points[1])); } /** * graphene_quad_bounds: * @q: a #graphene_quad_t * @r: (out caller-allocates): return location for a #graphene_rect_t * * Computes the bounding rectangle of @q and places it into @r. * * Since: 1.0 */ void graphene_quad_bounds (const graphene_quad_t *q, graphene_rect_t *r) { graphene_simd4f_t vx, vy; float min_x, max_x; float min_y, max_y; vx = graphene_simd4f_init (q->points[0].x, q->points[1].x, q->points[2].x, q->points[3].x); vy = graphene_simd4f_init (q->points[0].y, q->points[1].y, q->points[2].y, q->points[3].y); min_x = graphene_simd4f_get_x (graphene_simd4f_min_val (vx)); min_y = graphene_simd4f_get_x (graphene_simd4f_min_val (vy)); max_x = graphene_simd4f_get_x (graphene_simd4f_max_val (vx)); max_y = graphene_simd4f_get_x (graphene_simd4f_max_val (vy)); graphene_rect_init (r, min_x, min_y, max_x - min_x, max_y - min_y); } /** * graphene_quad_get_point: * @q: a #graphene_quad_t * @index_: the index of the point to retrieve * * Retrieves the point of a #graphene_quad_t at the given index. * * Returns: (transfer none): a #graphene_point_t * * Since: 1.0 */ const graphene_point_t * graphene_quad_get_point (const graphene_quad_t *q, unsigned int index_) { return &q->points[index_]; } graphene-1.8.0/src/graphene-quad.h000066400000000000000000000063361324365266600170170ustar00rootroot00000000000000/* graphene-quad.h: Quad * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_QUAD_H__ #define __GRAPHENE_QUAD_H__ #include "graphene-types.h" #include "graphene-point.h" GRAPHENE_BEGIN_DECLS /** * graphene_quad_t: * * A 4 vertex quadrilateral, as represented by four #graphene_point_t. * * The contents of a #graphene_quad_t are private and should never be * accessed directly. * * Since: 1.0 */ struct _graphene_quad_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_point_t, points[4]); }; GRAPHENE_AVAILABLE_IN_1_0 graphene_quad_t * graphene_quad_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quad_free (graphene_quad_t *q); GRAPHENE_AVAILABLE_IN_1_0 graphene_quad_t * graphene_quad_init (graphene_quad_t *q, const graphene_point_t *p1, const graphene_point_t *p2, const graphene_point_t *p3, const graphene_point_t *p4); GRAPHENE_AVAILABLE_IN_1_0 graphene_quad_t * graphene_quad_init_from_rect (graphene_quad_t *q, const graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_2 graphene_quad_t * graphene_quad_init_from_points (graphene_quad_t *q, const graphene_point_t points[]); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_quad_contains (const graphene_quad_t *q, const graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quad_bounds (const graphene_quad_t *q, graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_0 const graphene_point_t *graphene_quad_get_point (const graphene_quad_t *q, unsigned int index_); GRAPHENE_END_DECLS #endif /* __GRAPHENE_QUAD_H__ */ graphene-1.8.0/src/graphene-quaternion.c000066400000000000000000000502531324365266600202420ustar00rootroot00000000000000/* graphene-quaternion.c: Quaternion * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-quaternion * @title: Quaternion * @short_description: Quaternion operations * * Quaternions are a mathematical entity that can be used to represent * rotation transformations in 3D space; unlike the usual Euler representation * with roll, pitch, and yaw, quaternions do not suffer from the so-called * ["Gimbal Lock"](http://en.wikipedia.org/wiki/Gimbal_lock) problem. * * See also: #graphene_euler_t */ #include "graphene-private.h" #include "graphene-quaternion.h" #include "graphene-euler.h" #include "graphene-matrix.h" #include "graphene-point3d.h" #include "graphene-simd4f.h" #include "graphene-simd4x4f.h" #include "graphene-vec3.h" #include "graphene-vec4.h" #include /** * graphene_quaternion_alloc: (constructor) * * Allocates a new #graphene_quaternion_t. * * The contents of the returned value are undefined. * * Returns: (transfer full): the newly allocated #graphene_quaternion_t * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_alloc (void) { return calloc (1, sizeof (graphene_quaternion_t)); } /** * graphene_quaternion_free: * @q: a #graphene_quaternion_t * * Releases the resources allocated by graphene_quaternion_alloc(). * * Since: 1.0 */ void graphene_quaternion_free (graphene_quaternion_t *q) { free (q); } /** * graphene_quaternion_init: * @q: a #graphene_quaternion_t * @x: the first component of the quaternion * @y: the second component of the quaternion * @z: the third component of the quaternion * @w: the fourth component of the quaternion * * Initializes a #graphene_quaternion_t using the given four values. * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init (graphene_quaternion_t *q, float x, float y, float z, float w) { q->x = x; q->y = y; q->z = z; q->w = w; return q; } /** * graphene_quaternion_init_identity: * @q: a #graphene_quaternion_t * * Initializes a #graphene_quaternion_t using the identity * transformation. * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init_identity (graphene_quaternion_t *q) { q->x = q->y = q->z = 0.f; q->w = 1.f; return q; } /** * graphene_quaternion_init_from_quaternion: * @q: a #graphene_quaternion_t * @src: a #graphene_quaternion_t * * Initializes a #graphene_quaternion_t with the values from @src. * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init_from_quaternion (graphene_quaternion_t *q, const graphene_quaternion_t *src) { *q = *src; return q; } static graphene_quaternion_t * graphene_quaternion_init_from_simd4f (graphene_quaternion_t *q, graphene_simd4f_t v) { graphene_simd4f_dup_4f (v, (float *) q); return q; } /** * graphene_quaternion_init_from_vec4: * @q: a #graphene_quaternion_t * @src: a #graphene_vec4_t * * Initializes a #graphene_quaternion_t with the values from @src. * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init_from_vec4 (graphene_quaternion_t *q, const graphene_vec4_t *src) { return graphene_quaternion_init_from_simd4f (q, src->value); } /** * graphene_quaternion_to_vec4: * @q: a #graphene_quaternion_t * @res: (out caller-allocates): return location for a * #graphene_vec4_t * * Copies the components of a #graphene_quaternion_t into a * #graphene_vec4_t. * * Since: 1.0 */ void graphene_quaternion_to_vec4 (const graphene_quaternion_t *q, graphene_vec4_t *res) { res->value = graphene_simd4f_init (q->x, q->y, q->z, q->w); } /** * graphene_quaternion_init_from_matrix: * @q: a #graphene_quaternion_t * @m: a #graphene_matrix_t * * Initializes a #graphene_quaternion_t using the rotation components * of a transformation matrix. * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init_from_matrix (graphene_quaternion_t *q, const graphene_matrix_t *m) { float xx = graphene_matrix_get_value (m, 0, 0); float yy = graphene_matrix_get_value (m, 1, 1); float zz = graphene_matrix_get_value (m, 2, 2); q->w = 0.5f * sqrtf (MAX (1 + xx + yy + zz, 0.f)); q->x = 0.5f * sqrtf (MAX (1 + xx - yy - zz, 0.f)); q->y = 0.5f * sqrtf (MAX (1 - xx + yy - zz, 0.f)); q->z = 0.5f * sqrtf (MAX (1 - xx - yy + zz, 0.f)); if (graphene_matrix_get_value (m, 2, 1) > graphene_matrix_get_value (m, 1, 2)) q->x = -q->x; if (graphene_matrix_get_value (m, 0, 2) > graphene_matrix_get_value (m, 2, 0)) q->y = -q->y; if (graphene_matrix_get_value (m, 1, 0) > graphene_matrix_get_value (m, 0, 1)) q->z = -q->z; return q; } /** * graphene_quaternion_to_matrix: * @q: a #graphene_quaternion_t * @m: (out caller-allocates): a #graphene_matrix_t * * Converts a quaternion into a transformation matrix expressing * the rotation defined by the #graphene_quaternion_t. * * Since: 1.0 */ void graphene_quaternion_to_matrix (const graphene_quaternion_t *q, graphene_matrix_t *m) { m->value.x = graphene_simd4f_init (1.f - 2.f * (q->y * q->y + q->z * q->z), 2.f * (q->x * q->y + q->w * q->z), 2.f * (q->x * q->z - q->w * q->y), 0.f); m->value.y = graphene_simd4f_init ( 2.f * (q->x * q->y - q->w * q->z), 1.f - 2.f * (q->x * q->x + q->z * q->z), 2.f * (q->y * q->z + q->w * q->x), 0.f); m->value.z = graphene_simd4f_init ( 2.f * (q->x * q->z + q->w * q->y), 2.f * (q->y * q->z - q->w * q->x), 1.f - 2.f * (q->x * q->x + q->y * q->y), 0.f); m->value.w = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f); } /** * graphene_quaternion_slerp: * @a: a #graphene_quaternion_t * @b: a #graphene_quaternion_t * @factor: the linear interpolation factor * @res: (out caller-allocates): return location for the interpolated * quaternion * * Interpolates between the two given quaternions using a spherical * linear interpolation, or [SLERP](http://en.wikipedia.org/wiki/Slerp), * using the given interpolation @factor. * * Since: 1.0 */ void graphene_quaternion_slerp (const graphene_quaternion_t *a, const graphene_quaternion_t *b, float factor, graphene_quaternion_t *res) { graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, a->z, a->w); graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, b->z, b->w); float dot = CLAMP (graphene_simd4f_get_x (graphene_simd4f_dot4 (v_a, v_b)), -1.f, 1.f); if (graphene_approx_val (dot, 1.f)) { *res = *a; return; } float theta = acos (dot); float r_sin_theta = 1.f / sqrtf (1.f - dot * dot); float right_v = sinf (factor * theta) * r_sin_theta; float left_v = cosf (factor * theta) - dot * right_v; graphene_simd4f_t left = graphene_simd4f_init (a->x, a->y, a->z, a->w); graphene_simd4f_t right = graphene_simd4f_init (b->x, b->y, b->z, b->w); graphene_simd4f_t sum; left = graphene_simd4f_mul (left, graphene_simd4f_splat (left_v)); right = graphene_simd4f_mul (right, graphene_simd4f_splat (right_v)); sum = graphene_simd4f_add (left, right); graphene_quaternion_init_from_simd4f (res, sum); } /** * graphene_quaternion_init_from_angles: * @q: a #graphene_quaternion_t * @deg_x: rotation angle on the X axis (yaw), in degrees * @deg_y: rotation angle on the Y axis (pitch), in degrees * @deg_z: rotation angle on the Z axis (roll), in degrees * * Initializes a #graphene_quaternion_t using the values of * the [Euler angles](http://en.wikipedia.org/wiki/Euler_angles) * on each axis. * * See also: graphene_quaternion_init_from_euler() * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init_from_angles (graphene_quaternion_t *q, float deg_x, float deg_y, float deg_z) { return graphene_quaternion_init_from_radians (q, GRAPHENE_DEG_TO_RAD (deg_x), GRAPHENE_DEG_TO_RAD (deg_y), GRAPHENE_DEG_TO_RAD (deg_z)); } /** * graphene_quaternion_init_from_radians: * @q: a #graphene_quaternion_t * @rad_x: rotation angle on the X axis (yaw), in radians * @rad_y: rotation angle on the Y axis (pitch), in radians * @rad_z: rotation angle on the Z axis (roll), in radians * * Initializes a #graphene_quaternion_t using the values of * the [Euler angles](http://en.wikipedia.org/wiki/Euler_angles) * on each axis. * * See also: graphene_quaternion_init_from_euler() * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init_from_radians (graphene_quaternion_t *q, float rad_x, float rad_y, float rad_z) { float sin_x, sin_y, sin_z; float cos_x, cos_y, cos_z; graphene_sincos (rad_x * .5f, &sin_x, &cos_x); graphene_sincos (rad_y * .5f, &sin_y, &cos_y); graphene_sincos (rad_z * .5f, &sin_z, &cos_z); q->x = sin_x * cos_y * cos_z + cos_x * sin_y * sin_z; q->y = cos_x * sin_y * cos_z - sin_x * cos_y * sin_z; q->z = cos_x * cos_y * sin_z + sin_x * sin_y * cos_z; q->w = cos_x * cos_y * cos_z - sin_x * sin_y * sin_z; return q; } /** * graphene_quaternion_to_angles: * @q: a #graphene_quaternion_t * @deg_x: (out) (optional): return location for the rotation angle on * the X axis (yaw), in degrees * @deg_y: (out) (optional): return location for the rotation angle on * the Y axis (pitch), in degrees * @deg_z: (out) (optional): return location for the rotation angle on * the Z axis (roll), in degrees * * Converts a #graphene_quaternion_t to its corresponding rotations * on the [Euler angles](http://en.wikipedia.org/wiki/Euler_angles) * on each axis. * * Since: 1.2 */ void graphene_quaternion_to_angles (const graphene_quaternion_t *q, float *deg_x, float *deg_y, float *deg_z) { float rad_x, rad_y, rad_z; graphene_quaternion_to_radians (q, &rad_x, &rad_y, &rad_z); if (deg_x != NULL) *deg_x = GRAPHENE_RAD_TO_DEG (rad_x); if (deg_y != NULL) *deg_y = GRAPHENE_RAD_TO_DEG (rad_y); if (deg_z != NULL) *deg_z = GRAPHENE_RAD_TO_DEG (rad_z); } /** * graphene_quaternion_to_radians: * @q: a #graphene_quaternion_t * @rad_x: (out) (optional): return location for the rotation angle on * the X axis (yaw), in radians * @rad_y: (out) (optional): return location for the rotation angle on * the Y axis (pitch), in radians * @rad_z: (out) (optional): return location for the rotation angle on * the Z axis (roll), in radians * * Converts a #graphene_quaternion_t to its corresponding rotations * on the [Euler angles](http://en.wikipedia.org/wiki/Euler_angles) * on each axis. * * Since: 1.2 */ void graphene_quaternion_to_radians (const graphene_quaternion_t *q, float *rad_x, float *rad_y, float *rad_z) { graphene_vec4_t v; graphene_vec4_t sqv; graphene_quaternion_to_vec4 (q, &v); graphene_vec4_multiply (&v, &v, &sqv); float qa[4]; graphene_vec4_to_float (&v, qa); float sqa[4]; graphene_vec4_to_float (&sqv, sqa); if (rad_x != NULL) *rad_x = atan2f (2 * (qa[0] * qa[3] - qa[1] * qa[2]), (sqa[3] - sqa[0] - sqa[1] + sqa[2])); if (rad_y != NULL) *rad_y = asinf (CLAMP (2 * (qa[0] * qa[2] + qa[1] * qa[3]), -1, 1)); if (rad_z != NULL) *rad_z = atan2f (2 * (qa[2] * qa[3] - qa[0] * qa[1]), (sqa[3] + sqa[0] - sqa[1] - sqa[2])); } /** * graphene_quaternion_init_from_angle_vec3: * @q: a #graphene_quaternion_t * @angle: the rotation on a given axis, in degrees * @axis: the axis of rotation, expressed as a vector * * Initializes a #graphene_quaternion_t using an @angle on a * specific @axis. * * Returns: (transfer none): the initialized quaternion * * Since: 1.0 */ graphene_quaternion_t * graphene_quaternion_init_from_angle_vec3 (graphene_quaternion_t *q, float angle, const graphene_vec3_t *axis) { float rad, sin_a, cos_a; graphene_simd4f_t axis_n; rad = GRAPHENE_DEG_TO_RAD (angle) / 2.f; graphene_sincos (rad, &sin_a, &cos_a); axis_n = graphene_simd4f_mul (graphene_simd4f_normalize3 (axis->value), graphene_simd4f_splat (sin_a)); q->x = graphene_simd4f_get_x (axis_n); q->y = graphene_simd4f_get_y (axis_n); q->z = graphene_simd4f_get_z (axis_n); q->w = cos_a; return q; } /** * graphene_quaternion_to_angle_vec3: * @q: a #graphene_quaternion_t * @angle: (out): return location for the angle, in degrees * @axis: (out caller-allocates): return location for the rotation axis * * Converts a quaternion into an @angle, @axis pair. * * Since: 1.0 */ void graphene_quaternion_to_angle_vec3 (const graphene_quaternion_t *q, float *angle, graphene_vec3_t *axis) { graphene_quaternion_t q_n; float cos_a; graphene_quaternion_normalize (q, &q_n); cos_a = q_n.w; if (angle != NULL) *angle = GRAPHENE_RAD_TO_DEG (acosf (cos_a) * 2.f); if (axis != NULL) { float sin_a = sqrtf (1.f - cos_a * cos_a); if (fabsf (sin_a) < 0.00005) sin_a = 1.f; graphene_vec3_init (axis, q_n.x / sin_a, q_n.y / sin_a, q_n.z / sin_a); } } /** * graphene_quaternion_init_from_euler: * @q: the #graphene_quaternion_t to initialize * @e: a #graphene_euler_t * * Initializes a #graphene_quaternion_t using the given #graphene_euler_t. * * Returns: (transfer none): the initialized #graphene_quaternion_t * * Since: 1.2 */ graphene_quaternion_t * graphene_quaternion_init_from_euler (graphene_quaternion_t *q, const graphene_euler_t *e) { graphene_euler_order_t order = graphene_euler_get_order (e); const float ex = GRAPHENE_DEG_TO_RAD (graphene_euler_get_x (e)) / 2.f; const float ey = GRAPHENE_DEG_TO_RAD (graphene_euler_get_y (e)) / 2.f; const float ez = GRAPHENE_DEG_TO_RAD (graphene_euler_get_z (e)) / 2.f; float c1, c2, c3, s1, s2, s3; float s1c2c3, c1s2s3, c1s2c3, s1c2s3; float c1c2s3, s1s2c3, c1c2c3, s1s2s3; graphene_sincos (ex, &s1, &c1); graphene_sincos (ey, &s2, &c2); graphene_sincos (ez, &s3, &c3); s1c2c3 = s1 * c2 * c3; c1s2s3 = c1 * s2 * s3; c1s2c3 = c1 * s2 * c3; s1c2s3 = s1 * c2 * s3; c1c2s3 = c1 * c2 * s3; s1s2c3 = s1 * s2 * c3; c1c2c3 = c1 * c2 * c3; s1s2s3 = s1 * s2 * s3; switch (order) { case GRAPHENE_EULER_ORDER_XYZ: q->x = s1c2c3 + c1s2s3; q->y = c1s2c3 - s1c2s3; q->z = c1c2s3 + s1s2c3; q->w = c1c2c3 - s1s2s3; break; case GRAPHENE_EULER_ORDER_YXZ: q->x = s1c2c3 + c1s2s3; q->y = c1s2c3 - s1c2s3; q->z = c1c2s3 - s1s2c3; q->w = c1c2c3 + s1s2s3; break; case GRAPHENE_EULER_ORDER_ZXY: q->x = s1c2c3 - c1s2s3; q->y = c1s2c3 + s1c2s3; q->z = c1c2s3 + s1s2c3; q->w = c1c2c3 - s1s2s3; break; case GRAPHENE_EULER_ORDER_ZYX: q->x = s1c2c3 - c1s2s3; q->y = c1s2c3 + s1c2s3; q->z = c1c2s3 - s1s2c3; q->w = c1c2c3 + s1s2s3; break; case GRAPHENE_EULER_ORDER_YZX: q->x = s1c2c3 + c1s2s3; q->y = c1s2c3 + s1c2s3; q->z = c1c2s3 - s1s2c3; q->w = c1c2c3 - s1s2s3; break; case GRAPHENE_EULER_ORDER_XZY: q->x = s1c2c3 - c1s2s3; q->y = c1s2c3 - s1c2s3; q->z = c1c2s3 + s1s2c3; q->w = c1c2c3 + s1s2s3; break; case GRAPHENE_EULER_ORDER_DEFAULT: q->x = 0.f; q->y = 0.f; q->z = 0.f; q->w = 1.f; break; } return q; } static bool quaternion_equal (const void *p1, const void *p2) { const graphene_quaternion_t *a = p1; const graphene_quaternion_t *b = p2; return fabsf (a->x - b->x) < 0.00001 && fabsf (a->y - b->y) < 0.00001 && fabsf (a->z - b->z) < 0.00001 && fabsf (a->w - b->w) < 0.00001; } /** * graphene_quaternion_equal: * @a: a #graphene_quaternion_t * @b: a #graphene_quaternion_t * * Checks whether the given quaternions are equal. * * Returns: `true` if the quaternions are equal * * Since: 1.0 */ bool graphene_quaternion_equal (const graphene_quaternion_t *a, const graphene_quaternion_t *b) { return graphene_pointer_equal (a, b, quaternion_equal); } /** * graphene_quaternion_dot: * @a: a #graphene_quaternion_t * @b: a #graphene_quaternion_t * * Computes the dot product of two #graphene_quaternion_t. * * Returns: the value of the dot products * * Since: 1.0 */ float graphene_quaternion_dot (const graphene_quaternion_t *a, const graphene_quaternion_t *b) { graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, a->z, a->w); graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, b->z, b->w); return graphene_simd4f_get_x (graphene_simd4f_dot4 (v_a, v_b)); } /** * graphene_quaternion_invert: * @q: a #graphene_quaternion_t * @res: (out caller-allocates): return location for the inverted * quaternion * * Inverts a #graphene_quaternion_t. * * Since: 1.0 */ void graphene_quaternion_invert (const graphene_quaternion_t *q, graphene_quaternion_t *res) { res->x = -q->x; res->y = -q->y; res->z = -q->z; res->w = q->w; } /** * graphene_quaternion_normalize: * @q: a #graphene_quaternion_t * @res: (out caller-allocates): return location for the normalized * quaternion * * Normalizes a #graphene_quaternion_t. * * Since: 1.0 */ void graphene_quaternion_normalize (const graphene_quaternion_t *q, graphene_quaternion_t *res) { graphene_simd4f_t v_q; v_q = graphene_simd4f_init (q->x, q->y, q->z, q->w); v_q = graphene_simd4f_normalize4 (v_q); graphene_quaternion_init_from_simd4f (res, v_q); } graphene-1.8.0/src/graphene-quaternion.h000066400000000000000000000177461324365266600202610ustar00rootroot00000000000000/* graphene-quaternion.h: Quaternion * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_QUATERNION_H__ #define __GRAPHENE_QUATERNION_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-vec4.h" GRAPHENE_BEGIN_DECLS /** * graphene_quaternion_t: * * A quaternion. * * The contents of the #graphene_quaternion_t structure are private * and should never be accessed directly. * * Since: 1.0 */ struct _graphene_quaternion_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (float, x); GRAPHENE_PRIVATE_FIELD (float, y); GRAPHENE_PRIVATE_FIELD (float, z); GRAPHENE_PRIVATE_FIELD (float, w); }; GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quaternion_free (graphene_quaternion_t *q); GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_init (graphene_quaternion_t *q, float x, float y, float z, float w); GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_init_identity (graphene_quaternion_t *q); GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_init_from_quaternion (graphene_quaternion_t *q, const graphene_quaternion_t *src); GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_init_from_vec4 (graphene_quaternion_t *q, const graphene_vec4_t *src); GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_init_from_matrix (graphene_quaternion_t *q, const graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_init_from_angles (graphene_quaternion_t *q, float deg_x, float deg_y, float deg_z); GRAPHENE_AVAILABLE_IN_1_4 graphene_quaternion_t * graphene_quaternion_init_from_radians (graphene_quaternion_t *q, float rad_x, float rad_y, float rad_z); GRAPHENE_AVAILABLE_IN_1_0 graphene_quaternion_t * graphene_quaternion_init_from_angle_vec3 (graphene_quaternion_t *q, float angle, const graphene_vec3_t *axis); GRAPHENE_AVAILABLE_IN_1_2 graphene_quaternion_t * graphene_quaternion_init_from_euler (graphene_quaternion_t *q, const graphene_euler_t *e); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quaternion_to_vec4 (const graphene_quaternion_t *q, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quaternion_to_matrix (const graphene_quaternion_t *q, graphene_matrix_t *m); GRAPHENE_AVAILABLE_IN_1_2 void graphene_quaternion_to_angles (const graphene_quaternion_t *q, float *deg_x, float *deg_y, float *deg_z); GRAPHENE_AVAILABLE_IN_1_4 void graphene_quaternion_to_radians (const graphene_quaternion_t *q, float *rad_x, float *rad_y, float *rad_z); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quaternion_to_angle_vec3 (const graphene_quaternion_t *q, float *angle, graphene_vec3_t *axis); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_quaternion_equal (const graphene_quaternion_t *a, const graphene_quaternion_t *b); GRAPHENE_AVAILABLE_IN_1_0 float graphene_quaternion_dot (const graphene_quaternion_t *a, const graphene_quaternion_t *b); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quaternion_invert (const graphene_quaternion_t *q, graphene_quaternion_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quaternion_normalize (const graphene_quaternion_t *q, graphene_quaternion_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_quaternion_slerp (const graphene_quaternion_t *a, const graphene_quaternion_t *b, float factor, graphene_quaternion_t *res); GRAPHENE_END_DECLS #endif /* __GRAPHENE_QUATERNION_H__ */ graphene-1.8.0/src/graphene-ray.c000066400000000000000000000225231324365266600166470ustar00rootroot00000000000000/* graphene-ray.c: A ray emitted from an origin in a given direction * * Copyright 2015 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-ray * @Title: Ray * @Short_Description: A ray emitted from an origin in a given direction * * #graphene_ray_t is a structure representing a ray emitted by an origin, * identified by a point in 3D space, in a given direction, identified * by a vector with 3 components. */ #include "graphene-private.h" #include "graphene-ray.h" #include "graphene-alloc-private.h" #include "graphene-plane.h" #include "graphene-point3d.h" #include "graphene-vec3.h" #include #include /** * graphene_ray_alloc: (constructor) * * Allocates a new #graphene_ray_t structure. * * The contents of the returned structure are undefined. * * Returns: (transfer full): the newly allocated #graphene_ray_t. * Use graphene_ray_free() to free the resources allocated by * this function * * Since: 1.4 */ graphene_ray_t * graphene_ray_alloc (void) { return graphene_aligned_alloc (sizeof (graphene_ray_t), 1, 16); } /** * graphene_ray_free: * @r: a #graphene_ray_t * * Frees the resources allocated by graphene_ray_alloc(). * * Since: 1.4 */ void graphene_ray_free (graphene_ray_t *r) { graphene_aligned_free (r); } /** * graphene_ray_init: * @r: the #graphene_ray_t to initialize * @origin: (nullable): the origin of the ray * @direction: (nullable): the direction vector * * Initializes the given #graphene_ray_t using the given @origin * and @direction values. * * Returns: (transfer none): the initialized ray * * Since: 1.4 */ graphene_ray_t * graphene_ray_init (graphene_ray_t *r, const graphene_point3d_t *origin, const graphene_vec3_t *direction) { if (origin != NULL) graphene_point3d_to_vec3 (origin, &r->origin); else graphene_vec3_init_from_vec3 (&r->origin, graphene_vec3_zero ()); if (direction != NULL) graphene_vec3_normalize (direction, &r->direction); else graphene_vec3_init_from_vec3 (&r->direction, graphene_vec3_zero ()); return r; } /** * graphene_ray_init_from_ray: * @r: the #graphene_ray_t to initialize * @src: a #graphene_ray_t * * Initializes the given #graphene_ray_t using the origin and direction * values of another #graphene_ray_t. * * Returns: (transfer none): the initialized ray * * Since: 1.4 */ graphene_ray_t * graphene_ray_init_from_ray (graphene_ray_t *r, const graphene_ray_t *src) { return graphene_ray_init_from_vec3 (r, &src->origin, &src->direction); } /** * graphene_ray_init_from_vec3: * @r: the #graphene_ray_t to initialize * @origin: (nullable): a #graphene_vec3_t * @direction: (nullable): a #graphene_vec3_t * * Initializes the given #graphene_ray_t using the given vectors. * * Returns: (transfer none): the initialized ray * * Since: 1.4 */ graphene_ray_t * graphene_ray_init_from_vec3 (graphene_ray_t *r, const graphene_vec3_t *origin, const graphene_vec3_t *direction) { if (origin != NULL) graphene_vec3_init_from_vec3 (&r->origin, origin); else graphene_vec3_init_from_vec3 (&r->origin, graphene_vec3_zero ()); if (direction != NULL) graphene_vec3_normalize (direction, &r->direction); else graphene_vec3_init_from_vec3 (&r->direction, graphene_vec3_zero ()); return r; } /** * graphene_ray_get_origin: * @r: a #graphene_ray_t * @origin: (out caller-allocates): return location for the origin * * Retrieves the origin of the given #graphene_ray_t. * * Since: 1.4 */ void graphene_ray_get_origin (const graphene_ray_t *r, graphene_point3d_t *origin) { graphene_point3d_init_from_vec3 (origin, &r->origin); } /** * graphene_ray_get_direction: * @r: a #graphene_ray_t * @direction: (out caller-allocates): return location for the direction * * Retrieves the direction of the given #graphene_ray_t. * * Since: 1.4 */ void graphene_ray_get_direction (const graphene_ray_t *r, graphene_vec3_t *direction) { graphene_vec3_init_from_vec3 (direction, &r->direction); } /** * graphene_ray_get_position_at: * @r: a #graphene_ray_t * @t: the distance along the ray * @position: (out caller-allocates): return location for the position * * Retrieves the coordinates of a point at the distance @t along the * given #graphene_ray_t. * * Since: 1.4 */ void graphene_ray_get_position_at (const graphene_ray_t *r, float t, graphene_point3d_t *position) { graphene_vec3_t res; graphene_vec3_scale (&r->direction, t, &res); graphene_vec3_add (&res, &r->origin, &res); graphene_point3d_init_from_vec3 (position, &res); } /** * graphene_ray_get_distance_to_point: * @r: a #graphene_ray_t * @p: a #graphene_point3d_t * * Computes the distance from the origin of the given ray to the given point. * * Returns: the distance of the point * * Since: 1.4 */ float graphene_ray_get_distance_to_point (const graphene_ray_t *r, const graphene_point3d_t *p) { graphene_vec3_t point; graphene_vec3_t tmp; float distance; graphene_point3d_to_vec3 (p, &point); graphene_vec3_subtract (&point, &r->origin, &tmp); distance = graphene_vec3_dot (&tmp, &r->direction); /* the point is behind the ray */ if (distance < 0) { graphene_vec3_subtract (&r->origin, &point, &tmp); return graphene_vec3_length (&tmp); } /* get the position on the ray at the given distance */ graphene_vec3_scale (&r->direction, distance, &tmp); graphene_vec3_add (&tmp, &r->origin, &tmp); graphene_vec3_subtract (&tmp, &point, &tmp); return graphene_vec3_length (&tmp); } /** * graphene_ray_get_distance_to_plane: * @r: a #graphene_ray_t * @p: a #graphene_plane_t * * Computes the distance of the origin of the given #graphene_ray_t from the * given plane. * * If the ray does not intersect the plane, this function returns `INFINITY`. * * Returns: the distance of the origin of the ray from the plane * * Since: 1.4 */ float graphene_ray_get_distance_to_plane (const graphene_ray_t *r, const graphene_plane_t *p) { float denom, t; denom = graphene_vec3_dot (&p->normal, &r->direction); if (fabsf (denom) < GRAPHENE_FLOAT_EPSILON) { graphene_point3d_t tmp; /* If the ray is coplanar, return 0 */ graphene_point3d_init_from_vec3 (&tmp, &r->origin); if (fabsf (graphene_plane_distance (p, &tmp)) < GRAPHENE_FLOAT_EPSILON) return 0.f; return INFINITY; } t = -1.f * (graphene_vec3_dot (&r->origin, &p->normal) + p->constant) / denom; if (t >= 0.f) return t; return INFINITY; } static bool ray_equal (const void *p1, const void *p2) { const graphene_ray_t *a = p1; const graphene_ray_t *b = p2; return graphene_vec3_equal (&a->origin, &b->origin) && graphene_vec3_equal (&a->direction, &b->direction); } /** * graphene_ray_equal: * @a: a #graphene_ray_t * @b: a #graphene_ray_t * * Checks whether the two given #graphene_ray_t are equal. * * Returns: `true` if the given rays are equal * * Since: 1.4 */ bool graphene_ray_equal (const graphene_ray_t *a, const graphene_ray_t *b) { return graphene_pointer_equal (a, b, ray_equal); } /** * graphene_ray_get_closest_point_to_point: * @r: a #graphene_ray_t * @p: a #graphene_point3d_t * @res: (out caller-allocates): return location for the closest point3d * * Computes the point on the given #graphene_ray_t that is closest to the * given point @p. * * Since: 1.4 */ void graphene_ray_get_closest_point_to_point (const graphene_ray_t *r, const graphene_point3d_t *p, graphene_point3d_t *res) { graphene_vec3_t point, result; float distance; graphene_point3d_to_vec3 (p, &point); graphene_vec3_subtract (&point, &r->origin, &result); distance = graphene_vec3_dot (&result, &r->direction); if (distance < 0) graphene_vec3_init_from_vec3 (&result, &r->origin); else { graphene_vec3_scale (&r->direction, distance, &result); graphene_vec3_add (&result, &r->origin, &result); } graphene_point3d_init_from_vec3 (res, &result); } graphene-1.8.0/src/graphene-ray.h000066400000000000000000000112541324365266600166530ustar00rootroot00000000000000/* graphene-ray.h: A ray emitted from an origin in a given direction * * Copyright 2015 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_RAY_H__ #define __GRAPHENE_RAY_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-vec3.h" GRAPHENE_BEGIN_DECLS /** * graphene_ray_t: * * A ray emitted from an origin in a given direction. * * The contents of the `graphene_ray_t` structure are private, and should not * be modified directly. * * Since: 1.4 */ struct _graphene_ray_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, origin); GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, direction); }; GRAPHENE_AVAILABLE_IN_1_4 graphene_ray_t * graphene_ray_alloc (void); GRAPHENE_AVAILABLE_IN_1_4 void graphene_ray_free (graphene_ray_t *r); GRAPHENE_AVAILABLE_IN_1_4 graphene_ray_t * graphene_ray_init (graphene_ray_t *r, const graphene_point3d_t *origin, const graphene_vec3_t *direction); GRAPHENE_AVAILABLE_IN_1_4 graphene_ray_t * graphene_ray_init_from_ray (graphene_ray_t *r, const graphene_ray_t *src); GRAPHENE_AVAILABLE_IN_1_4 graphene_ray_t * graphene_ray_init_from_vec3 (graphene_ray_t *r, const graphene_vec3_t *origin, const graphene_vec3_t *direction); GRAPHENE_AVAILABLE_IN_1_4 void graphene_ray_get_origin (const graphene_ray_t *r, graphene_point3d_t *origin); GRAPHENE_AVAILABLE_IN_1_4 void graphene_ray_get_direction (const graphene_ray_t *r, graphene_vec3_t *direction); GRAPHENE_AVAILABLE_IN_1_4 void graphene_ray_get_position_at (const graphene_ray_t *r, float t, graphene_point3d_t *position); GRAPHENE_AVAILABLE_IN_1_4 float graphene_ray_get_distance_to_point (const graphene_ray_t *r, const graphene_point3d_t *p); GRAPHENE_AVAILABLE_IN_1_4 float graphene_ray_get_distance_to_plane (const graphene_ray_t *r, const graphene_plane_t *p); GRAPHENE_AVAILABLE_IN_1_4 bool graphene_ray_equal (const graphene_ray_t *a, const graphene_ray_t *b); GRAPHENE_AVAILABLE_IN_1_4 void graphene_ray_get_closest_point_to_point (const graphene_ray_t *r, const graphene_point3d_t *p, graphene_point3d_t *res); GRAPHENE_END_DECLS #endif /* __GRAPHENE_RAY_H__ */ graphene-1.8.0/src/graphene-rect.c000066400000000000000000000500401324365266600170040ustar00rootroot00000000000000/* graphene-rect.c: Rectangular type * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-rect * @title: Rectangle * @short_description: Rectangular shape type * * #graphene_rect_t is a type representing a rectangle through an origin * #graphene_point_t point and a #graphene_size_t size. * * ![](rectangle.png) * * Operations on a #graphene_rect_t will normalize the rectangle, to * ensure that the origin is always the top-left corner of the rectangle * and that the size is always positive. */ #include "graphene-private.h" #include "graphene-rect.h" #include /*< private > * graphene_rect_normalize_in_place: * @r: (inout): a #graphene_rect_t * * Normalizes the passed #graphene_rect_t. */ static inline void graphene_rect_normalize_in_place (graphene_rect_t *r) { if (r->size.width < 0.f) { float size = fabsf (r->size.width); r->origin.x -= size; r->size.width = size; } if (r->size.height < 0.f) { float size = fabsf (r->size.height); r->origin.y -= size; r->size.height = size; } } /** * graphene_rect_alloc: * * Allocates a new #graphene_rect_t. * * The contents of the returned rectangle are undefined. * * Returns: (transfer full): the newly allocated rectangle * * Since: 1.0 */ graphene_rect_t * graphene_rect_alloc (void) { return calloc (1, sizeof (graphene_rect_t)); } /** * graphene_rect_free: * @r: a #graphene_rect_t * * Frees the resources allocated by graphene_rect_alloc(). * * Since: 1.0 */ void graphene_rect_free (graphene_rect_t *r) { free (r); } /** * graphene_rect_init: * @r: a #graphene_rect_t * @x: the X coordinate of the @graphene_rect_t.origin * @y: the Y coordinate of the @graphene_rect_t.origin * @width: the width of the @graphene_rect_t.size * @height: the height of the @graphene_rect_t.size * * Initializes the given #graphene_rect_t with the given values. * * This function will implicitly normalize the #graphene_rect_t * before returning. * * Returns: (transfer none): the initialized rectangle * * Since: 1.0 */ graphene_rect_t * graphene_rect_init (graphene_rect_t *r, float x, float y, float width, float height) { graphene_point_init (&r->origin, x, y); graphene_size_init (&r->size, width, height); graphene_rect_normalize_in_place (r); return r; } /** * graphene_rect_init_from_rect: * @r: a #graphene_rect_t * @src: a #graphene_rect_t * * Initializes @r using the given @src rectangle. * * This function will implicitly normalize the #graphene_rect_t * before returning. * * Returns: (transfer none): the initialized rectangle * * Since: 1.0 */ graphene_rect_t * graphene_rect_init_from_rect (graphene_rect_t *r, const graphene_rect_t *src) { *r = *src; graphene_rect_normalize_in_place (r); return r; } static bool rect_equal (const void *p1, const void *p2) { const graphene_rect_t *a = p1; const graphene_rect_t *b = p2; graphene_rect_t r_a, r_b; graphene_rect_normalize_r (a, &r_a); graphene_rect_normalize_r (b, &r_b); return graphene_point_equal (&r_a.origin, &r_b.origin) && graphene_size_equal (&r_a.size, &r_b.size); } /** * graphene_rect_equal: * @a: a #graphene_rect_t * @b: a #graphene_rect_t * * Checks whether the two given rectangle are equal. * * Returns: `true` if the rectangles are equal * * Since: 1.0 */ bool graphene_rect_equal (const graphene_rect_t *a, const graphene_rect_t *b) { return graphene_pointer_equal (a, b, rect_equal); } /** * graphene_rect_normalize: * @r: a #graphene_rect_t * * Normalizes the passed rectangle. * * This function ensures that the size of the rectangle is made of * positive values, and that the origin is the top-left corner of * the rectangle. * * Returns: (transfer none): the normalized rectangle * * Since: 1.0 */ graphene_rect_t * graphene_rect_normalize (graphene_rect_t *r) { graphene_rect_normalize_in_place (r); return r; } /** * graphene_rect_normalize_r: * @r: a #graphene_rect_t * @res: (out caller-allocates): the return location for the * normalized rectangle * * Normalizes the passed rectangle. * * This function ensures that the size of the rectangle is made of * positive values, and that the origin is in the top-left corner * of the rectangle. * * Since: 1.4 */ void graphene_rect_normalize_r (const graphene_rect_t *r, graphene_rect_t *res) { if (res != r) *res = *r; graphene_rect_normalize_in_place (res); } /** * graphene_rect_get_center: * @r: a #graphene_rect_t * @p: (out caller-allocates): return location for a #graphene_point_t * * Retrieves the coordinates of the center of the given rectangle. * * Since: 1.0 */ void graphene_rect_get_center (const graphene_rect_t *r, graphene_point_t *p) { graphene_rect_t rr; rr = *r; graphene_rect_normalize_in_place (&rr); graphene_point_init (p, rr.origin.x + (rr.size.width / 2.f), rr.origin.y + (rr.size.height / 2.f)); } /** * graphene_rect_get_top_left: * @r: a #graphene_rect_t * @p: (out caller-allocates): return location for a #graphene_point_t * * Retrieves the coordinates of the top-left corner of the given rectangle. * * Since: 1.0 */ void graphene_rect_get_top_left (const graphene_rect_t *r, graphene_point_t *p) { graphene_rect_t rr; rr = *r; graphene_rect_normalize_in_place (&rr); graphene_point_init_from_point (p, &rr.origin); } /** * graphene_rect_get_top_right: * @r: a #graphene_rect_t * @p: (out caller-allocates): return location for a #graphene_point_t * * Retrieves the coordinates of the top-right corner of the given rectangle. * * Since: 1.0 */ void graphene_rect_get_top_right (const graphene_rect_t *r, graphene_point_t *p) { graphene_rect_t rr; rr = *r; graphene_rect_normalize_in_place (&rr); graphene_point_init (p, rr.origin.x + rr.size.width, rr.origin.y); } /** * graphene_rect_get_bottom_left: * @r: a #graphene_rect_t * @p: (out caller-allocates): return location for a #graphene_point_t * * Retrieves the coordinates of the bottom-left corner of the given rectangle. * * Since: 1.0 */ void graphene_rect_get_bottom_left (const graphene_rect_t *r, graphene_point_t *p) { graphene_rect_t rr; rr = *r; graphene_rect_normalize_in_place (&rr); graphene_point_init (p, rr.origin.x, rr.origin.y + rr.size.height); } /** * graphene_rect_get_bottom_right: * @r: a #graphene_rect_t * @p: (out caller-allocates): return location for a #graphene_point_t * * Retrieves the coordinates of the bottom-right corner of the given rectangle. * * Since: 1.0 */ void graphene_rect_get_bottom_right (const graphene_rect_t *r, graphene_point_t *p) { graphene_rect_t rr; rr = *r; graphene_rect_normalize_in_place (&rr); graphene_point_init (p, rr.origin.x + rr.size.width, rr.origin.y + rr.size.height); } /** * graphene_rect_get_vertices: * @r: a #graphene_rect_t * @vertices: (out) (array fixed-size=4): return location for an array * of 4 #graphene_vec2_t * * Computes the four vertices of a #graphene_rect_t. * * Since: 1.4 */ void graphene_rect_get_vertices (const graphene_rect_t *r, graphene_vec2_t vertices[]) { graphene_rect_t rr; graphene_rect_normalize_r (r, &rr); graphene_vec2_init (&vertices[0], rr.origin.x, rr.origin.y); graphene_vec2_init (&vertices[1], rr.origin.x + rr.size.width, rr.origin.y); graphene_vec2_init (&vertices[2], rr.origin.x + rr.size.width, rr.origin.y + rr.size.height); graphene_vec2_init (&vertices[3], rr.origin.x, rr.origin.y + rr.size.height); } #define GRAPHENE_RECT_GET(arg, part, field) \ float \ graphene_rect_get_ ## field (const graphene_rect_t * arg) \ { \ graphene_rect_t rr; \ \ rr = *arg; \ graphene_rect_normalize_in_place (&rr); \ \ return rr.part.field; \ } /** * graphene_rect_get_x: * @r: a #graphene_rect_t * * Retrieves the normalized X coordinate of the origin of the given * rectangle. * * Returns: the normalized X coordinate of the rectangle * * Since: 1.0 */ GRAPHENE_RECT_GET (r, origin, x) /** * graphene_rect_get_y: * @r: a #graphene_rect_t * * Retrieves the normalized Y coordinate of the origin of the given * rectangle. * * Returns: the normalized Y coordinate of the rectangle * * Since: 1.0 */ GRAPHENE_RECT_GET (r, origin, y) /** * graphene_rect_get_width: * @r: a #graphene_rect_t * * Retrieves the normalized width of the given rectangle. * * Returns: the normalized width of the rectangle * * Since: 1.0 */ GRAPHENE_RECT_GET (r, size, width) /** * graphene_rect_get_height: * @r: a #graphene_rect_t * * Retrieves the normalized height of the given rectangle. * * Returns: the normalized height of the rectangle * * Since: 1.0 */ GRAPHENE_RECT_GET (r, size, height) #undef GRAPHENE_RECT_GET /** * graphene_rect_union: * @a: a #graphene_rect_t * @b: a #graphene_rect_t * @res: (out caller-allocates): return location for a #graphene_rect_t * * Computes the union of the two given rectangles. * * ![](rectangle-union.png) * * The union in the image above is the blue outline. * * Since: 1.0 */ void graphene_rect_union (const graphene_rect_t *a, const graphene_rect_t *b, graphene_rect_t *res) { graphene_rect_t ra, rb; ra = *a; rb = *b; graphene_rect_normalize_in_place (&ra); graphene_rect_normalize_in_place (&rb); res->origin.x = MIN (ra.origin.x, rb.origin.x); res->origin.y = MIN (ra.origin.y, rb.origin.y); res->size.width = MAX (ra.origin.x + ra.size.width, rb.origin.x + rb.size.width) - res->origin.x; res->size.height = MAX (ra.origin.y + ra.size.height, rb.origin.y + rb.size.height) - res->origin.y; } /** * graphene_rect_intersection: * @a: a #graphene_rect_t * @b: a #graphene_rect_t * @res: (out caller-allocates) (optional): return location for * a #graphene_rect_t * * Computes the intersection of the two given rectangles. * * ![](rectangle-intersection.png) * * The intersection in the image above is the blue outline. * * If the two rectangles do not intersect, @res will contain * a degenerate rectangle with origin in (0, 0) and a size of 0. * * Returns: `true` if the two rectangles intersect * * Since: 1.0 */ bool graphene_rect_intersection (const graphene_rect_t *a, const graphene_rect_t *b, graphene_rect_t *res) { graphene_rect_t ra, rb; float x_1, y_1, x_2, y_2; ra = *a; rb = *b; graphene_rect_normalize_in_place (&ra); graphene_rect_normalize_in_place (&rb); x_1 = MAX (ra.origin.x, rb.origin.x); y_1 = MAX (ra.origin.y, rb.origin.y); x_2 = MIN (ra.origin.x + ra.size.width, rb.origin.x + rb.size.width); y_2 = MIN (ra.origin.y + ra.size.height, rb.origin.y + rb.size.height); if (x_1 >= x_2 || y_1 >= y_2) { if (res != NULL) graphene_rect_init (res, 0.0f, 0.0f, 0.0f, 0.0f); return false; } if (res != NULL) graphene_rect_init (res, x_1, y_1, x_2 - x_1, y_2 - y_1); return true; } /** * graphene_rect_contains_point: * @r: a #graphene_rect_t * @p: a #graphene_point_t * * Checks whether a #graphene_rect_t contains the given coordinates. * * Returns: `true` if the rectangle contains the point * * Since: 1.0 */ bool graphene_rect_contains_point (const graphene_rect_t *r, const graphene_point_t *p) { graphene_rect_t rr; rr = *r; graphene_rect_normalize_in_place (&rr); return p->x >= rr.origin.x && p->y >= rr.origin.y && p->x <= (rr.origin.x + rr.size.width) && p->y <= (rr.origin.y + rr.size.height); } /** * graphene_rect_contains_rect: * @a: a #graphene_rect_t * @b: a #graphene_rect_t * * Checks whether a #graphene_rect_t fully contains the given * rectangle. * * Returns: `true` if the rectangle @a fully contains @b * * Since: 1.0 */ bool graphene_rect_contains_rect (const graphene_rect_t *a, const graphene_rect_t *b) { graphene_rect_t res; graphene_rect_union (a, b, &res); return graphene_rect_equal (a, &res); } /** * graphene_rect_offset: * @r: a #graphene_rect_t * @d_x: the horizontal offset * @d_y: the vertical offset * * Offsets the origin by @d_x and @d_y. * * The size of the rectangle is unchanged. * * Returns: (transfer none): the offset rectangle * * Since: 1.0 */ graphene_rect_t * graphene_rect_offset (graphene_rect_t *r, float d_x, float d_y) { graphene_rect_offset_r (r, d_x, d_y, r); return r; } /** * graphene_rect_offset_r: * @r: a #graphene_rect_t * @d_x: the horizontal offset * @d_y: the vertical offset * @res: (out caller-allocates): return location for the offset * rectangle * * Offsets the origin of the given rectangle by @d_x and @d_y. * * The size of the rectangle is left unchanged. * * Since: 1.4 */ void graphene_rect_offset_r (const graphene_rect_t *r, float d_x, float d_y, graphene_rect_t *res) { graphene_rect_normalize_r (r, res); res->origin.x += d_x; res->origin.y += d_y; } /** * graphene_rect_inset: * @r: a #graphene_rect_t * @d_x: the horizontal inset * @d_y: the vertical inset * * Changes the given rectangle to be smaller, or larger depending on the * given inset parameters. * * To create an inset rectangle, use positive @d_x or @d_y values; to * create a larger, encompassing rectangle, use negative @d_x or @d_y * values. * * The origin of the rectangle is offset by @d_x and @d_y, while the size * is adjusted by `(2 * @d_x, 2 * @d_y)`. If @d_x and @d_y are positive * values, the size of the rectangle is decreased; if @d_x and @d_y are * negative values, the size of the rectangle is increased. * * If the size of the resulting inset rectangle has a negative width or * height then the size will be set to zero. * * Returns: (transfer none): the inset rectangle * * Since: 1.0 */ graphene_rect_t * graphene_rect_inset (graphene_rect_t *r, float d_x, float d_y) { graphene_rect_inset_r (r, d_x, d_y, r); return r; } /** * graphene_rect_inset_r: * @r: a #graphene_rect_t * @d_x: the horizontal inset * @d_y: the vertical inset * @res: (out caller-allocates): return location for the inset rectangle * * Changes the given rectangle to be smaller, or larger depending on the * given inset parameters. * * To create an inset rectangle, use positive @d_x or @d_y values; to * create a larger, encompassing rectangle, use negative @d_x or @d_y * values. * * The origin of the rectangle is offset by @d_x and @d_y, while the size * is adjusted by `(2 * @d_x, 2 * @d_y)`. If @d_x and @d_y are positive * values, the size of the rectangle is decreased; if @d_x and @d_y are * negative values, the size of the rectangle is increased. * * If the size of the resulting inset rectangle has a negative width or * height then the size will be set to zero. * * Since: 1.4 */ void graphene_rect_inset_r (const graphene_rect_t *r, float d_x, float d_y, graphene_rect_t *res) { graphene_rect_normalize_r (r, res); res->origin.x += d_x; res->origin.y += d_y; if (d_x >= 0.f) res->size.width -= (d_x * 2.f); else res->size.width += (d_x * -2.f); if (d_y >= 0.f) res->size.height -= (d_y * 2.f); else res->size.height += (d_y * -2.f); if (res->size.width < 0.f) res->size.width = 0.f; if (res->size.height < 0.f) res->size.height = 0.f; } /** * graphene_rect_round_to_pixel: * @r: a #graphene_rect_t * * Rounds the origin and the size of the given rectangle to * their nearest integer values; the rounding is guaranteed * to be large enough to contain the original rectangle. * * Returns: (transfer none): the pixel-aligned rectangle. * * Since: 1.0 * * Deprecated: 1.4: Use graphene_rect_round() instead */ graphene_rect_t * graphene_rect_round_to_pixel (graphene_rect_t *r) { graphene_rect_round (r, r); return r; } /** * graphene_rect_round: * @r: a #graphene_rect_t * @res: (out caller-allocates): return location for the * rounded rectangle * * Rounds the origin and size of the given rectangle to * their nearest integer values; the rounding is guaranteed * to be large enough to contain the original rectangle. * * This function is the equivalent of calling `floor` on * the coordinates of the origin, and `ceil` on the size. * * Since: 1.4 */ void graphene_rect_round (const graphene_rect_t *r, graphene_rect_t *res) { graphene_rect_normalize_r (r, res); res->origin.x = floorf (res->origin.x); res->origin.y = floorf (res->origin.y); res->size.width = ceilf (res->size.width); res->size.height = ceilf (res->size.height); } /** * graphene_rect_expand: * @r: a #graphene_rect_t * @p: a #graphene_point_t * @res: (out caller-allocates): return location for the expanded rectangle * * Expands a #graphene_rect_t to contain the given #graphene_point_t. * * Since: 1.4 */ void graphene_rect_expand (const graphene_rect_t *r, const graphene_point_t *p, graphene_rect_t *res) { graphene_rect_t tmp; graphene_rect_init (&tmp, p->x, p->y, 0.f, 0.f); graphene_rect_union (r, &tmp, res); graphene_rect_normalize_in_place (res); } /** * graphene_rect_interpolate: * @a: a #graphene_rect_t * @b: a #graphene_rect_t * @factor: the linear interpolation factor * @res: (out caller-allocates): return location for the * interpolated rectangle * * Linearly interpolates the origin and size of the two given * rectangles. * * Since: 1.0 */ void graphene_rect_interpolate (const graphene_rect_t *a, const graphene_rect_t *b, double factor, graphene_rect_t *res) { graphene_rect_t ra, rb; ra = *a; graphene_rect_normalize_in_place (&ra); rb = *b; graphene_rect_normalize_in_place (&rb); res->origin.x = graphene_lerp (ra.origin.x, rb.origin.x, factor); res->origin.y = graphene_lerp (ra.origin.y, rb.origin.y, factor); res->size.width = graphene_lerp (ra.size.width, rb.size.width, factor); res->size.height = graphene_lerp (ra.size.height, rb.size.height, factor); } static const graphene_rect_t _graphene_rect_zero; /** * graphene_rect_zero: * * Returns a degenerate rectangle with origin fixed at (0, 0) and * a size of 0, 0. * * Returns: (transfer none): a fixed rectangle * * Since: 1.4 */ const graphene_rect_t * graphene_rect_zero (void) { return &_graphene_rect_zero; } graphene-1.8.0/src/graphene-rect.h000066400000000000000000000215461324365266600170220ustar00rootroot00000000000000/* graphene-rect.h: Rectangular type * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_RECT_H__ #define __GRAPHENE_RECT_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-point.h" #include "graphene-size.h" #include "graphene-vec2.h" GRAPHENE_BEGIN_DECLS /** * GRAPHENE_RECT_INIT: * @_x: the X coordinate of the origin * @_y: the Y coordinate of the origin * @_w: the width * @_h: the height * * Initializes a #graphene_rect_t when declaring it. * * Since: 1.0 */ #define GRAPHENE_RECT_INIT(_x,_y,_w,_h) \ (graphene_rect_t) { .origin = { .x = (_x), .y = (_y) }, .size = { .width = (_w), .height = (_h) } } /** * graphene_rect_t: * @origin: the coordinates of the origin of the rectangle * @size: the size of the rectangle * * The location and size of a rectangle region. * * The width and height of a #graphene_rect_t can be negative; for instance, * a #graphene_rect_t with an origin of [ 0, 0 ] and a size of [ 10, 10 ] is * equivalent to a #graphene_rect_t with an origin of [ 10, 10 ] and a size * of [ -10, -10 ]. * * Application code can normalize rectangles using graphene_rect_normalize(); * this function will ensure that the width and height of a rectangle are * positive values. All functions taking a #graphene_rect_t as an argument * will internally operate on a normalized copy; all functions returning a * #graphene_rect_t will always return a normalized rectangle. * * Since: 1.0 */ struct _graphene_rect_t { graphene_point_t origin; graphene_size_t size; }; GRAPHENE_AVAILABLE_IN_1_0 graphene_rect_t * graphene_rect_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_free (graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_0 graphene_rect_t * graphene_rect_init (graphene_rect_t *r, float x, float y, float width, float height); GRAPHENE_AVAILABLE_IN_1_0 graphene_rect_t * graphene_rect_init_from_rect (graphene_rect_t *r, const graphene_rect_t *src); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_rect_equal (const graphene_rect_t *a, const graphene_rect_t *b); GRAPHENE_AVAILABLE_IN_1_0 graphene_rect_t * graphene_rect_normalize (graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_4 void graphene_rect_normalize_r (const graphene_rect_t *r, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_get_center (const graphene_rect_t *r, graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_get_top_left (const graphene_rect_t *r, graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_get_top_right (const graphene_rect_t *r, graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_get_bottom_right (const graphene_rect_t *r, graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_get_bottom_left (const graphene_rect_t *r, graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_4 void graphene_rect_get_vertices (const graphene_rect_t *r, graphene_vec2_t vertices[]); GRAPHENE_AVAILABLE_IN_1_0 float graphene_rect_get_x (const graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_0 float graphene_rect_get_y (const graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_0 float graphene_rect_get_width (const graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_0 float graphene_rect_get_height (const graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_union (const graphene_rect_t *a, const graphene_rect_t *b, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_rect_intersection (const graphene_rect_t *a, const graphene_rect_t *b, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_rect_contains_point (const graphene_rect_t *r, const graphene_point_t *p); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_rect_contains_rect (const graphene_rect_t *a, const graphene_rect_t *b); GRAPHENE_AVAILABLE_IN_1_0 graphene_rect_t * graphene_rect_offset (graphene_rect_t *r, float d_x, float d_y); GRAPHENE_AVAILABLE_IN_1_4 void graphene_rect_offset_r (const graphene_rect_t *r, float d_x, float d_y, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_0 graphene_rect_t * graphene_rect_inset (graphene_rect_t *r, float d_x, float d_y); GRAPHENE_AVAILABLE_IN_1_4 void graphene_rect_inset_r (const graphene_rect_t *r, float d_x, float d_y, graphene_rect_t *res); GRAPHENE_DEPRECATED_IN_1_4_FOR (graphene_rect_round) graphene_rect_t * graphene_rect_round_to_pixel (graphene_rect_t *r); GRAPHENE_AVAILABLE_IN_1_4 void graphene_rect_round (const graphene_rect_t *r, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_rect_interpolate (const graphene_rect_t *a, const graphene_rect_t *b, double factor, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_4 void graphene_rect_expand (const graphene_rect_t *r, const graphene_point_t *p, graphene_rect_t *res); GRAPHENE_AVAILABLE_IN_1_4 const graphene_rect_t * graphene_rect_zero (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_RECT_H__ */ graphene-1.8.0/src/graphene-simd4f.c000066400000000000000000000737731324365266600172570ustar00rootroot00000000000000/* graphene-simd4f.c * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-simd4f * @Title: SIMD vector * @short_description: Low level floating point 4-sized vector * * The #graphene_simd4f_t type wraps a platform specific implementation of * a vector of four floating point values. * * Graphene can be compiled to use different implementations of the SIMD * types, and will generally prefer the faster hardware-backed implementation * if one is available. * * The #graphene_simd4f_t should be treated as an opaque, integral type; * you cannot access its components directly, and you can only operate on * all components at the same time. */ #include "graphene-private.h" #include "graphene-simd4f.h" #include #include /** * graphene_simd4f_t: * * A vector type containing four floating point values. * * The contents of the #graphene_simd4f_t type are private and * cannot be directly accessed; use the provided API instead. * * Since: 1.0 */ /* fast paths are all defined in the graphene-simd4f.h header */ #if defined(GRAPHENE_USE_SSE) || defined(GRAPHENE_USE_GCC) || defined(GRAPHENE_USE_ARM_NEON) /** * graphene_simd4f_init: * @x: the first component of the vector * @y: the second component of the vector * @z: the third component of the vector * @w: the fourth component of the vector * * Initializes a #graphene_simd4f_t with the given values. * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_init) (float x, float y, float z, float w) { return graphene_simd4f_init (x, y, z, w); } /** * graphene_simd4f_init_zero: * * Initializes a #graphene_simd4f_t with 0 in all components. * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_init_zero) (void) { return graphene_simd4f_init_zero (); } /** * graphene_simd4f_init_4f: * @v: (array fixed-size=4): an array of at least 4 floating * point values * * Initializes a #graphene_simd4f_t using an array of 4 floating * point values. * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_init_4f) (const float *v) { return graphene_simd4f_init_4f (v); } /** * graphene_simd4f_init_3f: * @v: (array fixed-size=3): an array of at least 3 floating * point values * * Initializes a #graphene_simd4f_t using an array of 3 floating * point values. * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_init_3f) (const float *v) { return graphene_simd4f_init_3f (v); } /** * graphene_simd4f_init_2f: * @v: (array fixed-size=2): an array of at least 2 floating * point values * * Initializes a #graphene_simd4f_t using an array of 2 floating * point values. * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_init_2f) (const float *v) { return graphene_simd4f_init_2f (v); } /** * graphene_simd4f_dup_4f: * @s: a #graphene_simd4f_t * @v: (out) (array fixed-size=4): return location for an * array of at least 4 floating point values * * Copies the contents of a #graphene_simd4f_t into an * array of floating points. * * Since: 1.0 */ void (graphene_simd4f_dup_4f) (const graphene_simd4f_t s, float *v) { graphene_simd4f_dup_4f (s, v); } /** * graphene_simd4f_dup_3f: * @s: a #graphene_simd4f_t * @v: (out) (array fixed-size=3): return location for an * array of at least 3 floating point values * * Copies the contents of a #graphene_simd4f_t into an * array of floating points. * * Since: 1.0 */ void (graphene_simd4f_dup_3f) (const graphene_simd4f_t s, float *v) { graphene_simd4f_dup_3f (s, v); } /** * graphene_simd4f_dup_2f: * @s: a #graphene_simd4f_t * @v: (out) (array fixed-size=2): return location for an * array of at least 2 floating point values * * Copies the contents of a #graphene_simd4f_t into an * array of floating points. * * Since: 1.0 */ void (graphene_simd4f_dup_2f) (const graphene_simd4f_t s, float *v) { graphene_simd4f_dup_2f (s, v); } /** * graphene_simd4f_get: * @s: a #graphene_simd4f_t * @i: the index of the component to retrieve * * Retrieves the given component of a #graphene_simd4f_t. * * Since: 1.2 */ float (graphene_simd4f_get) (const graphene_simd4f_t s, unsigned int i) { switch (i) { case 0: return graphene_simd4f_get (s, 0); case 1: return graphene_simd4f_get (s, 1); case 2: return graphene_simd4f_get (s, 2); case 3: return graphene_simd4f_get (s, 3); default: return 0.f; } } /** * graphene_simd4f_get_x: * @s: a #graphene_simd4f_t * * Retrieves the first component of @s. * * Returns: the first component of a #graphene_simd4f_t * * Since: 1.0 */ float (graphene_simd4f_get_x) (const graphene_simd4f_t s) { return graphene_simd4f_get_x (s); } /** * graphene_simd4f_get_y: * @s: a #graphene_simd4f_t * * Retrieves the second component of @s. * * Returns: the second component of a #graphene_simd4f_t * * Since: 1.0 */ float (graphene_simd4f_get_y) (const graphene_simd4f_t s) { return graphene_simd4f_get_y (s); } /** * graphene_simd4f_get_z: * @s: a #graphene_simd4f_t * * Retrieves the third component of @s. * * Returns: the third component of a #graphene_simd4f_t * * Since: 1.0 */ float (graphene_simd4f_get_z) (const graphene_simd4f_t s) { return graphene_simd4f_get_z (s); } /** * graphene_simd4f_get_w: * @s: a #graphene_simd4f_t * * Retrieves the fourth component of @s. * * Returns: the fourth component of a #graphene_simd4f_t * * Since: 1.0 */ float (graphene_simd4f_get_w) (const graphene_simd4f_t s) { return graphene_simd4f_get_w (s); } /** * graphene_simd4f_splat: * @v: a floating point value * * Sets all the components of a new #graphene_simd4f_t to the * same value @v: * * |[ * { * .x = v, * .y = v, * .z = v, * .w = v * }; * ]| * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_splat) (float v) { return graphene_simd4f_splat (v); } /** * graphene_simd4f_splat_x: * @s: a #graphene_simd4f_t * * Sets all the components of a new #graphene_simd4f_t to the * same value of the first component of the passed vector: * * |[ * { * .x = s.x, * .y = s.x, * .z = s.x, * .w = s.x * } * ]| * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_splat_x) (const graphene_simd4f_t s) { return graphene_simd4f_splat_x (s); } /** * graphene_simd4f_splat_y: * @s: a #graphene_simd4f_t * * Sets all the components of a new #graphene_simd4f_t to the * same value of the second component of the passed vector: * * |[ * { * .x = s.y, * .y = s.y, * .z = s.y, * .w = s.y * } * ]| * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_splat_y) (const graphene_simd4f_t s) { return graphene_simd4f_splat_y (s); } /** * graphene_simd4f_splat_z: * @s: a #graphene_simd4f_t * * Sets all the components of a #graphene_simd4f_t to the * same value of the third component of the passed vector: * * |[ * { * .x = s.z, * .y = s.z, * .z = s.z, * .w = s.z * } * ]| * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_splat_z) (const graphene_simd4f_t s) { return graphene_simd4f_splat_z (s); } /** * graphene_simd4f_splat_w: * @s: a #graphene_simd4f_t * * Sets all the components of a #graphene_simd4f_t to the * same value of the fourth component of the passed vector: * * |[ * { * .x = s.w, * .y = s.w, * .z = s.w, * .w = s.w * } * ]| * * Returns: the initialized #graphene_simd4f_t * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_splat_w) (const graphene_simd4f_t s) { return graphene_simd4f_splat_w (s); } /** * graphene_simd4f_reciprocal: * @s: a #graphene_simd4f_t * * Computes the reciprocal of every component of @s. * * |[ * { * .x = 1.0 / s.x, * .y = 1.0 / s.y, * .z = 1.0 / s.z, * .w = 1.0 / s.w * } * ]| * * Returns: a vector containing the reciprocal of the * passed vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_reciprocal) (const graphene_simd4f_t s) { return graphene_simd4f_reciprocal (s); } /** * graphene_simd4f_sqrt: * @s: a #graphene_simd4f_t * * Computes the square root of every component of @s. * * |[ * { * .x = sqrt (s.x), * .y = sqrt (s.y), * .z = sqrt (s.z), * .w = sqrt (s.w) * } * ]| * * Returns: a vector containing the square root of the * passed vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_sqrt) (const graphene_simd4f_t s) { return graphene_simd4f_sqrt (s); } /** * graphene_simd4f_rsqrt: * @s: a #graphene_simd4f_t * * Computes the reciprocal square root of every component * of @s. * * |[ * { * .x = 1.0 / sqrt (s.x), * .y = 1.0 / sqrt (s.y), * .z = 1.0 / sqrt (s.z), * .w = 1.0 / sqrt (s.w) * } * ]| * * Returns: a vector containing the reciprocal square root * of the passed vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_rsqrt) (const graphene_simd4f_t s) { return graphene_simd4f_rsqrt (s); } /** * graphene_simd4f_add: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t vector where each * component is the sum of the respective components * in @a and @b. * * |[ * { * .x = a.x + b.x, * .y = a.y + b.y, * .z = a.z + b.z, * .w = a.w + b.w * } * ]| * * Returns: the sum vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_add) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_add (a, b); } /** * graphene_simd4f_sub: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t vector where each * component is the subtraction of the respective components * in @a and @b. * * |[ * { * .x = a.x - b.x, * .y = a.y - b.y, * .z = a.z - b.z, * .w = a.w - b.w * } * ]| * * Returns: the subtraction vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_sub) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_sub (a, b); } /** * graphene_simd4f_mul: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t vector where each * component is the multiplication of the respective components * in @a and @b. * * |[ * { * .x = a.x * b.x, * .y = a.y * b.y, * .z = a.z * b.z, * .w = a.w * b.w * } * ]| * * Returns: the multiplication vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_mul) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_mul (a, b); } /** * graphene_simd4f_div: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t vector where each * component is the division of the respective components * in @a and @b. * * |[ * { * .x = a.x / b.x, * .y = a.y / b.y, * .z = a.z / b.z, * .w = a.w / b.w * } * ]| * * Returns: the division vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_div) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_div (a, b); } /** * graphene_simd4f_cross3: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t vector where each * component contains the 3-way cross product of the * given @a and @b vectors. * * Returns: the cross3 vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_cross3) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_cross3 (a, b); } /** * graphene_simd4f_dot3: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Computes the dot product of the first three components of the * two given #graphene_simd4f_t. * * Returns: a vector whose components are all set to the * dot product of the components of the two operands * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_dot3) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_dot3 (a, b); } /** * graphene_simd4f_dot3_scalar: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Computes the dot product of the first three components of the * two given #graphene_simd4f_t. * * Returns: the dot product of the two vectors, as a scalar value. * * Since: 1.4 */ float (graphene_simd4f_dot3_scalar) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_dot3_scalar (a, b); } /** * graphene_simd4f_min: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * minimum value of each component of @a and @b. * * Returns: the new minimum vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_min) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_min (a, b); } /** * graphene_simd4f_max: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * maximum value of each component of @a and @b. * * Returns: the new maximum vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_max) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_max (a, b); } /** * graphene_simd4f_shuffle_wxyz: * @s: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * re-ordered values of the W, X, Y, and Z components * of @s. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_shuffle_wxyz) (const graphene_simd4f_t s) { return graphene_simd4f_shuffle_wxyz (s); } /** * graphene_simd4f_shuffle_zwxy: * @s: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * re-ordered values of the Z, W, X, and Y components * of @s. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_shuffle_zwxy) (const graphene_simd4f_t s) { return graphene_simd4f_shuffle_zwxy (s); } /** * graphene_simd4f_shuffle_yzwx: * @s: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * re-ordered values of the Y, Z, W, and X components * of @s. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_shuffle_yzwx) (const graphene_simd4f_t s) { return graphene_simd4f_shuffle_yzwx (s); } /** * graphene_simd4f_zero_w: * @s: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * same values of the given @s vector, except for the * W component, which is set to 0. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_zero_w) (const graphene_simd4f_t s) { return graphene_simd4f_zero_w (s); } /** * graphene_simd4f_zero_zw: * @s: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * same values of the given @s vector, except for the * Z and W components, which are set to 0. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_zero_zw) (const graphene_simd4f_t s) { return graphene_simd4f_zero_zw (s); } /** * graphene_simd4f_merge_w: * @s: a #graphene_simd4f_t * @v: the new value of the W component * * Creates a new #graphene_simd4f_t that contains the * same values of the given @s vector, except for the * W component, which is set to @v. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_merge_w) (const graphene_simd4f_t s, float v) { return graphene_simd4f_merge_w (s, v); } /** * graphene_simd4f_merge_high: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * last two components of the vector @a and the last * two components of the vector @b. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_merge_high) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_merge_high (a, b); } /** * graphene_simd4f_merge_low: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Creates a new #graphene_simd4f_t that contains the * first two components of the vector @a and the first * two components of the vector @b. * * Returns: the new vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_merge_low) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_merge_low (a, b); } /** * graphene_simd4f_flip_sign_0101: * @s: a #graphene_simd4f_t * * Flips the signs of the second and fourth components of * the given vector @s. * * Returns: the new vector, with the changed signs * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_flip_sign_0101) (const graphene_simd4f_t s) { return graphene_simd4f_flip_sign_0101 (s); } /** * graphene_simd4f_flip_sign_1010: * @s: a #graphene_simd4f_t * * Flips the signs of the first and third components of * the given vector @s. * * Returns: the new vector, with the changed signs * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_flip_sign_1010) (const graphene_simd4f_t s) { return graphene_simd4f_flip_sign_1010 (s); } /** * graphene_simd4f_cmp_eq: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Checks if the two given #graphene_simd4f_t are equal. * * Returns: `true` if the values of the vectors are equal * * Since: 1.0 */ bool (graphene_simd4f_cmp_eq) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_cmp_eq (a, b); } /** * graphene_simd4f_cmp_neq: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Checks if the two given #graphene_simd4f_t are not equal. * * Returns: `true` if the values of the vectors are not equal * * Since: 1.0 */ bool (graphene_simd4f_cmp_neq) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_cmp_neq (a, b); } /** * graphene_simd4f_cmp_lt: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Compares two #graphene_simd4f_t and checks if all components * of the vector @a are less than the respective components of * the vector @b. * * Returns: `true` if vector @a is less than @b * * Since: 1.2 */ bool (graphene_simd4f_cmp_lt) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_cmp_lt (a, b); } /** * graphene_simd4f_cmp_le: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Compares two #graphene_simd4f_t and checks if all components * of the vector @a are less than or equal to the respective components * of the vector @b. * * Returns: `true` if vector @a is less than or equal to @b * * Since: 1.2 */ bool (graphene_simd4f_cmp_le) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_cmp_le (a, b); } /** * graphene_simd4f_cmp_ge: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Compares two #graphene_simd4f_t and checks if all components * of the vector @a are greater than or equal to the respective * components of the vector @b. * * Returns: `true` if vector @a is greater than or equal to @b * * Since: 1.0 */ bool (graphene_simd4f_cmp_ge) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_cmp_ge (a, b); } /** * graphene_simd4f_cmp_gt: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Compares two #graphene_simd4f_t and checks if all components * of the vector @a are greater than the respective components of * the vector @b. * * Returns: `true` if vector @a is greater than @b * * Since: 1.0 */ bool (graphene_simd4f_cmp_gt) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_cmp_gt (a, b); } /** * graphene_simd4f_neg: * @s: a #graphene_simd4f_t * * Negates the values of @s. * * Returns: the negated vector * * Since: 1.0 */ graphene_simd4f_t (graphene_simd4f_neg) (const graphene_simd4f_t s) { return graphene_simd4f_neg (s); } #else /* GRAPHENE_USE_SCALAR */ graphene_simd4f_t (graphene_simd4f_init) (float x, float y, float z, float w) { graphene_simd4f_t s = { x, y, z, w }; return s; } graphene_simd4f_t (graphene_simd4f_init_zero) (void) { return graphene_simd4f_init (0.f, 0.f, 0.f, 0.f); } graphene_simd4f_t (graphene_simd4f_init_4f) (const float *v) { return graphene_simd4f_init (v[0], v[1], v[2], v[3]); } graphene_simd4f_t (graphene_simd4f_init_3f) (const float *v) { return graphene_simd4f_init (v[0], v[1], v[2], 0.f); } graphene_simd4f_t (graphene_simd4f_init_2f) (const float *v) { return graphene_simd4f_init (v[0], v[1], 0.f, 0.f); } void (graphene_simd4f_dup_4f) (const graphene_simd4f_t s, float *v) { memcpy (v, &s, sizeof (float) * 4); } void (graphene_simd4f_dup_3f) (const graphene_simd4f_t s, float *v) { memcpy (v, &s, sizeof (float) * 3); } void (graphene_simd4f_dup_2f) (const graphene_simd4f_t s, float *v) { memcpy (v, &s, sizeof (float) * 2); } float (graphene_simd4f_get) (const graphene_simd4f_t s, unsigned int i) { switch (i) { case 0: return s.x; case 1: return s.y; case 2: return s.z; case 3: return s.w; } return 0; } float (graphene_simd4f_get_x) (const graphene_simd4f_t s) { return s.x; } float (graphene_simd4f_get_y) (const graphene_simd4f_t s) { return s.y; } float (graphene_simd4f_get_z) (const graphene_simd4f_t s) { return s.z; } float (graphene_simd4f_get_w) (const graphene_simd4f_t s) { return s.w; } graphene_simd4f_t (graphene_simd4f_splat) (float v) { graphene_simd4f_t s = { v, v, v, v }; return s; } graphene_simd4f_t (graphene_simd4f_splat_x) (graphene_simd4f_t v) { graphene_simd4f_t s = { v.x, v.x, v.x, v.x }; return s; } graphene_simd4f_t (graphene_simd4f_splat_y) (graphene_simd4f_t v) { graphene_simd4f_t s = { v.y, v.y, v.y, v.y }; return s; } graphene_simd4f_t (graphene_simd4f_splat_z) (graphene_simd4f_t v) { graphene_simd4f_t s = { v.z, v.z, v.z, v.z }; return s; } graphene_simd4f_t (graphene_simd4f_splat_w) (graphene_simd4f_t v) { graphene_simd4f_t s = { v.w, v.w, v.w, v.w }; return s; } graphene_simd4f_t (graphene_simd4f_reciprocal) (graphene_simd4f_t v) { graphene_simd4f_t s = { v.x != 0.f ? 1.0f / v.x : 0.f, v.y != 0.f ? 1.0f / v.y : 0.f, v.z != 0.f ? 1.0f / v.z : 0.f, v.w != 0.f ? 1.0f / v.w : 0.f }; return s; } graphene_simd4f_t (graphene_simd4f_sqrt) (graphene_simd4f_t v) { graphene_simd4f_t s = { sqrtf (v.x), sqrtf (v.y), sqrtf (v.z), sqrtf (v.w) }; return s; } graphene_simd4f_t (graphene_simd4f_rsqrt) (graphene_simd4f_t v) { graphene_simd4f_t s = { v.x != 0.f ? 1.0f / sqrtf (v.x) : 0.f, v.y != 0.f ? 1.0f / sqrtf (v.y) : 0.f, v.z != 0.f ? 1.0f / sqrtf (v.z) : 0.f, v.w != 0.f ? 1.0f / sqrtf (v.w) : 0.f }; return s; } graphene_simd4f_t (graphene_simd4f_add) (const graphene_simd4f_t a, const graphene_simd4f_t b) { graphene_simd4f_t s = { a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; return s; } graphene_simd4f_t (graphene_simd4f_sub) (const graphene_simd4f_t a, const graphene_simd4f_t b) { graphene_simd4f_t s = { a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; return s; } graphene_simd4f_t (graphene_simd4f_mul) (const graphene_simd4f_t a, const graphene_simd4f_t b) { graphene_simd4f_t s = { a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; return s; } graphene_simd4f_t (graphene_simd4f_div) (const graphene_simd4f_t a, const graphene_simd4f_t b) { graphene_simd4f_t s = { b.x != 0.f ? a.x / b.x : 0.f, b.y != 0.f ? a.y / b.y : 0.f, b.z != 0.f ? a.z / b.z : 0.f, b.w != 0.f ? a.w / b.w : 0.f }; return s; } graphene_simd4f_t (graphene_simd4f_cross3) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_init (a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x, 0.f); } graphene_simd4f_t (graphene_simd4f_dot3) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_splat (graphene_simd4f_dot3_scalar (a, b)); } float (graphene_simd4f_dot3_scalar) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return a.x * b.x + a.y * b.y + a.z * b.z; } graphene_simd4f_t (graphene_simd4f_min) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_init (a.x < b.x ? a.x : b.x, a.y < b.y ? a.y : b.y, a.z < b.z ? a.z : b.z, a.w < b.w ? a.w : b.w); } graphene_simd4f_t (graphene_simd4f_max) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_init (a.x > b.x ? a.x : b.x, a.y > b.y ? a.y : b.y, a.z > b.z ? a.z : b.z, a.w > b.w ? a.w : b.w); } graphene_simd4f_t (graphene_simd4f_shuffle_wxyz) (const graphene_simd4f_t s) { return graphene_simd4f_init (s.w, s.x, s.y, s.z); } graphene_simd4f_t (graphene_simd4f_shuffle_zwxy) (const graphene_simd4f_t s) { return graphene_simd4f_init (s.z, s.w, s.x, s.y); } graphene_simd4f_t (graphene_simd4f_shuffle_yzwx) (const graphene_simd4f_t s) { return graphene_simd4f_init (s.y, s.z, s.w, s.x); } graphene_simd4f_t (graphene_simd4f_zero_w) (const graphene_simd4f_t s) { return graphene_simd4f_init (s.x, s.y, s.z, 0.0f); } graphene_simd4f_t (graphene_simd4f_zero_zw) (const graphene_simd4f_t s) { return graphene_simd4f_init (s.x, s.y, 0.0f, 0.0f); } graphene_simd4f_t (graphene_simd4f_merge_w) (const graphene_simd4f_t s, float v) { return graphene_simd4f_init (s.x, s.y, s.z, v); } graphene_simd4f_t (graphene_simd4f_merge_high) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_init (a.z, a.w, b.z, b.w); } graphene_simd4f_t (graphene_simd4f_merge_low) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_init (a.x, a.y, b.x, b.y); } graphene_simd4f_t (graphene_simd4f_flip_sign_0101) (const graphene_simd4f_t s) { return graphene_simd4f_init (s.x, -s.y, s.z, -s.w); } graphene_simd4f_t (graphene_simd4f_flip_sign_1010) (const graphene_simd4f_t s) { return graphene_simd4f_init (-s.x, s.y, -s.z, s.w); } bool (graphene_simd4f_cmp_eq) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; } bool (graphene_simd4f_cmp_neq) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; } bool (graphene_simd4f_cmp_lt) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return a.x < b.x && a.y < b.y && a.z < b.z && a.w < b.w; } bool (graphene_simd4f_cmp_le) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return a.x <= b.x && a.y <= b.y && a.z <= b.z && a.w <= b.w; } bool (graphene_simd4f_cmp_ge) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return a.x >= b.x && a.y >= b.y && a.z >= b.z && a.w >= b.w; } bool (graphene_simd4f_cmp_gt) (const graphene_simd4f_t a, const graphene_simd4f_t b) { return a.x > b.x && a.y > b.y && a.z > b.z && a.w > b.w; } graphene_simd4f_t (graphene_simd4f_neg) (const graphene_simd4f_t s) { return graphene_simd4f_init (-s.x, -s.y, -s.z, -s.w); } #endif /* GRAPHENE_USE_SCALAR */ graphene-1.8.0/src/graphene-simd4f.h000066400000000000000000001624261324365266600172560ustar00rootroot00000000000000/* graphene-simd4f.h: SIMD wrappers and operations * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SH1_0 THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_SIMD4F_H__ #define __GRAPHENE_SIMD4F_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif /* needed for memcpy() */ #include #include #include "graphene-config.h" #include "graphene-macros.h" #include "graphene-version-macros.h" GRAPHENE_BEGIN_DECLS /* Platform specific operations */ GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_init (float x, float y, float z, float w); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_init_zero (void); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_init_4f (const float *v); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_init_3f (const float *v); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_init_2f (const float *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_simd4f_dup_4f (const graphene_simd4f_t s, float *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_simd4f_dup_3f (const graphene_simd4f_t s, float *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_simd4f_dup_2f (const graphene_simd4f_t s, float *v); GRAPHENE_AVAILABLE_IN_1_2 float graphene_simd4f_get (const graphene_simd4f_t s, unsigned int i); GRAPHENE_AVAILABLE_IN_1_0 float graphene_simd4f_get_x (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 float graphene_simd4f_get_y (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 float graphene_simd4f_get_z (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 float graphene_simd4f_get_w (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_splat (float v); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_splat_x (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_splat_y (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_splat_z (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_splat_w (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_add (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_sub (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_mul (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_div (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_sqrt (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_reciprocal (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_rsqrt (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_cross3 (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_dot3 (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_4 float graphene_simd4f_dot3_scalar (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_min (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_max (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_shuffle_wxyz (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_shuffle_zwxy (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_shuffle_yzwx (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_zero_w (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_zero_zw (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_merge_high (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_merge_low (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_merge_w (const graphene_simd4f_t s, float v); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_flip_sign_0101 (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_flip_sign_1010 (const graphene_simd4f_t s); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_simd4f_cmp_eq (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_simd4f_cmp_neq (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_simd4f_cmp_lt (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_simd4f_cmp_le (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_simd4f_cmp_ge (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_simd4f_cmp_gt (const graphene_simd4f_t a, const graphene_simd4f_t b); GRAPHENE_AVAILABLE_IN_1_0 graphene_simd4f_t graphene_simd4f_neg (const graphene_simd4f_t s); #if !defined(__GI_SCANNER__) && defined(GRAPHENE_USE_SSE) /* SSE2 implementation of SIMD 4f */ /* Union type used to do single lane reading without memcpy */ typedef union { graphene_simd4f_t s; float f[4]; } graphene_simd4f_union_t; /* On GCC, we use __extension__ macros to avoid a static inline */ # if defined(__GNUC__) /* Use GCC statement __extension__ to inline all these functions */ # define graphene_simd4f_init(x,y,z,w) \ (__extension__ ({ \ (graphene_simd4f_t) { (x), (y), (z), (w) }; \ })) # define graphene_simd4f_init_zero() \ (__extension__ ({ \ (graphene_simd4f_t) _mm_setzero_ps(); \ })) # define graphene_simd4f_init_4f(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_loadu_ps (v); \ })) # define graphene_simd4f_init_3f(v) \ (__extension__ ({ \ (graphene_simd4f_t) { (v)[0], (v)[1], (v)[2], 0.f }; \ })) # define graphene_simd4f_init_2f(v) \ (__extension__ ({ \ (graphene_simd4f_t) { (v)[0], (v)[1], 0.f, 0.f }; \ })) # define graphene_simd4f_dup_4f(s,v) \ (__extension__ ({ \ _mm_storeu_ps ((v), (s)); \ })) # define graphene_simd4f_dup_3f(s,v) \ (__extension__ ({ \ memcpy ((v), &(s), sizeof (float) * 3); \ })) # define graphene_simd4f_dup_2f(s,v) \ (__extension__ ({ \ memcpy ((v), &(s), sizeof (float) * 2); \ })) # define graphene_simd4f_get(s,i) \ (__extension__ ({ \ graphene_simd4f_union_t __u = { (s) }; \ (float) __u.f[(i)]; \ })) # define graphene_simd4f_get_x(s) graphene_simd4f_get (s, 0) # define graphene_simd4f_get_y(s) graphene_simd4f_get (s, 1) # define graphene_simd4f_get_z(s) graphene_simd4f_get (s, 2) # define graphene_simd4f_get_w(s) graphene_simd4f_get (s, 3) # define graphene_simd4f_splat(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_set1_ps ((v)); \ })) # define graphene_simd4f_splat_x(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (0, 0, 0, 0)); \ })) # define graphene_simd4f_splat_y(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (1, 1, 1, 1)); \ })) # define graphene_simd4f_splat_z(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (2, 2, 2, 2)); \ })) # define graphene_simd4f_splat_w(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (3, 3, 3, 3)); \ })) # define graphene_simd4f_add(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_add_ps ((a), (b)); \ })) # define graphene_simd4f_sub(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_sub_ps ((a), (b)); \ })) # define graphene_simd4f_mul(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_mul_ps ((a), (b)); \ })) # define graphene_simd4f_div(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_div_ps ((a), (b)); \ })) # define graphene_simd4f_sqrt(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_sqrt_ps ((v)); \ })) # define graphene_simd4f_reciprocal(v) \ (__extension__ ({ \ const graphene_simd4f_t __two = graphene_simd4f_init (2.0f, 2.0f, 2.0f, 2.0f); \ graphene_simd4f_t __s = _mm_rcp_ps ((v)); \ graphene_simd4f_mul (__s, graphene_simd4f_sub (__two, graphene_simd4f_mul ((v), __s))); \ })) # define graphene_simd4f_rsqrt(v) \ (__extension__ ({ \ const graphene_simd4f_t __half = graphene_simd4f_init (0.5f, 0.5f, 0.5f, 0.5f); \ const graphene_simd4f_t __three = graphene_simd4f_init (3.0f, 3.0f, 3.0f, 3.0f); \ graphene_simd4f_t __s = _mm_rsqrt_ps ((v)); \ graphene_simd4f_mul (graphene_simd4f_mul (__s, __half), \ graphene_simd4f_sub (__three, \ graphene_simd4f_mul (__s, graphene_simd4f_mul ((v), __s)))); \ })) # define graphene_simd4f_cross3(a,b) \ (__extension__ ({ \ const graphene_simd4f_t __a_yzx = _mm_shuffle_ps ((a), (a), _MM_SHUFFLE (3, 0, 2, 1)); \ const graphene_simd4f_t __a_zxy = _mm_shuffle_ps ((a), (a), _MM_SHUFFLE (3, 1, 0, 2)); \ const graphene_simd4f_t __b_yzx = _mm_shuffle_ps ((b), (b), _MM_SHUFFLE (3, 0, 2, 1)); \ const graphene_simd4f_t __b_zxy = _mm_shuffle_ps ((b), (b), _MM_SHUFFLE (3, 1, 0, 2)); \ (graphene_simd4f_t) _mm_sub_ps (_mm_mul_ps (__a_yzx, __b_zxy), _mm_mul_ps (__a_zxy, __b_yzx)); \ })) # if defined(GRAPHENE_USE_SSE4_1) # define graphene_simd4f_dot3(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_dp_ps ((a), (b), 0x7f); \ })) # else # define graphene_simd4f_dot3(a,b) \ (__extension__ ({ \ GRAPHENE_ALIGN16 const unsigned int __mask_bits[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0 }; \ const graphene_simd4f_t __mask = _mm_load_ps ((const float *) __mask_bits); \ const graphene_simd4f_t __m = _mm_mul_ps ((a), (b)); \ const graphene_simd4f_t __s0 = _mm_and_ps (__m, __mask); \ const graphene_simd4f_t __s1 = _mm_add_ps (__s0, _mm_movehl_ps (__s0, __s0)); \ const graphene_simd4f_t __s2 = _mm_add_ss (__s1, _mm_shuffle_ps (__s1, __s1, 1)); \ (graphene_simd4f_t) _mm_shuffle_ps (__s2, __s2, 0); \ })) # endif # define graphene_simd4f_dot3_scalar(a,b) \ (__extension__ ({ \ float __res; \ _mm_store_ss (&__res, graphene_simd4f_dot3 (a, b)); \ __res; \ })) # define graphene_simd4f_min(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_min_ps ((a), (b)); \ })) # define graphene_simd4f_max(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_max_ps ((a), (b)); \ })) # define graphene_simd4f_shuffle_wxyz(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (2, 1, 0, 3)); \ })) # define graphene_simd4f_shuffle_zwxy(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (1, 0, 3, 2)); \ })) # define graphene_simd4f_shuffle_yzwx(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_shuffle_ps ((v), (v), _MM_SHUFFLE (0, 3, 2, 1)); \ })) # define graphene_simd4f_zero_w(v) \ (__extension__ ({ \ graphene_simd4f_t __s = _mm_unpackhi_ps ((v), _mm_setzero_ps ()); \ (graphene_simd4f_t) _mm_movelh_ps ((v), __s); \ })) # define graphene_simd4f_zero_zw(v) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_movelh_ps ((v), _mm_setzero_ps ()); \ })) # define graphene_simd4f_merge_w(s,v) \ (__extension__ ({ \ graphene_simd4f_t __s = _mm_unpackhi_ps ((s), _mm_set1_ps ((v))); \ (graphene_simd4f_t) _mm_movelh_ps ((s), __s); \ })) # define graphene_simd4f_merge_high(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_movehl_ps ((b), (a)); \ })) # define graphene_simd4f_merge_low(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) _mm_movelh_ps ((a), (b)); \ })) typedef GRAPHENE_ALIGN16 union { unsigned int ui[4]; float f[4]; } graphene_simd4f_uif_t; # define graphene_simd4f_flip_sign_0101(v) \ (__extension__ ({ \ const graphene_simd4f_uif_t __pnpn = { { \ 0x00000000, \ 0x80000000, \ 0x00000000, \ 0x80000000 \ } }; \ (graphene_simd4f_t) _mm_xor_ps ((v), _mm_load_ps (__pnpn.f)); \ })) # define graphene_simd4f_flip_sign_1010(v) \ (__extension__ ({ \ const graphene_simd4f_uif_t __npnp = { { \ 0x80000000, \ 0x00000000, \ 0x80000000, \ 0x00000000, \ } }; \ (graphene_simd4f_t) _mm_xor_ps ((v), _mm_load_ps (__npnp.f)); \ })) # define graphene_simd4f_cmp_eq(a,b) \ (__extension__ ({ \ __m128i __res = (__m128i) _mm_cmpneq_ps ((a), (b)); \ (bool) (_mm_movemask_epi8 (__res) == 0); \ })) # define graphene_simd4f_cmp_neq(a,b) \ (__extension__ ({ \ __m128i __res = (__m128i) _mm_cmpneq_ps ((a), (b)); \ (bool) (_mm_movemask_epi8 (__res) != 0); \ })) # define graphene_simd4f_cmp_lt(a,b) \ (__extension__ ({ \ __m128i __res = (__m128i) _mm_cmplt_ps ((a), (b)); \ (bool) (_mm_movemask_epi8 (__res) == 0xffff); \ })) # define graphene_simd4f_cmp_le(a,b) \ (__extension__ ({ \ __m128i __res = (__m128i) _mm_cmple_ps ((a), (b)); \ (bool) (_mm_movemask_epi8 (__res) == 0xffff); \ })) # define graphene_simd4f_cmp_ge(a,b) \ (__extension__ ({ \ __m128i __res = (__m128i) _mm_cmpge_ps ((a), (b)); \ (bool) (_mm_movemask_epi8 (__res) == 0xffff); \ })) # define graphene_simd4f_cmp_gt(a,b) \ (__extension__ ({ \ __m128i __res = (__m128i) _mm_cmpgt_ps ((a), (b)); \ (bool) (_mm_movemask_epi8 (__res) == 0xffff); \ })) # define graphene_simd4f_neg(s) \ (__extension__ ({ \ const graphene_simd4f_uif_t __mask = { { \ 0x80000000, \ 0x80000000, \ 0x80000000, \ 0x80000000, \ } }; \ (graphene_simd4f_t) _mm_xor_ps ((s), _mm_load_ps (__mask.f)); \ })) /* On MSVC, we use static inlines */ # elif defined (_MSC_VER) /* Use static inline to inline all these functions */ #define graphene_simd4f_init(x,y,z,w) _simd4f_init(x,y,z,w) static inline graphene_simd4f_t _simd4f_init (float x, float y, float z, float w) { graphene_simd4f_t __s = { x, y, z, w }; return __s; } #define graphene_simd4f_init_zero() \ _mm_setzero_ps() #define graphene_simd4f_init_4f(v) \ _mm_loadu_ps(v) #define graphene_simd4f_init_3f(v) \ graphene_simd4f_init (v[0], v[1], v[2], 0.f) #define graphene_simd4f_init_2f(v) \ graphene_simd4f_init (v[0], v[1], 0.f, 0.f) #define graphene_simd4f_dup_4f(s,v) \ _mm_storeu_ps (v, s) #define graphene_simd4f_dup_3f(s,v) \ memcpy (v, &s, sizeof (float) * 3) #define graphene_simd4f_dup_2f(s,v) \ memcpy (v, &s, sizeof (float) * 2) #define graphene_simd4f_get(s,i) _simd4f_get_xyzw(s, i) #define graphene_simd4f_get_x(s) _simd4f_get_xyzw(s, 0) #define graphene_simd4f_get_y(s) _simd4f_get_xyzw(s, 1) #define graphene_simd4f_get_z(s) _simd4f_get_xyzw(s, 2) #define graphene_simd4f_get_w(s) _simd4f_get_xyzw(s, 3) static inline float _simd4f_get_xyzw (graphene_simd4f_t s, int mode) { /* mode: get_x=0 get_y=1 get_z=2 get_w=3 */ graphene_simd4f_union_t u; u.s = s; return u.f[mode]; } #define graphene_simd4f_splat(v) \ _mm_set1_ps (v) #define graphene_simd4f_splat_x(v) \ _mm_shuffle_ps (v, v, _MM_SHUFFLE (0, 0, 0, 0)) #define graphene_simd4f_splat_y(v) \ _mm_shuffle_ps (v, v, _MM_SHUFFLE (1, 1, 1, 1)) #define graphene_simd4f_splat_z(v) \ _mm_shuffle_ps (v, v, _MM_SHUFFLE (2, 2, 2, 2)) #define graphene_simd4f_splat_w(v) \ _mm_shuffle_ps (v, v, _MM_SHUFFLE (3, 3, 3, 3)) #define graphene_simd4f_add(a,b) \ _mm_add_ps (a, b) #define graphene_simd4f_sub(a,b) \ _mm_sub_ps (a, b) #define graphene_simd4f_mul(a,b) \ _mm_mul_ps (a, b) #define graphene_simd4f_div(a,b) \ _mm_div_ps (a, b) #define graphene_simd4f_sqrt(v) \ _mm_sqrt_ps (v) #define graphene_simd4f_reciprocal(v) _simd4f_reciprocal(v) static inline graphene_simd4f_t _simd4f_reciprocal(const graphene_simd4f_t v) { const graphene_simd4f_t __two = graphene_simd4f_init (2.0f, 2.0f, 2.0f, 2.0f); graphene_simd4f_t __s = _mm_rcp_ps (v); return graphene_simd4f_mul (__s, graphene_simd4f_sub (__two, graphene_simd4f_mul (v, __s))); } #define graphene_simd4f_rsqrt(v) _simd4f_rsqrt(v) static inline graphene_simd4f_t _simd4f_rsqrt(const graphene_simd4f_t v) { const graphene_simd4f_t __half = graphene_simd4f_init (0.5f, 0.5f, 0.5f, 0.5f); const graphene_simd4f_t __three = graphene_simd4f_init (3.0f, 3.0f, 3.0f, 3.0f); graphene_simd4f_t __s = _mm_rsqrt_ps (v); return graphene_simd4f_mul (graphene_simd4f_mul (__s, __half), graphene_simd4f_sub (__three, graphene_simd4f_mul (__s, graphene_simd4f_mul (v, __s)))); } #define graphene_simd4f_cross3(a,b) \ _simd4f_cross3(a,b) static inline graphene_simd4f_t _simd4f_cross3 (const graphene_simd4f_t a, const graphene_simd4f_t b) { const graphene_simd4f_t __a_yzx = _mm_shuffle_ps (a, a, _MM_SHUFFLE (3, 0, 2, 1)); const graphene_simd4f_t __a_zxy = _mm_shuffle_ps (a, a, _MM_SHUFFLE (3, 1, 0, 2)); const graphene_simd4f_t __b_yzx = _mm_shuffle_ps (b, b, _MM_SHUFFLE (3, 0, 2, 1)); const graphene_simd4f_t __b_zxy = _mm_shuffle_ps (b, b, _MM_SHUFFLE (3, 1, 0, 2)); return _mm_sub_ps (_mm_mul_ps (__a_yzx, __b_zxy), _mm_mul_ps (__a_zxy, __b_yzx)); } #define graphene_simd4f_dot3(a,b) \ _simd4f_dot3(a,b) static inline graphene_simd4f_t _simd4f_dot3 (const graphene_simd4f_t a, const graphene_simd4f_t b) { #if defined(GRAPHENE_USE_SSE4_1) return _mm_dp_ps (a, b, 0x7f); #else GRAPHENE_ALIGN16 const unsigned int __mask_bits[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0 }; const graphene_simd4f_t __mask = _mm_load_ps ((const float *) __mask_bits); const graphene_simd4f_t __m = _mm_mul_ps ((a), (b)); const graphene_simd4f_t __s0 = _mm_and_ps (__m, __mask); const graphene_simd4f_t __s1 = _mm_add_ps (__s0, _mm_movehl_ps (__s0, __s0)); const graphene_simd4f_t __s2 = _mm_add_ss (__s1, _mm_shuffle_ps (__s1, __s1, 1)); return _mm_shuffle_ps (__s2, __s2, 0); #endif } #define graphene_simd4f_dot3_scalar(a,b) \ _simd4f_dot3_scalar(a,b) static inline float _simd4f_dot3_scalar (const graphene_simd4f_t a, const graphene_simd4f_t b) { float __res; _mm_store_ss (&__res, graphene_simd4f_dot3 (a, b)); return __res; } #define graphene_simd4f_min(a,b) \ _mm_min_ps (a, b) #define graphene_simd4f_max(a,b) \ _mm_max_ps (a, b) #define graphene_simd4f_shuffle_wxyz(v) \ _mm_shuffle_ps (v, v, _MM_SHUFFLE (2, 1, 0, 3)) #define graphene_simd4f_shuffle_zwxy(v) \ _mm_shuffle_ps (v, v, _MM_SHUFFLE (1, 0, 3, 2)) #define graphene_simd4f_shuffle_yzwx(v) \ _mm_shuffle_ps (v, v, _MM_SHUFFLE (0, 3, 2, 1)) #define graphene_simd4f_zero_w(v) \ _mm_movelh_ps (v, _mm_unpackhi_ps (v, _mm_setzero_ps ())) #define graphene_simd4f_zero_zw(v) \ _mm_movelh_ps (v, _mm_setzero_ps ()) #define graphene_simd4f_merge_w(s,v) \ _mm_movelh_ps (s, _mm_unpackhi_ps (s, _mm_set1_ps (v))) #define graphene_simd4f_merge_high(a,b) \ _mm_movehl_ps (b, a) #define graphene_simd4f_merge_low(a,b) \ _mm_movelh_ps (a, b) typedef GRAPHENE_ALIGN16 union { unsigned int ui[4]; float f[4]; } graphene_simd4f_uif_t; #define graphene_simd4f_flip_sign_0101(v) _simd4f_flip_sign_0101(v) static inline graphene_simd4f_t _simd4f_flip_sign_0101 (const graphene_simd4f_t v) { const graphene_simd4f_uif_t __pnpn = { { 0x00000000, 0x80000000, 0x00000000, 0x80000000 } }; return _mm_xor_ps (v, _mm_load_ps (__pnpn.f)); } #define graphene_simd4f_flip_sign_1010(v) _simd4f_flip_sign_1010(v) static inline graphene_simd4f_t _simd4f_flip_sign_1010(const graphene_simd4f_t v) { const graphene_simd4f_uif_t __npnp = { { 0x80000000, 0x00000000, 0x80000000, 0x00000000, } }; return _mm_xor_ps (v, _mm_load_ps (__npnp.f)); } #define graphene_simd4f_cmp_eq(a,b) _simd4f_cmp_eq(a,b) static inline bool _simd4f_cmp_eq (const graphene_simd4f_t a, const graphene_simd4f_t b) { __m128i __res = _mm_castps_si128 (_mm_cmpneq_ps (a, b)); return (_mm_movemask_epi8 (__res) == 0); } #define graphene_simd4f_cmp_neq(a,b) _simd4f_cmp_neq(a,b) static inline bool _simd4f_cmp_neq (const graphene_simd4f_t a, const graphene_simd4f_t b) { __m128i __res = _mm_castps_si128 (_mm_cmpneq_ps (a, b)); return (_mm_movemask_epi8 (__res) != 0); } #define graphene_simd4f_cmp_lt(a,b) _simd4f_cmp_lt(a,b) static inline bool _simd4f_cmp_lt (const graphene_simd4f_t a, const graphene_simd4f_t b) { __m128i __res = _mm_castps_si128 (_mm_cmplt_ps (a, b)); return (_mm_movemask_epi8 (__res) == 0xffff); } #define graphene_simd4f_cmp_le(a,b) _simd4f_cmp_le(a,b) static inline bool _simd4f_cmp_le (const graphene_simd4f_t a, const graphene_simd4f_t b) { __m128i __res = _mm_castps_si128 (_mm_cmple_ps (a, b)); return (_mm_movemask_epi8 (__res) == 0xffff); } #define graphene_simd4f_cmp_ge(a,b) _simd4f_cmp_ge(a,b) static inline bool _simd4f_cmp_ge (const graphene_simd4f_t a, const graphene_simd4f_t b) { __m128i __res = _mm_castps_si128 (_mm_cmpge_ps (a, b)); return (_mm_movemask_epi8 (__res) == 0xffff); } #define graphene_simd4f_cmp_gt(a,b) _simd4f_cmp_gt(a,b) static inline bool _simd4f_cmp_gt (const graphene_simd4f_t a, const graphene_simd4f_t b) { __m128i __res = _mm_castps_si128 (_mm_cmpgt_ps (a, b)); return (_mm_movemask_epi8 (__res) == 0xffff); } #define graphene_simd4f_neg(s) _simd4f_neg(s) static inline graphene_simd4f_t _simd4f_neg (const graphene_simd4f_t s) { const graphene_simd4f_uif_t __mask = { { 0x80000000, 0x80000000, 0x80000000, 0x80000000, } }; return _mm_xor_ps (s, _mm_load_ps (__mask.f)); } #else # error "Need GCC-compatible or Visual Studio compiler for SSE extensions." /* Use static inline to inline all these functions */ # endif /* __GNUC__ */ #elif !defined(__GI_SCANNER__) && defined(GRAPHENE_USE_GCC) /* GCC vector intrinsic implementation of SIMD 4f */ typedef int graphene_simd4i_t __attribute__((vector_size (16))); # define graphene_simd4f_init(x,y,z,w) \ (__extension__ ({ \ (graphene_simd4f_t) { (x), (y), (z), (w) }; \ })) # define graphene_simd4f_init_zero() \ (__extension__ ({ \ (graphene_simd4f_t) { 0.f, 0.f, 0.f, 0.f }; \ })) # define graphene_simd4f_init_4f(v) \ (__extension__ ({ \ (graphene_simd4f_t) { (v)[0], (v)[1], (v)[2], (v)[3] }; \ })) # define graphene_simd4f_init_3f(v) \ (__extension__ ({ \ (graphene_simd4f_t) { (v)[0], (v)[1], (v)[2], 0.f }; \ })) # define graphene_simd4f_init_2f(v) \ (__extension__ ({ \ (graphene_simd4f_t) { (v)[0], (v)[1], 0.f, 0.f }; \ })) # define graphene_simd4f_dup_4f(s,v) \ (__extension__ ({ \ memcpy ((v), &(s), sizeof (float) * 4); \ })) # define graphene_simd4f_dup_3f(s,v) \ (__extension__ ({ \ memcpy ((v), &(s), sizeof (float) * 3); \ })) # define graphene_simd4f_dup_2f(s,v) \ (__extension__ ({ \ memcpy ((v), &(s), sizeof (float) * 2); \ })) # define graphene_simd4f_get(s,i) (__extension__ ({ (float) (s)[(i)]; })) # define graphene_simd4f_get_x(s) graphene_simd4f_get ((s), 0) # define graphene_simd4f_get_y(s) graphene_simd4f_get ((s), 1) # define graphene_simd4f_get_z(s) graphene_simd4f_get ((s), 2) # define graphene_simd4f_get_w(s) graphene_simd4f_get ((s), 3) # define graphene_simd4f_splat(v) \ (__extension__ ({ \ (graphene_simd4f_t) { (v), (v), (v), (v) }; \ })) # define graphene_simd4f_splat_x(v) \ (__extension__ ({ \ float __val = graphene_simd4f_get_x ((v)); \ (graphene_simd4f_t) { __val, __val, __val, __val }; \ })) # define graphene_simd4f_splat_y(v) \ (__extension__ ({ \ float __val = graphene_simd4f_get_y ((v)); \ (graphene_simd4f_t) { __val, __val, __val, __val }; \ })) # define graphene_simd4f_splat_z(v) \ (__extension__ ({ \ float __val = graphene_simd4f_get_z ((v)); \ (graphene_simd4f_t) { __val, __val, __val, __val }; \ })) # define graphene_simd4f_splat_w(v) \ (__extension__ ({ \ float __val = graphene_simd4f_get_w ((v)); \ (graphene_simd4f_t) { __val, __val, __val, __val }; \ })) # define graphene_simd4f_reciprocal(v) \ (__extension__ ({ \ (graphene_simd4f_t) { \ (v)[0] != 0.f ? 1.f / (v)[0] : 0.f, \ (v)[1] != 0.f ? 1.f / (v)[1] : 0.f, \ (v)[2] != 0.f ? 1.f / (v)[2] : 0.f, \ (v)[3] != 0.f ? 1.f / (v)[3] : 0.f, \ }; \ })) # define graphene_simd4f_sqrt(v) \ (__extension__ ({ \ (graphene_simd4f_t) { \ sqrtf ((v)[0]), \ sqrtf ((v)[1]), \ sqrtf ((v)[2]), \ sqrtf ((v)[3]), \ }; \ })) # define graphene_simd4f_rsqrt(v) \ (__extension__ ({ \ (graphene_simd4f_t) { \ (v)[0] != 0.f ? 1.f / sqrtf ((v)[0]) : 0.f, \ (v)[1] != 0.f ? 1.f / sqrtf ((v)[1]) : 0.f, \ (v)[2] != 0.f ? 1.f / sqrtf ((v)[2]) : 0.f, \ (v)[3] != 0.f ? 1.f / sqrtf ((v)[3]) : 0.f, \ }; \ })) # define graphene_simd4f_add(a,b) (__extension__ ({ (graphene_simd4f_t) ((a) + (b)); })) # define graphene_simd4f_sub(a,b) (__extension__ ({ (graphene_simd4f_t) ((a) - (b)); })) # define graphene_simd4f_mul(a,b) (__extension__ ({ (graphene_simd4f_t) ((a) * (b)); })) # define graphene_simd4f_div(a,b) (__extension__ ({ (graphene_simd4f_t) ((a) / (b)); })) # define graphene_simd4f_cross3(a,b) \ (__extension__ ({ \ const graphene_simd4f_t __a = (a); \ const graphene_simd4f_t __b = (b); \ graphene_simd4f_init (__a[1] * __b[2] - __a[2] * __b[1], \ __a[2] * __b[0] - __a[0] * __b[2], \ __a[0] * __b[1] - __a[1] * __b[0], \ 0.f); \ })) # define graphene_simd4f_dot3(a,b) \ (__extension__ ({ \ const graphene_simd4f_t __a = (a); \ const graphene_simd4f_t __b = (b); \ const float __res = __a[0] * __b[0] + __a[1] * __b[1] + __a[2] * __b[2]; \ graphene_simd4f_init (__res, __res, __res, __res); \ })) # define graphene_simd4f_dot3_scalar(a,b) \ (__extension__ ({ \ graphene_simd4f_get_x (graphene_simd4f_dot3 (a, b)); \ })) # define graphene_simd4f_min(a,b) \ (__extension__ ({ \ const graphene_simd4f_t __a = (a); \ const graphene_simd4f_t __b = (b); \ graphene_simd4f_init (__a[0] < __b[0] ? __a[0] : __b[0], \ __a[1] < __b[1] ? __a[1] : __b[1], \ __a[2] < __b[2] ? __a[2] : __b[2], \ __a[3] < __b[3] ? __a[3] : __b[3]); \ })) # define graphene_simd4f_max(a,b) \ (__extension__ ({ \ const graphene_simd4f_t __a = (a); \ const graphene_simd4f_t __b = (b); \ graphene_simd4f_init (__a[0] > __b[0] ? __a[0] : __b[0], \ __a[1] > __b[1] ? __a[1] : __b[1], \ __a[2] > __b[2] ? __a[2] : __b[2], \ __a[3] > __b[3] ? __a[3] : __b[3]); \ })) # define graphene_simd4f_shuffle_wxyz(v) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 3, 0, 1, 2 }; \ (graphene_simd4f_t) __builtin_shuffle ((v), __mask); \ })) # define graphene_simd4f_shuffle_zwxy(v) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 2, 3, 0, 1 }; \ (graphene_simd4f_t) __builtin_shuffle ((v), __mask); \ })) # define graphene_simd4f_shuffle_yzwx(v) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 1, 2, 3, 0 }; \ (graphene_simd4f_t) __builtin_shuffle ((v), __mask); \ })) # define graphene_simd4f_zero_w(v) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 0, 1, 2, 4 }; \ (graphene_simd4f_t) __builtin_shuffle ((v), graphene_simd4f_init_zero (), __mask); \ })) # define graphene_simd4f_zero_zw(v) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 0, 1, 4, 4 }; \ (graphene_simd4f_t) __builtin_shuffle ((v), graphene_simd4f_init_zero (), __mask); \ })) # define graphene_simd4f_merge_w(s,v) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 0, 1, 2, 4 }; \ (graphene_simd4f_t) __builtin_shuffle ((s), graphene_simd4f_splat ((v)), __mask); \ })) # define graphene_simd4f_merge_high(a,b) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 2, 3, 6, 7 }; \ (graphene_simd4f_t) __builtin_shuffle ((a), (b), __mask); \ })) # define graphene_simd4f_merge_low(a,b) \ (__extension__ ({ \ const graphene_simd4i_t __mask = { 0, 1, 4, 5 }; \ (graphene_simd4f_t) __builtin_shuffle ((a), (b), __mask); \ })) # define graphene_simd4f_flip_sign_0101(v) \ (__extension__ ({ \ const graphene_simd4f_t __v = (v); \ graphene_simd4f_init (__v[0], -__v[1], __v[2], -__v[3]); \ })) # define graphene_simd4f_flip_sign_1010(v) \ (__extension__ ({ \ const graphene_simd4f_t __v = (v); \ graphene_simd4f_init (-__v[0], __v[1], -__v[2], __v[3]); \ })) # define graphene_simd4f_cmp_eq(a,b) \ (__extension__ ({ \ const graphene_simd4i_t __res = (a) == (b); \ (bool) (__res[0] != 0 && \ __res[1] != 0 && \ __res[2] != 0 && \ __res[3] != 0); \ })) # define graphene_simd4f_cmp_neq(a,b) (!graphene_simd4f_cmp_eq (a,b)) # define graphene_simd4f_cmp_lt(a,b) \ (__extension__ ({ \ const graphene_simd4i_t __res = (a) < (b); \ (bool) (__res[0] != 0 && \ __res[1] != 0 && \ __res[2] != 0 && \ __res[3] != 0); \ })) # define graphene_simd4f_cmp_le(a,b) \ (__extension__ ({ \ const graphene_simd4i_t __res = (a) <= (b); \ (bool) (__res[0] != 0 && \ __res[1] != 0 && \ __res[2] != 0 && \ __res[3] != 0); \ })) # define graphene_simd4f_cmp_ge(a,b) \ (__extension__ ({ \ const graphene_simd4i_t __res = (a) >= (b); \ (bool) (__res[0] != 0 && \ __res[1] != 0 && \ __res[2] != 0 && \ __res[3] != 0); \ })) # define graphene_simd4f_cmp_gt(a,b) \ (__extension__ ({ \ const graphene_simd4i_t __res = (a) > (b); \ (bool) (__res[0] != 0 && \ __res[1] != 0 && \ __res[2] != 0 && \ __res[3] != 0); \ })) # define graphene_simd4f_neg(s) \ (__extension__ ({ \ const graphene_simd4f_t __s = (s); \ const graphene_simd4f_t __minus_one = graphene_simd4f_splat (-1.f); \ graphene_simd4f_mul (__s, __minus_one); \ })) #elif !defined(__GI_SCANNER__) && defined(GRAPHENE_USE_ARM_NEON) /* ARM Neon implementation of SIMD4f */ # warning "The ARM Neon implementation of graphene_simd4f_t is experimental." /* Union type used for single lane reading without memcpy */ typedef union { graphene_simd4f_t s; float f[4]; } graphene_simd4f_union_t; /* NEON has optimised 2-lanes vectors we can use */ typedef float32x2_t graphene_simd2f_t; # define graphene_simd4f_init(x,y,z,w) \ (__extension__ ({ \ const float32_t __v[4] = { (x), (y), (z), (w) }; \ (graphene_simd4f_t) vld1q_f32 (__v); \ })) # define graphene_simd4f_init_zero() \ (__extension__ ({ \ (graphene_simd4f_t) vdupq_n_f32 (0.f); \ })) # define graphene_simd4f_init_4f(v) \ (__extension__ ({ \ const float32_t *__v32 = (const float32_t *) (v); \ (graphene_simd4f_t) vld1q_f32 (__v32); \ })) # define graphene_simd4f_init_3f(v) \ (__extension__ ({ \ graphene_simd4f_init (v[0], v[1], v[2], 0.f); \ })) # define graphene_simd4f_init_2f(v) \ (__extension__ ({ \ const float32_t *__v32 = (const float32_t *) (v); \ const graphene_simd2f_t __low = vld1_f32 (__v32); \ const float32_t __zero = 0; \ const graphene_simd2f_t __high = vld1_dup_f32 (&__zero); \ (graphene_simd4f_t) vcombine_f32 (__low, __high); \ })) # define graphene_simd4f_dup_4f(s,v) \ (__extension__ ({ \ vst1q_f32 ((float32_t *) (v), (s)); \ })) # define graphene_simd4f_dup_3f(s,v) \ (__extension__ ({ \ float *__v = (v); \ vst1q_lane_f32 (__v++, (s), 0); \ vst1q_lane_f32 (__v++, (s), 1); \ vst1q_lane_f32 (__v, (s), 2); \ })) # define graphene_simd4f_dup_2f(s,v) \ (__extension__ ({ \ const graphene_simd2f_t __low = vget_low_f32 ((s)); \ vst1_f32 ((float32_t *) (v), __low); \ })) # define graphene_simd4f_get(s,i) \ (__extension__ ({ \ (float) vgetq_lane_f32 ((s), (i)); \ })) # define graphene_simd4f_get_x(s) graphene_simd4f_get (s, 0) # define graphene_simd4f_get_y(s) graphene_simd4f_get (s, 1) # define graphene_simd4f_get_z(s) graphene_simd4f_get (s, 2) # define graphene_simd4f_get_w(s) graphene_simd4f_get (s, 3) # define graphene_simd4f_splat(v) \ (__extension__ ({ \ (graphene_simd4f_t) vdupq_n_f32 ((v)); \ })) # define graphene_simd4f_splat_x(s) \ (__extension__ ({ \ graphene_simd4f_splat (graphene_simd4f_get_x ((s))); \ })) # define graphene_simd4f_splat_y(s) \ (__extension__ ({ \ graphene_simd4f_splat (graphene_simd4f_get_y ((s))); \ })) # define graphene_simd4f_splat_z(s) \ (__extension__ ({ \ graphene_simd4f_splat (graphene_simd4f_get_z ((s))); \ })) # define graphene_simd4f_splat_w(s) \ (__extension__ ({ \ graphene_simd4f_splat (graphene_simd4f_get_w ((s))); \ })) # define graphene_simd4f_reciprocal(s) \ (__extension__ ({ \ graphene_simd4f_t __est = vrecpeq_f32 ((s)); \ __est = vmulq_f32 (vrecpsq_f32 (__est, (s)), __est); \ (graphene_simd4f_t) vmulq_f32 (vrecpsq_f32 (__est, (s)), __est); \ })) # define graphene_simd4f_add(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) vaddq_f32 ((a), (b)); \ })) # define graphene_simd4f_sub(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) vsubq_f32 ((a), (b)); \ })) # define graphene_simd4f_mul(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) vmulq_f32 ((a), (b)); \ })) # define graphene_simd4f_div(a,b) \ (__extension__ ({ \ graphene_simd4f_t __rec = graphene_simd4f_reciprocal ((b)); \ (graphene_simd4f_t) vmulq_f32 ((a), __rec); \ })) # define _simd4f_rsqrt_iter(v,estimate) \ (__extension__ ({ \ const graphene_simd4f_t __est1 = vmulq_f32 ((estimate), (v)); \ (graphene_simd4f_t) vmulq_f32 ((estimate), vrsqrtsq_f32 (__est1, (estimate))); \ })) # define graphene_simd4f_rsqrt(s) \ (__extension__ ({ \ graphene_simd4f_t __estimate = vrsqrteq_f32 ((s)); \ __estimate = _simd4f_rsqrt_iter ((s), __estimate); \ __estimate = _simd4f_rsqrt_iter ((s), __estimate); \ _simd4f_rsqrt_iter ((s), __estimate); \ })) # define graphene_simd4f_sqrt(s) \ (__extension__ ({ \ graphene_simd4f_t __rsq = graphene_simd4f_rsqrt ((s)); \ graphene_simd4f_t __rrsq = graphene_simd4f_reciprocal (__rsq); \ uint32x4_t __tmp = vreinterpretq_u32_f32 ((s)); \ (graphene_simd4f_t) vreinterpretq_f32_u32 (vandq_u32 (vtstq_u32 (__tmp, __tmp), vreinterpretq_u32_f32 (__rrsq))); \ })) # define graphene_simd4f_cross3(a,b) \ (__extension__ ({ \ const uint32_t __mask_bits[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0 }; \ const int32x4_t __mask = vld1q_s32 ((const int32_t *) __mask_bits); \ const graphene_simd4f_t __a = (a), __b = (b); \ const graphene_simd2f_t __a_low = vget_low_f32 (__a); \ const graphene_simd2f_t __b_low = vget_low_f32 (__b); \ const graphene_simd4f_t __a_yzx = vcombine_f32 (vext_f32 (__a_low, vget_high_f32 (__a), 1), __a_low); \ const graphene_simd4f_t __b_yzx = vcombine_f32 (vext_f32 (__b_low, vget_high_f32 (__b), 1), __b_low); \ graphene_simd4f_t __s3 = graphene_simd4f_sub (graphene_simd4f_mul (__b_yzx, __a), \ graphene_simd4f_mul (__a_yzx, __b)); \ graphene_simd2f_t __s3_low = vget_low_f32 (__s3); \ __s3 = vcombine_f32 (vext_f32 (__s3_low, vget_high_f32 (__s3), 1), __s3_low); \ (graphene_simd4f_t) vandq_s32 ((int32x4_t) __s3, __mask); \ })) # define graphene_simd4f_dot3(a,b) \ (__extension__ ({ \ graphene_simd4f_splat (graphene_simd4f_dot3_scalar (a, b)); \ })) # define graphene_simd4f_dot3_scalar(a,b) \ (__extension__ ({ \ const graphene_simd4f_t __m = graphene_simd4f_mul (a, b); \ const graphene_simd2f_t __s1 = vpadd_f32 (vget_low_f32 (__m), vget_low_f32 (__m)); \ (float) vget_lane_f32 (vadd_f32 (__s1, vget_high_f32 (__m)), 0); \ })) # define graphene_simd4f_min(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) vminq_f32 ((a), (b)); \ })) # define graphene_simd4f_max(a,b) \ (__extension__ ({ \ (graphene_simd4f_t) vmaxq_f32 (a, b); \ })) # define graphene_simd4f_shuffle_wxyz(v) \ (__extension__ ({ \ graphene_simd4f_union_t __u = { (v) }; \ graphene_simd4f_init (__u.f[3], __u.f[0], __u.f[1], __u.f[2]); \ })) # define graphene_simd4f_shuffle_zwxy(v) \ (__extension__ ({ \ graphene_simd4f_union_t __u = { (v) }; \ graphene_simd4f_init (__u.f[2], __u.f[3], __u.f[0], __u.f[1]); \ })) # define graphene_simd4f_shuffle_yzwx(v) \ (__extension__ ({ \ graphene_simd4f_union_t __u = { (v) }; \ graphene_simd4f_init (__u.f[1], __u.f[2], __u.f[3], __u.f[0]); \ })) # define graphene_simd4f_zero_w(v) \ (__extension__ ({ \ graphene_simd4f_union_t __u = { (v) }; \ graphene_simd4f_init (__u.f[0], __u.f[1], __u.f[2], 0.f); \ })) # define graphene_simd4f_zero_zw(v) \ (__extension__ ({ \ graphene_simd4f_union_t __u = { (v) }; \ graphene_simd4f_init (__u.f[0], __u.f[1], 0.f, 0.f); \ })) # define graphene_simd4f_merge_w(s,v) \ (__extension__ ({ \ graphene_simd4f_union_t __u = { (s) }; \ graphene_simd4f_init (__u.f[0], __u.f[1], __u.f[2], (v)); \ })) # define graphene_simd4f_merge_high(a,b) \ (__extension__ ({ \ graphene_simd4f_union_t __u_a = { (a) }; \ graphene_simd4f_union_t __u_b = { (b) }; \ graphene_simd4f_init (__u_a.f[2], __u_a.f[3], __u_b.f[2], __u_b.f[3]); \ })) # define graphene_simd4f_merge_low(a,b) \ (__extension__ ({ \ graphene_simd4f_union_t __u_a = { (a) }; \ graphene_simd4f_union_t __u_b = { (b) }; \ graphene_simd4f_init (__u_a.f[0], __u_a.f[1], __u_b.f[0], __u_b.f[1]); \ })) # define graphene_simd4f_flip_sign_0101(s) \ (__extension__ ({ \ const unsigned int __upnpn[4] = { \ 0x00000000, \ 0x80000000, \ 0x00000000, \ 0x80000000 \ }; \ const uint32x4_t __pnpn = vld1q_u32 (__upnpn); \ (graphene_simd4f_t) vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 ((s)), __pnpn)); \ })) # define graphene_simd4f_flip_sign_1010(s) \ (__extension__ ({ \ const unsigned int __unpnp[4] = { \ 0x80000000, \ 0x00000000, \ 0x80000000, \ 0x00000000 \ }; \ const uint32x4_t __npnp = vld1q_u32 (__unpnp); \ (graphene_simd4f_t) vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 ((s)), __npnp)); \ })) # define _graphene_movemask(a) \ (__extension__ ({ \ const int8_t __attribute__ ((aligned (16))) __xr[8] = { -7,-6,-5,-4,-3,-2,-1,0 }; \ const uint8x8_t __mask_and = vdup_n_u8 (0x80); \ const int8x8_t __mask_shift = vld1_s8 (__xr); \ uint8x8_t __lo = vget_low_u8 ((a)); \ uint8x8_t __hi = vget_high_u8 ((a)); \ __lo = vand_u8 (__lo, __mask_and); \ __lo = vshl_u8 (__lo, __mask_shift); \ __hi = vand_u8 (__hi, __mask_and); \ __hi = vshl_u8 (__hi, __mask_shift); \ __lo = vpadd_u8 (__lo, __lo); \ __lo = vpadd_u8 (__lo, __lo); \ __lo = vpadd_u8 (__lo, __lo); \ __hi = vpadd_u8 (__hi, __hi); \ __hi = vpadd_u8 (__hi, __hi); \ __hi = vpadd_u8 (__hi, __hi); \ (bool) ((__hi[0] << 8) | (__lo[0] & 0xff)); \ })) # define graphene_simd4f_cmp_eq(a,b) \ (__extension__ ({ \ const graphene_simd4f_union_t __u_a = { (a) }; \ const graphene_simd4f_union_t __u_b = { (b) }; \ (bool) (__u_a.f[0] == __u_b.f[0] && \ __u_a.f[1] == __u_b.f[1] && \ __u_a.f[2] == __u_b.f[2] && \ __u_a.f[3] == __u_b.f[3]); \ })) # define graphene_simd4f_cmp_neq(a,b) \ (__extension__ ({ \ const graphene_simd4f_union_t __u_a = { (a) }; \ const graphene_simd4f_union_t __u_b = { (b) }; \ (bool) (__u_a.f[0] != __u_b.f[0] && \ __u_a.f[1] != __u_b.f[1] && \ __u_a.f[2] != __u_b.f[2] && \ __u_a.f[3] != __u_b.f[3]); \ })) # define graphene_simd4f_cmp_lt(a,b) \ (__extension__ ({ \ const uint8x16_t __mask = vreinterpretq_u8_u32 (vcltq_f32 ((a), (b))); \ (bool) (_graphene_movemask (__mask) != 0); \ })) # define graphene_simd4f_cmp_le(a,b) \ (__extension__ ({ \ const uint8x16_t __mask = vreinterpretq_u8_u32 (vcleq_f32 ((a), (b))); \ (bool) (_graphene_movemask (__mask) != 0); \ })) # define graphene_simd4f_cmp_ge(a,b) \ (__extension__ ({ \ const uint8x16_t __mask = vreinterpretq_u8_u32 (vcgeq_f32 ((a), (b))); \ (bool) (_graphene_movemask (__mask) != 0); \ })) # define graphene_simd4f_cmp_gt(a,b) \ (__extension__ ({ \ const uint8x16_t __mask = vreinterpretq_u8_u32 (vcgeq_f32 ((a), (b))); \ (bool) (_graphene_movemask (__mask) != 0); \ })) # define graphene_simd4f_neg(s) \ (__extension__ ({ \ const unsigned int __umask[4] = { \ 0x80000000, \ 0x80000000, \ 0x80000000, \ 0x80000000 \ }; \ const uint32x4_t __mask = vld1q_u32 (__umask); \ (graphene_simd4f_t) vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 ((s)), __mask)); \ })) #elif defined(__GI_SCANNER__) || defined(GRAPHENE_USE_SCALAR) /* Fallback implementation using scalar types */ #define graphene_simd4f_init(x,y,z,w) \ (graphene_simd4f_init ((x), (y), (z), (w))) #define graphene_simd4f_init_zero() \ (graphene_simd4f_init_zero ()) #define graphene_simd4f_init_4f(v) \ (graphene_simd4f_init_4f ((const float *) (v))) #define graphene_simd4f_init_3f(v) \ (graphene_simd4f_init_3f ((const float *) (v))) #define graphene_simd4f_init_2f(v) \ (graphene_simd4f_init_2f ((const float *) (v))) #define graphene_simd4f_dup_4f(s,v) \ (graphene_simd4f_dup_4f ((s), (float *) (v))) #define graphene_simd4f_dup_3f(s,v) \ (graphene_simd4f_dup_3f ((s), (float *) (v))) #define graphene_simd4f_dup_2f(s,v) \ (graphene_simd4f_dup_2f ((s), (float *) (v))) #define graphene_simd4f_get(s,i) \ (graphene_simd4f_get ((s), (i))) #define graphene_simd4f_get_x(s) \ (graphene_simd4f_get_x ((s))) #define graphene_simd4f_get_y(s) \ (graphene_simd4f_get_y ((s))) #define graphene_simd4f_get_z(s) \ (graphene_simd4f_get_z ((s))) #define graphene_simd4f_get_w(s) \ (graphene_simd4f_get_w ((s))) #define graphene_simd4f_splat(v) \ (graphene_simd4f_splat ((v))) #define graphene_simd4f_splat_x(s) \ (graphene_simd4f_splat_x ((s))) #define graphene_simd4f_splat_y(s) \ (graphene_simd4f_splat_y ((s))) #define graphene_simd4f_splat_z(s) \ (graphene_simd4f_splat_z ((s))) #define graphene_simd4f_splat_w(s) \ (graphene_simd4f_splat_w ((s))) #define graphene_simd4f_add(a,b) \ (graphene_simd4f_add ((a), (b))) #define graphene_simd4f_sub(a,b) \ (graphene_simd4f_sub ((a), (b))) #define graphene_simd4f_mul(a,b) \ (graphene_simd4f_mul ((a), (b))) #define graphene_simd4f_div(a,b) \ (graphene_simd4f_div ((a), (b))) #define graphene_simd4f_sqrt(s) \ (graphene_simd4f_sqrt ((s))) #define graphene_simd4f_rsqrt(s) \ (graphene_simd4f_rsqrt ((s))) #define graphene_simd4f_reciprocal(s) \ (graphene_simd4f_reciprocal ((s))) #define graphene_simd4f_cross3(a,b) \ (graphene_simd4f_cross3 ((a), (b))) #define graphene_simd4f_dot3(a,b) \ (graphene_simd4f_dot3 ((a), (b))) #define graphene_simd4f_dot3_scalar(a,b) \ (graphene_simd4f_dot3_scalar ((a), (b))) #define graphene_simd4f_min(a,b) \ (graphene_simd4f_min ((a), (b))) #define graphene_simd4f_max(a,b) \ (graphene_simd4f_max ((a), (b))) #define graphene_simd4f_shuffle_wxyz(s) \ (graphene_simd4f_shuffle_wxyz ((s))) #define graphene_simd4f_shuffle_zwxy(s) \ (graphene_simd4f_shuffle_zwxy ((s))) #define graphene_simd4f_shuffle_yzwx(s) \ (graphene_simd4f_shuffle_yzwx ((s))) #define graphene_simd4f_flip_sign_0101(s) \ (graphene_simd4f_flip_sign_0101 ((s))) #define graphene_simd4f_flip_sign_1010(s) \ (graphene_simd4f_flip_sign_1010 ((s))) #define graphene_simd4f_zero_w(v) \ (graphene_simd4f_zero_w ((v))) #define graphene_simd4f_zero_zw(v) \ (graphene_simd4f_zero_zw ((v))) #define graphene_simd4f_merge_w(s,v) \ (graphene_simd4f_merge_w ((s), (v))) #define graphene_simd4f_merge_high(a,b) \ (graphene_simd4f_merge_high ((a), (b))) #define graphene_simd4f_merge_low(a,b) \ (graphene_simd4f_merge_low ((a), (b))) #define graphene_simd4f_cmp_eq(a,b) \ (graphene_simd4f_cmp_eq ((a), (b))) #define graphene_simd4f_cmp_neq(a,b) \ (graphene_simd4f_cmp_neq ((a), (b))) #define graphene_simd4f_cmp_lt(a,b) \ (graphene_simd4f_cmp_lt ((a), (b))) #define graphene_simd4f_cmp_le(a,b) \ (graphene_simd4f_cmp_le ((a), (b))) #define graphene_simd4f_cmp_ge(a,b) \ (graphene_simd4f_cmp_ge ((a), (b))) #define graphene_simd4f_cmp_gt(a,b) \ (graphene_simd4f_cmp_gt ((a), (b))) #define graphene_simd4f_neg(s) \ (graphene_simd4f_neg ((s))) #else # error "Unsupported simd4f implementation." #endif /* Generic operations, inlined */ /** * graphene_simd4f_madd: * @m1: a #graphene_simd4f_t * @m2: a #graphene_simd4f_t * @a: a #graphene_simd4f_t * * Adds @a to the product of @m1 and @m2. * * Returns: the result vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_madd (const graphene_simd4f_t m1, const graphene_simd4f_t m2, const graphene_simd4f_t a) { return graphene_simd4f_add (graphene_simd4f_mul (m1, m2), a); } /** * graphene_simd4f_sum: * @v: a #graphene_simd4f_t * * Sums all components of the given vector. * * Returns: a vector with all components set to be the * sum of the passed #graphene_simd4f_t * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_sum (const graphene_simd4f_t v) { const graphene_simd4f_t x = graphene_simd4f_splat_x (v); const graphene_simd4f_t y = graphene_simd4f_splat_y (v); const graphene_simd4f_t z = graphene_simd4f_splat_z (v); const graphene_simd4f_t w = graphene_simd4f_splat_w (v); return graphene_simd4f_add (graphene_simd4f_add (x, y), graphene_simd4f_add (z, w)); } /** * graphene_simd4f_sum_scalar: * @v: a #graphene_simd4f_t * * Sums all the components of the given vector. * * Returns: a scalar value with the sum of the components * of the given #graphene_simd4f_t * * Since: 1.0 */ static inline float graphene_simd4f_sum_scalar (const graphene_simd4f_t v) { return graphene_simd4f_get_x (graphene_simd4f_sum (v)); } /** * graphene_simd4f_dot4: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Computes the dot product of all the components of the two * given #graphene_simd4f_t. * * Returns: a vector whose components are all set to be the * dot product of the components of the two operands * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_dot4 (const graphene_simd4f_t a, const graphene_simd4f_t b) { return graphene_simd4f_sum (graphene_simd4f_mul (a, b)); } /** * graphene_simd4f_dot2: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * * Computes the dot product of the first two components of the * two given #graphene_simd4f_t. * * Returns: a vector whose components are all set to the * dot product of the components of the two operands * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_dot2 (const graphene_simd4f_t a, const graphene_simd4f_t b) { const graphene_simd4f_t m = graphene_simd4f_mul (a, b); const graphene_simd4f_t x = graphene_simd4f_splat_x (m); const graphene_simd4f_t y = graphene_simd4f_splat_y (m); return graphene_simd4f_add (x, y); } /** * graphene_simd4f_length4: * @v: a #graphene_simd4f_t * * Computes the length of the given #graphene_simd4f_t vector, * using all four of its components. * * Returns: the length vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_length4 (const graphene_simd4f_t v) { return graphene_simd4f_sqrt (graphene_simd4f_dot4 (v, v)); } /** * graphene_simd4f_length3: * @v: a #graphene_simd4f_t * * Computes the length of the given #graphene_simd4f_t vector, * using the first three of its components. * * Returns: the length vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_length3 (const graphene_simd4f_t v) { return graphene_simd4f_sqrt (graphene_simd4f_dot3 (v, v)); } /** * graphene_simd4f_length2: * @v: a #graphene_simd4f_t * * Computes the length of the given #graphene_simd4f_t vector, * using the first two of its components. * * Returns: the length vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_length2 (const graphene_simd4f_t v) { return graphene_simd4f_sqrt (graphene_simd4f_dot2 (v, v)); } /** * graphene_simd4f_normalize4: * @v: a #graphene_simd4f_t * * Computes the normalization of the given #graphene_simd4f_t vector, * using all of its components. * * Returns: the normalized vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_normalize4 (const graphene_simd4f_t v) { graphene_simd4f_t invlen = graphene_simd4f_rsqrt (graphene_simd4f_dot4 (v, v)); return graphene_simd4f_mul (v, invlen); } /** * graphene_simd4f_normalize3: * @v: a #graphene_simd4f_t * * Computes the normalization of the given #graphene_simd4f_t vector, * using the first three of its components. * * Returns: the normalized vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_normalize3 (const graphene_simd4f_t v) { graphene_simd4f_t invlen = graphene_simd4f_rsqrt (graphene_simd4f_dot3 (v, v)); return graphene_simd4f_mul (v, invlen); } /** * graphene_simd4f_normalize2: * @v: a #graphene_simd4f_t * * Computes the normalization of the given #graphene_simd4f_t vector, * using the first two of its components. * * Returns: the normalized vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_normalize2 (const graphene_simd4f_t v) { graphene_simd4f_t invlen = graphene_simd4f_rsqrt (graphene_simd4f_dot2 (v, v)); return graphene_simd4f_mul (v, invlen); } /** * graphene_simd4f_is_zero4: * @v: a #graphene_simd4f_t * * Checks whether the given #graphene_simd4f_t has all its components * set to 0. * * Returns: `true` if all the vector components are zero * * Since: 1.0 */ static inline bool graphene_simd4f_is_zero4 (const graphene_simd4f_t v) { graphene_simd4f_t zero = graphene_simd4f_init_zero (); return graphene_simd4f_cmp_eq (v, zero); } /** * graphene_simd4f_is_zero3: * @v: a #graphene_simd4f_t * * Checks whether the given #graphene_simd4f_t has the first three of * its components set to 0. * * Returns: `true` if the vector's components are zero * * Since: 1.0 */ static inline bool graphene_simd4f_is_zero3 (const graphene_simd4f_t v) { return graphene_simd4f_get_x (v) == 0.f && graphene_simd4f_get_y (v) == 0.f && graphene_simd4f_get_z (v) == 0.f; } /** * graphene_simd4f_is_zero2: * @v: a #graphene_simd4f_t * * Checks whether the given #graphene_simd4f_t has the first two of * its components set to 0. * * Returns: `true` if the vector's components are zero * * Since: 1.0 */ static inline bool graphene_simd4f_is_zero2 (const graphene_simd4f_t v) { return graphene_simd4f_get_x (v) == 0.f && graphene_simd4f_get_y (v) == 0.f; } /** * graphene_simd4f_interpolate: * @a: a #graphene_simd4f_t * @b: a #graphene_simd4f_t * @f: the interpolation factor * * Linearly interpolates all components of the two given * #graphene_simd4f_t vectors using the given factor @f. * * Returns: the intrerpolated vector * * Since: 1.0 */ static inline graphene_simd4f_t graphene_simd4f_interpolate (const graphene_simd4f_t a, const graphene_simd4f_t b, float f) { const graphene_simd4f_t one_minus_f = graphene_simd4f_sub (graphene_simd4f_splat (1.f), graphene_simd4f_splat (f)); return graphene_simd4f_add (graphene_simd4f_mul (one_minus_f, a), graphene_simd4f_mul (graphene_simd4f_splat (f), b)); } /** * graphene_simd4f_clamp: * @v: a #graphene_simd4f_t * @min: the lower boundary * @max: the upper boundary * * Ensures that all components of the vector @v are within * the components of the @lower and @upper boundaries. * * Returns: the clamped vector * * Since: 1.2 */ static inline graphene_simd4f_t graphene_simd4f_clamp (const graphene_simd4f_t v, const graphene_simd4f_t min, const graphene_simd4f_t max) { const graphene_simd4f_t tmp = graphene_simd4f_max (min, v); return graphene_simd4f_min (tmp, max); } /** * graphene_simd4f_clamp_scalar: * @v: a #graphene_simd4f_t * @min: the lower boundary * @max: the upper boundary * * Ensures that all components of the vector @v are within * the @lower and @upper boundary scalar values. * * Returns: the clamped vector * * Since: 1.2 */ static inline graphene_simd4f_t graphene_simd4f_clamp_scalar (const graphene_simd4f_t v, float min, float max) { return graphene_simd4f_clamp (v, graphene_simd4f_splat (min), graphene_simd4f_splat (max)); } /** * graphene_simd4f_min_val: * @v: a #graphene_simd4f_t * * Computes the minimum value of all the channels in the given vector. * * Returns: a vector whose components are all set to the * minimum value in the original vector * * Since: 1.4 */ static inline graphene_simd4f_t graphene_simd4f_min_val (const graphene_simd4f_t v) { graphene_simd4f_t s = v; s = graphene_simd4f_min (s, graphene_simd4f_shuffle_wxyz (s)); s = graphene_simd4f_min (s, graphene_simd4f_shuffle_zwxy (s)); return s; } /** * graphene_simd4f_max_val: * @v: a #graphene_simd4f_t * * Computes the maximum value of all the channels in the given vector. * * Returns: a vector whose components are all set to the * maximum value in the original vector * * Since: 1.4 */ static inline graphene_simd4f_t graphene_simd4f_max_val (const graphene_simd4f_t v) { graphene_simd4f_t s = v; s = graphene_simd4f_max (s, graphene_simd4f_shuffle_wxyz (s)); s = graphene_simd4f_max (s, graphene_simd4f_shuffle_zwxy (s)); return s; } GRAPHENE_END_DECLS #endif /* __GRAPHENE_SIMD4F_H__ */ graphene-1.8.0/src/graphene-simd4x4f.c000066400000000000000000000047021324365266600175150ustar00rootroot00000000000000/* graphene-simd4x4f.c * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-simd4x4f * @Title: SIMD matrix * @short_description: Low level floating point 4 by 4 matrix * * The #graphene_simd4x4f_t type wraps a platform specific implementation of * a four by four matrix of floating point values, using four #graphene_simd4f_t * row vectors. * * Like #graphene_simd4f_t, the #graphene_simd4x4f_t type should be treated * as an opaque type; you cannot access its components directly, and you can * only operate on all components at the same time. */ #include "graphene-private.h" #include "graphene-simd4x4f.h" #include #include #if defined(GRAPHENE_USE_SSE) || defined(GRAPHENE_USE_GCC) || defined(GRAPHENE_USE_ARM_NEON) /** * graphene_simd4x4f_transpose_in_place: * @s: a #graphene_simd4x4f_t * * Transposes @s in place. * * Since: 1.0 */ void (graphene_simd4x4f_transpose_in_place) (graphene_simd4x4f_t *s) { graphene_simd4x4f_transpose_in_place (s); } #else void (graphene_simd4x4f_transpose_in_place) (graphene_simd4x4f_t *s) { graphene_simd4x4f_t m = *s; s->x.x = m.x.x; s->x.y = m.y.x; s->x.z = m.z.x; s->x.w = m.w.x; s->y.x = m.x.y; s->y.y = m.y.y; s->y.z = m.z.y; s->y.w = m.w.y; s->z.x = m.x.z; s->z.y = m.y.z; s->z.z = m.z.z; s->z.w = m.w.z; s->w.x = m.x.w; s->w.y = m.y.w; s->w.z = m.z.w; s->w.w = m.w.w; } #endif graphene-1.8.0/src/graphene-simd4x4f.h000066400000000000000000001106551324365266600175270ustar00rootroot00000000000000/* graphene-simd4x4f.h: 4x4 float vector operations * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_SIMD4X4F_H__ #define __GRAPHENE_SIMD4X4F_H__ #include "graphene-simd4f.h" #include #include GRAPHENE_BEGIN_DECLS /** * graphene_simd4x4f_t: * * A SIMD-based matrix type that uses four #graphene_simd4f_t vectors. * * The matrix is treated as row-major, i.e. the x, y, z, and w vectors * are rows, and elements of each vector are a column: * * |[ * graphene_simd4x4f_t = { * x.x, x.y, x.z, x.w, * y.x, y.y, y.z, y.w, * z.x, z.y, z.z, z.w, * w.x, w.y, w.z, w.w * } * ]| * * The contents of the #graphene_simd4x4f_t type are private and * cannot be accessed directly; use the provided API instead. * * Since: 1.0 */ /** * graphene_simd4x4f_init: * @x: a #graphene_simd4f_t for the first row * @y: a #graphene_simd4f_t for the second row * @z: a #graphene_simd4f_t for the third row * @w: a #graphene_simd4f_t for the fourth row * * Creates a new #graphene_simd4x4f_t using the given row vectors * to initialize it. * * Returns: the newly created #graphene_simd4x4f_t * * Since: 1.0 */ static inline graphene_simd4x4f_t GRAPHENE_VECTORCALL graphene_simd4x4f_init (graphene_simd4f_t x, graphene_simd4f_t y, graphene_simd4f_t z, graphene_simd4f_t w) { graphene_simd4x4f_t s; s.x = x; s.y = y; s.z = z; s.w = w; return s; } /** * graphene_simd4x4f_init_identity: * @m: a #graphene_simd4x4f_t * * Initializes @m to be the identity matrix. * * Since: 1.0 */ static inline void graphene_simd4x4f_init_identity (graphene_simd4x4f_t *m) { *m = graphene_simd4x4f_init (graphene_simd4f_init (1.0f, 0.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 1.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 1.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 0.0f, 1.0f)); } /** * graphene_simd4x4f_init_from_float: * @m: a #graphene_simd4x4f_t * @f: (array fixed-size=16): an array of 16 floating point values * * Initializes a #graphene_simd4x4f_t with the given array * of floating point values. * * Since: 1.0 */ static inline void graphene_simd4x4f_init_from_float (graphene_simd4x4f_t *m, const float *f) { m->x = graphene_simd4f_init_4f (f + 0); m->y = graphene_simd4f_init_4f (f + 4); m->z = graphene_simd4f_init_4f (f + 8); m->w = graphene_simd4f_init_4f (f + 12); } /** * graphene_simd4x4f_to_float: * @m: a #graphene_sidm4x4f_t * @v: (out caller-allocates) (array fixed-size=16): a floating * point values vector capable of holding at least 16 values * * Copies the content of @m in a float array. * * Since: 1.0 */ static inline void graphene_simd4x4f_to_float (const graphene_simd4x4f_t *m, float *v) { graphene_simd4f_dup_4f (m->x, v + 0); graphene_simd4f_dup_4f (m->y, v + 4); graphene_simd4f_dup_4f (m->z, v + 8); graphene_simd4f_dup_4f (m->w, v + 12); } GRAPHENE_AVAILABLE_IN_1_0 void graphene_simd4x4f_transpose_in_place (graphene_simd4x4f_t *s); #if defined(GRAPHENE_USE_SSE) #ifdef __GNUC__ #define graphene_simd4x4f_transpose_in_place(s) \ (__extension__ ({ \ _MM_TRANSPOSE4_PS ((s)->x, (s)->y, (s)->z, (s)->w); \ })) #elif defined (_MSC_VER) #define graphene_simd4x4f_transpose_in_place(s) \ _MM_TRANSPOSE4_PS ((s)->x, (s)->y, (s)->z, (s)->w) #endif #elif defined(GRAPHENE_USE_GCC) #define graphene_simd4x4f_transpose_in_place(s) \ (__extension__ ({ \ const graphene_simd4f_t sx = (s)->x; \ const graphene_simd4f_t sy = (s)->y; \ const graphene_simd4f_t sz = (s)->z; \ const graphene_simd4f_t sw = (s)->w; \ (s)->x = graphene_simd4f_init (sx[0], sy[0], sz[0], sw[0]); \ (s)->y = graphene_simd4f_init (sx[1], sy[1], sz[1], sw[1]); \ (s)->z = graphene_simd4f_init (sx[2], sy[2], sz[2], sw[2]); \ (s)->w = graphene_simd4f_init (sx[3], sy[3], sz[3], sw[3]); \ })) #elif defined(GRAPHENE_USE_ARM_NEON) #define graphene_simd4x4f_transpose_in_place(s) \ (__extension__ ({ \ const graphene_simd4f_union_t sx = { (s)->x }; \ const graphene_simd4f_union_t sy = { (s)->y }; \ const graphene_simd4f_union_t sz = { (s)->z }; \ const graphene_simd4f_union_t sw = { (s)->w }; \ (s)->x = graphene_simd4f_init (sx.f[0], sy.f[0], sz.f[0], sw.f[0]); \ (s)->y = graphene_simd4f_init (sx.f[1], sy.f[1], sz.f[1], sw.f[1]); \ (s)->z = graphene_simd4f_init (sx.f[2], sy.f[2], sz.f[2], sw.f[2]); \ (s)->w = graphene_simd4f_init (sx.f[3], sy.f[3], sz.f[3], sw.f[3]); \ })) #elif defined(GRAPHENE_USE_SCALAR) #define graphene_simd4x4f_transpose_in_place(s) \ (graphene_simd4x4f_transpose_in_place ((graphene_simd4x4f_t *) (s))) #else # error "No implementation for graphene_simd4x4f_t defined." #endif /** * graphene_simd4x4f_sum: * @a: a #graphene_simd4f_t * @res: (out): return location for the sum vector * * Adds all the row vectors of @a. * * Since: 1.0 */ static inline void graphene_simd4x4f_sum (const graphene_simd4x4f_t *a, graphene_simd4f_t *res) { graphene_simd4f_t s = graphene_simd4f_add (a->x, a->y); s = graphene_simd4f_add (s, a->z); s = graphene_simd4f_add (s, a->w); *res = s; } /** * graphene_simd4x4f_vec4_mul: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4f_t * @res: (out): return location for a #graphene_simd4f_t * * Multiplies the given #graphene_simd4x4f_t with the given * #graphene_simd4f_t using a dot product. * * Since: 1.0 */ static inline void graphene_simd4x4f_vec4_mul (const graphene_simd4x4f_t *a, const graphene_simd4f_t *b, graphene_simd4f_t *res) { const graphene_simd4f_t v = *b; const graphene_simd4f_t v_x = graphene_simd4f_splat_x (v); const graphene_simd4f_t v_y = graphene_simd4f_splat_y (v); const graphene_simd4f_t v_z = graphene_simd4f_splat_z (v); const graphene_simd4f_t v_w = graphene_simd4f_splat_w (v); *res = graphene_simd4f_add (graphene_simd4f_add (graphene_simd4f_mul (a->x, v_x), graphene_simd4f_mul (a->y, v_y)), graphene_simd4f_add (graphene_simd4f_mul (a->z, v_z), graphene_simd4f_mul (a->w, v_w))); } /** * graphene_simd4x4f_vec3_mul: * @m: a #graphene_simd4x4f_t * @v: a #graphene_simd4f_t * @res: (out): return location for a #graphene_simd4f_t * * Multiplies the given #graphene_simd4x4f_t with the given * #graphene_simd4f_t, using only the first three row vectors * of the matrix, and the first three components of the vector. * * Since: 1.0 */ static inline void graphene_simd4x4f_vec3_mul (const graphene_simd4x4f_t *m, const graphene_simd4f_t *v, graphene_simd4f_t *res) { const graphene_simd4f_t v_x = graphene_simd4f_splat_x (*v); const graphene_simd4f_t v_y = graphene_simd4f_splat_y (*v); const graphene_simd4f_t v_z = graphene_simd4f_splat_z (*v); *res = graphene_simd4f_add (graphene_simd4f_add (graphene_simd4f_mul (m->x, v_x), graphene_simd4f_mul (m->y, v_y)), graphene_simd4f_mul (m->z, v_z)); } /** * graphene_simd4x4f_point3_mul: * @m: a #graphene_simd4x4f_t * @p: a #graphene_simd4f_t * @res: (out): return location for a #graphene_simd4f_t * * Multiplies the given #graphene_simd4x4f_t with the given * #graphene_simd4f_t. * * Unlike graphene_simd4x4f_vec3_mul(), this function will * also use the fourth row vector of the matrix. * * Since: 1.0 */ static inline void graphene_simd4x4f_point3_mul (const graphene_simd4x4f_t *m, const graphene_simd4f_t *p, graphene_simd4f_t *res) { const graphene_simd4f_t v = *p; const graphene_simd4f_t v_x = graphene_simd4f_splat_x (v); const graphene_simd4f_t v_y = graphene_simd4f_splat_y (v); const graphene_simd4f_t v_z = graphene_simd4f_splat_z (v); *res = graphene_simd4f_add (graphene_simd4f_add (graphene_simd4f_mul (m->x, v_x), graphene_simd4f_mul (m->y, v_y)), graphene_simd4f_add (graphene_simd4f_mul (m->z, v_z), m->w)); } /** * graphene_simd4x4f_transpose: * @s: a #graphene_simd4x4f_t * @res: (out): return location for the transposed matrix * * Transposes the given #graphene_simd4x4f_t. * * Since: 1.0 */ static inline void graphene_simd4x4f_transpose (const graphene_simd4x4f_t *s, graphene_simd4x4f_t *res) { *res = *s; graphene_simd4x4f_transpose_in_place (res); } /** * graphene_simd4x4f_inv_ortho_vec3_mul: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4f_t * @res: (out): return location for the transformed vector * * Performs the inverse orthographic transformation of the first * three components in the given vector, using the first three * row vectors of the given SIMD matrix. * * Since: 1.0 */ static inline void graphene_simd4x4f_inv_ortho_vec3_mul (const graphene_simd4x4f_t *a, const graphene_simd4f_t *b, graphene_simd4f_t *res) { graphene_simd4x4f_t transpose = *a; graphene_simd4f_t translation = *b; transpose.w = graphene_simd4f_init (0.f, 0.f, 0.f, 0.f); graphene_simd4x4f_transpose_in_place (&transpose); graphene_simd4x4f_vec3_mul (&transpose, &translation, res); } /** * graphene_simd4x4f_inv_ortho_point3_mul: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4x4f_t * @res: (out): return location for the result vector * * Performs the inverse orthographic transformation of the first * three components in the given vector, using the given SIMD * matrix. * * Unlike graphene_simd4x4f_inv_ortho_vec3_mul(), this function * will also use the fourth row vector of the SIMD matrix. * * Since: 1.0 */ static inline void graphene_simd4x4f_inv_ortho_point3_mul (const graphene_simd4x4f_t *a, const graphene_simd4f_t *b, graphene_simd4f_t *res) { graphene_simd4f_t translation = graphene_simd4f_sub (*b, a->w); graphene_simd4x4f_t transpose = *a; transpose.w = graphene_simd4f_init (0.f, 0.f, 0.f, 0.f); graphene_simd4x4f_transpose_in_place (&transpose); graphene_simd4x4f_point3_mul (&transpose, &translation, res); } /** * graphene_simd4x4f_matrix_mul: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4x4f_t * @res: (out): return location for the result * * Multiplies the two matrices. * * Since: 1.0 */ static inline void graphene_simd4x4f_matrix_mul (const graphene_simd4x4f_t *a, const graphene_simd4x4f_t *b, graphene_simd4x4f_t *res) { #if 0 /* this is the classic naive A*B implementation of the row * column * matrix product. using a SIMD scalar implementation, it's fairly * slow at 329ns per multiplication; the SSE implementation makes it * about 10x faster, at 32ns; the GCC vector implementation is only * 5x faster, at 66ns. the biggest culprits are the transpose operation * and the multiple, one lane reads to compute the scalar sum. */ graphene_simd4x4f_t t; graphene_simd4x4f_transpose (b, &t); res->x = graphene_simd4f_init (graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->x, t.x)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->x, t.y)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->x, t.z)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->x, t.w))); res->y = graphene_simd4f_init (graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->y, t.x)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->y, t.y)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->y, t.z)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->y, t.w))); res->z = graphene_simd4f_init (graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->z, t.x)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->z, t.y)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->z, t.z)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->z, t.w))); res->w = graphene_simd4f_init (graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->w, t.x)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->w, t.y)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->w, t.z)), graphene_simd4f_sum_scalar (graphene_simd4f_mul (a->w, t.w))); #else /* this is an optimized version of the matrix multiplication, using * four dot products for each row vector. this yields drastically * better numbers while retaining the same correct results as above: * the scalar implementation now clocks at 91ns; the GCC vector * implementation is 19ns; and the SSE implementation is 16ns. * * the order is correct if we want to multiply A with B; remember * that matrix multiplication is non-commutative. */ graphene_simd4x4f_vec4_mul (b, &a->x, &res->x); graphene_simd4x4f_vec4_mul (b, &a->y, &res->y); graphene_simd4x4f_vec4_mul (b, &a->z, &res->z); graphene_simd4x4f_vec4_mul (b, &a->w, &res->w); #endif } /** * graphene_simd4x4f_init_perspective: * @m: a #graphene_simd4x4f_t * @fovy_rad: the angle of the field of vision, in radians * @aspect: the aspect value * @z_near: the depth of the near clipping plane * @z_far: the depth of the far clipping plane * * Initializes a #graphene_simd4x4f_t with a perspective projection. * * Since: 1.0 */ static inline void graphene_simd4x4f_init_perspective (graphene_simd4x4f_t *m, float fovy_rad, float aspect, float z_near, float z_far) { float delta_z = z_far - z_near; float cotangent = tanf (GRAPHENE_PI_2 - fovy_rad * 0.5f); float a = cotangent / aspect; float b = cotangent; float c = -(z_far + z_near) / delta_z; float d = -2 * z_near * z_far / delta_z; m->x = graphene_simd4f_init ( a, 0.0f, 0.0f, 0.0f); m->y = graphene_simd4f_init (0.0f, b, 0.0f, 0.0f); m->z = graphene_simd4f_init (0.0f, 0.0f, c, -1.0f); m->w = graphene_simd4f_init (0.0f, 0.0f, d, 0.0f); } /** * graphene_simd4x4f_init_ortho: * @m: a #graphene_simd4x4f_t * @left: edge of the left clipping plane * @right: edge of the right clipping plane * @bottom: edge of the bottom clipping plane * @top: edge of the top clipping plane * @z_near: depth of the near clipping plane * @z_far: depth of the far clipping plane * * Initializes the given SIMD matrix with an orthographic projection. * * Since: 1.0 */ static inline void graphene_simd4x4f_init_ortho (graphene_simd4x4f_t *m, float left, float right, float bottom, float top, float z_near, float z_far) { float delta_x = right - left; float delta_y = top - bottom; float delta_z = z_far - z_near; float a = 2.0f / delta_x; float b = -(right + left) / delta_x; float c = 2.0f / delta_y; float d = -(top + bottom) / delta_y; float e = -2.0f / delta_z; float f = -(z_far + z_near) / delta_z; m->x = graphene_simd4f_init ( a, 0.0f, 0.0f, 0.0f); m->y = graphene_simd4f_init (0.0f, c, 0.0f, 0.0f); m->z = graphene_simd4f_init (0.0f, 0.0f, e, 0.0f); m->w = graphene_simd4f_init ( b, d, f, 1.0f); } /** * graphene_simd4x4f_init_look_at: * @m: a #graphene_simd4x4f_t * @eye: vector for the camera coordinates * @center: vector for the object coordinates * @up: vector for the upwards direction * * Initializes a SIMD matrix with the projection necessary for * the camera at the @eye coordinates to look at the object at * the @center coordinates. The top of the camera is aligned to * the @up vector. * * Since: 1.0 */ static inline void graphene_simd4x4f_init_look_at (graphene_simd4x4f_t *m, graphene_simd4f_t eye, graphene_simd4f_t center, graphene_simd4f_t up) { const graphene_simd4f_t z_axis = graphene_simd4f_normalize3 (graphene_simd4f_sub (center, eye)); const graphene_simd4f_t x_axis = graphene_simd4f_normalize3 (graphene_simd4f_cross3 (z_axis, up)); const graphene_simd4f_t y_axis = graphene_simd4f_cross3 (x_axis, z_axis); float eye_v[4]; graphene_simd4f_dup_4f (eye, eye_v); m->x = x_axis; m->y = y_axis; m->z = graphene_simd4f_neg (z_axis); m->w = graphene_simd4f_init (-eye_v[0], -eye_v[1], -eye_v[2], 1.f); } /** * graphene_simd4x4f_init_frustum: * @m: a #graphene_simd4x4f_t * @left: distance of the left clipping plane * @right: distance of the right clipping plane * @bottom: distance of the bottom clipping plane * @top: distance of the top clipping plane * @z_near: distance of the near clipping plane * @z_far: distance of the far clipping plane * * Initializes a SIMD matrix with a frustum described by the distances * of six clipping planes. * * Since: 1.2 */ static inline void graphene_simd4x4f_init_frustum (graphene_simd4x4f_t *m, float left, float right, float bottom, float top, float z_near, float z_far) { float x = 2.f * z_near / (right - left); float y = 2.f * z_near / (top - bottom); float a = (right + left) / (right - left); float b = (top + bottom) / (top - bottom); float c = -1.f * (z_far + z_near) / (z_far - z_near); float d = -2.f * z_far * z_near / (z_far - z_near); m->x = graphene_simd4f_init ( x, 0.f, 0.f, 0.f); m->y = graphene_simd4f_init (0.f, y, 0.f, 0.f); m->z = graphene_simd4f_init ( a, b, c, -1.f); m->w = graphene_simd4f_init (0.f, 0.f, d, 0.f); } /** * graphene_simd4x4f_perspective: * @m: a #graphene_simd4x4f_t * @depth: depth of the perspective * * Adds a perspective transformation for the given @depth. * * Since: 1.0 */ static inline void graphene_simd4x4f_perspective (graphene_simd4x4f_t *m, float depth) { #if 1 const float m_xw = graphene_simd4f_get_w (m->x); const float m_yw = graphene_simd4f_get_w (m->y); const float m_zw = graphene_simd4f_get_w (m->z); const float m_ww = graphene_simd4f_get_w (m->w); const float p0 = graphene_simd4f_get_z (m->x) + -1.0f / depth * m_xw; const float p1 = graphene_simd4f_get_z (m->y) + -1.0f / depth * m_yw; const float p2 = graphene_simd4f_get_z (m->z) + -1.0f / depth * m_zw; const float p3 = graphene_simd4f_get_z (m->w) + -1.0f / depth * m_ww; const graphene_simd4f_t p_x = graphene_simd4f_merge_w (m->x, m_xw + p0); const graphene_simd4f_t p_y = graphene_simd4f_merge_w (m->y, m_yw + p1); const graphene_simd4f_t p_z = graphene_simd4f_merge_w (m->z, m_zw + p2); const graphene_simd4f_t p_w = graphene_simd4f_merge_w (m->w, m_ww + p3); #else /* this is equivalent to the operations above, but trying to inline * them into SIMD registers as much as possible by transposing the * original matrix and operating on the resulting column vectors. it * should warrant a micro benchmark, because while the above code is * dominated by single channel reads, the code below has a transpose * operation. */ graphene_simd4x4f_t t; const graphene_simd4f_t f, p; const graphene_simd4f_t p_x, p_y, p_z, p_w; graphene_simd4x4f_transpose (m, &t); f = graphene_simd4f_neg (graphene_simd4f_reciprocal (graphene_simd4f_splat (depth))); p = graphene_simd4f_sum (t.w, graphene_simd4f_sum (t.z, graphene_simd4f_mul (f, t.w))); p_x = graphene_simd4f_merge_w (m->x, graphene_simd4f_get_x (p)); p_y = graphene_simd4f_merge_w (m->y, graphene_simd4f_get_y (p)); p_z = graphene_simd4f_merge_w (m->z, graphene_simd4f_get_z (p)); p_w = graphene_simd4f_merge_w (m->w, graphene_simd4f_get_w (p)); #endif *m = graphene_simd4x4f_init (p_x, p_y, p_z, p_w); } /** * graphene_simd4x4f_translation: * @m: a #graphene_simd4x4f_t * @x: coordinate of the X translation * @y: coordinate of the Y translation * @z: coordinate of the Z translation * * Initializes @m to contain a translation to the given coordinates. * * Since: 1.0 */ static inline void graphene_simd4x4f_translation (graphene_simd4x4f_t *m, float x, float y, float z) { *m = graphene_simd4x4f_init (graphene_simd4f_init (1.0f, 0.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 1.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 1.0f, 0.0f), graphene_simd4f_init ( x, y, z, 1.0f)); } /** * graphene_simd4x4f_scale: * @m: a #graphene_simd4x4f_t * @x: scaling factor on the X axis * @y: scaling factor on the Y axis * @z: scaling factor on the Z axis * * Initializes @m to contain a scaling transformation with the * given factors. * * Since: 1.0 */ static inline void graphene_simd4x4f_scale (graphene_simd4x4f_t *m, float x, float y, float z) { *m = graphene_simd4x4f_init (graphene_simd4f_init ( x, 0.0f, 0.0f, 0.0f), graphene_simd4f_init (0.0f, y, 0.0f, 0.0f), graphene_simd4f_init (0.0f, 0.0f, z, 0.0f), graphene_simd4f_init (0.0f, 0.0f, 0.0f, 1.0f)); } /** * graphene_simd4x4f_rotation: * @m: a #graphene_simd4x4f_t * @rad: the rotation, in radians * @axis: the vector of the axis of rotation * * Initializes @m to contain a rotation of the given angle * along the given axis. * * Since: 1.0 */ static inline void graphene_simd4x4f_rotation (graphene_simd4x4f_t *m, float rad, graphene_simd4f_t axis) { float sine, cosine; float x, y, z; float ab, bc, ca; float tx, ty, tz; graphene_simd4f_t i, j, k; rad = -rad; axis = graphene_simd4f_normalize3 (axis); /* We cannot use graphene_sincos() because it's a private function, whereas * graphene-simd4x4f.h is a public header */ sine = sinf (rad); cosine = cosf (rad); x = graphene_simd4f_get_x (axis); y = graphene_simd4f_get_y (axis); z = graphene_simd4f_get_z (axis); ab = x * y * (1.0f - cosine); bc = y * z * (1.0f - cosine); ca = z * x * (1.0f - cosine); tx = x * x; ty = y * y; tz = z * z; i = graphene_simd4f_init (tx + cosine * (1.0f - tx), ab - z * sine, ca + y * sine, 0.f); j = graphene_simd4f_init (ab + z * sine, ty + cosine * (1.0f - ty), bc - x * sine, 0.f); k = graphene_simd4f_init (ca - y * sine, bc + x * sine, tz + cosine * (1.0f - tz), 0.f); *m = graphene_simd4x4f_init (i, j, k, graphene_simd4f_init (0.0f, 0.0f, 0.0f, 1.0f)); } /** * graphene_simd4x4f_add: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4x4f_t * @res: (out caller-allocates): return location for a #graphene_simd4x4f_t * * Adds each row vector of @a and @b and places the results in @res. * * Since: 1.0 */ static inline void graphene_simd4x4f_add (const graphene_simd4x4f_t *a, const graphene_simd4x4f_t *b, graphene_simd4x4f_t *res) { res->x = graphene_simd4f_add (a->x, b->x); res->y = graphene_simd4f_add (a->y, b->y); res->z = graphene_simd4f_add (a->z, b->z); res->w = graphene_simd4f_add (a->w, b->w); } /** * graphene_simd4x4f_sub: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4x4f_t * @res: (out caller-allocates): return location for a #graphene_simd4x4f_t * * Subtracts each row vector of @a and @b and places the results in @res. * * Since: 1.0 */ static inline void graphene_simd4x4f_sub (const graphene_simd4x4f_t *a, const graphene_simd4x4f_t *b, graphene_simd4x4f_t *res) { res->x = graphene_simd4f_sub (a->x, b->x); res->y = graphene_simd4f_sub (a->y, b->y); res->z = graphene_simd4f_sub (a->z, b->z); res->w = graphene_simd4f_sub (a->w, b->w); } /** * graphene_simd4x4f_mul: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4x4f_t * @res: (out caller-allocates): return location for a #graphene_simd4x4f_t * * Multiplies each row vector of @a and @b and places the results in @res. * * You most likely want graphene_simd4x4f_matrix_mul() instead. * * Since: 1.0 */ static inline void graphene_simd4x4f_mul (const graphene_simd4x4f_t *a, const graphene_simd4x4f_t *b, graphene_simd4x4f_t *res) { res->x = graphene_simd4f_mul (a->x, b->x); res->y = graphene_simd4f_mul (a->y, b->y); res->z = graphene_simd4f_mul (a->z, b->z); res->w = graphene_simd4f_mul (a->w, b->w); } /** * graphene_simd4x4f_div: * @a: a #graphene_simd4x4f_t * @b: a #graphene_simd4x4f_t * @res: (out caller-allocates): return location for a #graphene_simd4x4f_t * * Divides each row vector of @a and @b and places the results in @res. * * Since: 1.0 */ static inline void graphene_simd4x4f_div (const graphene_simd4x4f_t *a, const graphene_simd4x4f_t *b, graphene_simd4x4f_t *res) { res->x = graphene_simd4f_div (a->x, b->x); res->y = graphene_simd4f_div (a->y, b->y); res->z = graphene_simd4f_div (a->z, b->z); res->w = graphene_simd4f_div (a->w, b->w); } /** * graphene_simd4x4f_inverse: * @m: a #graphene_simd4x4f_t * @res: (out): return location for the inverse matrix * * Inverts the given #graphene_simd4x4f_t. * * Returns: `true` if the matrix was invertible * * Since: 1.0 */ static inline bool graphene_simd4x4f_inverse (const graphene_simd4x4f_t *m, graphene_simd4x4f_t *res) { /* split rows */ const graphene_simd4f_t r0 = m->x; const graphene_simd4f_t r1 = m->y; const graphene_simd4f_t r2 = m->z; const graphene_simd4f_t r3 = m->w; /* cofactors */ const graphene_simd4f_t r0_wxyz = graphene_simd4f_shuffle_wxyz (r0); const graphene_simd4f_t r0_zwxy = graphene_simd4f_shuffle_zwxy (r0); const graphene_simd4f_t r0_yzwx = graphene_simd4f_shuffle_yzwx (r0); const graphene_simd4f_t r1_wxyz = graphene_simd4f_shuffle_wxyz (r1); const graphene_simd4f_t r1_zwxy = graphene_simd4f_shuffle_zwxy (r1); const graphene_simd4f_t r1_yzwx = graphene_simd4f_shuffle_yzwx (r1); const graphene_simd4f_t r2_wxyz = graphene_simd4f_shuffle_wxyz (r2); const graphene_simd4f_t r2_zwxy = graphene_simd4f_shuffle_zwxy (r2); const graphene_simd4f_t r2_yzwx = graphene_simd4f_shuffle_yzwx (r2); const graphene_simd4f_t r3_wxyz = graphene_simd4f_shuffle_wxyz (r3); const graphene_simd4f_t r3_zwxy = graphene_simd4f_shuffle_zwxy (r3); const graphene_simd4f_t r3_yzwx = graphene_simd4f_shuffle_yzwx (r3); const graphene_simd4f_t r0_wxyz_x_r1 = graphene_simd4f_mul (r0_wxyz, r1); const graphene_simd4f_t r0_wxyz_x_r1_yzwx = graphene_simd4f_mul (r0_wxyz, r1_yzwx); const graphene_simd4f_t r0_wxyz_x_r1_zwxy = graphene_simd4f_mul (r0_wxyz, r1_zwxy); const graphene_simd4f_t r2_wxyz_x_r3 = graphene_simd4f_mul (r2_wxyz, r3); const graphene_simd4f_t r2_wxyz_x_r3_yzwx = graphene_simd4f_mul (r2_wxyz, r3_yzwx); const graphene_simd4f_t r2_wxyz_x_r3_zwxy = graphene_simd4f_mul (r2_wxyz, r3_zwxy); const graphene_simd4f_t ar1 = graphene_simd4f_sub (graphene_simd4f_shuffle_wxyz (r2_wxyz_x_r3_zwxy), graphene_simd4f_shuffle_zwxy (r2_wxyz_x_r3)); const graphene_simd4f_t ar2 = graphene_simd4f_sub (graphene_simd4f_shuffle_zwxy (r2_wxyz_x_r3_yzwx), r2_wxyz_x_r3_yzwx); const graphene_simd4f_t ar3 = graphene_simd4f_sub (r2_wxyz_x_r3_zwxy, graphene_simd4f_shuffle_wxyz (r2_wxyz_x_r3)); const graphene_simd4f_t br1 = graphene_simd4f_sub (graphene_simd4f_shuffle_wxyz (r0_wxyz_x_r1_zwxy), graphene_simd4f_shuffle_zwxy (r0_wxyz_x_r1)); const graphene_simd4f_t br2 = graphene_simd4f_sub (graphene_simd4f_shuffle_zwxy (r0_wxyz_x_r1_yzwx), r0_wxyz_x_r1_yzwx); const graphene_simd4f_t br3 = graphene_simd4f_sub (r0_wxyz_x_r1_zwxy, graphene_simd4f_shuffle_wxyz (r0_wxyz_x_r1)); const graphene_simd4f_t r0_sum = graphene_simd4f_madd (r0_yzwx, ar3, graphene_simd4f_madd (r0_zwxy, ar2, graphene_simd4f_mul (r0_wxyz, ar1))); const graphene_simd4f_t r1_sum = graphene_simd4f_madd (r1_wxyz, ar1, graphene_simd4f_madd (r1_zwxy, ar2, graphene_simd4f_mul (r1_yzwx, ar3))); const graphene_simd4f_t r2_sum = graphene_simd4f_madd (r2_yzwx, br3, graphene_simd4f_madd (r2_zwxy, br2, graphene_simd4f_mul (r2_wxyz, br1))); const graphene_simd4f_t r3_sum = graphene_simd4f_madd (r3_yzwx, br3, graphene_simd4f_madd (r3_zwxy, br2, graphene_simd4f_mul (r3_wxyz, br1))); /* determinant and its inverse */ const graphene_simd4f_t d0 = graphene_simd4f_mul (r1_sum, r0); const graphene_simd4f_t d1 = graphene_simd4f_add (d0, graphene_simd4f_merge_high (d0, d0)); const graphene_simd4f_t det = graphene_simd4f_sub (d1, graphene_simd4f_splat_y (d1)); if (graphene_simd4f_get_x (det) != 0.f) { const graphene_simd4f_t invdet = graphene_simd4f_splat_x (graphene_simd4f_div (graphene_simd4f_splat (1.0f), det)); const graphene_simd4f_t o0 = graphene_simd4f_mul (graphene_simd4f_flip_sign_0101 (r1_sum), invdet); const graphene_simd4f_t o1 = graphene_simd4f_mul (graphene_simd4f_flip_sign_1010 (r0_sum), invdet); const graphene_simd4f_t o2 = graphene_simd4f_mul (graphene_simd4f_flip_sign_0101 (r3_sum), invdet); const graphene_simd4f_t o3 = graphene_simd4f_mul (graphene_simd4f_flip_sign_1010 (r2_sum), invdet); graphene_simd4x4f_t mt = graphene_simd4x4f_init (o0, o1, o2, o3); /* transpose the resulting matrix */ graphene_simd4x4f_transpose (&mt, res); return true; } return false; } /** * graphene_simd4x4f_determinant: * @m: a #graphene_simd4x4f_t * @det_r: (out): return location for the matrix determinant * @invdet_r: (out): return location for the inverse of the matrix * determinant * * Computes the determinant (and its inverse) of the given matrix * * Since: 1.0 */ static inline void graphene_simd4x4f_determinant (const graphene_simd4x4f_t *m, graphene_simd4f_t *det_r, graphene_simd4f_t *invdet_r) { /* split rows */ const graphene_simd4f_t r0 = m->x; const graphene_simd4f_t r1 = m->y; const graphene_simd4f_t r2 = m->z; const graphene_simd4f_t r3 = m->w; /* cofactors */ const graphene_simd4f_t r1_wxyz = graphene_simd4f_shuffle_wxyz (r1); const graphene_simd4f_t r1_zwxy = graphene_simd4f_shuffle_zwxy (r1); const graphene_simd4f_t r1_yzwx = graphene_simd4f_shuffle_yzwx (r1); const graphene_simd4f_t r2_wxyz = graphene_simd4f_shuffle_wxyz (r2); const graphene_simd4f_t r3_zwxy = graphene_simd4f_shuffle_zwxy (r3); const graphene_simd4f_t r3_yzwx = graphene_simd4f_shuffle_yzwx (r3); const graphene_simd4f_t r2_wxyz_x_r3 = graphene_simd4f_mul (r2_wxyz, r3); const graphene_simd4f_t r2_wxyz_x_r3_yzwx = graphene_simd4f_mul (r2_wxyz, r3_yzwx); const graphene_simd4f_t r2_wxyz_x_r3_zwxy = graphene_simd4f_mul (r2_wxyz, r3_zwxy); const graphene_simd4f_t ar1 = graphene_simd4f_sub (graphene_simd4f_shuffle_wxyz (r2_wxyz_x_r3_zwxy), graphene_simd4f_shuffle_zwxy (r2_wxyz_x_r3)); const graphene_simd4f_t ar2 = graphene_simd4f_sub (graphene_simd4f_shuffle_zwxy (r2_wxyz_x_r3_yzwx), r2_wxyz_x_r3_yzwx); const graphene_simd4f_t ar3 = graphene_simd4f_sub (r2_wxyz_x_r3_zwxy, graphene_simd4f_shuffle_wxyz (r2_wxyz_x_r3)); const graphene_simd4f_t r1_sum = graphene_simd4f_madd (r1_wxyz, ar1, graphene_simd4f_madd (r1_zwxy, ar2, graphene_simd4f_mul (r1_yzwx, ar3))); /* determinant and its inverse */ const graphene_simd4f_t d0 = graphene_simd4f_mul (r1_sum, r0); const graphene_simd4f_t d1 = graphene_simd4f_add (d0, graphene_simd4f_merge_high (d0, d0)); const graphene_simd4f_t det = graphene_simd4f_sub (d1, graphene_simd4f_splat_y (d1)); const graphene_simd4f_t invdet = graphene_simd4f_splat_x (graphene_simd4f_div (graphene_simd4f_splat (1.0f), det)); if (det_r != NULL) *det_r = det; if (invdet_r != NULL) *invdet_r = invdet; } /** * graphene_simd4x4f_is_identity: * @m: a #graphene_simd4x4f_t * * Checks whether the given matrix is the identity matrix. * * Returns: `true` if the matrix is the identity matrix * * Since: 1.0 */ static inline bool graphene_simd4x4f_is_identity (const graphene_simd4x4f_t *m) { const graphene_simd4f_t r0 = graphene_simd4f_init (1.0f, 0.0f, 0.0f, 0.0f); const graphene_simd4f_t r1 = graphene_simd4f_init (0.0f, 1.0f, 0.0f, 0.0f); const graphene_simd4f_t r2 = graphene_simd4f_init (0.0f, 0.0f, 1.0f, 0.0f); const graphene_simd4f_t r3 = graphene_simd4f_init (0.0f, 0.0f, 0.0f, 1.0f); return graphene_simd4f_cmp_eq (m->x, r0) && graphene_simd4f_cmp_eq (m->y, r1) && graphene_simd4f_cmp_eq (m->z, r2) && graphene_simd4f_cmp_eq (m->w, r3); } /** * graphene_simd4x4f_is_2d: * @m: a #graphene_simd4x4f_t * * Checks whether the given matrix is compatible with an affine * transformation matrix. * * Returns: `true` if the matrix is compatible with an affine * transformation matrix * * Since: 1.0 */ static inline bool graphene_simd4x4f_is_2d (const graphene_simd4x4f_t *m) { float f[4]; if (!(fabsf (graphene_simd4f_get_z (m->x)) < FLT_EPSILON && fabsf (graphene_simd4f_get_w (m->x)) < FLT_EPSILON)) return false; if (!(fabsf (graphene_simd4f_get_z (m->y)) < FLT_EPSILON && fabsf (graphene_simd4f_get_w (m->y)) < FLT_EPSILON)) return false; graphene_simd4f_dup_4f (m->z, f); if (!(fabsf (f[0]) < FLT_EPSILON && fabsf (f[1]) < FLT_EPSILON && 1.f - fabsf (f[2]) < FLT_EPSILON && fabsf (f[3]) < FLT_EPSILON)) return false; if (!(fabsf (graphene_simd4f_get_z (m->w)) < FLT_EPSILON && 1.f - fabsf (graphene_simd4f_get_w (m->w)) < FLT_EPSILON)) return false; return true; } GRAPHENE_END_DECLS #endif /* __GRAPHENE_SIMD4X4F_H__ */ graphene-1.8.0/src/graphene-size.c000066400000000000000000000115011324365266600170200ustar00rootroot00000000000000/* graphene-size.c: Size * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-size * @Title: Size * @short_description: Size representation * * #graphene_size_t represents a size composed of a @graphene_size_t.width * by a @graphene_size_t.height. */ #include "graphene-private.h" #include "graphene-size.h" #include /** * graphene_size_alloc: (constructor) * * Allocates a new #graphene_size_t. * * The contents of the returned value are undefined. * * Returns: (transfer full): the newly allocated #graphene_size_t * * Since: 1.0 */ graphene_size_t * graphene_size_alloc (void) { return calloc (1, sizeof (graphene_size_t)); } /** * graphene_size_free: * @s: a #graphene_size_t * * Frees the resources allocated by graphene_size_alloc(). * * Since: 1.0 */ void graphene_size_free (graphene_size_t *s) { free (s); } /** * graphene_size_init: * @s: a #graphene_size_t * @width: the width * @height: the height * * Initializes a #graphene_size_t using the given @width and @height. * * Returns: (transfer none): the initialized #graphene_size_t * * Since: 1.0 */ graphene_size_t * graphene_size_init (graphene_size_t *s, float width, float height) { s->width = width; s->height = height; return s; } /** * graphene_size_init_from_size: * @s: a #graphene_size_t * @src: a #graphene_size_t * * Initializes a #graphene_size_t using the width and height of * the given @src. * * Returns: (transfer none): the initialized #graphene_size_t * * Since: 1.0 */ graphene_size_t * graphene_size_init_from_size (graphene_size_t *s, const graphene_size_t *src) { *s = *src; return s; } static bool size_equal (const void *p1, const void *p2) { const graphene_size_t *a = p1; const graphene_size_t *b = p2; return graphene_approx_val (a->width, b->width) && graphene_approx_val (a->height, b->height); } /** * graphene_size_equal: * @a: a #graphene_size_t * @b: a #graphene_size_t * * Checks whether the two give #graphene_size_t are equal. * * Returns: `true` if the sizes are equal * * Since: 1.0 */ bool graphene_size_equal (const graphene_size_t *a, const graphene_size_t *b) { return graphene_pointer_equal (a, b, size_equal); } /** * graphene_size_scale: * @s: a #graphene_size_t * @factor: the scaling factor * @res: (out caller-allocates): return location for the scaled size * * Scales the components of a #graphene_size_t using the given @factor. * * Since: 1.0 */ void graphene_size_scale (const graphene_size_t *s, float factor, graphene_size_t *res) { *res = *s; res->width *= factor; res->height *= factor; } /** * graphene_size_interpolate: * @a: a #graphene_size_t * @b: a #graphene_size_t * @factor: the linear interpolation factor * @res: (out caller-allocates): return location for the interpolated size * * Linearly interpolates the two given #graphene_size_t using the given * interpolation @factor. * * Since: 1.0 */ void graphene_size_interpolate (const graphene_size_t *a, const graphene_size_t *b, double factor, graphene_size_t *res) { res->width = graphene_lerp (a->width, b->width, factor); res->height = graphene_lerp (a->height, b->height, factor); } static const graphene_size_t _graphene_size_zero; /** * graphene_size_zero: * * A constant pointer to a zero #graphene_size_t, useful for * equality checks and interpolations. * * Returns: (transfer none): a constant size * * Since: 1.0 */ const graphene_size_t * graphene_size_zero (void) { return &_graphene_size_zero; } graphene-1.8.0/src/graphene-size.h000066400000000000000000000075101324365266600170320ustar00rootroot00000000000000/* graphene-size.h: Size * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_SIZE_H__ #define __GRAPHENE_SIZE_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" GRAPHENE_BEGIN_DECLS /** * GRAPHENE_SIZE_INIT: * @_w: the width * @_h: the height * * Initializes a #graphene_size_t with the given sizes when * declaring it, e.g.: * * |[ * graphene_size_t size = GRAPHENE_SIZE_INIT (100.f, 100.f); * ]| * * Since: 1.0 */ #define GRAPHENE_SIZE_INIT(_w,_h) (graphene_size_t) { .width = (_w), .height = (_h) } /** * GRAPHENE_SIZE_INIT_ZERO: * * Initializes a #graphene_size_t to (0, 0) when declaring it. * * Since: 1.0 */ #define GRAPHENE_SIZE_INIT_ZERO GRAPHENE_SIZE_INIT (0.f, 0.f) /** * graphene_size_t: * @width: the width * @height: the height * * A size. * * Since: 1.0 */ struct _graphene_size_t { float width; float height; }; GRAPHENE_AVAILABLE_IN_1_0 graphene_size_t * graphene_size_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_size_free (graphene_size_t *s); GRAPHENE_AVAILABLE_IN_1_0 graphene_size_t * graphene_size_init (graphene_size_t *s, float width, float height); GRAPHENE_AVAILABLE_IN_1_0 graphene_size_t * graphene_size_init_from_size (graphene_size_t *s, const graphene_size_t *src); GRAPHENE_AVAILABLE_IN_1_0 bool graphene_size_equal (const graphene_size_t *a, const graphene_size_t *b); GRAPHENE_AVAILABLE_IN_1_0 void graphene_size_scale (const graphene_size_t *s, float factor, graphene_size_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_size_interpolate (const graphene_size_t *a, const graphene_size_t *b, double factor, graphene_size_t *res); GRAPHENE_AVAILABLE_IN_1_0 const graphene_size_t * graphene_size_zero (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_SIZE_H__ */ graphene-1.8.0/src/graphene-sphere.c000066400000000000000000000232651324365266600173460ustar00rootroot00000000000000/* graphene-sphere.c: A sphere * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-sphere * @Title: Sphere * @Short_Description: A sphere * * #graphene_sphere_t provides a representation of a sphere using its center * and radius. */ #include "graphene-private.h" #include "graphene-sphere.h" #include "graphene-alloc-private.h" #include "graphene-box.h" #include "graphene-point3d.h" #include "graphene-simd4f.h" #include /** * graphene_sphere_alloc: (constructor) * * Allocates a new #graphene_sphere_t. * * The contents of the newly allocated structure are undefined. * * Returns: (transfer full): the newly allocated #graphene_sphere_t. Use * graphene_sphere_free() to free the resources allocated by this function * * Since: 1.2 */ graphene_sphere_t * graphene_sphere_alloc (void) { return graphene_aligned_alloc0 (sizeof (graphene_sphere_t), 1, 16); } /** * graphene_sphere_free: * @s: a #graphene_sphere_t * * Frees the resources allocated by graphene_sphere_alloc(). * * Since: 1.2 */ void graphene_sphere_free (graphene_sphere_t *s) { graphene_aligned_free (s); } /** * graphene_sphere_init: * @s: the #graphene_sphere_t to initialize * @center: (nullable): the coordinates of the center of the sphere, or %NULL * for a center in (0, 0, 0) * @radius: the radius of the sphere * * Initializes the given #graphene_sphere_t with the given @center and @radius. * * Returns: (transfer none): the initialized #graphene_sphere_t * * Since: 1.2 */ graphene_sphere_t * graphene_sphere_init (graphene_sphere_t *s, const graphene_point3d_t *center, float radius) { if (center != NULL) graphene_point3d_to_vec3 (center, &s->center); else graphene_vec3_init_from_vec3 (&s->center, graphene_vec3_zero ()); s->radius = radius; return s; } static float distance_sq (const graphene_vec3_t *p1, const graphene_vec3_t *p2) { graphene_vec3_t delta; graphene_vec3_subtract (p1, p2, &delta); return graphene_vec3_dot (&delta, &delta); } /** * graphene_sphere_init_from_points: * @s: the #graphene_sphere_t to initialize * @n_points: the number of #graphene_point3d_t in the @points array * @points: (array length=n_points): an array of #graphene_point3d_t * @center: (nullable): the center of the sphere * * Initializes the given #graphene_sphere_t using the given array * of 3D coordinates so that the sphere includes them. * * The center of the sphere can either be specified, or will be center * of the 3D volume that encompasses all @points. * * Returns: (transfer none): the initialized #graphene_sphere_t * * Since: 1.2 */ graphene_sphere_t * graphene_sphere_init_from_points (graphene_sphere_t *s, unsigned int n_points, const graphene_point3d_t *points, const graphene_point3d_t *center) { float max_radius_sq = 0.f; if (center != NULL) graphene_point3d_to_vec3 (center, &s->center); else { graphene_box_t box; graphene_point3d_t c; graphene_box_init_from_points (&box, n_points, points); graphene_box_get_center (&box, &c); graphene_point3d_to_vec3 (&c, &s->center); } for (unsigned int i = 0; i < n_points; i++) { graphene_vec3_t p; graphene_point3d_to_vec3 (&points[i], &p); max_radius_sq = fmaxf (max_radius_sq, distance_sq (&s->center, &p)); } s->radius = sqrtf (max_radius_sq); return s; } /** * graphene_sphere_init_from_vectors: * @s: the #graphene_sphere_t to initialize * @n_vectors: the number of #graphene_vec3_t in the @vectors array * @vectors: (array length=n_vectors): an array of #graphene_vec3_t * @center: (nullable): the center of the sphere * * Initializes the given #graphene_sphere_t using the given array * of 3D coordinates so that the sphere includes them. * * The center of the sphere can either be specified, or will be center * of the 3D volume that encompasses all @vectors. * * Returns: (transfer none): the initialized #graphene_sphere_t * * Since: 1.2 */ graphene_sphere_t * graphene_sphere_init_from_vectors (graphene_sphere_t *s, unsigned int n_vectors, const graphene_vec3_t *vectors, const graphene_point3d_t *center) { float max_radius_sq = 0.f; if (center != NULL) graphene_point3d_to_vec3 (center, &s->center); else { graphene_box_t box; graphene_point3d_t c; graphene_box_init_from_vectors (&box, n_vectors, vectors); graphene_box_get_center (&box, &c); graphene_point3d_to_vec3 (&c, &s->center); } for (unsigned int i = 0; i < n_vectors; i++) max_radius_sq = fmaxf (max_radius_sq, distance_sq (&s->center, &vectors[i])); s->radius = sqrtf (max_radius_sq); return s; } /** * graphene_sphere_get_center: * @s: a #graphene_sphere_t * @center: (out caller-allocates): return location for the coordinates of * the center * * Retrieves the coordinates of the center of a #graphene_sphere_t. * * Since: 1.2 */ void graphene_sphere_get_center (const graphene_sphere_t *s, graphene_point3d_t *center) { graphene_point3d_init_from_vec3 (center, &s->center); } /** * graphene_sphere_get_radius: * @s: a #graphene_sphere_t * * Retrieves the radius of a #graphene_sphere_t. * * Since: 1.2 */ float graphene_sphere_get_radius (const graphene_sphere_t *s) { return s->radius; } /** * graphene_sphere_is_empty: * @s: a #graphene_sphere_t * * Checks whether the sphere has a zero radius. * * Returns: `true` if the sphere is empty * * Since: 1.2 */ bool graphene_sphere_is_empty (const graphene_sphere_t *s) { return s != NULL && s->radius <= 0; } /** * graphene_sphere_contains_point: * @s: a #graphene_sphere_t * @point: a #graphene_point3d_t * * Checks whether the given @point is contained in the volume * of a #graphene_sphere_t. * * Returns: `true` if the sphere contains the point * * Since: 1.2 */ bool graphene_sphere_contains_point (const graphene_sphere_t *s, const graphene_point3d_t *point) { graphene_vec3_t tmp; float radius_sq; graphene_point3d_to_vec3 (point, &tmp); radius_sq = s->radius * s->radius; if (distance_sq (&s->center, &tmp) <= radius_sq) return true; return false; } /** * graphene_sphere_distance: * @s: a #graphene_sphere_t * @point: a #graphene_point3d_t * * Computes the distance of the given @point from the surface of * a #graphene_sphere_t. * * Returns: the distance of the point * * Since: 1.2 */ float graphene_sphere_distance (const graphene_sphere_t *s, const graphene_point3d_t *point) { graphene_vec3_t tmp; graphene_point3d_to_vec3 (point, &tmp); return sqrtf (distance_sq (&s->center, &tmp)) - s->radius; } /** * graphene_sphere_get_bounding_box: * @s: a #graphene_sphere_t * @box: (out caller-allocates): return location for the bounding box * * Computes the bounding box capable of containing the * given #graphene_sphere_t. * * Since: 1.2 */ void graphene_sphere_get_bounding_box (const graphene_sphere_t *s, graphene_box_t *box) { graphene_box_init_from_vec3 (box, &s->center, &s->center); graphene_box_expand_scalar (box, s->radius, box); } /** * graphene_sphere_translate: * @s: a #graphene_sphere_t * @point: the coordinates of the translation * @res: (out caller-allocates): return location for the translated sphere * * Translates the center of the given #graphene_sphere_t using the @point * coordinates as the delta of the translation. * * Since: 1.2 */ void graphene_sphere_translate (const graphene_sphere_t *s, const graphene_point3d_t *point, graphene_sphere_t *res) { graphene_vec3_t tmp; graphene_point3d_to_vec3 (point, &tmp); graphene_vec3_add (&s->center, &tmp, &res->center); } static bool sphere_equal (const void *p1, const void *p2) { const graphene_sphere_t *a = p1; const graphene_sphere_t *b = p2; return graphene_vec3_equal (&a->center, &b->center) && graphene_approx_val (a->radius, b->radius); } /** * graphene_sphere_equal: * @a: a #graphene_sphere_t * @b: a #graphene_sphere_t * * Checks whether two #graphene_sphere_t are equal. * * Returns: `true` if the spheres are equal * * Since: 1.2 */ bool graphene_sphere_equal (const graphene_sphere_t *a, const graphene_sphere_t *b) { return graphene_pointer_equal (a, b, sphere_equal); } graphene-1.8.0/src/graphene-sphere.h000066400000000000000000000112101324365266600173360ustar00rootroot00000000000000/* graphene-sphere.h: A sphere * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_SPHERE_H__ #define __GRAPHENE_SPHERE_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-vec3.h" GRAPHENE_BEGIN_DECLS /** * graphene_sphere_t: * * A sphere, represented by its center and radius. * * Since: 1.2 */ struct _graphene_sphere_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, center); GRAPHENE_PRIVATE_FIELD (float, radius); }; GRAPHENE_AVAILABLE_IN_1_2 graphene_sphere_t * graphene_sphere_alloc (void); GRAPHENE_AVAILABLE_IN_1_2 void graphene_sphere_free (graphene_sphere_t *s); GRAPHENE_AVAILABLE_IN_1_2 graphene_sphere_t * graphene_sphere_init (graphene_sphere_t *s, const graphene_point3d_t *center, float radius); GRAPHENE_AVAILABLE_IN_1_2 graphene_sphere_t * graphene_sphere_init_from_points (graphene_sphere_t *s, unsigned int n_points, const graphene_point3d_t *points, const graphene_point3d_t *center); GRAPHENE_AVAILABLE_IN_1_2 graphene_sphere_t * graphene_sphere_init_from_vectors (graphene_sphere_t *s, unsigned int n_vectors, const graphene_vec3_t *vectors, const graphene_point3d_t *center); GRAPHENE_AVAILABLE_IN_1_2 void graphene_sphere_get_center (const graphene_sphere_t *s, graphene_point3d_t *center); GRAPHENE_AVAILABLE_IN_1_2 float graphene_sphere_get_radius (const graphene_sphere_t *s); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_sphere_is_empty (const graphene_sphere_t *s); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_sphere_equal (const graphene_sphere_t *a, const graphene_sphere_t *b); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_sphere_contains_point (const graphene_sphere_t *s, const graphene_point3d_t *point); GRAPHENE_AVAILABLE_IN_1_2 float graphene_sphere_distance (const graphene_sphere_t *s, const graphene_point3d_t *point); GRAPHENE_AVAILABLE_IN_1_2 void graphene_sphere_get_bounding_box (const graphene_sphere_t *s, graphene_box_t *box); GRAPHENE_AVAILABLE_IN_1_2 void graphene_sphere_translate (const graphene_sphere_t *s, const graphene_point3d_t *point, graphene_sphere_t *res); GRAPHENE_END_DECLS #endif /* __GRAPHENE_SPHERE_H__ */ graphene-1.8.0/src/graphene-triangle.c000066400000000000000000000312021324365266600176530ustar00rootroot00000000000000/* graphene-triangle.c: A triangle * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-triangle * @Title: Triangle * @Short_description: A triangle described by 3D points * * #graphene_triangle_t represents a triangle in 3D space. * */ #include "graphene-private.h" #include "graphene-triangle.h" #include "graphene-alloc-private.h" #include "graphene-box.h" #include "graphene-plane.h" #include "graphene-point3d.h" #include "graphene-vec2.h" #include /** * graphene_triangle_alloc: (constructor) * * Allocates a new #graphene_triangle_t. * * The contents of the returned structure are undefined. * * Returns: (transfer full): the newly allocated #graphene_triangle_t * structure. Use graphene_triangle_free() to free the resources * allocated by this function * * Since: 1.2 */ graphene_triangle_t * graphene_triangle_alloc (void) { return graphene_aligned_alloc0 (sizeof (graphene_triangle_t), 1, 16); } /** * graphene_triangle_free: * @t: a #graphene_triangle_t * * Frees the resources allocated by graphene_triangle_alloc(). * * Since: 1.2 */ void graphene_triangle_free (graphene_triangle_t *t) { graphene_aligned_free (t); } /** * graphene_triangle_init_from_point3d: * @t: the #graphene_triangle_t to initialize * @a: (nullable): a #graphene_point3d_t * @b: (nullable): a #graphene_point3d_t * @c: (nullable): a #graphene_point3d_t * * Initializes a #graphene_triangle_t using the three given 3D points. * * Returns: (transfer none): the initialized #graphene_triangle_t * * Since: 1.2 */ graphene_triangle_t * graphene_triangle_init_from_point3d (graphene_triangle_t *t, const graphene_point3d_t *a, const graphene_point3d_t *b, const graphene_point3d_t *c) { if (a != NULL) graphene_point3d_to_vec3 (a, &t->a); else graphene_vec3_init_from_vec3 (&t->a, graphene_vec3_zero ()); if (b != NULL) graphene_point3d_to_vec3 (b, &t->b); else graphene_vec3_init_from_vec3 (&t->b, graphene_vec3_zero ()); if (c != NULL) graphene_point3d_to_vec3 (c, &t->c); else graphene_vec3_init_from_vec3 (&t->c, graphene_vec3_zero ()); return t; } /** * graphene_triangle_init_from_vec3: * @t: the #graphene_triangle_t to initialize * @a: (nullable): a #graphene_vec3_t * @b: (nullable): a #graphene_vec3_t * @c: (nullable): a #graphene_vec3_t * * Initializes a #graphene_triangle_t using the three given vectors. * * Returns: (transfer none): the initialized #graphene_triangle_t * * Since: 1.2 */ graphene_triangle_t * graphene_triangle_init_from_vec3 (graphene_triangle_t *t, const graphene_vec3_t *a, const graphene_vec3_t *b, const graphene_vec3_t *c) { if (a != NULL) t->a = *a; else graphene_vec3_init_from_vec3 (&t->a, graphene_vec3_zero ()); if (b != NULL) t->b = *b; else graphene_vec3_init_from_vec3 (&t->b, graphene_vec3_zero ()); if (c != NULL) t->c = *c; else graphene_vec3_init_from_vec3 (&t->c, graphene_vec3_zero ()); return t; } /** * graphene_triangle_get_points: * @t: a #graphene_triangle_t * @a: (out caller-allocates) (optional): return location for the coordinates * of the first vertex * @b: (out caller-allocates) (optional): return location for the coordinates * of the second vertex * @c: (out caller-allocates) (optional): return location for the coordinates * of the third vertex * * Retrieves the three vertices of the given #graphene_triangle_t and returns * their coordinates as #graphene_point3d_t. * * Since: 1.2 */ void graphene_triangle_get_points (const graphene_triangle_t *t, graphene_point3d_t *a, graphene_point3d_t *b, graphene_point3d_t *c) { if (a != NULL) graphene_point3d_init_from_vec3 (a, &t->a); if (b != NULL) graphene_point3d_init_from_vec3 (b, &t->b); if (c != NULL) graphene_point3d_init_from_vec3 (c, &t->c); } /** * graphene_triangle_get_vertices: * @t: a #graphene_triangle_t * @a: (out caller-allocates) (optional): return location for the first vertex * @b: (out caller-allocates) (optional): return location for the second vertex * @c: (out caller-allocates) (optional): return location for the third vertex * * Retrieves the three vertices of the given #graphene_triangle_t. * * Since: 1.2 */ void graphene_triangle_get_vertices (const graphene_triangle_t *t, graphene_vec3_t *a, graphene_vec3_t *b, graphene_vec3_t *c) { if (a != NULL) *a = t->a; if (b != NULL) *b = t->b; if (c != NULL) *c = t->c; } /** * graphene_triangle_get_area: * @t: a #graphene_triangle_t * * Computes the area of the given #graphene_triangle_t. * * Returns: the area of the triangle * * Since: 1.2 */ float graphene_triangle_get_area (const graphene_triangle_t *t) { graphene_vec3_t v1, v2, tmp; graphene_vec3_subtract (&t->c, &t->b, &v1); graphene_vec3_subtract (&t->a, &t->b, &v2); graphene_vec3_cross (&v1, &v2, &tmp); return graphene_vec3_length (&tmp) * .5f; } /** * graphene_triangle_get_midpoint: * @t: a #graphene_triangle_t * @res: (out caller-allocates): return location for the coordinates of * the midpoint * * Computes the coordinates of the midpoint of the given #graphene_triangle_t. * * The midpoint G is the [centroid](https://en.wikipedia.org/wiki/Centroid#Triangle_centroid) * of the triangle, i.e. the intersection of its medians. * * Since: 1.2 */ void graphene_triangle_get_midpoint (const graphene_triangle_t *t, graphene_point3d_t *res) { graphene_vec3_t tmp; graphene_vec3_add (&t->a, &t->b, &tmp); graphene_vec3_add (&tmp, &t->c, &tmp); graphene_vec3_scale (&tmp, (1.f / 3.f), &tmp); graphene_point3d_init_from_vec3 (res, &tmp); } /** * graphene_triangle_get_normal: * @t: a #graphene_triangle_t * @res: (out caller-allocates): return location for the normal vector * * Computes the normal vector of the given #graphene_triangle_t. * * Since: 1.2 */ void graphene_triangle_get_normal (const graphene_triangle_t *t, graphene_vec3_t *res) { graphene_vec3_t v1, v2, tmp; float length_sq; graphene_vec3_subtract (&t->c, &t->b, &v1); graphene_vec3_subtract (&t->a, &t->b, &v2); graphene_vec3_cross (&v1, &v2, &tmp); length_sq = graphene_vec3_dot (&tmp, &tmp); if (length_sq > 0) graphene_vec3_scale (&tmp, 1.f / sqrtf (length_sq), res); else graphene_vec3_init_from_vec3 (res, graphene_vec3_zero ()); } /** * graphene_triangle_get_plane: * @t: a #graphene_triangle_t * @res: (out caller-allocates): return location for the plane * * Computes the plane based on the vertices of the given #graphene_triangle_t. * * Since: 1.2 */ void graphene_triangle_get_plane (const graphene_triangle_t *t, graphene_plane_t *res) { graphene_point3d_t a, b, c; graphene_point3d_init_from_vec3 (&a, &t->a); graphene_point3d_init_from_vec3 (&b, &t->b); graphene_point3d_init_from_vec3 (&c, &t->c); graphene_plane_init_from_points (res, &a, &b, &c); } /** * graphene_triangle_get_bounding_box: * @t: a #graphene_triangle_t * @res: (out caller-allocates): return location for the box * * Computes the bounding box of the given #graphene_triangle_t. * * Since: 1.2 */ void graphene_triangle_get_bounding_box (const graphene_triangle_t *t, graphene_box_t *res) { graphene_box_init_from_box (res, graphene_box_empty ()); graphene_box_expand_vec3 (res, &t->a, res); graphene_box_expand_vec3 (res, &t->b, res); graphene_box_expand_vec3 (res, &t->c, res); } static inline bool graphene_triangle_get_uv (const graphene_triangle_t *t, const graphene_vec3_t *point, float *u, float *v) { graphene_vec3_t v0, v1, v2; float dot00, dot01, dot02; float dot11, dot12; float denom, inv_denom; graphene_vec3_subtract (&t->c, &t->a, &v0); graphene_vec3_subtract (&t->b, &t->a, &v1); graphene_vec3_subtract (point, &t->a, &v2); dot00 = graphene_vec3_dot (&v0, &v0); dot01 = graphene_vec3_dot (&v0, &v1); dot02 = graphene_vec3_dot (&v0, &v2); dot11 = graphene_vec3_dot (&v1, &v1); dot12 = graphene_vec3_dot (&v1, &v2); denom = dot00 * dot11 - dot01 * dot01; if (denom == 0.f) return false; inv_denom = 1.f / denom; *u = (dot11 * dot02 - dot01 * dot12) * inv_denom; *v = (dot00 * dot12 - dot01 * dot02) * inv_denom; return true; } /** * graphene_triangle_get_barycoords: * @t: a #graphene_triangle_t * @p: (nullable): a #graphene_point3d_t * @res: (out caller-allocates): return location for the vector * with the barycentric coordinates * * Computes the [barycentric coordinates](http://en.wikipedia.org/wiki/Barycentric_coordinate_system) * of the given point @p. * * The point @p must lie on the same plane as the triangle @t; if the * point is not coplanar, the result of this function is undefined. * * If we place the origin in the coordinates of the triangle's A point, * the barycentric coordinates are `u`, which is on the AC vector; and `v` * which is on the AB vector: * * ![](triangle-barycentric.png) * * The returned #graphene_vec2_t contains the following values, in order: * * - `res.x = u` * - `res.y = v` * * Returns: `true` if the barycentric coordinates are valid * * Since: 1.2 */ bool graphene_triangle_get_barycoords (const graphene_triangle_t *t, const graphene_point3d_t *p, graphene_vec2_t *res) { graphene_vec3_t point; float u, v; if (p == NULL) graphene_vec3_init (&point, 0.f, 0.f, 0.f); else graphene_point3d_to_vec3 (p, &point); if (graphene_triangle_get_uv (t, &point, &u, &v)) { graphene_vec2_init (res, u, v); return true; } return false; } /** * graphene_triangle_contains_point: * @t: a #graphene_triangle_t * @p: a #graphene_point3d_t * * Checks whether the given triangle @t contains the point @p. * * Returns: `true` if the point is inside the triangle * * Since: 1.2 */ bool graphene_triangle_contains_point (const graphene_triangle_t *t, const graphene_point3d_t *p) { graphene_vec3_t point; float u, v; /* we use the barycoordinates from the given point to check * if the point is inside the triangle. * * see: http://www.blackpawn.com/texts/pointinpoly/default.html */ graphene_point3d_to_vec3 (p, &point); if (!graphene_triangle_get_uv (t, &point, &u, &v)) return false; return (u >= 0.f) && (v >= 0.f) && (u + v < 1.f); } static bool triangle_equal (const void *p1, const void *p2) { const graphene_triangle_t *a = p1; const graphene_triangle_t *b = p2; return graphene_vec3_equal (&a->a, &b->a) && graphene_vec3_equal (&a->b, &b->b) && graphene_vec3_equal (&a->c, &b->c); } /** * graphene_triangle_equal: * @a: a #graphene_triangle_t * @b: a #graphene_triangle_t * * Checks whether the two given #graphene_triangle_t are equal. * * Returns: `true` if the triangles are equal * * Since: 1.2 */ bool graphene_triangle_equal (const graphene_triangle_t *a, const graphene_triangle_t *b) { return graphene_pointer_equal (a, b, triangle_equal); } graphene-1.8.0/src/graphene-triangle.h000066400000000000000000000123221324365266600176620ustar00rootroot00000000000000/* graphene-triangle.h: A triangle * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_TRIANGLE_H__ #define __GRAPHENE_TRIANGLE_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" #include "graphene-vec3.h" GRAPHENE_BEGIN_DECLS /** * graphene_triangle_t: * * A triangle. * * Since: 1.2 */ struct _graphene_triangle_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, a); GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, b); GRAPHENE_PRIVATE_FIELD (graphene_vec3_t, c); }; GRAPHENE_AVAILABLE_IN_1_2 graphene_triangle_t * graphene_triangle_alloc (void); GRAPHENE_AVAILABLE_IN_1_2 void graphene_triangle_free (graphene_triangle_t *t); GRAPHENE_AVAILABLE_IN_1_2 graphene_triangle_t * graphene_triangle_init_from_point3d (graphene_triangle_t *t, const graphene_point3d_t *a, const graphene_point3d_t *b, const graphene_point3d_t *c); GRAPHENE_AVAILABLE_IN_1_2 graphene_triangle_t * graphene_triangle_init_from_vec3 (graphene_triangle_t *t, const graphene_vec3_t *a, const graphene_vec3_t *b, const graphene_vec3_t *c); GRAPHENE_AVAILABLE_IN_1_2 void graphene_triangle_get_points (const graphene_triangle_t *t, graphene_point3d_t *a, graphene_point3d_t *b, graphene_point3d_t *c); GRAPHENE_AVAILABLE_IN_1_2 void graphene_triangle_get_vertices (const graphene_triangle_t *t, graphene_vec3_t *a, graphene_vec3_t *b, graphene_vec3_t *c); GRAPHENE_AVAILABLE_IN_1_2 float graphene_triangle_get_area (const graphene_triangle_t *t); GRAPHENE_AVAILABLE_IN_1_2 void graphene_triangle_get_midpoint (const graphene_triangle_t *t, graphene_point3d_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_triangle_get_normal (const graphene_triangle_t *t, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_triangle_get_plane (const graphene_triangle_t *t, graphene_plane_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_triangle_get_bounding_box (const graphene_triangle_t *t, graphene_box_t *res); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_triangle_get_barycoords (const graphene_triangle_t *t, const graphene_point3d_t *p, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_triangle_contains_point (const graphene_triangle_t *t, const graphene_point3d_t *p); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_triangle_equal (const graphene_triangle_t *a, const graphene_triangle_t *b); GRAPHENE_END_DECLS #endif /* __GRAPHENE_TRIANGLE_H__ */ graphene-1.8.0/src/graphene-types.h000066400000000000000000000056061324365266600172300ustar00rootroot00000000000000/* graphene-types.h: Shared types * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_TYPES_H__ #define __GRAPHENE_TYPES_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-config.h" #include "graphene-macros.h" #include "graphene-version-macros.h" GRAPHENE_BEGIN_DECLS /** * GRAPHENE_VEC2_LEN: * * Evaluates to the number of components of a #graphene_vec2_t. * * Since: 1.0 */ #define GRAPHENE_VEC2_LEN 2 /** * GRAPHENE_VEC3_LEN: * * Evaluates to the number of components of a #graphene_vec3_t. * * Since: 1.0 */ #define GRAPHENE_VEC3_LEN 3 /** * GRAPHENE_VEC4_LEN: * * Evaluates to the number of components of a #graphene_vec4_t. * * Since: 1.0 */ #define GRAPHENE_VEC4_LEN 4 typedef struct _graphene_vec2_t graphene_vec2_t; typedef struct _graphene_vec3_t graphene_vec3_t; typedef struct _graphene_vec4_t graphene_vec4_t; typedef struct _graphene_matrix_t graphene_matrix_t; typedef struct _graphene_point_t graphene_point_t; typedef struct _graphene_size_t graphene_size_t; typedef struct _graphene_rect_t graphene_rect_t; typedef struct _graphene_point3d_t graphene_point3d_t; typedef struct _graphene_quad_t graphene_quad_t; typedef struct _graphene_quaternion_t graphene_quaternion_t; typedef struct _graphene_euler_t graphene_euler_t; typedef struct _graphene_plane_t graphene_plane_t; typedef struct _graphene_frustum_t graphene_frustum_t; typedef struct _graphene_sphere_t graphene_sphere_t; typedef struct _graphene_box_t graphene_box_t; typedef struct _graphene_triangle_t graphene_triangle_t; typedef struct _graphene_ray_t graphene_ray_t; GRAPHENE_END_DECLS #endif /* __GRAPHENE_TYPES_H__ */ graphene-1.8.0/src/graphene-vec2.h000066400000000000000000000145741324365266600167270ustar00rootroot00000000000000/* graphene-vec2.h: 2-coords vector * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_VEC2_H__ #define __GRAPHENE_VEC2_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" GRAPHENE_BEGIN_DECLS /** * graphene_vec2_t: * * A structure capable of holding a vector with two dimensions, x and y. * * The contents of the #graphene_vec2_t structure are private and should * never be accessed directly. */ struct _graphene_vec2_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_simd4f_t, value); }; GRAPHENE_AVAILABLE_IN_1_0 graphene_vec2_t * graphene_vec2_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_free (graphene_vec2_t *v); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec2_t * graphene_vec2_init (graphene_vec2_t *v, float x, float y); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec2_t * graphene_vec2_init_from_vec2 (graphene_vec2_t *v, const graphene_vec2_t *src); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec2_t * graphene_vec2_init_from_float (graphene_vec2_t *v, const float *src); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_to_float (const graphene_vec2_t *v, float *dest); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_add (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_subtract (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_multiply (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_divide (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec2_dot (const graphene_vec2_t *a, const graphene_vec2_t *b); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec2_length (const graphene_vec2_t *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_normalize (const graphene_vec2_t *v, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_vec2_scale (const graphene_vec2_t *v, float factor, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_vec2_negate (const graphene_vec2_t *v, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_vec2_near (const graphene_vec2_t *v1, const graphene_vec2_t *v2, float epsilon); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_vec2_equal (const graphene_vec2_t *v1, const graphene_vec2_t *v2); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_min (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec2_max (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec2_get_x (const graphene_vec2_t *v); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec2_get_y (const graphene_vec2_t *v); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec2_t * graphene_vec2_zero (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec2_t * graphene_vec2_one (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec2_t * graphene_vec2_x_axis (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec2_t * graphene_vec2_y_axis (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_VECTORS_H__ */ graphene-1.8.0/src/graphene-vec3.h000066400000000000000000000177221324365266600167260ustar00rootroot00000000000000/* graphene-vec3.h: 3-coords vector * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_VEC3_H__ #define __GRAPHENE_VEC3_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" GRAPHENE_BEGIN_DECLS /** * graphene_vec3_t: * * A structure capable of holding a vector with three dimensions: x, y, and z. * * The contents of the #graphene_vec3_t structure are private and should * never be accessed directly. */ struct _graphene_vec3_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_simd4f_t, value); }; GRAPHENE_AVAILABLE_IN_1_0 graphene_vec3_t * graphene_vec3_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_free (graphene_vec3_t *v); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec3_t * graphene_vec3_init (graphene_vec3_t *v, float x, float y, float z); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec3_t * graphene_vec3_init_from_vec3 (graphene_vec3_t *v, const graphene_vec3_t *src); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec3_t * graphene_vec3_init_from_float (graphene_vec3_t *v, const float *src); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_to_float (const graphene_vec3_t *v, float *dest); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_add (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_subtract (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_multiply (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_divide (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_cross (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec3_dot (const graphene_vec3_t *a, const graphene_vec3_t *b); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec3_length (const graphene_vec3_t *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_normalize (const graphene_vec3_t *v, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_vec3_scale (const graphene_vec3_t *v, float factor, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_vec3_negate (const graphene_vec3_t *v, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_vec3_equal (const graphene_vec3_t *v1, const graphene_vec3_t *v2); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_vec3_near (const graphene_vec3_t *v1, const graphene_vec3_t *v2, float epsilon); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_min (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_max (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec3_get_x (const graphene_vec3_t *v); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec3_get_y (const graphene_vec3_t *v); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec3_get_z (const graphene_vec3_t *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_get_xy (const graphene_vec3_t *v, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_get_xy0 (const graphene_vec3_t *v, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_get_xyz0 (const graphene_vec3_t *v, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_get_xyz1 (const graphene_vec3_t *v, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec3_get_xyzw (const graphene_vec3_t *v, float w, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec3_t * graphene_vec3_zero (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec3_t * graphene_vec3_one (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec3_t * graphene_vec3_x_axis (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec3_t * graphene_vec3_y_axis (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec3_t * graphene_vec3_z_axis (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_VEC3_H__ */ graphene-1.8.0/src/graphene-vec4.h000066400000000000000000000177001324365266600167230ustar00rootroot00000000000000/* graphene-vec4.h: 4-coords vector * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_VEC4_H__ #define __GRAPHENE_VEC4_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-types.h" GRAPHENE_BEGIN_DECLS /** * graphene_vec4_t: * * A structure capable of holding a vector with four dimensions: x, y, z, and w. * * The contents of the #graphene_vec4_t structure are private and should * never be accessed directly. */ struct _graphene_vec4_t { /*< private >*/ GRAPHENE_PRIVATE_FIELD (graphene_simd4f_t, value); }; GRAPHENE_AVAILABLE_IN_1_0 graphene_vec4_t * graphene_vec4_alloc (void); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_free (graphene_vec4_t *v); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec4_t * graphene_vec4_init (graphene_vec4_t *v, float x, float y, float z, float w); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec4_t * graphene_vec4_init_from_vec4 (graphene_vec4_t *v, const graphene_vec4_t *src); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec4_t * graphene_vec4_init_from_vec3 (graphene_vec4_t *v, const graphene_vec3_t *src, float w); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec4_t * graphene_vec4_init_from_vec2 (graphene_vec4_t *v, const graphene_vec2_t *src, float z, float w); GRAPHENE_AVAILABLE_IN_1_0 graphene_vec4_t * graphene_vec4_init_from_float (graphene_vec4_t *v, const float *src); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_to_float (const graphene_vec4_t *v, float *dest); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_add (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_subtract (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_multiply (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_divide (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec4_dot (const graphene_vec4_t *a, const graphene_vec4_t *b); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec4_length (const graphene_vec4_t *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_normalize (const graphene_vec4_t *v, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_vec4_scale (const graphene_vec4_t *v, float factor, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_2 void graphene_vec4_negate (const graphene_vec4_t *v, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_vec4_equal (const graphene_vec4_t *v1, const graphene_vec4_t *v2); GRAPHENE_AVAILABLE_IN_1_2 bool graphene_vec4_near (const graphene_vec4_t *v1, const graphene_vec4_t *v2, float epsilon); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_min (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_max (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec4_get_x (const graphene_vec4_t *v); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec4_get_y (const graphene_vec4_t *v); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec4_get_z (const graphene_vec4_t *v); GRAPHENE_AVAILABLE_IN_1_0 float graphene_vec4_get_w (const graphene_vec4_t *v); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_get_xy (const graphene_vec4_t *v, graphene_vec2_t *res); GRAPHENE_AVAILABLE_IN_1_0 void graphene_vec4_get_xyz (const graphene_vec4_t *v, graphene_vec3_t *res); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec4_t * graphene_vec4_zero (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec4_t * graphene_vec4_one (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec4_t * graphene_vec4_x_axis (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec4_t * graphene_vec4_y_axis (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec4_t * graphene_vec4_z_axis (void); GRAPHENE_AVAILABLE_IN_1_0 const graphene_vec4_t * graphene_vec4_w_axis (void); GRAPHENE_END_DECLS #endif /* __GRAPHENE_VECTORS_H__ */ graphene-1.8.0/src/graphene-vectors-private.h000066400000000000000000000026401324365266600212140ustar00rootroot00000000000000/* graphene-vectors-private.h: Private vector definitions * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_VECTORS_PRIVATE_H__ #define __GRAPHENE_VECTORS_PRIVATE_H__ #include "graphene-types.h" #include "graphene-vec2.h" #include "graphene-vec3.h" #include "graphene-vec4.h" #include "graphene-simd4f.h" #endif /* __GRAPHENE_VECTORS_PRIVATE_H__ */ graphene-1.8.0/src/graphene-vectors.c000066400000000000000000001323071324365266600175430ustar00rootroot00000000000000/* graphene-vectors.c: Assorted vectors * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "graphene-private.h" #include "graphene-vectors-private.h" #include "graphene-alloc-private.h" #include #if HAVE_PTHREAD #include #include #include #include #endif #if HAVE_INIT_ONCE #define _WIN32_WINNT 0x0600 #include #endif /** * SECTION:graphene-vectors * @Title: Vectors * @Short_Description: Vectors in 2, 3, and 4 dimensions * * Graphene has three vector types, distinguished by their length: * * 1. #graphene_vec2_t, which holds 2 components x and y * 2. #graphene_vec3_t, which holds 3 components x, y, and z * 3. #graphene_vec4_t, which holds 4 components x, y, z, and w * * Each vector type should be treated as an opaque data type. */ /* vec2 {{{ */ /** * graphene_vec2_alloc: (constructor) * * Allocates a new #graphene_vec2_t structure. * * The contents of the returned structure are undefined. * * Use graphene_vec2_init() to initialize the vector. * * Returns: (transfer full): the newly allocated #graphene_vec2_t * structure. Use graphene_vec2_free() to free the resources allocated * by this function. * * Since: 1.0 */ graphene_vec2_t * graphene_vec2_alloc (void) { return graphene_aligned_alloc (sizeof (graphene_vec2_t), 1, 16); } /** * graphene_vec2_free: * @v: a #graphene_vec2_t * * Frees the resources allocated by @v * * Since: 1.0 */ void graphene_vec2_free (graphene_vec2_t *v) { graphene_aligned_free (v); } /** * graphene_vec2_init: * @v: a #graphene_vec2_t * @x: the X field of the vector * @y: the Y field of the vector * * Initializes a #graphene_vec2_t using the given values. * * This function can be called multiple times. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec2_t * graphene_vec2_init (graphene_vec2_t *v, float x, float y) { v->value = graphene_simd4f_init (x, y, 0.f, 0.f); return v; } /** * graphene_vec2_init_from_vec2: * @v: a #graphene_vec2_t * @src: a #graphene_vec2_t * * Copies the contents of @src into @v. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec2_t * graphene_vec2_init_from_vec2 (graphene_vec2_t *v, const graphene_vec2_t *src) { v->value = src->value; return v; } /** * graphene_vec2_init_from_float: * @v: a #graphene_vec2_t * @src: (array fixed-size=2): an array of floating point values * with at least two elements * * Initializes @v with the contents of the given array. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec2_t * graphene_vec2_init_from_float (graphene_vec2_t *v, const float *src) { v->value = graphene_simd4f_init_2f (src); return v; } /** * graphene_vec2_get_x: * @v: a #graphene_vec2_t * * Retrieves the X component of the #graphene_vec2_t. * * Returns: the value of the X component * * Since: 1.0 */ float graphene_vec2_get_x (const graphene_vec2_t *v) { return graphene_simd4f_get_x (v->value); } /** * graphene_vec2_get_y: * @v: a #graphene_vec2_t * * Retrieves the Y component of the #graphene_vec2_t. * * Returns: the value of the Y component * * Since: 1.0 */ float graphene_vec2_get_y (const graphene_vec2_t *v) { return graphene_simd4f_get_y (v->value); } /** * graphene_vec2_to_float: * @v: a #graphene_vec2_t * @dest: (out caller-allocates) (array fixed-size=2): return location * for an array of floating point values with at least 2 elements * * Stores the components of @v into an array. * * Since: 1.0 */ void graphene_vec2_to_float (const graphene_vec2_t *v, float *dest) { graphene_simd4f_dup_2f (v->value, dest); } /** * graphene_vec2_add: * @a: a #graphene_vec2_t * @b: a #graphene_vec2_t * @res: (out caller-allocates): return location for the result * * Adds each component of the two passed vectors and places * each result into the components of @res. * * Since: 1.0 */ void graphene_vec2_add (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res) { res->value = graphene_simd4f_add (a->value, b->value); } /** * graphene_vec2_subtract: * @a: a #graphene_vec2_t * @b: a #graphene_vec2_t * @res: (out caller-allocates): return location for the result * * Subtracts from each component of the first operand @a the * corresponding component of the second operand @b and places * each result into the components of @res. * * Since: 1.0 */ void graphene_vec2_subtract (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res) { res->value = graphene_simd4f_sub (a->value, b->value); } /** * graphene_vec2_multiply: * @a: a #graphene_vec2_t * @b: a #graphene_vec2_t * @res: (out caller-allocates): return location for the result * * Multiplies each component of the two passed vectors and places * each result into the components of @res. * * Since: 1.0 */ void graphene_vec2_multiply (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res) { res->value = graphene_simd4f_mul (a->value, b->value); } /** * graphene_vec2_divide: * @a: a #graphene_vec2_t * @b: a #graphene_vec2_t * @res: (out caller-allocates): return location for the result * * Divides each component of the first operand @a by the corresponding * component of the second operand @b, and places the results into the * vector @res. * * Since: 1.0 */ void graphene_vec2_divide (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res) { res->value = graphene_simd4f_div (a->value, b->value); } /** * graphene_vec2_dot: * @a: a #graphene_vec2_t * @b: a #graphene_vec2_t * * Computes the dot product of the two given vectors. * * Returns: the dot product of the vectors * * Since: 1.0 */ float graphene_vec2_dot (const graphene_vec2_t *a, const graphene_vec2_t *b) { return graphene_simd4f_get_x (graphene_simd4f_dot2 (a->value, b->value)); } /** * graphene_vec2_length: * @v: a #graphene_vec2_t * * Computes the length of the given vector. * * Returns: the length of the vector * * Since: 1.0 */ float graphene_vec2_length (const graphene_vec2_t *v) { return graphene_simd4f_get_x (graphene_simd4f_length2 (v->value)); } /** * graphene_vec2_normalize: * @v: a #graphene_vec2_t * @res: (out caller-allocates): return location for the * normalized vector * * Computes the normalized vector for the given vector @v. * * Since: 1.0 */ void graphene_vec2_normalize (const graphene_vec2_t *v, graphene_vec2_t *res) { if (graphene_vec2_length (v) != 0.f) res->value = graphene_simd4f_normalize2 (v->value); else res->value = graphene_simd4f_init_zero (); } /** * graphene_vec2_min: * @a: a #graphene_vec2_t * @b: a #graphene_vec2_t * @res: (out caller-allocates): the resulting vector * * Compares the two given vectors and places the minimum * values of each component into @res. * * Since: 1.0 */ void graphene_vec2_min (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res) { res->value = graphene_simd4f_min (a->value, b->value); } /** * graphene_vec2_max: * @a: a #graphene_vec2_t * @b: a #graphene_vec2_t * @res: (out caller-allocates): the resulting vector * * Compares the two given vectors and places the maximum * values of each component into @res. * * Since: 1.0 */ void graphene_vec2_max (const graphene_vec2_t *a, const graphene_vec2_t *b, graphene_vec2_t *res) { res->value = graphene_simd4f_max (a->value, b->value); } /** * graphene_vec2_scale: * @v: a #graphene_vec2_t * @factor: the scalar factor * @res: (out caller-allocates): return location for the result vector * * Multiplies all components of the given vector with the given scalar @factor. * * Since: 1.2 */ void graphene_vec2_scale (const graphene_vec2_t *v, float factor, graphene_vec2_t *res) { res->value = graphene_simd4f_mul (v->value, graphene_simd4f_splat (factor)); } /** * graphene_vec2_negate: * @v: a #graphene_vec2_t * @res: (out caller-allocates): return location for the result vector * * Negates the given #graphene_vec2_t. * * Since: 1.2 */ void graphene_vec2_negate (const graphene_vec2_t *v, graphene_vec2_t *res) { res->value = graphene_simd4f_neg (v->value); } static bool vec2_equal (const void *p1, const void *p2) { const graphene_vec2_t *v1 = p1; const graphene_vec2_t *v2 = p2; if (graphene_simd4f_cmp_eq (v1->value, v2->value)) return true; return graphene_vec2_near (v1, v2, GRAPHENE_FLOAT_EPSILON); } /** * graphene_vec2_equal: * @v1: a #graphene_vec2_t * @v2: a #graphene_vec2_t * * Checks whether the two given #graphene_vec2_t are equal. * * Returns: `true` if the two vectors are equal, and false otherwise * * Since: 1.2 */ bool graphene_vec2_equal (const graphene_vec2_t *v1, const graphene_vec2_t *v2) { return graphene_pointer_equal (v1, v2, vec2_equal); } /** * graphene_vec2_near: * @v1: a #graphene_vec2_t * @v2: a #graphene_vec2_t * @epsilon: the threshold between the two vectors * * Compares the two given #graphene_vec2_t vectors and checks * whether their values are within the given @epsilon. * * Returns: `true` if the two vectors are near each other * * Since: 1.2 */ bool graphene_vec2_near (const graphene_vec2_t *v1, const graphene_vec2_t *v2, float epsilon) { graphene_simd4f_t d = graphene_simd4f_sub (v1->value, v2->value); float epsilon_sq = epsilon * epsilon; return graphene_simd4f_get_x (graphene_simd4f_dot2 (d, d)) < epsilon_sq; } enum { VEC2_ZERO, VEC2_ONE, VEC2_X_AXIS, VEC2_Y_AXIS, N_STATIC_VEC2 }; static graphene_vec2_t static_vec2[N_STATIC_VEC2]; static void init_static_vec2_once (void) { static_vec2[VEC2_ZERO].value = graphene_simd4f_init_zero (); static_vec2[VEC2_ONE].value = graphene_simd4f_init (1.f, 1.f, 0.f, 0.f); static_vec2[VEC2_X_AXIS].value = graphene_simd4f_init (1.f, 0.f, 0.f, 0.f); static_vec2[VEC2_Y_AXIS].value = graphene_simd4f_init (0.f, 1.f, 0.f, 0.f); } #if HAVE_PTHREAD static pthread_once_t static_vec2_once = PTHREAD_ONCE_INIT; static inline void init_static_vec2 (void) { int status = pthread_once (&static_vec2_once, init_static_vec2_once); if (status < 0) { int saved_errno = errno; fprintf (stderr, "pthread_once failed: %s (errno:%d)\n", strerror (saved_errno), saved_errno); } } #elif HAVE_INIT_ONCE static INIT_ONCE static_vec2_once = INIT_ONCE_STATIC_INIT; BOOL CALLBACK InitVec2Func (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext) { init_static_vec2_once (); return TRUE; } static inline void init_static_vec2 (void) { BOOL bStatus = InitOnceExecuteOnce (&static_vec2_once, InitVec2Func, NULL, NULL); if (!bStatus) fprintf (stderr, "InitOnceExecuteOnce failed\n"); } #else /* !HAVE_PTHREAD && !HAVE_INIT_ONCE */ static bool static_vec2_init = false; static inline void init_static_vec2 (void) { if (static_vec2_init) return; init_static_vec2_once (); static_vec2_init = true; } #endif /* HAVE_PTHREAD */ /** * graphene_vec2_zero: * * Retrieves a constant vector with (0, 0) components. * * Returns: (transfer none): the zero vector * * Since: 1.0 */ const graphene_vec2_t * graphene_vec2_zero (void) { init_static_vec2 (); return &(static_vec2[VEC2_ZERO]); } /** * graphene_vec2_one: * * Retrieves a constant vector with (1, 1) components. * * Returns: (transfer none): the one vector * * Since: 1.0 */ const graphene_vec2_t * graphene_vec2_one (void) { init_static_vec2 (); return &(static_vec2[VEC2_ONE]); } /** * graphene_vec2_x_axis: * * Retrieves a constant vector with (1, 0) components. * * Returns: (transfer none): the X axis vector * * Since: 1.0 */ const graphene_vec2_t * graphene_vec2_x_axis (void) { init_static_vec2 (); return &(static_vec2[VEC2_X_AXIS]); } /** * graphene_vec2_y_axis: * * Retrieves a constant vector with (0, 1) components. * * Returns: (transfer none): the Y axis vector * * Since: 1.0 */ const graphene_vec2_t * graphene_vec2_y_axis (void) { init_static_vec2 (); return &(static_vec2[VEC2_Y_AXIS]); } /* }}} vec2 */ /* vec3 {{{ */ /** * graphene_vec3_alloc: (constructor) * * Allocates a new #graphene_vec3_t structure. * * The contents of the returned structure are undefined. * * Use graphene_vec3_init() to initialize the vector. * * Returns: (transfer full): the newly allocated #graphene_vec3_t * structure. Use graphene_vec3_free() to free the resources allocated * by this function. * * Since: 1.0 */ graphene_vec3_t * graphene_vec3_alloc (void) { return graphene_aligned_alloc (sizeof (graphene_vec3_t), 1, 16); } /** * graphene_vec3_free: * @v: a #graphene_vec3_t * * Frees the resources allocated by @v * * Since: 1.0 */ void graphene_vec3_free (graphene_vec3_t *v) { graphene_aligned_free (v); } /** * graphene_vec3_init: * @v: a #graphene_vec3_t * @x: the X field of the vector * @y: the Y field of the vector * @z: the Z field of the vector * * Initializes a #graphene_vec3_t using the given values. * * This function can be called multiple times. * * Returns: (transfer none): a pointer to the initialized * vector * * Since: 1.0 */ graphene_vec3_t * graphene_vec3_init (graphene_vec3_t *v, float x, float y, float z) { v->value = graphene_simd4f_init (x, y, z, 0.f); return v; } /** * graphene_vec3_init_from_vec3: * @v: a #graphene_vec3_t * @src: a #graphene_vec3_t * * Initializes a #graphene_vec3_t with the values of another * #graphene_vec3_t. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec3_t * graphene_vec3_init_from_vec3 (graphene_vec3_t *v, const graphene_vec3_t *src) { v->value = src->value; return v; } /** * graphene_vec3_init_from_float: * @v: a #graphene_vec3_t * @src: (array fixed-size=3): an array of 3 floating point values * * Initializes a #graphene_vec3_t with the values from an array. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec3_t * graphene_vec3_init_from_float (graphene_vec3_t *v, const float *src) { v->value = graphene_simd4f_init_3f (src); return v; } /** * graphene_vec3_get_x: * @v: a #graphene_vec3_t * * Retrieves the first component of the given vector @v. * * Returns: the value of the first component of the vector * * Since: 1.0 */ float graphene_vec3_get_x (const graphene_vec3_t *v) { return graphene_simd4f_get_x (v->value); } /** * graphene_vec3_get_y: * @v: a #graphene_vec3_t * * Retrieves the second component of the given vector @v. * * Returns: the value of the second component of the vector * * Since: 1.0 */ float graphene_vec3_get_y (const graphene_vec3_t *v) { return graphene_simd4f_get_y (v->value); } /** * graphene_vec3_get_z: * @v: a #graphene_vec3_t * * Retrieves the third component of the given vector @v. * * Returns: the value of the third component of the vector * * Since: 1.0 */ float graphene_vec3_get_z (const graphene_vec3_t *v) { return graphene_simd4f_get_z (v->value); } /** * graphene_vec3_to_float: * @v: a #graphene_vec3_t * @dest: (out caller-allocates) (array fixed-size=3): return location for * an array of floating point values * * Copies the components of a #graphene_vec3_t into the given array. * * Since: 1.0 */ void graphene_vec3_to_float (const graphene_vec3_t *v, float *dest) { graphene_simd4f_dup_3f (v->value, dest); } /** * graphene_vec3_add: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * @res: (out caller-allocates): return location for the resulting vector * * Adds each component of the two given vectors. * * Since: 1.0 */ void graphene_vec3_add (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res) { res->value = graphene_simd4f_add (a->value, b->value); } /** * graphene_vec3_subtract: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * @res: (out caller-allocates): return location for the resulting vector * * Subtracts from each component of the first operand @a the * corresponding component of the second operand @b and places * each result into the components of @res. * * Since: 1.0 */ void graphene_vec3_subtract (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res) { res->value = graphene_simd4f_sub (a->value, b->value); } /** * graphene_vec3_multiply: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * @res: (out caller-allocates): return location for the resulting vector * * Multiplies each component of the two given vectors. * * Since: 1.0 */ void graphene_vec3_multiply (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res) { res->value = graphene_simd4f_mul (a->value, b->value); } /** * graphene_vec3_divide: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * @res: (out caller-allocates): return location for the resulting vector * * Divides each component of the first operand @a by the corresponding * component of the second operand @b, and places the results into the * vector @res. * * Since: 1.0 */ void graphene_vec3_divide (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res) { res->value = graphene_simd4f_div (a->value, b->value); } /** * graphene_vec3_cross: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * @res: (out caller-allocates): return location for the resulting vector * * Computes the cross product of the two given vectors. * * Since: 1.0 */ void graphene_vec3_cross (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res) { res->value = graphene_simd4f_cross3 (a->value, b->value); } /** * graphene_vec3_dot: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * * Computes the dot product of the two given vectors. * * Returns: the value of the dot product * * Since: 1.0 */ float graphene_vec3_dot (const graphene_vec3_t *a, const graphene_vec3_t *b) { return graphene_simd4f_dot3_scalar (a->value, b->value); } /** * graphene_vec3_length: * @v: a #graphene_vec3_t * * Retrieves the length of the given vector @v. * * Returns: the value of the length of the vector * * Since: 1.0 */ float graphene_vec3_length (const graphene_vec3_t *v) { return graphene_simd4f_get_x (graphene_simd4f_length3 (v->value)); } /** * graphene_vec3_normalize: * @v: a #graphene_vec3_t * @res: (out caller-allocates): return location for the normalized vector * * Normalizes the given #graphene_vec3_t. * * Since: 1.0 */ void graphene_vec3_normalize (const graphene_vec3_t *v, graphene_vec3_t *res) { if (graphene_vec3_length (v) != 0.f) res->value = graphene_simd4f_normalize3 (v->value); else res->value = graphene_simd4f_init_zero (); } /** * graphene_vec3_min: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * @res: (out caller-allocates): return location for the result vector * * Compares each component of the two given vectors and creates a * vector that contains the minimum values. * * Since: 1.0 */ void graphene_vec3_min (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res) { res->value = graphene_simd4f_min (a->value, b->value); } /** * graphene_vec3_max: * @a: a #graphene_vec3_t * @b: a #graphene_vec3_t * @res: (out caller-allocates): return location for the result vector * * Compares each component of the two given vectors and creates a * vector that contains the maximum values. * * Since: 1.0 */ void graphene_vec3_max (const graphene_vec3_t *a, const graphene_vec3_t *b, graphene_vec3_t *res) { res->value = graphene_simd4f_max (a->value, b->value); } /** * graphene_vec3_scale: * @v: a #graphene_vec3_t * @factor: the scalar factor * @res: (out caller-allocates): return location for the result vector * * Multiplies all components of the given vector with the given scalar @factor. * * Since: 1.2 */ void graphene_vec3_scale (const graphene_vec3_t *v, float factor, graphene_vec3_t *res) { res->value = graphene_simd4f_mul (v->value, graphene_simd4f_splat (factor)); } /** * graphene_vec3_get_xy: * @v: a #graphene_vec3_t * @res: (out caller-allocates): return location for a #graphene_vec2_t * * Creates a #graphene_vec2_t that contains the first and second * components of the given #graphene_vec3_t. * * Since: 1.0 */ void graphene_vec3_get_xy (const graphene_vec3_t *v, graphene_vec2_t *res) { res->value = graphene_simd4f_zero_zw (v->value); } /** * graphene_vec3_get_xy0: * @v: a #graphene_vec3_t * @res: (out caller-allocates): return location for a #graphene_vec3_t * * Creates a #graphene_vec3_t that contains the first two components of * the given #graphene_vec3_t, and the third component set to 0. * * Since: 1.0 */ void graphene_vec3_get_xy0 (const graphene_vec3_t *v, graphene_vec3_t *res) { res->value = graphene_simd4f_zero_zw (v->value); } /** * graphene_vec3_get_xyz0: * @v: a #graphene_vec3_t * @res: (out caller-allocates): return location for the vector * * Converts a #graphene_vec3_t in a #graphene_vec4_t using 0.0 * as the value for the fourth component of the resulting vector. * * Since: 1.0 */ void graphene_vec3_get_xyz0 (const graphene_vec3_t *v, graphene_vec4_t *res) { res->value = graphene_simd4f_zero_w (v->value); } /** * graphene_vec3_get_xyz1: * @v: a #graphene_vec3_t * @res: (out caller-allocates): return location for the vector * * Converts a #graphene_vec3_t in a #graphene_vec4_t using 1.0 * as the value for the fourth component of the resulting vector. * * Since: 1.0 */ void graphene_vec3_get_xyz1 (const graphene_vec3_t *v, graphene_vec4_t *res) { res->value = graphene_simd4f_add (graphene_simd4f_zero_w (v->value), graphene_simd4f_init (0.f, 0.f, 0.f, 1.f)); } /** * graphene_vec3_get_xyzw: * @v: a #graphene_vec3_t * @w: the value of the W component * @res: (out caller-allocates): return location for the vector * * Converts a #graphene_vec3_t in a #graphene_vec4_t using @w as * the value of the fourth component of the resulting vector. * * Since: 1.0 */ void graphene_vec3_get_xyzw (const graphene_vec3_t *v, float w, graphene_vec4_t *res) { res->value = graphene_simd4f_add (graphene_simd4f_zero_w (v->value), graphene_simd4f_init (0.f, 0.f, 0.f, w)); } /** * graphene_vec3_negate: * @v: a #graphene_vec3_t * @res: (out caller-allocates): return location for the result vector * * Negates the given #graphene_vec3_t. * * Since: 1.2 */ void graphene_vec3_negate (const graphene_vec3_t *v, graphene_vec3_t *res) { res->value = graphene_simd4f_neg (v->value); } static bool vec3_equal (const void *p1, const void *p2) { const graphene_vec3_t *v1 = p1; const graphene_vec3_t *v2 = p2; if (graphene_simd4f_cmp_eq (v1->value, v2->value)) return true; return graphene_vec3_near (v1, v2, GRAPHENE_FLOAT_EPSILON); } /** * graphene_vec3_equal: * @v1: a #graphene_vec3_t * @v2: a #graphene_vec3_t * * Checks whether the two given #graphene_vec3_t are equal. * * Returns: `true` if the two vectors are equal, and false otherwise * * Since: 1.2 */ bool graphene_vec3_equal (const graphene_vec3_t *v1, const graphene_vec3_t *v2) { return graphene_pointer_equal (v1, v2, vec3_equal); } /** * graphene_vec3_near: * @v1: a #graphene_vec3_t * @v2: a #graphene_vec3_t * @epsilon: the threshold between the two vectors * * Compares the two given #graphene_vec3_t vectors and checks * whether their values are within the given @epsilon. * * Returns: `true` if the two vectors are near each other * * Since: 1.2 */ bool graphene_vec3_near (const graphene_vec3_t *v1, const graphene_vec3_t *v2, float epsilon) { graphene_simd4f_t d = graphene_simd4f_sub (v1->value, v2->value); float epsilon_sq = epsilon * epsilon; return graphene_simd4f_dot3_scalar (d, d) < epsilon_sq; } enum { VEC3_ZERO, VEC3_ONE, VEC3_X_AXIS, VEC3_Y_AXIS, VEC3_Z_AXIS, N_STATIC_VEC3 }; static graphene_vec3_t static_vec3[N_STATIC_VEC3]; static void init_static_vec3_once (void) { static_vec3[VEC3_ZERO].value = graphene_simd4f_init_zero (); static_vec3[VEC3_ONE].value = graphene_simd4f_init (1.f, 1.f, 1.f, 0.f); static_vec3[VEC3_X_AXIS].value = graphene_simd4f_init (1.f, 0.f, 0.f, 0.f); static_vec3[VEC3_Y_AXIS].value = graphene_simd4f_init (0.f, 1.f, 0.f, 0.f); static_vec3[VEC3_Z_AXIS].value = graphene_simd4f_init (0.f, 0.f, 1.f, 0.f); } #if HAVE_PTHREAD static pthread_once_t static_vec3_once = PTHREAD_ONCE_INIT; static inline void init_static_vec3 (void) { int status = pthread_once (&static_vec3_once, init_static_vec3_once); if (status < 0) { int saved_errno = errno; fprintf (stderr, "pthread_once failed: %s (errno:%d)\n", strerror (saved_errno), saved_errno); } } #elif HAVE_INIT_ONCE static INIT_ONCE static_vec3_once = INIT_ONCE_STATIC_INIT; BOOL CALLBACK InitVec3Func (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext) { init_static_vec3_once (); return TRUE; } static inline void init_static_vec3 (void) { BOOL bStatus = InitOnceExecuteOnce (&static_vec3_once, InitVec3Func, NULL, NULL); if (!bStatus) fprintf (stderr, "InitOnceExecuteOnce failed\n"); } #else /* !HAVE_PTHREAD && !HAVE_INIT_ONCE*/ static bool static_vec3_init = false; static inline void init_static_vec3 (void) { if (static_vec3_init) return; init_static_vec3_once (); static_vec3_init = true; } #endif /* HAVE_PTHREAD */ /** * graphene_vec3_zero: * * Provides a constant pointer to a vector with three components, * all sets to 0. * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec3_t * graphene_vec3_zero (void) { init_static_vec3 (); return &(static_vec3[VEC3_ZERO]); } /** * graphene_vec3_one: * * Provides a constant pointer to a vector with three components, * all sets to 1. * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec3_t * graphene_vec3_one (void) { init_static_vec3 (); return &(static_vec3[VEC3_ONE]); } /** * graphene_vec3_x_axis: * * Provides a constant pointer to a vector with three components * with values set to (1, 0, 0). * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec3_t * graphene_vec3_x_axis (void) { init_static_vec3 (); return &(static_vec3[VEC3_X_AXIS]); } /** * graphene_vec3_y_axis: * * Provides a constant pointer to a vector with three components * with values set to (0, 1, 0). * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec3_t * graphene_vec3_y_axis (void) { init_static_vec3 (); return &(static_vec3[VEC3_Y_AXIS]); } /** * graphene_vec3_z_axis: * * Provides a constant pointer to a vector with three components * with values set to (0, 0, 1). * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec3_t * graphene_vec3_z_axis (void) { init_static_vec3 (); return &(static_vec3[VEC3_Z_AXIS]); } /* }}} vec3 */ /* vec4 {{{ */ /** * graphene_vec4_alloc: (constructor) * * Allocates a new #graphene_vec4_t structure. * * The contents of the returned structure are undefined. * * Use graphene_vec4_init() to initialize the vector. * * Returns: (transfer full): the newly allocated #graphene_vec4_t * structure. Use graphene_vec4_free() to free the resources allocated * by this function. * * Since: 1.0 */ graphene_vec4_t * graphene_vec4_alloc (void) { return graphene_aligned_alloc (sizeof (graphene_vec4_t), 1, 16); } /** * graphene_vec4_free: * @v: a #graphene_vec4_t * * Frees the resources allocated by @v * * Since: 1.0 */ void graphene_vec4_free (graphene_vec4_t *v) { graphene_aligned_free (v); } /** * graphene_vec4_init: * @v: a #graphene_vec4_t * @x: the X field of the vector * @y: the Y field of the vector * @z: the Z field of the vector * @w: the W field of the vector * * Initializes a #graphene_vec4_t using the given values. * * This function can be called multiple times. * * Returns: (transfer none): a pointer to the initialized * vector * * Since: 1.0 */ graphene_vec4_t * graphene_vec4_init (graphene_vec4_t *v, float x, float y, float z, float w) { v->value = graphene_simd4f_init (x, y, z, w); return v; } /** * graphene_vec4_init_from_vec4: * @v: a #graphene_vec4_t * @src: a #graphene_vec4_t * * Initializes a #graphene_vec4_t using the components of * another #graphene_vec4_t. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec4_t * graphene_vec4_init_from_vec4 (graphene_vec4_t *v, const graphene_vec4_t *src) { v->value = src->value; return v; } /** * graphene_vec4_init_from_vec3: * @v: a #graphene_vec4_t * @src: a #graphene_vec3_t * @w: the value for the fourth component of @v * * Initializes a #graphene_vec4_t using the components of a * #graphene_vec3_t and the value of @w. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec4_t * graphene_vec4_init_from_vec3 (graphene_vec4_t *v, const graphene_vec3_t *src, float w) { v->value = graphene_simd4f_merge_w (src->value, w); return v; } /** * graphene_vec4_init_from_vec2: * @v: a #graphene_vec4_t * @src: a #graphene_vec2_t * @z: the value for the third component of @v * @w: the value for the fourth component of @v * * Initializes a #graphene_vec4_t using the components of a * #graphene_vec2_t and the values of @z and @w. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec4_t * graphene_vec4_init_from_vec2 (graphene_vec4_t *v, const graphene_vec2_t *src, float z, float w) { v->value = graphene_simd4f_merge_low (src->value, graphene_simd4f_init (z, w, 0, 0)); return v; } /** * graphene_vec4_init_from_float: * @v: a #graphene_vec4_t * @src: (array fixed-size=4): an array of four floating point values * * Initializes a #graphene_vec4_t with the values inside the given array. * * Returns: (transfer none): the initialized vector * * Since: 1.0 */ graphene_vec4_t * graphene_vec4_init_from_float (graphene_vec4_t *v, const float *src) { v->value = graphene_simd4f_init_4f (src); return v; } /** * graphene_vec4_get_x: * @v: a #graphene_vec4_t * * Retrieves the value of the first component of the given #graphene_vec4_t. * * Returns: the value of the first component * * Since: 1.0 */ float graphene_vec4_get_x (const graphene_vec4_t *v) { return graphene_simd4f_get_x (v->value); } /** * graphene_vec4_get_y: * @v: a #graphene_vec4_t * * Retrieves the value of the second component of the given #graphene_vec4_t. * * Returns: the value of the second component * * Since: 1.0 */ float graphene_vec4_get_y (const graphene_vec4_t *v) { return graphene_simd4f_get_y (v->value); } /** * graphene_vec4_get_z: * @v: a #graphene_vec4_t * * Retrieves the value of the third component of the given #graphene_vec4_t. * * Returns: the value of the third component * * Since: 1.0 */ float graphene_vec4_get_z (const graphene_vec4_t *v) { return graphene_simd4f_get_z (v->value); } /** * graphene_vec4_get_w: * @v: a #graphene_vec4_t * * Retrieves the value of the fourth component of the given #graphene_vec4_t. * * Returns: the value of the fourth component * * Since: 1.0 */ float graphene_vec4_get_w (const graphene_vec4_t *v) { return graphene_simd4f_get_w (v->value); } /** * graphene_vec4_to_float: * @v: a #graphene_vec4_t * @dest: (out caller-allocates) (array fixed-size=4): return location for * an array of floating point values * * Stores the components of the given #graphene_vec4_t into an array * of floating point values. * * Since: 1.0 */ void graphene_vec4_to_float (const graphene_vec4_t *v, float *dest) { graphene_simd4f_dup_4f (v->value, dest); } /** * graphene_vec4_add: * @a: a #graphene_vec4_t * @b: a #graphene_vec4_t * @res: (out caller-allocates): return location for the resulting vector * * Adds each component of the two given vectors. * * Since: 1.0 */ void graphene_vec4_add (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res) { res->value = graphene_simd4f_add (a->value, b->value); } /** * graphene_vec4_subtract: * @a: a #graphene_vec4_t * @b: a #graphene_vec4_t * @res: (out caller-allocates): return location for the resulting vector * * Subtracts from each component of the first operand @a the * corresponding component of the second operand @b and places * each result into the components of @res. * * Since: 1.0 */ void graphene_vec4_subtract (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res) { res->value = graphene_simd4f_sub (a->value, b->value); } /** * graphene_vec4_multiply: * @a: a #graphene_vec4_t * @b: a #graphene_vec4_t * @res: (out caller-allocates): return location for the resulting vector * * Multiplies each component of the two given vectors. * * Since: 1.0 */ void graphene_vec4_multiply (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res) { res->value = graphene_simd4f_mul (a->value, b->value); } /** * graphene_vec4_divide: * @a: a #graphene_vec4_t * @b: a #graphene_vec4_t * @res: (out caller-allocates): return location for the resulting vector * * Divides each component of the first operand @a by the corresponding * component of the second operand @b, and places the results into the * vector @res. * * Since: 1.0 */ void graphene_vec4_divide (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res) { res->value = graphene_simd4f_div (a->value, b->value); } /** * graphene_vec4_dot: * @a: a #graphene_vec4_t * @b: a #graphene_vec4_t * * Computes the dot product of the two given vectors. * * Returns: the value of the dot product * * Since: 1.0 */ float graphene_vec4_dot (const graphene_vec4_t *a, const graphene_vec4_t *b) { return graphene_simd4f_get_x (graphene_simd4f_dot4 (a->value, b->value)); } /** * graphene_vec4_length: * @v: a #graphene_vec4_t * * Computes the length of the given #graphene_vec4_t. * * Returns: the length of the vector * * Since: 1.0 */ float graphene_vec4_length (const graphene_vec4_t *v) { return graphene_simd4f_get_x (graphene_simd4f_length4 (v->value)); } /** * graphene_vec4_normalize: * @v: a #graphene_vec4_t * @res: (out caller-allocates): return location for the normalized * vector * * Normalizes the given #graphene_vec4_t. * * Since: 1.0 */ void graphene_vec4_normalize (const graphene_vec4_t *v, graphene_vec4_t *res) { if (graphene_vec4_length (v) != 0.f) res->value = graphene_simd4f_normalize4 (v->value); else res->value = graphene_simd4f_init_zero (); } /** * graphene_vec4_min: * @a: a #graphene_vec4_t * @b: a #graphene_vec4_t * @res: (out caller-allocates): return location for the result vector * * Compares each component of the two given vectors and creates a * vector that contains the minimum values. * * Since: 1.0 */ void graphene_vec4_min (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res) { res->value = graphene_simd4f_min (a->value, b->value); } /** * graphene_vec4_max: * @a: a #graphene_vec4_t * @b: a #graphene_vec4_t * @res: (out caller-allocates): return location for the result vector * * Compares each component of the two given vectors and creates a * vector that contains the maximum values. * * Since: 1.0 */ void graphene_vec4_max (const graphene_vec4_t *a, const graphene_vec4_t *b, graphene_vec4_t *res) { res->value = graphene_simd4f_max (a->value, b->value); } /** * graphene_vec4_scale: * @v: a #graphene_vec4_t * @factor: the scalar factor * @res: (out caller-allocates): return location for the result vector * * Multiplies all components of the given vector with the given scalar @factor. * * Since: 1.2 */ void graphene_vec4_scale (const graphene_vec4_t *v, float factor, graphene_vec4_t *res) { res->value = graphene_simd4f_mul (v->value, graphene_simd4f_splat (factor)); } /** * graphene_vec4_get_xy: * @v: a #graphene_vec4_t * @res: (out caller-allocates): return location for a #graphene_vec2_t * * Creates a #graphene_vec2_t that contains the first two components * of the given #graphene_vec4_t. * * Since: 1.0 */ void graphene_vec4_get_xy (const graphene_vec4_t *v, graphene_vec2_t *res) { res->value = graphene_simd4f_zero_zw (v->value); } /** * graphene_vec4_get_xyz: * @v: a #graphene_vec4_t * @res: (out caller-allocates): return location for a graphene_vec3_t * * Creates a #graphene_vec3_t that contains the first three components * of the given #graphene_vec4_t. * * Since: 1.0 */ void graphene_vec4_get_xyz (const graphene_vec4_t *v, graphene_vec3_t *res) { res->value = graphene_simd4f_zero_w (v->value); } /** * graphene_vec4_negate: * @v: a #graphene_vec4_t * @res: (out caller-allocates): return location for the result vector * * Negates the given #graphene_vec4_t. * * Since: 1.2 */ void graphene_vec4_negate (const graphene_vec4_t *v, graphene_vec4_t *res) { res->value = graphene_simd4f_neg (v->value); } static bool vec4_equal (const void *p1, const void *p2) { const graphene_vec4_t *v1 = p1; const graphene_vec4_t *v2 = p2; if (graphene_simd4f_cmp_eq (v1->value, v2->value)) return true; return graphene_vec4_near (v1, v2, GRAPHENE_FLOAT_EPSILON); } /** * graphene_vec4_equal: * @v1: a #graphene_vec4_t * @v2: a #graphene_vec4_t * * Checks whether the two given #graphene_vec4_t are equal. * * Returns: `true` if the two vectors are equal, and false otherwise * * Since: 1.2 */ bool graphene_vec4_equal (const graphene_vec4_t *v1, const graphene_vec4_t *v2) { return graphene_pointer_equal (v1, v2, vec4_equal); } /** * graphene_vec4_near: * @v1: a #graphene_vec4_t * @v2: a #graphene_vec4_t * @epsilon: the threshold between the two vectors * * Compares the two given #graphene_vec4_t vectors and checks * whether their values are within the given @epsilon. * * Returns: `true` if the two vectors are near each other * * Since: 1.2 */ bool graphene_vec4_near (const graphene_vec4_t *v1, const graphene_vec4_t *v2, float epsilon) { graphene_simd4f_t d = graphene_simd4f_sub (v1->value, v2->value); float epsilon_sq = epsilon * epsilon; return graphene_simd4f_get_x (graphene_simd4f_dot4 (d, d)) < epsilon_sq; } enum { VEC4_ZERO, VEC4_ONE, VEC4_X_AXIS, VEC4_Y_AXIS, VEC4_Z_AXIS, VEC4_W_AXIS, N_STATIC_VEC4 }; static graphene_vec4_t static_vec4[N_STATIC_VEC4]; static void init_static_vec4_once (void) { static_vec4[VEC4_ZERO].value = graphene_simd4f_init_zero (); static_vec4[VEC4_ONE].value = graphene_simd4f_splat (1.f); static_vec4[VEC4_X_AXIS].value = graphene_simd4f_init (1.f, 0.f, 0.f, 0.f); static_vec4[VEC4_Y_AXIS].value = graphene_simd4f_init (0.f, 1.f, 0.f, 0.f); static_vec4[VEC4_Z_AXIS].value = graphene_simd4f_init (0.f, 0.f, 1.f, 0.f); static_vec4[VEC4_W_AXIS].value = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f); } #if HAVE_PTHREAD static pthread_once_t static_vec4_init_once = PTHREAD_ONCE_INIT; static inline void init_static_vec4 (void) { int status = pthread_once (&static_vec4_init_once, init_static_vec4_once); if (status < 0) { int saved_errno = errno; fprintf (stderr, "pthread_once failed: %s (errno:%d)\n", strerror (saved_errno), saved_errno); } } #elif HAVE_INIT_ONCE static INIT_ONCE static_vec4_once = INIT_ONCE_STATIC_INIT; BOOL CALLBACK InitVec4Func (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext) { init_static_vec4_once (); return TRUE; } static inline void init_static_vec4 (void) { BOOL bStatus = InitOnceExecuteOnce (&static_vec4_once, InitVec4Func, NULL, NULL); if (!bStatus) fprintf (stderr, "InitOnceExecuteOnce failed\n"); } #else /* !HAVE_PTHREAD && !HAVE_INIT_ONCE */ static bool static_vec4_init = false; static inline void init_static_vec4 (void) { if (static_vec4_init) return; init_static_vec4_once (); static_vec4_init = true; } #endif /* HAVE_PTHREAD */ /** * graphene_vec4_zero: * * Retrieves a pointer to a #graphene_vec4_t with all its * components set to 0. * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec4_t * graphene_vec4_zero (void) { init_static_vec4 (); return &(static_vec4[VEC4_ZERO]); } /** * graphene_vec4_one: * * Retrieves a pointer to a #graphene_vec4_t with all its * components set to 1. * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec4_t * graphene_vec4_one (void) { init_static_vec4 (); return &(static_vec4[VEC4_ONE]); } /** * graphene_vec4_x_axis: * * Retrieves a pointer to a #graphene_vec4_t with its * components set to (1, 0, 0, 0). * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec4_t * graphene_vec4_x_axis (void) { init_static_vec4 (); return &(static_vec4[VEC4_X_AXIS]); } /** * graphene_vec4_y_axis: * * Retrieves a pointer to a #graphene_vec4_t with its * components set to (0, 1, 0, 0). * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec4_t * graphene_vec4_y_axis (void) { init_static_vec4 (); return &(static_vec4[VEC4_Y_AXIS]); } /** * graphene_vec4_z_axis: * * Retrieves a pointer to a #graphene_vec4_t with its * components set to (0, 0, 1, 0). * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec4_t * graphene_vec4_z_axis (void) { init_static_vec4 (); return &(static_vec4[VEC4_Z_AXIS]); } /** * graphene_vec4_w_axis: * * Retrieves a pointer to a #graphene_vec4_t with its * components set to (0, 0, 0, 1). * * Returns: (transfer none): a constant vector * * Since: 1.0 */ const graphene_vec4_t * graphene_vec4_w_axis (void) { init_static_vec4 (); return &(static_vec4[VEC4_W_AXIS]); } /* }}} vec4 */ graphene-1.8.0/src/graphene-version-macros.h000066400000000000000000000171731324365266600210350ustar00rootroot00000000000000/* graphene-version.h: Versioning macros * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_VERSION_MACROS_H__ #define __GRAPHENE_VERSION_MACROS_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif #include "graphene-version.h" /** * GRAPHENE_ENCODE_VERSION: * @major: a major version * @minor: a minor version * @micro: a micro version * * Encodes the given components into a value that can be used for * version checks. * * Since: 1.0 */ #define GRAPHENE_ENCODE_VERSION(major,minor,micro) \ ((major) << 24 | (minor) << 16 | (micro) << 8) #define _GRAPHENE_ENCODE_VERSION(maj,min) \ ((maj) << 16 | (min) << 8) #ifdef GRAPHENE_DISABLE_DEPRECATION_WARNINGS # define GRAPHENE_DEPRECATED _GRAPHENE_PUBLIC # define GRAPHENE_DEPRECATED_FOR(f) _GRAPHENE_PUBLIC # define GRAPHENE_UNAVAILABLE(maj,min) _GRAPHENE_PUBLIC #else # define GRAPHENE_DEPRECATED _GRAPHENE_DEPRECATED _GRAPHENE_PUBLIC # define GRAPHENE_DEPRECATED_FOR(f) _GRAPHENE_DEPRECATED_FOR(f) _GRAPHENE_PUBLIC # define GRAPHENE_UNAVAILABLE(maj,min) _GRAPHENE_UNAVAILABLE(maj,min) _GRAPHENE_PUBLIC #endif /** * GRAPHENE_VERSION: * * The current version of the library, as encoded through * the %GRAPHENE_ENCODE_VERSION macro. Can be used for version * checking, for instance: * * |[ * #if GRAPHENE_VERSION >= GRAPHENE_ENCODE_VERSION (1, 2, 3) * // code that uses API introduced after version 1.2.3 * #endif * ]| * * Since: 1.0 */ #define GRAPHENE_VERSION \ GRAPHENE_ENCODE_VERSION (GRAPHENE_MAJOR_VERSION, \ GRAPHENE_MINOR_VERSION, \ GRAPHENE_MICRO_VERSION) #define GRAPHENE_CHECK_VERSION(major,minor,micro) \ ((major) > GRAPHENE_MAJOR_VERSION || \ (major) == GRAPHENE_MAJOR_VERSION && (minor) > GRAPHENE_MINOR_VERSION || \ (major) == GRAPHENE_MAJOR_VERSION && (minor) == GRAPHENE_MINOR_VERSION && (micro) >= GRAPHENE_MICRO_VERSION) /* evaluates to the current stable release; for development cycles * this means the next stable target. */ #if (GRAPHENE_MINOR_VERSION == 99) # define GRAPHENE_VERSION_CUR_STABLE (_GRAPHENE_ENCODE_VERSION (GRAPHENE_MAJOR_VERSION + 1, 0)) #elif (GRAPHENE_MINOR_VERSION % 2) # define GRAPHENE_VERSION_CUR_STABLE (_GRAPHENE_ENCODE_VERSION (GRAPHENE_MAJOR_VERSION, GRAPHENE_MINOR_VERSION + 1)) #else # define GRAPHENE_VERSION_CUR_STABLE (_GRAPHENE_ENCODE_VERSION (GRAPHENE_MAJOR_VERSION, GRAPHENE_MINOR_VERSION)) #endif /* evaluates to the previous stable version */ #if (GRAPHENE_MINOR_VERSION == 99) # define GRAPHENE_VERSION_PREV_STABLE (_GRAPHENE_ENCODE_VERSION (GRAPHENE_MAJOR_VERSION + 1, 0)) #elif (GRAPHENE_MINOR_VERSION % 2) # define GRAPHENE_VERSION_PREV_STABLE (_GRAPHENE_ENCODE_VERSION (GRAPHENE_MAJOR_VERSION, GRAPHENE_MINOR_VERSION - 1)) #else # define GRAPHENE_VERSION_PREV_STABLE (_GRAPHENE_ENCODE_VERSION (GRAPHENE_MAJOR_VERSION, GRAPHENE_MINOR_VERSION - 2)) #endif /* version defines * * remember to add new macros at the beginning of each development cycle */ #define GRAPHENE_VERSION_1_0 (_GRAPHENE_ENCODE_VERSION (1, 0)) #define GRAPHENE_VERSION_1_2 (_GRAPHENE_ENCODE_VERSION (1, 2)) #define GRAPHENE_VERSION_1_4 (_GRAPHENE_ENCODE_VERSION (1, 4)) #define GRAPHENE_VERSION_1_6 (_GRAPHENE_ENCODE_VERSION (1, 6)) #define GRAPHENE_VERSION_1_8 (_GRAPHENE_ENCODE_VERSION (1, 8)) #ifndef GRAPHENE_VERSION_MIN_REQUIRED # define GRAPHENE_VERSION_MIN_REQUIRED (GRAPHENE_VERSION_1_0) #endif #ifndef GRAPHENE_VERSION_MAX_ALLOWED # if GRAPHENE_VERSION_MIN_REQUIRED > GRAPHENE_VERSION_PREV_STABLE # define GRAPHENE_VERSION_MAX_ALLOWED (GRAPHENE_VERSION_MIN_REQUIRED) # else # define GRAPHENE_VERSION_MAX_ALLOWED (GRAPHENE_VERSION_CUR_STABLE) # endif #endif /* sanity checks */ #if GRAPHENE_VERSION_MAX_ALLOWED < GRAPHENE_VERSION_MIN_REQUIRED # error "GRAPHENE_VERSION_MAX_ALLOWED must be >= GRAPHENE_VERSION_MIN_REQUIRED" #endif #if GRAPHENE_VERSION_MIN_REQUIRED < GRAPHENE_VERSION_1_0 # error "GRAPHENE_VERSION_MIN_REQUIRED must be >= GRAPHENE_VERSION_1_0" #endif /* unconditional */ #define GRAPHENE_DEPRECATED_IN_1_0 GRAPHENE_DEPRECATED #define GRAPHENE_DEPRECATED_IN_1_0_FOR(f) GRAPHENE_DEPRECATED_FOR(f) #define GRAPHENE_AVAILABLE_IN_1_0 _GRAPHENE_PUBLIC /* Graphene 1.2 */ #if GRAPHENE_VERSION_MIN_REQUIRED >= GRAPHENE_VERSION_1_2 # define GRAPHENE_DEPRECATED_IN_1_2 GRAPHENE_DEPRECATED # define GRAPHENE_DEPRECATED_IN_1_2_FOR(f) GRAPHENE_DEPRECATED_FOR(f) #else # define GRAPHENE_DEPRECATED_IN_1_2 _GRAPHENE_PUBLIC # define GRAPHENE_DEPRECATED_IN_1_2_FOR(f) _GRAPHENE_PUBLIC #endif #if GRAPHENE_VERSION_MAX_ALLOWED < GRAPHENE_VERSION_1_2 # define GRAPHENE_AVAILABLE_IN_1_2 GRAPHENE_UNAVAILABLE(1,2) #else # define GRAPHENE_AVAILABLE_IN_1_2 _GRAPHENE_PUBLIC #endif /* Graphene 1.4 */ #if GRAPHENE_VERSION_MIN_REQUIRED >= GRAPHENE_VERSION_1_4 # define GRAPHENE_DEPRECATED_IN_1_4 GRAPHENE_DEPRECATED # define GRAPHENE_DEPRECATED_IN_1_4_FOR(f) GRAPHENE_DEPRECATED_FOR(f) #else # define GRAPHENE_DEPRECATED_IN_1_4 _GRAPHENE_PUBLIC # define GRAPHENE_DEPRECATED_IN_1_4_FOR(f) _GRAPHENE_PUBLIC #endif #if GRAPHENE_VERSION_MAX_ALLOWED < GRAPHENE_VERSION_1_4 # define GRAPHENE_AVAILABLE_IN_1_4 GRAPHENE_UNAVAILABLE(1,4) #else # define GRAPHENE_AVAILABLE_IN_1_4 _GRAPHENE_PUBLIC #endif /* Graphene 1.6 */ #if GRAPHENE_VERSION_MIN_REQUIRED >= GRAPHENE_VERSION_1_6 # define GRAPHENE_DEPRECATED_IN_1_6 GRAPHENE_DEPRECATED # define GRAPHENE_DEPRECATED_IN_1_6_FOR(f) GRAPHENE_DEPRECATED_FOR(f) #else # define GRAPHENE_DEPRECATED_IN_1_6 _GRAPHENE_PUBLIC # define GRAPHENE_DEPRECATED_IN_1_6_FOR(f) _GRAPHENE_PUBLIC #endif #if GRAPHENE_VERSION_MAX_ALLOWED < GRAPHENE_VERSION_1_6 # define GRAPHENE_AVAILABLE_IN_1_6 GRAPHENE_UNAVAILABLE(1,6) #else # define GRAPHENE_AVAILABLE_IN_1_6 _GRAPHENE_PUBLIC #endif /* Graphene 1.8 */ #if GRAPHENE_VERSION_MIN_REQUIRED >= GRAPHENE_VERSION_1_8 # define GRAPHENE_DEPRECATED_IN_1_8 GRAPHENE_DEPRECATED # define GRAPHENE_DEPRECATED_IN_1_8_FOR(f) GRAPHENE_DEPRECATED_FOR(f) #else # define GRAPHENE_DEPRECATED_IN_1_8 _GRAPHENE_PUBLIC # define GRAPHENE_DEPRECATED_IN_1_8_FOR(f) _GRAPHENE_PUBLIC #endif #if GRAPHENE_VERSION_MAX_ALLOWED < GRAPHENE_VERSION_1_8 # define GRAPHENE_AVAILABLE_IN_1_8 GRAPHENE_UNAVAILABLE(1,8) #else # define GRAPHENE_AVAILABLE_IN_1_8 _GRAPHENE_PUBLIC #endif #endif /* __GRAPHENE_VERSION_MACROS_H__ */ graphene-1.8.0/src/graphene-version.h.in000066400000000000000000000042641324365266600201550ustar00rootroot00000000000000/* graphene-version.h: Version info * * Copyright © 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * SECTION:graphene-version * @title: Versioning information * @short_description: Detemining the version of Graphene in use * * Graphene provides symbols to know the version of the library at compile * time. */ #ifndef __GRAPHENE_VERSION_H__ #define __GRAPHENE_VERSION_H__ #if !defined(GRAPHENE_H_INSIDE) && !defined(GRAPHENE_COMPILATION) #error "Only graphene.h can be included directly." #endif /** * GRAPHENE_MAJOR_VERSION: * * Evaluates to the major version number of the library version, * e.g. 1 in 1.2.3. * * Since: 1.0 */ #define GRAPHENE_MAJOR_VERSION (@GRAPHENE_MAJOR_VERSION@) /** * GRAPHENE_MINOR_VERSION: * * Evaluates to the minor version number of the library version, * e.g. 2 in 1.2.3. * * Since: 1.0 */ #define GRAPHENE_MINOR_VERSION (@GRAPHENE_MINOR_VERSION@) /** * GRAPHENE_MICRO_VERSION: * * Evaluates to the micro version number of the library version, * e.g. 3 in 1.2.3. * * Since: 1.0 */ #define GRAPHENE_MICRO_VERSION (@GRAPHENE_MICRO_VERSION@) #endif /* __GRAPHENE_VERSION_H__ */ graphene-1.8.0/src/graphene.h000066400000000000000000000036451324365266600160670ustar00rootroot00000000000000/* graphene * * Copyright 2014 Emmanuele Bassi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __GRAPHENE_H__ #define __GRAPHENE_H__ #define GRAPHENE_H_INSIDE #include "graphene-types.h" #include "graphene-macros.h" #include "graphene-config.h" #include "graphene-version.h" #include "graphene-version-macros.h" #include "graphene-simd4f.h" #include "graphene-simd4x4f.h" #include "graphene-vec2.h" #include "graphene-vec3.h" #include "graphene-vec4.h" #include "graphene-matrix.h" #include "graphene-point.h" #include "graphene-size.h" #include "graphene-rect.h" #include "graphene-point3d.h" #include "graphene-quad.h" #include "graphene-quaternion.h" #include "graphene-euler.h" #include "graphene-plane.h" #include "graphene-frustum.h" #include "graphene-sphere.h" #include "graphene-box.h" #include "graphene-triangle.h" #include "graphene-ray.h" #undef GRAPHENE_H_INSIDE #endif /* __GRAPHENE_H__ */ graphene-1.8.0/src/graphene.pc.in000066400000000000000000000010371324365266600166400ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ graphene_has_sse2=@has_sse2@ graphene_has_gcc=@has_gcc@ graphene_has_neon=@has_neon@ graphene_has_scalar=1 # Deprecated graphene_simd=@GRAPHENE_SIMD@ sse2_cflags=@SSE2_CFLAGS@ neon_cflags=@NEON_CFLAGS@ Name: Graphene Description: Math classes for graphic libraries Version: @GRAPHENE_VERSION@ Libs: -L${libdir} -lgraphene-1.0 Cflags: -I${includedir}/graphene-1.0 -I${libdir}/graphene-1.0/include @SSE2_CFLAGS@ @NEON_CFLAGS@ Requires.private: @GRAPHENE_REQS@ graphene-1.8.0/src/identfilter.py000077500000000000000000000034761324365266600170150ustar00rootroot00000000000000# Copyright 2014 Emmanuele Bassi # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import sys import re NUMBER_REGEX = re.compile(r'([0-9])([a-z])') def to_camel_case(text): # We only care about Graphene types if not text.startswith('graphene_') and not text.endswith('_t'): return text res = [] for token in text[:-2].split('_'): uc_token = token.title() # We need to do this for types like graphene_point3d_t, which # need to be transformed into GraphenePoint3D, not GraphenePoint3d matches = NUMBER_REGEX.match(uc_token) if matches and matches.group(2): uc_token = ''.join([matches.group(1), matches.group(2).title]) res.append(uc_token) return ''.join(res) if __name__ == '__main__': in_text = sys.stdin.read() sys.stdout.write(to_camel_case(in_text)) graphene-1.8.0/src/meson.build000066400000000000000000000120451324365266600162610ustar00rootroot00000000000000headers = [ 'graphene-box.h', 'graphene-euler.h', 'graphene-frustum.h', 'graphene-macros.h', 'graphene-matrix.h', 'graphene-plane.h', 'graphene-point.h', 'graphene-point3d.h', 'graphene-quad.h', 'graphene-quaternion.h', 'graphene-ray.h', 'graphene-rect.h', 'graphene-size.h', 'graphene-sphere.h', 'graphene-triangle.h', 'graphene-types.h', 'graphene-vec2.h', 'graphene-vec3.h', 'graphene-vec4.h', 'graphene-version-macros.h', ] simd_headers = [ 'graphene-simd4f.h', 'graphene-simd4x4f.h', ] private_headers = [ 'graphene-alloc-private.h', 'graphene-line-segment-private.h', 'graphene-private.h', 'graphene-vectors-private.h', ] sources = [ 'graphene-alloc.c', 'graphene-box.c', 'graphene-euler.c', 'graphene-frustum.c', 'graphene-matrix.c', 'graphene-plane.c', 'graphene-point.c', 'graphene-point3d.c', 'graphene-quad.c', 'graphene-quaternion.c', 'graphene-ray.c', 'graphene-rect.c', 'graphene-size.c', 'graphene-sphere.c', 'graphene-triangle.c', 'graphene-vectors.c' ] simd_sources = [ 'graphene-simd4f.c', 'graphene-simd4x4f.c', ] if build_gobject headers += [ 'graphene-gobject.h' ] sources += [ 'graphene-gobject.c' ] endif # Internal configuration header configure_file( output: 'config.h', configuration: conf, ) # External configuration header configure_file( input: 'graphene-config.h.meson', output: 'graphene-config.h', configuration: graphene_conf, install: true, install_dir: join_paths(graphene_libdir, graphene_api_path, 'include'), ) # Version header version_conf = configuration_data() version_conf.set('GRAPHENE_VERSION', graphene_version) version_conf.set('GRAPHENE_MAJOR_VERSION', graphene_major_version) version_conf.set('GRAPHENE_MINOR_VERSION', graphene_minor_version) version_conf.set('GRAPHENE_MICRO_VERSION', graphene_micro_version) configure_file( input: 'graphene-version.h.in', output: 'graphene-version.h', configuration: version_conf, install: true, install_dir: join_paths(graphene_includedir, graphene_api_path), ) install_headers(headers + simd_headers + [ 'graphene.h' ], subdir: graphene_api_path) pkgconfig_files = [ graphene_api_path ] platform_deps = [] if build_gobject pkgconfig_files += [ graphene_gobject_api_path ] platform_deps += [ gobject ] endif libgraphene = library( graphene_api_path, sources: sources + simd_sources + private_headers, version: libversion, soversion: soversion, install: true, dependencies: [ mathlib, threadlib ] + platform_deps, c_args: extra_args + common_cflags + debug_flags + [ '-DGRAPHENE_COMPILATION', ], link_args: common_ldflags, ) # Generate the pkg-config files pkg_conf = configuration_data() pkg_conf.set('GRAPHENE_VERSION', graphene_version) pkg_conf.set('prefix', graphene_prefix) pkg_conf.set('exec_prefix', graphene_prefix) pkg_conf.set('libdir', graphene_libdir) pkg_conf.set('includedir', graphene_includedir) pkg_conf.set('SSE2_CFLAGS', sse2_cflags) pkg_conf.set('NEON_CFLAGS', neon_cflags) pkg_conf.set('GRAPHENE_SIMD', ' '.join(graphene_simd)) foreach simd: [ 'sse2', 'gcc', 'neon' ] pkg_conf.set('has_' + simd, graphene_simd.contains(simd) ? '1' : '0') endforeach if build_gobject pkg_conf.set('GRAPHENE_REQS', 'gobject-2.0') else pkg_conf.set('GRAPHENE_REQS', '') endif foreach p: pkgconfig_files configure_file( input: 'graphene.pc.in', output: p + '.pc', configuration: pkg_conf, install: true, install_dir: join_paths(graphene_libdir, 'pkgconfig'), ) endforeach graphene_dep_sources = [] # Introspection if build_gir python = python3.find_python() identfilter_py = join_paths(meson.current_source_dir(), 'identfilter.py') gir_extra_args = [ '--identifier-filter-cmd=@0@ @1@'.format(python.path(), identfilter_py), '--accept-unprefixed', '--quiet', '--warn-all', '-DGRAPHENE_COMPILATION', ] graphene_gir = gnome.generate_gir(libgraphene, sources: headers + sources, namespace: 'Graphene', nsversion: graphene_api_version, identifier_prefix: 'Graphene', symbol_prefix: 'graphene', export_packages: graphene_gobject_api_path, includes: [ 'GObject-2.0' ], header: 'graphene-object.h', install: true, extra_args: gir_extra_args) graphene_dep_sources += graphene_gir endif # Dependency for tests and benchmarks and subproject usage graphene_inc = include_directories('.') graphene_dep = declare_dependency( sources: graphene_dep_sources, link_with: libgraphene, include_directories: [ graphene_inc ], dependencies: [ mathlib, threadlib ] + platform_deps, ) # tests and benchmarks depend on GLib, so we only build them if GObject is enabled if build_gobject if get_option('tests') subdir('tests') endif if get_option('benchmarks') subdir('bench') endif endif graphene-1.8.0/src/tests/000077500000000000000000000000001324365266600152575ustar00rootroot00000000000000graphene-1.8.0/src/tests/box.c000066400000000000000000000240351324365266600162170ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (box_init_min_max) { graphene_point3d_t points[] = { GRAPHENE_POINT3D_INIT (0.f, 0.f, 0.f), GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f) }; graphene_point3d_t min, max; graphene_box_t *b; b = graphene_box_init (graphene_box_alloc (), &points[0], &points[1]); g_assert_nonnull (b); graphene_box_get_min (b, &min); graphene_box_get_max (b, &max); g_assert_true (graphene_point3d_equal (&min, &zero3)); g_assert_true (graphene_point3d_equal (&max, &one3)); graphene_box_init (b, NULL, NULL); g_assert_true (graphene_box_equal (b, graphene_box_zero ())); graphene_box_init_from_vec3 (b, graphene_vec3_zero (), graphene_vec3_one ()); graphene_box_get_min (b, &min); graphene_box_get_max (b, &max); g_assert_true (graphene_point3d_equal (&min, &zero3)); g_assert_true (graphene_point3d_equal (&max, &one3)); graphene_box_init_from_vec3 (b, NULL, NULL); g_assert_true (graphene_box_equal (b, graphene_box_zero ())); graphene_box_free (b); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_init_from_points) { graphene_point3d_t points[] = { GRAPHENE_POINT3D_INIT (0.f, 0.f, 0.f), GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f), GRAPHENE_POINT3D_INIT (2.f, 2.f, 2.f), }; graphene_point3d_t min, max; graphene_box_t *b; b = graphene_box_init_from_points (graphene_box_alloc (), 3, points); graphene_box_get_min (b, &min); graphene_box_get_max (b, &max); g_assert_true (graphene_point3d_equal (&min, &points[0])); g_assert_true (graphene_point3d_equal (&max, &points[2])); graphene_box_init_from_points (b, 1, points + 1); graphene_box_get_min (b, &min); graphene_box_get_max (b, &max); g_assert_true (graphene_point3d_equal (&min, &points[1])); g_assert_true (graphene_point3d_equal (&max, &points[1])); g_assert_true (graphene_point3d_equal (&min, &max)); graphene_box_init_from_points (b, 0, NULL); g_assert_true (graphene_box_equal (b, graphene_box_empty ())); graphene_box_free (b); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_init_from_vectors) { graphene_point3d_t points[] = { GRAPHENE_POINT3D_INIT (0.f, 0.f, 0.f), GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f), GRAPHENE_POINT3D_INIT (2.f, 2.f, 2.f), }; graphene_vec3_t *vectors; graphene_point3d_t min, max; graphene_box_t *b; vectors = g_new (graphene_vec3_t, 3); graphene_point3d_to_vec3 (&points[0], &vectors[0]); graphene_point3d_to_vec3 (&points[1], &vectors[1]); graphene_point3d_to_vec3 (&points[2], &vectors[2]); b = graphene_box_init_from_vectors (graphene_box_alloc (), 3, vectors); graphene_box_get_min (b, &min); graphene_box_get_max (b, &max); g_assert_true (graphene_point3d_equal (&min, &points[0])); g_assert_true (graphene_point3d_equal (&max, &points[2])); graphene_box_init_from_vectors (b, 1, vectors + 1); graphene_box_get_min (b, &min); graphene_box_get_max (b, &max); g_assert_true (graphene_point3d_equal (&min, &points[1])); g_assert_true (graphene_point3d_equal (&max, &points[1])); g_assert_true (graphene_point3d_equal (&min, &max)); graphene_box_init_from_vectors (b, 0, NULL); g_assert_true (graphene_box_equal (b, graphene_box_empty ())); graphene_box_free (b); g_free (vectors); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_size) { graphene_vec3_t size; graphene_box_get_size (graphene_box_zero (), &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_zero ())); g_assert_cmpfloat (graphene_box_get_width (graphene_box_zero ()), ==, 0.f); g_assert_cmpfloat (graphene_box_get_height (graphene_box_one ()), ==, 1.f); g_assert_cmpfloat (graphene_box_get_depth (graphene_box_one_minus_one ()), ==, 2.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_center) { graphene_point3d_t center; graphene_box_t b; graphene_box_init_from_box (&b, graphene_box_zero ()); graphene_box_get_center (&b, ¢er); g_assert_true (graphene_point3d_equal (¢er, &zero3)); graphene_box_init_from_box (&b, graphene_box_one ()); graphene_box_get_center (&b, ¢er); g_assert_true (graphene_point3d_equal (¢er, &half3)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_equal) { g_assert_true (graphene_box_equal (NULL, NULL)); g_assert_false (graphene_box_equal (NULL, graphene_box_zero ())); g_assert_false (graphene_box_equal (graphene_box_zero (), NULL)); g_assert_true (graphene_box_equal (graphene_box_zero (), graphene_box_zero ())); g_assert_false (graphene_box_equal (graphene_box_zero (), graphene_box_one ())); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_union) { graphene_box_t res; graphene_box_union (graphene_box_zero (), graphene_box_zero (), &res); g_assert_true (graphene_box_equal (&res, graphene_box_zero ())); graphene_box_union (graphene_box_zero (), graphene_box_one (), &res); g_assert_true (graphene_box_equal (&res, graphene_box_one ())); graphene_box_union (graphene_box_minus_one (), graphene_box_one (), &res); g_assert_true (graphene_box_equal (&res, graphene_box_one_minus_one ())); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_intersection) { graphene_box_t res; g_assert_false (graphene_box_intersection (graphene_box_empty (), graphene_box_zero (), &res)); g_assert_true (graphene_box_equal (&res, graphene_box_empty ())); g_assert_true (graphene_box_intersection (graphene_box_one_minus_one (), graphene_box_one (), &res)); g_assert_true (graphene_box_equal (&res, graphene_box_one ())); g_assert_true (graphene_box_intersection (graphene_box_infinite (), graphene_box_one (), &res)); g_assert_true (graphene_box_equal (&res, graphene_box_one ())); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_expand_by_point) { graphene_box_t b; graphene_vec3_t size, tmp; graphene_point3d_t minus_one = GRAPHENE_POINT3D_INIT (-1.f, -1.f, -1.f); graphene_box_init_from_box (&b, graphene_box_zero ()); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_zero ())); graphene_box_expand (&b, &zero3, &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_zero ())); graphene_box_expand (&b, &one3, &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_one ())); graphene_box_expand (&b, &minus_one, &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_init (&tmp, 2.f, 2.f, 2.f))); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_expand_by_vector) { graphene_box_t b; graphene_vec3_t size, tmp; graphene_vec3_t minus_one; graphene_box_init_from_box (&b, graphene_box_zero ()); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_zero ())); graphene_box_expand_vec3 (&b, graphene_vec3_zero (), &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_zero ())); graphene_box_expand_vec3 (&b, graphene_vec3_one (), &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_one ())); graphene_vec3_init (&minus_one, -1.f, -1.f, -1.f); graphene_box_expand_vec3 (&b, &minus_one, &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_init (&tmp, 2.f, 2.f, 2.f))); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_expand_by_scalar) { graphene_box_t b; graphene_vec3_t size, tmp; graphene_box_init_from_box (&b, graphene_box_zero ()); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_zero ())); graphene_box_expand_scalar (&b, 0, &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_zero ())); graphene_box_expand_scalar (&b, 1, &b); graphene_box_get_size (&b, &size); g_assert_true (graphene_vec3_equal (&size, graphene_vec3_init (&tmp, 2.f, 2.f, 2.f))); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_contains_point) { graphene_box_t b; graphene_vec3_t points[8]; graphene_point3d_t center; graphene_point3d_t check; unsigned int i; graphene_box_init_from_box (&b, graphene_box_one_minus_one ()); graphene_box_get_center (&b, ¢er); g_assert_true (graphene_box_contains_point (&b, ¢er)); graphene_box_get_vertices (&b, points); for (i = 0; i < 8; i++) { graphene_point3d_init_from_vec3 (&check, &points[i]); g_assert_true (graphene_box_contains_point (&b, &check)); } graphene_point3d_init (&check, -2.f, 2.f, -2.f); g_assert_false (graphene_box_contains_point (&b, &check)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (box_contains_box) { graphene_box_t a, b; graphene_box_init_from_box (&a, graphene_box_one ()); graphene_box_init_from_box (&b, graphene_box_minus_one ()); g_assert_false (graphene_box_contains_box (&a, &b)); graphene_box_init_from_box (&a, graphene_box_one_minus_one ()); graphene_box_init_from_box (&b, graphene_box_one ()); g_assert_true (graphene_box_contains_box (&a, &b)); graphene_box_init_from_box (&a, graphene_box_infinite ()); g_assert_true (graphene_box_contains_box (&a, &b)); graphene_box_init_from_box (&a, graphene_box_empty ()); g_assert_false (graphene_box_contains_box (&a, &b)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/box/init/min-max", box_init_min_max) GRAPHENE_TEST_UNIT ("/box/init/from-points", box_init_from_points) GRAPHENE_TEST_UNIT ("/box/init/from-vectors", box_init_from_vectors) GRAPHENE_TEST_UNIT ("/box/size", box_size) GRAPHENE_TEST_UNIT ("/box/center", box_center) GRAPHENE_TEST_UNIT ("/box/equal", box_equal) GRAPHENE_TEST_UNIT ("/box/union", box_union) GRAPHENE_TEST_UNIT ("/box/intersection", box_intersection) GRAPHENE_TEST_UNIT ("/box/expand/by-point", box_expand_by_point) GRAPHENE_TEST_UNIT ("/box/expand/by-vector", box_expand_by_vector) GRAPHENE_TEST_UNIT ("/box/expand/by-scalar", box_expand_by_scalar) GRAPHENE_TEST_UNIT ("/box/contains/point", box_contains_point) GRAPHENE_TEST_UNIT ("/box/contains/box", box_contains_box) ) graphene-1.8.0/src/tests/euler.c000066400000000000000000000027421324365266600165440ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (euler_init) { graphene_euler_t *e; graphene_vec3_t v; e = graphene_euler_init (graphene_euler_alloc (), 0.f, 0.f, 0.f); g_assert_cmpfloat (graphene_euler_get_x (e), ==, 0.f); g_assert_cmpfloat (graphene_euler_get_y (e), ==, 0.f); g_assert_cmpfloat (graphene_euler_get_z (e), ==, 0.f); graphene_euler_to_vec3 (e, &v); graphene_assert_fuzzy_vec3_equal (&v, graphene_vec3_zero (), 0.00001); graphene_euler_free (e); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (euler_quaternion_roundtrip) { graphene_euler_t values[3]; unsigned int i; graphene_euler_init_with_order (&values[0], 0.f, 0.f, 0.f, GRAPHENE_EULER_ORDER_XYZ); graphene_euler_init_with_order (&values[1], 1.f, 0.f, 0.f, GRAPHENE_EULER_ORDER_XYZ); graphene_euler_init_with_order (&values[2], 0.f, 1.f, 0.f, GRAPHENE_EULER_ORDER_ZYX); for (i = 0; i < G_N_ELEMENTS (values); i++) { graphene_quaternion_t q, check; graphene_euler_t e; graphene_quaternion_init_from_euler (&q, &values[i]); graphene_euler_init_from_quaternion (&e, &q, graphene_euler_get_order (&values[i])); graphene_quaternion_init_from_euler (&check, &e); g_assert_true (graphene_quaternion_equal (&q, &check)); } } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/euler/init", euler_init) GRAPHENE_TEST_UNIT ("/euler/quaternion-roundtrip", euler_quaternion_roundtrip) ) graphene-1.8.0/src/tests/frustum.c000066400000000000000000000101631324365266600171310ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (frustum_init) { graphene_plane_t p0, p1, p2, p3, p4, p5; graphene_plane_t planes[6]; graphene_frustum_t *t; graphene_plane_init (&p0, graphene_vec3_x_axis (), -1.f); graphene_plane_init (&p1, graphene_vec3_x_axis (), 1.f); graphene_plane_init (&p2, graphene_vec3_x_axis (), 2.f); graphene_plane_init (&p3, graphene_vec3_x_axis (), 3.f); graphene_plane_init (&p4, graphene_vec3_x_axis (), 4.f); graphene_plane_init (&p5, graphene_vec3_x_axis (), 5.f); t = graphene_frustum_init (graphene_frustum_alloc (), &p0, &p1, &p2, &p3, &p4, &p5); graphene_frustum_get_planes (t, planes); g_assert_true (graphene_plane_equal (&planes[0], &p0)); g_assert_true (graphene_plane_equal (&planes[1], &p1)); g_assert_true (graphene_plane_equal (&planes[2], &p2)); g_assert_true (graphene_plane_equal (&planes[3], &p3)); g_assert_true (graphene_plane_equal (&planes[4], &p4)); g_assert_true (graphene_plane_equal (&planes[5], &p5)); graphene_frustum_free (t); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (frustum_ortho_contains_point) { graphene_matrix_t m; graphene_frustum_t f; graphene_point3d_t p; graphene_matrix_init_ortho (&m, -1.f, 1.f, -1.f, 1.f, 1.f, 100.f); graphene_frustum_init_from_matrix (&f, &m); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, 0.f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, -50.f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, -1.001f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, -1.f, -1.f, -1.001f))); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, -1.1f, -1.1f, -1.001f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 1.f, 1.f, -1.001f))); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 1.1f, 1.1f, -1.001f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, -100.f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, -1.f, -1.f, -100.f))); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, -1.1f, -1.1f, -100.1f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 1.f, 1.f, -100.f))); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 1.1f, 1.1f, -100.1f))); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, -101.f))); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (frustum_matrix_contains_point) { #if defined(GRAPHENE_USE_GCC) # if GLIB_CHECK_VERSION (2, 38, 0) g_test_skip ("Disabled when using GCC vectors"); # else if (g_test_verbose ()) g_test_message ("Disabled when using GCC vectors"); # endif #else graphene_matrix_t m; graphene_frustum_t f; graphene_point3d_t p; graphene_matrix_init_frustum (&m, -1.f, 1.f, -1.f, 1.f, 1.f, 100.f); graphene_frustum_init_from_matrix (&f, &m); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, 0.f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, -50.f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 0.f, 0.f, -1.001f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, -1.f, -1.f, -1.001f))); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, -1.1f, -1.1f, -1.001f))); g_assert_true (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 1.f, 1.f, -1.001f))); g_assert_false (graphene_frustum_contains_point (&f, graphene_point3d_init (&p, 1.1f, 1.1f, -1.001f))); #endif } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/frustum/init", frustum_init) GRAPHENE_TEST_UNIT ("/frustum/ortho/contains-point", frustum_ortho_contains_point) GRAPHENE_TEST_UNIT ("/frustum/matrix/contains-point", frustum_matrix_contains_point) ) graphene-1.8.0/src/tests/gen-installed-test.py000066400000000000000000000036161324365266600213420ustar00rootroot00000000000000# Copyright 2017 Emmanuele Bassi # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import sys import os import argparse def write_template(filename, data): with open(filename, 'w') as f: f.write(data) def build_template(testdir, testname): return "[Test]\nType=session\nExec={}\n".format(os.path.join(testdir, testname)) argparser = argparse.ArgumentParser(description='Generate installed-test data.') argparser.add_argument('--testdir', metavar='dir', required=True, help='Installed test directory') argparser.add_argument('--testname', metavar='name', required=True, help='Installed test name') argparser.add_argument('--outfile', metavar='file', required=True, help='Output file') argparser.add_argument('--outdir', metavar='dir', required=True, help='Output directory') args = argparser.parse_args() write_template(os.path.join(args.outdir, args.outfile), build_template(args.testdir, args.testname)) graphene-1.8.0/src/tests/graphene-test-compat.h000066400000000000000000000153061324365266600214640ustar00rootroot00000000000000#include #if !GLIB_CHECK_VERSION (2, 40, 0) # define g_assert_true(expr) g_assert ((expr)) # define g_assert_false(expr) g_assert (!(expr)) # define g_assert_null(expr) g_assert ((expr) == NULL) # define g_assert_nonnull(expr) g_assert ((expr) != NULL) #endif #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* Use typeof on GCC */ # define graphene_fuzzy_equals(n1,n2,epsilon) \ G_GNUC_EXTENSION({ \ __auto_type _n1 = (n1); \ __auto_type _n2 = (n2); \ __auto_type _epsilon = (epsilon); \ (bool) ((_n1 > _n2 ? (_n1 - _n2) : (_n2 - _n1)) < _epsilon); \ }) #else /* fallback for Visual Studio, typeof not supported */ # define graphene_fuzzy_equals(n1,n2,epsilon) \ (((n1) > (n2) ? ((n1) - (n2)) : ((n2) - (n1))) < (epsilon)) #endif /* __GNUC__ */ #define graphene_assert_fuzzy_equals(n1,n2,epsilon) \ G_STMT_START { \ if (graphene_fuzzy_equals (n1, n2, epsilon)) ; else { \ g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ #n1 " == " #n2 " (+/- " #epsilon ")", \ n1, "==", n2, 'f'); \ } \ } G_STMT_END #define graphene_assert_fuzzy_matrix_cell_equal(row,col,n1,n2,epsilon) \ G_STMT_START { \ if (graphene_fuzzy_equals (n1, n2, epsilon)) ; else { \ char *s = g_strdup_printf ("[%d][%d]: " #n1 " == " #n2 " (+/- " #epsilon "): (%.7g == %.7g)", \ row, col, n1, n2); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \ g_free (s); \ } \ } G_STMT_END #define graphene_assert_fuzzy_matrix_equal(m1,m2,epsilon) \ G_STMT_START { \ unsigned int __i, __j; \ float __m1[16], __m2[16]; \ graphene_matrix_to_float ((m1), __m1); \ graphene_matrix_to_float ((m2), __m2); \ for (__i = 0; __i < 4; __i++) { \ for (__j = 0; __j < 4; __j++) { \ unsigned int __idx = __i * 4 + __j; \ graphene_assert_fuzzy_matrix_cell_equal (__i, __j, __m1[__idx], __m2[__idx], epsilon); \ } \ } \ } G_STMT_END #define graphene_assert_fuzzy_vec2_equal(v1,v2,epsilon) \ G_STMT_START { \ if (graphene_vec2_near (v1, v2, epsilon)) ; \ else { \ char *s = g_strdup_printf (#v1 " == " #v2 " (+/- " #epsilon "): " \ "{ x:%.7g, y:%.7g } == { x:%.7g, y:%.7g }", \ graphene_vec2_get_x (v1), graphene_vec2_get_y (v1), \ graphene_vec2_get_x (v2), graphene_vec2_get_y (v2)); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \ g_free (s); \ } \ } G_STMT_END #define graphene_assert_fuzzy_vec3_equal(v1,v2,epsilon) \ G_STMT_START { \ if (graphene_vec3_near (v1, v2, epsilon)) ; \ else { \ char *s = g_strdup_printf (#v1 " == " #v2 " (+/- " #epsilon "): " \ "{ x:%.7g, y:%.7g, z:%.7g } == { x:%.7g, y:%.7g, z:%.7g }", \ graphene_vec3_get_x (v1), graphene_vec3_get_y (v1), graphene_vec3_get_z (v1), \ graphene_vec3_get_x (v2), graphene_vec3_get_y (v2), graphene_vec3_get_z (v2)); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \ g_free (s); \ } \ } G_STMT_END #define graphene_assert_fuzzy_vec4_equal(v1,v2,epsilon) \ G_STMT_START { \ if (graphene_vec4_near (v1, v2, epsilon)) ; \ else { \ char *s = g_strdup_printf (#v1 " == " #v2 " (+/- " #epsilon "): " \ "{ x:%.7g, y:%.7g, z:%.7g, w:%.7g } == { x:%.7g, y:%.7g, z:%.7g, w:%.7g }", \ graphene_vec4_get_x (v1), graphene_vec4_get_y (v1), graphene_vec4_get_z (v1), graphene_vec4_get_w (v1), \ graphene_vec4_get_x (v2), graphene_vec4_get_y (v2), graphene_vec4_get_z (v2), graphene_vec4_get_w (v2)); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \ g_free (s); \ } \ } G_STMT_END #define graphene_assert_fuzzy_point_equal(p1,p2,epsilon) \ G_STMT_START { \ if (graphene_point_near (p1, p2, epsilon)) ; \ else { \ char *s = g_strdup_printf (#p1 " == " #p2 " (+/- " #epsilon "): " \ "{ x:%.7g, y:%.7g } == { x:%.7g, y:%.7g }", \ (p1)->x, (p1)->y, (p2)->x, (p2)->y); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \ g_free (s); \ } \ } G_STMT_END #define graphene_assert_fuzzy_size_equal(s1,s2,epsilon) \ G_STMT_START { \ if (graphene_fuzzy_equals ((s1)->width, (s2)->width, epsilon) && \ graphene_fuzzy_equals ((s1)->height, (s2)->height, epsilon)) ; else { \ char *s = g_strdup_printf ("{ width:%.7g, height:%.7g } == { width:%.7g, height:%.7g }", \ (s1)->width, (s1)->height, (s2)->width, (s2)->height); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \ g_free (s); \ } \ } G_STMT_END #define graphene_assert_fuzzy_rect_equal(r1,r2,epsilon) \ G_STMT_START { \ graphene_assert_fuzzy_point_equal (&((r1)->origin), &((r2)->origin), epsilon); \ graphene_assert_fuzzy_size_equal (&((r1)->size), &((r2)->size), epsilon); \ } G_STMT_END #define GRAPHENE_TEST_UNUSED(type,var) \ if (0) { \ type unused G_GNUC_UNUSED; \ unused = var; \ } #define GRAPHENE_TEST_UNIT_BEGIN(name) \ static void \ name (void) \ { \ const float x = 2.f, y = 3.f, z = 4.f, w = 5.f; \ const graphene_point_t zero2 = GRAPHENE_POINT_INIT_ZERO; \ const graphene_point_t one2 = GRAPHENE_POINT_INIT (1.f, 1.f); \ const graphene_point_t half2 = GRAPHENE_POINT_INIT (.5f, .5f); \ const graphene_point3d_t zero3 = GRAPHENE_POINT3D_INIT_ZERO; \ const graphene_point3d_t one3 = GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f); \ const graphene_point3d_t half3 = GRAPHENE_POINT3D_INIT (.5f, .5f, .5f); #define GRAPHENE_TEST_UNIT_END \ GRAPHENE_TEST_UNUSED (float, x) \ GRAPHENE_TEST_UNUSED (float, y) \ GRAPHENE_TEST_UNUSED (float, z) \ GRAPHENE_TEST_UNUSED (float, w) \ GRAPHENE_TEST_UNUSED (graphene_point_t, zero2) \ GRAPHENE_TEST_UNUSED (graphene_point_t, one2) \ GRAPHENE_TEST_UNUSED (graphene_point_t, half2) \ GRAPHENE_TEST_UNUSED (graphene_point3d_t, zero3) \ GRAPHENE_TEST_UNUSED (graphene_point3d_t, one3) \ GRAPHENE_TEST_UNUSED (graphene_point3d_t, half3) \ } #define GRAPHENE_TEST_UNIT(path,name) \ g_test_add_func (path, name); #define GRAPHENE_TEST_SUITE(stanzas) \ int \ main (int argc, char *argv[]) \ { \ g_test_init (&argc, &argv, NULL); \ g_test_bug_base ("https://github.com/ebassi/graphene/issues/%s"); \ \ { \ stanzas \ } \ \ return g_test_run (); \ } graphene-1.8.0/src/tests/matrix.c000066400000000000000000000427641324365266600167440ustar00rootroot00000000000000#include #include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (matrix_identity) { graphene_matrix_t m; float v[16]; graphene_matrix_init_identity (&m); g_assert_true (graphene_matrix_is_identity (&m)); if (g_test_verbose ()) graphene_matrix_print (&m); g_assert_cmpfloat (graphene_matrix_get_value (&m, 0, 0), ==, 1.f); g_assert_cmpfloat (graphene_matrix_get_value (&m, 1, 1), ==, 1.f); g_assert_cmpfloat (graphene_matrix_get_value (&m, 2, 2), ==, 1.f); g_assert_cmpfloat (graphene_matrix_get_value (&m, 3, 3), ==, 1.f); graphene_matrix_to_float (&m, v); g_assert_cmpfloat (v[0], ==, 1.0f); g_assert_cmpfloat (v[5], ==, 1.0f); g_assert_cmpfloat (v[10], ==, 1.0f); graphene_matrix_scale (&m, 2.0f, 2.0f, 2.0f); g_assert_false (graphene_matrix_is_identity (&m)); v[0] = 1.f; v[4] = 0.f; v[8] = 0.f; v[12] = 0.f; v[1] = 0.f; v[5] = 1.f; v[9] = 0.f; v[13] = 0.f; v[2] = 0.f; v[6] = 0.f; v[10] = 1.f; v[14] = 0.f; v[3] = 0.f; v[7] = 0.f; v[11] = 0.f; v[15] = 1.f; graphene_matrix_init_from_float (&m, v); g_assert_true (graphene_matrix_is_identity (&m)); graphene_matrix_init_from_vec4 (&m, graphene_vec4_x_axis (), graphene_vec4_y_axis (), graphene_vec4_z_axis (), graphene_vec4_w_axis ()); g_assert_true (graphene_matrix_is_identity (&m)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_rotation) { graphene_matrix_t m; graphene_matrix_t m2; graphene_matrix_init_identity (&m); g_assert_true (graphene_matrix_is_identity (&m)); graphene_matrix_rotate (&m, 45.0f, graphene_vec3_x_axis ()); graphene_matrix_init_rotate (&m2, 45.0f, graphene_vec3_x_axis ()); if (g_test_verbose ()) graphene_matrix_print (&m); graphene_assert_fuzzy_matrix_equal (&m, &m2, 0.0001f); graphene_matrix_rotate (&m, 15.0f, graphene_vec3_x_axis ()); graphene_matrix_init_rotate (&m2, 60.0f, graphene_vec3_x_axis ()); if (g_test_verbose ()) graphene_matrix_print (&m); graphene_assert_fuzzy_matrix_equal (&m, &m2, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_rotation_euler_quaternion) { graphene_matrix_t m0, m1, m2; graphene_quaternion_t q; graphene_euler_t e; graphene_matrix_init_rotate (&m0, 60.f, graphene_vec3_x_axis ()); graphene_euler_init (&e, 60.f, 0.f, 0.f); graphene_quaternion_init_from_euler (&q, &e); graphene_matrix_init_identity (&m1); graphene_matrix_rotate_euler (&m1, &e); graphene_matrix_init_identity (&m2); graphene_matrix_rotate_quaternion (&m2, &q); graphene_assert_fuzzy_matrix_equal (&m0, &m1, 0.0001f); graphene_assert_fuzzy_matrix_equal (&m0, &m2, 0.0001f); graphene_assert_fuzzy_matrix_equal (&m1, &m2, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_translation) { graphene_matrix_t m; graphene_matrix_t m2; graphene_point3d_t trans = GRAPHENE_POINT3D_INIT (1.0f, 2.0f, 3.0f); graphene_matrix_init_identity (&m); g_assert_true (graphene_matrix_is_identity (&m)); graphene_matrix_translate (&m, &trans); graphene_matrix_init_translate (&m2, &trans); if (g_test_verbose ()) graphene_matrix_print (&m); graphene_assert_fuzzy_matrix_equal (&m, &m2, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_scale) { graphene_matrix_t m; graphene_matrix_t m2; graphene_matrix_init_identity (&m); g_assert_true (graphene_matrix_is_identity (&m)); graphene_matrix_scale (&m, 1.0f, 2.0f, 3.0f); graphene_matrix_init_scale (&m2, 1.0f, 2.0f, 3.0f); if (g_test_verbose ()) graphene_matrix_print (&m); graphene_assert_fuzzy_matrix_equal (&m, &m2, 0.0001f); g_assert_cmpfloat (graphene_matrix_get_x_scale (&m), ==, graphene_matrix_get_x_scale (&m2)); g_assert_cmpfloat (graphene_matrix_get_y_scale (&m), ==, graphene_matrix_get_y_scale (&m2)); g_assert_cmpfloat (graphene_matrix_get_z_scale (&m), ==, graphene_matrix_get_z_scale (&m2)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_invert) { graphene_matrix_t m; graphene_matrix_t identity; graphene_matrix_t inv; graphene_matrix_t res; graphene_point3d_t p; graphene_matrix_init_identity (&identity); graphene_matrix_init_identity (&m); graphene_matrix_inverse (&m , &inv); graphene_matrix_multiply (&m, &inv, &res); graphene_assert_fuzzy_matrix_equal (&identity, &res, 0.0001f); graphene_matrix_scale (&m, 1.0f, 2.0f, 3.0f); graphene_matrix_inverse (&m , &inv); graphene_matrix_multiply (&m, &inv, &res); graphene_assert_fuzzy_matrix_equal (&identity, &res, 0.0001f); graphene_matrix_rotate (&m, 44, graphene_vec3_x_axis ()); graphene_matrix_inverse (&m , &inv); graphene_matrix_multiply (&m, &inv, &res); graphene_assert_fuzzy_matrix_equal (&identity, &res, 0.0001f); graphene_matrix_rotate (&m, 12, graphene_vec3_y_axis ()); graphene_matrix_inverse (&m , &inv); graphene_matrix_multiply (&m, &inv, &res); graphene_assert_fuzzy_matrix_equal (&identity, &res, 0.0001f); graphene_matrix_translate (&m, graphene_point3d_init (&p, 1.f, 2.f, 3.f)); graphene_matrix_inverse (&m , &inv); graphene_matrix_multiply (&m, &inv, &res); graphene_assert_fuzzy_matrix_equal (&identity, &res, 0.0001f); graphene_matrix_rotate (&m, 200, graphene_vec3_z_axis ()); graphene_matrix_inverse (&m , &inv); graphene_matrix_multiply (&m, &inv, &res); graphene_assert_fuzzy_matrix_equal (&identity, &res, 0.0001f); /* g_print ("m:\n"); graphene_matrix_print (&m); g_print ("inv_m:\n"); graphene_matrix_print (&inv); g_print ("m * inv_m:\n"); graphene_matrix_print (&res); */ } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_neutral_element) { graphene_matrix_t identity; graphene_matrix_t scale; graphene_matrix_t translation; graphene_matrix_t rotation; graphene_point3d_t null_vector = GRAPHENE_POINT3D_INIT (0,0,0); graphene_matrix_init_identity (&identity); g_assert_true (graphene_matrix_is_identity (&identity)); graphene_matrix_scale (&identity, 1.0f, 1.0f, 1.0f); g_assert_true (graphene_matrix_is_identity (&identity)); graphene_matrix_init_scale (&scale, 1.0f, 1.0f, 1.0f); g_assert_true (graphene_matrix_is_identity (&scale)); graphene_matrix_rotate (&identity, 0.0f, graphene_vec3_z_axis ()); g_assert_true (graphene_matrix_is_identity (&identity)); graphene_matrix_init_rotate (&rotation, 0.0f, graphene_vec3_z_axis ()); g_assert_true (graphene_matrix_is_identity (&rotation)); graphene_matrix_translate (&identity, &null_vector); g_assert_true (graphene_matrix_is_identity (&identity)); graphene_matrix_init_translate (&translation, &null_vector); g_assert_true (graphene_matrix_is_identity (&translation)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_look_at) { graphene_matrix_t m; graphene_vec3_t neg_z_axis; graphene_vec3_t dir_xz, dir_yz, dir_xyz; graphene_point3d_t p; #if 0 graphene_vec3_t eye, center, up, dist, center_plus_up; graphene_vec4_t res; #endif graphene_matrix_t identity, identity_translated, rotated; graphene_matrix_init_identity (&identity); graphene_vec3_init (&neg_z_axis, 0, 0, -1); graphene_vec3_init (&dir_xz, 1, 0, -1); graphene_vec3_init (&dir_yz, 0, 1, -1); graphene_vec3_init (&dir_xyz, 1, 1, -1); if (g_test_verbose ()) g_print ("look_at: eye: (0, 0, 0), center: (0, 0, -1), up: (0, 1, 0)\n"); graphene_matrix_init_look_at (&m, graphene_vec3_zero (), &neg_z_axis, graphene_vec3_y_axis()); graphene_assert_fuzzy_matrix_equal (&m, &identity, 0.0001f); if (g_test_verbose ()) g_print ("look at: eye: (0, 0, 1), center: (0, 0, 0), up: (0, 1, 0)\n"); graphene_matrix_init_look_at (&m, graphene_vec3_z_axis(), graphene_vec3_zero (), graphene_vec3_y_axis()); identity_translated = identity; graphene_matrix_translate (&identity_translated, graphene_point3d_init (&p, 0, 0, -1)); graphene_assert_fuzzy_matrix_equal (&m, &identity_translated, 0.0001f); if (g_test_verbose ()) g_print ("look at: eye: (0, 0, 0), center: (1, 0, -1), up: (0, 1, 0)\n"); graphene_matrix_init_look_at (&m, graphene_vec3_zero (), &dir_xz, graphene_vec3_y_axis()); graphene_matrix_init_rotate (&rotated, -45, graphene_vec3_y_axis()); graphene_assert_fuzzy_matrix_equal (&m, &rotated, 0.0001f); if (g_test_verbose ()) g_print ("look at: eye: (0, 0, 0), center: (0, 1, -1), up: (0, 1, 0)\n"); graphene_matrix_init_look_at (&m, graphene_vec3_zero (), &dir_yz, graphene_vec3_y_axis()); graphene_matrix_init_rotate (&rotated, 45, graphene_vec3_x_axis()); graphene_assert_fuzzy_matrix_equal (&m, &rotated, 0.0001f); #if 0 graphene_vec3_init (&eye, g_random_double_range (-10000, 10000), g_random_double_range (-10000, 10000), g_random_double_range (-10000, 10000)); graphene_vec3_init (¢er, g_random_double_range (-10000, 10000), g_random_double_range (-10000, 10000), g_random_double_range (-10000, 10000)); graphene_vec3_init (&up, g_random_double_range (-1, 1), g_random_double_range (-1, 1), g_random_double_range (-1, 1)); graphene_vec3_normalize (&up, &up); if (g_test_verbose ()) g_print ("look at: eye: (%+5.3f, %+5.3f, %+5.3f), " "center: (+%5.3f, %+5.3f, %+5.3f), " "up: (%+.3f, %+.3f, %+.3f)\n", graphene_vec3_get_x (&eye), graphene_vec3_get_y (&eye), graphene_vec3_get_z (&eye), graphene_vec3_get_x (¢er), graphene_vec3_get_y (¢er), graphene_vec3_get_z (¢er), graphene_vec3_get_x (&up), graphene_vec3_get_y (&up), graphene_vec3_get_z (&up)); graphene_matrix_init_look_at (&m, &eye, ¢er, &up); graphene_vec4_init_from_vec3 (&res, ¢er, 1); graphene_matrix_transform_vec4 (&m, &res, &res); graphene_vec3_subtract (¢er, &eye, &dist); graphene_assert_fuzzy_equals (graphene_vec4_get_x (&res), 0, 0.01f); graphene_assert_fuzzy_equals (graphene_vec4_get_y (&res), 0, 0.01f); graphene_assert_fuzzy_equals (graphene_vec4_get_z (&res), -graphene_vec3_length (&dist), 0.01f); graphene_assert_fuzzy_equals (graphene_vec4_get_w (&res), 1, 0.01f); graphene_vec3_add (¢er, &up, ¢er_plus_up); graphene_vec3_subtract (¢er_plus_up, &eye, &dist); graphene_vec4_init_from_vec3 (&res, ¢er_plus_up, 1); graphene_matrix_transform_vec4 (&m, &res, &res); graphene_assert_fuzzy_equals (graphene_vec4_get_x (&res), 0, 0.01f); g_assert_cmpfloat (graphene_vec4_get_y (&res), <=, 1.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), >=, 0.f); graphene_assert_fuzzy_equals (graphene_vec4_get_z (&res), -graphene_vec3_length (&dist), 0.01f); graphene_assert_fuzzy_equals (graphene_vec4_get_w (&res), 1, 0.01f); #endif } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_2d_identity) { graphene_matrix_t m1; graphene_matrix_init_from_2d (&m1, 1, 0, 0, 1, 0, 0); g_assert_true (graphene_matrix_is_2d (&m1)); g_assert_true (graphene_matrix_is_identity (&m1)); graphene_matrix_init_from_2d (&m1, 1, 1, 1, 1, 0, 0); g_assert_true (graphene_matrix_is_2d (&m1)); g_assert_false (graphene_matrix_is_identity (&m1)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_2d_transforms) { graphene_matrix_t m1, m2; double xx, xy, yx, yy, x_0, y_0; graphene_matrix_init_identity (&m1); graphene_matrix_scale (&m1, 2.0, 2.0, 1.0); graphene_matrix_translate (&m1, &GRAPHENE_POINT3D_INIT (0.5, 0.5, 0.0)); if (g_test_verbose ()) { g_test_message ("m1 -> translate(0.5, 0.5, 0.0) -> scale(2.0, 2.0)"); graphene_matrix_print (&m1); } g_assert_true (graphene_matrix_is_2d (&m1)); graphene_matrix_init_from_2d (&m2, 2.0, 0.0, 0.0, 2.0, 0.5, 0.5); if (g_test_verbose ()) { g_test_message ("m2 -> [ 2.0, 0.0 | 0.0, 2.0 | 0.5, 0.5 ]"); graphene_matrix_print (&m2); } graphene_assert_fuzzy_matrix_equal (&m1, &m2, 0.0001); graphene_matrix_to_2d (&m1, &xx, &yx, &xy, &yy, &x_0, &y_0); graphene_assert_fuzzy_equals (xx, 2.0, 0.0001); graphene_assert_fuzzy_equals (yx, 0.0, 0.0001); graphene_assert_fuzzy_equals (xy, 0.0, 0.0001); graphene_assert_fuzzy_equals (yy, 2.0, 0.0001); graphene_assert_fuzzy_equals (x_0, 0.5, 0.0001); graphene_assert_fuzzy_equals (y_0, 0.5, 0.0001); graphene_matrix_init_identity (&m1); graphene_matrix_translate (&m1, &GRAPHENE_POINT3D_INIT (50, 50, 0)); graphene_matrix_rotate_z (&m1, 45.0); graphene_matrix_translate (&m1, &GRAPHENE_POINT3D_INIT (-50, -50, 0)); if (g_test_verbose ()) { g_test_message ("m1 -> translate(50,50) -> rotate(45deg) -> translate(-50, -50)"); graphene_matrix_print (&m1); } g_assert_true (graphene_matrix_is_2d (&m1)); graphene_matrix_init_identity (&m1); graphene_matrix_perspective (&m1, 500, &m1); graphene_matrix_rotate_y (&m1, 50.0); if (g_test_verbose ()) { g_test_message ("m1 -> perspective(500) -> rotateY(50deg)"); graphene_matrix_print (&m1); } g_assert_false (graphene_matrix_is_2d (&m1)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_2d_round_trip) { graphene_matrix_t m1, m2; double xx, xy, yx, yy, x_0, y_0; graphene_matrix_init_from_2d (&m1, 2.0, 0.0, 0.0, 2.0, 0.5, 0.5); g_assert_true (graphene_matrix_is_2d (&m1)); graphene_matrix_to_2d (&m1, &xx, &yx, &xy, &yy, &x_0, &y_0); graphene_assert_fuzzy_equals (xx, 2.0, 0.0001); graphene_assert_fuzzy_equals (yx, 0.0, 0.0001); graphene_assert_fuzzy_equals (xy, 0.0, 0.0001); graphene_assert_fuzzy_equals (yy, 2.0, 0.0001); graphene_assert_fuzzy_equals (x_0, 0.5, 0.0001); graphene_assert_fuzzy_equals (y_0, 0.5, 0.0001); graphene_matrix_init_from_2d (&m2, xx, yx, xy, yy, x_0, y_0); graphene_assert_fuzzy_matrix_equal (&m1, &m2, 0.0001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_interpolate) { graphene_matrix_t m1, m2, m3, mr; graphene_matrix_init_identity (&m1); graphene_matrix_init_identity (&m2); graphene_matrix_translate (&m2, &GRAPHENE_POINT3D_INIT (100.f, 100.f, 100.f)); g_assert_true (!graphene_matrix_is_2d (&m2)); graphene_matrix_interpolate (&m1, &m2, 0.0, &mr); graphene_assert_fuzzy_matrix_equal (&mr, &m1, 0.1); graphene_matrix_interpolate (&m1, &m2, 1.0, &mr); graphene_assert_fuzzy_matrix_equal (&mr, &m2, 0.1); graphene_matrix_init_translate (&m3, &GRAPHENE_POINT3D_INIT (50.f, 50.f, 50.f)); graphene_matrix_interpolate (&m1, &m2, 0.5, &mr); graphene_assert_fuzzy_matrix_equal (&mr, &m3, 0.1); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_2d_interpolate) { graphene_matrix_t m1, m2, m3, mr; graphene_matrix_init_identity (&m1); graphene_matrix_init_identity (&m2); graphene_matrix_translate (&m2, &GRAPHENE_POINT3D_INIT (100.f, 100.f, 0.f)); g_assert_true (graphene_matrix_is_2d (&m1)); g_assert_true (graphene_matrix_is_2d (&m2)); graphene_matrix_interpolate (&m1, &m2, 0.0, &mr); graphene_assert_fuzzy_matrix_equal (&mr, &m1, 0.01); graphene_matrix_interpolate (&m1, &m2, 1.0, &mr); graphene_assert_fuzzy_matrix_equal (&mr, &m2, 0.01); graphene_matrix_init_translate (&m3, &GRAPHENE_POINT3D_INIT (50.f, 50.f, 0.f)); graphene_matrix_interpolate (&m1, &m2, 0.5, &mr); graphene_assert_fuzzy_matrix_equal (&mr, &m3, 0.01); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (matrix_2d_transform_bound) { graphene_matrix_t m1, m2; graphene_rect_t r, r2, res; graphene_matrix_init_identity (&m1); graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT (100.f, 100.f, 0.f)); graphene_rect_init (&r, 0.f, 0.f, 50.f, 50.f); graphene_rect_init (&r2, 100.f, 100.f, 50.f, 50.f); graphene_matrix_transform_bounds (&m1, &r, &res); graphene_assert_fuzzy_rect_equal (&res, &r, 0.01); graphene_matrix_transform_bounds (&m2, &r, &res); graphene_assert_fuzzy_rect_equal (&res, &r2, 0.01); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/matrix/identity", matrix_identity) GRAPHENE_TEST_UNIT ("/matrix/scale", matrix_scale) GRAPHENE_TEST_UNIT ("/matrix/rotation", matrix_rotation) GRAPHENE_TEST_UNIT ("/matrix/rotation/euler-quaternion", matrix_rotation_euler_quaternion) GRAPHENE_TEST_UNIT ("/matrix/translation", matrix_translation) GRAPHENE_TEST_UNIT ("/matrix/neutral_element", matrix_neutral_element) GRAPHENE_TEST_UNIT ("/matrix/look_at", matrix_look_at) GRAPHENE_TEST_UNIT ("/matrix/invert", matrix_invert) GRAPHENE_TEST_UNIT ("/matrix/interpolate", matrix_interpolate) GRAPHENE_TEST_UNIT ("/matrix/2d/identity", matrix_2d_identity) GRAPHENE_TEST_UNIT ("/matrix/2d/transforms", matrix_2d_transforms) GRAPHENE_TEST_UNIT ("/matrix/2d/round-trip", matrix_2d_round_trip) GRAPHENE_TEST_UNIT ("/matrix/2d/interpolate", matrix_2d_interpolate) GRAPHENE_TEST_UNIT ("/matrix/2d/transform_bound", matrix_2d_transform_bound) ) graphene-1.8.0/src/tests/meson.build000066400000000000000000000033661324365266600174310ustar00rootroot00000000000000unit_tests = [ 'box', 'euler', 'frustum', 'matrix', 'plane', 'point', 'point3d', 'quad', 'quaternion', 'ray', 'rect', 'simd', 'size', 'sphere', 'triangle', 'vec2', 'vec3', 'vec4' ] python = python3.find_python() gen_installed_test = join_paths(meson.current_source_dir(), 'gen-installed-test.py') installed_test_datadir = join_paths(get_option('prefix'), get_option('datadir'), 'installed-tests', graphene_api_path) installed_test_bindir = join_paths(get_option('prefix'), get_option('libexecdir'), 'installed-tests', graphene_api_path) foreach unit: unit_tests wrapper = '@0@.test'.format(unit) data = custom_target(wrapper, output: wrapper, command: [ python, gen_installed_test, '--testdir=@0@'.format(installed_test_bindir), '--testname=@0@'.format(unit), '--outdir=@OUTDIR@', '--outfile=@0@'.format(wrapper), ], install: true, install_dir: installed_test_datadir) exe = executable(unit, unit + '.c', dependencies: graphene_dep, include_directories: graphene_inc, c_args: common_cflags + [ '-DG_LOG_DOMAIN="Graphene-Test"', '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_30', '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_32', '-DGLIB_DISABLE_DEPRECATION_WARNINGS', ], install: true, install_dir: installed_test_bindir) test(unit, exe, args: [ '--tap', '-k' ]) endforeach graphene-1.8.0/src/tests/plane.c000066400000000000000000000066231324365266600165310ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (plane_init_base) { graphene_plane_t *p; graphene_vec3_t n; p = graphene_plane_init (graphene_plane_alloc (), NULL, 0.f); graphene_plane_get_normal (p, &n); g_assert_true (graphene_vec3_equal (&n, graphene_vec3_x_axis ())); g_assert_cmpfloat (graphene_plane_get_constant (p), ==, 0.f); graphene_plane_init (p, graphene_vec3_one (), 0.f); graphene_plane_get_normal (p, &n); g_assert_true (graphene_vec3_equal (&n, graphene_vec3_one ())); g_assert_cmpfloat (graphene_plane_get_constant (p), ==, 0.f); graphene_plane_init (p, graphene_vec3_one (), 1.f); graphene_plane_get_normal (p, &n); g_assert_true (graphene_vec3_equal (&n, graphene_vec3_one ())); g_assert_cmpfloat (graphene_plane_get_constant (p), ==, 1.f); graphene_plane_free (p); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (plane_init_normal_point) { graphene_vec3_t normal, check; graphene_plane_t *p; graphene_vec3_normalize (graphene_vec3_one (), &normal); p = graphene_plane_init_from_point (graphene_plane_alloc (), &normal, &zero3); graphene_plane_get_normal (p, &check); g_assert_true (graphene_vec3_equal (&check, &normal)); g_assert_cmpfloat (graphene_plane_get_constant (p), ==, 0.f); graphene_plane_free (p); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (plane_normalize) { graphene_plane_t p; graphene_vec3_t tmp; graphene_plane_init (&p, graphene_vec3_init (&tmp, 2.f, 0.f, 0.f), 2.f); graphene_plane_normalize (&p, &p); graphene_plane_get_normal (&p, &tmp); graphene_assert_fuzzy_vec3_equal (&tmp, graphene_vec3_x_axis (), 0.0001f); graphene_assert_fuzzy_equals (graphene_vec3_length (&tmp), 1.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_plane_get_constant (&p), 1.f, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (plane_distance_positive) { graphene_plane_t p; graphene_vec3_t tmp; graphene_point3d_t point; graphene_plane_init (&p, graphene_vec3_init (&tmp, 2.f, 0.f, 0.f), -2.f); graphene_plane_normalize (&p, &p); graphene_point3d_init (&point, 4.f, 0.f, 0.f); graphene_assert_fuzzy_equals (graphene_plane_distance (&p, &point), 3.f, 0.0001); graphene_point3d_init (&point, 1.f, 0.f, 0.f); graphene_assert_fuzzy_equals (graphene_plane_distance (&p, &point), 0.f, 0.0001); graphene_plane_negate (&p, &p); graphene_point3d_init (&point, 4.f, 0.f, 0.f); graphene_assert_fuzzy_equals (graphene_plane_distance (&p, &point), -3.f, 0.0001); graphene_point3d_init (&point, 1.f, 0.f, 0.f); graphene_assert_fuzzy_equals (graphene_plane_distance (&p, &point), 0.f, 0.0001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (plane_distance_negative) { graphene_plane_t p; graphene_vec3_t tmp; graphene_point3d_t point; graphene_plane_init (&p, graphene_vec3_init (&tmp, 2.f, 0.f, 0.f), -2.f); graphene_plane_normalize (&p, &p); graphene_point3d_init (&point, 4.f, 0.f, 0.f); graphene_assert_fuzzy_equals (graphene_plane_distance (&p, &point), 3.f, 0.0001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/plane/init/base", plane_init_base) GRAPHENE_TEST_UNIT ("/plane/init/normal-point", plane_init_normal_point) GRAPHENE_TEST_UNIT ("/plane/normalize", plane_normalize) GRAPHENE_TEST_UNIT ("/plane/distance/positive", plane_distance_positive) GRAPHENE_TEST_UNIT ("/plane/distance/negative", plane_distance_negative) ) graphene-1.8.0/src/tests/point.c000066400000000000000000000073471324365266600165670ustar00rootroot00000000000000#include #include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (point_zero) { const graphene_point_t *p; graphene_point_t q; p = graphene_point_zero (); g_assert_nonnull (p); g_assert_true (p == graphene_point_zero ()); g_assert_true (graphene_point_equal (p, &zero2)); graphene_point_init_from_point (&q, graphene_point_zero ()); g_assert_true (graphene_point_equal (&q, &zero2)); g_assert_cmpfloat (graphene_point_distance (p, &q, NULL, NULL), ==, 0.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_alloc) { graphene_point_t *a, b; a = graphene_point_alloc (); g_assert_nonnull (a); graphene_point_init (a, x, y); graphene_point_init_from_point (&b, a); g_assert_true (graphene_point_equal (&b, a)); graphene_point_free (a); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_init) { graphene_point_t p, q; graphene_point_init (&p, 0.f, 0.f); g_assert_cmpfloat (p.x, ==, 0.f); g_assert_cmpfloat (p.y, ==, 0.f); graphene_point_init (&p, 1.f, 1.f); g_assert_cmpfloat (p.x, ==, 1.0f); g_assert_cmpfloat (p.y, ==, 1.0f); graphene_point_init_from_point (&q, &p); graphene_assert_fuzzy_point_equal (&p, &q, 0.0001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_equal) { graphene_point_t p, q; graphene_point_init (&p, 0.f, 0.f); graphene_point_init (&q, 0.f, 0.f); g_assert_true (graphene_point_equal (&p, &p)); g_assert_false (graphene_point_equal (&p, NULL)); g_assert_false (graphene_point_equal (NULL, &q)); g_assert_true (graphene_point_equal (&p, &q)); graphene_point_init (&q, 1.f, 1.f); g_assert_false (graphene_point_equal (&p, &q)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_distance) { graphene_point_t p, q; float x_d, y_d; graphene_point_init (&p, 0.f, 0.f); g_assert_cmpfloat (p.x, ==, 0.f); g_assert_cmpfloat (p.y, ==, 0.f); graphene_point_init (&q, 1.f, 1.f); g_assert_cmpfloat (q.x, ==, 1.0f); g_assert_cmpfloat (q.y, ==, 1.0f); g_assert_cmpfloat (graphene_point_distance (&p, &p, NULL, NULL), ==, 0.f); g_assert_cmpfloat (graphene_point_distance (&q, &q, NULL, NULL), ==, 0.f); x_d = y_d = 0.f; graphene_assert_fuzzy_equals (graphene_point_distance (&p, &q, &x_d, &y_d), sqrtf (2.f), 0.0001f); g_assert_cmpfloat (x_d, ==, 1.f); g_assert_cmpfloat (y_d, ==, 1.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_near) { graphene_point_t p, q; graphene_point_init (&p, 0.f, 0.f); graphene_point_init (&q, 0.1f, 0.1f); g_assert_true (graphene_point_near (&p, &q, 0.2f)); g_assert_false (graphene_point_near (&p, &q, 0.001f)); g_assert_false (graphene_point_near (&p, &q, 0.f)); g_assert_true (graphene_point_near (&p, &p, 0.f)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_interpolate) { graphene_point_t p, half, q, res; graphene_point_init (&p, 0.f, 0.f); graphene_point_init (&q, 1.f, 1.f); graphene_point_init (&half, .5f, .5f); graphene_point_interpolate (&p, &q, 0.0, &res); graphene_assert_fuzzy_point_equal (&res, &p, 0.0001); graphene_point_interpolate (&p, &q, 0.5, &res); graphene_assert_fuzzy_point_equal (&res, &half, 0.0001); graphene_point_interpolate (&p, &q, 1.0, &res); graphene_assert_fuzzy_point_equal (&res, &q, 0.0001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/point/alloc", point_alloc) GRAPHENE_TEST_UNIT ("/point/init", point_init) GRAPHENE_TEST_UNIT ("/point/equal", point_equal) GRAPHENE_TEST_UNIT ("/point/distance", point_distance) GRAPHENE_TEST_UNIT ("/point/near", point_near) GRAPHENE_TEST_UNIT ("/point/zero", point_zero) GRAPHENE_TEST_UNIT ("/point/interpolate", point_interpolate) ) graphene-1.8.0/src/tests/point3d.c000066400000000000000000000153241324365266600170100ustar00rootroot00000000000000#include #include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (point_zero) { const graphene_point3d_t *p; graphene_point3d_t q; p = graphene_point3d_zero (); g_assert_nonnull (p); g_assert_true (p == graphene_point3d_zero ()); g_assert_cmpfloat (p->x, ==, 0.f); g_assert_cmpfloat (p->y, ==, 0.f); g_assert_cmpfloat (p->z, ==, 0.f); graphene_point3d_init_from_point (&q, graphene_point3d_zero ()); g_assert_cmpfloat (q.x, ==, 0.f); g_assert_cmpfloat (q.y, ==, 0.f); g_assert_cmpfloat (q.z, ==, 0.f); g_assert_true (graphene_point3d_equal (p, &q)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_alloc) { graphene_point3d_t *a, b; a = graphene_point3d_alloc (); g_assert_nonnull (a); graphene_point3d_init (a, x, y, z); graphene_point3d_init_from_point (&b, a); g_assert_true (graphene_point3d_equal (&b, a)); graphene_point3d_free (a); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_init) { graphene_point3d_t p, q, r; graphene_vec3_t vec3; graphene_point3d_init (&p, 0.f, 0.f, 0.f); g_assert_cmpfloat (p.x, ==, 0.f); g_assert_cmpfloat (p.y, ==, 0.f); g_assert_cmpfloat (p.z, ==, 0.f); graphene_point3d_init (&p, 1.f, 1.f, 1.f); g_assert_cmpfloat (p.x, ==, 1.0f); g_assert_cmpfloat (p.y, ==, 1.0f); g_assert_cmpfloat (p.z, ==, 1.0f); graphene_point3d_init_from_point (&q, &p); g_assert_cmpfloat (q.x, ==, p.x); g_assert_cmpfloat (q.y, ==, p.y); g_assert_cmpfloat (q.z, ==, p.z); graphene_vec3_init (&vec3, x, y, w); graphene_point3d_init_from_vec3 (&r, &vec3); g_assert_cmpfloat (graphene_vec3_get_x (&vec3), ==, r.x); g_assert_cmpfloat (graphene_vec3_get_y (&vec3), ==, r.y); g_assert_cmpfloat (graphene_vec3_get_z (&vec3), ==, r.z); graphene_point3d_init (&r, x, y, z); graphene_point3d_to_vec3 (&r, &vec3); g_assert_cmpfloat (graphene_vec3_get_x (&vec3), ==, x); g_assert_cmpfloat (graphene_vec3_get_y (&vec3), ==, y); g_assert_cmpfloat (graphene_vec3_get_z (&vec3), ==, z); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_equal) { graphene_point3d_t p, q; graphene_point3d_init (&p, 0.f, 0.f, 0.f); graphene_point3d_init (&q, 0.f, 0.f, 0.f); g_assert_true (graphene_point3d_equal (&p, &p)); g_assert_false (graphene_point3d_equal (&p, NULL)); g_assert_false (graphene_point3d_equal (NULL, &q)); g_assert_true (graphene_point3d_equal (&p, &q)); graphene_point3d_init (&q, 1.f, 1.f, 1.f); g_assert_false (graphene_point3d_equal (&p, &q)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_near) { graphene_point3d_t p, q; graphene_point3d_init (&p, 0.f, 0.f, 0.f); graphene_point3d_init (&q, 0.1f, 0.1f, 0.1f); g_assert_true (graphene_point3d_near (&p, &q, 0.2f)); g_assert_false (graphene_point3d_near (&p, &q, 0.001f)); g_assert_false (graphene_point3d_near (&p, &q, 0.f)); g_assert_true (graphene_point3d_near (&p, &p, 0.f)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_interpolate) { graphene_point3d_t res; graphene_point3d_interpolate (&zero3, &one3, 0.0, &res); g_assert_cmpfloat (res.x, ==, zero3.x); g_assert_cmpfloat (res.y, ==, zero3.y); g_assert_cmpfloat (res.z, ==, zero3.z); graphene_point3d_interpolate (&zero3, &one3, 0.5, &res); g_assert_cmpfloat (res.x, ==, half3.x); g_assert_cmpfloat (res.y, ==, half3.y); g_assert_cmpfloat (res.z, ==, half3.z); graphene_point3d_interpolate (&zero3, &one3, 1.0, &res); g_assert_cmpfloat (res.x, ==, one3.x); g_assert_cmpfloat (res.y, ==, one3.y); g_assert_cmpfloat (res.z, ==, one3.z); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_scale) { graphene_point3d_t p; graphene_point3d_init (&p, x, y, z); graphene_point3d_scale (&p, 2.f, &p); g_assert_cmpfloat (p.x, ==, x * 2.f); g_assert_cmpfloat (p.y, ==, y * 2.f); g_assert_cmpfloat (p.z, ==, z * 2.f); graphene_point3d_init (&p, x, y, z); graphene_point3d_scale (&p, .5f, &p); g_assert_cmpfloat (p.x, ==, x * .5f); g_assert_cmpfloat (p.y, ==, y * .5f); g_assert_cmpfloat (p.z, ==, z * .5f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_cross) { graphene_point3d_t a, b, res; graphene_vec3_t v_a, v_b, v_res; graphene_point3d_init (&a, 1.f, 2.f, 3.f); graphene_point3d_init (&b, 4.f, 5.f, 6.f); graphene_point3d_to_vec3 (&a, &v_a); graphene_point3d_to_vec3 (&b, &v_b); graphene_point3d_cross (&a, &b, &res); graphene_vec3_cross (&v_a, &v_b, &v_res); g_assert_cmpfloat (res.x, ==, graphene_vec3_get_x (&v_res)); g_assert_cmpfloat (res.y, ==, graphene_vec3_get_y (&v_res)); g_assert_cmpfloat (res.z, ==, graphene_vec3_get_z (&v_res)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_dot) { graphene_point3d_t a, b; graphene_vec3_t v_a, v_b; graphene_point3d_init (&a, 1.f, 2.f, 3.f); graphene_point3d_init (&b, 4.f, 5.f, 6.f); graphene_point3d_to_vec3 (&a, &v_a); graphene_point3d_to_vec3 (&b, &v_b); g_assert_cmpfloat (graphene_point3d_dot (&a, &b), ==, graphene_vec3_dot (&v_a, &v_b)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_length) { graphene_point3d_t p; float res; graphene_point3d_init (&p, 1.f, 3.f, 5.f); res = sqrtf (1.f + (3.f * 3.f) + (5.f * 5.f)); graphene_assert_fuzzy_equals (graphene_point3d_length (&p), res, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_normalize) { graphene_point3d_t p, q; graphene_point3d_init (&p, 4.f, 8.f, 2.f); graphene_point3d_normalize (&p, &q); g_assert_false (graphene_point3d_equal (&p, &q)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (point_normalize_viewport) { graphene_point3d_t p, q; graphene_rect_t v; graphene_point3d_init (&p, 150.f, 20.f, 0.f); graphene_rect_init (&v, 0.f, 0.f, 640.f, 480.f); graphene_point3d_normalize_viewport (&p, &v, 1.f, 100.f, &q); g_assert_false (graphene_point3d_equal (&p, &q)); g_assert_cmpfloat (q.x, >=, -1.f); g_assert_cmpfloat (q.x, <, 1.f); g_assert_cmpfloat (q.y, >=, -1.f); g_assert_cmpfloat (q.y, <, 1.f); g_assert_cmpfloat (q.z, >=, -1.f); g_assert_cmpfloat (q.z, <, 1.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/point3d/alloc", point_alloc) GRAPHENE_TEST_UNIT ("/point3d/init", point_init) GRAPHENE_TEST_UNIT ("/point3d/equal", point_equal) GRAPHENE_TEST_UNIT ("/point3d/near", point_near) GRAPHENE_TEST_UNIT ("/point3d/zero", point_zero) GRAPHENE_TEST_UNIT ("/point3d/interpolate", point_interpolate) GRAPHENE_TEST_UNIT ("/point3d/scale", point_scale) GRAPHENE_TEST_UNIT ("/point3d/cross", point_cross) GRAPHENE_TEST_UNIT ("/point3d/dot", point_dot) GRAPHENE_TEST_UNIT ("/point3d/length", point_length) GRAPHENE_TEST_UNIT ("/point3d/normalize", point_normalize) GRAPHENE_TEST_UNIT ("/point3d/normalize-viewport", point_normalize_viewport) ) graphene-1.8.0/src/tests/quad.c000066400000000000000000000043621324365266600163620ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (quad_bounds) { graphene_quad_t p; graphene_rect_t r, s; graphene_point_t p0, p1, p2, p3; graphene_rect_init (&r, 0.f, 0.f, 10.f, 10.f); graphene_rect_get_top_left (&r, &p0); graphene_rect_get_top_right (&r, &p1); graphene_rect_get_bottom_right (&r, &p2); graphene_rect_get_bottom_left (&r, &p3); graphene_quad_init (&p, &p0, &p1, &p2, &p3); graphene_quad_bounds (&p, &s); g_assert_true (graphene_rect_contains_rect (&s, &r)); graphene_quad_init_from_rect (&p, &r); graphene_quad_bounds (&p, &s); g_assert_true (graphene_rect_contains_rect (&s, &r)); graphene_rect_get_top_left (&r, &p0); g_assert_true (graphene_point_equal (graphene_quad_get_point (&p, 0), &p0)); graphene_rect_get_top_right (&r, &p1); g_assert_true (graphene_point_equal (graphene_quad_get_point (&p, 1), &p1)); graphene_rect_get_bottom_right (&r, &p2); g_assert_true (graphene_point_equal (graphene_quad_get_point (&p, 2), &p2)); graphene_rect_get_bottom_left (&r, &p3); g_assert_true (graphene_point_equal (graphene_quad_get_point (&p, 3), &p3)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quad_contains) { graphene_point_t p[4] = { GRAPHENE_POINT_INIT ( 0.f, 0.f), GRAPHENE_POINT_INIT (10.f, 1.f), GRAPHENE_POINT_INIT (10.f, 9.f), GRAPHENE_POINT_INIT ( 0.f, 10.f), }; graphene_point_t a; graphene_quad_t *q; q = graphene_quad_init_from_points (graphene_quad_alloc (), p); graphene_point_init_from_point (&a, &p[0]); g_assert_true (graphene_quad_contains (q, &a)); graphene_point_init_from_point (&a, &p[1]); g_assert_true (graphene_quad_contains (q, &a)); graphene_point_init_from_point (&a, &p[2]); g_assert_true (graphene_quad_contains (q, &a)); graphene_point_init_from_point (&a, &p[3]); g_assert_true (graphene_quad_contains (q, &a)); graphene_point_init (&a, 5.f, 5.f); g_assert_true (graphene_quad_contains (q, &a)); graphene_point_init (&a, 10.f, 10.f); g_assert_false (graphene_quad_contains (q, &a)); graphene_quad_free (q); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/quad/bounds", quad_bounds) GRAPHENE_TEST_UNIT ("/quad/contains", quad_contains) ) graphene-1.8.0/src/tests/quaternion.c000066400000000000000000000136331324365266600176160ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (quaternion_init) { graphene_quaternion_t q1, q2; graphene_quaternion_init (&q1, 0.f, 0.f, 0.f, 1.f); graphene_quaternion_init_identity (&q2); g_assert_true (graphene_quaternion_equal (&q1, &q2)); graphene_quaternion_init (&q1, 1.f, 1.f, 1.f, 1.f); g_assert_false (graphene_quaternion_equal (&q1, &q2)); graphene_quaternion_init_from_quaternion (&q2, &q1); g_assert_true (graphene_quaternion_equal (&q1, &q2)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_operators_invert) { graphene_quaternion_t q1, q2, tmp; graphene_quaternion_init_identity (&q1); graphene_quaternion_invert (&q1, &q2); g_assert_true (graphene_quaternion_equal (&q1, &q2)); graphene_quaternion_init (&q1, 1.f, 1.f, 1.f, 1.f); g_assert_true (graphene_quaternion_equal (&q1, graphene_quaternion_init (&tmp, 1.f, 1.f, 1.f, 1.f))); graphene_quaternion_invert (&q1, &q2); g_assert_true (graphene_quaternion_equal (&q2, graphene_quaternion_init (&tmp, -1.f, -1.f, -1.f, 1.f))); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_operators_dot) { graphene_quaternion_t q1, q2; graphene_quaternion_init (&q1, 1.f, 1.f, 1.f, 1.f); graphene_quaternion_invert (&q1, &q2); g_assert_cmpfloat (graphene_quaternion_dot (&q1, &q2), ==, -2.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_operators_equal) { graphene_quaternion_t q1, q2; graphene_quaternion_init (&q1, 1.f, 1.f, 1.f, 1.f); graphene_quaternion_invert (&q1, &q2); g_assert_true (graphene_quaternion_equal (&q1, &q1)); g_assert_false (graphene_quaternion_equal (&q1, NULL)); g_assert_false (graphene_quaternion_equal (NULL, &q1)); g_assert_false (graphene_quaternion_equal (&q1, &q2)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_operators_normalize) { graphene_quaternion_t q1, q2; graphene_vec4_t v1, v2; graphene_quaternion_init (&q1, 1.f, 2.f, 3.f, 4.f); graphene_quaternion_normalize (&q1, &q2); graphene_vec4_init (&v1, 1.f, 2.f, 3.f, 4.f); graphene_vec4_normalize (&v1, &v1); graphene_quaternion_to_vec4 (&q2, &v2); graphene_assert_fuzzy_vec4_equal (&v1, &v2, 0.00001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_angles_to_from) { graphene_quaternion_t *q; float a, b, c; q = graphene_quaternion_init_from_angles (graphene_quaternion_alloc (), 90.f, 45.f, -105.f); graphene_quaternion_to_angles (q, &a, &b, &c); graphene_assert_fuzzy_equals (a, 90.f, 0.0001); graphene_assert_fuzzy_equals (b, 45.f, 0.0001); graphene_assert_fuzzy_equals (c, -105.f, 0.0001); graphene_quaternion_free (q); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_vec4_to_from) { graphene_quaternion_t *q; graphene_vec4_t v; graphene_vec4_init (&v, 0.f, 0.f, 0.f, 1.f); q = graphene_quaternion_init_from_vec4 (graphene_quaternion_alloc (), &v); graphene_quaternion_to_vec4 (q, &v); graphene_assert_fuzzy_equals (graphene_vec4_get_x (&v), 0.f, 0.00001); graphene_assert_fuzzy_equals (graphene_vec4_get_y (&v), 0.f, 0.00001); graphene_assert_fuzzy_equals (graphene_vec4_get_z (&v), 0.f, 0.00001); graphene_assert_fuzzy_equals (graphene_vec4_get_w (&v), 1.f, 0.00001); graphene_quaternion_free (q); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_matrix_to_from) { graphene_quaternion_t *q1, *q2; graphene_matrix_t *m; m = graphene_matrix_init_identity (graphene_matrix_alloc ()); q1 = graphene_quaternion_init_from_matrix (graphene_quaternion_alloc (), m); q2 = graphene_quaternion_init_identity (graphene_quaternion_alloc ()); g_assert_true (graphene_quaternion_equal (q1, q2)); graphene_matrix_rotate_x (m, 30.f); graphene_matrix_rotate_y (m, 45.f); graphene_matrix_rotate_z (m, -135.f); graphene_quaternion_init_from_matrix (q1, m); g_assert_false (graphene_quaternion_equal (q1, q2)); graphene_matrix_init_identity (m); graphene_matrix_rotate_quaternion (m, q1); graphene_quaternion_init_from_matrix (q2, m); g_assert_true (graphene_quaternion_equal (q1, q2)); graphene_quaternion_free (q2); graphene_quaternion_free (q1); graphene_matrix_free (m); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_angle_vec3_to_from) { graphene_quaternion_t q1, q2; graphene_vec3_t axis; float angle; graphene_quaternion_init_from_angle_vec3 (&q1, 45.f, graphene_vec3_y_axis ()); graphene_quaternion_init_from_quaternion (&q2, &q1); graphene_quaternion_to_angle_vec3 (&q2, &angle, &axis); graphene_assert_fuzzy_equals (angle, 45.f, 0.0001); graphene_assert_fuzzy_vec3_equal (&axis, graphene_vec3_y_axis (), 0.0001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (quaternion_slerp) { graphene_quaternion_t q1, q2, q3; graphene_quaternion_init (&q1, 0.0f, 0.0f, 0.0f, 1.0f); graphene_quaternion_init (&q2, 0.2f, 0.3f, 0.4f, 0.5f); g_assert_false (graphene_quaternion_equal (&q1, &q2)); graphene_quaternion_slerp (&q1, &q2, 0.33, &q3); g_assert_false (graphene_quaternion_equal (&q1, &q3)); graphene_quaternion_slerp (&q1, &q2, 0.66, &q3); g_assert_false (graphene_quaternion_equal (&q2, &q3)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/quaternion/init", quaternion_init) GRAPHENE_TEST_UNIT ("/quaternion/operators/invert", quaternion_operators_invert) GRAPHENE_TEST_UNIT ("/quaternion/operators/dot", quaternion_operators_dot) GRAPHENE_TEST_UNIT ("/quaternion/operators/equal", quaternion_operators_equal) GRAPHENE_TEST_UNIT ("/quaternion/operators/normalize", quaternion_operators_normalize) GRAPHENE_TEST_UNIT ("/quaternion/angles/to-from", quaternion_angles_to_from) GRAPHENE_TEST_UNIT ("/quaternion/vec4/to-from", quaternion_vec4_to_from) GRAPHENE_TEST_UNIT ("/quaternion/matrix/to-from", quaternion_matrix_to_from) GRAPHENE_TEST_UNIT ("/quaternion/angle-vec3/to-from", quaternion_angle_vec3_to_from) GRAPHENE_TEST_UNIT ("/quaternion/slerp", quaternion_slerp) ) graphene-1.8.0/src/tests/ray.c000066400000000000000000000100231324365266600162120ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (ray_init) { graphene_ray_t *r; graphene_point3d_t origin; graphene_vec3_t direction; r = graphene_ray_init (graphene_ray_alloc (), NULL, NULL); graphene_ray_get_origin (r, &origin); graphene_ray_get_direction (r, &direction); g_assert_true (graphene_point3d_equal (&origin, &zero3)); g_assert_true (graphene_vec3_equal (&direction, graphene_vec3_zero ())); graphene_ray_free (r); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (ray_get_position_at) { graphene_ray_t r; graphene_point3d_t tmp; graphene_ray_init (&r, &one3, graphene_vec3_z_axis ()); if (g_test_verbose ()) g_test_message ("On the ray's origin..."); graphene_ray_get_position_at (&r, 0.f, &tmp); g_assert_true (graphene_point3d_equal (&tmp, &one3)); if (g_test_verbose ()) g_test_message ("Behind the ray..."); graphene_ray_get_position_at (&r, -1.f, &tmp); graphene_assert_fuzzy_equals (tmp.x, 1.f, 0.0001); graphene_assert_fuzzy_equals (tmp.y, 1.f, 0.0001); graphene_assert_fuzzy_equals (tmp.z, 0.f, 0.0001); if (g_test_verbose ()) g_test_message ("On the ray..."); graphene_ray_get_position_at (&r, 1.f, &tmp); graphene_assert_fuzzy_equals (tmp.x, 1.f, 0.0001); graphene_assert_fuzzy_equals (tmp.y, 1.f, 0.0001); graphene_assert_fuzzy_equals (tmp.z, 2.f, 0.0001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (ray_get_distance_to_point) { graphene_ray_t r; graphene_point3d_t tmp = GRAPHENE_POINT3D_INIT (0, 0, 50); graphene_ray_init (&r, &one3, graphene_vec3_z_axis ()); if (g_test_verbose ()) g_test_message ("On the ray's origin..."); graphene_assert_fuzzy_equals (graphene_ray_get_distance_to_point (&r, &one3), 0.f, 0.00001); if (g_test_verbose ()) g_test_message ("Behind the ray..."); graphene_assert_fuzzy_equals (graphene_ray_get_distance_to_point (&r, &zero3), sqrtf (3.f), 0.00001); if (g_test_verbose ()) g_test_message ("On the ray..."); graphene_assert_fuzzy_equals (graphene_ray_get_distance_to_point (&r, &tmp), sqrtf (2.f), 0.00001); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (ray_closest_point_to_point) { graphene_point3d_t tmp = GRAPHENE_POINT3D_INIT (0.f, 0.f, 50.f); graphene_point3d_t check = GRAPHENE_POINT3D_INIT (1.f, 1.f, 50.f); graphene_point3d_t res; graphene_ray_t r; graphene_ray_init (&r, &one3, graphene_vec3_z_axis ()); if (g_test_verbose ()) g_test_message ("Behind the ray..."); graphene_ray_get_closest_point_to_point (&r, &zero3, &res); g_assert_true (graphene_point3d_near (&res, &one3, 0.00001)); if (g_test_verbose ()) g_test_message ("Front of the ray..."); graphene_ray_get_closest_point_to_point (&r, &tmp, &res); g_assert_true (graphene_point3d_near (&res, &check, 0.00001)); if (g_test_verbose ()) g_test_message ("On the ray..."); graphene_ray_get_closest_point_to_point (&r, &one3, &res); g_assert_true (graphene_point3d_near (&res, &one3, 0.00001)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (ray_matrix_transform) { graphene_ray_t r, res; graphene_matrix_t m; if (g_test_verbose ()) g_test_message ("Identity matrix..."); graphene_ray_init (&r, &one3, graphene_vec3_z_axis ()); graphene_matrix_init_identity (&m); graphene_matrix_transform_ray (&m, &r, &res); g_assert_true (graphene_ray_equal (&r, &res)); if (g_test_verbose ()) g_test_message ("Rotation matrix: rotateZ(90deg)"); graphene_ray_init (&r, &zero3, graphene_vec3_z_axis ()); graphene_matrix_init_rotate (&m, 90, graphene_vec3_z_axis ()); graphene_matrix_transform_ray (&m, &r, &res); g_assert_true (graphene_ray_equal (&r, &res)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/ray/init", ray_init) GRAPHENE_TEST_UNIT ("/ray/get-position-at", ray_get_position_at) GRAPHENE_TEST_UNIT ("/ray/get-distance-to-point", ray_get_distance_to_point) GRAPHENE_TEST_UNIT ("/ray/closest-point-to-point", ray_closest_point_to_point) GRAPHENE_TEST_UNIT ("/ray/matrix-transform", ray_matrix_transform) ) graphene-1.8.0/src/tests/rect.c000066400000000000000000000213021324365266600163560ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (rect_init) { graphene_rect_t *r; graphene_rect_t s; r = graphene_rect_init (graphene_rect_alloc (), 0.f, 0.f, 10.f, 10.f); g_assert_cmpfloat (r->origin.x, ==, 0.f); g_assert_cmpfloat (r->origin.y, ==, 0.f); g_assert_cmpfloat (r->size.width, ==, 10.f); g_assert_cmpfloat (r->size.height, ==, 10.f); graphene_rect_init_from_rect (&s, r); g_assert_true (graphene_rect_equal (&s, r)); graphene_rect_free (r); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_normalize) { graphene_rect_t r = GRAPHENE_RECT_INIT (10.f, 10.f, -10.f, -10.f); graphene_rect_t s = GRAPHENE_RECT_INIT ( 0.f, 0.f, 10.f, 10.f); g_assert_cmpfloat (graphene_rect_get_x (&r), ==, 0.f); g_assert_cmpfloat (graphene_rect_get_y (&r), ==, 0.f); g_assert_cmpfloat (graphene_rect_get_width (&r), ==, 10.f); g_assert_cmpfloat (graphene_rect_get_height (&r), ==, 10.f); g_assert_true (graphene_rect_equal (&r, &s)); graphene_rect_normalize (&r); g_assert_true (graphene_rect_equal (&r, &s)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_equal) { graphene_rect_t *r, *s; r = graphene_rect_init (graphene_rect_alloc (), 0.f, 0.f, 10.f, 10.f); s = graphene_rect_init (graphene_rect_alloc (), 1.f, 1.f, 9.f, 9.f); g_assert_true (graphene_rect_equal (r, r)); g_assert_false (graphene_rect_equal (r, NULL)); g_assert_false (graphene_rect_equal (NULL, r)); g_assert_false (graphene_rect_equal (r, s)); graphene_rect_free (r); graphene_rect_free (s); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_contains_point) { graphene_rect_t r = GRAPHENE_RECT_INIT (0.f, 0.f, 10.f, 10.f); graphene_point_t p; graphene_rect_get_top_left (&r, &p); g_assert_true (graphene_rect_contains_point (&r, &p)); graphene_rect_get_top_right (&r, &p); g_assert_true (graphene_rect_contains_point (&r, &p)); graphene_rect_get_bottom_right (&r, &p); g_assert_true (graphene_rect_contains_point (&r, &p)); graphene_rect_get_bottom_left (&r, &p); g_assert_true (graphene_rect_contains_point (&r, &p)); graphene_rect_get_center (&r, &p); g_assert_true (graphene_rect_contains_point (&r, &p)); graphene_point_init (&p, -1.f, -1.f); g_assert_false (graphene_rect_contains_point (&r, &p)); graphene_point_init (&p, 11.f, 11.f); g_assert_false (graphene_rect_contains_point (&r, &p)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_contains_rect) { graphene_rect_t *r, *s; r = graphene_rect_init (graphene_rect_alloc (), 0.f, 0.f, 10.f, 10.f); s = graphene_rect_init (graphene_rect_alloc (), 1.f, 1.f, 9.f, 9.f); g_assert_true (graphene_rect_contains_rect (r, r)); g_assert_false (graphene_rect_equal (r, s)); g_assert_true (graphene_rect_contains_rect (r, s)); g_assert_false (graphene_rect_contains_rect (s, r)); graphene_rect_free (r); graphene_rect_free (s); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_intersect) { graphene_rect_t r = GRAPHENE_RECT_INIT (0.f, 0.f, 10.f, 10.f); graphene_rect_t s = GRAPHENE_RECT_INIT (5.f, 5.f, 15.f, 15.f); graphene_rect_t q = GRAPHENE_RECT_INIT (11.f, 11.f, 2.f, 2.f); graphene_rect_t i, j; g_assert_true (graphene_rect_intersection (&r, &s, &i)); g_assert_cmpfloat (graphene_rect_get_x (&i), ==, 5.f); g_assert_cmpfloat (graphene_rect_get_y (&i), ==, 5.f); g_assert_cmpfloat (graphene_rect_get_width (&i), ==, 5.f); g_assert_cmpfloat (graphene_rect_get_height (&i), ==, 5.f); g_assert_false (graphene_rect_intersection (&i, &q, &j)); g_assert_cmpfloat (j.origin.x, ==, 0.f); g_assert_cmpfloat (j.origin.y, ==, 0.f); g_assert_cmpfloat (j.size.width, ==, 0.f); g_assert_cmpfloat (j.size.height, ==, 0.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_union) { graphene_rect_t r = GRAPHENE_RECT_INIT (0.f, 0.f, 10.f, 10.f); graphene_rect_t s = GRAPHENE_RECT_INIT (5.f, 5.f, 15.f, 15.f); graphene_rect_t u; graphene_rect_union (&r, &s, &u); g_assert_cmpfloat (u.origin.x, ==, 0.f); g_assert_cmpfloat (u.origin.y, ==, 0.f); g_assert_cmpfloat (u.size.width, ==, 20.f); g_assert_cmpfloat (u.size.height, ==, 20.f); g_assert_true (graphene_rect_contains_rect (&u, &r)); g_assert_true (graphene_rect_contains_rect (&u, &s)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_offset) { graphene_rect_t r = GRAPHENE_RECT_INIT (0.f, 0.f, 10.f, 10.f); graphene_rect_offset (&r, 5.f, 5.f); g_assert_cmpfloat (r.origin.x, ==, 5.f); g_assert_cmpfloat (r.origin.y, ==, 5.f); g_assert_cmpfloat (r.size.width, ==, 10.f); g_assert_cmpfloat (r.size.height, ==, 10.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_inset) { graphene_rect_t r = GRAPHENE_RECT_INIT (0.f, 0.f, 10.f, 10.f); graphene_rect_inset (&r, 2.f, 2.f); g_assert_cmpfloat (r.origin.x, ==, 2.f); g_assert_cmpfloat (r.origin.y, ==, 2.f); g_assert_cmpfloat (r.size.width, ==, 6.f); g_assert_cmpfloat (r.size.height, ==, 6.f); graphene_rect_inset (&r, 2.f, -2.f); g_assert_cmpfloat (r.origin.x, ==, 4.f); g_assert_cmpfloat (r.origin.y, ==, 0.f); g_assert_cmpfloat (r.size.width, ==, 2.f); g_assert_cmpfloat (r.size.height, ==, 10.f); graphene_rect_inset (&r, -2.f, 6.f); g_assert_cmpfloat (r.origin.x, ==, 2.f); g_assert_cmpfloat (r.origin.y, ==, 6.f); g_assert_cmpfloat (r.size.width, ==, 6.f); g_assert_cmpfloat (r.size.height, ==, 0.f); graphene_rect_inset (&r, 8.f, 0.f); g_assert_cmpfloat (r.origin.x, ==, 10.f); g_assert_cmpfloat (r.origin.y, ==, 6.f); g_assert_cmpfloat (r.size.width, ==, 0.f); g_assert_cmpfloat (r.size.height, ==, 0.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_round_to_pixel) { graphene_rect_t r = GRAPHENE_RECT_INIT (0.5f, 1.9f, 9.3f, 8.7f); graphene_rect_t s = GRAPHENE_RECT_INIT (0.0f, 1.0f, 10.0f, 9.0f); graphene_rect_round_to_pixel (&r); g_assert_true (graphene_rect_contains_rect (&s, &r)); g_assert_true (graphene_rect_equal (&r, &s)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_expand) { graphene_rect_t r = GRAPHENE_RECT_INIT (0.f, 0.f, 100.f, 100.f); graphene_point_t p; graphene_rect_t check; if (g_test_verbose ()) g_test_message ("Behind the origin..."); graphene_rect_expand (&r, graphene_point_init (&p, -10.f, -10.f), &check); g_assert_true (graphene_point_equal (&p, &(check.origin))); g_assert_cmpfloat (check.size.width, ==, 110.f); g_assert_cmpfloat (check.size.height, ==, 110.f); g_assert_true (graphene_rect_contains_rect (&check, &r)); if (g_test_verbose ()) g_test_message ("Outside the anti-origin..."); graphene_rect_expand (&r, graphene_point_init (&p, 150.f, 150.f), &check); g_assert_true (graphene_point_equal (&r.origin, &(check.origin))); g_assert_cmpfloat (check.size.width, ==, 150.f); g_assert_cmpfloat (check.size.height, ==, 150.f); g_assert_true (graphene_rect_contains_rect (&check, &r)); if (g_test_verbose ()) g_test_message ("Halfway in and out..."); graphene_rect_expand (&r, graphene_point_init (&p, 50.f, 150.f), &check); g_assert_true (graphene_point_equal (&r.origin, &(check.origin))); g_assert_cmpfloat (check.size.width, ==, r.size.width); g_assert_cmpfloat (check.size.height, ==, 150.f); g_assert_true (graphene_rect_contains_rect (&check, &r)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (rect_interpolate) { graphene_rect_t a = GRAPHENE_RECT_INIT ( 0.f, 0.f, 10.f, 10.f); graphene_rect_t b = GRAPHENE_RECT_INIT (10.f, 5.f, 30.f, 20.f); graphene_rect_t c; graphene_rect_t res; graphene_rect_interpolate (&a, &b, 0.0, &res); g_assert_true (graphene_rect_equal (&a, &res)); graphene_rect_interpolate (&a, &b, 1.0, &res); g_assert_true (graphene_rect_equal (&b, &res)); c.origin.x = a.origin.x + (b.origin.x - a.origin.x) * 0.25f; c.origin.y = a.origin.y + (b.origin.y - a.origin.y) * 0.25f; c.size.width = a.size.width + (b.size.width - a.size.width) * 0.25f; c.size.height = a.size.height + (b.size.height - a.size.height) * 0.25f; graphene_rect_interpolate (&a, &b, 0.25, &res); g_assert_true (graphene_rect_equal (&c, &res)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/rect/init", rect_init) GRAPHENE_TEST_UNIT ("/rect/normalize", rect_normalize) GRAPHENE_TEST_UNIT ("/rect/equal", rect_equal) GRAPHENE_TEST_UNIT ("/rect/contains/point", rect_contains_point) GRAPHENE_TEST_UNIT ("/rect/contains/rect", rect_contains_rect) GRAPHENE_TEST_UNIT ("/rect/intersect", rect_intersect) GRAPHENE_TEST_UNIT ("/rect/union", rect_union) GRAPHENE_TEST_UNIT ("/rect/offset", rect_offset) GRAPHENE_TEST_UNIT ("/rect/inset", rect_inset) GRAPHENE_TEST_UNIT ("/rect/round-to-pixel", rect_round_to_pixel) GRAPHENE_TEST_UNIT ("/rect/expand", rect_expand) GRAPHENE_TEST_UNIT ("/rect/interpolate", rect_interpolate) ) graphene-1.8.0/src/tests/simd.c000066400000000000000000000175011324365266600163630ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" static void simd_dup_4f (void) { graphene_simd4f_t s; float v[4]; struct { float x, y, z, w; } p; s = graphene_simd4f_init (2.f, 3.f, 4.f, 5.f); graphene_simd4f_dup_4f (s, v); g_assert_cmpfloat (v[0], ==, 2.f); g_assert_cmpfloat (v[1], ==, 3.f); g_assert_cmpfloat (v[2], ==, 4.f); g_assert_cmpfloat (v[3], ==, 5.f); graphene_simd4f_dup_4f (s, &(p.x)); g_assert_cmpfloat (p.x, ==, 2.f); g_assert_cmpfloat (p.y, ==, 3.f); g_assert_cmpfloat (p.z, ==, 4.f); g_assert_cmpfloat (p.w, ==, 5.f); } static void simd_dup_3f (void) { graphene_simd4f_t s; float v[3]; struct { float x, y, z; } p; s = graphene_simd4f_init (2.f, 3.f, 4.f, 5.f); graphene_simd4f_dup_3f (s, v); g_assert_cmpfloat (v[0], ==, 2.f); g_assert_cmpfloat (v[1], ==, 3.f); g_assert_cmpfloat (v[2], ==, 4.f); graphene_simd4f_dup_3f (s, &(p.x)); g_assert_cmpfloat (p.x, ==, 2.f); g_assert_cmpfloat (p.y, ==, 3.f); g_assert_cmpfloat (p.z, ==, 4.f); } static void simd_dup_2f (void) { graphene_simd4f_t s; float v[2]; struct { float x, y; } p; s = graphene_simd4f_init (2.f, 3.f, 4.f, 5.f); graphene_simd4f_dup_2f (s, v); g_assert_cmpfloat (v[0], ==, 2.f); g_assert_cmpfloat (v[1], ==, 3.f); graphene_simd4f_dup_2f (s, &(p.x)); g_assert_cmpfloat (p.x, ==, 2.f); g_assert_cmpfloat (p.y, ==, 3.f); } static void simd_compare_eq (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (1.f, 0.f, 1.f, 0.f); g_assert_true (graphene_simd4f_cmp_eq (a, a)); b = graphene_simd4f_init (1.f, 0.f, 1.f, 0.f); g_assert_true (graphene_simd4f_cmp_eq (a, b)); g_assert_true (graphene_simd4f_cmp_eq (b, a)); c = graphene_simd4f_splat (1.f); g_assert_false (graphene_simd4f_cmp_eq (a, c)); g_assert_false (graphene_simd4f_cmp_eq (b, c)); } static void simd_compare_neq (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (1.f, 0.f, 1.f, 0.f); g_assert_false (graphene_simd4f_cmp_neq (a, a)); b = graphene_simd4f_init (1.f, 0.f, 1.f, 0.f); g_assert_false (graphene_simd4f_cmp_neq (a, b)); g_assert_false (graphene_simd4f_cmp_neq (b, a)); c = graphene_simd4f_splat (1.f); g_assert_true (graphene_simd4f_cmp_neq (a, c)); g_assert_true (graphene_simd4f_cmp_neq (b, c)); } static void simd_compare_lt (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (0.f, 0.f, 0.f, 0.f); b = graphene_simd4f_init (1.f, 1.f, 1.f, 1.f); g_assert_true (graphene_simd4f_cmp_lt (a, b)); g_assert_false (graphene_simd4f_cmp_lt (b, a)); c = graphene_simd4f_init (0.f, 1.f, 0.f, 1.f); g_assert_false (graphene_simd4f_cmp_lt (a, c)); } static void simd_compare_le (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (0.f, 0.f, 0.f, 0.f); b = graphene_simd4f_init (1.f, 1.f, 1.f, 1.f); g_assert_true (graphene_simd4f_cmp_le (a, b)); g_assert_false (graphene_simd4f_cmp_le (b, a)); c = graphene_simd4f_init (0.f, 1.f, 0.f, 1.f); g_assert_true (graphene_simd4f_cmp_le (a, c)); g_assert_false (graphene_simd4f_cmp_le (b, c)); } static void simd_compare_ge (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (0.f, 0.f, 0.f, 0.f); b = graphene_simd4f_init (1.f, 1.f, 1.f, 1.f); g_assert_false (graphene_simd4f_cmp_ge (a, b)); g_assert_true (graphene_simd4f_cmp_ge (b, a)); c = graphene_simd4f_init (0.f, 1.f, 0.f, 1.f); g_assert_false (graphene_simd4f_cmp_ge (a, c)); g_assert_true (graphene_simd4f_cmp_ge (b, c)); } static void simd_compare_gt (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (0.f, 0.f, 0.f, 0.f); b = graphene_simd4f_init (1.f, 1.f, 1.f, 1.f); g_assert_false (graphene_simd4f_cmp_gt (a, b)); g_assert_true (graphene_simd4f_cmp_gt (b, a)); c = graphene_simd4f_init (0.f, 1.f, 0.f, 1.f); g_assert_false (graphene_simd4f_cmp_gt (c, a)); } static void simd_operators_dot_2 (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (1.f, 2.f, 0.f, 0.f); b = graphene_simd4f_init (3.f, 4.f, 0.f, 0.f); c = graphene_simd4f_dot2 (a, b); graphene_assert_fuzzy_equals (graphene_simd4f_get_x (c), 3.f * 1.f + 2.f * 4.f, 0.0001f); } static void simd_operators_dot_3 (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (1.f, 2.f, 3.f, 0.f); b = graphene_simd4f_init (4.f, 5.f, 6.f, 0.f); c = graphene_simd4f_dot3 (a, b); graphene_assert_fuzzy_equals (graphene_simd4f_get_x (c), 1.f * 4.f + 2.f * 5.f + 3.f * 6.f, 0.0001f); } static void simd_operators_dot_4 (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (1.f, 2.f, 3.f, 4.f); b = graphene_simd4f_init (5.f, 6.f, 7.f, 8.f); c = graphene_simd4f_dot4 (a, b); graphene_assert_fuzzy_equals (graphene_simd4f_get_x (c), 1.f * 5.f + 2.f * 6.f + 3.f * 7.f + 4.f * 8.f, 0.0001f); } static void simd_operators_min (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (1.f, 6.f, 3.f, 8.f); b = graphene_simd4f_init (5.f, 2.f, 7.f, 4.f); c = graphene_simd4f_min (a, b); graphene_assert_fuzzy_equals (graphene_simd4f_get_x (c), 1.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_y (c), 2.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_z (c), 3.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_w (c), 4.f, 0.0001f); } static void simd_operators_max (void) { graphene_simd4f_t a, b, c; a = graphene_simd4f_init (1.f, 6.f, 3.f, 8.f); b = graphene_simd4f_init (5.f, 2.f, 7.f, 4.f); c = graphene_simd4f_max (a, b); graphene_assert_fuzzy_equals (graphene_simd4f_get_x (c), 5.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_y (c), 6.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_z (c), 7.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_w (c), 8.f, 0.0001f); } static void simd_operators_min_val (void) { graphene_simd4f_t a, b; a = graphene_simd4f_init (1.f, 2.f, 3.f, 4.f); b = graphene_simd4f_min_val (a); graphene_assert_fuzzy_equals (graphene_simd4f_get_x (b), 1.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_y (b), 1.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_z (b), 1.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_w (b), 1.f, 0.0001f); } static void simd_operators_max_val (void) { graphene_simd4f_t a, b; a = graphene_simd4f_init (1.f, 2.f, 3.f, 4.f); b = graphene_simd4f_max_val (a); graphene_assert_fuzzy_equals (graphene_simd4f_get_x (b), 4.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_y (b), 4.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_z (b), 4.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_simd4f_get_w (b), 4.f, 0.0001f); } int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/simd/dup/4f", simd_dup_4f); g_test_add_func ("/simd/dup/3f", simd_dup_3f); g_test_add_func ("/simd/dup/2f", simd_dup_2f); g_test_add_func ("/simd/compare/eq", simd_compare_eq); g_test_add_func ("/simd/compare/neq", simd_compare_neq); g_test_add_func ("/simd/compare/lt", simd_compare_lt); g_test_add_func ("/simd/compare/le", simd_compare_le); g_test_add_func ("/simd/compare/ge", simd_compare_ge); g_test_add_func ("/simd/compare/gt", simd_compare_gt); g_test_add_func ("/simd/operators/dot/2", simd_operators_dot_2); g_test_add_func ("/simd/operators/dot/3", simd_operators_dot_3); g_test_add_func ("/simd/operators/dot/4", simd_operators_dot_4); g_test_add_func ("/simd/operators/min", simd_operators_min); g_test_add_func ("/simd/operators/min-val", simd_operators_min_val); g_test_add_func ("/simd/operators/max", simd_operators_max); g_test_add_func ("/simd/operators/max-val", simd_operators_max_val); return g_test_run (); } graphene-1.8.0/src/tests/size.c000066400000000000000000000043651324365266600164050ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (size_zero) { const graphene_size_t *zero; graphene_size_t *s; zero = graphene_size_zero (); g_assert_cmpfloat (zero->width, ==, 0.f); g_assert_cmpfloat (zero->height, ==, 0.f); g_assert_true (zero == graphene_size_zero ()); g_assert_true (graphene_size_equal (zero, graphene_size_zero ())); s = graphene_size_init_from_size (graphene_size_alloc (), graphene_size_zero ()); g_assert_false (s == zero); g_assert_true (graphene_size_equal (s, zero)); graphene_size_free (s); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (size_equal) { const graphene_size_t *zero; zero = graphene_size_zero (); g_assert_true (graphene_size_equal (zero, zero)); g_assert_false (graphene_size_equal (zero, NULL)); g_assert_false (graphene_size_equal (NULL, zero)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (size_init) { graphene_size_t s; graphene_size_init (&s, 10.f, 20.f); g_assert_cmpfloat (s.width, ==, 10.f); g_assert_cmpfloat (s.height, ==, 20.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (size_scale) { graphene_size_t s, r; graphene_size_init (&s, 10.f, 10.f); graphene_size_scale (&s, .5f, &r); g_assert_cmpfloat (s.width, >, r.width); g_assert_cmpfloat (s.height, >, r.height); g_assert_cmpfloat (s.width, ==, (r.width * 2.f)); g_assert_cmpfloat (s.height, ==, (r.height * 2.f)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (size_interpolate) { graphene_size_t a, b, half, res; graphene_size_init (&a, 10.f, 10.f); graphene_size_init (&b, 20.f, 20.f); graphene_size_init (&half, 15.f, 15.f); graphene_size_interpolate (&a, &b, 0.0, &res); g_assert_true (graphene_size_equal (&a, &res)); graphene_size_interpolate (&a, &b, 1.0, &res); g_assert_true (graphene_size_equal (&b, &res)); graphene_size_interpolate (&a, &b, 0.5, &res); g_assert_true (graphene_size_equal (&half, &res)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/size/init", size_init) GRAPHENE_TEST_UNIT ("/size/zero", size_zero) GRAPHENE_TEST_UNIT ("/size/equal", size_equal) GRAPHENE_TEST_UNIT ("/size/scale", size_scale) GRAPHENE_TEST_UNIT ("/size/interpolate", size_interpolate) ) graphene-1.8.0/src/tests/sphere.c000066400000000000000000000061221324365266600167120ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (sphere_init) { graphene_point3d_t check; graphene_sphere_t *s; s = graphene_sphere_init (graphene_sphere_alloc (), &zero3, 1.f); g_assert_nonnull (s); g_assert_false (graphene_sphere_is_empty (s)); graphene_sphere_get_center (s, &check); g_assert_true (graphene_point3d_equal (&zero3, &check)); g_assert_cmpfloat (graphene_sphere_get_radius (s), ==, 1.f); graphene_sphere_init (s, NULL, 1.f); graphene_sphere_get_center (s, &check); g_assert_true (graphene_point3d_equal (&zero3, &check)); g_assert_cmpfloat (graphene_sphere_get_radius (s), ==, 1.f); graphene_sphere_free (s); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (sphere_contains_point) { graphene_point3d_t check; graphene_sphere_t *s; s = graphene_sphere_init (graphene_sphere_alloc (), &zero3, 1.f); g_assert_nonnull (s); g_assert_true (graphene_sphere_contains_point (s, &zero3)); graphene_point3d_init (&check, 1.f, 0.f, 0.f); g_assert_true (graphene_sphere_contains_point (s, &check)); graphene_point3d_init (&check, 0.f, -1.f, 0.f); g_assert_true (graphene_sphere_contains_point (s, &check)); g_assert_false (graphene_sphere_contains_point (s, &one3)); graphene_sphere_free (s); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (sphere_bounding_box) { graphene_sphere_t s; graphene_box_t b, check; graphene_point3d_t tmp; graphene_box_init (&check, &zero3, graphene_point3d_init (&tmp, 2.f, 2.f, 2.f)); graphene_sphere_init (&s, &one3, 1.f); graphene_sphere_get_bounding_box (&s, &b); g_assert_true (graphene_box_equal (&b, &check)); graphene_sphere_init (&s, &zero3, 0.f); graphene_sphere_get_bounding_box (&s, &b); g_assert_true (graphene_box_equal (&b, graphene_box_zero ())); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (sphere_distance) { graphene_sphere_t s; graphene_sphere_init (&s, &one3, 1.f); g_assert_cmpfloat (graphene_sphere_distance (&s, &zero3) - 0.7320, <, 0.001); g_assert_cmpfloat (graphene_sphere_distance (&s, &one3), ==, -1.f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (sphere_translate) { graphene_sphere_t s; graphene_point3d_t p; graphene_sphere_init (&s, &one3, 1.f); graphene_point3d_init (&p, -1.f, -1.f, -1.f); graphene_sphere_translate (&s, &p, &s); graphene_sphere_get_center (&s, &p); g_assert_true (graphene_point3d_equal (&p, &zero3)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (sphere_empty) { graphene_sphere_t s; graphene_sphere_init (&s, NULL, 0.f); g_assert_true (graphene_sphere_is_empty (&s)); graphene_sphere_init (&s, &one3, 1.f); g_assert_false (graphene_sphere_is_empty (&s)); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/sphere/init", sphere_init) GRAPHENE_TEST_UNIT ("/sphere/contains-point", sphere_contains_point) GRAPHENE_TEST_UNIT ("/sphere/bounding-box", sphere_bounding_box) GRAPHENE_TEST_UNIT ("/sphere/distance", sphere_distance) GRAPHENE_TEST_UNIT ("/sphere/translate", sphere_translate) GRAPHENE_TEST_UNIT ("/sphere/empty", sphere_empty) ) graphene-1.8.0/src/tests/triangle.c000066400000000000000000000206711324365266600172360ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" GRAPHENE_TEST_UNIT_BEGIN (triangle_init_from_point3d) { graphene_point3d_t a = GRAPHENE_POINT3D_INIT ( 0.f, 1.f, 0.f); graphene_point3d_t b = GRAPHENE_POINT3D_INIT ( 1.f, -1.f, 0.f); graphene_point3d_t c = GRAPHENE_POINT3D_INIT (-1.f, -1.f, 0.f); graphene_point3d_t check_a, check_b, check_c; graphene_triangle_t *t; t = graphene_triangle_init_from_point3d (graphene_triangle_alloc (), &a, &b, &c); graphene_triangle_get_points (t, &check_a, &check_b, &check_c); graphene_assert_fuzzy_equals (graphene_triangle_get_area (t), 2.f, 0.0001f); g_assert_true (graphene_point3d_equal (&check_a, &a)); g_assert_true (graphene_point3d_equal (&check_b, &b)); g_assert_true (graphene_point3d_equal (&check_c, &c)); graphene_triangle_init_from_point3d (t, NULL, NULL, NULL); graphene_triangle_get_points (t, &check_a, &check_b, &check_c); g_assert_cmpfloat (graphene_triangle_get_area (t), ==, 0.f); g_assert_true (graphene_point3d_equal (&check_a, &zero3)); g_assert_true (graphene_point3d_equal (&check_b, &zero3)); g_assert_true (graphene_point3d_equal (&check_c, &zero3)); graphene_triangle_free (t); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (triangle_init_from_vec3) { graphene_vec3_t a, b, c; graphene_vec3_t check_a, check_b, check_c; graphene_triangle_t *t; graphene_vec3_init (&a, 0, 1, 0); graphene_vec3_init (&b, 1, -1, 0); graphene_vec3_init (&c, -1, -1, 0); t = graphene_triangle_init_from_vec3 (graphene_triangle_alloc (), &a, &b, &c); graphene_triangle_get_vertices (t, &check_a, &check_b, &check_c); graphene_assert_fuzzy_equals (graphene_triangle_get_area (t), 2.f, 0.0001f); g_assert_true (graphene_vec3_equal (&check_a, &a)); g_assert_true (graphene_vec3_equal (&check_b, &b)); g_assert_true (graphene_vec3_equal (&check_c, &c)); graphene_triangle_init_from_vec3 (t, NULL, NULL, NULL); graphene_triangle_get_vertices (t, &check_a, &check_b, &check_c); g_assert_cmpfloat (graphene_triangle_get_area (t), ==, 0.f); g_assert_true (graphene_vec3_equal (&check_a, graphene_vec3_zero ())); g_assert_true (graphene_vec3_equal (&check_b, graphene_vec3_zero ())); g_assert_true (graphene_vec3_equal (&check_c, graphene_vec3_zero ())); graphene_triangle_free (t); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (triangle_contains_point) { graphene_point3d_t a = GRAPHENE_POINT3D_INIT ( 0.f, 1.f, 0.f); graphene_point3d_t b = GRAPHENE_POINT3D_INIT ( 1.f, -1.f, 0.f); graphene_point3d_t c = GRAPHENE_POINT3D_INIT (-1.f, -1.f, 0.f); graphene_triangle_t *t; graphene_point3d_t midpoint; t = graphene_triangle_init_from_point3d (graphene_triangle_alloc (), &a, &b, &c); graphene_triangle_get_midpoint (t, &midpoint); g_assert_true (graphene_triangle_contains_point (t, &zero3)); g_assert_false (graphene_triangle_contains_point (t, &one3)); g_assert_true (graphene_triangle_contains_point (t, &midpoint)); graphene_triangle_free (t); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (triangle_plane) { graphene_triangle_t t; graphene_plane_t p; graphene_point3d_t a, b, c; graphene_vec3_t t_norm, p_norm; graphene_triangle_init_from_point3d (&t, NULL, NULL, NULL); graphene_triangle_get_plane (&t, &p); graphene_triangle_get_points (&t, &a, &b, &c); g_assert_cmpfloat (graphene_plane_distance (&p, &a), ==, 0.f); g_assert_cmpfloat (graphene_plane_distance (&p, &b), ==, 0.f); g_assert_cmpfloat (graphene_plane_distance (&p, &c), ==, 0.f); graphene_triangle_get_normal (&t, &t_norm); graphene_plane_get_normal (&p, &p_norm); /* we create an artificial normal for the a:0, b:0, c:0 degenerate triangle */ g_assert_true (graphene_vec3_equal (&t_norm, graphene_vec3_zero ())); g_assert_true (graphene_vec3_equal (&t_norm, &p_norm)); graphene_point3d_init (&a, 0.f, 0.f, 0.f); graphene_point3d_init (&b, 1.f, 0.f, 0.f); graphene_point3d_init (&c, 0.f, 1.f, 0.f); graphene_triangle_init_from_point3d (&t, &a, &b, &c); graphene_triangle_get_plane (&t, &p); g_assert_cmpfloat (graphene_plane_distance (&p, &a), ==, 0.f); g_assert_cmpfloat (graphene_plane_distance (&p, &b), ==, 0.f); g_assert_cmpfloat (graphene_plane_distance (&p, &c), ==, 0.f); graphene_triangle_get_normal (&t, &t_norm); graphene_plane_get_normal (&p, &p_norm); graphene_assert_fuzzy_vec3_equal (&t_norm, &p_norm, 0.0001f); graphene_point3d_init (&a, 2.f, 0.f, 0.f); graphene_point3d_init (&b, 0.f, 0.f, 0.f); graphene_point3d_init (&c, 0.f, 0.f, 2.f); graphene_triangle_init_from_point3d (&t, &a, &b, &c); graphene_triangle_get_plane (&t, &p); g_assert_cmpfloat (graphene_plane_distance (&p, &a), ==, 0.f); g_assert_cmpfloat (graphene_plane_distance (&p, &b), ==, 0.f); g_assert_cmpfloat (graphene_plane_distance (&p, &c), ==, 0.f); graphene_triangle_get_normal (&t, &t_norm); graphene_vec3_normalize (&t_norm, &t_norm); graphene_plane_get_normal (&p, &p_norm); graphene_assert_fuzzy_vec3_equal (&t_norm, &p_norm, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (triangle_barycoords) { graphene_triangle_t t; graphene_point3d_t a, b, c, p; graphene_vec2_t barycoords; graphene_vec2_t check; graphene_point3d_init (&a, 0.f, 0.f, 0.f); graphene_point3d_init (&b, 1.f, 0.f, 0.f); graphene_point3d_init (&c, 1.f, 1.f, 0.f); graphene_triangle_init_from_point3d (&t, &a, &b, &c); /* Inside or on the border of the triangle */ g_assert_true (graphene_triangle_get_barycoords (&t, &a, &barycoords)); graphene_vec2_init (&check, 0.f, 0.f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); g_assert_true (graphene_triangle_get_barycoords (&t, &b, &barycoords)); graphene_vec2_init (&check, 0.f, 1.f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); g_assert_true (graphene_triangle_get_barycoords (&t, &c, &barycoords)); graphene_vec2_init (&check, 1.f, 0.f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); graphene_point3d_init (&p, 0.5f, 0.f, 0.f); g_assert_true (graphene_triangle_get_barycoords (&t, &p, &barycoords)); graphene_vec2_init (&check, 0.f, 0.5f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); graphene_point3d_init (&p, 0.5f, 0.5f, 0.f); g_assert_true (graphene_triangle_get_barycoords (&t, &p, &barycoords)); graphene_vec2_init (&check, 0.5f, 0.f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); graphene_point3d_init (&p, 1.f, 0.5f, 0.f); g_assert_true (graphene_triangle_get_barycoords (&t, &p, &barycoords)); graphene_vec2_init (&check, 0.5f, 0.5f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); /* Outside the triangle, same plane */ graphene_point3d_init (&p, 2.f, 1.f, 0.f); g_assert_true (graphene_triangle_get_barycoords (&t, &p, &barycoords)); graphene_vec2_init (&check, 1.f, 1.f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); graphene_point3d_init (&p, -1.f, 0.f, 0.f); g_assert_true (graphene_triangle_get_barycoords (&t, &p, &barycoords)); graphene_vec2_init (&check, 0.f, -1.f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); /* Outside the triangle plane */ /* FIXME is that normal? */ graphene_point3d_init (&p, 0.f, 0.f, 1.f); g_assert_true (graphene_triangle_get_barycoords (&t, &p, &barycoords)); graphene_vec2_init (&check, 0.f, 0.f); graphene_assert_fuzzy_vec2_equal (&barycoords, &check, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_UNIT_BEGIN (triangle_area) { graphene_triangle_t t; graphene_point3d_t a, b, c; float area; /* Counterclockwise */ graphene_point3d_init (&a, 0.f, 0.f, 0.f); graphene_point3d_init (&b, 1.f, 0.f, 0.f); graphene_point3d_init (&c, 1.f, 1.f, 0.f); graphene_triangle_init_from_point3d (&t, &a, &b, &c); area = graphene_triangle_get_area (&t); graphene_assert_fuzzy_equals (area, 0.5f, 0.0001f); /* Clockwise (positive too) */ graphene_triangle_init_from_point3d (&t, &a, &c, &b); area = graphene_triangle_get_area (&t); graphene_assert_fuzzy_equals (area, 0.5f, 0.0001f); } GRAPHENE_TEST_UNIT_END GRAPHENE_TEST_SUITE ( GRAPHENE_TEST_UNIT ("/triangle/init/from-point3", triangle_init_from_point3d) GRAPHENE_TEST_UNIT ("/triangle/init/from-vec3", triangle_init_from_vec3) GRAPHENE_TEST_UNIT ("/triangle/contains-point", triangle_contains_point); GRAPHENE_TEST_UNIT ("/triangle/plane", triangle_plane); GRAPHENE_TEST_UNIT ("/triangle/barycoords", triangle_barycoords); GRAPHENE_TEST_UNIT ("/triangle/area", triangle_area); ) graphene-1.8.0/src/tests/vec2.c000066400000000000000000000170301324365266600162630ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" static void vectors_vec2_const (void) { const graphene_vec2_t *vec2; vec2 = graphene_vec2_zero (); g_assert_nonnull (vec2); g_assert_true (vec2 == graphene_vec2_zero ()); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, 0.f); g_assert_cmpfloat (graphene_vec2_get_y (vec2), ==, 0.f); g_assert_cmpfloat (graphene_vec2_length (vec2), ==, 0.f); vec2 = graphene_vec2_one (); g_assert_nonnull (vec2); g_assert_true (vec2 == graphene_vec2_one ()); g_assert_true (vec2 != graphene_vec2_zero ()); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, 1.f); g_assert_cmpfloat (graphene_vec2_get_y (vec2), ==, 1.f); vec2 = graphene_vec2_x_axis (); g_assert_nonnull (vec2); g_assert_true (vec2 == graphene_vec2_x_axis ()); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, 1.f); g_assert_cmpfloat (graphene_vec2_get_y (vec2), ==, 0.f); vec2 = graphene_vec2_y_axis (); g_assert_nonnull (vec2); g_assert_true (vec2 == graphene_vec2_y_axis ()); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, 0.f); g_assert_cmpfloat (graphene_vec2_get_y (vec2), ==, 1.f); } static void vectors_vec2_init (void) { graphene_vec2_t *vec2 = graphene_vec2_alloc (); const float v[2] = { 3.f, 4.f }; float v_out[2]; graphene_vec2_init (vec2, 0.5f, 0.5f); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, 0.5f); g_assert_cmpfloat (graphene_vec2_get_y (vec2), ==, 0.5f); graphene_vec2_init (vec2, 1.0f, 1.0f); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, graphene_vec2_get_y (vec2)); graphene_vec2_init_from_vec2 (vec2, graphene_vec2_one ()); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, 1.f); g_assert_cmpfloat (graphene_vec2_get_y (vec2), ==, 1.f); graphene_vec2_init_from_float (vec2, v); g_assert_cmpfloat (graphene_vec2_get_x (vec2), ==, v[0]); g_assert_cmpfloat (graphene_vec2_get_y (vec2), ==, v[1]); graphene_vec2_to_float (vec2, v_out); g_assert_cmpfloat (v_out[0], ==, v[0]); g_assert_cmpfloat (v_out[1], ==, v[1]); graphene_vec2_free (vec2); } static void vectors_vec2_ops_add (void) { graphene_vec2_t a, b, res; graphene_vec2_init (&a, 1.f, 2.f); graphene_vec2_init (&b, 3.f, 4.f); graphene_vec2_add (&a, &b, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, 4.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, 6.f); } static void vectors_vec2_ops_sub (void) { graphene_vec2_t a, b, res; graphene_vec2_init (&a, 1.f, 2.f); graphene_vec2_init (&b, 3.f, 4.f); graphene_vec2_subtract (&a, &b, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, -2.f); } static void vectors_vec2_ops_mul (void) { graphene_vec2_t a, b, res; graphene_vec2_init (&a, 1.f, 2.f); graphene_vec2_init (&b, 3.f, 4.f); graphene_vec2_multiply (&a, &b, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, 3.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, 8.f); } static void vectors_vec2_ops_div (void) { graphene_vec2_t a, b, res; graphene_vec2_init (&a, 6.f, 4.f); graphene_vec2_init (&b, 3.f, 2.f); graphene_vec2_divide (&a, &b, &res); graphene_assert_fuzzy_equals (graphene_vec2_get_x (&res), 2.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_vec2_get_y (&res), 2.f, 0.0001f); } static void vectors_vec2_ops_dot (void) { graphene_vec2_t a, b; float dot, check; graphene_vec2_init (&a, 1.f, 2.f); graphene_vec2_init (&b, 2.f, 3.f); dot = graphene_vec2_dot (&a, &b); check = 1.f * 2.f + 2.f * 3.f; graphene_assert_fuzzy_equals (dot, check, 0.0001); } static void vectors_vec2_ops_scale (void) { graphene_vec2_t a, res; graphene_vec2_init (&a, 1.f, 2.f); graphene_vec2_scale (&a, 2.f, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, 2.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, 4.f); } static void vectors_vec2_ops_negate (void) { graphene_vec2_t a, res; graphene_vec2_init (&a, 1.f, 2.f); graphene_vec2_negate (&a, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, -1.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, -2.f); } static void vectors_vec2_length (void) { graphene_vec2_t a; float len, check; graphene_vec2_init (&a, 10.f, 20.f); len = graphene_vec2_length (&a); check = sqrtf ((10.f * 10.f) + (20.f * 20.f)); graphene_assert_fuzzy_equals (len, check, 0.0001); } static void vectors_vec2_normalize (void) { graphene_vec2_t a, b; float len; graphene_vec2_init (&a, 10.f, 20.f); len = graphene_vec2_length (&a); graphene_vec2_normalize (&a, &b); graphene_assert_fuzzy_equals (graphene_vec2_get_x (&b), (graphene_vec2_get_x (&a) / len), 0.0001); graphene_assert_fuzzy_equals (graphene_vec2_get_y (&b), (graphene_vec2_get_y (&a) / len), 0.0001); } static void vectors_vec2_compare (void) { const graphene_vec2_t *zero = graphene_vec2_zero (); const graphene_vec2_t *one = graphene_vec2_one (); graphene_vec2_t a, b; graphene_vec2_t res; graphene_vec2_min (zero, one, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, 0.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, 0.f); graphene_vec2_max (zero, one, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, 1.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, 1.f); graphene_vec2_init (&a, 5.f, 10.f); graphene_vec2_init (&b, 2.f, 12.f); graphene_vec2_min (&a, &b, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, 2.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, 10.f); graphene_vec2_max (&a, &b, &res); g_assert_cmpfloat (graphene_vec2_get_x (&res), ==, 5.f); g_assert_cmpfloat (graphene_vec2_get_y (&res), ==, 12.f); } static void vectors_vec2_equal (void) { const graphene_vec2_t *zero = graphene_vec2_zero (); const graphene_vec2_t *one = graphene_vec2_one (); graphene_vec2_t a, b; graphene_vec2_init (&a, 0.f, 0.f); graphene_vec2_init (&b, 1.f, 1.f); g_assert_true (graphene_vec2_equal (zero, zero)); g_assert_true (graphene_vec2_equal (one, one)); g_assert_true (graphene_vec2_equal (zero, &a)); g_assert_true (graphene_vec2_equal (one, &b)); g_assert_false (graphene_vec2_equal (zero, one)); g_assert_false (graphene_vec2_equal (one, zero)); g_assert_false (graphene_vec2_equal (&a, &b)); g_assert_true (graphene_vec2_equal (NULL, NULL)); g_assert_false (graphene_vec2_equal (graphene_vec2_one (), NULL)); g_assert_false (graphene_vec2_equal (NULL, graphene_vec2_one ())); } int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/vectors/vec2/const", vectors_vec2_const); g_test_add_func ("/vectors/vec2/init", vectors_vec2_init); g_test_add_func ("/vectors/vec2/operations/add", vectors_vec2_ops_add); g_test_add_func ("/vectors/vec2/operations/sub", vectors_vec2_ops_sub); g_test_add_func ("/vectors/vec2/operations/mul", vectors_vec2_ops_mul); g_test_add_func ("/vectors/vec2/operations/div", vectors_vec2_ops_div); g_test_add_func ("/vectors/vec2/operations/dot", vectors_vec2_ops_dot); g_test_add_func ("/vectors/vec2/operations/scale", vectors_vec2_ops_scale); g_test_add_func ("/vectors/vec2/operations/negate", vectors_vec2_ops_negate); g_test_add_func ("/vectors/vec2/length", vectors_vec2_length); g_test_add_func ("/vectors/vec2/normalize", vectors_vec2_normalize); g_test_add_func ("/vectors/vec2/compare", vectors_vec2_compare); g_test_add_func ("/vectors/vec2/equal", vectors_vec2_equal); return g_test_run (); } graphene-1.8.0/src/tests/vec3.c000066400000000000000000000263221324365266600162700ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" static void vectors_vec3_const (void) { const graphene_vec3_t *vec3; vec3 = graphene_vec3_zero (); g_assert_nonnull (vec3); g_assert_true (vec3 == graphene_vec3_zero ()); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, 0.f); g_assert_cmpfloat (graphene_vec3_length (vec3), ==, 0.f); vec3 = graphene_vec3_one (); g_assert_nonnull (vec3); g_assert_true (vec3 == graphene_vec3_one ()); g_assert_true (vec3 != graphene_vec3_zero ()); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, 1.f); vec3 = graphene_vec3_x_axis (); g_assert_nonnull (vec3); g_assert_true (vec3 == graphene_vec3_x_axis ()); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, 0.f); vec3 = graphene_vec3_y_axis (); g_assert_nonnull (vec3); g_assert_true (vec3 == graphene_vec3_y_axis ()); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, 0.f); vec3 = graphene_vec3_z_axis (); g_assert_nonnull (vec3); g_assert_true (vec3 == graphene_vec3_z_axis ()); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, 1.f); } static void vectors_vec3_init (void) { graphene_vec3_t *vec3 = graphene_vec3_alloc (); const float v[3] = { 1.f, 2.f, 3.f }; float v_out[3]; graphene_vec3_init (vec3, 0.5f, 0.5f, 0.5f); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, 0.5f); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, 0.5f); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, 0.5f); graphene_vec3_init (vec3, 1.0f, 1.0f, 1.0f); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, graphene_vec3_get_y (vec3)); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, graphene_vec3_get_z (vec3)); graphene_vec3_init_from_vec3 (vec3, graphene_vec3_one ()); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, 1.f); graphene_vec3_init_from_float (vec3, v); g_assert_cmpfloat (graphene_vec3_get_x (vec3), ==, v[0]); g_assert_cmpfloat (graphene_vec3_get_y (vec3), ==, v[1]); g_assert_cmpfloat (graphene_vec3_get_z (vec3), ==, v[2]); graphene_vec3_to_float (vec3, v_out); g_assert_cmpfloat (v_out[0], ==, v[0]); g_assert_cmpfloat (v_out[1], ==, v[1]); g_assert_cmpfloat (v_out[2], ==, v[2]); graphene_vec3_free (vec3); } static void vectors_vec3_ops_add (void) { graphene_vec3_t a, b, res; graphene_vec3_init (&a, 1.f, 2.f, 3.f); graphene_vec3_init (&b, 3.f, 4.f, 5.f); graphene_vec3_add (&a, &b, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, 4.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, 6.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, 8.f); } static void vectors_vec3_ops_sub (void) { graphene_vec3_t a, b, res; graphene_vec3_init (&a, 1.f, 2.f, 3.f); graphene_vec3_init (&b, 3.f, 4.f, 5.f); graphene_vec3_subtract (&a, &b, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, -2.f); } static void vectors_vec3_ops_mul (void) { graphene_vec3_t a, b, res; graphene_vec3_init (&a, 1.f, 2.f, 3.f); graphene_vec3_init (&b, 3.f, 4.f, 5.f); graphene_vec3_multiply (&a, &b, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, 3.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, 8.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, 15.f); } static void vectors_vec3_ops_div (void) { graphene_vec3_t a, b, res; graphene_vec3_init (&a, 6.f, 4.f, 2.f); graphene_vec3_init (&b, 3.f, 2.f, 1.f); graphene_vec3_divide (&a, &b, &res); graphene_assert_fuzzy_equals (graphene_vec3_get_x (&res), 2.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_vec3_get_y (&res), 2.f, 0.0001f); graphene_assert_fuzzy_equals (graphene_vec3_get_z (&res), 2.f, 0.0001f); } static void vectors_vec3_ops_dot (void) { graphene_vec3_t a, b; float dot, check; graphene_vec3_init (&a, 1.f, 2.f, 3.f); graphene_vec3_init (&b, 2.f, 3.f, 4.f); dot = graphene_vec3_dot (&a, &b); check = 1.f * 2.f + 2.f * 3.f + 3.f * 4.f; graphene_assert_fuzzy_equals (dot, check, 0.0001f); } static void vectors_vec3_ops_cross (void) { graphene_vec3_t a, b, res, cross; float cross_x, cross_y, cross_z; graphene_vec3_init (&a, 1.f, 2.f, 3.f); graphene_vec3_init (&b, 2.f, 3.f, 4.f); graphene_vec3_cross (&a, &b, &res); cross_x = 2.f * 4.f - 3.f * 3.f; cross_y = 3.f * 2.f - 1.f * 4.f; cross_z = 1.f * 3.f - 2.f * 2.f; graphene_vec3_init (&cross, cross_x, cross_y, cross_z); graphene_assert_fuzzy_vec3_equal (&res, &cross, 0.0001f); } static void vectors_vec3_ops_scale (void) { graphene_vec3_t a, res; graphene_vec3_init (&a, 1.f, 2.f, 3.f); graphene_vec3_scale (&a, 2.f, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, 2.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, 4.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, 6.f); } static void vectors_vec3_ops_negate (void) { graphene_vec3_t a, res; graphene_vec3_init (&a, 1.f, 2.f, 3.f); graphene_vec3_negate (&a, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, -1.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, -3.f); } static void vectors_vec3_length (void) { graphene_vec3_t a; float len, check; graphene_vec3_init (&a, 1.f, 2.f, 3.f); len = graphene_vec3_length (&a); check = sqrtf ((1.f * 1.f) + (2.f * 2.f) + (3.f * 3.f)); graphene_assert_fuzzy_equals (len, check, 0.0001f); } static void vectors_vec3_normalize (void) { graphene_vec3_t a, b, check; float inv_len; graphene_vec3_init (&a, 1.f, 2.f, 3.f); inv_len = 1.f / graphene_vec3_length (&a); graphene_vec3_normalize (&a, &b); graphene_vec3_scale (&a, inv_len, &check); graphene_assert_fuzzy_vec3_equal (&b, &check, 0.0001f); } static void vectors_vec3_compare (void) { const graphene_vec3_t *zero = graphene_vec3_zero (); const graphene_vec3_t *one = graphene_vec3_one (); graphene_vec3_t a, b; graphene_vec3_t res; graphene_vec3_min (zero, one, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, 0.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, 0.f); graphene_vec3_max (zero, one, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, 1.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, 1.f); graphene_vec3_init (&a, 5.f, 10.f, 8.f); graphene_vec3_init (&b, 2.f, 12.f, 8.f); graphene_vec3_min (&a, &b, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, 2.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, 10.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, 8.f); graphene_vec3_max (&a, &b, &res); g_assert_cmpfloat (graphene_vec3_get_x (&res), ==, 5.f); g_assert_cmpfloat (graphene_vec3_get_y (&res), ==, 12.f); g_assert_cmpfloat (graphene_vec3_get_z (&res), ==, 8.f); } static void vectors_vec3_conversion (void) { graphene_vec3_t v; graphene_vec3_init (&v, 1.f, 2.f, 3.f); { graphene_vec2_t xy; graphene_vec3_get_xy (&v, &xy); g_assert_cmpfloat (graphene_vec2_get_x (&xy), ==, 1.f); g_assert_cmpfloat (graphene_vec2_get_y (&xy), ==, 2.f); } { graphene_vec3_t xy0; graphene_vec3_get_xy0 (&v, &xy0); g_assert_cmpfloat (graphene_vec3_get_x (&xy0), ==, graphene_vec3_get_x (&v)); g_assert_cmpfloat (graphene_vec3_get_y (&xy0), ==, graphene_vec3_get_y (&v)); g_assert_cmpfloat (graphene_vec3_get_z (&xy0), !=, graphene_vec3_get_z (&v)); g_assert_cmpfloat (graphene_vec3_get_z (&xy0), ==, 0.f); } { graphene_vec4_t xyz0, xyz1, xyzw; graphene_vec3_get_xyz0 (&v, &xyz0); g_assert_cmpfloat (graphene_vec4_get_x (&xyz0), ==, graphene_vec3_get_x (&v)); g_assert_cmpfloat (graphene_vec4_get_y (&xyz0), ==, graphene_vec3_get_y (&v)); g_assert_cmpfloat (graphene_vec4_get_z (&xyz0), ==, graphene_vec3_get_z (&v)); g_assert_cmpfloat (graphene_vec4_get_w (&xyz0), ==, 0.f); graphene_vec3_get_xyz1 (&v, &xyz1); g_assert_cmpfloat (graphene_vec4_get_x (&xyz1), ==, graphene_vec3_get_x (&v)); g_assert_cmpfloat (graphene_vec4_get_y (&xyz1), ==, graphene_vec3_get_y (&v)); g_assert_cmpfloat (graphene_vec4_get_z (&xyz1), ==, graphene_vec3_get_z (&v)); g_assert_cmpfloat (graphene_vec4_get_w (&xyz1), ==, 1.f); graphene_vec3_get_xyzw (&v, 4.f, &xyzw); g_assert_cmpfloat (graphene_vec4_get_x (&xyzw), ==, graphene_vec3_get_x (&v)); g_assert_cmpfloat (graphene_vec4_get_y (&xyzw), ==, graphene_vec3_get_y (&v)); g_assert_cmpfloat (graphene_vec4_get_z (&xyzw), ==, graphene_vec3_get_z (&v)); g_assert_cmpfloat (graphene_vec4_get_w (&xyzw), ==, 4.f); } } static void vectors_vec3_equal (void) { const graphene_vec3_t *zero = graphene_vec3_zero (); const graphene_vec3_t *one = graphene_vec3_one (); graphene_vec3_t a, b; graphene_vec3_init (&a, 0.f, 0.f, 0.f); graphene_vec3_init (&b, 1.f, 1.f, 1.f); g_assert_true (graphene_vec3_equal (zero, zero)); g_assert_true (graphene_vec3_equal (one, one)); g_assert_true (graphene_vec3_equal (zero, &a)); g_assert_true (graphene_vec3_equal (one, &b)); g_assert_false (graphene_vec3_equal (zero, one)); g_assert_false (graphene_vec3_equal (one, zero)); g_assert_false (graphene_vec3_equal (&a, &b)); g_assert_true (graphene_vec3_equal (NULL, NULL)); g_assert_false (graphene_vec3_equal (graphene_vec3_one (), NULL)); g_assert_false (graphene_vec3_equal (NULL, graphene_vec3_one ())); } int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/vectors/vec3/const", vectors_vec3_const); g_test_add_func ("/vectors/vec3/init", vectors_vec3_init); g_test_add_func ("/vectors/vec3/operations/add", vectors_vec3_ops_add); g_test_add_func ("/vectors/vec3/operations/sub", vectors_vec3_ops_sub); g_test_add_func ("/vectors/vec3/operations/mul", vectors_vec3_ops_mul); g_test_add_func ("/vectors/vec3/operations/div", vectors_vec3_ops_div); g_test_add_func ("/vectors/vec3/operations/dot", vectors_vec3_ops_dot); g_test_add_func ("/vectors/vec3/operations/cross", vectors_vec3_ops_cross); g_test_add_func ("/vectors/vec3/operations/scale", vectors_vec3_ops_scale); g_test_add_func ("/vectors/vec3/operations/negate", vectors_vec3_ops_negate); g_test_add_func ("/vectors/vec3/length", vectors_vec3_length); g_test_add_func ("/vectors/vec3/normalize", vectors_vec3_normalize); g_test_add_func ("/vectors/vec3/compare", vectors_vec3_compare); g_test_add_func ("/vectors/vec3/conversion", vectors_vec3_conversion); g_test_add_func ("/vectors/vec3/equal", vectors_vec3_equal); return g_test_run (); } graphene-1.8.0/src/tests/vec4.c000066400000000000000000000274401324365266600162730ustar00rootroot00000000000000#include #include #include "graphene-test-compat.h" static void vectors_vec4_const (void) { const graphene_vec4_t *vec4; vec4 = graphene_vec4_zero (); g_assert_nonnull (vec4); g_assert_true (vec4 == graphene_vec4_zero ()); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_length (vec4), ==, 0.f); vec4 = graphene_vec4_one (); g_assert_nonnull (vec4); g_assert_true (vec4 == graphene_vec4_one ()); g_assert_true (vec4 != graphene_vec4_zero ()); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 1.f); vec4 = graphene_vec4_x_axis (); g_assert_nonnull (vec4); g_assert_true (vec4 == graphene_vec4_x_axis ()); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 0.f); vec4 = graphene_vec4_y_axis (); g_assert_nonnull (vec4); g_assert_true (vec4 == graphene_vec4_y_axis ()); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 0.f); vec4 = graphene_vec4_z_axis (); g_assert_nonnull (vec4); g_assert_true (vec4 == graphene_vec4_z_axis ()); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 0.f); vec4 = graphene_vec4_w_axis (); g_assert_nonnull (vec4); g_assert_true (vec4 == graphene_vec4_w_axis ()); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 1.f); } static void vectors_vec4_init (void) { graphene_vec4_t *vec4 = graphene_vec4_alloc (); const float v[4] = { 1.f, 2.f, 3.f, 4.f }; float v_out[4]; graphene_vec4_init (vec4, 0.5f, 0.5f, 0.5f, 0.5f); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 0.5f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 0.5f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 0.5f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 0.5f); graphene_vec4_init (vec4, 1.0f, 1.0f, 1.0f, 1.0f); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, graphene_vec4_get_y (vec4)); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, graphene_vec4_get_z (vec4)); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, graphene_vec4_get_w (vec4)); graphene_vec4_init_from_vec4 (vec4, graphene_vec4_one ()); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 1.f); graphene_vec4_init_from_vec3 (vec4, graphene_vec3_x_axis (), 0.f); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 0.f); graphene_vec4_init_from_vec2 (vec4, graphene_vec2_y_axis (), 0.f, 0.f); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, 0.f); graphene_vec4_init_from_float (vec4, v); g_assert_cmpfloat (graphene_vec4_get_x (vec4), ==, v[0]); g_assert_cmpfloat (graphene_vec4_get_y (vec4), ==, v[1]); g_assert_cmpfloat (graphene_vec4_get_z (vec4), ==, v[2]); g_assert_cmpfloat (graphene_vec4_get_w (vec4), ==, v[3]); graphene_vec4_to_float (vec4, v_out); g_assert_cmpfloat (v_out[0], ==, v[0]); g_assert_cmpfloat (v_out[1], ==, v[1]); g_assert_cmpfloat (v_out[2], ==, v[2]); g_assert_cmpfloat (v_out[3], ==, v[3]); graphene_vec4_free (vec4); } static void vectors_vec4_ops_add (void) { graphene_vec4_t a, b, res; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); graphene_vec4_init (&b, 3.f, 4.f, 5.f, 6.f); graphene_vec4_add (&a, &b, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, 4.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, 6.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, 8.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, 10.f); } static void vectors_vec4_ops_sub (void) { graphene_vec4_t a, b, res; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); graphene_vec4_init (&b, 3.f, 4.f, 5.f, 6.f); graphene_vec4_subtract (&a, &b, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, -2.f); } static void vectors_vec4_ops_mul (void) { graphene_vec4_t a, b, res; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); graphene_vec4_init (&b, 3.f, 4.f, 5.f, 6.f); graphene_vec4_multiply (&a, &b, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, 3.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, 8.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, 15.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, 24.f); } static void vectors_vec4_ops_div (void) { graphene_vec4_t a, b, res; graphene_vec4_init (&a, 6.f, 4.f, 2.f, 12.f); graphene_vec4_init (&b, 3.f, 2.f, 1.f, 6.f); graphene_vec4_divide (&a, &b, &res); graphene_assert_fuzzy_equals (graphene_vec4_get_x (&res), 2.f, 0.0001); graphene_assert_fuzzy_equals (graphene_vec4_get_y (&res), 2.f, 0.0001); graphene_assert_fuzzy_equals (graphene_vec4_get_z (&res), 2.f, 0.0001); graphene_assert_fuzzy_equals (graphene_vec4_get_w (&res), 2.f, 0.0001); } static void vectors_vec4_ops_dot (void) { graphene_vec4_t a, b; float dot, check; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); graphene_vec4_init (&b, 2.f, 3.f, 4.f, 5.f); dot = graphene_vec4_dot (&a, &b); check = 1.f * 2.f + 2.f * 3.f + 3.f * 4.f + 4.f * 5.f; graphene_assert_fuzzy_equals (dot, check, 0.0001f); } static void vectors_vec4_ops_scale (void) { graphene_vec4_t a, res; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); graphene_vec4_scale (&a, 2.f, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, 2.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, 4.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, 6.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, 8.f); } static void vectors_vec4_ops_negate (void) { graphene_vec4_t a, res; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); graphene_vec4_negate (&a, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, -1.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, -2.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, -3.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, -4.f); } static void vectors_vec4_length (void) { graphene_vec4_t a; float len, check; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); len = graphene_vec4_length (&a); check = sqrtf ((1.f * 1.f) + (2.f * 2.f) + (3.f * 3.f) + (4.f * 4.f)); graphene_assert_fuzzy_equals (len, check, 0.0001f); } static void vectors_vec4_normalize (void) { graphene_vec4_t a, b, c; float inv_len; graphene_vec4_init (&a, 1.f, 2.f, 3.f, 4.f); inv_len = 1.f / graphene_vec4_length (&a); graphene_vec4_normalize (&a, &b); graphene_vec4_scale (&a, inv_len, &c); graphene_assert_fuzzy_vec4_equal (&b, &c, 0.0001f); } static void vectors_vec4_compare (void) { const graphene_vec4_t *zero = graphene_vec4_zero (); const graphene_vec4_t *one = graphene_vec4_one (); graphene_vec4_t a, b; graphene_vec4_t res; graphene_vec4_min (zero, one, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, 0.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, 0.f); graphene_vec4_max (zero, one, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, 1.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, 1.f); graphene_vec4_init (&a, 5.f, 10.f, 8.f, -1.f); graphene_vec4_init (&b, 2.f, 12.f, 8.f, 1.f); graphene_vec4_min (&a, &b, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, 2.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, 10.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, 8.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, -1.f); graphene_vec4_max (&a, &b, &res); g_assert_cmpfloat (graphene_vec4_get_x (&res), ==, 5.f); g_assert_cmpfloat (graphene_vec4_get_y (&res), ==, 12.f); g_assert_cmpfloat (graphene_vec4_get_z (&res), ==, 8.f); g_assert_cmpfloat (graphene_vec4_get_w (&res), ==, 1.f); } static void vectors_vec4_conversion (void) { graphene_vec4_t v; graphene_vec4_init (&v, 1.f, 2.f, 3.f, 4.f); { graphene_vec2_t xy; graphene_vec4_get_xy (&v, &xy); g_assert_cmpfloat (graphene_vec2_get_x (&xy), ==, 1.f); g_assert_cmpfloat (graphene_vec2_get_y (&xy), ==, 2.f); } { graphene_vec3_t xyz; graphene_vec4_get_xyz (&v, &xyz); g_assert_cmpfloat (graphene_vec3_get_x (&xyz), ==, graphene_vec4_get_x (&v)); g_assert_cmpfloat (graphene_vec3_get_y (&xyz), ==, graphene_vec4_get_y (&v)); g_assert_cmpfloat (graphene_vec3_get_z (&xyz), ==, graphene_vec4_get_z (&v)); } } static void vectors_vec4_equal (void) { const graphene_vec4_t *zero = graphene_vec4_zero (); const graphene_vec4_t *one = graphene_vec4_one (); graphene_vec4_t a, b; graphene_vec4_init (&a, 0.f, 0.f, 0.f, 0.f); graphene_vec4_init (&b, 1.f, 1.f, 1.f, 1.f); g_assert_true (graphene_vec4_equal (zero, zero)); g_assert_true (graphene_vec4_equal (one, one)); g_assert_true (graphene_vec4_equal (zero, &a)); g_assert_true (graphene_vec4_equal (one, &b)); g_assert_false (graphene_vec4_equal (zero, one)); g_assert_false (graphene_vec4_equal (one, zero)); g_assert_false (graphene_vec4_equal (&a, &b)); g_assert_true (graphene_vec4_equal (NULL, NULL)); g_assert_false (graphene_vec4_equal (graphene_vec4_one (), NULL)); g_assert_false (graphene_vec4_equal (NULL, graphene_vec4_one ())); } int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/vectors/vec4/const", vectors_vec4_const); g_test_add_func ("/vectors/vec4/init", vectors_vec4_init); g_test_add_func ("/vectors/vec4/operations/add", vectors_vec4_ops_add); g_test_add_func ("/vectors/vec4/operations/sub", vectors_vec4_ops_sub); g_test_add_func ("/vectors/vec4/operations/mul", vectors_vec4_ops_mul); g_test_add_func ("/vectors/vec4/operations/div", vectors_vec4_ops_div); g_test_add_func ("/vectors/vec4/operations/dot", vectors_vec4_ops_dot); g_test_add_func ("/vectors/vec4/operations/scale", vectors_vec4_ops_scale); g_test_add_func ("/vectors/vec4/operations/negate", vectors_vec4_ops_negate); g_test_add_func ("/vectors/vec4/length", vectors_vec4_length); g_test_add_func ("/vectors/vec4/normalize", vectors_vec4_normalize); g_test_add_func ("/vectors/vec4/compare", vectors_vec4_compare); g_test_add_func ("/vectors/vec4/conversion", vectors_vec4_conversion); g_test_add_func ("/vectors/vec4/equal", vectors_vec4_equal); return g_test_run (); }