fracplanet/BUGS0000644000175100017510000000651611262220434013226 0ustar timdaytimday- Display list mode doesn't render sea on Lenovo S10e with Debian/Lenny. Also Ubuntu VMs. Hmmm works fine on 64bit Debian/Lenny with Nvidia OpenGL. Seems to be mesa-only problem. GL_MAX_ELEMENTS_VERTICES & GL_MAX_ELEMENTS_INDICES are only 3000 on mesa. Seems to be a GL error in display list. - GL area dies on Ubuntu in virtualbox when widget is minimised then restored. (Partial fix in code is to recreate GL area when terrain regenerated) - Sparc etch build doesn't display on Nvidia i386 machine. However, nvidia OpenGL i386 build does display on the sparc. - The Ubuntu dapper built packages seem to have some problems when meshes are drawn with glDraw[Range]Elements (NB the problem seems to be in the built app, NOT the xserver). The confusion seems to occur above the 1k primitives mark. Reducing the number of primitives per glDrawRangeElements seems to help although some xservers seem to spew X Error: GLXBadLargeRequest. and give a blank view. If this happens, increase the Create/Colours/...emissive... spinbox from zero; this uses a different render path. [I did wonder if this was something to do with Ubuntu using the mesa GL libraries and Debian using the XFree86 versions: dpkg-query -S /usr/include/GL/gl.h Sarge: xlibmesa-gl-dev: /usr/include/GL/gl.h Dapper: mesa-common-dev: /usr/include/GL/gl.h But building the package on Debian Etch against libgl1-mesa-dev,libglu1-mesa-dev,mesa-common-dev (add them into the yadda build dependencies in the mkdeb script) doesn't reproduce the problem there. Both platforms are gcc 4.0.3. It's a mystery! Any help gratefully received.] Haven't tried edgy yet. - fracplanet running on 64 bit lenny shows missing polys (all sea?) when viewed by display list from 32bit lenny mesa - Bear in mind that selecting display list rendering means a copy the GL system takes a copy of the triangle mesh. This needs memory; if there isn't enough the application may crash (some drivers may crash if the display list doesn't fit on the graphics card). - Base land height doesn't affect noise-only terrain (when vertical perturbation is reduced to zero; probably because it's expressed as a proportion of vertical perturbation - should just be absolute). - Blender seems to ignore alpha in the cloud layer, and renders it as solid. It doesn't pass per-vertex alphas out to yafray either. This may just be some material flag which needs setting, but haven't been able to discover a solution. Any help appreciated. The workround is to emit an opaque pre-blended cloud layer. - River generation can be VERY slow (especially at high levels of subdivision) due to the time taken to fill up large lakes (just like in the real world, strangely enough :^): raising the water level slightly to the level of a potential outflow currently necessitates adjusting the height of all the points in the lake, which takes a long time with big lakes. The progress dialog gives a bit more feedback about this now. It WILL complete; just give it time. - Flat (non-planet) terrain mostly disappears when viewed from beneath due to back-face culling. - Export to Blender doesn't support emissive terrain. - Doing the clouds as a mesh might seem pointless but there are plans to perturb the mesh to produce weather systems. Maybe add some height too. fracplanet/BUILD0000755000175100017510000000010711055516536013331 0ustar timdaytimday#!/bin/bash PATH=$QTDIR/bin:$PATH export PATH ./configure $@ && make fracplanet/LICENSE0000644000175100017510000004313111055516536013555 0ustar timdaytimday GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. fracplanet/NEWS0000644000175100017510000000561611262220434013242 0ustar timdaytimdayFrom release 0.3.3: - Bump version number to 0.4.0 (0.4.0dev while under development) - Migrate sourceforge repository to svn - Port to Qt4 - Enable multisampling in OpenGL window - Restructure startup - Precompiled headers - CHANGES renamed to NEWS - License boilerplate managed by "headache" From release 0.3.2: - Bump version number to 0.3.3 (dev while under development) - Add menu entry - Update for etch & edgy (warning-free c++, package building) From release 0.3.1: - Bump version number to 0.3.2 (dev while under development) - Reinstate weather systems (spinbox to control number). - Various commandline options (uses boost::program_options). - Save to texture, shaded and unshaded. - Illumination direction control From release 0.3.0: - Bump version number to 0.3.1dev - Use boost's mt19937 for random number generation. - Minor GUI improvement (terrain type pull down). - Add simple man page. - Deb building script. From release 0.2.0: - Bump version number to 0.3.0 - Different flat terrain types - Blender export (faux alpha for clouds). - Internal changes (RGB to RGBA, overload alpha for emission) - Built in docs - Cloud layer (with Blender and POV support). - Render (OpenGL) background colour control From release 0.1.0: - Bump version number to 0.2.0 - Progress dialog separated and better behaved - Variation uses % scale for consistency (was 1/1000ths before) - Cosmetic changes - Add multiscale Perlin noise step - River generation faster and more reliable. - Subdivision enumerated as 1...levels in progress dialog (not from zero) - Improvements to river generation memory usage. - Saved povray file no longer needs colors.inc From release 0.0.3: - Bump version number to 0.1.0 - Support emissive oceans and rivers (including POV save) - Fix .inc filename bug (spurious ") - Update docs - Viewer to separate top-level. - Don't burn CPU when OpenGL area not visible. - Crude flight-simulator mode. Joystick-mouse selector. - Save uses Qt file-picker dialog - Slider control of ambient - Amount of movement independent of FPS rate. - Clean up bogus files in CVS From release 0.0.1: - Bump version number to 0.0.3 (0.0.2 omitted docs) - Add fracplanet.htm, fracplanet.css user documentation. - Minor changes to code (compiles on RH9) - Tweak doxygen.cfg - Display list option - Frame rate display - VERSION and mktgz done evolvotron style From release 0.0.0: - CHANGES file added. - lake_becomes_sea initialisation changed from 5 to 0.05 (so displays "5" on controls instead of "100"). - Remove .qmake.internal.cache from CVS control (don't you just HATE it when that happens) - Move hardwired colours into ParametersTerrain class (in anticipation of control from GUI). - Add colour picking to GUI. - Bump version number to 0.0.1 (appears only in control_about.cpp) - Generated .pov file correctly includes basename.inc (was always including terrain.inc before). fracplanet/README0000644000175100017510000001236011261123520013412 0ustar timdaytimdayABOUT ===== Fracplanet generates random planets and terrain with oceans, mountains, icecaps and rivers. Parameters are specified interactively and the results displayed using OpenGL. The generated objects can be exported as Pov-Ray or Blender models, or as textures. It uses C++ (with STL and boost), Qt and OpenGL. Home page: http://www.bottlenose.demon.co.uk/share/fracplanet Author: timday at timday dot com LICENSE ======= This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. [The license should be in the LICENSE file in this directory] BUILDING ======== Either use the traditional ./configure make (NB The configure script is NOT autoconf generated and none of the usual autoconf options work) Or just have both done for you by running ./BUILD (which also adds $QTDIR/bin to the PATH while running the above commands; this may be useful on the many distros which don't have qmake in the default user path). NB In either case you almost certainly DO need your QTDIR environment variable to be correctly defined. This will give you a "fracplanet" executable which you can run with ./fracplanet or copy to wherever you like (see INSTALL section below). If you have xsltproc (and sed) installed then you should get a copy of the fracplanet.htm documentation built into the application. [The author primarily uses Debian Sarge these days]. [Selden E Ball Jr reports that "FracPlanet v0.2 builds and runs with no errors under the current version of Cygwin for Windows. Of course, the appropriate optional software development subsets have to be installed."] BUILD OPTIONS ============= Qt's qmake builds the Makefile used to build the application so to change compile options you should mess with the fracplanet.pro (if you do change it, do a "make distclean" before you rebuild to make sure Makefiles are rebuilt) or provide overrides on qmake's command line. An example of how to do this is provided by the configure-custom script, but note that details may well be different on your system. On the author's P4 system the extra optimisation options make no measurable difference to the application performance (to either the display framerate or mesh generation times). BUILD PROBLEMS ============== - Recent versions of gcc may output a lot of warnings about Qt's lack of virtual destructors. Don't worry about them. - For a Debian system with nvidia-glx installed it may be necessary to have nvidia-glx-dev installed when you build, otherwise the application may not function properly. Note that binaries built in an nvidia-free pbuilder environment seem to run fine on an nvidia accelerated system. USAGE ===== User documentation is contained in fracplanet.htm and accessible from the ABout tab of the application while running. If you just want to dive in all you need to know is this: After changing ANY of the terrain generation parameters, you must hit "regenerate" to create and display a new model. This keeps the random seeds for terrain and river generation the same. There are a couple of extra buttons which also change the random seed for the terrain or river network before regenerating, Most of the parameter entry fields have tooltips on them which give an idea of what they're about. To begin with it's best to start by making small changes to most parameters, especially the number of subdivisions. PERFORMANCE =========== The biggest factor influencing performance (both generation and display) is the degree of subdivision. For 9 subdivisions (for a planet) around 260MB of memory is required. 10 subdivisions needs just over a gigabyte. Needless to say, if it starts swapping, it's not pretty. On a 2.4GHz machine with a GeForce4 (well, an "MX") and the Nvidia OpenGL drivers display rates start to suffer around subdivision level 7 (for planets). A NVidia 5200 will get to the next level. See the BUGS file for other issues. FSAA/MULTISAMPLING ================== On the author's GeForce7600 system, the standard Qt3 built fracplanet runs nicely antialiased simply by doing __GL_FSAA_MODE=7 ./fracplanet INSTALL ======= Doing make install no longer attempts to do anything useful. The only build product is the executable "fracplanet"; simply copy it wherever you like. Other files of interest are: man/man1/fracplanet.1 fracplanet.htm fracplanet.css BUGS TODO THANKS NEWS OTHER STUFF =========== Probably only of interest to those actively developing the code: - mktgz builds the tarballs released on sourceforge. - mkdeb builds .deb binary installables for Debian systems. (It probably assumes you have things pbuilder set up in a certain way). - mkdoc (in the CVS, not distributed) builds source-code documentation using doxygen. fracplanet/THANKS0000644000175100017510000000022011055516536013453 0ustar timdaytimdayTHANKS ====== For bug reports, feedback and patches: Tobias Klausmann Frank Plohmann Steve Roylance Leon Brooks Selden E Ball Jr fracplanet/TODO0000644000175100017510000001502411262220434013225 0ustar timdaytimday- stopping flying should hold position and allow spin and tilt manipulation (have planet rotate under current viewpoint) - cancel button on progress bar - plate tectonics simulation: Use zero contour of multiscale noise field to modulate heights (gives some boundary-like features). Maybe another field to modulate activity level there (subduction vs collision; fall vs raise terrain?) - coding style is a mess of _-prefixed and not prefixed members. Cleanup should include stronger use of accessors. - Get models into K3D somehow Generating python for K3D's idea of a mesh_source script seems most promising. Does seem to allow setting of vertex properties. Imported file formats all too limiting, and python API maybe better documented than K3D's XML file format. - Sourceforge tracker reports problems with Beryl/Compiz. Try it out now have this working with Debian/lenny. - Export Ogre .xml mesh files: http://www.ogre3d.org/wiki/index.php/Creating_a_triangle_strip http://www.ogre3d.org/phpBB2/viewtopic.php?p=228739#228739 http://www.ogre3d.org/wiki/index.php/Ogre_meshxml_DTD - Debian transitioning Apps to Applications (post Etch) see bug 361418 - Look at Art of Illusion. Try it's .pov import. (It can also import .obj, but that doesn't support per-vertext colour). - Texture export should have the option of a .obj file for the DEM. - Export to wings3d ? Would probably be via .obj - If you checkout fracplanet to say fracplanet-0.3.3 then mktgz script doesn't like it. (Not clear how useful this is in practice because you wouldn't tag it in cvs without building tgz first to check testtgz and mkdeb; maybe something like -0.3.3rc1 though ?). - .debs should create a menu entry. They do, but yada bug (Debian #419878) getting in the way. Doesn't work on Ubuntu either (install to wrong dir? no update menu?) - DEB_BUILD_OPTIONS should also recognize debug ? (and do same as noopt probably) It's not actually in the policy manual. - Check clouds tab's documentation. - More control over clouds. - Texture render should also output a specular map for celestia. - Add an option to load vertex heights from a DEM (would replace mid-point perturbation during subdivision; would retain our colouring rules, ability to add noise, rivers etc). - Texture render for clouds. Will end up with duplicate code in cloud mesh's ScanConvertHelper; use boost MPL/Fusion to produce generic version operating on general tuples ? - Craters. - X gets bigger when using display lists (remote only?) ? Need to delete on exit ? - Find out what the errors are this guy mentions: http://douglas.nerad.org/journal/2006/04/03/ - More control over weather and clouds. - Another noise fn to modulate (c.f add) subdivided terrain. Might help reduce middle-of-continent highlands. - Another noise fn to modulate power law (could get a mix of highland mesas and deposited lowlands). - Use Qtime (getCurrentTime) instead of time (more portable ?). - Abort on progress bar (throw exception out to top level ? Hmmm) - Make colours depend on more interesting things than height (e.g slope) - Reshow, so don't need to regenerate after hiding viewer - Save to texture with shading for spheres should have the option of some sort of "atlas shading": effectively local illumination giving impression terrain has been "unpeeled" then illuminated. - Does POV-Ray mesh support given vertex normals ? Renderings show facet shading with smooth colouring, which is legitimate but maybe not what's wanted. (Hmmm can't actually remember how fracplanet does this but it doesn't show facets). - Move blender/pov save parameters into nested classes, pass parameters into lowest-level save fns rather than multiple args. - Scale parameter for blender output. - Ability to load/save fracplanet parameters (simple keyword=value text file) - Mesh optimisation. - Save clouds as some more blender-friendly texture type thing. - Rename Save to Export. (Eventually want Save/Load/Export POV-Ray/Export Blender/Export Texture/Import Texture). - Cloud controls. Noise parameters and thresholds. - More control over cloud undersides, shadowing etc (c.f on/off in POVRay). (Add checkboxes to POVRay save dialog). Maybe need better control over ambient, or actually use the ambient parameter on the render tab (move to colours). Then shadows wouldn't be black; wouldn't get a night-side though, without varying ambient around sphere. - Give cloud illusion of depth using GLSL (parallax effects). - Use GLSL to get hard edged rivers. Not so useful without some way of exporting to PovRay/Blender (texture and texture co-ords?) - Shadows of clouds on ground in OpenGL (needs shaders, shadow buffers etc). - Optimise matix33 inversion - End abuse of alpha as flag; just use it as the emissive quantity. Mesh then gets a flag for meaning of alpha channels. - Terrain patches but with planetary geometry (ie curvature). This would give a sensible horizon when near the centre of the patch. - Control over treeline and shoreline heights (these are hardwired currently). - Clean up progress stuff; push steps->% (rate management) into progress API. - std::auto_ptr sucks; use something better from boost - Add perturbation decay rate for subdivision too. - Noise perturbation in X&Y too; might help break up subdivision ridge artefacts - Basic "man" page besides HTML - Make more keys do stuff in fly mode (e.g home to return to start). - Console mode app: read parameters, generate planet. - Fix river/lake hang for high subdivision levels - Perlin noise to modify terrain colours. - Continue GUI procesing when progressing. - More feedback (progress bar?) when building display list (unfortunately a lot of the delay happens in OpenGL when the list is completed) - Borrow some improvements from sister evolvotron project - Check for OpenGL errors - Add control over heights at which colours switch. - Improve code documentation. - Save/load parameters. Automatic mode (load parameters, generate model, exit). - Seasonal variations. e.g snowline, ice packs on ocean. - Ability to save sequences of models (probably by offline generation for parameter file load) - Are we 64bit ready ? Onwards to subdivision levels 12,13,14... - Put ONLY the terrain data in the .inc file; rest in .pov or a different .inc - Split up mesh file (3 parts: vertices, colours, meshing) - Ringworld and Dyson sphere/hollow-Earth starting geometries for fun. - yafray export (note povray not available for sparc, but yafray is) Could do, but rejected: - Build for ultrasparc ./configure 'QMAKE_CXXFLAGS_RELEASE += -mcpu=ultrasparc' but it's no faster fracplanet/VERSION0000755000175100017510000000055611262220434013614 0ustar timdaytimday#!/bin/bash # Script to echo the current version number. # THIS IS THE ONLY PLACE A VERSION NUMBER SHOULD BE SPECIFIED # NB If you edit this, you will need to "make distclean" and then rebuild (./BUILD) as there is no dependency checking # Avoid '-' or '_' in the version as it confuses mkdeb. # Use dev or wip qualifier while working to a release. echo "0.4.0" fracplanet/configure0000755000175100017510000000217711261123520014446 0ustar timdaytimday#!/bin/bash if [ -z "$QTDIR" ] ; then echo "QTDIR not defined" echo "You almost certainly need QTDIR defined and pointing at your QT installation" echo "If you know different, edit ./configure and remove this test." exit 1 fi echo "Your qmake-qt4 version is:" qmake-qt4 --version echo echo "Your gcc version is (unless qmake is set up to use a different one):" gcc --version echo echo "Building built-in user manual..." if ! xsltproc -stringparam version `./VERSION` -html htm_to_qml.xsl fracplanet.htm | sed 's/"/\\"/g' | sed 's/^/"/g' | sed 's/$/\\n"/g'> usage_text.h ; then echo "Couldn't build usage_text.h" ; fi if ! test -s usage_text.h ; then echo "\"Full built-in user documentation not available due to problem during build configuration. Maybe the builder didn't have xsltproc or sed installed ?\"" > usage_text.h ; echo "Something went wrong, used built-in user documentation fallback plan"; fi echo "...built built-in user documentation" VERSION_NUMBER=`./VERSION` echo echo "Running qmake-qt4..." qmake-qt4 "VERSION_NUMBER=$VERSION_NUMBER" "$@" fracplanet.pro echo "...configuration completed - ready to do 'make' now" fracplanet/doxygen.cfg0000644000175100017510000010734211055516536014713 0ustar timdaytimday# Doxyfile 1.2.14 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = fracplanet # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, # German, Greek, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, # Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. OUTPUT_LANGUAGE = English # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these class will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower case letters. If set to YES upper case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are adviced to set this option to NO. CASE_SENSE_NAMES = YES # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # reimplements. INHERIT_DOCS = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = YES # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consist of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse. FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the Html help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, # or Internet explorer 4.0+). Note that for large projects the tree generation # can take a very long time. In such cases it is better to disable this feature. # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assigments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_XML = NO #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line and do not end with a semicolon. Such function macros are typically # used for boiler-plate code, and will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES tag can be used to specify one or more tagfiles. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superceded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yield more powerful graphs. CLASS_DIAGRAMS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # changed from NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are gif, jpg, and png # If left blank gif will be used. DOT_IMAGE_FORMAT = gif # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermedate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO # The CGI_NAME tag should be the name of the CGI script that # starts the search engine (doxysearch) with the correct parameters. # A script with this name will be generated by doxygen. CGI_NAME = search.cgi # The CGI_URL tag should be the absolute URL to the directory where the # cgi binaries are located. See the documentation of your http daemon for # details. CGI_URL = # The DOC_URL tag should be the absolute URL to the directory where the # documentation is located. If left blank the absolute path to the # documentation, with file:// prepended to it, will be used. DOC_URL = # The DOC_ABSPATH tag should be the absolute path to the directory where the # documentation is located. If left blank the directory on the local machine # will be used. DOC_ABSPATH = # The BIN_ABSPATH tag must point to the directory where the doxysearch binary # is installed. BIN_ABSPATH = /usr/local/bin/ # The EXT_DOC_PATHS tag can be used to specify one or more paths to # documentation generated for other projects. This allows doxysearch to search # the documentation for these projects as well. EXT_DOC_PATHS = fracplanet/fracplanet.css0000644000175100017510000000070211055516536015376 0ustar timdaytimdayBODY { background-color: #ffffff; color: #000000; } H1, H2, H3, H4 { font-family: sans-serif; border-bottom: thin #888888 solid; background-color: #dddddd; } H1 { font-size: 200%; margin-left: 0.125in; } H2 { font-size: 150%; margin-left: 0.25in; } H3 { font-size: 125%; margin-left: 0.375in; } H4 { font-size: 110%; margin-left: 0.5in; } P,DL,UL { margin-left: 0.5in; } DT { font-weight: bolder; } fracplanet/fracplanet.htm0000644000175100017510000006750011262220434015374 0ustar timdaytimday Fracplanet user manual

Fracplanet user manual

Introduction

Fracplanet is an application to generate simple random planets and terrain with oceans, mountains, icecaps and rivers. Parameters are specified interactively and the results displayed using OpenGL. The generated objects can be exported in formats directly usable by POV-Ray or Blender, or as more generally useful texture images.

Command line arguments

Some command line arguments (not listed here) are intercepted and interpreted by Qt. These are pretty much what you'd expect most X11 applications to handle e.g -geometry XxY. Fracplanet's own command line arguments are:

--help, -h
Display a list of recognised arguments.
--verbose, -v
Output information about fracplanet execution (and OpenGL) to stderr.
--display-list, -d
Start up the application with rendering in display list mode by default (c.f immediate mode). This is particularly useful when the application is running remotely as the generated meshes are then only sent to the local OpenGL display hardware once.
--invert-mouse-y, -y
Start application with mouse in non-joystick mode for flight.
--wireframe, -w
Start application with rendering set to wireframe mode.

GUI

The main part of the fracplanet GUI is a tabbed control. The terrain generated is shown in a separate window (which disappears while regenerating). A progress dialog is generally displayed while generating terrain (except during application startup).

Create tab

Note that none of the parameters adjustable on this tab have any effect on the displayed model until one of the "Regenerate" buttons is pressed. This tab is further subdivided into sub-tabs ("Terrain", "Snow", "Rivers", "Colours", "Clouds").

Terrain

This tab is actually even further subdivided ("Basics", "Subdivision" and "Noise" tabs), but the list below doesn't distinguish.

Starting geometry: Generate...
A pull-down menu (or "combo-box") selects the initial geometry which will be "fractalized". Planet creates planets by subdividing an icosahedron. The other terrain area type create planar terrain areas by subdividing one or more triangles. Note that the square type doesn't produce very good results because the triangles it uses aren't equilateral.
Base land height
This expresses the initial height of the terrain (relative to the sea level) as a percentage of the vertical maximum perturbation size. Negative values produce (on average) more ocean than land, positive values produce more land than ocean.
Terrain random seed
Specifies the random number generator seed used when creating terrain. Regenerating without changing this value will produce the same terrain, allowing the user to play with subdivision levels, colours etc while still retaining the same basic pattern of oceans and continents. The value is initially set to the system time on application start-up.
Power law
A power law applied to all above-sea-level heights after terrain generation. (This consists of normalising the height relative to the maximum height in the terrain model and raising it to the power of this number divided by 100). Values above 100 flatten low terrain, tending to produce smooth plains surrounding spiky mountains. Values below 100 flatten high terrain, tending to produce smooth highlands surrounded by steep cliffs.
Subdivisions
The number of subdivisions of the initial structure. Each successive level of subdivision increases the number of triangles by a factor of four, so users should increase this parameter with caution. This has a major impact on the amount of memory consumed, the frame rate and the responsiveness of the application.
Unperturbed subdivisions
Specifies the number of the subdivisions which will be performed without random perturbation of the vertices. Lower numbers (0, 1) produce a few large continents. Higher values produce many small islands.
Vertical perturbation
Specifies the maximum size of vertical perturbations at the first level of subdivision. The maximum perturbation size is then halved at each subsequent subdivision. Planets and terrain areas both have a nominal radius of 1.0, and the number here is divided by 100 so if you specify a vertical variation of 12 you could get mountains which are on the order of 12 percent of the planet's radius high, or larger if subsequent perturbations accumulate upwards at a point (of course suppressing initial large perturbations using the "Unperturbed" parameter will tend to reduce this). This is of course a ridiculous height for mountains on anything but an asteroid, but using realistic values will just produce very boring looking planets.
Horizontal perturbation
Specifies the maximum size of horizontal perturbations at the first level of subdivision. The maximum perturbation size is then halved at each subsequent subdivision. Beware of making this value too large as it can produce overhanging/self-intersecting terrain, on the other hand small values can be useful for breaking up obvious artifacts of the initial geometry.
Noise terms
Number of terms in a Perlin noise function added to the terrain heights. Each subsequent term doubles the frequency. The best way to get an appreciation of the qualitative differences between Perlin noise and subdivision-perturbation is to reduce "Vertical perturbation" (on the "Subdivision" tab) to zero and increase the number of noise terms.
Noise frequency
Frequency of 1st noise term. 100 gives a scale on the order of the terrain radius. Subsequent terms double the frequency (and therefore halve their length scale).
Noise amplitude
Amplitude of 1st noise term, as a percentage of the nominal object radius.
Noise amplitude decay rate
The amplitude of subsequent noise terms decays to this percentage of the amplitude of the previous term. Fifty percent does the classic fractal thing of scaling perturbation size with length scale. Increasing it slightly (to e.g sixty percent) has the interesting effect of making rivers meander more as small-scale variations now have a bigger effect on local gradients than large scale features.

Snow

Snowline at equator
The nominal height of the snowline at the equator of a planet (and everywhere on a flat-based terrain area), expressed as a percentage of the maximum height of the terrain.
Snowline at pole
The nominal height of the snowline at the poles of a planet (unused for a flat-based terrain area), expressed as a percentage of the maximum height of the terrain.
Snowline power law
Tweaking this parameter lets you control whether the snowline remains high up and only plunges downward towards the poles, or whether it only quickly rises near the equator. Experiment, it has a fairly subtle effect.
Snowline slope suppression
The larger this value is, the harder it is for snow to stick to steep slopes (you can see this effect for real on any mountain range). This breaks up the snowline quite nicely, as it otherwise tends to stop at an artificially uniform height (reduce this parameter to zero to see what I mean).
Snowline glacier effect
If this parameter is positive, rivers tend to form glaciers and you will see e.g white lines running out of snowy areas, and frozen lakes. If this parameter is negative rivers find it harder to freeze and you will see them running through snowy areas and forming un-frozen lakes.

Rivers

Rivers
Specifies the number of rivers to be generated. Note that rivers starting in the sea are immediately abandoned, but still count against this number (this is so the relative proportions of land/ocean can be tweaked without affecting the river source density). Rivers run from vertex to vertex along triangle edges, and are then rendered by blending from the river vertex colour to the surrounding terrain colour. This isn't ideal as they aren't very sharply defined. A previous version of the software flowed rivers from triangle to triangle which produced nice solid edged rivers (like the oceans are) but since they weren't flat it wasn't ideal either.
Rivers seed
Random number seed for river generation. If you change this, but not the perturbation seed, you can get a different river network on the same terrain.
Lake becomes sea
As a river is flowed across a terrain, it will sometimes form a lake as the water level rises sufficiently to overcome a terrain barrier. If the lake becomes sufficiently large (greater than the percentage of available surface area specified here) then it is considered to have become an inland sea and it is no longer necessary for the lake to rise until an outflow to be discovered (in the real world, surface evaporation replaces the outflow). Increasing this number may result in larger lakes, but the process of river generation can take considerably longer.

Colours

Change colours
Click on these buttons to bring up a colour-picking dialog and change the colour for the selected class of terrain. Each button displays the colour currently selected for that class. Obvious things you might want to do are to change the shoreline colour to the same colour as the low level terrain (those beaches are pretty absurdly wide otherwise), change the orange highlands to a more mountainous grey, or perhaps you preferd an apocalyptic "lava world" with red rivers and oceans (use emission to make them glow), black shorelines and ash-grey terrain.
Oceans and rivers emissive
Sets the emission (also called "glow") of lakes and rivers, on a scale of 0-100. This is mainly to facilitate glowing lava planets. Note that for terrain generated with emission non-zero, an alternative OpenGL rendering path must be used which may be a little slower.

Clouds

The cloud layer, when generated, is a triangle mesh with variable translucency at each vertex. Note that it's not a texture in the normal sense.

Clouds enabled
Select the check box to trigger creation of a cloud layer.
Subdivisions
When left unchecked, the cloud layer will be subdivided to the same degree as the terrain. Check the box for explicit control of cloud layer subdivision.
Clouds seed.
Change this to get a different cloud pattern.
Cloud height
Change this to get adjust the height of the clouds above the terrain.

Other "Create" tab controls

Generate
Click this button to regenerate the planet/terrain area without changing the random seeds.
...new rivers seed
Click this button to increment the river generation seed by one and regenerate. This gets you the same landscape with a different river network.
...new terrain seed
Click this button increment the terrain seed by one and regenerate. This will get you a completely different terrain. (The river network will be different too, although it's seed won't have changed, as the rivers flow over the tarrain differently).
...new clouds seed
Click this button increment the clouds seed by one and regenerate. This will get you a different cloud layer.

Render tab

Options controlling OpenGL rendering appear on this tab. Generally none of these makes any difference to the state of the rendered mesh. However, some of the parameters do affect some export methods; see the individual item descriptions.

Wireframe checkbox
Selects OpenGL wireframe rendering mode.
Joystick mouse checkbox
This simply affects whether, when in flight mode, pulling the mouse down the screen flies you in that direction, or whether it's more like an aircraft joystick and pitches you up instead.
Display list
Selects OpenGL display list rendering. Display list rendering is generally but not always faster (depends on your OpenGL implementation and graphics drivers). The main reason display list rendering is not enabled by default is that the application may pause for a long time while OpenGL processes the list when it is first rendered; the amount of additional memory consumed by the display list is also a problem for very large meshes.
Background colour
Colour picking buttons to control the colour used for the viewing area background. The low altitude colour is also used when exporting a cloud mesh to blender.
Ambient
The amount of ambient illumination. This is also used when exporting shaded textures.
Illumination azimuth and elevation
Control the illumination direction. These are also used when exporting shaded textures.
Status
A text field displaying information about the rendered mesh, and rendering performance (recent average frames-per-second).

Save tab

Strictly speaking it's Export which is provided, not save, as fracplanet's state cannot be restored (yet). There are currently three ways of exporting models from fracplanet for other uses: to POV-Ray, to Blender and as textures.

POV-Ray

Add atmosphere
This tick-box causes additional POV-Ray directives to be emitted to render a thin layer of atmosphere.
Sea object
This tick-box causes a single sphere or infinite plane to generated for the oceans instead of numerous individual triangles.
Base filename
Enter the filename root to be used here. Two files will be generated, one with ".pov" appended, and one with ".inc" appended. The .inc file actually contains the object (using POV-Rays's mesh2 format), plus any other objects generated due to the options above. The .pov just includes the .inc and adds a camera and light source and was primarily intended for testing: the expectation is that users will generally include the .inc into their own scenes, probably wrapping it in a POV-Ray union with embedded translate/scale/rotate directives).
Save (POV-Ray)
Click this button to create the POV-Ray files. This can take quite a long time so a progress bar is used to track the completed percentage.

There are additional comments on usage with POV-Ray below.

Blender

Per vertex alpha
This check box selects Fracplanet's preferred method for outputting clouds: by specifying per-vertex alpha components. However, Blender seems to ignore these so a workround is used and an opaque cloud layer is output (which should be ok if you fly underneath it and light it sensibly). You probably don't want to switch this on.
Save (Blender)
Click this button to create a file (a file dialog will appear) which can be imported into Blender. Note that the save file takes the form of a Python script (traditionally a .py file extension) which can be executed by Blender to reconstruct the fracplanet model.

There are additional comments on usage with Blender below.

Texture

Saving as texture(s) gives you a set of 2D images which can be used by other rendering or modelling applications, if not immediately then perhaps after a little massaging with the ImageMagick or NetPBM tools. On saving you'll be prompted for a base filename.ppm. A number of files are then saved:

filename.ppm
The basic texture. This will be embedded in black pixels if the terrain isn't square e.g for the hexagonal terrain area. Planets produce a cylindrically projected latitude-longitude "spheremap".
filename_dem.pgm
The height field (a "DEM" is a Digital Elevation Model). This is output as a PGM image, with heights from 0.0 to 1.0 scaling to 0 to 65535. If the DEM contains a value greater than or equal to 256 (highly likely, except for exceptionally flat terrains), then it will be output as a 16-bit PGM which, while part of the PGM "standard" isn't well supported by many common graphics tools which appear to otherwise offer good PPM support (e.g The Gimp doesn't like it). The NetPBM tools are your best bet to convert this to something else (e.g pnmdepth). Imagemagick's simple "display" tool also handles them well, scaling the maximum value to white.
filename_norm.pgm
The surface normals; XYZ components are mapped to RGB; [-1, 1] is scaled to [0,255]. It is thought this should be useful for bump-mapping renderers (e.g Celestia) where the illusion of surface relief is produced by normal perturbation. If you intend to use this file, you almost certainly want to disable shading (see below), as your renderer will compute it later.

Other texture save options:

Shaded texture
Controls whether the texture map includes the effect of lighting. If you intend to use the information in the _norm.ppm or the _dem.pgm files to subsequently compute lighting, then you almost certainly do not want the output texture to be shaded. The amount of ambient lighting is taken from the slider on the render tab. (Disabling shading is the same effect as setting ambient to 1.0). The lighting direction is controlled by the render tab's illumination azimuth and elevation controls. If you want to use the OpenGL window to preview the lighting, you should set zero spin and tilt by hitting the "reset"button and dragging the tilt to the centre (unfortunately, this gives you an edge-on view of flat terrain areas so it may be necessary to use the "fly" mode).
Texture height
The number of pixels high the saved texture images are. The width is implicitly determined by the height. For flat terrain the width is the same as the height. For planets the width is twice the height because the height spans [-90,+90] degrees latitude, and the width spans [-180,180] degrees longitude.

There are additional comments exported texture usage below.

About tab

This tab displays information about the software (in particular the version number) and its license. There is a button to show a dialog containing user documentation, and another button to display information about the Qt toolkit.

Display window

The display window, when shown, shows the current (most recently generated) terrain model. It is hidden when terrain is being regenerated or saved. The (badly named) "tilt" slider controls the latitude of the camera (when viewing a sphere-based object), and the elevation (as in azimuth-elevation) of the camera when viewing a planar based terrain area. Note that in the latter case the bottom half of the slider places the camera below base ground level/sea level, which results in little being seen due to back-face culling. The "spin rate" controls the rate at which the object is rotated. The display window update rate is clamped to 60Hz, although this will typically only be reached at the lower levels of subdivision.

Hitting the "Fly" button puts you into free-flight mode. Pitch and yaw are controlled by the mouse position relative to the window centre (if the pitch control feels backwards, invert mouse-Y behaviour on the render tab). Roll is controlled by left/right mouse buttons, or the keyboard left/right arrow keys. Speed is controlled by the mouse wheel or the keyboard up/down arrow keys. Hit Esc to return to the normal viewing mode.

Fracplanet exports: usage notes

POV-Ray

To ray-trace a saved terrain (saved as terrain.pov and terrain.inc, say) do:
povray -Q9 -geometry 768x576 terrain.pov
Expect to get MANY "determinant too small" messages, especially when using high degrees of subdivision. It used to take POV-Ray a LOT longer to read large models than to render them, but it seems to load much faster these days.

Note that clouds, if generated, are output using POV-Ray's double_illuminate and no_shadow declarations. double_illuminate means that both sides of clouds are the same colour (rather than the underside being black). no_shadow means that the clouds cast no shadow on the ground (where the clouds are solid, the shadows are completely black, which looks more unnatural than no shadows). If desired, the declarations can be found at the end of the saved .inc file and simply edited out.

(The author currently uses POV-Ray 3.6).

Blender

The easiest way to load mesh saved for blender is with blender's -P <filename.py> command line argument on startup. Note that you'll have to remove blender's default initially created object to see much of the fracplanet object. Also, its shading won't look much like it did in fracplanet until you change blender's viewport shading mode to something better than the "solid" default.

Blender consumes an alarming amount of memory. Even loading a planet generated with fracplanet's default five levels of subdivision consumes a quarter of a gigabyte of RAM. It would probably help if fracplanet made some effort to optimise its meshes, and/or made use of textures rather than trying to do everything using geometry, but it doesn't yet.

Blender's per-vertex-colours capability seems to ignore the alpha component of per-vertex colours, with the result that the cloud layer is rendered as a solid opaque colour. If anyone has a solution to this it would be gratefully received. Fracplanet's workround is to output an opaque surface with the blending (with the "low altitude" colour from the render tab controls) already done. The "per-vertex alpha" checkbox switches to the preferred behaviour in case it ever gets fixed.

Each mesh is output with 2 materials. The clouds just use material 0. For the terrain, material 0 is for land facets, material 1 for the sea. This may be useful for users wanting to give them different shader properties.

In Blender, the terrain mesh is named "fracplanet.terrain". There will also be a "fracplanet.cloud" if clouds were enabled.

Emissive terrain isn't supported.

If you want to manipulate the terrain, and know a bit of Python, an easy way might be to edit the .py file; at the start there are two functions defined: v called to create each vertex and f called to create each face.

(The author currently uses Blender 2.46).

Texture Maps

It is hoped that the texture export option will be of use to those building planets for Celestia. (The author hasn't tried it himself yet; at time of writing Celestia is waiting to make it's way from Debian Unstable to Testing). Celestia's texture formats are well documented at the Celestia Motherlode, in particular by the Virtual Surface Textures document. The main issues for anyone doing this would seem to be the need to reduce the height map from 16 to 8 bit (easily changed by pnmdepth) and the possiblity that fracplanet's normal map (if used, alternative Celestia can compute normal maps from the height map) needs it's components exchanging or reflecting. Celestia can also take a specular map, generally used to indicating the presence of reflective water (or snow); fracplanet doesn't output this (yet) but it should be possible to fake something by processing the height or texture map.

As a simple demonstration of how to use a saved planet texture, here's how to use it as a spheremap in POV-Ray. Save an unshaded spheremap.ppm from fracplanet, and do:
convert spheremap.ppm spheremap.png
convert -depth 8 spheremap_dem.pgm spheremap_dem.png
cat <<EOF > spheremap.pov
camera {perspective location <0,1,-4.5> look_at <0,0,0> angle 45}
light_source {<100,100,-100> color rgb<1,1,1>}
sphere
{
<0,0,0>,1
pigment { image_map {png "spheremap.png" map_type 1} }
normal { bump_map {png "spheremap_dem.png" map_type 1 bump_size 20.0} }
rotate <0,clock*360,0.0>
}
EOF
povray spheremap.pov +KFI1 +KFF100 +W640 +H480 +Of.png
animate f???.png

convert is one of the ImageMagick utilities. You could omit the line beginning "normal" but you will get a rather flat looking planet. The factor of 20.0 at the end of the line is a rather arbitrary parameter. Raise or lower it to adjust the apparent roughness of the planet.

License

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

The full license can be also viewed on fracplanet's "About" tab.

fracplanet/htm_to_qml.xsl0000644000175100017510000000232011055516536015436 0ustar timdaytimday

Version:

(see )
fracplanet/mkdeb0000755000175100017510000000701011262220434013541 0ustar timdaytimday#!/bin/bash -ev # Before using this you probably need to install # sudo pbuilder yada devscripts lintian cdeboostrap (or debootstrap) # and maybe dpkg-sig. Also: # set up for sudo # set up pbuilder with # sudo emacs -nw /etc/pbuilderrc # ...change MIRRORSITE & DEBSECSERVER # sudo pbuilder create --distribution sarge/etch/whatever # and/or update with # sudo pbuilder update # Expect a lot of warnings re LOGNAME - see Debian bug Bug#275118 # TODO: DEBEMAIL VER=`./VERSION` TARBALL=fracplanet-${VER}.tar.gz if [ ! -s ${TARBALL} ] ; then echo "Could't find ${TARBALL}" ; exit ; fi export DISTRIBUTION=`lsb_release -s -c` echo "*** Will package ${TARBALL} for distribution \"${DISTRIBUTION}\"" echo -n "*** Starting in 10 seconds..." for t in 10 9 8 7 6 5 4 3 2 1 ; do sleep 1 ; echo -n "." ; done PROJECT=`echo $TARBALL | sed 's/-.*//'` TARBALLORIG="${PROJECT}_${VER}.orig.tar.gz" REV="1${DISTRIBUTION}1" WORKDIR=pkg_${VER}-${REV} rm -r -f ${WORKDIR} mkdir ${WORKDIR} cd ${WORKDIR} cp ../${TARBALL} ${TARBALLORIG} tar xvfz ${TARBALLORIG} mv ${PROJECT} ${PROJECT}-${VER} cd ${PROJECT}-${VER} sed -i "s/${VER}/${VER}-${REV}/g" VERSION mkdir debian echo "${PROJECT} (${VER}-${REV}) ${DISTRIBUTION}; urgency=low" > debian/changelog echo >> debian/changelog echo " * Package created by ${PROJECT}'s mkdeb script." >> debian/changelog echo >> debian/changelog DATE=`822-date` echo " -- $USER <$EMAIL> $DATE" >> debian/changelog # Presumably a dch -i here would increment revision cat << EOF > debian/packages Source: fracplanet Section: graphics Priority: extra Maintainer: Tim Day Standards-Version: 3.6.1 Upstream-Source: Home-Page: Description: Fractal terrain generator Copyright: GPL Copyright 2009 Tim Day Build-Depends: qt4-qmake,libqt4-dev,libqt4-opengl-dev,libboost1.35-dev,libboost-program-options1.35-dev,xsltproc Build: sh export QTDIR=/usr/share/qt4 # Note: yada install deals with DEB_BUILD_OPTIONS 'nostrip' if [ "${DEB_BUILD_OPTIONS#*noopt}" != "$DEB_BUILD_OPTIONS" ]; then ./configure "CONFIG -= release" "CONFIG += debug" else ./configure # No noticeable advantage in overriding default qt optimisation options fi make Clean: sh make distclean || make clean || true Package: fracplanet Architecture: any Depends: [] Suggests: povray,blender Description: Fractal terrain generator Fracplanet generates random planets and terrain with oceans, mountains, icecaps and rivers. Parameters are specified interactively and the results displayed using OpenGL. The generated objects can be exported as geometry for Pov-Ray or Blender, or as textures. Install: sh yada install -bin fracplanet yada install -doc fracplanet.htm fracplanet.css yada install -doc BUGS TODO NEWS THANKS yada install -man man/man1/fracplanet.1 Menu: ?package(fracplanet): needs="x11" section="Applications/Graphics" title="Fracplanet" command="/usr/bin/fracplanet" longtitle="Fractal terrain generator" EOF yada rebuild cd .. dpkg-source -b ${PROJECT}-${VER} ${TARBALLORIG} # Alternative but inferior approach is apparently to do # dpkg-buildpackage -rfakeroot mkdir result echo "Building package" sudo pbuilder build --buildresult ./result ${PROJECT}_${VER}-${REV}.dsc sudo chown ${USER}:${USER} result/* RESULT=`(cd .. ; find ${WORKDIR} -name '*.deb')` echo "Results: ${RESULT}" echo "Don't forget to lintian ${RESULT}" echo 'Also dpkg-sig --sign builder -k $DPKGSIG_KEYID any .deb files' fracplanet/mktgz0000755000175100017510000000201411262220434013612 0ustar timdaytimday#!/bin/bash # Execute this to package up fracplanet as a .tar.gz. # This is the script used to build the tarballs released on sourceforge VERSION=`./VERSION` DIR=${PWD##*/} cd .. PRUNE='-name moc -prune -o -name obj -prune -o -name pkg_* -prune -o -name usage_text.h -prune' FILES_MISC=`ls ${DIR}/{README,BUILD,LICENSE,TODO,NEWS,BUGS,VERSION,THANKS,configure,doxygen.cfg,mktgz,testtgz,mkdeb,fracplanet.css,fracplanet.htm,htm_to_qml.xsl}` FILES_PRO=`find ${DIR} ${PRUNE} -o -name '*.pro' -print` FILES_MAN=`find ${DIR}/man ${PRUNE} -o -name '*.1' -print` FILES_H=`find ${DIR} ${PRUNE} -o -name '*.h' -print` FILES_C=`find ${DIR} ${PRUNE} -o -name '*.c' -print` FILES_CPP=`find ${DIR} ${PRUNE} -o -name '*.cpp' -print` FILES="$FILES_MISC $FILES_PRO $FILES_MAN $FILES_H $FILES_C $FILES_CPP" tar --transform "s:^${DIR}/:fracplanet/:" -cz -f ${DIR}/fracplanet.tar.gz $FILES echo "***" echo "*** Suggestion:" echo "*** mv fracplanet.tar.gz fracplanet-$VERSION.tar.gz" echo "*** ./testtgz fracplanet-$VERSION.tar.gz" echo "***" fracplanet/testtgz0000755000175100017510000000076011055516536014203 0ustar timdaytimday#!/bin/bash -e rm -r -f /tmp/fracplanet mkdir /tmp/fracplanet cp $1 /tmp/fracplanet/ cd /tmp/fracplanet/ tar xvfz $1 if ! test -d ./fracplanet ; then echo "*** Un-tar failed" ; exit ; fi cd ./fracplanet ./BUILD echo "Please save xxx.pov for PovRay, xxx.py for Blender, then quit" if ! test -s ./fracplanet ; then echo "*** Build failed" ; exit ; fi ./fracplanet echo "Checking POV-Ray" povray -Q9 -geometry 768x576 xxx.pov echo "Checking Blender" blender -w -p 100 100 800 800 -P xxx.py fracplanet/fracplanet.pro0000644000175100017510000000262211262227632015405 0ustar timdaytimdayTARGET = fracplanet TEMPLATE = app CONFIG+= qt stl precompile_header exceptions release # debug/release QT += opengl PRECOMPILED_HEADER = precompiled.h HEADERS += $$system(ls *.h) SOURCES += $$system(ls *.cpp) LIBS += -lboost_program_options DEFINES += QT_DLL ####################################### # Version numbering. This is ENTIRELY controlled by what is echoed by the VERSION script QMAKE_CXXFLAGS_RELEASE += '-DFRACPLANET_VERSION="$$VERSION_NUMBER"' QMAKE_CXXFLAGS_DEBUG += '-DFRACPLANET_VERSION="$$VERSION_NUMBER"' QMAKE_CXXFLAGS_RELEASE += '-DFRACPLANET_BUILD="$$VERSION_NUMBER (release build)"' QMAKE_CXXFLAGS_DEBUG += '-DFRACPLANET_BUILD="$$VERSION_NUMBER (debug build)"' # qmake's library code can use this too (but only for shared libraries which we don't use) VERSION=$$VERSION_NUMBER ####################################### # Disable assertions in release version QMAKE_CXXFLAGS_RELEASE += -DNDEBUG QMAKE_CFLAGS_RELEASE += -DNDEBUG ###################################### # Other stuff: # Disable implicit cast from QString to char* # If have trouble on sparc add -pthread -DBOOST_SP_USE_PTHREADS as a workround for debian bug 485434 # seems to cause trouble on x86 though so not used by default. QMAKE_CXXFLAGS_RELEASE += -DQT_NO_ASCII_CAST QMAKE_CXXFLAGS_DEBUG += -DQT_NO_ASCII_CAST ###################################### # Hide those crufty moc_ files away MOC_DIR = moc OBJECTS_DIR = obj fracplanet/man/man1/fracplanet.10000644000175100017510000000346111261123444016351 0ustar timdaytimday.TH FRACPLANET 1 "26 Apr 2006" "www.timday.com" "Fracplanet" .SH NAME fracplanet \- Create and view random fractal terrain and planets. .SH SYNOPSIS fracplanet [ .I ] [ .B --help ] [ .B --verbose ] [ .B --display-list ] [ .B --invert-mouse-y ] [ .B --wireframe ] .SH DESCRIPTION .B Fracplanet generates random planets and terrain with oceans, mountains, icecaps and rivers. Parameters are specified interactively and the results displayed using OpenGL. The generated objects can be exported for Pov-Ray or Blender. A document fully describing usage via the application's GUI is accessible from the application's "About" menu once it is running. .SH GENERAL OPTIONS .I Standard options recognised by the Qt toolkit (for example .B \-geometry .I x Note that these use the single-dash option style. ). .B --help, -h Display a list of recognised arguments. .B --verbose, -v Display information about fracplanet and the GL graphics system it's running on. .SH RENDERING OPTIONS These affect the initial settings on the render controls tab, which controls the OpenGL display. .B --display-list, -d Start up the application with rendering in display list mode by default (c.f immediate mode). This is particularly useful when the application is running remotely as the generated meshes are then only sent to the local OpenGL display hardware once. .B --invert-mouse-y, -y Start application with mouse in non-joystick mode for flight. .B --wireframe, -w Start application with rendering set to wireframe mode. .SH SEE ALSO .B blender .B povray .SH AUTHOR .B fracplanet was written by Tim Day (www.timday.com) and is released under the conditions of the GNU General Public License. For further details see the application's "About" dialog or the file LICENSE supplied with the source code. fracplanet/random.h0000644000175100017510000000366711261123520014175 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Random and derived classes. */ #ifndef _random_h_ #define _random_h_ //! Generates random numbers in the range [0,1). class Random01 { public: // Constructor. Argument is seed value. Random01(uint s=0); //! Destructor. ~Random01(); // Return random number in 0-1 (don't think we care whether open interval or not). double operator()() { return _gen(); } private: boost::mt19937 _rng; boost::uniform_real<> _dist; boost::variate_generator > _gen; }; #endif fracplanet/spinbox.h0000644000175100017510000000275111261123520014370 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! QSpinBox ctor helper */ class SpinBox : public QSpinBox { public: SpinBox(int lo,int hi,int step); ~SpinBox(); }; fracplanet/triangle_mesh_terrain.h0000644000175100017510000001132211261123520017245 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class TriangleMeshTerrain and derived classes. */ #ifndef _triangle_mesh_terrain_h_ #define _triangle_mesh_terrain_h_ #include "image.h" #include "parameters_terrain.h" #include "triangle_mesh.h" //! This class holds all the terrain-related methods. /*! It's intended to be used as a "mix-in", adding terrain generating functionality to terrain objects subclassed from simpler geometries. \todo Ugh!!! This is really yucky use of multiple inheritance. Better for these terrain types to have-a TriangleMesh. */ class TriangleMeshTerrain : virtual public TriangleMesh { public: //! Constructor. TriangleMeshTerrain(Progress* progress); //! Destructor. ~TriangleMeshTerrain(); //! Dump the model as a POV scene. /*! Virtual method because spherical and flat terrains need e.g different sea-level planes and atmosphere layers. */ virtual void write_povray(std::ofstream& out,const ParametersSave&,const ParametersTerrain&) const =0; //! Dump the model for Blender. /*! Unlike write_povray there are no specialisations for flat/spherical terrain. */ virtual void write_blender(std::ofstream& out,const ParametersSave&,const ParametersTerrain&,const std::string& mesh_name) const; //! Render the mesh onto raster images (colour texture, and optionally 16-bit DEM and/or normal map). virtual void render_texture(Raster&,Raster*,Raster*,bool shading,float ambient,const XYZ& illumination) const; protected: //! Indices of the set of triangles with all vertices at sea-level std::set sea_triangles; //! Indices of the set of vertices comprising the river network std::set river_vertices; //! Maximum height of terrain (used to scale to/from "normalised" height). float max_height; //! Add noise to the terrain void do_noise(const ParametersTerrain& parameters); //! Impose a sea level (raise lower vertices, and note sea triangles). void do_sea_level(const ParametersTerrain& parameters); //! Apply power law void do_power_law(const ParametersTerrain& parameters); //! Generate river network. void do_rivers(const ParametersTerrain& parameters); //! Final colouration pass. void do_colours(const ParametersTerrain& parameters); //! Invokes all the above steps (sea-level through final colouring) on a pre-subdivided triangle mesh. void do_terrain(const ParametersTerrain& parameters); }; //! Class constructing specific case of a planetary terrain. class TriangleMeshTerrainPlanet : public TriangleMeshSubdividedIcosahedron, virtual public TriangleMeshTerrain { public: //! Constructor. TriangleMeshTerrainPlanet(const ParametersTerrain& param,Progress* progress); //! Destructor. ~TriangleMeshTerrainPlanet() {} //! Specifc dump-to-povray for planet terrain. void write_povray(std::ofstream& out,const ParametersSave&,const ParametersTerrain&) const; }; //! Class constructing specific case of a flat-base terrain area. class TriangleMeshTerrainFlat : public TriangleMeshFlat, virtual public TriangleMeshTerrain { public: //! Constructor. TriangleMeshTerrainFlat(const ParametersTerrain& parameters,Progress* progress); //! Destructor. ~TriangleMeshTerrainFlat() {} //! Specifc dump-to-povray for flat terrain area. void write_povray(std::ofstream& out,const ParametersSave&,const ParametersTerrain&) const; }; #endif fracplanet/fracplanet_main.h0000644000175100017510000000677411262220434016045 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class FracplanetMain. */ #ifndef _fracplanet_main_h_ #define _fracplanet_main_h_ #include "control_about.h" #include "control_render.h" #include "control_save.h" #include "control_terrain.h" #include "parameters_render.h" #include "parameters_save.h" #include "parameters_terrain.h" #include "random.h" #include "triangle_mesh_cloud.h" #include "triangle_mesh_terrain.h" #include "triangle_mesh_viewer.h" //! Top level GUI component for fracplanet application: contains parameter controls and viewing area class FracplanetMain : public QWidget,public Progress { private: Q_OBJECT public: FracplanetMain(QWidget* parent,QApplication* app,const boost::program_options::variables_map& opts,bool verbose); ~FracplanetMain(); virtual void progress_start(uint target,const std::string&); virtual void progress_stall(const std::string& reason); virtual void progress_step(uint step); virtual void progress_complete(const std::string&); public slots: //! Invoked by ControlTerrain to generate new TriangleMesh. void regenerate(); //! Invoked by ControlSave to save to file (POV-Ray format). void save_pov(); //! Invoked by ControlSave to save to file (Blender format). void save_blender(); //! Invoked by ControlSave to save to file as texture(s). void save_texture(); private: //! Control logging. const bool _verbose; QApplication*const application; //! Owned terrain. boost::scoped_ptr mesh_terrain; //! Owned clouds, if any. boost::scoped_ptr mesh_cloud; //! Downcast version for use by mesh viewer. std::vector meshes; ParametersTerrain parameters_terrain; ParametersCloud parameters_cloud; ParametersRender parameters_render; ParametersSave parameters_save; ControlTerrain* control_terrain; ControlRender* control_render; ControlSave* control_save; ControlAbout* control_about; boost::scoped_ptr viewer; QTabWidget* tab; uint last_step; std::auto_ptr progress_dialog; std::string progress_info; bool progress_was_stalled; }; #endif fracplanet/triangle_mesh_viewer.h0000644000175100017510000001022311262220434017104 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class TriangleMeshViewer. */ #ifndef _triangle_mesh_viewer_h_ #define _triangle_mesh_viewer_h_ #include "parameters_render.h" #include "random.h" #include "triangle_mesh.h" #include "triangle_mesh_viewer_display.h" //! A class to display a triangle mesh. /*! Wraps a TriangleMeshViewerDisplay with some controls. \todo Add better controls. */ class TriangleMeshViewer : public QWidget { private: Q_OBJECT; public: //! Constructor. TriangleMeshViewer(QWidget* parent,const ParametersRender* param,const std::vector& m,bool verbose); //! Destructor ~TriangleMeshViewer(); //! Used to set message in statusbar void notify(const std::string&); //! Sets the TriangleMesh to be displayed. void set_mesh(const std::vector& m); public slots: void fly(); void unfly(); void set_tilt(int v); void set_spinrate(int v); private: //! Control logging const bool _verbose; //! Pointer to the rendering parameters. const ParametersRender* parameters; //! The actual rendering area. TriangleMeshViewerDisplay* display; //! Real time for computing how much to advance animation boost::scoped_ptr clock; //! Record time last tick int last_t; //! Label and box around the elevation slider. QGroupBox* tilt_box; //! Slider controlling tilt QSlider* tilt_slider; //! Container for fly and reset buttons QWidget* button_box; //! Label and box arond the spin-rate slider. QGroupBox* spinrate_box; //! Spin rate slider. QSlider* spinrate_slider; //! Display fly velocity, render info QStatusBar* statusbar; //! Last notified message std::string notify_message; //@{ //! Parameter of camera position. XYZ camera_position; XYZ camera_forward; XYZ camera_up; float camera_velocity; float camera_yaw_rate; float camera_pitch_rate; float camera_roll_rate; //@} //@{ //! Parameters of object float object_tilt; float object_rotation; float object_spinrate; //@} //@{ //! Key state bool keypressed_arrow_left; bool keypressed_arrow_right; bool keypressed_arrow_up; bool keypressed_arrow_down; bool keypressed_mouse_left; bool keypressed_mouse_right; //@} //! Whether in fly mode bool fly_mode; //! Interested in some key presses void keyPressEvent(QKeyEvent* e); //! Interested in some key state void keyReleaseEvent(QKeyEvent* e); //! Interested in mouse clicks for steering void mousePressEvent(QMouseEvent* e); //! Interested in some button state void mouseReleaseEvent(QMouseEvent* e); //! Interested in mouse position for steering void mouseMoveEvent(QMouseEvent* e); //! Interested in wheel for speed void wheelEvent(QWheelEvent* e); private slots: void tick(); void reset(); }; #endif fracplanet/license.h0000644000175100017510000000303711261123520014326 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Header declaring license string. */ #ifndef _license_h #define _license_h_ //! String containing code license. extern const char*const license_string; #endif fracplanet/parameters_noise.h0000644000175100017510000000354311261123520016246 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ParametersNoise. */ #ifndef _parameters_noise_h_ #define _parameters_noise_h_ class ParametersNoise { public: //! Construct with given number of terms ParametersNoise(uint); //! Destructor ~ParametersNoise(); //! Number of Perlin noise terms uint terms; //! Frequency of 1st noise term float frequency; //! Amplitude of 1st noise term float amplitude; //! Amplitude decay rate for successive terms float amplitude_decay; }; #endif fracplanet/parameters_save.h0000644000175100017510000000435411261123520016070 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ParametersSave. */ #ifndef _parameters_save_h_ #define _parameters_save_h_ class ParametersRender; //! Aggregates controllable parameters for all things related to save. class ParametersSave { public: //! Constructor. ParametersSave(const ParametersRender*); //! Destructor. ~ParametersSave(); //! Whether to emit an atmosphere object to POV file. bool pov_atmosphere; //! Whether to emit a single sea-level object to POV file. bool pov_sea_object; //! Whether to try using per-vertex-alpha in the blender output. bool blender_per_vertex_alpha; //! Whether textures should include shading. bool texture_shaded; //! Size of texture for texture save (is height; width is implicit). uint texture_height; //! Save for blender needs access to some of these. const ParametersRender*const parameters_render; }; #endif fracplanet/xyz.h0000644000175100017510000001423711261123520013542 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class XYZ. */ #ifndef _xyz_h_ #define _xyz_h_ #include "random.h" //! Class to hold vectors in 3D cartesian co-ordinates. /*! Direct access to the x,y,z members is permitted. There is a general assumption that the co-ordinate system will be right handed, and that for terrain type applications x and y will be plan position and z will be height. */ class XYZ { public: float x; float y; float z; //! Null constructor. /*! NB The components are not cleared to zero. */ XYZ() {} //! Copy constructor. XYZ(const XYZ& v) :x(v.x),y(v.y),z(v.z){} //! Initialise from separate components. XYZ(float vx,float vy,float vz) :x(vx),y(vy),z(vz){} //! Destructor. ~XYZ() {} typedef float XYZ::* ElementPtr; static ElementPtr element_table[3]; //! Access by number const float& element(uint e) const { return this->*(element_table[e]); } //! Access by number float& element(uint e) { return this->*(element_table[e]); } //! Multiply by scalar. void operator*=(float k) { x*=k; y*=k; z*=k; } //! Divide by scalar. /*! Implemented assuming one divide and three multiplies is faster than three divides. */ void operator/=(float k) { const float ik(1.0/k); x*=ik; y*=ik; z*=ik; } //! Vector addition. void operator+=(const XYZ& v) { x+=v.x; y+=v.y; z+=v.z; } //! Vector subtraction. void operator-=(const XYZ& v) { x-=v.x; y-=v.y; z-=v.z; } //! Assignment. void assign(const XYZ& v) { x=v.x; y=v.y; z=v.z; } //! Negation. const XYZ operator-() const { return XYZ(-x,-y,-z); } //! Return the square of the magnitude. float magnitude2() const { return x*x+y*y+z*z; } //! Return the magnitude. float magnitude() const { return sqrt(magnitude2()); } //! Return the vector normalised. const XYZ normalised() const; //! Normalise this vector. void normalise(); //! Write the vector (spaces as separators). std::ostream& write(std::ostream&) const; //! Alternate formatting. const std::string format_comma() const; //! Alternate formatting. const std::string format_blender() const; //! Alternate formatting. const std::string format_pov() const; }; //! Cross product. inline const XYZ operator*(const XYZ& a,const XYZ& b) { return XYZ( a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x ); } //! Dot product. /*! Perhaps a curious choice of operator but it works for me. */ inline float operator%(const XYZ& a,const XYZ& b) { return a.x*b.x+a.y*b.y+a.z*b.z; } //! Vector addition. inline const XYZ operator+(const XYZ& a,const XYZ& b) { return XYZ(a.x+b.x,a.y+b.y,a.z+b.z); } //! Vector subtraction. inline const XYZ operator-(const XYZ& a,const XYZ& b) { return XYZ(a.x-b.x,a.y-b.y,a.z-b.z); } //! Multiplication by scalar. inline const XYZ operator*(float k,const XYZ& v) { return XYZ(k*v.x,k*v.y,k*v.z); } //! Multiplication by scalar. inline const XYZ operator*(const XYZ& v,float k) { return XYZ(k*v.x,k*v.y,k*v.z); } //! Division by scalar. inline const XYZ operator/(const XYZ& v,float k) { return (1.0/k)*v; } //! Equality operator. inline bool operator==(const XYZ& a,const XYZ& b) { return (a.x==b.x && a.y==b.y && a.z==b.z); } //! Inequality operator. inline bool operator!=(const XYZ& a,const XYZ& b) { return (a.x!=b.x || a.y!=b.y || a.z!=b.z); } /*! Will fail assertion if the co-ordinate has zero magnitude. */ inline const XYZ XYZ::normalised() const { const float m=magnitude(); assert(m!=0.0); return (*this)/m; } /*! Will fail assertion if the co-ordinate has zero magnitude. */ inline void XYZ::normalise() { (*this)=normalised(); } //! Stream output operator. inline std::ostream& operator<<(std::ostream& out,const XYZ& v) { return v.write(out); } //! Generates a random point in the cube bounded by (0,0,0) and (1.0,1.0,1.0) class RandomXYZInUnitCube : public XYZ { public: RandomXYZInUnitCube(Random01&); }; //! Generates random points in a recnangular box centred on the origin class RandomXYZInBox : public XYZ { public: RandomXYZInBox(Random01& rng,const XYZ& bounds); }; //! Generates a random point in or on a unit-radius sphere centred on the origin. class RandomXYZInSphere : public XYZ { public: RandomXYZInSphere(Random01& rng,float radius); }; //! Generates a random point in or on an origin-centred ellipsoid with semi-axes of the specified size. class RandomXYZInEllipsoid : public XYZ { public: RandomXYZInEllipsoid(Random01& rng,const XYZ& axes); }; //! Generates a random point on the surface of a unit-radius sphere class RandomXYZSphereNormal : public XYZ { public: RandomXYZSphereNormal(Random01& rng); }; #endif fracplanet/triangle_mesh.h0000644000175100017510000002046411261123520015530 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #ifndef _triangle_mesh_h_ #define _triangle_mesh_h_ #include "geometry.h" #include "parameters_save.h" #include "parameters_terrain.h" #include "progress.h" #include "random.h" #include "triangle.h" #include "triangle_edge.h" #include "vertex.h" /*! \file \brief Interface for class TriangleMesh. */ //! Contains vertices and triangles of a triangle mesh. /*! Abstract base class because specific classes must specify a geometry. Not as general-purpose as it might be due to constraints imposed by OpenGL. In particular, Triangle can have no attributes (e.g normal, colour) if a single OpenGL call is to be made to draw all triangles, so this information is entirely associated with Vertex. Two colours can be associated with each vertex (required for fracplanet application to obtain sharp coastlines), and it it a requirement for subclasses to sort triangles so that all those before _triangle_switch_colour use vertex colour index 0, and those afterwards vertex colour index 1. \todo The geometry() method is a mess. It would surely be better to have a Geometry* in the base class passed in via the constructor. */ class TriangleMesh { public: //! Constructor. TriangleMesh(Progress* progress); //! Destructor. virtual ~TriangleMesh(); //! Accessor void set_emissive(float e) { _emissive=e; } //! Accessor float emissive() const { return _emissive; } //! Append a vertex. void add_vertex(const Vertex& v) { _vertex.push_back(v); } //! Append a triangle. void add_triangle(const Triangle& t) { _triangle.push_back(t); } //! Accessor. const Vertex& vertex(uint i) const { return _vertex[i]; } //! Accessor. const Triangle& triangle(uint i) const { return _triangle[i]; } //! Access the geometry of this class (needed to abstract concepts like "mid-point" and "height"). virtual const Geometry& geometry() const =0; //! Return height of a vertex. float vertex_height(uint i) const { return geometry().height(vertex(i).position()); } //! Set height of a vertex. void set_vertex_height(uint i,float h) { XYZ p(vertex(i).position()); geometry().set_height(p,h); vertex(i).position(p); } //! Return minimum height of a triangle's vertices. float triangle_height_min(uint i) const { const Triangle& t=triangle(i); return minimum ( vertex_height(t.vertex(0)), vertex_height(t.vertex(1)), vertex_height(t.vertex(2)) ); } //! Return maximum height of a triangle's vertices. float triangle_height_max(uint i) const { const Triangle& t=triangle(i); return maximum ( vertex_height(t.vertex(0)), vertex_height(t.vertex(1)), vertex_height(t.vertex(2)) ); } //! Return mean height of a triangle's vertices. float triangle_height_average(uint i) const { const Triangle& t=triangle(i); return ( vertex_height(t.vertex(0)) +vertex_height(t.vertex(1)) +vertex_height(t.vertex(2)) )/3.0; } //! Compute and return the normal to a triangle const XYZ triangle_normal(uint i) const; //! Return which vertex colour to use for a triangle. uint which_colour_for_triangle(uint t) const { return (t<_triangle_switch_colour ? 0 : 1); } //! Returns number of vertices in mesh. uint vertices() const { return _vertex.size(); } //! Returns number of triangles in mesh. uint triangles() const { return _triangle.size(); } //! Returns number of triangles in mesh indexing colour[0] of vertices. uint triangles_of_colour0() const { return _triangle_switch_colour; } //! Returns number of triangles in mesh indexing colour[1] of vertices. uint triangles_of_colour1() const { return triangles()-_triangle_switch_colour; } //! (Re-)computes vertex normals. void compute_vertex_normals(); //! Perform a single subdivision pass with perturbations up to the specified size void subdivide(const XYZ& variation,uint level,uint levels); //! Perform a number of subdivisions, possibly some unperturbed ("flat"), and halving the perturbation variation each iteration. void subdivide(uint subdivisions,uint flat_subdivisions,const XYZ& variation); //! Dump the mesh to the file in a form suitable for use by POVRay. void write_povray(std::ofstream& out,bool exclude_alternate_colour,bool double_illuminate,bool no_shadow) const; //! Dump the mesh to the file in a form suitable for use by Blender. void write_blender(std::ofstream& out,const std::string& mesh_name,const FloatRGBA* fake_alpha) const; protected: //! The vertices of this mesh. std::vector _vertex; //! The triangles of this mesh. std::vector _triangle; //! The index of the triangle at which we switch to the alternate colour. uint _triangle_switch_colour; //! The emission level for vertices with the _emissive flag set float _emissive; //! Pointer to the progress object to which progress reports should be made. Progress*const _progress; //! Accessor. Vertex& vertex(uint i) { return _vertex[i]; } //! Accessor. Triangle& triangle(uint i) { return _triangle[i]; } //! Convenience wrapper with null test. void progress_start(uint steps,const std::string& info) const; //! Convenience wrapper with null test. void progress_stall(const std::string& reason) const; //! Convenience wrapper with null test. void progress_step(uint step) const; //! Convenience wrapper with null test. void progress_complete(const std::string& info) const; private: //! Fake per-vertex alpha for Blender. static ByteRGBA blender_alpha_workround(const ByteRGBA*,const ByteRGBA&); }; //! A single triangle lying in the z-plane. class TriangleMeshFlat : virtual public TriangleMesh { public: //! Constructor. TriangleMeshFlat(ParametersObject::ObjectType obj,float z,uint seed,Progress* progress); //! Destructor. ~TriangleMeshFlat() {} //! Returns the specific geometry. virtual const Geometry& geometry() const { return _geometry; } private: //! The specifc geometry for this mesh. GeometryFlat _geometry; }; //! An icosahedron. class TriangleMeshIcosahedron : virtual public TriangleMesh { public: //! Constructor. TriangleMeshIcosahedron(float radius,uint seed,Progress* progress); //! Destructor. ~TriangleMeshIcosahedron() {} //! Returns the specific geometry. virtual const Geometry& geometry() const { return _geometry; } private: //! The specifc geometry for this mesh. GeometrySpherical _geometry; }; //! A subdivided icosahedron. class TriangleMeshSubdividedIcosahedron : public TriangleMeshIcosahedron { public: //! Constructor. TriangleMeshSubdividedIcosahedron(float radius,uint subdivisions,uint flat_subdivisions,uint seed,const XYZ& variation,Progress* progress); //! Destructor. ~TriangleMeshSubdividedIcosahedron() {} }; #endif fracplanet/triangle_edge.h0000644000175100017510000000544611261123520015503 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class TriangleEdge. */ #ifndef _triangle_edge_h_ #define _triangle_edge_h_ //! Class to store triangle edges. /*! An edge is described by two vertices. These are ordered internally for more efficient sorting and comparison. This class is useful for, for example, discovering adjacent triangles through edges they have in common. NB There is no void constructor because the const vertices wouldn't be set. */ class TriangleEdge { public: //! Constructor. Sorts arguments to ensure _vertex0<_vertex1 TriangleEdge(uint v0,uint v1) :_vertex0(v0v1 ? v0 : v1) {} //! Copy constructor. TriangleEdge(const TriangleEdge& e) :_vertex0(e._vertex0) ,_vertex1(e._vertex1) {} //! Destructor. ~TriangleEdge() {} //! Accessor. uint vertex0() const {return _vertex0;} //! Accessor. uint vertex1() const {return _vertex1;} protected: //! One vertex of the edge. This should always be the lesser valued index. const uint _vertex0; //! The other vertex of the edge. This should always be the greater valued index. const uint _vertex1; }; //! Comparison operator, required to build ordered STL data-structures. inline bool operator<(const TriangleEdge& e0,const TriangleEdge& e1) { return ( e0.vertex0(). */ /**************************************************************************/ /*! \file \brief Interface for class Triangle. */ #ifndef _triangle_h_ #define _triangle_h_ #include "rgb.h" #include "xyz.h" //! Class to store triangle state. /*! There is no direct access to members. Should probably be a protected member class of TriangleMesh. */ class Triangle { public: Triangle() {} Triangle(uint v0,uint v1,uint v2) { _vertex[0]=v0; _vertex[1]=v1; _vertex[2]=v2; } Triangle(const Triangle& t) { _vertex[0]=t.vertex(0); _vertex[1]=t.vertex(1); _vertex[2]=t.vertex(2); } //! Return a reference to the vertex because GL will want it's address const uint& vertex(uint i) const { return _vertex[i]; } protected: uint _vertex[3]; }; #endif fracplanet/parameters_terrain.h0000644000175100017510000000700211261123520016567 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ParametersTerrain. */ #ifndef _parameters_terrain_h_ #define _parameters_terrain_h_ #include "parameters_noise.h" #include "parameters_object.h" #include "rgb.h" #include "xyz.h" //! This class aggregates the controllable parameters for all things related to terrain generation. /*! \todo Add these to ParametersTerrain (and ControlTerrain): float treeline; float beachline; */ class ParametersTerrain : public ParametersObject { public: //! Constructor sets up some hopefully sensible defaults. ParametersTerrain(); //! Destructor ~ParametersTerrain(); //! Numer of subdivisions (at the top level) which will be unperturbed uint subdivisions_unperturbed; //! Maximum size of perturbations (z in vertical direction, x & y horizontally). XYZ variation; ParametersNoise noise; //! Initial height of unsubdivided, unperturbed terrain, expressed as a proportion of variation.z float base_height; //! Power law applied to terrain heights. /*! When >1, flattens low areas. When <1, flattens highland areas and creates gorges. */ float power_law; //! Normalised height of snowline at the equator. float snowline_equator; //! Normalised height of snowline at the pole. float snowline_pole; //! Power law for snowline. float snowline_power_law; //! Supresses snow on slopes. float snowline_slope_effect; //! When positive, rivers become glaciers. When negative, rivers remain blue. float snowline_glacier_effect; //! Number of rivers to generate. uint rivers; //! Random seed for river generation. uint rivers_seed; //! Limit on lake size as a proportion of available surface. /*! When lakes (produced during the river-growing step) cover this fraction of the available terrain they become seas and no-longer need to find a drain. */ float lake_becomes_sea; //! Amount of emissive colour for oceans and rivers. float oceans_and_rivers_emissive; //@{ //! Colour for a terrain type. FloatRGBA colour_ocean; FloatRGBA colour_river; FloatRGBA colour_shoreline; FloatRGBA colour_low; FloatRGBA colour_high; FloatRGBA colour_snow; //@} }; #endif fracplanet/dialog_documentation.h0000644000175100017510000000335011261123520017072 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class DialogDocumentation. */ #ifndef _dialog_documentation_h_ #define _dialog_documentation_h_ //! Provides a dialog box with some user documentation. class DialogDocumentation : public QDialog { private: Q_OBJECT public: //! Constructor. DialogDocumentation(QWidget* parent); //! Destructor. ~DialogDocumentation(); }; #endif fracplanet/matrix33.h0000644000175100017510000001246011261123520014356 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Matrix33. */ #ifndef _matrix33_h_ #define _matrix33_h_ #include "xyz.h" //! Class to hold 3x3 matrics class Matrix33 { public: //! Column vectors of matrix XYZ basis[3]; //! Null constructor /*! NB Doesn't set up identity or anything useful */ Matrix33() {} //! Construct from column vectors Matrix33(const XYZ& rx,const XYZ& ry,const XYZ& rz) { basis[0]=rx; basis[1]=ry; basis[2]=rz; } //! Destructor. ~Matrix33() {} void assign(const Matrix33& m) { basis[0]=m.basis[0]; basis[1]=m.basis[1]; basis[2]=m.basis[2]; } //! Access a given element const float& element(uint row,uint col) const { return basis[col].element(row); } //! Access a given element float& element(uint row,uint col) { return basis[col].element(row); } //! Extract copy of the first row of matrix const XYZ row0() const { return XYZ(basis[0].x,basis[1].x,basis[2].x); } //! Extract copy of the second row of matrix const XYZ row1() const { return XYZ(basis[0].y,basis[1].y,basis[2].y); } //! Extract copy of the third row of matrix const XYZ row2() const { return XYZ(basis[0].z,basis[1].z,basis[2].z); } //! Cofactor of an element float cofactor(uint row,uint col) const; //! Determinant of matrix float determinant() const; //! Return inverse of matrix const Matrix33 inverted() const; }; //! Multiplication by scalar inline const Matrix33 operator*(float k,const Matrix33& m) { return Matrix33(k*m.basis[0],k*m.basis[1],k*m.basis[2]); } //! Multiplication by scalar inline const Matrix33 operator*(const Matrix33& m,float k) { return Matrix33(m.basis[0]*k,m.basis[1]*k,m.basis[2]*k); } //! Division by scalar inline const Matrix33 operator/(const Matrix33& m,float k) { return Matrix33(m.basis[0]/k,m.basis[1]/k,m.basis[2]/k); } //! Apply matrix to vector inline const XYZ operator*(const Matrix33& m,const XYZ& v) { return XYZ ( m.row0()%v, m.row1()%v, m.row2()%v ); } //! Matrix multiplication inline const Matrix33 operator*(const Matrix33& a,const Matrix33& b) { return Matrix33 ( a*b.basis[0], a*b.basis[1], a*b.basis[2] ); } //! 3x3 Identity matrix class Matrix33Identity : public Matrix33 { public: Matrix33Identity() { basis[0]=XYZ(1.0f,0.0f,0.0f); basis[1]=XYZ(0.0f,1.0f,0.0f); basis[2]=XYZ(0.0f,0.0f,1.0f); } }; class Matrix33RotateAboutX : public Matrix33 { public: Matrix33RotateAboutX(float angle) { const float ca=cos(angle); const float sa=sin(angle); basis[0]=XYZ(1.0f,0.0f,0.0f); basis[1]=XYZ(0.0f, ca, sa); basis[2]=XYZ(0.0f,-sa, ca); } }; class Matrix33RotateAboutY : public Matrix33 { public: Matrix33RotateAboutY(float angle) { const float ca=cos(angle); const float sa=sin(angle); basis[0]=XYZ(ca, 0.0f,-sa); basis[1]=XYZ(0.0f,1.0f,0.0f); basis[2]=XYZ(sa ,0.0f,ca); } }; class Matrix33RotateAboutZ : public Matrix33 { public: Matrix33RotateAboutZ(float angle) { const float ca=cos(angle); const float sa=sin(angle); basis[0]=XYZ( ca,sa,0.0f); basis[1]=XYZ(-sa,ca,0.0f); basis[2]=XYZ(0.0f,0.0f,1.0f); } }; class Matrix33RotateAboutAxis : public Matrix33 { public: //! NB Axis must be normalized. Matrix33RotateAboutAxis(const XYZ& axis,float angle) { // Want 2 vectors perpendicular to axis TODO: Check for degenerate cases const XYZ axis_ortho0((axis*XYZ(1.0,0.0,0.0)).normalised()); const XYZ axis_ortho1(axis*axis_ortho0); // The matrix which rotates identity basis to axis&orthos. z axis goes to passed in axis const Matrix33 xyz_to_axis ( axis_ortho0, axis_ortho1, axis ); const Matrix33 axis_to_xyz(xyz_to_axis.inverted()); assign(xyz_to_axis*Matrix33RotateAboutZ(angle)*axis_to_xyz); } }; #endif fracplanet/vertex.h0000644000175100017510000000644511261123520014227 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Vertex. */ #ifndef _vertex_h_ #define _vertex_h_ #include "rgb.h" #include "xyz.h" //! Class to store vertex state information /*! There is no direct access to members. Should probably be a protected member class of TriangleMesh. sizeof(Vertex) should ideally be 3*4+3*4+2*4=32 */ class Vertex { public: //! Constructor. NB Almost no default values set. Vertex() {} //! Copy constructor. Vertex(const Vertex& v) :_position(v._position) ,_normal(v._normal) { _colour[0]=v._colour[0]; _colour[1]=v._colour[1]; } //! Construct from position only. explicit Vertex(const XYZ& p) :_position(p) ,_normal(0.0,0.0,0.0) { _colour[0]=ByteRGBA(0,0,0,255); _colour[1]=ByteRGBA(0,0,0,255); } //! Accessor. const XYZ& position() const { return _position; } //! Accessor. const XYZ& normal() const { return _normal; } //! Accessor. const ByteRGBA& colour(uint c) const { assert(c<2); return _colour[c]; } //! Accessor. void position(const XYZ& p) { _position=p; } //! Accessor. void normal(const XYZ& n) { _normal=n; } //! Accessor. void colour(uint c,const ByteRGBA& col) { assert(c<2); _colour[c]=col; } //! Accessor. void colour(uint c,const FloatRGBA& col) { assert(c<2); _colour[c]=ByteRGBA(col); } private: //! Position of vertex. XYZ _position; //! Normal at vertex (for smooth shading). XYZ _normal; //! Colours at vertex (could be a different colour in different triangles). /*! By convention, in triangle meshes with emissive in use, we overload the alpha channel to indicate emissive (zero indicates emissive) shading is required. Actual alpha or emissive are therefore mutually exclusive (anticipate alpha for clouds, emissive for ground). */ ByteRGBA _colour[2]; }; #endif fracplanet/parameters_object.h0000644000175100017510000000404611261123520016376 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Parameters. */ #ifndef _parameters_h_ #define _parameters_h_ //! Common base for ParametersTerrain and ParametersCloud. class ParametersObject { public: //! Constructor sets up some hopefully sensible defaults. ParametersObject(); //! Destructor virtual ~ParametersObject(); //! What kind of object will be generated. typedef enum { ObjectTypePlanet, ObjectTypeFlatHexagon, ObjectTypeFlatTriangle, ObjectTypeFlatSquare } ObjectType; //! Kind of object. ObjectType object_type; //! Random seed for subdivision and noise. uint seed; //! Number of subdivisions. uint subdivisions; }; #endif fracplanet/rgb.h0000644000175100017510000001363011261123520013456 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /* Copyright (C) 1998,1999 T Day */ /*! \file \brief Interface for class ByteRGBA and class FloatRGBA. */ #ifndef _image_rgb_h_ #define _image_rgb_h_ /*! Direct access to class members is permitted. The uchar version is intended as a minimal class for efficient storage of colours. (However, padding means there is a wasted byte if we just want RGB so we might as well have an alpha channel). */ template class RGBA { public: //@{ //! Colour component. T r; T g; T b; T a; //@} //! Null constructor. /* NB There are no default values. */ RGBA() {} //! Copy constructor. RGBA(const RGBA& c) :r(c.r) ,g(c.g) ,b(c.b) ,a(c.a) {} //! Initialise from separate components. RGBA(T vr,T vg,T vb,T va) :r(vr) ,g(vg) ,b(vb) ,a(va) {} //! Colour addition. void operator+=(const RGBA& v) { r+=v.r; g+=v.g; b+=v.b; a+=v.a; } //! Colour subtraction. void operator-=(const RGBA& v) { r-=v.r; g-=v.g; b-=v.b; a-=v.a; } }; //! Colour equality operator. template inline bool operator==(const RGBA& a,const RGBA& b) { return (a.r==b.r && a.g==b.g && a.b==b.b && a.a==b.a); } //! Colour inequality operator. template inline bool operator!=(const RGBA& a,const RGBA& b) { return (a.r!=b.r || a.g!=b.g || a.b!=b.b || a.a!=b.a); } //! Colour addition operator. template inline RGBA operator+(const RGBA& a,const RGBA& b) { return RGBA ( a.r+b.r, a.g+b.g, a.b+b.b, a.a+b.a ); } //! Colour negation operator. template inline RGBA operator-(const RGBA& c) { return RGBA ( -c.r, -c.g, -c.b, -c.a ); } //! Colour subtraction operator. template inline RGBA operator-(const RGBA& a,const RGBA& b) { return RGBA ( a.r-b.r, a.g-b.g, a.b-b.b, a.a-b.a ); } //! Class to represent red-green-blue-alpha colours stored with 8-bit resolution. class ByteRGBA : public RGBA { public: //! Null constructor. NB There are no default values. ByteRGBA() :RGBA() {} //! Copy constructor. ByteRGBA(const RGBA& c) :RGBA(c) {} //! Componentwise initialization. ByteRGBA(uchar vr,uchar vg,uchar vb,uchar va) :RGBA(vr,vg,vb,va) {} //! Construct ByteRGBA from float RGBAs. /*! Components in the range [0.0,1.0] are scaled to [0,255]. */ explicit ByteRGBA(const RGBA& c) :RGBA ( static_cast(255.0*clamped(c.r,0.0f,1.0f)), static_cast(255.0*clamped(c.g,0.0f,1.0f)), static_cast(255.0*clamped(c.b,0.0f,1.0f)), static_cast(255.0*clamped(c.a,0.0f,1.0f)) ) {} std::ostream& write(std::ostream&) const; const std::string format_comma() const; }; //! Class to represent red-green-blue-alpha colours stored to floating point accuracy. class FloatRGBA : public RGBA { public: //! Null constructor. /* NB There are no default values. */ FloatRGBA() {} //! Copy constructor. FloatRGBA(const RGBA& c) :RGBA(c) {} //! Initialise from separate components. FloatRGBA(float vr,float vg,float vb,float va) :RGBA(vr,vg,vb,va) {} //! Initialise from ByteRGBA. /*! Byte values [0,255] are normalised to [0.0,1.0] */ explicit FloatRGBA(const RGBA& c) :RGBA(c.r/255.0f,c.g/255.0f,c.b/255.0,c.a/255.0) {} //! Output method. std::ostream& write(std::ostream&) const; const std::string format_pov_rgb() const; const std::string format_pov_rgbf() const; }; //! Colour multiplication-by-scalar operator. inline FloatRGBA operator*(float k,const FloatRGBA& c) { return FloatRGBA ( k*c.r, k*c.g, k*c.b, k*c.a ); } //! Colour multiplication-by-scalar operator. inline FloatRGBA operator*(const FloatRGBA& c,float k) { return FloatRGBA ( k*c.r, k*c.g, k*c.b, k*c.a ); } //! Colour division-by-scalar operator. inline FloatRGBA operator/(const FloatRGBA& c,float k) { return FloatRGBA ( c.r/k, c.g/k, c.b/k, c.a/k ); } //! Colour multiplication operator. /*! Componentwise multiplication. */ inline FloatRGBA operator*(const FloatRGBA& a,const FloatRGBA& b) { return FloatRGBA ( a.r*b.r, a.g*b.g, a.b*b.b, a.a*b.a ); } inline std::ostream& operator<<(std::ostream& out,const FloatRGBA& c) { return c.write(out); } #endif fracplanet/geometry.h0000644000175100017510000002203511261123520014536 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Geometry and derived classes. */ #ifndef _geometry_h_ #define _geometry_h_ #include "scan.h" #include "vertex.h" #include "xyz.h" //! Class to provide abstract interface to different world geometries. /*! This is an abstract base class providing methods which will differ between world geometries. For example, the direction of "up" at a given point will vary depending on whether we are generating a flat world or a spherical one. \todo Most of these methods should have their implementation moved geometry.cpp */ class Geometry : public ScanConverter { public: //! Constructor. Geometry(uint seed) :_r01(seed) {} //! Destructor. virtual ~Geometry() {} //! Return the height of the given point. virtual float height(const XYZ& p) const =0; //! Move the specified point vertically until. virtual void set_height(XYZ& p,float v) const =0; //! Return a point halfway between the two given points. virtual const XYZ midpoint(const XYZ& v0,const XYZ& v1) const =0; //! Really only meaningful for spherical geometries. virtual float normalised_latitude(const XYZ&p) const =0; //! Return the direction of "up" at the specified point. virtual const XYZ up(const XYZ& p) const =0; //! Return the direction of "north" at the specified point. virtual const XYZ north(const XYZ& p) const =0; //! Return the direction of "east" at the specified point. virtual const XYZ east(const XYZ& p) const =0; //! Add a random variation to a point virtual const XYZ perturb(const XYZ& v,const XYZ& variation) const =0; //! Nasty hack to work around height setting possibly not being exact. /*! In some geometries (e.g spherical, but not flat) modifying a point to be at a particular height does not guarantee that exact value will be returned on a susequent height query. If this is the case, a non-zero epsilon value can be returned and used as an error tolerence when comparing two heights for equivalence. */ virtual float epsilon() const =0; //! Multiplier for width of a scan-converted image. virtual uint scan_convert_image_aspect_ratio() const { return 1; } protected: //! Common scan-converter code static void scan_convert_common ( const boost::array& v, const ScanConvertBackend& backend ); //! Random number generator used for perturbations and the like. /*! Declared mutable so it can be used in const methods. \todo Perhaps theres a better place for the geometry random number generator to live: having it here creates the anomaly of having to pass random seeds into apparently non-random objects like icosahedrons etc. */ mutable Random01 _r01; }; //! Concrete class providing a flat geometry (in the XY-plane, with Z up). class GeometryFlat : public Geometry { public: GeometryFlat(uint seed) :Geometry(seed) {} ~GeometryFlat() {} //! Height is just the z co-ordinate of a point. float height(const XYZ& p) const { return p.z; } //! Setting a height is simply assigning to the z-coordinate. void set_height(XYZ& p,float v) const { p.z=v; } //! The mid-point between two points is simply their average. const XYZ midpoint(const XYZ& v0,const XYZ& v1) const { return 0.5f*(v0+v1); } //! This doesn't really mean anything here, so return zero, which would correspond to the equator of a spherical geometry. float normalised_latitude(const XYZ&) const { return 0.0f; } //! Returns unit z vector. (Up is the same everywhere in this geometry). const XYZ up(const XYZ&) const { return XYZ(0.0f,0.0f,1.0f); } //! Returns unit y vector. (North is the same everywhere in this geometry). const XYZ north(const XYZ&) const { return XYZ(0.0f,1.0f,0.0f); } //! Returns unit x vector. (East is the same everywhere in this geometry). const XYZ east(const XYZ&) const { return XYZ(1.0f,0.0f,0.0f); } //! Add a random variation to a point. const XYZ perturb(const XYZ& p,const XYZ& variation) const { // The correct thing to do would be to return p+RandomXYZInEllipsoid(_r01,variation); // however, this uses a variable number of random number calls which means small parameter changes can have big effects on generated terrain. // This, on the other hand, always uses the same number of random numbers, but isn't statistically equivalent: return p+RandomXYZInBox(_r01,variation); } //! Returns zero. Heights are stored exactly once assigned so no need for non-zero epsilon. float epsilon() const { return 0.0f; // No need 'cos heights are stored exactly } virtual void scan_convert ( const boost::array& v, const ScanConvertBackend& ) const; }; //! Concrete class providing a flat geometry (a sphere with nominal radius 1, equator in the XY-plane, Z axis through the poles). class GeometrySpherical : public Geometry { public: //! Constructor. GeometrySpherical(uint seed) :Geometry(seed) {} //! Destructor. ~GeometrySpherical() {} //! Height is relative to the surface of the unit radius sphere. float height(const XYZ& p) const { return p.magnitude()-1.0f; } //! The height set is relative to the surface of the unit radius sphere. void set_height(XYZ& p,float h) const { const float m=p.magnitude(); p*=((1.0f+h)/m); } //! Don't just take the mid-point of the straight-line path through the sphere's surface: must work relative to the sphere's surface. const XYZ midpoint(const XYZ& v0,const XYZ& v1) const { const float h0=v0.magnitude(); const float h1=v1.magnitude(); const float h_av=0.5f*(h0+h1); const XYZ m(0.5f*(v0+v1)); return (h_av/m.magnitude())*m; } //! Normalised latitude is 1.0 at the north pole, -1.0 at the south pole float normalised_latitude(const XYZ& p) const { return p.z; } //! Up is normal to the sphere. const XYZ up(const XYZ& p) const { return p.normalised(); } //! North is perpendicular to "up" and "east" /*! \warning Returns zero vector at the poles */ const XYZ north(const XYZ& p) const { if (p.x==0.0f && p.y==0.0f) return XYZ(0.0f,0.0f,0.0f); else return (up(p)*east(p)).normalised(); } //! East is perpendicular to "up" and the polar vector. /*! \warning Returns zero vector at the poles */ const XYZ east(const XYZ& p) const { if (p.x==0.0f && p.y==0.0f) return XYZ(0.0f,0.0f,0.0f); else return (XYZ(0.0f,0.0f,1.0f)*up(p)).normalised(); } //! Add a random variation to a point. /*! In spherical geometry, the variation ellipsoid tracks the surface (ie z corresponds to up, north to y) */ const XYZ perturb(const XYZ& p,const XYZ& variation) const { // The correct thing to do would be to use const RandomXYZInEllipsoid v(_r01,variation); // however, this uses a variable number of random number calls which means small parameter changes can have big effects on generated terrain. // This, on the other hand, always uses the same number of random numbers, but isn't statistically equivalent: const RandomXYZInBox v(_r01,variation); return p+v.x*east(p)+v.y*north(p)+v.z*up(p); } //! This needs to return something small for the lake flooding algorithm to work. float epsilon() const { return 0.000001f; } void scan_convert ( const boost::array& v, const ScanConvertBackend& ) const; //! Return 2.0 for spheres because vertical range is +/- pi/2, horizontal is +/- pi uint scan_convert_image_aspect_ratio() const { return 2; } }; #endif fracplanet/control_about.h0000644000175100017510000000320011262220434015551 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ControlAbout. */ #ifndef _control_about_h_ #define _control_about_h_ #include "control.h" //! Displays "About" type info class ControlAbout : public Control { private: Q_OBJECT; public: ControlAbout(QApplication*); }; #endif fracplanet/progress.h0000644000175100017510000000457311261123520014556 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Progress. */ #ifndef _progress_h_ #define _progress_h_ //! Mix-in class for call-backs from long operations. /*! Use concrete implementations of these methods to drive progress bars. */ class Progress { public: virtual ~Progress(); virtual void progress_start(uint steps,const std::string& info) =0; // This will change the dialog text to indicate that progress is stalled for some reason. // It resets to the original text when progress_step is next stalled. // (Used by river generation). virtual void progress_stall(const std::string& reason) =0; virtual void progress_step(uint step) =0; virtual void progress_complete(const std::string& info) =0; }; //! Helper class to facilitate driving progress bar class ProgressScope { public: ProgressScope(uint steps,const std::string& info,Progress* tgt); ~ProgressScope(); void step(); private: const uint _steps; const std::string _info; Progress*const _target; uint _step; }; #endif fracplanet/matrix34.h0000644000175100017510000000617711261123520014367 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Matrix34. */ #ifndef _matrix34_h_ #define _matrix34_h_ #include "matrix33.h" #include "xyz.h" //! Class to hold 3x4 matrices /*! Rotation below actually means any sort of origin preserving transform; it's just easier to visualize rotations and most of the time that's what they are. */ class Matrix34 { public: //! 3x3 rotational component Matrix33 rotate; //! Translational component XYZ translate; //! Null constructor. /*! NB The components are not cleared to zero. */ Matrix34() {} //! Construct from a rotation and translation Matrix34(const Matrix33& r,const XYZ& t) :rotate(r) ,translate(t) {} //! Construct from column vectors Matrix34(const XYZ& rx,const XYZ& ry,const XYZ& rz,const XYZ& tr) :rotate(rx,ry,rz) ,translate(tr) {} //! Destructor. ~Matrix34() {} void assign(const Matrix34& m) { rotate=m.rotate; translate=m.translate; } }; inline const XYZ operator*(const Matrix34& m,const XYZ& v) { return m.rotate*v+m.translate; } inline const Matrix34 operator*(const Matrix34& a,const Matrix34& b) { return Matrix34 ( a.rotate*b.rotate, a.rotate*b.translate+a.translate ); } class Matrix34Identity : public Matrix34 { public: Matrix34Identity() :Matrix34(Matrix33Identity(),XYZ(0.0f,0.0f,0.0f)) {} }; class Matrix34Translate : public Matrix34 { public: Matrix34Translate(const XYZ& t) :Matrix34(Matrix33Identity(),t) {} }; class Matrix34RotateAboutAxisThrough : public Matrix34 { public: //! Axis must be normalized Matrix34RotateAboutAxisThrough(const XYZ& axis,float angle,const XYZ& pt); //! Axis size gives rotation size Matrix34RotateAboutAxisThrough(const XYZ& axis,const XYZ& pt); }; #endif fracplanet/control_terrain.h0000644000175100017510000002004511261123520016106 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ControlTerrain. */ #ifndef _control_terrain_h_ #define _control_terrain_h_ #include "parameters_terrain.h" #include "parameters_cloud.h" #include "control.h" class FracplanetMain; //! Encapsulates controls for setting terrain generation parameters /*! \todo: Way too much stuff in this classes .h file. Shift it to the .cpp! */ class ControlTerrain : public Control { private: Q_OBJECT; public: ControlTerrain(FracplanetMain* tgt,ParametersTerrain* param_terrain,ParametersCloud* param_cloud); ~ControlTerrain() {} public slots: void setObjectType(int id) { parameters_terrain->object_type=static_cast(id); parameters_cloud->object_type=static_cast(id); } void setTerrainSeed(int v) { parameters_terrain->seed=v; } void setTerrainSubdivisions(int v) { parameters_terrain->subdivisions=v; } void setCloudSubdivisions(int v) { parameters_cloud->subdivisions=v; } void setSubdivisionsUnperturbed(int v) { parameters_terrain->subdivisions_unperturbed=v; } void setVariationVertical(int v) { parameters_terrain->variation.z=v/100.0; } void setVariationHorizontal(int v) { parameters_terrain->variation.x=v/100.0; parameters_terrain->variation.y=v/100.0; } void setNoiseTerms(int v) { parameters_terrain->noise.terms=v; } void setNoiseFrequency(int v) { parameters_terrain->noise.frequency=v/100.0; } void setNoiseAmplitude(int v) { parameters_terrain->noise.amplitude=v/100.0; } void setNoiseAmplitudeDecay(int v) { parameters_terrain->noise.amplitude_decay=v/100.0; } void setBaseHeight(int v) { parameters_terrain->base_height=v/100.0; } void setPowerLaw(int v) { parameters_terrain->power_law=v/100.0; } void setSnowlineEquator(int v) { parameters_terrain->snowline_equator=v/100.0; } void setSnowlinePole(int v) { parameters_terrain->snowline_pole=v/100.0; } void setSnowlinePowerLaw(int v) { parameters_terrain->snowline_power_law=v/100.0; } void setSnowlineSlopeEffect(int v) { parameters_terrain->snowline_slope_effect=v/100.0; } void setSnowlineGlacierEffect(int v) { parameters_terrain->snowline_glacier_effect=v/100.0; } void setRivers(int v) { parameters_terrain->rivers=v; } void setRiversSeed(int v) { parameters_terrain->rivers_seed=v; } void setLakeBecomesSea(int v) { parameters_terrain->lake_becomes_sea=v/100.0; } void setOceansAndRiversEmissive(int v) { parameters_terrain->oceans_and_rivers_emissive=v/100.0; } void pickColourOcean() { emit pickColour(colour_ocean_button,parameters_terrain->colour_ocean); } void pickColourShoreline() { emit pickColour(colour_shoreline_button,parameters_terrain->colour_shoreline); } void pickColourLow() { emit pickColour(colour_low_button,parameters_terrain->colour_low); } void pickColourRiver() { emit pickColour(colour_river_button,parameters_terrain->colour_river); } void pickColourSnow() { emit pickColour(colour_snow_button,parameters_terrain->colour_snow); } void pickColourHigh() { emit pickColour(colour_high_button,parameters_terrain->colour_high); } void pickColourCloud() { emit pickColour(colour_cloud_button,parameters_cloud->colour); } void setCloudsSubdivisionsUnlocked(bool f) { if (f) { disconnect( subdivisions_spinbox,SIGNAL(valueChanged(int)), clouds_subdivisions_spinbox,SLOT(setValue(int)) ); } else { clouds_subdivisions_spinbox->setValue(parameters_terrain->subdivisions); connect( subdivisions_spinbox,SIGNAL(valueChanged(int)), clouds_subdivisions_spinbox,SLOT(setValue(int)) ); } } void setCloudsEnabled(bool f) { parameters_cloud->enabled=f; } void setCloudbase(int v) { parameters_cloud->cloudbase=v/100.0f; } void setWeatherSystems(int v) { parameters_cloud->weather_systems=v; } void regenerate_with_new_terrain_seed(); void regenerate_with_new_rivers_seed(); void regenerate_with_new_clouds_seed(); private: //! Pointer to the terrain parameters we control. ParametersTerrain*const parameters_terrain; //! Pointer to the cloud parameters we control. ParametersCloud*const parameters_cloud; //! Requests to regenerate terrain are forwarded to the top level GUI widget. FracplanetMain* regenerate_target; QComboBox* object_type_combo_box; QLabel* base_height_label; QSpinBox* base_height_spinbox; QLabel* terrain_seed_label; QSpinBox* terrain_seed_spinbox; QLabel* subdivisions_label; QSpinBox* subdivisions_spinbox; QLabel* subdivisions_unperturbed_label; QSpinBox* subdivisions_unperturbed_spinbox; QLabel* variation_vertical_label; QSpinBox* variation_vertical_spinbox; QLabel* variation_horizontal_label; QSpinBox* variation_horizontal_spinbox; QLabel* noise_terms_label; QSpinBox* noise_terms_spinbox; QLabel* noise_frequency_label; QSpinBox* noise_frequency_spinbox; QLabel* noise_amplitude_label; QSpinBox* noise_amplitude_spinbox; QLabel* noise_amplitude_decay_label; QSpinBox* noise_amplitude_decay_spinbox; QLabel* power_law_label; QSpinBox* power_law_spinbox; QLabel* snowline_equator_label; QSpinBox* snowline_equator_spinbox; QLabel* snowline_pole_label; QSpinBox* snowline_pole_spinbox; QLabel* snowline_power_law_label; QSpinBox* snowline_power_law_spinbox; QLabel* snowline_slope_effect_label; QSpinBox* snowline_slope_effect_spinbox; QLabel* snowline_glacier_effect_label; QSpinBox* snowline_glacier_effect_spinbox; QLabel* rivers_label; QSpinBox* rivers_spinbox; QLabel* rivers_seed_label; QSpinBox* rivers_seed_spinbox; QLabel* lake_becomes_sea_label; QSpinBox* lake_becomes_sea_spinbox; QSpinBox* oceans_and_rivers_emissive_spinbox; QLabel* clouds_seed_label; QSpinBox* clouds_seed_spinbox; QLabel* colour_label; QPushButton* colour_ocean_button; QPushButton* colour_shoreline_button; QPushButton* colour_low_button; QPushButton* colour_river_button; QPushButton* colour_snow_button; QPushButton* colour_high_button; QPushButton* colour_cloud_button; QCheckBox* clouds_subdivisions_unlock_checkbox; QSpinBox* clouds_subdivisions_spinbox; QPushButton* regenerate_button; QPushButton* regenerate_with_new_terrain_seed_button; QPushButton* regenerate_with_new_rivers_seed_button; QPushButton* regenerate_with_new_clouds_seed_button; QWidget* padding; }; #endif fracplanet/parameters_cloud.h0000644000175100017510000000403411261123520016233 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ParametersCloud. */ #ifndef _parameters_cloud_h_ #define _parameters_cloud_h_ #include "parameters_object.h" #include "rgb.h" #include "xyz.h" //! This class aggregates the controllable parameters for all things related to cloud generation. class ParametersCloud : public ParametersObject { public: //! Constructor sets up some hopefully sensible defaults. ParametersCloud(); //! Destructor ~ParametersCloud(); //! Whether clouds will be generated. bool enabled; //! Height of base of clouds float cloudbase; //! Number of weather systems uint weather_systems; //! Colour for clouds FloatRGBA colour; }; #endif fracplanet/control_save.h0000644000175100017510000000377411261123520015412 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ControlSave. */ #ifndef _control_save_h_ #define _control_save_h_ #include "control.h" #include "parameters_save.h" class FracplanetMain; //! Encapsulates GUI elements for controlling save. class ControlSave : public Control { private: Q_OBJECT public: ControlSave(FracplanetMain* save_target,ParametersSave* param); ~ControlSave(); public slots: void setAtmosphere(int v); void setSeaSphere(int v); void setPerVertexAlpha(int v); void setTextureShaded(int v); void setTextureHeight(int v); private: //! The parameters set we control ParametersSave*const parameters; }; #endif fracplanet/noise.h0000644000175100017510000000437211261123520014024 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface to Noise class. */ #ifndef _noise_h_ #define _noise_h_ #include "xyz.h" //! Perlin noise generator. class Noise { public: //! Constructor. Noise(uint seed); //! Destructor. ~Noise(); //! Return noise value at a point. float operator()(const XYZ& p) const; protected: //! Number of table entries. enum {N=256}; int _p[2*N+2]; XYZ _g[2*N+2]; }; //! Multiscale noise generator. class MultiscaleNoise { public: //! Constructor. MultiscaleNoise(uint seed,uint terms,float decay); //! Destructor. ~MultiscaleNoise(); //! Return noise value at a point. float operator()(const XYZ& p) const; private: //! Number of terms const uint _terms; //! Noise functions for each frequency. boost::scoped_array > _noise; //! Amplitude for each frequency. boost::scoped_array _amplitude; }; #endif fracplanet/control_render.h0000644000175100017510000000454111262220434015727 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ControlRender. */ #ifndef _control_render_h_ #define _control_render_h_ #include "control.h" #include "parameters_render.h" //! Encapsulates GUI elements for controlling OpenGL rendering. class ControlRender : public Control { private: Q_OBJECT; public: ControlRender(ParametersRender* param); ~ControlRender(); public slots: void setWireframe(int v); void setDisplayList(int v); void setJoystickMouse(int v); void setAmbient(int v); void setIlluminationAzimuth(int v); void setIlluminationElevation(int v); void pickBackgroundColourLow(); void pickBackgroundColourHigh(); private: //! The parameter set being controlled. ParametersRender*const parameters; QCheckBox* wireframe; QCheckBox* display_list; QCheckBox* joystick_mouse; QSlider* ambient; QSlider* illumination_azimuth; QSlider* illumination_elevation; QPushButton* background_colour_low_button; QPushButton* background_colour_high_button; }; #endif fracplanet/scan.h0000644000175100017510000000561711261123520013636 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for classes for scan conversion. */ #ifndef _scan_h_ #define _scan_h_ #include "xyz.h" //! Encapsulates information needed for scan conversion. /*! We want to be independent of what quantity the client is going to interpolate over, so the best we can do is identify (by index in given triangle) the vertices delimiting an edge and give the weights. */ class ScanEdge { public: ScanEdge() {} ScanEdge(float vx,uint v0,uint v1,float l) :x(vx) ,vertex0(v0) ,vertex1(v1) ,lambda(l) {} float x; uint vertex0; uint vertex1; float lambda; }; class ScanConvertBackend; class ScanConverter { public: ScanConverter() {} virtual ~ScanConverter() {} //! Set-up for scan conversion of given vertices to the given map. /* Scan conversion output is a series of [,) open intervals with vertex identifiers and weightings for each end. */ virtual void scan_convert ( const boost::array& v, const ScanConvertBackend& ) const =0; }; class ScanConvertBackend { public: ScanConvertBackend(int w,int h) :_width(w) ,_height(h) {} virtual ~ScanConvertBackend() {} int width() const { return _width; } int height() const { return _height; } virtual void scan_convert_backend(uint y,const ScanEdge& edge0,const ScanEdge& edge1) const =0; virtual void subdivide(const boost::array&,const XYZ&,const ScanConverter&) const =0; private: const int _width; const int _height; }; #endif fracplanet/precompiled.h0000644000175100017510000000267011261123520015211 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #ifndef _precompiled_h_ #define _precompiled_h_ #include "common.h" #endif fracplanet/triangle_mesh_cloud.h0000644000175100017510000000633611261123520016720 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class TriangleMeshCloud and derived classes. */ #ifndef _triangle_mesh_cloud_h_ #define _triangle_mesh_cloud_h_ #include "image.h" #include "parameters_cloud.h" #include "triangle_mesh.h" //! This class holds all the cloud-related methods. /*! It's intended to be used as a "mix-in", adding cloud generating functionality to cloud objects subclassed from simpler geometries. \todo Ugh!!! This is really yucky use of multiple inheritance. Better for these terrain types to have-a TriangleMesh. */ class TriangleMeshCloud : virtual public TriangleMesh { public: //! Constructor. TriangleMeshCloud(Progress* progress); //! Destructor. ~TriangleMeshCloud(); //! Dump mesh to file for POV-Ray void write_povray(std::ofstream& out,const ParametersSave&,const ParametersCloud&) const; //! Dump mesh to file for Blender void write_blender(std::ofstream& out,const ParametersSave&,const ParametersCloud&,const std::string& mesh_name) const; //! Render the mesh onto a raster image. /*! The only interesting thing with clouds is their alpha, so render a greyscale. */ void render_texture(Raster&) const; protected: void do_cloud(const ParametersCloud& parameters); }; //! Class constructing specific case of a planetary cloud. class TriangleMeshCloudPlanet : public TriangleMeshSubdividedIcosahedron, virtual public TriangleMeshCloud { public: //! Constructor. TriangleMeshCloudPlanet(const ParametersCloud& param,Progress* progress); //! Destructor. ~TriangleMeshCloudPlanet() {} }; //! Class constructing specific case of a flat-base terrain area. class TriangleMeshCloudFlat : public TriangleMeshFlat, virtual public TriangleMeshCloud { public: //! Constructor. TriangleMeshCloudFlat(const ParametersCloud& parameters,Progress* progress); //! Destructor. ~TriangleMeshCloudFlat() {} }; #endif fracplanet/image.h0000644000175100017510000002256511261123520013775 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface (and implementation) for templated Image class. */ #ifndef _image_h_ #define _image_h_ #include "rgb.h" class Progress; //! Class to support specialisation for particular pixel formats template class PixelTraits { public: typedef T ComputeType; typedef T ScalarType; static ScalarType scalar(const T& v) {return v;} }; template<> class PixelTraits { public: typedef float ComputeType; typedef uchar ScalarType; static ScalarType scalar(const uchar& v) {return v;} }; template<> class PixelTraits { public: typedef float ComputeType; typedef ushort ScalarType; static ScalarType scalar(const ushort& v) {return v;} }; template<> class PixelTraits { public: typedef FloatRGBA ComputeType; typedef float ScalarType; static ScalarType scalar(const ByteRGBA& v) {return (static_cast(v.r)+static_cast(v.g)+static_cast(v.b))/3.0f;} }; //! Class for 2D raster images of a specified type. /*! Assumes explicit instantiation. NB The base type just refers to storage allocated elsewhere. Used to be gratuitously implemented using boost multiarray type, but that was too inefficient This is still pretty bad byt gcc 4.1 seems to do a very nice job with -O2. */ template class Raster { public: typedef typename PixelTraits::ComputeType ComputeType; typedef typename PixelTraits::ScalarType ScalarType; static const ScalarType scalar(const T& v) {return PixelTraits::scalar(v);} Raster(uint w,uint h,uint p,T* d) :_width(w) ,_height(h) ,_pitch(p) ,_data(d) ,_row_end(row_range(h),p) ,_const_row_end(row_range(h),p) {} virtual ~Raster() {} uint width() const { return _width; } uint height() const { return _height; } uint pitch() const { return _pitch; } bool contiguous() const { return (_width==_pitch); } uint contiguous_size() const { assert(contiguous()); return _width*_height; } T* contiguous_begin() { assert(contiguous()); return _data; } const T* contiguous_begin() const { assert(contiguous()); return _data; } T* contiguous_end() { assert(contiguous()); return _data+contiguous_size(); } const T* contiguous_end() const { assert(contiguous()); return _data+contiguous_size(); } T* row(uint r) { return _data+r*_pitch; } const T* row(uint r) const { return _data+r*_pitch; } boost::iterator_range row_range(uint r) { T*const it=row(r); return boost::iterator_range(it,it+_width); } boost::iterator_range row_range(uint r) const { const T*const it=row(r); return boost::iterator_range(it,it+_width); } class RowIterator : public std::iterator > { public: RowIterator(const boost::iterator_range& row, uint p) :_row(row) ,_pitch(p) {} ~RowIterator() {} RowIterator& operator=(const RowIterator& it) { _row=it._row; assert(_pitch==it._pitch); return (*this); } bool operator==(const RowIterator& it) const { return _row.begin()==it._row.begin(); } bool operator!=(const RowIterator& it) const { return _row.begin()!=it._row.begin(); } RowIterator& operator++() { _row=boost::iterator_range ( _row.begin()+_pitch, _row.end()+_pitch ); return (*this); } RowIterator operator++(int) { RowIterator tmp(*this); _row=boost::iterator_range ( _row.begin()+_pitch, _row.end()+_pitch ); return tmp; } boost::iterator_range& operator*() { return _row; } boost::iterator_range* operator->() { return &_row; } private: boost::iterator_range _row; const uint _pitch; }; RowIterator row_begin() { return RowIterator(row_range(0),_pitch); } RowIterator row_end() { return _row_end; } class ConstRowIterator : public std::iterator > { public: ConstRowIterator(const boost::iterator_range& row, uint p) :_row(row) ,_pitch(p) {} ~ConstRowIterator() {} ConstRowIterator& operator=(const ConstRowIterator& it) { _row=it._row; assert(_pitch==it._pitch); return (*this); } bool operator==(const ConstRowIterator& it) const { return _row.begin()==it._row.begin(); } bool operator!=(const ConstRowIterator& it) const { return _row.begin()!=it._row.begin(); } ConstRowIterator& operator++() { _row=boost::iterator_range ( _row.begin()+_pitch, _row.end()+_pitch ); return (*this); } ConstRowIterator operator++(int) { ConstRowIterator tmp(*this); _row=boost::iterator_range ( _row.begin()+_pitch, _row.end()+_pitch ); return tmp; } boost::iterator_range& operator*() { return _row; } boost::iterator_range* operator->() { return &_row; } private: boost::iterator_range _row; const uint _pitch; }; ConstRowIterator row_begin() const { return ConstRowIterator(row_range(0),_pitch); } ConstRowIterator row_end() const { return _const_row_end; } //! Clear the image to a constant value. void fill(const T& v); const ScalarType maximum_scalar_pixel_value() const; //! Fill a line segment on the given half-open range [x0,x1), interpolating between the two given values. void scan(uint y,float x0,const ComputeType& v0,float x1,const ComputeType& v1); //! Variant scan, interpolates between two values then process them through function before template void scan(uint y,float x0,const V& v0,float x1,const V& v1,const boost::function& fn); bool write_ppmfile(const std::string&,Progress*) const; bool write_pgmfile(const std::string&,Progress*) const; private: const uint _width; const uint _height; const uint _pitch; T*const _data; const RowIterator _row_end; const ConstRowIterator _const_row_end; }; /*! Scan x0 to x1 into image. Pixel centres are at 0.5 , so x0=0.75 goes to pixel 1. Rightmost pixel is at width()-0.5. */ template inline void Raster::scan(uint y,float x0,const ComputeType& v0,float x1,const ComputeType& v1) { assert(x0<=x1); if (x1<0.5f || width()-0.5f(std::max(0.0f ,ceilf(x0-0.5f))); const int ix_max=static_cast(std::min(width()-0.5f,floorf(x1-0.5f))); const ComputeType kv((v1-v0)/(x1-x0)); T*const row_ptr=row(y); for (int ix=ix_min;ix<=ix_max;ix++) { const ComputeType v(v0+kv*(ix+0.5f-x0)); row_ptr[ix]=static_cast(v); } } template template inline void Raster::scan(uint y,float x0,const V& v0,float x1,const V& v1,const boost::function& fn) { assert(x0<=x1); if (x1<0.5f || width()-0.5f(std::max(0.0f ,ceilf(x0-0.5f))); const int ix_max=static_cast(std::min(width()-0.5f,floorf(x1-0.5f))); const V kv((v1-v0)/(x1-x0)); T*const row_ptr=row(y); for (int ix=ix_min;ix<=ix_max;ix++) { const ComputeType v(fn(v0+kv*(ix+0.5f-x0))); row_ptr[ix]=static_cast(v); } } template class ImageStorage { public: ImageStorage(int n) :_storage(new T[n]) {} ~ImageStorage() {} protected: boost::scoped_array _storage; }; template class Image : private ImageStorage, public Raster, public boost::noncopyable { public: Image(uint w,uint h) :ImageStorage(w*h) ,Raster(w,h,w,ImageStorage::_storage.get()) {} ~Image() {} }; #endif fracplanet/common.h0000644000175100017510000001031711261470632014204 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #ifndef _common_h_ #define _common_h_ extern "C" { #include #include } #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GL_GLEXT_PROTOTYPES #include #include #include #define stringify(S) __STRING(S) typedef unsigned int uint; typedef unsigned short ushort; typedef unsigned char uchar; template inline const T maximum(T a,T b) {return (a>b ? a : b);} template inline const T minimum(T a,T b) {return (a inline const T maximum(T a,T b,T c) {return maximum(a,maximum(b,c));} template inline const T minimum(T a,T b,T c) {return minimum(a,minimum(b,c));} template inline const T maximum(T a,T b,T c,T d) {return maximum(maximum(a,b),maximum(c,d));} template inline const T minimum(T a,T b,T c,T d) {return minimum(minimum(a,b),minimum(c,d));} template inline const T sqr(T a) {return a*a;} template inline const T clamped(T v,T lo,T hi) {return (vhi ? hi : v));} template inline void clamp(T& v,T lo,T hi) {v=(vhi ? hi : v));} template inline void exchange(T& a,T& b) {const T x(a);a=b;b=x;} extern void fatal_error(const char*); inline void fatal_error(const std::string& s) { fatal_error(s.c_str()); } extern void fatal_internal_error(const char* src_file,uint src_line); extern void constraint_violation(const char* test,const char* src_file,uint src_line); #define constraint(TEST) {if (!TEST) {constraint_violation(#TEST,__FILE__,__LINE__);}} #endif fracplanet/parameters_render.h0000644000175100017510000000500711261123520016405 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class ParametersRender. */ #ifndef _parameters_render_h_ #define _parameters_render_h_ #include "rgb.h" class XYZ; //! Aggregates controllable parameters for all things related to OpenGL rendering. class ParametersRender { public: //! Constructor. ParametersRender(const boost::program_options::variables_map& opts); //! Destructor. ~ParametersRender(); //! Flag selecting OpenGL wireframe rendering. bool wireframe; //! Render via display list bool display_list; //! Joystick mode for flight bool joystick_mouse; //! Amount of global ambient illumination (0-1) float ambient; //! Controls illumination direction. float illumination_azimuth; //! Controls illumination direction. float illumination_elevation; //! Background colour at low altitude FloatRGBA background_colour_low; //! Background colour at high altitude FloatRGBA background_colour_high; //! Target frame rate float fps_target; //! Illumination direction computed from azimuth and elevation angles const XYZ illumination_direction() const; static boost::program_options::options_description options(); }; #endif fracplanet/triangle_mesh_viewer_display.h0000644000175100017510000000721711262220434020642 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class TriangleMeshViewerDisplay. */ #ifndef _triangle_mesh_viewer_display_h_ #define _triangle_mesh_viewer_display_h_ #include "parameters_render.h" #include "random.h" #include "triangle_mesh.h" class TriangleMeshViewer; //! Contains the actual rendering functionality of a TriangleMeshViewer. class TriangleMeshViewerDisplay : public QGLWidget { private: Q_OBJECT; public: //! Constructor. TriangleMeshViewerDisplay(TriangleMeshViewer* parent,const QGLFormat& format,const ParametersRender* param,const std::vector& m,bool verbose ); //! Destructor ~TriangleMeshViewerDisplay(); //! Specify a minimum size QSize minimumSizeHint() const; //! Guideline size QSize sizeHint() const; //! Set the mesh being rendered. void set_mesh(const std::vector& m); protected: //! Called to repaint GL area. void paintGL(); //! Set up OpenGL. void initializeGL(); //! Deal with resize. void resizeGL(int w,int h); public slots: //! Called to redisplay scene void draw_frame(const XYZ& p,const XYZ& l,const XYZ& u,float r,float t); private: //! Need to know this to update framerate text TriangleMeshViewer& _notify; //! Control logging const bool _verbose; //! The meshes being displayed. /*! NB NOT owned here */ std::vector mesh; //! Pointer to the rendering parameters. const ParametersRender* parameters; //! GL display list index /*! Zero is not a valid value according to red book, so use zero to designate unset */ uint gl_display_list_index; //! Frame count. uint frame_number; //! Display area width. uint width; //! Display area height. uint height; //! Time frames for FPS measurement. QTime frame_time; //! Time since FPS last reported. QTime frame_time_reported; //! Queue of frame times to average. std::deque frame_times; //@{ //! Parameter of camera position. XYZ camera_position; XYZ camera_lookat; XYZ camera_up; //@} //@{ //! Parameters of object float object_tilt; float object_rotation; //@} void check_for_gl_errors(const char*) const; //! Compute background colour from render parameters and camera height const FloatRGBA background_colour() const; }; #endif fracplanet/control.h0000644000175100017510000000357311261123520014371 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Interface for class Control. */ #ifndef _control_h_ #define _control_h_ #include "rgb.h" //! Base class for other controls; useful for shared stuff. class Control : public QWidget { public: Control(); ~Control(); //! Use Qt's colour-picking dialog to replace the referenced colour void pickColour(QPushButton* button,FloatRGBA& colour); protected: //! Utility function to build a small Qt icon of the specified colour. static QIcon build_icon_of_colour(const FloatRGBA& col); }; #endif fracplanet/control_save.cpp0000644000175100017510000001310411261123520015731 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "control_save.h" #include "fracplanet_main.h" ControlSave::ControlSave(FracplanetMain* save_target,ParametersSave* param) :Control() ,parameters(param) { QTabWidget*const tabs=new QTabWidget(); layout()->addWidget(tabs); QWidget*const tab_pov=new QWidget(); tabs->addTab(tab_pov,"POV-Ray"); tab_pov->setLayout(new QVBoxLayout()); QCheckBox*const atmosphere_checkbox=new QCheckBox("Add atmosphere"); tab_pov->layout()->addWidget(atmosphere_checkbox); atmosphere_checkbox->setChecked(parameters->pov_atmosphere); atmosphere_checkbox->setToolTip("Select to add an atmosphere"); connect( atmosphere_checkbox,SIGNAL(stateChanged(int)), this,SLOT(setAtmosphere(int)) ); QCheckBox*const sea_object_checkbox=new QCheckBox("Sea as single object"); tab_pov->layout()->addWidget(sea_object_checkbox); sea_object_checkbox->setChecked(parameters->pov_sea_object); sea_object_checkbox->setToolTip("Select to emit a single object (instead of multiple triangles) for the sea surface"); connect( sea_object_checkbox,SIGNAL(stateChanged(int)), this,SLOT(setSeaSphere(int)) ); QPushButton*const save_pov=new QPushButton("Save for POV-Ray"); tab_pov->layout()->addWidget(save_pov); save_pov->setToolTip("Press to save object for POV-Ray"); connect( save_pov,SIGNAL(clicked()), save_target,SLOT(save_pov()) ); QWidget*const tab_blender=new QWidget(); tabs->addTab(tab_blender,"Blender"); tab_blender->setLayout(new QVBoxLayout()); QCheckBox*const per_vertex_alpha=new QCheckBox("Use per-vertex alpha (for clouds)"); tab_blender->layout()->addWidget(per_vertex_alpha); per_vertex_alpha->setChecked(parameters->blender_per_vertex_alpha); per_vertex_alpha->setToolTip("Unfortunately Blender seems to ignore alpha components supplied with per-vertex\ncolours so a workround is normally used.\nCheck this box to save as if per-vertex alpha worked."); connect( per_vertex_alpha,SIGNAL(stateChanged(int)), this,SLOT(setPerVertexAlpha(int)) ); QPushButton*const save_blender=new QPushButton("Save for Blender"); tab_blender->layout()->addWidget(save_blender); save_blender->setToolTip("Press to save object for Blender"); connect( save_blender,SIGNAL(clicked()), save_target,SLOT(save_blender()) ); QWidget*const tab_texture=new QWidget(); tabs->addTab(tab_texture,"Texture"); tab_texture->setLayout(new QVBoxLayout()); QCheckBox*const shaded_checkbox=new QCheckBox("Shaded texture"); tab_texture->layout()->addWidget(shaded_checkbox); shaded_checkbox->setChecked(parameters->texture_shaded); shaded_checkbox->setToolTip("Check to have the texture include relief shading"); connect( shaded_checkbox,SIGNAL(stateChanged(int)), this,SLOT(setTextureShaded(int)) ); QWidget*const grid_texture=new QWidget(); tab_texture->layout()->addWidget(grid_texture); QGridLayout* grid_layout=new QGridLayout(); grid_texture->setLayout(grid_layout); grid_layout->addWidget(new QLabel("Texture height",grid_texture),0,0); QSpinBox* texture_height_spinbox=new QSpinBox(); grid_layout->addWidget(texture_height_spinbox,0,1); texture_height_spinbox->setMinimum(1); texture_height_spinbox->setMaximum(0x7fffffff); texture_height_spinbox->setValue(1024); texture_height_spinbox->setToolTip("Texture height in pixels; the texture width is the same as the height\nexcept for spherical geometry (planets) when it is double."); connect( texture_height_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setTextureHeight(int)) ); QPushButton*const save_texture=new QPushButton("Save as texture"); tab_texture->layout()->addWidget(save_texture); save_texture->setToolTip("Press to save object as textures"); connect( save_texture,SIGNAL(clicked()), save_target,SLOT(save_texture()) ); } ControlSave::~ControlSave() {} void ControlSave::setAtmosphere(int v) { parameters->pov_atmosphere=(v==2); } void ControlSave::setSeaSphere(int v) { parameters->pov_sea_object=(v==2); } void ControlSave::setPerVertexAlpha(int v) { parameters->blender_per_vertex_alpha=(v==2); } void ControlSave::setTextureShaded(int v) { parameters->texture_shaded=(v==2); } void ControlSave::setTextureHeight(int v) { parameters->texture_height=v; } fracplanet/control_about.cpp0000644000175100017510000000552311262220434016116 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "control_about.h" #include "license.h" #include "dialog_documentation.h" ControlAbout::ControlAbout(QApplication* app) :Control() { QLabel*const label0=new QLabel("\nFracplanet - version "+QString(stringify(FRACPLANET_VERSION))); layout()->addWidget(label0); label0->setAlignment(Qt::AlignHCenter|label0->alignment()); QFont label0_font(QApplication::font()); label0_font.setBold(true); label0->setFont(label0_font); QLabel*const label1=new QLabel("by timday@timday.com\nhttp://fracplanet.sourceforge.net"); layout()->addWidget(label1); label1->setAlignment(Qt::AlignHCenter|label0->alignment()); QFont label1_font(QApplication::font()); label1_font.setPointSize(std::max(2,label1_font.pointSize()-1)); label1->setFont(label1_font); DialogDocumentation*const dialog_docs=new DialogDocumentation(this); QPushButton*const button_docs=new QPushButton("Show documentation"); layout()->addWidget(button_docs); connect(button_docs,SIGNAL(clicked()),dialog_docs,SLOT(show())); QLabel*const label2=new QLabel("Fracplanet License:"); layout()->addWidget(label2); label2->setAlignment(Qt::AlignHCenter|label0->alignment()); QTextEdit*const license=new QTextEdit(); layout()->addWidget(license); license->setReadOnly(true); license->setText(license_string); QPushButton*const button_about_qt=new QPushButton("About Qt"); layout()->addWidget(button_about_qt); connect(button_about_qt,SIGNAL(clicked()),app,SLOT(aboutQt())); } fracplanet/vertex.cpp0000644000175100017510000000263111261123520014553 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "vertex.h" fracplanet/parameters_save.cpp0000644000175100017510000000324511261123520016421 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "parameters_save.h" ParametersSave::ParametersSave(const ParametersRender* pr) :pov_atmosphere(false) ,pov_sea_object(true) ,blender_per_vertex_alpha(false) ,texture_shaded(false) ,texture_height(1024) ,parameters_render(pr) {} ParametersSave::~ParametersSave() {} fracplanet/matrix34.cpp0000644000175100017510000000375011261123520014714 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "matrix34.h" Matrix34RotateAboutAxisThrough::Matrix34RotateAboutAxisThrough(const XYZ& axis,float angle,const XYZ& pt) { assign ( Matrix34Translate(pt) *Matrix34(Matrix33RotateAboutAxis(axis,angle),XYZ(0.0f,0.0f,0.0f)) *Matrix34Translate(-pt) ); } Matrix34RotateAboutAxisThrough::Matrix34RotateAboutAxisThrough(const XYZ& axis,const XYZ& pt) { const float axis_magnitude=axis.magnitude(); if (axis_magnitude==0.0f) { assign(Matrix34Identity()); } else { assign(Matrix34RotateAboutAxisThrough(axis/axis_magnitude,axis_magnitude,pt)); } } fracplanet/common.cpp0000644000175100017510000000371511261123520014532 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "common.h" void fatal_error(const char* msg) { std::cerr << "\n*** Fatal error: " << msg << " ***\n"; exit(1); } void fatal_internal_error(const char* src_file,uint src_line) { std::cerr << "\n*** Fatal internal error in " << src_file << " at line " << src_line << " ***\n"; exit(1); } void constraint_violation(const char* test,const char* src_file,uint src_line) { std::cerr << "\n*** Constraint \"" << test << "\" violated in file" << src_file << " at line " << src_line << " ***\n"; exit(1); } fracplanet/parameters_cloud.cpp0000644000175100017510000000313511261123520016567 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "parameters_cloud.h" ParametersCloud::ParametersCloud() :ParametersObject() ,enabled(false) ,cloudbase(0.1) ,weather_systems(0) ,colour(1.0,1.0,1.0,1.0) {} ParametersCloud::~ParametersCloud() {} fracplanet/spinbox.cpp0000644000175100017510000000305111261123520014715 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "spinbox.h" SpinBox::SpinBox(int lo,int hi,int step) :QSpinBox() { setMinimum(lo); setMaximum(hi); setSingleStep(step); } SpinBox::~SpinBox() {} fracplanet/triangle_mesh.cpp0000644000175100017510000003316611261123520016066 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "triangle_mesh.h" TriangleMesh::TriangleMesh(Progress* progress) :_triangle_switch_colour(0) ,_emissive(0.0) ,_progress(progress) {} TriangleMesh::~TriangleMesh() {} void TriangleMesh::progress_start(uint steps,const std::string& info) const { if (_progress) _progress->progress_start(steps,info); } void TriangleMesh::progress_stall(const std::string& reason) const { if (_progress) _progress->progress_stall(reason); } void TriangleMesh::progress_step(uint step) const { if (_progress) _progress->progress_step(step); } void TriangleMesh::progress_complete(const std::string& info) const { if (_progress) _progress->progress_complete(info); } const XYZ TriangleMesh::triangle_normal(uint i) const { const Triangle& t=triangle(i); const XYZ& v0=vertex(t.vertex(0)).position(); const XYZ& v1=vertex(t.vertex(1)).position(); const XYZ& v2=vertex(t.vertex(2)).position(); const XYZ n((v1-v0)*(v2-v0)); return n.normalised(); } void TriangleMesh::compute_vertex_normals() { const uint steps=triangles()+vertices(); uint step=0; progress_start(100,"Compute normals"); { std::vector > vertices_to_triangles(vertices()); for (uint i=0;i old_vertex; old_vertex.swap(_vertex); std::vector old_triangle; old_triangle.swap(_triangle); // Copy back all vertices and perturb for (uint v=0;v EdgeMap; EdgeMap edge_map; // Create new vertices and new triangles for (uint t=0;t"; out << "," << triangle(t).vertex(0)+(t byte_faux_alpha; if (faux_alpha) byte_faux_alpha=std::auto_ptr(new ByteRGBA(*faux_alpha)); const uint steps=vertices()+triangles(); uint step=0; { std::ostringstream msg; msg << "Writing mesh " << mesh_name << " to Blender file"; progress_start(100,msg.str()); } out << "mat0=Material.New()\n"; out << "mat0.rgbCol=[0.0,1.0,0.0]\n"; out << "mat0.mode=Material.Modes.VCOL_PAINT\n"; out << "\n"; out << "mat1=Material.New()\n"; out << "mat1.rgbCol=[0.0,0.0,1.0]\n"; out << "mat1.mode=Material.Modes.VCOL_PAINT\n"; out << "\n"; out << "m=NMesh.GetRaw()\n"; out << "m.materials.append(mat0)\n"; out << "m.materials.append(mat1)\n"; out << "m.hasVertexColours(1)\n"; out << "\n"; for (uint v=0;v(c.a); return ByteRGBA ( (ia*c.r+(255-ia)*f->r)/255, (ia*c.g+(255-ia)*f->g)/255, (ia*c.b+(255-ia)*f->b)/255, 255 ); } else return c; } TriangleMeshFlat::TriangleMeshFlat(ParametersObject::ObjectType obj,float z,uint seed,Progress* progress) :TriangleMesh(progress) ,_geometry(seed) { switch(obj) { case ParametersObject::ObjectTypeFlatTriangle: for (uint i=0;i<3;i++) { add_vertex(Vertex(XYZ(cos(i*2.0*M_PI/3.0),sin(i*2.0*M_PI/3.0),z))); } add_triangle(Triangle(0,1,2)); break; case ParametersObject::ObjectTypeFlatSquare: add_vertex(Vertex(XYZ( 0.0, 0.0,z))); add_vertex(Vertex(XYZ( 1.0, 1.0,z))); add_vertex(Vertex(XYZ(-1.0, 1.0,z))); add_vertex(Vertex(XYZ(-1.0,-1.0,z))); add_vertex(Vertex(XYZ( 1.0,-1.0,z))); for (uint i=0;i<4;i++) { add_triangle(Triangle(0,1+i,1+(i+1)%4)); } break; case ParametersObject::ObjectTypeFlatHexagon: default: add_vertex(Vertex(XYZ(0.0,0.0,z))); for (uint i=0;i<6;i++) { add_vertex(Vertex(XYZ(cos(i*M_PI/3.0),sin(i*M_PI/3.0),z))); } for (uint i=0;i<6;i++) { add_triangle(Triangle(0,1+i,1+(i+1)%6)); } break; } } TriangleMeshIcosahedron::TriangleMeshIcosahedron(float radius,uint seed,Progress* progress) :TriangleMesh(progress) ,_geometry(seed) { const float x=0.525731112119133606; const float z=0.850650808352039932; const float vdata[12][3]= { { -x,0.0, z}, { x,0.0, z}, { -x,0.0, -z}, { x,0.0, -z}, {0.0, z, x}, {0.0, z, -x}, {0.0, -z, x}, {0.0, -z, -x}, { z, x,0.0}, { -z, x,0.0}, { z, -x,0.0}, { -z, -x,0.0} }; for (uint v=0;v<12;v++) add_vertex(Vertex(radius*XYZ(vdata[v][0],vdata[v][1],vdata[v][2]).normalised())); uint tindices[20][3]= { { 0, 4, 1}, { 0, 9, 4}, { 9, 5, 4}, { 4, 5, 8}, { 4, 8, 1}, { 8,10, 1}, { 8, 3,10}, { 5, 3, 8}, { 5, 2, 3}, { 2, 7, 3}, { 7,10, 3}, { 7, 6,10}, { 7,11, 6}, {11, 0, 6}, { 0, 1, 6}, { 6, 1,10}, { 9, 0,11}, { 9,11, 2}, { 9, 2, 5}, { 7, 2,11} }; for (uint t=0;t<20;t++) add_triangle(Triangle(tindices[t][2],tindices[t][1],tindices[t][0])); } TriangleMeshSubdividedIcosahedron::TriangleMeshSubdividedIcosahedron(float radius,uint subdivisions,uint flat_subdivisions,uint seed,const XYZ& variation,Progress* progress) :TriangleMesh(progress) ,TriangleMeshIcosahedron(radius,seed,progress) { subdivide(subdivisions,flat_subdivisions,variation); } fracplanet/triangle.cpp0000644000175100017510000000263311261123520015045 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "triangle.h" fracplanet/xyz.cpp0000644000175100017510000000612411261123520014071 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "xyz.h" /*! Table so we can look up by element number. */ XYZ::ElementPtr XYZ::element_table[3]={&XYZ::x,&XYZ::y,&XYZ::z}; std::ostream& XYZ::write(std::ostream& out) const { return out << x << " " << y << " " << z; } const std::string XYZ::format_comma() const { std::ostringstream s; s << x << "," << y << "," << z; return s.str(); } const std::string XYZ::format_blender() const { std::ostringstream s; s << x << "," << y << "," << z; return s.str(); } /*! Also transposes y and z co-ordinates because of POV-Rays idea of up. */ const std::string XYZ::format_pov() const { std::ostringstream s; s << "<" << x << "," << z << "," << y << ">"; return s.str(); } RandomXYZInUnitCube::RandomXYZInUnitCube(Random01& rng) :XYZ() { x=rng(); y=rng(); z=rng(); } RandomXYZInBox::RandomXYZInBox(Random01& rng,const XYZ& bounds) :XYZ() { x=-bounds.x+2.0*bounds.x*rng(); y=-bounds.y+2.0*bounds.y*rng(); z=-bounds.z+2.0*bounds.z*rng(); } RandomXYZInSphere::RandomXYZInSphere(Random01& rng,float radius) :XYZ() { do { x=2.0*rng()-1.0; y=2.0*rng()-1.0; z=2.0*rng()-1.0; } while (magnitude2()>1.0); (*this)*=radius; } /*! Can handle case of individual axes being zero. */ RandomXYZInEllipsoid::RandomXYZInEllipsoid(Random01& rng,const XYZ& axes) :XYZ() { do { assign(RandomXYZInBox(rng,axes)); } while ( (axes.x==0.0 ? 0.0 : sqr(x/axes.x)) +(axes.y==0.0 ? 0.0 : sqr(y/axes.y)) +(axes.z==0.0 ? 0.0 : sqr(z/axes.z)) >1.0 ); } RandomXYZSphereNormal::RandomXYZSphereNormal(Random01& rng) :XYZ(0.0,0.0,0.0) { float m2; do { assign(RandomXYZInSphere(rng,1.0)); m2=magnitude2(); } while (m2==0.0); (*this)/=sqrtf(m2); } fracplanet/fracplanet.cpp0000644000175100017510000000657711262220434015375 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \mainpage Fracplanet : fractal terrain generator \author Tim Day \section introduction Introduction "Fracplanet" is an interactive tool for generating fractal planets and terrains. It can output the generated meshes to files suitable for use by POV-Ray. \todo For new features to be added, see the TODO file. */ #include "precompiled.h" #include "fracplanet_main.h" //! Application code /*! Currently this simply creates a TriangleMesh object of some sort, then passes it to a viewer. */ int main(int argc,char* argv[]) { QApplication app(argc,argv); boost::program_options::variables_map opts; try { boost::program_options::options_description opt_desc ("Recognised options (besides Qt standards):"); opt_desc.add_options() ("help,h","show list of recognised options") ("verbose,v","verbose output to stderr") ; opt_desc.add(ParametersRender::options()); boost::program_options::store ( boost::program_options::parse_command_line(argc,argv,opt_desc), opts ); boost::program_options::notify(opts); if (opts.count("help")) { std::cerr << opt_desc << std::endl; return 1; } } catch (boost::program_options::error& e) { std::cerr << "Bad command line: " << e.what() << std::endl; std::cerr << "Use -h or --help to list recognised options" << std::endl; return 1; } const bool verbose=opts.count("verbose"); if (verbose) std::cerr << "Setting up...\n"; FracplanetMain*const main_widget=new FracplanetMain(0,&app,opts,verbose); if (verbose) std::cerr << "...setup completed\n"; main_widget->show(); if (verbose) { std::cerr << "Fracplanet:" << std::endl; std::cerr << " sizeof(ByteRGBA) is " << sizeof(ByteRGBA) << " (4 is good)" << std::endl; std::cerr << " sizeof(Vertex) is " << sizeof(Vertex) << " (32 is good)" << std::endl; std::cerr << " sizeof(Triangle) is " << sizeof(Triangle) << " (12 is good)" << std::endl; } main_widget->regenerate(); return app.exec(); } fracplanet/triangle_mesh_viewer.cpp0000644000175100017510000002341411262220434017445 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "triangle_mesh_viewer.h" /*! The viewer will be parented on the specified widget, but with a Qt::Window flag to make it a top-level window */ TriangleMeshViewer::TriangleMeshViewer(QWidget* parent,const ParametersRender* param,const std::vector& mesh,bool verbose) :QWidget(parent,Qt::Window) ,_verbose(verbose) ,parameters(param) ,camera_position(0.0f,-3.0f,0.0f) ,camera_forward(0.0f,1.0f,0.0f) ,camera_up(0.0f,0.0f,1.0f) ,camera_velocity(0.0f) ,camera_yaw_rate(0.0f) ,camera_pitch_rate(0.0f) ,camera_roll_rate(0.0f) ,object_tilt(30.0f*M_PI/180.0f) ,object_rotation(0.0f) ,object_spinrate(0.0f) ,keypressed_arrow_left(false) ,keypressed_arrow_right(false) ,keypressed_arrow_up(false) ,keypressed_arrow_down(false) ,keypressed_mouse_left(false) ,keypressed_mouse_right(false) ,fly_mode(false) { QGridLayout*const grid=new QGridLayout(); setLayout(grid); grid->setRowStretch(0,1); grid->setColumnStretch(0,1); //! \todo Is there any good reason not to enable multisampling by default ? QGLFormat gl_format; gl_format.setSampleBuffers(true); display=new TriangleMeshViewerDisplay(this,gl_format,param,mesh,_verbose); grid->addWidget(display,0,0); tilt_box=new QGroupBox("Tilt"); tilt_box->setLayout(new QVBoxLayout()); tilt_box->layout()->setAlignment(Qt::AlignCenter); tilt_slider=new QSlider(Qt::Vertical); tilt_box->layout()->addWidget(tilt_slider); tilt_slider->setRange(-80,80); tilt_slider->setSingleStep(10); tilt_slider->setValue(30); tilt_slider->setTickInterval(10); tilt_slider->setTickPosition(QSlider::TicksBothSides); tilt_slider->setTracking(true); grid->addWidget(tilt_box,0,1); spinrate_box=new QGroupBox("Spin Rate"); spinrate_box->setLayout(new QHBoxLayout()); spinrate_box->layout()->setAlignment(Qt::AlignCenter); spinrate_slider=new QSlider(Qt::Horizontal); spinrate_box->layout()->addWidget(spinrate_slider); spinrate_slider->setRange(-80,80); spinrate_slider->setSingleStep(10); spinrate_slider->setValue(0); spinrate_slider->setTickInterval(10); spinrate_slider->setTickPosition(QSlider::TicksBothSides); spinrate_slider->setTracking(true); grid->addWidget(spinrate_box,1,0); button_box=new QWidget(); button_box->setLayout(new QVBoxLayout()); grid->addWidget(button_box,1,1); QPushButton*const fly_button=new QPushButton("Fly"); button_box->layout()->addWidget(fly_button); fly_button->setToolTip("While flying:\nEsc will return to normal view.\nMouse controls pitch and yaw.\nLeft and right mouse buttons (or left/right arrow keys) control roll.\nMouse wheel (or up/down arrow keys) control speed."); QPushButton*const reset_button=new QPushButton("Reset"); button_box->layout()->addWidget(reset_button); reset_button->setToolTip("Press to restore initial default orientation."); statusbar=new QStatusBar(); grid->addWidget(statusbar,2,0,1,2); //Calling setFocus() when switching to fly mode seems to avoid need for this, but do it anyway. tilt_slider->setFocusPolicy(Qt::NoFocus); spinrate_slider->setFocusPolicy(Qt::NoFocus); connect( tilt_slider,SIGNAL(valueChanged(int)), this,SLOT(set_tilt(int)) ); connect( spinrate_slider,SIGNAL(valueChanged(int)), this,SLOT(set_spinrate(int)) ); connect( fly_button,SIGNAL(clicked()), this,SLOT(fly()) ); connect( reset_button,SIGNAL(clicked()), this,SLOT(reset()) ); clock.reset(new QTime()); clock->start(); last_t=0; QTimer*const timer=new QTimer(this); connect(timer,SIGNAL(timeout()),this,SLOT(tick())); timer->start(static_cast(ceil(1000.0f/parameters->fps_target))); setMouseTracking(true); // To get moves regardless of button state display->setMouseTracking(true); setFocus(); } TriangleMeshViewer::~TriangleMeshViewer() {} void TriangleMeshViewer::notify(const std::string& msg) { notify_message=msg; } void TriangleMeshViewer::keyPressEvent(QKeyEvent* e) { if (fly_mode) { if (e->key()==Qt::Key_Escape) unfly(); else if (e->key()==Qt::Key_Left) keypressed_arrow_left=true; else if (e->key()==Qt::Key_Right) keypressed_arrow_right=true; else if (e->key()==Qt::Key_Up) keypressed_arrow_up=true; else if (e->key()==Qt::Key_Down) keypressed_arrow_down=true; else e->ignore(); } else { e->ignore(); } } void TriangleMeshViewer::keyReleaseEvent(QKeyEvent* e) { if (fly_mode) { if (e->key()==Qt::Key_Left) keypressed_arrow_left=false; else if (e->key()==Qt::Key_Right) keypressed_arrow_right=false; else if (e->key()==Qt::Key_Up) keypressed_arrow_up=false; else if (e->key()==Qt::Key_Down) keypressed_arrow_down=false; else e->ignore(); } else { e->ignore(); } } void TriangleMeshViewer::mousePressEvent(QMouseEvent* e) { if (fly_mode) { if (e->button()==Qt::LeftButton) keypressed_mouse_left=true; else if (e->button()==Qt::RightButton) keypressed_mouse_right=true; else if (e->button()==Qt::MidButton) camera_velocity=0.0f; else e->ignore(); } else { e->ignore(); } } void TriangleMeshViewer::mouseReleaseEvent(QMouseEvent* e) { if (fly_mode) { if (e->button()==Qt::LeftButton) keypressed_mouse_left=false; else if (e->button()==Qt::RightButton) keypressed_mouse_right=false; else e->ignore(); } else { e->ignore(); } } void TriangleMeshViewer::wheelEvent(QWheelEvent* e) { if (fly_mode) { camera_velocity+=e->delta()*(0.03125f/480.0f); } else { e->ignore(); } } inline float signedsquare(float v) { return (v<0.0f ? -v*v : v*v); } void TriangleMeshViewer::mouseMoveEvent(QMouseEvent* e) { if (fly_mode) { camera_yaw_rate=4.0f*signedsquare(e->pos().x()/static_cast(size().width())-0.5f); camera_pitch_rate=(parameters->joystick_mouse ? 1.0f : -1.0f)*4.0f*signedsquare(e->pos().y()/static_cast(size().height())-0.5f); } else { e->ignore(); } } void TriangleMeshViewer::set_mesh(const std::vector& m) { if (fly_mode) unfly(); display->set_mesh(m); } void TriangleMeshViewer::fly() { fly_mode=true; camera_velocity=0.125f; spinrate_slider->setValue(0); tilt_box->hide(); spinrate_box->hide(); button_box->hide(); setFocus(); QCursor::setPos(mapToGlobal(QPoint(width()/2,height()/2))); } void TriangleMeshViewer::unfly() { reset(); tilt_box->show(); spinrate_box->show(); button_box->show(); } void TriangleMeshViewer::reset() { fly_mode=false; camera_position=XYZ(0.0f,-3.0f,0.0f); camera_forward=XYZ(0.0f,1.0f,0.0f); camera_up=XYZ(0.0f,0.0f,1.0f); camera_velocity=0.0f; camera_yaw_rate=0.0f; camera_pitch_rate=0.0f; camera_roll_rate=0.0f; tilt_slider->setValue(30); spinrate_slider->setValue(0); object_rotation=0.0f; statusbar->clearMessage(); } void TriangleMeshViewer::tick() { const int t=clock->elapsed(); const float dt=0.001f*(t-last_t); last_t=t; camera_roll_rate=0.0f; if (keypressed_arrow_left || keypressed_mouse_left) camera_roll_rate+=0.5f; if (keypressed_arrow_right || keypressed_mouse_right) camera_roll_rate-=0.5f; if (keypressed_arrow_up) camera_velocity+=120.0f*(0.03125f/480.0f); if (keypressed_arrow_down) camera_velocity-=120.0f*(0.03125f/480.0f); //! \todo Replace cheesy rotation hacks with proper rotation matrices XYZ camera_right=(camera_forward*camera_up).normalised(); const XYZ camera_right_rolled=camera_right+(dt*camera_roll_rate)*camera_up; const XYZ camera_up_rolled=camera_up-(dt*camera_roll_rate)*camera_right; camera_right=camera_right_rolled.normalised(); camera_up=camera_up_rolled.normalised(); camera_forward=(camera_forward+dt*camera_yaw_rate*camera_right+dt*camera_pitch_rate*camera_up).normalised(); camera_up=(camera_right*camera_forward).normalised(); camera_position+=(dt*camera_velocity)*camera_forward; object_rotation+=object_spinrate*dt; if (display->isVisible()) { display->draw_frame(camera_position,camera_position+camera_forward,camera_up,object_rotation,object_tilt); } std::ostringstream msg; if (fly_mode) { msg << "Velocity:" << camera_velocity << " Roll rate:" << camera_roll_rate << " "; } msg << notify_message; statusbar->showMessage(msg.str().c_str()); } void TriangleMeshViewer::set_tilt(int v) { object_tilt=v*(M_PI/180.0); } void TriangleMeshViewer::set_spinrate(int v) { object_spinrate=v*(M_PI/180.0); } fracplanet/control_render.cpp0000644000175100017510000001471211261123520016260 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "control_render.h" ControlRender::ControlRender(ParametersRender* param) :Control() ,parameters(param) { wireframe=new QCheckBox("Wireframe"); layout()->addWidget(wireframe); wireframe->setChecked(parameters->wireframe); wireframe->setToolTip("Selects wireframe OpenGL rendering"); connect( wireframe,SIGNAL(stateChanged(int)), this,SLOT(setWireframe(int)) ); joystick_mouse=new QCheckBox("Joystick mouse-Y (fly mode)"); layout()->addWidget(joystick_mouse); joystick_mouse->setChecked(parameters->joystick_mouse); joystick_mouse->setToolTip("Mouse y-axis functions as joystick in fly mode:\nmouse moved down/pulled-back pitches up."); connect( joystick_mouse,SIGNAL(stateChanged(int)), this,SLOT(setJoystickMouse(int)) ); display_list=new QCheckBox("Display list"); layout()->addWidget(display_list); display_list->setChecked(parameters->display_list); display_list->setToolTip("Use OpenGL display lists; CAUTION: unstable on many platforms"); connect( display_list,SIGNAL(stateChanged(int)), this,SLOT(setDisplayList(int)) ); background_colour_low_button=new QPushButton(build_icon_of_colour(parameters->background_colour_low),"Background colour (low altitude)"); layout()->addWidget(background_colour_low_button); background_colour_low_button->setToolTip("Colour used in display area when the camera is low."); connect(background_colour_low_button,SIGNAL(clicked()), this,SLOT(pickBackgroundColourLow()) ); background_colour_high_button=new QPushButton(build_icon_of_colour(parameters->background_colour_high),"Background colour (high altitude)"); layout()->addWidget(background_colour_high_button); background_colour_high_button->setToolTip("Colour used in display area when the camera is high."); connect(background_colour_high_button,SIGNAL(clicked()), this,SLOT(pickBackgroundColourHigh()) ); QGroupBox* ambient_box=new QGroupBox("Ambient"); layout()->addWidget(ambient_box); ambient_box->setLayout(new QHBoxLayout()); ambient_box->layout()->addWidget(new QLabel("0.0")); ambient=new QSlider(Qt::Horizontal); ambient_box->layout()->addWidget(ambient); ambient->setMinimum(0); ambient->setValue(10); //! \todo Should be obtained from somewhere ? ambient->setMaximum(100); ambient->setTickInterval(10); ambient->setTickPosition(QSlider::TicksBothSides); ambient->setTracking(true); ambient_box->layout()->addWidget(new QLabel("1.0")); connect( ambient,SIGNAL(valueChanged(int)), this,SLOT(setAmbient(int)) ); QGroupBox* illumination_box=new QGroupBox("Illumination azimuth/elevation"); layout()->addWidget(illumination_box); illumination_box->setLayout(new QHBoxLayout()); // TODO: Need a grid here, not an hbox illumination_box->layout()->addWidget(new QLabel("-180")); illumination_azimuth=new QSlider(Qt::Horizontal); illumination_box->layout()->addWidget(illumination_azimuth); illumination_azimuth->setMinimum(-180); illumination_azimuth->setValue(static_cast(parameters->illumination_azimuth*180/M_PI)); illumination_azimuth->setMaximum(180); illumination_azimuth->setTickInterval(10); illumination_azimuth->setTickPosition(QSlider::TicksBothSides); illumination_azimuth->setTracking(true); illumination_box->layout()->addWidget(new QLabel("180")); illumination_box->layout()->addWidget(new QLabel("-90")); illumination_elevation=new QSlider(Qt::Horizontal); illumination_box->layout()->addWidget(illumination_elevation); illumination_elevation->setMinimum(-90); illumination_elevation->setValue(static_cast(parameters->illumination_elevation*180/M_PI)); illumination_elevation->setMaximum(90); illumination_elevation->setTickInterval(10); illumination_elevation->setTickPosition(QSlider::TicksBothSides); illumination_elevation->setTracking(true); illumination_box->layout()->addWidget(new QLabel("90")); connect( illumination_azimuth,SIGNAL(valueChanged(int)), this,SLOT(setIlluminationAzimuth(int)) ); connect( illumination_elevation,SIGNAL(valueChanged(int)), this,SLOT(setIlluminationElevation(int)) ); QWidget*const padding=new QWidget(); layout()->addWidget(padding); padding->setSizePolicy(QSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding)); // Expanding vertically } ControlRender::~ControlRender() {} void ControlRender::setWireframe(int v) { parameters->wireframe=(v==2); } void ControlRender::setDisplayList(int v) { parameters->display_list=(v==2); } void ControlRender::setJoystickMouse(int v) { parameters->joystick_mouse=(v==2); } void ControlRender::setAmbient(int v) { parameters->ambient=v/100.0f; } void ControlRender::setIlluminationAzimuth(int v) { parameters->illumination_azimuth=v*M_PI/180; } void ControlRender::setIlluminationElevation(int v) { parameters->illumination_elevation=v*M_PI/180; } void ControlRender::pickBackgroundColourLow() { emit pickColour(background_colour_low_button,parameters->background_colour_low); } void ControlRender::pickBackgroundColourHigh() { emit pickColour(background_colour_high_button,parameters->background_colour_high); } fracplanet/dialog_documentation.cpp0000644000175100017510000000425211261123520017427 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of class DialogDocumentation. */ #include "precompiled.h" #include "dialog_documentation.h" static const char*const text= #include "usage_text.h" ; DialogDocumentation::DialogDocumentation(QWidget* parent) :QDialog(parent) { setWindowTitle("Fracplanet User Manual"); setMinimumSize(480,320); setSizeGripEnabled(true); setLayout(new QVBoxLayout()); QTextBrowser*const browser=new QTextBrowser(); layout()->addWidget(browser); browser->setText(text); QPushButton*const ok=new QPushButton("OK"); layout()->addWidget(ok); //! \todo: These button settings don't seem to do anything. Find out what's up. ok->setAutoDefault(true); ok->setDefault(true); connect( ok,SIGNAL(clicked()), this,SLOT(hide()) ); } DialogDocumentation::~DialogDocumentation() {} fracplanet/matrix33.cpp0000644000175100017510000000417311261123520014713 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "matrix33.h" float Matrix33::cofactor(uint row,uint col) const { const uint row0=(row==0 ? 1 : 0); const uint col0=(col==0 ? 1 : 0); const uint row1=(row==2 ? 1 : 2); const uint col1=(col==2 ? 1 : 2); return element(row0,col0)*element(row1,col1) - element(row0,col1)*element(row1,col0); } float Matrix33::determinant() const { return element(0,0)*cofactor(0,0) -element(0,1)*cofactor(0,1) +element(0,2)*cofactor(0,2); } const Matrix33 Matrix33::inverted() const { Matrix33 ret; for (uint row=0;row<3;row++) for (uint col=0;col<3;col++) { const float cf=cofactor(row,col); ret.element(col,row)=(((row+col)&1) ? -cf : cf); // NB Transpose is deliberate } return ret/determinant(); } fracplanet/progress.cpp0000644000175100017510000000347311261123520015107 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "progress.h" Progress::~Progress() {} ProgressScope::ProgressScope(uint steps,const std::string& info,Progress* tgt) :_steps(steps) ,_info(info) ,_target(tgt) ,_step(0) { if (_target) _target->progress_start(_steps,_info); } ProgressScope::~ProgressScope() { if (_target) _target->progress_complete(_info+" completed"); } void ProgressScope::step() { _step++; if (_target) _target->progress_step(_step); } fracplanet/triangle_mesh_viewer_display.cpp0000644000175100017510000003312711262220434021174 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "triangle_mesh_viewer_display.h" #include "matrix33.h" #include "triangle_mesh_viewer.h" TriangleMeshViewerDisplay::TriangleMeshViewerDisplay(TriangleMeshViewer* parent,const QGLFormat& format,const ParametersRender* param,const std::vector& m,bool verbose) :QGLWidget(format,parent) ,_notify(*parent) ,_verbose(verbose) ,mesh(m) ,parameters(param) ,gl_display_list_index(0) ,frame_number(0) ,width(0) ,height(0) ,frame_time() ,camera_position(3.0f,0.0f,0.0f) ,camera_lookat(0.0f,0.0f,0.0f) ,camera_up(0.0f,0.0f,1.0f) ,object_tilt(30.0f*M_PI/180.0f) ,object_rotation(0.0f) { assert(isValid()); setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding)); frame_time.start(); frame_time_reported.start(); } TriangleMeshViewerDisplay::~TriangleMeshViewerDisplay() { makeCurrent(); if (gl_display_list_index) glDeleteLists(gl_display_list_index,1); } QSize TriangleMeshViewerDisplay::minimumSizeHint() const { return QSize(64,64); } QSize TriangleMeshViewerDisplay::sizeHint() const { return QSize(512,512); } void TriangleMeshViewerDisplay::set_mesh(const std::vector& m) { mesh=m; // If there is a display list allocated for the previous mesh, delete it. if (gl_display_list_index!=0) { glDeleteLists(gl_display_list_index,1); gl_display_list_index=0; } } const FloatRGBA TriangleMeshViewerDisplay::background_colour() const { if (mesh.empty()) return FloatRGBA(0.0f,0.0f,0.0f,1.0f); const XYZ relative_camera_position =Matrix33RotateAboutZ(-object_rotation)*Matrix33RotateAboutX(-object_tilt)*camera_position; const float h = mesh[0]->geometry().height(relative_camera_position); if (h<=0.0f) return parameters->background_colour_low; else if (h>=1.0f) return parameters->background_colour_high; else return parameters->background_colour_low+h*(parameters->background_colour_high-parameters->background_colour_low); } void TriangleMeshViewerDisplay::check_for_gl_errors(const char* where) const { GLenum error; while ((error=glGetError())!=GL_NO_ERROR) { std::ostringstream msg; msg << "GL error in " << where << " (frame " << frame_number << ") : "; switch (error) { case GL_INVALID_ENUM: msg << "GL_INVALID_ENUM"; break; case GL_INVALID_VALUE: msg << "GL_INVALID_VALUE"; break; case GL_INVALID_OPERATION: msg << "GL_INVALID_OPERATION"; break; case GL_STACK_OVERFLOW: msg << "GL_STACK_OVERFLOW"; break; case GL_STACK_UNDERFLOW: msg << "GL_STACK_UNDERFLOW"; break; case GL_OUT_OF_MEMORY: msg << "GL_OUT_OF_MEMORY"; break; } std::cerr << msg.str() << std::endl; } } void TriangleMeshViewerDisplay::paintGL() { assert(isValid()); const FloatRGBA bg=background_colour(); glClearColor(bg.r,bg.g,bg.b,1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); const float a=parameters->ambient; GLfloat global_ambient[]={a,a,a,1.0}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT,global_ambient); GLfloat light_diffuse[]={1.0-a,1.0-a,1.0-a,1.0}; glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt( camera_position.x,camera_position.y,camera_position.z, camera_lookat.x ,camera_lookat.y ,camera_lookat.z, camera_up.x ,camera_up.y ,camera_up.z ); const XYZ light_direction(parameters->illumination_direction()); GLfloat light_position[]= { light_direction.x, light_direction.y, light_direction.z, 0.0f // w=0 implies directional light }; glLightfv(GL_LIGHT0,GL_POSITION,light_position); glRotatef((180.0/M_PI)*object_tilt,1.0,0.0,0.0); glRotatef((180.0/M_PI)*object_rotation,0.0,0.0,1.0); glPolygonMode(GL_FRONT_AND_BACK,(parameters->wireframe ? GL_LINE : GL_FILL)); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); if (parameters->display_list && gl_display_list_index!=0) { glCallList(gl_display_list_index); } else { bool building_display_list=(parameters->display_list && gl_display_list_index==0); if (building_display_list) { gl_display_list_index=glGenLists(1); assert(gl_display_list_index!=0); glNewList(gl_display_list_index,GL_COMPILE_AND_EXECUTE); if (_verbose) std::cerr << "Building display list..."; } GLfloat default_material_white[3]={1.0f,1.0f,1.0f}; GLfloat default_material_black[3]={0.0f,0.0f,0.0f}; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,default_material_white); glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,default_material_black); for (uint m=0;memissive()==0.0f) { if (m) // Switch blending on for non-emissive meshes after the first { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } // Use "Color Material" mode 'cos everything is the same material.... just change the colour glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); // Point GL at arrays of data glVertexPointer(3,GL_FLOAT,sizeof(Vertex),&(it->vertex(0).position().x)); glNormalPointer(GL_FLOAT,sizeof(Vertex),&(it->vertex(0).normal().x)); // For a second mesh, use alpha (actually could use it for the first mesh but maybe it's more efficient not to). glColorPointer((m==0 ? 3 : 4),GL_UNSIGNED_BYTE,sizeof(Vertex),&(it->vertex(0).colour(0).r)); // Builds on some platforms (ie Ubuntu) seem to get in a mess if you render >1k primitives // (3k vertices). NB This is a problem in the client; not the xserver. // Debian (Sarge or Etch) has no problems with unlimited batches. // Note it's simply the batch size; there doesn't seem to be any problem with the 10Ks of vertices. // Since the limited batch size doesn't seem to hurt working implementations we just use it everywhere. const uint batch_size=1000; // Draw the colour-zero triangles for (uint t=0;ttriangles_of_colour0();t+=batch_size) { glDrawRangeElements ( GL_TRIANGLES, 0, it->vertices()-1, 3*std::min(batch_size,static_cast(it->triangles_of_colour0()-t)), GL_UNSIGNED_INT, &(it->triangle(t).vertex(0)) ); if (_verbose && building_display_list) { std::cerr << "."; } } // Switch to alternate colour and draw the colour-one triangles glColorPointer(3,GL_UNSIGNED_BYTE,sizeof(Vertex),&(it->vertex(0).colour(1).r)); for (uint t=it->triangles_of_colour0();ttriangles();t+=batch_size) { glDrawRangeElements ( GL_TRIANGLES, 0, it->vertices()-1, 3*std::min(batch_size,static_cast(it->triangles()-t)), GL_UNSIGNED_INT, &(it->triangle(t).vertex(0)) ); if (_verbose && building_display_list) { std::cerr << "."; } } glDisable(GL_COLOR_MATERIAL); } else // implies mesh[m]->emissive()>0.0 { // We abuse alpha for emission, so no blending glDisable(GL_BLEND); // If there could be emissive vertices, we need to do things the hard way // using immediate mode. Maybe the display list capture will help. const float k=1.0f/255.0f; const float em=k*( it->emissive()); const float ad=k*(1.0f-it->emissive()); glBegin(GL_TRIANGLES); for (unsigned int t=0;ttriangles();t++) { if (_verbose && building_display_list && (t&0x3ff) == 0) { std::cerr << "."; } const uint c=(ttriangles_of_colour0() ? 0 : 1); for (uint i=0;i<3;i++) { const uint vn=it->triangle(t).vertex(i); const Vertex& v=it->vertex(vn); GLfloat c_ad[3]; GLfloat c_em[3]; if (v.colour(c).a==0) // Zero alpha used to imply emissive vertex colour { c_ad[0]=v.colour(c).r*ad; c_ad[1]=v.colour(c).g*ad; c_ad[2]=v.colour(c).b*ad; c_em[0]=v.colour(c).r*em; c_em[1]=v.colour(c).g*em; c_em[2]=v.colour(c).b*em; } else { c_ad[0]=v.colour(c).r*k; c_ad[1]=v.colour(c).g*k; c_ad[2]=v.colour(c).b*k; c_em[0]=0.0f; c_em[1]=0.0f; c_em[2]=0.0f; } glNormal3fv(&(v.normal().x)); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,c_ad); glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,c_em); glVertex3fv(&(v.position().x)); } } glEnd(); } } } if (building_display_list) { glEndList(); if (_verbose) { std::cerr << "\n...built display list\n"; } } } if (_verbose) check_for_gl_errors(__PRETTY_FUNCTION__); // Get time taken since last frame const uint dt=frame_time.restart(); // Save it in the queue frame_times.push_back(dt); // Keep last 30 frame times while (frame_times.size()>30) frame_times.pop_front(); // Only update frame time a couple of times a second to reduce flashing if (frame_time_reported.elapsed()>500) { //! \todo Frame time calculation is wrong... need -1 correction to number of frames const float average_time=std::accumulate ( frame_times.begin(), frame_times.end(), 0 )/static_cast(frame_times.size()); const float fps=1000.0/average_time; std::ostringstream report; report.setf(std::ios::fixed); report.precision(1); uint n_triangles=0; uint n_vertices=0; for (uint m=0;mtriangles(); n_vertices+=mesh[m]->vertices(); } } report << "Triangles: " << n_triangles << ", " << "Vertices: " << n_vertices << ", " << "FPS: " << fps << "\n"; _notify.notify(report.str()); frame_time_reported.restart(); } } void TriangleMeshViewerDisplay::initializeGL() { if (_verbose) { std::cerr << "Double buffering " << (doubleBuffer() ? "ON" : "OFF") << "\n"; std::cerr << "Auto Buffer Swap " << (autoBufferSwap() ? "ON" : "OFF") << "\n"; std::cerr << "Multisampling " << (format().sampleBuffers() ? "ON" : "OFF") << "\n"; } const FloatRGBA bg=background_colour(); glClearColor(bg.r,bg.g,bg.b,1.0f); // Switch depth-buffering on glEnable(GL_DEPTH_TEST); // Basic lighting stuff (set ambient globally rather than in light) GLfloat black_light[]={0.0,0.0,0.0,1.0}; glLightfv(GL_LIGHT0,GL_AMBIENT,black_light); glLightfv(GL_LIGHT0,GL_SPECULAR,black_light); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); // Do smooth shading 'cos colours are specified at vertices glShadeModel(GL_SMOOTH); // Use arrays of data glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); } void TriangleMeshViewerDisplay::resizeGL(int w,int h) { width=w; height=h; if (_verbose) std::cerr << "QGLWidget resized to " << width << "x" << height << std::endl; glViewport(0,0,static_cast(w),static_cast(h)); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // View angle is specified in vertical direction, but we need to exaggerate it if image is taller than wide. const float view_angle_degrees=minimum(90.0,width>height ? 45.0 : 45.0*height/width); gluPerspective ( view_angle_degrees, static_cast(width)/static_cast(height), 0.01,10.0 ); // Was 0.1 (too far); 0.001 gives artefacts glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void TriangleMeshViewerDisplay::draw_frame(const XYZ& p,const XYZ& l,const XYZ& u,float r,float t) { frame_number++; camera_position=p; camera_lookat=l; camera_up=u; object_rotation=r; object_tilt=t; updateGL(); } fracplanet/scan.cpp0000644000175100017510000000262711261123520014167 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "scan.h" fracplanet/random.cpp0000644000175100017510000000300211261123520014507 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "random.h" Random01::Random01(uint s) :_rng(s) ,_dist(0,1) ,_gen(_rng,_dist) {} Random01::~Random01() {} fracplanet/license.cpp0000644000175100017510000004773211261123520014673 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief License string boilerplate. */ #include "precompiled.h" #include "license.h" //! \todo Currently emits a warning about multi-line string. Replace line breaks with backslash-n instead. const char*const license_string= "This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n" "\n" "GNU GENERAL PUBLIC LICENSE\n" "Version 2, June 1991\n" "\n" " Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" " Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\n" "\n" "Preamble\n" "\n" " The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.\n" " When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.\n" "\n" " To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.\n" "\n" " For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\n" "\n" " We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy,distribute and/or modify the software.\n" "\n" " Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.\n" "\n" " Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.\n" "\n" " The precise terms and conditions for copying, distribution and\n" "modification follow.\n" "\n" "GNU GENERAL PUBLIC LICENSE\n" "TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n" "\n" " 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The \"Program\", below, refers to any such program or work, and a \"work based on the Program\" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term \"modification\".) Each licensee is addressed as \"you\".\n" "\n" "Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.\n" "\n" " 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.\n" "\n" "You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\n" " 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\n" "\n" " a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\n" "\n" " b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.\n" "\n" " c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)\n" "\n" "These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\n" "\n" "Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.\n" "\n" "In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.\n" "\n" " 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:\n" "\n" " a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\n" "\n" " b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\n" "\n" " c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)\n" "\n" "The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.\n" "\n" "If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.\n" "\n" " 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.\n" "\n" " 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.\n" "\n" " 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.\n" "\n" " 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.\n" "\n" "If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.\n" "\n" "It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.\n" "\n" "This section is intended to make thoroughly clear what is believed tobe a consequence of the rest of this License.\n" "\n" " 8. If the distribution and/or use of the Program is restricted incertain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.\n" "\n" " 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n" "\n" "Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and \"any later version\", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.\n" "\n" " 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.\n" "\n" "NO WARRANTY\n" "\n" " 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSEDOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n" "\n" " 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n" "\n" "END OF TERMS AND CONDITIONS\n" "\n" "How to Apply These Terms to Your New Programs\n" "\n" " If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.\n" "\n" " To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the \"copyright\" line and a pointer to where the full notice is found.\n" "\n" " \n" " Copyright (C) \n" "\n" " This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.\n" "\n" " This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n" "\n" " You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" "\n" "Also add information on how to contact you by electronic and paper mail.\n" "\n" "If the program is interactive, make it output a short notice like this when it starts in an interactive mode:\n" "\n" " Gnomovision version 69, Copyright (C) year name of author\n" " Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n" " This is free software, and you are welcome to redistribute it\n" " under certain conditions; type `show c' for details.\n" "\n" "The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.\n" "\n" "You should also get your employer (if you work as a programmer) or your school, if any, to sign a \"copyright disclaimer\" for the program, if necessary. Here is a sample; alter the names:\n" "\n" " Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n" " `Gnomovision' (which makes passes at compilers) written by James Hacker.\n" "\n" " , 1 April 1989\n" " Ty Coon, President of Vice\n" "\n" "This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.\n" ; fracplanet/parameters_noise.cpp0000644000175100017510000000310211261123520016570 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "parameters_noise.h" ParametersNoise::ParametersNoise(uint n) :terms(n) ,frequency(1.0) ,amplitude(0.125) ,amplitude_decay(0.5) {} ParametersNoise::~ParametersNoise() {} fracplanet/triangle_mesh_terrain.cpp0000644000175100017510000006014711261123520017611 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "triangle_mesh_terrain.h" #include "noise.h" TriangleMeshTerrain::TriangleMeshTerrain(Progress* progress) :TriangleMesh(progress) ,max_height(0.0) {} TriangleMeshTerrain::~TriangleMeshTerrain() {} void TriangleMeshTerrain::do_noise(const ParametersTerrain& parameters) { if (parameters.noise.terms==0 || parameters.noise.amplitude==0) return; const uint steps=vertices(); uint step=0; progress_start(100,"Noise"); MultiscaleNoise noise(parameters.seed,parameters.noise.terms,parameters.noise.amplitude_decay); for (uint i=0;i sea_vertices(vertices()); // Flag vertices forced to sea level for (uint i=0;imax_height) max_height=m; } std::vector land_sea[2]; for (uint i=0;igeometry().epsilon()) set_vertex_height(i,max_height*pow(h/max_height,parameters.power_law)); } progress_complete("Power law completed"); } inline void insert_unique(std::vector& v,uint x) { if (std::find(v.begin(),v.end(),x)==v.end()) v.push_back(x); } void TriangleMeshTerrain::do_rivers(const ParametersTerrain& parameters) { if (parameters.rivers==0) return; Random01 r01(parameters.rivers_seed); std::vector is_sea_vertex(vertices()); // Used to use a vector of sets, but this saves memory and there aren't many elements to each set std::vector > vertex_neighbours(vertices()); progress_start(100,"River preparation"); const uint prep_steps=triangles(); uint step=0; // Need to know each vertex's neighbours (for land vertices) for (uint i=0;i vertices_to_add; // Also track the height of vertices in the river. // When a river level rise is forced we can look for upstream points to bring back into the current set std::multimap vertices_to_add_by_height; std::set current_vertices; float current_vertices_height; // Pick a random non sea triangle to start river // Would like to use __gnu_cxx::random_sample_n but can't get it to work uint source_vertex=(uint)(r01()*vertices()); // Rivers starting in the sea are skipped to keep river density independent of land area, and to avoid lock-up on all-sea planets if (is_sea_vertex[source_vertex]) continue; current_vertices.insert(source_vertex); current_vertices_height=vertex_height(source_vertex); while(true) { bool reached_sea=false; std::set current_vertices_neighbours; for (std::set::const_iterator it=current_vertices.begin();it!=current_vertices.end();it++) { vertices_to_add.insert(*it); vertices_to_add_by_height.insert(std::make_pair(current_vertices_height,*it)); reached_sea|=(is_sea_vertex[*it]); const std::vector& neighbours=vertex_neighbours[*it]; // Only vertices NOT in the current river section are of interest for (std::vector::const_iterator it_n=neighbours.begin();it_n!=neighbours.end();it_n++) { if (current_vertices.find(*it_n)==current_vertices.end()) current_vertices_neighbours.insert(*it_n); } } // Find the heights of everything we could flow to std::multimap flow_candidates; for (std::set::const_iterator it=current_vertices_neighbours.begin();it!=current_vertices_neighbours.end();it++) { flow_candidates.insert(std::multimap::value_type(vertex_height(*it),*it)); } if (reached_sea) { break; } else if (current_vertices.size()>=maximum_lake_size) { break; // Lake becomes an inland sea } else { // If there is any intersection between the current river hexes and completed rivers then we're done bool meets_existing=false; for (std::set::const_iterator it=current_vertices.begin();it!=current_vertices.end();it++) { if (river_vertices.find(*it)!=river_vertices.end()) { meets_existing=true; break; } } if (meets_existing) { break; } } unsigned int num_current_vertices=0; if (flow_candidates.empty()) // Not sure how this could ever happen, but just to be safe... { std::cerr << "Warning: Unexpected internal state: no flow candidates for a river\n"; break; } else if ((*(flow_candidates.begin())).first::const_iterator flat_end=flow_candidates.upper_bound(current_vertices_height+geometry().epsilon()); for (std::multimap::const_iterator it_flat=flow_candidates.begin();it_flat!=flat_end;it_flat++) { current_vertices.insert((*it_flat).second); } num_current_vertices=current_vertices.size(); //std::cerr << "=" << current_vertices.size(); } else // Otherwise the water level must rise to height of the lowest flow candidate { current_vertices_height=(*(flow_candidates.begin())).first+geometry().epsilon(); // Rise a bit more to avoid getting stuck due to precision. const uint outflow_vertex=(*(flow_candidates.begin())).second; current_vertices.insert(outflow_vertex); // Any vertices upstream below the new height should now become part of the current set, and have their level raised. std::multimap::iterator backflow_end=vertices_to_add_by_height.upper_bound(current_vertices_height); for (std::multimap::iterator it=vertices_to_add_by_height.begin();it!=backflow_end;it++) { const uint v=(*it).second; current_vertices.insert(v); set_vertex_height(v,current_vertices_height); } vertices_to_add_by_height.erase(vertices_to_add_by_height.begin(),backflow_end); // Raise level of everything in the working set // Also count vertices rather than having .size() iterate over them again. for (std::set::const_iterator it=current_vertices.begin();it!=current_vertices.end();it++) { set_vertex_height(*it,current_vertices_height); num_current_vertices++; } //std::cerr << "+" << current_vertices.size(); } if (num_current_vertices>=last_stall_warning+100) { std::ostringstream msg; msg << "Rivers (delay: " << num_current_vertices << " vertex lake)"; progress_stall(msg.str()); last_stall_warning=num_current_vertices; } else if (num_current_vertices+100<=last_stall_warning) { std::ostringstream msg; msg << "Rivers: lake complete"; progress_stall(msg.str()); last_stall_warning=num_current_vertices; } } river_vertices.insert(vertices_to_add.begin(),vertices_to_add.end()); } progress_complete("Rivers completed"); } void TriangleMeshTerrain::do_colours(const ParametersTerrain& parameters) { const uint steps=triangles_of_colour1()+vertices(); uint step=0; progress_start(100,"Colouring"); // Colour any triangles which need colouring (ie just sea) ByteRGBA colour_ocean(parameters.colour_ocean); ByteRGBA colour_river(parameters.colour_river); if (parameters.oceans_and_rivers_emissive>0.0f) { colour_ocean.a=0; colour_river.a=0; } for (uint i=triangles_of_colour0();i!=triangles();i++) { step++; progress_step((100*step)/steps); vertex(triangle(i).vertex(0)).colour(1,colour_ocean); vertex(triangle(i).vertex(1)).colour(1,colour_ocean); vertex(triangle(i).vertex(2)).colour(1,colour_ocean); // For debugging, set the colour0 of those triangles to red vertex(triangle(i).vertex(0)).colour(0,ByteRGBA(255,0,0,255)); vertex(triangle(i).vertex(1)).colour(0,ByteRGBA(255,0,0,255)); vertex(triangle(i).vertex(2)).colour(0,ByteRGBA(255,0,0,255)); } const float treeline=0.25; const float beachline=0.01; // Colour all vertices for (uint i=0;i0.0) snowline_here=pow(snowline_here,parameters.snowline_power_law); if (normalised_height>snowline_here) { vertex(i).colour(0,parameters.colour_snow); } else if (is_river) { vertex(i).colour(0,parameters.colour_river); } else if (normalised_height const T lerp(float l,const T& v0,const T& v1) { return (1.0f-l)*v0+l*v1; } FloatRGBA fn(const XYZ& v) { const XYZ n(v.normalised()); return FloatRGBA(0.5f+0.5f*n.x,0.5f+0.5f*n.y,0.5f+0.5f*n.z,0.0f); } class ScanConvertHelper : public ScanConvertBackend { public: ScanConvertHelper ( Raster& image, Raster* dem, Raster* normalmap, const boost::array& vertex_colours, const boost::array& vertex_heights, const boost::array& vertex_normals ) :ScanConvertBackend(image.width(),image.height()) ,_image(image) ,_dem(dem) ,_normalmap(normalmap) ,_vertex_colours(vertex_colours) ,_vertex_heights(vertex_heights) ,_vertex_normals(vertex_normals) { if (_dem) assert(_image.width()==_dem->width() && _image.height()==_dem->height()); if (_normalmap) assert(_image.width()==_normalmap->width() && _image.height()==_normalmap->height()); } virtual ~ScanConvertHelper() {} virtual void scan_convert_backend(uint y,const ScanEdge& edge0,const ScanEdge& edge1) const { const FloatRGBA c0=lerp(edge0.lambda,_vertex_colours[edge0.vertex0],_vertex_colours[edge0.vertex1]); const FloatRGBA c1=lerp(edge1.lambda,_vertex_colours[edge1.vertex0],_vertex_colours[edge1.vertex1]); _image.scan(y,edge0.x,c0,edge1.x,c1); if (_dem) { const float h0=lerp(edge0.lambda,_vertex_heights[edge0.vertex0],_vertex_heights[edge0.vertex1]); const float h1=lerp(edge1.lambda,_vertex_heights[edge1.vertex0],_vertex_heights[edge1.vertex1]); _dem->scan(y,edge0.x,h0,edge1.x,h1); } if (_normalmap) { const XYZ n0(lerp(edge0.lambda,_vertex_normals[edge0.vertex0],_vertex_normals[edge0.vertex1]).normalised()); const XYZ n1(lerp(edge1.lambda,_vertex_normals[edge1.vertex0],_vertex_normals[edge1.vertex1]).normalised()); _normalmap->scan(y,edge0.x,n0,edge1.x,n1,fn); } } virtual void subdivide(const boost::array& v,const XYZ& m,const ScanConverter& scan_converter) const { // Subdivision pattern (into 7) avoids creating any mid-points in edges shared with other triangles. const boost::array vm= {{ (v[1]+v[2]+m)/3.0f, (v[0]+v[2]+m)/3.0f, (v[0]+v[1]+m)/3.0f }}; //! \todo This isn't right (for correct value would need to compute barycentric coordinates of m), but it will should only affect one facet at the pole. const boost::array cm= {{ 0.5f*(_vertex_colours[1]+_vertex_colours[2]), 0.5f*(_vertex_colours[0]+_vertex_colours[2]), 0.5f*(_vertex_colours[0]+_vertex_colours[1]) }}; const boost::array hm= {{ 0.5f*(_vertex_heights[1]+_vertex_heights[2]), 0.5f*(_vertex_heights[0]+_vertex_heights[2]), 0.5f*(_vertex_heights[0]+_vertex_heights[1]) }}; const boost::array nm= {{ (_vertex_normals[1]+_vertex_normals[2]).normalised(), (_vertex_normals[0]+_vertex_normals[2]).normalised(), (_vertex_normals[0]+_vertex_normals[1]).normalised() }}; { const boost::array p={{v[0],v[1],vm[2]}}; const boost::array c={{_vertex_colours[0],_vertex_colours[1],cm[2]}}; const boost::array h={{_vertex_heights[0],_vertex_heights[1],hm[2]}}; const boost::array n={{_vertex_normals[0],_vertex_normals[1],nm[2]}}; scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n)); } { const boost::array p={{v[1],v[2],vm[0]}}; const boost::array c={{_vertex_colours[1],_vertex_colours[2],cm[0]}}; const boost::array h={{_vertex_heights[1],_vertex_heights[2],hm[0]}}; const boost::array n={{_vertex_normals[1],_vertex_normals[2],nm[0]}}; scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n)); } { const boost::array p={{v[2],v[0],vm[1]}}; const boost::array c={{_vertex_colours[2],_vertex_colours[0],cm[1]}}; const boost::array h={{_vertex_heights[2],_vertex_heights[0],hm[1]}}; const boost::array n={{_vertex_normals[2],_vertex_normals[0],nm[1]}}; scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n)); } { const boost::array p={{v[0],vm[2],vm[1]}}; const boost::array c={{_vertex_colours[0],cm[2],cm[1]}}; const boost::array h={{_vertex_heights[0],hm[2],hm[1]}}; const boost::array n={{_vertex_normals[0],nm[2],nm[1]}}; scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n)); } { const boost::array p={{v[1],vm[0],vm[2]}}; const boost::array c={{_vertex_colours[1],cm[0],cm[2]}}; const boost::array h={{_vertex_heights[1],hm[0],hm[2]}}; const boost::array n={{_vertex_normals[1],nm[0],nm[2]}}; scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n)); } { const boost::array p={{v[2],vm[1],vm[0]}}; const boost::array c={{_vertex_colours[2],cm[1],cm[0]}}; const boost::array h={{_vertex_heights[2],hm[1],hm[0]}}; const boost::array n={{_vertex_normals[2],nm[1],nm[0]}}; scan_converter.scan_convert(p,ScanConvertHelper(_image,_dem,_normalmap,c,h,n)); } { scan_converter.scan_convert(vm,ScanConvertHelper(_image,_dem,_normalmap,cm,hm,nm)); } } private: Raster& _image; Raster* _dem; Raster* _normalmap; const boost::array& _vertex_colours; const boost::array& _vertex_heights; const boost::array& _vertex_normals; }; } void TriangleMeshTerrain::render_texture ( Raster& image, Raster* dem, Raster* normal_map, bool shading, float ambient, const XYZ& illumination ) const { progress_start(100,"Generating textures"); for (uint i=0;i vertices ={{ &vertex(t.vertex(0)), &vertex(t.vertex(1)), &vertex(t.vertex(2)), }}; const boost::array vertex_positions ={{ vertices[0]->position(), vertices[1]->position(), vertices[2]->position() }}; const uint which_colour=(i vertex_colours ={{ FloatRGBA(vertices[0]->colour(which_colour))*(shading ? ambient+(1.0f-ambient)*std::max(0.0f,vertices[0]->normal()%illumination) : 1.0f), FloatRGBA(vertices[1]->colour(which_colour))*(shading ? ambient+(1.0f-ambient)*std::max(0.0f,vertices[1]->normal()%illumination) : 1.0f), FloatRGBA(vertices[2]->colour(which_colour))*(shading ? ambient+(1.0f-ambient)*std::max(0.0f,vertices[2]->normal()%illumination) : 1.0f) }}; const boost::array vertex_heights ={{ std::max(0.0f,std::min(65535.0f,65535.0f*geometry().height(vertices[0]->position()))), std::max(0.0f,std::min(65535.0f,65535.0f*geometry().height(vertices[1]->position()))), std::max(0.0f,std::min(65535.0f,65535.0f*geometry().height(vertices[2]->position()))) }}; const boost::array vertex_normals ={{ vertices[0]->normal(), vertices[1]->normal(), vertices[2]->normal() }}; ScanConvertHelper backend(image,dem,normal_map,vertex_colours,vertex_heights,vertex_normals); geometry().scan_convert ( vertex_positions, backend ); progress_step((100*i)/(triangles()-1)); } progress_complete("Texture generation completed"); } TriangleMeshTerrainPlanet::TriangleMeshTerrainPlanet(const ParametersTerrain& parameters,Progress* progress) :TriangleMesh(progress) ,TriangleMeshTerrain(progress) ,TriangleMeshSubdividedIcosahedron(1.0+parameters.variation.z*parameters.base_height,parameters.subdivisions,parameters.subdivisions_unperturbed,parameters.seed,parameters.variation,progress) { do_terrain(parameters); } void TriangleMeshTerrainPlanet::write_povray(std::ofstream& out,const ParametersSave& param_save,const ParametersTerrain& parameters_terrain) const { if (param_save.pov_sea_object) { out << "sphere {<0.0,0.0,0.0>,1.0 pigment{rgb " << parameters_terrain.colour_ocean.format_pov_rgb() << "} finish {ambient " << emissive() << " diffuse " << 1.0f-emissive() << "}}\n"; } if (param_save.pov_atmosphere) { out << "sphere {<0.0,0.0,0.0>,1.025 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <1.0,1.0,1.0> extinction 1}}}}\n" << "sphere {<0.0,0.0,0.0>,1.05 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <0.0,0.0,1.0> extinction 1}}}}\n"; } TriangleMesh::write_povray(out,param_save.pov_sea_object,false,false); // Don't double illuminate. Don't no-shadow. } TriangleMeshTerrainFlat::TriangleMeshTerrainFlat(const ParametersTerrain& parameters,Progress* progress) :TriangleMesh(progress) ,TriangleMeshTerrain(progress) ,TriangleMeshFlat(parameters.object_type,parameters.variation.z*parameters.base_height,parameters.seed,progress) { subdivide(parameters.subdivisions,parameters.subdivisions_unperturbed,parameters.variation); do_terrain(parameters); } void TriangleMeshTerrainFlat::write_povray(std::ofstream& out,const ParametersSave& param_save,const ParametersTerrain& parameters_terrain) const { if (param_save.pov_sea_object) { out << "plane {<0.0,1.0,0.0>,0.0 pigment{rgb " << parameters_terrain.colour_ocean.format_pov_rgb() << "} finish {ambient " << emissive() << " diffuse " << 1.0f-emissive() << "}}\n"; } if (param_save.pov_atmosphere) { out << "plane {<0.0,1.0,0.0>,0.05 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <1.0,1.0,1.0> extinction 1}}}}\n" << "plane {<0.0,1.0,0.0>,0.1 hollow texture {pigment {color rgbf 1}} interior{media{scattering{1,color rgb <0.0,0.0,1.0> extinction 1}}}}\n"; } TriangleMesh::write_povray(out,param_save.pov_sea_object,false,false); // Don't double illuminate. Don't no-shadow. } fracplanet/rgb.cpp0000644000175100017510000000445111261123520014012 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for class ByteRGBA and class FloatRGBA. */ #include "precompiled.h" #include "rgb.h" std::ostream& ByteRGBA::write(std::ostream& out) const { return out << static_cast(r) << " " << static_cast(g) << " " << static_cast(b) << " " << static_cast(a); } const std::string ByteRGBA::format_comma() const { std::ostringstream s; s << static_cast(r) << "," << static_cast(g) << "," << static_cast(b) << "," << static_cast(a); return s.str(); } std::ostream& FloatRGBA::write(std::ostream& out) const { return out << r << " " << g << " " << b << " " << a; } const std::string FloatRGBA::format_pov_rgb() const { std::ostringstream s; s << "<" << r << "," << g << "," << b << ">"; return s.str(); } const std::string FloatRGBA::format_pov_rgbf() const { std::ostringstream s; s << "<" << r << "," << g << "," << b << "," << 1.0f-a << ">"; return s.str(); } fracplanet/triangle_edge.cpp0000644000175100017510000000264011261123520016027 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "triangle_edge.h" fracplanet/fracplanet_main.cpp0000644000175100017510000003251211262220434016365 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "fracplanet_main.h" #include "image.h" FracplanetMain::FracplanetMain(QWidget* parent,QApplication* app,const boost::program_options::variables_map& opts,bool verbose) :QWidget(parent) ,_verbose(verbose) ,application(app) ,mesh_terrain(0) ,mesh_cloud(0) ,parameters_terrain() ,parameters_cloud() ,parameters_render(opts) ,parameters_save(¶meters_render) ,last_step(0) ,progress_was_stalled(false) { setLayout(new QVBoxLayout); tab=new QTabWidget(); layout()->addWidget(tab); control_terrain=new ControlTerrain(this,¶meters_terrain,¶meters_cloud); tab->addTab(control_terrain,"Create"); control_render=new ControlRender(¶meters_render); tab->addTab(control_render,"Render"); control_save=new ControlSave(this,¶meters_save); tab->addTab(control_save,"Save"); control_about=new ControlAbout(application); tab->addTab(control_about,"About"); } FracplanetMain::~FracplanetMain() {} void FracplanetMain::progress_start(uint target,const std::string& info) { if (!progress_dialog.get()) { progress_dialog=std::auto_ptr(new QProgressDialog("Progress","Cancel",0,100,this)); progress_dialog->setWindowModality(Qt::WindowModal); progress_dialog->setCancelButton(0); // Cancel not supported progress_dialog->setAutoClose(false); // Avoid it flashing on and off progress_dialog->setMinimumDuration(0); } progress_was_stalled=false; progress_info=info; progress_dialog->reset(); progress_dialog->setMaximum(target+1); // Not sure why, but +1 seems to avoid the progress bar dropping back to the start on completion progress_dialog->setLabelText(progress_info.c_str()); progress_dialog->show(); last_step=static_cast(-1); QApplication::setOverrideCursor(Qt::WaitCursor); application->processEvents(); } void FracplanetMain::progress_stall(const std::string& reason) { progress_was_stalled=true; progress_dialog->setLabelText(reason.c_str()); application->processEvents(); } void FracplanetMain::progress_step(uint step) { if (progress_was_stalled) { progress_dialog->setLabelText(progress_info.c_str()); progress_was_stalled=false; application->processEvents(); } // We might be called lots of times with the same step. // Don't know if Qt handles this efficiently so check for it ourselves. if (step!=last_step) { progress_dialog->setValue(step); last_step=step; application->processEvents(); } // TODO: Probably better to base call to processEvents() on time since we last called it. // (but certainly calling it every step is a bad idea: really slows app down) } void FracplanetMain::progress_complete(const std::string& info) { progress_dialog->setLabelText(info.c_str()); last_step=static_cast(-1); QApplication::restoreOverrideCursor(); application->processEvents(); } void FracplanetMain::regenerate() //! \todo Should be able to retain ground or clouds { const bool first_viewer=!viewer; if (viewer) { viewer->hide(); viewer.reset(); } meshes.clear(); mesh_terrain.reset(); mesh_cloud.reset(); //! \todo Recreating viewer every time seems like overkill, but Ubuntu (in VM) doesn't seem to like it otherwise. viewer.reset(new TriangleMeshViewer(this,¶meters_render,std::vector(),_verbose)); // Tweak viewer appearance so controls not too dominant QFont viewer_font; viewer_font.setPointSize(viewer_font.pointSize()-2); viewer->setFont(viewer_font); viewer->layout()->setSpacing(2); viewer->layout()->setContentsMargins(2,2,2,2); const clock_t t0=clock(); // There are some issues with type here: // We need to keep hold of a pointer to TriangleMeshTerrain so we can call its write_povray method // but the triangle viewer needs the TriangleMesh. // So we end up with code like this to avoid a premature downcast. switch (parameters_terrain.object_type) { case ParametersObject::ObjectTypePlanet: { std::auto_ptr it(new TriangleMeshTerrainPlanet(parameters_terrain,this)); meshes.push_back(it.get()); mesh_terrain.reset(it.release()); break; } default: { std::auto_ptr it(new TriangleMeshTerrainFlat(parameters_terrain,this)); meshes.push_back(it.get()); mesh_terrain.reset(it.release()); break; } } if (parameters_cloud.enabled) { switch (parameters_cloud.object_type) { case ParametersObject::ObjectTypePlanet: { std::auto_ptr it(new TriangleMeshCloudPlanet(parameters_cloud,this)); meshes.push_back(it.get()); mesh_cloud.reset(it.release()); break; } default: { std::auto_ptr it(new TriangleMeshCloudFlat(parameters_cloud,this)); meshes.push_back(it.get()); mesh_cloud.reset(it.release()); break; } } } const clock_t t1=clock(); progress_dialog.reset(0); if (_verbose) std::cerr << "Mesh build time was " << (t1-t0)/static_cast(CLOCKS_PER_SEC) << "s" << std::endl; viewer->set_mesh(meshes); viewer->showNormal(); // showNormal() needed to restore from minimised viewer->raise(); // Only display this first time viewer is created if (_verbose && first_viewer) { std::cerr << "GL info:" << std::endl; std::cerr << " Vendor : " << glGetString(GL_VENDOR) << std::endl; std::cerr << " Renderer : " << glGetString(GL_RENDERER) << std::endl; std::cerr << " Version : " << glGetString(GL_VERSION) << std::endl; GLint max_elements_vertices; GLint max_elements_indices; glGetIntegerv(GL_MAX_ELEMENTS_VERTICES,&max_elements_vertices); glGetIntegerv(GL_MAX_ELEMENTS_INDICES,&max_elements_indices); std::cerr << " GL_MAX_ELEMENTS_VERTICES : " << max_elements_vertices << std::endl; std::cerr << " GL_MAX_ELEMENTS_INDICES : " << max_elements_indices << std::endl; //std::cerr << " GL Extensions are : \"" << glGetString(GL_EXTENSIONS) << "\"" << std::endl; } } void FracplanetMain::save_pov() { const QString selected_filename=QFileDialog::getSaveFileName ( this, "POV-Ray", ".", "(*.pov *.inc)" ); if (selected_filename.isEmpty()) { QMessageBox::critical(this,"Fracplanet","No file specified\nNothing saved"); } else if (!(selected_filename.toUpper().endsWith(".POV") || selected_filename.toUpper().endsWith(".INC"))) { QMessageBox::critical(this,"Fracplanet","File selected must have .pov or .inc suffix."); } else { viewer->hide(); const std::string filename_base(selected_filename.left(selected_filename.length()-4).toLocal8Bit()); const std::string filename_pov=filename_base+".pov"; const std::string filename_inc=filename_base+".inc"; const size_t last_separator=filename_inc.rfind('/'); const std::string filename_inc_relative_to_pov= "./" +( last_separator==std::string::npos ? filename_inc : filename_inc.substr(last_separator+1) ); std::ofstream out_pov(filename_pov.c_str()); std::ofstream out_inc(filename_inc.c_str()); // Boilerplate for renderer out_pov << "camera {perspective location <0,1,-4.5> look_at <0,0,0> angle 45}\n"; out_pov << "light_source {<100,100,-100> color rgb <1.0,1.0,1.0>}\n"; out_pov << "#include \""+filename_inc_relative_to_pov+"\"\n"; mesh_terrain->write_povray(out_inc,parameters_save,parameters_terrain); if (mesh_cloud) mesh_cloud->write_povray(out_inc,parameters_save,parameters_cloud); out_pov.close(); out_inc.close(); const bool ok=(out_pov && out_inc); progress_dialog.reset(0); viewer->showNormal(); viewer->raise(); if (!ok) { QMessageBox::critical(this,"Fracplanet","Errors ocurred while the files were being written."); } } } void FracplanetMain::save_blender() { const QString selected_filename=QFileDialog::getSaveFileName ( this, "Blender", ".", "(*.py)" ); if (selected_filename.isEmpty()) { QMessageBox::critical(this,"Fracplanet","No file specified\nNothing saved"); } else { viewer->hide(); const std::string filename(selected_filename.toLocal8Bit()); std::ofstream out(filename.c_str()); // Boilerplate out << "#!BPY\n\n"; out << "import Blender\n"; out << "from Blender import NMesh, Material\n"; out << "\n"; out << "def v(mesh,x,y,z):\n"; out << "\tmesh.verts.append(NMesh.Vert(x,y,z))\n"; out << "\n"; out << "def f(mesh,material,v0,v1,v2,c0,c1,c2):\n"; out << "\tface=NMesh.Face()\n"; out << "\tface.transp=NMesh.FaceTranspModes.ALPHA\n"; out << "\tface.smooth=1\n"; out << "\tface.mat=material\n"; out << "\tface.v.append(mesh.verts[v0])\n"; out << "\tface.v.append(mesh.verts[v1])\n"; out << "\tface.v.append(mesh.verts[v2])\n"; out << "\tface.col.append(NMesh.Col(c0[0],c0[1],c0[2],c0[3]))\n"; out << "\tface.col.append(NMesh.Col(c1[0],c1[1],c1[2],c1[3]))\n"; out << "\tface.col.append(NMesh.Col(c2[0],c2[1],c2[2],c2[3]))\n"; out << "\tmesh.faces.append(face)\n"; out << "\n"; mesh_terrain->write_blender(out,parameters_save,parameters_terrain,"fracplanet"); if (mesh_cloud) mesh_cloud->write_blender(out,parameters_save,parameters_cloud,"fracplanet"); out << "Blender.Redraw()\n"; out.close(); progress_dialog.reset(0); viewer->showNormal(); viewer->raise(); if (!out) { QMessageBox::critical(this,"Fracplanet","Errors ocurred while the files were being written."); } } } void FracplanetMain::save_texture() { const uint height=parameters_save.texture_height; const uint width=height*mesh_terrain->geometry().scan_convert_image_aspect_ratio(); const QString selected_filename=QFileDialog::getSaveFileName ( this, "Texture", ".", "(*.ppm)" ); if (selected_filename.isEmpty()) { QMessageBox::critical(this,"Fracplanet","No file specified\nNothing saved"); } else if (!(selected_filename.toUpper().endsWith(".PPM"))) { QMessageBox::critical(this,"Fracplanet","File selected must have .ppm suffix."); } else { const std::string filename(selected_filename.toLocal8Bit()); const std::string filename_base(selected_filename.left(selected_filename.length()-4).toLocal8Bit()); viewer->hide(); bool ok=true; { boost::scoped_ptr > terrain_image(new Image(width,height)); terrain_image->fill(ByteRGBA(0,0,0,0)); boost::scoped_ptr > terrain_dem(new Image(width,height)); terrain_dem->fill(0); boost::scoped_ptr > terrain_normals(new Image(width,height)); terrain_normals->fill(ByteRGBA(128,128,128,0)); mesh_terrain->render_texture ( *terrain_image, terrain_dem.get(), terrain_normals.get(), parameters_save.texture_shaded, parameters_render.ambient, parameters_render.illumination_direction() ); if (!terrain_image->write_ppmfile(filename,this)) ok=false; if (ok && terrain_dem) { if (!terrain_dem->write_pgmfile(filename_base+"_dem.pgm",this)) ok=false; } if (ok && terrain_normals) { if (!terrain_normals->write_ppmfile(filename_base+"_norm.ppm",this)) ok=false; } } if (ok && mesh_cloud) { QMessageBox::warning(this,"Fracplanet","Texture save of cloud mesh not currently supported"); //boost::scoped_ptr > cloud_image(new Image(width,height)); //mesh_cloud->render_texture(*cloud_image); //if (!cloud_image->write_pgmfile(filename_base+"_cloud.png",this)) ok=false; } progress_dialog.reset(0); viewer->showNormal(); viewer->raise(); if (!ok) { QMessageBox::critical(this,"Fracplanet","Errors ocurred while the files were being written."); } } } fracplanet/noise.cpp0000644000175100017510000001070611261123520014355 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation of Noise class */ #include "precompiled.h" #include "noise.h" Noise::Noise(uint seed) { // We use our own random number generator so saved pictures will be the same when reloaded! // (Besides, one isn't actually conveniently available) Random01 r_01(seed); // Create an array of random gradient vectors uniformly on the unit sphere unsigned int i; for (i=0;i0;i-=2) { const int j=(static_cast(r_01()*N)); int k=_p[i]; _p[i]=_p[j]; _p[j]=k; } // Extend g and p arrays to allow for faster indexing for (i=0;i(tx); const int ity=static_cast(ty); const int itz=static_cast(tz); const int bx0=( itx &(N-1)); const int bx1=((bx0+1)&(N-1)); const int by0=( ity &(N-1)); const int by1=((by0+1)&(N-1)); const int bz0=( itz &(N-1)); const int bz1=((bz0+1)&(N-1)); const int i=_p[bx0]; const int b00=_p[i+by0]; const int b01=_p[i+by1]; const int j=_p[bx1]; const int b10=_p[j+by0]; const int b11=_p[j+by1]; const float rx0=tx-itx; const float ry0=ty-ity; const float rz0=tz-itz; const float rx1=rx0-1.0; const float ry1=ry0-1.0; const float rz1=rz0-1.0; const float sx=surve(rx0); const float a0=lerp(sx,value(_g[b00+bz0],rx0,ry0,rz0),value(_g[b10+bz0],rx1,ry0,rz0)); const float b0=lerp(sx,value(_g[b01+bz0],rx0,ry1,rz0),value(_g[b11+bz0],rx1,ry1,rz0)); const float a1=lerp(sx,value(_g[b00+bz1],rx0,ry0,rz1),value(_g[b10+bz1],rx1,ry0,rz1)); const float b1=lerp(sx,value(_g[b01+bz1],rx0,ry1,rz1),value(_g[b11+bz1],rx1,ry1,rz1)); const float sy=surve(ry0); const float c=lerp(sy,a0,b0); const float d=lerp(sy,a1,b1); const float sz=surve(rz0); return 1.5*lerp(sz,c,d); } MultiscaleNoise::MultiscaleNoise(uint seed,uint terms,float decay) :_terms(terms) ,_noise(new boost::scoped_ptr[terms]) ,_amplitude(new float[terms]) { float k=1.0f; float kt=0.0f; for (uint i=0;i<_terms;i++) { _noise[i].reset(new Noise(seed+i)); _amplitude[i]=k; kt+=k; k*=decay; } for (uint i=0;i<_terms;i++) { _amplitude[i]/=kt; } } MultiscaleNoise::~MultiscaleNoise() {} //! Return noise value at a point. float MultiscaleNoise::operator()(const XYZ& p) const { float v=0.0; for (uint i=0;i<_terms;i++) { v+=_amplitude[i]*(*_noise[i])(p*(1<. */ /**************************************************************************/ #include "precompiled.h" #include "control_terrain.h" #include "fracplanet_main.h" #include "spinbox.h" /*! Lots of tedious code to instantiate controls and wire things up. */ ControlTerrain::ControlTerrain(FracplanetMain* tgt,ParametersTerrain* param_terrain,ParametersCloud* param_cloud) :Control() ,parameters_terrain(param_terrain) ,parameters_cloud(param_cloud) ,regenerate_target(tgt) { QTabWidget* tabs=new QTabWidget(); // Top level tab widget layout()->addWidget(tabs); tabs->setMinimumWidth(512); QTabWidget* tab_terrain=new QTabWidget(this); tabs->addTab(tab_terrain,"Terrain"); QWidget*const tab_terrain_basics=new QWidget(); tab_terrain->addTab(tab_terrain_basics,"Basics"); QWidget*const tab_terrain_subdivision=new QWidget(); tab_terrain->addTab(tab_terrain_subdivision,"Subdivision"); QWidget*const tab_terrain_noise=new QWidget(); tab_terrain->addTab(tab_terrain_noise,"Noise"); QWidget*const tab_snow=new QWidget(); tabs->addTab(tab_snow,"Snow"); QWidget*const tab_rivers=new QWidget(); tabs->addTab(tab_rivers,"Rivers"); QWidget*const tab_colours=new QWidget(); tabs->addTab(tab_colours,"Colours"); QWidget* tab_clouds=new QWidget(); tabs->addTab(tab_clouds,"Clouds"); QGridLayout*const grid_terrain_basics=new QGridLayout(); tab_terrain_basics->setLayout(grid_terrain_basics); QGridLayout*const grid_terrain_subdivision=new QGridLayout(); tab_terrain_subdivision->setLayout(grid_terrain_subdivision); QGridLayout*const grid_terrain_noise=new QGridLayout(); tab_terrain_noise->setLayout(grid_terrain_noise); grid_terrain_basics->addWidget(new QLabel("Generate:"),0,0); QComboBox* object_type_combo_box=new QComboBox(); grid_terrain_basics->addWidget(object_type_combo_box,0,1); object_type_combo_box->insertItem(ParametersObject::ObjectTypePlanet,"Planet"); object_type_combo_box->insertItem(ParametersObject::ObjectTypeFlatHexagon,"Hexagonal Area"); object_type_combo_box->insertItem(ParametersObject::ObjectTypeFlatTriangle,"Triangular Area"); object_type_combo_box->insertItem(ParametersObject::ObjectTypeFlatSquare,"Square Area"); object_type_combo_box->setCurrentIndex(parameters_terrain->object_type); connect( object_type_combo_box,SIGNAL(activated(int)), this,SLOT(setObjectType(int)) ); base_height_label=new QLabel("Base land height (%):"); grid_terrain_basics->addWidget(base_height_label,1,0); base_height_spinbox=new SpinBox(-100,100,10); grid_terrain_basics->addWidget(base_height_spinbox,1,1); base_height_spinbox->setValue((uint)(100.0*parameters_terrain->base_height)); connect( base_height_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setBaseHeight(int)) ); base_height_spinbox->setToolTip("The initial height of land relative to sea-level"); terrain_seed_label=new QLabel("Terrain random seed:"); grid_terrain_basics->addWidget(terrain_seed_label,2,0); terrain_seed_spinbox=new SpinBox(0xffffffff,0x7fffffff,1); grid_terrain_basics->addWidget(terrain_seed_spinbox,2,1); terrain_seed_spinbox->setValue(parameters_terrain->seed); connect( terrain_seed_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setTerrainSeed(int)) ); terrain_seed_spinbox->setToolTip("The random seed for subdivision and noise."); subdivisions_label=new QLabel("Subdivisions:"); grid_terrain_subdivision->addWidget(subdivisions_label,0,0); subdivisions_spinbox=new SpinBox(0,16,1); grid_terrain_subdivision->addWidget(subdivisions_spinbox,0,1); subdivisions_spinbox->setValue(parameters_terrain->subdivisions); connect( subdivisions_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setTerrainSubdivisions(int)) ); subdivisions_spinbox->setToolTip("The number of times the initial structure will be subdivided.\nWARNING: EACH STEP QUADRUPLES THE MEMORY REQUIREMENT!"); subdivisions_unperturbed_label=new QLabel("Unperturbed subdivisions:"); grid_terrain_subdivision->addWidget(subdivisions_unperturbed_label,1,0); subdivisions_unperturbed_spinbox=new SpinBox(0,16,1); grid_terrain_subdivision->addWidget(subdivisions_unperturbed_spinbox,1,1); subdivisions_unperturbed_spinbox->setValue(parameters_terrain->subdivisions_unperturbed); connect( subdivisions_unperturbed_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setSubdivisionsUnperturbed(int)) ); subdivisions_unperturbed_spinbox->setToolTip("The number of subdivisions which will be performed without perturbing vertices"); variation_vertical_label=new QLabel("Vertical perturbation :"); grid_terrain_subdivision->addWidget(variation_vertical_label,2,0); variation_vertical_spinbox=new SpinBox(0,50,1); grid_terrain_subdivision->addWidget(variation_vertical_spinbox,2,1); variation_vertical_spinbox->setValue((int)(100*parameters_terrain->variation.z)); connect( variation_vertical_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setVariationVertical(int)) ); variation_vertical_spinbox->setToolTip("The magnitude of random height perturbations"); variation_horizontal_label=new QLabel("Horizontal perturbation:"); grid_terrain_subdivision->addWidget(variation_horizontal_label,3,0); variation_horizontal_spinbox=new SpinBox(0,25,1); grid_terrain_subdivision->addWidget(variation_horizontal_spinbox,3,1); variation_horizontal_spinbox->setValue((int)(100*parameters_terrain->variation.x)); connect( variation_horizontal_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setVariationHorizontal(int)) ); variation_horizontal_spinbox->setToolTip("The magnitude of random horizontal perturbations"); noise_terms_label=new QLabel("Noise terms"); grid_terrain_noise->addWidget(noise_terms_label,0,0); noise_terms_spinbox=new SpinBox(0,10,1); grid_terrain_noise->addWidget(noise_terms_spinbox,0,1); noise_terms_spinbox->setValue(parameters_terrain->noise.terms); connect( noise_terms_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setNoiseTerms(int)) ); noise_terms_spinbox->setToolTip("Number of terms in added Perlin noise"); noise_frequency_label=new QLabel("Noise frequency"); grid_terrain_noise->addWidget(noise_frequency_label,1,0); noise_frequency_spinbox=new SpinBox(0,10000,10); grid_terrain_noise->addWidget(noise_frequency_spinbox,1,1); noise_frequency_spinbox->setValue(static_cast(100*parameters_terrain->noise.frequency)); connect( noise_frequency_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setNoiseFrequency(int)) ); noise_frequency_spinbox->setToolTip("Frequency for Perlin noise 1st term"); noise_amplitude_label=new QLabel("Noise amplitude"); grid_terrain_noise->addWidget(noise_amplitude_label,2,0); noise_amplitude_spinbox=new SpinBox(0,100,1); grid_terrain_noise->addWidget(noise_amplitude_spinbox,2,1); noise_amplitude_spinbox->setValue(static_cast(100*parameters_terrain->noise.amplitude)); connect( noise_amplitude_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setNoiseAmplitude(int)) ); noise_amplitude_spinbox->setToolTip("Amplitude for Perlin noise 1st term"); noise_amplitude_decay_label=new QLabel("Noise amplitude decay rate"); grid_terrain_noise->addWidget(noise_amplitude_decay_label,3,0); noise_amplitude_decay_spinbox=new SpinBox(0,100,10); grid_terrain_noise->addWidget(noise_amplitude_decay_spinbox,3,1); noise_amplitude_decay_spinbox->setValue(static_cast(100*parameters_terrain->noise.amplitude_decay)); connect( noise_amplitude_decay_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setNoiseAmplitudeDecay(int)) ); noise_amplitude_decay_spinbox->setToolTip("Amplitude decay rate for subsequent Perlin noise terms\n(subsequent terms are this percentage amplitude of the previous term)"); power_law_label=new QLabel("Power law:"); grid_terrain_basics->addWidget(power_law_label,3,0); power_law_spinbox=new SpinBox(1,10000,10); grid_terrain_basics->addWidget(power_law_spinbox,3,1); power_law_spinbox->setValue((int)(100*parameters_terrain->power_law)); connect( power_law_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setPowerLaw(int)) ); power_law_spinbox->setToolTip("The power-law to be applied to elevations."); QGridLayout*const grid_snow=new QGridLayout(); tab_snow->setLayout(grid_snow); snowline_equator_label=new QLabel("Snowline at equator"); grid_snow->addWidget(snowline_equator_label,0,0); snowline_equator_spinbox=new SpinBox(-100,200,10); grid_snow->addWidget(snowline_equator_spinbox,0,1); snowline_equator_spinbox->setValue((int)(100*parameters_terrain->snowline_equator)); connect( snowline_equator_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setSnowlineEquator(int)) ); snowline_equator_spinbox->setToolTip("Snowline on the equator (as a % of the maximum height)"); snowline_pole_label=new QLabel("Snowline at pole"); grid_snow->addWidget(snowline_pole_label,1,0); snowline_pole_spinbox=new SpinBox(-100,200,10); grid_snow->addWidget(snowline_pole_spinbox,1,1); snowline_pole_spinbox->setValue((int)(100*parameters_terrain->snowline_pole)); connect( snowline_pole_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setSnowlinePole(int)) ); snowline_pole_spinbox->setToolTip("Snowline at the poles (as a % of the maximum height)"); snowline_power_law_label=new QLabel("Snowline power law"); grid_snow->addWidget(snowline_power_law_label,2,0); snowline_power_law_spinbox=new SpinBox(1,1000,10); grid_snow->addWidget(snowline_power_law_spinbox,2,1); snowline_power_law_spinbox->setValue((int)(100*parameters_terrain->snowline_power_law)); connect( snowline_power_law_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setSnowlinePowerLaw(int)) ); snowline_power_law_spinbox->setToolTip("Power law applied to snowline elevation."); snowline_slope_effect_label=new QLabel("Snowline slope suppression"); grid_snow->addWidget(snowline_slope_effect_label,3,0); snowline_slope_effect_spinbox=new SpinBox(0,10000,5); grid_snow->addWidget(snowline_slope_effect_spinbox,3,1); snowline_slope_effect_spinbox->setValue((int)(100*parameters_terrain->snowline_slope_effect)); connect( snowline_slope_effect_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setSnowlineSlopeEffect(int)) ); snowline_slope_effect_spinbox->setToolTip("Snow suppression on slopes."); snowline_glacier_effect_label=new QLabel("Snowline glacier effect"); grid_snow->addWidget(snowline_glacier_effect_label,4,0); snowline_glacier_effect_spinbox=new SpinBox(-1000,1000,5); grid_snow->addWidget(snowline_glacier_effect_spinbox,4,1); snowline_glacier_effect_spinbox->setValue((int)(100*parameters_terrain->snowline_glacier_effect)); connect( snowline_glacier_effect_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setSnowlineGlacierEffect(int)) ); snowline_glacier_effect_spinbox->setToolTip("Converts rivers to glaciers."); QGridLayout*const grid_rivers=new QGridLayout(); tab_rivers->setLayout(grid_rivers); rivers_label=new QLabel("Rivers:"); grid_rivers->addWidget(rivers_label,0,0); rivers_spinbox=new SpinBox(0,1000000,100); grid_rivers->addWidget(rivers_spinbox,0,1); rivers_spinbox->setValue(parameters_terrain->rivers); connect( rivers_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setRivers(int)) ); rivers_spinbox->setToolTip("The number of rivers to be attempted to be generated"); rivers_seed_label=new QLabel("Rivers seed:"); grid_rivers->addWidget(rivers_seed_label,1,0); rivers_seed_spinbox=new SpinBox(0xffffffff,0x7fffffff,1); grid_rivers->addWidget(rivers_seed_spinbox,1,1); rivers_seed_spinbox->setValue(parameters_terrain->rivers_seed); connect( rivers_seed_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setRiversSeed(int)) ); rivers_seed_spinbox->setToolTip("The random seed for river generation."); lake_becomes_sea_label=new QLabel("Lake becomes sea:"); grid_rivers->addWidget(lake_becomes_sea_label,2,0); lake_becomes_sea_spinbox=new SpinBox(1,100,1); grid_rivers->addWidget(lake_becomes_sea_spinbox,2,1); lake_becomes_sea_spinbox->setValue((uint)(100.0*parameters_terrain->lake_becomes_sea)); connect( lake_becomes_sea_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setLakeBecomesSea(int)) ); lake_becomes_sea_spinbox->setToolTip("The percentage of planetary surface which must be covered by a lake for it to be considered a sea"); QGridLayout*const grid_colours=new QGridLayout(); tab_colours->setLayout(grid_colours); colour_ocean_button=new QPushButton(build_icon_of_colour(parameters_terrain->colour_ocean),"Ocean"); grid_colours->addWidget(colour_ocean_button,0,0); connect( colour_ocean_button,SIGNAL(clicked()), this,SLOT(pickColourOcean()) ); colour_shoreline_button=new QPushButton(build_icon_of_colour(parameters_terrain->colour_shoreline),"Shore"); grid_colours->addWidget(colour_shoreline_button,0,1); connect( colour_shoreline_button,SIGNAL(clicked()), this,SLOT(pickColourShoreline()) ); colour_river_button=new QPushButton(build_icon_of_colour(parameters_terrain->colour_river),"River"); grid_colours->addWidget(colour_river_button,1,0); connect( colour_river_button,SIGNAL(clicked()), this,SLOT(pickColourRiver()) ); colour_low_button=new QPushButton(build_icon_of_colour(parameters_terrain->colour_low),"Low"); grid_colours->addWidget(colour_low_button,1,1); connect( colour_low_button,SIGNAL(clicked()), this,SLOT(pickColourLow()) ); colour_snow_button=new QPushButton(build_icon_of_colour(parameters_terrain->colour_snow),"Snow"); grid_colours->addWidget(colour_snow_button,2,0); connect( colour_snow_button,SIGNAL(clicked()), this,SLOT(pickColourSnow()) ); colour_high_button=new QPushButton(build_icon_of_colour(parameters_terrain->colour_high),"High"); grid_colours->addWidget(colour_high_button,2,1); connect( colour_high_button,SIGNAL(clicked()), this,SLOT(pickColourHigh()) ); grid_colours->addWidget(new QLabel("Oceans & rivers emissive"),3,0); oceans_and_rivers_emissive_spinbox=new SpinBox(0,100,10); grid_colours->addWidget(oceans_and_rivers_emissive_spinbox,3,1); oceans_and_rivers_emissive_spinbox->setValue((uint)(100.0*parameters_terrain->oceans_and_rivers_emissive)); connect( oceans_and_rivers_emissive_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setOceansAndRiversEmissive(int)) ); oceans_and_rivers_emissive_spinbox->setToolTip("Percentage of ocean and river colour which is emissive"); tab_clouds->setLayout(new QVBoxLayout()); QCheckBox*const clouds_checkbox=new QCheckBox("Clouds enabled"); tab_clouds->layout()->addWidget(clouds_checkbox); clouds_checkbox->setToolTip("Switch on cloud generation"); clouds_checkbox->setChecked(parameters_cloud->enabled); connect( clouds_checkbox,SIGNAL(toggled(bool)), this,SLOT(setCloudsEnabled(bool)) ); QWidget*const clouds_widget=new QWidget(); tab_clouds->layout()->addWidget(clouds_widget); QGridLayout*const grid_clouds=new QGridLayout(); clouds_widget->setLayout(grid_clouds); clouds_subdivisions_unlock_checkbox=new QCheckBox("Subdivisions "); grid_clouds->addWidget(clouds_subdivisions_unlock_checkbox,1,0); clouds_subdivisions_unlock_checkbox->setChecked(false); clouds_subdivisions_unlock_checkbox->setToolTip("Enable explicit control of cloud subdivisons.\nWhen disabled, the cloud mesh will be subdivided by the same amount as the terrain"); connect(clouds_subdivisions_unlock_checkbox,SIGNAL(toggled(bool)), this,SLOT(setCloudsSubdivisionsUnlocked(bool)) ); clouds_subdivisions_spinbox=new SpinBox(0,16,1); grid_clouds->addWidget(clouds_subdivisions_spinbox,1,1); clouds_subdivisions_spinbox->setValue(parameters_cloud->subdivisions); connect( clouds_subdivisions_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setCloudSubdivisions(int)) ); clouds_subdivisions_spinbox->setToolTip("The number of times the initial structure will be subdivided.\nWARNING: EACH STEP QUADRUPLES THE MEMORY REQUIREMENT!"); clouds_subdivisions_spinbox->setEnabled(clouds_subdivisions_unlock_checkbox->isChecked()); connect( clouds_subdivisions_unlock_checkbox,SIGNAL(toggled(bool)), clouds_subdivisions_spinbox,SLOT(setEnabled(bool)) ); setCloudsSubdivisionsUnlocked(clouds_subdivisions_unlock_checkbox->isChecked()); clouds_seed_label=new QLabel("Clouds seed:"); grid_clouds->addWidget(clouds_seed_label,2,0); clouds_seed_spinbox=new SpinBox(0xffffffff,0x7fffffff,1); grid_clouds->addWidget(clouds_seed_spinbox,2,1); clouds_seed_spinbox->setValue(parameters_cloud->seed); clouds_seed_spinbox->setToolTip("Random seed for cloud generation"); grid_clouds->addWidget(new QLabel("Cloud height"),3,0); QSpinBox*const clouds_height_spinbox=new SpinBox(1,100,1); grid_clouds->addWidget(clouds_height_spinbox,3,1); clouds_height_spinbox->setValue(static_cast(parameters_cloud->cloudbase*100.0f)); clouds_height_spinbox->setToolTip("Altitude of cloud layer"); connect( clouds_height_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setCloudbase(int)) ); grid_clouds->addWidget(new QLabel("Weather systems"),4,0); QSpinBox*const clouds_weather_systems_spinbox=new SpinBox(0,1000,10); grid_clouds->addWidget(clouds_weather_systems_spinbox,4,1); clouds_weather_systems_spinbox->setValue(parameters_cloud->weather_systems); clouds_weather_systems_spinbox->setToolTip("Number of cyclonic features in clouds"); connect( clouds_weather_systems_spinbox,SIGNAL(valueChanged(int)), this,SLOT(setWeatherSystems(int)) ); colour_cloud_button=new QPushButton(build_icon_of_colour(parameters_cloud->colour),"Cloud colour"); grid_clouds->addWidget(colour_cloud_button,5,0,1,2); connect( colour_cloud_button,SIGNAL(clicked()), this,SLOT(pickColourCloud()) ); // Wiring to disable all cloud controls clouds_widget->setEnabled(parameters_cloud->enabled); connect( clouds_checkbox,SIGNAL(toggled(bool)), clouds_widget,SLOT(setEnabled(bool)) ); QWidget*const regenerate_widget=new QWidget(); layout()->addWidget(regenerate_widget); QGridLayout*const regenerate_grid=new QGridLayout(); regenerate_widget->setLayout(regenerate_grid); regenerate_button=new QPushButton("Generate"); regenerate_grid->addWidget(regenerate_button,0,0,1,3); connect( regenerate_button,SIGNAL(clicked()), regenerate_target,SLOT(regenerate()) ); regenerate_with_new_terrain_seed_button=new QPushButton("...new terrain seed"); regenerate_grid->addWidget(regenerate_with_new_terrain_seed_button,1,0); connect( regenerate_with_new_terrain_seed_button,SIGNAL(clicked()), this,SLOT(regenerate_with_new_terrain_seed()) ); regenerate_with_new_rivers_seed_button=new QPushButton("...new rivers seed"); regenerate_grid->addWidget(regenerate_with_new_rivers_seed_button,1,1); connect( regenerate_with_new_rivers_seed_button,SIGNAL(clicked()), this,SLOT(regenerate_with_new_rivers_seed()) ); regenerate_with_new_clouds_seed_button=new QPushButton("...new clouds seed"); regenerate_grid->addWidget(regenerate_with_new_clouds_seed_button,1,2); connect( regenerate_with_new_clouds_seed_button,SIGNAL(clicked()), this,SLOT(regenerate_with_new_clouds_seed()) ); regenerate_with_new_clouds_seed_button->setEnabled(parameters_cloud->enabled); connect( clouds_checkbox,SIGNAL(toggled(bool)), regenerate_with_new_clouds_seed_button,SLOT(setEnabled(bool)) ); } void ControlTerrain::regenerate_with_new_terrain_seed() { parameters_terrain->seed++; terrain_seed_spinbox->setValue(parameters_terrain->seed); regenerate_target->regenerate(); } void ControlTerrain::regenerate_with_new_rivers_seed() { parameters_terrain->rivers_seed++; rivers_seed_spinbox->setValue(parameters_terrain->rivers_seed); regenerate_target->regenerate(); } void ControlTerrain::regenerate_with_new_clouds_seed() { parameters_cloud->seed++; clouds_seed_spinbox->setValue(parameters_cloud->seed); regenerate_target->regenerate(); } fracplanet/control.cpp0000644000175100017510000000422311261123520014715 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "control.h" Control::Control() :QWidget() { setLayout(new QVBoxLayout()); } Control::~Control() {} void Control::pickColour(QPushButton* button,FloatRGBA& colour) { const ByteRGBA col_old(colour); QColor qcol_old(col_old.r,col_old.g,col_old.b); QColor qcol_new=QColorDialog::getColor(qcol_old,this); if (qcol_new.isValid()) { colour=FloatRGBA(ByteRGBA(qcol_new.red(),qcol_new.green(),qcol_new.blue(),255)); QPixmap pmap(16,16); pmap.fill(qcol_new); button->setIcon(QIcon(pmap)); } } /*! Used when initialising colour-chooser buttons. */ QIcon Control::build_icon_of_colour(const FloatRGBA& col) { QPixmap pmap(16,16); const ByteRGBA bcol(col); pmap.fill(QColor(bcol.r,bcol.g,bcol.b)); return QIcon(pmap); } fracplanet/geometry.cpp0000644000175100017510000001430211261123520015067 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "geometry.h" /*! Common scan-converter code */ void Geometry::scan_convert_common ( const boost::array& v, const ScanConvertBackend& backend ) { // Sort vertices by increasing image y co-ordinate boost::array sort={{0,1,2}}; if (v[sort[0]].y>v[sort[1]].y) exchange(sort[0],sort[1]); if (v[sort[1]].y>v[sort[2]].y) exchange(sort[1],sort[2]); if (v[sort[0]].y>v[sort[1]].y) exchange(sort[0],sort[1]); // deltas const float x02=v[sort[2]].x-v[sort[0]].x; const float y02=v[sort[2]].y-v[sort[0]].y; const float x01=v[sort[1]].x-v[sort[0]].x; const float y01=v[sort[1]].y-v[sort[0]].y; const float x12=v[sort[2]].x-v[sort[1]].x; const float y12=v[sort[2]].y-v[sort[1]].y; boost::optional ky02; boost::optional ky01; boost::optional ky12; if (y02==0.0f) return; ky02=1.0f/y02; if (y01!=0.0f) ky01=1.0f/y01; if (y12!=0.0f) ky12=1.0f/y12; // y range in image co-ordinates const int map_height=backend.height(); const int iy_min=static_cast(std::max(0.0f,ceilf(v[sort[0]].y-0.5f))); const int iy_mid=static_cast(floorf(v[sort[1]].y-0.5f)); const int iy_max=static_cast(std::min(map_height-0.5f,floorf(v[sort[2]].y-0.5f))); if (ky01) for (int iy=iy_min;iy<=iy_mid;iy++) { const float yp02=(iy+0.5f-v[sort[0]].y)*ky02.get(); const ScanEdge edge0(v[sort[0]].x+yp02*x02,sort[0],sort[2],yp02); const float yp01=(iy+0.5f-v[sort[0]].y)*ky01.get(); const ScanEdge edge1(v[sort[0]].x+yp01*x01,sort[0],sort[1],yp01); if (edge0.x<=edge1.x) backend.scan_convert_backend(iy,edge0,edge1); else backend.scan_convert_backend(iy,edge1,edge0); } if (ky12) for (int iy=iy_mid+1;iy<=iy_max;iy++) { const float yp02=(iy+0.5f-v[sort[0]].y)*ky02.get(); const ScanEdge edge0(v[sort[0]].x+yp02*x02,sort[0],sort[2],yp02); const float yp12=(iy+0.5f-v[sort[1]].y)*ky12.get(); const ScanEdge edge1(v[sort[1]].x+yp12*x12,sort[1],sort[2],yp12); if (edge0.x<=edge1.x) backend.scan_convert_backend(iy,edge0,edge1); else backend.scan_convert_backend(iy,edge1,edge0); } } /*! Scan lines are through the centre of pixels at y=0.5. This function doesn't care about quantization in x; that's for the backend. */ void GeometryFlat::scan_convert ( const boost::array& v, const ScanConvertBackend& backend ) const { const boost::array vp ={{ XYZ(backend.width()*0.5f*(1.0f+v[0].x),backend.height()*0.5f*(1.0f-v[0].y),0.0f), XYZ(backend.width()*0.5f*(1.0f+v[1].x),backend.height()*0.5f*(1.0f-v[1].y),0.0f), XYZ(backend.width()*0.5f*(1.0f+v[2].x),backend.height()*0.5f*(1.0f-v[2].y),0.0f) }}; scan_convert_common(vp,backend); } /*! The problem with spherical geometry is that spans can go off one side of the map and come back on the other. */ void GeometrySpherical::scan_convert ( const boost::array& v, const ScanConvertBackend& backend ) const { const boost::array vn={{v[0].normalised(),v[1].normalised(),v[2].normalised()}}; const bool coplanar=(fabsf((vn[0]*vn[1]).normalised()%vn[2]) < 1e-6f); if (coplanar) return; { const XYZ pole(0.0f,0.0f,1.0f); const float p01=pole%(v[0]*v[1]); const float p12=pole%(v[1]*v[2]); const float p20=pole%(v[2]*v[0]); const bool contains_pole=((p01>=0.0f && p12>=0.0f && p20>=0.0f) || (p01<=0.0f && p12<=0.0f && p20<=0.0f)); if (contains_pole) { // Don't subdivide when furthest vertex is so close it won't be rendered const float mx=std::max(fabsf(vn[0].x),std::max(fabsf(vn[1].x),fabsf(vn[2].x))); const float my=std::max(fabsf(vn[0].y),std::max(fabsf(vn[1].y),fabsf(vn[2].y))); const float m=std::max(mx,my); if (m<0.25f/backend.height()) return; else { const XYZ which_pole(0.0f,0.0f,((v[0]+v[1]+v[2]).z>0.0f? 1.0f : -1.0f)); backend.subdivide(v,which_pole,*this); } } } boost::array vp; for (uint i=0;i<3;i++) { vp[i].x=backend.width()*0.5f*(1.0f+M_1_PI*atan2f(vn[i].y,vn[i].x)); // atan2f returns [-pi to +pi] so vp[0] in [0,width] if (i!=0) { // Need to keep all the vertices in the same domain if (vp[i].x-vp[0].x>0.5*backend.width()) vp[i].x-=backend.width(); else if (vp[i].x-vp[0].x<-0.5*backend.width()) vp[i].x+=backend.width(); } vp[i].y=backend.height()*0.5f*(1.0f-asinf(vn[i].z)*M_2_PI); vp[i].z=0.0f; } for (float d=-1.0f;d<=1.0f;d+=1.0f) { // Easiest way to deal with triangles on the "date line" is to // render them with all possible placements and let the back end cull them. /*! \todo Might be better if span replication was done in backed rather than duplicating all the y-compute. */ boost::array vpt; for (uint i=0;i<3;i++) { vpt[i].x=vp[i].x+d*backend.width(); vpt[i].y=vp[i].y; vpt[i].z=vp[i].z; } scan_convert_common(vpt,backend); } } fracplanet/triangle_mesh_cloud.cpp0000644000175100017510000001515711261123520017254 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "triangle_mesh_cloud.h" #include "noise.h" #include "matrix34.h" #include "parameters_render.h" TriangleMeshCloud::TriangleMeshCloud(Progress* progress) :TriangleMesh(progress) {} TriangleMeshCloud::~TriangleMeshCloud() {} void TriangleMeshCloud::write_povray(std::ofstream& out,const ParametersSave&,const ParametersCloud&) const { // Double illuminate so underside of clouds is white. // No-shadow so clouds don't cast crazy dark shadows. TriangleMesh::write_povray(out,false,true,true); } void TriangleMeshCloud::write_blender(std::ofstream& out,const ParametersSave& parameters_save,const ParametersCloud&,const std::string& mesh_name) const { TriangleMesh::write_blender ( out, mesh_name+".cloud", (parameters_save.blender_per_vertex_alpha ? 0 : ¶meters_save.parameters_render->background_colour_low) ); } namespace { class ScanConvertHelper : public ScanConvertBackend { public: ScanConvertHelper(Raster& image,const boost::array& vertex_colours) :ScanConvertBackend(image.width(),image.height()) ,_image(image) ,_vertex_colours(vertex_colours) {} virtual ~ScanConvertHelper() {} virtual void scan_convert_backend(uint /*y*/,const ScanEdge& /*edge0*/,const ScanEdge& /*edge1*/) const {} virtual void subdivide(const boost::array& /*v*/,const XYZ& /*m*/,const ScanConverter& /*scan_converter*/) const {} private: Raster& _image; const boost::array& _vertex_colours; }; } void TriangleMeshCloud::render_texture(Raster& image) const { assert(false); image.fill(0); for (uint i=0;i vertex_positions ={{ vertex(t.vertex(0)).position(), vertex(t.vertex(1)).position(), vertex(t.vertex(2)).position() }}; const boost::array vertex_colours ={{ FloatRGBA(vertex(t.vertex(0)).colour(0)).a, FloatRGBA(vertex(t.vertex(1)).colour(0)).a, FloatRGBA(vertex(t.vertex(2)).colour(0)).a }}; ScanConvertHelper scan_convert_backend(image,vertex_colours); geometry().scan_convert ( vertex_positions, scan_convert_backend ); } } void TriangleMeshCloud::do_cloud(const ParametersCloud& parameters) { compute_vertex_normals(); progress_start(100,"Cloud colouring"); const ByteRGBA c(parameters.colour); //! \todo Wire up terms, decay and base fequency and thresholds MultiscaleNoise noise(parameters.seed,6,0.5); for (uint i=0;i(255.0*vs))); // Set other colour (unused) to red for debug vertex(i).colour(1,ByteRGBA(255,0,0,255)); } progress_complete("Cloud colouring completed"); // TODO: Eliminate all-transparent triangles & unused vertices. // Leave if nothing left // TODO: Bias weather into temperate bands (maybe not) progress_start(100,"Weather systems"); Random01 r01(parameters.seed); const uint steps=100*vertices(); uint step=0; for (uint i=0;i(r01()*vertices()); const XYZ position(vertex(random_vertex).position()); const XYZ axis(geometry().up(position)); // Rotate opposite direction in other hemisphere const float strength=r01()*(position.z<0.0 ? -M_PI : M_PI); for (uint j=0;j0.0f) // Don't create same feature on other side of planet (actually the distance would be big so could drop this) { const float distance=(p-position).magnitude(); const float rotation_angle=strength*exp(-10.0*distance); // Now rotate p about axis through position by the rotation angle // TODO: Optimise! axis and position is the same for all points; we're constantly recomputing the basis change matrices. // Create a stateful version of Matrix34RotateAboutAxisThrough. vertex(j).position ( Matrix34RotateAboutAxisThrough(axis,rotation_angle,position)*p ); } } } progress_complete("Weather systems completed"); _triangle_switch_colour=triangles(); } TriangleMeshCloudPlanet::TriangleMeshCloudPlanet(const ParametersCloud& parameters,Progress* progress) :TriangleMesh(progress) ,TriangleMeshCloud(progress) ,TriangleMeshSubdividedIcosahedron(1.0+parameters.cloudbase,parameters.subdivisions,parameters.subdivisions,parameters.seed,XYZ(0.0,0.0,0.0),progress) { do_cloud(parameters); } TriangleMeshCloudFlat::TriangleMeshCloudFlat(const ParametersCloud& parameters,Progress* progress) :TriangleMesh(progress) ,TriangleMeshCloud(progress) ,TriangleMeshFlat(parameters.object_type,parameters.cloudbase,parameters.seed,progress) { subdivide(parameters.subdivisions,parameters.subdivisions,XYZ(0.0,0.0,0.0)); do_cloud(parameters); } fracplanet/parameters_render.cpp0000644000175100017510000000471511261123520016745 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "parameters_render.h" #include "xyz.h" boost::program_options::options_description ParametersRender::options() { boost::program_options::options_description desc("Render options"); desc.add_options() ("display-list,d","use display list rendering") ("wireframe,w","render in wireframe mode") ("invert-mouse-y,y","invert mouse-y in flight mode"); return desc; } ParametersRender::ParametersRender(const boost::program_options::variables_map& opts) :wireframe(opts.count("wireframe")) ,display_list(opts.count("display-list")) ,joystick_mouse(!opts.count("invert-mouse-y")) ,ambient(0.1f) ,illumination_azimuth(-M_PI/3) ,illumination_elevation(M_PI/6) ,background_colour_low(0.25f,0.25f,1.0f,0.0f) ,background_colour_high(0.0f,0.0f,0.0f,0.0f) ,fps_target(60.0f) {} ParametersRender::~ParametersRender() {} const XYZ ParametersRender::illumination_direction() const { return XYZ ( cos(illumination_azimuth)*cos(illumination_elevation), sin(illumination_azimuth)*cos(illumination_elevation), sin(illumination_elevation) ); } fracplanet/parameters_terrain.cpp0000644000175100017510000000427011261123520017126 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "parameters_terrain.h" /*! \todo: Might be better (more portable) to use QTime::currentTime () for random seeds. */ ParametersTerrain::ParametersTerrain() :ParametersObject() ,subdivisions_unperturbed(1) ,variation(0.0,0.0,0.125) ,noise(0) ,base_height(0) ,power_law(1.5) ,snowline_equator(0.8) ,snowline_pole(-0.1) ,snowline_power_law(1.0) ,snowline_slope_effect(1.0) ,snowline_glacier_effect(0.1) ,rivers(0) ,rivers_seed(time(0)) ,lake_becomes_sea(0.05) ,oceans_and_rivers_emissive(0.0) ,colour_ocean (0.0,0.0,1.0,1.0) ,colour_river (0.0,0.0,1.0,1.0) ,colour_shoreline(1.0,1.0,0.0,1.0) ,colour_low (0.0,1.0,0.0,1.0) ,colour_high (1.0,0.5,0.0,1.0) ,colour_snow (1.0,1.0,1.0,1.0) {} ParametersTerrain::~ParametersTerrain() {} fracplanet/parameters_object.cpp0000644000175100017510000000307411261123520016731 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ #include "precompiled.h" #include "parameters_object.h" ParametersObject::ParametersObject() :object_type(ObjectTypePlanet) ,seed(time(0)) ,subdivisions(5) {} ParametersObject::~ParametersObject() {} fracplanet/image.cpp0000644000175100017510000001312211261123520014315 0ustar timdaytimday/**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Fracplanet is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Fracplanet is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Fracplanet. If not, see . */ /**************************************************************************/ /**************************************************************************/ /* Copyright 2009 Tim Day */ /* */ /* This file is part of Fracplanet */ /* */ /* Evolvotron is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* Evolvotron is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with Evolvotron. If not, see . */ /**************************************************************************/ /*! \file \brief Implementation for templated Image class. */ #include "precompiled.h" #include "image.h" #include "progress.h" #include "rgb.h" template void Raster::fill(const T& v) { if (contiguous()) { std::fill(contiguous_begin(),contiguous_end(),v); } else { for (RowIterator row=row_begin();row!=row_end();++row) std::fill((*row).begin(),(*row).end(),v); } } template const typename Raster::ScalarType Raster::maximum_scalar_pixel_value() const { ScalarType m(scalar(*_data)); for (ConstRowIterator row=row_begin();row!=row_end();++row) for (const T* it=row->begin();it!=row->end();++it) { const ScalarType v(scalar(*it)); if (v>m) m=v; } return m; } template <> bool Raster::write_pgmfile(const std::string& filename,Progress* target) const { ProgressScope progress(height(),"Writing PGM image:\n"+filename,target); std::ofstream out(filename.c_str(),std::ios::binary); out << "P5" << std::endl; out << width() << " " << height() << std::endl; out << "255" << std::endl; for (ConstRowIterator row=row_begin();row!=row_end();++row) { progress.step(); out.write(reinterpret_cast(&(*(row->begin()))),row->size()); } out.close(); return out; } template <> bool Raster::write_pgmfile(const std::string& filename,Progress* target) const { ProgressScope progress(height(),"Writing PGM image:\n"+filename,target); std::ofstream out(filename.c_str(),std::ios::binary); out << "P5" << std::endl; out << width() << " " << height() << std::endl; const ushort m=maximum_scalar_pixel_value(); out << m << std::endl; for (ConstRowIterator row=row_begin();row!=row_end();++row) { progress.step(); for (const ushort* it=row->begin();it!=row->end();++it) { const uchar p[2]={((*it)>>8),(*it)}; if (m>=256) { // PGM spec is most significant byte first out.write(reinterpret_cast(p),2); } else { assert(p[0]==0); out.write(reinterpret_cast(p+1),1); } } } out.close(); return out; } template <> bool Raster::write_ppmfile(const std::string& filename,Progress* target) const { ProgressScope progress(height(),"Writing PPM image:\n"+filename,target); std::ofstream out(filename.c_str(),std::ios::binary); out << "P6" << std::endl; out << width() << " " << height() << std::endl; out << "255" << std::endl; for (ConstRowIterator row=row_begin();row!=row_end();++row) { progress.step(); for (const ByteRGBA* it=row->begin();it!=row->end();++it) out.write(reinterpret_cast(&((*it).r)),3); } out.close(); return out; } template class Raster; template class Image; template class Raster; template class Image; template class Raster; template class Image;