dbf-halloween2015
changeset 0:50683c78264e
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 01 Nov 2015 00:09:12 +0200 |
parents | |
children | c3f5c32cb210 |
files | .hgignore LICENSE Makefile README RUN sdr/default.v.glsl sdr/spot.p.glsl src/audio/audio.cc src/audio/audio.h src/audio/openal.h src/audio/ovstream.cc src/audio/ovstream.h src/audio/stream.cc src/audio/stream.h src/dsys/dsys.c src/dsys/dsys.h src/dsys/dsys_impl.h src/geom.cc src/geom.h src/image.cc src/image.h src/light.cc src/light.h src/main.cc src/mesh.cc src/mesh.h src/meshgen.cc src/meshgen.h src/object.cc src/object.h src/opengl.c src/opengl.h src/opt.cc src/opt.h src/pnoise.cc src/pnoise.h src/rng.cc src/rng.h src/scene.cc src/scene.h src/sdr.c src/sdr.h src/timer.cc src/timer.h |
diffstat | 44 files changed, 6867 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Sun Nov 01 00:09:12 2015 +0200 1.3 @@ -0,0 +1,8 @@ 1.4 +\.swp$ 1.5 +\.o$ 1.6 +\.d$ 1.7 +\.jpg$ 1.8 +\.png$ 1.9 +^data/ 1.10 +^bin/ 1.11 +^lib/
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/LICENSE Sun Nov 01 00:09:12 2015 +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 01 00:09:12 2015 +0200 3.3 @@ -0,0 +1,31 @@ 3.4 +src = $(wildcard src/*.cc) $(wildcard src/audio/*.cc) 3.5 +csrc = $(wildcard src/*.c) $(wildcard src/dsys/*.c) 3.6 +obj = $(src:.cc=.o) $(csrc:.c=.o) 3.7 +dep = $(obj:.o=.d) 3.8 +bin = halloween 3.9 + 3.10 +opt = -O2 3.11 + 3.12 +CFLAGS = -pedantic -Wall -g $(opt) -Isrc 3.13 +CXXFLAGS = -pedantic -Wall -g $(opt) -Isrc 3.14 +LDFLAGS = -lGL -lGLU -lglut -lGLEW -lvmath -limago -lm -ldl -lpthread \ 3.15 + -lvorbisfile -logg -lpthread -lopenal 3.16 + 3.17 +$(bin): $(obj) 3.18 + $(CXX) -o $@ $(obj) $(LDFLAGS) 3.19 + 3.20 +-include $(dep) 3.21 + 3.22 +%.d: %.c 3.23 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 3.24 + 3.25 +%.d: %.cc 3.26 + @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ 3.27 + 3.28 +.PHONY: clean 3.29 +clean: 3.30 + rm -f $(obj) $(bin) 3.31 + 3.32 +.PHONY: cleandep 3.33 +cleandep: 3.34 + rm -f $(dep)
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/README Sun Nov 01 00:09:12 2015 +0200 4.3 @@ -0,0 +1,4 @@ 4.4 +"party-version", 64bit GNU/Linux-only release. 4.5 +Expect final v1.1 with binaries for other platforms, and more details, soon. 4.6 + 4.7 +Contact: nuclear@member.fsf.org
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/RUN Sun Nov 01 00:09:12 2015 +0200 5.3 @@ -0,0 +1,3 @@ 5.4 +#!/bin/sh 5.5 + 5.6 +LD_LIBRARY_PATH=lib ./bin/halloween $*
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/sdr/default.v.glsl Sun Nov 01 00:09:12 2015 +0200 6.3 @@ -0,0 +1,16 @@ 6.4 +uniform mat4 world_matrix; 6.5 + 6.6 +varying vec3 lpos, wpos, vpos, norm, ldir; 6.7 + 6.8 +void main() 6.9 +{ 6.10 + lpos = gl_Vertex.xyz; 6.11 + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 6.12 + 6.13 + vpos = (gl_ModelViewMatrix * gl_Vertex).xyz; 6.14 + wpos = (world_matrix * gl_Vertex).xyz; 6.15 + norm = gl_NormalMatrix * gl_Normal; 6.16 + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; 6.17 + 6.18 + ldir = gl_LightSource[0].position.xyz - vpos; 6.19 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/sdr/spot.p.glsl Sun Nov 01 00:09:12 2015 +0200 7.3 @@ -0,0 +1,30 @@ 7.4 +uniform sampler2D tex; 7.5 + 7.6 +varying vec3 lpos, wpos, vpos, norm, ldir; 7.7 + 7.8 +#define KD gl_FrontMaterial.diffuse.rgb 7.9 +#define KS gl_FrontMaterial.specular.rgb 7.10 +#define LTCOL gl_LightSource[0].diffuse.rgb 7.11 + 7.12 +void main() 7.13 +{ 7.14 + vec4 texel = texture2D(tex, gl_TexCoord[0].st); 7.15 + 7.16 + float dist = length(wpos.xz); 7.17 + float spot = 1.0 - smoothstep(4.0, 10.0, dist); 7.18 + 7.19 + vec3 n = normalize(norm); 7.20 + vec3 v = -normalize(vpos); 7.21 + vec3 l = normalize(ldir); 7.22 + vec3 h = normalize(v + l); 7.23 + 7.24 + float ndotl = max(dot(n, l), 0.0); 7.25 + float ndoth = max(dot(n, h), 0.0); 7.26 + 7.27 + vec3 ambient = gl_LightModel.ambient.rgb * texel.rgb; 7.28 + vec3 diffuse = KD * LTCOL * ndotl * texel.rgb; 7.29 + vec3 specular = KS * LTCOL * pow(ndoth, gl_FrontMaterial.shininess); 7.30 + 7.31 + gl_FragColor.rgb = (ambient + diffuse + specular) * spot; 7.32 + gl_FragColor.a = gl_FrontMaterial.diffuse.a * texel.a; 7.33 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/audio/audio.cc Sun Nov 01 00:09:12 2015 +0200 8.3 @@ -0,0 +1,70 @@ 8.4 +#include <stdio.h> 8.5 + 8.6 +#include "openal.h" 8.7 +#include "audio.h" 8.8 + 8.9 +static ALCdevice *dev; 8.10 +static ALCcontext *ctx; 8.11 + 8.12 +bool init_audio() 8.13 +{ 8.14 + if (dev) { 8.15 + // Already initiated. 8.16 + return true; 8.17 + } 8.18 + else if (!(dev = alcOpenDevice(0))) { 8.19 + fprintf(stderr, "failed to open OpenAL device\n"); 8.20 + return false; 8.21 + } 8.22 + 8.23 + if (ctx) 8.24 + { 8.25 + return true; 8.26 + } 8.27 + else if (!(ctx = alcCreateContext(dev, 0))) 8.28 + { 8.29 + fprintf(stderr, "failed to create context\n"); 8.30 + alcCloseDevice(dev); 8.31 + return false; 8.32 + } 8.33 + 8.34 + alcMakeContextCurrent(ctx); 8.35 + 8.36 + // Clear error state. 8.37 + alGetError(); 8.38 + 8.39 + return true; 8.40 +} 8.41 + 8.42 +void destroy_audio() 8.43 +{ 8.44 + alcMakeContextCurrent(0); 8.45 + 8.46 + if (ctx) { 8.47 + alcDestroyContext(ctx); 8.48 + } 8.49 + 8.50 + if (dev) { 8.51 + alcCloseDevice(dev); 8.52 + } 8.53 +} 8.54 + 8.55 +void set_audio_listener(const Matrix4x4 &xform) 8.56 +{ 8.57 + float pos[3], orient[6]; 8.58 + 8.59 + pos[0] = xform[0][3]; 8.60 + pos[1] = xform[1][3]; 8.61 + pos[2] = xform[2][3]; 8.62 + 8.63 + orient[0] = xform[0][2]; 8.64 + orient[1] = xform[1][2]; 8.65 + orient[2] = -xform[2][2]; 8.66 + 8.67 + orient[3] = xform[0][1]; 8.68 + orient[4] = xform[1][1]; 8.69 + orient[5] = xform[2][1]; 8.70 + 8.71 + alListenerfv(AL_POSITION, pos); 8.72 + alListenerfv(AL_ORIENTATION, orient); 8.73 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/audio/audio.h Sun Nov 01 00:09:12 2015 +0200 9.3 @@ -0,0 +1,11 @@ 9.4 +#ifndef AUDIO_H_ 9.5 +#define AUDIO_H_ 9.6 + 9.7 +#include "vmath/vmath.h" 9.8 + 9.9 +bool init_audio(); 9.10 +void destroy_audio(); 9.11 + 9.12 +void set_audio_listener(const Matrix4x4 &xform); 9.13 + 9.14 +#endif // AUDIO_H_
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/audio/openal.h Sun Nov 01 00:09:12 2015 +0200 10.3 @@ -0,0 +1,12 @@ 10.4 +#ifndef OPENAL_H_ 10.5 +#define OPENAL_H_ 10.6 + 10.7 +#ifndef __APPLE__ 10.8 +#include <AL/al.h> 10.9 +#include <AL/alc.h> 10.10 +#else 10.11 +#include <OpenAL/al.h> 10.12 +#include <OpenAL/alc.h> 10.13 +#endif 10.14 + 10.15 +#endif /* OPENAL_H_ */
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/audio/ovstream.cc Sun Nov 01 00:09:12 2015 +0200 11.3 @@ -0,0 +1,95 @@ 11.4 +#include <stdio.h> 11.5 +#include <assert.h> 11.6 +#include "ovstream.h" 11.7 + 11.8 +OggVorbisStream::OggVorbisStream() 11.9 +{ 11.10 + vfopen = false; 11.11 + 11.12 + pthread_mutex_init(&vflock, 0); 11.13 +} 11.14 + 11.15 +OggVorbisStream::~OggVorbisStream() 11.16 +{ 11.17 + close(); 11.18 +} 11.19 + 11.20 +bool OggVorbisStream::open(const char *fname) 11.21 +{ 11.22 + close(); 11.23 + 11.24 + pthread_mutex_lock(&vflock); 11.25 + 11.26 + if(ov_fopen(fname, &vf) != 0) { 11.27 + fprintf(stderr, "failed to open ogg/vorbis stream: %s\n", fname ? fname : "<not found>"); 11.28 + pthread_mutex_unlock(&vflock); 11.29 + return false; 11.30 + } 11.31 + 11.32 + vfopen = true; 11.33 + pthread_mutex_unlock(&vflock); 11.34 + return true; 11.35 +} 11.36 + 11.37 +void OggVorbisStream::close() 11.38 +{ 11.39 + pthread_mutex_lock(&vflock); 11.40 + if(vfopen) { 11.41 + ov_clear(&vf); 11.42 + vfopen = false; 11.43 + } 11.44 + pthread_mutex_unlock(&vflock); 11.45 +} 11.46 + 11.47 +void OggVorbisStream::play(AUDIO_PLAYMODE mode) 11.48 +{ 11.49 + if (vfopen) 11.50 + { 11.51 + AudioStream::play(mode); 11.52 + } else { 11.53 + fprintf(stderr, "failed to play audio track.\n"); 11.54 + } 11.55 +} 11.56 + 11.57 +void OggVorbisStream::rewind() 11.58 +{ 11.59 + pthread_mutex_lock(&vflock); 11.60 + if(vfopen) { 11.61 + ov_raw_seek(&vf, 0); 11.62 + } 11.63 + pthread_mutex_unlock(&vflock); 11.64 +} 11.65 + 11.66 +bool OggVorbisStream::more_samples(AudioStreamBuffer *buf) 11.67 +{ 11.68 + pthread_mutex_lock(&vflock); 11.69 + 11.70 + vorbis_info *vinfo = ov_info(&vf, -1); 11.71 + buf->channels = vinfo->channels; 11.72 + buf->sample_rate = vinfo->rate; 11.73 + assert(buf->channels == 2); 11.74 + assert(buf->sample_rate == 44100); 11.75 + 11.76 + long bufsz = AUDIO_BUFFER_BYTES; 11.77 + long total_read = 0; 11.78 + while(total_read < bufsz) { 11.79 + int bitstream; 11.80 + long rd = ov_read(&vf, buf->samples + total_read, bufsz - total_read, 0, 2, 1, &bitstream); 11.81 + 11.82 + if(!rd) { 11.83 + bufsz = total_read; 11.84 + } else { 11.85 + total_read += rd; 11.86 + } 11.87 + } 11.88 + 11.89 + if(!total_read) { 11.90 + buf->num_samples = 0; 11.91 + pthread_mutex_unlock(&vflock); 11.92 + return false; 11.93 + } 11.94 + 11.95 + buf->num_samples = bufsz / vinfo->channels / 2; 11.96 + pthread_mutex_unlock(&vflock); 11.97 + return true; 11.98 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/src/audio/ovstream.h Sun Nov 01 00:09:12 2015 +0200 12.3 @@ -0,0 +1,27 @@ 12.4 +#ifndef OVSTREAM_H_ 12.5 +#define OVSTREAM_H_ 12.6 + 12.7 +#include <pthread.h> 12.8 +#include <vorbis/vorbisfile.h> 12.9 +#include "stream.h" 12.10 + 12.11 +class OggVorbisStream : public AudioStream { 12.12 +private: 12.13 + OggVorbis_File vf; 12.14 + bool vfopen; 12.15 + pthread_mutex_t vflock; 12.16 + 12.17 + virtual bool more_samples(AudioStreamBuffer *buf); 12.18 + 12.19 +public: 12.20 + OggVorbisStream(); 12.21 + virtual ~OggVorbisStream(); 12.22 + 12.23 + bool open(const char *fname); 12.24 + void close(); 12.25 + 12.26 + virtual void play(AUDIO_PLAYMODE mode); 12.27 + virtual void rewind(); 12.28 +}; 12.29 + 12.30 +#endif // OVSTREAM_H_
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/src/audio/stream.cc Sun Nov 01 00:09:12 2015 +0200 13.3 @@ -0,0 +1,264 @@ 13.4 +#include <stdio.h> 13.5 +#include <stdint.h> 13.6 +#include <assert.h> 13.7 +#include "openal.h" 13.8 +#include "stream.h" 13.9 +#include "timer.h" 13.10 + 13.11 +static ALenum alformat(AudioStreamBuffer *buf) 13.12 +{ 13.13 + return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; 13.14 +} 13.15 + 13.16 +AudioStream::AudioStream() 13.17 +{ 13.18 + alsrc = 0; 13.19 + poll_interval = 25; 13.20 + done = true; 13.21 + loop = false; 13.22 + volume = 1.0; 13.23 + pitch = 1.0; 13.24 + 13.25 + pthread_mutex_init(&mutex, 0); 13.26 +} 13.27 + 13.28 +AudioStream::~AudioStream() 13.29 +{ 13.30 + stop(); 13.31 +} 13.32 + 13.33 +bool AudioStream::open(const char *fname) 13.34 +{ 13.35 + return false; 13.36 +} 13.37 + 13.38 +void AudioStream::close() 13.39 +{ 13.40 +} 13.41 + 13.42 +void AudioStream::set_volume(float vol) 13.43 +{ 13.44 + if(vol < 0.0) vol = 0.0; 13.45 + if(vol > 1.0) vol = 1.0; 13.46 + 13.47 + volume = vol; 13.48 + 13.49 + pthread_mutex_lock(&mutex); 13.50 + if(alsrc) { 13.51 + alSourcef(alsrc, AL_GAIN, vol); 13.52 + } 13.53 + pthread_mutex_unlock(&mutex); 13.54 +} 13.55 + 13.56 +float AudioStream::get_volume() const 13.57 +{ 13.58 + return volume; 13.59 +} 13.60 +void AudioStream::set_pitch(float pitch) 13.61 +{ 13.62 + if(pitch < 0.0) pitch = 0.0; 13.63 + if(pitch > 1.0) pitch = 1.0; 13.64 + 13.65 + this->pitch = pitch; 13.66 + 13.67 + pthread_mutex_lock(&mutex); 13.68 + if(alsrc) { 13.69 + alSourcef(alsrc, AL_PITCH, pitch); 13.70 + } 13.71 + pthread_mutex_unlock(&mutex); 13.72 +} 13.73 + 13.74 +float AudioStream::get_pitch() const 13.75 +{ 13.76 + return pitch; 13.77 +} 13.78 + 13.79 + 13.80 +static void *thread_func(void *arg) 13.81 +{ 13.82 + AudioStream *astr = (AudioStream*)arg; 13.83 + astr->poll_loop(); 13.84 + return 0; 13.85 +} 13.86 + 13.87 +void AudioStream::play(AUDIO_PLAYMODE mode) 13.88 +{ 13.89 + loop = (mode == AUDIO_PLAYMODE_LOOP); 13.90 + done = false; 13.91 + 13.92 + if(pthread_create(&play_thread, 0, thread_func, this) != 0) { 13.93 + fprintf(stderr, "failed to create music playback thread\n"); 13.94 + } 13.95 +} 13.96 + 13.97 +void AudioStream::stop() 13.98 +{ 13.99 + pthread_mutex_lock(&mutex); 13.100 + 13.101 + if(alsrc) { 13.102 + done = true; 13.103 + //alSourceStop(alsrc); 13.104 + printf("waiting for the music thread to stop\n"); 13.105 + pthread_mutex_unlock(&mutex); 13.106 + pthread_join(play_thread, 0); 13.107 + } else { 13.108 + pthread_mutex_unlock(&mutex); 13.109 + } 13.110 +} 13.111 + 13.112 +// gets an array of buffers and returns the index of the one matching id 13.113 +static inline int find_buffer(unsigned int id, unsigned int *barr, int num) 13.114 +{ 13.115 + for(int i=0; i<num; i++) { 13.116 + if(barr[i] == id) { 13.117 + return i; 13.118 + } 13.119 + } 13.120 + return -1; 13.121 +} 13.122 + 13.123 + 13.124 +static int queued_idx_list[AUDIO_NUM_BUFFERS]; 13.125 +static int queued_idx_head = 0; 13.126 +static int queued_idx_tail = 0; 13.127 + 13.128 +#define BUFQ_UNQUEUE() \ 13.129 + do { \ 13.130 + queued_idx_tail = (queued_idx_tail + 1) % AUDIO_NUM_BUFFERS; \ 13.131 + } while(0) 13.132 + 13.133 + 13.134 +#define BUFQ_QUEUE(idx) \ 13.135 + do { \ 13.136 + queued_idx_head = (queued_idx_head + 1) % AUDIO_NUM_BUFFERS; \ 13.137 + queued_idx_list[queued_idx_head] = idx; \ 13.138 + } while(0) 13.139 + 13.140 +// thread function 13.141 +void AudioStream::poll_loop() 13.142 +{ 13.143 + long prev_msec = -1000; 13.144 + unsigned int albuf[AUDIO_NUM_BUFFERS]; 13.145 + 13.146 + pthread_mutex_lock(&mutex); 13.147 + alGenSources(1, &alsrc); 13.148 + alSourcei(alsrc, AL_LOOPING, AL_FALSE); 13.149 + alSourcef(alsrc, AL_GAIN, volume); 13.150 + alSourcef(alsrc, AL_PITCH, pitch); 13.151 + alGenBuffers(AUDIO_NUM_BUFFERS, albuf); 13.152 + AudioStreamBuffer *buf = new AudioStreamBuffer; 13.153 + 13.154 + assert(alGetError() == 0); 13.155 + for(int i=0; i<AUDIO_NUM_BUFFERS; i++) { 13.156 + if(more_samples(buf)) { 13.157 + int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples 13.158 + alBufferData(albuf[i], alformat(buf), buf->samples, bufsz, buf->sample_rate); 13.159 + 13.160 + if(alGetError()) { 13.161 + fprintf(stderr, "failed to load sample data into OpenAL buffer\n"); 13.162 + } 13.163 + 13.164 + alSourceQueueBuffers(alsrc, 1, albuf + i); 13.165 + BUFQ_QUEUE(i); 13.166 + 13.167 + if(alGetError()) { 13.168 + fprintf(stderr, "failed to start streaming audio buffers\n"); 13.169 + } 13.170 + } else { 13.171 + break; 13.172 + } 13.173 + } 13.174 + 13.175 + // start playback 13.176 + alSourcePlay(alsrc); 13.177 + while(!done) { 13.178 + /* find out how many (if any) of the queued buffers are 13.179 + * done, and free to be reused. 13.180 + */ 13.181 + int num_buf_done; 13.182 + alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done); 13.183 + for(int i=0; i<num_buf_done; i++) { 13.184 + int err; 13.185 + // unqueue a buffer... 13.186 + unsigned int buf_id; 13.187 + alSourceUnqueueBuffers(alsrc, 1, &buf_id); 13.188 + 13.189 + if((err = alGetError())) { 13.190 + fprintf(stderr, "failed to unqueue used buffer (error: %x)\n", err); 13.191 + num_buf_done = i; 13.192 + break; 13.193 + } 13.194 + BUFQ_UNQUEUE(); 13.195 + 13.196 + // find out which one of our al buffers we just unqueued 13.197 + int bidx = find_buffer(buf_id, albuf, AUDIO_NUM_BUFFERS); 13.198 + assert(bidx != -1); 13.199 + 13.200 + int looping; 13.201 + 13.202 + alGetSourcei(alsrc, AL_LOOPING, &looping); 13.203 + assert(looping == AL_FALSE); 13.204 + /*if((unsigned int)cur_buf == buf_id) { 13.205 + continue; 13.206 + }*/ 13.207 + 13.208 + // if there are more data, fill it up and requeue it 13.209 + if(more_samples(buf)) { 13.210 + int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples 13.211 + alBufferData(buf_id, alformat(buf), buf->samples, bufsz, buf->sample_rate); 13.212 + if((err = alGetError())) { 13.213 + fprintf(stderr, "failed to load sample data into OpenAL buffer (error: %x)\n", err); 13.214 + } 13.215 + 13.216 + alSourceQueueBuffers(alsrc, 1, &buf_id); 13.217 + if(alGetError()) { 13.218 + fprintf(stderr, "failed to start streaming audio buffers\n"); 13.219 + } 13.220 + BUFQ_QUEUE(bidx); 13.221 + } else { 13.222 + // no more data... 13.223 + if(loop) { 13.224 + printf("audio stream looping...\n"); 13.225 + rewind(); 13.226 + } else { 13.227 + done = true; 13.228 + } 13.229 + } 13.230 + } 13.231 + 13.232 + if(num_buf_done) { 13.233 + // make sure playback didn't stop 13.234 + int state; 13.235 + alGetSourcei(alsrc, AL_SOURCE_STATE, &state); 13.236 + if(state != AL_PLAYING) { 13.237 + alSourcePlay(alsrc); 13.238 + } 13.239 + } 13.240 + 13.241 + pthread_mutex_unlock(&mutex); 13.242 + long msec = get_time_msec(); 13.243 + long dt = msec - prev_msec; 13.244 + prev_msec = msec; 13.245 + 13.246 + if(dt < (long)poll_interval) { 13.247 + sleep_msec(poll_interval - dt); 13.248 + } else { 13.249 + sched_yield(); 13.250 + } 13.251 + pthread_mutex_lock(&mutex); 13.252 + } 13.253 + 13.254 + 13.255 + // done with the data, wait for the source to stop playing before cleanup 13.256 + int state; 13.257 + while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) { 13.258 + sched_yield(); 13.259 + } 13.260 + 13.261 + alDeleteBuffers(AUDIO_NUM_BUFFERS, albuf); 13.262 + alDeleteSources(1, &alsrc); 13.263 + alsrc = 0; 13.264 + pthread_mutex_unlock(&mutex); 13.265 + 13.266 + delete buf; 13.267 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/src/audio/stream.h Sun Nov 01 00:09:12 2015 +0200 14.3 @@ -0,0 +1,65 @@ 14.4 +#ifndef STREAM_H_ 14.5 +#define STREAM_H_ 14.6 + 14.7 +#include <pthread.h> 14.8 + 14.9 +#define AUDIO_FFT_BINS 16 14.10 +#define AUDIO_FFT_DOWNSAMPLE 1 14.11 + 14.12 +#define AUDIO_NUM_BUFFERS 8 14.13 +#define AUDIO_BUFFER_MSEC 32 14.14 +// TODO should the sampling rate be hardcoded? 14.15 +#define AUDIO_BUFFER_SAMPLES (AUDIO_BUFFER_MSEC * 44100 / 1000) 14.16 +// TODO unhardcode the channels number 14.17 +#define AUDIO_BUFFER_BYTES (AUDIO_BUFFER_SAMPLES * 2 * 2) 14.18 + 14.19 +#define AUDIO_FFT_SAMPLES (AUDIO_BUFFER_SAMPLES / AUDIO_FFT_DOWNSAMPLE) 14.20 + 14.21 +enum AUDIO_PLAYMODE 14.22 +{ 14.23 + AUDIO_PLAYMODE_ONCE, 14.24 + AUDIO_PLAYMODE_LOOP 14.25 +}; 14.26 + 14.27 +struct AudioStreamBuffer { 14.28 + char samples[AUDIO_BUFFER_BYTES]; 14.29 + 14.30 + int num_samples; 14.31 + int channels; 14.32 + int sample_rate; 14.33 +}; 14.34 + 14.35 +class AudioStream { 14.36 +private: 14.37 + pthread_t play_thread; 14.38 + pthread_mutex_t mutex; 14.39 + 14.40 + float volume, pitch; 14.41 + bool done, loop; 14.42 + unsigned int poll_interval; 14.43 + unsigned int alsrc; 14.44 + 14.45 + virtual bool more_samples(AudioStreamBuffer *buf) = 0; 14.46 + 14.47 +public: 14.48 + void poll_loop(); 14.49 + 14.50 + AudioStream(); 14.51 + virtual ~AudioStream(); 14.52 + 14.53 + virtual bool open(const char *fname); 14.54 + virtual void close(); 14.55 + 14.56 + virtual void set_volume(float vol); 14.57 + virtual float get_volume() const; 14.58 + 14.59 + virtual void set_pitch(float p); 14.60 + virtual float get_pitch() const; 14.61 + 14.62 + virtual void play(AUDIO_PLAYMODE mode); 14.63 + virtual void stop(); 14.64 + 14.65 + virtual void rewind() = 0; 14.66 +}; 14.67 + 14.68 +#endif // AUDIO_STREAM_H_
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/src/dsys/dsys.c Sun Nov 01 00:09:12 2015 +0200 15.3 @@ -0,0 +1,515 @@ 15.4 +#include <stdio.h> 15.5 +#include <math.h> 15.6 +#include <stdlib.h> 15.7 +#include <string.h> 15.8 +#include <ctype.h> 15.9 +#include <errno.h> 15.10 +#include "dsys.h" 15.11 +#include "dsys_impl.h" 15.12 + 15.13 +static int read_script(struct dsys_demo *demo, FILE *fp, const char *fname); 15.14 +static char *strip_ws(char *buf); 15.15 +static void dbg_print_events(struct dsys_event *ev); 15.16 + 15.17 +static void proc_event(struct dsys_event *ev, demotime_t tm); 15.18 +static void link_callback(struct dsys_event *ev, void *cls); 15.19 +static void free_event(struct dsys_event *ev); 15.20 + 15.21 +static struct dsys_event *sort_evlist(struct dsys_event *list, int num_ev); 15.22 +static struct dsys_event *merge_evlists(struct dsys_event *list1, struct dsys_event *list2); 15.23 + 15.24 + 15.25 +struct dsys_demo *dsys_open(const char *fname) 15.26 +{ 15.27 + FILE *fp; 15.28 + struct dsys_demo *demo; 15.29 + 15.30 + if(!(fp = fopen(fname, "r"))) { 15.31 + fprintf(stderr, "failed to open demoscript: %s: %s\n", fname, strerror(errno)); 15.32 + return 0; 15.33 + } 15.34 + 15.35 + if(!(demo = malloc(sizeof *demo))) { 15.36 + perror("failed to allocate memory"); 15.37 + fclose(fp); 15.38 + return 0; 15.39 + } 15.40 + memset(demo, 0, sizeof *demo); 15.41 + 15.42 + demo->src_tm = demo->start_tm = -1; 15.43 + 15.44 + if(read_script(demo, fp, fname) == -1) { 15.45 + free(demo); 15.46 + fclose(fp); 15.47 + return 0; 15.48 + } 15.49 + 15.50 + fclose(fp); 15.51 + return demo; 15.52 +} 15.53 + 15.54 +struct dsys_demo *dsys_open_stream(FILE *fp) 15.55 +{ 15.56 + struct dsys_demo *demo; 15.57 + 15.58 + if(!(demo = malloc(sizeof *demo))) { 15.59 + perror("failed to allocate memory"); 15.60 + return 0; 15.61 + } 15.62 + memset(demo, 0, sizeof *demo); 15.63 + 15.64 + demo->src_tm = demo->start_tm = -1; 15.65 + 15.66 + if(read_script(demo, fp, 0) == -1) { 15.67 + free(demo); 15.68 + return 0; 15.69 + } 15.70 + 15.71 + return demo; 15.72 +} 15.73 + 15.74 +void dsys_close(struct dsys_demo *demo) 15.75 +{ 15.76 + while(demo->evlist) { 15.77 + struct dsys_event *ev = demo->evlist; 15.78 + demo->evlist = demo->evlist->next; 15.79 + free_event(ev); 15.80 + } 15.81 + 15.82 + free(demo); 15.83 +} 15.84 + 15.85 + 15.86 +#define SEP " \t\n\r" 15.87 + 15.88 +static int read_script(struct dsys_demo *demo, FILE *fp, const char *fname) 15.89 +{ 15.90 + int nline = 0; 15.91 + char buf[512], *line, *tok, *endp; 15.92 + unsigned int t0, t1; 15.93 + struct dsys_event *ev; 15.94 + 15.95 + if(!fname) { 15.96 + fname = "<unknown>"; 15.97 + } 15.98 + 15.99 + demo->duration = dsys_msec_to_dtime(0); 15.100 + 15.101 + while(fgets(buf, sizeof buf, fp)) { 15.102 + nline++; 15.103 + 15.104 + line = strip_ws(buf); 15.105 + 15.106 + if(!line || !*line) { 15.107 + continue; 15.108 + } 15.109 + 15.110 + if(!(tok = strtok(line, SEP)) || (t0 = strtol(tok, &endp, 10), endp == tok)) { 15.111 + fprintf(stderr, "%s line: %d, error: expected timestamp t0\n", fname, nline); 15.112 + return -1; 15.113 + } 15.114 + 15.115 + if(!(tok = strtok(0, SEP))) { 15.116 + fprintf(stderr, "%s line: %d, error: expected second timestamp or event name\n", fname, nline); 15.117 + return -1; 15.118 + } 15.119 + 15.120 + t1 = strtol(tok, &endp, 10); 15.121 + if(endp == tok) { 15.122 + t1 = t0; 15.123 + } else { 15.124 + if(!(tok = strtok(0, SEP))) { 15.125 + fprintf(stderr, "%s line: %d, error: expected event name\n", fname, nline); 15.126 + return -1; 15.127 + } 15.128 + } 15.129 + 15.130 + if(!(ev = malloc(sizeof *ev))) { 15.131 + perror("read_script: failed to allocate memory for an event\n"); 15.132 + return -1; 15.133 + } 15.134 + memset(ev, 0, sizeof *ev); 15.135 + ev->t0 = dsys_msec_to_dtime(t0); 15.136 + ev->t1 = dsys_msec_to_dtime(t1); 15.137 + 15.138 + if(!(ev->name = malloc(strlen(tok) + 1))) { 15.139 + free(ev); 15.140 + fprintf(stderr, "read_script: failed to allocate memory for the event name: %s\n", tok); 15.141 + return -1; 15.142 + } 15.143 + strcpy(ev->name, tok); 15.144 + 15.145 + ev->eval = t0 == t1 ? dsys_eval_step : dsys_eval_lerp; 15.146 + 15.147 + ev->next = demo->evlist; 15.148 + ev->prev = 0; 15.149 + if(demo->evlist) { 15.150 + demo->evlist->prev = ev; 15.151 + } 15.152 + demo->evlist = ev; 15.153 + demo->num_ev++; 15.154 + 15.155 + if(ev->t1 > demo->duration) { 15.156 + demo->duration = ev->t1; 15.157 + } 15.158 + } 15.159 + 15.160 + demo->evlist = sort_evlist(demo->evlist, demo->num_ev); 15.161 + 15.162 + /*dbg_print_events(demo->evlist);*/ 15.163 + 15.164 + return 0; 15.165 +} 15.166 + 15.167 +static char *strip_ws(char *buf) 15.168 +{ 15.169 + char *ptr; 15.170 + 15.171 + while(isspace(*buf)) { 15.172 + buf++; 15.173 + } 15.174 + 15.175 + ptr = buf; 15.176 + while(*ptr) { 15.177 + if(*ptr == '\n' || *ptr == '\r' || *ptr == '#') { 15.178 + *ptr = 0; 15.179 + break; 15.180 + } 15.181 + ptr++; 15.182 + } 15.183 + 15.184 + return buf; 15.185 +} 15.186 + 15.187 +/*static void dbg_print_events(struct dsys_event *ev) 15.188 +{ 15.189 + int i; 15.190 + 15.191 + for(i=0; ev; i++) { 15.192 + printf("%02d - %s (%f -> %f) [%s]\n", i, ev->eval == dsys_eval_step ? "step" : "lerp", 15.193 + ev->t0, ev->t1, ev->name); 15.194 + ev = ev->next; 15.195 + } 15.196 +}*/ 15.197 + 15.198 +void dsys_update(struct dsys_demo *demo, demotime_t tm) 15.199 +{ 15.200 + struct dsys_event *ev; 15.201 + 15.202 + demo->src_tm = tm; 15.203 + 15.204 + if(demo->start_tm == -1) { 15.205 + dsys_start(demo); 15.206 + } 15.207 + 15.208 + if(!demo->running) { 15.209 + return; /* nothing changes */ 15.210 + } 15.211 + 15.212 + demo->tm = tm - demo->start_tm - demo->stoppage_tm; 15.213 + 15.214 + if(demo->tm < 0) { 15.215 + demo->tm = 0; 15.216 + } 15.217 + if(demo->tm > demo->duration) { 15.218 + demo->tm = demo->duration; 15.219 + } 15.220 + 15.221 + while(demo->active && demo->active->t1 <= demo->tm) { 15.222 + proc_event(demo->active, demo->tm); 15.223 + demo->active = demo->active->next; 15.224 + } 15.225 + 15.226 + ev = demo->active; 15.227 + while(ev && ev->t0 <= demo->tm) { 15.228 + proc_event(ev, demo->tm); 15.229 + ev = ev->next; 15.230 + } 15.231 + demo->nextev = ev; 15.232 + 15.233 + 15.234 + if(demo->tm >= demo->duration) { 15.235 + dsys_stop(demo); 15.236 + } 15.237 +} 15.238 + 15.239 +static void proc_event(struct dsys_event *ev, demotime_t tm) 15.240 +{ 15.241 + float val = ev->eval(ev, tm); 15.242 + 15.243 + if(ev->val != val) { 15.244 + struct callback *cb = ev->cblist; 15.245 + 15.246 + ev->val = val; 15.247 + 15.248 + while(cb) { 15.249 + cb->func(ev, cb->cls); 15.250 + cb = cb->next; 15.251 + } 15.252 + } 15.253 +} 15.254 + 15.255 +void dsys_start(struct dsys_demo *demo) 15.256 +{ 15.257 + if(demo->running) { 15.258 + return; 15.259 + } 15.260 + 15.261 + if(demo->start_tm == -1) { 15.262 + demo->start_tm = demo->src_tm; 15.263 + demo->nextev = demo->active = demo->evlist; 15.264 + } else { 15.265 + demo->stoppage_tm += demo->src_tm - demo->stop_tm; 15.266 + } 15.267 + 15.268 + demo->running = 1; 15.269 +} 15.270 + 15.271 +void dsys_stop(struct dsys_demo *demo) 15.272 +{ 15.273 + if(!demo->running) { 15.274 + return; 15.275 + } 15.276 + 15.277 + demo->stop_tm = demo->src_tm; 15.278 + demo->running = 0; 15.279 +} 15.280 + 15.281 +int dsys_is_running(struct dsys_demo *demo) 15.282 +{ 15.283 + return demo->running; 15.284 +} 15.285 + 15.286 + 15.287 +demotime_t dsys_duration(struct dsys_demo *demo) 15.288 +{ 15.289 + return demo->duration; 15.290 +} 15.291 + 15.292 +demotime_t dsys_time(struct dsys_demo *demo) 15.293 +{ 15.294 + return demo->tm; 15.295 +} 15.296 + 15.297 +float dsys_progress(struct dsys_demo *demo) 15.298 +{ 15.299 + return demo->tm / demo->duration; 15.300 +} 15.301 + 15.302 +/* seek without continuity */ 15.303 +void dsys_seek(struct dsys_demo *demo, demotime_t tm) 15.304 +{ 15.305 + struct dsys_event *ev; 15.306 + 15.307 + if(tm < 0) { 15.308 + tm = 0; 15.309 + } 15.310 + if(tm > demo->duration) { 15.311 + tm = demo->duration; 15.312 + } 15.313 + 15.314 + if(tm < demo->tm) { 15.315 + /* on backwards seek, invalidate the sliding window */ 15.316 + demo->nextev = demo->active = demo->evlist; 15.317 + } 15.318 + 15.319 + demo->start_tm = demo->src_tm - tm; 15.320 + demo->stoppage_tm = 0; 15.321 + demo->stop_tm = demo->src_tm; 15.322 + demo->tm = tm; 15.323 + 15.324 + /* recalculate events */ 15.325 + ev = demo->evlist; 15.326 + while(ev) { 15.327 + proc_event(ev, tm); 15.328 + ev = ev->next; 15.329 + } 15.330 +} 15.331 + 15.332 +void dsys_seek_norm(struct dsys_demo *demo, float t) 15.333 +{ 15.334 + dsys_seek(demo, t * demo->duration); 15.335 +} 15.336 + 15.337 +/* seek by accelerating time */ 15.338 +void dsys_warp(struct dsys_demo *demo, demotime_t tm) 15.339 +{ 15.340 + fprintf(stderr, "dsys_warp not implemented yet\n"); 15.341 +} 15.342 + 15.343 +void dsys_warp_norm(struct dsys_demo *demo, float t) 15.344 +{ 15.345 + dsys_warp(demo, t * demo->duration); 15.346 +} 15.347 + 15.348 + 15.349 +/* events */ 15.350 +struct dsys_event *dsys_event(struct dsys_demo *demo, const char *name) 15.351 +{ 15.352 + struct dsys_event *iter = demo->evlist; 15.353 + 15.354 + while(iter) { 15.355 + if(strcmp(iter->name, name) == 0) { 15.356 + return iter; 15.357 + } 15.358 + iter = iter->next; 15.359 + } 15.360 + return 0; 15.361 +} 15.362 + 15.363 +enum dsys_evtype dsys_event_type(struct dsys_event *ev) 15.364 +{ 15.365 + return ev->type; 15.366 +} 15.367 + 15.368 +float dsys_event_value(struct dsys_event *ev) 15.369 +{ 15.370 + return ev->val; 15.371 +} 15.372 + 15.373 +int dsys_event_callback(struct dsys_event *ev, void (*func)(struct dsys_event*, void*), void *cls) 15.374 +{ 15.375 + struct callback *cb; 15.376 + 15.377 + if(!(cb = malloc(sizeof *cb))) { 15.378 + perror("failed to allocate memory"); 15.379 + return -1; 15.380 + } 15.381 + cb->func = func; 15.382 + cb->cls = cls; 15.383 + cb->next = ev->cblist; 15.384 + ev->cblist = cb; 15.385 + return 0; 15.386 +} 15.387 + 15.388 +int dsys_event_link(struct dsys_event *ev, float *link) 15.389 +{ 15.390 + return dsys_event_callback(ev, link_callback, link); 15.391 +} 15.392 + 15.393 +static void link_callback(struct dsys_event *ev, void *cls) 15.394 +{ 15.395 + *(float*)cls = ev->val; 15.396 +} 15.397 + 15.398 + 15.399 +/* time conversion */ 15.400 +demotime_t dsys_sec_to_dtime(float sec) 15.401 +{ 15.402 + return sec; 15.403 +} 15.404 + 15.405 +demotime_t dsys_msec_to_dtime(unsigned long msec) 15.406 +{ 15.407 + return (demotime_t)msec / 1000.0; 15.408 +} 15.409 + 15.410 +float dsys_dtime_to_sec(demotime_t tm) 15.411 +{ 15.412 + return tm; 15.413 +} 15.414 + 15.415 +unsigned long dsys_dtime_to_msec(demotime_t tm) 15.416 +{ 15.417 + return (unsigned long)(tm * 1000.0); 15.418 +} 15.419 + 15.420 + 15.421 +float dsys_eval_step(struct dsys_event *ev, demotime_t t) 15.422 +{ 15.423 + return t >= ev->t1 ? 1.0 : 0.0; 15.424 +} 15.425 + 15.426 +#define CLAMP(x, low, high) ((x) < (low) ? (low) : ((x) > (high) ? (high) : (x))) 15.427 + 15.428 +float dsys_eval_lerp(struct dsys_event *ev, demotime_t t) 15.429 +{ 15.430 + float res = (t - ev->t0) / (ev->t1 - ev->t0); 15.431 + return CLAMP(res, 0.0, 1.0); 15.432 +} 15.433 + 15.434 +float dsys_eval_sigmoid(struct dsys_event *ev, demotime_t t) 15.435 +{ 15.436 + t = dsys_eval_lerp(ev, t); 15.437 + return 1.0 - (cos(t * M_PI) * 0.5 + 0.5); 15.438 +} 15.439 + 15.440 +static void free_event(struct dsys_event *ev) 15.441 +{ 15.442 + while(ev->cblist) { 15.443 + struct callback *cb = ev->cblist; 15.444 + ev->cblist = ev->cblist->next; 15.445 + free(cb); 15.446 + } 15.447 +} 15.448 + 15.449 +static struct dsys_event *sort_evlist(struct dsys_event *list, int num_ev) 15.450 +{ 15.451 + int i, num_left, num_right; 15.452 + struct dsys_event *left, *right, *node = list; 15.453 + 15.454 + if(num_ev < 2) { 15.455 + return list; 15.456 + } 15.457 + 15.458 + num_left = num_ev / 2; 15.459 + num_right = num_ev - num_left; 15.460 + 15.461 + for(i=0; i<num_ev/2; i++) { 15.462 + node = node->next; 15.463 + } 15.464 + 15.465 + if(node->prev) { 15.466 + node->prev->next = 0; 15.467 + node->prev = 0; 15.468 + } 15.469 + 15.470 + left = sort_evlist(list, num_left); 15.471 + right = sort_evlist(node, num_right); 15.472 + 15.473 + return merge_evlists(left, right); 15.474 +} 15.475 + 15.476 +static struct dsys_event *merge_evlists(struct dsys_event *list1, struct dsys_event *list2) 15.477 +{ 15.478 + struct dsys_event *head, *tail, *node; 15.479 + 15.480 + if(!list1) { 15.481 + return list2; 15.482 + } 15.483 + if(!list2) { 15.484 + return list1; 15.485 + } 15.486 + 15.487 + head = tail = 0; 15.488 + 15.489 + while(list1 && list2) { 15.490 + if(list1->t0 < list2->t0) { 15.491 + node = list1; 15.492 + list1 = list1->next; 15.493 + } else { 15.494 + node = list2; 15.495 + list2 = list2->next; 15.496 + } 15.497 + 15.498 + node->next = 0; 15.499 + node->prev = tail; 15.500 + 15.501 + if(!head) { 15.502 + head = node; 15.503 + } else { 15.504 + tail->next = node; 15.505 + } 15.506 + tail = node; 15.507 + } 15.508 + 15.509 + if(list1) { 15.510 + tail->next = list1; 15.511 + list1->prev = tail; 15.512 + } else if(list2) { 15.513 + tail->next = list2; 15.514 + list2->prev = tail; 15.515 + } 15.516 + 15.517 + return head; 15.518 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/src/dsys/dsys.h Sun Nov 01 00:09:12 2015 +0200 16.3 @@ -0,0 +1,71 @@ 16.4 +#ifndef DSYS2_H_ 16.5 +#define DSYS2_H_ 16.6 + 16.7 +#include <stdio.h> 16.8 + 16.9 +struct dsys_demo; 16.10 +struct dsys_event; 16.11 + 16.12 +typedef float demotime_t; 16.13 + 16.14 +enum dsys_evtype { 16.15 + DSYS_SINGLE, 16.16 + DSYS_PERIODIC 16.17 +}; 16.18 + 16.19 +#ifdef __cplusplus 16.20 +extern "C" { 16.21 +#endif 16.22 + 16.23 +struct dsys_demo *dsys_open(const char *fname); 16.24 +struct dsys_demo *dsys_open_stream(FILE *fp); 16.25 +void dsys_close(struct dsys_demo *demo); 16.26 + 16.27 +void dsys_update(struct dsys_demo *demo, demotime_t tm); 16.28 + 16.29 + 16.30 +void dsys_start(struct dsys_demo *demo); 16.31 +void dsys_stop(struct dsys_demo *demo); 16.32 +int dsys_is_running(struct dsys_demo *demo); 16.33 + 16.34 + 16.35 +demotime_t dsys_duration(struct dsys_demo *demo); 16.36 +demotime_t dsys_time(struct dsys_demo *demo); 16.37 +float dsys_progress(struct dsys_demo *demo); 16.38 + 16.39 +/* seek without continuity */ 16.40 +void dsys_seek(struct dsys_demo *demo, demotime_t tm); 16.41 +void dsys_seek_norm(struct dsys_demo *demo, float t); 16.42 + 16.43 +/* seek by accelerating time */ 16.44 +void dsys_warp(struct dsys_demo *demo, demotime_t tm); 16.45 +void dsys_warp_norm(struct dsys_demo *demo, float t); 16.46 + 16.47 + 16.48 +/* events */ 16.49 +struct dsys_event *dsys_event(struct dsys_demo *demo, const char *name); 16.50 + 16.51 +enum dsys_evtype dsys_event_type(struct dsys_event *ev); 16.52 +float dsys_event_value(struct dsys_event *ev); 16.53 + 16.54 +int dsys_event_callback(struct dsys_event *ev, void (*func)(struct dsys_event*, void*), void *cls); 16.55 +int dsys_event_link(struct dsys_event *ev, float *link); 16.56 + 16.57 +/* event evaluators */ 16.58 +float dsys_eval_step(struct dsys_event *ev, demotime_t t); 16.59 +float dsys_eval_lerp(struct dsys_event *ev, demotime_t t); 16.60 +float dsys_eval_sigmoid(struct dsys_event *ev, demotime_t t); 16.61 + 16.62 +/* time conversion */ 16.63 +demotime_t dsys_sec_to_dtime(float sec); 16.64 +demotime_t dsys_msec_to_dtime(unsigned long msec); 16.65 + 16.66 +float dsys_dtime_to_sec(demotime_t tm); 16.67 +unsigned long dsys_dtime_to_msec(demotime_t tm); 16.68 + 16.69 +#ifdef __cplusplus 16.70 +} 16.71 +#endif 16.72 + 16.73 + 16.74 +#endif /* DSYS2_H_ */
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/src/dsys/dsys_impl.h Sun Nov 01 00:09:12 2015 +0200 17.3 @@ -0,0 +1,40 @@ 17.4 +#ifndef DSYS_IMPL_H_ 17.5 +#define DSYS_IMPL_H_ 17.6 + 17.7 +#include "dsys.h" 17.8 + 17.9 +struct dsys_demo { 17.10 + demotime_t tm, src_tm, start_tm, stop_tm, duration; 17.11 + demotime_t stoppage_tm; 17.12 + 17.13 + struct dsys_event *evlist; 17.14 + int num_ev; 17.15 + 17.16 + struct dsys_event *nextev, *active; 17.17 + 17.18 + int running; 17.19 +}; 17.20 + 17.21 +struct callback { 17.22 + void (*func)(struct dsys_event*, void*); 17.23 + void *cls; 17.24 + 17.25 + struct callback *next; 17.26 +}; 17.27 + 17.28 + 17.29 +struct dsys_event { 17.30 + enum dsys_evtype type; 17.31 + 17.32 + char *name; 17.33 + demotime_t t0, t1; 17.34 + float val; 17.35 + 17.36 + float (*eval)(struct dsys_event*, demotime_t); 17.37 + 17.38 + struct callback *cblist; 17.39 + 17.40 + struct dsys_event *next, *prev; 17.41 +}; 17.42 + 17.43 +#endif /* DSYS_IMPL_H_ */
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/src/geom.cc Sun Nov 01 00:09:12 2015 +0200 18.3 @@ -0,0 +1,251 @@ 18.4 +#include <algorithm> 18.5 +#include <float.h> 18.6 +#include "geom.h" 18.7 + 18.8 +GeomObject::~GeomObject() 18.9 +{ 18.10 +} 18.11 + 18.12 + 18.13 +Sphere::Sphere() 18.14 +{ 18.15 + radius = 1.0; 18.16 +} 18.17 + 18.18 +Sphere::Sphere(const Vector3 ¢, float radius) 18.19 + : center(cent) 18.20 +{ 18.21 + this->radius = radius; 18.22 +} 18.23 + 18.24 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2) 18.25 +{ 18.26 + const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1); 18.27 + const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2); 18.28 + 18.29 + if(!sph1 || !sph2) { 18.30 + fprintf(stderr, "Sphere::set_union: arguments must be spheres"); 18.31 + return; 18.32 + } 18.33 + 18.34 + float dist = (sph1->center - sph2->center).length(); 18.35 + float surf_dist = dist - (sph1->radius + sph2->radius); 18.36 + float d1 = sph1->radius + surf_dist / 2.0; 18.37 + float d2 = sph2->radius + surf_dist / 2.0; 18.38 + float t = d1 / (d1 + d2); 18.39 + 18.40 + if(t < 0.0) t = 0.0; 18.41 + if(t > 1.0) t = 1.0; 18.42 + 18.43 + center = sph1->center * t + sph2->center * (1.0 - t); 18.44 + radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius); 18.45 +} 18.46 + 18.47 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2) 18.48 +{ 18.49 + fprintf(stderr, "Sphere::intersection undefined\n"); 18.50 +} 18.51 + 18.52 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const 18.53 +{ 18.54 + float a = dot_product(ray.dir, ray.dir); 18.55 + float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) + 18.56 + 2.0 * ray.dir.y * (ray.origin.y - center.y) + 18.57 + 2.0 * ray.dir.z * (ray.origin.z - center.z); 18.58 + float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) - 18.59 + 2.0 * dot_product(ray.origin, center) - radius * radius; 18.60 + 18.61 + float discr = b * b - 4.0 * a * c; 18.62 + if(discr < 1e-4) { 18.63 + return false; 18.64 + } 18.65 + 18.66 + float sqrt_discr = sqrt(discr); 18.67 + float t0 = (-b + sqrt_discr) / (2.0 * a); 18.68 + float t1 = (-b - sqrt_discr) / (2.0 * a); 18.69 + 18.70 + if(t0 < 1e-4) 18.71 + t0 = t1; 18.72 + if(t1 < 1e-4) 18.73 + t1 = t0; 18.74 + 18.75 + float t = t0 < t1 ? t0 : t1; 18.76 + if(t < 1e-4) { 18.77 + return false; 18.78 + } 18.79 + 18.80 + // fill the HitPoint structure 18.81 + if(hit) { 18.82 + hit->obj = this; 18.83 + hit->dist = t; 18.84 + hit->pos = ray.origin + ray.dir * t; 18.85 + hit->normal = (hit->pos - center) / radius; 18.86 + } 18.87 + return true; 18.88 +} 18.89 + 18.90 + 18.91 +AABox::AABox() 18.92 +{ 18.93 +} 18.94 + 18.95 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax) 18.96 + : min(vmin), max(vmax) 18.97 +{ 18.98 +} 18.99 + 18.100 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2) 18.101 +{ 18.102 + const AABox *box1 = dynamic_cast<const AABox*>(obj1); 18.103 + const AABox *box2 = dynamic_cast<const AABox*>(obj2); 18.104 + 18.105 + if(!box1 || !box2) { 18.106 + fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n"); 18.107 + return; 18.108 + } 18.109 + 18.110 + min.x = std::min(box1->min.x, box2->min.x); 18.111 + min.y = std::min(box1->min.y, box2->min.y); 18.112 + min.z = std::min(box1->min.z, box2->min.z); 18.113 + 18.114 + max.x = std::max(box1->max.x, box2->max.x); 18.115 + max.y = std::max(box1->max.y, box2->max.y); 18.116 + max.z = std::max(box1->max.z, box2->max.z); 18.117 +} 18.118 + 18.119 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2) 18.120 +{ 18.121 + const AABox *box1 = dynamic_cast<const AABox*>(obj1); 18.122 + const AABox *box2 = dynamic_cast<const AABox*>(obj2); 18.123 + 18.124 + if(!box1 || !box2) { 18.125 + fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n"); 18.126 + return; 18.127 + } 18.128 + 18.129 + for(int i=0; i<3; i++) { 18.130 + min[i] = std::max(box1->min[i], box2->min[i]); 18.131 + max[i] = std::min(box1->max[i], box2->max[i]); 18.132 + 18.133 + if(max[i] < min[i]) { 18.134 + max[i] = min[i]; 18.135 + } 18.136 + } 18.137 +} 18.138 + 18.139 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const 18.140 +{ 18.141 + Vector3 param[2] = {min, max}; 18.142 + Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); 18.143 + int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; 18.144 + 18.145 + float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; 18.146 + float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; 18.147 + float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; 18.148 + float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; 18.149 + 18.150 + if(tmin > tymax || tymin > tmax) { 18.151 + return false; 18.152 + } 18.153 + if(tymin > tmin) { 18.154 + tmin = tymin; 18.155 + } 18.156 + if(tymax < tmax) { 18.157 + tmax = tymax; 18.158 + } 18.159 + 18.160 + float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; 18.161 + float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; 18.162 + 18.163 + if(tmin > tzmax || tzmin > tmax) { 18.164 + return false; 18.165 + } 18.166 + if(tzmin > tmin) { 18.167 + tmin = tzmin; 18.168 + } 18.169 + if(tzmax < tmax) { 18.170 + tmax = tzmax; 18.171 + } 18.172 + 18.173 + float t = tmin < 1e-4 ? tmax : tmin; 18.174 + if(t >= 1e-4) { 18.175 + 18.176 + if(hit) { 18.177 + hit->obj = this; 18.178 + hit->dist = t; 18.179 + hit->pos = ray.origin + ray.dir * t; 18.180 + 18.181 + float min_dist = FLT_MAX; 18.182 + Vector3 offs = min + (max - min) / 2.0; 18.183 + Vector3 local_hit = hit->pos - offs; 18.184 + 18.185 + static const Vector3 axis[] = { 18.186 + Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) 18.187 + }; 18.188 + //int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}}; 18.189 + 18.190 + for(int i=0; i<3; i++) { 18.191 + float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i])); 18.192 + if(dist < min_dist) { 18.193 + min_dist = dist; 18.194 + hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0); 18.195 + //hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]); 18.196 + } 18.197 + } 18.198 + } 18.199 + return true; 18.200 + } 18.201 + return false; 18.202 + 18.203 +} 18.204 + 18.205 +Plane::Plane() 18.206 + : normal(0.0, 1.0, 0.0) 18.207 +{ 18.208 +} 18.209 + 18.210 +Plane::Plane(const Vector3 &p, const Vector3 &norm) 18.211 + : pt(p) 18.212 +{ 18.213 + normal = norm.normalized(); 18.214 +} 18.215 + 18.216 +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3) 18.217 + : pt(p1) 18.218 +{ 18.219 + normal = cross_product(p2 - p1, p3 - p1).normalized(); 18.220 +} 18.221 + 18.222 +Plane::Plane(const Vector3 &normal, float dist) 18.223 +{ 18.224 + this->normal = normal.normalized(); 18.225 + pt = this->normal * dist; 18.226 +} 18.227 + 18.228 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2) 18.229 +{ 18.230 + fprintf(stderr, "Plane::set_union undefined\n"); 18.231 +} 18.232 + 18.233 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2) 18.234 +{ 18.235 + fprintf(stderr, "Plane::set_intersection undefined\n"); 18.236 +} 18.237 + 18.238 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const 18.239 +{ 18.240 + float ndotdir = dot_product(normal, ray.dir); 18.241 + if(fabs(ndotdir) < 1e-4) { 18.242 + return false; 18.243 + } 18.244 + 18.245 + if(hit) { 18.246 + Vector3 ptdir = pt - ray.origin; 18.247 + float t = dot_product(normal, ptdir) / ndotdir; 18.248 + 18.249 + hit->pos = ray.origin + ray.dir * t; 18.250 + hit->normal = normal; 18.251 + hit->obj = this; 18.252 + } 18.253 + return true; 18.254 +}
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/src/geom.h Sun Nov 01 00:09:12 2015 +0200 19.3 @@ -0,0 +1,70 @@ 19.4 +#ifndef GEOMOBJ_H_ 19.5 +#define GEOMOBJ_H_ 19.6 + 19.7 +#include "vmath/vmath.h" 19.8 + 19.9 +class GeomObject; 19.10 +class SceneNode; 19.11 + 19.12 +struct HitPoint { 19.13 + float dist; //< parametric distance along the ray 19.14 + Vector3 pos; //< position of intersection (orig + dir * dist) 19.15 + Vector3 normal; //< normal at the point of intersection 19.16 + const void *obj; //< pointer to the intersected object 19.17 + const SceneNode *node; 19.18 + Ray ray; 19.19 +}; 19.20 + 19.21 +class GeomObject { 19.22 +public: 19.23 + virtual ~GeomObject(); 19.24 + 19.25 + virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0; 19.26 + virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0; 19.27 + 19.28 + virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0; 19.29 +}; 19.30 + 19.31 +class Sphere : public GeomObject { 19.32 +public: 19.33 + Vector3 center; 19.34 + float radius; 19.35 + 19.36 + Sphere(); 19.37 + Sphere(const Vector3 ¢er, float radius); 19.38 + 19.39 + void set_union(const GeomObject *obj1, const GeomObject *obj2); 19.40 + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); 19.41 + 19.42 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 19.43 +}; 19.44 + 19.45 +class AABox : public GeomObject { 19.46 +public: 19.47 + Vector3 min, max; 19.48 + 19.49 + AABox(); 19.50 + AABox(const Vector3 &min, const Vector3 &max); 19.51 + 19.52 + void set_union(const GeomObject *obj1, const GeomObject *obj2); 19.53 + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); 19.54 + 19.55 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 19.56 +}; 19.57 + 19.58 +class Plane : public GeomObject { 19.59 +public: 19.60 + Vector3 pt, normal; 19.61 + 19.62 + Plane(); 19.63 + Plane(const Vector3 &pt, const Vector3 &normal); 19.64 + Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3); 19.65 + Plane(const Vector3 &normal, float dist); 19.66 + 19.67 + void set_union(const GeomObject *obj1, const GeomObject *obj2); 19.68 + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); 19.69 + 19.70 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 19.71 +}; 19.72 + 19.73 +#endif // GEOMOBJ_H_
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/src/image.cc Sun Nov 01 00:09:12 2015 +0200 20.3 @@ -0,0 +1,365 @@ 20.4 +#include <string.h> 20.5 +#include <stdlib.h> 20.6 +#include <alloca.h> 20.7 +#include "opengl.h" 20.8 +#include "image.h" 20.9 +#include "imago2.h" 20.10 + 20.11 + 20.12 +static unsigned int next_pow2(unsigned int x); 20.13 + 20.14 +Image::Image() 20.15 +{ 20.16 + width = height = tex_width = tex_height = 0; 20.17 + pixels = 0; 20.18 + tex = 0; 20.19 + tex_valid = false; 20.20 +} 20.21 + 20.22 +Image::~Image() 20.23 +{ 20.24 + destroy(); 20.25 +} 20.26 + 20.27 +Image::Image(const Image &img) 20.28 +{ 20.29 + pixels = 0; 20.30 + create(img.width, img.height, img.pixels); 20.31 +} 20.32 + 20.33 +Image &Image::operator =(const Image &img) 20.34 +{ 20.35 + if(&img != this) { 20.36 + create(img.width, img.height, img.pixels); 20.37 + } 20.38 + return *this; 20.39 +} 20.40 + 20.41 +bool Image::create(int width, int height, unsigned char *pixels) 20.42 +{ 20.43 + destroy(); 20.44 + 20.45 + try { 20.46 + unsigned char *tmp = new unsigned char[width * height * 4]; 20.47 + this->pixels = tmp; 20.48 + this->width = width; 20.49 + this->height = height; 20.50 + } 20.51 + catch(...) { 20.52 + return false; 20.53 + } 20.54 + 20.55 + if(pixels) { 20.56 + memcpy(this->pixels, pixels, width * height * 4); 20.57 + } 20.58 + return true; 20.59 +} 20.60 + 20.61 +void Image::destroy() 20.62 +{ 20.63 + delete [] pixels; 20.64 + pixels = 0; 20.65 + width = height = 0; 20.66 + 20.67 + if(tex) { 20.68 + glDeleteTextures(1, &tex); 20.69 + tex = 0; 20.70 + tex_valid = false; 20.71 + } 20.72 +} 20.73 + 20.74 +bool Image::load(const char *fname) 20.75 +{ 20.76 + int xsz, ysz; 20.77 + unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32); 20.78 + if(!pix) { 20.79 + return false; 20.80 + } 20.81 + return create(xsz, ysz, pix); 20.82 +} 20.83 + 20.84 +bool Image::save(const char *fname) const 20.85 +{ 20.86 + return img_save_pixels(fname, pixels, width, height, IMG_FMT_RGBA32) != -1; 20.87 +} 20.88 + 20.89 +unsigned int Image::texture() const 20.90 +{ 20.91 + if(!pixels) { 20.92 + return 0; 20.93 + } 20.94 + if(!tex) { 20.95 + glGenTextures(1, &tex); 20.96 + } 20.97 + 20.98 + if(!tex_valid) { 20.99 + tex_width = next_pow2(width); 20.100 + tex_height = next_pow2(height); 20.101 + 20.102 + glBindTexture(GL_TEXTURE_2D, tex); 20.103 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 20.104 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 20.105 + 20.106 + if(GLEW_SGIS_generate_mipmap) { 20.107 + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1); 20.108 + 20.109 + void *data = (width == tex_width && height == tex_height) ? pixels : 0; 20.110 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 20.111 + if(!data) { 20.112 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 20.113 + } 20.114 + } else { 20.115 + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 20.116 + } 20.117 + 20.118 + if(GLEW_EXT_texture_filter_anisotropic) { 20.119 + static float max_aniso = -1.0; 20.120 + 20.121 + if(max_aniso < 0.0) { 20.122 + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso); 20.123 + printf("using anisotropic filtering: x%g\n", max_aniso); 20.124 + } 20.125 + 20.126 + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso); 20.127 + } 20.128 + tex_valid = true; 20.129 + } 20.130 + return tex; 20.131 +} 20.132 + 20.133 +int Image::texture_width() const 20.134 +{ 20.135 + return tex_width; 20.136 +} 20.137 + 20.138 +int Image::texture_height() const 20.139 +{ 20.140 + return tex_height; 20.141 +} 20.142 + 20.143 +void Image::invalidate_texture() 20.144 +{ 20.145 + tex_valid = false; 20.146 +} 20.147 + 20.148 + 20.149 +void clear_image(Image *img) 20.150 +{ 20.151 + clear_image(img, 0, 0, 0, 255); 20.152 +} 20.153 + 20.154 +void clear_image(Image *img, float r, float g, float b, float a) 20.155 +{ 20.156 + if(!img->pixels) { 20.157 + return; 20.158 + } 20.159 + 20.160 + unsigned char col[4]; 20.161 + unsigned char *ptr = img->pixels; 20.162 + int npix = img->width * img->height; 20.163 + 20.164 + col[0] = (int)(r * 255.0); 20.165 + col[1] = (int)(g * 255.0); 20.166 + col[2] = (int)(b * 255.0); 20.167 + col[3] = (int)(a * 255.0); 20.168 + 20.169 + for(int i=0; i<npix; i++) { 20.170 + for(int j=0; j<4; j++) { 20.171 + ptr[j] = col[j]; 20.172 + } 20.173 + ptr += 4; 20.174 + } 20.175 +} 20.176 + 20.177 +void clear_image_alpha(Image *img, float a) 20.178 +{ 20.179 + if(!img->pixels) { 20.180 + return; 20.181 + } 20.182 + 20.183 + unsigned char alpha = (int)(a * 255.0); 20.184 + unsigned char *ptr = img->pixels; 20.185 + int npix = img->width * img->height; 20.186 + 20.187 + for(int i=0; i<npix; i++) { 20.188 + ptr[3] = alpha; 20.189 + ptr += 4; 20.190 + } 20.191 +} 20.192 + 20.193 +bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op, float t) 20.194 +{ 20.195 + int xsz = dest->width; 20.196 + int ysz = dest->height; 20.197 + int npixels = xsz * ysz; 20.198 + int nbytes = npixels * 4; 20.199 + int tint = (int)(t * 255); 20.200 + 20.201 + if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) { 20.202 + return false; 20.203 + } 20.204 + 20.205 + unsigned char *dptr = dest->pixels; 20.206 + const unsigned char *aptr = aimg->pixels; 20.207 + const unsigned char *bptr = bimg->pixels; 20.208 + 20.209 + switch(op) { 20.210 + case IMG_OP_ADD: 20.211 + for(int i=0; i<nbytes; i++) { 20.212 + unsigned int x = *aptr++ + *bptr++; 20.213 + *dptr++ = x > 255 ? 255 : x; 20.214 + } 20.215 + break; 20.216 + 20.217 + case IMG_OP_SUB: 20.218 + for(int i=0; i<nbytes; i++) { 20.219 + int x = (int)*aptr++ - (int)*bptr++; 20.220 + *dptr++ = x < 0 ? 0 : x; 20.221 + } 20.222 + break; 20.223 + 20.224 + case IMG_OP_MUL: 20.225 + for(int i=0; i<nbytes; i++) { 20.226 + unsigned int x = ((unsigned int)*aptr++ * (unsigned int)*bptr++) >> 8; 20.227 + *dptr++ = x > 255 ? 255 : x; 20.228 + } 20.229 + break; 20.230 + 20.231 + case IMG_OP_LERP: 20.232 + for(int i=0; i<nbytes; i++) { 20.233 + int x = (int)*aptr + ((((int)*bptr - (int)*aptr) * tint) >> 8); 20.234 + *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x); 20.235 + } 20.236 + break; 20.237 + 20.238 + default: 20.239 + break; 20.240 + } 20.241 + 20.242 + dest->invalidate_texture(); 20.243 + return true; 20.244 +} 20.245 + 20.246 +void convolve_horiz_image(Image *dest, float *kern, int ksz, float scale) 20.247 +{ 20.248 + if((ksz & 1) == 0) { 20.249 + fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz); 20.250 + --ksz; 20.251 + } 20.252 + if(scale == 0.0) { 20.253 + // calculate scale factor 20.254 + float sum = 0.0; 20.255 + for(int i=0; i<ksz; i++) { 20.256 + sum += kern[i]; 20.257 + } 20.258 + scale = 1.0 / sum; 20.259 + } 20.260 + int krad = ksz / 2; 20.261 + float *buf = (float*)alloca(dest->width * 4 * sizeof *buf); 20.262 + unsigned char *sptr = dest->pixels; 20.263 + 20.264 + for(int i=0; i<dest->height; i++) { 20.265 + float *bptr = buf; 20.266 + for(int j=0; j<dest->width * 4; j++) { 20.267 + *bptr++ = (float)(sptr[j] / 255.0); 20.268 + } 20.269 + 20.270 + for(int j=0; j<dest->width; j++) { 20.271 + float col[] = {0, 0, 0, 0}; 20.272 + 20.273 + for(int k=0; k<ksz; k++) { 20.274 + int idx = j + k - krad; 20.275 + if(idx < 0) idx = 0; 20.276 + if(idx >= dest->width) idx = dest->width - 1; 20.277 + 20.278 + col[0] += buf[idx * 4] * kern[k]; 20.279 + col[1] += buf[idx * 4 + 1] * kern[k]; 20.280 + col[2] += buf[idx * 4 + 2] * kern[k]; 20.281 + col[3] += buf[idx * 4 + 3] * kern[k]; 20.282 + } 20.283 + 20.284 + int ri = (int)(col[0] * scale * 255.0); 20.285 + int gi = (int)(col[1] * scale * 255.0); 20.286 + int bi = (int)(col[2] * scale * 255.0); 20.287 + int ai = (int)(col[3] * scale * 255.0); 20.288 + 20.289 + sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri); 20.290 + sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi); 20.291 + sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi); 20.292 + sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai); 20.293 + sptr += 4; 20.294 + } 20.295 + } 20.296 + 20.297 + dest->invalidate_texture(); 20.298 +} 20.299 + 20.300 +void convolve_vert_image(Image *dest, float *kern, int ksz, float scale) 20.301 +{ 20.302 + if((ksz & 1) == 0) { 20.303 + fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz); 20.304 + --ksz; 20.305 + } 20.306 + if(scale == 0.0) { 20.307 + // calculate scale factor 20.308 + float sum = 0.0; 20.309 + for(int i=0; i<ksz; i++) { 20.310 + sum += kern[i]; 20.311 + } 20.312 + scale = 1.0 / sum; 20.313 + } 20.314 + int krad = ksz / 2; 20.315 + float *buf = (float*)alloca(dest->height * 4 * sizeof *buf); 20.316 + unsigned char *sptr = dest->pixels; 20.317 + 20.318 + for(int i=0; i<dest->width; i++) { 20.319 + float *bptr = buf; 20.320 + sptr = dest->pixels + i * 4; 20.321 + 20.322 + for(int j=0; j<dest->height; j++) { 20.323 + for(int k=0; k<4; k++) { 20.324 + *bptr++ = (float)(sptr[k] / 255.0); 20.325 + } 20.326 + sptr += dest->width * 4; 20.327 + } 20.328 + 20.329 + sptr = dest->pixels + i * 4; 20.330 + 20.331 + for(int j=0; j<dest->height; j++) { 20.332 + float col[] = {0, 0, 0, 0}; 20.333 + 20.334 + for(int k=0; k<ksz; k++) { 20.335 + int idx = j + k - krad; 20.336 + if(idx < 0) idx = 0; 20.337 + if(idx >= dest->height) idx = dest->height - 1; 20.338 + 20.339 + col[0] += buf[idx * 4] * kern[k]; 20.340 + col[1] += buf[idx * 4 + 1] * kern[k]; 20.341 + col[2] += buf[idx * 4 + 2] * kern[k]; 20.342 + col[3] += buf[idx * 4 + 3] * kern[k]; 20.343 + } 20.344 + 20.345 + int ri = (int)(col[0] * scale * 255.0); 20.346 + int gi = (int)(col[1] * scale * 255.0); 20.347 + int bi = (int)(col[2] * scale * 255.0); 20.348 + int ai = (int)(col[3] * scale * 255.0); 20.349 + 20.350 + sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri); 20.351 + sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi); 20.352 + sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi); 20.353 + sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai); 20.354 + sptr += dest->width * 4; 20.355 + } 20.356 + } 20.357 +} 20.358 + 20.359 +static unsigned int next_pow2(unsigned int x) 20.360 +{ 20.361 + x--; 20.362 + x = (x >> 1) | x; 20.363 + x = (x >> 2) | x; 20.364 + x = (x >> 4) | x; 20.365 + x = (x >> 8) | x; 20.366 + x = (x >> 16) | x; 20.367 + return x + 1; 20.368 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/src/image.h Sun Nov 01 00:09:12 2015 +0200 21.3 @@ -0,0 +1,49 @@ 21.4 +#ifndef IMAGE_H_ 21.5 +#define IMAGE_H_ 21.6 + 21.7 +class Image { 21.8 +private: 21.9 + mutable int tex_width, tex_height; 21.10 + mutable unsigned int tex; 21.11 + mutable bool tex_valid; 21.12 + 21.13 +public: 21.14 + int width, height; 21.15 + unsigned char *pixels; 21.16 + 21.17 + Image(); 21.18 + ~Image(); 21.19 + 21.20 + Image(const Image &img); 21.21 + Image &operator =(const Image &img); 21.22 + 21.23 + bool create(int width, int height, unsigned char *pixels = 0); 21.24 + void destroy(); 21.25 + 21.26 + bool load(const char *fname); 21.27 + bool save(const char *fname) const; 21.28 + 21.29 + unsigned int texture() const; 21.30 + int texture_width() const; 21.31 + int texture_height() const; 21.32 + 21.33 + void invalidate_texture(); 21.34 +}; 21.35 + 21.36 +void clear_image(Image *img); 21.37 +void clear_image(Image *img, float r, float g, float b, float a = 255); 21.38 +void clear_image_alpha(Image *img, float a); 21.39 + 21.40 +enum ImgCombine { 21.41 + IMG_OP_ADD, 21.42 + IMG_OP_SUB, 21.43 + IMG_OP_MUL, 21.44 + IMG_OP_LERP 21.45 +}; 21.46 + 21.47 +bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op = IMG_OP_LERP, float t = 0.5); 21.48 + 21.49 +void convolve_horiz_image(Image *dest, float *kern, int ksz, float scale = 0.0); 21.50 +void convolve_vert_image(Image *dest, float *kern, int ksz, float scale = 0.0); 21.51 + 21.52 +#endif // IMAGE_H_
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/src/light.cc Sun Nov 01 00:09:12 2015 +0200 22.3 @@ -0,0 +1,17 @@ 22.4 +#include "light.h" 22.5 +#include "opengl.h" 22.6 + 22.7 +Light::Light() 22.8 + : color(1, 1, 1) 22.9 +{ 22.10 +} 22.11 + 22.12 +void Light::setup(int idx) const 22.13 +{ 22.14 + float lpos[] = {pos.x, pos.y, pos.z, 1.0}; 22.15 + float col[] = {color.x, color.y, color.z, 1.0}; 22.16 + 22.17 + glLightfv(GL_LIGHT0 + idx, GL_POSITION, lpos); 22.18 + glLightfv(GL_LIGHT0 + idx, GL_DIFFUSE, col); 22.19 + glLightfv(GL_LIGHT0 + idx, GL_SPECULAR, col); 22.20 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 23.2 +++ b/src/light.h Sun Nov 01 00:09:12 2015 +0200 23.3 @@ -0,0 +1,16 @@ 23.4 +#ifndef LIGHT_H_ 23.5 +#define LIGHT_H_ 23.6 + 23.7 +#include "vmath/vmath.h" 23.8 + 23.9 +class Light { 23.10 +public: 23.11 + Vector3 pos; 23.12 + Vector3 color; 23.13 + 23.14 + Light(); 23.15 + 23.16 + void setup(int idx = 0) const; 23.17 +}; 23.18 + 23.19 +#endif // LIGHT_H_
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/src/main.cc Sun Nov 01 00:09:12 2015 +0200 24.3 @@ -0,0 +1,409 @@ 24.4 +#include <stdio.h> 24.5 +#include <stdlib.h> 24.6 +#include <assert.h> 24.7 +#include <vector> 24.8 +#include "opengl.h" 24.9 +#include <GL/glut.h> 24.10 +#include "scene.h" 24.11 +#include "meshgen.h" 24.12 +#include "pnoise.h" 24.13 +#include "image.h" 24.14 +#include "rng.h" 24.15 +#include "sdr.h" 24.16 +#include "audio/audio.h" 24.17 +#include "audio/ovstream.h" 24.18 +#include "dsys/dsys.h" 24.19 + 24.20 +bool init(); 24.21 +void cleanup(); 24.22 +void display(); 24.23 +void idle(); 24.24 +void reshape(int x, int y); 24.25 +void keyb(unsigned char key, int x, int y); 24.26 +void mouse(int bn, int st, int x, int y); 24.27 +void motion(int x, int y); 24.28 + 24.29 +float cam_theta, cam_phi = 25, cam_dist = 6; 24.30 +Scene *scn; 24.31 +bool wireframe; 24.32 +int num_shells = 64; 24.33 +float shell_scale = 1.015; 24.34 +bool anim = true; 24.35 +bool fullscr = true; 24.36 + 24.37 +static std::vector<Image*> images; 24.38 +static Object *pkin_obj; 24.39 +static Mesh *pkin_mesh; 24.40 +static unsigned int pkin_tex; 24.41 + 24.42 +static unsigned int sdr_spot; 24.43 + 24.44 +static float ramp[3]; 24.45 + 24.46 + 24.47 +static OggVorbisStream *music; 24.48 +static struct dsys_demo *demo; 24.49 + 24.50 + 24.51 +int main(int argc, char **argv) 24.52 +{ 24.53 + glutInit(&argc, argv); 24.54 + glutInitWindowSize(1280, 720); 24.55 + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 24.56 + glutCreateWindow("DBF Halloween 2015 compo entry"); 24.57 + 24.58 + if(argv[1]) { 24.59 + if(strcmp(argv[1], "-w") == 0 || strcmp(argv[1], "-windowed") == 0) { 24.60 + fullscr = false; 24.61 + } else { 24.62 + fprintf(stderr, "unrecognized argument: %s\nUse -w or -windowed to run in a window\n", argv[1]); 24.63 + return 1; 24.64 + } 24.65 + } 24.66 + if(fullscr) { 24.67 + glutFullScreen(); 24.68 + } 24.69 + 24.70 + glutDisplayFunc(display); 24.71 + glutIdleFunc(idle); 24.72 + glutReshapeFunc(reshape); 24.73 + glutKeyboardFunc(keyb); 24.74 + glutMouseFunc(mouse); 24.75 + glutMotionFunc(motion); 24.76 + 24.77 + if(!init()) { 24.78 + return 1; 24.79 + } 24.80 + glutMainLoop(); 24.81 + return 0; 24.82 +} 24.83 + 24.84 +static float ground_func(float u, float v, void *cls) 24.85 +{ 24.86 + return fbm2(u * 3.0, v * 3.0, 2) * 0.8; 24.87 +} 24.88 + 24.89 +static Vector2 pumpkin_func(float u, float v, void *cls) 24.90 +{ 24.91 + float theta = v * M_PI; 24.92 + float r = sin(theta) * 0.5 + 0.5; 24.93 + 24.94 + // modulate a high-frequency short-amp wave along u to make the ribs(?) 24.95 + r += fabs(sin(u * M_PI * 12.0)) * 0.02;// + 1.0; 24.96 + 24.97 + // throw some noise in there for good measure 24.98 + r += pnoise2(u * 16.0, v * 8.0, 16) * 0.05;// + 1.0; 24.99 + 24.100 + float x = sin(theta) * r; 24.101 + float y = cos(theta) * r; 24.102 + return Vector2(x, y); 24.103 +} 24.104 + 24.105 +#define CLAMP(x, a, b) std::max<float>(std::min<float>(x, b), a) 24.106 + 24.107 +bool init() 24.108 +{ 24.109 + if(init_opengl() == -1) { 24.110 + return false; 24.111 + } 24.112 + Mesh::use_custom_sdr_attr = false; 24.113 + 24.114 + glEnable(GL_DEPTH_TEST); 24.115 + glEnable(GL_CULL_FACE); 24.116 + glEnable(GL_LIGHTING); 24.117 + glEnable(GL_NORMALIZE); 24.118 + 24.119 + if(!(demo = dsys_open("data/demo.script"))) { 24.120 + fprintf(stderr, "failed to load sequencing file\n"); 24.121 + return false; 24.122 + } 24.123 + for(int i=0; i<3; i++) { 24.124 + char name[16]; 24.125 + sprintf(name, "ramp%d", i); 24.126 + struct dsys_event *ev = dsys_event(demo, name); 24.127 + if(ev) { 24.128 + printf("found event: %s\n", name); 24.129 + dsys_event_link(ev, ramp + i); 24.130 + } 24.131 + } 24.132 + 24.133 + 24.134 + if(!(sdr_spot = create_program_load("sdr/default.v.glsl", "sdr/spot.p.glsl"))) { 24.135 + return false; 24.136 + } 24.137 + 24.138 + Matrix4x4 xform; 24.139 + 24.140 + scn = new Scene; 24.141 + 24.142 + Light *lt = new Light; 24.143 + lt->pos = Vector3(-10, 10, 10); 24.144 + scn->add_light(lt); 24.145 + 24.146 + // floor 24.147 + Mesh *mesh = new Mesh; 24.148 + gen_heightmap(mesh, 20, 20, 50, 50, ground_func); 24.149 + xform.set_rotation(Vector3(-M_PI / 2.0, 0, 0)); 24.150 + mesh->apply_xform(xform); 24.151 + 24.152 + Object *obj = new Object; 24.153 + obj->set_mesh(mesh); 24.154 + obj->xform().set_translation(Vector3(0, -0.9, 0)); 24.155 + obj->mtl.diffuse = Vector3(0.7, 0.7, 0.7); 24.156 + obj->set_shader(sdr_spot); 24.157 + scn->add_object(obj); 24.158 + 24.159 + Image *img = new Image; 24.160 + if(!img->load("data/grass02.jpg")) { 24.161 + return false; 24.162 + } 24.163 + images.push_back(img); 24.164 + obj->tex_xform().set_scaling(Vector3(5.0, 10.0, 1.0)); 24.165 + obj->set_texture(img->texture()); 24.166 + 24.167 + // pumpkin texture 24.168 + img = new Image; 24.169 + if(!img->create(1024, 512)) { 24.170 + return false; 24.171 + } 24.172 + images.push_back(img); 24.173 + 24.174 + static const Vector3 pkin_col = Vector3(0.824, 0.325, 0.063); 24.175 + unsigned char *pptr = img->pixels; 24.176 + for(int i=0; i<img->height; i++) { 24.177 + float v = (float)i / (float)img->height; 24.178 + for(int j=0; j<img->width; j++) { 24.179 + float u = (float)j / (float)img->width; 24.180 + 24.181 + float val = pfbm2(u * 64.0, v * 32.0, 3, 128) * 0.1 + 1.0; 24.182 + val *= fabs(sin(u * M_PI * 12.0)) * 0.2 + 0.8; 24.183 + Vector3 col = pkin_col * val; 24.184 + 24.185 + *pptr++ = (int)(CLAMP(col.x, 0.0, 1.0) * 255.0f); 24.186 + *pptr++ = (int)(CLAMP(col.y, 0.0, 1.0) * 255.0f); 24.187 + *pptr++ = (int)(CLAMP(col.z, 0.0, 1.0) * 255.0f); 24.188 + *pptr++ = 255; 24.189 + } 24.190 + } 24.191 + 24.192 + // pumpkin 24.193 + pkin_mesh = new Mesh; 24.194 + gen_revol(pkin_mesh, 64, 20, pumpkin_func); 24.195 + 24.196 + pkin_obj = new Object; 24.197 + pkin_obj->xform().set_rotation(Vector3(DEG_TO_RAD(-10), DEG_TO_RAD(90), 0)); 24.198 + pkin_obj->set_mesh(pkin_mesh); 24.199 + pkin_obj->set_texture(img->texture()); 24.200 + obj->set_shader(sdr_spot); 24.201 + scn->add_object(pkin_obj); 24.202 + 24.203 + int num_pumpkins = 20; 24.204 + float dtheta = 1.0 / (float)num_pumpkins; 24.205 + 24.206 + for(int i=0; i<num_pumpkins; i++) { 24.207 + float theta = (((float)i + rng_frand() * 0.5) * dtheta) * 2.0 * M_PI * 2.0; 24.208 + float r = 5.0 * (float)i / (float)num_pumpkins + 4.0; 24.209 + 24.210 + float x = cos(theta) * r; 24.211 + float y = sin(theta) * r; 24.212 + 24.213 + float tu = (x + 10.0) / 20.0; 24.214 + float tv = (10.0 - y) / 20.0; 24.215 + float h = ground_func(tu, tv, 0); 24.216 + 24.217 + obj = new Object; 24.218 + obj->xform().translate(Vector3(x, h - 0.5, y)); 24.219 + obj->xform().rotate(Vector3(DEG_TO_RAD(rng_frand() * 40.0 - 20.0), rng_frand() * M_PI * 2.0, 0)); 24.220 + obj->xform().scale(Vector3(0.7, 0.7, 0.7)); 24.221 + obj->set_mesh(pkin_mesh); 24.222 + obj->set_texture(img->texture()); 24.223 + obj->set_shader(sdr_spot); 24.224 + scn->add_object(obj); 24.225 + } 24.226 + 24.227 + // pumpkin glow mask 24.228 + img = new Image; 24.229 + if(!img->load("data/pumpkin_mask_blured.png")) { 24.230 + return false; 24.231 + } 24.232 + images.push_back(img); 24.233 + pkin_tex = img->texture(); 24.234 + 24.235 + if(!init_audio()) { 24.236 + fprintf(stderr, "failed to initialize audio\n"); 24.237 + return false; 24.238 + } 24.239 + music = new OggVorbisStream; 24.240 + if(!music->open("data/welcome_to_horrorland.ogg")) { 24.241 + fprintf(stderr, "failed to open music\n"); 24.242 + return false; 24.243 + } 24.244 + music->play(AUDIO_PLAYMODE_LOOP); 24.245 + 24.246 + return true; 24.247 +} 24.248 + 24.249 +void cleanup() 24.250 +{ 24.251 + music->stop(); 24.252 + delete music; 24.253 + destroy_audio(); 24.254 + 24.255 + delete scn; 24.256 + 24.257 + for(size_t i=0; i<images.size(); i++) { 24.258 + delete images[i]; 24.259 + } 24.260 + images.clear(); 24.261 +} 24.262 + 24.263 +void display() 24.264 +{ 24.265 + unsigned int msec = glutGet(GLUT_ELAPSED_TIME); 24.266 + float sec = (float)msec / 1000.0; 24.267 + 24.268 + dsys_update(demo, dsys_msec_to_dtime(msec)); 24.269 + if(!dsys_is_running(demo)) { 24.270 + exit(0); 24.271 + } 24.272 + 24.273 + float offs[3]; 24.274 + 24.275 + if(anim) { 24.276 + float t = sec * 0.5; 24.277 + cam_theta = cos(t) * 35.0;// + fbm1(t * 6.0, 1) * 2.0; 24.278 + cam_phi = sin(t * 2.0) * 10.0 + 25.0;// + fbm1(t * 8.0, 1) * 3.0; 24.279 + 24.280 + float mag = std::max(fmod(ramp[0], 1.0), std::max(fmod(ramp[1], 1.0), fmod(ramp[2], 1.0))) * 0.8 + 0.15; 24.281 + //printf("ramps: %g %g %g, mag: %g\n", ramp[0], ramp[1], ramp[2], mag); 24.282 + for(int i=0; i<3; i++) { 24.283 + offs[i] = turbulence1(sec * 4.0 + i, 2) * mag; 24.284 + } 24.285 + } 24.286 + 24.287 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 24.288 + 24.289 + glMatrixMode(GL_MODELVIEW); 24.290 + glLoadIdentity(); 24.291 + glTranslatef(0, 0, -cam_dist); 24.292 + glRotatef(cam_phi, 1, 0, 0); 24.293 + glRotatef(cam_theta, 0, 1, 0); 24.294 + glTranslatef(offs[0], offs[1], offs[2]); 24.295 + 24.296 + scn->draw(); 24.297 + 24.298 + glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT); 24.299 + glDisable(GL_CULL_FACE); 24.300 + 24.301 + glDepthMask(0); 24.302 + glEnable(GL_BLEND); 24.303 + glBlendFunc(GL_SRC_ALPHA, GL_ONE); 24.304 + 24.305 + glBindTexture(GL_TEXTURE_2D, pkin_tex); 24.306 + glEnable(GL_TEXTURE_2D); 24.307 + 24.308 + glMatrixMode(GL_MODELVIEW); 24.309 + glPushMatrix(); 24.310 + glMultTransposeMatrixf(pkin_obj->xform()[0]); 24.311 + 24.312 + num_shells = fbm1(sec * 2.0, 2) * 28.0 + 45; 24.313 + 24.314 + for(int i=0; i<num_shells; i++) { 24.315 + float x = (float)i / (float)num_shells; 24.316 + float alpha = 0.025 / (x * x); 24.317 + 24.318 + float black[] = {0, 0, 0, std::min(alpha, 1.0f) * 0.3f}; 24.319 + float glow_col[] = {0.7, 0.5, 0.25, 1.0}; 24.320 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); 24.321 + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); 24.322 + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, glow_col); 24.323 + 24.324 + glScalef(shell_scale, shell_scale, shell_scale); 24.325 + pkin_mesh->draw(); 24.326 + } 24.327 + glDepthMask(1); 24.328 + 24.329 + glPopMatrix(); 24.330 + glPopAttrib(); 24.331 + 24.332 + 24.333 + glutSwapBuffers(); 24.334 + assert(glGetError() == GL_NO_ERROR); 24.335 +} 24.336 + 24.337 +void idle() 24.338 +{ 24.339 + glutPostRedisplay(); 24.340 +} 24.341 + 24.342 +void reshape(int x, int y) 24.343 +{ 24.344 + glViewport(0, 0, x, y); 24.345 + 24.346 + glMatrixMode(GL_PROJECTION); 24.347 + glLoadIdentity(); 24.348 + gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); 24.349 +} 24.350 + 24.351 +void keyb(unsigned char key, int x, int y) 24.352 +{ 24.353 + switch(key) { 24.354 + case 27: 24.355 + exit(0); 24.356 + 24.357 + case 'w': 24.358 + wireframe = !wireframe; 24.359 + break; 24.360 + 24.361 + case 'f': 24.362 + case 'F': 24.363 + { 24.364 + static int prev_pos[2] = {50, 80}; 24.365 + 24.366 + fullscr = !fullscr; 24.367 + if(fullscr) { 24.368 + prev_pos[0] = glutGet(GLUT_WINDOW_X); 24.369 + prev_pos[1] = glutGet(GLUT_WINDOW_Y); 24.370 + glutFullScreen(); 24.371 + } else { 24.372 + glutPositionWindow(prev_pos[0], prev_pos[1]); 24.373 + } 24.374 + } 24.375 + break; 24.376 + } 24.377 +} 24.378 + 24.379 +static int prev_x, prev_y; 24.380 +static bool bnstate[16]; 24.381 + 24.382 +void mouse(int bn, int st, int x, int y) 24.383 +{ 24.384 + prev_x = x; 24.385 + prev_y = y; 24.386 + bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN; 24.387 + 24.388 + anim = !(st == GLUT_DOWN); 24.389 +} 24.390 + 24.391 +void motion(int x, int y) 24.392 +{ 24.393 + int dx = x - prev_x; 24.394 + int dy = y - prev_y; 24.395 + prev_x = x; 24.396 + prev_y = y; 24.397 + 24.398 + if(!dx && !dy) return; 24.399 + 24.400 + if(bnstate[0]) { 24.401 + //anim = false; 24.402 + cam_theta += dx * 0.5; 24.403 + cam_phi += dy * 0.5; 24.404 + if(cam_phi < -90) cam_phi = -90; 24.405 + if(cam_phi > 90) cam_phi = 90; 24.406 + } 24.407 + if(bnstate[2]) { 24.408 + //anim = false; 24.409 + cam_dist += dy * 0.1; 24.410 + if(cam_dist < 0.0) cam_dist = 0.0; 24.411 + } 24.412 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/src/mesh.cc Sun Nov 01 00:09:12 2015 +0200 25.3 @@ -0,0 +1,1237 @@ 25.4 +#include <stdio.h> 25.5 +#include <stdlib.h> 25.6 +#include <float.h> 25.7 +#include <assert.h> 25.8 +#include "opengl.h" 25.9 +#include "mesh.h" 25.10 +//#include "xform_node.h" 25.11 + 25.12 +#define USE_OLDGL 25.13 + 25.14 +bool Mesh::use_custom_sdr_attr = true; 25.15 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 }; 25.16 +/* 25.17 + (int)SDR_ATTR_VERTEX, 25.18 + (int)SDR_ATTR_NORMAL, 25.19 + (int)SDR_ATTR_TANGENT, 25.20 + (int)SDR_ATTR_TEXCOORD, 25.21 + (int)SDR_ATTR_COLOR, 25.22 + -1, -1}; 25.23 +*/ 25.24 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT; 25.25 +float Mesh::vertex_sel_dist = 0.01; 25.26 +float Mesh::vis_vecsize = 1.0; 25.27 + 25.28 +Mesh::Mesh() 25.29 +{ 25.30 + clear(); 25.31 + 25.32 + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); 25.33 + 25.34 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.35 + vattr[i].vbo = buffer_objects[i]; 25.36 + } 25.37 + ibo = buffer_objects[NUM_MESH_ATTR]; 25.38 + wire_ibo = 0; 25.39 +} 25.40 + 25.41 +Mesh::~Mesh() 25.42 +{ 25.43 + glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects); 25.44 + 25.45 + if(wire_ibo) { 25.46 + glDeleteBuffers(1, &wire_ibo); 25.47 + } 25.48 +} 25.49 + 25.50 +Mesh::Mesh(const Mesh &rhs) 25.51 +{ 25.52 + clear(); 25.53 + 25.54 + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); 25.55 + 25.56 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.57 + vattr[i].vbo = buffer_objects[i]; 25.58 + } 25.59 + ibo = buffer_objects[NUM_MESH_ATTR]; 25.60 + wire_ibo = 0; 25.61 + 25.62 + clone(rhs); 25.63 +} 25.64 + 25.65 +Mesh &Mesh::operator =(const Mesh &rhs) 25.66 +{ 25.67 + if(&rhs != this) { 25.68 + clone(rhs); 25.69 + } 25.70 + return *this; 25.71 +} 25.72 + 25.73 +bool Mesh::clone(const Mesh &m) 25.74 +{ 25.75 + clear(); 25.76 + 25.77 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.78 + if(m.has_attrib(i)) { 25.79 + m.get_attrib_data(i); // force validation of the actual data on the source mesh 25.80 + 25.81 + vattr[i].nelem = m.vattr[i].nelem; 25.82 + vattr[i].data = m.vattr[i].data; // copy the actual data 25.83 + vattr[i].data_valid = true; 25.84 + } 25.85 + } 25.86 + 25.87 + if(m.is_indexed()) { 25.88 + m.get_index_data(); // again, force validation 25.89 + 25.90 + // copy the index data 25.91 + idata = m.idata; 25.92 + idata_valid = true; 25.93 + } 25.94 + 25.95 + name = m.name; 25.96 + nverts = m.nverts; 25.97 + nfaces = m.nfaces; 25.98 + 25.99 + //bones = m.bones; 25.100 + 25.101 + memcpy(cur_val, m.cur_val, sizeof cur_val); 25.102 + 25.103 + aabb = m.aabb; 25.104 + aabb_valid = m.aabb_valid; 25.105 + bsph = m.bsph; 25.106 + bsph_valid = m.bsph_valid; 25.107 + 25.108 + hitface = m.hitface; 25.109 + hitvert = m.hitvert; 25.110 + 25.111 + intersect_mode = m.intersect_mode; 25.112 + vertex_sel_dist = m.vertex_sel_dist; 25.113 + vis_vecsize = m.vis_vecsize; 25.114 + 25.115 + return true; 25.116 +} 25.117 + 25.118 +void Mesh::set_name(const char *name) 25.119 +{ 25.120 + this->name = name; 25.121 +} 25.122 + 25.123 +const char *Mesh::get_name() const 25.124 +{ 25.125 + return name.c_str(); 25.126 +} 25.127 + 25.128 +bool Mesh::has_attrib(int attr) const 25.129 +{ 25.130 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 25.131 + return false; 25.132 + } 25.133 + 25.134 + // if neither of these is valid, then nobody has set this attribute 25.135 + return vattr[attr].vbo_valid || vattr[attr].data_valid; 25.136 +} 25.137 + 25.138 +bool Mesh::is_indexed() const 25.139 +{ 25.140 + return ibo_valid || idata_valid; 25.141 +} 25.142 + 25.143 +void Mesh::clear() 25.144 +{ 25.145 + //bones.clear(); 25.146 + 25.147 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.148 + vattr[i].nelem = 0; 25.149 + vattr[i].vbo_valid = false; 25.150 + vattr[i].data_valid = false; 25.151 + //vattr[i].sdr_loc = -1; 25.152 + vattr[i].data.clear(); 25.153 + } 25.154 + ibo_valid = idata_valid = false; 25.155 + idata.clear(); 25.156 + 25.157 + wire_ibo_valid = false; 25.158 + 25.159 + nverts = nfaces = 0; 25.160 + 25.161 + bsph_valid = false; 25.162 + aabb_valid = false; 25.163 +} 25.164 + 25.165 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data) 25.166 +{ 25.167 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 25.168 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 25.169 + return 0; 25.170 + } 25.171 + 25.172 + if(nverts && num != nverts) { 25.173 + fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts); 25.174 + return 0; 25.175 + } 25.176 + nverts = num; 25.177 + 25.178 + vattr[attrib].data.clear(); 25.179 + vattr[attrib].nelem = nelem; 25.180 + vattr[attrib].data.resize(num * nelem); 25.181 + 25.182 + if(data) { 25.183 + memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data); 25.184 + } 25.185 + 25.186 + vattr[attrib].data_valid = true; 25.187 + vattr[attrib].vbo_valid = false; 25.188 + return &vattr[attrib].data[0]; 25.189 +} 25.190 + 25.191 +float *Mesh::get_attrib_data(int attrib) 25.192 +{ 25.193 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 25.194 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 25.195 + return 0; 25.196 + } 25.197 + 25.198 + vattr[attrib].vbo_valid = false; 25.199 + return (float*)((const Mesh*)this)->get_attrib_data(attrib); 25.200 +} 25.201 + 25.202 +const float *Mesh::get_attrib_data(int attrib) const 25.203 +{ 25.204 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 25.205 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 25.206 + return 0; 25.207 + } 25.208 + 25.209 + if(!vattr[attrib].data_valid) { 25.210 +#if GL_ES_VERSION_2_0 25.211 + fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__); 25.212 + return 0; 25.213 +#else 25.214 + if(!vattr[attrib].vbo_valid) { 25.215 + fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib); 25.216 + return 0; 25.217 + } 25.218 + 25.219 + // local data copy is unavailable, grab the data from the vbo 25.220 + Mesh *m = (Mesh*)this; 25.221 + m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem); 25.222 + 25.223 + glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo); 25.224 + void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 25.225 + memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float)); 25.226 + glUnmapBuffer(GL_ARRAY_BUFFER); 25.227 + 25.228 + vattr[attrib].data_valid = true; 25.229 +#endif 25.230 + } 25.231 + 25.232 + return &vattr[attrib].data[0]; 25.233 +} 25.234 + 25.235 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v) 25.236 +{ 25.237 + float *data = get_attrib_data(attrib); 25.238 + if(data) { 25.239 + data += idx * vattr[attrib].nelem; 25.240 + for(int i=0; i<vattr[attrib].nelem; i++) { 25.241 + data[i] = v[i]; 25.242 + } 25.243 + } 25.244 +} 25.245 + 25.246 +Vector4 Mesh::get_attrib(int attrib, int idx) const 25.247 +{ 25.248 + Vector4 v(0.0, 0.0, 0.0, 1.0); 25.249 + const float *data = get_attrib_data(attrib); 25.250 + if(data) { 25.251 + data += idx * vattr[attrib].nelem; 25.252 + for(int i=0; i<vattr[attrib].nelem; i++) { 25.253 + v[i] = data[i]; 25.254 + } 25.255 + } 25.256 + return v; 25.257 +} 25.258 + 25.259 +int Mesh::get_attrib_count(int attrib) const 25.260 +{ 25.261 + return has_attrib(attrib) ? nverts : 0; 25.262 +} 25.263 + 25.264 + 25.265 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices) 25.266 +{ 25.267 + int nidx = nfaces * 3; 25.268 + if(nidx && num != nidx) { 25.269 + fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx); 25.270 + return 0; 25.271 + } 25.272 + nfaces = num / 3; 25.273 + 25.274 + idata.clear(); 25.275 + idata.resize(num); 25.276 + 25.277 + if(indices) { 25.278 + memcpy(&idata[0], indices, num * sizeof *indices); 25.279 + } 25.280 + 25.281 + idata_valid = true; 25.282 + ibo_valid = false; 25.283 + 25.284 + return &idata[0]; 25.285 +} 25.286 + 25.287 +unsigned int *Mesh::get_index_data() 25.288 +{ 25.289 + ibo_valid = false; 25.290 + return (unsigned int*)((const Mesh*)this)->get_index_data(); 25.291 +} 25.292 + 25.293 +const unsigned int *Mesh::get_index_data() const 25.294 +{ 25.295 + if(!idata_valid) { 25.296 +#if GL_ES_VERSION_2_0 25.297 + fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__); 25.298 + return 0; 25.299 +#else 25.300 + if(!ibo_valid) { 25.301 + fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__); 25.302 + return 0; 25.303 + } 25.304 + 25.305 + // local data copy is unavailable, gram the data from the ibo 25.306 + Mesh *m = (Mesh*)this; 25.307 + int nidx = nfaces * 3; 25.308 + m->idata.resize(nidx); 25.309 + 25.310 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 25.311 + void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); 25.312 + memcpy(&m->idata[0], data, nidx * sizeof(unsigned int)); 25.313 + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); 25.314 + 25.315 + idata_valid = true; 25.316 +#endif 25.317 + } 25.318 + 25.319 + return &idata[0]; 25.320 +} 25.321 + 25.322 +int Mesh::get_index_count() const 25.323 +{ 25.324 + return nfaces * 3; 25.325 +} 25.326 + 25.327 +void Mesh::append(const Mesh &mesh) 25.328 +{ 25.329 + unsigned int idxoffs = nverts; 25.330 + 25.331 + if(!nverts) { 25.332 + clone(mesh); 25.333 + return; 25.334 + } 25.335 + 25.336 + nverts += mesh.nverts; 25.337 + nfaces += mesh.nfaces; 25.338 + 25.339 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.340 + if(has_attrib(i) && mesh.has_attrib(i)) { 25.341 + // force validating the data arrays 25.342 + get_attrib_data(i); 25.343 + mesh.get_attrib_data(i); 25.344 + 25.345 + // append the mesh data 25.346 + vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end()); 25.347 + } 25.348 + } 25.349 + 25.350 + if(ibo_valid || idata_valid) { 25.351 + // make index arrays valid 25.352 + get_index_data(); 25.353 + mesh.get_index_data(); 25.354 + 25.355 + size_t orig_sz = idata.size(); 25.356 + 25.357 + idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end()); 25.358 + 25.359 + // fixup all the new indices 25.360 + for(size_t i=orig_sz; i<idata.size(); i++) { 25.361 + idata[i] += idxoffs; 25.362 + } 25.363 + } 25.364 + 25.365 + // fuck everything 25.366 + wire_ibo_valid = false; 25.367 + aabb_valid = false; 25.368 + bsph_valid = false; 25.369 +} 25.370 + 25.371 +// assemble a complete vertex by adding all the useful attributes 25.372 +void Mesh::vertex(float x, float y, float z) 25.373 +{ 25.374 + cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f); 25.375 + vattr[MESH_ATTR_VERTEX].data_valid = true; 25.376 + vattr[MESH_ATTR_VERTEX].nelem = 3; 25.377 + 25.378 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.379 + if(vattr[i].data_valid) { 25.380 + for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) { 25.381 + vattr[i].data.push_back(cur_val[i][j]); 25.382 + } 25.383 + } 25.384 + vattr[i].vbo_valid = false; 25.385 + } 25.386 + 25.387 + if(idata_valid) { 25.388 + idata.clear(); 25.389 + } 25.390 + ibo_valid = idata_valid = false; 25.391 +} 25.392 + 25.393 +void Mesh::normal(float nx, float ny, float nz) 25.394 +{ 25.395 + cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f); 25.396 + vattr[MESH_ATTR_NORMAL].data_valid = true; 25.397 + vattr[MESH_ATTR_NORMAL].nelem = 3; 25.398 +} 25.399 + 25.400 +void Mesh::tangent(float tx, float ty, float tz) 25.401 +{ 25.402 + cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f); 25.403 + vattr[MESH_ATTR_TANGENT].data_valid = true; 25.404 + vattr[MESH_ATTR_TANGENT].nelem = 3; 25.405 +} 25.406 + 25.407 +void Mesh::texcoord(float u, float v, float w) 25.408 +{ 25.409 + cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f); 25.410 + vattr[MESH_ATTR_TEXCOORD].data_valid = true; 25.411 + vattr[MESH_ATTR_TEXCOORD].nelem = 3; 25.412 +} 25.413 + 25.414 +void Mesh::boneweights(float w1, float w2, float w3, float w4) 25.415 +{ 25.416 + cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4); 25.417 + vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true; 25.418 + vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4; 25.419 +} 25.420 + 25.421 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4) 25.422 +{ 25.423 + cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4); 25.424 + vattr[MESH_ATTR_BONEIDX].data_valid = true; 25.425 + vattr[MESH_ATTR_BONEIDX].nelem = 4; 25.426 +} 25.427 + 25.428 +int Mesh::get_poly_count() const 25.429 +{ 25.430 + if(nfaces) { 25.431 + return nfaces; 25.432 + } 25.433 + if(nverts) { 25.434 + return nverts / 3; 25.435 + } 25.436 + return 0; 25.437 +} 25.438 + 25.439 +/// static function 25.440 +void Mesh::set_attrib_location(int attr, int loc) 25.441 +{ 25.442 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 25.443 + return; 25.444 + } 25.445 + Mesh::global_sdr_loc[attr] = loc; 25.446 +} 25.447 + 25.448 +/// static function 25.449 +int Mesh::get_attrib_location(int attr) 25.450 +{ 25.451 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 25.452 + return -1; 25.453 + } 25.454 + return Mesh::global_sdr_loc[attr]; 25.455 +} 25.456 + 25.457 +/// static function 25.458 +void Mesh::clear_attrib_locations() 25.459 +{ 25.460 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.461 + Mesh::global_sdr_loc[i] = -1; 25.462 + } 25.463 +} 25.464 + 25.465 +/// static function 25.466 +void Mesh::set_vis_vecsize(float sz) 25.467 +{ 25.468 + Mesh::vis_vecsize = sz; 25.469 +} 25.470 + 25.471 +float Mesh::get_vis_vecsize() 25.472 +{ 25.473 + return Mesh::vis_vecsize; 25.474 +} 25.475 + 25.476 +void Mesh::apply_xform(const Matrix4x4 &xform) 25.477 +{ 25.478 + Matrix4x4 dir_xform = xform; 25.479 + dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f; 25.480 + dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f; 25.481 + dir_xform[3][3] = 1.0f; 25.482 + 25.483 + apply_xform(xform, dir_xform); 25.484 +} 25.485 + 25.486 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform) 25.487 +{ 25.488 + for(unsigned int i=0; i<nverts; i++) { 25.489 + Vector4 v = get_attrib(MESH_ATTR_VERTEX, i); 25.490 + set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform)); 25.491 + 25.492 + if(has_attrib(MESH_ATTR_NORMAL)) { 25.493 + Vector3 n = get_attrib(MESH_ATTR_NORMAL, i); 25.494 + set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform)); 25.495 + } 25.496 + if(has_attrib(MESH_ATTR_TANGENT)) { 25.497 + Vector3 t = get_attrib(MESH_ATTR_TANGENT, i); 25.498 + set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform)); 25.499 + } 25.500 + } 25.501 +} 25.502 + 25.503 +void Mesh::flip() 25.504 +{ 25.505 + flip_faces(); 25.506 + flip_normals(); 25.507 +} 25.508 + 25.509 +void Mesh::flip_faces() 25.510 +{ 25.511 + if(is_indexed()) { 25.512 + unsigned int *indices = get_index_data(); 25.513 + if(!indices) return; 25.514 + 25.515 + int idxnum = get_index_count(); 25.516 + for(int i=0; i<idxnum; i+=3) { 25.517 + unsigned int tmp = indices[i + 2]; 25.518 + indices[i + 2] = indices[i + 1]; 25.519 + indices[i + 1] = tmp; 25.520 + } 25.521 + 25.522 + } else { 25.523 + Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); 25.524 + if(!verts) return; 25.525 + 25.526 + int vnum = get_attrib_count(MESH_ATTR_VERTEX); 25.527 + for(int i=0; i<vnum; i+=3) { 25.528 + Vector3 tmp = verts[i + 2]; 25.529 + verts[i + 2] = verts[i + 1]; 25.530 + verts[i + 1] = tmp; 25.531 + } 25.532 + } 25.533 +} 25.534 + 25.535 +void Mesh::flip_normals() 25.536 +{ 25.537 + Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); 25.538 + if(!normals) return; 25.539 + 25.540 + int num = get_attrib_count(MESH_ATTR_NORMAL); 25.541 + for(int i=0; i<num; i++) { 25.542 + normals[i] = -normals[i]; 25.543 + } 25.544 +} 25.545 + 25.546 +/* 25.547 +int Mesh::add_bone(XFormNode *bone) 25.548 +{ 25.549 + int idx = bones.size(); 25.550 + bones.push_back(bone); 25.551 + return idx; 25.552 +} 25.553 + 25.554 +const XFormNode *Mesh::get_bone(int idx) const 25.555 +{ 25.556 + if(idx < 0 || idx >= (int)bones.size()) { 25.557 + return 0; 25.558 + } 25.559 + return bones[idx]; 25.560 +} 25.561 + 25.562 +int Mesh::get_bones_count() const 25.563 +{ 25.564 + return (int)bones.size(); 25.565 +} 25.566 +*/ 25.567 + 25.568 +bool Mesh::pre_draw() const 25.569 +{ 25.570 + cur_sdr = 0; 25.571 + if(glcaps.shaders) { 25.572 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 25.573 + } 25.574 + 25.575 + ((Mesh*)this)->update_buffers(); 25.576 + 25.577 + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { 25.578 + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); 25.579 + return false; 25.580 + } 25.581 + 25.582 + if(cur_sdr && use_custom_sdr_attr) { 25.583 + // rendering with shaders 25.584 + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { 25.585 + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); 25.586 + return false; 25.587 + } 25.588 + 25.589 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.590 + int loc = global_sdr_loc[i]; 25.591 + if(loc >= 0 && vattr[i].vbo_valid) { 25.592 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 25.593 + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); 25.594 + glEnableVertexAttribArray(loc); 25.595 + } 25.596 + } 25.597 + } else { 25.598 +#ifndef GL_ES_VERSION_2_0 25.599 + // rendering with fixed-function (not available in GLES2) 25.600 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo); 25.601 + glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0); 25.602 + glEnableClientState(GL_VERTEX_ARRAY); 25.603 + 25.604 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 25.605 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo); 25.606 + glNormalPointer(GL_FLOAT, 0, 0); 25.607 + glEnableClientState(GL_NORMAL_ARRAY); 25.608 + } 25.609 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 25.610 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo); 25.611 + glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0); 25.612 + glEnableClientState(GL_TEXTURE_COORD_ARRAY); 25.613 + } 25.614 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 25.615 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo); 25.616 + glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0); 25.617 + glEnableClientState(GL_COLOR_ARRAY); 25.618 + } 25.619 +#endif 25.620 + } 25.621 + glBindBuffer(GL_ARRAY_BUFFER, 0); 25.622 + 25.623 + return true; 25.624 +} 25.625 + 25.626 +void Mesh::draw() const 25.627 +{ 25.628 + if(!pre_draw()) return; 25.629 + 25.630 + if(ibo_valid) { 25.631 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 25.632 + glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0); 25.633 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 25.634 + } else { 25.635 + glDrawArrays(GL_TRIANGLES, 0, nverts); 25.636 + } 25.637 + 25.638 + post_draw(); 25.639 +} 25.640 + 25.641 +void Mesh::post_draw() const 25.642 +{ 25.643 + if(cur_sdr && use_custom_sdr_attr) { 25.644 + // rendered with shaders 25.645 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.646 + int loc = global_sdr_loc[i]; 25.647 + if(loc >= 0 && vattr[i].vbo_valid) { 25.648 + glDisableVertexAttribArray(loc); 25.649 + } 25.650 + } 25.651 + } else { 25.652 +#ifndef GL_ES_VERSION_2_0 25.653 + // rendered with fixed-function 25.654 + glDisableClientState(GL_VERTEX_ARRAY); 25.655 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 25.656 + glDisableClientState(GL_NORMAL_ARRAY); 25.657 + } 25.658 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 25.659 + glDisableClientState(GL_TEXTURE_COORD_ARRAY); 25.660 + } 25.661 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 25.662 + glDisableClientState(GL_COLOR_ARRAY); 25.663 + } 25.664 +#endif 25.665 + } 25.666 +} 25.667 + 25.668 +void Mesh::draw_wire() const 25.669 +{ 25.670 + if(!pre_draw()) return; 25.671 + 25.672 + ((Mesh*)this)->update_wire_ibo(); 25.673 + 25.674 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 25.675 + glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0); 25.676 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 25.677 + 25.678 + post_draw(); 25.679 +} 25.680 + 25.681 +void Mesh::draw_vertices() const 25.682 +{ 25.683 + if(!pre_draw()) return; 25.684 + 25.685 + glDrawArrays(GL_POINTS, 0, nverts); 25.686 + 25.687 + post_draw(); 25.688 +} 25.689 + 25.690 +void Mesh::draw_normals() const 25.691 +{ 25.692 +#ifdef USE_OLDGL 25.693 + int cur_sdr = 0; 25.694 + if(glcaps.shaders) { 25.695 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 25.696 + } 25.697 + 25.698 + Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); 25.699 + Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); 25.700 + if(!varr || !norm) { 25.701 + return; 25.702 + } 25.703 + 25.704 + glBegin(GL_LINES); 25.705 + if(cur_sdr && use_custom_sdr_attr) { 25.706 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 25.707 + if(vert_loc < 0) { 25.708 + glEnd(); 25.709 + return; 25.710 + } 25.711 + 25.712 + for(size_t i=0; i<nverts; i++) { 25.713 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 25.714 + Vector3 end = varr[i] + norm[i] * vis_vecsize; 25.715 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 25.716 + } 25.717 + } else { 25.718 + for(size_t i=0; i<nverts; i++) { 25.719 + glVertex3f(varr[i].x, varr[i].y, varr[i].z); 25.720 + Vector3 end = varr[i] + norm[i] * vis_vecsize; 25.721 + glVertex3f(end.x, end.y, end.z); 25.722 + } 25.723 + } 25.724 + glEnd(); 25.725 +#endif // USE_OLDGL 25.726 +} 25.727 + 25.728 +void Mesh::draw_tangents() const 25.729 +{ 25.730 +#ifdef USE_OLDGL 25.731 + int cur_sdr = 0; 25.732 + if(glcaps.shaders) { 25.733 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 25.734 + } 25.735 + 25.736 + Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); 25.737 + Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT); 25.738 + if(!varr || !tang) { 25.739 + return; 25.740 + } 25.741 + 25.742 + glBegin(GL_LINES); 25.743 + if(cur_sdr && use_custom_sdr_attr) { 25.744 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 25.745 + if(vert_loc < 0) { 25.746 + glEnd(); 25.747 + return; 25.748 + } 25.749 + 25.750 + for(size_t i=0; i<nverts; i++) { 25.751 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 25.752 + Vector3 end = varr[i] + tang[i] * vis_vecsize; 25.753 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 25.754 + } 25.755 + } else { 25.756 + for(size_t i=0; i<nverts; i++) { 25.757 + glVertex3f(varr[i].x, varr[i].y, varr[i].z); 25.758 + Vector3 end = varr[i] + tang[i] * vis_vecsize; 25.759 + glVertex3f(end.x, end.y, end.z); 25.760 + } 25.761 + } 25.762 + glEnd(); 25.763 +#endif // USE_OLDGL 25.764 +} 25.765 + 25.766 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const 25.767 +{ 25.768 + if(!aabb_valid) { 25.769 + ((Mesh*)this)->calc_aabb(); 25.770 + } 25.771 + *vmin = aabb.min; 25.772 + *vmax = aabb.max; 25.773 +} 25.774 + 25.775 +const AABox &Mesh::get_aabbox() const 25.776 +{ 25.777 + if(!aabb_valid) { 25.778 + ((Mesh*)this)->calc_aabb(); 25.779 + } 25.780 + return aabb; 25.781 +} 25.782 + 25.783 +float Mesh::get_bsphere(Vector3 *center, float *rad) const 25.784 +{ 25.785 + if(!bsph_valid) { 25.786 + ((Mesh*)this)->calc_bsph(); 25.787 + } 25.788 + *center = bsph.center; 25.789 + *rad = bsph.radius; 25.790 + return bsph.radius; 25.791 +} 25.792 + 25.793 +const Sphere &Mesh::get_bsphere() const 25.794 +{ 25.795 + if(!bsph_valid) { 25.796 + ((Mesh*)this)->calc_bsph(); 25.797 + } 25.798 + return bsph; 25.799 +} 25.800 + 25.801 +/// static function 25.802 +void Mesh::set_intersect_mode(unsigned int mode) 25.803 +{ 25.804 + Mesh::intersect_mode = mode; 25.805 +} 25.806 + 25.807 +/// static function 25.808 +unsigned int Mesh::get_intersect_mode() 25.809 +{ 25.810 + return Mesh::intersect_mode; 25.811 +} 25.812 + 25.813 +/// static function 25.814 +void Mesh::set_vertex_select_distance(float dist) 25.815 +{ 25.816 + Mesh::vertex_sel_dist = dist; 25.817 +} 25.818 + 25.819 +/// static function 25.820 +float Mesh::get_vertex_select_distance() 25.821 +{ 25.822 + return Mesh::vertex_sel_dist; 25.823 +} 25.824 + 25.825 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const 25.826 +{ 25.827 + assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE)); 25.828 + 25.829 + const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); 25.830 + const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); 25.831 + if(!varr) { 25.832 + return false; 25.833 + } 25.834 + const unsigned int *idxarr = get_index_data(); 25.835 + 25.836 + // first test with the bounding box 25.837 + AABox box; 25.838 + get_aabbox(&box.min, &box.max); 25.839 + if(!box.intersect(ray)) { 25.840 + return false; 25.841 + } 25.842 + 25.843 + HitPoint nearest_hit; 25.844 + nearest_hit.dist = FLT_MAX; 25.845 + nearest_hit.obj = 0; 25.846 + 25.847 + if(Mesh::intersect_mode & ISECT_VERTICES) { 25.848 + // we asked for "intersections" with the vertices of the mesh 25.849 + long nearest_vidx = -1; 25.850 + float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist; 25.851 + 25.852 + for(unsigned int i=0; i<nverts; i++) { 25.853 + 25.854 + if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) { 25.855 + continue; 25.856 + } 25.857 + 25.858 + // project the vertex onto the ray line 25.859 + float t = dot_product(varr[i] - ray.origin, ray.dir); 25.860 + Vector3 vproj = ray.origin + ray.dir * t; 25.861 + 25.862 + float dist_sq = (vproj - varr[i]).length_sq(); 25.863 + if(dist_sq < thres_sq) { 25.864 + if(!hit) { 25.865 + return true; 25.866 + } 25.867 + if(t < nearest_hit.dist) { 25.868 + nearest_hit.dist = t; 25.869 + nearest_vidx = i; 25.870 + } 25.871 + } 25.872 + } 25.873 + 25.874 + if(nearest_vidx != -1) { 25.875 + hitvert = varr[nearest_vidx]; 25.876 + nearest_hit.obj = &hitvert; 25.877 + } 25.878 + 25.879 + } else { 25.880 + // regular intersection test with polygons 25.881 + 25.882 + for(unsigned int i=0; i<nfaces; i++) { 25.883 + Triangle face(i, varr, idxarr); 25.884 + 25.885 + // ignore back-facing polygons if the mode flags include ISECT_FRONT 25.886 + if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) { 25.887 + continue; 25.888 + } 25.889 + 25.890 + HitPoint fhit; 25.891 + if(face.intersect(ray, hit ? &fhit : 0)) { 25.892 + if(!hit) { 25.893 + return true; 25.894 + } 25.895 + if(fhit.dist < nearest_hit.dist) { 25.896 + nearest_hit = fhit; 25.897 + hitface = face; 25.898 + } 25.899 + } 25.900 + } 25.901 + } 25.902 + 25.903 + if(nearest_hit.obj) { 25.904 + if(hit) { 25.905 + *hit = nearest_hit; 25.906 + 25.907 + // if we are interested in the mesh and not the faces set obj to this 25.908 + if(Mesh::intersect_mode & ISECT_FACE) { 25.909 + hit->obj = &hitface; 25.910 + } else if(Mesh::intersect_mode & ISECT_VERTICES) { 25.911 + hit->obj = &hitvert; 25.912 + } else { 25.913 + hit->obj = this; 25.914 + } 25.915 + } 25.916 + return true; 25.917 + } 25.918 + return false; 25.919 +} 25.920 + 25.921 + 25.922 +// texture coordinate manipulation 25.923 +void Mesh::texcoord_apply_xform(const Matrix4x4 &xform) 25.924 +{ 25.925 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 25.926 + return; 25.927 + } 25.928 + 25.929 + for(unsigned int i=0; i<nverts; i++) { 25.930 + Vector4 tc = get_attrib(MESH_ATTR_TEXCOORD, i); 25.931 + set_attrib(MESH_ATTR_TEXCOORD, i, tc.transformed(xform)); 25.932 + } 25.933 +} 25.934 + 25.935 +void Mesh::texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang) 25.936 +{ 25.937 + if(!nverts) return; 25.938 + 25.939 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 25.940 + // allocate texture coordinate attribute array 25.941 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 25.942 + } 25.943 + 25.944 + Vector3 n = norm.normalized(); 25.945 + Vector3 b = cross_product(n, tang).normalized(); 25.946 + Vector3 t = cross_product(b, n); 25.947 + 25.948 + for(unsigned int i=0; i<nverts; i++) { 25.949 + Vector3 pos = get_attrib(MESH_ATTR_VERTEX, i); 25.950 + 25.951 + // distance along the tangent direction 25.952 + float u = dot_product(pos, t); 25.953 + // distance along the bitangent direction 25.954 + float v = dot_product(pos, b); 25.955 + 25.956 + set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(u, v, 0, 1)); 25.957 + } 25.958 +} 25.959 + 25.960 +void Mesh::texcoord_gen_box() 25.961 +{ 25.962 + if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return; 25.963 + 25.964 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 25.965 + // allocate texture coordinate attribute array 25.966 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 25.967 + } 25.968 + 25.969 + for(unsigned int i=0; i<nverts; i++) { 25.970 + Vector3 pos = Vector3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vector3(0.5, 0.5, 0.5); 25.971 + Vector3 norm = get_attrib(MESH_ATTR_NORMAL, i); 25.972 + 25.973 + float abs_nx = fabs(norm.x); 25.974 + float abs_ny = fabs(norm.y); 25.975 + float abs_nz = fabs(norm.z); 25.976 + int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2); 25.977 + 25.978 + float uv[2], *uvptr = uv; 25.979 + for(int j=0; j<3; j++) { 25.980 + if(j == dom) continue; // skip dominant axis 25.981 + 25.982 + *uvptr++ = pos[j]; 25.983 + } 25.984 + set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(uv[0], uv[1], 0, 1)); 25.985 + } 25.986 +} 25.987 + 25.988 +// ------ private member functions ------ 25.989 + 25.990 +void Mesh::calc_aabb() 25.991 +{ 25.992 + // the cast is to force calling the const version which doesn't invalidate 25.993 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 25.994 + return; 25.995 + } 25.996 + 25.997 + aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX); 25.998 + aabb.max = -aabb.min; 25.999 + 25.1000 + for(unsigned int i=0; i<nverts; i++) { 25.1001 + Vector4 v = get_attrib(MESH_ATTR_VERTEX, i); 25.1002 + for(int j=0; j<3; j++) { 25.1003 + if(v[j] < aabb.min[j]) { 25.1004 + aabb.min[j] = v[j]; 25.1005 + } 25.1006 + if(v[j] > aabb.max[j]) { 25.1007 + aabb.max[j] = v[j]; 25.1008 + } 25.1009 + } 25.1010 + } 25.1011 + aabb_valid = true; 25.1012 +} 25.1013 + 25.1014 +void Mesh::calc_bsph() 25.1015 +{ 25.1016 + // the cast is to force calling the const version which doesn't invalidate 25.1017 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 25.1018 + return; 25.1019 + } 25.1020 + 25.1021 + Vector3 v; 25.1022 + bsph.center = Vector3(0, 0, 0); 25.1023 + 25.1024 + // first find the center 25.1025 + for(unsigned int i=0; i<nverts; i++) { 25.1026 + v = get_attrib(MESH_ATTR_VERTEX, i); 25.1027 + bsph.center += v; 25.1028 + } 25.1029 + bsph.center /= (float)nverts; 25.1030 + 25.1031 + bsph.radius = 0.0f; 25.1032 + for(unsigned int i=0; i<nverts; i++) { 25.1033 + v = get_attrib(MESH_ATTR_VERTEX, i); 25.1034 + float dist_sq = (v - bsph.center).length_sq(); 25.1035 + if(dist_sq > bsph.radius) { 25.1036 + bsph.radius = dist_sq; 25.1037 + } 25.1038 + } 25.1039 + bsph.radius = sqrt(bsph.radius); 25.1040 + 25.1041 + bsph_valid = true; 25.1042 +} 25.1043 + 25.1044 +void Mesh::update_buffers() 25.1045 +{ 25.1046 + for(int i=0; i<NUM_MESH_ATTR; i++) { 25.1047 + if(has_attrib(i) && !vattr[i].vbo_valid) { 25.1048 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 25.1049 + glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW); 25.1050 + vattr[i].vbo_valid = true; 25.1051 + } 25.1052 + } 25.1053 + glBindBuffer(GL_ARRAY_BUFFER, 0); 25.1054 + 25.1055 + if(idata_valid && !ibo_valid) { 25.1056 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 25.1057 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW); 25.1058 + ibo_valid = true; 25.1059 + } 25.1060 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 25.1061 +} 25.1062 + 25.1063 +void Mesh::update_wire_ibo() 25.1064 +{ 25.1065 + update_buffers(); 25.1066 + 25.1067 + if(wire_ibo_valid) { 25.1068 + return; 25.1069 + } 25.1070 + 25.1071 + if(!wire_ibo) { 25.1072 + glGenBuffers(1, &wire_ibo); 25.1073 + } 25.1074 + 25.1075 + unsigned int *wire_idxarr = new unsigned int[nfaces * 6]; 25.1076 + unsigned int *dest = wire_idxarr; 25.1077 + 25.1078 + if(ibo_valid) { 25.1079 + // we're dealing with an indexed mesh 25.1080 + const unsigned int *idxarr = ((const Mesh*)this)->get_index_data(); 25.1081 + 25.1082 + for(unsigned int i=0; i<nfaces; i++) { 25.1083 + *dest++ = idxarr[0]; 25.1084 + *dest++ = idxarr[1]; 25.1085 + *dest++ = idxarr[1]; 25.1086 + *dest++ = idxarr[2]; 25.1087 + *dest++ = idxarr[2]; 25.1088 + *dest++ = idxarr[0]; 25.1089 + idxarr += 3; 25.1090 + } 25.1091 + } else { 25.1092 + // not an indexed mesh ... 25.1093 + for(unsigned int i=0; i<nfaces; i++) { 25.1094 + int vidx = i * 3; 25.1095 + *dest++ = vidx; 25.1096 + *dest++ = vidx + 1; 25.1097 + *dest++ = vidx + 1; 25.1098 + *dest++ = vidx + 2; 25.1099 + *dest++ = vidx + 2; 25.1100 + *dest++ = vidx; 25.1101 + } 25.1102 + } 25.1103 + 25.1104 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 25.1105 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW); 25.1106 + delete [] wire_idxarr; 25.1107 + wire_ibo_valid = true; 25.1108 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 25.1109 +} 25.1110 + 25.1111 + 25.1112 +// ------ class Triangle ------ 25.1113 +Triangle::Triangle() 25.1114 +{ 25.1115 + normal_valid = false; 25.1116 + id = -1; 25.1117 +} 25.1118 + 25.1119 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2) 25.1120 +{ 25.1121 + v[0] = v0; 25.1122 + v[1] = v1; 25.1123 + v[2] = v2; 25.1124 + normal_valid = false; 25.1125 + id = -1; 25.1126 +} 25.1127 + 25.1128 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr) 25.1129 +{ 25.1130 + if(idxarr) { 25.1131 + v[0] = varr[idxarr[n * 3]]; 25.1132 + v[1] = varr[idxarr[n * 3 + 1]]; 25.1133 + v[2] = varr[idxarr[n * 3 + 2]]; 25.1134 + } else { 25.1135 + v[0] = varr[n * 3]; 25.1136 + v[1] = varr[n * 3 + 1]; 25.1137 + v[2] = varr[n * 3 + 2]; 25.1138 + } 25.1139 + normal_valid = false; 25.1140 + id = n; 25.1141 +} 25.1142 + 25.1143 +void Triangle::calc_normal() 25.1144 +{ 25.1145 + normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized(); 25.1146 + normal_valid = true; 25.1147 +} 25.1148 + 25.1149 +const Vector3 &Triangle::get_normal() const 25.1150 +{ 25.1151 + if(!normal_valid) { 25.1152 + ((Triangle*)this)->calc_normal(); 25.1153 + } 25.1154 + return normal; 25.1155 +} 25.1156 + 25.1157 +void Triangle::transform(const Matrix4x4 &xform) 25.1158 +{ 25.1159 + v[0].transform(xform); 25.1160 + v[1].transform(xform); 25.1161 + v[2].transform(xform); 25.1162 + normal_valid = false; 25.1163 +} 25.1164 + 25.1165 +void Triangle::draw() const 25.1166 +{ 25.1167 + Vector3 n[3]; 25.1168 + n[0] = get_normal(); 25.1169 + n[1] = get_normal(); 25.1170 + n[2] = get_normal(); 25.1171 + 25.1172 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 25.1173 + int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL); 25.1174 + 25.1175 + glEnableVertexAttribArray(vloc); 25.1176 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 25.1177 + glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x); 25.1178 + 25.1179 + glDrawArrays(GL_TRIANGLES, 0, 3); 25.1180 + 25.1181 + glDisableVertexAttribArray(vloc); 25.1182 + glDisableVertexAttribArray(nloc); 25.1183 +} 25.1184 + 25.1185 +void Triangle::draw_wire() const 25.1186 +{ 25.1187 + static const int idxarr[] = {0, 1, 1, 2, 2, 0}; 25.1188 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 25.1189 + 25.1190 + glEnableVertexAttribArray(vloc); 25.1191 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 25.1192 + 25.1193 + glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr); 25.1194 + 25.1195 + glDisableVertexAttribArray(vloc); 25.1196 +} 25.1197 + 25.1198 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const 25.1199 +{ 25.1200 + Vector3 norm = get_normal(); 25.1201 + 25.1202 + float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm)); 25.1203 + if(area_sq < 1e-5) { 25.1204 + return Vector3(0, 0, 0); 25.1205 + } 25.1206 + 25.1207 + float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm)); 25.1208 + float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm)); 25.1209 + float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm)); 25.1210 + 25.1211 + return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq); 25.1212 +} 25.1213 + 25.1214 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const 25.1215 +{ 25.1216 + Vector3 normal = get_normal(); 25.1217 + 25.1218 + float ndotdir = dot_product(ray.dir, normal); 25.1219 + if(fabs(ndotdir) < 1e-4) { 25.1220 + return false; 25.1221 + } 25.1222 + 25.1223 + Vector3 vertdir = v[0] - ray.origin; 25.1224 + float t = dot_product(normal, vertdir) / ndotdir; 25.1225 + 25.1226 + Vector3 pos = ray.origin + ray.dir * t; 25.1227 + Vector3 bary = calc_barycentric(pos); 25.1228 + 25.1229 + if(bary.x + bary.y + bary.z > 1.00001) { 25.1230 + return false; 25.1231 + } 25.1232 + 25.1233 + if(hit) { 25.1234 + hit->dist = t; 25.1235 + hit->pos = ray.origin + ray.dir * t; 25.1236 + hit->normal = normal; 25.1237 + hit->obj = this; 25.1238 + } 25.1239 + return true; 25.1240 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/src/mesh.h Sun Nov 01 00:09:12 2015 +0200 26.3 @@ -0,0 +1,236 @@ 26.4 +#ifndef MESH_H_ 26.5 +#define MESH_H_ 26.6 + 26.7 +#include <string> 26.8 +#include <vector> 26.9 +#include "vmath/vmath.h" 26.10 +#include "geom.h" 26.11 + 26.12 +enum { 26.13 + MESH_ATTR_VERTEX, 26.14 + MESH_ATTR_NORMAL, 26.15 + MESH_ATTR_TANGENT, 26.16 + MESH_ATTR_TEXCOORD, 26.17 + MESH_ATTR_COLOR, 26.18 + MESH_ATTR_BONEWEIGHTS, 26.19 + MESH_ATTR_BONEIDX, 26.20 + 26.21 + NUM_MESH_ATTR 26.22 +}; 26.23 + 26.24 +// intersection mode flags 26.25 +enum { 26.26 + ISECT_DEFAULT = 0, // default (whole mesh, all intersections) 26.27 + ISECT_FRONT = 1, // front-faces only 26.28 + ISECT_FACE = 2, // return intersected face pointer instead of mesh 26.29 + ISECT_VERTICES = 4 // return (?) TODO 26.30 +}; 26.31 + 26.32 +//class XFormNode; 26.33 + 26.34 + 26.35 +class Triangle { 26.36 +public: 26.37 + Vector3 v[3]; 26.38 + Vector3 normal; 26.39 + bool normal_valid; 26.40 + int id; 26.41 + 26.42 + Triangle(); 26.43 + Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2); 26.44 + Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0); 26.45 + 26.46 + /// calculate normal (quite expensive) 26.47 + void calc_normal(); 26.48 + const Vector3 &get_normal() const; 26.49 + 26.50 + void transform(const Matrix4x4 &xform); 26.51 + 26.52 + void draw() const; 26.53 + void draw_wire() const; 26.54 + 26.55 + /// calculate barycentric coordinates of a point 26.56 + Vector3 calc_barycentric(const Vector3 &pos) const; 26.57 + 26.58 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 26.59 +}; 26.60 + 26.61 + 26.62 +class Mesh { 26.63 +private: 26.64 + std::string name; 26.65 + unsigned int nverts, nfaces; 26.66 + 26.67 + // current value for each attribute for the immedate mode 26.68 + // interface. 26.69 + Vector4 cur_val[NUM_MESH_ATTR]; 26.70 + 26.71 + unsigned int buffer_objects[NUM_MESH_ATTR + 1]; 26.72 + 26.73 + // vertex attribute data and buffer objects 26.74 + struct { 26.75 + int nelem; // number of elements per attribute range: [1, 4] 26.76 + std::vector<float> data; 26.77 + unsigned int vbo; 26.78 + mutable bool vbo_valid; // if this is false, the vbo needs updating from the data 26.79 + mutable bool data_valid; // if this is false, the data needs to be pulled from the vbo 26.80 + //int sdr_loc; 26.81 + } vattr[NUM_MESH_ATTR]; 26.82 + 26.83 + static int global_sdr_loc[NUM_MESH_ATTR]; 26.84 + 26.85 + //std::vector<XFormNode*> bones; // bones affecting this mesh 26.86 + 26.87 + // index data and buffer object 26.88 + std::vector<unsigned int> idata; 26.89 + unsigned int ibo; 26.90 + mutable bool ibo_valid; 26.91 + mutable bool idata_valid; 26.92 + 26.93 + // index buffer object for wireframe rendering (constructed on demand) 26.94 + unsigned int wire_ibo; 26.95 + mutable bool wire_ibo_valid; 26.96 + 26.97 + // axis-aligned bounding box 26.98 + mutable AABox aabb; 26.99 + mutable bool aabb_valid; 26.100 + 26.101 + // bounding sphere 26.102 + mutable Sphere bsph; 26.103 + mutable bool bsph_valid; 26.104 + 26.105 + // keeps the last intersected face 26.106 + mutable Triangle hitface; 26.107 + // keeps the last intersected vertex position 26.108 + mutable Vector3 hitvert; 26.109 + 26.110 + void calc_aabb(); 26.111 + void calc_bsph(); 26.112 + 26.113 + static unsigned int intersect_mode; 26.114 + static float vertex_sel_dist; 26.115 + 26.116 + static float vis_vecsize; 26.117 + 26.118 + /// update the VBOs after data has changed (invalid vbo/ibo) 26.119 + void update_buffers(); 26.120 + /// construct/update the wireframe index buffer (called from draw_wire). 26.121 + void update_wire_ibo(); 26.122 + 26.123 + mutable int cur_sdr; 26.124 + bool pre_draw() const; 26.125 + void post_draw() const; 26.126 + 26.127 + 26.128 +public: 26.129 + static bool use_custom_sdr_attr; 26.130 + 26.131 + Mesh(); 26.132 + ~Mesh(); 26.133 + 26.134 + Mesh(const Mesh &rhs); 26.135 + Mesh &operator =(const Mesh &rhs); 26.136 + bool clone(const Mesh &m); 26.137 + 26.138 + void set_name(const char *name); 26.139 + const char *get_name() const; 26.140 + 26.141 + bool has_attrib(int attr) const; 26.142 + bool is_indexed() const; 26.143 + 26.144 + // clears everything about this mesh, and returns to the newly constructed state 26.145 + void clear(); 26.146 + 26.147 + // access the vertex attribute data 26.148 + // if vdata == 0, space is just allocated 26.149 + float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo 26.150 + float *get_attrib_data(int attrib); // invalidates vbo 26.151 + const float *get_attrib_data(int attrib) const; 26.152 + 26.153 + // simple access to any particular attribute 26.154 + void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo 26.155 + Vector4 get_attrib(int attrib, int idx) const; 26.156 + 26.157 + int get_attrib_count(int attrib) const; 26.158 + 26.159 + // ... same for index data 26.160 + unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo 26.161 + unsigned int *get_index_data(); // invalidates ibo 26.162 + const unsigned int *get_index_data() const; 26.163 + 26.164 + int get_index_count() const; 26.165 + 26.166 + void append(const Mesh &mesh); 26.167 + 26.168 + // immediate-mode style mesh construction interface 26.169 + void vertex(float x, float y, float z); 26.170 + void normal(float nx, float ny, float nz); 26.171 + void tangent(float tx, float ty, float tz); 26.172 + void texcoord(float u, float v, float w); 26.173 + void boneweights(float w1, float w2, float w3, float w4); 26.174 + void boneidx(int idx1, int idx2, int idx3, int idx4); 26.175 + 26.176 + int get_poly_count() const; 26.177 + 26.178 + /* apply a transformation to the vertices and its inverse-transpose 26.179 + * to the normals and tangents. 26.180 + */ 26.181 + void apply_xform(const Matrix4x4 &xform); 26.182 + void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform); 26.183 + 26.184 + void flip(); // both faces and normals 26.185 + void flip_faces(); 26.186 + void flip_normals(); 26.187 + 26.188 + // adds a bone and returns its index 26.189 + /*int add_bone(XFormNode *bone); 26.190 + const XFormNode *get_bone(int idx) const; 26.191 + int get_bones_count() const;*/ 26.192 + 26.193 + // access the shader attribute locations 26.194 + static void set_attrib_location(int attr, int loc); 26.195 + static int get_attrib_location(int attr); 26.196 + static void clear_attrib_locations(); 26.197 + 26.198 + static void set_vis_vecsize(float sz); 26.199 + static float get_vis_vecsize(); 26.200 + 26.201 + void draw() const; 26.202 + void draw_wire() const; 26.203 + void draw_vertices() const; 26.204 + void draw_normals() const; 26.205 + void draw_tangents() const; 26.206 + 26.207 + /** get the bounding box in local space. The result will be cached, and subsequent 26.208 + * calls will return the same box. The cache gets invalidated by any functions that can affect 26.209 + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). 26.210 + * @{ */ 26.211 + void get_aabbox(Vector3 *vmin, Vector3 *vmax) const; 26.212 + const AABox &get_aabbox() const; 26.213 + /// @} 26.214 + 26.215 + /** get the bounding sphere in local space. The result will be cached, and subsequent 26.216 + * calls will return the same box. The cache gets invalidated by any functions that can affect 26.217 + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). 26.218 + * @{ */ 26.219 + float get_bsphere(Vector3 *center, float *rad) const; 26.220 + const Sphere &get_bsphere() const; 26.221 + 26.222 + static void set_intersect_mode(unsigned int mode); 26.223 + static unsigned int get_intersect_mode(); 26.224 + static void set_vertex_select_distance(float dist); 26.225 + static float get_vertex_select_distance(); 26.226 + 26.227 + /** Find the intersection between the mesh and a ray. 26.228 + * XXX Brute force at the moment, not intended to be used for anything other than picking in tools. 26.229 + * If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it! 26.230 + */ 26.231 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 26.232 + 26.233 + // texture coordinate manipulation 26.234 + void texcoord_apply_xform(const Matrix4x4 &xform); 26.235 + void texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang); 26.236 + void texcoord_gen_box(); 26.237 +}; 26.238 + 26.239 +#endif // MESH_H_
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/src/meshgen.cc Sun Nov 01 00:09:12 2015 +0200 27.3 @@ -0,0 +1,775 @@ 27.4 +#include <stdio.h> 27.5 +#include "meshgen.h" 27.6 +#include "mesh.h" 27.7 + 27.8 +// -------- sphere -------- 27.9 + 27.10 +#define SURAD(u) ((u) * 2.0 * M_PI) 27.11 +#define SVRAD(v) ((v) * M_PI) 27.12 + 27.13 +static Vector3 sphvec(float theta, float phi) 27.14 +{ 27.15 + return Vector3(sin(theta) * sin(phi), 27.16 + cos(phi), 27.17 + cos(theta) * sin(phi)); 27.18 +} 27.19 + 27.20 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange) 27.21 +{ 27.22 + if(usub < 4) usub = 4; 27.23 + if(vsub < 2) vsub = 2; 27.24 + 27.25 + int uverts = usub + 1; 27.26 + int vverts = vsub + 1; 27.27 + 27.28 + int num_verts = uverts * vverts; 27.29 + int num_quads = usub * vsub; 27.30 + int num_tri = num_quads * 2; 27.31 + 27.32 + mesh->clear(); 27.33 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.34 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.35 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.36 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.37 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.38 + 27.39 + float du = urange / (float)(uverts - 1); 27.40 + float dv = vrange / (float)(vverts - 1); 27.41 + 27.42 + float u = 0.0; 27.43 + for(int i=0; i<uverts; i++) { 27.44 + float theta = u * 2.0 * M_PI; 27.45 + 27.46 + float v = 0.0; 27.47 + for(int j=0; j<vverts; j++) { 27.48 + float phi = v * M_PI; 27.49 + 27.50 + Vector3 pos = sphvec(theta, phi); 27.51 + 27.52 + *varr++ = pos * rad; 27.53 + *narr++ = pos; 27.54 + *tarr++ = (sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f)).normalized(); 27.55 + *uvarr++ = Vector2(u * urange, v * vrange); 27.56 + 27.57 + if(i < usub && j < vsub) { 27.58 + int idx = i * vverts + j; 27.59 + *idxarr++ = idx; 27.60 + *idxarr++ = idx + 1; 27.61 + *idxarr++ = idx + vverts + 1; 27.62 + 27.63 + *idxarr++ = idx; 27.64 + *idxarr++ = idx + vverts + 1; 27.65 + *idxarr++ = idx + vverts; 27.66 + } 27.67 + 27.68 + v += dv; 27.69 + } 27.70 + u += du; 27.71 + } 27.72 +} 27.73 + 27.74 +// -------- torus ----------- 27.75 +static Vector3 torusvec(float theta, float phi, float mr, float rr) 27.76 +{ 27.77 + theta = -theta; 27.78 + 27.79 + float rx = -cos(phi) * rr + mr; 27.80 + float ry = sin(phi) * rr; 27.81 + float rz = 0.0; 27.82 + 27.83 + float x = rx * sin(theta) + rz * cos(theta); 27.84 + float y = ry; 27.85 + float z = -rx * cos(theta) + rz * sin(theta); 27.86 + 27.87 + return Vector3(x, y, z); 27.88 +} 27.89 + 27.90 +void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange, float vrange) 27.91 +{ 27.92 + if(usub < 4) usub = 4; 27.93 + if(vsub < 2) vsub = 2; 27.94 + 27.95 + int uverts = usub + 1; 27.96 + int vverts = vsub + 1; 27.97 + 27.98 + int num_verts = uverts * vverts; 27.99 + int num_quads = usub * vsub; 27.100 + int num_tri = num_quads * 2; 27.101 + 27.102 + mesh->clear(); 27.103 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.104 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.105 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.106 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.107 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.108 + 27.109 + float du = urange / (float)(uverts - 1); 27.110 + float dv = vrange / (float)(vverts - 1); 27.111 + 27.112 + float u = 0.0; 27.113 + for(int i=0; i<uverts; i++) { 27.114 + float theta = u * 2.0 * M_PI; 27.115 + 27.116 + float v = 0.0; 27.117 + for(int j=0; j<vverts; j++) { 27.118 + float phi = v * 2.0 * M_PI; 27.119 + 27.120 + Vector3 pos = torusvec(theta, phi, mainrad, ringrad); 27.121 + Vector3 cent = torusvec(theta, phi, mainrad, 0.0); 27.122 + 27.123 + *varr++ = pos; 27.124 + *narr++ = (pos - cent) / ringrad; 27.125 + 27.126 + Vector3 pprev = torusvec(theta - 0.1f, phi, mainrad, ringrad); 27.127 + Vector3 pnext = torusvec(theta + 0.1f, phi, mainrad, ringrad); 27.128 + 27.129 + *tarr++ = (pnext - pprev).normalized(); 27.130 + *uvarr++ = Vector2(u * urange, v * vrange); 27.131 + 27.132 + if(i < usub && j < vsub) { 27.133 + int idx = i * vverts + j; 27.134 + *idxarr++ = idx; 27.135 + *idxarr++ = idx + 1; 27.136 + *idxarr++ = idx + vverts + 1; 27.137 + 27.138 + *idxarr++ = idx; 27.139 + *idxarr++ = idx + vverts + 1; 27.140 + *idxarr++ = idx + vverts; 27.141 + } 27.142 + 27.143 + v += dv; 27.144 + } 27.145 + u += du; 27.146 + } 27.147 +} 27.148 + 27.149 + 27.150 +// -------- cylinder -------- 27.151 + 27.152 +static Vector3 cylvec(float theta, float height) 27.153 +{ 27.154 + return Vector3(sin(theta), height, cos(theta)); 27.155 +} 27.156 + 27.157 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange) 27.158 +{ 27.159 + if(usub < 4) usub = 4; 27.160 + if(vsub < 1) vsub = 1; 27.161 + 27.162 + int uverts = usub + 1; 27.163 + int vverts = vsub + 1; 27.164 + 27.165 + int num_body_verts = uverts * vverts; 27.166 + int num_body_quads = usub * vsub; 27.167 + int num_body_tri = num_body_quads * 2; 27.168 + 27.169 + int capvverts = capsub ? capsub + 1 : 0; 27.170 + int num_cap_verts = uverts * capvverts; 27.171 + int num_cap_quads = usub * capsub; 27.172 + int num_cap_tri = num_cap_quads * 2; 27.173 + 27.174 + int num_verts = num_body_verts + num_cap_verts * 2; 27.175 + int num_tri = num_body_tri + num_cap_tri * 2; 27.176 + 27.177 + mesh->clear(); 27.178 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.179 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.180 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.181 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.182 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.183 + 27.184 + float du = urange / (float)(uverts - 1); 27.185 + float dv = vrange / (float)(vverts - 1); 27.186 + 27.187 + float u = 0.0; 27.188 + for(int i=0; i<uverts; i++) { 27.189 + float theta = SURAD(u); 27.190 + 27.191 + float v = 0.0; 27.192 + for(int j=0; j<vverts; j++) { 27.193 + float y = (v - 0.5) * height; 27.194 + Vector3 pos = cylvec(theta, y); 27.195 + 27.196 + *varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad); 27.197 + *narr++ = Vector3(pos.x, 0.0, pos.z); 27.198 + *tarr++ = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized(); 27.199 + *uvarr++ = Vector2(u * urange, v * vrange); 27.200 + 27.201 + if(i < usub && j < vsub) { 27.202 + int idx = i * vverts + j; 27.203 + 27.204 + *idxarr++ = idx; 27.205 + *idxarr++ = idx + vverts + 1; 27.206 + *idxarr++ = idx + 1; 27.207 + 27.208 + *idxarr++ = idx; 27.209 + *idxarr++ = idx + vverts; 27.210 + *idxarr++ = idx + vverts + 1; 27.211 + } 27.212 + 27.213 + v += dv; 27.214 + } 27.215 + u += du; 27.216 + } 27.217 + 27.218 + 27.219 + // now the cap! 27.220 + if(!capsub) { 27.221 + return; 27.222 + } 27.223 + 27.224 + dv = 1.0 / (float)(capvverts - 1); 27.225 + 27.226 + u = 0.0; 27.227 + for(int i=0; i<uverts; i++) { 27.228 + float theta = SURAD(u); 27.229 + 27.230 + float v = 0.0; 27.231 + for(int j=0; j<capvverts; j++) { 27.232 + float r = v * rad; 27.233 + 27.234 + Vector3 pos = cylvec(theta, height / 2.0) * r; 27.235 + pos.y = height / 2.0; 27.236 + Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized(); 27.237 + 27.238 + *varr++ = pos; 27.239 + *narr++ = Vector3(0, 1, 0); 27.240 + *tarr++ = tang; 27.241 + *uvarr++ = Vector2(u * urange, v); 27.242 + 27.243 + pos.y = -height / 2.0; 27.244 + *varr++ = pos; 27.245 + *narr++ = Vector3(0, -1, 0); 27.246 + *tarr++ = -tang; 27.247 + *uvarr++ = Vector2(u * urange, v); 27.248 + 27.249 + if(i < usub && j < capsub) { 27.250 + unsigned int idx = num_body_verts + (i * capvverts + j) * 2; 27.251 + 27.252 + unsigned int vidx[4] = { 27.253 + idx, 27.254 + idx + capvverts * 2, 27.255 + idx + (capvverts + 1) * 2, 27.256 + idx + 2 27.257 + }; 27.258 + 27.259 + *idxarr++ = vidx[0]; 27.260 + *idxarr++ = vidx[2]; 27.261 + *idxarr++ = vidx[1]; 27.262 + *idxarr++ = vidx[0]; 27.263 + *idxarr++ = vidx[3]; 27.264 + *idxarr++ = vidx[2]; 27.265 + 27.266 + *idxarr++ = vidx[0] + 1; 27.267 + *idxarr++ = vidx[1] + 1; 27.268 + *idxarr++ = vidx[2] + 1; 27.269 + *idxarr++ = vidx[0] + 1; 27.270 + *idxarr++ = vidx[2] + 1; 27.271 + *idxarr++ = vidx[3] + 1; 27.272 + } 27.273 + 27.274 + v += dv; 27.275 + } 27.276 + u += du; 27.277 + } 27.278 +} 27.279 + 27.280 +// -------- cone -------- 27.281 + 27.282 +static Vector3 conevec(float theta, float y, float height) 27.283 +{ 27.284 + float scale = 1.0 - y / height; 27.285 + return Vector3(sin(theta) * scale, y, cos(theta) * scale); 27.286 +} 27.287 + 27.288 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange) 27.289 +{ 27.290 + if(usub < 4) usub = 4; 27.291 + if(vsub < 1) vsub = 1; 27.292 + 27.293 + int uverts = usub + 1; 27.294 + int vverts = vsub + 1; 27.295 + 27.296 + int num_body_verts = uverts * vverts; 27.297 + int num_body_quads = usub * vsub; 27.298 + int num_body_tri = num_body_quads * 2; 27.299 + 27.300 + int capvverts = capsub ? capsub + 1 : 0; 27.301 + int num_cap_verts = uverts * capvverts; 27.302 + int num_cap_quads = usub * capsub; 27.303 + int num_cap_tri = num_cap_quads * 2; 27.304 + 27.305 + int num_verts = num_body_verts + num_cap_verts; 27.306 + int num_tri = num_body_tri + num_cap_tri; 27.307 + 27.308 + mesh->clear(); 27.309 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.310 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.311 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.312 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.313 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.314 + 27.315 + float du = urange / (float)(uverts - 1); 27.316 + float dv = vrange / (float)(vverts - 1); 27.317 + 27.318 + float u = 0.0; 27.319 + for(int i=0; i<uverts; i++) { 27.320 + float theta = SURAD(u); 27.321 + 27.322 + float v = 0.0; 27.323 + for(int j=0; j<vverts; j++) { 27.324 + float y = v * height; 27.325 + Vector3 pos = conevec(theta, y, height); 27.326 + 27.327 + Vector3 tang = (conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height)).normalized(); 27.328 + Vector3 bitang = (conevec(theta, y + 0.1, height) - pos).normalized(); 27.329 + 27.330 + *varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad); 27.331 + *narr++ = cross_product(tang, bitang); 27.332 + *tarr++ = tang; 27.333 + *uvarr++ = Vector2(u * urange, v * vrange); 27.334 + 27.335 + if(i < usub && j < vsub) { 27.336 + int idx = i * vverts + j; 27.337 + 27.338 + *idxarr++ = idx; 27.339 + *idxarr++ = idx + vverts + 1; 27.340 + *idxarr++ = idx + 1; 27.341 + 27.342 + *idxarr++ = idx; 27.343 + *idxarr++ = idx + vverts; 27.344 + *idxarr++ = idx + vverts + 1; 27.345 + } 27.346 + 27.347 + v += dv; 27.348 + } 27.349 + u += du; 27.350 + } 27.351 + 27.352 + 27.353 + // now the bottom cap! 27.354 + if(!capsub) { 27.355 + return; 27.356 + } 27.357 + 27.358 + dv = 1.0 / (float)(capvverts - 1); 27.359 + 27.360 + u = 0.0; 27.361 + for(int i=0; i<uverts; i++) { 27.362 + float theta = SURAD(u); 27.363 + 27.364 + float v = 0.0; 27.365 + for(int j=0; j<capvverts; j++) { 27.366 + float r = v * rad; 27.367 + 27.368 + Vector3 pos = conevec(theta, 0.0, height) * r; 27.369 + Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized(); 27.370 + 27.371 + *varr++ = pos; 27.372 + *narr++ = Vector3(0, -1, 0); 27.373 + *tarr++ = tang; 27.374 + *uvarr++ = Vector2(u * urange, v); 27.375 + 27.376 + if(i < usub && j < capsub) { 27.377 + unsigned int idx = num_body_verts + i * capvverts + j; 27.378 + 27.379 + unsigned int vidx[4] = { 27.380 + idx, 27.381 + idx + capvverts, 27.382 + idx + (capvverts + 1), 27.383 + idx + 1 27.384 + }; 27.385 + 27.386 + *idxarr++ = vidx[0]; 27.387 + *idxarr++ = vidx[1]; 27.388 + *idxarr++ = vidx[2]; 27.389 + *idxarr++ = vidx[0]; 27.390 + *idxarr++ = vidx[2]; 27.391 + *idxarr++ = vidx[3]; 27.392 + } 27.393 + 27.394 + v += dv; 27.395 + } 27.396 + u += du; 27.397 + } 27.398 +} 27.399 + 27.400 + 27.401 +// -------- plane -------- 27.402 + 27.403 +void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub) 27.404 +{ 27.405 + gen_heightmap(mesh, width, height, usub, vsub, 0); 27.406 +} 27.407 + 27.408 + 27.409 +// ----- heightmap ------ 27.410 + 27.411 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata) 27.412 +{ 27.413 + if(usub < 1) usub = 1; 27.414 + if(vsub < 1) vsub = 1; 27.415 + 27.416 + mesh->clear(); 27.417 + 27.418 + int uverts = usub + 1; 27.419 + int vverts = vsub + 1; 27.420 + int num_verts = uverts * vverts; 27.421 + 27.422 + int num_quads = usub * vsub; 27.423 + int num_tri = num_quads * 2; 27.424 + 27.425 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.426 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.427 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.428 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.429 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.430 + 27.431 + float du = 1.0 / (float)usub; 27.432 + float dv = 1.0 / (float)vsub; 27.433 + 27.434 + float u = 0.0; 27.435 + for(int i=0; i<uverts; i++) { 27.436 + float v = 0.0; 27.437 + for(int j=0; j<vverts; j++) { 27.438 + float x = (u - 0.5) * width; 27.439 + float y = (v - 0.5) * height; 27.440 + float z = hf ? hf(u, v, hfdata) : 0.0; 27.441 + 27.442 + Vector3 normal = Vector3(0, 0, 1); 27.443 + if(hf) { 27.444 + float u1z = hf(u + du, v, hfdata); 27.445 + float v1z = hf(u, v + dv, hfdata); 27.446 + 27.447 + Vector3 tang = Vector3(du * width, 0, u1z - z); 27.448 + Vector3 bitan = Vector3(0, dv * height, v1z - z); 27.449 + normal = cross_product(tang, bitan).normalized(); 27.450 + } 27.451 + 27.452 + *varr++ = Vector3(x, y, z); 27.453 + *narr++ = normal; 27.454 + *tarr++ = Vector3(1, 0, 0); 27.455 + *uvarr++ = Vector2(u, v); 27.456 + 27.457 + if(i < usub && j < vsub) { 27.458 + int idx = i * vverts + j; 27.459 + 27.460 + *idxarr++ = idx; 27.461 + *idxarr++ = idx + vverts + 1; 27.462 + *idxarr++ = idx + 1; 27.463 + 27.464 + *idxarr++ = idx; 27.465 + *idxarr++ = idx + vverts; 27.466 + *idxarr++ = idx + vverts + 1; 27.467 + } 27.468 + 27.469 + v += dv; 27.470 + } 27.471 + u += du; 27.472 + } 27.473 +} 27.474 + 27.475 +// ----- box ------ 27.476 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub, int vsub) 27.477 +{ 27.478 + static const float face_angles[][2] = { 27.479 + {0, 0}, 27.480 + {M_PI / 2.0, 0}, 27.481 + {M_PI, 0}, 27.482 + {3.0 * M_PI / 2.0, 0}, 27.483 + {0, M_PI / 2.0}, 27.484 + {0, -M_PI / 2.0} 27.485 + }; 27.486 + 27.487 + if(usub < 1) usub = 1; 27.488 + if(vsub < 1) vsub = 1; 27.489 + 27.490 + mesh->clear(); 27.491 + 27.492 + for(int i=0; i<6; i++) { 27.493 + Matrix4x4 xform, dir_xform; 27.494 + Mesh m; 27.495 + 27.496 + gen_plane(&m, 1, 1, usub, vsub); 27.497 + xform.rotate(Vector3(face_angles[i][1], face_angles[i][0], 0)); 27.498 + dir_xform = xform; 27.499 + xform.translate(Vector3(0, 0, 0.5)); 27.500 + m.apply_xform(xform, dir_xform); 27.501 + 27.502 + mesh->append(m); 27.503 + } 27.504 + 27.505 + Matrix4x4 scale; 27.506 + scale.set_scaling(Vector3(xsz, ysz, zsz)); 27.507 + mesh->apply_xform(scale, Matrix4x4::identity); 27.508 +} 27.509 + 27.510 +/* 27.511 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz) 27.512 +{ 27.513 + mesh->clear(); 27.514 + 27.515 + const int num_faces = 6; 27.516 + int num_verts = num_faces * 4; 27.517 + int num_tri = num_faces * 2; 27.518 + 27.519 + float x = xsz / 2.0; 27.520 + float y = ysz / 2.0; 27.521 + float z = zsz / 2.0; 27.522 + 27.523 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.524 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.525 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.526 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.527 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.528 + 27.529 + static const Vector2 uv[] = { Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(0, 1) }; 27.530 + 27.531 + // front 27.532 + for(int i=0; i<4; i++) { 27.533 + *narr++ = Vector3(0, 0, 1); 27.534 + *tarr++ = Vector3(1, 0, 0); 27.535 + *uvarr++ = uv[i]; 27.536 + } 27.537 + *varr++ = Vector3(-x, -y, z); 27.538 + *varr++ = Vector3(x, -y, z); 27.539 + *varr++ = Vector3(x, y, z); 27.540 + *varr++ = Vector3(-x, y, z); 27.541 + // right 27.542 + for(int i=0; i<4; i++) { 27.543 + *narr++ = Vector3(1, 0, 0); 27.544 + *tarr++ = Vector3(0, 0, -1); 27.545 + *uvarr++ = uv[i]; 27.546 + } 27.547 + *varr++ = Vector3(x, -y, z); 27.548 + *varr++ = Vector3(x, -y, -z); 27.549 + *varr++ = Vector3(x, y, -z); 27.550 + *varr++ = Vector3(x, y, z); 27.551 + // back 27.552 + for(int i=0; i<4; i++) { 27.553 + *narr++ = Vector3(0, 0, -1); 27.554 + *tarr++ = Vector3(-1, 0, 0); 27.555 + *uvarr++ = uv[i]; 27.556 + } 27.557 + *varr++ = Vector3(x, -y, -z); 27.558 + *varr++ = Vector3(-x, -y, -z); 27.559 + *varr++ = Vector3(-x, y, -z); 27.560 + *varr++ = Vector3(x, y, -z); 27.561 + // left 27.562 + for(int i=0; i<4; i++) { 27.563 + *narr++ = Vector3(-1, 0, 0); 27.564 + *tarr++ = Vector3(0, 0, 1); 27.565 + *uvarr++ = uv[i]; 27.566 + } 27.567 + *varr++ = Vector3(-x, -y, -z); 27.568 + *varr++ = Vector3(-x, -y, z); 27.569 + *varr++ = Vector3(-x, y, z); 27.570 + *varr++ = Vector3(-x, y, -z); 27.571 + // top 27.572 + for(int i=0; i<4; i++) { 27.573 + *narr++ = Vector3(0, 1, 0); 27.574 + *tarr++ = Vector3(1, 0, 0); 27.575 + *uvarr++ = uv[i]; 27.576 + } 27.577 + *varr++ = Vector3(-x, y, z); 27.578 + *varr++ = Vector3(x, y, z); 27.579 + *varr++ = Vector3(x, y, -z); 27.580 + *varr++ = Vector3(-x, y, -z); 27.581 + // bottom 27.582 + for(int i=0; i<4; i++) { 27.583 + *narr++ = Vector3(0, -1, 0); 27.584 + *tarr++ = Vector3(1, 0, 0); 27.585 + *uvarr++ = uv[i]; 27.586 + } 27.587 + *varr++ = Vector3(-x, -y, -z); 27.588 + *varr++ = Vector3(x, -y, -z); 27.589 + *varr++ = Vector3(x, -y, z); 27.590 + *varr++ = Vector3(-x, -y, z); 27.591 + 27.592 + // index array 27.593 + static const int faceidx[] = {0, 1, 2, 0, 2, 3}; 27.594 + for(int i=0; i<num_faces; i++) { 27.595 + for(int j=0; j<6; j++) { 27.596 + *idxarr++ = faceidx[j] + i * 4; 27.597 + } 27.598 + } 27.599 +} 27.600 +*/ 27.601 + 27.602 +static inline Vector3 rev_vert(float u, float v, Vector2 (*rf)(float, float, void*), void *cls) 27.603 +{ 27.604 + Vector2 pos = rf(u, v, cls); 27.605 + 27.606 + float angle = u * 2.0 * M_PI; 27.607 + float x = pos.x * cos(angle); 27.608 + float y = pos.y; 27.609 + float z = pos.x * sin(angle); 27.610 + 27.611 + return Vector3(x, y, z); 27.612 +} 27.613 + 27.614 +// ------ surface of revolution ------- 27.615 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), void *cls) 27.616 +{ 27.617 + gen_revol(mesh, usub, vsub, rfunc, 0, cls); 27.618 +} 27.619 + 27.620 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), 27.621 + Vector2 (*nfunc)(float, float, void*), void *cls) 27.622 +{ 27.623 + if(!rfunc) return; 27.624 + if(usub < 3) usub = 3; 27.625 + if(vsub < 1) vsub = 1; 27.626 + 27.627 + mesh->clear(); 27.628 + 27.629 + int uverts = usub + 1; 27.630 + int vverts = vsub + 1; 27.631 + int num_verts = uverts * vverts; 27.632 + 27.633 + int num_quads = usub * vsub; 27.634 + int num_tri = num_quads * 2; 27.635 + 27.636 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.637 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.638 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.639 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.640 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.641 + 27.642 + float du = 1.0 / (float)(uverts - 1); 27.643 + float dv = 1.0 / (float)(vverts - 1); 27.644 + 27.645 + float u = 0.0; 27.646 + for(int i=0; i<uverts; i++) { 27.647 + float v = 0.0; 27.648 + for(int j=0; j<vverts; j++) { 27.649 + Vector3 pos = rev_vert(u, v, rfunc, cls); 27.650 + 27.651 + Vector3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls); 27.652 + Vector3 tang = nextu - pos; 27.653 + if(tang.length_sq() < 1e-6) { 27.654 + float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25; 27.655 + nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls); 27.656 + tang = nextu - pos; 27.657 + } 27.658 + 27.659 + Vector3 normal; 27.660 + if(nfunc) { 27.661 + normal = rev_vert(u, v, nfunc, cls); 27.662 + } else { 27.663 + Vector3 nextv = rev_vert(u, v + dv, rfunc, cls); 27.664 + Vector3 bitan = nextv - pos; 27.665 + if(bitan.length_sq() < 1e-6) { 27.666 + nextv = rev_vert(u, v - dv, rfunc, cls); 27.667 + bitan = pos - nextv; 27.668 + } 27.669 + 27.670 + normal = cross_product(tang, bitan); 27.671 + } 27.672 + 27.673 + *varr++ = pos; 27.674 + *narr++ = normal.normalized(); 27.675 + *tarr++ = tang.normalized(); 27.676 + *uvarr++ = Vector2(u, v); 27.677 + 27.678 + if(i < usub && j < vsub) { 27.679 + int idx = i * vverts + j; 27.680 + 27.681 + *idxarr++ = idx; 27.682 + *idxarr++ = idx + vverts + 1; 27.683 + *idxarr++ = idx + 1; 27.684 + 27.685 + *idxarr++ = idx; 27.686 + *idxarr++ = idx + vverts; 27.687 + *idxarr++ = idx + vverts + 1; 27.688 + } 27.689 + 27.690 + v += dv; 27.691 + } 27.692 + u += du; 27.693 + } 27.694 +} 27.695 + 27.696 + 27.697 +static inline Vector3 sweep_vert(float u, float v, float height, Vector2 (*sf)(float, float, void*), void *cls) 27.698 +{ 27.699 + Vector2 pos = sf(u, v, cls); 27.700 + 27.701 + float x = pos.x; 27.702 + float y = v * height; 27.703 + float z = pos.y; 27.704 + 27.705 + return Vector3(x, y, z); 27.706 +} 27.707 + 27.708 +// ---- sweep shape along a path ---- 27.709 +void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vector2 (*sfunc)(float, float, void*), void *cls) 27.710 +{ 27.711 + if(!sfunc) return; 27.712 + if(usub < 3) usub = 3; 27.713 + if(vsub < 1) vsub = 1; 27.714 + 27.715 + mesh->clear(); 27.716 + 27.717 + int uverts = usub + 1; 27.718 + int vverts = vsub + 1; 27.719 + int num_verts = uverts * vverts; 27.720 + 27.721 + int num_quads = usub * vsub; 27.722 + int num_tri = num_quads * 2; 27.723 + 27.724 + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 27.725 + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 27.726 + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 27.727 + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 27.728 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 27.729 + 27.730 + float du = 1.0 / (float)(uverts - 1); 27.731 + float dv = 1.0 / (float)(vverts - 1); 27.732 + 27.733 + float u = 0.0; 27.734 + for(int i=0; i<uverts; i++) { 27.735 + float v = 0.0; 27.736 + for(int j=0; j<vverts; j++) { 27.737 + Vector3 pos = sweep_vert(u, v, height, sfunc, cls); 27.738 + 27.739 + Vector3 nextu = sweep_vert(fmod(u + du, 1.0), v, height, sfunc, cls); 27.740 + Vector3 tang = nextu - pos; 27.741 + if(tang.length_sq() < 1e-6) { 27.742 + float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25; 27.743 + nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls); 27.744 + tang = nextu - pos; 27.745 + } 27.746 + 27.747 + Vector3 normal; 27.748 + Vector3 nextv = sweep_vert(u, v + dv, height, sfunc, cls); 27.749 + Vector3 bitan = nextv - pos; 27.750 + if(bitan.length_sq() < 1e-6) { 27.751 + nextv = sweep_vert(u, v - dv, height, sfunc, cls); 27.752 + bitan = pos - nextv; 27.753 + } 27.754 + 27.755 + normal = cross_product(tang, bitan); 27.756 + 27.757 + *varr++ = pos; 27.758 + *narr++ = normal.normalized(); 27.759 + *tarr++ = tang.normalized(); 27.760 + *uvarr++ = Vector2(u, v); 27.761 + 27.762 + if(i < usub && j < vsub) { 27.763 + int idx = i * vverts + j; 27.764 + 27.765 + *idxarr++ = idx; 27.766 + *idxarr++ = idx + vverts + 1; 27.767 + *idxarr++ = idx + 1; 27.768 + 27.769 + *idxarr++ = idx; 27.770 + *idxarr++ = idx + vverts; 27.771 + *idxarr++ = idx + vverts + 1; 27.772 + } 27.773 + 27.774 + v += dv; 27.775 + } 27.776 + u += du; 27.777 + } 27.778 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/src/meshgen.h Sun Nov 01 00:09:12 2015 +0200 28.3 @@ -0,0 +1,22 @@ 28.4 +#ifndef MESHGEN_H_ 28.5 +#define MESHGEN_H_ 28.6 + 28.7 +#include "vmath/vmath.h" 28.8 + 28.9 +class Mesh; 28.10 + 28.11 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange = 1.0, float vrange = 1.0); 28.12 +void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange = 1.0, float vrange = 1.0); 28.13 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0); 28.14 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0); 28.15 +void gen_plane(Mesh *mesh, float width, float height, int usub = 1, int vsub = 1); 28.16 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata = 0); 28.17 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub = 1, int vsub = 1); 28.18 + 28.19 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), void *cls = 0); 28.20 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), Vector2 (*nfunc)(float, float, void*), void *cls); 28.21 + 28.22 +/* callback args: (float u, float v, void *cls) -> Vector2 XZ offset u,v in [0, 1] */ 28.23 +void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vector2 (*sfunc)(float, float, void*), void *cls = 0); 28.24 + 28.25 +#endif // MESHGEN_H_
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/src/object.cc Sun Nov 01 00:09:12 2015 +0200 29.3 @@ -0,0 +1,226 @@ 29.4 +#include "object.h" 29.5 +#include "opengl.h" 29.6 +#include "sdr.h" 29.7 + 29.8 +Material::Material() 29.9 + : diffuse(1, 1, 1), specular(0, 0, 0) 29.10 +{ 29.11 + shininess = 60.0; 29.12 + alpha = 1.0; 29.13 +} 29.14 + 29.15 +RenderOps::RenderOps() 29.16 +{ 29.17 + zwrite = true; 29.18 + cast_shadows = true; 29.19 + transparent = false; 29.20 +} 29.21 + 29.22 +void RenderOps::setup() const 29.23 +{ 29.24 + if(!zwrite) { 29.25 + glDepthMask(0); 29.26 + } 29.27 + if(transparent) { 29.28 + glEnable(GL_BLEND); 29.29 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 29.30 + } else { 29.31 + glDisable(GL_BLEND); 29.32 + } 29.33 +} 29.34 + 29.35 +Object::Object() 29.36 +{ 29.37 + mesh = 0; 29.38 + tex = 0; 29.39 + sdr = 0; 29.40 +} 29.41 + 29.42 +Object::~Object() 29.43 +{ 29.44 + delete mesh; 29.45 +} 29.46 + 29.47 +Matrix4x4 &Object::xform() 29.48 +{ 29.49 + return matrix; 29.50 +} 29.51 + 29.52 +const Matrix4x4 &Object::xform() const 29.53 +{ 29.54 + return matrix; 29.55 +} 29.56 + 29.57 +Matrix4x4 &Object::tex_xform() 29.58 +{ 29.59 + return tex_matrix; 29.60 +} 29.61 + 29.62 +const Matrix4x4 &Object::tex_xform() const 29.63 +{ 29.64 + return tex_matrix; 29.65 +} 29.66 + 29.67 +void Object::set_mesh(Mesh *m) 29.68 +{ 29.69 + this->mesh = m; 29.70 +} 29.71 + 29.72 +Mesh *Object::get_mesh() const 29.73 +{ 29.74 + return mesh; 29.75 +} 29.76 + 29.77 +void Object::set_texture(unsigned int tex) 29.78 +{ 29.79 + this->tex = tex; 29.80 +} 29.81 + 29.82 +unsigned int Object::get_texture() const 29.83 +{ 29.84 + return tex; 29.85 +} 29.86 + 29.87 +void Object::set_shader(unsigned int sdr) 29.88 +{ 29.89 + if(GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader) { 29.90 + this->sdr = sdr; 29.91 + } 29.92 +} 29.93 + 29.94 +unsigned int Object::get_shader() const 29.95 +{ 29.96 + return sdr; 29.97 +} 29.98 + 29.99 +void Object::draw() const 29.100 +{ 29.101 + if(!mesh) return; 29.102 + 29.103 + /* 29.104 + if(shadow_pass && !rop.cast_shadows) { 29.105 + return; 29.106 + } 29.107 + */ 29.108 + 29.109 + glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT); 29.110 + rop.setup(); 29.111 + 29.112 + glUseProgram(sdr); 29.113 + 29.114 + if(tex) { 29.115 + glBindTexture(GL_TEXTURE_2D, tex); 29.116 + glEnable(GL_TEXTURE_2D); 29.117 + 29.118 + glMatrixMode(GL_TEXTURE); 29.119 + glPushMatrix(); 29.120 + glLoadTransposeMatrixf(tex_matrix[0]); 29.121 + } else { 29.122 + glDisable(GL_TEXTURE_2D); 29.123 + } 29.124 + 29.125 + glMatrixMode(GL_MODELVIEW); 29.126 + glPushMatrix(); 29.127 + glMultTransposeMatrixf(matrix[0]); 29.128 + 29.129 + if(sdr) { 29.130 + set_uniform_matrix4_transposed(sdr, "world_matrix", (float*)matrix[0]); 29.131 + } 29.132 + 29.133 + float dcol[] = {mtl.diffuse.x, mtl.diffuse.y, mtl.diffuse.z, mtl.alpha}; 29.134 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dcol); 29.135 + float scol[] = {mtl.specular.x, mtl.specular.y, mtl.specular.z, 1.0f}; 29.136 + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol); 29.137 + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mtl.shininess); 29.138 + 29.139 + mesh->draw(); 29.140 + 29.141 + if(tex) { 29.142 + glDisable(GL_TEXTURE_2D); 29.143 + 29.144 + glMatrixMode(GL_TEXTURE); 29.145 + glPopMatrix(); 29.146 + } 29.147 + 29.148 + if(sdr) { 29.149 + glUseProgram(0); 29.150 + } 29.151 + 29.152 + glMatrixMode(GL_MODELVIEW); 29.153 + glPopMatrix(); 29.154 + 29.155 + glPopAttrib(); 29.156 +} 29.157 + 29.158 +void Object::draw_wire(const Vector4 &col) const 29.159 +{ 29.160 + glPushAttrib(GL_ENABLE_BIT); 29.161 + glDisable(GL_LIGHTING); 29.162 + glUseProgram(0); 29.163 + 29.164 + glMatrixMode(GL_MODELVIEW); 29.165 + glPushMatrix(); 29.166 + glMultTransposeMatrixf(matrix[0]); 29.167 + 29.168 + glColor4f(col.x, col.y, col.z, col.w); 29.169 + mesh->draw_wire(); 29.170 + 29.171 + glPopMatrix(); 29.172 + glPopAttrib(); 29.173 +} 29.174 + 29.175 +void Object::draw_vertices(const Vector4 &col) const 29.176 +{ 29.177 + glPushAttrib(GL_ENABLE_BIT); 29.178 + glDisable(GL_LIGHTING); 29.179 + glUseProgram(0); 29.180 + 29.181 + glMatrixMode(GL_MODELVIEW); 29.182 + glPushMatrix(); 29.183 + glMultTransposeMatrixf(matrix[0]); 29.184 + 29.185 + glColor4f(col.x, col.y, col.z, col.w); 29.186 + mesh->draw_vertices(); 29.187 + 29.188 + glPopMatrix(); 29.189 + glPopAttrib(); 29.190 +} 29.191 + 29.192 +void Object::draw_normals(float len, const Vector4 &col) const 29.193 +{ 29.194 + glPushAttrib(GL_ENABLE_BIT); 29.195 + glDisable(GL_LIGHTING); 29.196 + 29.197 + glMatrixMode(GL_MODELVIEW); 29.198 + glPushMatrix(); 29.199 + glMultTransposeMatrixf(matrix[0]); 29.200 + 29.201 + glColor4f(col.x, col.y, col.z, col.w); 29.202 + mesh->set_vis_vecsize(len); 29.203 + mesh->draw_normals(); 29.204 + 29.205 + glPopMatrix(); 29.206 + glPopAttrib(); 29.207 +} 29.208 + 29.209 +void Object::draw_tangents(float len, const Vector4 &col) const 29.210 +{ 29.211 + glPushAttrib(GL_ENABLE_BIT); 29.212 + glDisable(GL_LIGHTING); 29.213 + 29.214 + glMatrixMode(GL_MODELVIEW); 29.215 + glPushMatrix(); 29.216 + glMultTransposeMatrixf(matrix[0]); 29.217 + 29.218 + glColor4f(col.x, col.y, col.z, col.w); 29.219 + mesh->set_vis_vecsize(len); 29.220 + mesh->draw_tangents(); 29.221 + 29.222 + glPopMatrix(); 29.223 + glPopAttrib(); 29.224 +} 29.225 + 29.226 +bool Object::intersect(const Ray &ray, HitPoint *hit) const 29.227 +{ 29.228 + return false; // TODO 29.229 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/src/object.h Sun Nov 01 00:09:12 2015 +0200 30.3 @@ -0,0 +1,64 @@ 30.4 +#ifndef OBJECT_H_ 30.5 +#define OBJECT_H_ 30.6 + 30.7 +#include "mesh.h" 30.8 +#include "geom.h" 30.9 +#include "vmath/vmath.h" 30.10 + 30.11 +struct Material { 30.12 + Vector3 diffuse; 30.13 + Vector3 specular; 30.14 + float shininess; 30.15 + float alpha; 30.16 + 30.17 + Material(); 30.18 +}; 30.19 + 30.20 +struct RenderOps { 30.21 + bool zwrite; 30.22 + bool cast_shadows; 30.23 + bool transparent; 30.24 + 30.25 + RenderOps(); 30.26 + void setup() const; 30.27 +}; 30.28 + 30.29 +class Object { 30.30 +private: 30.31 + Mesh *mesh; 30.32 + Matrix4x4 matrix; 30.33 + unsigned int tex; 30.34 + Matrix4x4 tex_matrix; 30.35 + unsigned int sdr; 30.36 + 30.37 +public: 30.38 + Material mtl; 30.39 + RenderOps rop; 30.40 + 30.41 + Object(); 30.42 + ~Object(); 30.43 + 30.44 + Matrix4x4 &xform(); 30.45 + const Matrix4x4 &xform() const; 30.46 + 30.47 + Matrix4x4 &tex_xform(); 30.48 + const Matrix4x4 &tex_xform() const; 30.49 + 30.50 + void set_mesh(Mesh *m); 30.51 + Mesh *get_mesh() const; 30.52 + 30.53 + void set_texture(unsigned int tex); 30.54 + unsigned int get_texture() const; 30.55 + void set_shader(unsigned int sdr); 30.56 + unsigned int get_shader() const; 30.57 + 30.58 + void draw() const; 30.59 + void draw_wire(const Vector4 &col = Vector4(1, 1, 1, 1)) const; 30.60 + void draw_vertices(const Vector4 &col = Vector4(1, 0.3, 0.2, 1)) const; 30.61 + void draw_normals(float len = 1.0, const Vector4 &col = Vector4(0.1, 0.2, 1.0, 1)) const; 30.62 + void draw_tangents(float len = 1.0, const Vector4 &col = Vector4(0.1, 1.0, 0.2, 1)) const; 30.63 + 30.64 + bool intersect(const Ray &ray, HitPoint *hit) const; 30.65 +}; 30.66 + 30.67 +#endif // OBJECT_H_
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/src/opengl.c Sun Nov 01 00:09:12 2015 +0200 31.3 @@ -0,0 +1,16 @@ 31.4 +#include "opengl.h" 31.5 + 31.6 +struct GLCaps glcaps; 31.7 + 31.8 +int init_opengl() 31.9 +{ 31.10 + glewInit(); 31.11 + 31.12 + glcaps.shaders = GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader; 31.13 + glcaps.fsaa = GLEW_ARB_multisample; 31.14 + glcaps.sep_spec = GLEW_EXT_separate_specular_color; 31.15 + glcaps.fbo = GLEW_ARB_framebuffer_object; 31.16 + glcaps.shadow = GLEW_ARB_shadow | GLEW_SGIX_shadow; 31.17 + 31.18 + return 0; 31.19 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/src/opengl.h Sun Nov 01 00:09:12 2015 +0200 32.3 @@ -0,0 +1,25 @@ 32.4 +#ifndef OPENGL_H_ 32.5 +#define OPENGL_H_ 32.6 + 32.7 +#include <GL/glew.h> 32.8 + 32.9 +struct GLCaps { 32.10 + int shaders; 32.11 + int fsaa; 32.12 + int sep_spec; 32.13 + int fbo; 32.14 + int shadow; 32.15 +}; 32.16 +extern struct GLCaps glcaps; 32.17 + 32.18 +#ifdef __cplusplus 32.19 +extern "C" { 32.20 +#endif 32.21 + 32.22 +int init_opengl(); 32.23 + 32.24 +#ifdef __cplusplus 32.25 +} 32.26 +#endif 32.27 + 32.28 +#endif /* OPENGL_H_ */
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/src/opt.cc Sun Nov 01 00:09:12 2015 +0200 33.3 @@ -0,0 +1,17 @@ 33.4 +#include <stdio.h> 33.5 +#include "opt.h" 33.6 + 33.7 +Options opt; 33.8 + 33.9 +bool init_options(int argc, char **argv) 33.10 +{ 33.11 + // TODO read config files, parse args, etc... 33.12 + 33.13 + opt.xres = 1280; 33.14 + opt.yres = 800; 33.15 + opt.fullscreen = false; 33.16 + opt.shadows = true; 33.17 + opt.reflections = true; 33.18 + 33.19 + return true; 33.20 +}
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/src/opt.h Sun Nov 01 00:09:12 2015 +0200 34.3 @@ -0,0 +1,16 @@ 34.4 +#ifndef OPT_H_ 34.5 +#define OPT_H_ 34.6 + 34.7 +#include "vmath/vmath.h" 34.8 + 34.9 +struct Options { 34.10 + int xres, yres; 34.11 + bool fullscreen; 34.12 + bool shadows, reflections; 34.13 +}; 34.14 + 34.15 +extern Options opt; 34.16 + 34.17 +bool init_options(int argc, char **argv); 34.18 + 34.19 +#endif /* OPT_H_ */
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/src/pnoise.cc Sun Nov 01 00:09:12 2015 +0200 35.3 @@ -0,0 +1,166 @@ 35.4 +#include <stdlib.h> 35.5 +#include "pnoise.h" 35.6 +#include "vmath/vmath.h" 35.7 + 35.8 +#define B 0x100 35.9 +#define BM 0xff 35.10 +#define N 0x1000 35.11 +#define NP 12 35.12 +#define NM 0xfff 35.13 + 35.14 +#define s_curve(t) ((t) * (t) * (3.0f - 2.0f * (t))) 35.15 +#define setup(elem, b0, b1, r0, r1) \ 35.16 + do { \ 35.17 + scalar_t t = elem + N; \ 35.18 + b0 = ((int)t) & BM; \ 35.19 + b1 = (b0 + 1) & BM; \ 35.20 + r0 = t - (int)t; \ 35.21 + r1 = r0 - 1.0f; \ 35.22 + } while(0) 35.23 + 35.24 +#define setup_p(elem, b0, b1, r0, r1, p) \ 35.25 + do { \ 35.26 + scalar_t t = elem + N; \ 35.27 + b0 = (((int)t) & BM) % p; \ 35.28 + b1 = ((b0 + 1) & BM) % p; \ 35.29 + r0 = t - (int)t; \ 35.30 + r1 = r0 - 1.0f; \ 35.31 + } while(0) 35.32 + 35.33 +static int perm[B + B + 2]; 35.34 +static vec2_t grad2[B + B + 2]; 35.35 +static bool tables_valid; 35.36 + 35.37 +static void init_noise() 35.38 +{ 35.39 + for(int i=0; i<B; i++) { 35.40 + perm[i] = i; 35.41 + 35.42 + grad2[i].x = (float)((rand() % (B + B)) - B) / B; 35.43 + grad2[i].y = (float)((rand() % (B + B)) - B) / B; 35.44 + grad2[i] = v2_normalize(grad2[i]); 35.45 + } 35.46 + 35.47 + for(int i=0; i<B; i++) { 35.48 + int rand_idx = rand() % B; 35.49 + 35.50 + int tmp = perm[i]; 35.51 + perm[i] = perm[rand_idx]; 35.52 + perm[rand_idx] = tmp; 35.53 + } 35.54 + 35.55 + for(int i=0; i<B+2; i++) { 35.56 + perm[B + i] = perm[i]; 35.57 + grad2[B + i] = grad2[i]; 35.58 + } 35.59 +} 35.60 + 35.61 +#define lerp(a, b, t) ((a) + ((b) - (a)) * t) 35.62 + 35.63 +float dbg_noise2(float x, float y) 35.64 +{ 35.65 + if(!tables_valid) { 35.66 + init_noise(); 35.67 + tables_valid = true; 35.68 + } 35.69 + 35.70 + int bx0, bx1, by0, by1; 35.71 + float rx0, rx1, ry0, ry1; 35.72 + setup(x, bx0, bx1, rx0, rx1); 35.73 + setup(y, by0, by1, ry0, ry1); 35.74 + 35.75 + int i = perm[bx0]; 35.76 + int j = perm[bx1]; 35.77 + 35.78 + int b00 = perm[i + by0]; 35.79 + int b10 = perm[j + by0]; 35.80 + int b01 = perm[i + by1]; 35.81 + int b11 = perm[j + by1]; 35.82 + 35.83 + float sx = s_curve(rx0); 35.84 + float sy = s_curve(ry0); 35.85 + 35.86 + vec2_t g00 = grad2[b00]; 35.87 + vec2_t g10 = grad2[b10]; 35.88 + vec2_t g01 = grad2[b01]; 35.89 + vec2_t g11 = grad2[b11]; 35.90 + 35.91 + float u = g00.x * rx0 + g00.y * ry0; 35.92 + float v = g10.x * rx1 + g10.y * ry0; 35.93 + float a = lerp(u, v, sx); 35.94 + 35.95 + u = g01.x * rx0 + g01.y * ry1; 35.96 + v = g11.x * rx1 + g11.y * ry1; 35.97 + float b = lerp(u, v, sx); 35.98 + 35.99 + return lerp(a, b, sy); 35.100 +} 35.101 + 35.102 +float pnoise2(float x, float y, int period) 35.103 +{ 35.104 + if(!tables_valid) { 35.105 + init_noise(); 35.106 + tables_valid = true; 35.107 + } 35.108 + 35.109 + int bx0, bx1, by0, by1; 35.110 + float rx0, rx1, ry0, ry1; 35.111 + setup_p(x, bx0, bx1, rx0, rx1, period); 35.112 + setup_p(y, by0, by1, ry0, ry1, period); 35.113 + 35.114 + int i = perm[bx0]; 35.115 + int j = perm[bx1]; 35.116 + 35.117 + int b00 = perm[i + by0]; 35.118 + int b10 = perm[j + by0]; 35.119 + int b01 = perm[i + by1]; 35.120 + int b11 = perm[j + by1]; 35.121 + 35.122 + float sx = s_curve(rx0); 35.123 + float sy = s_curve(ry0); 35.124 + 35.125 + vec2_t g00 = grad2[b00]; 35.126 + vec2_t g10 = grad2[b10]; 35.127 + vec2_t g01 = grad2[b01]; 35.128 + vec2_t g11 = grad2[b11]; 35.129 + 35.130 + float u = g00.x * rx0 + g00.y * ry0; 35.131 + float v = g10.x * rx1 + g10.y * ry0; 35.132 + float a = lerp(u, v, sx); 35.133 + 35.134 + u = g01.x * rx0 + g01.y * ry1; 35.135 + v = g11.x * rx1 + g11.y * ry1; 35.136 + float b = lerp(u, v, sx); 35.137 + 35.138 + return lerp(a, b, sy); 35.139 +} 35.140 + 35.141 +float pfbm2(float x, float y, int octaves, int period) 35.142 +{ 35.143 + float res = 0.0; 35.144 + float s = 1.0; 35.145 + 35.146 + for(int i=0; i<octaves; i++) { 35.147 + float v = pnoise2(x * s, y * s, period); 35.148 + res += v / s; 35.149 + s *= 2.0; 35.150 + period *= 2; 35.151 + } 35.152 + 35.153 + return res; 35.154 +} 35.155 + 35.156 +float pturbulence2(float x, float y, int octaves, int period) 35.157 +{ 35.158 + float res = 0.0; 35.159 + float s = 1.0; 35.160 + 35.161 + for(int i=0; i<octaves; i++) { 35.162 + float v = fabs(pnoise2(x * s, y * s, period)); 35.163 + res += v / s; 35.164 + s *= 2.0; 35.165 + period *= 2; 35.166 + } 35.167 + 35.168 + return res; 35.169 +}
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/src/pnoise.h Sun Nov 01 00:09:12 2015 +0200 36.3 @@ -0,0 +1,9 @@ 36.4 +#ifndef PNOISE_H_ 36.5 +#define PNOISE_H_ 36.6 + 36.7 +float dbg_noise2(float x, float y); 36.8 +float pnoise2(float x, float y, int period); 36.9 +float pfbm2(float x, float y, int octaves, int period); 36.10 +float pturbulence2(float x, float y, int octaves, int period); 36.11 + 36.12 +#endif // PNOISE_H_
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 37.2 +++ b/src/rng.cc Sun Nov 01 00:09:12 2015 +0200 37.3 @@ -0,0 +1,217 @@ 37.4 +#include <stdlib.h> 37.5 +#include <string.h> 37.6 +#include "rng.h" 37.7 + 37.8 +//#define USE_STD_RAND 37.9 + 37.10 +// defined at the end 37.11 +/** 37.12 + * tinymt32 internal state vector and parameters 37.13 + */ 37.14 +struct tinymt32_t { 37.15 + uint32_t status[4]; 37.16 + uint32_t mat1; 37.17 + uint32_t mat2; 37.18 + uint32_t tmat; 37.19 +}; 37.20 + 37.21 +#ifndef USE_STD_RAND 37.22 +static void tinymt32_init(tinymt32_t * random, uint32_t seed); 37.23 +inline static uint32_t tinymt32_generate_uint32(tinymt32_t * random); 37.24 +inline static float tinymt32_generate_float(tinymt32_t * random); 37.25 +#endif 37.26 + 37.27 +static RandGen defrng; 37.28 + 37.29 +struct RandGenState { 37.30 + tinymt32_t st; 37.31 +}; 37.32 + 37.33 +RandGen::RandGen() 37.34 +{ 37.35 + state = new RandGenState; 37.36 + memset(state, 0, sizeof *state); 37.37 +#ifndef USE_STD_RAND 37.38 + tinymt32_init(&state->st, 0); 37.39 +#endif 37.40 +} 37.41 + 37.42 +RandGen::~RandGen() 37.43 +{ 37.44 + delete state; 37.45 +} 37.46 + 37.47 +void RandGen::seed(uint32_t s) 37.48 +{ 37.49 +#ifndef USE_STD_RAND 37.50 + tinymt32_init(&state->st, s); 37.51 +#else 37.52 + srand(s); 37.53 +#endif 37.54 +} 37.55 + 37.56 +uint32_t RandGen::generate() 37.57 +{ 37.58 +#ifndef USE_STD_RAND 37.59 + return tinymt32_generate_uint32(&state->st); 37.60 +#else 37.61 + return rand(); 37.62 +#endif 37.63 +} 37.64 + 37.65 +float RandGen::generate_float() 37.66 +{ 37.67 +#ifndef USE_STD_RAND 37.68 + return tinymt32_generate_float(&state->st); 37.69 +#else 37.70 + return (float)rand() / (float)RAND_MAX; 37.71 +#endif 37.72 +} 37.73 + 37.74 +void rng_srand(uint32_t s) 37.75 +{ 37.76 + defrng.seed(s); 37.77 +} 37.78 + 37.79 +uint32_t rng_rand() 37.80 +{ 37.81 + return defrng.generate(); 37.82 +} 37.83 + 37.84 +float rng_frand() 37.85 +{ 37.86 + return defrng.generate_float(); 37.87 +} 37.88 + 37.89 + 37.90 +#ifndef USE_STD_RAND 37.91 +/** 37.92 + * @file tinymt32.h 37.93 + * 37.94 + * @brief Tiny Mersenne Twister only 127 bit internal state 37.95 + * 37.96 + * @author Mutsuo Saito (Hiroshima University) 37.97 + * @author Makoto Matsumoto (University of Tokyo) 37.98 + * 37.99 + * Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto, 37.100 + * Hiroshima University and The University of Tokyo. 37.101 + * All rights reserved. 37.102 + * 37.103 + * The 3-clause BSD License is applied to this software, see 37.104 + * LICENSE.txt 37.105 + */ 37.106 +#define TINYMT32_MEXP 127 37.107 +#define TINYMT32_SH0 1 37.108 +#define TINYMT32_SH1 10 37.109 +#define TINYMT32_SH8 8 37.110 +#define TINYMT32_MASK UINT32_C(0x7fffffff) 37.111 +#define TINYMT32_MUL (1.0f / 4294967296.0f) 37.112 + 37.113 +/** 37.114 + * This function changes internal state of tinymt32. 37.115 + * Users should not call this function directly. 37.116 + * @param random tinymt internal status 37.117 + */ 37.118 +inline static void tinymt32_next_state(tinymt32_t * random) { 37.119 + uint32_t x; 37.120 + uint32_t y; 37.121 + 37.122 + y = random->status[3]; 37.123 + x = (random->status[0] & TINYMT32_MASK) 37.124 + ^ random->status[1] 37.125 + ^ random->status[2]; 37.126 + x ^= (x << TINYMT32_SH0); 37.127 + y ^= (y >> TINYMT32_SH0) ^ x; 37.128 + random->status[0] = random->status[1]; 37.129 + random->status[1] = random->status[2]; 37.130 + random->status[2] = x ^ (y << TINYMT32_SH1); 37.131 + random->status[3] = y; 37.132 + random->status[1] ^= -((int32_t)(y & 1)) & random->mat1; 37.133 + random->status[2] ^= -((int32_t)(y & 1)) & random->mat2; 37.134 +} 37.135 + 37.136 +/** 37.137 + * This function outputs 32-bit unsigned integer from internal state. 37.138 + * Users should not call this function directly. 37.139 + * @param random tinymt internal status 37.140 + * @return 32-bit unsigned pseudorandom number 37.141 + */ 37.142 +inline static uint32_t tinymt32_temper(tinymt32_t * random) { 37.143 + uint32_t t0, t1; 37.144 + t0 = random->status[3]; 37.145 +#if defined(LINEARITY_CHECK) 37.146 + t1 = random->status[0] 37.147 + ^ (random->status[2] >> TINYMT32_SH8); 37.148 +#else 37.149 + t1 = random->status[0] 37.150 + + (random->status[2] >> TINYMT32_SH8); 37.151 +#endif 37.152 + t0 ^= t1; 37.153 + t0 ^= -((int32_t)(t1 & 1)) & random->tmat; 37.154 + return t0; 37.155 +} 37.156 + 37.157 +/** 37.158 + * This function outputs 32-bit unsigned integer from internal state. 37.159 + * @param random tinymt internal status 37.160 + * @return 32-bit unsigned integer r (0 <= r < 2^32) 37.161 + */ 37.162 +inline static uint32_t tinymt32_generate_uint32(tinymt32_t * random) { 37.163 + tinymt32_next_state(random); 37.164 + return tinymt32_temper(random); 37.165 +} 37.166 + 37.167 +/** 37.168 + * This function outputs floating point number from internal state. 37.169 + * This function is implemented using multiplying by 1 / 2^32. 37.170 + * floating point multiplication is faster than using union trick in 37.171 + * my Intel CPU. 37.172 + * @param random tinymt internal status 37.173 + * @return floating point number r (0.0 <= r < 1.0) 37.174 + */ 37.175 +inline static float tinymt32_generate_float(tinymt32_t * random) { 37.176 + tinymt32_next_state(random); 37.177 + return tinymt32_temper(random) * TINYMT32_MUL; 37.178 +} 37.179 + 37.180 +#define MIN_LOOP 8 37.181 +#define PRE_LOOP 8 37.182 + 37.183 +/** 37.184 + * This function certificate the period of 2^127-1. 37.185 + * @param random tinymt state vector. 37.186 + */ 37.187 +static void period_certification(tinymt32_t * random) { 37.188 + if ((random->status[0] & TINYMT32_MASK) == 0 && 37.189 + random->status[1] == 0 && 37.190 + random->status[2] == 0 && 37.191 + random->status[3] == 0) { 37.192 + random->status[0] = 'T'; 37.193 + random->status[1] = 'I'; 37.194 + random->status[2] = 'N'; 37.195 + random->status[3] = 'Y'; 37.196 + } 37.197 +} 37.198 + 37.199 +/** 37.200 + * This function initializes the internal state array with a 32-bit 37.201 + * unsigned integer seed. 37.202 + * @param random tinymt state vector. 37.203 + * @param seed a 32-bit unsigned integer used as a seed. 37.204 + */ 37.205 +static void tinymt32_init(tinymt32_t * random, uint32_t seed) { 37.206 + random->status[0] = seed; 37.207 + random->status[1] = random->mat1; 37.208 + random->status[2] = random->mat2; 37.209 + random->status[3] = random->tmat; 37.210 + for (int i = 1; i < MIN_LOOP; i++) { 37.211 + random->status[i & 3] ^= i + UINT32_C(1812433253) 37.212 + * (random->status[(i - 1) & 3] 37.213 + ^ (random->status[(i - 1) & 3] >> 30)); 37.214 + } 37.215 + period_certification(random); 37.216 + for (int i = 0; i < PRE_LOOP; i++) { 37.217 + tinymt32_next_state(random); 37.218 + } 37.219 +} 37.220 +#endif // !defined(USE_STD_RAND)
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/src/rng.h Sun Nov 01 00:09:12 2015 +0200 38.3 @@ -0,0 +1,30 @@ 38.4 +#ifndef RNG_H_ 38.5 +#define RNG_H_ 38.6 + 38.7 +#include <stdint.h> 38.8 + 38.9 +struct RandGenState; 38.10 + 38.11 +class RandGen { 38.12 +private: 38.13 + RandGenState *state; 38.14 + 38.15 + RandGen(const RandGen&); 38.16 + RandGen &operator =(const RandGen&); 38.17 + 38.18 +public: 38.19 + RandGen(); 38.20 + ~RandGen(); 38.21 + 38.22 + void seed(uint32_t s); 38.23 + 38.24 + uint32_t generate(); 38.25 + float generate_float(); 38.26 +}; 38.27 + 38.28 +void rng_srand(uint32_t s); 38.29 +uint32_t rng_rand(); 38.30 +float rng_frand(); 38.31 + 38.32 + 38.33 +#endif // RNG_H_
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/src/scene.cc Sun Nov 01 00:09:12 2015 +0200 39.3 @@ -0,0 +1,63 @@ 39.4 +#include "scene.h" 39.5 +#include "opengl.h" 39.6 +#include "opt.h" 39.7 + 39.8 +extern bool wireframe; 39.9 +static int max_lights = -1; 39.10 + 39.11 +Scene::~Scene() 39.12 +{ 39.13 + clear(); 39.14 +} 39.15 + 39.16 +void Scene::clear() 39.17 +{ 39.18 + for(size_t i=0; i<objects.size(); i++) { 39.19 + delete objects[i]; 39.20 + } 39.21 + objects.clear(); 39.22 + 39.23 + for(size_t i=0; i<lights.size(); i++) { 39.24 + delete lights[i]; 39.25 + } 39.26 + lights.clear(); 39.27 +} 39.28 + 39.29 +void Scene::add_object(Object *obj) 39.30 +{ 39.31 + objects.push_back(obj); 39.32 +} 39.33 + 39.34 +void Scene::add_light(Light *lt) 39.35 +{ 39.36 + lights.push_back(lt); 39.37 +} 39.38 + 39.39 +void Scene::draw(unsigned int flags) const 39.40 +{ 39.41 + if(max_lights == -1) { 39.42 + glGetIntegerv(GL_MAX_LIGHTS, &max_lights); 39.43 + printf("max lights: %d\n", max_lights); 39.44 + } 39.45 + 39.46 + int num_lt = lights.size(); 39.47 + for(int i=0; i<max_lights; i++) { 39.48 + if(i < num_lt) { 39.49 + glEnable(GL_LIGHT0 + i); 39.50 + lights[i]->setup(i); 39.51 + } else { 39.52 + glDisable(GL_LIGHT0 + i); 39.53 + } 39.54 + } 39.55 + 39.56 + for(size_t i=0; i<objects.size(); i++) { 39.57 + unsigned int mask = objects[i]->rop.transparent ? DRAW_TRANSPARENT : DRAW_SOLID; 39.58 + if(mask & flags) { 39.59 + if(wireframe) { 39.60 + objects[i]->draw_wire(); 39.61 + } else { 39.62 + objects[i]->draw(); 39.63 + } 39.64 + } 39.65 + } 39.66 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 40.2 +++ b/src/scene.h Sun Nov 01 00:09:12 2015 +0200 40.3 @@ -0,0 +1,29 @@ 40.4 +#ifndef SCENE_H_ 40.5 +#define SCENE_H_ 40.6 + 40.7 +#include <vector> 40.8 +#include "object.h" 40.9 +#include "light.h" 40.10 + 40.11 +enum { 40.12 + DRAW_SOLID = 1, 40.13 + DRAW_TRANSPARENT = 2, 40.14 + DRAW_ALL = 0x7fffffff 40.15 +}; 40.16 + 40.17 +class Scene { 40.18 +public: 40.19 + std::vector<Object*> objects; 40.20 + std::vector<Light*> lights; 40.21 + 40.22 + ~Scene(); 40.23 + 40.24 + void clear(); 40.25 + 40.26 + void add_object(Object *obj); 40.27 + void add_light(Light *lt); 40.28 + 40.29 + void draw(unsigned int flags = DRAW_ALL) const; 40.30 +}; 40.31 + 40.32 +#endif // SCENE_H_
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 41.2 +++ b/src/sdr.c Sun Nov 01 00:09:12 2015 +0200 41.3 @@ -0,0 +1,407 @@ 41.4 +#include <stdio.h> 41.5 +#include <stdlib.h> 41.6 +#include <string.h> 41.7 +#include <errno.h> 41.8 +#include <stdarg.h> 41.9 +#include <assert.h> 41.10 +#include "opengl.h" 41.11 + 41.12 +#if defined(unix) || defined(__unix__) 41.13 +#include <unistd.h> 41.14 +#include <sys/stat.h> 41.15 +#endif /* unix */ 41.16 + 41.17 +#include "sdr.h" 41.18 + 41.19 +static const char *sdrtypestr(unsigned int sdrtype); 41.20 + 41.21 +unsigned int create_vertex_shader(const char *src) 41.22 +{ 41.23 + return create_shader(src, GL_VERTEX_SHADER); 41.24 +} 41.25 + 41.26 +unsigned int create_pixel_shader(const char *src) 41.27 +{ 41.28 + return create_shader(src, GL_FRAGMENT_SHADER); 41.29 +} 41.30 + 41.31 +unsigned int create_tessctl_shader(const char *src) 41.32 +{ 41.33 +#ifdef GL_TESS_CONTROL_SHADER 41.34 + return create_shader(src, GL_TESS_CONTROL_SHADER); 41.35 +#else 41.36 + return 0; 41.37 +#endif 41.38 +} 41.39 + 41.40 +unsigned int create_tesseval_shader(const char *src) 41.41 +{ 41.42 +#ifdef GL_TESS_EVALUATION_SHADER 41.43 + return create_shader(src, GL_TESS_EVALUATION_SHADER); 41.44 +#else 41.45 + return 0; 41.46 +#endif 41.47 +} 41.48 + 41.49 +unsigned int create_geometry_shader(const char *src) 41.50 +{ 41.51 +#ifdef GL_GEOMETRY_SHADER 41.52 + return create_shader(src, GL_GEOMETRY_SHADER); 41.53 +#else 41.54 + return 0; 41.55 +#endif 41.56 +} 41.57 + 41.58 +unsigned int create_shader(const char *src, unsigned int sdr_type) 41.59 +{ 41.60 + unsigned int sdr; 41.61 + int success, info_len; 41.62 + char *info_str = 0; 41.63 + GLenum err; 41.64 + 41.65 + sdr = glCreateShader(sdr_type); 41.66 + assert(glGetError() == GL_NO_ERROR); 41.67 + glShaderSource(sdr, 1, &src, 0); 41.68 + err = glGetError(); 41.69 + assert(err == GL_NO_ERROR); 41.70 + glCompileShader(sdr); 41.71 + assert(glGetError() == GL_NO_ERROR); 41.72 + 41.73 + glGetShaderiv(sdr, GL_COMPILE_STATUS, &success); 41.74 + assert(glGetError() == GL_NO_ERROR); 41.75 + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); 41.76 + assert(glGetError() == GL_NO_ERROR); 41.77 + 41.78 + if(info_len) { 41.79 + if((info_str = malloc(info_len + 1))) { 41.80 + glGetShaderInfoLog(sdr, info_len, 0, info_str); 41.81 + assert(glGetError() == GL_NO_ERROR); 41.82 + info_str[info_len] = 0; 41.83 + } 41.84 + } 41.85 + 41.86 + if(success) { 41.87 + fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str); 41.88 + } else { 41.89 + fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str); 41.90 + glDeleteShader(sdr); 41.91 + sdr = 0; 41.92 + } 41.93 + 41.94 + free(info_str); 41.95 + return sdr; 41.96 +} 41.97 + 41.98 +void free_shader(unsigned int sdr) 41.99 +{ 41.100 + glDeleteShader(sdr); 41.101 +} 41.102 + 41.103 +unsigned int load_vertex_shader(const char *fname) 41.104 +{ 41.105 + return load_shader(fname, GL_VERTEX_SHADER); 41.106 +} 41.107 + 41.108 +unsigned int load_pixel_shader(const char *fname) 41.109 +{ 41.110 + return load_shader(fname, GL_FRAGMENT_SHADER); 41.111 +} 41.112 + 41.113 +unsigned int load_tessctl_shader(const char *fname) 41.114 +{ 41.115 +#ifdef GL_TESS_CONTROL_SHADER 41.116 + return load_shader(fname, GL_TESS_CONTROL_SHADER); 41.117 +#else 41.118 + return 0; 41.119 +#endif 41.120 +} 41.121 + 41.122 +unsigned int load_tesseval_shader(const char *fname) 41.123 +{ 41.124 +#ifdef GL_TESS_EVALUATION_SHADER 41.125 + return load_shader(fname, GL_TESS_EVALUATION_SHADER); 41.126 +#else 41.127 + return 0; 41.128 +#endif 41.129 +} 41.130 + 41.131 +unsigned int load_geometry_shader(const char *fname) 41.132 +{ 41.133 +#ifdef GL_GEOMETRY_SHADER 41.134 + return load_shader(fname, GL_GEOMETRY_SHADER); 41.135 +#else 41.136 + return 0; 41.137 +#endif 41.138 +} 41.139 + 41.140 +unsigned int load_shader(const char *fname, unsigned int sdr_type) 41.141 +{ 41.142 + unsigned int sdr; 41.143 + size_t filesize; 41.144 + FILE *fp; 41.145 + char *src; 41.146 + 41.147 + if(!(fp = fopen(fname, "rb"))) { 41.148 + fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); 41.149 + return 0; 41.150 + } 41.151 + 41.152 + fseek(fp, 0, SEEK_END); 41.153 + filesize = ftell(fp); 41.154 + fseek(fp, 0, SEEK_SET); 41.155 + 41.156 + if(!(src = malloc(filesize + 1))) { 41.157 + fclose(fp); 41.158 + return 0; 41.159 + } 41.160 + fread(src, 1, filesize, fp); 41.161 + src[filesize] = 0; 41.162 + fclose(fp); 41.163 + 41.164 + fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname); 41.165 + sdr = create_shader(src, sdr_type); 41.166 + 41.167 + free(src); 41.168 + return sdr; 41.169 +} 41.170 + 41.171 + 41.172 +/* ---- gpu programs ---- */ 41.173 + 41.174 +unsigned int create_program(void) 41.175 +{ 41.176 + unsigned int prog = glCreateProgram(); 41.177 + assert(glGetError() == GL_NO_ERROR); 41.178 + return prog; 41.179 +} 41.180 + 41.181 +unsigned int create_program_link(unsigned int sdr0, ...) 41.182 +{ 41.183 + unsigned int prog, sdr; 41.184 + va_list ap; 41.185 + 41.186 + if(!(prog = create_program())) { 41.187 + return 0; 41.188 + } 41.189 + 41.190 + attach_shader(prog, sdr0); 41.191 + if(glGetError()) { 41.192 + return 0; 41.193 + } 41.194 + 41.195 + va_start(ap, sdr0); 41.196 + while((sdr = va_arg(ap, unsigned int))) { 41.197 + attach_shader(prog, sdr); 41.198 + if(glGetError()) { 41.199 + return 0; 41.200 + } 41.201 + } 41.202 + va_end(ap); 41.203 + 41.204 + if(link_program(prog) == -1) { 41.205 + free_program(prog); 41.206 + return 0; 41.207 + } 41.208 + return prog; 41.209 +} 41.210 + 41.211 +unsigned int create_program_load(const char *vfile, const char *pfile) 41.212 +{ 41.213 + unsigned int vs = 0, ps = 0; 41.214 + 41.215 + if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) { 41.216 + return 0; 41.217 + } 41.218 + if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) { 41.219 + return 0; 41.220 + } 41.221 + return create_program_link(vs, ps, 0); 41.222 +} 41.223 + 41.224 +void free_program(unsigned int sdr) 41.225 +{ 41.226 + glDeleteProgram(sdr); 41.227 +} 41.228 + 41.229 +void attach_shader(unsigned int prog, unsigned int sdr) 41.230 +{ 41.231 + int err; 41.232 + 41.233 + if(prog && sdr) { 41.234 + assert(glGetError() == GL_NO_ERROR); 41.235 + glAttachShader(prog, sdr); 41.236 + if((err = glGetError()) != GL_NO_ERROR) { 41.237 + fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err); 41.238 + abort(); 41.239 + } 41.240 + } 41.241 +} 41.242 + 41.243 +int link_program(unsigned int prog) 41.244 +{ 41.245 + int linked, info_len, retval = 0; 41.246 + char *info_str = 0; 41.247 + 41.248 + glLinkProgram(prog); 41.249 + assert(glGetError() == GL_NO_ERROR); 41.250 + glGetProgramiv(prog, GL_LINK_STATUS, &linked); 41.251 + assert(glGetError() == GL_NO_ERROR); 41.252 + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); 41.253 + assert(glGetError() == GL_NO_ERROR); 41.254 + 41.255 + if(info_len) { 41.256 + if((info_str = malloc(info_len + 1))) { 41.257 + glGetProgramInfoLog(prog, info_len, 0, info_str); 41.258 + assert(glGetError() == GL_NO_ERROR); 41.259 + info_str[info_len] = 0; 41.260 + } 41.261 + } 41.262 + 41.263 + if(linked) { 41.264 + fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str); 41.265 + } else { 41.266 + fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str); 41.267 + retval = -1; 41.268 + } 41.269 + 41.270 + free(info_str); 41.271 + return retval; 41.272 +} 41.273 + 41.274 +int bind_program(unsigned int prog) 41.275 +{ 41.276 + GLenum err; 41.277 + 41.278 + glUseProgram(prog); 41.279 + if(prog && (err = glGetError()) != GL_NO_ERROR) { 41.280 + /* maybe the program is not linked, try linking first */ 41.281 + if(err == GL_INVALID_OPERATION) { 41.282 + if(link_program(prog) == -1) { 41.283 + return -1; 41.284 + } 41.285 + glUseProgram(prog); 41.286 + return glGetError() == GL_NO_ERROR ? 0 : -1; 41.287 + } 41.288 + return -1; 41.289 + } 41.290 + return 0; 41.291 +} 41.292 + 41.293 +/* ugly but I'm not going to write the same bloody code over and over */ 41.294 +#define BEGIN_UNIFORM_CODE \ 41.295 + int loc, curr_prog; \ 41.296 + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \ 41.297 + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \ 41.298 + return -1; \ 41.299 + } \ 41.300 + if((loc = glGetUniformLocation(prog, name)) != -1) 41.301 + 41.302 +#define END_UNIFORM_CODE \ 41.303 + if((unsigned int)curr_prog != prog) { \ 41.304 + bind_program(curr_prog); \ 41.305 + } \ 41.306 + return loc == -1 ? -1 : 0 41.307 + 41.308 +int set_uniform_int(unsigned int prog, const char *name, int val) 41.309 +{ 41.310 + BEGIN_UNIFORM_CODE { 41.311 + glUniform1i(loc, val); 41.312 + } 41.313 + END_UNIFORM_CODE; 41.314 +} 41.315 + 41.316 +int set_uniform_float(unsigned int prog, const char *name, float val) 41.317 +{ 41.318 + BEGIN_UNIFORM_CODE { 41.319 + glUniform1f(loc, val); 41.320 + } 41.321 + END_UNIFORM_CODE; 41.322 +} 41.323 + 41.324 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y) 41.325 +{ 41.326 + BEGIN_UNIFORM_CODE { 41.327 + glUniform2f(loc, x, y); 41.328 + } 41.329 + END_UNIFORM_CODE; 41.330 +} 41.331 + 41.332 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z) 41.333 +{ 41.334 + BEGIN_UNIFORM_CODE { 41.335 + glUniform3f(loc, x, y, z); 41.336 + } 41.337 + END_UNIFORM_CODE; 41.338 +} 41.339 + 41.340 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w) 41.341 +{ 41.342 + BEGIN_UNIFORM_CODE { 41.343 + glUniform4f(loc, x, y, z, w); 41.344 + } 41.345 + END_UNIFORM_CODE; 41.346 +} 41.347 + 41.348 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat) 41.349 +{ 41.350 + BEGIN_UNIFORM_CODE { 41.351 + glUniformMatrix4fv(loc, 1, GL_FALSE, mat); 41.352 + } 41.353 + END_UNIFORM_CODE; 41.354 +} 41.355 + 41.356 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat) 41.357 +{ 41.358 + BEGIN_UNIFORM_CODE { 41.359 + glUniformMatrix4fv(loc, 1, GL_TRUE, mat); 41.360 + } 41.361 + END_UNIFORM_CODE; 41.362 +} 41.363 + 41.364 +int get_attrib_loc(unsigned int prog, const char *name) 41.365 +{ 41.366 + int loc, curr_prog; 41.367 + 41.368 + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); 41.369 + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { 41.370 + return -1; 41.371 + } 41.372 + 41.373 + loc = glGetAttribLocation(prog, (char*)name); 41.374 + 41.375 + if((unsigned int)curr_prog != prog) { 41.376 + bind_program(curr_prog); 41.377 + } 41.378 + return loc; 41.379 +} 41.380 + 41.381 +void set_attrib_float3(int attr_loc, float x, float y, float z) 41.382 +{ 41.383 + glVertexAttrib3f(attr_loc, x, y, z); 41.384 +} 41.385 + 41.386 +static const char *sdrtypestr(unsigned int sdrtype) 41.387 +{ 41.388 + switch(sdrtype) { 41.389 + case GL_VERTEX_SHADER: 41.390 + return "vertex"; 41.391 + case GL_FRAGMENT_SHADER: 41.392 + return "pixel"; 41.393 +#ifdef GL_TESS_CONTROL_SHADER 41.394 + case GL_TESS_CONTROL_SHADER: 41.395 + return "tessellation control"; 41.396 +#endif 41.397 +#ifdef GL_TESS_EVALUATION_SHADER 41.398 + case GL_TESS_EVALUATION_SHADER: 41.399 + return "tessellation evaluation"; 41.400 +#endif 41.401 +#ifdef GL_GEOMETRY_SHADER 41.402 + case GL_GEOMETRY_SHADER: 41.403 + return "geometry"; 41.404 +#endif 41.405 + 41.406 + default: 41.407 + break; 41.408 + } 41.409 + return "<unknown>"; 41.410 +}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 42.2 +++ b/src/sdr.h Sun Nov 01 00:09:12 2015 +0200 42.3 @@ -0,0 +1,52 @@ 42.4 +#ifndef SDR_H_ 42.5 +#define SDR_H_ 42.6 + 42.7 +#ifdef __cplusplus 42.8 +extern "C" { 42.9 +#endif /* __cplusplus */ 42.10 + 42.11 +/* ---- shaders ---- */ 42.12 +unsigned int create_vertex_shader(const char *src); 42.13 +unsigned int create_pixel_shader(const char *src); 42.14 +unsigned int create_tessctl_shader(const char *src); 42.15 +unsigned int create_tesseval_shader(const char *src); 42.16 +unsigned int create_geometry_shader(const char *src); 42.17 +unsigned int create_shader(const char *src, unsigned int sdr_type); 42.18 +void free_shader(unsigned int sdr); 42.19 + 42.20 +unsigned int load_vertex_shader(const char *fname); 42.21 +unsigned int load_pixel_shader(const char *fname); 42.22 +unsigned int load_tessctl_shader(const char *fname); 42.23 +unsigned int load_tesseval_shader(const char *fname); 42.24 +unsigned int load_geometry_shader(const char *fname); 42.25 +unsigned int load_shader(const char *src, unsigned int sdr_type); 42.26 + 42.27 +int add_shader(const char *fname, unsigned int sdr); 42.28 +int remove_shader(const char *fname); 42.29 + 42.30 +/* ---- gpu programs ---- */ 42.31 +unsigned int create_program(void); 42.32 +unsigned int create_program_link(unsigned int sdr0, ...); 42.33 +unsigned int create_program_load(const char *vfile, const char *pfile); 42.34 +void free_program(unsigned int sdr); 42.35 + 42.36 +void attach_shader(unsigned int prog, unsigned int sdr); 42.37 +int link_program(unsigned int prog); 42.38 +int bind_program(unsigned int prog); 42.39 + 42.40 +int set_uniform_int(unsigned int prog, const char *name, int val); 42.41 +int set_uniform_float(unsigned int prog, const char *name, float val); 42.42 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y); 42.43 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z); 42.44 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w); 42.45 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat); 42.46 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat); 42.47 + 42.48 +int get_attrib_loc(unsigned int prog, const char *name); 42.49 +void set_attrib_float3(int attr_loc, float x, float y, float z); 42.50 + 42.51 +#ifdef __cplusplus 42.52 +} 42.53 +#endif /* __cplusplus */ 42.54 + 42.55 +#endif /* SDR_H_ */
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 43.2 +++ b/src/timer.cc Sun Nov 01 00:09:12 2015 +0200 43.3 @@ -0,0 +1,118 @@ 43.4 +#include "timer.h" 43.5 + 43.6 +#if defined(__APPLE__) && !defined(__unix__) 43.7 +#define __unix__ 43.8 +#endif 43.9 + 43.10 +#ifdef __unix__ 43.11 +#include <time.h> 43.12 +#include <unistd.h> 43.13 +#include <sys/time.h> 43.14 + 43.15 +#ifdef CLOCK_MONOTONIC 43.16 +unsigned long get_time_msec(void) 43.17 +{ 43.18 + struct timespec ts; 43.19 + static struct timespec ts0; 43.20 + 43.21 + clock_gettime(CLOCK_MONOTONIC, &ts); 43.22 + if(ts0.tv_sec == 0 && ts0.tv_nsec == 0) { 43.23 + ts0 = ts; 43.24 + return 0; 43.25 + } 43.26 + return (ts.tv_sec - ts0.tv_sec) * 1000 + (ts.tv_nsec - ts0.tv_nsec) / 1000000; 43.27 +} 43.28 +#else /* no fancy POSIX clocks, fallback to good'ol gettimeofday */ 43.29 +unsigned long get_time_msec(void) 43.30 +{ 43.31 + struct timeval tv; 43.32 + static struct timeval tv0; 43.33 + 43.34 + gettimeofday(&tv, 0); 43.35 + if(tv0.tv_sec == 0 && tv0.tv_usec == 0) { 43.36 + tv0 = tv; 43.37 + return 0; 43.38 + } 43.39 + return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000; 43.40 +} 43.41 +#endif /* !posix clock */ 43.42 + 43.43 +void sleep_msec(unsigned long msec) 43.44 +{ 43.45 + usleep(msec * 1000); 43.46 +} 43.47 +#endif 43.48 + 43.49 +#ifdef WIN32 43.50 +#include <windows.h> 43.51 +#pragma comment(lib, "winmm.lib") 43.52 + 43.53 +unsigned long get_time_msec(void) 43.54 +{ 43.55 + return timeGetTime(); 43.56 +} 43.57 + 43.58 +void sleep_msec(unsigned long msec) 43.59 +{ 43.60 + Sleep(msec); 43.61 +} 43.62 +#endif 43.63 + 43.64 +double get_time_sec(void) 43.65 +{ 43.66 + return get_time_msec() / 1000.0f; 43.67 +} 43.68 + 43.69 +void sleep_sec(double sec) 43.70 +{ 43.71 + if(sec > 0.0f) { 43.72 + sleep_msec(sec * 1000.0f); 43.73 + } 43.74 +} 43.75 + 43.76 + 43.77 +Timer::Timer() 43.78 +{ 43.79 + reset(); 43.80 +} 43.81 + 43.82 +void Timer::reset() 43.83 +{ 43.84 + pause_time = 0; 43.85 + start_time = get_time_msec(); 43.86 +} 43.87 + 43.88 +void Timer::start() 43.89 +{ 43.90 + if(!is_running()) { 43.91 + // resuming 43.92 + start_time += get_time_msec() - pause_time; 43.93 + pause_time = 0; 43.94 + } 43.95 +} 43.96 + 43.97 +void Timer::stop() 43.98 +{ 43.99 + if(is_running()) { 43.100 + pause_time = get_time_msec(); 43.101 + } 43.102 +} 43.103 + 43.104 +bool Timer::is_running() const 43.105 +{ 43.106 + return pause_time == 0; 43.107 +} 43.108 + 43.109 +unsigned long Timer::get_msec() const 43.110 +{ 43.111 + if(!is_running()) { 43.112 + // in paused state... 43.113 + return pause_time - start_time; 43.114 + } 43.115 + return get_time_msec() - start_time; 43.116 +} 43.117 + 43.118 +double Timer::get_sec() const 43.119 +{ 43.120 + return (double)get_msec() / 1000.0; 43.121 +}
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 44.2 +++ b/src/timer.h Sun Nov 01 00:09:12 2015 +0200 44.3 @@ -0,0 +1,29 @@ 44.4 +#ifndef TIMER_H_ 44.5 +#define TIMER_H_ 44.6 + 44.7 +unsigned long get_time_msec(void); 44.8 +void sleep_msec(unsigned long msec); 44.9 + 44.10 +double get_time_sec(void); 44.11 +void sleep_sec(double sec); 44.12 + 44.13 + 44.14 +class Timer { 44.15 +private: 44.16 + unsigned long start_time, pause_time; 44.17 + 44.18 +public: 44.19 + Timer(); 44.20 + 44.21 + void reset(); 44.22 + 44.23 + void start(); 44.24 + void stop(); 44.25 + 44.26 + bool is_running() const; 44.27 + 44.28 + unsigned long get_msec() const; 44.29 + double get_sec() const; 44.30 +}; 44.31 + 44.32 +#endif // TIMER_H_