gpuray_glsl
changeset 0:f234630e38ff
initial commit
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, <->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, <->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_ */