gpuray_glsl

changeset 0:f234630e38ff

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 09 Nov 2014 13:03:36 +0200
parents
children 92695e89164b
files .hgignore COPYING Makefile README anim/anim.c anim/anim.h anim/config.h anim/dynarr.c anim/dynarr.h anim/track.c anim/track.h sdr/postsdr.glsl sdr/rt.glsl sdr/vertex.glsl src/box.cc src/box.h src/camera.cc src/camera.h src/glsdr.c src/glsdr.h src/gpuscene.cc src/gpuscene.h src/image.cc src/image.h src/light.cc src/light.h src/main.cc src/material.cc src/material.h src/object.cc src/object.h src/opengl.h src/plane.cc src/plane.h src/rend.cc src/rend.h src/scene.cc src/scene.h src/scene_load.cc src/sphere.cc src/sphere.h src/texture.cc src/texture.h src/xform_node.cc src/xform_node.h util/anim.c vmath/matrix.cc vmath/matrix.h vmath/matrix.inl vmath/matrix_c.c vmath/quat.cc vmath/quat.h vmath/quat.inl vmath/quat_c.c vmath/ray.cc vmath/ray.h vmath/ray.inl vmath/ray_c.c vmath/vector.cc vmath/vector.h vmath/vector.inl vmath/vmath.h vmath/vmath.inl vmath/vmath_config.h vmath/vmath_types.h
diffstat 65 files changed, 10437 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sun Nov 09 13:03:36 2014 +0200
     1.3 @@ -0,0 +1,6 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +\.jpg$
     1.8 +\.png$
     1.9 +\.cubemap$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/COPYING	Sun Nov 09 13:03:36 2014 +0200
     2.3 @@ -0,0 +1,674 @@
     2.4 +                    GNU GENERAL PUBLIC LICENSE
     2.5 +                       Version 3, 29 June 2007
     2.6 +
     2.7 + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
     2.8 + Everyone is permitted to copy and distribute verbatim copies
     2.9 + of this license document, but changing it is not allowed.
    2.10 +
    2.11 +                            Preamble
    2.12 +
    2.13 +  The GNU General Public License is a free, copyleft license for
    2.14 +software and other kinds of works.
    2.15 +
    2.16 +  The licenses for most software and other practical works are designed
    2.17 +to take away your freedom to share and change the works.  By contrast,
    2.18 +the GNU General Public License is intended to guarantee your freedom to
    2.19 +share and change all versions of a program--to make sure it remains free
    2.20 +software for all its users.  We, the Free Software Foundation, use the
    2.21 +GNU General Public License for most of our software; it applies also to
    2.22 +any other work released this way by its authors.  You can apply it to
    2.23 +your programs, too.
    2.24 +
    2.25 +  When we speak of free software, we are referring to freedom, not
    2.26 +price.  Our General Public Licenses are designed to make sure that you
    2.27 +have the freedom to distribute copies of free software (and charge for
    2.28 +them if you wish), that you receive source code or can get it if you
    2.29 +want it, that you can change the software or use pieces of it in new
    2.30 +free programs, and that you know you can do these things.
    2.31 +
    2.32 +  To protect your rights, we need to prevent others from denying you
    2.33 +these rights or asking you to surrender the rights.  Therefore, you have
    2.34 +certain responsibilities if you distribute copies of the software, or if
    2.35 +you modify it: responsibilities to respect the freedom of others.
    2.36 +
    2.37 +  For example, if you distribute copies of such a program, whether
    2.38 +gratis or for a fee, you must pass on to the recipients the same
    2.39 +freedoms that you received.  You must make sure that they, too, receive
    2.40 +or can get the source code.  And you must show them these terms so they
    2.41 +know their rights.
    2.42 +
    2.43 +  Developers that use the GNU GPL protect your rights with two steps:
    2.44 +(1) assert copyright on the software, and (2) offer you this License
    2.45 +giving you legal permission to copy, distribute and/or modify it.
    2.46 +
    2.47 +  For the developers' and authors' protection, the GPL clearly explains
    2.48 +that there is no warranty for this free software.  For both users' and
    2.49 +authors' sake, the GPL requires that modified versions be marked as
    2.50 +changed, so that their problems will not be attributed erroneously to
    2.51 +authors of previous versions.
    2.52 +
    2.53 +  Some devices are designed to deny users access to install or run
    2.54 +modified versions of the software inside them, although the manufacturer
    2.55 +can do so.  This is fundamentally incompatible with the aim of
    2.56 +protecting users' freedom to change the software.  The systematic
    2.57 +pattern of such abuse occurs in the area of products for individuals to
    2.58 +use, which is precisely where it is most unacceptable.  Therefore, we
    2.59 +have designed this version of the GPL to prohibit the practice for those
    2.60 +products.  If such problems arise substantially in other domains, we
    2.61 +stand ready to extend this provision to those domains in future versions
    2.62 +of the GPL, as needed to protect the freedom of users.
    2.63 +
    2.64 +  Finally, every program is threatened constantly by software patents.
    2.65 +States should not allow patents to restrict development and use of
    2.66 +software on general-purpose computers, but in those that do, we wish to
    2.67 +avoid the special danger that patents applied to a free program could
    2.68 +make it effectively proprietary.  To prevent this, the GPL assures that
    2.69 +patents cannot be used to render the program non-free.
    2.70 +
    2.71 +  The precise terms and conditions for copying, distribution and
    2.72 +modification follow.
    2.73 +
    2.74 +                       TERMS AND CONDITIONS
    2.75 +
    2.76 +  0. Definitions.
    2.77 +
    2.78 +  "This License" refers to version 3 of the GNU General Public License.
    2.79 +
    2.80 +  "Copyright" also means copyright-like laws that apply to other kinds of
    2.81 +works, such as semiconductor masks.
    2.82 +
    2.83 +  "The Program" refers to any copyrightable work licensed under this
    2.84 +License.  Each licensee is addressed as "you".  "Licensees" and
    2.85 +"recipients" may be individuals or organizations.
    2.86 +
    2.87 +  To "modify" a work means to copy from or adapt all or part of the work
    2.88 +in a fashion requiring copyright permission, other than the making of an
    2.89 +exact copy.  The resulting work is called a "modified version" of the
    2.90 +earlier work or a work "based on" the earlier work.
    2.91 +
    2.92 +  A "covered work" means either the unmodified Program or a work based
    2.93 +on the Program.
    2.94 +
    2.95 +  To "propagate" a work means to do anything with it that, without
    2.96 +permission, would make you directly or secondarily liable for
    2.97 +infringement under applicable copyright law, except executing it on a
    2.98 +computer or modifying a private copy.  Propagation includes copying,
    2.99 +distribution (with or without modification), making available to the
   2.100 +public, and in some countries other activities as well.
   2.101 +
   2.102 +  To "convey" a work means any kind of propagation that enables other
   2.103 +parties to make or receive copies.  Mere interaction with a user through
   2.104 +a computer network, with no transfer of a copy, is not conveying.
   2.105 +
   2.106 +  An interactive user interface displays "Appropriate Legal Notices"
   2.107 +to the extent that it includes a convenient and prominently visible
   2.108 +feature that (1) displays an appropriate copyright notice, and (2)
   2.109 +tells the user that there is no warranty for the work (except to the
   2.110 +extent that warranties are provided), that licensees may convey the
   2.111 +work under this License, and how to view a copy of this License.  If
   2.112 +the interface presents a list of user commands or options, such as a
   2.113 +menu, a prominent item in the list meets this criterion.
   2.114 +
   2.115 +  1. Source Code.
   2.116 +
   2.117 +  The "source code" for a work means the preferred form of the work
   2.118 +for making modifications to it.  "Object code" means any non-source
   2.119 +form of a work.
   2.120 +
   2.121 +  A "Standard Interface" means an interface that either is an official
   2.122 +standard defined by a recognized standards body, or, in the case of
   2.123 +interfaces specified for a particular programming language, one that
   2.124 +is widely used among developers working in that language.
   2.125 +
   2.126 +  The "System Libraries" of an executable work include anything, other
   2.127 +than the work as a whole, that (a) is included in the normal form of
   2.128 +packaging a Major Component, but which is not part of that Major
   2.129 +Component, and (b) serves only to enable use of the work with that
   2.130 +Major Component, or to implement a Standard Interface for which an
   2.131 +implementation is available to the public in source code form.  A
   2.132 +"Major Component", in this context, means a major essential component
   2.133 +(kernel, window system, and so on) of the specific operating system
   2.134 +(if any) on which the executable work runs, or a compiler used to
   2.135 +produce the work, or an object code interpreter used to run it.
   2.136 +
   2.137 +  The "Corresponding Source" for a work in object code form means all
   2.138 +the source code needed to generate, install, and (for an executable
   2.139 +work) run the object code and to modify the work, including scripts to
   2.140 +control those activities.  However, it does not include the work's
   2.141 +System Libraries, or general-purpose tools or generally available free
   2.142 +programs which are used unmodified in performing those activities but
   2.143 +which are not part of the work.  For example, Corresponding Source
   2.144 +includes interface definition files associated with source files for
   2.145 +the work, and the source code for shared libraries and dynamically
   2.146 +linked subprograms that the work is specifically designed to require,
   2.147 +such as by intimate data communication or control flow between those
   2.148 +subprograms and other parts of the work.
   2.149 +
   2.150 +  The Corresponding Source need not include anything that users
   2.151 +can regenerate automatically from other parts of the Corresponding
   2.152 +Source.
   2.153 +
   2.154 +  The Corresponding Source for a work in source code form is that
   2.155 +same work.
   2.156 +
   2.157 +  2. Basic Permissions.
   2.158 +
   2.159 +  All rights granted under this License are granted for the term of
   2.160 +copyright on the Program, and are irrevocable provided the stated
   2.161 +conditions are met.  This License explicitly affirms your unlimited
   2.162 +permission to run the unmodified Program.  The output from running a
   2.163 +covered work is covered by this License only if the output, given its
   2.164 +content, constitutes a covered work.  This License acknowledges your
   2.165 +rights of fair use or other equivalent, as provided by copyright law.
   2.166 +
   2.167 +  You may make, run and propagate covered works that you do not
   2.168 +convey, without conditions so long as your license otherwise remains
   2.169 +in force.  You may convey covered works to others for the sole purpose
   2.170 +of having them make modifications exclusively for you, or provide you
   2.171 +with facilities for running those works, provided that you comply with
   2.172 +the terms of this License in conveying all material for which you do
   2.173 +not control copyright.  Those thus making or running the covered works
   2.174 +for you must do so exclusively on your behalf, under your direction
   2.175 +and control, on terms that prohibit them from making any copies of
   2.176 +your copyrighted material outside their relationship with you.
   2.177 +
   2.178 +  Conveying under any other circumstances is permitted solely under
   2.179 +the conditions stated below.  Sublicensing is not allowed; section 10
   2.180 +makes it unnecessary.
   2.181 +
   2.182 +  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
   2.183 +
   2.184 +  No covered work shall be deemed part of an effective technological
   2.185 +measure under any applicable law fulfilling obligations under article
   2.186 +11 of the WIPO copyright treaty adopted on 20 December 1996, or
   2.187 +similar laws prohibiting or restricting circumvention of such
   2.188 +measures.
   2.189 +
   2.190 +  When you convey a covered work, you waive any legal power to forbid
   2.191 +circumvention of technological measures to the extent such circumvention
   2.192 +is effected by exercising rights under this License with respect to
   2.193 +the covered work, and you disclaim any intention to limit operation or
   2.194 +modification of the work as a means of enforcing, against the work's
   2.195 +users, your or third parties' legal rights to forbid circumvention of
   2.196 +technological measures.
   2.197 +
   2.198 +  4. Conveying Verbatim Copies.
   2.199 +
   2.200 +  You may convey verbatim copies of the Program's source code as you
   2.201 +receive it, in any medium, provided that you conspicuously and
   2.202 +appropriately publish on each copy an appropriate copyright notice;
   2.203 +keep intact all notices stating that this License and any
   2.204 +non-permissive terms added in accord with section 7 apply to the code;
   2.205 +keep intact all notices of the absence of any warranty; and give all
   2.206 +recipients a copy of this License along with the Program.
   2.207 +
   2.208 +  You may charge any price or no price for each copy that you convey,
   2.209 +and you may offer support or warranty protection for a fee.
   2.210 +
   2.211 +  5. Conveying Modified Source Versions.
   2.212 +
   2.213 +  You may convey a work based on the Program, or the modifications to
   2.214 +produce it from the Program, in the form of source code under the
   2.215 +terms of section 4, provided that you also meet all of these conditions:
   2.216 +
   2.217 +    a) The work must carry prominent notices stating that you modified
   2.218 +    it, and giving a relevant date.
   2.219 +
   2.220 +    b) The work must carry prominent notices stating that it is
   2.221 +    released under this License and any conditions added under section
   2.222 +    7.  This requirement modifies the requirement in section 4 to
   2.223 +    "keep intact all notices".
   2.224 +
   2.225 +    c) You must license the entire work, as a whole, under this
   2.226 +    License to anyone who comes into possession of a copy.  This
   2.227 +    License will therefore apply, along with any applicable section 7
   2.228 +    additional terms, to the whole of the work, and all its parts,
   2.229 +    regardless of how they are packaged.  This License gives no
   2.230 +    permission to license the work in any other way, but it does not
   2.231 +    invalidate such permission if you have separately received it.
   2.232 +
   2.233 +    d) If the work has interactive user interfaces, each must display
   2.234 +    Appropriate Legal Notices; however, if the Program has interactive
   2.235 +    interfaces that do not display Appropriate Legal Notices, your
   2.236 +    work need not make them do so.
   2.237 +
   2.238 +  A compilation of a covered work with other separate and independent
   2.239 +works, which are not by their nature extensions of the covered work,
   2.240 +and which are not combined with it such as to form a larger program,
   2.241 +in or on a volume of a storage or distribution medium, is called an
   2.242 +"aggregate" if the compilation and its resulting copyright are not
   2.243 +used to limit the access or legal rights of the compilation's users
   2.244 +beyond what the individual works permit.  Inclusion of a covered work
   2.245 +in an aggregate does not cause this License to apply to the other
   2.246 +parts of the aggregate.
   2.247 +
   2.248 +  6. Conveying Non-Source Forms.
   2.249 +
   2.250 +  You may convey a covered work in object code form under the terms
   2.251 +of sections 4 and 5, provided that you also convey the
   2.252 +machine-readable Corresponding Source under the terms of this License,
   2.253 +in one of these ways:
   2.254 +
   2.255 +    a) Convey the object code in, or embodied in, a physical product
   2.256 +    (including a physical distribution medium), accompanied by the
   2.257 +    Corresponding Source fixed on a durable physical medium
   2.258 +    customarily used for software interchange.
   2.259 +
   2.260 +    b) Convey the object code in, or embodied in, a physical product
   2.261 +    (including a physical distribution medium), accompanied by a
   2.262 +    written offer, valid for at least three years and valid for as
   2.263 +    long as you offer spare parts or customer support for that product
   2.264 +    model, to give anyone who possesses the object code either (1) a
   2.265 +    copy of the Corresponding Source for all the software in the
   2.266 +    product that is covered by this License, on a durable physical
   2.267 +    medium customarily used for software interchange, for a price no
   2.268 +    more than your reasonable cost of physically performing this
   2.269 +    conveying of source, or (2) access to copy the
   2.270 +    Corresponding Source from a network server at no charge.
   2.271 +
   2.272 +    c) Convey individual copies of the object code with a copy of the
   2.273 +    written offer to provide the Corresponding Source.  This
   2.274 +    alternative is allowed only occasionally and noncommercially, and
   2.275 +    only if you received the object code with such an offer, in accord
   2.276 +    with subsection 6b.
   2.277 +
   2.278 +    d) Convey the object code by offering access from a designated
   2.279 +    place (gratis or for a charge), and offer equivalent access to the
   2.280 +    Corresponding Source in the same way through the same place at no
   2.281 +    further charge.  You need not require recipients to copy the
   2.282 +    Corresponding Source along with the object code.  If the place to
   2.283 +    copy the object code is a network server, the Corresponding Source
   2.284 +    may be on a different server (operated by you or a third party)
   2.285 +    that supports equivalent copying facilities, provided you maintain
   2.286 +    clear directions next to the object code saying where to find the
   2.287 +    Corresponding Source.  Regardless of what server hosts the
   2.288 +    Corresponding Source, you remain obligated to ensure that it is
   2.289 +    available for as long as needed to satisfy these requirements.
   2.290 +
   2.291 +    e) Convey the object code using peer-to-peer transmission, provided
   2.292 +    you inform other peers where the object code and Corresponding
   2.293 +    Source of the work are being offered to the general public at no
   2.294 +    charge under subsection 6d.
   2.295 +
   2.296 +  A separable portion of the object code, whose source code is excluded
   2.297 +from the Corresponding Source as a System Library, need not be
   2.298 +included in conveying the object code work.
   2.299 +
   2.300 +  A "User Product" is either (1) a "consumer product", which means any
   2.301 +tangible personal property which is normally used for personal, family,
   2.302 +or household purposes, or (2) anything designed or sold for incorporation
   2.303 +into a dwelling.  In determining whether a product is a consumer product,
   2.304 +doubtful cases shall be resolved in favor of coverage.  For a particular
   2.305 +product received by a particular user, "normally used" refers to a
   2.306 +typical or common use of that class of product, regardless of the status
   2.307 +of the particular user or of the way in which the particular user
   2.308 +actually uses, or expects or is expected to use, the product.  A product
   2.309 +is a consumer product regardless of whether the product has substantial
   2.310 +commercial, industrial or non-consumer uses, unless such uses represent
   2.311 +the only significant mode of use of the product.
   2.312 +
   2.313 +  "Installation Information" for a User Product means any methods,
   2.314 +procedures, authorization keys, or other information required to install
   2.315 +and execute modified versions of a covered work in that User Product from
   2.316 +a modified version of its Corresponding Source.  The information must
   2.317 +suffice to ensure that the continued functioning of the modified object
   2.318 +code is in no case prevented or interfered with solely because
   2.319 +modification has been made.
   2.320 +
   2.321 +  If you convey an object code work under this section in, or with, or
   2.322 +specifically for use in, a User Product, and the conveying occurs as
   2.323 +part of a transaction in which the right of possession and use of the
   2.324 +User Product is transferred to the recipient in perpetuity or for a
   2.325 +fixed term (regardless of how the transaction is characterized), the
   2.326 +Corresponding Source conveyed under this section must be accompanied
   2.327 +by the Installation Information.  But this requirement does not apply
   2.328 +if neither you nor any third party retains the ability to install
   2.329 +modified object code on the User Product (for example, the work has
   2.330 +been installed in ROM).
   2.331 +
   2.332 +  The requirement to provide Installation Information does not include a
   2.333 +requirement to continue to provide support service, warranty, or updates
   2.334 +for a work that has been modified or installed by the recipient, or for
   2.335 +the User Product in which it has been modified or installed.  Access to a
   2.336 +network may be denied when the modification itself materially and
   2.337 +adversely affects the operation of the network or violates the rules and
   2.338 +protocols for communication across the network.
   2.339 +
   2.340 +  Corresponding Source conveyed, and Installation Information provided,
   2.341 +in accord with this section must be in a format that is publicly
   2.342 +documented (and with an implementation available to the public in
   2.343 +source code form), and must require no special password or key for
   2.344 +unpacking, reading or copying.
   2.345 +
   2.346 +  7. Additional Terms.
   2.347 +
   2.348 +  "Additional permissions" are terms that supplement the terms of this
   2.349 +License by making exceptions from one or more of its conditions.
   2.350 +Additional permissions that are applicable to the entire Program shall
   2.351 +be treated as though they were included in this License, to the extent
   2.352 +that they are valid under applicable law.  If additional permissions
   2.353 +apply only to part of the Program, that part may be used separately
   2.354 +under those permissions, but the entire Program remains governed by
   2.355 +this License without regard to the additional permissions.
   2.356 +
   2.357 +  When you convey a copy of a covered work, you may at your option
   2.358 +remove any additional permissions from that copy, or from any part of
   2.359 +it.  (Additional permissions may be written to require their own
   2.360 +removal in certain cases when you modify the work.)  You may place
   2.361 +additional permissions on material, added by you to a covered work,
   2.362 +for which you have or can give appropriate copyright permission.
   2.363 +
   2.364 +  Notwithstanding any other provision of this License, for material you
   2.365 +add to a covered work, you may (if authorized by the copyright holders of
   2.366 +that material) supplement the terms of this License with terms:
   2.367 +
   2.368 +    a) Disclaiming warranty or limiting liability differently from the
   2.369 +    terms of sections 15 and 16 of this License; or
   2.370 +
   2.371 +    b) Requiring preservation of specified reasonable legal notices or
   2.372 +    author attributions in that material or in the Appropriate Legal
   2.373 +    Notices displayed by works containing it; or
   2.374 +
   2.375 +    c) Prohibiting misrepresentation of the origin of that material, or
   2.376 +    requiring that modified versions of such material be marked in
   2.377 +    reasonable ways as different from the original version; or
   2.378 +
   2.379 +    d) Limiting the use for publicity purposes of names of licensors or
   2.380 +    authors of the material; or
   2.381 +
   2.382 +    e) Declining to grant rights under trademark law for use of some
   2.383 +    trade names, trademarks, or service marks; or
   2.384 +
   2.385 +    f) Requiring indemnification of licensors and authors of that
   2.386 +    material by anyone who conveys the material (or modified versions of
   2.387 +    it) with contractual assumptions of liability to the recipient, for
   2.388 +    any liability that these contractual assumptions directly impose on
   2.389 +    those licensors and authors.
   2.390 +
   2.391 +  All other non-permissive additional terms are considered "further
   2.392 +restrictions" within the meaning of section 10.  If the Program as you
   2.393 +received it, or any part of it, contains a notice stating that it is
   2.394 +governed by this License along with a term that is a further
   2.395 +restriction, you may remove that term.  If a license document contains
   2.396 +a further restriction but permits relicensing or conveying under this
   2.397 +License, you may add to a covered work material governed by the terms
   2.398 +of that license document, provided that the further restriction does
   2.399 +not survive such relicensing or conveying.
   2.400 +
   2.401 +  If you add terms to a covered work in accord with this section, you
   2.402 +must place, in the relevant source files, a statement of the
   2.403 +additional terms that apply to those files, or a notice indicating
   2.404 +where to find the applicable terms.
   2.405 +
   2.406 +  Additional terms, permissive or non-permissive, may be stated in the
   2.407 +form of a separately written license, or stated as exceptions;
   2.408 +the above requirements apply either way.
   2.409 +
   2.410 +  8. Termination.
   2.411 +
   2.412 +  You may not propagate or modify a covered work except as expressly
   2.413 +provided under this License.  Any attempt otherwise to propagate or
   2.414 +modify it is void, and will automatically terminate your rights under
   2.415 +this License (including any patent licenses granted under the third
   2.416 +paragraph of section 11).
   2.417 +
   2.418 +  However, if you cease all violation of this License, then your
   2.419 +license from a particular copyright holder is reinstated (a)
   2.420 +provisionally, unless and until the copyright holder explicitly and
   2.421 +finally terminates your license, and (b) permanently, if the copyright
   2.422 +holder fails to notify you of the violation by some reasonable means
   2.423 +prior to 60 days after the cessation.
   2.424 +
   2.425 +  Moreover, your license from a particular copyright holder is
   2.426 +reinstated permanently if the copyright holder notifies you of the
   2.427 +violation by some reasonable means, this is the first time you have
   2.428 +received notice of violation of this License (for any work) from that
   2.429 +copyright holder, and you cure the violation prior to 30 days after
   2.430 +your receipt of the notice.
   2.431 +
   2.432 +  Termination of your rights under this section does not terminate the
   2.433 +licenses of parties who have received copies or rights from you under
   2.434 +this License.  If your rights have been terminated and not permanently
   2.435 +reinstated, you do not qualify to receive new licenses for the same
   2.436 +material under section 10.
   2.437 +
   2.438 +  9. Acceptance Not Required for Having Copies.
   2.439 +
   2.440 +  You are not required to accept this License in order to receive or
   2.441 +run a copy of the Program.  Ancillary propagation of a covered work
   2.442 +occurring solely as a consequence of using peer-to-peer transmission
   2.443 +to receive a copy likewise does not require acceptance.  However,
   2.444 +nothing other than this License grants you permission to propagate or
   2.445 +modify any covered work.  These actions infringe copyright if you do
   2.446 +not accept this License.  Therefore, by modifying or propagating a
   2.447 +covered work, you indicate your acceptance of this License to do so.
   2.448 +
   2.449 +  10. Automatic Licensing of Downstream Recipients.
   2.450 +
   2.451 +  Each time you convey a covered work, the recipient automatically
   2.452 +receives a license from the original licensors, to run, modify and
   2.453 +propagate that work, subject to this License.  You are not responsible
   2.454 +for enforcing compliance by third parties with this License.
   2.455 +
   2.456 +  An "entity transaction" is a transaction transferring control of an
   2.457 +organization, or substantially all assets of one, or subdividing an
   2.458 +organization, or merging organizations.  If propagation of a covered
   2.459 +work results from an entity transaction, each party to that
   2.460 +transaction who receives a copy of the work also receives whatever
   2.461 +licenses to the work the party's predecessor in interest had or could
   2.462 +give under the previous paragraph, plus a right to possession of the
   2.463 +Corresponding Source of the work from the predecessor in interest, if
   2.464 +the predecessor has it or can get it with reasonable efforts.
   2.465 +
   2.466 +  You may not impose any further restrictions on the exercise of the
   2.467 +rights granted or affirmed under this License.  For example, you may
   2.468 +not impose a license fee, royalty, or other charge for exercise of
   2.469 +rights granted under this License, and you may not initiate litigation
   2.470 +(including a cross-claim or counterclaim in a lawsuit) alleging that
   2.471 +any patent claim is infringed by making, using, selling, offering for
   2.472 +sale, or importing the Program or any portion of it.
   2.473 +
   2.474 +  11. Patents.
   2.475 +
   2.476 +  A "contributor" is a copyright holder who authorizes use under this
   2.477 +License of the Program or a work on which the Program is based.  The
   2.478 +work thus licensed is called the contributor's "contributor version".
   2.479 +
   2.480 +  A contributor's "essential patent claims" are all patent claims
   2.481 +owned or controlled by the contributor, whether already acquired or
   2.482 +hereafter acquired, that would be infringed by some manner, permitted
   2.483 +by this License, of making, using, or selling its contributor version,
   2.484 +but do not include claims that would be infringed only as a
   2.485 +consequence of further modification of the contributor version.  For
   2.486 +purposes of this definition, "control" includes the right to grant
   2.487 +patent sublicenses in a manner consistent with the requirements of
   2.488 +this License.
   2.489 +
   2.490 +  Each contributor grants you a non-exclusive, worldwide, royalty-free
   2.491 +patent license under the contributor's essential patent claims, to
   2.492 +make, use, sell, offer for sale, import and otherwise run, modify and
   2.493 +propagate the contents of its contributor version.
   2.494 +
   2.495 +  In the following three paragraphs, a "patent license" is any express
   2.496 +agreement or commitment, however denominated, not to enforce a patent
   2.497 +(such as an express permission to practice a patent or covenant not to
   2.498 +sue for patent infringement).  To "grant" such a patent license to a
   2.499 +party means to make such an agreement or commitment not to enforce a
   2.500 +patent against the party.
   2.501 +
   2.502 +  If you convey a covered work, knowingly relying on a patent license,
   2.503 +and the Corresponding Source of the work is not available for anyone
   2.504 +to copy, free of charge and under the terms of this License, through a
   2.505 +publicly available network server or other readily accessible means,
   2.506 +then you must either (1) cause the Corresponding Source to be so
   2.507 +available, or (2) arrange to deprive yourself of the benefit of the
   2.508 +patent license for this particular work, or (3) arrange, in a manner
   2.509 +consistent with the requirements of this License, to extend the patent
   2.510 +license to downstream recipients.  "Knowingly relying" means you have
   2.511 +actual knowledge that, but for the patent license, your conveying the
   2.512 +covered work in a country, or your recipient's use of the covered work
   2.513 +in a country, would infringe one or more identifiable patents in that
   2.514 +country that you have reason to believe are valid.
   2.515 +
   2.516 +  If, pursuant to or in connection with a single transaction or
   2.517 +arrangement, you convey, or propagate by procuring conveyance of, a
   2.518 +covered work, and grant a patent license to some of the parties
   2.519 +receiving the covered work authorizing them to use, propagate, modify
   2.520 +or convey a specific copy of the covered work, then the patent license
   2.521 +you grant is automatically extended to all recipients of the covered
   2.522 +work and works based on it.
   2.523 +
   2.524 +  A patent license is "discriminatory" if it does not include within
   2.525 +the scope of its coverage, prohibits the exercise of, or is
   2.526 +conditioned on the non-exercise of one or more of the rights that are
   2.527 +specifically granted under this License.  You may not convey a covered
   2.528 +work if you are a party to an arrangement with a third party that is
   2.529 +in the business of distributing software, under which you make payment
   2.530 +to the third party based on the extent of your activity of conveying
   2.531 +the work, and under which the third party grants, to any of the
   2.532 +parties who would receive the covered work from you, a discriminatory
   2.533 +patent license (a) in connection with copies of the covered work
   2.534 +conveyed by you (or copies made from those copies), or (b) primarily
   2.535 +for and in connection with specific products or compilations that
   2.536 +contain the covered work, unless you entered into that arrangement,
   2.537 +or that patent license was granted, prior to 28 March 2007.
   2.538 +
   2.539 +  Nothing in this License shall be construed as excluding or limiting
   2.540 +any implied license or other defenses to infringement that may
   2.541 +otherwise be available to you under applicable patent law.
   2.542 +
   2.543 +  12. No Surrender of Others' Freedom.
   2.544 +
   2.545 +  If conditions are imposed on you (whether by court order, agreement or
   2.546 +otherwise) that contradict the conditions of this License, they do not
   2.547 +excuse you from the conditions of this License.  If you cannot convey a
   2.548 +covered work so as to satisfy simultaneously your obligations under this
   2.549 +License and any other pertinent obligations, then as a consequence you may
   2.550 +not convey it at all.  For example, if you agree to terms that obligate you
   2.551 +to collect a royalty for further conveying from those to whom you convey
   2.552 +the Program, the only way you could satisfy both those terms and this
   2.553 +License would be to refrain entirely from conveying the Program.
   2.554 +
   2.555 +  13. Use with the GNU Affero General Public License.
   2.556 +
   2.557 +  Notwithstanding any other provision of this License, you have
   2.558 +permission to link or combine any covered work with a work licensed
   2.559 +under version 3 of the GNU Affero General Public License into a single
   2.560 +combined work, and to convey the resulting work.  The terms of this
   2.561 +License will continue to apply to the part which is the covered work,
   2.562 +but the special requirements of the GNU Affero General Public License,
   2.563 +section 13, concerning interaction through a network will apply to the
   2.564 +combination as such.
   2.565 +
   2.566 +  14. Revised Versions of this License.
   2.567 +
   2.568 +  The Free Software Foundation may publish revised and/or new versions of
   2.569 +the GNU General Public License from time to time.  Such new versions will
   2.570 +be similar in spirit to the present version, but may differ in detail to
   2.571 +address new problems or concerns.
   2.572 +
   2.573 +  Each version is given a distinguishing version number.  If the
   2.574 +Program specifies that a certain numbered version of the GNU General
   2.575 +Public License "or any later version" applies to it, you have the
   2.576 +option of following the terms and conditions either of that numbered
   2.577 +version or of any later version published by the Free Software
   2.578 +Foundation.  If the Program does not specify a version number of the
   2.579 +GNU General Public License, you may choose any version ever published
   2.580 +by the Free Software Foundation.
   2.581 +
   2.582 +  If the Program specifies that a proxy can decide which future
   2.583 +versions of the GNU General Public License can be used, that proxy's
   2.584 +public statement of acceptance of a version permanently authorizes you
   2.585 +to choose that version for the Program.
   2.586 +
   2.587 +  Later license versions may give you additional or different
   2.588 +permissions.  However, no additional obligations are imposed on any
   2.589 +author or copyright holder as a result of your choosing to follow a
   2.590 +later version.
   2.591 +
   2.592 +  15. Disclaimer of Warranty.
   2.593 +
   2.594 +  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
   2.595 +APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
   2.596 +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
   2.597 +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
   2.598 +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   2.599 +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
   2.600 +IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
   2.601 +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
   2.602 +
   2.603 +  16. Limitation of Liability.
   2.604 +
   2.605 +  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
   2.606 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
   2.607 +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
   2.608 +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
   2.609 +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
   2.610 +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
   2.611 +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
   2.612 +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
   2.613 +SUCH DAMAGES.
   2.614 +
   2.615 +  17. Interpretation of Sections 15 and 16.
   2.616 +
   2.617 +  If the disclaimer of warranty and limitation of liability provided
   2.618 +above cannot be given local legal effect according to their terms,
   2.619 +reviewing courts shall apply local law that most closely approximates
   2.620 +an absolute waiver of all civil liability in connection with the
   2.621 +Program, unless a warranty or assumption of liability accompanies a
   2.622 +copy of the Program in return for a fee.
   2.623 +
   2.624 +                     END OF TERMS AND CONDITIONS
   2.625 +
   2.626 +            How to Apply These Terms to Your New Programs
   2.627 +
   2.628 +  If you develop a new program, and you want it to be of the greatest
   2.629 +possible use to the public, the best way to achieve this is to make it
   2.630 +free software which everyone can redistribute and change under these terms.
   2.631 +
   2.632 +  To do so, attach the following notices to the program.  It is safest
   2.633 +to attach them to the start of each source file to most effectively
   2.634 +state the exclusion of warranty; and each file should have at least
   2.635 +the "copyright" line and a pointer to where the full notice is found.
   2.636 +
   2.637 +    <one line to give the program's name and a brief idea of what it does.>
   2.638 +    Copyright (C) <year>  <name of author>
   2.639 +
   2.640 +    This program is free software: you can redistribute it and/or modify
   2.641 +    it under the terms of the GNU General Public License as published by
   2.642 +    the Free Software Foundation, either version 3 of the License, or
   2.643 +    (at your option) any later version.
   2.644 +
   2.645 +    This program is distributed in the hope that it will be useful,
   2.646 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   2.647 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   2.648 +    GNU General Public License for more details.
   2.649 +
   2.650 +    You should have received a copy of the GNU General Public License
   2.651 +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   2.652 +
   2.653 +Also add information on how to contact you by electronic and paper mail.
   2.654 +
   2.655 +  If the program does terminal interaction, make it output a short
   2.656 +notice like this when it starts in an interactive mode:
   2.657 +
   2.658 +    <program>  Copyright (C) <year>  <name of author>
   2.659 +    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
   2.660 +    This is free software, and you are welcome to redistribute it
   2.661 +    under certain conditions; type `show c' for details.
   2.662 +
   2.663 +The hypothetical commands `show w' and `show c' should show the appropriate
   2.664 +parts of the General Public License.  Of course, your program's commands
   2.665 +might be different; for a GUI interface, you would use an "about box".
   2.666 +
   2.667 +  You should also get your employer (if you work as a programmer) or school,
   2.668 +if any, to sign a "copyright disclaimer" for the program, if necessary.
   2.669 +For more information on this, and how to apply and follow the GNU GPL, see
   2.670 +<http://www.gnu.org/licenses/>.
   2.671 +
   2.672 +  The GNU General Public License does not permit incorporating your program
   2.673 +into proprietary programs.  If your program is a subroutine library, you
   2.674 +may consider it more useful to permit linking proprietary applications with
   2.675 +the library.  If this is what you want to do, use the GNU Lesser General
   2.676 +Public License instead of this License.  But first, please read
   2.677 +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/Makefile	Sun Nov 09 13:03:36 2014 +0200
     3.3 @@ -0,0 +1,50 @@
     3.4 +src = $(wildcard src/*.cc) $(wildcard vmath/*.cc)
     3.5 +csrc = $(wildcard src/*.c) $(wildcard vmath/*.c) $(wildcard anim/*.c)
     3.6 +obj = $(src:.cc=.o) $(csrc:.c=.o)
     3.7 +dep = $(obj:.o=.d)
     3.8 +bin = ray1
     3.9 +
    3.10 +opt = -O3 -march=native
    3.11 +dbg = -g
    3.12 +#prof = -pg
    3.13 +CFLAGS = -pedantic -Wall $(dbg) $(opt) $(prof) -I.
    3.14 +CXXFLAGS = -std=c++11 $(CFLAGS)
    3.15 +LDFLAGS = $(prof) $(libgl) -limago
    3.16 +
    3.17 +ifeq ($(shell uname -s), Darwin)
    3.18 +	# the gcc shipping with Darwin is ancient and doesn't support C++11
    3.19 +	# use clang instead.
    3.20 +	CXX = clang++
    3.21 +	CPP = clang -E
    3.22 +	CXXFLAGS += -stdlib=libc++
    3.23 +	LDFLAGS += -stdlib=libc++
    3.24 +
    3.25 +	libgl = -framework OpenGL -framework GLUT -lGLEW
    3.26 +else
    3.27 +	libgl = -lGL -lGLU -lglut -lGLEW
    3.28 +endif
    3.29 +
    3.30 +ifeq ($(CC), icc)
    3.31 +	libomp = -liomp5
    3.32 +else
    3.33 +	libomp = -lgomp
    3.34 +endif
    3.35 +
    3.36 +$(bin): $(obj)
    3.37 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    3.38 +
    3.39 +-include $(dep)
    3.40 +
    3.41 +%.d: %.c
    3.42 +	@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
    3.43 +
    3.44 +%.d: %.cc
    3.45 +	@$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
    3.46 +
    3.47 +.PHONY: clean
    3.48 +clean:
    3.49 +	rm -f $(obj) $(bin)
    3.50 +
    3.51 +.PHONY: cleandep
    3.52 +cleandep: clean
    3.53 +	rm -f $(dep)
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/README	Sun Nov 09 13:03:36 2014 +0200
     4.3 @@ -0,0 +1,11 @@
     4.4 +To compile just type make. Install a recent version of the g++ compiler,
     4.5 +preferable 4.7, as the code is written according to the recent C++11 standard.
     4.6 +
     4.7 +Copyright 2012 John Tsiombikas <nuclear@member.fsf.org>
     4.8 +You may use, modify, and distribute the program under the terms of the GNU
     4.9 +General Public License version 3, or at your option, any later version published
    4.10 +by the Free Software Foundation. See COPYING for details.
    4.11 +
    4.12 +Dependencies:
    4.13 + - GLUT: http://freeglut.sourceforge.net
    4.14 + - libimago: http://code.google.com/p/libimago
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/anim/anim.c	Sun Nov 09 13:03:36 2014 +0200
     5.3 @@ -0,0 +1,498 @@
     5.4 +#include <stdlib.h>
     5.5 +#include <limits.h>
     5.6 +#include <assert.h>
     5.7 +#include "anim.h"
     5.8 +#include "dynarr.h"
     5.9 +
    5.10 +#define ROT_USE_SLERP
    5.11 +
    5.12 +static void invalidate_cache(struct anm_node *node);
    5.13 +
    5.14 +int anm_init_node(struct anm_node *node)
    5.15 +{
    5.16 +	int i, j;
    5.17 +	static const float defaults[] = {
    5.18 +		0.0f, 0.0f, 0.0f,		/* default position */
    5.19 +		0.0f, 0.0f, 0.0f, 1.0f,	/* default rotation quat */
    5.20 +		1.0f, 1.0f, 1.0f		/* default scale factor */
    5.21 +	};
    5.22 +
    5.23 +	memset(node, 0, sizeof *node);
    5.24 +
    5.25 +	/* initialize thread-local matrix cache */
    5.26 +	pthread_key_create(&node->cache_key, 0);
    5.27 +	pthread_mutex_init(&node->cache_list_lock, 0);
    5.28 +
    5.29 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
    5.30 +		if(anm_init_track(node->tracks + i) == -1) {
    5.31 +			for(j=0; j<i; j++) {
    5.32 +				anm_destroy_track(node->tracks + i);
    5.33 +			}
    5.34 +		}
    5.35 +		anm_set_track_default(node->tracks + i, defaults[i]);
    5.36 +	}
    5.37 +	return 0;
    5.38 +}
    5.39 +
    5.40 +void anm_destroy_node(struct anm_node *node)
    5.41 +{
    5.42 +	int i;
    5.43 +	free(node->name);
    5.44 +
    5.45 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
    5.46 +		anm_destroy_track(node->tracks + i);
    5.47 +	}
    5.48 +
    5.49 +	/* destroy thread-specific cache */
    5.50 +	pthread_key_delete(node->cache_key);
    5.51 +
    5.52 +	while(node->cache_list) {
    5.53 +		struct mat_cache *tmp = node->cache_list;
    5.54 +		node->cache_list = tmp->next;
    5.55 +		free(tmp);
    5.56 +	}
    5.57 +}
    5.58 +
    5.59 +void anm_destroy_node_tree(struct anm_node *tree)
    5.60 +{
    5.61 +	struct anm_node *c, *tmp;
    5.62 +
    5.63 +	if(!tree) return;
    5.64 +
    5.65 +	c = tree->child;
    5.66 +	while(c) {
    5.67 +		tmp = c;
    5.68 +		c = c->next;
    5.69 +
    5.70 +		anm_destroy_node_tree(tmp);
    5.71 +	}
    5.72 +	anm_destroy_node(tree);
    5.73 +}
    5.74 +
    5.75 +struct anm_node *anm_create_node(void)
    5.76 +{
    5.77 +	struct anm_node *n;
    5.78 +
    5.79 +	if((n = malloc(sizeof *n))) {
    5.80 +		if(anm_init_node(n) == -1) {
    5.81 +			free(n);
    5.82 +			return 0;
    5.83 +		}
    5.84 +	}
    5.85 +	return n;
    5.86 +}
    5.87 +
    5.88 +void anm_free_node(struct anm_node *node)
    5.89 +{
    5.90 +	anm_destroy_node(node);
    5.91 +	free(node);
    5.92 +}
    5.93 +
    5.94 +void anm_free_node_tree(struct anm_node *tree)
    5.95 +{
    5.96 +	struct anm_node *c, *tmp;
    5.97 +
    5.98 +	if(!tree) return;
    5.99 +
   5.100 +	c = tree->child;
   5.101 +	while(c) {
   5.102 +		tmp = c;
   5.103 +		c = c->next;
   5.104 +
   5.105 +		anm_free_node_tree(tmp);
   5.106 +	}
   5.107 +
   5.108 +	anm_free_node(tree);
   5.109 +}
   5.110 +
   5.111 +int anm_set_node_name(struct anm_node *node, const char *name)
   5.112 +{
   5.113 +	char *str;
   5.114 +
   5.115 +	if(!(str = malloc(strlen(name) + 1))) {
   5.116 +		return -1;
   5.117 +	}
   5.118 +	strcpy(str, name);
   5.119 +	free(node->name);
   5.120 +	node->name = str;
   5.121 +	return 0;
   5.122 +}
   5.123 +
   5.124 +const char *anm_get_node_name(struct anm_node *node)
   5.125 +{
   5.126 +	return node->name ? node->name : "";
   5.127 +}
   5.128 +
   5.129 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
   5.130 +{
   5.131 +	int i;
   5.132 +
   5.133 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
   5.134 +		anm_set_track_interpolator(node->tracks + i, in);
   5.135 +	}
   5.136 +	invalidate_cache(node);
   5.137 +}
   5.138 +
   5.139 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
   5.140 +{
   5.141 +	int i;
   5.142 +
   5.143 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
   5.144 +		anm_set_track_extrapolator(node->tracks + i, ex);
   5.145 +	}
   5.146 +	invalidate_cache(node);
   5.147 +}
   5.148 +
   5.149 +void anm_link_node(struct anm_node *p, struct anm_node *c)
   5.150 +{
   5.151 +	c->next = p->child;
   5.152 +	p->child = c;
   5.153 +
   5.154 +	c->parent = p;
   5.155 +	invalidate_cache(c);
   5.156 +}
   5.157 +
   5.158 +int anm_unlink_node(struct anm_node *p, struct anm_node *c)
   5.159 +{
   5.160 +	struct anm_node *iter;
   5.161 +
   5.162 +	if(p->child == c) {
   5.163 +		p->child = c->next;
   5.164 +		c->next = 0;
   5.165 +		invalidate_cache(c);
   5.166 +		return 0;
   5.167 +	}
   5.168 +
   5.169 +	iter = p->child;
   5.170 +	while(iter->next) {
   5.171 +		if(iter->next == c) {
   5.172 +			iter->next = c->next;
   5.173 +			c->next = 0;
   5.174 +			invalidate_cache(c);
   5.175 +			return 0;
   5.176 +		}
   5.177 +	}
   5.178 +	return -1;
   5.179 +}
   5.180 +
   5.181 +void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
   5.182 +{
   5.183 +	anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x);
   5.184 +	anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y);
   5.185 +	anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z);
   5.186 +	invalidate_cache(node);
   5.187 +}
   5.188 +
   5.189 +vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
   5.190 +{
   5.191 +	vec3_t v;
   5.192 +	v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm);
   5.193 +	v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm);
   5.194 +	v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm);
   5.195 +	return v;
   5.196 +}
   5.197 +
   5.198 +void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
   5.199 +{
   5.200 +	anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x);
   5.201 +	anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
   5.202 +	anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
   5.203 +	anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w);
   5.204 +	invalidate_cache(node);
   5.205 +}
   5.206 +
   5.207 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
   5.208 +{
   5.209 +#ifndef ROT_USE_SLERP
   5.210 +	quat_t q;
   5.211 +	q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm);
   5.212 +	q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm);
   5.213 +	q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm);
   5.214 +	q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm);
   5.215 +	return q;
   5.216 +#else
   5.217 +	int idx0, idx1, last_idx;
   5.218 +	anm_time_t tstart, tend;
   5.219 +	float t, dt;
   5.220 +	struct anm_track *track_x, *track_y, *track_z, *track_w;
   5.221 +	quat_t q, q1, q2;
   5.222 +
   5.223 +	track_x = node->tracks + ANM_TRACK_ROT_X;
   5.224 +	track_y = node->tracks + ANM_TRACK_ROT_Y;
   5.225 +	track_z = node->tracks + ANM_TRACK_ROT_Z;
   5.226 +	track_w = node->tracks + ANM_TRACK_ROT_W;
   5.227 +
   5.228 +	if(!track_x->count) {
   5.229 +		q.x = track_x->def_val;
   5.230 +		q.y = track_y->def_val;
   5.231 +		q.z = track_z->def_val;
   5.232 +		q.w = track_w->def_val;
   5.233 +		return q;
   5.234 +	}
   5.235 +
   5.236 +	last_idx = track_x->count - 1;
   5.237 +
   5.238 +	tstart = track_x->keys[0].time;
   5.239 +	tend = track_x->keys[last_idx].time;
   5.240 +
   5.241 +	if(tstart == tend) {
   5.242 +		q.x = track_x->keys[0].val;
   5.243 +		q.y = track_y->keys[0].val;
   5.244 +		q.z = track_z->keys[0].val;
   5.245 +		q.w = track_w->keys[0].val;
   5.246 +		return q;
   5.247 +	}
   5.248 +
   5.249 +	tm = anm_remap_time(track_x, tm, tstart, tend);
   5.250 +
   5.251 +	idx0 = anm_get_key_interval(track_x, tm);
   5.252 +	assert(idx0 >= 0 && idx0 < track_x->count);
   5.253 +	idx1 = idx0 + 1;
   5.254 +
   5.255 +	if(idx0 == last_idx) {
   5.256 +		q.x = track_x->keys[idx0].val;
   5.257 +		q.y = track_y->keys[idx0].val;
   5.258 +		q.z = track_z->keys[idx0].val;
   5.259 +		q.w = track_w->keys[idx0].val;
   5.260 +		return q;
   5.261 +	}
   5.262 +
   5.263 +	dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time);
   5.264 +	t = (float)(tm - track_x->keys[idx0].time) / dt;
   5.265 +
   5.266 +	q1.x = track_x->keys[idx0].val;
   5.267 +	q1.y = track_y->keys[idx0].val;
   5.268 +	q1.z = track_z->keys[idx0].val;
   5.269 +	q1.w = track_w->keys[idx0].val;
   5.270 +
   5.271 +	q2.x = track_x->keys[idx1].val;
   5.272 +	q2.y = track_y->keys[idx1].val;
   5.273 +	q2.z = track_z->keys[idx1].val;
   5.274 +	q2.w = track_w->keys[idx1].val;
   5.275 +
   5.276 +	/*q1 = quat_normalize(q1);
   5.277 +	q2 = quat_normalize(q2);*/
   5.278 +
   5.279 +	return quat_slerp(q1, q2, t);
   5.280 +#endif
   5.281 +}
   5.282 +
   5.283 +void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
   5.284 +{
   5.285 +	anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x);
   5.286 +	anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
   5.287 +	anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
   5.288 +	invalidate_cache(node);
   5.289 +}
   5.290 +
   5.291 +vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
   5.292 +{
   5.293 +	vec3_t v;
   5.294 +	v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm);
   5.295 +	v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm);
   5.296 +	v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm);
   5.297 +	return v;
   5.298 +}
   5.299 +
   5.300 +
   5.301 +vec3_t anm_get_position(struct anm_node *node, anm_time_t tm)
   5.302 +{
   5.303 +	mat4_t xform;
   5.304 +	vec3_t pos = {0.0, 0.0, 0.0};
   5.305 +
   5.306 +	if(!node->parent) {
   5.307 +		return anm_get_node_position(node, tm);
   5.308 +	}
   5.309 +
   5.310 +	anm_get_matrix(node, xform, tm);
   5.311 +	return v3_transform(pos, xform);
   5.312 +}
   5.313 +
   5.314 +quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm)
   5.315 +{
   5.316 +	quat_t rot, prot;
   5.317 +	rot = anm_get_node_rotation(node, tm);
   5.318 +
   5.319 +	if(!node->parent) {
   5.320 +		return rot;
   5.321 +	}
   5.322 +
   5.323 +	prot = anm_get_rotation(node->parent, tm);
   5.324 +	return quat_mul(prot, rot);
   5.325 +}
   5.326 +
   5.327 +vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm)
   5.328 +{
   5.329 +	vec3_t s, ps;
   5.330 +	s = anm_get_node_scaling(node, tm);
   5.331 +
   5.332 +	if(!node->parent) {
   5.333 +		return s;
   5.334 +	}
   5.335 +
   5.336 +	ps = anm_get_scaling(node->parent, tm);
   5.337 +	return v3_mul(s, ps);
   5.338 +}
   5.339 +
   5.340 +void anm_set_pivot(struct anm_node *node, vec3_t piv)
   5.341 +{
   5.342 +	node->pivot = piv;
   5.343 +}
   5.344 +
   5.345 +vec3_t anm_get_pivot(struct anm_node *node)
   5.346 +{
   5.347 +	return node->pivot;
   5.348 +}
   5.349 +
   5.350 +void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
   5.351 +{
   5.352 +	int i;
   5.353 +	mat4_t rmat;
   5.354 +	vec3_t pos, scale;
   5.355 +	quat_t rot;
   5.356 +
   5.357 +	pos = anm_get_node_position(node, tm);
   5.358 +	rot = anm_get_node_rotation(node, tm);
   5.359 +	scale = anm_get_node_scaling(node, tm);
   5.360 +
   5.361 +	m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);
   5.362 +
   5.363 +	quat_to_mat4(rmat, rot);
   5.364 +	for(i=0; i<3; i++) {
   5.365 +		mat[i][0] = rmat[i][0];
   5.366 +		mat[i][1] = rmat[i][1];
   5.367 +		mat[i][2] = rmat[i][2];
   5.368 +	}
   5.369 +	/* this loop is equivalent to: m4_mult(mat, mat, rmat); */
   5.370 +
   5.371 +	mat[0][0] *= scale.x; mat[0][1] *= scale.y; mat[0][2] *= scale.z; mat[0][3] += pos.x;
   5.372 +	mat[1][0] *= scale.x; mat[1][1] *= scale.y; mat[1][2] *= scale.z; mat[1][3] += pos.y;
   5.373 +	mat[2][0] *= scale.x; mat[2][1] *= scale.y; mat[2][2] *= scale.z; mat[2][3] += pos.z;
   5.374 +
   5.375 +	m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);
   5.376 +
   5.377 +	/* that's basically: pivot * rotation * translation * scaling * -pivot */
   5.378 +}
   5.379 +
   5.380 +void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
   5.381 +{
   5.382 +	mat4_t tmp;
   5.383 +	anm_get_node_matrix(node, tmp, tm);
   5.384 +	m4_inverse(mat, tmp);
   5.385 +}
   5.386 +
   5.387 +void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
   5.388 +{
   5.389 +	struct mat_cache *cache = pthread_getspecific(node->cache_key);
   5.390 +	if(!cache) {
   5.391 +		cache = malloc(sizeof *cache);
   5.392 +		assert(cache);
   5.393 +
   5.394 +		pthread_mutex_lock(&node->cache_list_lock);
   5.395 +		cache->next = node->cache_list;
   5.396 +		node->cache_list = cache;
   5.397 +		pthread_mutex_unlock(&node->cache_list_lock);
   5.398 +
   5.399 +		cache->time = ANM_TIME_INVAL;
   5.400 +		cache->inv_time = ANM_TIME_INVAL;
   5.401 +		pthread_setspecific(node->cache_key, cache);
   5.402 +	}
   5.403 +
   5.404 +	if(cache->time != tm) {
   5.405 +		anm_get_node_matrix(node, cache->matrix, tm);
   5.406 +
   5.407 +		if(node->parent) {
   5.408 +			mat4_t parent_mat;
   5.409 +
   5.410 +			anm_get_matrix(node->parent, parent_mat, tm);
   5.411 +			m4_mult(cache->matrix, parent_mat, cache->matrix);
   5.412 +		}
   5.413 +		cache->time = tm;
   5.414 +	}
   5.415 +	m4_copy(mat, cache->matrix);
   5.416 +}
   5.417 +
   5.418 +void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
   5.419 +{
   5.420 +	struct mat_cache *cache = pthread_getspecific(node->cache_key);
   5.421 +	if(!cache) {
   5.422 +		cache = malloc(sizeof *cache);
   5.423 +		assert(cache);
   5.424 +
   5.425 +		pthread_mutex_lock(&node->cache_list_lock);
   5.426 +		cache->next = node->cache_list;
   5.427 +		node->cache_list = cache;
   5.428 +		pthread_mutex_unlock(&node->cache_list_lock);
   5.429 +
   5.430 +		cache->inv_time = ANM_TIME_INVAL;
   5.431 +		cache->inv_time = ANM_TIME_INVAL;
   5.432 +		pthread_setspecific(node->cache_key, cache);
   5.433 +	}
   5.434 +
   5.435 +	if(cache->inv_time != tm) {
   5.436 +		anm_get_matrix(node, mat, tm);
   5.437 +		m4_inverse(cache->inv_matrix, mat);
   5.438 +		cache->inv_time = tm;
   5.439 +	}
   5.440 +	m4_copy(mat, cache->inv_matrix);
   5.441 +}
   5.442 +
   5.443 +anm_time_t anm_get_start_time(struct anm_node *node)
   5.444 +{
   5.445 +	int i;
   5.446 +	struct anm_node *c;
   5.447 +	anm_time_t res = LONG_MAX;
   5.448 +
   5.449 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
   5.450 +		if(node->tracks[i].count) {
   5.451 +			anm_time_t tm = node->tracks[i].keys[0].time;
   5.452 +			if(tm < res) {
   5.453 +				res = tm;
   5.454 +			}
   5.455 +		}
   5.456 +	}
   5.457 +
   5.458 +	c = node->child;
   5.459 +	while(c) {
   5.460 +		anm_time_t tm = anm_get_start_time(c);
   5.461 +		if(tm < res) {
   5.462 +			res = tm;
   5.463 +		}
   5.464 +		c = c->next;
   5.465 +	}
   5.466 +	return res;
   5.467 +}
   5.468 +
   5.469 +anm_time_t anm_get_end_time(struct anm_node *node)
   5.470 +{
   5.471 +	int i;
   5.472 +	struct anm_node *c;
   5.473 +	anm_time_t res = LONG_MIN;
   5.474 +
   5.475 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
   5.476 +		if(node->tracks[i].count) {
   5.477 +			anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time;
   5.478 +			if(tm > res) {
   5.479 +				res = tm;
   5.480 +			}
   5.481 +		}
   5.482 +	}
   5.483 +
   5.484 +	c = node->child;
   5.485 +	while(c) {
   5.486 +		anm_time_t tm = anm_get_end_time(c);
   5.487 +		if(tm > res) {
   5.488 +			res = tm;
   5.489 +		}
   5.490 +		c = c->next;
   5.491 +	}
   5.492 +	return res;
   5.493 +}
   5.494 +
   5.495 +static void invalidate_cache(struct anm_node *node)
   5.496 +{
   5.497 +	struct mat_cache *cache = pthread_getspecific(node->cache_key);
   5.498 +	if(cache) {
   5.499 +	   cache->time = cache->inv_time = ANM_TIME_INVAL;
   5.500 +	}
   5.501 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/anim/anim.h	Sun Nov 09 13:03:36 2014 +0200
     6.3 @@ -0,0 +1,117 @@
     6.4 +#ifndef LIBANIM_H_
     6.5 +#define LIBANIM_H_
     6.6 +
     6.7 +#include "config.h"
     6.8 +
     6.9 +#include <pthread.h>
    6.10 +
    6.11 +#include <vmath/vector.h>
    6.12 +#include <vmath/quat.h>
    6.13 +#include <vmath/matrix.h>
    6.14 +#include "track.h"
    6.15 +
    6.16 +enum {
    6.17 +	ANM_TRACK_POS_X,
    6.18 +	ANM_TRACK_POS_Y,
    6.19 +	ANM_TRACK_POS_Z,
    6.20 +
    6.21 +	ANM_TRACK_ROT_X,
    6.22 +	ANM_TRACK_ROT_Y,
    6.23 +	ANM_TRACK_ROT_Z,
    6.24 +	ANM_TRACK_ROT_W,
    6.25 +
    6.26 +	ANM_TRACK_SCL_X,
    6.27 +	ANM_TRACK_SCL_Y,
    6.28 +	ANM_TRACK_SCL_Z,
    6.29 +
    6.30 +	ANM_NUM_TRACKS
    6.31 +};
    6.32 +
    6.33 +struct anm_node {
    6.34 +	char *name;
    6.35 +
    6.36 +	struct anm_track tracks[ANM_NUM_TRACKS];
    6.37 +	vec3_t pivot;
    6.38 +
    6.39 +	/* matrix cache */
    6.40 +	struct mat_cache {
    6.41 +		mat4_t matrix, inv_matrix;
    6.42 +		anm_time_t time, inv_time;
    6.43 +		struct mat_cache *next;
    6.44 +	} *cache_list;
    6.45 +	pthread_key_t cache_key;
    6.46 +	pthread_mutex_t cache_list_lock;
    6.47 +
    6.48 +	struct anm_node *parent;
    6.49 +	struct anm_node *child;
    6.50 +	struct anm_node *next;
    6.51 +};
    6.52 +
    6.53 +#ifdef __cplusplus
    6.54 +extern "C" {
    6.55 +#endif
    6.56 +
    6.57 +/* node constructor and destructor */
    6.58 +int anm_init_node(struct anm_node *node);
    6.59 +void anm_destroy_node(struct anm_node *node);
    6.60 +
    6.61 +/* recursively destroy an animation node tree */
    6.62 +void anm_destroy_node_tree(struct anm_node *tree);
    6.63 +
    6.64 +/* helper functions to allocate/construct and destroy/free with
    6.65 + * a single call. They call anm_init_node and anm_destroy_node
    6.66 + * internally.
    6.67 + */
    6.68 +struct anm_node *anm_create_node(void);
    6.69 +void anm_free_node(struct anm_node *node);
    6.70 +
    6.71 +/* recursively destroy and free the nodes of a node tree */
    6.72 +void anm_free_node_tree(struct anm_node *tree);
    6.73 +
    6.74 +int anm_set_node_name(struct anm_node *node, const char *name);
    6.75 +const char *anm_get_node_name(struct anm_node *node);
    6.76 +
    6.77 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in);
    6.78 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex);
    6.79 +
    6.80 +/* link and unlink nodes with parent/child relations */
    6.81 +void anm_link_node(struct anm_node *parent, struct anm_node *child);
    6.82 +int anm_unlink_node(struct anm_node *parent, struct anm_node *child);
    6.83 +
    6.84 +void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm);
    6.85 +vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm);
    6.86 +
    6.87 +void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm);
    6.88 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm);
    6.89 +
    6.90 +void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm);
    6.91 +vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm);
    6.92 +
    6.93 +/* these three return the full p/r/s taking hierarchy into account */
    6.94 +vec3_t anm_get_position(struct anm_node *node, anm_time_t tm);
    6.95 +quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm);
    6.96 +vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm);
    6.97 +
    6.98 +void anm_set_pivot(struct anm_node *node, vec3_t pivot);
    6.99 +vec3_t anm_get_pivot(struct anm_node *node);
   6.100 +
   6.101 +/* these calculate the matrix and inverse matrix of this node alone */
   6.102 +void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
   6.103 +void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
   6.104 +
   6.105 +/* These calculate the matrix and inverse matrix of this node taking hierarchy
   6.106 + * into account. The results are cached in thread-specific storage and returned
   6.107 + * if there's no change in time or tracks from the last query...
   6.108 + */
   6.109 +void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
   6.110 +void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
   6.111 +
   6.112 +/* those return the start and end times of the whole tree */
   6.113 +anm_time_t anm_get_start_time(struct anm_node *node);
   6.114 +anm_time_t anm_get_end_time(struct anm_node *node);
   6.115 +
   6.116 +#ifdef __cplusplus
   6.117 +}
   6.118 +#endif
   6.119 +
   6.120 +#endif	/* LIBANIM_H_ */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/anim/config.h	Sun Nov 09 13:03:36 2014 +0200
     7.3 @@ -0,0 +1,6 @@
     7.4 +#ifndef ANIM_CONFIG_H_
     7.5 +#define ANIM_CONFIG_H_
     7.6 +
     7.7 +#undef ANIM_THREAD_SAFE
     7.8 +
     7.9 +#endif	/* ANIM_CONFIG_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/anim/dynarr.c	Sun Nov 09 13:03:36 2014 +0200
     8.3 @@ -0,0 +1,122 @@
     8.4 +#include <stdio.h>
     8.5 +#include <stdlib.h>
     8.6 +#include <string.h>
     8.7 +#include "dynarr.h"
     8.8 +
     8.9 +/* The array descriptor keeps auxilliary information needed to manipulate
    8.10 + * the dynamic array. It's allocated adjacent to the array buffer.
    8.11 + */
    8.12 +struct arrdesc {
    8.13 +	int nelem, szelem;
    8.14 +	int max_elem;
    8.15 +	int bufsz;	/* not including the descriptor */
    8.16 +};
    8.17 +
    8.18 +#define DESC(x)		((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc)))
    8.19 +
    8.20 +void *dynarr_alloc(int elem, int szelem)
    8.21 +{
    8.22 +	struct arrdesc *desc;
    8.23 +
    8.24 +	if(!(desc = malloc(elem * szelem + sizeof *desc))) {
    8.25 +		return 0;
    8.26 +	}
    8.27 +	desc->nelem = desc->max_elem = elem;
    8.28 +	desc->szelem = szelem;
    8.29 +	desc->bufsz = elem * szelem;
    8.30 +	return (char*)desc + sizeof *desc;
    8.31 +}
    8.32 +
    8.33 +void dynarr_free(void *da)
    8.34 +{
    8.35 +	if(da) {
    8.36 +		free(DESC(da));
    8.37 +	}
    8.38 +}
    8.39 +
    8.40 +void *dynarr_resize(void *da, int elem)
    8.41 +{
    8.42 +	int newsz;
    8.43 +	void *tmp;
    8.44 +	struct arrdesc *desc;
    8.45 +
    8.46 +	if(!da) return 0;
    8.47 +	desc = DESC(da);
    8.48 +
    8.49 +	newsz = desc->szelem * elem;
    8.50 +
    8.51 +	if(!(tmp = realloc(desc, newsz + sizeof *desc))) {
    8.52 +		return 0;
    8.53 +	}
    8.54 +	desc = tmp;
    8.55 +
    8.56 +	desc->nelem = desc->max_elem = elem;
    8.57 +	desc->bufsz = newsz;
    8.58 +	return (char*)desc + sizeof *desc;
    8.59 +}
    8.60 +
    8.61 +int dynarr_empty(void *da)
    8.62 +{
    8.63 +	return DESC(da)->nelem ? 0 : 1;
    8.64 +}
    8.65 +
    8.66 +int dynarr_size(void *da)
    8.67 +{
    8.68 +	return DESC(da)->nelem;
    8.69 +}
    8.70 +
    8.71 +
    8.72 +/* stack semantics */
    8.73 +void *dynarr_push(void *da, void *item)
    8.74 +{
    8.75 +	struct arrdesc *desc;
    8.76 +	int nelem;
    8.77 +
    8.78 +	desc = DESC(da);
    8.79 +	nelem = desc->nelem;
    8.80 +
    8.81 +	if(nelem >= desc->max_elem) {
    8.82 +		/* need to resize */
    8.83 +		struct arrdesc *tmp;
    8.84 +		int newsz = desc->max_elem ? desc->max_elem * 2 : 1;
    8.85 +
    8.86 +		if(!(tmp = dynarr_resize(da, newsz))) {
    8.87 +			fprintf(stderr, "failed to resize\n");
    8.88 +			return da;
    8.89 +		}
    8.90 +		da = tmp;
    8.91 +		desc = DESC(da);
    8.92 +		desc->nelem = nelem;
    8.93 +	}
    8.94 +
    8.95 +	memcpy((char*)da + desc->nelem++ * desc->szelem, item, desc->szelem);
    8.96 +	return da;
    8.97 +}
    8.98 +
    8.99 +void *dynarr_pop(void *da)
   8.100 +{
   8.101 +	struct arrdesc *desc;
   8.102 +	int nelem;
   8.103 +
   8.104 +	desc = DESC(da);
   8.105 +	nelem = desc->nelem;
   8.106 +
   8.107 +	if(!nelem) return da;
   8.108 +
   8.109 +	if(nelem <= desc->max_elem / 3) {
   8.110 +		/* reclaim space */
   8.111 +		struct arrdesc *tmp;
   8.112 +		int newsz = desc->max_elem / 2;
   8.113 +
   8.114 +		if(!(tmp = dynarr_resize(da, newsz))) {
   8.115 +			fprintf(stderr, "failed to resize\n");
   8.116 +			return da;
   8.117 +		}
   8.118 +		da = tmp;
   8.119 +		desc = DESC(da);
   8.120 +		desc->nelem = nelem;
   8.121 +	}
   8.122 +	desc->nelem--;
   8.123 +
   8.124 +	return da;
   8.125 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/anim/dynarr.h	Sun Nov 09 13:03:36 2014 +0200
     9.3 @@ -0,0 +1,16 @@
     9.4 +#ifndef DYNARR_H_
     9.5 +#define DYNARR_H_
     9.6 +
     9.7 +void *dynarr_alloc(int elem, int szelem);
     9.8 +void dynarr_free(void *da);
     9.9 +void *dynarr_resize(void *da, int elem);
    9.10 +
    9.11 +int dynarr_empty(void *da);
    9.12 +int dynarr_size(void *da);
    9.13 +
    9.14 +/* stack semantics */
    9.15 +void *dynarr_push(void *da, void *item);
    9.16 +void *dynarr_pop(void *da);
    9.17 +
    9.18 +
    9.19 +#endif	/* DYNARR_H_ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/anim/track.c	Sun Nov 09 13:03:36 2014 +0200
    10.3 @@ -0,0 +1,316 @@
    10.4 +#include <stdlib.h>
    10.5 +#include <string.h>
    10.6 +#include <assert.h>
    10.7 +#include "track.h"
    10.8 +#include "dynarr.h"
    10.9 +
   10.10 +static int keycmp(const void *a, const void *b);
   10.11 +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm);
   10.12 +
   10.13 +static float interp_step(float v0, float v1, float v2, float v3, float t);
   10.14 +static float interp_linear(float v0, float v1, float v2, float v3, float t);
   10.15 +static float interp_cubic(float v0, float v1, float v2, float v3, float t);
   10.16 +
   10.17 +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end);
   10.18 +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end);
   10.19 +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end);
   10.20 +static anm_time_t remap_pingpong(anm_time_t tm, anm_time_t start, anm_time_t end);
   10.21 +
   10.22 +/* XXX keep this in sync with enum anm_interpolator at track.h */
   10.23 +static float (*interp[])(float, float, float, float, float) = {
   10.24 +	interp_step,
   10.25 +	interp_linear,
   10.26 +	interp_cubic,
   10.27 +	0
   10.28 +};
   10.29 +
   10.30 +/* XXX keep this in sync with enum anm_extrapolator at track.h */
   10.31 +static anm_time_t (*remap_time[])(anm_time_t, anm_time_t, anm_time_t) = {
   10.32 +	remap_extend,
   10.33 +	remap_clamp,
   10.34 +	remap_repeat,
   10.35 +	remap_pingpong,
   10.36 +	0
   10.37 +};
   10.38 +
   10.39 +int anm_init_track(struct anm_track *track)
   10.40 +{
   10.41 +	memset(track, 0, sizeof *track);
   10.42 +
   10.43 +	if(!(track->keys = dynarr_alloc(0, sizeof *track->keys))) {
   10.44 +		return -1;
   10.45 +	}
   10.46 +	track->interp = ANM_INTERP_LINEAR;
   10.47 +	track->extrap = ANM_EXTRAP_CLAMP;
   10.48 +	return 0;
   10.49 +}
   10.50 +
   10.51 +void anm_destroy_track(struct anm_track *track)
   10.52 +{
   10.53 +	dynarr_free(track->keys);
   10.54 +}
   10.55 +
   10.56 +struct anm_track *anm_create_track(void)
   10.57 +{
   10.58 +	struct anm_track *track;
   10.59 +
   10.60 +	if((track = malloc(sizeof *track))) {
   10.61 +		if(anm_init_track(track) == -1) {
   10.62 +			free(track);
   10.63 +			return 0;
   10.64 +		}
   10.65 +	}
   10.66 +	return track;
   10.67 +}
   10.68 +
   10.69 +void anm_free_track(struct anm_track *track)
   10.70 +{
   10.71 +	anm_destroy_track(track);
   10.72 +	free(track);
   10.73 +}
   10.74 +
   10.75 +void anm_copy_track(struct anm_track *dest, struct anm_track *src)
   10.76 +{
   10.77 +	free(dest->name);
   10.78 +	if(dest->keys) {
   10.79 +		dynarr_free(dest->keys);
   10.80 +	}
   10.81 +
   10.82 +	if(src->name) {
   10.83 +		dest->name = malloc(strlen(src->name) + 1);
   10.84 +		strcpy(dest->name, src->name);
   10.85 +	}
   10.86 +
   10.87 +	dest->count = src->count;
   10.88 +	dest->keys = dynarr_alloc(src->count, sizeof *dest->keys);
   10.89 +	memcpy(dest->keys, src->keys, src->count * sizeof *dest->keys);
   10.90 +
   10.91 +	dest->def_val = src->def_val;
   10.92 +	dest->interp = src->interp;
   10.93 +	dest->extrap = src->extrap;
   10.94 +}
   10.95 +
   10.96 +int anm_set_track_name(struct anm_track *track, const char *name)
   10.97 +{
   10.98 +	char *tmp;
   10.99 +
  10.100 +	if(!(tmp = malloc(strlen(name) + 1))) {
  10.101 +		return -1;
  10.102 +	}
  10.103 +	free(track->name);
  10.104 +	track->name = tmp;
  10.105 +	return 0;
  10.106 +}
  10.107 +
  10.108 +const char *anm_get_track_name(struct anm_track *track)
  10.109 +{
  10.110 +	return track->name;
  10.111 +}
  10.112 +
  10.113 +void anm_set_track_interpolator(struct anm_track *track, enum anm_interpolator in)
  10.114 +{
  10.115 +	track->interp = in;
  10.116 +}
  10.117 +
  10.118 +void anm_set_track_extrapolator(struct anm_track *track, enum anm_extrapolator ex)
  10.119 +{
  10.120 +	track->extrap = ex;
  10.121 +}
  10.122 +
  10.123 +anm_time_t anm_remap_time(struct anm_track *track, anm_time_t tm, anm_time_t start, anm_time_t end)
  10.124 +{
  10.125 +	return remap_time[track->extrap](tm, start, end);
  10.126 +}
  10.127 +
  10.128 +void anm_set_track_default(struct anm_track *track, float def)
  10.129 +{
  10.130 +	track->def_val = def;
  10.131 +}
  10.132 +
  10.133 +int anm_set_keyframe(struct anm_track *track, struct anm_keyframe *key)
  10.134 +{
  10.135 +	int idx = anm_get_key_interval(track, key->time);
  10.136 +
  10.137 +	/* if we got a valid keyframe index, compare them... */
  10.138 +	if(idx >= 0 && idx < track->count && keycmp(key, track->keys + idx) == 0) {
  10.139 +		/* ... it's the same key, just update the value */
  10.140 +		track->keys[idx].val = key->val;
  10.141 +	} else {
  10.142 +		/* ... it's a new key, add it and re-sort them */
  10.143 +		void *tmp;
  10.144 +		if(!(tmp = dynarr_push(track->keys, key))) {
  10.145 +			return -1;
  10.146 +		}
  10.147 +		track->keys = tmp;
  10.148 +		/* TODO lazy qsort */
  10.149 +		qsort(track->keys, ++track->count, sizeof *track->keys, keycmp);
  10.150 +	}
  10.151 +	return 0;
  10.152 +}
  10.153 +
  10.154 +static int keycmp(const void *a, const void *b)
  10.155 +{
  10.156 +	return ((struct anm_keyframe*)a)->time - ((struct anm_keyframe*)b)->time;
  10.157 +}
  10.158 +
  10.159 +struct anm_keyframe *anm_get_keyframe(struct anm_track *track, int idx)
  10.160 +{
  10.161 +	if(idx < 0 || idx >= track->count) {
  10.162 +		return 0;
  10.163 +	}
  10.164 +	return track->keys + idx;
  10.165 +}
  10.166 +
  10.167 +int anm_get_key_interval(struct anm_track *track, anm_time_t tm)
  10.168 +{
  10.169 +	int last;
  10.170 +
  10.171 +	if(!track->count || tm < track->keys[0].time) {
  10.172 +		return -1;
  10.173 +	}
  10.174 +
  10.175 +	last = track->count - 1;
  10.176 +	if(tm > track->keys[last].time) {
  10.177 +		return last;
  10.178 +	}
  10.179 +
  10.180 +	return find_prev_key(track->keys, 0, last, tm);
  10.181 +}
  10.182 +
  10.183 +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm)
  10.184 +{
  10.185 +	int mid;
  10.186 +
  10.187 +	if(end - start <= 1) {
  10.188 +		return start;
  10.189 +	}
  10.190 +
  10.191 +	mid = (start + end) / 2;
  10.192 +	if(tm < arr[mid].time) {
  10.193 +		return find_prev_key(arr, start, mid, tm);
  10.194 +	}
  10.195 +	if(tm > arr[mid].time) {
  10.196 +		return find_prev_key(arr, mid, end, tm);
  10.197 +	}
  10.198 +	return mid;
  10.199 +}
  10.200 +
  10.201 +int anm_set_value(struct anm_track *track, anm_time_t tm, float val)
  10.202 +{
  10.203 +	struct anm_keyframe key;
  10.204 +	key.time = tm;
  10.205 +	key.val = val;
  10.206 +
  10.207 +	return anm_set_keyframe(track, &key);
  10.208 +}
  10.209 +
  10.210 +float anm_get_value(struct anm_track *track, anm_time_t tm)
  10.211 +{
  10.212 +	int idx0, idx1, last_idx;
  10.213 +	anm_time_t tstart, tend;
  10.214 +	float t, dt;
  10.215 +	float v0, v1, v2, v3;
  10.216 +
  10.217 +	if(!track->count) {
  10.218 +		return track->def_val;
  10.219 +	}
  10.220 +
  10.221 +	last_idx = track->count - 1;
  10.222 +
  10.223 +	tstart = track->keys[0].time;
  10.224 +	tend = track->keys[last_idx].time;
  10.225 +
  10.226 +	if(tstart == tend) {
  10.227 +		return track->keys[0].val;
  10.228 +	}
  10.229 +
  10.230 +	tm = remap_time[track->extrap](tm, tstart, tend);
  10.231 +
  10.232 +	idx0 = anm_get_key_interval(track, tm);
  10.233 +	assert(idx0 >= 0 && idx0 < track->count);
  10.234 +	idx1 = idx0 + 1;
  10.235 +
  10.236 +	if(idx0 == last_idx) {
  10.237 +		return track->keys[idx0].val;
  10.238 +	}
  10.239 +
  10.240 +	dt = (float)(track->keys[idx1].time - track->keys[idx0].time);
  10.241 +	t = (float)(tm - track->keys[idx0].time) / dt;
  10.242 +
  10.243 +	v1 = track->keys[idx0].val;
  10.244 +	v2 = track->keys[idx1].val;
  10.245 +
  10.246 +	/* get the neigboring values to allow for cubic interpolation */
  10.247 +	v0 = idx0 > 0 ? track->keys[idx0 - 1].val : v1;
  10.248 +	v3 = idx1 < last_idx ? track->keys[idx1 + 1].val : v2;
  10.249 +
  10.250 +	return interp[track->interp](v0, v1, v2, v3, t);
  10.251 +}
  10.252 +
  10.253 +
  10.254 +static float interp_step(float v0, float v1, float v2, float v3, float t)
  10.255 +{
  10.256 +	return v1;
  10.257 +}
  10.258 +
  10.259 +static float interp_linear(float v0, float v1, float v2, float v3, float t)
  10.260 +{
  10.261 +	return v1 + (v2 - v1) * t;
  10.262 +}
  10.263 +
  10.264 +static float interp_cubic(float a, float b, float c, float d, float t)
  10.265 +{
  10.266 +	float x, y, z, w;
  10.267 +	float tsq = t * t;
  10.268 +
  10.269 +	x = -a + 3.0 * b - 3.0 * c + d;
  10.270 +	y = 2.0 * a - 5.0 * b + 4.0 * c - d;
  10.271 +	z = c - a;
  10.272 +	w = 2.0 * b;
  10.273 +
  10.274 +	return 0.5 * (x * tsq * t + y * tsq + z * t + w);
  10.275 +}
  10.276 +
  10.277 +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end)
  10.278 +{
  10.279 +	return remap_repeat(tm, start, end);
  10.280 +}
  10.281 +
  10.282 +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end)
  10.283 +{
  10.284 +	if(start == end) {
  10.285 +		return start;
  10.286 +	}
  10.287 +	return tm < start ? start : (tm >= end ? end - 1 : tm);
  10.288 +}
  10.289 +
  10.290 +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end)
  10.291 +{
  10.292 +	anm_time_t x, interv = end - start;
  10.293 +
  10.294 +	if(interv == 0) {
  10.295 +		return start;
  10.296 +	}
  10.297 +
  10.298 +	x = (tm - start) % interv;
  10.299 +	if(x < 0) {
  10.300 +		x += interv;
  10.301 +	}
  10.302 +	return x + start;
  10.303 +
  10.304 +	/*if(tm < start) {
  10.305 +		while(tm < start) {
  10.306 +			tm += interv;
  10.307 +		}
  10.308 +		return tm;
  10.309 +	}
  10.310 +	return (tm - start) % interv + start;*/
  10.311 +}
  10.312 +
  10.313 +static anm_time_t remap_pingpong(anm_time_t tm, anm_time_t start, anm_time_t end)
  10.314 +{
  10.315 +	anm_time_t interv = end - start;
  10.316 +	anm_time_t x = remap_repeat(tm, start, end + interv);
  10.317 +
  10.318 +	return x > end ? end + interv - x : x;
  10.319 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/anim/track.h	Sun Nov 09 13:03:36 2014 +0200
    11.3 @@ -0,0 +1,101 @@
    11.4 +/* An animation track defines the values of a single scalar over time
    11.5 + * and supports various interpolation and extrapolation modes.
    11.6 + */
    11.7 +#ifndef LIBANIM_TRACK_H_
    11.8 +#define LIBANIM_TRACK_H_
    11.9 +
   11.10 +#include <limits.h>
   11.11 +#include "config.h"
   11.12 +
   11.13 +enum anm_interpolator {
   11.14 +	ANM_INTERP_STEP,
   11.15 +	ANM_INTERP_LINEAR,
   11.16 +	ANM_INTERP_CUBIC
   11.17 +};
   11.18 +
   11.19 +enum anm_extrapolator {
   11.20 +	ANM_EXTRAP_EXTEND,	/* extend to infinity */
   11.21 +	ANM_EXTRAP_CLAMP,	/* clamp to last value */
   11.22 +	ANM_EXTRAP_REPEAT,	/* repeat motion */
   11.23 +	ANM_EXTRAP_PINGPONG	/* repeat with mirroring */
   11.24 +};
   11.25 +
   11.26 +typedef long anm_time_t;
   11.27 +#define ANM_TIME_INVAL	LONG_MIN
   11.28 +
   11.29 +#define ANM_SEC2TM(x)	((anm_time_t)((x) * 1000))
   11.30 +#define ANM_MSEC2TM(x)	((anm_time_t)(x))
   11.31 +#define ANM_TM2SEC(x)	((x) / 1000.0)
   11.32 +#define ANM_TM2MSEC(x)	(x)
   11.33 +
   11.34 +struct anm_keyframe {
   11.35 +	anm_time_t time;
   11.36 +	float val;
   11.37 +};
   11.38 +
   11.39 +struct anm_track {
   11.40 +	char *name;
   11.41 +	int count;
   11.42 +	struct anm_keyframe *keys;
   11.43 +
   11.44 +	float def_val;
   11.45 +
   11.46 +	enum anm_interpolator interp;
   11.47 +	enum anm_extrapolator extrap;
   11.48 +};
   11.49 +
   11.50 +#ifdef __cplusplus
   11.51 +extern "C" {
   11.52 +#endif
   11.53 +
   11.54 +/* track constructor and destructor */
   11.55 +int anm_init_track(struct anm_track *track);
   11.56 +void anm_destroy_track(struct anm_track *track);
   11.57 +
   11.58 +/* helper functions that use anm_init_track and anm_destroy_track internally */
   11.59 +struct anm_track *anm_create_track(void);
   11.60 +void anm_free_track(struct anm_track *track);
   11.61 +
   11.62 +/* copies track src to dest
   11.63 + * XXX: dest must have been initialized first
   11.64 + */
   11.65 +void anm_copy_track(struct anm_track *dest, struct anm_track *src);
   11.66 +
   11.67 +int anm_set_track_name(struct anm_track *track, const char *name);
   11.68 +const char *anm_get_track_name(struct anm_track *track);
   11.69 +
   11.70 +void anm_set_track_interpolator(struct anm_track *track, enum anm_interpolator in);
   11.71 +void anm_set_track_extrapolator(struct anm_track *track, enum anm_extrapolator ex);
   11.72 +
   11.73 +anm_time_t anm_remap_time(struct anm_track *track, anm_time_t tm, anm_time_t start, anm_time_t end);
   11.74 +
   11.75 +void anm_set_track_default(struct anm_track *track, float def);
   11.76 +
   11.77 +/* set or update a keyframe */
   11.78 +int anm_set_keyframe(struct anm_track *track, struct anm_keyframe *key);
   11.79 +
   11.80 +/* get the idx-th keyframe, returns null if it doesn't exist */
   11.81 +struct anm_keyframe *anm_get_keyframe(struct anm_track *track, int idx);
   11.82 +
   11.83 +/* Finds the 0-based index of the intra-keyframe interval which corresponds
   11.84 + * to the specified time. If the time falls exactly onto the N-th keyframe
   11.85 + * the function returns N.
   11.86 + *
   11.87 + * Special cases:
   11.88 + * - if the time is before the first keyframe -1 is returned.
   11.89 + * - if the time is after the last keyframe, the index of the last keyframe
   11.90 + *   is returned.
   11.91 + */
   11.92 +int anm_get_key_interval(struct anm_track *track, anm_time_t tm);
   11.93 +
   11.94 +int anm_set_value(struct anm_track *track, anm_time_t tm, float val);
   11.95 +
   11.96 +/* evaluates and returns the value of the track for a particular time */
   11.97 +float anm_get_value(struct anm_track *track, anm_time_t tm);
   11.98 +
   11.99 +#ifdef __cplusplus
  11.100 +}
  11.101 +#endif
  11.102 +
  11.103 +
  11.104 +#endif	/* LIBANIM_TRACK_H_ */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/sdr/postsdr.glsl	Sun Nov 09 13:03:36 2014 +0200
    12.3 @@ -0,0 +1,9 @@
    12.4 +uniform sampler2D fb;
    12.5 +
    12.6 +void main()
    12.7 +{
    12.8 +	vec4 pixel = texture2D(fb, gl_TexCoord[0].st);
    12.9 +
   12.10 +	gl_FragColor.rgb = pow(pixel.rgb, vec3(1.0 / 2.2));
   12.11 +	gl_FragColor.a = pixel.a;
   12.12 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/sdr/rt.glsl	Sun Nov 09 13:03:36 2014 +0200
    13.3 @@ -0,0 +1,523 @@
    13.4 +/* vi:set filetype=glsl ts=4 sw=4: */
    13.5 +#version 120
    13.6 +#extension GL_ARB_gpu_shader5 : enable
    13.7 +
    13.8 +#define M_PI	3.1415926
    13.9 +
   13.10 +#define INIT_EVERYTHING
   13.11 +#define USE_XFORM
   13.12 +#define OBJ_LINE_WIDTH	16.0
   13.13 +
   13.14 +struct Ray {
   13.15 +	vec3 origin, dir;
   13.16 +};
   13.17 +
   13.18 +struct Material {
   13.19 +	vec3 diffuse, specular;
   13.20 +	float shininess;
   13.21 +	vec4 megatex_rect;
   13.22 +	float reflectivity;
   13.23 +};
   13.24 +
   13.25 +struct HitPoint {
   13.26 +	float dist;
   13.27 +	vec3 pos, normal;
   13.28 +	vec2 texcoord;
   13.29 +	struct Material mat;
   13.30 +};
   13.31 +
   13.32 +struct Sphere {
   13.33 +	float index;
   13.34 +	vec3 pos;
   13.35 +	float radius;
   13.36 +	struct Material mat;
   13.37 +};
   13.38 +
   13.39 +struct Plane {
   13.40 +	float index;
   13.41 +	vec3 normal;
   13.42 +	float dist;
   13.43 +	struct Material mat;
   13.44 +};
   13.45 +
   13.46 +struct Box {
   13.47 +	float index;
   13.48 +	vec3 min, max;
   13.49 +	struct Material mat;
   13.50 +};
   13.51 +
   13.52 +struct Light {
   13.53 +	vec3 pos, color;
   13.54 +};
   13.55 +
   13.56 +vec3 shade(in Ray ray, in HitPoint hit);
   13.57 +bool find_intersection(in Ray ray, out HitPoint hit);
   13.58 +bool sphere_intersect(in Sphere sph, in Ray ray, out HitPoint pt);
   13.59 +bool plane_intersect(in Plane plane, in Ray ray, out HitPoint pt);
   13.60 +bool box_intersect(in Box box, in Ray ray, out HitPoint pt);
   13.61 +vec3 transform(in vec3 v, in mat4 inv_xform);
   13.62 +Ray transform(in Ray ray, in mat4 xform, in mat4 inv_xform);
   13.63 +Ray get_primary_ray();
   13.64 +
   13.65 +Sphere read_sphere(in float idx);
   13.66 +Plane read_plane(in float idx);
   13.67 +Box read_box(in float idx);
   13.68 +Material read_material(in sampler2D tex, in float ty);
   13.69 +void read_xform(in float idx, out mat4 xform, out mat4 inv_xform);
   13.70 +
   13.71 +uniform sampler2D tex_raydir;
   13.72 +uniform sampler2D tex_spheres, tex_planes, tex_boxes;
   13.73 +uniform sampler2D tex_megatex;
   13.74 +uniform sampler2D tex_xforms;
   13.75 +uniform samplerCube tex_env;
   13.76 +uniform vec2 fog;
   13.77 +
   13.78 +uniform Light lights[8];
   13.79 +uniform int num_lights;
   13.80 +
   13.81 +int num_spheres, num_planes, num_boxes;
   13.82 +float sph_tex_sz, plane_tex_sz, box_tex_sz, xform_tex_sz;
   13.83 +
   13.84 +#ifdef INIT_EVERYTHING
   13.85 +Material default_material;
   13.86 +#endif
   13.87 +
   13.88 +void main()
   13.89 +{
   13.90 +#ifdef INIT_EVERYTHING
   13.91 +	default_material.diffuse = default_material.specular = vec3(0.0, 0.0, 0.0);
   13.92 +	default_material.shininess = 1.0;
   13.93 +	default_material.reflectivity = 0.0;
   13.94 +	default_material.megatex_rect = vec4(0.0, 0.0, 0.0, 0.0);
   13.95 +#endif
   13.96 +
   13.97 +	Ray ray = get_primary_ray();
   13.98 +
   13.99 +	/* read the various descriptors specifying dimensions and counts for
  13.100 +	 * all the relevant data textures
  13.101 +	 */
  13.102 +	vec4 desc = texture2D(tex_spheres, vec2(0.0, 0.0));
  13.103 +	num_spheres = int(desc.x);
  13.104 +	sph_tex_sz = desc.y;
  13.105 +
  13.106 +	desc = texture2D(tex_planes, vec2(0.0, 0.0));
  13.107 +	num_planes = int(desc.x);
  13.108 +	plane_tex_sz = desc.y;
  13.109 +
  13.110 +	desc = texture2D(tex_boxes, vec2(0.0, 0.0));
  13.111 +	num_boxes = int(desc.x);
  13.112 +	box_tex_sz = desc.y;
  13.113 +
  13.114 +	xform_tex_sz = texture2D(tex_xforms, vec2(0.0, 0.0)).x;
  13.115 +
  13.116 +
  13.117 +	HitPoint hit;
  13.118 +#ifdef INIT_EVERYTHING
  13.119 +	hit.dist = 0.0;
  13.120 +	hit.pos = hit.normal = vec3(0.0, 0.0, 0.0);
  13.121 +#endif
  13.122 +
  13.123 +	vec3 color = vec3(0.0, 0.0, 0.0);
  13.124 +	float energy = 1.0;
  13.125 +
  13.126 +	int iter = 0;
  13.127 +	while(energy > 0.01 && iter++ < 4) {
  13.128 +		vec3 envcol = textureCube(tex_env, ray.dir).xyz;
  13.129 +
  13.130 +		if(find_intersection(ray, hit)) {
  13.131 +			float fog_t = clamp((hit.dist - fog.x) / (fog.y - fog.x), 0.0, 1.0);
  13.132 +			color += mix(shade(ray, hit), envcol, fog_t) * energy;
  13.133 +			energy *= hit.mat.reflectivity * (1.0 - fog_t);
  13.134 +			ray.origin = hit.pos;
  13.135 +			ray.dir = reflect(ray.dir, hit.normal);
  13.136 +		} else {
  13.137 +			color += envcol * energy;
  13.138 +			energy = 0.0;
  13.139 +			iter = 100;
  13.140 +		}
  13.141 +	}
  13.142 +
  13.143 +	gl_FragColor.xyz = color;
  13.144 +	gl_FragColor.w = 1.0;
  13.145 +}
  13.146 +
  13.147 +vec3 shade(in Ray ray, in HitPoint hit)
  13.148 +{
  13.149 +	vec3 normal = faceforward(hit.normal, ray.dir, hit.normal);
  13.150 +
  13.151 +	vec3 vdir = normalize(ray.dir);
  13.152 +	vec3 vref = reflect(vdir, normal);
  13.153 +
  13.154 +	/* if there's no texture rect.zw will be (0, 0, 0, 0) so this will map onto
  13.155 +	 * the top-left 1x1 null texture which is all white (having no effect)
  13.156 +	 */
  13.157 +	vec2 tc = mod(hit.texcoord, vec2(1.0, 1.0)) * hit.mat.megatex_rect.zw + hit.mat.megatex_rect.xy;
  13.158 +
  13.159 +	vec3 diffuse_color = hit.mat.diffuse * texture2D(tex_megatex, tc).xyz;
  13.160 +
  13.161 +	vec3 color = vec3(0.0, 0.0, 0.0);
  13.162 +	for(int i=0; i<num_lights; i++) {
  13.163 +		Ray shadow_ray;
  13.164 +		shadow_ray.origin = hit.pos;
  13.165 +		shadow_ray.dir = lights[i].pos - hit.pos;
  13.166 +
  13.167 +		HitPoint shadow_hit;
  13.168 +		if(!find_intersection(shadow_ray, shadow_hit) || shadow_hit.dist > 1.0) {
  13.169 +			vec3 ldir = normalize(shadow_ray.dir);
  13.170 +
  13.171 +			float diffuse = max(dot(ldir, normal), 0.0);
  13.172 +			float specular = pow(max(dot(ldir, vref), 0.0), hit.mat.shininess);
  13.173 +
  13.174 +			color += (diffuse_color * diffuse + hit.mat.specular * specular) * lights[i].color;
  13.175 +		}
  13.176 +	}
  13.177 +
  13.178 +	return color;
  13.179 +}
  13.180 +
  13.181 +bool find_intersection(in Ray ray, out HitPoint hit)
  13.182 +{
  13.183 +	hit.dist = 100000.0;
  13.184 +#ifdef INIT_EVERYTHING
  13.185 +	hit.pos = hit.normal = vec3(0.0, 0.0, 0.0);
  13.186 +	hit.mat = default_material;
  13.187 +	hit.texcoord = vec2(0.0, 0.0);
  13.188 +#endif
  13.189 +	bool found = false;
  13.190 +
  13.191 +	for(int i=0; i<num_spheres; i++) {
  13.192 +		Sphere sph = read_sphere(i);
  13.193 +
  13.194 +		HitPoint tmphit;
  13.195 +		if(sphere_intersect(sph, ray, tmphit) && tmphit.dist < hit.dist) {
  13.196 +			hit = tmphit;
  13.197 +			found = true;
  13.198 +		}
  13.199 +	}
  13.200 +
  13.201 +	for(int i=0; i<num_planes; i++) {
  13.202 +		Plane plane = read_plane(i);
  13.203 +
  13.204 +		HitPoint tmphit;
  13.205 +		if(plane_intersect(plane, ray, tmphit) && tmphit.dist < hit.dist) {
  13.206 +			hit = tmphit;
  13.207 +			found = true;
  13.208 +		}
  13.209 +	}
  13.210 +
  13.211 +	for(int i=0; i<num_boxes; i++) {
  13.212 +		Box box = read_box(i);
  13.213 +
  13.214 +		HitPoint tmphit;
  13.215 +		if(box_intersect(box, ray, tmphit) && tmphit.dist < hit.dist) {
  13.216 +			hit = tmphit;
  13.217 +			found = true;
  13.218 +		}
  13.219 +	}
  13.220 +
  13.221 +	return found;
  13.222 +}
  13.223 +
  13.224 +#define EPSILON	1e-4
  13.225 +#define SQ(x)	((x) * (x))
  13.226 +
  13.227 +bool sphere_intersect(in Sphere sph, in Ray inray, out HitPoint pt)
  13.228 +{
  13.229 +#ifdef USE_XFORM
  13.230 +	mat4 xform, inv_xform;
  13.231 +	read_xform(sph.index, xform, inv_xform);
  13.232 +
  13.233 +	Ray ray = transform(inray, inv_xform, xform);
  13.234 +#else
  13.235 +	Ray ray = inray;
  13.236 +#endif
  13.237 +
  13.238 +#ifdef INIT_EVERYTHING
  13.239 +	pt.dist = 0.0;
  13.240 +	pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
  13.241 +	pt.mat = default_material;
  13.242 +	pt.texcoord = vec2(0.0, 0.0);
  13.243 +#endif
  13.244 +
  13.245 +	float a = dot(ray.dir, ray.dir);
  13.246 +	float b = dot(ray.dir, ray.origin - sph.pos) * 2.0;
  13.247 +	float c = dot(ray.origin, ray.origin) + dot(sph.pos, sph.pos) -
  13.248 +		2.0 * dot(ray.origin, sph.pos) - sph.radius * sph.radius;
  13.249 +
  13.250 +	float discr = b * b - 4.0 * a * c;
  13.251 +	if(discr < EPSILON)
  13.252 +		return false;
  13.253 +
  13.254 +	float sqrt_discr = sqrt(discr);
  13.255 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
  13.256 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
  13.257 +
  13.258 +	if(t0 < EPSILON)
  13.259 +		t0 = t1;
  13.260 +	if(t1 < EPSILON)
  13.261 +		t1 = t0;
  13.262 +
  13.263 +	float t = min(t0, t1);
  13.264 +	if(t < EPSILON)
  13.265 +		return false;
  13.266 +
  13.267 +	// fill the HitPoint structure
  13.268 +	pt.dist = t;
  13.269 +	pt.pos = ray.origin + ray.dir * t;
  13.270 +	pt.normal = (pt.pos - sph.pos) / sph.radius;
  13.271 +	pt.mat = sph.mat;
  13.272 +
  13.273 +	pt.texcoord.x = 0.5 * atan(pt.normal.z, pt.normal.x) / M_PI + 0.5;
  13.274 +	pt.texcoord.y = acos(pt.normal.y) / M_PI;
  13.275 +
  13.276 +#ifdef USE_XFORM
  13.277 +	pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
  13.278 +	pt.normal = normalize(transform(pt.normal, xform));
  13.279 +#endif
  13.280 +	return true;
  13.281 +}
  13.282 +
  13.283 +bool plane_intersect(in Plane plane, in Ray inray, out HitPoint pt)
  13.284 +{
  13.285 +#ifdef USE_XFORM
  13.286 +	mat4 xform, inv_xform;
  13.287 +	read_xform(plane.index, xform, inv_xform);
  13.288 +
  13.289 +	Ray ray = transform(inray, inv_xform, xform);
  13.290 +#else
  13.291 +	Ray ray = inray;
  13.292 +#endif
  13.293 +
  13.294 +#ifdef INIT_EVERYTHING
  13.295 +	pt.dist = 0.0;
  13.296 +	pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
  13.297 +	pt.mat = default_material;
  13.298 +	pt.texcoord = vec2(0.0, 0.0);
  13.299 +#endif
  13.300 +
  13.301 +	float ndotdir = dot(plane.normal, ray.dir);
  13.302 +	if(abs(ndotdir) < EPSILON) {
  13.303 +		return false;
  13.304 +	}
  13.305 +
  13.306 +	vec3 planept = plane.normal * plane.dist;
  13.307 +	vec3 pptdir = planept - ray.origin;
  13.308 +
  13.309 +	float t = dot(plane.normal, pptdir) / ndotdir;
  13.310 +	if(t < EPSILON) {
  13.311 +		return false;
  13.312 +	}
  13.313 +
  13.314 +	pt.dist = t;
  13.315 +	pt.pos = ray.origin + ray.dir * t;
  13.316 +	pt.normal = plane.normal;
  13.317 +	pt.mat = plane.mat;
  13.318 +	pt.texcoord.x = pt.pos.x;
  13.319 +	pt.texcoord.y = pt.pos.z;
  13.320 +
  13.321 +#ifdef USE_XFORM
  13.322 +	pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
  13.323 +	pt.normal = normalize(transform(pt.normal, xform));
  13.324 +#endif
  13.325 +	return true;
  13.326 +}
  13.327 +
  13.328 +bool box_intersect(in Box box, in Ray inray, out HitPoint pt)
  13.329 +{
  13.330 +#ifdef USE_XFORM
  13.331 +	mat4 xform, inv_xform;
  13.332 +	read_xform(box.index, xform, inv_xform);
  13.333 +
  13.334 +	Ray ray = transform(inray, inv_xform, xform);
  13.335 +#else
  13.336 +	Ray ray = inray;
  13.337 +#endif
  13.338 +
  13.339 +#ifdef INIT_EVERYTHING
  13.340 +	pt.dist = 0.0;
  13.341 +	pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
  13.342 +	pt.mat = default_material;
  13.343 +	pt.texcoord = vec2(0.0, 0.0);
  13.344 +#endif
  13.345 +
  13.346 +	vec3 param[2];
  13.347 +	param[0] = box.min;
  13.348 +	param[1] = box.max;
  13.349 +
  13.350 +	vec3 inv_dir = 1.0 / ray.dir;
  13.351 +	int sgn[3];
  13.352 +	sgn[0] = inv_dir.x < 0.0 ? 1 : 0;
  13.353 +	sgn[1] = inv_dir.y < 0.0 ? 1 : 0;
  13.354 +	sgn[2] = inv_dir.z < 0.0 ? 1 : 0;
  13.355 +
  13.356 +	float tmin = (param[sgn[0]].x - ray.origin.x) * inv_dir.x;
  13.357 +	float tmax = (param[1 - sgn[0]].x - ray.origin.x) * inv_dir.x;
  13.358 +	float tymin = (param[sgn[1]].y - ray.origin.y) * inv_dir.y;
  13.359 +	float tymax = (param[1 - sgn[1]].y - ray.origin.y) * inv_dir.y;
  13.360 +
  13.361 +	pt.normal = vec3(ray.origin.x > 0.0 ? 1.0 : -1.0, 0.0, 0.0);
  13.362 +
  13.363 +	if(tmin > tymax || tymin > tmax) {
  13.364 +		return false;
  13.365 +	}
  13.366 +	if(tymin > tmin) {
  13.367 +		pt.normal = vec3(0.0, ray.origin.y > 0.0 ? 1.0 : -1.0, 0.0);
  13.368 +		tmin = tymin;
  13.369 +	}
  13.370 +	if(tymax < tmax) {
  13.371 +		tmax = tymax;
  13.372 +	}
  13.373 +
  13.374 +	float tzmin = (param[sgn[2]].z - ray.origin.z) * inv_dir.z;
  13.375 +	float tzmax = (param[1 - sgn[2]].z - ray.origin.z) * inv_dir.z;
  13.376 +
  13.377 +	if(tmin > tzmax || tzmin > tmax) {
  13.378 +		return false;
  13.379 +	}
  13.380 +	if(tzmin > tmin) {
  13.381 +		pt.normal = vec3(0.0, 0.0, ray.origin.z > 0.0 ? 1.0 : -1.0);
  13.382 +		tmin = tzmin;
  13.383 +	}
  13.384 +	if(tzmax < tmax) {
  13.385 +		tmax = tzmax;
  13.386 +	}
  13.387 +
  13.388 +	float t = tmin < EPSILON ? tmax : tmin;
  13.389 +	if(t >= 1e-4) {
  13.390 +		pt.dist = t;
  13.391 +		pt.pos = ray.origin + ray.dir * t;
  13.392 +		pt.mat = box.mat;
  13.393 +
  13.394 +		float min_dist = 10000.0;
  13.395 +
  13.396 +		vec3 offs = box.min + (box.max - box.min) / 2.0;
  13.397 +		vec3 local_pt = pt.pos - offs;
  13.398 +
  13.399 +		vec3 dist = abs((box.max - offs) - abs(local_pt));
  13.400 +		if(dist.x < min_dist) {
  13.401 +			min_dist = dist.x;
  13.402 +			pt.normal = sign(local_pt.x) * vec3(1.0, 0.0, 0.0);
  13.403 +			pt.texcoord = pt.pos.zy;
  13.404 +		}
  13.405 +		if(dist.y < min_dist) {
  13.406 +			min_dist = dist.y;
  13.407 +			pt.normal = sign(local_pt.y) * vec3(0.0, 1.0, 0.0);
  13.408 +			pt.texcoord = pt.pos.xz;
  13.409 +		}
  13.410 +		if(dist.z < min_dist) {
  13.411 +			pt.normal = sign(local_pt.y) * vec3(0.0, 0.0, 1.0);
  13.412 +			pt.texcoord = pt.pos.xy;
  13.413 +		}
  13.414 +
  13.415 +
  13.416 +#ifdef USE_XFORM
  13.417 +		pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
  13.418 +		pt.normal = normalize(transform(pt.normal, xform));
  13.419 +#endif
  13.420 +		return true;
  13.421 +	}
  13.422 +	return false;
  13.423 +}
  13.424 +
  13.425 +vec3 transform(in vec3 v, in mat4 xform)
  13.426 +{
  13.427 +	return mat3(xform) * v;
  13.428 +}
  13.429 +
  13.430 +Ray transform(in Ray ray, in mat4 xform, in mat4 inv_xform)
  13.431 +{
  13.432 +	Ray res;
  13.433 +	res.origin = (xform * vec4(ray.origin, 1.0)).xyz;
  13.434 +	res.dir = transform(ray.dir, xform);
  13.435 +	return res;
  13.436 +}
  13.437 +
  13.438 +Ray get_primary_ray()
  13.439 +{
  13.440 +	Ray ray;
  13.441 +	ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
  13.442 +	vec3 dir = texture2D(tex_raydir, gl_TexCoord[0].st).xyz;
  13.443 +	ray.dir = normalize(gl_NormalMatrix * dir);
  13.444 +	return ray;
  13.445 +}
  13.446 +
  13.447 +#define ITEM(x)	((float(x) + 0.5) / OBJ_LINE_WIDTH)
  13.448 +
  13.449 +Sphere read_sphere(in float idx)
  13.450 +{
  13.451 +	Sphere sph;
  13.452 +	// +1 because the first scanline is the descriptor
  13.453 +	float ty = (idx + 1.0) / sph_tex_sz;
  13.454 +
  13.455 +	sph.index = texture2D(tex_spheres, vec2(ITEM(0), ty)).x;
  13.456 +
  13.457 +	vec4 texel = texture2D(tex_spheres, vec2(ITEM(1), ty));
  13.458 +	sph.pos = texel.xyz;
  13.459 +	sph.radius = texel.w;
  13.460 +
  13.461 +	sph.mat = read_material(tex_spheres, ty);
  13.462 +	return sph;
  13.463 +}
  13.464 +
  13.465 +Plane read_plane(in float idx)
  13.466 +{
  13.467 +	Plane plane;
  13.468 +	// +1 (see above)
  13.469 +	float ty = (idx + 1.0) / plane_tex_sz;
  13.470 +
  13.471 +	plane.index = texture2D(tex_planes, vec2(ITEM(0), ty)).x;
  13.472 +
  13.473 +	vec4 texel = texture2D(tex_planes, vec2(ITEM(1), ty));
  13.474 +	plane.normal = texel.xyz;
  13.475 +	plane.dist = texel.w;
  13.476 +
  13.477 +	plane.mat = read_material(tex_planes, ty);
  13.478 +	return plane;
  13.479 +}
  13.480 +
  13.481 +Box read_box(in float idx)
  13.482 +{
  13.483 +	Box box;
  13.484 +	float ty = (idx + 1.0) / box_tex_sz;
  13.485 +
  13.486 +	box.index = texture2D(tex_boxes, vec2(ITEM(0), ty)).x;
  13.487 +
  13.488 +	box.min = texture2D(tex_boxes, vec2(ITEM(1), ty)).xyz;
  13.489 +	box.max = texture2D(tex_boxes, vec2(ITEM(2), ty)).xyz;
  13.490 +
  13.491 +	box.mat = read_material(tex_boxes, ty);
  13.492 +	return box;
  13.493 +}
  13.494 +
  13.495 +void read_xform(in float idx, out mat4 xform, out mat4 inv_xform)
  13.496 +{
  13.497 +	float ty = (idx + 1.0) / xform_tex_sz;
  13.498 +
  13.499 +	for(int i=0; i<4; i++) {
  13.500 +		xform[i] = texture2D(tex_xforms, vec2(ITEM(i), ty));
  13.501 +	}
  13.502 +	inv_xform = inverse(xform);
  13.503 +	/*for(int i=0; i<4; i++) {
  13.504 +		inv_xform[i] = texture2D(tex_xforms, vec2(ITEM(float(i) + 4.0), ty));
  13.505 +	}*/
  13.506 +}
  13.507 +
  13.508 +#define MAT_START	4
  13.509 +Material read_material(in sampler2D tex, in float ty)
  13.510 +{
  13.511 +	Material mat;
  13.512 +
  13.513 +	vec4 texel = texture2D(tex, vec2(ITEM(MAT_START), ty));
  13.514 +	mat.diffuse = texel.xyz;
  13.515 +
  13.516 +	texel = texture2D(tex, vec2(ITEM(MAT_START + 1), ty));
  13.517 +	mat.specular = texel.xyz;
  13.518 +	mat.shininess = texel.w;
  13.519 +
  13.520 +	texel = texture2D(tex, vec2(ITEM(MAT_START + 2), ty));
  13.521 +	mat.reflectivity = texel.x;
  13.522 +
  13.523 +	mat.megatex_rect = texture2D(tex, vec2(ITEM(MAT_START + 3), ty));
  13.524 +
  13.525 +	return mat;
  13.526 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/sdr/vertex.glsl	Sun Nov 09 13:03:36 2014 +0200
    14.3 @@ -0,0 +1,6 @@
    14.4 +void main()
    14.5 +{
    14.6 +	gl_Position = gl_Vertex;
    14.7 +	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
    14.8 +	gl_TexCoord[1] = gl_MultiTexCoord0;
    14.9 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/box.cc	Sun Nov 09 13:03:36 2014 +0200
    15.3 @@ -0,0 +1,63 @@
    15.4 +#include "box.h"
    15.5 +
    15.6 +Box::Box()
    15.7 +	: min(-0.5, -0.5, -0.5), max(0.5, 0.5, 0.5)
    15.8 +{
    15.9 +}
   15.10 +
   15.11 +Box::Box(const Vector3 &min_arg, const Vector3 &max_arg)
   15.12 +	: min(min_arg), max(max_arg)
   15.13 +{
   15.14 +}
   15.15 +
   15.16 +bool Box::intersect(const Ray &inray, HitPoint *pt) const
   15.17 +{
   15.18 +	Ray ray = inray.transformed(inv_xform);
   15.19 +
   15.20 +	Vector3 param[2] = {min, max};
   15.21 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
   15.22 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
   15.23 +
   15.24 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
   15.25 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
   15.26 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
   15.27 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
   15.28 +
   15.29 +	pt->normal = Vector3(ray.origin.x > 0.0 ? 1 : -1, 0, 0);
   15.30 +
   15.31 +	if(tmin > tymax || tymin > tmax) {
   15.32 +		return false;
   15.33 +	}
   15.34 +	if(tymin > tmin) {
   15.35 +		pt->normal = Vector3(0, ray.origin.y > 0.0 ? 1 : -1, 0);
   15.36 +		tmin = tymin;
   15.37 +	}
   15.38 +	if(tymax < tmax) {
   15.39 +		tmax = tymax;
   15.40 +	}
   15.41 +
   15.42 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
   15.43 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
   15.44 +
   15.45 +	if(tmin > tzmax || tzmin > tmax) {
   15.46 +		return false;
   15.47 +	}
   15.48 +	if(tzmin > tmin) {
   15.49 +		pt->normal = Vector3(0, 0, ray.origin.z > 0.0 ? 1 : -1);
   15.50 +		tmin = tzmin;
   15.51 +	}
   15.52 +	if(tzmax < tmax) {
   15.53 +		tmax = tzmax;
   15.54 +	}
   15.55 +
   15.56 +	float t = tmin < 1e-4 ? tmax : tmin;
   15.57 +	if(t >= 1e-4) {
   15.58 +		pt->obj = this;
   15.59 +		pt->dist = t;
   15.60 +		pt->pos = ray.origin + ray.dir * t;
   15.61 +		pt->pos.transform(xform);
   15.62 +		pt->normal.transform(dir_xform);
   15.63 +		return true;
   15.64 +	}
   15.65 +	return false;
   15.66 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/box.h	Sun Nov 09 13:03:36 2014 +0200
    16.3 @@ -0,0 +1,17 @@
    16.4 +#ifndef BOX_H_
    16.5 +#define BOX_H_
    16.6 +
    16.7 +#include "vmath/vmath.h"
    16.8 +#include "object.h"
    16.9 +
   16.10 +class Box : public Object {
   16.11 +public:
   16.12 +	Vector3 min, max;
   16.13 +
   16.14 +	Box();
   16.15 +	Box(const Vector3 &min, const Vector3 &max);
   16.16 +
   16.17 +	bool intersect(const Ray &ray, HitPoint *pt) const;
   16.18 +};
   16.19 +
   16.20 +#endif	// BOX_H_
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/camera.cc	Sun Nov 09 13:03:36 2014 +0200
    17.3 @@ -0,0 +1,199 @@
    17.4 +#include <stdio.h>
    17.5 +#include <math.h>
    17.6 +#include "camera.h"
    17.7 +
    17.8 +static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos);
    17.9 +
   17.10 +Camera::Camera()
   17.11 +{
   17.12 +	vfov = M_PI / 4.0;
   17.13 +	cached_matrix_valid = false;
   17.14 +
   17.15 +	rdir_cache_width = rdir_cache_height = 0;
   17.16 +	rdir_cache = 0;
   17.17 +}
   17.18 +
   17.19 +Camera::Camera(const Vector3 &p)
   17.20 +	: pos(p)
   17.21 +{
   17.22 +	vfov = M_PI / 4.0;
   17.23 +	cached_matrix_valid = false;
   17.24 +
   17.25 +	rdir_cache_width = rdir_cache_height = 0;
   17.26 +	rdir_cache = 0;
   17.27 +}
   17.28 +
   17.29 +Camera::~Camera()
   17.30 +{
   17.31 +	delete [] rdir_cache;
   17.32 +}
   17.33 +
   17.34 +void Camera::set_fov(float vfov)
   17.35 +{
   17.36 +	this->vfov = vfov;
   17.37 +
   17.38 +	// invalidate the dir cache
   17.39 +	delete [] rdir_cache;
   17.40 +}
   17.41 +
   17.42 +float Camera::get_fov() const
   17.43 +{
   17.44 +	return vfov;
   17.45 +}
   17.46 +
   17.47 +void Camera::set_position(const Vector3 &pos)
   17.48 +{
   17.49 +	this->pos = pos;
   17.50 +	cached_matrix_valid = false;	// invalidate the cached matrix
   17.51 +}
   17.52 +
   17.53 +const Vector3 &Camera::get_position() const
   17.54 +{
   17.55 +	return pos;
   17.56 +}
   17.57 +
   17.58 +const Matrix4x4 &Camera::get_matrix() const
   17.59 +{
   17.60 +	if(!cached_matrix_valid) {
   17.61 +		calc_matrix(&cached_matrix);
   17.62 +		cached_matrix_valid = true;
   17.63 +	}
   17.64 +	return cached_matrix;
   17.65 +}
   17.66 +
   17.67 +Vector2 Camera::calc_sample_pos(int x, int y, int xsz, int ysz, int sample) const
   17.68 +{
   17.69 +	float ppos[2];
   17.70 +	float aspect = (float)xsz / (float)ysz;
   17.71 +
   17.72 +	float pwidth = 2.0 * aspect / (float)xsz;
   17.73 +	float pheight = 2.0 / (float)ysz;
   17.74 +
   17.75 +	ppos[0] = (float)x * pwidth - aspect;
   17.76 +	ppos[1] = 1.0 - (float)y * pheight;
   17.77 +
   17.78 +	calc_sample_pos_rec(sample, pwidth, pheight, ppos);
   17.79 +	return Vector2(ppos[0], ppos[1]);
   17.80 +}
   17.81 +
   17.82 +Ray Camera::get_primary_ray(int x, int y, int xsz, int ysz, int sample) const
   17.83 +{
   17.84 +	if(!rdir_cache || rdir_cache_width != xsz || rdir_cache_height != ysz) {
   17.85 +		printf("calculating primary ray direction cache\n");
   17.86 +
   17.87 +		delete [] rdir_cache;
   17.88 +		rdir_cache = new Vector3[xsz * ysz];
   17.89 +
   17.90 +		for(int i=0; i<ysz; i++) {
   17.91 +			Vector3 *rdir = rdir_cache + i * xsz;
   17.92 +			for(int j=0; j<xsz; j++) {
   17.93 +				Vector2 ppos = calc_sample_pos(j, i, xsz, ysz, 0);
   17.94 +
   17.95 +				rdir->x = ppos.x;
   17.96 +				rdir->y = ppos.y;
   17.97 +				rdir->z = 1.0 / tan(vfov / 2.0);
   17.98 +				rdir->normalize();
   17.99 +
  17.100 +				rdir++;
  17.101 +			}
  17.102 +		}
  17.103 +		rdir_cache_width = xsz;
  17.104 +		rdir_cache_height = ysz;
  17.105 +	}
  17.106 +
  17.107 +	Ray ray;
  17.108 +	ray.origin = pos;
  17.109 +	ray.dir = rdir_cache[y * xsz + x];
  17.110 +
  17.111 +	// transform the ray direction with the camera matrix
  17.112 +	Matrix4x4 mat = get_matrix();
  17.113 +	mat.m[0][3] = mat.m[1][3] = mat.m[2][3] = mat.m[3][0] = mat.m[3][1] = mat.m[3][2] = 0.0;
  17.114 +	mat.m[3][3] = 1.0;
  17.115 +
  17.116 +	ray.dir = ray.dir.transformed(mat);
  17.117 +	return ray;
  17.118 +}
  17.119 +
  17.120 +TargetCamera::TargetCamera() {}
  17.121 +
  17.122 +TargetCamera::TargetCamera(const Vector3 &pos, const Vector3 &targ)
  17.123 +	: Camera(pos), target(targ)
  17.124 +{
  17.125 +}
  17.126 +
  17.127 +void TargetCamera::set_target(const Vector3 &targ)
  17.128 +{
  17.129 +	target = targ;
  17.130 +	cached_matrix_valid = false; // invalidate the cached matrix
  17.131 +}
  17.132 +
  17.133 +const Vector3 &TargetCamera::get_target() const
  17.134 +{
  17.135 +	return target;
  17.136 +}
  17.137 +
  17.138 +void TargetCamera::calc_matrix(Matrix4x4 *mat) const
  17.139 +{
  17.140 +	Vector3 up(0, 1, 0);
  17.141 +	Vector3 dir = (target - pos).normalized();
  17.142 +	Vector3 right = cross_product(up, dir);
  17.143 +	up = cross_product(dir, right);
  17.144 +
  17.145 +	*mat = Matrix4x4(
  17.146 +			right.x, up.x, dir.x, pos.x,
  17.147 +			right.y, up.y, dir.y, pos.y,
  17.148 +			right.z, up.z, dir.z, pos.z,
  17.149 +			0.0, 0.0, 0.0, 1.0);
  17.150 +}
  17.151 +
  17.152 +void FlyCamera::input_move(float x, float y, float z)
  17.153 +{
  17.154 +	static const Vector3 vfwd(0, 0, 1), vright(1, 0, 0);
  17.155 +
  17.156 +	Vector3 k = vfwd.transformed(rot);
  17.157 +	Vector3	i = vright.transformed(rot);
  17.158 +	Vector3 j = cross_product(k, i);
  17.159 +
  17.160 +	pos += i * x + j * y + k * z;
  17.161 +	cached_matrix_valid = false;
  17.162 +}
  17.163 +
  17.164 +void FlyCamera::input_rotate(float x, float y, float z)
  17.165 +{
  17.166 +	Vector3 axis(x, y, z);
  17.167 +	float axis_len = axis.length();
  17.168 +	if(fabs(axis_len) < 1e-5) {
  17.169 +		return;
  17.170 +	}
  17.171 +	rot.rotate(axis / axis_len, -axis_len);
  17.172 +	rot.normalize();
  17.173 +
  17.174 +	cached_matrix_valid = false;
  17.175 +}
  17.176 +
  17.177 +void FlyCamera::calc_matrix(Matrix4x4 *mat) const
  17.178 +{
  17.179 +	Matrix3x3 rmat = rot.get_rotation_matrix();
  17.180 +	*mat = rmat;
  17.181 +}
  17.182 +
  17.183 +/* generates a sample position for sample number sidx, in the unit square
  17.184 + * by recursive subdivision and jittering
  17.185 + */
  17.186 +static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos)
  17.187 +{
  17.188 +    static const float subpt[4][2] = {
  17.189 +        {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25}
  17.190 +    };
  17.191 +
  17.192 +    if(!sidx) {
  17.193 +        return;
  17.194 +    }
  17.195 +
  17.196 +    /* determine which quadrant to recurse into */
  17.197 +    int quadrant = ((sidx - 1) % 4);
  17.198 +    pos[0] += subpt[quadrant][0] * xsz;
  17.199 +    pos[1] += subpt[quadrant][1] * ysz;
  17.200 +
  17.201 +    calc_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos);
  17.202 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/camera.h	Sun Nov 09 13:03:36 2014 +0200
    18.3 @@ -0,0 +1,61 @@
    18.4 +#ifndef CAMERA_H_
    18.5 +#define CAMERA_H_
    18.6 +
    18.7 +#include "vmath/vmath.h"
    18.8 +
    18.9 +class Camera {
   18.10 +protected:
   18.11 +	Vector3 pos;
   18.12 +	float vfov;	// vertical field of view in radians
   18.13 +
   18.14 +	mutable Matrix4x4 cached_matrix;
   18.15 +	mutable bool cached_matrix_valid;
   18.16 +
   18.17 +	mutable Vector3 *rdir_cache;
   18.18 +	mutable int rdir_cache_width, rdir_cache_height;
   18.19 +
   18.20 +	virtual void calc_matrix(Matrix4x4 *mat) const = 0;
   18.21 +
   18.22 +	Vector2 calc_sample_pos(int x, int y, int xsz, int ysz, int sample) const;
   18.23 +
   18.24 +public:
   18.25 +	Camera();
   18.26 +	Camera(const Vector3 &pos);
   18.27 +	virtual ~Camera();
   18.28 +
   18.29 +	virtual void set_fov(float vfov);
   18.30 +	virtual float get_fov() const;
   18.31 +
   18.32 +	virtual void set_position(const Vector3 &pos);
   18.33 +	virtual const Vector3 &get_position() const;
   18.34 +	virtual const Matrix4x4 &get_matrix() const;
   18.35 +
   18.36 +	virtual Ray get_primary_ray(int x, int y, int xsz, int ysz, int sample = 0) const;
   18.37 +};
   18.38 +
   18.39 +class TargetCamera : public Camera {
   18.40 +protected:
   18.41 +	Vector3 target;
   18.42 +
   18.43 +	void calc_matrix(Matrix4x4 *mat) const;
   18.44 +
   18.45 +public:
   18.46 +	TargetCamera();
   18.47 +	TargetCamera(const Vector3 &pos, const Vector3 &targ);
   18.48 +
   18.49 +	virtual void set_target(const Vector3 &targ);
   18.50 +	virtual const Vector3 &get_target() const;
   18.51 +};
   18.52 +
   18.53 +class FlyCamera : public Camera {
   18.54 +protected:
   18.55 +	Quaternion rot;
   18.56 +
   18.57 +	void calc_matrix(Matrix4x4 *mat) const;
   18.58 +
   18.59 +public:
   18.60 +	void input_move(float x, float y, float z);
   18.61 +	void input_rotate(float x, float y, float z);
   18.62 +};
   18.63 +
   18.64 +#endif	// CAMERA_H_
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/glsdr.c	Sun Nov 09 13:03:36 2014 +0200
    19.3 @@ -0,0 +1,411 @@
    19.4 +#include <stdio.h>
    19.5 +#include <stdlib.h>
    19.6 +#include <string.h>
    19.7 +#include <errno.h>
    19.8 +#include <stdarg.h>
    19.9 +#include <assert.h>
   19.10 +#include <GL/glew.h>
   19.11 +
   19.12 +#if defined(unix) || defined(__unix__)
   19.13 +#include <unistd.h>
   19.14 +#include <sys/stat.h>
   19.15 +#endif	/* unix */
   19.16 +
   19.17 +#include "glsdr.h"
   19.18 +
   19.19 +static const char *sdrtypestr(unsigned int sdrtype);
   19.20 +
   19.21 +unsigned int create_vertex_shader(const char *src)
   19.22 +{
   19.23 +	return create_shader(src, GL_VERTEX_SHADER);
   19.24 +}
   19.25 +
   19.26 +unsigned int create_pixel_shader(const char *src)
   19.27 +{
   19.28 +	return create_shader(src, GL_FRAGMENT_SHADER);
   19.29 +}
   19.30 +
   19.31 +unsigned int create_tessctl_shader(const char *src)
   19.32 +{
   19.33 +	return create_shader(src, GL_TESS_CONTROL_SHADER);
   19.34 +}
   19.35 +
   19.36 +unsigned int create_tesseval_shader(const char *src)
   19.37 +{
   19.38 +	return create_shader(src, GL_TESS_EVALUATION_SHADER);
   19.39 +}
   19.40 +
   19.41 +unsigned int create_geometry_shader(const char *src)
   19.42 +{
   19.43 +	return create_shader(src, GL_GEOMETRY_SHADER);
   19.44 +}
   19.45 +
   19.46 +unsigned int create_shader(const char *src, unsigned int sdr_type)
   19.47 +{
   19.48 +	unsigned int sdr;
   19.49 +	int success, info_len;
   19.50 +	char *info_str = 0;
   19.51 +	GLenum err;
   19.52 +
   19.53 +	sdr = glCreateShader(sdr_type);
   19.54 +	assert(glGetError() == GL_NO_ERROR);
   19.55 +	glShaderSource(sdr, 1, &src, 0);
   19.56 +	err = glGetError();
   19.57 +	assert(err == GL_NO_ERROR);
   19.58 +	glCompileShader(sdr);
   19.59 +	assert(glGetError() == GL_NO_ERROR);
   19.60 +
   19.61 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
   19.62 +	assert(glGetError() == GL_NO_ERROR);
   19.63 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
   19.64 +	assert(glGetError() == GL_NO_ERROR);
   19.65 +
   19.66 +	if(info_len) {
   19.67 +		if((info_str = malloc(info_len + 1))) {
   19.68 +			glGetShaderInfoLog(sdr, info_len, 0, info_str);
   19.69 +			assert(glGetError() == GL_NO_ERROR);
   19.70 +		}
   19.71 +	}
   19.72 +
   19.73 +	if(success) {
   19.74 +		fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
   19.75 +	} else {
   19.76 +		fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
   19.77 +		glDeleteShader(sdr);
   19.78 +		sdr = 0;
   19.79 +	}
   19.80 +
   19.81 +	free(info_str);
   19.82 +	return sdr;
   19.83 +}
   19.84 +
   19.85 +void free_shader(unsigned int sdr)
   19.86 +{
   19.87 +	glDeleteShader(sdr);
   19.88 +}
   19.89 +
   19.90 +unsigned int load_vertex_shader(const char *fname)
   19.91 +{
   19.92 +	return load_shader(fname, GL_VERTEX_SHADER);
   19.93 +}
   19.94 +
   19.95 +unsigned int load_pixel_shader(const char *fname)
   19.96 +{
   19.97 +	return load_shader(fname, GL_FRAGMENT_SHADER);
   19.98 +}
   19.99 +
  19.100 +unsigned int load_tessctl_shader(const char *fname)
  19.101 +{
  19.102 +	return load_shader(fname, GL_TESS_CONTROL_SHADER);
  19.103 +}
  19.104 +
  19.105 +unsigned int load_tesseval_shader(const char *fname)
  19.106 +{
  19.107 +	return load_shader(fname, GL_TESS_EVALUATION_SHADER);
  19.108 +}
  19.109 +
  19.110 +unsigned int load_geometry_shader(const char *fname)
  19.111 +{
  19.112 +	return load_shader(fname, GL_GEOMETRY_SHADER);
  19.113 +}
  19.114 +
  19.115 +unsigned int load_shader(const char *fname, unsigned int sdr_type)
  19.116 +{
  19.117 +#if defined(unix) || defined(__unix__)
  19.118 +	struct stat st;
  19.119 +#endif
  19.120 +	unsigned int sdr;
  19.121 +	size_t filesize;
  19.122 +	FILE *fp;
  19.123 +	char *src;
  19.124 +
  19.125 +	if(!(fp = fopen(fname, "r"))) {
  19.126 +		fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
  19.127 +		return 0;
  19.128 +	}
  19.129 +
  19.130 +#if defined(unix) || defined(__unix__)
  19.131 +	fstat(fileno(fp), &st);
  19.132 +	filesize = st.st_size;
  19.133 +#else
  19.134 +	fseek(fp, 0, SEEK_END);
  19.135 +	filesize = ftell(fp);
  19.136 +	fseek(fp, 0, SEEK_SET);
  19.137 +#endif	/* unix */
  19.138 +
  19.139 +	if(!(src = malloc(filesize + 1))) {
  19.140 +		fclose(fp);
  19.141 +		return 0;
  19.142 +	}
  19.143 +	fread(src, 1, filesize, fp);
  19.144 +	src[filesize] = 0;
  19.145 +	fclose(fp);
  19.146 +
  19.147 +	fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
  19.148 +	sdr = create_shader(src, sdr_type);
  19.149 +
  19.150 +	free(src);
  19.151 +	return sdr;
  19.152 +}
  19.153 +
  19.154 +
  19.155 +unsigned int get_vertex_shader(const char *fname)
  19.156 +{
  19.157 +	return get_shader(fname, GL_VERTEX_SHADER);
  19.158 +}
  19.159 +
  19.160 +unsigned int get_pixel_shader(const char *fname)
  19.161 +{
  19.162 +	return get_shader(fname, GL_FRAGMENT_SHADER);
  19.163 +}
  19.164 +
  19.165 +unsigned int get_tessctl_shader(const char *fname)
  19.166 +{
  19.167 +	return get_shader(fname, GL_TESS_CONTROL_SHADER);
  19.168 +}
  19.169 +
  19.170 +unsigned int get_tesseval_shader(const char *fname)
  19.171 +{
  19.172 +	return get_shader(fname, GL_TESS_EVALUATION_SHADER);
  19.173 +}
  19.174 +
  19.175 +unsigned int get_geometry_shader(const char *fname)
  19.176 +{
  19.177 +	return get_shader(fname, GL_GEOMETRY_SHADER);
  19.178 +}
  19.179 +
  19.180 +unsigned int get_shader(const char *fname, unsigned int sdr_type)
  19.181 +{
  19.182 +	unsigned int sdr;
  19.183 +	if(!(sdr = load_shader(fname, sdr_type))) {
  19.184 +		return 0;
  19.185 +	}
  19.186 +	return sdr;
  19.187 +}
  19.188 +
  19.189 +
  19.190 +/* ---- gpu programs ---- */
  19.191 +
  19.192 +unsigned int create_program(void)
  19.193 +{
  19.194 +	unsigned int prog = glCreateProgram();
  19.195 +	assert(glGetError() == GL_NO_ERROR);
  19.196 +	return prog;
  19.197 +}
  19.198 +
  19.199 +unsigned int create_program_link(unsigned int sdr0, ...)
  19.200 +{
  19.201 +	unsigned int prog, sdr;
  19.202 +	va_list ap;
  19.203 +
  19.204 +	if(!(prog = create_program())) {
  19.205 +		return 0;
  19.206 +	}
  19.207 +
  19.208 +	attach_shader(prog, sdr0);
  19.209 +	if(glGetError()) {
  19.210 +		return 0;
  19.211 +	}
  19.212 +
  19.213 +	va_start(ap, sdr0);
  19.214 +	while((sdr = va_arg(ap, unsigned int))) {
  19.215 +		attach_shader(prog, sdr);
  19.216 +		if(glGetError()) {
  19.217 +			return 0;
  19.218 +		}
  19.219 +	}
  19.220 +	va_end(ap);
  19.221 +
  19.222 +	if(link_program(prog) == -1) {
  19.223 +		free_program(prog);
  19.224 +		return 0;
  19.225 +	}
  19.226 +	return prog;
  19.227 +}
  19.228 +
  19.229 +unsigned int create_program_load(const char *vfile, const char *pfile)
  19.230 +{
  19.231 +	unsigned int sdr[2];
  19.232 +	int i = 0;
  19.233 +
  19.234 +	if(vfile && *vfile && !(sdr[i++] = get_vertex_shader(vfile))) {
  19.235 +		return 0;
  19.236 +	}
  19.237 +	if(pfile && *pfile && !(sdr[i++] = get_pixel_shader(pfile))) {
  19.238 +		return 0;
  19.239 +	}
  19.240 +	return create_program_link(sdr[0], sdr[1], 0);
  19.241 +}
  19.242 +
  19.243 +void free_program(unsigned int sdr)
  19.244 +{
  19.245 +	glDeleteProgram(sdr);
  19.246 +}
  19.247 +
  19.248 +void attach_shader(unsigned int prog, unsigned int sdr)
  19.249 +{
  19.250 +	glAttachShader(prog, sdr);
  19.251 +	assert(glGetError() == GL_NO_ERROR);
  19.252 +}
  19.253 +
  19.254 +int link_program(unsigned int prog)
  19.255 +{
  19.256 +	int linked, info_len, retval = 0;
  19.257 +	char *info_str = 0;
  19.258 +
  19.259 +	glLinkProgram(prog);
  19.260 +	assert(glGetError() == GL_NO_ERROR);
  19.261 +	glGetProgramiv(prog, GL_LINK_STATUS, &linked);
  19.262 +	assert(glGetError() == GL_NO_ERROR);
  19.263 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
  19.264 +	assert(glGetError() == GL_NO_ERROR);
  19.265 +
  19.266 +	if(info_len) {
  19.267 +		if((info_str = malloc(info_len + 1))) {
  19.268 +			glGetProgramInfoLog(prog, info_len, 0, info_str);
  19.269 +			assert(glGetError() == GL_NO_ERROR);
  19.270 +		}
  19.271 +	}
  19.272 +
  19.273 +	if(linked) {
  19.274 +		fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
  19.275 +	} else {
  19.276 +		fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
  19.277 +		retval = -1;
  19.278 +	}
  19.279 +
  19.280 +	free(info_str);
  19.281 +	return retval;
  19.282 +}
  19.283 +
  19.284 +int bind_program(unsigned int prog)
  19.285 +{
  19.286 +	GLenum err;
  19.287 +
  19.288 +	glUseProgram(prog);
  19.289 +	if(prog && (err = glGetError()) != GL_NO_ERROR) {
  19.290 +		/* maybe the program is not linked, try linking first */
  19.291 +		if(err == GL_INVALID_OPERATION) {
  19.292 +			if(link_program(prog) == -1) {
  19.293 +				return -1;
  19.294 +			}
  19.295 +			glUseProgram(prog);
  19.296 +			return glGetError() == GL_NO_ERROR ? 0 : -1;
  19.297 +		}
  19.298 +		return -1;
  19.299 +	}
  19.300 +	return 0;
  19.301 +}
  19.302 +
  19.303 +/* ugly but I'm not going to write the same bloody code over and over */
  19.304 +#define BEGIN_UNIFORM_CODE \
  19.305 +	int loc, curr_prog; \
  19.306 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
  19.307 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
  19.308 +		return -1; \
  19.309 +	} \
  19.310 +	if((loc = glGetUniformLocation(prog, name)) != -1)
  19.311 +
  19.312 +#define END_UNIFORM_CODE \
  19.313 +	if((unsigned int)curr_prog != prog) { \
  19.314 +		bind_program(curr_prog); \
  19.315 +	} \
  19.316 +	return loc == -1 ? -1 : 0
  19.317 +
  19.318 +int set_uniform_int(unsigned int prog, const char *name, int val)
  19.319 +{
  19.320 +	BEGIN_UNIFORM_CODE {
  19.321 +		glUniform1i(loc, val);
  19.322 +	}
  19.323 +	END_UNIFORM_CODE;
  19.324 +}
  19.325 +
  19.326 +int set_uniform_float(unsigned int prog, const char *name, float val)
  19.327 +{
  19.328 +	BEGIN_UNIFORM_CODE {
  19.329 +		glUniform1f(loc, val);
  19.330 +	}
  19.331 +	END_UNIFORM_CODE;
  19.332 +}
  19.333 +
  19.334 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
  19.335 +{
  19.336 +	BEGIN_UNIFORM_CODE {
  19.337 +		glUniform2f(loc, x, y);
  19.338 +	}
  19.339 +	END_UNIFORM_CODE;
  19.340 +}
  19.341 +
  19.342 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
  19.343 +{
  19.344 +	BEGIN_UNIFORM_CODE {
  19.345 +		glUniform3f(loc, x, y, z);
  19.346 +	}
  19.347 +	END_UNIFORM_CODE;
  19.348 +}
  19.349 +
  19.350 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
  19.351 +{
  19.352 +	BEGIN_UNIFORM_CODE {
  19.353 +		glUniform4f(loc, x, y, z, w);
  19.354 +	}
  19.355 +	END_UNIFORM_CODE;
  19.356 +}
  19.357 +
  19.358 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat)
  19.359 +{
  19.360 +	BEGIN_UNIFORM_CODE {
  19.361 +		glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
  19.362 +	}
  19.363 +	END_UNIFORM_CODE;
  19.364 +}
  19.365 +
  19.366 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat)
  19.367 +{
  19.368 +	BEGIN_UNIFORM_CODE {
  19.369 +		glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
  19.370 +	}
  19.371 +	END_UNIFORM_CODE;
  19.372 +}
  19.373 +
  19.374 +int get_attrib_loc(unsigned int prog, const char *name)
  19.375 +{
  19.376 +	int loc, curr_prog;
  19.377 +
  19.378 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
  19.379 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
  19.380 +		return -1;
  19.381 +	}
  19.382 +
  19.383 +	loc = glGetAttribLocation(prog, (char*)name);
  19.384 +
  19.385 +	if((unsigned int)curr_prog != prog) {
  19.386 +		bind_program(curr_prog);
  19.387 +	}
  19.388 +	return loc;
  19.389 +}
  19.390 +
  19.391 +void set_attrib_float3(int attr_loc, float x, float y, float z)
  19.392 +{
  19.393 +	glVertexAttrib3f(attr_loc, x, y, z);
  19.394 +}
  19.395 +
  19.396 +static const char *sdrtypestr(unsigned int sdrtype)
  19.397 +{
  19.398 +	switch(sdrtype) {
  19.399 +	case GL_VERTEX_SHADER:
  19.400 +		return "vertex";
  19.401 +	case GL_FRAGMENT_SHADER:
  19.402 +		return "pixel";
  19.403 +	case GL_TESS_CONTROL_SHADER:
  19.404 +		return "tessellation control";
  19.405 +	case GL_TESS_EVALUATION_SHADER:
  19.406 +		return "tessellation evaluation";
  19.407 +	case GL_GEOMETRY_SHADER:
  19.408 +		return "geometry";
  19.409 +
  19.410 +	default:
  19.411 +		break;
  19.412 +	}
  19.413 +	return "<unknown>";
  19.414 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/glsdr.h	Sun Nov 09 13:03:36 2014 +0200
    20.3 @@ -0,0 +1,59 @@
    20.4 +#ifndef SDR_H_
    20.5 +#define SDR_H_
    20.6 +
    20.7 +#ifdef __cplusplus
    20.8 +extern "C" {
    20.9 +#endif	/* __cplusplus */
   20.10 +
   20.11 +/* ---- shaders ---- */
   20.12 +unsigned int create_vertex_shader(const char *src);
   20.13 +unsigned int create_pixel_shader(const char *src);
   20.14 +unsigned int create_tessctl_shader(const char *src);
   20.15 +unsigned int create_tesseval_shader(const char *src);
   20.16 +unsigned int create_geometry_shader(const char *src);
   20.17 +unsigned int create_shader(const char *src, unsigned int sdr_type);
   20.18 +void free_shader(unsigned int sdr);
   20.19 +
   20.20 +unsigned int load_vertex_shader(const char *fname);
   20.21 +unsigned int load_pixel_shader(const char *fname);
   20.22 +unsigned int load_tessctl_shader(const char *fname);
   20.23 +unsigned int load_tesseval_shader(const char *fname);
   20.24 +unsigned int load_geometry_shader(const char *fname);
   20.25 +unsigned int load_shader(const char *src, unsigned int sdr_type);
   20.26 +
   20.27 +unsigned int get_vertex_shader(const char *fname);
   20.28 +unsigned int get_pixel_shader(const char *fname);
   20.29 +unsigned int get_tessctl_shader(const char *fname);
   20.30 +unsigned int get_tesseval_shader(const char *fname);
   20.31 +unsigned int get_geometry_shader(const char *fname);
   20.32 +unsigned int get_shader(const char *fname, unsigned int sdr_type);
   20.33 +
   20.34 +int add_shader(const char *fname, unsigned int sdr);
   20.35 +int remove_shader(const char *fname);
   20.36 +
   20.37 +/* ---- gpu programs ---- */
   20.38 +unsigned int create_program(void);
   20.39 +unsigned int create_program_link(unsigned int sdr0, ...);
   20.40 +unsigned int create_program_load(const char *vfile, const char *pfile);
   20.41 +void free_program(unsigned int sdr);
   20.42 +
   20.43 +void attach_shader(unsigned int prog, unsigned int sdr);
   20.44 +int link_program(unsigned int prog);
   20.45 +int bind_program(unsigned int prog);
   20.46 +
   20.47 +int set_uniform_int(unsigned int prog, const char *name, int val);
   20.48 +int set_uniform_float(unsigned int prog, const char *name, float val);
   20.49 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y);
   20.50 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z);
   20.51 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w);
   20.52 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat);
   20.53 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat);
   20.54 +
   20.55 +int get_attrib_loc(unsigned int prog, const char *name);
   20.56 +void set_attrib_float3(int attr_loc, float x, float y, float z);
   20.57 +
   20.58 +#ifdef __cplusplus
   20.59 +}
   20.60 +#endif	/* __cplusplus */
   20.61 +
   20.62 +#endif	/* SDR_H_ */
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/gpuscene.cc	Sun Nov 09 13:03:36 2014 +0200
    21.3 @@ -0,0 +1,317 @@
    21.4 +#include <algorithm>
    21.5 +#include <assert.h>
    21.6 +#include "gpuscene.h"
    21.7 +#include "sphere.h"
    21.8 +#include "plane.h"
    21.9 +#include "box.h"
   21.10 +#include "opengl.h"
   21.11 +
   21.12 +GPUScene::GPUScene()
   21.13 +{
   21.14 +	glGenTextures(NUM_TEXTURES, textures);
   21.15 +
   21.16 +	for(int i=0; i<NUM_TEXTURES; i++) {
   21.17 +		glBindTexture(GL_TEXTURE_2D, textures[i]);
   21.18 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   21.19 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   21.20 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   21.21 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   21.22 +	}
   21.23 +
   21.24 +	xform_buf = 0;
   21.25 +}
   21.26 +
   21.27 +GPUScene::~GPUScene()
   21.28 +{
   21.29 +	glDeleteTextures(NUM_TEXTURES, textures);
   21.30 +	delete [] xform_buf;
   21.31 +}
   21.32 +
   21.33 +bool GPUScene::create_textures()
   21.34 +{
   21.35 +	// must be first to generate the megatecture rectangles
   21.36 +	create_megatexture();
   21.37 +
   21.38 +	Sphere *sph;
   21.39 +	Plane *plane;
   21.40 +	Box *box;
   21.41 +
   21.42 +	std::vector<Sphere*> spheres;
   21.43 +	std::vector<Plane*> planes;
   21.44 +	std::vector<Box*> boxes;
   21.45 +
   21.46 +	// collect all objects into the different type-specific arrays
   21.47 +	for(auto obj : objects) {
   21.48 +		if((sph = dynamic_cast<Sphere*>(obj))) {
   21.49 +			spheres.push_back(sph);
   21.50 +
   21.51 +		} else if((plane = dynamic_cast<Plane*>(obj))) {
   21.52 +			planes.push_back(plane);
   21.53 +
   21.54 +		} else if((box = dynamic_cast<Box*>(obj))) {
   21.55 +			boxes.push_back(box);
   21.56 +
   21.57 +		} else {
   21.58 +			fprintf(stderr, "skipping object of unknown type: %s\n", obj->get_name());
   21.59 +		}
   21.60 +	}
   21.61 +
   21.62 +	create_sphere_texture(spheres);
   21.63 +	create_plane_texture(planes);
   21.64 +	create_box_texture(boxes);
   21.65 +
   21.66 +	create_env_texture();
   21.67 +	create_xform_texture();
   21.68 +
   21.69 +	return true;
   21.70 +}
   21.71 +
   21.72 +unsigned int GPUScene::get_texture(int which) const
   21.73 +{
   21.74 +	return textures[which];
   21.75 +}
   21.76 +
   21.77 +#define MAT_START	4
   21.78 +static void copy_material(Vector4 *ptr, const Material *mtl)
   21.79 +{
   21.80 +	ptr[MAT_START].x = mtl->diffuse.x;
   21.81 +	ptr[MAT_START].y = mtl->diffuse.y;
   21.82 +	ptr[MAT_START].z = mtl->diffuse.z;
   21.83 +	ptr[MAT_START].w = mtl->transparency;
   21.84 +
   21.85 +	ptr[MAT_START + 1].x = mtl->specular.x;
   21.86 +	ptr[MAT_START + 1].y = mtl->specular.y;
   21.87 +	ptr[MAT_START + 1].z = mtl->specular.z;
   21.88 +	ptr[MAT_START + 1].w = mtl->shininess;
   21.89 +
   21.90 +	ptr[MAT_START + 2].x = mtl->reflectivity;
   21.91 +	ptr[MAT_START + 2].y = mtl->ior;
   21.92 +
   21.93 +	ptr[MAT_START + 3] = mtl->mega_rect;
   21.94 +}
   21.95 +
   21.96 +int GPUScene::object_index(const Object *obj) const
   21.97 +{
   21.98 +	for(int i=0; i<(int)objects.size(); i++) {
   21.99 +		if(objects[i] == obj) {
  21.100 +			return i;
  21.101 +		}
  21.102 +	}
  21.103 +	abort();	// can't happen
  21.104 +	return -1;
  21.105 +}
  21.106 +
  21.107 +#define OBJ_LINE_WIDTH	16
  21.108 +void GPUScene::create_sphere_texture(const std::vector<Sphere*> &spheres)
  21.109 +{
  21.110 +	int xsz = OBJ_LINE_WIDTH;
  21.111 +	int ysz = (int)spheres.size() + 1;
  21.112 +	int tex_ysz = next_pow2(ysz);
  21.113 +
  21.114 +	Vector4 *pixels = new Vector4[xsz * tex_ysz];
  21.115 +
  21.116 +	pixels[0].x = (float)ysz;
  21.117 +	pixels[0].y = (float)tex_ysz;
  21.118 +	pixels[0].z = 0.5;
  21.119 +	pixels[0].w = 1.0;
  21.120 +
  21.121 +	Vector4 *pixptr = pixels + xsz;
  21.122 +
  21.123 +	for(size_t i=0; i<spheres.size(); i++) {
  21.124 +		pixptr[0].x = object_index(spheres[i]);
  21.125 +
  21.126 +		pixptr[1].x = spheres[i]->pos.x;
  21.127 +		pixptr[1].y = spheres[i]->pos.y;
  21.128 +		pixptr[1].z = spheres[i]->pos.z;
  21.129 +		pixptr[1].w = spheres[i]->radius;
  21.130 +
  21.131 +		copy_material(pixptr, &spheres[i]->material);
  21.132 +		pixptr += OBJ_LINE_WIDTH;
  21.133 +	}
  21.134 +
  21.135 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_SPHERE]);
  21.136 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
  21.137 +
  21.138 +	delete [] pixels;
  21.139 +}
  21.140 +
  21.141 +void GPUScene::create_plane_texture(const std::vector<Plane*> &planes)
  21.142 +{
  21.143 +	int xsz = OBJ_LINE_WIDTH;
  21.144 +	int ysz = (int)planes.size() + 1;
  21.145 +	int tex_ysz = next_pow2(ysz);
  21.146 +
  21.147 +	Vector4 *pixels = new Vector4[xsz * tex_ysz];
  21.148 +
  21.149 +	pixels[0].x = (float)ysz;
  21.150 +	pixels[0].y = (float)tex_ysz;
  21.151 +
  21.152 +	Vector4 *pixptr = pixels + xsz;
  21.153 +
  21.154 +	for(size_t i=0; i<planes.size(); i++) {
  21.155 +		pixptr[0].x = object_index(planes[i]);
  21.156 +
  21.157 +		pixptr[1].x = planes[i]->normal.x;
  21.158 +		pixptr[1].y = planes[i]->normal.y;
  21.159 +		pixptr[1].z = planes[i]->normal.z;
  21.160 +		pixptr[1].w = planes[i]->dist;
  21.161 +
  21.162 +		copy_material(pixptr, &planes[i]->material);
  21.163 +		pixptr += OBJ_LINE_WIDTH;
  21.164 +	}
  21.165 +
  21.166 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_PLANE]);
  21.167 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
  21.168 +
  21.169 +	delete [] pixels;
  21.170 +}
  21.171 +
  21.172 +void GPUScene::create_box_texture(const std::vector<Box*> &boxes)
  21.173 +{
  21.174 +	int xsz = OBJ_LINE_WIDTH;
  21.175 +	int ysz = (int)boxes.size() + 1;
  21.176 +	int tex_ysz = next_pow2(ysz);
  21.177 +
  21.178 +	Vector4 *pixels = new Vector4[xsz * tex_ysz];
  21.179 +
  21.180 +	pixels[0].x = (float)ysz;
  21.181 +	pixels[0].y = (float)tex_ysz;
  21.182 +
  21.183 +	Vector4 *pixptr = pixels + xsz;
  21.184 +
  21.185 +	for(size_t i=0; i<boxes.size(); i++) {
  21.186 +		pixptr[0].x = object_index(boxes[i]);
  21.187 +		pixptr[1] = boxes[i]->min;
  21.188 +		pixptr[2] = boxes[i]->max;
  21.189 +
  21.190 +		copy_material(pixptr, &boxes[i]->material);
  21.191 +		pixptr += OBJ_LINE_WIDTH;
  21.192 +	}
  21.193 +
  21.194 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_BOX]);
  21.195 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
  21.196 +
  21.197 +	delete [] pixels;
  21.198 +}
  21.199 +
  21.200 +void GPUScene::create_megatexture()
  21.201 +{
  21.202 +	// at least a 1x1 dummy white texture
  21.203 +	int xsz = 1;
  21.204 +	int ysz = 1;
  21.205 +	int num_textures = 0;
  21.206 +
  21.207 +	for(auto obj : objects) {
  21.208 +		// only need 2D textures at this point
  21.209 +		Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
  21.210 +		if(tex) {
  21.211 +			const Image *img = tex->get_image();
  21.212 +
  21.213 +			xsz = std::max(xsz, img->xsz);
  21.214 +			ysz += img->ysz;
  21.215 +			num_textures++;
  21.216 +		}
  21.217 +	}
  21.218 +
  21.219 +	int tex_xsz = next_pow2(xsz);
  21.220 +	int tex_ysz = next_pow2(ysz);
  21.221 +
  21.222 +	Color *pixels = new Color[tex_xsz * tex_ysz];
  21.223 +
  21.224 +	// null texture
  21.225 +	pixels[0] = Color(1, 1, 1);
  21.226 +
  21.227 +	Color *pixptr = pixels + tex_xsz;
  21.228 +
  21.229 +	float offs_y = 0.0;
  21.230 +	for(auto obj : objects) {
  21.231 +		Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
  21.232 +		if(tex) {
  21.233 +			const Image *img = tex->get_image();
  21.234 +
  21.235 +			Vector4 rect{0.0, offs_y, (float)img->xsz / (float)tex_xsz,
  21.236 +				(float)img->ysz / (float)tex_ysz};
  21.237 +
  21.238 +			offs_y += rect.w;
  21.239 +
  21.240 +			obj->material.mega_rect = rect;
  21.241 +
  21.242 +			for(int i=0; i<img->ysz; i++) {
  21.243 +				memcpy(pixptr, img->pixels + i * img->xsz, img->xsz * sizeof *pixels);
  21.244 +				pixptr += tex_xsz;
  21.245 +			}
  21.246 +		} else {
  21.247 +			obj->material.mega_rect = Vector4(0, 0, 0, 0);
  21.248 +		}
  21.249 +	}
  21.250 +
  21.251 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_TEXTURE]);
  21.252 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, pixels);
  21.253 +
  21.254 +	delete [] pixels;
  21.255 +}
  21.256 +
  21.257 +void GPUScene::create_env_texture()
  21.258 +{
  21.259 +	// create the scene cubemap, or a null cubemap if we don't have one
  21.260 +	glDeleteTextures(1, textures + TEX_ENV);	// cause it's not a 2D texture :)
  21.261 +
  21.262 +	glGenTextures(1, textures + TEX_ENV);
  21.263 +	glBindTexture(GL_TEXTURE_CUBE_MAP, textures[TEX_ENV]);
  21.264 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  21.265 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  21.266 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  21.267 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  21.268 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  21.269 +
  21.270 +	if(envmap) {
  21.271 +		// we have an environment cubemap, just pass the data to OpenGL
  21.272 +		for(int i=0; i<6; i++) {
  21.273 +			const Image *img = envmap->get_image(i);
  21.274 +
  21.275 +			int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
  21.276 +			glTexImage2D(face, 0, GL_RGB16F, img->xsz, img->ysz, 0, GL_RGB, GL_FLOAT, img->pixels);
  21.277 +		}
  21.278 +	} else {
  21.279 +		// we don't have an env cubemap, make a dummy 1x1 cubemap with the background color
  21.280 +		for(int i=0; i<6; i++) {
  21.281 +			int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
  21.282 +			glTexImage2D(face, 0, GL_RGB16F, 1, 1, 0, GL_RGB, GL_FLOAT, &bgcolor);
  21.283 +		}
  21.284 +	}
  21.285 +}
  21.286 +
  21.287 +#define XFORM_LINE_WIDTH	OBJ_LINE_WIDTH
  21.288 +void GPUScene::create_xform_texture()
  21.289 +{
  21.290 +	int tex_xsz = XFORM_LINE_WIDTH;
  21.291 +	int tex_ysz = next_pow2((int)objects.size() + 1);	// leave space for the descriptor
  21.292 +
  21.293 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
  21.294 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
  21.295 +
  21.296 +	update_xform_texture();
  21.297 +}
  21.298 +
  21.299 +void GPUScene::update_xform_texture()
  21.300 +{
  21.301 +	int tex_xsz = XFORM_LINE_WIDTH;
  21.302 +	int tex_ysz = next_pow2((int)objects.size() + 1);	// leave space for the descriptor
  21.303 +
  21.304 +	if(!xform_buf) {
  21.305 +		xform_buf = new Vector4[tex_xsz * tex_ysz];
  21.306 +		xform_buf[0].x = tex_ysz;	// descriptor
  21.307 +	}
  21.308 +
  21.309 +	Vector4 *pixptr = xform_buf + tex_xsz;
  21.310 +	for(auto obj : objects) {
  21.311 +		for(int i=0; i<4; i++) {
  21.312 +			pixptr[i] = obj->xform.get_column_vector(i);
  21.313 +			pixptr[i + 4] = obj->inv_xform.get_column_vector(i);
  21.314 +		}
  21.315 +		pixptr += tex_xsz;
  21.316 +	}
  21.317 +
  21.318 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
  21.319 +	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_xsz, tex_ysz, GL_RGBA, GL_FLOAT, xform_buf);
  21.320 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/gpuscene.h	Sun Nov 09 13:03:36 2014 +0200
    22.3 @@ -0,0 +1,38 @@
    22.4 +#ifndef GPUSCENE_H_
    22.5 +#define GPUSCENE_H_
    22.6 +
    22.7 +#include <vector>
    22.8 +#include "scene.h"
    22.9 +#include "sphere.h"
   22.10 +#include "plane.h"
   22.11 +#include "box.h"
   22.12 +
   22.13 +class GPUScene : public Scene {
   22.14 +public:
   22.15 +	enum { TEX_SPHERE, TEX_PLANE, TEX_BOX, TEX_TEXTURE, TEX_ENV, TEX_XFORM, NUM_TEXTURES };
   22.16 +
   22.17 +private:
   22.18 +	unsigned int textures[NUM_TEXTURES];
   22.19 +	Vector4 *xform_buf;
   22.20 +
   22.21 +	int object_index(const Object *obj) const;
   22.22 +
   22.23 +	void create_sphere_texture(const std::vector<Sphere*> &spheres);
   22.24 +	void create_plane_texture(const std::vector<Plane*> &planes);
   22.25 +	void create_box_texture(const std::vector<Box*> &box);
   22.26 +	void create_megatexture();
   22.27 +	void create_env_texture();
   22.28 +	void create_xform_texture();
   22.29 +
   22.30 +public:
   22.31 +	GPUScene();
   22.32 +	~GPUScene();
   22.33 +
   22.34 +	bool create_textures();
   22.35 +
   22.36 +	void update_xform_texture();
   22.37 +
   22.38 +	unsigned int get_texture(int which) const;
   22.39 +};
   22.40 +
   22.41 +#endif	// GPUSCENE_H_
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/image.cc	Sun Nov 09 13:03:36 2014 +0200
    23.3 @@ -0,0 +1,69 @@
    23.4 +#include <stdio.h>
    23.5 +#include <string.h>
    23.6 +#include <errno.h>
    23.7 +#include "image.h"
    23.8 +#include "material.h"
    23.9 +#include <imago2.h>
   23.10 +
   23.11 +Image::Image()
   23.12 +{
   23.13 +	pixels = 0;
   23.14 +	xsz = ysz = 0;
   23.15 +}
   23.16 +
   23.17 +Image::Image(int xsz, int ysz)
   23.18 +{
   23.19 +	pixels = 0;
   23.20 +	set_pixels(xsz, ysz, 0);
   23.21 +}
   23.22 +
   23.23 +Image::~Image()
   23.24 +{
   23.25 +	delete [] pixels;
   23.26 +}
   23.27 +
   23.28 +void Image::set_pixels(int xsz, int ysz, const Color *pix)
   23.29 +{
   23.30 +	delete [] pixels;
   23.31 +
   23.32 +	pixels = new Color[xsz * ysz];
   23.33 +	this->xsz = xsz;
   23.34 +	this->ysz = ysz;
   23.35 +
   23.36 +	if(pix) {
   23.37 +		memcpy(pixels, pix, xsz * ysz * sizeof *pixels);
   23.38 +	}
   23.39 +}
   23.40 +
   23.41 +bool Image::load(const char *fname)
   23.42 +{
   23.43 +	int xsz, ysz;
   23.44 +	Color *img = (Color*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBF);
   23.45 +	if(!img) {
   23.46 +		return false;
   23.47 +	}
   23.48 +
   23.49 +	/* convert the pixels to linear color space */
   23.50 +	for(int i=0; i<xsz*ysz; i++) {
   23.51 +		img[i].x = pow(img[i].x, 2.2);
   23.52 +		img[i].y = pow(img[i].y, 2.2);
   23.53 +		img[i].z = pow(img[i].z, 2.2);
   23.54 +	}
   23.55 +
   23.56 +	set_pixels(xsz, ysz, img);
   23.57 +	img_free_pixels(img);
   23.58 +	return true;
   23.59 +}
   23.60 +
   23.61 +
   23.62 +bool Image::save(const char *fname) const
   23.63 +{
   23.64 +	if(!pixels) {
   23.65 +		return false;
   23.66 +	}
   23.67 +
   23.68 +	if(img_save_pixels(fname, pixels, xsz, ysz, IMG_FMT_RGBAF) == -1) {
   23.69 +		return false;
   23.70 +	}
   23.71 +	return true;
   23.72 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/image.h	Sun Nov 09 13:03:36 2014 +0200
    24.3 @@ -0,0 +1,21 @@
    24.4 +#ifndef IMAGE_H_
    24.5 +#define IMAGE_H_
    24.6 +
    24.7 +#include "material.h"
    24.8 +
    24.9 +class Image {
   24.10 +public:
   24.11 +	Color *pixels;
   24.12 +	int xsz, ysz;
   24.13 +
   24.14 +	Image();
   24.15 +	Image(int xsz, int ysz);
   24.16 +	~Image();
   24.17 +
   24.18 +	void set_pixels(int xsz, int ysz, const Color *pix);
   24.19 +
   24.20 +	bool load(const char *fname);
   24.21 +	bool save(const char *fname) const;
   24.22 +};
   24.23 +
   24.24 +#endif	// IMAGE_H_
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/light.cc	Sun Nov 09 13:03:36 2014 +0200
    25.3 @@ -0,0 +1,28 @@
    25.4 +/*
    25.5 +Simple introductory ray tracer
    25.6 +Copyright (C) 2012  John Tsiombikas <nuclear@member.fsf.org>
    25.7 +
    25.8 +This program is free software: you can redistribute it and/or modify
    25.9 +it under the terms of the GNU General Public License as published by
   25.10 +the Free Software Foundation, either version 3 of the License, or
   25.11 +(at your option) any later version.
   25.12 +
   25.13 +This program is distributed in the hope that it will be useful,
   25.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   25.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   25.16 +GNU General Public License for more details.
   25.17 +
   25.18 +You should have received a copy of the GNU General Public License
   25.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   25.20 +*/
   25.21 +#include "light.h"
   25.22 +
   25.23 +Light::Light()
   25.24 +	: color(1, 1, 1)
   25.25 +{
   25.26 +}
   25.27 +
   25.28 +Light::Light(const Vector3 &p, const Color &col)
   25.29 +	: pos(p), color(col)
   25.30 +{
   25.31 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/light.h	Sun Nov 09 13:03:36 2014 +0200
    26.3 @@ -0,0 +1,33 @@
    26.4 +/*
    26.5 +Simple introductory ray tracer
    26.6 +Copyright (C) 2012  John Tsiombikas <nuclear@member.fsf.org>
    26.7 +
    26.8 +This program is free software: you can redistribute it and/or modify
    26.9 +it under the terms of the GNU General Public License as published by
   26.10 +the Free Software Foundation, either version 3 of the License, or
   26.11 +(at your option) any later version.
   26.12 +
   26.13 +This program is distributed in the hope that it will be useful,
   26.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   26.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   26.16 +GNU General Public License for more details.
   26.17 +
   26.18 +You should have received a copy of the GNU General Public License
   26.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   26.20 +*/
   26.21 +#ifndef LIGHT_H_
   26.22 +#define LIGHT_H_
   26.23 +
   26.24 +#include "vmath/vmath.h"
   26.25 +#include "material.h"
   26.26 +
   26.27 +class Light {
   26.28 +public:
   26.29 +	Vector3 pos;
   26.30 +	Color color;
   26.31 +
   26.32 +	Light();
   26.33 +	Light(const Vector3 &pos, const Color &col = Color(1, 1, 1));
   26.34 +};
   26.35 +
   26.36 +#endif	// LIGHT_H_
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/main.cc	Sun Nov 09 13:03:36 2014 +0200
    27.3 @@ -0,0 +1,396 @@
    27.4 +#include <stdio.h>
    27.5 +#include <stdlib.h>
    27.6 +#include <stdarg.h>
    27.7 +#include <assert.h>
    27.8 +#include "opengl.h"
    27.9 +
   27.10 +#include "gpuscene.h"
   27.11 +#include "sphere.h"
   27.12 +#include "plane.h"
   27.13 +#include "image.h"
   27.14 +#include "rend.h"
   27.15 +#include "glsdr.h"
   27.16 +
   27.17 +static bool init(const char *scene_fname);
   27.18 +static void cleanup();
   27.19 +static void disp();
   27.20 +static void draw_text(float r, float g, float b, const char *fmt, ...);
   27.21 +//static void update_texture(const float *fb);
   27.22 +static void idle();
   27.23 +static void reshape(int x, int y);
   27.24 +static void handle_keys(float dt);
   27.25 +static void keyb(unsigned char key, int x, int y);
   27.26 +static void keyb_up(unsigned char key, int x, int y);
   27.27 +static void skeyb(int key, int x, int y);
   27.28 +static void mouse(int bn, int st, int x, int y);
   27.29 +static void motion(int x, int y);
   27.30 +static void sball_motion(int x, int y, int z);
   27.31 +static void sball_rotate(int x, int y, int z);
   27.32 +static void sball_button(int bn, int state);
   27.33 +
   27.34 +static unsigned int tex;
   27.35 +static long last_fps_upd, first_time = -1;
   27.36 +static long frames, total_frames;
   27.37 +static float fps;
   27.38 +static int xsz = 800;
   27.39 +static int ysz = 450;
   27.40 +//static int tex_xsz, tex_ysz;
   27.41 +
   27.42 +static GPUScene *scn;
   27.43 +static FlyCamera *cam;
   27.44 +
   27.45 +static float img_scale = 1.0f;
   27.46 +static bool keystate[256];
   27.47 +
   27.48 +static char *scene_fname;
   27.49 +static bool sdr_valid = true;
   27.50 +
   27.51 +int main(int argc, char **argv)
   27.52 +{
   27.53 +	glutInit(&argc, argv);
   27.54 +
   27.55 +	int num_samples = 1;
   27.56 +
   27.57 +	for(int i=1; i<argc; i++) {
   27.58 +		if(argv[i][0] == '-') {
   27.59 +			if(strcmp(argv[i], "-size") == 0) {
   27.60 +				if(sscanf(argv[++i], "%dx%d", &xsz, &ysz) < 2) {
   27.61 +					fprintf(stderr, "-size must be followed by the image resolution (WxH)\n");
   27.62 +					return 1;
   27.63 +				}
   27.64 +
   27.65 +			} else if(strcmp(argv[i], "-samples") == 0) {
   27.66 +				num_samples = atoi(argv[++i]);
   27.67 +				if(num_samples <= 0) {
   27.68 +					fprintf(stderr, "-samples must be followed by the number of samples per pixel\n");
   27.69 +					return 1;
   27.70 +				}
   27.71 +			} else if(strcmp(argv[i], "-scale") == 0) {
   27.72 +				img_scale = atof(argv[++i]);
   27.73 +				if(img_scale <= 1.0f) {
   27.74 +					fprintf(stderr, "-scale must be followed by an image scale factor >= 1\n");
   27.75 +					return 1;
   27.76 +				}
   27.77 +			} else {
   27.78 +				fprintf(stderr, "invalid option: %s\n", argv[i]);
   27.79 +				return 1;
   27.80 +			}
   27.81 +		} else {
   27.82 +			if(scene_fname) {
   27.83 +				fprintf(stderr, "unexpected argument: %s\n", argv[i]);
   27.84 +				return 1;
   27.85 +			}
   27.86 +			scene_fname = argv[i];
   27.87 +		}
   27.88 +	}
   27.89 +
   27.90 +	glutInitWindowSize(xsz * img_scale, ysz * img_scale);
   27.91 +	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
   27.92 +	glutCreateWindow("single threaded");
   27.93 +
   27.94 +	glutDisplayFunc(disp);
   27.95 +	glutIdleFunc(idle);
   27.96 +	glutReshapeFunc(reshape);
   27.97 +	glutKeyboardFunc(keyb);
   27.98 +	glutKeyboardUpFunc(keyb_up);
   27.99 +	glutSpecialFunc(skeyb);
  27.100 +	glutMouseFunc(mouse);
  27.101 +	glutMotionFunc(motion);
  27.102 +	glutSpaceballMotionFunc(sball_motion);
  27.103 +	glutSpaceballRotateFunc(sball_rotate);
  27.104 +	glutSpaceballButtonFunc(sball_button);
  27.105 +
  27.106 +	glewInit();
  27.107 +
  27.108 +	if(!init(scene_fname)) {
  27.109 +		return 1;
  27.110 +	}
  27.111 +	atexit(cleanup);
  27.112 +
  27.113 +	glutMainLoop();
  27.114 +	return 0;
  27.115 +}
  27.116 +
  27.117 +static bool init(const char *scene_fname)
  27.118 +{
  27.119 +	scn = new GPUScene;
  27.120 +	if(!scn->load(scene_fname ? scene_fname : "scene")) {
  27.121 +		return false;
  27.122 +	}
  27.123 +
  27.124 +	cam = new FlyCamera;
  27.125 +	cam->input_move(0, 1.5, -10);
  27.126 +	cam->input_rotate(25, 0, 0);
  27.127 +	scn->set_camera(cam);
  27.128 +
  27.129 +	if(!init_renderer(scn, xsz, ysz)) {
  27.130 +		return false;
  27.131 +	}
  27.132 +
  27.133 +	glGenTextures(1, &tex);
  27.134 +	glBindTexture(GL_TEXTURE_2D, tex);
  27.135 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  27.136 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  27.137 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  27.138 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  27.139 +
  27.140 +	int srgb_capable;
  27.141 +	if(GLEW_EXT_framebuffer_sRGB && (glGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgb_capable), srgb_capable)) {
  27.142 +		printf("enabling sRGB framebuffer\n");
  27.143 +		glEnable(GL_FRAMEBUFFER_SRGB);
  27.144 +	} else {
  27.145 +		printf("using post shader for gamma correction\n");
  27.146 +		unsigned int post_sdr = create_program_load(0, "sdr/postsdr.glsl");
  27.147 +		if(post_sdr) {
  27.148 +			glUseProgram(post_sdr);
  27.149 +		}
  27.150 +	}
  27.151 +
  27.152 +	last_fps_upd = glutGet(GLUT_ELAPSED_TIME);
  27.153 +	first_time = last_fps_upd;
  27.154 +	total_frames = 0;
  27.155 +	return true;
  27.156 +}
  27.157 +
  27.158 +static void cleanup()
  27.159 +{
  27.160 +	long interval = glutGet(GLUT_ELAPSED_TIME) - first_time;
  27.161 +	printf("average fps: %.2f\n", (float)total_frames / ((float)interval / 1000.0f));
  27.162 +
  27.163 +	glDeleteTextures(1, &tex);
  27.164 +
  27.165 +	destroy_renderer();
  27.166 +	delete scn;
  27.167 +}
  27.168 +
  27.169 +static void disp()
  27.170 +{
  27.171 +	static long prev_msec;
  27.172 +	long interval, msec = glutGet(GLUT_ELAPSED_TIME);
  27.173 +
  27.174 +	handle_keys((msec - prev_msec) / 1000.0f);
  27.175 +	prev_msec = msec;
  27.176 +
  27.177 +	//update_texture();
  27.178 +	if(sdr_valid) {
  27.179 +		render_frame(msec);
  27.180 +	} else {
  27.181 +		glUseProgram(0);
  27.182 +		glMatrixMode(GL_MODELVIEW);
  27.183 +		glLoadIdentity();
  27.184 +		glMatrixMode(GL_PROJECTION);
  27.185 +		glLoadIdentity();
  27.186 +
  27.187 +		glLineWidth(8.0);
  27.188 +		glBegin(GL_LINES);
  27.189 +		glColor3f(1, 0, 0);
  27.190 +		glVertex2f(-1, -1);
  27.191 +		glVertex2f(1, 1);
  27.192 +		glVertex2f(-1, 1);
  27.193 +		glVertex2f(1, -1);
  27.194 +		glEnd();
  27.195 +		glLineWidth(1.0);
  27.196 +	}
  27.197 +
  27.198 +	draw_text(0.8, 0.75, 0, "fps: %.2f", fps);
  27.199 +
  27.200 +	glutSwapBuffers();
  27.201 +	frames++;
  27.202 +	total_frames++;
  27.203 +
  27.204 +	interval = (msec = glutGet(GLUT_ELAPSED_TIME)) - last_fps_upd;
  27.205 +	if(interval >= 2000) {
  27.206 +		float tm = (float)interval / 1000.0f;
  27.207 +		fps = (float)frames / tm;
  27.208 +		/*printf("%.2f fps         \r", (float)frames / tm);
  27.209 +		fflush(stdout);*/
  27.210 +		last_fps_upd = msec;
  27.211 +		frames = 0;
  27.212 +	}
  27.213 +}
  27.214 +
  27.215 +void draw_text(float r, float g, float b, const char *fmt, ...)
  27.216 +{
  27.217 +	char buf[256], *text = buf;
  27.218 +	va_list ap;
  27.219 +
  27.220 +	va_start(ap, fmt);
  27.221 +	vsprintf(buf, fmt, ap);
  27.222 +	va_end(ap);
  27.223 +
  27.224 +	glUseProgram(0);
  27.225 +
  27.226 +	glMatrixMode(GL_MODELVIEW);
  27.227 +	glPushMatrix();
  27.228 +	glLoadIdentity();
  27.229 +	glMatrixMode(GL_PROJECTION);
  27.230 +	glPushMatrix();
  27.231 +	glLoadIdentity();
  27.232 +	glOrtho(0, xsz, 0, ysz, -1, 1);
  27.233 +
  27.234 +	glColor3f(r, g, b);
  27.235 +	glRasterPos2f(2, 4);
  27.236 +	while(*text) {
  27.237 +		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *text++);
  27.238 +	}
  27.239 +	glColor3f(1, 1, 1);
  27.240 +
  27.241 +	glPopMatrix();
  27.242 +	glMatrixMode(GL_MODELVIEW);
  27.243 +	glPopMatrix();
  27.244 +}
  27.245 +
  27.246 +
  27.247 +/*
  27.248 +static void update_texture()
  27.249 +{
  27.250 +	int ntx = next_pow2(xsz);
  27.251 +	int nty = next_pow2(ysz);
  27.252 +
  27.253 +	if(ntx != tex_xsz || nty != tex_ysz) {
  27.254 +		tex_xsz = ntx;
  27.255 +		tex_ysz = nty;
  27.256 +
  27.257 +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, 0);
  27.258 +	}
  27.259 +}
  27.260 +*/
  27.261 +
  27.262 +static void idle()
  27.263 +{
  27.264 +	glutPostRedisplay();
  27.265 +}
  27.266 +
  27.267 +static void reshape(int x, int y)
  27.268 +{
  27.269 +	int tx, ty;
  27.270 +
  27.271 +	xsz = x / img_scale;
  27.272 +	ysz = y / img_scale;
  27.273 +
  27.274 +	glViewport(0, 0, x, y);
  27.275 +
  27.276 +	/* setup the texture matrix that maps just the visible area
  27.277 +	 * of the texture to [0, 1]
  27.278 +	 */
  27.279 +	tx = next_pow2(xsz);
  27.280 +	ty = next_pow2(ysz);
  27.281 +
  27.282 +	glMatrixMode(GL_TEXTURE);
  27.283 +	glLoadIdentity();
  27.284 +	glScalef((float)xsz / tx, (float)ysz / ty, 1.0f);
  27.285 +
  27.286 +	resize_renderer(xsz, ysz);
  27.287 +}
  27.288 +
  27.289 +static void handle_keys(float dt)
  27.290 +{
  27.291 +	Vector3 move;
  27.292 +	float tilt = 0.0f;
  27.293 +	float offs = dt * 8.0;
  27.294 +
  27.295 +	if(keystate['w']) {
  27.296 +		move.z += offs;
  27.297 +	}
  27.298 +	if(keystate['s']) {
  27.299 +		move.z -= offs;
  27.300 +	}
  27.301 +	if(keystate['d']) {
  27.302 +		move.x += offs;
  27.303 +	}
  27.304 +	if(keystate['a']) {
  27.305 +		move.x -= offs;
  27.306 +	}
  27.307 +
  27.308 +	if(keystate['q']) {
  27.309 +		tilt -= dt;
  27.310 +	}
  27.311 +	if(keystate['e']) {
  27.312 +		tilt += dt;
  27.313 +	}
  27.314 +
  27.315 +	cam->input_move(move.x, move.y, move.z);
  27.316 +	cam->input_rotate(0, 0, tilt);
  27.317 +}
  27.318 +
  27.319 +static void keyb(unsigned char key, int x, int y)
  27.320 +{
  27.321 +	keystate[key] = true;
  27.322 +
  27.323 +	switch(key) {
  27.324 +	case 27:
  27.325 +		exit(0);
  27.326 +
  27.327 +	case '`':
  27.328 +		sdr_valid = reload_shader();
  27.329 +		break;
  27.330 +	}
  27.331 +}
  27.332 +
  27.333 +static void keyb_up(unsigned char key, int x, int y)
  27.334 +{
  27.335 +	keystate[key] = false;
  27.336 +}
  27.337 +
  27.338 +static void skeyb(int key, int x, int y)
  27.339 +{
  27.340 +	switch(key) {
  27.341 +	case GLUT_KEY_F1:
  27.342 +		printf("reinitializing\n");
  27.343 +		cleanup();
  27.344 +		sdr_valid = init(scene_fname);
  27.345 +		break;
  27.346 +
  27.347 +	default:
  27.348 +		break;
  27.349 +	}
  27.350 +}
  27.351 +
  27.352 +static int prev_x, prev_y;
  27.353 +
  27.354 +static void mouse(int bn, int st, int x, int y)
  27.355 +{
  27.356 +	prev_x = x;
  27.357 +	prev_y = y;
  27.358 +}
  27.359 +
  27.360 +static void motion(int x, int y)
  27.361 +{
  27.362 +	int dx = x - prev_x;
  27.363 +	int dy = y - prev_y;
  27.364 +	prev_x = x;
  27.365 +	prev_y = y;
  27.366 +	cam->input_rotate(-dy * 0.01, -dx * 0.01,  0);
  27.367 +}
  27.368 +
  27.369 +static void sball_motion(int x, int y, int z)
  27.370 +{
  27.371 +	float fx = x * 0.01;
  27.372 +	float fy = y * 0.01;
  27.373 +	float fz = z * 0.01;
  27.374 +	cam->input_move(fx, fy, fz);
  27.375 +}
  27.376 +
  27.377 +static void sball_rotate(int x, int y, int z)
  27.378 +{
  27.379 +	float fx = x * 0.00025;
  27.380 +	float fy = y * 0.00025;
  27.381 +	float fz = z * 0.00025;
  27.382 +	cam->input_rotate(fx, fy, fz);
  27.383 +}
  27.384 +
  27.385 +static void sball_button(int bn, int state)
  27.386 +{
  27.387 +}
  27.388 +
  27.389 +
  27.390 +int next_pow2(int x)
  27.391 +{
  27.392 +	x--;
  27.393 +	x = (x >> 1) | x;
  27.394 +	x = (x >> 2) | x;
  27.395 +	x = (x >> 4) | x;
  27.396 +	x = (x >> 8) | x;
  27.397 +	x = (x >> 16) | x;
  27.398 +	return x + 1;
  27.399 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/material.cc	Sun Nov 09 13:03:36 2014 +0200
    28.3 @@ -0,0 +1,41 @@
    28.4 +/*
    28.5 +Simple introductory ray tracer
    28.6 +Copyright (C) 2012  John Tsiombikas <nuclear@member.fsf.org>
    28.7 +
    28.8 +This program is free software: you can redistribute it and/or modify
    28.9 +it under the terms of the GNU General Public License as published by
   28.10 +the Free Software Foundation, either version 3 of the License, or
   28.11 +(at your option) any later version.
   28.12 +
   28.13 +This program is distributed in the hope that it will be useful,
   28.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   28.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   28.16 +GNU General Public License for more details.
   28.17 +
   28.18 +You should have received a copy of the GNU General Public License
   28.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   28.20 +*/
   28.21 +#include "material.h"
   28.22 +
   28.23 +Material::Material()
   28.24 +	: diffuse(1.0, 1.0, 1.0), specular(0.0, 0.0, 0.0)
   28.25 +{
   28.26 +	shininess = 60.0;
   28.27 +	reflectivity = 0.0;
   28.28 +	transparency = 0.0;
   28.29 +	ior = 1.0;
   28.30 +
   28.31 +	tex = 0;
   28.32 +}
   28.33 +
   28.34 +Material::Material(const Color &dcol, const Color &scol, float spow,
   28.35 +		float refl, float refr, float ior)
   28.36 +	: diffuse(dcol), specular(scol)
   28.37 +{
   28.38 +	shininess = spow;
   28.39 +	reflectivity = refl;
   28.40 +	transparency = refr;
   28.41 +	this->ior = ior;
   28.42 +
   28.43 +	tex = 0;
   28.44 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/material.h	Sun Nov 09 13:03:36 2014 +0200
    29.3 @@ -0,0 +1,50 @@
    29.4 +/*
    29.5 +Simple introductory ray tracer
    29.6 +Copyright (C) 2012  John Tsiombikas <nuclear@member.fsf.org>
    29.7 +
    29.8 +This program is free software: you can redistribute it and/or modify
    29.9 +it under the terms of the GNU General Public License as published by
   29.10 +the Free Software Foundation, either version 3 of the License, or
   29.11 +(at your option) any later version.
   29.12 +
   29.13 +This program is distributed in the hope that it will be useful,
   29.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   29.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   29.16 +GNU General Public License for more details.
   29.17 +
   29.18 +You should have received a copy of the GNU General Public License
   29.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   29.20 +*/
   29.21 +#ifndef MATERIAL_H_
   29.22 +#define MATERIAL_H_
   29.23 +
   29.24 +#include "vmath/vmath.h"
   29.25 +
   29.26 +// colors are simply RGB vectors
   29.27 +typedef Vector3 Color;
   29.28 +
   29.29 +class Texture;
   29.30 +
   29.31 +class Material {
   29.32 +public:
   29.33 +	// phong model parameters
   29.34 +	Color diffuse;    // amount of diffuse light scattering (per color channel)
   29.35 +	Color specular;   // amount of specular light reflection (per color channel)
   29.36 +	float shininess;  // higher shininess values -> more focused specular refl.
   29.37 +
   29.38 +	Color emission;   // emissive light
   29.39 +
   29.40 +	// additional raytracing parameters
   29.41 +	float reflectivity; // range [0, 1]
   29.42 +	float transparency; // range [0, 1]
   29.43 +	float ior;          // index of refraction
   29.44 +
   29.45 +	Texture *tex;
   29.46 +	Vector4 mega_rect;	// tex coords for the megatexture
   29.47 +
   29.48 +	Material();
   29.49 +	Material(const Color &dcol, const Color &scol = Color(1.0, 1.0, 1.0), float spow = 60.0,
   29.50 +			float refl = 0.0, float refr = 0.0, float ior = 1.0);
   29.51 +};
   29.52 +
   29.53 +#endif	// MATERIAL_H_
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/object.cc	Sun Nov 09 13:03:36 2014 +0200
    30.3 @@ -0,0 +1,8 @@
    30.4 +#include "object.h"
    30.5 +
    30.6 +void Object::prepare_xform(long msec)
    30.7 +{
    30.8 +	get_xform(msec, &xform, &inv_xform);
    30.9 +	dir_xform = xform;
   30.10 +	dir_xform.keep_upper_left();
   30.11 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/object.h	Sun Nov 09 13:03:36 2014 +0200
    31.3 @@ -0,0 +1,48 @@
    31.4 +/*
    31.5 +Simple introductory ray tracer
    31.6 +Copyright (C) 2012  John Tsiombikas <nuclear@member.fsf.org>
    31.7 +
    31.8 +This program is free software: you can redistribute it and/or modify
    31.9 +it under the terms of the GNU General Public License as published by
   31.10 +the Free Software Foundation, either version 3 of the License, or
   31.11 +(at your option) any later version.
   31.12 +
   31.13 +This program is distributed in the hope that it will be useful,
   31.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   31.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   31.16 +GNU General Public License for more details.
   31.17 +
   31.18 +You should have received a copy of the GNU General Public License
   31.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   31.20 +*/
   31.21 +#ifndef OBJECT_H_
   31.22 +#define OBJECT_H_
   31.23 +
   31.24 +#include "vmath/vmath.h"
   31.25 +#include "material.h"
   31.26 +#include "xform_node.h"
   31.27 +
   31.28 +struct HitPoint;
   31.29 +
   31.30 +class Object : public XFormNode {
   31.31 +public:
   31.32 +	Matrix4x4 xform, inv_xform, dir_xform;
   31.33 +
   31.34 +	Material material;		// surface material properties
   31.35 +
   31.36 +	virtual ~Object() {}
   31.37 +
   31.38 +	virtual void prepare_xform(long msec);
   31.39 +
   31.40 +	virtual bool intersect(const Ray &ray, HitPoint *pt) const = 0;
   31.41 +};
   31.42 +
   31.43 +struct HitPoint {
   31.44 +	float dist;       // parametric distance of intersection along the ray
   31.45 +	Vector3 pos;       // world position of the intersection point
   31.46 +	Vector3 normal;    // surface normal vector at the intersection point
   31.47 +	Vector2 texcoord;  // texture coordinates at the intersection point
   31.48 +	const Object *obj; // pointer to the intersected object
   31.49 +};
   31.50 +
   31.51 +#endif	// OBJECT_H_
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/opengl.h	Sun Nov 09 13:03:36 2014 +0200
    32.3 @@ -0,0 +1,14 @@
    32.4 +#ifndef OPENGL_H_
    32.5 +#define OPENGL_H_
    32.6 +
    32.7 +#include <GL/glew.h>
    32.8 +
    32.9 +#ifndef __APPLE__
   32.10 +#include <GL/glut.h>
   32.11 +#else
   32.12 +#include <GLUT/glut.h>
   32.13 +#endif
   32.14 +
   32.15 +int next_pow2(int x);
   32.16 +
   32.17 +#endif	// OPENGL_H_
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/plane.cc	Sun Nov 09 13:03:36 2014 +0200
    33.3 @@ -0,0 +1,45 @@
    33.4 +#include "plane.h"
    33.5 +
    33.6 +Plane::Plane()
    33.7 +	: normal(0.0, 1.0, 0.0)
    33.8 +{
    33.9 +	dist = 0.0;
   33.10 +}
   33.11 +
   33.12 +Plane::Plane(const Vector3 &norm, float dist)
   33.13 +	: normal(norm)
   33.14 +{
   33.15 +	normal.normalize();
   33.16 +	this->dist = dist;
   33.17 +}
   33.18 +
   33.19 +bool Plane::intersect(const Ray &inray, HitPoint *pt) const
   33.20 +{
   33.21 +	Ray ray = inray.transformed(inv_xform);
   33.22 +
   33.23 +	float ndotdir = dot_product(normal, ray.dir);
   33.24 +	if(fabs(ndotdir) < 1e-5) {
   33.25 +		return false;	// ray parallel to the plane
   33.26 +	}
   33.27 +
   33.28 +	Vector3 planept = normal * dist;
   33.29 +	Vector3 pptdir = planept - ray.origin;
   33.30 +
   33.31 +	float t = dot_product(normal, pptdir) / ndotdir;
   33.32 +	if(t < 1e-4) {
   33.33 +		return false;	// discard intersections behind the origin
   33.34 +	}
   33.35 +
   33.36 +	// fill the HitPoint structure
   33.37 +	pt->obj = this;
   33.38 +	pt->dist = t;
   33.39 +
   33.40 +	pt->pos = ray.origin + ray.dir * t;
   33.41 +
   33.42 +	pt->texcoord.x = pt->pos.x;
   33.43 +	pt->texcoord.y = pt->pos.z;
   33.44 +
   33.45 +	pt->pos.transform(xform);
   33.46 +	pt->normal = normal.transformed(dir_xform);//.normalized();
   33.47 +	return true;
   33.48 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/plane.h	Sun Nov 09 13:03:36 2014 +0200
    34.3 @@ -0,0 +1,35 @@
    34.4 +/*
    34.5 +Simple introductory ray tracer
    34.6 +Copyright (C) 2012  John Tsiombikas <nuclear@member.fsf.org>
    34.7 +
    34.8 +This program is free software: you can redistribute it and/or modify
    34.9 +it under the terms of the GNU General Public License as published by
   34.10 +the Free Software Foundation, either version 3 of the License, or
   34.11 +(at your option) any later version.
   34.12 +
   34.13 +This program is distributed in the hope that it will be useful,
   34.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   34.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   34.16 +GNU General Public License for more details.
   34.17 +
   34.18 +You should have received a copy of the GNU General Public License
   34.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   34.20 +*/
   34.21 +#ifndef PLANE_H_
   34.22 +#define PLANE_H_
   34.23 +
   34.24 +#include "vmath/vmath.h"
   34.25 +#include "object.h"
   34.26 +
   34.27 +class Plane : public Object {
   34.28 +public:
   34.29 +	Vector3 normal;
   34.30 +	float dist;
   34.31 +
   34.32 +	Plane();
   34.33 +	Plane(const Vector3 &norm, float dist);
   34.34 +
   34.35 +	bool intersect(const Ray &ray, HitPoint *pt) const;
   34.36 +};
   34.37 +
   34.38 +#endif	// PLANE_H_
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/src/rend.cc	Sun Nov 09 13:03:36 2014 +0200
    35.3 @@ -0,0 +1,372 @@
    35.4 +#include <assert.h>
    35.5 +#include "scene.h"
    35.6 +#include "image.h"
    35.7 +#include "rend.h"
    35.8 +#include "opengl.h"
    35.9 +#include "glsdr.h"
   35.10 +
   35.11 +enum {
   35.12 +	TEX_RAYDIR,
   35.13 +	TEX_SPHERES,
   35.14 +	TEX_PLANES,
   35.15 +	TEX_BOXES,
   35.16 +	TEX_TEXTURES,
   35.17 +	TEX_ENV,
   35.18 +	TEX_XFORM,
   35.19 +
   35.20 +	NUM_SDR_TEXTURES
   35.21 +};
   35.22 +
   35.23 +bool reload_shader();
   35.24 +void gen_ray_texture(unsigned int tex, int xsz, int ysz, float vfov);
   35.25 +static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg);
   35.26 +static int round_pow2(int x);
   35.27 +
   35.28 +static GPUScene *scn;
   35.29 +
   35.30 +static unsigned int sdr;
   35.31 +static unsigned int textures[NUM_SDR_TEXTURES];
   35.32 +
   35.33 +bool init_renderer(GPUScene *s, int xsz, int ysz)
   35.34 +{
   35.35 +	scn = s;
   35.36 +
   35.37 +	glGenTextures(1, textures + TEX_RAYDIR);
   35.38 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_RAYDIR]);
   35.39 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   35.40 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   35.41 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   35.42 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   35.43 +
   35.44 +	if(!(s->create_textures())) {
   35.45 +		fprintf(stderr, "failed to create scene textures\n");
   35.46 +		return false;
   35.47 +	}
   35.48 +
   35.49 +	textures[TEX_SPHERES] = s->get_texture(GPUScene::TEX_SPHERE);
   35.50 +	textures[TEX_PLANES] = s->get_texture(GPUScene::TEX_PLANE);
   35.51 +	textures[TEX_BOXES] = s->get_texture(GPUScene::TEX_BOX);
   35.52 +	textures[TEX_TEXTURES] = s->get_texture(GPUScene::TEX_TEXTURE);
   35.53 +	textures[TEX_ENV] = s->get_texture(GPUScene::TEX_ENV);
   35.54 +	textures[TEX_XFORM] = s->get_texture(GPUScene::TEX_XFORM);
   35.55 +
   35.56 +	if(!reload_shader()) {
   35.57 +		return false;
   35.58 +	}
   35.59 +
   35.60 +	resize_renderer(xsz, ysz);
   35.61 +
   35.62 +	return true;
   35.63 +}
   35.64 +
   35.65 +bool reload_shader()
   35.66 +{
   35.67 +	if(sdr) {
   35.68 +		free_program(sdr);
   35.69 +	}
   35.70 +
   35.71 +	printf("loading shader...\n");
   35.72 +
   35.73 +	if(!(sdr = create_program_load("sdr/vertex.glsl", "sdr/rt.glsl"))) {
   35.74 +		return false;
   35.75 +	}
   35.76 +	set_uniform_int(sdr, "tex_raydir", TEX_RAYDIR);
   35.77 +	set_uniform_int(sdr, "tex_spheres", TEX_SPHERES);
   35.78 +	set_uniform_int(sdr, "tex_planes", TEX_PLANES);
   35.79 +	set_uniform_int(sdr, "tex_boxes", TEX_BOXES);
   35.80 +	set_uniform_int(sdr, "tex_megatex", TEX_TEXTURES);
   35.81 +	set_uniform_int(sdr, "tex_env", TEX_ENV);
   35.82 +	set_uniform_int(sdr, "tex_xforms", TEX_XFORM);
   35.83 +
   35.84 +	set_uniform_int(sdr, "num_lights", scn->get_light_count());
   35.85 +
   35.86 +	for(int i=0; i<scn->get_light_count(); i++) {
   35.87 +		const Light *lt = scn->get_light(i);
   35.88 +
   35.89 +		char name[64];
   35.90 +		sprintf(name, "lights[%d].pos", i);
   35.91 +		set_uniform_float3(sdr, name, lt->pos.x, lt->pos.y, lt->pos.z);
   35.92 +
   35.93 +		sprintf(name, "lights[%d].color", i);
   35.94 +		set_uniform_float3(sdr, name, lt->color.x, lt->color.y, lt->color.z);
   35.95 +	}
   35.96 +
   35.97 +	Vector2 fog;
   35.98 +	scn->get_fog(&fog.x, &fog.y);
   35.99 +	if(fog.x < 0.0 && fog.y < 0.0) {
  35.100 +		fog.x = 0.0;
  35.101 +		fog.y = 100000.0;
  35.102 +	}
  35.103 +	set_uniform_float2(sdr, "fog", fog.x, fog.y);
  35.104 +	return true;
  35.105 +}
  35.106 +
  35.107 +void destroy_renderer()
  35.108 +{
  35.109 +	free_program(sdr);
  35.110 +	sdr = 0;
  35.111 +}
  35.112 +
  35.113 +void resize_renderer(int xsz, int ysz)
  35.114 +{
  35.115 +	gen_ray_texture(textures[TEX_RAYDIR], xsz, ysz, 45.0f);
  35.116 +}
  35.117 +
  35.118 +float *render_frame(long msec)
  35.119 +{
  35.120 +	scn->prepare_xform(msec);
  35.121 +	scn->update_xform_texture();
  35.122 +
  35.123 +	Camera *cam = scn->get_camera();
  35.124 +	glMatrixMode(GL_MODELVIEW);
  35.125 +	glLoadIdentity();
  35.126 +	Vector3 cpos = cam->get_position();
  35.127 +	glTranslatef(cpos.x, cpos.y, cpos.z);
  35.128 +	Matrix4x4 cmat = cam->get_matrix();
  35.129 +	glMultTransposeMatrixf(cmat[0]);
  35.130 +
  35.131 +	for(int i=0; i<NUM_SDR_TEXTURES; i++) {
  35.132 +		glActiveTexture(GL_TEXTURE0 + i);
  35.133 +		if(i == TEX_ENV) {
  35.134 +			glBindTexture(GL_TEXTURE_CUBE_MAP, textures[i]);
  35.135 +		} else {
  35.136 +			glBindTexture(GL_TEXTURE_2D, textures[i]);
  35.137 +		}
  35.138 +	}
  35.139 +	glActiveTexture(GL_TEXTURE0);
  35.140 +
  35.141 +	glUseProgram(sdr);
  35.142 +
  35.143 +	glBegin(GL_QUADS);
  35.144 +	glTexCoord2f(0, 1);
  35.145 +	glVertex2f(-1, -1);
  35.146 +	glTexCoord2f(1, 1);
  35.147 +	glVertex2f(1, -1);
  35.148 +	glTexCoord2f(1, 0);
  35.149 +	glVertex2f(1, 1);
  35.150 +	glTexCoord2f(0, 0);
  35.151 +	glVertex2f(-1, 1);
  35.152 +	glEnd();
  35.153 +
  35.154 +	glUseProgram(0);
  35.155 +
  35.156 +	assert(glGetError() == GL_NO_ERROR);
  35.157 +	return 0;
  35.158 +}
  35.159 +
  35.160 +void gen_ray_texture(unsigned int tex, int xsz, int ysz, float vfov)
  35.161 +{
  35.162 +	int tex_xsz = round_pow2(xsz);
  35.163 +	int tex_ysz = round_pow2(ysz);
  35.164 +	float *teximg, *dir;
  35.165 +
  35.166 +	teximg = new float[3 * tex_xsz * tex_ysz];
  35.167 +	dir = teximg;
  35.168 +
  35.169 +	for(int i=0; i<tex_ysz; i++) {
  35.170 +		for(int j=0; j<tex_xsz; j++) {
  35.171 +			if(j < xsz && i < ysz) {
  35.172 +				Vector3 rdir = get_primary_ray_dir(j, i, xsz, ysz, vfov);
  35.173 +				dir[0] = rdir.x;
  35.174 +				dir[1] = rdir.y;
  35.175 +				dir[2] = rdir.z;
  35.176 +			} else {
  35.177 +				dir[0] = dir[1] = 0.0f;
  35.178 +				dir[2] = 1.0f;
  35.179 +			}
  35.180 +
  35.181 +			dir += 3;
  35.182 +		}
  35.183 +	}
  35.184 +
  35.185 +	glBindTexture(GL_TEXTURE_2D, tex);
  35.186 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, teximg);
  35.187 +	delete [] teximg;
  35.188 +}
  35.189 +
  35.190 +static Vector3 calc_sample_pos(int x, int y, int xsz, int ysz)
  35.191 +{
  35.192 +	float ppos[2];
  35.193 +	float aspect = (float)xsz / (float)ysz;
  35.194 +
  35.195 +	float pwidth = 2.0 * aspect / (float)xsz;
  35.196 +	float pheight = 2.0 / (float)ysz;
  35.197 +
  35.198 +	ppos[0] = (float)x * pwidth - aspect;
  35.199 +	ppos[1] = 1.0 - (float)y * pheight;
  35.200 +
  35.201 +	return Vector3(ppos[0], ppos[1], 0.0f);
  35.202 +}
  35.203 +
  35.204 +
  35.205 +static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg)
  35.206 +{
  35.207 +	float vfov = M_PI * vfov_deg / 180.0;
  35.208 +
  35.209 +	Vector3 dir = calc_sample_pos(x, y, w, h);
  35.210 +	dir.z = 1.0 / tan(vfov / 2.0);
  35.211 +	dir.normalize();
  35.212 +
  35.213 +	return dir;
  35.214 +}
  35.215 +
  35.216 +static int round_pow2(int x)
  35.217 +{
  35.218 +	x--;
  35.219 +	x = (x >> 1) | x;
  35.220 +	x = (x >> 2) | x;
  35.221 +	x = (x >> 4) | x;
  35.222 +	x = (x >> 8) | x;
  35.223 +	x = (x >> 16) | x;
  35.224 +	return x + 1;
  35.225 +}
  35.226 +
  35.227 +
  35.228 +#if 0
  35.229 +Color trace_ray(const Scene *scn, const Ray &ray, int rdepth)
  35.230 +{
  35.231 +	HitPoint hit;
  35.232 +
  35.233 +	if(scn->intersect(ray, &hit)) {
  35.234 +		float t;
  35.235 +		if(scn->fog_start >= 0.0 && (t = (hit.dist - scn->fog_start) / (scn->fog_end - scn->fog_start)) > 0.0) {
  35.236 +			return lerp(shade(scn, ray, hit, rdepth), scn->env_color(ray), t > 1.0 ? 1.0 : t);
  35.237 +		}
  35.238 +		return shade(scn, ray, hit, rdepth);
  35.239 +	}
  35.240 +
  35.241 +	return scn->env_color(ray);
  35.242 +}
  35.243 +
  35.244 +Color shade(const Scene *scn, const Ray &ray, const HitPoint &hit, int rdepth)
  35.245 +{
  35.246 +	const Material *mat = &hit.obj->material;
  35.247 +
  35.248 +	// if we're leaving the object, we need to invert the normal (and ior)
  35.249 +	Vector3 normal;
  35.250 +	bool entering;
  35.251 +	if(dot_product(hit.normal, ray.dir) <= 0.0) {
  35.252 +		normal = hit.normal;
  35.253 +		entering = true;
  35.254 +	} else {
  35.255 +		normal = -hit.normal;
  35.256 +		entering = false;
  35.257 +	}
  35.258 +
  35.259 +	Vector3 vdir = -ray.dir;
  35.260 +
  35.261 +	Color diffuse_color = mat->diffuse;
  35.262 +	Color tex_color{1, 1, 1};
  35.263 +	if(mat->tex) {
  35.264 +		tex_color *= mat->tex->sample(hit);
  35.265 +		diffuse_color *= tex_color;
  35.266 +	}
  35.267 +
  35.268 +	Color color = mat->emission * tex_color;
  35.269 +
  35.270 +	// image-based lighting
  35.271 +	if(scn->envmap_conv) {
  35.272 +		// pick a random direction and create a sampling ray
  35.273 +		Ray envray;
  35.274 +		envray.origin = hit.pos;
  35.275 +		rand_dir(&envray.dir.x, &envray.dir.y, &envray.dir.z, (unsigned int*)ray.user);
  35.276 +		if(dot_product(envray.dir, normal) < 0.0) {
  35.277 +			envray.dir = -envray.dir;
  35.278 +		}
  35.279 +
  35.280 +		HitPoint env_hit;
  35.281 +		if(!scn->intersect(envray, &env_hit)) {
  35.282 +			Vector3 dir = envray.dir;
  35.283 +			color += scn->envmap_conv->sample(dir.x, dir.y, dir.z) * diffuse_color;
  35.284 +		}
  35.285 +	}
  35.286 +
  35.287 +	for(Light *lt: scn->lights) {
  35.288 +
  35.289 +		/* construct a shadow ray to determine if there is an uninterrupted
  35.290 +		 * path between the intersection point and the light source
  35.291 +		 */
  35.292 +		Ray shadow_ray = ray;
  35.293 +		shadow_ray.origin = hit.pos;
  35.294 +		shadow_ray.dir = lt->pos - hit.pos;
  35.295 +
  35.296 +		/* the interval [0, 1] represents the part of the ray from the origin
  35.297 +		 * to the light. We don't care about intersections behind the origin
  35.298 +		 * of the shadow ray (behind the surface of the object), or after the
  35.299 +		 * light source. We only care if there's something in between hiding the
  35.300 +		 * light.
  35.301 +		 */
  35.302 +		HitPoint shadow_hit;
  35.303 +		if(scn->intersect(shadow_ray, &shadow_hit) && shadow_hit.dist < 1.0f) {
  35.304 +			continue;	// skip this light, it's hidden from view
  35.305 +		}
  35.306 +
  35.307 +		// calculate the light direction
  35.308 +		Vector3 ldir = shadow_ray.dir.normalized();
  35.309 +		// calculate the reflected light direction
  35.310 +		Vector3 lref = ldir.reflection(normal);
  35.311 +
  35.312 +		float diffuse = std::max(dot_product(ldir, normal), 0.0f);
  35.313 +		float specular = pow(std::max(dot_product(lref, vdir), 0.0f), mat->shininess);
  35.314 +
  35.315 +		color += (diffuse_color * diffuse + mat->specular * specular) * lt->color;
  35.316 +	}
  35.317 +
  35.318 +	Color spec_col;
  35.319 +
  35.320 +	if(mat->reflectivity > 0.001f && rdepth < MAX_RAY_DEPTH) {
  35.321 +		Ray refl_ray{ray};
  35.322 +		refl_ray.origin = hit.pos;
  35.323 +		refl_ray.dir = -ray.dir.reflection(normal);
  35.324 +
  35.325 +		spec_col += trace_ray(scn, refl_ray, rdepth + 1) * mat->reflectivity;
  35.326 +	}
  35.327 +
  35.328 +	if(mat->transparency > 0.001f && rdepth < MAX_RAY_DEPTH) {
  35.329 +		float from_ior = entering ? 1.0 : mat->ior;
  35.330 +		float to_ior = entering ? mat->ior : 1.0;
  35.331 +
  35.332 +		Ray refr_ray{ray};
  35.333 +		refr_ray.origin = hit.pos;
  35.334 +		refr_ray.dir = ray.dir.refraction(normal, from_ior / to_ior);
  35.335 +
  35.336 +		Color tcol = trace_ray(scn, refr_ray, rdepth + 1) * mat->transparency;
  35.337 +
  35.338 +		float fres = fresnel(ray.dir, refr_ray.dir, normal, from_ior, to_ior);
  35.339 +		spec_col = spec_col * fres + tcol * (1.0 - fres);
  35.340 +	}
  35.341 +
  35.342 +	return color + spec_col;
  35.343 +}
  35.344 +
  35.345 +
  35.346 +static void rand_dir(float *x, float *y, float *z, unsigned int *seedp)
  35.347 +{
  35.348 +	float u = (float)rand_r(seedp) / RAND_MAX;
  35.349 +	float v = (float)rand_r(seedp) / RAND_MAX;
  35.350 +
  35.351 +	float theta = 2.0 * M_PI * u;
  35.352 +	float phi = acos(2.0 * v - 1.0);
  35.353 +
  35.354 +	*x = cos(theta) * sin(phi);
  35.355 +	*y = sin(theta) * sin(phi);
  35.356 +	*z = cos(phi);
  35.357 +}
  35.358 +
  35.359 +static float fresnel(const Vector3 &inc, const Vector3 &trans, const Vector3 &norm, float ior_inc, float ior_trans)
  35.360 +{
  35.361 +	float cos_inc = dot_product(-inc, norm);
  35.362 +	float cos_trans = dot_product(-trans, norm);
  35.363 +
  35.364 +	return fresnel(cos_inc, cos_trans, ior_inc, ior_trans);
  35.365 +}
  35.366 +
  35.367 +static float fresnel(float cos_inc, float cos_trans, float ior_inc, float ior_trans)
  35.368 +{
  35.369 +	float r0 = ((ior_trans * cos_inc) - (ior_inc * cos_trans)) /
  35.370 +		((ior_trans * cos_inc) + (ior_inc * cos_trans));
  35.371 +	float r1 = ((ior_inc * cos_inc) - (ior_trans * cos_trans)) /
  35.372 +		((ior_inc * cos_inc) + (ior_trans * cos_trans));
  35.373 +	return (r0 * r0 + r1 * r1) * 0.5f;
  35.374 +}
  35.375 +#endif
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/src/rend.h	Sun Nov 09 13:03:36 2014 +0200
    36.3 @@ -0,0 +1,14 @@
    36.4 +#ifndef REND_H_
    36.5 +#define REND_H_
    36.6 +
    36.7 +#include "gpuscene.h"
    36.8 +
    36.9 +bool init_renderer(GPUScene *scn, int xsz, int ysz);
   36.10 +bool reload_shader();
   36.11 +void destroy_renderer();
   36.12 +
   36.13 +void resize_renderer(int xsz, int ysz);
   36.14 +
   36.15 +float *render_frame(long msec);
   36.16 +
   36.17 +#endif	// REND_H_
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/src/scene.cc	Sun Nov 09 13:03:36 2014 +0200
    37.3 @@ -0,0 +1,153 @@
    37.4 +#include <stdio.h>
    37.5 +#include <stdlib.h>
    37.6 +#include <float.h>
    37.7 +#include <algorithm>
    37.8 +#include "scene.h"
    37.9 +#include "texture.h"
   37.10 +
   37.11 +bool load_scene_file(Scene *scn, const char *fname);
   37.12 +bool save_scene_file(const Scene *scn, const char *fname);
   37.13 +
   37.14 +
   37.15 +// default camera
   37.16 +TargetCamera Scene::def_cam(Vector3(0, 0, -10), Vector3(0, 0, 0));
   37.17 +
   37.18 +Scene::Scene()
   37.19 +{
   37.20 +	camera = &def_cam;
   37.21 +	bgcolor = Color(0, 0, 0);
   37.22 +	envmap = envmap_conv = 0;
   37.23 +	fog_start = fog_end = -1;
   37.24 +}
   37.25 +
   37.26 +Scene::~Scene()
   37.27 +{
   37.28 +	for(auto obj: objects) {
   37.29 +		delete obj;
   37.30 +	}
   37.31 +	for(auto lt: lights) {
   37.32 +		delete lt;
   37.33 +	}
   37.34 +	if(camera != &def_cam) {
   37.35 +		delete camera;
   37.36 +	}
   37.37 +
   37.38 +	delete envmap;
   37.39 +	if(envmap_conv != envmap) {
   37.40 +		delete envmap_conv;
   37.41 +	}
   37.42 +}
   37.43 +
   37.44 +bool Scene::load(const char *fname)
   37.45 +{
   37.46 +	return load_scene_file(this, fname);
   37.47 +}
   37.48 +
   37.49 +bool Scene::save(const char *fname) const
   37.50 +{
   37.51 +	return save_scene_file(this, fname);
   37.52 +}
   37.53 +
   37.54 +void Scene::set_background_color(const Color &color)
   37.55 +{
   37.56 +	bgcolor = color;
   37.57 +}
   37.58 +
   37.59 +void Scene::set_fog(float fog_start, float fog_end)
   37.60 +{
   37.61 +	this->fog_start = fog_start;
   37.62 +	this->fog_end = fog_end;
   37.63 +}
   37.64 +
   37.65 +void Scene::get_fog(float *fog_start, float *fog_end) const
   37.66 +{
   37.67 +	*fog_start = this->fog_start;
   37.68 +	*fog_end = this->fog_end;
   37.69 +}
   37.70 +
   37.71 +void Scene::set_environment_map(TextureCube *map, TextureCube *map_conv)
   37.72 +{
   37.73 +	envmap = map;
   37.74 +	envmap_conv = map_conv;//map_conv ? map_conv : map;
   37.75 +}
   37.76 +
   37.77 +void Scene::add_object(Object *obj)
   37.78 +{
   37.79 +	objects.push_back(obj);
   37.80 +}
   37.81 +
   37.82 +Object *Scene::get_object(int i) const
   37.83 +{
   37.84 +	if(i < 0 || i >= (int)objects.size()) {
   37.85 +		return 0;
   37.86 +	}
   37.87 +	return objects[i];
   37.88 +}
   37.89 +
   37.90 +int Scene::get_object_count() const
   37.91 +{
   37.92 +	return (int)objects.size();
   37.93 +}
   37.94 +
   37.95 +void Scene::add_light(Light *lt)
   37.96 +{
   37.97 +	lights.push_back(lt);
   37.98 +}
   37.99 +
  37.100 +Light *Scene::get_light(int i) const
  37.101 +{
  37.102 +	if(i < 0 || i >= (int)lights.size()) {
  37.103 +		return 0;
  37.104 +	}
  37.105 +	return lights[i];
  37.106 +}
  37.107 +
  37.108 +int Scene::get_light_count() const
  37.109 +{
  37.110 +	return (int)lights.size();
  37.111 +}
  37.112 +
  37.113 +void Scene::set_camera(Camera *cam)
  37.114 +{
  37.115 +	if(camera != &def_cam) {
  37.116 +		delete camera;
  37.117 +	}
  37.118 +	camera = cam;
  37.119 +}
  37.120 +
  37.121 +Camera *Scene::get_camera() const
  37.122 +{
  37.123 +	return camera;
  37.124 +}
  37.125 +
  37.126 +bool Scene::intersect(const Ray &ray, HitPoint *nearest_hit) const
  37.127 +{
  37.128 +	nearest_hit->obj = 0;
  37.129 +	nearest_hit->dist = FLT_MAX;
  37.130 +
  37.131 +	// find the nearest hit (if any)
  37.132 +	for(Object *obj: objects) {
  37.133 +		HitPoint hit;
  37.134 +		if(obj->intersect(ray, &hit) && hit.dist < nearest_hit->dist) {
  37.135 +			*nearest_hit = hit;
  37.136 +		}
  37.137 +	}
  37.138 +	return nearest_hit->obj != 0;
  37.139 +}
  37.140 +
  37.141 +Color Scene::env_color(const Ray &ray) const
  37.142 +{
  37.143 +	if(envmap) {
  37.144 +		Vector3 dir = ray.dir.normalized();
  37.145 +		return envmap->sample(dir.x, dir.y, dir.z);
  37.146 +	}
  37.147 +	return bgcolor;
  37.148 +}
  37.149 +
  37.150 +void Scene::prepare_xform(long msec)
  37.151 +{
  37.152 +	int nobj = get_object_count();
  37.153 +	for(int i=0; i<nobj; i++) {
  37.154 +		objects[i]->prepare_xform(msec);
  37.155 +	}
  37.156 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/src/scene.h	Sun Nov 09 13:03:36 2014 +0200
    38.3 @@ -0,0 +1,56 @@
    38.4 +#ifndef SCENE_H_
    38.5 +#define SCENE_H_
    38.6 +
    38.7 +#include <vector>
    38.8 +#include "object.h"
    38.9 +#include "light.h"
   38.10 +#include "camera.h"
   38.11 +#include "texture.h"
   38.12 +
   38.13 +class Scene {
   38.14 +protected:
   38.15 +	std::vector<Object*> objects;
   38.16 +	std::vector<Light*> lights;
   38.17 +	Camera *camera;
   38.18 +
   38.19 +	static TargetCamera def_cam;	// default camera
   38.20 +
   38.21 +	Color bgcolor;
   38.22 +	TextureCube *envmap, *envmap_conv;
   38.23 +	float fog_start, fog_end;
   38.24 +
   38.25 +public:
   38.26 +	Scene();
   38.27 +	virtual ~Scene();
   38.28 +
   38.29 +	virtual bool load(const char *fname);
   38.30 +	virtual bool save(const char *fname) const;
   38.31 +
   38.32 +	virtual void set_background_color(const Color &color);
   38.33 +	virtual void set_fog(float fog_start, float fog_end);
   38.34 +	virtual void get_fog(float *fog_start, float *fog_end) const;
   38.35 +
   38.36 +	virtual void set_environment_map(TextureCube *map, TextureCube *map_conv = 0);
   38.37 +
   38.38 +	virtual void add_object(Object *obj);
   38.39 +	virtual Object *get_object(int i) const;
   38.40 +	virtual int get_object_count() const;
   38.41 +
   38.42 +	virtual void add_light(Light *lt);
   38.43 +	virtual Light *get_light(int i) const;
   38.44 +	virtual int get_light_count() const;
   38.45 +
   38.46 +	virtual void set_camera(Camera *cam);
   38.47 +	virtual Camera *get_camera() const;
   38.48 +
   38.49 +	virtual bool intersect(const Ray &ray, HitPoint *hit) const;
   38.50 +
   38.51 +	virtual Color env_color(const Ray &ray) const;
   38.52 +
   38.53 +	virtual void prepare_xform(long msec);
   38.54 +
   38.55 +	friend Color trace_ray(const Scene *scn, const Ray &ray, int rdepth);
   38.56 +	friend Color shade(const Scene *scn, const Ray &ray, const HitPoint &hit, int rdepth);
   38.57 +};
   38.58 +
   38.59 +#endif	// SCENE_H_
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/src/scene_load.cc	Sun Nov 09 13:03:36 2014 +0200
    39.3 @@ -0,0 +1,681 @@
    39.4 +#include <stdio.h>
    39.5 +#include <math.h>
    39.6 +#include <map>
    39.7 +#include "scene.h"
    39.8 +#include "sphere.h"
    39.9 +#include "plane.h"
   39.10 +#include "box.h"
   39.11 +#include "light.h"
   39.12 +#include "camera.h"
   39.13 +#include "texture.h"
   39.14 +
   39.15 +static bool parse_material(char **argv, Material *mtl, std::string *name);
   39.16 +static Object *parse_sphere(char **argv, const std::map<std::string, Material> &materials);
   39.17 +static Object *parse_plane(char **argv, const std::map<std::string, Material> &materials);
   39.18 +static Object *parse_box(char **argv, const std::map<std::string, Material> &materials);
   39.19 +static Light *parse_light(char **argv);
   39.20 +static Camera *parse_camera(char **argv);
   39.21 +static bool parse_env(char **argv, Scene *scn);
   39.22 +static bool parse_xform(char **argv, Scene *scn);
   39.23 +static bool parse_vec(char **argv, Vector3 *vptr);
   39.24 +
   39.25 +static char *strip_space(char *s);
   39.26 +static char **split_args(char *args);
   39.27 +
   39.28 +bool load_scene_file(Scene *scn, const char *fname)
   39.29 +{
   39.30 +	FILE *fp;
   39.31 +	if(!(fp = fopen(fname, "rb"))) {
   39.32 +		fprintf(stderr, "%s: failed to open scene file: %s: %s\n", __FUNCTION__, fname, strerror(errno));
   39.33 +		return false;
   39.34 +	}
   39.35 +
   39.36 +	char buf[512];
   39.37 +	std::map<std::string, Material> materials;
   39.38 +
   39.39 +	int lineno = 0;
   39.40 +	while(fgets(buf, sizeof buf, fp)) {
   39.41 +		char *line = strip_space(buf);
   39.42 +
   39.43 +		lineno++;
   39.44 +
   39.45 +		if(!*line || *line == '\n' || *line == '#') {
   39.46 +			continue;
   39.47 +		}
   39.48 +
   39.49 +		if(strstr(line, "material") == line) {
   39.50 +			Material mtl;
   39.51 +			std::string name;
   39.52 +
   39.53 +			char *args = strip_space(line + strlen("material"));
   39.54 +			if(!parse_material(split_args(args), &mtl, &name)) {
   39.55 +				goto err;
   39.56 +			}
   39.57 +			materials[name] = mtl;
   39.58 +
   39.59 +		} else if(strstr(line, "sphere") == line) {
   39.60 +			char *args = strip_space(line + strlen("sphere"));
   39.61 +			Object *obj = parse_sphere(split_args(args), materials);
   39.62 +			if(!obj) {
   39.63 +				goto err;
   39.64 +			}
   39.65 +			scn->add_object(obj);
   39.66 +
   39.67 +		} else if(strstr(line, "plane") == line) {
   39.68 +			char *args = strip_space(line + strlen("plane"));
   39.69 +			Object *obj = parse_plane(split_args(args), materials);
   39.70 +			if(!obj) {
   39.71 +				goto err;
   39.72 +			}
   39.73 +			scn->add_object(obj);
   39.74 +
   39.75 +		} else if(strstr(line, "box") == line) {
   39.76 +			char *args = strip_space(line + strlen("box"));
   39.77 +			Object *obj = parse_box(split_args(args), materials);
   39.78 +			if(!obj) {
   39.79 +				goto err;
   39.80 +			}
   39.81 +			scn->add_object(obj);
   39.82 +
   39.83 +		} else if(strstr(line, "light") == line) {
   39.84 +			char *args = strip_space(line + strlen("light"));
   39.85 +			Light *lt = parse_light(split_args(args));
   39.86 +			if(!lt) {
   39.87 +				goto err;
   39.88 +			}
   39.89 +			scn->add_light(lt);
   39.90 +
   39.91 +		} else if(strstr(line, "camera") == line) {
   39.92 +			char *args = strip_space(line + strlen("camera"));
   39.93 +			Camera *cam = parse_camera(split_args(args));
   39.94 +			if(!cam) {
   39.95 +				goto err;
   39.96 +			}
   39.97 +			scn->set_camera(cam);
   39.98 +
   39.99 +		} else if(strstr(line, "environment") == line) {
  39.100 +			char *args = strip_space(line + strlen("environment"));
  39.101 +			if(!parse_env(split_args(args), scn)) {
  39.102 +				goto err;
  39.103 +			}
  39.104 +
  39.105 +		} else if(strstr(line, "xform") == line) {
  39.106 +			char *args = strip_space(line + strlen("xform"));
  39.107 +			if(!parse_xform(split_args(args), scn)) {
  39.108 +				goto err;
  39.109 +			}
  39.110 +
  39.111 +		} else {
  39.112 +			fprintf(stderr, "%s error %s:%d: unknown command: %s\n", __FUNCTION__, fname, lineno, line);
  39.113 +			goto err;
  39.114 +		}
  39.115 +
  39.116 +	}
  39.117 +
  39.118 +	fclose(fp);
  39.119 +	return true;
  39.120 +
  39.121 +err:
  39.122 +	fclose(fp);
  39.123 +	return false;
  39.124 +}
  39.125 +
  39.126 +bool save_scene_file(const Scene *scn, const char *fname)
  39.127 +{
  39.128 +	FILE *fp;
  39.129 +	if(!(fp = fopen(fname, "wb"))) {
  39.130 +		fprintf(stderr, "%s: failed to save scene file: %s: %s\n", __FUNCTION__, fname, strerror(errno));
  39.131 +		return false;
  39.132 +	}
  39.133 +
  39.134 +	for(int i=0; i<scn->get_object_count(); i++) {
  39.135 +		// first write the material
  39.136 +		const Object *obj = scn->get_object(i);
  39.137 +		const Material *mat = &obj->material;
  39.138 +
  39.139 +		char name[128];
  39.140 +		sprintf(name, "mat%d", i);
  39.141 +
  39.142 +		fprintf(fp, "material -name %s", name);
  39.143 +		fprintf(fp, " -diffuse %.3f %.3f %.3f", mat->diffuse.x, mat->diffuse.y, mat->diffuse.z);
  39.144 +		fprintf(fp, " -specular %.3f %.3f %.3f", mat->specular.x, mat->specular.y, mat->specular.z);
  39.145 +		fprintf(fp, " -shininess %.3f", mat->shininess);
  39.146 +		fprintf(fp, " -emission %.3f %.3f %.3f", mat->emission.x, mat->emission.y, mat->emission.z);
  39.147 +		fprintf(fp, " -reflect %.3f", mat->reflectivity);
  39.148 +		fprintf(fp, " -trans %.3f", mat->transparency);
  39.149 +		fprintf(fp, " -ior %.3f", mat->ior);
  39.150 +		if(mat->tex) {
  39.151 +			fprintf(fp, " -texture %s", mat->tex->get_name());
  39.152 +		}
  39.153 +		fputc('\n', fp);
  39.154 +
  39.155 +		// then write the object
  39.156 +		const Sphere *sph;
  39.157 +		const Plane *plane;
  39.158 +		const Box *box;
  39.159 +		if((sph = dynamic_cast<const Sphere*>(obj))) {
  39.160 +			fprintf(fp, "sphere -material %s", name);
  39.161 +			fprintf(fp, " -center %.3f %.3f %.3f", sph->pos.x, sph->pos.y, sph->pos.z);
  39.162 +			fprintf(fp, " -radius %.3f\n", sph->radius);
  39.163 +		} else if((plane = dynamic_cast<const Plane*>(obj))) {
  39.164 +			fprintf(fp, "plane -material %s", name);
  39.165 +			fprintf(fp, " -normal %.3f %.3f %.3f", plane->normal.x, plane->normal.y, plane->normal.z);
  39.166 +			fprintf(fp, " -distance %.3f\n", plane->dist);
  39.167 +		} else if((box = dynamic_cast<const Box*>(obj))) {
  39.168 +			fprintf(fp, "box -material %s", name);
  39.169 +			fprintf(fp, " -min %.3f %.3f %.3f", box->min.x, box->min.y, box->min.z);
  39.170 +			fprintf(fp, " -max %.3f %.3f %.3f\n", box->max.x, box->max.y, box->max.z);
  39.171 +		}
  39.172 +	}
  39.173 +
  39.174 +	for(int i=0; i<scn->get_light_count(); i++) {
  39.175 +		const Light *lt = scn->get_light(i);
  39.176 +
  39.177 +		fprintf(fp, "light -position %.3f %.3f %.3f", lt->pos.x, lt->pos.y, lt->pos.z);
  39.178 +		fprintf(fp, " -color %.3f %.3f %.3f\n", lt->color.x, lt->color.y, lt->color.z);
  39.179 +	}
  39.180 +
  39.181 +	const TargetCamera *tcam = dynamic_cast<const TargetCamera*>(scn->get_camera());
  39.182 +	if(tcam) {
  39.183 +		Vector3 pos = tcam->get_position();
  39.184 +		fprintf(fp, "camera -position %.3f %.3f %.3f", pos.x, pos.y, pos.z);
  39.185 +		Vector3 targ = tcam->get_target();
  39.186 +		fprintf(fp, " -target %.3f %.3f %.3f", targ.x, targ.y, targ.z);
  39.187 +		fprintf(fp, " -fov %.3f\n", tcam->get_fov());
  39.188 +	}
  39.189 +
  39.190 +
  39.191 +	fclose(fp);
  39.192 +	return true;
  39.193 +}
  39.194 +
  39.195 +#define ARGERR(n) \
  39.196 +	do { fprintf(stderr, "failed to parse %s argument\n", (n)); return false; } while(0)
  39.197 +
  39.198 +static bool parse_material(char **argv, Material *mtl, std::string *name)
  39.199 +{
  39.200 +	char *endp;
  39.201 +
  39.202 +	for(int i=0; argv[i]; i++) {
  39.203 +		if(strcmp(argv[i], "-name") == 0) {
  39.204 +			*name = argv[++i];
  39.205 +		} else if(strcmp(argv[i], "-diffuse") == 0) {
  39.206 +			if(!parse_vec(argv + i + 1, &mtl->diffuse)) {
  39.207 +				ARGERR("diffuse");
  39.208 +			}
  39.209 +			argv += 3;
  39.210 +
  39.211 +		} else if(strcmp(argv[i], "-specular") == 0) {
  39.212 +			if(!parse_vec(argv + i + 1, &mtl->specular)) {
  39.213 +				ARGERR("specular");
  39.214 +			}
  39.215 +			argv += 3;
  39.216 +
  39.217 +		} else if(strcmp(argv[i], "-emission") == 0) {
  39.218 +			if(!parse_vec(argv + i + 1, &mtl->emission)) {
  39.219 +				ARGERR("emission");
  39.220 +			}
  39.221 +			argv += 3;
  39.222 +
  39.223 +		} else if(strcmp(argv[i], "-shininess") == 0) {
  39.224 +			mtl->shininess = strtod(argv[++i], &endp);
  39.225 +			if(endp == argv[i]) {
  39.226 +				ARGERR("shininess");
  39.227 +			}
  39.228 +
  39.229 +		} else if(strcmp(argv[i], "-reflect") == 0) {
  39.230 +			mtl->reflectivity = strtod(argv[++i], &endp);
  39.231 +			if(endp == argv[i]) {
  39.232 +				ARGERR("reflect");
  39.233 +			}
  39.234 +
  39.235 +		} else if(strcmp(argv[i], "-trans") == 0) {
  39.236 +			mtl->transparency = strtod(argv[++i], &endp);
  39.237 +			if(endp == argv[i]) {
  39.238 +				ARGERR("trans");
  39.239 +			}
  39.240 +
  39.241 +		} else if(strcmp(argv[i], "-ior") == 0) {
  39.242 +			mtl->ior = strtod(argv[++i], &endp);
  39.243 +			if(endp == argv[i]) {
  39.244 +				ARGERR("ior");
  39.245 +			}
  39.246 +
  39.247 +		} else if(strcmp(argv[i], "-texture") == 0) {
  39.248 +			if(!(mtl->tex = load_texture(argv[++i]))) {
  39.249 +				return false;
  39.250 +			}
  39.251 +
  39.252 +		} else {
  39.253 +			fprintf(stderr, "invalid material option: %s\n", argv[i]);
  39.254 +			return false;
  39.255 +		}
  39.256 +	}
  39.257 +	return true;
  39.258 +}
  39.259 +
  39.260 +static Object *parse_sphere(char **argv, const std::map<std::string, Material> &materials)
  39.261 +{
  39.262 +	char *endp;
  39.263 +	Sphere *sph = new Sphere;
  39.264 +
  39.265 +	for(int i=0; argv[i]; i++) {
  39.266 +		if(strcmp(argv[i], "-name") == 0) {
  39.267 +			sph->set_name(argv[++i]);
  39.268 +
  39.269 +		} else if(strcmp(argv[i], "-center") == 0) {
  39.270 +			if(!parse_vec(argv + i + 1, &sph->pos)) {
  39.271 +				fprintf(stderr, "failed to parse sphere center vector\n");
  39.272 +				return 0;
  39.273 +			}
  39.274 +			argv += 3;
  39.275 +
  39.276 +		} else if(strcmp(argv[i], "-radius") == 0) {
  39.277 +			sph->radius = strtod(argv[++i], &endp);
  39.278 +			if(endp == argv[i]) {
  39.279 +				fprintf(stderr, "failed to parse sphere radius\n");
  39.280 +				return 0;
  39.281 +			}
  39.282 +
  39.283 +		} else if(strcmp(argv[i], "-material") == 0) {
  39.284 +			auto it = materials.find(argv[++i]);
  39.285 +			if(it == materials.end()) {
  39.286 +				fprintf(stderr, "material %s not found\n", argv[i]);
  39.287 +				return 0;
  39.288 +			}
  39.289 +
  39.290 +			sph->material = it->second;
  39.291 +		} else {
  39.292 +			fprintf(stderr, "invalid sphere option: %s\n", argv[i]);
  39.293 +			return 0;
  39.294 +		}
  39.295 +	}
  39.296 +
  39.297 +	return sph;
  39.298 +}
  39.299 +
  39.300 +static Object *parse_plane(char **argv, const std::map<std::string, Material> &materials)
  39.301 +{
  39.302 +	char *endp;
  39.303 +	Plane *plane = new Plane;
  39.304 +
  39.305 +	for(int i=0; argv[i]; i++) {
  39.306 +		if(strcmp(argv[i], "-name") == 0) {
  39.307 +			plane->set_name(argv[++i]);
  39.308 +
  39.309 +		} else if(strcmp(argv[i], "-normal") == 0) {
  39.310 +			if(!parse_vec(argv + i + 1, &plane->normal)) {
  39.311 +				fprintf(stderr, "failed to parse plane normal\n");
  39.312 +				return 0;
  39.313 +			}
  39.314 +			plane->normal.normalize();
  39.315 +			argv += 3;
  39.316 +
  39.317 +		} else if(strcmp(argv[i], "-distance") == 0) {
  39.318 +			plane->dist = strtod(argv[++i], &endp);
  39.319 +			if(endp == argv[i]) {
  39.320 +				fprintf(stderr, "failed to parse plane distance\n");
  39.321 +				return 0;
  39.322 +			}
  39.323 +
  39.324 +		} else if(strcmp(argv[i], "-material") == 0) {
  39.325 +			auto it = materials.find(argv[++i]);
  39.326 +			if(it == materials.end()) {
  39.327 +				fprintf(stderr, "material %s not found\n", argv[i]);
  39.328 +				return 0;
  39.329 +			}
  39.330 +
  39.331 +			plane->material = it->second;
  39.332 +		} else {
  39.333 +			fprintf(stderr, "invalid plane option: %s\n", argv[i]);
  39.334 +			return 0;
  39.335 +		}
  39.336 +	}
  39.337 +
  39.338 +	return plane;
  39.339 +}
  39.340 +
  39.341 +static Object *parse_box(char **argv, const std::map<std::string, Material> &materials)
  39.342 +{
  39.343 +	Box *box = new Box;
  39.344 +
  39.345 +	for(int i=0; argv[i]; i++) {
  39.346 +		if(strcmp(argv[i], "-name") == 0) {
  39.347 +			box->set_name(argv[++i]);
  39.348 +
  39.349 +		} else if(strcmp(argv[i], "-min") == 0) {
  39.350 +			if(!parse_vec(argv + i + 1, &box->min)) {
  39.351 +				fprintf(stderr, "failed to parse box min\n");
  39.352 +				return 0;
  39.353 +			}
  39.354 +			argv += 3;
  39.355 +
  39.356 +		} else if(strcmp(argv[i], "-max") == 0) {
  39.357 +			if(!parse_vec(argv + i + 1, &box->max)) {
  39.358 +				fprintf(stderr, "failed to parse box max\n");
  39.359 +				return 0;
  39.360 +			}
  39.361 +			argv += 3;
  39.362 +
  39.363 +		} else if(strcmp(argv[i], "-material") == 0) {
  39.364 +			auto it = materials.find(argv[++i]);
  39.365 +			if(it == materials.end()) {
  39.366 +				fprintf(stderr, "material %s not found\n", argv[i]);
  39.367 +				return 0;
  39.368 +			}
  39.369 +
  39.370 +			box->material = it->second;
  39.371 +		} else {
  39.372 +			fprintf(stderr, "invalid box option: %s\n", argv[i]);
  39.373 +			return 0;
  39.374 +		}
  39.375 +	}
  39.376 +
  39.377 +	return box;
  39.378 +}
  39.379 +
  39.380 +static Light *parse_light(char **argv)
  39.381 +{
  39.382 +	Light *lt = new Light;
  39.383 +
  39.384 +	for(int i=0; argv[i]; i++) {
  39.385 +		if(strcmp(argv[i], "-position") == 0) {
  39.386 +			if(!parse_vec(argv + i + 1, &lt->pos)) {
  39.387 +				fprintf(stderr, "failed to parse light position\n");
  39.388 +				return 0;
  39.389 +			}
  39.390 +			argv += 3;
  39.391 +
  39.392 +		} else if(strcmp(argv[i], "-color") == 0) {
  39.393 +			if(!parse_vec(argv + i + 1, &lt->color)) {
  39.394 +				fprintf(stderr, "failed to parse light color\n");
  39.395 +				return 0;
  39.396 +			}
  39.397 +			argv += 3;
  39.398 +
  39.399 +		} else {
  39.400 +			fprintf(stderr, "invalid light option: %s\n", argv[i]);
  39.401 +			return 0;
  39.402 +		}
  39.403 +	}
  39.404 +
  39.405 +	return lt;
  39.406 +}
  39.407 +
  39.408 +static Camera *parse_camera(char **argv)
  39.409 +{
  39.410 +	char *endp;
  39.411 +	TargetCamera *cam = new TargetCamera;
  39.412 +
  39.413 +	for(int i=0; argv[i]; i++) {
  39.414 +		if(strcmp(argv[i], "-position") == 0) {
  39.415 +			Vector3 pos;
  39.416 +			if(!parse_vec(argv + i + 1, &pos)) {
  39.417 +				fprintf(stderr, "failed to parse camera position\n");
  39.418 +				return 0;
  39.419 +			}
  39.420 +			argv += 3;
  39.421 +			cam->set_position(pos);
  39.422 +
  39.423 +		} else if(strcmp(argv[i], "-target") == 0) {
  39.424 +			Vector3 targ;
  39.425 +			if(!parse_vec(argv + i + 1, &targ)) {
  39.426 +				fprintf(stderr, "failed to parse camera target\n");
  39.427 +				return 0;
  39.428 +			}
  39.429 +			argv += 3;
  39.430 +			cam->set_target(targ);
  39.431 +
  39.432 +		} else if(strcmp(argv[i], "-fov") == 0) {
  39.433 +			float fov = strtod(argv[++i], &endp);
  39.434 +			if(endp == argv[i]) {
  39.435 +				fprintf(stderr, "failed to parse camera fov\n");
  39.436 +				return 0;
  39.437 +			}
  39.438 +			cam->set_fov(M_PI * fov / 180.0);
  39.439 +
  39.440 +		} else {
  39.441 +			fprintf(stderr, "invalid camera option: %s\n", argv[i]);
  39.442 +			return 0;
  39.443 +		}
  39.444 +	}
  39.445 +
  39.446 +	return cam;
  39.447 +}
  39.448 +
  39.449 +static bool parse_env(char **argv, Scene *scn)
  39.450 +{
  39.451 +	char *endp;
  39.452 +
  39.453 +	TextureCube *env_tex = 0;
  39.454 +	TextureCube *conv_tex = 0;
  39.455 +
  39.456 +	float fog_start = -1;
  39.457 +	float fog_end = -1;
  39.458 +
  39.459 +	for(int i=0; argv[i]; i++) {
  39.460 +		if(strcmp(argv[i], "-color") == 0) {
  39.461 +			Color bgcolor;
  39.462 +			if(!parse_vec(argv + i + 1, &bgcolor)) {
  39.463 +				fprintf(stderr, "failed to parse environment color\n");
  39.464 +				return false;
  39.465 +			}
  39.466 +			i += 3;
  39.467 +			scn->set_background_color(bgcolor);
  39.468 +
  39.469 +		} else if(strcmp(argv[i], "-fog-start") == 0) {
  39.470 +			fog_start = strtod(argv[++i], &endp);
  39.471 +			if(endp == argv[i]) {
  39.472 +				fprintf(stderr, "failed to parse environment fog start\n");
  39.473 +				return false;
  39.474 +			}
  39.475 +
  39.476 +		} else if(strcmp(argv[i], "-fog-end") == 0) {
  39.477 +			fog_end = strtod(argv[++i], &endp);
  39.478 +			if(endp == argv[i]) {
  39.479 +				fprintf(stderr, "failed to parse environment fog end\n");
  39.480 +				return false;
  39.481 +			}
  39.482 +
  39.483 +		} else if(strcmp(argv[i], "-texture") == 0 || strcmp(argv[i], "-texture-conv") == 0) {
  39.484 +			Texture *tex = load_texture(argv[++i]);
  39.485 +			if(!tex || !dynamic_cast<TextureCube*>(tex)) {
  39.486 +				fprintf(stderr, "failed to load environment cubemap: %s\n", argv[i]);
  39.487 +				delete tex;
  39.488 +				return false;
  39.489 +			}
  39.490 +
  39.491 +			if(strstr(argv[i - 1], "-conv")) {
  39.492 +				conv_tex = (TextureCube*)tex;
  39.493 +			} else {
  39.494 +				env_tex = (TextureCube*)tex;
  39.495 +			}
  39.496 +
  39.497 +		} else {
  39.498 +			fprintf(stderr, "invalid environment option: %s\n", argv[i]);
  39.499 +			return false;
  39.500 +		}
  39.501 +	}
  39.502 +
  39.503 +	if(env_tex || conv_tex) {
  39.504 +		scn->set_environment_map(env_tex, conv_tex);
  39.505 +	}
  39.506 +
  39.507 +	if(fog_start > 0.0 && fog_end > 0.0) {
  39.508 +		scn->set_fog(fog_start, fog_end);
  39.509 +	}
  39.510 +
  39.511 +	return true;
  39.512 +}
  39.513 +
  39.514 +static bool parse_xform(char **argv, Scene *scn)
  39.515 +{
  39.516 +	char *endp, *name = 0;
  39.517 +	Vector3 pos, rot_axis, scale;
  39.518 +	float rot_angle = 0;
  39.519 +	long tm = 0;
  39.520 +	Extrap extrap = EXTRAP_REPEAT;
  39.521 +
  39.522 +	bool have_pos = false;
  39.523 +	bool have_rot_axis = false;
  39.524 +	bool have_rot_angle = false;
  39.525 +	bool have_scale = false;
  39.526 +	bool have_extrap = false;
  39.527 +
  39.528 +	for(int i=0; argv[i]; i++) {
  39.529 +		if(strcmp(argv[i], "-name") == 0) {
  39.530 +			name = argv[++i];
  39.531 +
  39.532 +		} else if(strcmp(argv[i], "-pos") == 0) {
  39.533 +			if(!parse_vec(argv + i + 1, &pos)) {
  39.534 +				fprintf(stderr, "failed to parse xform position\n");
  39.535 +				return false;
  39.536 +			}
  39.537 +			have_pos = true;
  39.538 +			i += 3;
  39.539 +
  39.540 +		} else if(strcmp(argv[i], "-rot-axis") == 0) {
  39.541 +			if(!parse_vec(argv + i + 1, &rot_axis)) {
  39.542 +				fprintf(stderr, "failed to parse xform rotation axis\n");
  39.543 +				return false;
  39.544 +			}
  39.545 +			have_rot_axis = true;
  39.546 +			i += 3;
  39.547 +
  39.548 +		} else if(strcmp(argv[i], "-rot-angle") == 0) {
  39.549 +			rot_angle = strtod(argv[++i], &endp);
  39.550 +			if(endp == argv[i]) {
  39.551 +				fprintf(stderr, "failed to parse xform rotation angle\n");
  39.552 +				return false;
  39.553 +			}
  39.554 +			rot_angle = M_PI * rot_angle / 180.0;
  39.555 +			have_rot_angle = true;
  39.556 +
  39.557 +		} else if(strcmp(argv[i], "-scale") == 0) {
  39.558 +			if(!parse_vec(argv + i + 1, &scale)) {
  39.559 +				fprintf(stderr, "failed to parse xform scale\n");
  39.560 +				return false;
  39.561 +			}
  39.562 +			have_scale = true;
  39.563 +			i += 3;
  39.564 +
  39.565 +		} else if(strcmp(argv[i], "-time") == 0) {
  39.566 +			float tm_sec = strtod(argv[++i], &endp);
  39.567 +			if(endp == argv[i]) {
  39.568 +				fprintf(stderr, "failed to parse xform time\n");
  39.569 +				return false;
  39.570 +			}
  39.571 +			tm = (long)(tm_sec * 1000.0f);
  39.572 +
  39.573 +		} else if(strcmp(argv[i], "-extrapolation") == 0) {
  39.574 +			if(strcmp(argv[++i], "extend") == 0) {
  39.575 +				extrap = EXTRAP_EXTEND;
  39.576 +			} else if(strcmp(argv[i], "clamp") == 0) {
  39.577 +				extrap = EXTRAP_CLAMP;
  39.578 +			} else if(strcmp(argv[i], "repeat") == 0) {
  39.579 +				extrap = EXTRAP_REPEAT;
  39.580 +			} else if(strcmp(argv[i], "pingpong") == 0) {
  39.581 +				extrap = EXTRAP_PINGPONG;
  39.582 +			} else {
  39.583 +				fprintf(stderr, "failed to parse xform extrapolation, invalid mode: %s\n", argv[i]);
  39.584 +				return false;
  39.585 +			}
  39.586 +			have_extrap = true;
  39.587 +
  39.588 +		} else {
  39.589 +			fprintf(stderr, "invalid xform option: %s\n", argv[i]);
  39.590 +			return false;
  39.591 +		}
  39.592 +	}
  39.593 +
  39.594 +	if(!name) {
  39.595 +		fprintf(stderr, "invalid xform command, missing -name option\n");
  39.596 +		return false;
  39.597 +	}
  39.598 +	if(have_rot_angle != have_rot_axis) {
  39.599 +		fprintf(stderr, "invalid xform command, must have both -rot-angle and -rot-axis or neither\n");
  39.600 +		return false;
  39.601 +	}
  39.602 +
  39.603 +	Object *obj = 0;
  39.604 +
  39.605 +	int nobj = scn->get_object_count();
  39.606 +	for(int i=0; i<nobj; i++) {
  39.607 +		Object *tmp = scn->get_object(i);
  39.608 +		if(strcmp(tmp->get_name(), name) == 0) {
  39.609 +			obj = tmp;
  39.610 +			break;
  39.611 +		}
  39.612 +	}
  39.613 +
  39.614 +	if(!obj) {
  39.615 +		fprintf(stderr, "invalid xform, refers to nonexistent object: %s\n", name);
  39.616 +		return false;
  39.617 +	}
  39.618 +
  39.619 +	if(have_pos) {
  39.620 +		obj->set_position(pos, tm);
  39.621 +	}
  39.622 +	if(have_rot_angle) {
  39.623 +		obj->set_rotation(Quaternion(rot_axis, rot_angle), tm);
  39.624 +	}
  39.625 +	if(have_scale) {
  39.626 +		obj->set_scaling(scale, tm);
  39.627 +	}
  39.628 +
  39.629 +	if(have_extrap) {
  39.630 +		obj->set_extrapolator(extrap);
  39.631 +	}
  39.632 +	return true;
  39.633 +}
  39.634 +
  39.635 +static bool parse_vec(char **argv, Vector3 *vptr)
  39.636 +{
  39.637 +	char *endp;
  39.638 +
  39.639 +	vptr->x = strtod(argv[0], &endp);
  39.640 +	if(endp == argv[0])
  39.641 +		return false;
  39.642 +	vptr->y = strtod(argv[1], &endp);
  39.643 +	if(endp == argv[1])
  39.644 +		return false;
  39.645 +	vptr->z = strtod(argv[2], &endp);
  39.646 +	if(endp == argv[2])
  39.647 +		return false;
  39.648 +
  39.649 +	return true;
  39.650 +}
  39.651 +
  39.652 +
  39.653 +static char *strip_space(char *s)
  39.654 +{
  39.655 +	while(*s && isspace(*s)) s++;
  39.656 +
  39.657 +	if(!*s)
  39.658 +		return s;
  39.659 +
  39.660 +	char *endp = s + strlen(s) - 1;
  39.661 +	while(isspace(*endp)) endp--;
  39.662 +	endp[1] = 0;
  39.663 +
  39.664 +	if((endp = strrchr(s, '#'))) {
  39.665 +		*endp = 0;
  39.666 +	}
  39.667 +
  39.668 +	return s;
  39.669 +}
  39.670 +
  39.671 +static char **split_args(char *args)
  39.672 +{
  39.673 +	static std::vector<char*> argv;
  39.674 +	char *tok = 0;
  39.675 +
  39.676 +	argv.clear();
  39.677 +
  39.678 +	while((tok = strtok(tok ? 0 : args, " \t\v\n\r"))) {
  39.679 +		argv.push_back(tok);
  39.680 +	}
  39.681 +	argv.push_back(0);
  39.682 +
  39.683 +	return &argv[0];
  39.684 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/src/sphere.cc	Sun Nov 09 13:03:36 2014 +0200
    40.3 @@ -0,0 +1,52 @@
    40.4 +#include <stdio.h>
    40.5 +#include "sphere.h"
    40.6 +
    40.7 +Sphere::Sphere()
    40.8 +{
    40.9 +	radius = 1.0;
   40.10 +}
   40.11 +
   40.12 +Sphere::Sphere(const Vector3 &pos, float rad)
   40.13 +{
   40.14 +	radius = rad;
   40.15 +	this->pos = pos;
   40.16 +}
   40.17 +
   40.18 +bool Sphere::intersect(const Ray &inray, HitPoint *pt) const
   40.19 +{
   40.20 +	Ray ray = inray.transformed(inv_xform);
   40.21 +
   40.22 +	float a = dot_product(ray.dir, ray.dir);
   40.23 +	float b = 2.0 * ray.dir.x * (ray.origin.x - pos.x) +
   40.24 +		2.0 * ray.dir.y * (ray.origin.y - pos.y) +
   40.25 +		2.0 * ray.dir.z * (ray.origin.z - pos.z);
   40.26 +	float c = dot_product(ray.origin, ray.origin) + dot_product(pos, pos) -
   40.27 +		2.0 * dot_product(ray.origin, pos) - radius * radius;
   40.28 +
   40.29 +	float discr = b * b - 4.0 * a * c;
   40.30 +	if(discr < 1e-4)
   40.31 +		return false;
   40.32 +
   40.33 +	float sqrt_discr = sqrt(discr);
   40.34 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
   40.35 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
   40.36 +
   40.37 +	if(t0 < 1e-4)
   40.38 +		t0 = t1;
   40.39 +	if(t1 < 1e-4)
   40.40 +		t1 = t0;
   40.41 +
   40.42 +	float t = t0 < t1 ? t0 : t1;
   40.43 +	if(t < 1e-4)
   40.44 +		return false;
   40.45 +
   40.46 +	// fill the HitPoint structure
   40.47 +	pt->obj = this;
   40.48 +	pt->dist = t;
   40.49 +	pt->pos = ray.origin + ray.dir * t;
   40.50 +	pt->normal = (pt->pos - pos) / radius;
   40.51 +
   40.52 +	pt->pos.transform(xform);
   40.53 +	pt->normal.transform(dir_xform);
   40.54 +	return true;
   40.55 +}
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/src/sphere.h	Sun Nov 09 13:03:36 2014 +0200
    41.3 @@ -0,0 +1,35 @@
    41.4 +/*
    41.5 +Simple introductory ray tracer
    41.6 +Copyright (C) 2012  John Tsiombikas <nuclear@member.fsf.org>
    41.7 +
    41.8 +This program is free software: you can redistribute it and/or modify
    41.9 +it under the terms of the GNU General Public License as published by
   41.10 +the Free Software Foundation, either version 3 of the License, or
   41.11 +(at your option) any later version.
   41.12 +
   41.13 +This program is distributed in the hope that it will be useful,
   41.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   41.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   41.16 +GNU General Public License for more details.
   41.17 +
   41.18 +You should have received a copy of the GNU General Public License
   41.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   41.20 +*/
   41.21 +#ifndef SPHERE_H_
   41.22 +#define SPHERE_H_
   41.23 +
   41.24 +#include "vmath/vmath.h"
   41.25 +#include "object.h"
   41.26 +
   41.27 +class Sphere : public Object {
   41.28 +public:
   41.29 +	Vector3 pos;
   41.30 +	float radius;
   41.31 +
   41.32 +	Sphere();
   41.33 +	Sphere(const Vector3 &pos, float rad);
   41.34 +
   41.35 +	bool intersect(const Ray &ray, HitPoint *pt) const;
   41.36 +};
   41.37 +
   41.38 +#endif	// SPHERE_H_
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/src/texture.cc	Sun Nov 09 13:03:36 2014 +0200
    42.3 @@ -0,0 +1,237 @@
    42.4 +#include <stdio.h>
    42.5 +#include <unistd.h>
    42.6 +#include <string.h>
    42.7 +#include <errno.h>
    42.8 +#include "texture.h"
    42.9 +#include "object.h"
   42.10 +
   42.11 +static inline Color sample_image(const Image &img, float u, float v, Texture::WrapMode wrapping);
   42.12 +
   42.13 +Texture::Texture()
   42.14 +	: sampling(SampleMode::nearest), wrapping(WrapMode::repeat)
   42.15 +{
   42.16 +}
   42.17 +
   42.18 +Texture::~Texture() {}
   42.19 +
   42.20 +void Texture::set_name(const char *name)
   42.21 +{
   42.22 +	this->name = name;
   42.23 +}
   42.24 +
   42.25 +const char *Texture::get_name() const
   42.26 +{
   42.27 +	return name.c_str();
   42.28 +}
   42.29 +
   42.30 +void Texture::set_sampling_mode(SampleMode mode)
   42.31 +{
   42.32 +	sampling = mode;
   42.33 +}
   42.34 +
   42.35 +Texture::SampleMode Texture::get_sampling_mode() const
   42.36 +{
   42.37 +	return sampling;
   42.38 +}
   42.39 +
   42.40 +void Texture::set_wrapping_mode(WrapMode mode)
   42.41 +{
   42.42 +	wrapping = mode;
   42.43 +}
   42.44 +
   42.45 +Texture::WrapMode Texture::get_wrapping_mode() const
   42.46 +{
   42.47 +	return wrapping;
   42.48 +}
   42.49 +
   42.50 +
   42.51 +Color Texture::sample(const HitPoint &hit) const
   42.52 +{
   42.53 +	return sample(hit.texcoord.x, hit.texcoord.y, 0.0f);
   42.54 +}
   42.55 +
   42.56 +Image *Texture2D::get_image(int idx)
   42.57 +{
   42.58 +	return &img;
   42.59 +}
   42.60 +
   42.61 +const Image *Texture2D::get_image(int idx) const
   42.62 +{
   42.63 +	return &img;
   42.64 +}
   42.65 +
   42.66 +
   42.67 +bool Texture2D::load(const char *fname)
   42.68 +{
   42.69 +	name = fname;
   42.70 +	return img.load(fname);
   42.71 +}
   42.72 +
   42.73 +Color Texture2D::sample(float u, float v, float w) const
   42.74 +{
   42.75 +	return sample_image(img, u, v, wrapping);
   42.76 +}
   42.77 +
   42.78 +TextureCube::TextureCube()
   42.79 +{
   42.80 +	wrapping = WrapMode::clamp;
   42.81 +}
   42.82 +
   42.83 +Image *TextureCube::get_image(int idx)
   42.84 +{
   42.85 +	return &img[idx];
   42.86 +}
   42.87 +
   42.88 +const Image *TextureCube::get_image(int idx) const
   42.89 +{
   42.90 +	return &img[idx];
   42.91 +}
   42.92 +
   42.93 +
   42.94 +bool TextureCube::load(const char *fname)
   42.95 +{
   42.96 +	// assume it's a cubemap descriptor file (face path per line)
   42.97 +	FILE *fp;
   42.98 +	if(!(fp = fopen(fname, "r"))) {
   42.99 +		fprintf(stderr, "failed to open the cubemap descriptor %s: %s\n", fname, strerror(errno));
  42.100 +		return false;
  42.101 +	}
  42.102 +
  42.103 +	name = fname;
  42.104 +
  42.105 +	char *prefix = (char*)alloca(strlen(fname) + 1);
  42.106 +	strcpy(prefix, fname);
  42.107 +	char *ptr = strrchr(prefix, '/');
  42.108 +	if(!ptr) {
  42.109 +		ptr = prefix;
  42.110 +	}
  42.111 +	*ptr = 0;
  42.112 +
  42.113 +	int xsz = 0, ysz = 0;
  42.114 +
  42.115 +	// load the faces
  42.116 +	char buf[512];
  42.117 +	for(int i=0; i<6; i++) {
  42.118 +		if(!fgets(buf, sizeof buf, fp)) {
  42.119 +			fprintf(stderr, "invalid cubemap descriptor file: %s\n", fname);
  42.120 +			return false;
  42.121 +		}
  42.122 +		if(buf[strlen(buf) - 1] == '\n') {
  42.123 +			buf[strlen(buf) - 1] = 0;
  42.124 +		}
  42.125 +
  42.126 +		std::string path = std::string(prefix) + "/" + std::string(buf);
  42.127 +		if(!img[i].load(path.c_str())) {
  42.128 +			fprintf(stderr, "failed to load image: %s\n", path.c_str());
  42.129 +			fclose(fp);
  42.130 +			return false;
  42.131 +		}
  42.132 +
  42.133 +		if(i == 0) {
  42.134 +			xsz = img[i].xsz;
  42.135 +			ysz = img[i].ysz;
  42.136 +		} else {
  42.137 +			if(img[i].xsz != xsz || img[i].ysz != ysz) {
  42.138 +				fprintf(stderr, "cubemap %s face image %s size (%dx%d) doesn't match the previous faces (%dx%d)\n",
  42.139 +						fname, path.c_str(), img[i].xsz, img[i].ysz, xsz, ysz);
  42.140 +				fclose(fp);
  42.141 +				return false;
  42.142 +			}
  42.143 +		}
  42.144 +	}
  42.145 +	return true;
  42.146 +}
  42.147 +
  42.148 +Color TextureCube::sample(float u, float v, float w) const
  42.149 +{
  42.150 +	int face;
  42.151 +	Vector2 uv;
  42.152 +
  42.153 +	float abs_u = fabs(u);
  42.154 +	float abs_v = fabs(v);
  42.155 +	float abs_w = fabs(w);
  42.156 +
  42.157 +	if(abs_u > abs_v && abs_u > abs_w) {
  42.158 +		if(u >= 0.0) {
  42.159 +			face = 0;
  42.160 +			uv.x = w / abs_u;
  42.161 +			uv.y = v / abs_u;
  42.162 +		} else {
  42.163 +			face = 1;
  42.164 +			uv.x = -w / abs_u;
  42.165 +			uv.y = v / abs_u;
  42.166 +		}
  42.167 +	} else if(abs_v > abs_w) {
  42.168 +		if(v >= 0.0) {
  42.169 +			face = 2;
  42.170 +			uv.x = u / abs_v;
  42.171 +			uv.y = w / abs_v;
  42.172 +		} else {
  42.173 +			face = 3;
  42.174 +			uv.x = u / abs_v;
  42.175 +			uv.y = -w / abs_v;
  42.176 +		}
  42.177 +	} else {
  42.178 +		if(w >= 0.0) {
  42.179 +			face = 5;
  42.180 +			uv.x = -u / abs_w;
  42.181 +			uv.y = v / abs_w;
  42.182 +		} else {
  42.183 +			face = 4;
  42.184 +			uv.x = u / abs_w;
  42.185 +			uv.y = v / abs_w;
  42.186 +		}
  42.187 +	}
  42.188 +
  42.189 +	return sample_image(img[face], uv.x * 0.5 + 0.5, uv.y * 0.5 + 0.5, wrapping);
  42.190 +}
  42.191 +
  42.192 +Color TextureCube::sample(const HitPoint &hit) const
  42.193 +{
  42.194 +	return sample(hit.normal.x, hit.normal.y, hit.normal.z);
  42.195 +}
  42.196 +
  42.197 +Texture *load_texture(const char *fname)
  42.198 +{
  42.199 +	if(access(fname, R_OK) == -1) {
  42.200 +		fprintf(stderr, "failed to load texture %s: %s\n", fname, strerror(errno));
  42.201 +		return 0;
  42.202 +	}
  42.203 +
  42.204 +	Texture2D *tex2d = new Texture2D;
  42.205 +	if(tex2d->load(fname)) {
  42.206 +		return tex2d;
  42.207 +	}
  42.208 +	delete tex2d;
  42.209 +
  42.210 +	TextureCube *texcube = new TextureCube;
  42.211 +	if(texcube->load(fname)) {
  42.212 +		return texcube;
  42.213 +	}
  42.214 +	delete texcube;
  42.215 +
  42.216 +	return 0;
  42.217 +}
  42.218 +
  42.219 +#define CLAMP(x, lo, hi)	((x) < (lo) ? (lo) : ((x) > (hi) ? (hi) : (x)))
  42.220 +
  42.221 +static inline Color sample_image(const Image &img, float u, float v, Texture::WrapMode wrapping)
  42.222 +{
  42.223 +	int x = (int)round(u * img.xsz);
  42.224 +	int y = (int)round((1.0 - v) * img.ysz);
  42.225 +
  42.226 +	if(wrapping == Texture::WrapMode::clamp) {
  42.227 +		x = CLAMP(x, 0, img.xsz - 1);
  42.228 +		y = CLAMP(y, 0, img.ysz - 1);
  42.229 +	} else {
  42.230 +		x %= img.xsz;
  42.231 +		y %= img.ysz;
  42.232 +
  42.233 +		if(x < 0)
  42.234 +			x += img.xsz;
  42.235 +		if(y < 0)
  42.236 +			y += img.ysz;
  42.237 +	}
  42.238 +
  42.239 +	return img.pixels[y * img.xsz + x];
  42.240 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/src/texture.h	Sun Nov 09 13:03:36 2014 +0200
    43.3 @@ -0,0 +1,76 @@
    43.4 +#ifndef TEXTURE_H_
    43.5 +#define TEXTURE_H_
    43.6 +
    43.7 +#include <string>
    43.8 +#include "image.h"
    43.9 +
   43.10 +struct HitPoint;
   43.11 +
   43.12 +class Texture {
   43.13 +public:
   43.14 +	enum class SampleMode { nearest, linear };
   43.15 +	enum class WrapMode { clamp, repeat };
   43.16 +
   43.17 +protected:
   43.18 +	std::string name;
   43.19 +
   43.20 +	SampleMode sampling;
   43.21 +	WrapMode wrapping;
   43.22 +
   43.23 +public:
   43.24 +	Texture();
   43.25 +	virtual ~Texture();
   43.26 +
   43.27 +	virtual void set_name(const char *name);
   43.28 +	virtual const char *get_name() const;
   43.29 +
   43.30 +	virtual Image *get_image(int idx = 0) = 0;
   43.31 +	virtual const Image *get_image(int idx = 0) const = 0;
   43.32 +
   43.33 +	virtual void set_sampling_mode(SampleMode mode);
   43.34 +	virtual SampleMode get_sampling_mode() const;
   43.35 +	virtual void set_wrapping_mode(WrapMode mode);
   43.36 +	virtual WrapMode get_wrapping_mode() const;
   43.37 +
   43.38 +	virtual bool load(const char *fname) = 0;
   43.39 +
   43.40 +	virtual Color sample(float u, float v, float w) const = 0;
   43.41 +	virtual Color sample(const HitPoint &hit) const;
   43.42 +};
   43.43 +
   43.44 +class Texture2D : public Texture {
   43.45 +private:
   43.46 +	Image img;
   43.47 +
   43.48 +public:
   43.49 +	virtual Image *get_image(int idx = 0);
   43.50 +	virtual const Image *get_image(int idx = 0) const;
   43.51 +
   43.52 +	virtual bool load(const char *fname);
   43.53 +
   43.54 +	virtual Color sample(float u, float v, float w) const;
   43.55 +
   43.56 +	friend Texture *load_texture(const char *fname);
   43.57 +};
   43.58 +
   43.59 +class TextureCube : public Texture {
   43.60 +private:
   43.61 +	Image img[6];
   43.62 +
   43.63 +public:
   43.64 +	TextureCube();
   43.65 +
   43.66 +	virtual Image *get_image(int idx = 0);
   43.67 +	virtual const Image *get_image(int idx = 0) const;
   43.68 +
   43.69 +	virtual bool load(const char *fname);
   43.70 +
   43.71 +	virtual Color sample(float u, float v, float w) const;
   43.72 +	virtual Color sample(const HitPoint &hit) const;
   43.73 +
   43.74 +	friend Texture *load_texture(const char *fname);
   43.75 +};
   43.76 +
   43.77 +Texture *load_texture(const char *fname);
   43.78 +
   43.79 +#endif	// TEXTURE_H_
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/src/xform_node.cc	Sun Nov 09 13:03:36 2014 +0200
    44.3 @@ -0,0 +1,372 @@
    44.4 +#include <assert.h>
    44.5 +#include <algorithm>
    44.6 +#include "xform_node.h"
    44.7 +#include "anim/anim.h"
    44.8 +#include "anim/track.h"
    44.9 +
   44.10 +static inline anm_interpolator track_interpolator(Interp in);
   44.11 +static inline anm_extrapolator track_extrapolator(Extrap ex);
   44.12 +
   44.13 +XFormNode::XFormNode()
   44.14 +{
   44.15 +	anm = new anm_node;
   44.16 +	anm_init_node(anm);
   44.17 +}
   44.18 +
   44.19 +XFormNode::~XFormNode()
   44.20 +{
   44.21 +	anm_destroy_node(anm);
   44.22 +	delete anm;
   44.23 +}
   44.24 +
   44.25 +void XFormNode::set_name(const char *name)
   44.26 +{
   44.27 +	anm_set_node_name(anm, name);
   44.28 +}
   44.29 +
   44.30 +const char *XFormNode::get_name() const
   44.31 +{
   44.32 +	return anm_get_node_name(anm);
   44.33 +}
   44.34 +
   44.35 +void XFormNode::set_interpolator(Interp in)
   44.36 +{
   44.37 +	anm_set_interpolator(anm, track_interpolator(in));
   44.38 +	interp = in;
   44.39 +}
   44.40 +
   44.41 +Interp XFormNode::get_interpolator() const
   44.42 +{
   44.43 +	return interp;
   44.44 +}
   44.45 +
   44.46 +void XFormNode::set_extrapolator(Extrap ex)
   44.47 +{
   44.48 +	anm_set_extrapolator(anm, track_extrapolator(ex));
   44.49 +	extrap = ex;
   44.50 +}
   44.51 +
   44.52 +Extrap XFormNode::get_extrapolator() const
   44.53 +{
   44.54 +	return extrap;
   44.55 +}
   44.56 +
   44.57 +void XFormNode::add_child(XFormNode *child)
   44.58 +{
   44.59 +	children.push_back(child);
   44.60 +	anm_link_node(anm, child->anm);
   44.61 +}
   44.62 +
   44.63 +void XFormNode::remove_child(XFormNode *child)
   44.64 +{
   44.65 +	std::vector<XFormNode*>::iterator it;
   44.66 +	it = std::find(children.begin(), children.end(), child);
   44.67 +	if(it != children.end()) {
   44.68 +		children.erase(it);
   44.69 +		anm_unlink_node(anm, child->anm);
   44.70 +	}
   44.71 +}
   44.72 +
   44.73 +int XFormNode::get_children_count() const
   44.74 +{
   44.75 +	return (int)children.size();
   44.76 +}
   44.77 +
   44.78 +XFormNode *XFormNode::get_child(int idx)
   44.79 +{
   44.80 +	if(idx >= 0 && idx < get_children_count()) {
   44.81 +		return children[idx];
   44.82 +	}
   44.83 +	return 0;
   44.84 +}
   44.85 +
   44.86 +const XFormNode *XFormNode::get_child(int idx) const
   44.87 +{
   44.88 +	if(idx >= 0 && idx < get_children_count()) {
   44.89 +		return children[idx];
   44.90 +	}
   44.91 +	return 0;
   44.92 +}
   44.93 +
   44.94 +void XFormNode::set_position(const Vector3 &pos, long tmsec)
   44.95 +{
   44.96 +	anm_set_position(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
   44.97 +}
   44.98 +
   44.99 +Vector3 XFormNode::get_node_position(long tmsec) const
  44.100 +{
  44.101 +	vec3_t p = anm_get_node_position(anm, ANM_MSEC2TM(tmsec));
  44.102 +	return Vector3(p.x, p.y, p.z);
  44.103 +}
  44.104 +
  44.105 +void XFormNode::set_rotation(const Quaternion &quat, long tmsec)
  44.106 +{
  44.107 +	anm_set_rotation(anm, quat_cons(quat.s, quat.v.x, quat.v.y, quat.v.z), ANM_MSEC2TM(tmsec));
  44.108 +}
  44.109 +
  44.110 +Quaternion XFormNode::get_node_rotation(long tmsec) const
  44.111 +{
  44.112 +	quat_t q = anm_get_node_rotation(anm, ANM_MSEC2TM(tmsec));
  44.113 +	return Quaternion(q.w, q.x, q.y, q.z);
  44.114 +}
  44.115 +
  44.116 +void XFormNode::set_scaling(const Vector3 &pos, long tmsec)
  44.117 +{
  44.118 +	anm_set_scaling(anm, v3_cons(pos.x, pos.y, pos.z), ANM_MSEC2TM(tmsec));
  44.119 +}
  44.120 +
  44.121 +Vector3 XFormNode::get_node_scaling(long tmsec) const
  44.122 +{
  44.123 +	vec3_t s = anm_get_node_scaling(anm, ANM_MSEC2TM(tmsec));
  44.124 +	return Vector3(s.x, s.y, s.z);
  44.125 +}
  44.126 +
  44.127 +// these take hierarchy into account
  44.128 +Vector3 XFormNode::get_position(long tmsec) const
  44.129 +{
  44.130 +	vec3_t v = anm_get_position(anm, ANM_MSEC2TM(tmsec));
  44.131 +	return Vector3(v.x, v.y, v.z);
  44.132 +}
  44.133 +
  44.134 +Quaternion XFormNode::get_rotation(long tmsec) const
  44.135 +{
  44.136 +	quat_t q = anm_get_rotation(anm, tmsec);
  44.137 +	return Quaternion(q.w, q.x, q.y, q.z);
  44.138 +}
  44.139 +
  44.140 +Vector3 XFormNode::get_scaling(long tmsec) const
  44.141 +{
  44.142 +	vec3_t v = anm_get_scaling(anm, ANM_MSEC2TM(tmsec));
  44.143 +	return Vector3(v.x, v.y, v.z);
  44.144 +}
  44.145 +
  44.146 +void XFormNode::set_pivot(const Vector3 &pivot)
  44.147 +{
  44.148 +	anm_set_pivot(anm, v3_cons(pivot.x, pivot.y, pivot.z));
  44.149 +}
  44.150 +
  44.151 +Vector3 XFormNode::get_pivot() const
  44.152 +{
  44.153 +	vec3_t p = anm_get_pivot(anm);
  44.154 +	return Vector3(p.x, p.y, p.z);
  44.155 +}
  44.156 +
  44.157 +void XFormNode::set_local_matrix(const Matrix4x4 &mat)
  44.158 +{
  44.159 +	local_matrix = mat;
  44.160 +}
  44.161 +
  44.162 +const Matrix4x4 &XFormNode::get_local_matrix() const
  44.163 +{
  44.164 +	return local_matrix;
  44.165 +}
  44.166 +
  44.167 +void XFormNode::set_bone_matrix(const Matrix4x4 &bmat)
  44.168 +{
  44.169 +	bone_matrix = bmat;
  44.170 +}
  44.171 +
  44.172 +const Matrix4x4 &XFormNode::get_bone_matrix() const
  44.173 +{
  44.174 +	return bone_matrix;
  44.175 +}
  44.176 +
  44.177 +#define FOO
  44.178 +
  44.179 +void XFormNode::get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  44.180 +{
  44.181 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  44.182 +
  44.183 +	if(mat) {
  44.184 +		anm_get_node_matrix(anm, (scalar_t(*)[4])mat, tm);
  44.185 +#ifdef FOO
  44.186 +		*mat = local_matrix * *mat;
  44.187 +#else
  44.188 +		*mat = *mat * local_matrix;
  44.189 +#endif
  44.190 +	}
  44.191 +	if(inv_mat) {
  44.192 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  44.193 +	}
  44.194 +}
  44.195 +
  44.196 +void XFormNode::get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat) const
  44.197 +{
  44.198 +	anm_time_t tm = ANM_MSEC2TM(tmsec);
  44.199 +
  44.200 +	if(mat) {
  44.201 +		anm_get_matrix(anm, (scalar_t(*)[4])mat, tm);
  44.202 +#ifdef FOO
  44.203 +		*mat = local_matrix * *mat;
  44.204 +#else
  44.205 +		*mat = *mat * local_matrix;
  44.206 +#endif
  44.207 +	}
  44.208 +	if(inv_mat) {
  44.209 +		anm_get_inv_matrix(anm, (scalar_t(*)[4])inv_mat, tm);
  44.210 +	}
  44.211 +}
  44.212 +
  44.213 +
  44.214 +// ---- Track ----
  44.215 +
  44.216 +Track::Track()
  44.217 +{
  44.218 +	trk = new anm_track;
  44.219 +	anm_init_track(trk);
  44.220 +}
  44.221 +
  44.222 +Track::~Track()
  44.223 +{
  44.224 +	anm_destroy_track(trk);
  44.225 +	delete trk;
  44.226 +}
  44.227 +
  44.228 +Track::Track(const Track &rhs)
  44.229 +{
  44.230 +	trk = new anm_track;
  44.231 +	anm_init_track(trk);
  44.232 +	anm_copy_track(trk, rhs.trk);
  44.233 +	interp = rhs.interp;
  44.234 +	extrap = rhs.extrap;
  44.235 +}
  44.236 +
  44.237 +Track &Track::operator =(const Track &rhs)
  44.238 +{
  44.239 +	if(&rhs == this) {
  44.240 +		return *this;
  44.241 +	}
  44.242 +
  44.243 +	anm_copy_track(trk, rhs.trk);
  44.244 +	interp = rhs.interp;
  44.245 +	extrap = rhs.extrap;
  44.246 +	return *this;
  44.247 +}
  44.248 +
  44.249 +
  44.250 +void Track::set_interpolator(Interp in)
  44.251 +{
  44.252 +	anm_set_track_interpolator(trk, track_interpolator(in));
  44.253 +	interp = in;
  44.254 +}
  44.255 +
  44.256 +Interp Track::get_interpolator() const
  44.257 +{
  44.258 +	return interp;
  44.259 +}
  44.260 +
  44.261 +void Track::set_extrapolator(Extrap ex)
  44.262 +{
  44.263 +	anm_set_track_extrapolator(trk, track_extrapolator(ex));
  44.264 +	extrap = ex;
  44.265 +}
  44.266 +
  44.267 +Extrap Track::get_extrapolator() const
  44.268 +{
  44.269 +	return extrap;
  44.270 +}
  44.271 +
  44.272 +void Track::set_default(double def)
  44.273 +{
  44.274 +	anm_set_track_default(trk, def);
  44.275 +}
  44.276 +
  44.277 +void Track::set_value(float val, long tmsec)
  44.278 +{
  44.279 +	anm_set_value(trk, ANM_MSEC2TM(tmsec), val);
  44.280 +}
  44.281 +
  44.282 +float Track::get_value(long tmsec) const
  44.283 +{
  44.284 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  44.285 +}
  44.286 +
  44.287 +float Track::operator ()(long tmsec) const
  44.288 +{
  44.289 +	return anm_get_value(trk, ANM_MSEC2TM(tmsec));
  44.290 +}
  44.291 +
  44.292 +
  44.293 +// ---- Track3 ----
  44.294 +
  44.295 +void Track3::set_interpolator(Interp in)
  44.296 +{
  44.297 +	for(int i=0; i<3; i++) {
  44.298 +		track[i].set_interpolator(in);
  44.299 +	}
  44.300 +}
  44.301 +
  44.302 +Interp Track3::get_interpolator() const
  44.303 +{
  44.304 +	return track[0].get_interpolator();
  44.305 +}
  44.306 +
  44.307 +void Track3::set_extrapolator(Extrap ex)
  44.308 +{
  44.309 +	for(int i=0; i<3; i++) {
  44.310 +		track[i].set_extrapolator(ex);
  44.311 +	}
  44.312 +}
  44.313 +
  44.314 +Extrap Track3::get_extrapolator() const
  44.315 +{
  44.316 +	return track[0].get_extrapolator();
  44.317 +}
  44.318 +
  44.319 +void Track3::set_default(const Vector3 &def)
  44.320 +{
  44.321 +	for(int i=0; i<3; i++) {
  44.322 +		track[i].set_default(def[i]);
  44.323 +	}
  44.324 +}
  44.325 +
  44.326 +void Track3::set_value(const Vector3 &val, long tmsec)
  44.327 +{
  44.328 +	for(int i=0; i<3; i++) {
  44.329 +		track[i].set_value(val[i], tmsec);
  44.330 +	}
  44.331 +}
  44.332 +
  44.333 +Vector3 Track3::get_value(long tmsec) const
  44.334 +{
  44.335 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  44.336 +}
  44.337 +
  44.338 +Vector3 Track3::operator ()(long tmsec) const
  44.339 +{
  44.340 +	return Vector3(track[0](tmsec), track[1](tmsec), track[2](tmsec));
  44.341 +}
  44.342 +
  44.343 +
  44.344 +static inline anm_interpolator track_interpolator(Interp in)
  44.345 +{
  44.346 +	switch(in) {
  44.347 +	case INTERP_STEP:
  44.348 +		return ANM_INTERP_STEP;
  44.349 +	case INTERP_LINEAR:
  44.350 +		return ANM_INTERP_LINEAR;
  44.351 +	case INTERP_CUBIC:
  44.352 +		return ANM_INTERP_CUBIC;
  44.353 +	}
  44.354 +
  44.355 +	assert(0);
  44.356 +	return ANM_INTERP_STEP;
  44.357 +}
  44.358 +
  44.359 +static inline anm_extrapolator track_extrapolator(Extrap ex)
  44.360 +{
  44.361 +	switch(ex) {
  44.362 +	case EXTRAP_EXTEND:
  44.363 +		return ANM_EXTRAP_EXTEND;
  44.364 +	case EXTRAP_CLAMP:
  44.365 +		return ANM_EXTRAP_CLAMP;
  44.366 +	case EXTRAP_REPEAT:
  44.367 +		return ANM_EXTRAP_REPEAT;
  44.368 +	case EXTRAP_PINGPONG:
  44.369 +		return ANM_EXTRAP_PINGPONG;
  44.370 +	}
  44.371 +
  44.372 +	assert(0);
  44.373 +	return ANM_EXTRAP_EXTEND;
  44.374 +}
  44.375 +
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/src/xform_node.h	Sun Nov 09 13:03:36 2014 +0200
    45.3 @@ -0,0 +1,134 @@
    45.4 +/*
    45.5 +TODO: add multiple animations per node in libanim (i.e. multiple sets of tracks)
    45.6 +*/
    45.7 +#ifndef XFORM_NODE_H_
    45.8 +#define XFORM_NODE_H_
    45.9 +
   45.10 +#include <vector>
   45.11 +#include "vmath/vector.h"
   45.12 +#include "vmath/quat.h"
   45.13 +#include "vmath/matrix.h"
   45.14 +
   45.15 +enum Interp { INTERP_STEP, INTERP_LINEAR, INTERP_CUBIC };
   45.16 +enum Extrap { EXTRAP_EXTEND, EXTRAP_CLAMP, EXTRAP_REPEAT, EXTRAP_PINGPONG };
   45.17 +
   45.18 +struct anm_node;
   45.19 +struct anm_track;
   45.20 +
   45.21 +// XXX all time arguments are milliseconds
   45.22 +
   45.23 +class XFormNode {
   45.24 +private:
   45.25 +	struct anm_node *anm;
   45.26 +	std::vector<XFormNode*> children;
   45.27 +
   45.28 +	Interp interp;
   45.29 +	Extrap extrap;
   45.30 +
   45.31 +	Matrix4x4 local_matrix;
   45.32 +	Matrix4x4 bone_matrix;
   45.33 +
   45.34 +	XFormNode(const XFormNode &node) {}
   45.35 +	XFormNode &operator =(const XFormNode &node) { return *this; }
   45.36 +
   45.37 +public:
   45.38 +	XFormNode();
   45.39 +	virtual ~XFormNode();
   45.40 +
   45.41 +	void set_name(const char *name);
   45.42 +	const char *get_name() const;
   45.43 +
   45.44 +	void set_interpolator(Interp in);
   45.45 +	Interp get_interpolator() const;
   45.46 +	void set_extrapolator(Extrap ex);
   45.47 +	Extrap get_extrapolator() const;
   45.48 +
   45.49 +	// children management
   45.50 +	void add_child(XFormNode *child);
   45.51 +	void remove_child(XFormNode *child);
   45.52 +
   45.53 +	int get_children_count() const;
   45.54 +	XFormNode *get_child(int idx);
   45.55 +	const XFormNode *get_child(int idx) const;
   45.56 +
   45.57 +
   45.58 +	void set_position(const Vector3 &pos, long tmsec = 0);
   45.59 +	Vector3 get_node_position(long tmsec = 0) const;
   45.60 +
   45.61 +	void set_rotation(const Quaternion &quat, long tmsec = 0);
   45.62 +	Quaternion get_node_rotation(long tmsec = 0) const;
   45.63 +
   45.64 +	void set_scaling(const Vector3 &pos, long tmsec = 0);
   45.65 +	Vector3 get_node_scaling(long tmsec = 0) const;
   45.66 +
   45.67 +	// these take hierarchy into account
   45.68 +	Vector3 get_position(long tmsec = 0) const;
   45.69 +	Quaternion get_rotation(long tmsec = 0) const;
   45.70 +	Vector3 get_scaling(long tmsec = 0) const;
   45.71 +
   45.72 +	void set_pivot(const Vector3 &pivot);
   45.73 +	Vector3 get_pivot() const;
   45.74 +
   45.75 +	// the local matrix is concatenated with the regular node/anim matrix
   45.76 +	void set_local_matrix(const Matrix4x4 &mat);
   45.77 +	const Matrix4x4 &get_local_matrix() const;
   45.78 +
   45.79 +	// for bone nodes, the transformation of the bone in bind position
   45.80 +	void set_bone_matrix(const Matrix4x4 &bmat);
   45.81 +	const Matrix4x4 &get_bone_matrix() const;
   45.82 +
   45.83 +	// node transformation alone
   45.84 +	void get_node_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
   45.85 +
   45.86 +	// node transformation taking hierarchy into account
   45.87 +	void get_xform(long tmsec, Matrix4x4 *mat, Matrix4x4 *inv_mat = 0) const;
   45.88 +};
   45.89 +
   45.90 +
   45.91 +class Track {
   45.92 +private:
   45.93 +	struct anm_track *trk;
   45.94 +	Interp interp;
   45.95 +	Extrap extrap;
   45.96 +
   45.97 +public:
   45.98 +	Track();
   45.99 +	~Track();
  45.100 +
  45.101 +	Track(const Track &trk);
  45.102 +	Track &operator =(const Track &trk);
  45.103 +
  45.104 +	void set_interpolator(Interp in);
  45.105 +	Interp get_interpolator() const;
  45.106 +	void set_extrapolator(Extrap ex);
  45.107 +	Extrap get_extrapolator() const;
  45.108 +
  45.109 +	void set_default(double def);
  45.110 +
  45.111 +	void set_value(float val, long tmsec = 0);
  45.112 +	float get_value(long tmsec = 0) const;
  45.113 +
  45.114 +	// the same as get_value
  45.115 +	float operator ()(long tmsec = 0) const;
  45.116 +};
  45.117 +
  45.118 +class Track3 {
  45.119 +private:
  45.120 +	Track track[3];
  45.121 +
  45.122 +public:
  45.123 +	void set_interpolator(Interp in);
  45.124 +	Interp get_interpolator() const;
  45.125 +	void set_extrapolator(Extrap ex);
  45.126 +	Extrap get_extrapolator() const;
  45.127 +
  45.128 +	void set_default(const Vector3 &def);
  45.129 +
  45.130 +	void set_value(const Vector3 &val, long tmsec = 0);
  45.131 +	Vector3 get_value(long tmsec = 0) const;
  45.132 +
  45.133 +	// the same as get_value
  45.134 +	Vector3 operator ()(long tmsec = 0) const;
  45.135 +};
  45.136 +
  45.137 +#endif	/* XFORM_NODE_H_ */
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/util/anim.c	Sun Nov 09 13:03:36 2014 +0200
    46.3 @@ -0,0 +1,26 @@
    46.4 +#include <stdio.h>
    46.5 +#include <math.h>
    46.6 +
    46.7 +#define NUM_SEG	96
    46.8 +#define DIST	12
    46.9 +#define NAME	"green_sphere"
   46.10 +#define FULL_TIME	10.0
   46.11 +#define BOUNCES		6.0
   46.12 +#define HEIGHT		3.5
   46.13 +
   46.14 +int main(void)
   46.15 +{
   46.16 +	int i;
   46.17 +	for(i=0; i<NUM_SEG; i++) {
   46.18 +		float t = (float)i / (NUM_SEG - 1);
   46.19 +		float angle = 2.0 * M_PI * t;
   46.20 +		float x = -cos(angle) * DIST;
   46.21 +		float z = -sin(angle) * DIST;
   46.22 +
   46.23 +		float y = fabs(sin(angle * BOUNCES)) * HEIGHT;
   46.24 +
   46.25 +		printf("xform -name %s -time %.2f -pos %.2f %.2f %.2f\n",
   46.26 +				NAME, t * FULL_TIME, x, y, z);
   46.27 +	}
   46.28 +	return 0;
   46.29 +}
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/vmath/matrix.cc	Sun Nov 09 13:03:36 2014 +0200
    47.3 @@ -0,0 +1,802 @@
    47.4 +#include <cstdio>
    47.5 +#include <cmath>
    47.6 +#include "matrix.h"
    47.7 +#include "vector.h"
    47.8 +#include "quat.h"
    47.9 +
   47.10 +using namespace std;
   47.11 +
   47.12 +// ----------- Matrix3x3 --------------
   47.13 +
   47.14 +Matrix3x3 Matrix3x3::identity = Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
   47.15 +
   47.16 +Matrix3x3::Matrix3x3()
   47.17 +{
   47.18 +	*this = identity;
   47.19 +}
   47.20 +
   47.21 +Matrix3x3::Matrix3x3(	scalar_t m11, scalar_t m12, scalar_t m13,
   47.22 +						scalar_t m21, scalar_t m22, scalar_t m23,
   47.23 +						scalar_t m31, scalar_t m32, scalar_t m33)
   47.24 +{
   47.25 +	m[0][0] = m11; m[0][1] = m12; m[0][2] = m13;
   47.26 +	m[1][0] = m21; m[1][1] = m22; m[1][2] = m23;
   47.27 +	m[2][0] = m31; m[2][1] = m32; m[2][2] = m33;
   47.28 +}
   47.29 +
   47.30 +Matrix3x3::Matrix3x3(const Vector3 &ivec, const Vector3 &jvec, const Vector3 &kvec)
   47.31 +{
   47.32 +	set_row_vector(ivec, 0);
   47.33 +	set_row_vector(jvec, 1);
   47.34 +	set_row_vector(kvec, 2);
   47.35 +}
   47.36 +
   47.37 +Matrix3x3::Matrix3x3(const mat3_t cmat)
   47.38 +{
   47.39 +	memcpy(m, cmat, sizeof(mat3_t));
   47.40 +}
   47.41 +
   47.42 +Matrix3x3::Matrix3x3(const Matrix4x4 &mat4x4)
   47.43 +{
   47.44 +	for(int i=0; i<3; i++) {
   47.45 +		for(int j=0; j<3; j++) {
   47.46 +			m[i][j] = mat4x4[i][j];
   47.47 +		}
   47.48 +	}
   47.49 +}
   47.50 +
   47.51 +Matrix3x3 operator +(const Matrix3x3 &m1, const Matrix3x3 &m2)
   47.52 +{
   47.53 +	Matrix3x3 res;
   47.54 +	const scalar_t *op1 = m1.m[0], *op2 = m2.m[0];
   47.55 +	scalar_t *dest = res.m[0];
   47.56 +
   47.57 +	for(int i=0; i<9; i++) {
   47.58 +		*dest++ = *op1++ + *op2++;
   47.59 +	}
   47.60 +	return res;
   47.61 +}
   47.62 +
   47.63 +Matrix3x3 operator -(const Matrix3x3 &m1, const Matrix3x3 &m2)
   47.64 +{
   47.65 +	Matrix3x3 res;
   47.66 +	const scalar_t *op1 = m1.m[0], *op2 = m2.m[0];
   47.67 +	scalar_t *dest = res.m[0];
   47.68 +
   47.69 +	for(int i=0; i<9; i++) {
   47.70 +		*dest++ = *op1++ - *op2++;
   47.71 +	}
   47.72 +	return res;
   47.73 +}
   47.74 +
   47.75 +Matrix3x3 operator *(const Matrix3x3 &m1, const Matrix3x3 &m2)
   47.76 +{
   47.77 +	Matrix3x3 res;
   47.78 +	for(int i=0; i<3; i++) {
   47.79 +		for(int j=0; j<3; j++) {
   47.80 +			res.m[i][j] = m1.m[i][0] * m2.m[0][j] + m1.m[i][1] * m2.m[1][j] + m1.m[i][2] * m2.m[2][j];
   47.81 +		}
   47.82 +	}
   47.83 +	return res;
   47.84 +}
   47.85 +
   47.86 +void operator +=(Matrix3x3 &m1, const Matrix3x3 &m2)
   47.87 +{
   47.88 +	scalar_t *op1 = m1.m[0];
   47.89 +	const scalar_t *op2 = m2.m[0];
   47.90 +
   47.91 +	for(int i=0; i<9; i++) {
   47.92 +		*op1++ += *op2++;
   47.93 +	}
   47.94 +}
   47.95 +
   47.96 +void operator -=(Matrix3x3 &m1, const Matrix3x3 &m2)
   47.97 +{
   47.98 +	scalar_t *op1 = m1.m[0];
   47.99 +	const scalar_t *op2 = m2.m[0];
  47.100 +
  47.101 +	for(int i=0; i<9; i++) {
  47.102 +		*op1++ -= *op2++;
  47.103 +	}
  47.104 +}
  47.105 +
  47.106 +void operator *=(Matrix3x3 &m1, const Matrix3x3 &m2)
  47.107 +{
  47.108 +	Matrix3x3 res;
  47.109 +	for(int i=0; i<3; i++) {
  47.110 +		for(int j=0; j<3; j++) {
  47.111 +			res.m[i][j] = m1.m[i][0] * m2.m[0][j] + m1.m[i][1] * m2.m[1][j] + m1.m[i][2] * m2.m[2][j];
  47.112 +		}
  47.113 +	}
  47.114 +	memcpy(m1.m, res.m, 9 * sizeof(scalar_t));
  47.115 +}
  47.116 +
  47.117 +Matrix3x3 operator *(const Matrix3x3 &mat, scalar_t scalar)
  47.118 +{
  47.119 +	Matrix3x3 res;
  47.120 +	const scalar_t *mptr = mat.m[0];
  47.121 +	scalar_t *dptr = res.m[0];
  47.122 +
  47.123 +	for(int i=0; i<9; i++) {
  47.124 +		*dptr++ = *mptr++ * scalar;
  47.125 +	}
  47.126 +	return res;
  47.127 +}
  47.128 +
  47.129 +Matrix3x3 operator *(scalar_t scalar, const Matrix3x3 &mat)
  47.130 +{
  47.131 +	Matrix3x3 res;
  47.132 +	const scalar_t *mptr = mat.m[0];
  47.133 +	scalar_t *dptr = res.m[0];
  47.134 +
  47.135 +	for(int i=0; i<9; i++) {
  47.136 +		*dptr++ = *mptr++ * scalar;
  47.137 +	}
  47.138 +	return res;
  47.139 +}
  47.140 +
  47.141 +void operator *=(Matrix3x3 &mat, scalar_t scalar)
  47.142 +{
  47.143 +	scalar_t *mptr = mat.m[0];
  47.144 +
  47.145 +	for(int i=0; i<9; i++) {
  47.146 +		*mptr++ *= scalar;
  47.147 +	}
  47.148 +}
  47.149 +
  47.150 +void Matrix3x3::translate(const Vector2 &trans)
  47.151 +{
  47.152 +	Matrix3x3 tmat(1, 0, trans.x, 0, 1, trans.y, 0, 0, 1);
  47.153 +	*this *= tmat;
  47.154 +}
  47.155 +
  47.156 +void Matrix3x3::set_translation(const Vector2 &trans)
  47.157 +{
  47.158 +	*this = Matrix3x3(1, 0, trans.x, 0, 1, trans.y, 0, 0, 1);
  47.159 +}
  47.160 +
  47.161 +void Matrix3x3::rotate(scalar_t angle)
  47.162 +{
  47.163 +	scalar_t cos_a = cos(angle);
  47.164 +	scalar_t sin_a = sin(angle);
  47.165 +	Matrix3x3 rmat(	cos_a,	-sin_a,		0,
  47.166 +					sin_a,	cos_a,		0,
  47.167 +					0,		0,			1);
  47.168 +	*this *= rmat;
  47.169 +}
  47.170 +
  47.171 +void Matrix3x3::set_rotation(scalar_t angle)
  47.172 +{
  47.173 +	scalar_t cos_a = cos(angle);
  47.174 +	scalar_t sin_a = sin(angle);
  47.175 +	*this = Matrix3x3(cos_a, -sin_a, 0, sin_a, cos_a, 0, 0, 0, 1);
  47.176 +}
  47.177 +
  47.178 +void Matrix3x3::rotate(const Vector3 &euler_angles)
  47.179 +{
  47.180 +	Matrix3x3 xrot, yrot, zrot;
  47.181 +
  47.182 +	xrot = Matrix3x3(	1,			0,					0,
  47.183 +						0,	cos(euler_angles.x),	-sin(euler_angles.x),
  47.184 +						0,	sin(euler_angles.x),	cos(euler_angles.x));
  47.185 +
  47.186 +	yrot = Matrix3x3(	cos(euler_angles.y),	0,	sin(euler_angles.y),
  47.187 +								0,				1,				0,
  47.188 +						-sin(euler_angles.y),	0,	cos(euler_angles.y));
  47.189 +
  47.190 +	zrot = Matrix3x3(	cos(euler_angles.z),	-sin(euler_angles.z),	0,
  47.191 +						sin(euler_angles.z),	cos(euler_angles.z),	0,
  47.192 +								0,						0,				1);
  47.193 +
  47.194 +	*this *= xrot * yrot * zrot;
  47.195 +}
  47.196 +
  47.197 +void Matrix3x3::set_rotation(const Vector3 &euler_angles)
  47.198 +{
  47.199 +	Matrix3x3 xrot, yrot, zrot;
  47.200 +
  47.201 +	xrot = Matrix3x3(	1,			0,					0,
  47.202 +						0,	cos(euler_angles.x),	-sin(euler_angles.x),
  47.203 +						0,	sin(euler_angles.x),	cos(euler_angles.x));
  47.204 +
  47.205 +	yrot = Matrix3x3(	cos(euler_angles.y),	0,	sin(euler_angles.y),
  47.206 +								0,				1,				0,
  47.207 +						-sin(euler_angles.y),	0,	cos(euler_angles.y));
  47.208 +
  47.209 +	zrot = Matrix3x3(	cos(euler_angles.z),	-sin(euler_angles.z),	0,
  47.210 +						sin(euler_angles.z),	cos(euler_angles.z),	0,
  47.211 +								0,						0,				1);
  47.212 +
  47.213 +	*this = xrot * yrot * zrot;
  47.214 +}
  47.215 +
  47.216 +void Matrix3x3::rotate(const Vector3 &axis, scalar_t angle)
  47.217 +{
  47.218 +	scalar_t sina = (scalar_t)sin(angle);
  47.219 +	scalar_t cosa = (scalar_t)cos(angle);
  47.220 +	scalar_t invcosa = 1-cosa;
  47.221 +	scalar_t nxsq = axis.x * axis.x;
  47.222 +	scalar_t nysq = axis.y * axis.y;
  47.223 +	scalar_t nzsq = axis.z * axis.z;
  47.224 +
  47.225 +	Matrix3x3 xform;
  47.226 +	xform.m[0][0] = nxsq + (1-nxsq) * cosa;
  47.227 +	xform.m[0][1] = axis.x * axis.y * invcosa - axis.z * sina;
  47.228 +	xform.m[0][2] = axis.x * axis.z * invcosa + axis.y * sina;
  47.229 +
  47.230 +	xform.m[1][0] = axis.x * axis.y * invcosa + axis.z * sina;
  47.231 +	xform.m[1][1] = nysq + (1-nysq) * cosa;
  47.232 +	xform.m[1][2] = axis.y * axis.z * invcosa - axis.x * sina;
  47.233 +
  47.234 +	xform.m[2][0] = axis.x * axis.z * invcosa - axis.y * sina;
  47.235 +	xform.m[2][1] = axis.y * axis.z * invcosa + axis.x * sina;
  47.236 +	xform.m[2][2] = nzsq + (1-nzsq) * cosa;
  47.237 +
  47.238 +	*this *= xform;
  47.239 +}
  47.240 +
  47.241 +void Matrix3x3::set_rotation(const Vector3 &axis, scalar_t angle)
  47.242 +{
  47.243 +	scalar_t sina = (scalar_t)sin(angle);
  47.244 +	scalar_t cosa = (scalar_t)cos(angle);
  47.245 +	scalar_t invcosa = 1-cosa;
  47.246 +	scalar_t nxsq = axis.x * axis.x;
  47.247 +	scalar_t nysq = axis.y * axis.y;
  47.248 +	scalar_t nzsq = axis.z * axis.z;
  47.249 +
  47.250 +	reset_identity();
  47.251 +	m[0][0] = nxsq + (1-nxsq) * cosa;
  47.252 +	m[0][1] = axis.x * axis.y * invcosa - axis.z * sina;
  47.253 +	m[0][2] = axis.x * axis.z * invcosa + axis.y * sina;
  47.254 +	m[1][0] = axis.x * axis.y * invcosa + axis.z * sina;
  47.255 +	m[1][1] = nysq + (1-nysq) * cosa;
  47.256 +	m[1][2] = axis.y * axis.z * invcosa - axis.x * sina;
  47.257 +	m[2][0] = axis.x * axis.z * invcosa - axis.y * sina;
  47.258 +	m[2][1] = axis.y * axis.z * invcosa + axis.x * sina;
  47.259 +	m[2][2] = nzsq + (1-nzsq) * cosa;
  47.260 +}
  47.261 +
  47.262 +// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
  47.263 +// article "Quaternion Calculus and Fast Animation".
  47.264 +// adapted from: http://www.geometrictools.com/LibMathematics/Algebra/Wm5Quaternion.inl
  47.265 +Quaternion Matrix3x3::get_rotation_quat() const
  47.266 +{
  47.267 +	static const int next[3] = {1, 2, 0};
  47.268 +
  47.269 +	float quat[4];
  47.270 +
  47.271 +	scalar_t trace = m[0][0] + m[1][1] + m[2][2];
  47.272 +	scalar_t root;
  47.273 +
  47.274 +	if(trace > 0.0f) {
  47.275 +		// |w| > 1/2
  47.276 +		root = sqrt(trace + 1.0f);	// 2w
  47.277 +		quat[0] = 0.5f * root;
  47.278 +		root = 0.5f / root;	// 1 / 4w
  47.279 +		quat[1] = (m[2][1] - m[1][2]) * root;
  47.280 +		quat[2] = (m[0][2] - m[2][0]) * root;
  47.281 +		quat[3] = (m[1][0] - m[0][1]) * root;
  47.282 +	} else {
  47.283 +		// |w| <= 1/2
  47.284 +		int i = 0;
  47.285 +		if(m[1][1] > m[0][0]) {
  47.286 +			i = 1;
  47.287 +		}
  47.288 +		if(m[2][2] > m[i][i]) {
  47.289 +			i = 2;
  47.290 +		}
  47.291 +		int j = next[i];
  47.292 +		int k = next[j];
  47.293 +
  47.294 +		root = sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0f);
  47.295 +		quat[i + 1] = 0.5f * root;
  47.296 +		root = 0.5f / root;
  47.297 +		quat[0] = (m[k][j] - m[j][k]) * root;
  47.298 +		quat[j + 1] = (m[j][i] - m[i][j]) * root;
  47.299 +		quat[k + 1] = (m[k][i] - m[i][k]) * root;
  47.300 +	}
  47.301 +	return Quaternion(quat[0], quat[1], quat[2], quat[3]);
  47.302 +}
  47.303 +
  47.304 +void Matrix3x3::scale(const Vector3 &scale_vec)
  47.305 +{
  47.306 +	Matrix3x3 smat(	scale_vec.x, 0, 0,
  47.307 +					0, scale_vec.y, 0,
  47.308 +					0, 0, scale_vec.z);
  47.309 +	*this *= smat;
  47.310 +}
  47.311 +
  47.312 +void Matrix3x3::set_scaling(const Vector3 &scale_vec)
  47.313 +{
  47.314 +	*this = Matrix3x3(	scale_vec.x, 0, 0,
  47.315 +						0, scale_vec.y, 0,
  47.316 +						0, 0, scale_vec.z);
  47.317 +}
  47.318 +
  47.319 +void Matrix3x3::set_column_vector(const Vector3 &vec, unsigned int col_index)
  47.320 +{
  47.321 +	m[0][col_index] = vec.x;
  47.322 +	m[1][col_index] = vec.y;
  47.323 +	m[2][col_index] = vec.z;
  47.324 +}
  47.325 +
  47.326 +void Matrix3x3::set_row_vector(const Vector3 &vec, unsigned int row_index)
  47.327 +{
  47.328 +	m[row_index][0] = vec.x;
  47.329 +	m[row_index][1] = vec.y;
  47.330 +	m[row_index][2] = vec.z;
  47.331 +}
  47.332 +
  47.333 +Vector3 Matrix3x3::get_column_vector(unsigned int col_index) const
  47.334 +{
  47.335 +	return Vector3(m[0][col_index], m[1][col_index], m[2][col_index]);
  47.336 +}
  47.337 +
  47.338 +Vector3 Matrix3x3::get_row_vector(unsigned int row_index) const
  47.339 +{
  47.340 +	return Vector3(m[row_index][0], m[row_index][1], m[row_index][2]);
  47.341 +}
  47.342 +
  47.343 +void Matrix3x3::transpose()
  47.344 +{
  47.345 +	Matrix3x3 tmp = *this;
  47.346 +	for(int i=0; i<3; i++) {
  47.347 +		for(int j=0; j<3; j++) {
  47.348 +			m[i][j] = tmp[j][i];
  47.349 +		}
  47.350 +	}
  47.351 +}
  47.352 +
  47.353 +Matrix3x3 Matrix3x3::transposed() const
  47.354 +{
  47.355 +	Matrix3x3 res;
  47.356 +	for(int i=0; i<3; i++) {
  47.357 +		for(int j=0; j<3; j++) {
  47.358 +			res[i][j] = m[j][i];
  47.359 +		}
  47.360 +	}
  47.361 +	return res;
  47.362 +}
  47.363 +
  47.364 +scalar_t Matrix3x3::determinant() const
  47.365 +{
  47.366 +	return	m[0][0] * (m[1][1]*m[2][2] - m[1][2]*m[2][1]) -
  47.367 +			m[0][1] * (m[1][0]*m[2][2] - m[1][2]*m[2][0]) +
  47.368 +			m[0][2] * (m[1][0]*m[2][1] - m[1][1]*m[2][0]);
  47.369 +}
  47.370 +
  47.371 +Matrix3x3 Matrix3x3::inverse() const
  47.372 +{
  47.373 +	// TODO: implement 3x3 inverse
  47.374 +	return *this;
  47.375 +}
  47.376 +
  47.377 +ostream &operator <<(ostream &out, const Matrix3x3 &mat)
  47.378 +{
  47.379 +	for(int i=0; i<3; i++) {
  47.380 +		char str[100];
  47.381 +		sprintf(str, "[ %12.5f %12.5f %12.5f ]\n", (float)mat.m[i][0], (float)mat.m[i][1], (float)mat.m[i][2]);
  47.382 +		out << str;
  47.383 +	}
  47.384 +	return out;
  47.385 +}
  47.386 +
  47.387 +
  47.388 +
  47.389 +/* ----------------- Matrix4x4 implementation --------------- */
  47.390 +
  47.391 +Matrix4x4 Matrix4x4::identity = Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
  47.392 +
  47.393 +Matrix4x4::Matrix4x4()
  47.394 +{
  47.395 +	*this = identity;
  47.396 +}
  47.397 +
  47.398 +Matrix4x4::Matrix4x4(	scalar_t m11, scalar_t m12, scalar_t m13, scalar_t m14,
  47.399 +						scalar_t m21, scalar_t m22, scalar_t m23, scalar_t m24,
  47.400 +						scalar_t m31, scalar_t m32, scalar_t m33, scalar_t m34,
  47.401 +						scalar_t m41, scalar_t m42, scalar_t m43, scalar_t m44)
  47.402 +{
  47.403 +	m[0][0] = m11; m[0][1] = m12; m[0][2] = m13; m[0][3] = m14;
  47.404 +	m[1][0] = m21; m[1][1] = m22; m[1][2] = m23; m[1][3] = m24;
  47.405 +	m[2][0] = m31; m[2][1] = m32; m[2][2] = m33; m[2][3] = m34;
  47.406 +	m[3][0] = m41; m[3][1] = m42; m[3][2] = m43; m[3][3] = m44;
  47.407 +}
  47.408 +
  47.409 +Matrix4x4::Matrix4x4(const mat4_t cmat)
  47.410 +{
  47.411 +	memcpy(m, cmat, sizeof(mat4_t));
  47.412 +}
  47.413 +
  47.414 +Matrix4x4::Matrix4x4(const Matrix3x3 &mat3x3)
  47.415 +{
  47.416 +	reset_identity();
  47.417 +	for(int i=0; i<3; i++) {
  47.418 +		for(int j=0; j<3; j++) {
  47.419 +			m[i][j] = mat3x3[i][j];
  47.420 +		}
  47.421 +	}
  47.422 +}
  47.423 +
  47.424 +Matrix4x4 operator +(const Matrix4x4 &m1, const Matrix4x4 &m2)
  47.425 +{
  47.426 +	Matrix4x4 res;
  47.427 +	const scalar_t *op1 = m1.m[0], *op2 = m2.m[0];
  47.428 +	scalar_t *dest = res.m[0];
  47.429 +
  47.430 +	for(int i=0; i<16; i++) {
  47.431 +		*dest++ = *op1++ + *op2++;
  47.432 +	}
  47.433 +	return res;
  47.434 +}
  47.435 +
  47.436 +Matrix4x4 operator -(const Matrix4x4 &m1, const Matrix4x4 &m2)
  47.437 +{
  47.438 +	Matrix4x4 res;
  47.439 +	const scalar_t *op1 = m1.m[0], *op2 = m2.m[0];
  47.440 +	scalar_t *dest = res.m[0];
  47.441 +
  47.442 +	for(int i=0; i<16; i++) {
  47.443 +		*dest++ = *op1++ - *op2++;
  47.444 +	}
  47.445 +	return res;
  47.446 +}
  47.447 +
  47.448 +void operator +=(Matrix4x4 &m1, const Matrix4x4 &m2)
  47.449 +{
  47.450 +	scalar_t *op1 = m1.m[0];
  47.451 +	const scalar_t *op2 = m2.m[0];
  47.452 +
  47.453 +	for(int i=0; i<16; i++) {
  47.454 +		*op1++ += *op2++;
  47.455 +	}
  47.456 +}
  47.457 +
  47.458 +void operator -=(Matrix4x4 &m1, const Matrix4x4 &m2)
  47.459 +{
  47.460 +	scalar_t *op1 = m1.m[0];
  47.461 +	const scalar_t *op2 = m2.m[0];
  47.462 +
  47.463 +	for(int i=0; i<16; i++) {
  47.464 +		*op1++ -= *op2++;
  47.465 +	}
  47.466 +}
  47.467 +
  47.468 +Matrix4x4 operator *(const Matrix4x4 &mat, scalar_t scalar)
  47.469 +{
  47.470 +	Matrix4x4 res;
  47.471 +	const scalar_t *mptr = mat.m[0];
  47.472 +	scalar_t *dptr = res.m[0];
  47.473 +
  47.474 +	for(int i=0; i<16; i++) {
  47.475 +		*dptr++ = *mptr++ * scalar;
  47.476 +	}
  47.477 +	return res;
  47.478 +}
  47.479 +
  47.480 +Matrix4x4 operator *(scalar_t scalar, const Matrix4x4 &mat)
  47.481 +{
  47.482 +	Matrix4x4 res;
  47.483 +	const scalar_t *mptr = mat.m[0];
  47.484 +	scalar_t *dptr = res.m[0];
  47.485 +
  47.486 +	for(int i=0; i<16; i++) {
  47.487 +		*dptr++ = *mptr++ * scalar;
  47.488 +	}
  47.489 +	return res;
  47.490 +}
  47.491 +
  47.492 +void operator *=(Matrix4x4 &mat, scalar_t scalar)
  47.493 +{
  47.494 +	scalar_t *mptr = mat.m[0];
  47.495 +
  47.496 +	for(int i=0; i<16; i++) {
  47.497 +		*mptr++ *= scalar;
  47.498 +	}
  47.499 +}
  47.500 +
  47.501 +void Matrix4x4::translate(const Vector3 &trans)
  47.502 +{
  47.503 +	Matrix4x4 tmat(1, 0, 0, trans.x, 0, 1, 0, trans.y, 0, 0, 1, trans.z, 0, 0, 0, 1);
  47.504 +	*this *= tmat;
  47.505 +}
  47.506 +
  47.507 +void Matrix4x4::set_translation(const Vector3 &trans)
  47.508 +{
  47.509 +	*this = Matrix4x4(1, 0, 0, trans.x, 0, 1, 0, trans.y, 0, 0, 1, trans.z, 0, 0, 0, 1);
  47.510 +}
  47.511 +
  47.512 +Vector3 Matrix4x4::get_translation() const
  47.513 +{
  47.514 +	return Vector3(m[0][3], m[1][3], m[2][3]);
  47.515 +}
  47.516 +
  47.517 +void Matrix4x4::rotate(const Vector3 &euler_angles)
  47.518 +{
  47.519 +	Matrix3x3 xrot, yrot, zrot;
  47.520 +
  47.521 +	xrot = Matrix3x3(	1,			0,					0,
  47.522 +						0,	cos(euler_angles.x),	-sin(euler_angles.x),
  47.523 +						0,	sin(euler_angles.x),	cos(euler_angles.x));
  47.524 +
  47.525 +	yrot = Matrix3x3(	cos(euler_angles.y),	0,	sin(euler_angles.y),
  47.526 +								0,				1,				0,
  47.527 +						-sin(euler_angles.y),	0,	cos(euler_angles.y));
  47.528 +
  47.529 +	zrot = Matrix3x3(	cos(euler_angles.z),	-sin(euler_angles.z),	0,
  47.530 +						sin(euler_angles.z),	cos(euler_angles.z),	0,
  47.531 +								0,						0,				1);
  47.532 +
  47.533 +	*this *= Matrix4x4(xrot * yrot * zrot);
  47.534 +}
  47.535 +
  47.536 +void Matrix4x4::set_rotation(const Vector3 &euler_angles)
  47.537 +{
  47.538 +	Matrix3x3 xrot, yrot, zrot;
  47.539 +
  47.540 +	xrot = Matrix3x3(	1,			0,					0,
  47.541 +						0,	cos(euler_angles.x),	-sin(euler_angles.x),
  47.542 +						0,	sin(euler_angles.x),	cos(euler_angles.x));
  47.543 +
  47.544 +	yrot = Matrix3x3(	cos(euler_angles.y),	0,	sin(euler_angles.y),
  47.545 +								0,				1,				0,
  47.546 +						-sin(euler_angles.y),	0,	cos(euler_angles.y));
  47.547 +
  47.548 +	zrot = Matrix3x3(	cos(euler_angles.z),	-sin(euler_angles.z),	0,
  47.549 +						sin(euler_angles.z),	cos(euler_angles.z),	0,
  47.550 +								0,						0,				1);
  47.551 +
  47.552 +	*this = Matrix4x4(xrot * yrot * zrot);
  47.553 +}
  47.554 +
  47.555 +void Matrix4x4::rotate(const Vector3 &axis, scalar_t angle)
  47.556 +{
  47.557 +	scalar_t sina = (scalar_t)sin(angle);
  47.558 +	scalar_t cosa = (scalar_t)cos(angle);
  47.559 +	scalar_t invcosa = 1-cosa;
  47.560 +	scalar_t nxsq = axis.x * axis.x;
  47.561 +	scalar_t nysq = axis.y * axis.y;
  47.562 +	scalar_t nzsq = axis.z * axis.z;
  47.563 +
  47.564 +	Matrix4x4 xform;
  47.565 +	xform[0][0] = nxsq + (1-nxsq) * cosa;
  47.566 +	xform[0][1] = axis.x * axis.y * invcosa - axis.z * sina;
  47.567 +	xform[0][2] = axis.x * axis.z * invcosa + axis.y * sina;
  47.568 +	xform[1][0] = axis.x * axis.y * invcosa + axis.z * sina;
  47.569 +	xform[1][1] = nysq + (1-nysq) * cosa;
  47.570 +	xform[1][2] = axis.y * axis.z * invcosa - axis.x * sina;
  47.571 +	xform[2][0] = axis.x * axis.z * invcosa - axis.y * sina;
  47.572 +	xform[2][1] = axis.y * axis.z * invcosa + axis.x * sina;
  47.573 +	xform[2][2] = nzsq + (1-nzsq) * cosa;
  47.574 +
  47.575 +	*this *= xform;
  47.576 +}
  47.577 +
  47.578 +void Matrix4x4::set_rotation(const Vector3 &axis, scalar_t angle)
  47.579 +{
  47.580 +	scalar_t sina = (scalar_t)sin(angle);
  47.581 +	scalar_t cosa = (scalar_t)cos(angle);
  47.582 +	scalar_t invcosa = 1-cosa;
  47.583 +	scalar_t nxsq = axis.x * axis.x;
  47.584 +	scalar_t nysq = axis.y * axis.y;
  47.585 +	scalar_t nzsq = axis.z * axis.z;
  47.586 +
  47.587 +	reset_identity();
  47.588 +	m[0][0] = nxsq + (1-nxsq) * cosa;
  47.589 +	m[0][1] = axis.x * axis.y * invcosa - axis.z * sina;
  47.590 +	m[0][2] = axis.x * axis.z * invcosa + axis.y * sina;
  47.591 +	m[1][0] = axis.x * axis.y * invcosa + axis.z * sina;
  47.592 +	m[1][1] = nysq + (1-nysq) * cosa;
  47.593 +	m[1][2] = axis.y * axis.z * invcosa - axis.x * sina;
  47.594 +	m[2][0] = axis.x * axis.z * invcosa - axis.y * sina;
  47.595 +	m[2][1] = axis.y * axis.z * invcosa + axis.x * sina;
  47.596 +	m[2][2] = nzsq + (1-nzsq) * cosa;
  47.597 +}
  47.598 +
  47.599 +void Matrix4x4::rotate(const Quaternion &quat)
  47.600 +{
  47.601 +	*this *= quat.get_rotation_matrix();
  47.602 +}
  47.603 +
  47.604 +void Matrix4x4::set_rotation(const Quaternion &quat)
  47.605 +{
  47.606 +	*this = quat.get_rotation_matrix();
  47.607 +}
  47.608 +
  47.609 +Quaternion Matrix4x4::get_rotation_quat() const
  47.610 +{
  47.611 +	Matrix3x3 mat3 = *this;
  47.612 +	return mat3.get_rotation_quat();
  47.613 +}
  47.614 +
  47.615 +void Matrix4x4::scale(const Vector4 &scale_vec)
  47.616 +{
  47.617 +	Matrix4x4 smat(	scale_vec.x, 0, 0, 0,
  47.618 +					0, scale_vec.y, 0, 0,
  47.619 +					0, 0, scale_vec.z, 0,
  47.620 +					0, 0, 0, scale_vec.w);
  47.621 +	*this *= smat;
  47.622 +}
  47.623 +
  47.624 +void Matrix4x4::set_scaling(const Vector4 &scale_vec)
  47.625 +{
  47.626 +	*this = Matrix4x4(	scale_vec.x, 0, 0, 0,
  47.627 +						0, scale_vec.y, 0, 0,
  47.628 +						0, 0, scale_vec.z, 0,
  47.629 +						0, 0, 0, scale_vec.w);
  47.630 +}
  47.631 +
  47.632 +Vector3 Matrix4x4::get_scaling() const
  47.633 +{
  47.634 +	Vector3 vi = get_row_vector(0);
  47.635 +	Vector3 vj = get_row_vector(1);
  47.636 +	Vector3 vk = get_row_vector(2);
  47.637 +
  47.638 +	return Vector3(vi.length(), vj.length(), vk.length());
  47.639 +}
  47.640 +
  47.641 +void Matrix4x4::set_column_vector(const Vector4 &vec, unsigned int col_index)
  47.642 +{
  47.643 +	m[0][col_index] = vec.x;
  47.644 +	m[1][col_index] = vec.y;
  47.645 +	m[2][col_index] = vec.z;
  47.646 +	m[3][col_index] = vec.w;
  47.647 +}
  47.648 +
  47.649 +void Matrix4x4::set_row_vector(const Vector4 &vec, unsigned int row_index)
  47.650 +{
  47.651 +	m[row_index][0] = vec.x;
  47.652 +	m[row_index][1] = vec.y;
  47.653 +	m[row_index][2] = vec.z;
  47.654 +	m[row_index][3] = vec.w;
  47.655 +}
  47.656 +
  47.657 +Vector4 Matrix4x4::get_column_vector(unsigned int col_index) const
  47.658 +{
  47.659 +	return Vector4(m[0][col_index], m[1][col_index], m[2][col_index], m[3][col_index]);
  47.660 +}
  47.661 +
  47.662 +Vector4 Matrix4x4::get_row_vector(unsigned int row_index) const
  47.663 +{
  47.664 +	return Vector4(m[row_index][0], m[row_index][1], m[row_index][2], m[row_index][3]);
  47.665 +}
  47.666 +
  47.667 +void Matrix4x4::transpose()
  47.668 +{
  47.669 +	Matrix4x4 tmp = *this;
  47.670 +	for(int i=0; i<4; i++) {
  47.671 +		for(int j=0; j<4; j++) {
  47.672 +			m[i][j] = tmp[j][i];
  47.673 +		}
  47.674 +	}
  47.675 +}
  47.676 +
  47.677 +Matrix4x4 Matrix4x4::transposed() const
  47.678 +{
  47.679 +	Matrix4x4 res;
  47.680 +	for(int i=0; i<4; i++) {
  47.681 +		for(int j=0; j<4; j++) {
  47.682 +			res[i][j] = m[j][i];
  47.683 +		}
  47.684 +	}
  47.685 +	return res;
  47.686 +}
  47.687 +
  47.688 +scalar_t Matrix4x4::determinant() const
  47.689 +{
  47.690 +	scalar_t det11 =	(m[1][1] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  47.691 +						(m[1][2] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) +
  47.692 +						(m[1][3] * (m[2][1] * m[3][2] - m[3][1] * m[2][2]));
  47.693 +
  47.694 +	scalar_t det12 =	(m[1][0] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  47.695 +						(m[1][2] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  47.696 +						(m[1][3] * (m[2][0] * m[3][2] - m[3][0] * m[2][2]));
  47.697 +
  47.698 +	scalar_t det13 =	(m[1][0] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) -
  47.699 +						(m[1][1] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  47.700 +						(m[1][3] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  47.701 +
  47.702 +	scalar_t det14 =	(m[1][0] * (m[2][1] * m[3][2] - m[3][1] * m[2][2])) -
  47.703 +						(m[1][1] * (m[2][0] * m[3][2] - m[3][0] * m[2][2])) +
  47.704 +						(m[1][2] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  47.705 +
  47.706 +	return m[0][0] * det11 - m[0][1] * det12 + m[0][2] * det13 - m[0][3] * det14;
  47.707 +}
  47.708 +
  47.709 +
  47.710 +Matrix4x4 Matrix4x4::adjoint() const
  47.711 +{
  47.712 +	Matrix4x4 coef;
  47.713 +
  47.714 +	coef.m[0][0] =	(m[1][1] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  47.715 +					(m[1][2] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) +
  47.716 +					(m[1][3] * (m[2][1] * m[3][2] - m[3][1] * m[2][2]));
  47.717 +	coef.m[0][1] =	(m[1][0] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  47.718 +					(m[1][2] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  47.719 +					(m[1][3] * (m[2][0] * m[3][2] - m[3][0] * m[2][2]));
  47.720 +	coef.m[0][2] =	(m[1][0] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) -
  47.721 +					(m[1][1] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  47.722 +					(m[1][3] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  47.723 +	coef.m[0][3] =	(m[1][0] * (m[2][1] * m[3][2] - m[3][1] * m[2][2])) -
  47.724 +					(m[1][1] * (m[2][0] * m[3][2] - m[3][0] * m[2][2])) +
  47.725 +					(m[1][2] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  47.726 +
  47.727 +	coef.m[1][0] =	(m[0][1] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  47.728 +					(m[0][2] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) +
  47.729 +					(m[0][3] * (m[2][1] * m[3][2] - m[3][1] * m[2][2]));
  47.730 +	coef.m[1][1] =	(m[0][0] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  47.731 +					(m[0][2] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  47.732 +					(m[0][3] * (m[2][0] * m[3][2] - m[3][0] * m[2][2]));
  47.733 +	coef.m[1][2] =	(m[0][0] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) -
  47.734 +					(m[0][1] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  47.735 +					(m[0][3] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  47.736 +	coef.m[1][3] =	(m[0][0] * (m[2][1] * m[3][2] - m[3][1] * m[2][2])) -
  47.737 +					(m[0][1] * (m[2][0] * m[3][2] - m[3][0] * m[2][2])) +
  47.738 +					(m[0][2] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  47.739 +
  47.740 +	coef.m[2][0] =	(m[0][1] * (m[1][2] * m[3][3] - m[3][2] * m[1][3])) -
  47.741 +					(m[0][2] * (m[1][1] * m[3][3] - m[3][1] * m[1][3])) +
  47.742 +					(m[0][3] * (m[1][1] * m[3][2] - m[3][1] * m[1][2]));
  47.743 +	coef.m[2][1] =	(m[0][0] * (m[1][2] * m[3][3] - m[3][2] * m[1][3])) -
  47.744 +					(m[0][2] * (m[1][0] * m[3][3] - m[3][0] * m[1][3])) +
  47.745 +					(m[0][3] * (m[1][0] * m[3][2] - m[3][0] * m[1][2]));
  47.746 +	coef.m[2][2] =	(m[0][0] * (m[1][1] * m[3][3] - m[3][1] * m[1][3])) -
  47.747 +					(m[0][1] * (m[1][0] * m[3][3] - m[3][0] * m[1][3])) +
  47.748 +					(m[0][3] * (m[1][0] * m[3][1] - m[3][0] * m[1][1]));
  47.749 +	coef.m[2][3] =	(m[0][0] * (m[1][1] * m[3][2] - m[3][1] * m[1][2])) -
  47.750 +					(m[0][1] * (m[1][0] * m[3][2] - m[3][0] * m[1][2])) +
  47.751 +					(m[0][2] * (m[1][0] * m[3][1] - m[3][0] * m[1][1]));
  47.752 +
  47.753 +	coef.m[3][0] =	(m[0][1] * (m[1][2] * m[2][3] - m[2][2] * m[1][3])) -
  47.754 +					(m[0][2] * (m[1][1] * m[2][3] - m[2][1] * m[1][3])) +
  47.755 +					(m[0][3] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]));
  47.756 +	coef.m[3][1] =	(m[0][0] * (m[1][2] * m[2][3] - m[2][2] * m[1][3])) -
  47.757 +					(m[0][2] * (m[1][0] * m[2][3] - m[2][0] * m[1][3])) +
  47.758 +					(m[0][3] * (m[1][0] * m[2][2] - m[2][0] * m[1][2]));
  47.759 +	coef.m[3][2] =	(m[0][0] * (m[1][1] * m[2][3] - m[2][1] * m[1][3])) -
  47.760 +					(m[0][1] * (m[1][0] * m[2][3] - m[2][0] * m[1][3])) +
  47.761 +					(m[0][3] * (m[1][0] * m[2][1] - m[2][0] * m[1][1]));
  47.762 +	coef.m[3][3] =	(m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])) -
  47.763 +					(m[0][1] * (m[1][0] * m[2][2] - m[2][0] * m[1][2])) +
  47.764 +					(m[0][2] * (m[1][0] * m[2][1] - m[2][0] * m[1][1]));
  47.765 +
  47.766 +	coef.transpose();
  47.767 +
  47.768 +	for(int i=0; i<4; i++) {
  47.769 +		for(int j=0; j<4; j++) {
  47.770 +			coef.m[i][j] = j%2 ? -coef.m[i][j] : coef.m[i][j];
  47.771 +			if(i%2) coef.m[i][j] = -coef.m[i][j];
  47.772 +		}
  47.773 +	}
  47.774 +
  47.775 +	return coef;
  47.776 +}
  47.777 +
  47.778 +Matrix4x4 Matrix4x4::inverse() const
  47.779 +{
  47.780 +	Matrix4x4 adj = adjoint();
  47.781 +
  47.782 +	return adj * (1.0f / determinant());
  47.783 +}
  47.784 +
  47.785 +void Matrix4x4::keep_upper_left()
  47.786 +{
  47.787 +	m[3][0] = m[3][1] = m[3][2] = m[0][3] = m[1][3] = m[2][3] = 0.0f;
  47.788 +	m[3][3] = 1.0f;
  47.789 +}
  47.790 +
  47.791 +void Matrix4x4::clear_upper_left()
  47.792 +{
  47.793 +	m[0][0] = m[1][1] = m[2][2] = 1.0f;
  47.794 +	m[0][1] = m[0][2] = m[1][2] = m[1][0] = m[2][0] = m[2][1] = 0.0f;
  47.795 +}
  47.796 +
  47.797 +ostream &operator <<(ostream &out, const Matrix4x4 &mat)
  47.798 +{
  47.799 +	for(int i=0; i<4; i++) {
  47.800 +		char str[100];
  47.801 +		sprintf(str, "[ %12.5f %12.5f %12.5f %12.5f ]\n", (float)mat.m[i][0], (float)mat.m[i][1], (float)mat.m[i][2], (float)mat.m[i][3]);
  47.802 +		out << str;
  47.803 +	}
  47.804 +	return out;
  47.805 +}
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/vmath/matrix.h	Sun Nov 09 13:03:36 2014 +0200
    48.3 @@ -0,0 +1,260 @@
    48.4 +/*
    48.5 +libvmath - a vector math library
    48.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    48.7 +
    48.8 +This program is free software: you can redistribute it and/or modify
    48.9 +it under the terms of the GNU Lesser General Public License as published
   48.10 +by the Free Software Foundation, either version 3 of the License, or
   48.11 +(at your option) any later version.
   48.12 +
   48.13 +This program is distributed in the hope that it will be useful,
   48.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   48.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   48.16 +GNU Lesser General Public License for more details.
   48.17 +
   48.18 +You should have received a copy of the GNU Lesser General Public License
   48.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   48.20 +*/
   48.21 +
   48.22 +#ifndef VMATH_MATRIX_H_
   48.23 +#define VMATH_MATRIX_H_
   48.24 +
   48.25 +#include <stdio.h>
   48.26 +#include "vmath_types.h"
   48.27 +
   48.28 +#ifdef __cplusplus
   48.29 +extern "C" {
   48.30 +#endif	/* __cplusplus */
   48.31 +
   48.32 +/* C matrix 3x3 functions */
   48.33 +static inline void m3_identity(mat3_t m);
   48.34 +static inline void m3_cons(mat3_t m,
   48.35 +		scalar_t m11, scalar_t m12, scalar_t m13,
   48.36 +		scalar_t m21, scalar_t m22, scalar_t m23,
   48.37 +		scalar_t m31, scalar_t m32, scalar_t m33);
   48.38 +static inline void m3_copy(mat3_t dest, mat3_t src);
   48.39 +void m3_to_m4(mat4_t dest, mat3_t src);
   48.40 +
   48.41 +void m3_print(FILE *fp, mat3_t m);
   48.42 +
   48.43 +/* C matrix 4x4 functions */
   48.44 +static inline void m4_identity(mat4_t m);
   48.45 +static inline void m4_cons(mat4_t m,
   48.46 +		scalar_t m11, scalar_t m12, scalar_t m13, scalar_t m14,
   48.47 +		scalar_t m21, scalar_t m22, scalar_t m23, scalar_t m24,
   48.48 +		scalar_t m31, scalar_t m32, scalar_t m33, scalar_t m34,
   48.49 +		scalar_t m41, scalar_t m42, scalar_t m43, scalar_t m44);
   48.50 +static inline void m4_copy(mat4_t dest, mat4_t src);
   48.51 +void m4_to_m3(mat3_t dest, mat4_t src);
   48.52 +
   48.53 +static inline void m4_mult(mat4_t res, mat4_t m1, mat4_t m2);
   48.54 +
   48.55 +void m4_set_translation(mat4_t m, scalar_t x, scalar_t y, scalar_t z);
   48.56 +void m4_translate(mat4_t m, scalar_t x, scalar_t y, scalar_t z);
   48.57 +
   48.58 +void m4_rotate(mat4_t m, scalar_t x, scalar_t y, scalar_t z);
   48.59 +
   48.60 +void m4_set_rotation_x(mat4_t m, scalar_t angle);
   48.61 +void m4_rotate_x(mat4_t m, scalar_t angle);
   48.62 +void m4_set_rotation_y(mat4_t m, scalar_t angle);
   48.63 +void m4_rotate_y(mat4_t m, scalar_t angle);
   48.64 +void m4_set_rotation_z(mat4_t m, scalar_t angle);
   48.65 +void m4_rotate_z(mat4_t m, scalar_t angle);
   48.66 +/* axis-angle rotation */
   48.67 +void m4_set_rotation_axis(mat4_t m, scalar_t angle, scalar_t x, scalar_t y, scalar_t z);
   48.68 +void m4_rotate_axis(mat4_t m, scalar_t angle, scalar_t x, scalar_t y, scalar_t z);
   48.69 +/* concatentate a rotation quaternion */
   48.70 +void m4_rotate_quat(mat4_t m, quat_t q);
   48.71 +
   48.72 +void m4_set_scaling(mat4_t m, scalar_t x, scalar_t y, scalar_t z);
   48.73 +void m4_scale(mat4_t m, scalar_t x, scalar_t y, scalar_t z);
   48.74 +
   48.75 +static inline void m4_set_column(mat4_t m, vec4_t v, int idx);
   48.76 +static inline void m4_set_row(mat4_t m, vec4_t v, int idx);
   48.77 +
   48.78 +void m4_transpose(mat4_t res, mat4_t m);
   48.79 +scalar_t m4_determinant(mat4_t m);
   48.80 +void m4_adjoint(mat4_t res, mat4_t m);
   48.81 +void m4_inverse(mat4_t res, mat4_t m);
   48.82 +
   48.83 +void m4_print(FILE *fp, mat4_t m);
   48.84 +
   48.85 +#ifdef __cplusplus
   48.86 +}
   48.87 +
   48.88 +/* when included from C++ source files, also define the matrix classes */
   48.89 +#include <iostream>
   48.90 +
   48.91 +/** 3x3 matrix */
   48.92 +class Matrix3x3 {
   48.93 +public:
   48.94 +	scalar_t m[3][3];
   48.95 +
   48.96 +	static Matrix3x3 identity;
   48.97 +
   48.98 +	Matrix3x3();
   48.99 +	Matrix3x3(	scalar_t m11, scalar_t m12, scalar_t m13,
  48.100 +				scalar_t m21, scalar_t m22, scalar_t m23,
  48.101 +				scalar_t m31, scalar_t m32, scalar_t m33);
  48.102 +	Matrix3x3(const Vector3 &ivec, const Vector3 &jvec, const Vector3 &kvec);
  48.103 +	Matrix3x3(const mat3_t cmat);
  48.104 +
  48.105 +	Matrix3x3(const Matrix4x4 &mat4x4);
  48.106 +
  48.107 +	/* binary operations matrix (op) matrix */
  48.108 +	friend Matrix3x3 operator +(const Matrix3x3 &m1, const Matrix3x3 &m2);
  48.109 +	friend Matrix3x3 operator -(const Matrix3x3 &m1, const Matrix3x3 &m2);
  48.110 +	friend Matrix3x3 operator *(const Matrix3x3 &m1, const Matrix3x3 &m2);
  48.111 +
  48.112 +	friend void operator +=(Matrix3x3 &m1, const Matrix3x3 &m2);
  48.113 +	friend void operator -=(Matrix3x3 &m1, const Matrix3x3 &m2);
  48.114 +	friend void operator *=(Matrix3x3 &m1, const Matrix3x3 &m2);
  48.115 +
  48.116 +	/* binary operations matrix (op) scalar and scalar (op) matrix */
  48.117 +	friend Matrix3x3 operator *(const Matrix3x3 &mat, scalar_t scalar);
  48.118 +	friend Matrix3x3 operator *(scalar_t scalar, const Matrix3x3 &mat);
  48.119 +
  48.120 +	friend void operator *=(Matrix3x3 &mat, scalar_t scalar);
  48.121 +
  48.122 +	inline scalar_t *operator [](int index);
  48.123 +	inline const scalar_t *operator [](int index) const;
  48.124 +
  48.125 +	inline void reset_identity();
  48.126 +
  48.127 +	void translate(const Vector2 &trans);
  48.128 +	void set_translation(const Vector2 &trans);
  48.129 +
  48.130 +	void rotate(scalar_t angle);						/* 2d rotation */
  48.131 +	void rotate(const Vector3 &euler_angles);			/* 3d rotation with euler angles */
  48.132 +	void rotate(const Vector3 &axis, scalar_t angle);	/* 3d axis/angle rotation */
  48.133 +	void set_rotation(scalar_t angle);
  48.134 +	void set_rotation(const Vector3 &euler_angles);
  48.135 +	void set_rotation(const Vector3 &axis, scalar_t angle);
  48.136 +	Quaternion get_rotation_quat() const;
  48.137 +
  48.138 +	void scale(const Vector3 &scale_vec);
  48.139 +	void set_scaling(const Vector3 &scale_vec);
  48.140 +
  48.141 +	void set_column_vector(const Vector3 &vec, unsigned int col_index);
  48.142 +	void set_row_vector(const Vector3 &vec, unsigned int row_index);
  48.143 +	Vector3 get_column_vector(unsigned int col_index) const;
  48.144 +	Vector3 get_row_vector(unsigned int row_index) const;
  48.145 +
  48.146 +	void transpose();
  48.147 +	Matrix3x3 transposed() const;
  48.148 +	scalar_t determinant() const;
  48.149 +	Matrix3x3 inverse() const;
  48.150 +
  48.151 +	friend std::ostream &operator <<(std::ostream &out, const Matrix3x3 &mat);
  48.152 +};
  48.153 +
  48.154 +/* binary operations matrix (op) matrix */
  48.155 +Matrix3x3 operator +(const Matrix3x3 &m1, const Matrix3x3 &m2);
  48.156 +Matrix3x3 operator -(const Matrix3x3 &m1, const Matrix3x3 &m2);
  48.157 +Matrix3x3 operator *(const Matrix3x3 &m1, const Matrix3x3 &m2);
  48.158 +
  48.159 +void operator +=(Matrix3x3 &m1, const Matrix3x3 &m2);
  48.160 +void operator -=(Matrix3x3 &m1, const Matrix3x3 &m2);
  48.161 +void operator *=(Matrix3x3 &m1, const Matrix3x3 &m2);
  48.162 +
  48.163 +/* binary operations matrix (op) scalar and scalar (op) matrix */
  48.164 +Matrix3x3 operator *(const Matrix3x3 &mat, scalar_t scalar);
  48.165 +Matrix3x3 operator *(scalar_t scalar, const Matrix3x3 &mat);
  48.166 +
  48.167 +void operator *=(Matrix3x3 &mat, scalar_t scalar);
  48.168 +
  48.169 +std::ostream &operator <<(std::ostream &out, const Matrix3x3 &mat);
  48.170 +
  48.171 +
  48.172 +
  48.173 +/** 4x4 matrix */
  48.174 +class Matrix4x4 {
  48.175 +public:
  48.176 +	scalar_t m[4][4];
  48.177 +
  48.178 +	static Matrix4x4 identity;
  48.179 +
  48.180 +	Matrix4x4();
  48.181 +	Matrix4x4(	scalar_t m11, scalar_t m12, scalar_t m13, scalar_t m14,
  48.182 +				scalar_t m21, scalar_t m22, scalar_t m23, scalar_t m24,
  48.183 +				scalar_t m31, scalar_t m32, scalar_t m33, scalar_t m34,
  48.184 +				scalar_t m41, scalar_t m42, scalar_t m43, scalar_t m44);
  48.185 +	Matrix4x4(const mat4_t cmat);
  48.186 +
  48.187 +	Matrix4x4(const Matrix3x3 &mat3x3);
  48.188 +
  48.189 +	/* binary operations matrix (op) matrix */
  48.190 +	friend Matrix4x4 operator +(const Matrix4x4 &m1, const Matrix4x4 &m2);
  48.191 +	friend Matrix4x4 operator -(const Matrix4x4 &m1, const Matrix4x4 &m2);
  48.192 +	friend Matrix4x4 operator *(const Matrix4x4 &m1, const Matrix4x4 &m2);
  48.193 +
  48.194 +	friend void operator +=(Matrix4x4 &m1, const Matrix4x4 &m2);
  48.195 +	friend void operator -=(Matrix4x4 &m1, const Matrix4x4 &m2);
  48.196 +	friend inline void operator *=(Matrix4x4 &m1, const Matrix4x4 &m2);
  48.197 +
  48.198 +	/* binary operations matrix (op) scalar and scalar (op) matrix */
  48.199 +	friend Matrix4x4 operator *(const Matrix4x4 &mat, scalar_t scalar);
  48.200 +	friend Matrix4x4 operator *(scalar_t scalar, const Matrix4x4 &mat);
  48.201 +
  48.202 +	friend void operator *=(Matrix4x4 &mat, scalar_t scalar);
  48.203 +
  48.204 +	inline scalar_t *operator [](int index);
  48.205 +	inline const scalar_t *operator [](int index) const;
  48.206 +
  48.207 +	inline void reset_identity();
  48.208 +
  48.209 +	void translate(const Vector3 &trans);
  48.210 +	void set_translation(const Vector3 &trans);
  48.211 +	Vector3 get_translation() const;	/* extract translation */
  48.212 +
  48.213 +	void rotate(const Vector3 &euler_angles);			/* 3d rotation with euler angles */
  48.214 +	void rotate(const Vector3 &axis, scalar_t angle);	/* 3d axis/angle rotation */
  48.215 +	void rotate(const Quaternion &quat);
  48.216 +	void set_rotation(const Vector3 &euler_angles);
  48.217 +	void set_rotation(const Vector3 &axis, scalar_t angle);
  48.218 +	void set_rotation(const Quaternion &quat);
  48.219 +	Quaternion get_rotation_quat() const;		/* extract rotation */
  48.220 +
  48.221 +	void scale(const Vector4 &scale_vec);
  48.222 +	void set_scaling(const Vector4 &scale_vec);
  48.223 +	Vector3 get_scaling() const;		/* extract scaling */
  48.224 +
  48.225 +	void set_column_vector(const Vector4 &vec, unsigned int col_index);
  48.226 +	void set_row_vector(const Vector4 &vec, unsigned int row_index);
  48.227 +	Vector4 get_column_vector(unsigned int col_index) const;
  48.228 +	Vector4 get_row_vector(unsigned int row_index) const;
  48.229 +
  48.230 +	void transpose();
  48.231 +	Matrix4x4 transposed() const;
  48.232 +	scalar_t determinant() const;
  48.233 +	Matrix4x4 adjoint() const;
  48.234 +	Matrix4x4 inverse() const;
  48.235 +
  48.236 +	void keep_upper_left();
  48.237 +	void clear_upper_left();
  48.238 +
  48.239 +	friend std::ostream &operator <<(std::ostream &out, const Matrix4x4 &mat);
  48.240 +};
  48.241 +
  48.242 +/* binary operations matrix (op) matrix */
  48.243 +Matrix4x4 operator +(const Matrix4x4 &m1, const Matrix4x4 &m2);
  48.244 +Matrix4x4 operator -(const Matrix4x4 &m1, const Matrix4x4 &m2);
  48.245 +inline Matrix4x4 operator *(const Matrix4x4 &m1, const Matrix4x4 &m2);
  48.246 +
  48.247 +void operator +=(Matrix4x4 &m1, const Matrix4x4 &m2);
  48.248 +void operator -=(Matrix4x4 &m1, const Matrix4x4 &m2);
  48.249 +inline void operator *=(Matrix4x4 &m1, const Matrix4x4 &m2);
  48.250 +
  48.251 +/* binary operations matrix (op) scalar and scalar (op) matrix */
  48.252 +Matrix4x4 operator *(const Matrix4x4 &mat, scalar_t scalar);
  48.253 +Matrix4x4 operator *(scalar_t scalar, const Matrix4x4 &mat);
  48.254 +
  48.255 +void operator *=(Matrix4x4 &mat, scalar_t scalar);
  48.256 +
  48.257 +std::ostream &operator <<(std::ostream &out, const Matrix4x4 &mat);
  48.258 +
  48.259 +#endif	/* __cplusplus */
  48.260 +
  48.261 +#include "matrix.inl"
  48.262 +
  48.263 +#endif	/* VMATH_MATRIX_H_ */
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/vmath/matrix.inl	Sun Nov 09 13:03:36 2014 +0200
    49.3 @@ -0,0 +1,200 @@
    49.4 +/*
    49.5 +libvmath - a vector math library
    49.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    49.7 +
    49.8 +This program is free software: you can redistribute it and/or modify
    49.9 +it under the terms of the GNU Lesser General Public License as published
   49.10 +by the Free Software Foundation, either version 3 of the License, or
   49.11 +(at your option) any later version.
   49.12 +
   49.13 +This program is distributed in the hope that it will be useful,
   49.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   49.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   49.16 +GNU Lesser General Public License for more details.
   49.17 +
   49.18 +You should have received a copy of the GNU Lesser General Public License
   49.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   49.20 +*/
   49.21 +
   49.22 +#include <string.h>
   49.23 +
   49.24 +#ifdef __cplusplus
   49.25 +extern "C" {
   49.26 +#endif	/* __cplusplus */
   49.27 +
   49.28 +/* C matrix 3x3 functions */
   49.29 +static inline void m3_identity(mat3_t m)
   49.30 +{
   49.31 +	static const mat3_t id = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
   49.32 +	memcpy(m, id, sizeof id);
   49.33 +}
   49.34 +
   49.35 +static inline void m3_cons(mat3_t m,
   49.36 +		scalar_t m11, scalar_t m12, scalar_t m13,
   49.37 +		scalar_t m21, scalar_t m22, scalar_t m23,
   49.38 +		scalar_t m31, scalar_t m32, scalar_t m33)
   49.39 +{
   49.40 +	m[0][0] = m11; m[0][1] = m12; m[0][2] = m13;
   49.41 +	m[1][0] = m21; m[1][1] = m22; m[1][2] = m23;
   49.42 +	m[2][0] = m31; m[2][1] = m32; m[2][2] = m33;
   49.43 +}
   49.44 +
   49.45 +static inline void m3_copy(mat3_t dest, mat3_t src)
   49.46 +{
   49.47 +	memcpy(dest, src, sizeof(mat3_t));
   49.48 +}
   49.49 +
   49.50 +
   49.51 +/* C matrix 4x4 functions */
   49.52 +static inline void m4_identity(mat4_t m)
   49.53 +{
   49.54 +	static const mat4_t id = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
   49.55 +	memcpy(m, id, sizeof id);
   49.56 +}
   49.57 +
   49.58 +static inline void m4_cons(mat4_t m,
   49.59 +		scalar_t m11, scalar_t m12, scalar_t m13, scalar_t m14,
   49.60 +		scalar_t m21, scalar_t m22, scalar_t m23, scalar_t m24,
   49.61 +		scalar_t m31, scalar_t m32, scalar_t m33, scalar_t m34,
   49.62 +		scalar_t m41, scalar_t m42, scalar_t m43, scalar_t m44)
   49.63 +{
   49.64 +	m[0][0] = m11; m[0][1] = m12; m[0][2] = m13; m[0][3] = m14;
   49.65 +	m[1][0] = m21; m[1][1] = m22; m[1][2] = m23; m[1][3] = m24;
   49.66 +	m[2][0] = m31; m[2][1] = m32; m[2][2] = m33; m[2][3] = m34;
   49.67 +	m[3][0] = m41; m[3][1] = m42; m[3][2] = m43; m[3][3] = m44;
   49.68 +}
   49.69 +
   49.70 +static inline void m4_copy(mat4_t dest, mat4_t src)
   49.71 +{
   49.72 +	memcpy(dest, src, sizeof(mat4_t));
   49.73 +}
   49.74 +
   49.75 +static inline void m4_mult(mat4_t res, mat4_t m1, mat4_t m2)
   49.76 +{
   49.77 +	mat4_t tmp;
   49.78 +
   49.79 +	/*
   49.80 +	int i, j;
   49.81 +	for(i=0; i<4; i++) {
   49.82 +		for(j=0; j<4; j++) {
   49.83 +			tmp[i][j] = m1[i][0] * m2[0][j] + m1[i][1] * m2[1][j] + m1[i][2] * m2[2][j] + m1[i][3] * m2[3][j];
   49.84 +		}
   49.85 +	}
   49.86 +	*/
   49.87 +
   49.88 +	tmp[0][0] = m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0] + m1[0][2] * m2[2][0] + m1[0][3] * m2[3][0];
   49.89 +	tmp[0][1] = m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1] + m1[0][2] * m2[2][1] + m1[0][3] * m2[3][1];
   49.90 +	tmp[0][2] = m1[0][0] * m2[0][2] + m1[0][1] * m2[1][2] + m1[0][2] * m2[2][2] + m1[0][3] * m2[3][2];
   49.91 +	tmp[0][3] = m1[0][0] * m2[0][3] + m1[0][1] * m2[1][3] + m1[0][2] * m2[2][3] + m1[0][3] * m2[3][3];
   49.92 +
   49.93 +	tmp[1][0] = m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0] + m1[1][2] * m2[2][0] + m1[1][3] * m2[3][0];
   49.94 +	tmp[1][1] = m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1] + m1[1][2] * m2[2][1] + m1[1][3] * m2[3][1];
   49.95 +	tmp[1][2] = m1[1][0] * m2[0][2] + m1[1][1] * m2[1][2] + m1[1][2] * m2[2][2] + m1[1][3] * m2[3][2];
   49.96 +	tmp[1][3] = m1[1][0] * m2[0][3] + m1[1][1] * m2[1][3] + m1[1][2] * m2[2][3] + m1[1][3] * m2[3][3];
   49.97 +
   49.98 +	tmp[2][0] = m1[2][0] * m2[0][0] + m1[2][1] * m2[1][0] + m1[2][2] * m2[2][0] + m1[2][3] * m2[3][0];
   49.99 +	tmp[2][1] = m1[2][0] * m2[0][1] + m1[2][1] * m2[1][1] + m1[2][2] * m2[2][1] + m1[2][3] * m2[3][1];
  49.100 +	tmp[2][2] = m1[2][0] * m2[0][2] + m1[2][1] * m2[1][2] + m1[2][2] * m2[2][2] + m1[2][3] * m2[3][2];
  49.101 +	tmp[2][3] = m1[2][0] * m2[0][3] + m1[2][1] * m2[1][3] + m1[2][2] * m2[2][3] + m1[2][3] * m2[3][3];
  49.102 +
  49.103 +	tmp[3][0] = m1[3][0] * m2[0][0] + m1[3][1] * m2[1][0] + m1[3][2] * m2[2][0] + m1[3][3] * m2[3][0];
  49.104 +	tmp[3][1] = m1[3][0] * m2[0][1] + m1[3][1] * m2[1][1] + m1[3][2] * m2[2][1] + m1[3][3] * m2[3][1];
  49.105 +	tmp[3][2] = m1[3][0] * m2[0][2] + m1[3][1] * m2[1][2] + m1[3][2] * m2[2][2] + m1[3][3] * m2[3][2];
  49.106 +	tmp[3][3] = m1[3][0] * m2[0][3] + m1[3][1] * m2[1][3] + m1[3][2] * m2[2][3] + m1[3][3] * m2[3][3];
  49.107 +
  49.108 +	m4_copy(res, tmp);
  49.109 +}
  49.110 +
  49.111 +static inline void m4_set_column(mat4_t m, vec4_t v, int idx)
  49.112 +{
  49.113 +	m[0][idx] = v.x;
  49.114 +	m[1][idx] = v.y;
  49.115 +	m[2][idx] = v.z;
  49.116 +	m[3][idx] = v.w;
  49.117 +}
  49.118 +
  49.119 +static inline void m4_set_row(mat4_t m, vec4_t v, int idx)
  49.120 +{
  49.121 +	m[idx][0] = v.x;
  49.122 +	m[idx][1] = v.y;
  49.123 +	m[idx][2] = v.z;
  49.124 +	m[idx][3] = v.w;
  49.125 +}
  49.126 +
  49.127 +#ifdef __cplusplus
  49.128 +}	/* extern "C" */
  49.129 +
  49.130 +
  49.131 +/* unrolled to hell and inline */
  49.132 +inline Matrix4x4 operator *(const Matrix4x4 &m1, const Matrix4x4 &m2)
  49.133 +{
  49.134 +	Matrix4x4 res;
  49.135 +
  49.136 +	/*
  49.137 +	for(i=0; i<4; i++) {
  49.138 +		for(j=0; j<4; j++) {
  49.139 +			res.m[i][j] = m1.m[i][0] * m2.m[0][j] + m1.m[i][1] * m2.m[1][j] + m1.m[i][2] * m2.m[2][j] + m1.m[i][3] * m2.m[3][j];
  49.140 +		}
  49.141 +	}
  49.142 +	*/
  49.143 +
  49.144 +	res.m[0][0] = m1.m[0][0] * m2.m[0][0] + m1.m[0][1] * m2.m[1][0] + m1.m[0][2] * m2.m[2][0] + m1.m[0][3] * m2.m[3][0];
  49.145 +	res.m[0][1] = m1.m[0][0] * m2.m[0][1] + m1.m[0][1] * m2.m[1][1] + m1.m[0][2] * m2.m[2][1] + m1.m[0][3] * m2.m[3][1];
  49.146 +	res.m[0][2] = m1.m[0][0] * m2.m[0][2] + m1.m[0][1] * m2.m[1][2] + m1.m[0][2] * m2.m[2][2] + m1.m[0][3] * m2.m[3][2];
  49.147 +	res.m[0][3] = m1.m[0][0] * m2.m[0][3] + m1.m[0][1] * m2.m[1][3] + m1.m[0][2] * m2.m[2][3] + m1.m[0][3] * m2.m[3][3];
  49.148 +
  49.149 +	res.m[1][0] = m1.m[1][0] * m2.m[0][0] + m1.m[1][1] * m2.m[1][0] + m1.m[1][2] * m2.m[2][0] + m1.m[1][3] * m2.m[3][0];
  49.150 +	res.m[1][1] = m1.m[1][0] * m2.m[0][1] + m1.m[1][1] * m2.m[1][1] + m1.m[1][2] * m2.m[2][1] + m1.m[1][3] * m2.m[3][1];
  49.151 +	res.m[1][2] = m1.m[1][0] * m2.m[0][2] + m1.m[1][1] * m2.m[1][2] + m1.m[1][2] * m2.m[2][2] + m1.m[1][3] * m2.m[3][2];
  49.152 +	res.m[1][3] = m1.m[1][0] * m2.m[0][3] + m1.m[1][1] * m2.m[1][3] + m1.m[1][2] * m2.m[2][3] + m1.m[1][3] * m2.m[3][3];
  49.153 +
  49.154 +	res.m[2][0] = m1.m[2][0] * m2.m[0][0] + m1.m[2][1] * m2.m[1][0] + m1.m[2][2] * m2.m[2][0] + m1.m[2][3] * m2.m[3][0];
  49.155 +	res.m[2][1] = m1.m[2][0] * m2.m[0][1] + m1.m[2][1] * m2.m[1][1] + m1.m[2][2] * m2.m[2][1] + m1.m[2][3] * m2.m[3][1];
  49.156 +	res.m[2][2] = m1.m[2][0] * m2.m[0][2] + m1.m[2][1] * m2.m[1][2] + m1.m[2][2] * m2.m[2][2] + m1.m[2][3] * m2.m[3][2];
  49.157 +	res.m[2][3] = m1.m[2][0] * m2.m[0][3] + m1.m[2][1] * m2.m[1][3] + m1.m[2][2] * m2.m[2][3] + m1.m[2][3] * m2.m[3][3];
  49.158 +
  49.159 +	res.m[3][0] = m1.m[3][0] * m2.m[0][0] + m1.m[3][1] * m2.m[1][0] + m1.m[3][2] * m2.m[2][0] + m1.m[3][3] * m2.m[3][0];
  49.160 +	res.m[3][1] = m1.m[3][0] * m2.m[0][1] + m1.m[3][1] * m2.m[1][1] + m1.m[3][2] * m2.m[2][1] + m1.m[3][3] * m2.m[3][1];
  49.161 +	res.m[3][2] = m1.m[3][0] * m2.m[0][2] + m1.m[3][1] * m2.m[1][2] + m1.m[3][2] * m2.m[2][2] + m1.m[3][3] * m2.m[3][2];
  49.162 +	res.m[3][3] = m1.m[3][0] * m2.m[0][3] + m1.m[3][1] * m2.m[1][3] + m1.m[3][2] * m2.m[2][3] + m1.m[3][3] * m2.m[3][3];
  49.163 +
  49.164 +	return res;
  49.165 +}
  49.166 +
  49.167 +inline void operator *=(Matrix4x4 &m1, const Matrix4x4 &m2)
  49.168 +{
  49.169 +	Matrix4x4 res = m1 * m2;
  49.170 +	m1 = res;
  49.171 +}
  49.172 +
  49.173 +
  49.174 +inline scalar_t *Matrix3x3::operator [](int index)
  49.175 +{
  49.176 +	return m[index];
  49.177 +}
  49.178 +
  49.179 +inline const scalar_t *Matrix3x3::operator [](int index) const
  49.180 +{
  49.181 +	return m[index];
  49.182 +}
  49.183 +
  49.184 +inline void Matrix3x3::reset_identity()
  49.185 +{
  49.186 +	*this = identity;
  49.187 +}
  49.188 +
  49.189 +inline scalar_t *Matrix4x4::operator [](int index)
  49.190 +{
  49.191 +	return m[index];
  49.192 +}
  49.193 +
  49.194 +inline const scalar_t *Matrix4x4::operator [](int index) const
  49.195 +{
  49.196 +	return m[index];
  49.197 +}
  49.198 +
  49.199 +inline void Matrix4x4::reset_identity()
  49.200 +{
  49.201 +	*this = identity;
  49.202 +}
  49.203 +#endif	/* __cplusplus */
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/vmath/matrix_c.c	Sun Nov 09 13:03:36 2014 +0200
    50.3 @@ -0,0 +1,292 @@
    50.4 +/*
    50.5 +libvmath - a vector math library
    50.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    50.7 +
    50.8 +This program is free software: you can redistribute it and/or modify
    50.9 +it under the terms of the GNU Lesser General Public License as published
   50.10 +by the Free Software Foundation, either version 3 of the License, or
   50.11 +(at your option) any later version.
   50.12 +
   50.13 +This program is distributed in the hope that it will be useful,
   50.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   50.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   50.16 +GNU Lesser General Public License for more details.
   50.17 +
   50.18 +You should have received a copy of the GNU Lesser General Public License
   50.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   50.20 +*/
   50.21 +
   50.22 +
   50.23 +#include <stdio.h>
   50.24 +#include "matrix.h"
   50.25 +#include "vector.h"
   50.26 +#include "quat.h"
   50.27 +
   50.28 +void m3_to_m4(mat4_t dest, mat3_t src)
   50.29 +{
   50.30 +	int i, j;
   50.31 +
   50.32 +	memset(dest, 0, sizeof(mat4_t));
   50.33 +	for(i=0; i<3; i++) {
   50.34 +		for(j=0; j<3; j++) {
   50.35 +			dest[i][j] = src[i][j];
   50.36 +		}
   50.37 +	}
   50.38 +	dest[3][3] = 1.0;
   50.39 +}
   50.40 +
   50.41 +void m3_print(FILE *fp, mat3_t m)
   50.42 +{
   50.43 +	int i;
   50.44 +	for(i=0; i<3; i++) {
   50.45 +		fprintf(fp, "[ %12.5f %12.5f %12.5f ]\n", (float)m[i][0], (float)m[i][1], (float)m[i][2]);
   50.46 +	}
   50.47 +}
   50.48 +
   50.49 +/* C matrix 4x4 functions */
   50.50 +void m4_to_m3(mat3_t dest, mat4_t src)
   50.51 +{
   50.52 +	int i, j;
   50.53 +	for(i=0; i<3; i++) {
   50.54 +		for(j=0; j<3; j++) {
   50.55 +			dest[i][j] = src[i][j];
   50.56 +		}
   50.57 +	}
   50.58 +}
   50.59 +
   50.60 +void m4_set_translation(mat4_t m, scalar_t x, scalar_t y, scalar_t z)
   50.61 +{
   50.62 +	m4_identity(m);
   50.63 +	m[0][3] = x;
   50.64 +	m[1][3] = y;
   50.65 +	m[2][3] = z;
   50.66 +}
   50.67 +
   50.68 +void m4_translate(mat4_t m, scalar_t x, scalar_t y, scalar_t z)
   50.69 +{
   50.70 +	mat4_t tm;
   50.71 +	m4_set_translation(tm, x, y, z);
   50.72 +	m4_mult(m, m, tm);
   50.73 +}
   50.74 +
   50.75 +void m4_rotate(mat4_t m, scalar_t x, scalar_t y, scalar_t z)
   50.76 +{
   50.77 +	m4_rotate_x(m, x);
   50.78 +	m4_rotate_y(m, y);
   50.79 +	m4_rotate_z(m, z);
   50.80 +}
   50.81 +
   50.82 +void m4_set_rotation_x(mat4_t m, scalar_t angle)
   50.83 +{
   50.84 +	m4_identity(m);
   50.85 +	m[1][1] = cos(angle); m[1][2] = -sin(angle);
   50.86 +	m[2][1] = sin(angle); m[2][2] = cos(angle);
   50.87 +}
   50.88 +
   50.89 +void m4_rotate_x(mat4_t m, scalar_t angle)
   50.90 +{
   50.91 +	mat4_t rm;
   50.92 +	m4_set_rotation_x(m, angle);
   50.93 +	m4_mult(m, m, rm);
   50.94 +}
   50.95 +
   50.96 +void m4_set_rotation_y(mat4_t m, scalar_t angle)
   50.97 +{
   50.98 +	m4_identity(m);
   50.99 +	m[0][0] = cos(angle); m[0][2] = sin(angle);
  50.100 +	m[2][0] = -sin(angle); m[2][2] = cos(angle);
  50.101 +}
  50.102 +
  50.103 +void m4_rotate_y(mat4_t m, scalar_t angle)
  50.104 +{
  50.105 +	mat4_t rm;
  50.106 +	m4_set_rotation_y(rm, angle);
  50.107 +	m4_mult(m, m, rm);
  50.108 +}
  50.109 +
  50.110 +void m4_set_rotation_z(mat4_t m, scalar_t angle)
  50.111 +{
  50.112 +	m4_identity(m);
  50.113 +	m[0][0] = cos(angle); m[0][1] = -sin(angle);
  50.114 +	m[1][0] = sin(angle); m[1][1] = cos(angle);
  50.115 +}
  50.116 +
  50.117 +void m4_rotate_z(mat4_t m, scalar_t angle)
  50.118 +{
  50.119 +	mat4_t rm;
  50.120 +	m4_set_rotation_z(rm, angle);
  50.121 +	m4_mult(m, m, rm);
  50.122 +}
  50.123 +
  50.124 +void m4_set_rotation_axis(mat4_t m, scalar_t angle, scalar_t x, scalar_t y, scalar_t z)
  50.125 +{
  50.126 +	scalar_t sina = sin(angle);
  50.127 +	scalar_t cosa = cos(angle);
  50.128 +	scalar_t one_minus_cosa = 1.0 - cosa;
  50.129 +	scalar_t nxsq = x * x;
  50.130 +	scalar_t nysq = y * y;
  50.131 +	scalar_t nzsq = z * z;
  50.132 +
  50.133 +	m[0][0] = nxsq + (1.0 - nxsq) * cosa;
  50.134 +	m[0][1] = x * y * one_minus_cosa - z * sina;
  50.135 +	m[0][2] = x * z * one_minus_cosa + y * sina;
  50.136 +	m[1][0] = x * y * one_minus_cosa + z * sina;
  50.137 +	m[1][1] = nysq + (1.0 - nysq) * cosa;
  50.138 +	m[1][2] = y * z * one_minus_cosa - x * sina;
  50.139 +	m[2][0] = x * z * one_minus_cosa - y * sina;
  50.140 +	m[2][1] = y * z * one_minus_cosa + x * sina;
  50.141 +	m[2][2] = nzsq + (1.0 - nzsq) * cosa;
  50.142 +
  50.143 +	/* the rest are identity */
  50.144 +	m[3][0] = m[3][1] = m[3][2] = m[0][3] = m[1][3] = m[2][3] = 0.0;
  50.145 +	m[3][3] = 1.0;
  50.146 +}
  50.147 +
  50.148 +void m4_rotate_axis(mat4_t m, scalar_t angle, scalar_t x, scalar_t y, scalar_t z)
  50.149 +{
  50.150 +	mat4_t xform;
  50.151 +	m4_set_rotation_axis(xform, angle, x, y, z);
  50.152 +	m4_mult(m, m, xform);
  50.153 +}
  50.154 +
  50.155 +void m4_rotate_quat(mat4_t m, quat_t q)
  50.156 +{
  50.157 +	mat4_t rm;
  50.158 +	quat_to_mat4(rm, q);
  50.159 +	m4_mult(m, m, rm);
  50.160 +}
  50.161 +
  50.162 +void m4_scale(mat4_t m, scalar_t x, scalar_t y, scalar_t z)
  50.163 +{
  50.164 +	mat4_t sm;
  50.165 +	m4_identity(sm);
  50.166 +	sm[0][0] = x;
  50.167 +	sm[1][1] = y;
  50.168 +	sm[2][2] = z;
  50.169 +	m4_mult(m, m, sm);
  50.170 +}
  50.171 +
  50.172 +void m4_transpose(mat4_t res, mat4_t m)
  50.173 +{
  50.174 +	int i, j;
  50.175 +	mat4_t tmp;
  50.176 +	m4_copy(tmp, m);
  50.177 +
  50.178 +	for(i=0; i<4; i++) {
  50.179 +		for(j=0; j<4; j++) {
  50.180 +			res[i][j] = tmp[j][i];
  50.181 +		}
  50.182 +	}
  50.183 +}
  50.184 +
  50.185 +scalar_t m4_determinant(mat4_t m)
  50.186 +{
  50.187 +	scalar_t det11 =	(m[1][1] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  50.188 +						(m[1][2] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) +
  50.189 +						(m[1][3] * (m[2][1] * m[3][2] - m[3][1] * m[2][2]));
  50.190 +
  50.191 +	scalar_t det12 =	(m[1][0] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  50.192 +						(m[1][2] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  50.193 +						(m[1][3] * (m[2][0] * m[3][2] - m[3][0] * m[2][2]));
  50.194 +
  50.195 +	scalar_t det13 =	(m[1][0] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) -
  50.196 +						(m[1][1] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  50.197 +						(m[1][3] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  50.198 +
  50.199 +	scalar_t det14 =	(m[1][0] * (m[2][1] * m[3][2] - m[3][1] * m[2][2])) -
  50.200 +						(m[1][1] * (m[2][0] * m[3][2] - m[3][0] * m[2][2])) +
  50.201 +						(m[1][2] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  50.202 +
  50.203 +	return m[0][0] * det11 - m[0][1] * det12 + m[0][2] * det13 - m[0][3] * det14;
  50.204 +}
  50.205 +
  50.206 +void m4_adjoint(mat4_t res, mat4_t m)
  50.207 +{
  50.208 +	int i, j;
  50.209 +	mat4_t coef;
  50.210 +
  50.211 +	coef[0][0] =	(m[1][1] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  50.212 +					(m[1][2] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) +
  50.213 +					(m[1][3] * (m[2][1] * m[3][2] - m[3][1] * m[2][2]));
  50.214 +	coef[0][1] =	(m[1][0] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  50.215 +					(m[1][2] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  50.216 +					(m[1][3] * (m[2][0] * m[3][2] - m[3][0] * m[2][2]));
  50.217 +	coef[0][2] =	(m[1][0] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) -
  50.218 +					(m[1][1] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  50.219 +					(m[1][3] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  50.220 +	coef[0][3] =	(m[1][0] * (m[2][1] * m[3][2] - m[3][1] * m[2][2])) -
  50.221 +					(m[1][1] * (m[2][0] * m[3][2] - m[3][0] * m[2][2])) +
  50.222 +					(m[1][2] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  50.223 +
  50.224 +	coef[1][0] =	(m[0][1] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  50.225 +					(m[0][2] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) +
  50.226 +					(m[0][3] * (m[2][1] * m[3][2] - m[3][1] * m[2][2]));
  50.227 +	coef[1][1] =	(m[0][0] * (m[2][2] * m[3][3] - m[3][2] * m[2][3])) -
  50.228 +					(m[0][2] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  50.229 +					(m[0][3] * (m[2][0] * m[3][2] - m[3][0] * m[2][2]));
  50.230 +	coef[1][2] =	(m[0][0] * (m[2][1] * m[3][3] - m[3][1] * m[2][3])) -
  50.231 +					(m[0][1] * (m[2][0] * m[3][3] - m[3][0] * m[2][3])) +
  50.232 +					(m[0][3] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  50.233 +	coef[1][3] =	(m[0][0] * (m[2][1] * m[3][2] - m[3][1] * m[2][2])) -
  50.234 +					(m[0][1] * (m[2][0] * m[3][2] - m[3][0] * m[2][2])) +
  50.235 +					(m[0][2] * (m[2][0] * m[3][1] - m[3][0] * m[2][1]));
  50.236 +
  50.237 +	coef[2][0] =	(m[0][1] * (m[1][2] * m[3][3] - m[3][2] * m[1][3])) -
  50.238 +					(m[0][2] * (m[1][1] * m[3][3] - m[3][1] * m[1][3])) +
  50.239 +					(m[0][3] * (m[1][1] * m[3][2] - m[3][1] * m[1][2]));
  50.240 +	coef[2][1] =	(m[0][0] * (m[1][2] * m[3][3] - m[3][2] * m[1][3])) -
  50.241 +					(m[0][2] * (m[1][0] * m[3][3] - m[3][0] * m[1][3])) +
  50.242 +					(m[0][3] * (m[1][0] * m[3][2] - m[3][0] * m[1][2]));
  50.243 +	coef[2][2] =	(m[0][0] * (m[1][1] * m[3][3] - m[3][1] * m[1][3])) -
  50.244 +					(m[0][1] * (m[1][0] * m[3][3] - m[3][0] * m[1][3])) +
  50.245 +					(m[0][3] * (m[1][0] * m[3][1] - m[3][0] * m[1][1]));
  50.246 +	coef[2][3] =	(m[0][0] * (m[1][1] * m[3][2] - m[3][1] * m[1][2])) -
  50.247 +					(m[0][1] * (m[1][0] * m[3][2] - m[3][0] * m[1][2])) +
  50.248 +					(m[0][2] * (m[1][0] * m[3][1] - m[3][0] * m[1][1]));
  50.249 +
  50.250 +	coef[3][0] =	(m[0][1] * (m[1][2] * m[2][3] - m[2][2] * m[1][3])) -
  50.251 +					(m[0][2] * (m[1][1] * m[2][3] - m[2][1] * m[1][3])) +
  50.252 +					(m[0][3] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]));
  50.253 +	coef[3][1] =	(m[0][0] * (m[1][2] * m[2][3] - m[2][2] * m[1][3])) -
  50.254 +					(m[0][2] * (m[1][0] * m[2][3] - m[2][0] * m[1][3])) +
  50.255 +					(m[0][3] * (m[1][0] * m[2][2] - m[2][0] * m[1][2]));
  50.256 +	coef[3][2] =	(m[0][0] * (m[1][1] * m[2][3] - m[2][1] * m[1][3])) -
  50.257 +					(m[0][1] * (m[1][0] * m[2][3] - m[2][0] * m[1][3])) +
  50.258 +					(m[0][3] * (m[1][0] * m[2][1] - m[2][0] * m[1][1]));
  50.259 +	coef[3][3] =	(m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])) -
  50.260 +					(m[0][1] * (m[1][0] * m[2][2] - m[2][0] * m[1][2])) +
  50.261 +					(m[0][2] * (m[1][0] * m[2][1] - m[2][0] * m[1][1]));
  50.262 +
  50.263 +	m4_transpose(res, coef);
  50.264 +
  50.265 +	for(i=0; i<4; i++) {
  50.266 +		for(j=0; j<4; j++) {
  50.267 +			res[i][j] = j % 2 ? -res[i][j] : res[i][j];
  50.268 +			if(i % 2) res[i][j] = -res[i][j];
  50.269 +		}
  50.270 +	}
  50.271 +}
  50.272 +
  50.273 +void m4_inverse(mat4_t res, mat4_t m)
  50.274 +{
  50.275 +	int i, j;
  50.276 +	mat4_t adj;
  50.277 +	scalar_t det;
  50.278 +
  50.279 +	m4_adjoint(adj, m);
  50.280 +	det = m4_determinant(m);
  50.281 +	
  50.282 +	for(i=0; i<4; i++) {
  50.283 +		for(j=0; j<4; j++) {
  50.284 +			res[i][j] = adj[i][j] / det;
  50.285 +		}
  50.286 +	}
  50.287 +}
  50.288 +
  50.289 +void m4_print(FILE *fp, mat4_t m)
  50.290 +{
  50.291 +	int i;
  50.292 +	for(i=0; i<4; i++) {
  50.293 +		fprintf(fp, "[ %12.5f %12.5f %12.5f %12.5f ]\n", (float)m[i][0], (float)m[i][1], (float)m[i][2], (float)m[i][3]);
  50.294 +	}
  50.295 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/vmath/quat.cc	Sun Nov 09 13:03:36 2014 +0200
    51.3 @@ -0,0 +1,191 @@
    51.4 +#include "quat.h"
    51.5 +#include "vmath.h"
    51.6 +
    51.7 +Quaternion::Quaternion() {
    51.8 +	s = 1.0;
    51.9 +	v.x = v.y = v.z = 0.0;
   51.10 +}
   51.11 +
   51.12 +Quaternion::Quaternion(scalar_t s, const Vector3 &v) {
   51.13 +	this->s = s;
   51.14 +	this->v = v;
   51.15 +}
   51.16 +
   51.17 +Quaternion::Quaternion(scalar_t s, scalar_t x, scalar_t y, scalar_t z) {
   51.18 +	v.x = x;
   51.19 +	v.y = y;
   51.20 +	v.z = z;
   51.21 +	this->s = s;
   51.22 +}
   51.23 +
   51.24 +Quaternion::Quaternion(const Vector3 &axis, scalar_t angle) {
   51.25 +	set_rotation(axis, angle);
   51.26 +}
   51.27 +
   51.28 +Quaternion::Quaternion(const quat_t &quat)
   51.29 +{
   51.30 +	v.x = quat.x;
   51.31 +	v.y = quat.y;
   51.32 +	v.z = quat.z;
   51.33 +	s = quat.w;
   51.34 +}
   51.35 +
   51.36 +Quaternion Quaternion::operator +(const Quaternion &quat) const
   51.37 +{
   51.38 +	return Quaternion(s + quat.s, v + quat.v);
   51.39 +}
   51.40 +
   51.41 +Quaternion Quaternion::operator -(const Quaternion &quat) const
   51.42 +{
   51.43 +	return Quaternion(s - quat.s, v - quat.v);
   51.44 +}
   51.45 +
   51.46 +Quaternion Quaternion::operator -() const
   51.47 +{
   51.48 +	return Quaternion(-s, -v);
   51.49 +}
   51.50 +
   51.51 +/** Quaternion Multiplication:
   51.52 + * Q1*Q2 = [s1*s2 - v1.v2,  s1*v2 + s2*v1 + v1(x)v2]
   51.53 + */
   51.54 +Quaternion Quaternion::operator *(const Quaternion &quat) const {
   51.55 +	Quaternion newq;
   51.56 +	newq.s = s * quat.s - dot_product(v, quat.v);
   51.57 +	newq.v = quat.v * s + v * quat.s + cross_product(v, quat.v);
   51.58 +	return newq;
   51.59 +}
   51.60 +
   51.61 +void Quaternion::operator +=(const Quaternion &quat) {
   51.62 +	*this = Quaternion(s + quat.s, v + quat.v);
   51.63 +}
   51.64 +
   51.65 +void Quaternion::operator -=(const Quaternion &quat) {
   51.66 +	*this = Quaternion(s - quat.s, v - quat.v);
   51.67 +}
   51.68 +
   51.69 +void Quaternion::operator *=(const Quaternion &quat) {
   51.70 +	*this = *this * quat;
   51.71 +}
   51.72 +
   51.73 +void Quaternion::reset_identity() {
   51.74 +	s = 1.0;
   51.75 +	v.x = v.y = v.z = 0.0;
   51.76 +}
   51.77 +
   51.78 +Quaternion Quaternion::conjugate() const {
   51.79 +	return Quaternion(s, -v);
   51.80 +}
   51.81 +
   51.82 +scalar_t Quaternion::length() const {
   51.83 +	return (scalar_t)sqrt(v.x*v.x + v.y*v.y + v.z*v.z + s*s);
   51.84 +}
   51.85 +
   51.86 +/** Q * ~Q = ||Q||^2 */
   51.87 +scalar_t Quaternion::length_sq() const {
   51.88 +	return v.x*v.x + v.y*v.y + v.z*v.z + s*s;
   51.89 +}
   51.90 +
   51.91 +void Quaternion::normalize() {
   51.92 +	scalar_t len = (scalar_t)sqrt(v.x*v.x + v.y*v.y + v.z*v.z + s*s);
   51.93 +	v.x /= len;
   51.94 +	v.y /= len;
   51.95 +	v.z /= len;
   51.96 +	s /= len;
   51.97 +}
   51.98 +
   51.99 +Quaternion Quaternion::normalized() const {
  51.100 +	Quaternion nq = *this;
  51.101 +	scalar_t len = (scalar_t)sqrt(v.x*v.x + v.y*v.y + v.z*v.z + s*s);
  51.102 +	nq.v.x /= len;
  51.103 +	nq.v.y /= len;
  51.104 +	nq.v.z /= len;
  51.105 +	nq.s /= len;
  51.106 +	return nq;
  51.107 +}
  51.108 +
  51.109 +/** Quaternion Inversion: Q^-1 = ~Q / ||Q||^2 */
  51.110 +Quaternion Quaternion::inverse() const {
  51.111 +	Quaternion inv = conjugate();
  51.112 +	scalar_t lensq = length_sq();
  51.113 +	inv.v /= lensq;
  51.114 +	inv.s /= lensq;
  51.115 +
  51.116 +	return inv;
  51.117 +}
  51.118 +
  51.119 +
  51.120 +void Quaternion::set_rotation(const Vector3 &axis, scalar_t angle) {
  51.121 +	scalar_t half_angle = angle / 2.0;
  51.122 +	s = cos(half_angle);
  51.123 +	v = axis * sin(half_angle);
  51.124 +}
  51.125 +
  51.126 +void Quaternion::rotate(const Vector3 &axis, scalar_t angle) {
  51.127 +	Quaternion q;
  51.128 +	scalar_t half_angle = angle / 2.0;
  51.129 +	q.s = cos(half_angle);
  51.130 +	q.v = axis * sin(half_angle);
  51.131 +
  51.132 +	*this *= q;
  51.133 +}
  51.134 +
  51.135 +void Quaternion::rotate(const Quaternion &q) {
  51.136 +	*this = q * *this * q.conjugate();
  51.137 +}
  51.138 +
  51.139 +Matrix3x3 Quaternion::get_rotation_matrix() const {
  51.140 +	return Matrix3x3(
  51.141 +			1.0 - 2.0 * v.y*v.y - 2.0 * v.z*v.z,	2.0 * v.x * v.y - 2.0 * s * v.z,		2.0 * v.z * v.x + 2.0 * s * v.y,
  51.142 +			2.0 * v.x * v.y + 2.0 * s * v.z,		1.0 - 2.0 * v.x*v.x - 2.0 * v.z*v.z,	2.0 * v.y * v.z - 2.0 * s * v.x,
  51.143 +			2.0 * v.z * v.x - 2.0 * s * v.y,		2.0 * v.y * v.z + 2.0 * s * v.x,		1.0 - 2.0 * v.x*v.x - 2.0 * v.y*v.y);
  51.144 +}
  51.145 +
  51.146 +
  51.147 +/** Spherical linear interpolation (slerp) */
  51.148 +Quaternion slerp(const Quaternion &quat1, const Quaternion &q2, scalar_t t) {
  51.149 +	Quaternion q1;
  51.150 +	scalar_t dot = q1.s * q2.s + q1.v.x * q2.v.x + q1.v.y * q2.v.y + q1.v.z * q2.v.z;
  51.151 +
  51.152 +	if(dot < 0.0) {
  51.153 +		/* make sure we interpolate across the shortest arc */
  51.154 +		q1 = -quat1;
  51.155 +		dot = -dot;
  51.156 +	} else {
  51.157 +		q1 = quat1;
  51.158 +	}
  51.159 +
  51.160 +	/* clamp dot to [-1, 1] in order to avoid domain errors in acos due to
  51.161 +	 * floating point imprecisions
  51.162 +	 */
  51.163 +	if(dot < -1.0) dot = -1.0;
  51.164 +	if(dot > 1.0) dot = 1.0;
  51.165 +
  51.166 +	scalar_t angle = acos(dot);
  51.167 +	scalar_t a, b;
  51.168 +
  51.169 +	scalar_t sin_angle = sin(angle);
  51.170 +	if(fabs(sin_angle) < SMALL_NUMBER) {
  51.171 +		/* for very small angles or completely opposite orientations
  51.172 +		 * use linear interpolation to avoid div/zero (in the first case it makes sense,
  51.173 +		 * the second case is pretty much undefined anyway I guess ...
  51.174 +		 */
  51.175 +		a = 1.0f - t;
  51.176 +		b = t;
  51.177 +	} else {
  51.178 +		a = sin((1.0f - t) * angle) / sin_angle;
  51.179 +		b = sin(t * angle) / sin_angle;
  51.180 +	}
  51.181 +
  51.182 +	scalar_t x = q1.v.x * a + q2.v.x * b;
  51.183 +	scalar_t y = q1.v.y * a + q2.v.y * b;
  51.184 +	scalar_t z = q1.v.z * a + q2.v.z * b;
  51.185 +	scalar_t s = q1.s * a + q2.s * b;
  51.186 +
  51.187 +	return Quaternion(s, Vector3(x, y, z));
  51.188 +}
  51.189 +
  51.190 +
  51.191 +std::ostream &operator <<(std::ostream &out, const Quaternion &q) {
  51.192 +	out << "(" << q.s << ", " << q.v << ")";
  51.193 +	return out;
  51.194 +}
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/vmath/quat.h	Sun Nov 09 13:03:36 2014 +0200
    52.3 @@ -0,0 +1,118 @@
    52.4 +/*
    52.5 +libvmath - a vector math library
    52.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    52.7 +
    52.8 +This program is free software: you can redistribute it and/or modify
    52.9 +it under the terms of the GNU Lesser General Public License as published
   52.10 +by the Free Software Foundation, either version 3 of the License, or
   52.11 +(at your option) any later version.
   52.12 +
   52.13 +This program is distributed in the hope that it will be useful,
   52.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   52.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   52.16 +GNU Lesser General Public License for more details.
   52.17 +
   52.18 +You should have received a copy of the GNU Lesser General Public License
   52.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   52.20 +*/
   52.21 +
   52.22 +#ifndef VMATH_QUATERNION_H_
   52.23 +#define VMATH_QUATERNION_H_
   52.24 +
   52.25 +#include <stdio.h>
   52.26 +#include "vmath_types.h"
   52.27 +#include "vector.h"
   52.28 +
   52.29 +#ifdef __cplusplus
   52.30 +extern "C" {
   52.31 +#endif	/* __cplusplus */
   52.32 +
   52.33 +#define quat_cons(s, x, y, z)	v4_cons(x, y, z, s)
   52.34 +#define quat_vec(q)				v3_cons((q).x, (q).y, (q).z)
   52.35 +#define quat_s(q)				((q).w)
   52.36 +#define quat_identity()			quat_cons(1.0, 0.0, 0.0, 0.0)
   52.37 +void quat_print(FILE *fp, quat_t q);
   52.38 +
   52.39 +#define quat_add		v4_add
   52.40 +#define quat_sub		v4_sub
   52.41 +#define quat_neg		v4_neg
   52.42 +
   52.43 +static inline quat_t quat_mul(quat_t q1, quat_t q2);
   52.44 +
   52.45 +static inline quat_t quat_conjugate(quat_t q);
   52.46 +
   52.47 +#define quat_length		v4_length
   52.48 +#define quat_length_sq	v4_length_sq
   52.49 +
   52.50 +#define quat_normalize	v4_normalize
   52.51 +static inline quat_t quat_inverse(quat_t q);
   52.52 +
   52.53 +quat_t quat_rotate(quat_t q, scalar_t angle, scalar_t x, scalar_t y, scalar_t z);
   52.54 +quat_t quat_rotate_quat(quat_t q, quat_t rotq);
   52.55 +
   52.56 +static inline void quat_to_mat3(mat3_t res, quat_t q);
   52.57 +static inline void quat_to_mat4(mat4_t res, quat_t q);
   52.58 +
   52.59 +#define quat_lerp quat_slerp
   52.60 +quat_t quat_slerp(quat_t q1, quat_t q2, scalar_t t);
   52.61 +
   52.62 +
   52.63 +#ifdef __cplusplus
   52.64 +}	/* extern "C" */
   52.65 +
   52.66 +#include <iostream>
   52.67 +
   52.68 +/* Quaternion */
   52.69 +class Quaternion {
   52.70 +public:
   52.71 +	scalar_t s;
   52.72 +	Vector3 v;
   52.73 +
   52.74 +	Quaternion();
   52.75 +	Quaternion(scalar_t s, const Vector3 &v);
   52.76 +	Quaternion(scalar_t s, scalar_t x, scalar_t y, scalar_t z);
   52.77 +	Quaternion(const Vector3 &axis, scalar_t angle);
   52.78 +	Quaternion(const quat_t &quat);
   52.79 +
   52.80 +	Quaternion operator +(const Quaternion &quat) const;
   52.81 +	Quaternion operator -(const Quaternion &quat) const;
   52.82 +	Quaternion operator -() const;
   52.83 +	Quaternion operator *(const Quaternion &quat) const;
   52.84 +
   52.85 +	void operator +=(const Quaternion &quat);
   52.86 +	void operator -=(const Quaternion &quat);
   52.87 +	void operator *=(const Quaternion &quat);
   52.88 +
   52.89 +	void reset_identity();
   52.90 +
   52.91 +	Quaternion conjugate() const;
   52.92 +
   52.93 +	scalar_t length() const;
   52.94 +	scalar_t length_sq() const;
   52.95 +
   52.96 +	void normalize();
   52.97 +	Quaternion normalized() const;
   52.98 +
   52.99 +	Quaternion inverse() const;
  52.100 +
  52.101 +	void set_rotation(const Vector3 &axis, scalar_t angle);
  52.102 +	void rotate(const Vector3 &axis, scalar_t angle);
  52.103 +	/* note: this is a totally different operation from the above
  52.104 +	 * this treats the quaternion as signifying direction and rotates
  52.105 +	 * it by a rotation quaternion by rot * q * rot'
  52.106 +	 */
  52.107 +	void rotate(const Quaternion &q);
  52.108 +
  52.109 +	Matrix3x3 get_rotation_matrix() const;
  52.110 +};
  52.111 +
  52.112 +Quaternion slerp(const Quaternion &q1, const Quaternion &q2, scalar_t t);
  52.113 +inline Quaternion lerp(const Quaternion &q1, const Quaternion &q2, scalar_t t);
  52.114 +
  52.115 +std::ostream &operator <<(std::ostream &out, const Quaternion &q);
  52.116 +
  52.117 +#endif	/* __cplusplus */
  52.118 +
  52.119 +#include "quat.inl"
  52.120 +
  52.121 +#endif	/* VMATH_QUATERNION_H_ */
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/vmath/quat.inl	Sun Nov 09 13:03:36 2014 +0200
    53.3 @@ -0,0 +1,81 @@
    53.4 +/*
    53.5 +libvmath - a vector math library
    53.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    53.7 +
    53.8 +This program is free software: you can redistribute it and/or modify
    53.9 +it under the terms of the GNU Lesser General Public License as published
   53.10 +by the Free Software Foundation, either version 3 of the License, or
   53.11 +(at your option) any later version.
   53.12 +
   53.13 +This program is distributed in the hope that it will be useful,
   53.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   53.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   53.16 +GNU Lesser General Public License for more details.
   53.17 +
   53.18 +You should have received a copy of the GNU Lesser General Public License
   53.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   53.20 +*/
   53.21 +
   53.22 +#include "vector.h"
   53.23 +#include "matrix.h"
   53.24 +
   53.25 +#ifdef __cplusplus
   53.26 +extern "C" {
   53.27 +#endif	/* __cplusplus */
   53.28 +
   53.29 +static inline quat_t quat_mul(quat_t q1, quat_t q2)
   53.30 +{
   53.31 +	quat_t res;
   53.32 +	vec3_t v1 = quat_vec(q1);
   53.33 +	vec3_t v2 = quat_vec(q2);
   53.34 +
   53.35 +	res.w = q1.w * q2.w - v3_dot(v1, v2);
   53.36 +	/* resvec = v2 * q1 + v1 * q2 + cross(v1, v2) */
   53.37 +	res.x = v2.x * q1.w + v1.x * q2.w + (v1.y * v2.z - v1.z * v2.y);
   53.38 +	res.y = v2.y * q1.w + v1.y * q2.w + (v1.z * v2.x - v1.x * v2.z);
   53.39 +	res.z = v2.z * q1.w + v1.z * q2.w + (v1.x * v2.y - v1.y * v2.x);
   53.40 +	return res;
   53.41 +}
   53.42 +
   53.43 +static inline quat_t quat_conjugate(quat_t q)
   53.44 +{
   53.45 +	q.x = -q.x;
   53.46 +	q.y = -q.y;
   53.47 +	q.z = -q.z;
   53.48 +	return q;
   53.49 +}
   53.50 +
   53.51 +static inline quat_t quat_inverse(quat_t q)
   53.52 +{
   53.53 +	scalar_t lensq = quat_length_sq(q);
   53.54 +	q = quat_conjugate(q);
   53.55 +	q.x /= lensq;
   53.56 +	q.y /= lensq;
   53.57 +	q.z /= lensq;
   53.58 +	q.w /= lensq;
   53.59 +	return q;
   53.60 +}
   53.61 +
   53.62 +static inline void quat_to_mat3(mat3_t res, quat_t q)
   53.63 +{
   53.64 +	m3_cons(res, 1.0 - 2.0 * q.y*q.y - 2.0 * q.z*q.z, 2.0 * q.x * q.y - 2.0 * q.w * q.z,   2.0 * q.z * q.x + 2.0 * q.w * q.y,
   53.65 +				 2.0 * q.x * q.y + 2.0 * q.w * q.z,   1.0 - 2.0 * q.x*q.x - 2.0 * q.z*q.z, 2.0 * q.y * q.z - 2.0 * q.w * q.x,
   53.66 +				 2.0 * q.z * q.x - 2.0 * q.w * q.y,   2.0 * q.y * q.z + 2.0 * q.w * q.x,   1.0 - 2.0 * q.x*q.x - 2.0 * q.y*q.y);
   53.67 +}
   53.68 +
   53.69 +static inline void quat_to_mat4(mat4_t res, quat_t q)
   53.70 +{
   53.71 +	m4_cons(res, 1.0 - 2.0 * q.y*q.y - 2.0 * q.z*q.z, 2.0 * q.x * q.y - 2.0 * q.w * q.z,   2.0 * q.z * q.x + 2.0 * q.w * q.y,   0,
   53.72 +				 2.0 * q.x * q.y + 2.0 * q.w * q.z,   1.0 - 2.0 * q.x*q.x - 2.0 * q.z*q.z, 2.0 * q.y * q.z - 2.0 * q.w * q.x,   0,
   53.73 +				 2.0 * q.z * q.x - 2.0 * q.w * q.y,   2.0 * q.y * q.z + 2.0 * q.w * q.x,   1.0 - 2.0 * q.x*q.x - 2.0 * q.y*q.y, 0,
   53.74 +				 0, 0, 0, 1);
   53.75 +}
   53.76 +
   53.77 +#ifdef __cplusplus
   53.78 +}	/* extern "C" */
   53.79 +
   53.80 +inline Quaternion lerp(const Quaternion &a, const Quaternion &b, scalar_t t)
   53.81 +{
   53.82 +	return slerp(a, b, t);
   53.83 +}
   53.84 +#endif	/* __cplusplus */
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/vmath/quat_c.c	Sun Nov 09 13:03:36 2014 +0200
    54.3 @@ -0,0 +1,89 @@
    54.4 +/*
    54.5 +libvmath - a vector math library
    54.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    54.7 +
    54.8 +This program is free software: you can redistribute it and/or modify
    54.9 +it under the terms of the GNU Lesser General Public License as published
   54.10 +by the Free Software Foundation, either version 3 of the License, or
   54.11 +(at your option) any later version.
   54.12 +
   54.13 +This program is distributed in the hope that it will be useful,
   54.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   54.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   54.16 +GNU Lesser General Public License for more details.
   54.17 +
   54.18 +You should have received a copy of the GNU Lesser General Public License
   54.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   54.20 +*/
   54.21 +
   54.22 +
   54.23 +#include <stdio.h>
   54.24 +#include <math.h>
   54.25 +#include "quat.h"
   54.26 +
   54.27 +void quat_print(FILE *fp, quat_t q)
   54.28 +{
   54.29 +	fprintf(fp, "([ %.4f %.4f %.4f ] %.4f)", q.x, q.y, q.z, q.w);
   54.30 +}
   54.31 +
   54.32 +quat_t quat_rotate(quat_t q, scalar_t angle, scalar_t x, scalar_t y, scalar_t z)
   54.33 +{
   54.34 +	quat_t rq;
   54.35 +	scalar_t half_angle = angle * 0.5;
   54.36 +	scalar_t sin_half = sin(half_angle);
   54.37 +
   54.38 +	rq.w = cos(half_angle);
   54.39 +	rq.x = x * sin_half;
   54.40 +	rq.y = y * sin_half;
   54.41 +	rq.z = z * sin_half;
   54.42 +
   54.43 +	return quat_mul(q, rq);
   54.44 +}
   54.45 +
   54.46 +quat_t quat_rotate_quat(quat_t q, quat_t rotq)
   54.47 +{
   54.48 +	return quat_mul(quat_mul(rotq, q), quat_conjugate(rotq));
   54.49 +}
   54.50 +
   54.51 +quat_t quat_slerp(quat_t q1, quat_t q2, scalar_t t)
   54.52 +{
   54.53 +	quat_t res;
   54.54 +	scalar_t a, b, angle, sin_angle, dot;
   54.55 +
   54.56 +	dot = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
   54.57 +	if(dot < 0.0) {
   54.58 +		/* make sure we interpolate across the shortest arc */
   54.59 +		q1.x = -q1.x;
   54.60 +		q1.y = -q1.y;
   54.61 +		q1.z = -q1.z;
   54.62 +		q1.w = -q1.w;
   54.63 +		dot = -dot;
   54.64 +	}
   54.65 +
   54.66 +	/* clamp dot to [-1, 1] in order to avoid domain errors in acos due to
   54.67 +	 * floating point imprecisions
   54.68 +	 */
   54.69 +	if(dot < -1.0) dot = -1.0;
   54.70 +	if(dot > 1.0) dot = 1.0;
   54.71 +
   54.72 +	angle = acos(dot);
   54.73 +	sin_angle = sin(angle);
   54.74 +
   54.75 +	if(fabs(sin_angle) < SMALL_NUMBER) {
   54.76 +		/* for very small angles or completely opposite orientations
   54.77 +		 * use linear interpolation to avoid div/zero (in the first case it makes sense,
   54.78 +		 * the second case is pretty much undefined anyway I guess ...
   54.79 +		 */
   54.80 +		a = 1.0f - t;
   54.81 +		b = t;
   54.82 +	} else {
   54.83 +		a = sin((1.0f - t) * angle) / sin_angle;
   54.84 +		b = sin(t * angle) / sin_angle;
   54.85 +	}
   54.86 +
   54.87 +	res.x = q1.x * a + q2.x * b;
   54.88 +	res.y = q1.y * a + q2.y * b;
   54.89 +	res.z = q1.z * a + q2.z * b;
   54.90 +	res.w = q1.w * a + q2.w * b;
   54.91 +	return res;
   54.92 +}
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/vmath/ray.cc	Sun Nov 09 13:03:36 2014 +0200
    55.3 @@ -0,0 +1,39 @@
    55.4 +#include "ray.h"
    55.5 +#include "vector.h"
    55.6 +
    55.7 +scalar_t Ray::env_ior = 1.0;
    55.8 +
    55.9 +Ray::Ray()
   55.10 +{
   55.11 +	ior = env_ior;
   55.12 +	energy = 1.0;
   55.13 +	time = 0;
   55.14 +	iter = 0;
   55.15 +}
   55.16 +
   55.17 +Ray::Ray(const Vector3 &origin, const Vector3 &dir)
   55.18 +{
   55.19 +	this->origin = origin;
   55.20 +	this->dir = dir;
   55.21 +	ior = env_ior;
   55.22 +	energy = 1.0;
   55.23 +	time = 0;
   55.24 +	iter = 0;
   55.25 +}
   55.26 +
   55.27 +void Ray::transform(const Matrix4x4 &xform)
   55.28 +{
   55.29 +	Matrix4x4 upper = xform;
   55.30 +	upper[0][3] = upper[1][3] = upper[2][3] = upper[3][0] = upper[3][1] = upper[3][2] = 0.0;
   55.31 +	upper[3][3] = 1.0;
   55.32 +
   55.33 +	dir.transform(upper);
   55.34 +	origin.transform(xform);
   55.35 +}
   55.36 +
   55.37 +Ray Ray::transformed(const Matrix4x4 &xform) const
   55.38 +{
   55.39 +	Ray foo = *this;
   55.40 +	foo.transform(xform);
   55.41 +	return foo;
   55.42 +}
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/vmath/ray.h	Sun Nov 09 13:03:36 2014 +0200
    56.3 @@ -0,0 +1,66 @@
    56.4 +/*
    56.5 +libvmath - a vector math library
    56.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    56.7 +
    56.8 +This program is free software: you can redistribute it and/or modify
    56.9 +it under the terms of the GNU Lesser General Public License as published
   56.10 +by the Free Software Foundation, either version 3 of the License, or
   56.11 +(at your option) any later version.
   56.12 +
   56.13 +This program is distributed in the hope that it will be useful,
   56.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   56.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   56.16 +GNU Lesser General Public License for more details.
   56.17 +
   56.18 +You should have received a copy of the GNU Lesser General Public License
   56.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   56.20 +*/
   56.21 +
   56.22 +#ifndef VMATH_RAY_H_
   56.23 +#define VMATH_RAY_H_
   56.24 +
   56.25 +#include "matrix.h"
   56.26 +#include "vector.h"
   56.27 +
   56.28 +typedef struct {
   56.29 +	vec3_t origin, dir;
   56.30 +} ray_t;
   56.31 +
   56.32 +#ifdef __cplusplus
   56.33 +extern "C" {
   56.34 +#endif	/* __cplusplus */
   56.35 +
   56.36 +static inline ray_t ray_cons(vec3_t origin, vec3_t dir);
   56.37 +ray_t ray_transform(ray_t r, mat4_t m);
   56.38 +
   56.39 +#ifdef __cplusplus
   56.40 +}	/* __cplusplus */
   56.41 +
   56.42 +#include <stack>
   56.43 +
   56.44 +class Ray {
   56.45 +public:
   56.46 +	static scalar_t env_ior;
   56.47 +
   56.48 +	Vector3 origin, dir;
   56.49 +	scalar_t energy;
   56.50 +	int iter;
   56.51 +	scalar_t ior;
   56.52 +	long time;
   56.53 +
   56.54 +	void *user;	/* store any random crap with the ray */
   56.55 +
   56.56 +	Ray();
   56.57 +	Ray(const Vector3 &origin, const Vector3 &dir);
   56.58 +
   56.59 +	void transform(const Matrix4x4 &xform);
   56.60 +	Ray transformed(const Matrix4x4 &xform) const;
   56.61 +};
   56.62 +
   56.63 +inline Ray reflect_ray(const Ray &inray, const Vector3 &norm);
   56.64 +inline Ray refract_ray(const Ray &inray, const Vector3 &norm, scalar_t from_ior, scalar_t to_ior);
   56.65 +#endif	/* __cplusplus */
   56.66 +
   56.67 +#include "ray.inl"
   56.68 +
   56.69 +#endif	/* VMATH_RAY_H_ */
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/vmath/ray.inl	Sun Nov 09 13:03:36 2014 +0200
    57.3 @@ -0,0 +1,52 @@
    57.4 +/*
    57.5 +libvmath - a vector math library
    57.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    57.7 +
    57.8 +This program is free software: you can redistribute it and/or modify
    57.9 +it under the terms of the GNU Lesser General Public License as published
   57.10 +by the Free Software Foundation, either version 3 of the License, or
   57.11 +(at your option) any later version.
   57.12 +
   57.13 +This program is distributed in the hope that it will be useful,
   57.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   57.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   57.16 +GNU Lesser General Public License for more details.
   57.17 +
   57.18 +You should have received a copy of the GNU Lesser General Public License
   57.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   57.20 +*/
   57.21 +
   57.22 +#ifdef __cplusplus
   57.23 +extern "C" {
   57.24 +#endif	/* __cplusplus */
   57.25 +
   57.26 +static inline ray_t ray_cons(vec3_t origin, vec3_t dir)
   57.27 +{
   57.28 +	ray_t r;
   57.29 +	r.origin = origin;
   57.30 +	r.dir = dir;
   57.31 +	return r;
   57.32 +}
   57.33 +
   57.34 +#ifdef __cplusplus
   57.35 +}
   57.36 +
   57.37 +inline Ray reflect_ray(const Ray &inray, const Vector3 &norm)
   57.38 +{
   57.39 +	Ray ray = inray;
   57.40 +	ray.dir = ray.dir.reflection(norm);
   57.41 +	return ray;
   57.42 +}
   57.43 +
   57.44 +inline Ray refract_ray(const Ray &inray, const Vector3 &norm, scalar_t from_ior, scalar_t to_ior)
   57.45 +{
   57.46 +	Ray ray = inray;
   57.47 +	ray.dir = ray.dir.refraction(norm, from_ior, to_ior);
   57.48 +
   57.49 +	/* check TIR */
   57.50 +	if(dot_product(ray.dir, norm) > 0.0) {
   57.51 +		return reflect_ray(inray, norm);
   57.52 +	}
   57.53 +	return ray;
   57.54 +}
   57.55 +#endif	/* __cplusplus */
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/vmath/ray_c.c	Sun Nov 09 13:03:36 2014 +0200
    58.3 @@ -0,0 +1,36 @@
    58.4 +/*
    58.5 +libvmath - a vector math library
    58.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    58.7 +
    58.8 +This program is free software: you can redistribute it and/or modify
    58.9 +it under the terms of the GNU Lesser General Public License as published
   58.10 +by the Free Software Foundation, either version 3 of the License, or
   58.11 +(at your option) any later version.
   58.12 +
   58.13 +This program is distributed in the hope that it will be useful,
   58.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   58.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   58.16 +GNU Lesser General Public License for more details.
   58.17 +
   58.18 +You should have received a copy of the GNU Lesser General Public License
   58.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   58.20 +*/
   58.21 +
   58.22 +#include "ray.h"
   58.23 +#include "vector.h"
   58.24 +
   58.25 +ray_t ray_transform(ray_t r, mat4_t xform)
   58.26 +{
   58.27 +	mat4_t upper;
   58.28 +	vec3_t dir;
   58.29 +
   58.30 +	m4_copy(upper, xform);
   58.31 +	upper[0][3] = upper[1][3] = upper[2][3] = upper[3][0] = upper[3][1] = upper[3][2] = 0.0;
   58.32 +	upper[3][3] = 1.0;
   58.33 +
   58.34 +	dir = v3_sub(r.dir, r.origin);
   58.35 +	dir = v3_transform(dir, upper);
   58.36 +	r.origin = v3_transform(r.origin, xform);
   58.37 +	r.dir = v3_add(dir, r.origin);
   58.38 +	return r;
   58.39 +}
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/vmath/vector.cc	Sun Nov 09 13:03:36 2014 +0200
    59.3 @@ -0,0 +1,313 @@
    59.4 +#include "vector.h"
    59.5 +#include "vmath.h"
    59.6 +
    59.7 +// ---------- Vector2 -----------
    59.8 +
    59.9 +Vector2::Vector2(scalar_t x, scalar_t y)
   59.10 +{
   59.11 +	this->x = x;
   59.12 +	this->y = y;
   59.13 +}
   59.14 +
   59.15 +Vector2::Vector2(const vec2_t &vec)
   59.16 +{
   59.17 +	x = vec.x;
   59.18 +	y = vec.y;
   59.19 +}
   59.20 +
   59.21 +Vector2::Vector2(const Vector3 &vec)
   59.22 +{
   59.23 +	x = vec.x;
   59.24 +	y = vec.y;
   59.25 +}
   59.26 +
   59.27 +Vector2::Vector2(const Vector4 &vec)
   59.28 +{
   59.29 +	x = vec.x;
   59.30 +	y = vec.y;
   59.31 +}
   59.32 +
   59.33 +void Vector2::normalize()
   59.34 +{
   59.35 +	scalar_t len = length();
   59.36 +	x /= len;
   59.37 +	y /= len;
   59.38 +}
   59.39 +
   59.40 +Vector2 Vector2::normalized() const
   59.41 +{
   59.42 +	scalar_t len = length();
   59.43 +	return Vector2(x / len, y / len);
   59.44 +}
   59.45 +
   59.46 +void Vector2::transform(const Matrix3x3 &mat)
   59.47 +{
   59.48 +	scalar_t nx = mat[0][0] * x + mat[0][1] * y + mat[0][2];
   59.49 +	y = mat[1][0] * x + mat[1][1] * y + mat[1][2];
   59.50 +	x = nx;
   59.51 +}
   59.52 +
   59.53 +Vector2 Vector2::transformed(const Matrix3x3 &mat) const
   59.54 +{
   59.55 +	Vector2 vec;
   59.56 +	vec.x = mat[0][0] * x + mat[0][1] * y + mat[0][2];
   59.57 +	vec.y = mat[1][0] * x + mat[1][1] * y + mat[1][2];
   59.58 +	return vec;
   59.59 +}
   59.60 +
   59.61 +void Vector2::rotate(scalar_t angle)
   59.62 +{
   59.63 +	*this = Vector2(cos(angle) * x - sin(angle) * y, sin(angle) * x + cos(angle) * y);
   59.64 +}
   59.65 +
   59.66 +Vector2 Vector2::rotated(scalar_t angle) const
   59.67 +{
   59.68 +	return Vector2(cos(angle) * x - sin(angle) * y, sin(angle) * x + cos(angle) * y);
   59.69 +}
   59.70 +
   59.71 +Vector2 Vector2::reflection(const Vector2 &normal) const
   59.72 +{
   59.73 +	return 2.0 * dot_product(*this, normal) * normal - *this;
   59.74 +}
   59.75 +
   59.76 +Vector2 Vector2::refraction(const Vector2 &normal, scalar_t src_ior, scalar_t dst_ior) const
   59.77 +{
   59.78 +	// quick and dirty implementation :)
   59.79 +	Vector3 v3refr = Vector3(this->x, this->y, 1.0).refraction(Vector3(this->x, this->y, 1), src_ior, dst_ior);
   59.80 +	return Vector2(v3refr.x, v3refr.y);
   59.81 +}
   59.82 +
   59.83 +std::ostream &operator <<(std::ostream &out, const Vector2 &vec)
   59.84 +{
   59.85 +	out << "[" << vec.x << " " << vec.y << "]";
   59.86 +	return out;
   59.87 +}
   59.88 +
   59.89 +
   59.90 +
   59.91 +// --------- Vector3 ----------
   59.92 +
   59.93 +Vector3::Vector3(scalar_t x, scalar_t y, scalar_t z)
   59.94 +{
   59.95 +	this->x = x;
   59.96 +	this->y = y;
   59.97 +	this->z = z;
   59.98 +}
   59.99 +
  59.100 +Vector3::Vector3(const vec3_t &vec)
  59.101 +{
  59.102 +	x = vec.x;
  59.103 +	y = vec.y;
  59.104 +	z = vec.z;
  59.105 +}
  59.106 +
  59.107 +Vector3::Vector3(const Vector2 &vec)
  59.108 +{
  59.109 +	x = vec.x;
  59.110 +	y = vec.y;
  59.111 +	z = 1;
  59.112 +}
  59.113 +
  59.114 +Vector3::Vector3(const Vector4 &vec)
  59.115 +{
  59.116 +	x = vec.x;
  59.117 +	y = vec.y;
  59.118 +	z = vec.z;
  59.119 +}
  59.120 +
  59.121 +void Vector3::normalize()
  59.122 +{
  59.123 +	scalar_t len = length();
  59.124 +	x /= len;
  59.125 +	y /= len;
  59.126 +	z /= len;
  59.127 +}
  59.128 +
  59.129 +Vector3 Vector3::normalized() const
  59.130 +{
  59.131 +	scalar_t len = length();
  59.132 +	return Vector3(x / len, y / len, z / len);
  59.133 +}
  59.134 +
  59.135 +Vector3 Vector3::reflection(const Vector3 &normal) const
  59.136 +{
  59.137 +	return 2.0 * dot_product(*this, normal) * normal - *this;
  59.138 +}
  59.139 +
  59.140 +Vector3 Vector3::refraction(const Vector3 &normal, scalar_t src_ior, scalar_t dst_ior) const
  59.141 +{
  59.142 +	return refraction(normal, src_ior / dst_ior);
  59.143 +}
  59.144 +
  59.145 +Vector3 Vector3::refraction(const Vector3 &normal, scalar_t ior) const
  59.146 +{
  59.147 +	scalar_t cos_inc = dot_product(*this, -normal);
  59.148 +
  59.149 +	scalar_t radical = 1.0 + SQ(ior) * (SQ(cos_inc) - 1.0);
  59.150 +
  59.151 +	if(radical < 0.0) {		// total internal reflection
  59.152 +		return -reflection(normal);
  59.153 +	}
  59.154 +
  59.155 +	scalar_t beta = ior * cos_inc - sqrt(radical);
  59.156 +
  59.157 +	return *this * ior + normal * beta;
  59.158 +}
  59.159 +
  59.160 +void Vector3::transform(const Matrix3x3 &mat)
  59.161 +{
  59.162 +	scalar_t nx = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z;
  59.163 +	scalar_t ny = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z;
  59.164 +	z = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z;
  59.165 +	x = nx;
  59.166 +	y = ny;
  59.167 +}
  59.168 +
  59.169 +Vector3 Vector3::transformed(const Matrix3x3 &mat) const
  59.170 +{
  59.171 +	Vector3 vec;
  59.172 +	vec.x = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z;
  59.173 +	vec.y = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z;
  59.174 +	vec.z = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z;
  59.175 +	return vec;
  59.176 +}
  59.177 +
  59.178 +void Vector3::transform(const Matrix4x4 &mat)
  59.179 +{
  59.180 +	scalar_t nx = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z + mat[0][3];
  59.181 +	scalar_t ny = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z + mat[1][3];
  59.182 +	z = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z + mat[2][3];
  59.183 +	x = nx;
  59.184 +	y = ny;
  59.185 +}
  59.186 +
  59.187 +Vector3 Vector3::transformed(const Matrix4x4 &mat) const
  59.188 +{
  59.189 +	Vector3 vec;
  59.190 +	vec.x = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z + mat[0][3];
  59.191 +	vec.y = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z + mat[1][3];
  59.192 +	vec.z = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z + mat[2][3];
  59.193 +	return vec;
  59.194 +}
  59.195 +
  59.196 +void Vector3::transform(const Quaternion &quat)
  59.197 +{
  59.198 +	Quaternion vq(0.0f, *this);
  59.199 +	vq = quat * vq * quat.inverse();
  59.200 +	*this = vq.v;
  59.201 +}
  59.202 +
  59.203 +Vector3 Vector3::transformed(const Quaternion &quat) const
  59.204 +{
  59.205 +	Quaternion vq(0.0f, *this);
  59.206 +	vq = quat * vq * quat.inverse();
  59.207 +	return vq.v;
  59.208 +}
  59.209 +
  59.210 +void Vector3::rotate(const Vector3 &euler)
  59.211 +{
  59.212 +	Matrix4x4 rot;
  59.213 +	rot.set_rotation(euler);
  59.214 +	transform(rot);
  59.215 +}
  59.216 +
  59.217 +Vector3 Vector3::rotated(const Vector3 &euler) const
  59.218 +{
  59.219 +	Matrix4x4 rot;
  59.220 +	rot.set_rotation(euler);
  59.221 +	return transformed(rot);
  59.222 +}
  59.223 +
  59.224 +std::ostream &operator <<(std::ostream &out, const Vector3 &vec)
  59.225 +{
  59.226 +	out << "[" << vec.x << " " << vec.y << " " << vec.z << "]";
  59.227 +	return out;
  59.228 +}
  59.229 +
  59.230 +
  59.231 +// -------------- Vector4 --------------
  59.232 +Vector4::Vector4(scalar_t x, scalar_t y, scalar_t z, scalar_t w)
  59.233 +{
  59.234 +	this->x = x;
  59.235 +	this->y = y;
  59.236 +	this->z = z;
  59.237 +	this->w = w;
  59.238 +}
  59.239 +
  59.240 +Vector4::Vector4(const vec4_t &vec)
  59.241 +{
  59.242 +	x = vec.x;
  59.243 +	y = vec.y;
  59.244 +	z = vec.z;
  59.245 +	w = vec.w;
  59.246 +}
  59.247 +
  59.248 +Vector4::Vector4(const Vector2 &vec)
  59.249 +{
  59.250 +	x = vec.x;
  59.251 +	y = vec.y;
  59.252 +	z = 1;
  59.253 +	w = 1;
  59.254 +}
  59.255 +
  59.256 +Vector4::Vector4(const Vector3 &vec)
  59.257 +{
  59.258 +	x = vec.x;
  59.259 +	y = vec.y;
  59.260 +	z = vec.z;
  59.261 +	w = 1;
  59.262 +}
  59.263 +
  59.264 +void Vector4::normalize()
  59.265 +{
  59.266 +	scalar_t len = (scalar_t)sqrt(x*x + y*y + z*z + w*w);
  59.267 +	x /= len;
  59.268 +	y /= len;
  59.269 +	z /= len;
  59.270 +	w /= len;
  59.271 +}
  59.272 +
  59.273 +Vector4 Vector4::normalized() const
  59.274 +{
  59.275 +	scalar_t len = (scalar_t)sqrt(x*x + y*y + z*z + w*w);
  59.276 +	return Vector4(x / len, y / len, z / len, w / len);
  59.277 +}
  59.278 +
  59.279 +void Vector4::transform(const Matrix4x4 &mat)
  59.280 +{
  59.281 +	scalar_t nx = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z + mat[0][3] * w;
  59.282 +	scalar_t ny = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z + mat[1][3] * w;
  59.283 +	scalar_t nz = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z + mat[2][3] * w;
  59.284 +	w = mat[3][0] * x + mat[3][1] * y + mat[3][2] * z + mat[3][3] * w;
  59.285 +	x = nx;
  59.286 +	y = ny;
  59.287 +	z = nz;
  59.288 +}
  59.289 +
  59.290 +Vector4 Vector4::transformed(const Matrix4x4 &mat) const
  59.291 +{
  59.292 +	Vector4 vec;
  59.293 +	vec.x = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z + mat[0][3] * w;
  59.294 +	vec.y = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z + mat[1][3] * w;
  59.295 +	vec.z = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z + mat[2][3] * w;
  59.296 +	vec.w = mat[3][0] * x + mat[3][1] * y + mat[3][2] * z + mat[3][3] * w;
  59.297 +	return vec;
  59.298 +}
  59.299 +
  59.300 +// TODO: implement 4D vector reflection
  59.301 +Vector4 Vector4::reflection(const Vector4 &normal) const
  59.302 +{
  59.303 +	return *this;
  59.304 +}
  59.305 +
  59.306 +// TODO: implement 4D vector refraction
  59.307 +Vector4 Vector4::refraction(const Vector4 &normal, scalar_t src_ior, scalar_t dst_ior) const
  59.308 +{
  59.309 +	return *this;
  59.310 +}
  59.311 +
  59.312 +std::ostream &operator <<(std::ostream &out, const Vector4 &vec)
  59.313 +{
  59.314 +	out << "[" << vec.x << " " << vec.y << " " << vec.z << " " << vec.w << "]";
  59.315 +	return out;
  59.316 +}
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/vmath/vector.h	Sun Nov 09 13:03:36 2014 +0200
    60.3 @@ -0,0 +1,291 @@
    60.4 +/*
    60.5 +libvmath - a vector math library
    60.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    60.7 +
    60.8 +This program is free software: you can redistribute it and/or modify
    60.9 +it under the terms of the GNU Lesser General Public License as published
   60.10 +by the Free Software Foundation, either version 3 of the License, or
   60.11 +(at your option) any later version.
   60.12 +
   60.13 +This program is distributed in the hope that it will be useful,
   60.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   60.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   60.16 +GNU Lesser General Public License for more details.
   60.17 +
   60.18 +You should have received a copy of the GNU Lesser General Public License
   60.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   60.20 +*/
   60.21 +
   60.22 +#ifndef VMATH_VECTOR_H_
   60.23 +#define VMATH_VECTOR_H_
   60.24 +
   60.25 +#include <stdio.h>
   60.26 +#include "vmath_types.h"
   60.27 +
   60.28 +#ifdef __cplusplus
   60.29 +extern "C" {
   60.30 +#endif	/* __cplusplus */
   60.31 +
   60.32 +/* C 2D vector functions */
   60.33 +static inline vec2_t v2_cons(scalar_t x, scalar_t y);
   60.34 +static inline void v2_print(FILE *fp, vec2_t v);
   60.35 +
   60.36 +static inline vec2_t v2_add(vec2_t v1, vec2_t v2);
   60.37 +static inline vec2_t v2_sub(vec2_t v1, vec2_t v2);
   60.38 +static inline vec2_t v2_scale(vec2_t v, scalar_t s);
   60.39 +static inline scalar_t v2_dot(vec2_t v1, vec2_t v2);
   60.40 +static inline scalar_t v2_length(vec2_t v);
   60.41 +static inline scalar_t v2_length_sq(vec2_t v);
   60.42 +static inline vec2_t v2_normalize(vec2_t v);
   60.43 +
   60.44 +static inline vec2_t v2_lerp(vec2_t v1, vec2_t v2, scalar_t t);
   60.45 +
   60.46 +/* C 3D vector functions */
   60.47 +static inline vec3_t v3_cons(scalar_t x, scalar_t y, scalar_t z);
   60.48 +static inline void v3_print(FILE *fp, vec3_t v);
   60.49 +
   60.50 +static inline vec3_t v3_add(vec3_t v1, vec3_t v2);
   60.51 +static inline vec3_t v3_sub(vec3_t v1, vec3_t v2);
   60.52 +static inline vec3_t v3_neg(vec3_t v);
   60.53 +static inline vec3_t v3_mul(vec3_t v1, vec3_t v2);
   60.54 +static inline vec3_t v3_scale(vec3_t v1, scalar_t s);
   60.55 +static inline scalar_t v3_dot(vec3_t v1, vec3_t v2);
   60.56 +static inline vec3_t v3_cross(vec3_t v1, vec3_t v2);
   60.57 +static inline scalar_t v3_length(vec3_t v);
   60.58 +static inline scalar_t v3_length_sq(vec3_t v);
   60.59 +static inline vec3_t v3_normalize(vec3_t v);
   60.60 +static inline vec3_t v3_transform(vec3_t v, mat4_t m);
   60.61 +
   60.62 +static inline vec3_t v3_rotate(vec3_t v, scalar_t x, scalar_t y, scalar_t z);
   60.63 +static inline vec3_t v3_rotate_axis(vec3_t v, scalar_t angle, scalar_t x, scalar_t y, scalar_t z);
   60.64 +static inline vec3_t v3_rotate_quat(vec3_t v, quat_t q);
   60.65 +
   60.66 +static inline vec3_t v3_reflect(vec3_t v, vec3_t n);
   60.67 +
   60.68 +static inline vec3_t v3_lerp(vec3_t v1, vec3_t v2, scalar_t t);
   60.69 +
   60.70 +/* C 4D vector functions */
   60.71 +static inline vec4_t v4_cons(scalar_t x, scalar_t y, scalar_t z, scalar_t w);
   60.72 +static inline void v4_print(FILE *fp, vec4_t v);
   60.73 +
   60.74 +static inline vec4_t v4_add(vec4_t v1, vec4_t v2);
   60.75 +static inline vec4_t v4_sub(vec4_t v1, vec4_t v2);
   60.76 +static inline vec4_t v4_neg(vec4_t v);
   60.77 +static inline vec4_t v4_mul(vec4_t v1, vec4_t v2);
   60.78 +static inline vec4_t v4_scale(vec4_t v, scalar_t s);
   60.79 +static inline scalar_t v4_dot(vec4_t v1, vec4_t v2);
   60.80 +static inline scalar_t v4_length(vec4_t v);
   60.81 +static inline scalar_t v4_length_sq(vec4_t v);
   60.82 +static inline vec4_t v4_normalize(vec4_t v);
   60.83 +static inline vec4_t v4_transform(vec4_t v, mat4_t m);
   60.84 +
   60.85 +#ifdef __cplusplus
   60.86 +}	/* extern "C" */
   60.87 +
   60.88 +/* when included from C++ source files, also define the vector classes */
   60.89 +#include <iostream>
   60.90 +
   60.91 +/** 2D Vector */
   60.92 +class Vector2 {
   60.93 +public:
   60.94 +	scalar_t x, y;
   60.95 +
   60.96 +	Vector2(scalar_t x = 0.0, scalar_t y = 0.0);
   60.97 +	Vector2(const vec2_t &vec);
   60.98 +	Vector2(const Vector3 &vec);
   60.99 +	Vector2(const Vector4 &vec);
  60.100 +
  60.101 +	inline scalar_t &operator [](int elem);
  60.102 +	inline const scalar_t &operator [](int elem) const;
  60.103 +
  60.104 +	inline scalar_t length() const;
  60.105 +	inline scalar_t length_sq() const;
  60.106 +	void normalize();
  60.107 +	Vector2 normalized() const;
  60.108 +
  60.109 +	void transform(const Matrix3x3 &mat);
  60.110 +	Vector2 transformed(const Matrix3x3 &mat) const;
  60.111 +
  60.112 +	void rotate(scalar_t angle);
  60.113 +	Vector2 rotated(scalar_t angle) const;
  60.114 +
  60.115 +	Vector2 reflection(const Vector2 &normal) const;
  60.116 +	Vector2 refraction(const Vector2 &normal, scalar_t src_ior, scalar_t dst_ior) const;
  60.117 +};
  60.118 +
  60.119 +/* unary operations */
  60.120 +inline Vector2 operator -(const Vector2 &vec);
  60.121 +
  60.122 +/* binary vector (op) vector operations */
  60.123 +inline scalar_t dot_product(const Vector2 &v1, const Vector2 &v2);
  60.124 +
  60.125 +inline Vector2 operator +(const Vector2 &v1, const Vector2 &v2);
  60.126 +inline Vector2 operator -(const Vector2 &v1, const Vector2 &v2);
  60.127 +inline Vector2 operator *(const Vector2 &v1, const Vector2 &v2);
  60.128 +inline Vector2 operator /(const Vector2 &v1, const Vector2 &v2);
  60.129 +inline bool operator ==(const Vector2 &v1, const Vector2 &v2);
  60.130 +
  60.131 +inline void operator +=(Vector2 &v1, const Vector2 &v2);
  60.132 +inline void operator -=(Vector2 &v1, const Vector2 &v2);
  60.133 +inline void operator *=(Vector2 &v1, const Vector2 &v2);
  60.134 +inline void operator /=(Vector2 &v1, const Vector2 &v2);
  60.135 +
  60.136 +/* binary vector (op) scalar and scalar (op) vector operations */
  60.137 +inline Vector2 operator +(const Vector2 &vec, scalar_t scalar);
  60.138 +inline Vector2 operator +(scalar_t scalar, const Vector2 &vec);
  60.139 +inline Vector2 operator -(const Vector2 &vec, scalar_t scalar);
  60.140 +inline Vector2 operator *(const Vector2 &vec, scalar_t scalar);
  60.141 +inline Vector2 operator *(scalar_t scalar, const Vector2 &vec);
  60.142 +inline Vector2 operator /(const Vector2 &vec, scalar_t scalar);
  60.143 +
  60.144 +inline void operator +=(Vector2 &vec, scalar_t scalar);
  60.145 +inline void operator -=(Vector2 &vec, scalar_t scalar);
  60.146 +inline void operator *=(Vector2 &vec, scalar_t scalar);
  60.147 +inline void operator /=(Vector2 &vec, scalar_t scalar);
  60.148 +
  60.149 +std::ostream &operator <<(std::ostream &out, const Vector2 &vec);
  60.150 +
  60.151 +inline Vector2 lerp(const Vector2 &a, const Vector2 &b, scalar_t t);
  60.152 +inline Vector2 catmull_rom_spline(const Vector2 &v0, const Vector2 &v1,
  60.153 +		const Vector2 &v2, const Vector2 &v3, scalar_t t);
  60.154 +
  60.155 +/* 3D Vector */
  60.156 +class Vector3 {
  60.157 +public:
  60.158 +	scalar_t x, y, z;
  60.159 +
  60.160 +	Vector3(scalar_t x = 0.0, scalar_t y = 0.0, scalar_t z = 0.0);
  60.161 +	Vector3(const vec3_t &vec);
  60.162 +	Vector3(const Vector2 &vec);
  60.163 +	Vector3(const Vector4 &vec);
  60.164 +
  60.165 +	inline scalar_t &operator [](int elem);
  60.166 +	inline const scalar_t &operator [](int elem) const;
  60.167 +
  60.168 +	inline scalar_t length() const;
  60.169 +	inline scalar_t length_sq() const;
  60.170 +	void normalize();
  60.171 +	Vector3 normalized() const;
  60.172 +
  60.173 +	void transform(const Matrix3x3 &mat);
  60.174 +	Vector3 transformed(const Matrix3x3 &mat) const;
  60.175 +	void transform(const Matrix4x4 &mat);
  60.176 +	Vector3 transformed(const Matrix4x4 &mat) const;
  60.177 +	void transform(const Quaternion &quat);
  60.178 +	Vector3 transformed(const Quaternion &quat) const;
  60.179 +
  60.180 +	void rotate(const Vector3 &euler);
  60.181 +	Vector3 rotated(const Vector3 &euler) const;
  60.182 +
  60.183 +	Vector3 reflection(const Vector3 &normal) const;
  60.184 +	Vector3 refraction(const Vector3 &normal, scalar_t src_ior, scalar_t dst_ior) const;
  60.185 +	Vector3 refraction(const Vector3 &normal, scalar_t ior) const;
  60.186 +};
  60.187 +
  60.188 +/* unary operations */
  60.189 +inline Vector3 operator -(const Vector3 &vec);
  60.190 +
  60.191 +/* binary vector (op) vector operations */
  60.192 +inline scalar_t dot_product(const Vector3 &v1, const Vector3 &v2);
  60.193 +inline Vector3 cross_product(const Vector3 &v1, const Vector3 &v2);
  60.194 +
  60.195 +inline Vector3 operator +(const Vector3 &v1, const Vector3 &v2);
  60.196 +inline Vector3 operator -(const Vector3 &v1, const Vector3 &v2);
  60.197 +inline Vector3 operator *(const Vector3 &v1, const Vector3 &v2);
  60.198 +inline Vector3 operator /(const Vector3 &v1, const Vector3 &v2);
  60.199 +inline bool operator ==(const Vector3 &v1, const Vector3 &v2);
  60.200 +
  60.201 +inline void operator +=(Vector3 &v1, const Vector3 &v2);
  60.202 +inline void operator -=(Vector3 &v1, const Vector3 &v2);
  60.203 +inline void operator *=(Vector3 &v1, const Vector3 &v2);
  60.204 +inline void operator /=(Vector3 &v1, const Vector3 &v2);
  60.205 +
  60.206 +/* binary vector (op) scalar and scalar (op) vector operations */
  60.207 +inline Vector3 operator +(const Vector3 &vec, scalar_t scalar);
  60.208 +inline Vector3 operator +(scalar_t scalar, const Vector3 &vec);
  60.209 +inline Vector3 operator -(const Vector3 &vec, scalar_t scalar);
  60.210 +inline Vector3 operator *(const Vector3 &vec, scalar_t scalar);
  60.211 +inline Vector3 operator *(scalar_t scalar, const Vector3 &vec);
  60.212 +inline Vector3 operator /(const Vector3 &vec, scalar_t scalar);
  60.213 +
  60.214 +inline void operator +=(Vector3 &vec, scalar_t scalar);
  60.215 +inline void operator -=(Vector3 &vec, scalar_t scalar);
  60.216 +inline void operator *=(Vector3 &vec, scalar_t scalar);
  60.217 +inline void operator /=(Vector3 &vec, scalar_t scalar);
  60.218 +
  60.219 +std::ostream &operator <<(std::ostream &out, const Vector3 &vec);
  60.220 +
  60.221 +inline Vector3 lerp(const Vector3 &a, const Vector3 &b, scalar_t t);
  60.222 +inline Vector3 catmull_rom_spline(const Vector3 &v0, const Vector3 &v1,
  60.223 +		const Vector3 &v2, const Vector3 &v3, scalar_t t);
  60.224 +
  60.225 +inline Vector3 faceforward(const Vector3 &v, const Vector3 &ref);
  60.226 +
  60.227 +/* 4D Vector */
  60.228 +class Vector4 {
  60.229 +public:
  60.230 +	scalar_t x, y, z, w;
  60.231 +
  60.232 +	Vector4(scalar_t x = 0.0, scalar_t y = 0.0, scalar_t z = 0.0, scalar_t w = 0.0);
  60.233 +	Vector4(const vec4_t &vec);
  60.234 +	Vector4(const Vector2 &vec);
  60.235 +	Vector4(const Vector3 &vec);
  60.236 +
  60.237 +	inline scalar_t &operator [](int elem);
  60.238 +	inline const scalar_t &operator [](int elem) const;
  60.239 +
  60.240 +	inline scalar_t length() const;
  60.241 +	inline scalar_t length_sq() const;
  60.242 +	void normalize();
  60.243 +	Vector4 normalized() const;
  60.244 +
  60.245 +	void transform(const Matrix4x4 &mat);
  60.246 +	Vector4 transformed(const Matrix4x4 &mat) const;
  60.247 +
  60.248 +	Vector4 reflection(const Vector4 &normal) const;
  60.249 +	Vector4 refraction(const Vector4 &normal, scalar_t src_ior, scalar_t dst_ior) const;
  60.250 +};
  60.251 +
  60.252 +
  60.253 +/* unary operations */
  60.254 +inline Vector4 operator -(const Vector4 &vec);
  60.255 +
  60.256 +/* binary vector (op) vector operations */
  60.257 +inline scalar_t dot_product(const Vector4 &v1, const Vector4 &v2);
  60.258 +inline Vector4 cross_product(const Vector4 &v1, const Vector4 &v2, const Vector4 &v3);
  60.259 +
  60.260 +inline Vector4 operator +(const Vector4 &v1, const Vector4 &v2);
  60.261 +inline Vector4 operator -(const Vector4 &v1, const Vector4 &v2);
  60.262 +inline Vector4 operator *(const Vector4 &v1, const Vector4 &v2);
  60.263 +inline Vector4 operator /(const Vector4 &v1, const Vector4 &v2);
  60.264 +inline bool operator ==(const Vector4 &v1, const Vector4 &v2);
  60.265 +
  60.266 +inline void operator +=(Vector4 &v1, const Vector4 &v2);
  60.267 +inline void operator -=(Vector4 &v1, const Vector4 &v2);
  60.268 +inline void operator *=(Vector4 &v1, const Vector4 &v2);
  60.269 +inline void operator /=(Vector4 &v1, const Vector4 &v2);
  60.270 +
  60.271 +/* binary vector (op) scalar and scalar (op) vector operations */
  60.272 +inline Vector4 operator +(const Vector4 &vec, scalar_t scalar);
  60.273 +inline Vector4 operator +(scalar_t scalar, const Vector4 &vec);
  60.274 +inline Vector4 operator -(const Vector4 &vec, scalar_t scalar);
  60.275 +inline Vector4 operator *(const Vector4 &vec, scalar_t scalar);
  60.276 +inline Vector4 operator *(scalar_t scalar, const Vector4 &vec);
  60.277 +inline Vector4 operator /(const Vector4 &vec, scalar_t scalar);
  60.278 +
  60.279 +inline void operator +=(Vector4 &vec, scalar_t scalar);
  60.280 +inline void operator -=(Vector4 &vec, scalar_t scalar);
  60.281 +inline void operator *=(Vector4 &vec, scalar_t scalar);
  60.282 +inline void operator /=(Vector4 &vec, scalar_t scalar);
  60.283 +
  60.284 +std::ostream &operator <<(std::ostream &out, const Vector4 &vec);
  60.285 +
  60.286 +inline Vector4 lerp(const Vector4 &v0, const Vector4 &v1, scalar_t t);
  60.287 +inline Vector4 catmull_rom_spline(const Vector4 &v0, const Vector4 &v1,
  60.288 +		const Vector4 &v2, const Vector4 &v3, scalar_t t);
  60.289 +
  60.290 +#endif	/* __cplusplus */
  60.291 +
  60.292 +#include "vector.inl"
  60.293 +
  60.294 +#endif	/* VMATH_VECTOR_H_ */
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/vmath/vector.inl	Sun Nov 09 13:03:36 2014 +0200
    61.3 @@ -0,0 +1,766 @@
    61.4 +/*
    61.5 +libvmath - a vector math library
    61.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    61.7 +
    61.8 +This program is free software: you can redistribute it and/or modify
    61.9 +it under the terms of the GNU Lesser General Public License as published
   61.10 +by the Free Software Foundation, either version 3 of the License, or
   61.11 +(at your option) any later version.
   61.12 +
   61.13 +This program is distributed in the hope that it will be useful,
   61.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   61.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   61.16 +GNU Lesser General Public License for more details.
   61.17 +
   61.18 +You should have received a copy of the GNU Lesser General Public License
   61.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   61.20 +*/
   61.21 +
   61.22 +#include <math.h>
   61.23 +
   61.24 +#ifdef __cplusplus
   61.25 +extern "C" {
   61.26 +#endif	/* __cplusplus */
   61.27 +
   61.28 +/* C 2D vector functions */
   61.29 +static inline vec2_t v2_cons(scalar_t x, scalar_t y)
   61.30 +{
   61.31 +	vec2_t v;
   61.32 +	v.x = x;
   61.33 +	v.y = y;
   61.34 +	return v;
   61.35 +}
   61.36 +
   61.37 +static inline void v2_print(FILE *fp, vec2_t v)
   61.38 +{
   61.39 +	fprintf(fp, "[ %.4f %.4f ]", v.x, v.y);
   61.40 +}
   61.41 +
   61.42 +static inline vec2_t v2_add(vec2_t v1, vec2_t v2)
   61.43 +{
   61.44 +	vec2_t res;
   61.45 +	res.x = v1.x + v2.x;
   61.46 +	res.y = v1.y + v2.y;
   61.47 +	return res;
   61.48 +}
   61.49 +
   61.50 +static inline vec2_t v2_sub(vec2_t v1, vec2_t v2)
   61.51 +{
   61.52 +	vec2_t res;
   61.53 +	res.x = v1.x - v2.x;
   61.54 +	res.y = v1.y - v2.y;
   61.55 +	return res;
   61.56 +}
   61.57 +
   61.58 +static inline vec2_t v2_scale(vec2_t v, scalar_t s)
   61.59 +{
   61.60 +	vec2_t res;
   61.61 +	res.x = v.x * s;
   61.62 +	res.y = v.y * s;
   61.63 +	return res;
   61.64 +}
   61.65 +
   61.66 +static inline scalar_t v2_dot(vec2_t v1, vec2_t v2)
   61.67 +{
   61.68 +	return v1.x * v2.x + v1.y * v2.y;
   61.69 +}
   61.70 +
   61.71 +static inline scalar_t v2_length(vec2_t v)
   61.72 +{
   61.73 +	return sqrt(v.x * v.x + v.y * v.y);
   61.74 +}
   61.75 +
   61.76 +static inline scalar_t v2_length_sq(vec2_t v)
   61.77 +{
   61.78 +	return v.x * v.x + v.y * v.y;
   61.79 +}
   61.80 +
   61.81 +static inline vec2_t v2_normalize(vec2_t v)
   61.82 +{
   61.83 +	scalar_t len = (scalar_t)sqrt(v.x * v.x + v.y * v.y);
   61.84 +	v.x /= len;
   61.85 +	v.y /= len;
   61.86 +	return v;
   61.87 +}
   61.88 +
   61.89 +static inline vec2_t v2_lerp(vec2_t v1, vec2_t v2, scalar_t t)
   61.90 +{
   61.91 +	vec2_t res;
   61.92 +	res.x = v1.x + (v2.x - v1.x) * t;
   61.93 +	res.y = v1.y + (v2.y - v1.y) * t;
   61.94 +	return res;
   61.95 +}
   61.96 +
   61.97 +
   61.98 +/* C 3D vector functions */
   61.99 +static inline vec3_t v3_cons(scalar_t x, scalar_t y, scalar_t z)
  61.100 +{
  61.101 +	vec3_t v;
  61.102 +	v.x = x;
  61.103 +	v.y = y;
  61.104 +	v.z = z;
  61.105 +	return v;
  61.106 +}
  61.107 +
  61.108 +static inline void v3_print(FILE *fp, vec3_t v)
  61.109 +{
  61.110 +	fprintf(fp, "[ %.4f %.4f %.4f ]", v.x, v.y, v.z);
  61.111 +}
  61.112 +
  61.113 +static inline vec3_t v3_add(vec3_t v1, vec3_t v2)
  61.114 +{
  61.115 +	v1.x += v2.x;
  61.116 +	v1.y += v2.y;
  61.117 +	v1.z += v2.z;
  61.118 +	return v1;
  61.119 +}
  61.120 +
  61.121 +static inline vec3_t v3_sub(vec3_t v1, vec3_t v2)
  61.122 +{
  61.123 +	v1.x -= v2.x;
  61.124 +	v1.y -= v2.y;
  61.125 +	v1.z -= v2.z;
  61.126 +	return v1;
  61.127 +}
  61.128 +
  61.129 +static inline vec3_t v3_neg(vec3_t v)
  61.130 +{
  61.131 +	v.x = -v.x;
  61.132 +	v.y = -v.y;
  61.133 +	v.z = -v.z;
  61.134 +	return v;
  61.135 +}
  61.136 +
  61.137 +static inline vec3_t v3_mul(vec3_t v1, vec3_t v2)
  61.138 +{
  61.139 +	v1.x *= v2.x;
  61.140 +	v1.y *= v2.y;
  61.141 +	v1.z *= v2.z;
  61.142 +	return v1;
  61.143 +}
  61.144 +
  61.145 +static inline vec3_t v3_scale(vec3_t v1, scalar_t s)
  61.146 +{
  61.147 +	v1.x *= s;
  61.148 +	v1.y *= s;
  61.149 +	v1.z *= s;
  61.150 +	return v1;
  61.151 +}
  61.152 +
  61.153 +static inline scalar_t v3_dot(vec3_t v1, vec3_t v2)
  61.154 +{
  61.155 +	return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
  61.156 +}
  61.157 +
  61.158 +static inline vec3_t v3_cross(vec3_t v1, vec3_t v2)
  61.159 +{
  61.160 +	vec3_t v;
  61.161 +	v.x = v1.y * v2.z - v1.z * v2.y;
  61.162 +	v.y = v1.z * v2.x - v1.x * v2.z;
  61.163 +	v.z = v1.x * v2.y - v1.y * v2.x;
  61.164 +	return v;
  61.165 +}
  61.166 +
  61.167 +static inline scalar_t v3_length(vec3_t v)
  61.168 +{
  61.169 +	return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
  61.170 +}
  61.171 +
  61.172 +static inline scalar_t v3_length_sq(vec3_t v)
  61.173 +{
  61.174 +	return v.x * v.x + v.y * v.y + v.z * v.z;
  61.175 +}
  61.176 +
  61.177 +static inline vec3_t v3_normalize(vec3_t v)
  61.178 +{
  61.179 +	scalar_t len = sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
  61.180 +	v.x /= len;
  61.181 +	v.y /= len;
  61.182 +	v.z /= len;
  61.183 +	return v;
  61.184 +}
  61.185 +
  61.186 +static inline vec3_t v3_transform(vec3_t v, mat4_t m)
  61.187 +{
  61.188 +	vec3_t res;
  61.189 +	res.x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3];
  61.190 +	res.y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3];
  61.191 +	res.z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3];
  61.192 +	return res;
  61.193 +}
  61.194 +
  61.195 +static inline vec3_t v3_rotate(vec3_t v, scalar_t x, scalar_t y, scalar_t z)
  61.196 +{
  61.197 +	void m4_rotate(mat4_t, scalar_t, scalar_t, scalar_t);
  61.198 +
  61.199 +	mat4_t m = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
  61.200 +	m4_rotate(m, x, y, z);
  61.201 +	return v3_transform(v, m);
  61.202 +}
  61.203 +
  61.204 +static inline vec3_t v3_rotate_axis(vec3_t v, scalar_t angle, scalar_t x, scalar_t y, scalar_t z)
  61.205 +{
  61.206 +	void m4_rotate_axis(mat4_t, scalar_t, scalar_t, scalar_t, scalar_t);
  61.207 +
  61.208 +	mat4_t m = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
  61.209 +	m4_rotate_axis(m, angle, x, y, z);
  61.210 +	return v3_transform(v, m);
  61.211 +}
  61.212 +
  61.213 +static inline vec3_t v3_rotate_quat(vec3_t v, quat_t q)
  61.214 +{
  61.215 +	quat_t quat_rotate_quat(quat_t, quat_t);
  61.216 +
  61.217 +	quat_t vq = v4_cons(v.x, v.y, v.z, 0.0);
  61.218 +	quat_t res = quat_rotate_quat(vq, q);
  61.219 +	return v3_cons(res.x, res.y, res.z);
  61.220 +}
  61.221 +
  61.222 +static inline vec3_t v3_reflect(vec3_t v, vec3_t n)
  61.223 +{
  61.224 +	scalar_t dot = v3_dot(v, n);
  61.225 +	return v3_sub(v3_scale(n, dot * 2.0), v);
  61.226 +}
  61.227 +
  61.228 +static inline vec3_t v3_lerp(vec3_t v1, vec3_t v2, scalar_t t)
  61.229 +{
  61.230 +	v1.x += (v2.x - v1.x) * t;
  61.231 +	v1.y += (v2.y - v1.y) * t;
  61.232 +	v1.z += (v2.z - v1.z) * t;
  61.233 +	return v1;
  61.234 +}
  61.235 +
  61.236 +/* C 4D vector functions */
  61.237 +static inline vec4_t v4_cons(scalar_t x, scalar_t y, scalar_t z, scalar_t w)
  61.238 +{
  61.239 +	vec4_t v;
  61.240 +	v.x = x;
  61.241 +	v.y = y;
  61.242 +	v.z = z;
  61.243 +	v.w = w;
  61.244 +	return v;
  61.245 +}
  61.246 +
  61.247 +static inline void v4_print(FILE *fp, vec4_t v)
  61.248 +{
  61.249 +	fprintf(fp, "[ %.4f %.4f %.4f %.4f ]", v.x, v.y, v.z, v.w);
  61.250 +}
  61.251 +
  61.252 +static inline vec4_t v4_add(vec4_t v1, vec4_t v2)
  61.253 +{
  61.254 +	v1.x += v2.x;
  61.255 +	v1.y += v2.y;
  61.256 +	v1.z += v2.z;
  61.257 +	v1.w += v2.w;
  61.258 +	return v1;
  61.259 +}
  61.260 +
  61.261 +static inline vec4_t v4_sub(vec4_t v1, vec4_t v2)
  61.262 +{
  61.263 +	v1.x -= v2.x;
  61.264 +	v1.y -= v2.y;
  61.265 +	v1.z -= v2.z;
  61.266 +	v1.w -= v2.w;
  61.267 +	return v1;
  61.268 +}
  61.269 +
  61.270 +static inline vec4_t v4_neg(vec4_t v)
  61.271 +{
  61.272 +	v.x = -v.x;
  61.273 +	v.y = -v.y;
  61.274 +	v.z = -v.z;
  61.275 +	v.w = -v.w;
  61.276 +	return v;
  61.277 +}
  61.278 +
  61.279 +static inline vec4_t v4_mul(vec4_t v1, vec4_t v2)
  61.280 +{
  61.281 +	v1.x *= v2.x;
  61.282 +	v1.y *= v2.y;
  61.283 +	v1.z *= v2.z;
  61.284 +	v1.w *= v2.w;
  61.285 +	return v1;
  61.286 +}
  61.287 +
  61.288 +static inline vec4_t v4_scale(vec4_t v, scalar_t s)
  61.289 +{
  61.290 +	v.x *= s;
  61.291 +	v.y *= s;
  61.292 +	v.z *= s;
  61.293 +	v.w *= s;
  61.294 +	return v;
  61.295 +}
  61.296 +
  61.297 +static inline scalar_t v4_dot(vec4_t v1, vec4_t v2)
  61.298 +{
  61.299 +	return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
  61.300 +}
  61.301 +
  61.302 +static inline scalar_t v4_length(vec4_t v)
  61.303 +{
  61.304 +	return sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
  61.305 +}
  61.306 +
  61.307 +static inline scalar_t v4_length_sq(vec4_t v)
  61.308 +{
  61.309 +	return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;
  61.310 +}
  61.311 +
  61.312 +static inline vec4_t v4_normalize(vec4_t v)
  61.313 +{
  61.314 +	scalar_t len = sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
  61.315 +	v.x /= len;
  61.316 +	v.y /= len;
  61.317 +	v.z /= len;
  61.318 +	v.w /= len;
  61.319 +	return v;
  61.320 +}
  61.321 +
  61.322 +static inline vec4_t v4_transform(vec4_t v, mat4_t m)
  61.323 +{
  61.324 +	vec4_t res;
  61.325 +	res.x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w;
  61.326 +	res.y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w;
  61.327 +	res.z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w;
  61.328 +	res.w = m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w;
  61.329 +	return res;
  61.330 +}
  61.331 +
  61.332 +#ifdef __cplusplus
  61.333 +}	/* extern "C" */
  61.334 +
  61.335 +
  61.336 +/* --------------- C++ part -------------- */
  61.337 +
  61.338 +inline scalar_t &Vector2::operator [](int elem) {
  61.339 +	return elem ? y : x;
  61.340 +}
  61.341 +
  61.342 +inline const scalar_t &Vector2::operator [](int elem) const {
  61.343 +	return elem ? y : x;
  61.344 +}
  61.345 +
  61.346 +inline Vector2 operator -(const Vector2 &vec) {
  61.347 +	return Vector2(-vec.x, -vec.y);
  61.348 +}
  61.349 +
  61.350 +inline scalar_t dot_product(const Vector2 &v1, const Vector2 &v2) {
  61.351 +	return v1.x * v2.x + v1.y * v2.y;
  61.352 +}
  61.353 +
  61.354 +inline Vector2 operator +(const Vector2 &v1, const Vector2 &v2) {
  61.355 +	return Vector2(v1.x + v2.x, v1.y + v2.y);
  61.356 +}
  61.357 +
  61.358 +inline Vector2 operator -(const Vector2 &v1, const Vector2 &v2) {
  61.359 +	return Vector2(v1.x - v2.x, v1.y - v2.y);
  61.360 +}
  61.361 +
  61.362 +inline Vector2 operator *(const Vector2 &v1, const Vector2 &v2) {
  61.363 +	return Vector2(v1.x * v2.x, v1.y * v2.y);
  61.364 +}
  61.365 +
  61.366 +inline Vector2 operator /(const Vector2 &v1, const Vector2 &v2) {
  61.367 +	return Vector2(v1.x / v2.x, v1.y / v2.y);
  61.368 +}
  61.369 +
  61.370 +inline bool operator ==(const Vector2 &v1, const Vector2 &v2) {
  61.371 +	return (fabs(v1.x - v2.x) < XSMALL_NUMBER) && (fabs(v1.y - v2.x) < XSMALL_NUMBER);
  61.372 +}
  61.373 +
  61.374 +inline void operator +=(Vector2 &v1, const Vector2 &v2) {
  61.375 +	v1.x += v2.x;
  61.376 +	v1.y += v2.y;
  61.377 +}
  61.378 +
  61.379 +inline void operator -=(Vector2 &v1, const Vector2 &v2) {
  61.380 +	v1.x -= v2.x;
  61.381 +	v1.y -= v2.y;
  61.382 +}
  61.383 +
  61.384 +inline void operator *=(Vector2 &v1, const Vector2 &v2) {
  61.385 +	v1.x *= v2.x;
  61.386 +	v1.y *= v2.y;
  61.387 +}
  61.388 +
  61.389 +inline void operator /=(Vector2 &v1, const Vector2 &v2) {
  61.390 +	v1.x /= v2.x;
  61.391 +	v1.y /= v2.y;
  61.392 +}
  61.393 +
  61.394 +inline Vector2 operator +(const Vector2 &vec, scalar_t scalar) {
  61.395 +	return Vector2(vec.x + scalar, vec.y + scalar);
  61.396 +}
  61.397 +
  61.398 +inline Vector2 operator +(scalar_t scalar, const Vector2 &vec) {
  61.399 +	return Vector2(vec.x + scalar, vec.y + scalar);
  61.400 +}
  61.401 +
  61.402 +inline Vector2 operator -(scalar_t scalar, const Vector2 &vec) {
  61.403 +	return Vector2(vec.x - scalar, vec.y - scalar);
  61.404 +}
  61.405 +
  61.406 +inline Vector2 operator *(const Vector2 &vec, scalar_t scalar) {
  61.407 +	return Vector2(vec.x * scalar, vec.y * scalar);
  61.408 +}
  61.409 +
  61.410 +inline Vector2 operator *(scalar_t scalar, const Vector2 &vec) {
  61.411 +	return Vector2(vec.x * scalar, vec.y * scalar);
  61.412 +}
  61.413 +
  61.414 +inline Vector2 operator /(const Vector2 &vec, scalar_t scalar) {
  61.415 +	return Vector2(vec.x / scalar, vec.y / scalar);
  61.416 +}
  61.417 +
  61.418 +inline void operator +=(Vector2 &vec, scalar_t scalar) {
  61.419 +	vec.x += scalar;
  61.420 +	vec.y += scalar;
  61.421 +}
  61.422 +
  61.423 +inline void operator -=(Vector2 &vec, scalar_t scalar) {
  61.424 +	vec.x -= scalar;
  61.425 +	vec.y -= scalar;
  61.426 +}
  61.427 +
  61.428 +inline void operator *=(Vector2 &vec, scalar_t scalar) {
  61.429 +	vec.x *= scalar;
  61.430 +	vec.y *= scalar;
  61.431 +}
  61.432 +
  61.433 +inline void operator /=(Vector2 &vec, scalar_t scalar) {
  61.434 +	vec.x /= scalar;
  61.435 +	vec.y /= scalar;
  61.436 +}
  61.437 +
  61.438 +inline scalar_t Vector2::length() const {
  61.439 +	return sqrt(x*x + y*y);
  61.440 +}
  61.441 +
  61.442 +inline scalar_t Vector2::length_sq() const {
  61.443 +	return x*x + y*y;
  61.444 +}
  61.445 +
  61.446 +inline Vector2 lerp(const Vector2 &a, const Vector2 &b, scalar_t t)
  61.447 +{
  61.448 +	return a + (b - a) * t;
  61.449 +}
  61.450 +
  61.451 +inline Vector2 catmull_rom_spline(const Vector2 &v0, const Vector2 &v1,
  61.452 +		const Vector2 &v2, const Vector2 &v3, scalar_t t)
  61.453 +{
  61.454 +	scalar_t spline(scalar_t, scalar_t, scalar_t, scalar_t, scalar_t);
  61.455 +	scalar_t x = spline(v0.x, v1.x, v2.x, v3.x, t);
  61.456 +	scalar_t y = spline(v0.y, v1.y, v2.y, v3.y, t);
  61.457 +	return Vector2(x, y);
  61.458 +}
  61.459 +
  61.460 +
  61.461 +/* ------------- Vector3 -------------- */
  61.462 +
  61.463 +inline scalar_t &Vector3::operator [](int elem) {
  61.464 +	return elem ? (elem == 1 ? y : z) : x;
  61.465 +}
  61.466 +
  61.467 +inline const scalar_t &Vector3::operator [](int elem) const {
  61.468 +	return elem ? (elem == 1 ? y : z) : x;
  61.469 +}
  61.470 +
  61.471 +/* unary operations */
  61.472 +inline Vector3 operator -(const Vector3 &vec) {
  61.473 +	return Vector3(-vec.x, -vec.y, -vec.z);
  61.474 +}
  61.475 +
  61.476 +/* binary vector (op) vector operations */
  61.477 +inline scalar_t dot_product(const Vector3 &v1, const Vector3 &v2) {
  61.478 +	return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
  61.479 +}
  61.480 +
  61.481 +inline Vector3 cross_product(const Vector3 &v1, const Vector3 &v2) {
  61.482 +	return Vector3(v1.y * v2.z - v1.z * v2.y,  v1.z * v2.x - v1.x * v2.z,  v1.x * v2.y - v1.y * v2.x);
  61.483 +}
  61.484 +
  61.485 +
  61.486 +inline Vector3 operator +(const Vector3 &v1, const Vector3 &v2) {
  61.487 +	return Vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
  61.488 +}
  61.489 +
  61.490 +inline Vector3 operator -(const Vector3 &v1, const Vector3 &v2) {
  61.491 +	return Vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
  61.492 +}
  61.493 +
  61.494 +inline Vector3 operator *(const Vector3 &v1, const Vector3 &v2) {
  61.495 +	return Vector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
  61.496 +}
  61.497 +
  61.498 +inline Vector3 operator /(const Vector3 &v1, const Vector3 &v2) {
  61.499 +	return Vector3(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z);
  61.500 +}
  61.501 +
  61.502 +inline bool operator ==(const Vector3 &v1, const Vector3 &v2) {
  61.503 +	return (fabs(v1.x - v2.x) < XSMALL_NUMBER) && (fabs(v1.y - v2.y) < XSMALL_NUMBER) && (fabs(v1.z - v2.z) < XSMALL_NUMBER);
  61.504 +}
  61.505 +
  61.506 +inline void operator +=(Vector3 &v1, const Vector3 &v2) {
  61.507 +	v1.x += v2.x;
  61.508 +	v1.y += v2.y;
  61.509 +	v1.z += v2.z;
  61.510 +}
  61.511 +
  61.512 +inline void operator -=(Vector3 &v1, const Vector3 &v2) {
  61.513 +	v1.x -= v2.x;
  61.514 +	v1.y -= v2.y;
  61.515 +	v1.z -= v2.z;
  61.516 +}
  61.517 +
  61.518 +inline void operator *=(Vector3 &v1, const Vector3 &v2) {
  61.519 +	v1.x *= v2.x;
  61.520 +	v1.y *= v2.y;
  61.521 +	v1.z *= v2.z;
  61.522 +}
  61.523 +
  61.524 +inline void operator /=(Vector3 &v1, const Vector3 &v2) {
  61.525 +	v1.x /= v2.x;
  61.526 +	v1.y /= v2.y;
  61.527 +	v1.z /= v2.z;
  61.528 +}
  61.529 +/* binary vector (op) scalar and scalar (op) vector operations */
  61.530 +inline Vector3 operator +(const Vector3 &vec, scalar_t scalar) {
  61.531 +	return Vector3(vec.x + scalar, vec.y + scalar, vec.z + scalar);
  61.532 +}
  61.533 +
  61.534 +inline Vector3 operator +(scalar_t scalar, const Vector3 &vec) {
  61.535 +	return Vector3(vec.x + scalar, vec.y + scalar, vec.z + scalar);
  61.536 +}
  61.537 +
  61.538 +inline Vector3 operator -(const Vector3 &vec, scalar_t scalar) {
  61.539 +	return Vector3(vec.x - scalar, vec.y - scalar, vec.z - scalar);
  61.540 +}
  61.541 +
  61.542 +inline Vector3 operator *(const Vector3 &vec, scalar_t scalar) {
  61.543 +	return Vector3(vec.x * scalar, vec.y * scalar, vec.z * scalar);
  61.544 +}
  61.545 +
  61.546 +inline Vector3 operator *(scalar_t scalar, const Vector3 &vec) {
  61.547 +	return Vector3(vec.x * scalar, vec.y * scalar, vec.z * scalar);
  61.548 +}
  61.549 +
  61.550 +inline Vector3 operator /(const Vector3 &vec, scalar_t scalar) {
  61.551 +	return Vector3(vec.x / scalar, vec.y / scalar, vec.z / scalar);
  61.552 +}
  61.553 +
  61.554 +inline void operator +=(Vector3 &vec, scalar_t scalar) {
  61.555 +	vec.x += scalar;
  61.556 +	vec.y += scalar;
  61.557 +	vec.z += scalar;
  61.558 +}
  61.559 +
  61.560 +inline void operator -=(Vector3 &vec, scalar_t scalar) {
  61.561 +	vec.x -= scalar;
  61.562 +	vec.y -= scalar;
  61.563 +	vec.z -= scalar;
  61.564 +}
  61.565 +
  61.566 +inline void operator *=(Vector3 &vec, scalar_t scalar) {
  61.567 +	vec.x *= scalar;
  61.568 +	vec.y *= scalar;
  61.569 +	vec.z *= scalar;
  61.570 +}
  61.571 +
  61.572 +inline void operator /=(Vector3 &vec, scalar_t scalar) {
  61.573 +	vec.x /= scalar;
  61.574 +	vec.y /= scalar;
  61.575 +	vec.z /= scalar;
  61.576 +}
  61.577 +
  61.578 +inline scalar_t Vector3::length() const {
  61.579 +	return sqrt(x*x + y*y + z*z);
  61.580 +}
  61.581 +inline scalar_t Vector3::length_sq() const {
  61.582 +	return x*x + y*y + z*z;
  61.583 +}
  61.584 +
  61.585 +inline Vector3 lerp(const Vector3 &a, const Vector3 &b, scalar_t t) {
  61.586 +	return a + (b - a) * t;
  61.587 +}
  61.588 +
  61.589 +inline Vector3 catmull_rom_spline(const Vector3 &v0, const Vector3 &v1,
  61.590 +		const Vector3 &v2, const Vector3 &v3, scalar_t t)
  61.591 +{
  61.592 +	scalar_t spline(scalar_t, scalar_t, scalar_t, scalar_t, scalar_t);
  61.593 +	scalar_t x = spline(v0.x, v1.x, v2.x, v3.x, t);
  61.594 +	scalar_t y = spline(v0.y, v1.y, v2.y, v3.y, t);
  61.595 +	scalar_t z = spline(v0.z, v1.z, v2.z, v3.z, t);
  61.596 +	return Vector3(x, y, z);
  61.597 +}
  61.598 +
  61.599 +inline Vector3 faceforward(const Vector3 &v, const Vector3 &ref)
  61.600 +{
  61.601 +	return dot_product(v, ref) >= 0.0 ? -v : v;
  61.602 +}
  61.603 +
  61.604 +/* ----------- Vector4 ----------------- */
  61.605 +
  61.606 +inline scalar_t &Vector4::operator [](int elem) {
  61.607 +	return elem ? (elem == 1 ? y : (elem == 2 ? z : w)) : x;
  61.608 +}
  61.609 +
  61.610 +inline const scalar_t &Vector4::operator [](int elem) const {
  61.611 +	return elem ? (elem == 1 ? y : (elem == 2 ? z : w)) : x;
  61.612 +}
  61.613 +
  61.614 +inline Vector4 operator -(const Vector4 &vec) {
  61.615 +	return Vector4(-vec.x, -vec.y, -vec.z, -vec.w);
  61.616 +}
  61.617 +
  61.618 +inline scalar_t dot_product(const Vector4 &v1, const Vector4 &v2) {
  61.619 +	return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
  61.620 +}
  61.621 +
  61.622 +inline Vector4 cross_product(const Vector4 &v1, const Vector4 &v2, const Vector4 &v3) {
  61.623 +	scalar_t a, b, c, d, e, f;       /* Intermediate Values */
  61.624 +    Vector4 result;
  61.625 +
  61.626 +    /* Calculate intermediate values. */
  61.627 +    a = (v2.x * v3.y) - (v2.y * v3.x);
  61.628 +    b = (v2.x * v3.z) - (v2.z * v3.x);
  61.629 +    c = (v2.x * v3.w) - (v2.w * v3.x);
  61.630 +    d = (v2.y * v3.z) - (v2.z * v3.y);
  61.631 +    e = (v2.y * v3.w) - (v2.w * v3.y);
  61.632 +    f = (v2.z * v3.w) - (v2.w * v3.z);
  61.633 +
  61.634 +    /* Calculate the result-vector components. */
  61.635 +    result.x =   (v1.y * f) - (v1.z * e) + (v1.w * d);
  61.636 +    result.y = - (v1.x * f) + (v1.z * c) - (v1.w * b);
  61.637 +    result.z =   (v1.x * e) - (v1.y * c) + (v1.w * a);
  61.638 +    result.w = - (v1.x * d) + (v1.y * b) - (v1.z * a);
  61.639 +    return result;
  61.640 +}
  61.641 +
  61.642 +inline Vector4 operator +(const Vector4 &v1, const Vector4 &v2) {
  61.643 +	return Vector4(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.w + v2.w);
  61.644 +}
  61.645 +
  61.646 +inline Vector4 operator -(const Vector4 &v1, const Vector4 &v2) {
  61.647 +	return Vector4(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.w - v2.w);
  61.648 +}
  61.649 +
  61.650 +inline Vector4 operator *(const Vector4 &v1, const Vector4 &v2) {
  61.651 +	return Vector4(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.w * v2.w);
  61.652 +}
  61.653 +
  61.654 +inline Vector4 operator /(const Vector4 &v1, const Vector4 &v2) {
  61.655 +	return Vector4(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.w / v2.w);
  61.656 +}
  61.657 +
  61.658 +inline bool operator ==(const Vector4 &v1, const Vector4 &v2) {
  61.659 +	return	(fabs(v1.x - v2.x) < XSMALL_NUMBER) &&
  61.660 +			(fabs(v1.y - v2.y) < XSMALL_NUMBER) &&
  61.661 +			(fabs(v1.z - v2.z) < XSMALL_NUMBER) &&
  61.662 +			(fabs(v1.w - v2.w) < XSMALL_NUMBER);
  61.663 +}
  61.664 +
  61.665 +inline void operator +=(Vector4 &v1, const Vector4 &v2) {
  61.666 +	v1.x += v2.x;
  61.667 +	v1.y += v2.y;
  61.668 +	v1.z += v2.z;
  61.669 +	v1.w += v2.w;
  61.670 +}
  61.671 +
  61.672 +inline void operator -=(Vector4 &v1, const Vector4 &v2) {
  61.673 +	v1.x -= v2.x;
  61.674 +	v1.y -= v2.y;
  61.675 +	v1.z -= v2.z;
  61.676 +	v1.w -= v2.w;
  61.677 +}
  61.678 +
  61.679 +inline void operator *=(Vector4 &v1, const Vector4 &v2) {
  61.680 +	v1.x *= v2.x;
  61.681 +	v1.y *= v2.y;
  61.682 +	v1.z *= v2.z;
  61.683 +	v1.w *= v2.w;
  61.684 +}
  61.685 +
  61.686 +inline void operator /=(Vector4 &v1, const Vector4 &v2) {
  61.687 +	v1.x /= v2.x;
  61.688 +	v1.y /= v2.y;
  61.689 +	v1.z /= v2.z;
  61.690 +	v1.w /= v2.w;
  61.691 +}
  61.692 +
  61.693 +/* binary vector (op) scalar and scalar (op) vector operations */
  61.694 +inline Vector4 operator +(const Vector4 &vec, scalar_t scalar) {
  61.695 +	return Vector4(vec.x + scalar, vec.y + scalar, vec.z + scalar, vec.w + scalar);
  61.696 +}
  61.697 +
  61.698 +inline Vector4 operator +(scalar_t scalar, const Vector4 &vec) {
  61.699 +	return Vector4(vec.x + scalar, vec.y + scalar, vec.z + scalar, vec.w + scalar);
  61.700 +}
  61.701 +
  61.702 +inline Vector4 operator -(const Vector4 &vec, scalar_t scalar) {
  61.703 +	return Vector4(vec.x - scalar, vec.y - scalar, vec.z - scalar, vec.w - scalar);
  61.704 +}
  61.705 +
  61.706 +inline Vector4 operator *(const Vector4 &vec, scalar_t scalar) {
  61.707 +	return Vector4(vec.x * scalar, vec.y * scalar, vec.z * scalar, vec.w * scalar);
  61.708 +}
  61.709 +
  61.710 +inline Vector4 operator *(scalar_t scalar, const Vector4 &vec) {
  61.711 +	return Vector4(vec.x * scalar, vec.y * scalar, vec.z * scalar, vec.w * scalar);
  61.712 +}
  61.713 +
  61.714 +inline Vector4 operator /(const Vector4 &vec, scalar_t scalar) {
  61.715 +	return Vector4(vec.x / scalar, vec.y / scalar, vec.z / scalar, vec.w / scalar);
  61.716 +}
  61.717 +
  61.718 +inline void operator +=(Vector4 &vec, scalar_t scalar) {
  61.719 +	vec.x += scalar;
  61.720 +	vec.y += scalar;
  61.721 +	vec.z += scalar;
  61.722 +	vec.w += scalar;
  61.723 +}
  61.724 +
  61.725 +inline void operator -=(Vector4 &vec, scalar_t scalar) {
  61.726 +	vec.x -= scalar;
  61.727 +	vec.y -= scalar;
  61.728 +	vec.z -= scalar;
  61.729 +	vec.w -= scalar;
  61.730 +}
  61.731 +
  61.732 +inline void operator *=(Vector4 &vec, scalar_t scalar) {
  61.733 +	vec.x *= scalar;
  61.734 +	vec.y *= scalar;
  61.735 +	vec.z *= scalar;
  61.736 +	vec.w *= scalar;
  61.737 +}
  61.738 +
  61.739 +inline void operator /=(Vector4 &vec, scalar_t scalar) {
  61.740 +	vec.x /= scalar;
  61.741 +	vec.y /= scalar;
  61.742 +	vec.z /= scalar;
  61.743 +	vec.w /= scalar;
  61.744 +}
  61.745 +
  61.746 +inline scalar_t Vector4::length() const {
  61.747 +	return sqrt(x*x + y*y + z*z + w*w);
  61.748 +}
  61.749 +inline scalar_t Vector4::length_sq() const {
  61.750 +	return x*x + y*y + z*z + w*w;
  61.751 +}
  61.752 +
  61.753 +inline Vector4 lerp(const Vector4 &v0, const Vector4 &v1, scalar_t t)
  61.754 +{
  61.755 +	return v0 + (v1 - v0) * t;
  61.756 +}
  61.757 +
  61.758 +inline Vector4 catmull_rom_spline(const Vector4 &v0, const Vector4 &v1,
  61.759 +		const Vector4 &v2, const Vector4 &v3, scalar_t t)
  61.760 +{
  61.761 +	scalar_t spline(scalar_t, scalar_t, scalar_t, scalar_t, scalar_t);
  61.762 +	scalar_t x = spline(v0.x, v1.x, v2.x, v3.x, t);
  61.763 +	scalar_t y = spline(v0.y, v1.y, v2.y, v3.y, t);
  61.764 +	scalar_t z = spline(v0.z, v1.z, v2.z, v3.z, t);
  61.765 +	scalar_t w = spline(v0.w, v1.w, v2.w, v3.w, t);
  61.766 +	return Vector4(x, y, z, w);
  61.767 +}
  61.768 +
  61.769 +#endif	/* __cplusplus */
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/vmath/vmath.h	Sun Nov 09 13:03:36 2014 +0200
    62.3 @@ -0,0 +1,92 @@
    62.4 +/*
    62.5 +libvmath - a vector math library
    62.6 +Copyright (C) 2004-2013 John Tsiombikas <nuclear@member.fsf.org>
    62.7 +
    62.8 +This program is free software: you can redistribute it and/or modify
    62.9 +it under the terms of the GNU Lesser General Public License as published
   62.10 +by the Free Software Foundation, either version 3 of the License, or
   62.11 +(at your option) any later version.
   62.12 +
   62.13 +This program is distributed in the hope that it will be useful,
   62.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   62.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   62.16 +GNU Lesser General Public License for more details.
   62.17 +
   62.18 +You should have received a copy of the GNU Lesser General Public License
   62.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   62.20 +*/
   62.21 +
   62.22 +#ifndef VMATH_H_
   62.23 +#define VMATH_H_
   62.24 +
   62.25 +#include <math.h>
   62.26 +#include "vmath_types.h"
   62.27 +
   62.28 +#ifndef M_PI
   62.29 +#define M_PI	PI
   62.30 +#endif
   62.31 +
   62.32 +#ifndef M_E
   62.33 +#define M_E				2.718281828459045
   62.34 +#endif
   62.35 +
   62.36 +#define PI				3.141592653589793
   62.37 +#define HALF_PI			1.570796326794897
   62.38 +#define QUARTER_PI		0.785398163397448
   62.39 +#define TWO_PI			6.283185307179586
   62.40 +
   62.41 +
   62.42 +#define RAD_TO_DEG(a) ((((scalar_t)a) * 360.0) / TWO_PI)
   62.43 +#define DEG_TO_RAD(a) (((scalar_t)a) * (PI / 180.0))
   62.44 +
   62.45 +#define SQ(x) ((x) * (x))
   62.46 +
   62.47 +#define MIN(a, b)	((a) < (b) ? (a) : (b))
   62.48 +#define MAX(a, b)	((a) > (b) ? (a) : (b))
   62.49 +
   62.50 +#ifndef __GNUC__
   62.51 +#define round(x)	((x) >= 0 ? (x) + 0.5 : (x) - 0.5)
   62.52 +#endif
   62.53 +
   62.54 +#ifdef __cplusplus
   62.55 +extern "C" {
   62.56 +#endif	/* __cplusplus */
   62.57 +
   62.58 +static inline scalar_t smoothstep(float a, float b, float x);
   62.59 +
   62.60 +static inline scalar_t frand(scalar_t range);
   62.61 +static inline vec3_t sphrand(scalar_t rad);
   62.62 +
   62.63 +scalar_t integral(scalar_t (*f)(scalar_t), scalar_t low, scalar_t high, int samples);
   62.64 +scalar_t gaussian(scalar_t x, scalar_t mean, scalar_t sdev);
   62.65 +
   62.66 +static inline scalar_t lerp(scalar_t a, scalar_t b, scalar_t t);
   62.67 +
   62.68 +scalar_t bspline(scalar_t a, scalar_t b, scalar_t c, scalar_t d, scalar_t t);
   62.69 +scalar_t spline(scalar_t a, scalar_t b, scalar_t c, scalar_t d, scalar_t t);
   62.70 +scalar_t bezier(scalar_t a, scalar_t b, scalar_t c, scalar_t d, scalar_t t);
   62.71 +
   62.72 +scalar_t noise1(scalar_t x);
   62.73 +scalar_t noise2(scalar_t x, scalar_t y);
   62.74 +scalar_t noise3(scalar_t x, scalar_t y, scalar_t z);
   62.75 +
   62.76 +scalar_t fbm1(scalar_t x, int octaves);
   62.77 +scalar_t fbm2(scalar_t x, scalar_t y, int octaves);
   62.78 +scalar_t fbm3(scalar_t x, scalar_t y, scalar_t z, int octaves);
   62.79 +
   62.80 +scalar_t turbulence1(scalar_t x, int octaves);
   62.81 +scalar_t turbulence2(scalar_t x, scalar_t y, int octaves);
   62.82 +scalar_t turbulence3(scalar_t x, scalar_t y, scalar_t z, int octaves);
   62.83 +
   62.84 +#ifdef __cplusplus
   62.85 +}
   62.86 +#endif	/* __cplusplus */
   62.87 +
   62.88 +#include "vmath.inl"
   62.89 +
   62.90 +#include "vector.h"
   62.91 +#include "matrix.h"
   62.92 +#include "quat.h"
   62.93 +#include "ray.h"
   62.94 +
   62.95 +#endif	/* VMATH_H_ */
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/vmath/vmath.inl	Sun Nov 09 13:03:36 2014 +0200
    63.3 @@ -0,0 +1,56 @@
    63.4 +/*
    63.5 +libvmath - a vector math library
    63.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    63.7 +
    63.8 +This program is free software: you can redistribute it and/or modify
    63.9 +it under the terms of the GNU Lesser General Public License as published
   63.10 +by the Free Software Foundation, either version 3 of the License, or
   63.11 +(at your option) any later version.
   63.12 +
   63.13 +This program is distributed in the hope that it will be useful,
   63.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   63.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   63.16 +GNU Lesser General Public License for more details.
   63.17 +
   63.18 +You should have received a copy of the GNU Lesser General Public License
   63.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   63.20 +*/
   63.21 +
   63.22 +#include <stdlib.h>
   63.23 +
   63.24 +static inline scalar_t smoothstep(float a, float b, float x)
   63.25 +{
   63.26 +	if(x < a) return 0.0;
   63.27 +	if(x >= b) return 1.0;
   63.28 +
   63.29 +	x = (x - a) / (b - a);
   63.30 +	return x * x * (3.0 - 2.0 * x);
   63.31 +}
   63.32 +
   63.33 +/** Generates a random number in [0, range) */
   63.34 +static inline scalar_t frand(scalar_t range)
   63.35 +{
   63.36 +	return range * (scalar_t)rand() / (scalar_t)RAND_MAX;
   63.37 +}
   63.38 +
   63.39 +/** Generates a random vector on the surface of a sphere */
   63.40 +static inline vec3_t sphrand(scalar_t rad)
   63.41 +{
   63.42 +	scalar_t u = (scalar_t)rand() / RAND_MAX;
   63.43 +	scalar_t v = (scalar_t)rand() / RAND_MAX;
   63.44 +
   63.45 +	scalar_t theta = 2.0 * M_PI * u;
   63.46 +	scalar_t phi = acos(2.0 * v - 1.0);
   63.47 +
   63.48 +	vec3_t res;
   63.49 +	res.x = rad * cos(theta) * sin(phi);
   63.50 +	res.y = rad * sin(theta) * sin(phi);
   63.51 +	res.z = rad * cos(phi);
   63.52 +	return res;
   63.53 +}
   63.54 +
   63.55 +/** linear interpolation */
   63.56 +static inline scalar_t lerp(scalar_t a, scalar_t b, scalar_t t)
   63.57 +{
   63.58 +	return a + (b - a) * t;
   63.59 +}
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/vmath/vmath_config.h	Sun Nov 09 13:03:36 2014 +0200
    64.3 @@ -0,0 +1,19 @@
    64.4 +#ifndef VMATH_CONFIG_H_
    64.5 +#define VMATH_CONFIG_H_
    64.6 +
    64.7 +#if (__STDC_VERSION__ < 199999)
    64.8 +#if defined(__GNUC__) || defined(_MSC_VER)
    64.9 +#define inline __inline
   64.10 +#else
   64.11 +#define inline
   64.12 +
   64.13 +#ifdef VECTOR_H_
   64.14 +#warning "compiling vector operations without inline, performance might suffer"
   64.15 +#endif	/* VECTOR_H_ */
   64.16 +
   64.17 +#endif	/* gcc/msvc */
   64.18 +#endif	/* not C99 */
   64.19 +
   64.20 +#define SINGLE_PRECISION_MATH
   64.21 +
   64.22 +#endif	/* VMATH_CONFIG_H_ */
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/vmath/vmath_types.h	Sun Nov 09 13:03:36 2014 +0200
    65.3 @@ -0,0 +1,58 @@
    65.4 +/*
    65.5 +libvmath - a vector math library
    65.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org>
    65.7 +
    65.8 +This program is free software: you can redistribute it and/or modify
    65.9 +it under the terms of the GNU Lesser General Public License as published
   65.10 +by the Free Software Foundation, either version 3 of the License, or
   65.11 +(at your option) any later version.
   65.12 +
   65.13 +This program is distributed in the hope that it will be useful,
   65.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
   65.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   65.16 +GNU Lesser General Public License for more details.
   65.17 +
   65.18 +You should have received a copy of the GNU Lesser General Public License
   65.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
   65.20 +*/
   65.21 +
   65.22 +#ifndef VMATH_TYPES_H_
   65.23 +#define VMATH_TYPES_H_
   65.24 +
   65.25 +#include "vmath_config.h"
   65.26 +
   65.27 +#define SMALL_NUMBER	1.e-4
   65.28 +#define XSMALL_NUMBER	1.e-8
   65.29 +#define ERROR_MARGIN	1.e-6
   65.30 +
   65.31 +
   65.32 +#ifdef SINGLE_PRECISION_MATH
   65.33 +typedef float scalar_t;
   65.34 +#else
   65.35 +typedef double scalar_t;
   65.36 +#endif	/* floating point precision */
   65.37 +
   65.38 +/* vectors */
   65.39 +typedef struct { scalar_t x, y; } vec2_t;
   65.40 +typedef struct { scalar_t x, y, z; } vec3_t;
   65.41 +typedef struct { scalar_t x, y, z, w; } vec4_t;
   65.42 +
   65.43 +/* quaternions */
   65.44 +typedef vec4_t quat_t;
   65.45 +
   65.46 +/* matrices */
   65.47 +typedef scalar_t mat3_t[3][3];
   65.48 +typedef scalar_t mat4_t[4][4];
   65.49 +
   65.50 +
   65.51 +#ifdef __cplusplus
   65.52 +class Vector2;
   65.53 +class Vector3;
   65.54 +class Vector4;
   65.55 +class Quaternion;
   65.56 +class Matrix3x3;
   65.57 +class Matrix4x4;
   65.58 +class SphVector;
   65.59 +#endif	/* __cplusplus */
   65.60 +
   65.61 +#endif	/* VMATH_TYPES_H_ */